Memory Instructions
Instruction table
| Inst | Name | FMT | Opcode | funct3 | Description (C) | Syntax |
|---|---|---|---|---|---|---|
lb |
Load Byte | I | 0000011 |
0x0 |
rd = M[rs1+imm][7:0] |
op rd, imm(rs1) |
lh |
Load Half | I | 0000011 |
0x1 |
rd = M[rs1+imm][15:0] |
op rd, imm(rs1) |
lw |
Load Word | I | 0000011 |
0x2 |
rd = M[rs1+imm][31:0] |
op rd, imm(rs1) |
lbu |
Load Byte (U) | I | 0000011 |
0x4 |
rd = M[rs1+imm][7:0] |
op rd, imm(rs1) |
lhu |
Load Half (U) | I | 0000011 |
0x5 |
rd = M[rs1+imm][15:0] |
op rd, imm(rs1) |
sb |
Store Byte | S | 0100011 |
0x0 |
M[rs1+imm][7:0] = rs2[7:0] |
op rs2, imm(rs1) |
sh |
Store Half | S | 0100011 |
0x1 |
M[rs1+imm][15:0] = rs2[15:0] |
op rs2, imm(rs1) |
sw |
Store Word | S | 0100011 |
0x2 |
M[rs1+imm][31:0] = rs2[31:0] |
op rs2, imm(rs1) |
lwandswbehave the same way as offset mode LDR/STR in ARM.- Note that
lwandswdo not have the same format. - There are no pre/post-index modes — as only one register can be written by
an instruction, base register and destination register can't be updated within
the same instruction.
- Incrementing the base register has to be done explicitly using
add/addiinstructions.
- Incrementing the base register has to be done explicitly using
-
No pre/post-index also means there are no load/store (LDM/STM) multiple type of instructions, and hence, no PUSH/POP.
Think about it
Does this make the code slower? Bigger?
- Implementing a stack (conventionally full descending) will need to be done
entirely in software, using multiple separate
lw/swandaddiinstructions. - Conventionally,
sp— stack pointer, which isx2, is used.
- Implementing a stack (conventionally full descending) will need to be done
entirely in software, using multiple separate
Pseudoinstructions
Pseudoinstructions lw rd, LABEL and sw rs2, LABEL, rt (where rt is a
temporary register) are also valid, which will be translated to:
auipc rd, imm1
lw rd, imm2(rd)
auipc rt, imm1
sw rs2, imm2(rt)
where imm1 and imm2 are chosen by the assembler such that
LABEL = PC + imm1<<12 + imm2.
Sign and zero extension
- For
lbandlh, which load a byte or a half word, the rest of the bits are formed by sign-extension of the byte/half-word. - For
lbuandlhu, zero extension is done instead.1 - In all cases, the offset used to generate the memory address is MSB-extended as it is an immediate.
sbandshdo not involve any extension, as only a byte or half-word in the memory is modified; the rest of the bytes/half-word within the word is unmodified.
Memory instruction example
Assuming s1/x9 = 0x4321DCBA; s2/x18 = 0x00002408.
| Pseudoinstruction / Assembler Directive | Actual Instruction | Operation | Actual Memory Location Content (Instruction in Hex) |
|---|---|---|---|
sw s1, -4(s2) |
sw x9, 0xffc(x18) |
M[x18+0xfffffffc = 0x00002408+0xfffffffc = 0x00002404] = x9 = 0x4321DCBA |
0xfe992e23 |
lb s4, -4(s2) |
lb x20, 0xffc(x18) |
x20[7:0] = M[x18+0xfffffffc = 0x00002408+0xfffffffc = 0x00002404]x20[31:8] = x20[7]x20 = 0xFFFFFFBA (0x000000BA if lbu) |
0xffc90a03( 0xffc94a03 if lbu) |
sw (S-type) and lb (I-type). Note the split immediate in the store.-
Note that this does not contradict our earlier statement that RISC-V always MSB-extends the immediate. We are not talking about extending immediates here, but about extending the half-word or byte loaded from memory. ↩