基本概念
指令与指令集
- 指令(Instruction):CPU执行的基本操作单元,包含操作码和操作数。
- 指令集(Instruction Set Architecture, ISA):定义CPU支持的指令类型和格式的规范,决定了CPU的功能和性能。
- 常见的指令集有x86、ARM、MIPS等,RISC-V是近年来兴起的一种开源指令集架构。
汇编语言
- 汇编语言(Assembly Language):一种低级编程语言,直接对应于机器指令,使用助记符表示操作码和寄存器。
- Instruction set for a particular architecture (e.g. RISC-V) is represented by the Assembly language.(一个特定架构的指令集由汇编语言表示。)
- Each line of assembly code represents one instruction for the compute.(每行汇编代码代表计算机的一条指令。)
寄存器
- 寄存器(Register):CPU内部的高速存储单元,用于临时存储数据和指令。寄存器数量有限,访问速度快。
- 内存(Memory):用于存储程序和数据的较大容量存储设备,访问速度较慢。
- 汇编语言不能使用变量,而是操纵寄存器。CPU从内存中加载数据到寄存器,进行计算后再存回内存。
- 寄存器比内存快得多。操作内存的速度大约是操作一次寄存器的速度(0.25ns)的50-500倍。
- 在RISC-V中,一共有32个寄存器,每个寄存器32位宽(4个字节)
- 寄存器命名:x0-x31,其中x0始终为0,x1-x31可用于存储数据。寄存器中的数据没有类型,类型由指令决定。
大字端与小字端
- 大字端(Big-endian):数据的高位字节存储在低地址,低位字节存储在高地址。
- 小字端(Little-endian):数据的低位字节存储在低地址,高位字节存储在高地址。
- RISC-V,以及世界上大多数现代处理器,采用小字端格式存储数据。
ADD/SUB
add
add rd, rs1, rs2- 功能:将寄存器rs1和rs2中的值相加,并将结果存储在寄存器rd中。
- 操作数:3个寄存器,分别是目的寄存器(rd)和两个源寄存器(rs1和rs2)。
sub
sub rd, rs1, rs2- 功能:将寄存器rs1中的值减去寄存器rs2中的值,并将结果存储在寄存器rd中。
- 操作数:3个寄存器,分别是目的寄存器(rd)和两个源寄存器(rs1和rs2)。
addi
addi rd, rs1, imm- 功能:将寄存器rs1中的值与立即数imm相加,并将结果存储在寄存器rd中。
- 操作数:2个寄存器(rd和rs1)和一个立即数(imm)。立即数是一个常数值,直接编码在指令中。
Data Transfer
lw
lw rd, offset(rs1)举例: 假设x15存了int数组A的起始地址,lw指令可以从内存中加载一个字(4字节)到寄存器中:
lw x5, 0(x15) # 从地址x15加载第一个元素
lw x6, 4(x15) # 从地址x15+4加载第二个元素x5就是A[0],x6就是A[1]。
sw
sw rs2, offset(rs1)举例: 假设x15存了int数组A的起始地址,sw指令可以将寄存器中的值存储到内存中:
sw x5, 0(x15) # 将寄存器x5的值存储到地址x15
sw x6, 4(x15) # 将寄存器x6的值存储到地址x15+4lb,sb
lb rd, offset(rs1) # 加载一个字节到寄存器
sb rs2, offset(rs1) # 将寄存器中的一个字节存储到内存功能:
lb/sb指令与lw/sw很相似,但是lb指令从内存中加载1个字节(8位)到寄存器中,sb指令将寄存器中的1个字节存储到内存中。
举例:
假设x15存了char数组B的起始地址,lb指令可以从内存中加载一个字节到寄存器中:
lb x5, 0(x15) # 从地址x15加载第一个元素
lb x6, 1(x15) # 从地址x15+1加载第二个元素
sb x5, 2(x15) # 将寄存器x5的值存储到地址x15x5就是B[0],x6就是B[1],sb指令将x5的值存储到地址x15+2,即B[2]。所以现在B[2]的值被更新为B[0]的值。
lbu
lbu rd, offset(rs1) # 加载一个字节到寄存器,无符号扩展功能:
lbu指令与lb指令类似,但它加载一个字节到寄存器时进行无符号扩展,即不考虑最高位的符号,直接在寄存器的高位填充0。
习题:
addi x11, x0, 0x3F5
sw x11, 0(x5)
lb x12, 1(x5)x12 的结果是什么?
解答:
addi x11, x0, 0x3F5:将立即数0x3F5加载到寄存器x11中。sw x11, 0(x5):将寄存器x11的值(0x3F5)按照 小端序 存储到内存地址x5开始的 4 个字节中。 内存地址(设x5 = A):
A[0] = 0xF5(0x3F5的最低字节)A[1] = 0x03(0x3F5的次低字节)A[2] = 0x00(0x3F5的次高字节)A[3] = 0x00(0x3F5的最高字节)
lb x12, 1(x5):从内存地址x5 + 1(即A[1])加载一个字节到寄存器x12中。A[1]的值是0x03,最高位是0,所以进行符号扩展时,会在寄存器x12的高位填充0,最终结果是0x00000003。