记忆:加载与存储

记忆:加载与存储

内存是一大排带编号的存储槽,每个槽存放一个字节(8 位)。槽的编号就是它的地址。寄存器是 CPU 的一小组快速槽位。内存大得多但更慢,它存放所有放不进寄存器的内容,比如数组和字符串。要操作内存中的值,你把它加载到寄存器,修改它,再存回去。

寄存器很少,内存很大。(load word)把一个字从内存复制到寄存器,(store word)把它复制回去。地址写作 offset(register)。

RISC-V 内存按字节寻址,所以每个字节按顺序都有自己的地址。一个字是 32 位,即 4 字节,所以要把内存指针前进 4 才能到达下一个字。这就是数组偏移量为 0、4、8 等的原因。在真实硬件上,从不是 4 的倍数的地址加载一个字可能很慢,也可能触发陷阱。本模拟器允许这样做,但你应该养成让字对齐到 4 字节的习惯。

加载/存储形状
lw t0, 0(a1) # t0 = 地址 a1 处的内存
sw t0, 4(a1) # 地址 a1+4 处的内存 = t0

在 offset(register) 中,寄存器保存的地址会加上那个小的偏移量。0(a1) 就是 a1 本身的地址,4(a1) 是它往后 4 字节。这样你无需改变基址寄存器就能访问附近的值。

正在存储到内存
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

寄存器和内存从零开始。

在动画中,基址寄存器 a0 保持不变。只有指令中写出的字面偏移量在增加,移动到下一个目标内存地址。 要创建符合这种模式的内存,请在数据段用 .word(一个或多个 32 位值)或 .space N(N 个空白字节)预留具名内存。每个字占 4 字节,所以连续项位于偏移量 0、4、8,这些正是你在存储指令中使用的数字。

用 .word(一个或多个 32 位值)或 .space N(N 个空白字节)在数据段预留具名内存。每个字占 4 字节,所以连续项位于偏移量 0、4、8 等。

在内存中求数组之和
.data
nums: .word 10, 20, 30, 40 # 四个字
.text
la t1, nums # t1 = 数组的地址
li t2, 4 # 计数
li t0, 0 # 累计总和
loop:
beq t2, zero, done
lw t3, 0(t1) # 加载当前元素
add t0, t0, t3 # 加到总和中
addi t1, t1, 4 # 前进到下一个字 (4 字节)
addi t2, t2, -1 # 剩余数减一
j loop
done:
mv a0, t0 # 打印总和 (100)
li a7, 1
ecall
li a7, 10
ecall

把数组的地址放入 t1,t2 记录剩余 4 个元素,t0 保存累计和。每一轮中, 在没有元素剩余时停止循环。 加载 t1 指向的元素, 把它加到和中, 把指针前进一个字, 减少计数。四个元素全部处理完后(10 + 20 + 30 + 40),done 打印 100。

💡
使用模拟器工具栏中的 HEX/DEC 切换来改变地址和值的显示方式。选择让当前步骤更易跟随的进制。