6.⾃制操作系统:risc-v⽐较和跳转指令⽐较指令
指令
名称
功能ISA type⽤法含义
BEQ相等时分⽀RV32I/RV64I B beq rs1,
rs2, offset
若寄存器 x[rs1]和寄存器 x[rs2]的值相等,把 pc 的值设为当前值加上
符号位扩展的偏移 offset。
BEQZ等于0时分⽀RV32I/RV64I 伪指
beqz rs1,
offset
可视为beq rs1, x0, offset
BGE ⼤于等于时
分⽀
RV32I/RV64I B
bge rs1,
rs2, offset
若寄存器 x[rs1]的值⼤于等于寄存器 x[rs2]的值(均视为⼆进制补
码),把 pc 的值设为当前值加上符号位扩展的偏移 offset
BGEU ⽆符号⼤于
等于分⽀
RV32I/RV64I B
bgeu rs1,
rs2, offset
若寄存器 x[rs1]的值⼤于等于寄存器 x[rs2]的值(均视为⽆符号数),
把 pc 的值设为当前值加上符号位扩展的偏移 offset
BGEZ ⼤于等于零
时分⽀
RV32I/RV64I
伪指
bgez rs1,
offset
可视为bge rs1, x0, offset
BGT⼤于分⽀RV32I/RV64I 伪指
bgt rs1,
rs2, offset
可视为blt rs2, rs1, offset
BGTU ⽆符号⼤于
时分⽀
RV32I/RV64I
伪指
bgtu rs1,
rs2, offset
可视为bltu rs2, rs1, offset
BGTZ⼤于0时分⽀RV32I/RV64I 伪指
bgtz rs1,
offset
可视为blt x0, rs2, offset
BLE ⼩于等于时
分⽀
RV32I/RV64I
伪指
ble rs1, rs2,
offset
可视为 bge rs2, rs1, offset
BLEU ⽆符号⼩于
等于时分⽀
RV32I/RV64I
伪指
bleu rs1,
rs2, offset
可视为 bgeu rs2, rs1, offset
BLEZ ⼩于等于0时
分⽀
RV32I/RV64I
伪指
blez rs2,
offset
可视为 bge x0, rs2, offset
BLT⼩于时分⽀RV32I/RV64I B blt rs1, rs2
offset
若寄存器 x[rs1]的值⼩于寄存器 x[rs2]的值(均视为⼆进制补码),把
pc 的值设为当前值加上符号位扩展的偏移 offset。
BLTZ ⼩于零时分
RV32I/RV64I
伪指
bltz rs2,
offset
可视为 blt rs1, x0, offset
BLTU ⽆符号⼩于
时分⽀
RV32I/RV64I B
bltu rs1,
rs2, offset
若寄存器 x[rs1]的值⼩于寄存器 x[rs2]的值(均视为⽆符号数),把
pc 的值设为当前值加上符号位扩展的偏移 offset。
BNE 不相等时分
RV32I/RV64I B
bne rs1,
rs2, offset
offset指令是什么意思
若寄存器 x[rs1]和寄存器 x[rs2]的值不相等,把 pc 的值设为当前值加
上符号位扩展的偏移offset
BNEZ 不等于0时分
RV32I/RV64I
伪指
bnez rs1,
offset
可视为 bne rs1, x0, offset
跳转指令
指令
名称
功能ISA type⽤法含义
J跳转RV32I/RV64I 伪指
j offset
把 pc 设置为当前值加上符号位扩展的 offset,等同于 jal x0,
offset.
JAL跳转并链接RV32I/RV64I J jal rd, offset 把下⼀条指令的地址(pc+4),然后把 pc 设置为当前值加上符号位扩展的offset。rd 默认为 x1( rd为return address)
JALR 跳转并寄存器链接
(jump and link
register)
RV32I/RV64I I
jalr rd,
offset(rs1)
把 pc 设置为 x[rs1] + sign-extend(offset),把计算出的地址
的最低有效位设为 0,并将原 pc+4的值写⼊f[rd]。 rd 默认为
x1。
JR寄存器跳转RV32I/RV64I 伪指
jr rs1把 pc 设置为 x[rs1],等同于 jalr x0, 0(rs1)。
CALL调⽤RV32I/RV64I 伪指
call rd,
symbol
把下⼀条指令的地址(pc+4) 写⼊ x[rd],然后把 pc 设为
symbol。等同于 auipc rd, offestHi,再加上⼀条 jalr rd,
offsetLo(rd). 若省略了 rd,默认为 x1.
RET返回RV32I/RV64I 伪指
ret从⼦过程返回。实际被扩展为 jalr x0, 0(x1)。
跳转指令实例
1.RET指令
#
#  unsigned long jump_isa_ret(void)
#  测试⽬的:将ret指令替换为jalr x0, 0(ra)指令,测试此函数是否能正常返回
#  将pc设置为(ra)
.globl jump_isa_ret
jump_isa_ret:
li a0, 1
jalr x0, 0(ra) #ra is return address
以上是将ret指令替换为jalr x0, 0(ra)指令的汇编代码。ret指令是伪代码,实际的代码是jalr x0, 0(ra)。其
中x0是zero,ra是返回地址。jalr指令将pc赋值为了ra,(这⾥为什么要给ra加上括号,rsic-v括号表⽰是取地址上的数据出来),即实现了返回。
2.JAL指令
#
#  unsigned long jump_isa_jal(unsigned long i)
#  下⾯的代码⽆法返回,因为ra被修改了。
.globl jump_isa_jal
jump_isa_jal:
addi a0, a0, 1
jal ra, jump_isa_jal_depend
ret
.globl jump_isa_jal_depend
jump_isa_jal_depend:
addi a0, a0, 1
ret
1.了解jal指令⽤法
把下⼀条指令的地址(pc+4)存放到ra中,然后把 pc 设置为当前值加上符号位扩展的offset(即跳转到jump_isa_jal_depend函数)。
2.问题
上⾯汇编代码在执⾏到jump_isa_jal的ret函数后将⽆法返回到调⽤jump_isa_jal的函数中。根据risc-v的函数调⽤规则,ret指令是将ra地址赋值给pc。
修改:
#
#  unsigned long jump_isa_jal_yes(unsigned long i)
#  在c语⾔调⽤jump_isa_jal_yes时,已经在使⽤ra寄存器了,
#  但是在jump_isa_jal_yes中调⽤jump_isa_jal_depend_yes
#  函数时需要使⽤ra作为返回地址,所以,这⾥必须要保存ra的值。
#
.globl jump_isa_jal_yes
jump_isa_jal_yes:
add t1, ra, x0
addi a0, a0, 1
jal ra, jump_isa_jal_depend_yes
add ra, t1, x0
ret
.
globl jump_isa_jal_depend_yes
jump_isa_jal_depend_yes:
addi a0, a0, 1
ret

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。