本文是RVSC-V处理器学习的第一篇文章,对RV32IMAFDC指令集的学习笔记。
1. 运算指令
立即数运算指令
addi rd,rs1,imm[11:0]
功能
1.将rs1与12位立即数(进行符号位扩展)相加,并将结果存到rd寄存器中去,如果结果溢出,舍弃溢出位,不做处理,保留低32位结果 2.addi rd,rs1,0 指将rs1寄存器中的值存入rd中去
为什么没有立即数减法操作? 因为addi运算是带符号位进行运算的,可以用addi rd,rs1,-10 实现rd=rs1-10功能
寄存器运算指令
add rd,rs1,rs2
sub rd,rs1,rs2
功能
1.将rs1与rs2相加,并将结果存到rd寄存器中去,如果结果溢出,舍弃溢出位,不做处理,保留低32位结果,sub指令类似
x0特殊寄存器
通过硬件方式,x0寄存器固定为0,为只读寄存器
add x3,x4,x0
功能
1.将x4赋值给x3
rv32有32个寄存器,从x0到x31 zero:x0
2. 访问存储指令
- 首先明确一下,在RV32中1字(word)=4(bytes)=32(bit),内存是以字节为单位,一个字的内存由4字节组成。
- 默认小端模式其中寄存器访问速度大概是DRAM的100~500倍。
- 小端模式下,一个字的地址与它最低位的字节地址相同。
c code:
int A[100];
g=h+A[3]
s code:
lw x10,12(x15)
add x11,x12,x10
x15存放A数组的基地址,12表示偏移量(偏移地址),12(x15)即表示A[3] 注意:偏移地址在RV32中在字为操作单元的指令中需为4的倍数,如:lw、sw
功能
1.lw读一个32位的数据,存入寄存器中。
lb、lbu、sw、sb
lb rd,offset[11:0](res) #读一个8位数据,并进行符号位扩展 用于有符号数
lbu rd,offset[11:0](res) #读一个8位数据,并进行高位补零 用于无符号数**
sw rs2,offset[11:0](res) #写
sb rs2,offset[11:0](res) #写
为什么需要符号位或者高位扩展? 因为当从存储器读一个8位数据到寄存器时,寄存器为32位故需要扩展。
3.条件判断转移指令
3.1 条件跳转
指令后加u代表对无符号数操作
beq rs1,rs2,label #相等跳
bne rs1,rs2,label #不相等跳
bge rs1,rs2,label #大于等于跳 有符号数
bgeu rs1,rs2,label #大于等于跳 无符号数
blt rs1,rs2,label #小于
bltu rs1,rs2,label #
if-else例子:
3.2 无条件跳转
j label #无条件跳转
4.逻辑运算指令
and rd,rs1,rs2 将rs1和rs2进行与运算,结果存rd
or rd,rs1,rs2 将rs1和rs2进行或运算
xor rd,rs1,rs2 将rs1和rs2进行异或或运算
sll rd,rs1,rs2 逻辑左移(低位补零)
srl rd,rs1,rs2 逻辑右移(高位补零)
sra rd,rs1,rs2 算术右移(高位补符号位)
- 逻辑非实现:使用异或操作,例如:
xor rd,rs1,0xff ,表示rs1寄存器低八位取非 - 算术右移与逻辑右移运算区别?
逻辑运算不考虑符号位,右移左边直接添零,算术运算考虑符号位,左边添加符号位 在算术运算中右移n位并不一定代表除以2的n次方,如图
小练习
5. 函数调用
1.每条指令都以32位(4字节)机器码形式存放在存储器中 2.函数数调用的六个过程 ①. 函数调用时,执行函数前,先将调用中要用到的参数保存; ②.控制权移交给调用的功能函数; ③.申请存储空间,满足执行过程中内存开耗 ④.执行函数的功能操作 ⑤.函数执行完后,保存结果数据,同时还原函数执行过程中使用到的寄存器值、释放分配给函数的本地存储空间(局部变量等)。 ⑥.释放控制权
函数调用常用到的寄存器
a0-a7(x10-x17):8个寄存器用于传递参数,a0-a1常用于传递返回值 x1(ra):用于放置原函数返回地址 x2(sp):堆栈指针 s0-s11和s2-s11:用于保存原函数的关键数据,不受破坏
- 注意: ra寄存器中的返回地址,为当前地址+4,
- zero代指x0寄存器 hard zero
- 解释:
j label 和jr r1 的区别是j 是跳转到一个具体的地址,而jr 是跳转到一个寄存器地址,sum的函数调用肯定会发生在不同地点,故函数返回值都不相同- 一般使用
ret 指令代替jr ra 指令 - 使用
jal ra,label 跳转指令,可保存函数返回值到ra 中去,值为pc+4
|