指令名称 |
功能 |
ISA |
type | 用法 |
含义 |
LA |
地址加载 |
RV32I/RV64I |
伪指令 |
la rd, symbol |
将 symbol 的地址加载到 x[rd]中。当编译位置无关的代码时,它会被扩展为对全局偏移量表(Global Offset Table)的加载。 对于 RV32I, 等同于执行 auipc rd, offsetHi,然后是 lw rd,offsetLo(rd);对于 RV64I,则等同于 auipc rd, offsetHi 和 ld rd, offsetLo(rd)。如果 offset 过大,开始的算加载地址的指令会变成两条,先是 auipc rd, offsetHi 然后是 addi rd, rd, offsetLo |
LI |
立即数加载, |
RV32I/RV64I |
伪指令 |
li rd, immediate |
使用尽可能少的指令将常量加载到 x[rd]中。 在 RV32I 中,它等同于执行 lui 和/或 addi; 对于 RV64I, 会扩展为这种指令序列 lui, addi, slli, addi, slli, addi ,slli, addi。 |
LLA |
本地地址加载 |
RV32I/RV64I |
伪指令 |
lla rd, symbol |
将 symbol 的地址加载到 x[rd]中。 等同于执行 auipc rd, offsetHi,然后是 addi rd, rd, offsetLo。 |
LB |
字节加载 |
RV32I/RV64I |
I |
lb rd, offset(rs1) |
从地址 x[rs1] + sign-extend(offset)读取一个字节,经符号位扩展后写入 x[rd]。 |
LBU |
无符号字节加载 |
RV32I/RV64I |
I |
lbu rd, offset(rs1) |
从地址 x[rs1] + sign-extend(offset)读取一个字节,经零扩展后写入 x[rd]。 |
LH |
半字加载 |
RV32I/RV64I |
I |
lh rd, offset(rs1) | 从地址 x[rs1] + sign-extend(offset)读取两个字节,经符号位扩展后写入 x[rd]。 |
LHU |
无符号半字加载 |
RV32I/RV64I |
I |
lhu rd, offset(rs1) | 从地址 x[rs1] + sign-extend(offset)读取两个字节,经零扩展后写入 x[rd]。 |
LD |
双字加载 |
RV32I/RV64I |
I |
ld rd, offset(rs1) |
从地址 x[rs1] + sign-extend(offset)读取八个字节,写入 x[rd]。 |
LR.D |
加载保留双字 |
RV64A |
R |
lr.d rd, (rs1) |
从内存中地址为 x[rs1]中加载八个字节,写入 x[rd], 并对这个内存双字注册保留 |
LW |
字加载 |
RV32I/RV64I |
I |
lw rd, offset(rs1) |
从地址 x[rs1] + sign-extend(offset)读取四个字节,写入 x[rd]。对于 RV64I,结果要进行符号位扩展。 |
LR.W |
加载保留字 |
RV32A/RV64A |
R |
lr.w rd, (rs1) |
从内存中地址为 x[rs1]中加载四个字节,符号位扩展后写入 x[rd], 并对这个内存字注册保留。 |
LWU |
无符号字加载 |
RV64I |
I |
lwu rd, offset(rs1) |
从地址 x[rs1] + sign-extend(offset)读取四个字节,零扩展后写入 x[rd]。 |
LUI |
高位立即数加载 |
RV32I/RV64I |
U |
lui rd, immediate |
将符号位扩展的 20 位立即数 immediate 左移 12 位, 并将低 12 位置零, 写入 x[rd中。 |
学习LA/LB/LD/LH/LHU指令用法
#
# 学习la和lb指令用法:
# 函数char load_isa_la_lb(int index)
# 函数含义:
# la加载msg的地址到s2寄存器,参数index在汇编中用a0表示
# 然后使用lb指令读取msg字符串的第index个字节,返回值存放在a0中。
# 总结:
# la 地址加载指令,伪指令,用法 la rd, symbol, 将symbol加载到x[rd]寄存器中
# lb 字节加载指令,lb rd, offset(rs1),从地址x[rs1]+sign-extend(offset) 读取一个字节
.globl load_isa_la_lb
load_isa_la_lb:
la s2, msg
add s3, s2, a0
lb a0, 0(s3)
ret
#
# 函数unsigned long load_isa_ld(unsigned long *array, int index)
# 函数含义:
# 返回array[index]的值。
# array的值存放在寄存器a0中,index的值存放在寄存器a1中
# slli 逻辑左移指令,将index的值左移3位,相当于乘以8
# 总结:
# 1. 在汇编中,index只是一个数值,不会智能的将其转换为array[index],
# 必须转化为array+8*index 才能得到array[index]的值
# 2. ld指令为双字加载指令,格式 ld rd, offset(rs1)
# 从地址x[rs1]+sign-extend(offset)读取8个字节,写入x[rd]
.globl load_isa_ld
load_isa_ld:
slli a1, a1, 3 # a1*8
add s1, a0, a1
ld a0, 0(s1)
ret
#
# 函数unsigned int load_isa_lh(unsigned int *array, int index)
# load_isa_lh和load_isa_lhu函数是为了对比lh和lhu指令
# lh: lh rd offset(rs1) 半字加载指令,从地址x[rs1]+sign-extend(offset)读取2个字节,经过符号位扩展后写入x[rd]
# lhu: lhu rd offset(rs1) 无符号半字加载指令,从地址x[rs1]+sign-extend(offset)读取2个字节,经过符号位扩展后写入x[rd]
.globl load_isa_lh
load_isa_lh:
slli a1, a1, 2 # a1*4
add s1, a0, a1
lh a0, 0(s1)
ret
#
# 函数unsigned int load_isa_lhu(unsigned int *array, int index)
#
.globl load_isa_lhu
load_isa_lhu:
slli a1, a1, 2 # a1*4
add s1, a0, a1
lhu a0, 0(s1)
ret
.section .data
msg:
.string "Hello, world!\n"
测试la lb
printk("test lb la isa:\n");
for(int index; index < 14; index++)
printk("%c", load_isa_la_lb(index));
结果
test lb la isa:
Hello, world!
指令名称 |
功能 |
ISA |
type |
用法 |
含义 |
SD |
存双字 |
RV64I |
S |
sd rs2, offset(rs1) |
将 x[rs2]中的 8 字节存入内存地址 x[rs1]+sign-extend(offset)。 |
SC.D |
条件存入双字 |
RV64A |
R |
sc.d rd, rs2, (rs1) |
如果内存地址 x[rs1]上存在加载保留,将 x[rs2]寄存器中的 8 字节数存入该地址。如果存入成功,向寄存器 x[rd]中存入 0,否则存入一个非 0 的错误码 |
SW |
存字 |
RV32I/RV64I |
S |
sw rs2, offset(rs1) |
将 x[rs2]的低位 4 个字节存入内存地址 x[rs1]+sign-extend(offset)。 |
SC.W |
条件存入字 |
RV32A/RV64A |
R |
sc.w rd, rs2, (rs1) |
内存地址 x[rs1]上存在加载保留,将 x[rs2]寄存器中的 4 字节数存入该地址。如果存入成功,向寄存器 x[rd]中存入 0,否则存入一个非 0 的错误码。 |
SH |
存半字 |
RV32I/RV64I |
S |
sh rs2, offset(rs1) |
将 x[rs2]的低位 2 个字节存入内存地址 x[rs1]+sign-extend(offset)。 |
SB |
存字节 |
RV32I/RV64I |
S |
sb rs2, offset(rs1) |
将 x[rs2]的低位字节存入内存地址 x[rs1]+sign-extend(offset)。 |
学习SD/SW/SH/SB指令
#
# unsigned long store_isa_sd(unsigned long *addr, unsigned long v)
# 函数含义:
# 将v存储到地址addr中,然后在读取addr内存中数据的值,返回
#
.globl store_isa_sd
store_isa_sd:
sd a1, 0(a0)
ld a0, 0(a0)
ret
# unsigned int store_isa_sd(unsigned int *addr, unsigned int v)
.globl store_isa_sw
store_isa_sw:
sw a1, 0(a0)
lw a0, 0(a0)
ret
# unsigned short store_isa_sd(unsigned short *addr, unsigned short v)
.globl store_isa_sh
store_isa_sh:
sh a1, 0(a0)
lh a0, 0(a0)
ret
# unsigned char store_isa_sd(unsigned short *char, unsigned char v)
.globl store_isa_sb
store_isa_sb:
sb a1, 0(a0)
lb a0, 0(a0)
ret
注意LR/SC能被用作构造lock-free数据结构。
如下比较交换函数:
# a0 holds address of memory location
# a1 holds expected value
# a2 holds desired value
# a0 holds return value, 0 if successful, !0 otherwise
cas:
lr.w t0, (a0)
bne t0, a1, fail
sc.w t0, a2, (a0)
bnez t0, cas
li a0, 0
jr ra
fail:
li a0, 1
jr ra
# Load original value.
# Doesn’t match, so fail.
# Try to update.
# Retry if store-conditional failed.
# Set return to success.
# Return.
# Set return to failure.
# Return.
汇编参考代码
调用汇编代码