记忆:加载与存储
内存是一大排带编号的存储槽,每个槽存放一个字节(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)
| Address | Value |
|---|---|
| 0x100C | 0x00000000 |
| 0x1008 | 0x00000000 |
| 0x1004 | 0x00000000 |
| 0x1000 | 0x00000000 |
| 0x0FFC | 0x00000000 |
寄存器和内存从零开始。
a0 保持不变。只有指令中写出的字面偏移量在增加,移动到下一个目标内存地址。
要创建符合这种模式的内存,请在数据段用 .word(一个或多个 32 位值)或 .space N(N 个空白字节)预留具名内存。每个字占 4 字节,所以连续项位于偏移量 0、4、8,这些正是你在存储指令中使用的数字。用 .word(一个或多个 32 位值)或 .space N(N 个空白字节)在数据段预留具名内存。每个字占 4 字节,所以连续项位于偏移量 0、4、8 等。
在内存中求数组之和
.datanums: .word 10, 20, 30, 40 # 四个字.textla t1, nums # t1 = 数组的地址li t2, 4 # 计数li t0, 0 # 累计总和loop:beq t2, zero, donelw t3, 0(t1) # 加载当前元素add t0, t0, t3 # 加到总和中addi t1, t1, 4 # 前进到下一个字 (4 字节)addi t2, t2, -1 # 剩余数减一j loopdone:mv a0, t0 # 打印总和 (100)li a7, 1ecallli a7, 10ecall
把数组的地址放入 t1,t2 记录剩余 4 个元素,t0 保存累计和。每一轮中, 在没有元素剩余时停止循环。 加载 t1 指向的元素, 把它加到和中, 把指针前进一个字, 减少计数。四个元素全部处理完后(10 + 20 + 30 + 40),done 打印 100。
💡
使用模拟器工具栏中的 HEX/DEC 切换来改变地址和值的显示方式。选择让当前步骤更易跟随的进制。
