4.自制操作系统: risc-v 加载存储指令

加载指令

指令名称

功能

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中。

load指令练习

学习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)。

store指令练习

学习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

注意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.

汇编参考代码

调用汇编代码

你可能感兴趣的:(risc-v,bare,metal,risc-v)