RISC-V简介

也可以看一下 数字系统设计复习笔记:第十二篇

寄存器

RV32/64I指令集定义了32个32/64位的通用整数寄存器x0~x31,其中x0固定用于存放数据0;寄存器位数决定了其可以访问的地址空间大小。

寄存器 别名 常见用途
x1 ra 返回地址 (Return Address)jal 指令自动将返回地址存入此处。
x2 sp 栈指针 (Stack Pointer):指向当前栈顶。
x3 gp 全局指针 (Global Pointer):指向 2048 字节的小数据区(.sdata),用于高效访问小全局变量。
x4 tp 线程指针 (Thread Pointer):用于线程本地存储(TLS)。
x5 t0 临时寄存器 (Temporary):调用者保存(caller-saved)。
x6x7 t1, t2 额外的临时寄存器。
x8 s0 / fp 保存寄存器 / 帧指针:被调用者保存(callee-saved)。也可用作帧指针。
x9 s1 保存寄存器。
x10x17 a0a7 函数参数和返回值:传递前 8 个参数;a0/a1 也用于返回值。
x18x27 s2s11 保存寄存器:被调用者保存,适合存放局部变量。
x28x31 t3t6 临时寄存器。

指令组成

也可以看一下 从零开始学RISCV:序篇

单周期RISC-V处理器的数据通路

I-Type (LOAD)

lw的指令格式为I-Type:

1
2
3
[31:20]    [19:15]    [14:12]    [11:7]    [6:0]
imm rs1 funct3 rd op
12bits 5bits 3bits 5bits 7bits

首先从指令内存中取指,根据op决定是lw指令,随后从指令中拆分出寄存器地址rs1并从寄存器堆中读取对应地址的值,再将立即数imm从12位补全到32位,接着将两个值送进ALU进行运算。运算完成后,将结果输入数据内存,读取对应地址数据值,再将数据值传回寄存器堆,写入目标寄存器rd,最后决定下一个指令的地址为PC+4,送回PC寄存器

lw单周期数据通路

S-Type

sw的指令格式为S-Type:

1
2
3
[31:25]    [24:20]    [19:15]    [14:12]    [11:7]    [6:0]
imm[11:5] rs2 rs1 funct3 imm[4:0] op
6bits 5bits 5bits 3bits 5bits 7bits

首先从指令内存中取指,根据op决定是sw指令,随后从指令中拆分出寄存器地址rs1并从寄存器堆中读取对应地址的值,再将立即数imm从12位补全到32位,接着将两个值送进ALU进行运算。运算完成后,将结果输入数据内存,以选择目标地址,再将数据值从寄存器堆传入数据内存,最后决定下一个指令的地址为PC+4,送回PC寄存器

sw单周期数据通路

R-Type

or的指令格式为R-Type:

1
2
3
[31:25]    [24:20]    [19:15]    [14:12]    [11:7]    [6:0]
funct7 rs2 rs1 funct3 rd op
6bits 5bits 5bits 3bits 5bits 7bits

首先从指令内存中取指,根据op只能决定是R-Type指令,具体为什么指令还需要读取funct7funct3进行判断。判断为or后,从指令中拆分出寄存器地址rs1rs2,并从寄存器堆中读取对应地址的值,不经过立即数拓展,直接送入ALU进行比较,随后将数据值传回寄存器堆,写入目标寄存器rd,最后决定下一个指令的地址为PC+4,送回PC寄存器

or单周期数据通路

B-Type

beq的指令格式为B-Type:

1
2
3
[31:25]        [24:20]    [19:15]    [14:12]    [11:7]        [6:0]
imm[12, 10:5] rs2 rs1 funct3 imm[4:1, 11] op
6bits 5bits 5bits 3bits 5bits 7bits

首先从指令内存中取指,根据op决定为B-Type,随后从指令中拆分出寄存器地址rs1rs2,并从寄存器堆中读取对应地址的值,接着将两个值送进ALU进行运算,结果为14-14=0。运算完成后,将CPSR的Z设置为1。同时,立即数扩展产生-12,与PC相加,得到新的PC地址,并送入PC选择器以便随后使用。

这里为什么是-12?

0xFFA1111_1111_1010,负数补码为取反加一,因此是0000_0000_0101(2)+1(2)=0110(2)=6(10)。所以0xFFA为-6。又因为要低位拓展为0,即算术左移,相当于乘以2,所以最终的立即数为-12。

