Memory: load & store

Memory: load & store

Memory is a large row of numbered storage slots, and each slot holds one byte (8 bits). The number of a slot is its address. Registers are the CPU's small set of fast slots. Memory is much larger but slower, and it holds everything that does not fit in registers, such as arrays and strings. To work with a value in memory, you load it into a register, change it, and store it back.

Registers are few and memory is large. (load word) copies a word from memory into a register, and (store word) copies it back. The address is written as offset(register).

RISC-V memory is byte-addressed, so each byte has its own address in sequence. A word is 32 bits, or 4 bytes, so you advance a memory pointer by 4 to reach the next word. This is why array offsets are 0, 4, 8, and so on. On real hardware, loading a word from an address that is not a multiple of 4 can be slow or can cause a trap. This simulator permits it, but you should form the habit of keeping words aligned to 4 bytes.

Load / store shape
lw t0, 0(a1) # t0 = memory at address a1
sw t0, 4(a1) # memory at address a1+4 = t0

In offset(register), the address held in the register has the small offset number added to it. 0(a1) is the address in a1 itself, and 4(a1) is 4 bytes past it. This lets you reach nearby values without changing the base register.

Storing to memory
CPU
li t0, 0x11111111
li t1, 0x22222222
li a0, 0x1000
sw t0, 0(a0)
sw t1, 8(a0)
Registers
t00x00000000
t10x00000000
a00x00000000
Random Access Memory (RAM)
AddressValue
0x100C0x00000000
0x10080x00000000
0x10040x00000000
0x1000
0x00000000
0x0FFC0x00000000

Registers and memory start at zero.

In the animation, the base register a0 stays the same. Only the literal offset written in the instruction increases, moving to the next target memory address. To create memory that matches this pattern, reserve named memory in the data section with .word (one or more 32-bit values) or .space N (N blank bytes). Each word is 4 bytes, so consecutive items sit at offsets 0, 4, 8, which are the same numbers used in your store instructions.

Use .word (one or more 32-bit values) or .space N (N blank bytes) to reserve named memory in the data section. Each word takes 4 bytes, so consecutive items are at offsets 0, 4, 8 and so on.

Sum an array in memory
.data
nums: .word 10, 20, 30, 40 # four words
.text
la t1, nums # t1 = address of the array
li t2, 4 # count
li t0, 0 # running sum
loop:
beq t2, zero, done
lw t3, 0(t1) # load current element
add t0, t0, t3 # add to sum
addi t1, t1, 4 # advance to next word (4 bytes)
addi t2, t2, -1 # one fewer left
j loop
done:
mv a0, t0 # print the total (100)
li a7, 1
ecall
li a7, 10
ecall

puts the address of the array in t1, t2 counts the 4 remaining elements, and t0 holds the running sum. On each pass, stops the loop when no elements remain. loads the element that t1 points to, adds it to the sum, advances the pointer by one word, and reduces the count. After all four elements (10 + 20 + 30 + 40), done prints 100.

💡
Use the HEX/DEC toggle in the simulator toolbar to switch how addresses and values are displayed. Pick whichever base makes the current step easier to follow.