【RISC-V】 li指令

在RISC-V中有这样一条伪指令:

li a0, immediately

可以将任意的32位数据或者地址加载到指定的寄存器中

在 RV32I中,它扩展到 lui 和/或 addi

li 何时扩展为 lui 或者 addi呢?又何时扩展为lui 和 addi呢?

我们观察lui 和 addi 的指令码即可得出结果
在这里插入图片描述
在这里插入图片描述
由上图可知,lui加载的立即数为高20位,addi加载的立即数为低12位

由此得出结论

  • li 加载的立即数范围为:0~4096 时,会扩展成 addi 指令

    li a0, immediately ⇒ addi a0, x0, imme

  • li 加载的立即数范围超过4096时,会扩展成 lui 指令addi 指令

    li a0, immediately 扩展成
    1、lui a0, (immediately >> 12)
    2、addi a0, a0, (immediately & 0xFFF)

  • li 加载的立即数范围超过4096时,并且低12位为0,会扩展成 lui 指令

    li a0, immediately
    扩展成
    lui a0, (immediately >> 12)


接上文,观察 lui指令addi指令 会得到这个结果:lui指令加载的立即数为无符号,无需注意。addi指令加载的为有符号数,这个需要考虑一下立即数的符号位

假如我们要加载大立即数到指定的寄存器,需要考虑两种情况

1、第11位为0

第11位为0,则指令:li a0, immediate 会直接扩展成:

lui   a0,  immediate >> 12
addi  a0, a0, (immediate & 0xFFF)

2、第11位为1

第11位为1,此时 li a0, immediate 就不会扩展成

lui   a0,  immediate >> 12
addi  a0, a0, (immediate & 0xFFF)

而是扩展成

lui   a0,  ((immediate >> 12) + 1)
addi  a0, a0, ((immediate & 0xFFF) - 2^12)

解释一下:

addi指令所加载的立即数的第11位为1时,这个立即数是符号扩展的,因此加数将为负数。这意味着除了添加常量的最右边11位
之外,我们还需要减去2^12。为了弥补这个错误,只需将lui 加载的常量添加一个1,因为 lui 常量缩小了 2 ^12倍

例如:将 0xE76 加载到寄存器a0中
答:

lui   a0,  0x01
addi  a0, a0, (0xE76 - 4096)

代码实现

#define immediate  XXXX

uint32_t MSB, LSB;
MSB = immediate >> 12;
LSB = immediate & 0xFFF;

if (MSB == 0) {
	if (LSB & 0x800) {
		asm volatile("lui a0, 0x01"); 
		asm volatile("addi a0, a0, LSB - 4096"); 
	} else {
		asm volatile("addi a0, x0, LSB"); 
	}
} else {
	if (LSB & 0x800) {
		asm volatile("lui a0, MSB + 0x01"); 
		asm volatile("addi a0, a0, LSB - 4096"); 
	} else {
		asm volatile("lui a0, MSB"); 
		asm volatile("addi a0, x0, LSB"); 
	}
}
  • 9
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
好的,以下是一个简单的RISC-V汇编指令的冒泡排序的实现: ``` # RISC-V汇编指令的冒泡排序 .data array: .word 5, 2, 8, 3, 1 # 待排序的数组 n: .word 5 # 数组的长度 .text .globl main main: # 初始化寄存器 la x1, array # 数组地址存储在 x1 中 lw x2, n # 数组长度存储在 x2 中 li x3, 1 # 将 1 存储在 x3 中,用于比较 # 开始排序 loop: li x4, 0 # 将 0 存储在 x4 中,用于判断是否交换位置 li x5, 0 # 将 0 存储在 x5 中,用于遍历数组 loop1: beq x5, x2, end # 如果 x5 = x2,则跳出循环 lw x6, 0(x1) # 将 array[x5] 存储在 x6 中 lw x7, 4(x1) # 将 array[x5+1] 存储在 x7 中 blt x6, x7, skip # 如果 array[x5] < array[x5+1],则跳过交换操作 sw x7, 0(x1) # 将 array[x5+1] 存储到 array[x5] 中 sw x6, 4(x1) # 将 array[x5] 存储到 array[x5+1] 中 li x4, 1 # 标记已交换 skip: addi x5, x5, 1 # x5++ addi x1, x1, 4 # 指向下一个元素 j loop1 # 继续遍历 beq x4, x3, loop # 如果已经完成排序,则跳出循环 subi x2, x2, 1 # x2-- li x5, 0 # 重新开始遍历数组 la x1, array # 指向数组的第一个元素 j loop # 继续排序 end: # 排序完成,输出结果 li x10, 1 # 将 1 存储在 x10 中,用于输出整数 li x5, 0 # 将 0 存储在 x5 中,用于遍历数组 loop2: beq x5, x2, exit # 如果 x5 = x2,则跳出循环 lw a0, 0(x1) # 将 array[x5] 存储在 a0 中 li a7, 1 # 将系统调用号 1(输出整数)存储在 a7 中 ecall # 调用系统 addi x5, x5, 1 # x5++ addi x1, x1, 4 # 指向下一个元素 j loop2 # 继续遍历 exit: li a7, 10 # 将系统调用号 10(退出程序)存储在 a7 中 ecall # 调用系统,退出程序 ``` 这段代码实现了一个简单的冒泡排序,通过遍历数组并比较相邻元素的值,不断交换位置直到排序完成。在排序完成后,程序输出排序后的结果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

点灯大师~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值