注意这里的立即数是imm[12:1],低位还需要补0。最终为13位立即数,表达式为:
{20{Instr[31]}, Instr[7], Instr[30:25], Instr[11:8], 1'b0}

beq单周期数据通路

控制信号生成

单周期处理器的控制单元基于opfunct3funct7设计控制信号。RV32I 指令集只使用funct7的第 5 位。

控制信号生成的高层与底层结构图

增强的I-Type指令支持

对于addi指令,其同样为I-Type,但是仅靠先前的通路无法执行,因其控制信号与lw不同。ImmSrc依旧为00,ALUSrc为1,代表使用立即数扩展后的结果。但ResultSrc为0,代表直接使用ALU的计算结果而不从数据寄存器取值。

addi单周期数据通路以及控制信号

J-Type

jal的指令格式为J-Type:

1
2
3
[31:11]                   [11:7]        [6:0]
imm[20, 10:1, 11, 19:12] rd op
20bits 5bits 7bits

首先从指令内存中取指,根据op决定为J-Type,随后从指令中拆分出寄存器地址rd,并将pc+4写入寄存器堆,再将立即数imm从21位补全到32位,和pc一起送入ALU进行运算,求得新的地址值,最后传回PC寄存器

I/S-Type的立即数均为12位,B-Type的立即数为13位,J-Type最长,为21位!

和B-Type类似,J-Type同样需要低位补0(乘以2)。

jal单周期数据通路以及控制信号

执行时间

对于单周期处理器来说,周期时间受限于关键路径,即执行时间最长的路径。通常,路径中的瓶颈在内存存取、ALU和寄存器堆读写中。

各组件执行任务所需时间

对于所有指令操作,lw是执行最长的。可将时间简化为:

Tcsingle=tpcqPC+2tmem+tRFread+tALU+tmux+tRFsetupT_{\mathrm{c_{-}single}}=t_{\mathrm{pcq_{-}PC}}+2t_{\mathrm{mem}}+t_{\mathrm{RFread}}+t_{\mathrm{ALU}}+t_{\mathrm{mux}}+t_{\mathrm{RFsetup}}

多周期RISC-V处理器

单周期处理器有 3 个明显的缺点。首先,使用两个独立的内存分别存储指令和数据,而大多数处理器只有一个内存用于存储指令和数据;其次,需要足够长的时钟周期支持最慢的指令lw, 尽管大多数指令可能更快;最后,用了 3 个加法器(1 个在 ALU 中,2 个用于实现 PC 逻辑),而加法器是相对昂贵的电路,尤其是需要快速时价格更高。

对于多周期处理器,使用组合内存,既存储指令也存储数据。这样,可以在一个周期读取指令而在另一个周期读取或写入数据。

多周期处理器结构,注意有一个用于存储旧PC的寄存器

流水线RISC-V处理器

这应该是处理器的最终形态了:用流水线来增加吞吐量。

参考 计算机原理与嵌入式系统笔记:第十篇

带控制器的流水线处理器

性能计算

必考。了解如何计算,以及哪些指令需要阻塞。

我们假定:

  • 40% 的load指令被下一条指令使用;
  • 50% 的分支指令预测错误;
  • 不停滞时Load CPI = 1, 停滞时为2;
  • 不停滞时Branch CPI = 1,停滞时为3;

对于平均Load CPI,计算为 1x0.6 + 2x0.4=1.4;分支CPI同理,可求得为2。

对于 SPECINT2000 benchmark 测评程序:

  • 25% loads
  • 10% stores
  • 11% branches
  • 2% jumps
  • 52% R-type/I-type ALU

我们认为Jump指令的CPI为3,是因为前两个周期(IF/ID)正常执行,但还需要一周期的气泡。

因此,可求得平均CPI为 0.25x1.4 + 0.1x1 + 0.11x2 + 0.02x3 + 0.52x1 = 1.25

执行时间

参考上面的表格,计算关键路径:

流水线处理器关键路径

可列出流水线周期表达式为:

Tc_pipelined=tpcq+4tmux+tALU+tANDOR+tsetupT_{c\_pipelined} = t_{pcq} + 4t_\text{mux} + t_\text{ALU} + t_{AND-OR} + t_\text{setup}

求得流水线的周期为350ps。因此,执行1000亿条指令的程序,在求得CPI为1.25的状况下,总消耗时间为:

100×109×1.25×(350×1012)=44 s100\times10^9\times1.25\times(350\times10^{12})=44\ s

处理器 执行时间 加速比
单周期 75s 1
多周期 155s 0.5
流水线 44s 1.7

先进微架构

  • 超标量(Superscalar)架构:在一个时钟周期内发射多条指令(例如 Intel Core、AMD Zen 系列)。
  • 深度流水线(Deep Pipeline):将指令执行分解为更多阶段(例如 Intel NetBurst 曾达到 31 级流水线)。
  • 动态流水线调整:现代架构(如 Apple M1、AMD Zen 4)可根据功耗和负载动态调整流水线深度。
  • 乱序执行(Out-of-Order Execution):打破程序的指令顺序约束,动态调度以最大化执行单元利用率。
  • 寄存器重命名(Register Renaming):避免伪依赖(false dependency),提升并行度。
  • 混合架构(Hybrid Architecture):如 Intel Alder Lake 的 Performance Core 与 Efficiency Core。
  • 多线程(Multithreading):如 Intel 的 Hyper-Threading(超线程)技术

超标量

超标量内部含有多条数据通路,可以同时执行多条指令。

对于两路超标量,理想的IPC(Instruction Per Cycle,每周期执行指令数,为CPI的倒数)为2;对于上面带数据依赖的程序,实际的IPC为6 / 5 = 1.2,因实际周期时间从5到9,为5个周期。注意lw指令后必定阻塞一拍。

乱序发射

乱序提前检测多条指令并尽快发送无依赖的指令。只要保证依赖关系满足,可以产生预期效果,就可以不按照程序编写的顺序发送指令。

对于上面带依赖关系的乱序执行,其IPC为6 / 4 = 1.5

SIMD

SIMD(Single Instruction Multiple Data,单指令多数据)可以显著增加数据的并行度,如将8个8位元素相加。