| 类型 | 数量 | 名称示例 | 访问方式 | 主要用途 |
|---|---|---|---|---|
| 通用寄存器 | 32个 | x0-x31 a0-a7, sp, ra, s0-s11, t0-t6 |
普通指令直接访问add, lw, sw等 |
程序运行时数据存储和计算 |
| 控制状态寄存器(CSR) | 上百个 | mstatus, mie, mtvec, mepc, mcause, satp |
专用CSR指令访问csrrw, csrrs, csrrc等 |
控制CPU状态、中断、异常、内存管理等 |
add、lw等操作31 23 15 7 0
| SD | WPRI | FS | XS | MPP | WPRI | SPP | MPIE | UBE | SPIE | WPRI | MIE | WPRI | SIE | UIE |
| 位域 | 名称 | 含义 | 说明 |
|---|---|---|---|
| [31] | SD | 状态脏位 | 1=FS或XS字段显示扩展状态为脏 |
| [30:23] | WPRI | 保留 | 写保持值,读忽略 |
| [22:21] | WPRI | 保留 | - |
| [20:19] | WPRI | 保留 | - |
| [18:17] | WPRI | 保留 | - |
| [16:15] | FS | 浮点状态 | 00: Off, 01: Initial, 10: Clean, 11: Dirty |
| [14:13] | XS | 扩展状态 | 扩展单元状态(类似FS) |
| [12:11] | MPP | 机器前特权级 | 异常前特权模式:00=U, 01=S, 11=M |
| [10:9] | WPRI | 保留 | - |
| [8] | SPP | 监管前特权级 | 监管模式异常前的特权级 |
| [7] | MPIE | 机器前中断使能 | 异常前MIE的值 |
| [6] | UBE | 字节序 | 1=大端, 0=小端 |
| [5] | SPIE | 监管前中断使能 | 监管模式异常前SIE的值 |
| [4] | WPRI | 保留 | - |
| [3] | MIE | 机器中断使能 | 全局机器模式中断使能 |
| [2] | WPRI | 保留 | - |
| [1] | SIE | 监管中断使能 | 监管模式中断使能 |
| [0] | UIE | 用户中断使能 | 用户模式中断使能 |
| CSR名称 | 地址 | 特权级 | 说明 |
|---|---|---|---|
| mstatus | 0x300 | Machine | 机器状态寄存器 |
| misa | 0x301 | Machine | ISA和信息寄存器 |
| mie | 0x304 | Machine | 机器中断使能 |
| mtvec | 0x305 | Machine | 陷阱向量基地址 |
| mepc | 0x341 | Machine | 异常程序计数器 |
| mcause | 0x342 | Machine | 陷阱原因 |
| mtval | 0x343 | Machine | 陷阱值 |
| mip | 0x344 | Machine | 中断挂起 |
| mscratch | 0x340 | Machine | 临时存储 |
| satp | 0x180 | Supervisor | 页表基址 |
RISC-V提供了6条CSR操作指令,用于原子性地读写控制和状态寄存器。
31 20 19 15 14 12 11 7 6 0
| csr[11:0] | rs1 | funct3 | rd | opcode |
CSRRW: csr | rs1 | 001 | rd | 1110011 # 读-写操作
CSRRS: csr | rs1 | 010 | rd | 1110011 # 读-置位操作
CSRRC: csr | rs1 | 011 | rd | 1110011 # 读-清零操作
CSRRWI: csr | zimm | 101 | rd | 1110011 # 立即数读-写
CSRRSI: csr | zimm | 110 | rd | 1110011 # 立即数读-置位
CSRRCI: csr | zimm | 111 | rd | 1110011 # 立即数读-清零
操作语义:
temp = CSR[csr]
CSR[csr] = x[rs1]
x[rd] = temp
特点: 原子交换CSR和通用寄存器的值
特殊用法: rd=x0时只写不读
ABI寄存器示例:
# 保存mstatus并禁用中断
csrrw s0, mstatus, zero # s0 = 旧mstatus, mstatus = 0
# 配置mtvec只写不读
la a0, trap_handler
csrrw zero, mtvec, a0 # mtvec = 陷阱处理程序地址
操作语义:
temp = CSR[csr]
CSR[csr] = temp | x[rs1]
x[rd] = temp
特点: 原子读取并置位CSR的指定位
特殊用法: rs1=x0时只读不写
ABI寄存器示例:
# 启用定时器中断
li a1, 0x80 # MTIE位
csrrs zero, mie, a1 # mie |= 0x80
# 只读取mstatus当前值
csrrs a2, mstatus, zero # a2 = mstatus
操作语义:
temp = CSR[csr]
CSR[csr] = temp & ~x[rs1]
x[rd] = temp
特点: 原子读取并清零CSR的指定位
特殊用法: rs1=x0时只读不写
ABI寄存器示例:
# 禁用外部中断
li a3, 0x888 # MEIE, SEIE, UEIE位
csrrc zero, mie, a3 # mie &= ~0x888
# 读取mepc值
csrrc a4, mepc, zero # a4 = mepc
操作语义:
temp = CSR[csr]
CSR[csr] = zimm
x[rd] = temp
特点: 使用5位零扩展立即数原子写CSR
注意: zimm范围0-31
ABI寄存器示例:
# 快速设置mstatus为特定值
csrrwi s1, mstatus, 0x8 # s1 = 旧mstatus, mstatus = 0x8
# 快速清零mscratch
csrrwi zero, mscratch, 0 # mscratch = 0
操作语义:
temp = CSR[csr]
CSR[csr] = temp | zimm
x[rd] = temp
特点: 使用立即数原子置位CSR
特殊用法: zimm=0时只读不写
ABI寄存器示例:
# 设置MPP字段为机器模式
csrrsi zero, mstatus, 0x1800 # mstatus[12:11] = 3
# 读取并启用软件中断
csrrsi a5, mie, 0x8 # a5 = 旧mie, mie[3] = 1
操作语义:
temp = CSR[csr]
CSR[csr] = temp & ~zimm
x[rd] = temp
特点: 使用立即数原子清零CSR
特殊用法: zimm=0时只读不写
ABI寄存器示例:
# 清除监管模式中断使能
csrrci zero, mstatus, 0x2 # mstatus[1] = 0
# 读取并清除定时器中断挂起
csrrci a6, mip, 0x80 # a6 = 旧mip, mip[7] = 0
# 启用机器模式中断
enable_interrupts:
# 保存当前状态
csrrw s2, mstatus, zero # s2 = 当前mstatus
# 启用定时器和外部中断
li a0, 0x888 # MTIE | MEIE
csrrs zero, mie, a0
# 全局启用中断
ori s2, s2, 0x8 # 设置MIE位
csrrw zero, mstatus, s2 # 恢复mstatus并启用中断
ret
# 安全禁用中断
disable_interrupts:
csrrw s3, mstatus, zero # 保存当前状态
andi s3, s3, ~0x8 # 清除MIE位
csrrw zero, mstatus, s3 # 禁用中断
ret
# 异常处理入口
trap_handler:
# 使用mscratch保存原始栈指针
csrrw sp, mscratch, sp # 交换sp和mscratch
# 保存关键寄存器
addi sp, sp, -64
sw ra, 0(sp)
sw a0, 4(sp)
sw a1, 8(sp)
sw a2, 12(sp)
sw s0, 16(sp)
sw s1, 20(sp)
# 保存CSR状态
csrrw a0, mstatus, zero
sw a0, 60(sp)
csrrw a1, mepc, zero
sw a1, 56(sp)
csrrw a2, mcause, zero
sw a2, 52(sp)
# 根据mcause分发处理
andi a3, a2, 0x7FFFFFFF
li t0, 11 # 机器模式环境调用
beq a3, t0, handle_mecall
# 恢复上下文并返回
trap_return:
lw a0, 60(sp)
csrrw zero, mstatus, a0
lw a1, 56(sp)
csrrw zero, mepc, a1
lw ra, 0(sp)
lw a0, 4(sp)
lw a1, 8(sp)
lw a2, 12(sp)
lw s0, 16(sp)
lw s1, 20(sp)
addi sp, sp, 64
csrrw sp, mscratch, sp # 恢复原始sp
mret
# 切换到用户模式
enter_user_mode:
# 设置mstatus: MPP=用户模式
li a0, 0x1800 # MPP字段掩码
csrrc s4, mstatus, a0 # 清除MPP字段
# 设置用户模式入口点
la a1, user_entry
csrrw zero, mepc, a1
# 返回用户模式
mret
# 设置陷阱向量
setup_trap:
la a0, trap_vector
csrrw zero, mtvec, a0
ret
# 安全修改mstatus的特定字段
modify_mstatus_bits:
# 目标: 修改MPP和MPIE,不影响其他位
li a0, 0x1880 # MPP[12:11] + MPIE[7]
csrrc s5, mstatus, a0 # 清除目标位
# 设置新值: MPP=监管模式(01), MPIE=1
li a1, 0x0800 # MPP=01 << 11
ori a1, a1, 0x80 # MPIE=1
or s5, s5, a1 # 组合新值
csrrw zero, mstatus, s5 # 原子写回
ret
# 使用立即数版本提高小常数操作性能
# 慢速版本:
li a0, 8
csrrs zero, mstatus, a0
# 快速版本:
csrrsi zero, mstatus, 8 # 单指令完成
# CSR读取优化
csrrs a0, mstatus, zero # 标准读取
csrrw a0, mstatus, zero # 同样效果,可能更清晰
// 所有CSR操作都是原子的
// 在读取旧值和写入新值之间不会被中断
// 这对于并发编程至关重要
# rd = zero: 不读取CSR旧值(只写)
csrrw zero, mstatus, a0 # 只写mstatus,不保存旧值
# rs1 = zero: 不改变CSR值(只读)
csrrs a0, mstatus, zero # 只读mstatus,不修改它
# zimm = 0: 立即数版本只读不写
csrrsi a1, mie, 0 # 只读mie,不修改
// CSR访问受特权级别限制
// 用户模式尝试访问机器模式CSR会引发异常
// 必须确保在正确的特权级执行CSR操作
// 立即数版本只能使用5位立即数(0-31)
// 对于更大的值必须使用寄存器版本
li a0, 0x1800
csrrs zero, mstatus, a0 # 正确:大数值
csrrsi zero, mstatus, 0x1800 # 错误:立即数太大
| 指令 | 功能 | 操作 | 特殊用法 | 典型用途 |
|---|---|---|---|---|
| CSRRW | 读-写 | CSR←rs1, rd←CSR旧值 | rd=zero: 只写不读 | 保存并替换CSR |
| CSRRS | 读-置位 | CSR←CSR|rs1, rd←CSR旧值 | rs1=zero: 只读不写 | 启用功能位 |
| CSRRC | 读-清零 | CSR←CSR&~rs1, rd←CSR旧值 | rs1=zero: 只读不写 | 禁用功能位 |
| CSRRWI | 立即数读-写 | CSR←zimm, rd←CSR旧值 | rd=zero: 只写不读 | 快速设置小值 |
| CSRRSI | 立即数读-置位 | CSR←CSR|zimm, rd←CSR旧值 | zimm=0: 只读不写 | 快速置位 |
| CSRRCI | 立即数读-清零 | CSR←CSR&~zimm, rd←CSR旧值 | zimm=0: 只读不写 | 快速清零 |
这些CSR指令为操作系统和系统软件提供了强大的处理器状态管理能力,是构建可靠系统软件的基础。