Computational instructions only work on the contents of registers. Memory access instruction exchange 8/16/32-bit values ("bytes"/ "halfs"/"words") between registers and RAM locations.
There are 5 load ("RAM to register") instructions and 3 store ("register to RAM") instructions. They use byte addresses in RAM encoded as the value in register rs1 added with 12-bit sign-extended immediate.
2 fence instructions serialize concurrent accesses to RAM from different hardware threads.
Misaligned RAM access is allowed, but can be non-atomic and/or much slower.
|lw rd, imm(rs1)||"load word"|
|lh rd, imm(rs1)||"load half",|
|lb rd, imm(rs1)||"load byte",|
|lhu rd, imm(rs1)||"load half unsigned"|
|lbu rd, imm(rs1)||"load byte unsigned"|
|sw imm(rs1), rs2||"store word"|
|sh imm(rs1), rs2||"store half"|
|sb imm(rs1), rs2||"store byte"|
|fence pred, succ||an explicit barrier for the specified kinds of |
concurrent memory accesses
|fence.i||an explicit barrier for writing and executing |
instructions in RAM concurrently
When multiple harts, hardware threads ("cores") are present and share the same RAM, it is necessary to control how changes by one hart are perceived by another.
Some (ahem, x86_64) architectures provide sequential consistency, which guarantees that any observed state can be described by some combination of concurrent sequential changes. This model makes it easier to reason about machine code, but can significantly complicate hardware. Under sequential consistency, speculative and out-of-order execution must maintain a separate externally visible sequentially-consistent state.
Since different harts work with different areas of RAM most of the time, RISC-V assumes a relaxed memory model, which requires explicit synchronization when needed.
A fence instruction provides an ordering guarantee between memory accesses before and after the fence. The arguments describe:
- the predecessor set: kinds of accesses by prior instructions that must be completed before fence
- the successor set: kinds of accesses by subsequent instructions that must not start before the fence
The kinds of accesses are:
- R: "read memory"
- W: "write memory"
- I: "device input"
- O: "device output"
fence rw, w guarantees that all reads and writes by preceding
instructions appear completed before this instruction and any reordered writes
by subseqent instructions must wait until this instruction.
Note: reads by subsequent instructions can happen before this fence.
A fence.i allows to synchronize RAM data-access and instruction-access. E.g. if one hart writes instructions to RAM and another executes them, fence.i guarantees that preceding stores by one hart become visible to instruction fetches from another hart after.
Stores are in S-type format:
The following instructions are in I-type format:
Least significant byte looks like:
TODO: clarify encoding of pred/succ masks.