Lecture 19: RISC-V Single Cycle Datapath II

Implementing Loads

实现 lw 指令

  • lw 指令的格式lw x14, 8(x2) 使用 I 型格式,其中 x2 是基址寄存器,8 是立即数偏移。

  • lw 指令的二进制表示
    • imm[11:0]:立即数部分,占用12位。
    • rs1:源寄存器1,占用5位,这里是 x2。
    • funct3:功能码,占用3位,表示加载操作。
    • rd:目标寄存器,占用5位,这里是 x14。
    • opcode:操作码,占用7位,表示加载字(LOAD)。
  • 与 addi 类似的数据通路:lw 指令的实现与 addi 指令类似,但 lw 指令创建的是一个地址,而不是最终存储的值。
    • 地址计算addr = (基址寄存器 rs1) + (符号扩展的立即数 imm)

image-20240804122631850

状态元素访问现在包括内存读取

  • DMEM:在 addr 地址读取字数据。
  • 寄存器文件(RegFile)
    • Reg[rs1]:读取数据。
    • Reg[rd]:写入数据。
  • 程序计数器(PC)PC = PC + 4

将内存读取保存到寄存器文件

  • 数据通路图解释
    • PC:程序计数器,在每个时钟周期增加4。
    • IMEM:指令存储器,根据 PC 提供当前指令。
    • ImmGen:立即数生成模块,从指令中提取并符号扩展立即数。
    • RegFile:寄存器文件,根据 rs1 读取数据,根据 rd 写入数据。
    • ALU:算术逻辑单元,计算地址 addr = R[rs1] + imm
    • DMEM:数据存储器,根据计算得到的地址 addr 读取数据。
    • 控制信号
      • MemRW:内存读写控制信号,读操作时为 1。
      • WBSel:写回选择信号,决定写回的数据是从内存读取的数据还是 ALU 计算的结果。

image-20240804123003634

通过这种方式,lw 指令能够读取内存中的数据并将其保存到寄存器文件中,完成数据加载操作。

Lighting the LOAD Datapath

点亮 LOAD 数据路径

  • 步骤解析
    • PC 递增到下一条指令:每次时钟上升沿,PC 增加 4,指向下一条指令。
    • 立即数生成模块(ImmGen):从指令的 31:20 位中提取立即数,并将其符号扩展为 32 位。
    • ALU 计算地址:ALU 使用 R[rs1] 和符号扩展的立即数 imm 进行相加,计算得到地址 alu = R[rs1] + imm
    • 读取内存中的数据:在地址 alu 处读取内存中的数据。
    • 将读取的内存值写入寄存器:将内存中读取的数据写入目标寄存器 rd

image-20240804123401935

RV32I 可以加载不同宽度的数据

  • 支持的加载类型
    • lb:加载字节(8 位),符号扩展。
    • lh:加载半字(16 位),符号扩展。
    • lw:加载字(32 位)。
    • lbu:加载字节(8 位),零扩展。
    • lhu:加载半字(16 位),零扩展。

image-20240804123539247

  • 支持窄加载的步骤
    • 从内存加载 32 位字;
    • 添加额外的逻辑提取正确的字节或半字;
    • 将结果符号扩展或零扩展为 32 位,以写入寄存器文件。
  • 实现细节
    • 使用 MUX 和一些逻辑门实现加载类型的选择和数据的扩展。

通过这种方式,RISC-V 处理器能够灵活地从内存中加载不同宽度的数据,并将其正确地存储在寄存器文件中,满足不同指令的需求。

Implementing Stores

sw 指令的实现

  • 指令格式 (S-Format)sw x14, 36(x2)
    • 指令二进制表示
      • imm[11:5]:0000001
      • rs2:01110
      • rs1:00010
      • funct3:010
      • imm[4:0]:00100
      • opcode:0100011
  • 新的立即数格式
    • imm 被分为两部分:imm[11:5]imm[4:0]
    • 地址计算:addr = (基地址寄存器 rs1) + (符号扩展的 imm 偏移量)

image-20240804124527105

  • 访问的状态元件
    • DMEM:将 R[rs2] 的值写入地址 addr 处的内存单元
    • 寄存器文件 (RegFile):读取 R[rs1] (基地址),读取 R[rs2] (要存储的值)
    • 程序计数器 (PC)PC = PC + 4

更新后的 sw

  • 立即数生成 (ImmGen)
    • 控制信号 ImmSel 选择如何生成立即数类型(I 型或 S 型)。
  • 内存写入控制
    • 控制信号 MemRW 设置为写入操作,将 rs2 的值在下一个上升沿写入内存。

image-20240804124601907

数据路径的具体实现

  • 指令分割
    • 将指令分割成不同的字段,以便在寄存器文件中使用。
    • 使用 ImmGen 从指令中提取立即数部分,并进行符号扩展。
  • 地址计算
    • 使用 ALU 计算内存地址 alu = R[rs1] + imm
    • 将计算得到的地址传递给 DMEM,用于数据存储。
  • 数据写入
    • R[rs2] 的值通过 dataW 总线传递给 DMEM,在内存地址 addr 处进行存储。

通过上述步骤,实现了 sw 指令的功能,即将寄存器中的值存储到内存中指定的位置。

如何设置 sw 控制线?

控制线设置

在实现 sw 指令时,需要设置以下控制信号:

  • RegWEn:寄存器写使能信号
  • Bsel:选择立即数或寄存器作为 ALU 输入
  • WBSel:选择写回数据来源

根据 sw 指令格式,控制线应设置如下:

  • RegWEn:0 (因为 sw 指令不写回寄存器文件)
  • Bsel:1 (选择立即数作为 ALU 输入)
  • WBSel:1 (选择内存作为写回数据来源)

STORE 数据路径的点亮

sw 指令的执行过程中,数据路径的具体实现如下:

  1. 立即数生成
    • 立即数生成块从 S 型指令中构建 32 位立即数 imm
  2. 地址计算
    • 使用 ALU 计算内存地址 alu = R[rs1] + imm
    • 计算得到的地址传递给 DMEM,用于数据存储。
  3. 数据写入
    • R[rs2] 的值通过 dataW 总线传递给 DMEM,在内存地址 addr 处进行存储。

具体实现图示

image-20240804125042485

图示展示了 sw 指令的具体实现,包括如何设置控制信号以及数据在数据路径中的流动。

通过上述步骤和设置控制信号,实现了 sw 指令的功能,即将寄存器中的值存储到内存中指定的位置。

Adding B-Type (Branches)

B-格式:条件分支

在RISC-V指令集中,B-格式(在教材中标为SB-类型)与S-格式非常相似,用于条件分支指令。它的格式如下所示:

opname  rs1, rs2, Label

image-20240804125600658

  • 立即数格式:新的立即数格式,立即数由imm[12|10:5]imm[4:1|11]组成,通过重新排列位可以生成完整的立即数。
  • PC状态元素:在条件分支指令中,程序计数器(PC)的值将根据比较结果有条件地改变。
    • 如果分支成立PC = PC + imm
    • 如果分支不成立PC = PC + 4

分支需要计算什么?

为了实现条件分支,处理器需要执行以下步骤:

  1. 比较寄存器值:比较R[rs1]R[rs2]的值。
  2. 条件更新PC:根据比较结果,选择下一条指令的地址。
    • 如果R[rs1] == R[rs2]:PC更新为PC + imm
    • 否则:PC更新为PC + 4

image-20240804130128661

数据路径图解

图示展示了在实现条件分支指令时的数据路径,包括以下关键部分:

  • 立即数生成块(ImmGen):从指令中提取并生成32位的立即数imm
  • 比较逻辑:使用ALU比较R[rs1]R[rs2]的值。
  • PC更新逻辑:根据比较结果,选择并更新PC的值。

需要注意的事项

  • 硬件需求:由于每个时钟周期内只有一个ALU可用,因此在实现条件分支时需要额外的硬件支持,以确保同时进行比较和地址计算。
  • 控制信号:根据分支结果,控制信号需要调整,以选择正确的PC更新路径。

The Branch Comparator Block

分支比较器模块

分支比较器是一个组合逻辑块,用于实现条件分支指令中的比较操作。

输入

  • 两条数据总线:分别来自数据路径的R[rs1]R[rs2],表示要比较的两个寄存器的值。
  • BrUn控制位:用于指示比较是无符号还是有符号。

输出

  • BrEq标志:当A == B时,标志位设为1。
  • BrLT标志:当A < B时,标志位设为1。如果BrUn=1,则进行无符号比较,否则进行有符号比较。

image-20240804130856144

控制逻辑

  • BrUn:根据当前指令的inst[31:0]设置BrUn位。
  • PCSel:根据分支标志BrLTBrEq的状态来设置PCSel位,决定程序计数器(PC)是否跳转。

示例

  • blt(小于分支):如果BrLT=1并且BrEq=0,则PCSel=跳转
  • bge(大于或等于分支):如果A >= B(即BrLT=0),则PCSel=跳转

数据路径说明

  1. 比较寄存器值:通过分支比较器模块,将R[rs1]R[rs2]的值进行比较。
  2. 控制逻辑:根据比较结果,设置PCSel控制信号,决定下一条指令的地址。
  3. PC更新:如果PCSel表明分支成立,则PC更新为PC + imm,否则更新为PC + 4

通过这个模块,可以实现RISC-V指令集中的条件分支指令,确保在满足条件时正确跳转到指定的地址,继续执行程序。

The ALU Computes PC + Imm

ALU计算PC + Imm

为了计算分支跳转地址,我们使用ALU进行计算:alu = PC + imm

  1. 立即数生成:通过立即数生成模块(Immediate Generation Block),将指令中的立即数部分提取并扩展成32位。
  2. 计算分支地址:ALU负责计算当前PC加上立即数(imm)后的地址。

image-20240804133618710

Lighting the Branch Datapath

点亮分支数据路径

  1. 更新PC:如果PCSel表示跳转成立,PC更新为ALU输出;否则,PC更新为PC + 4
  2. 生成立即数:从B型指令(B-type instruction)中提取立即数,并通过立即数生成模块进行处理。
  3. 分支比较器:比较R[rs1]R[rs2],根据结果设置控制信号。
  4. ALU计算:计算PC + imm,将结果反馈给控制逻辑。
  5. 控制信号PCSel根据分支结果决定下一步的操作,ImmSel选择立即数类型,ALUSel选择ALU操作,MemRWWBSel决定是否写入内存或寄存器。

image-20240804133847539

数据路径说明

  1. PC + imm:ALU计算PC加上立即数的结果,用于分支跳转。
  2. 控制逻辑:根据分支比较器的结果,设置相应的控制信号以更新PC或执行下一条指令。
  3. 寄存器和内存:根据操作类型,决定是否写入寄存器或内存。

通过这些模块的协同工作,RISC-V处理器能够正确处理条件分支指令,确保在满足特定条件时,跳转到相应的地址执行后续指令。

Designing the Immediate Generation Block, Part 2

I-Type and S-Type Immediates

I型和S型立即数

指令格式(inst[31:0]):

  • I型指令:imm[11:0]rs1funct3rdopcode
  • S型指令:imm[11:5]rs2rs1funct3imm[4:0]opcode

I型指令

  1. 立即数(imm[11:0]):由指令的高12位组成。
  2. 符号扩展:将指令的最高位(inst[31])扩展到imm的高20位。

S型指令

  1. 立即数分段:imm分为两部分,分别是高7位(imm[11:5])和低5位(imm[4:0])。
  2. 符号扩展:同样将指令的最高位(inst[31])扩展到imm的高20位。

image-20240804135146528

为了方便硬件实现,设计了5-bit MUX选择器,用于填充imm[4:0]的位。

  • 选择器功能:根据指令类型选择正确的imm位。
  • 控制信号ImmSel控制选择器。

image-20240804135246511

B-Type Immediates

B型立即数

B型指令格式(inst[31:0]):

  • B型指令:imm[12|10:5]rs2rs1funct3imm[4:1|11]opcode

这张图展示了RISC-V架构中B型(B-Type)指令的立即数(Immediate)生成过程,特别是如何从指令的不同位段提取和组合立即数。我们将逐步解析这张图的各个部分。

image-20240804140207668

立即数生成

立即数生成模块(Imm. Gen)从指令的不同位段提取和组合立即数。对于B型指令,立即数生成包括以下几个步骤:

  1. 符号位
    • instr[31] 是符号位(sign bit),用于立即数的符号扩展。
  2. 立即数各位提取和组合
    • imm[12]:从instr[31]提取。
    • imm[11]:从instr[7]提取。
    • imm[10:5]:从instr[30:25]提取。
    • imm[4:1]:从instr[11:8]提取。
    • imm[0]:始终为0,因为B型指令的立即数是字(word)对齐的。

多路复用器(MUX)的选择

图中展示了多路复用器(MUX)如何选择立即数的不同部分:

  1. MUX for imm[11]
    • 对于S型指令,imm[11] 来自 instr[31]
    • 对于B型指令,imm[11] 来自 instr[7]
  2. MUX for imm[0]
    • 对于S型指令,imm[0] 来自 instr[7]
    • 对于B型指令,imm[0] 始终为0。

立即数的最终组合

在立即数生成器的末尾,将不同位段组合起来,形成一个完整的32位立即数:

  • imm[31:12]:符号扩展,所有位都与imm[12](符号位)相同。
  • imm[11:0]:从上述不同位段组合而成。

指令格式

  1. I型指令(I-Type)
    • 立即数位段:imm[11:0]
    • 位段分布:inst[31:20]
  2. S型指令(S-Type)
    • 立即数位段:imm[11:0]
    • 位段分布:inst[31:25]inst[11:7]
  3. B型指令(B-Type)
    • 立即数位段:imm[12|10:5|4:1|11]
    • 位段分布:inst[31] (符号位), inst[7], inst[30:25], inst[11:8]

Adding Jumps jal, jalr

J-Format: Unconditional Jump

J型指令格式:无条件跳转

  • 指令:jal rd, Label
  • 格式:
    • imm[20|10:1|11|19:12]rdopcode

新的立即数格式

  • imm由多个位段组成:imm[20]imm[10:1]imm[11]imm[19:12]
  • 在立即数生成过程中需要对这些位段进行拼接和符号扩展

状态元素更新

  • 程序计数器(PC)
    • PC = PC + imm(无条件PC相对跳转)
  • 寄存器文件(RegFile)
    • rd = PC + 4(将返回地址保存到目标寄存器)

Block Updates Needed for JAL

JAL指令所需的模块更新

  • 立即数生成模块
    • 需要支持J型指令:生成20位半字节偏移量(byte offset)
  • 控制信号
    • ImmSel设置为J,选择J型指令的立即数生成
    • WBSel现在控制一个三输入MUX,用于选择将PC+4保存到寄存器文件中

image-20240804141728346

Lighting the JAL Datapath

点亮JAL数据路径

  1. 将PC送入各个模块
    • PC的当前值被送入指令存储器和ALU模块
  2. 生成字节偏移量imm
    • 立即数生成模块生成偏移量imm,并送入ALU
  3. 计算跳转地址
    • ALU计算PC + imm并将结果写回PC
  4. 保存返回地址
    • PC + 4的值被写入寄存器文件中的目标寄存器rd

在JAL指令中,由于它是无条件跳转指令,不需要关心分支条件。控制信号如PCSelWBSel确保跳转地址和返回地址的正确计算和存储。

image-20240804142211060

I-Format Instruction Layout: jalr

I型指令格式:jalr

指令格式

  • 指令:jalr rd, rs1, imm
  • 格式:
    • imm[11:0]rs1funct3rdopcode

image-20240804142536546

状态变化

  • 程序计数器(PC)
    • PC = R[rs1] + imm(绝对地址)
  • 寄存器文件(RegFile)
    • R[rd] = PC + 4(保存返回地址)

立即数格式

  • I型指令格式意味着jalr使用与算术和加载指令相同的立即数格式
  • 换句话说,imm已经是一个字节偏移量

Lighting the JALR Datapath

点亮JALR数据路径

  1. 将PC送入各个模块
    • PC的当前值被送入指令存储器和ALU模块
  2. 生成12位立即数imm
    • 立即数生成模块生成12位偏移量imm,并送入ALU
  3. 计算跳转地址
    • ALU计算R[rs1] + imm并将结果写回PC
  4. 保存返回地址
    • PC + 4的值被写入寄存器文件中的目标寄存器rd

image-20240804142705812

控制信号

  • PCSel:选择更新PC的信号
  • ImmSel:选择立即数类型为I型
  • RegWEn:寄存器写使能信号
  • Bsel:选择立即数或寄存器作为ALU的输入
  • ALUSel:选择ALU的操作类型(加法)
  • WBSel:选择写回数据的来源(PC+4)

jalr指令使用I型立即数格式,实现了绝对地址跳转,同时保存返回地址到目标寄存器。通过控制信号的正确设置,数据路径能够实现指令的功能。

Adding U-Types

U-Format Instruction Layout

  • U型指令:U型指令用于表示高位立即数(upper immediate)。这种指令包括 luiauipc
  • 指令格式
    • opname rd, immed:指令格式为 操作码 rd, 立即数,其中 rd 是目标寄存器,immed 是立即数。
  • 立即数表示:立即数表示一个32位立即数的高20位(upper 20 bits)。

  • 新立即数格式:这是一个新的立即数格式,专门用于luiauipc指令。

  • 使用于两条指令
    • lui:Load Upper Immediate,用于加载上部立即数。
    • auipc:Add Upper Immediate to PC,将上部立即数加到程序计数器(PC)上。
    • 共同点:两条指令都将PC增加到下一条指令并将结果保存到目标寄存器中。

image-20240804144931682

指令字段解释:

  • 31:12位:立即数的高20位。
  • 11:7位:目标寄存器(rd)。
  • 6:0位:操作码(opcode)。

U-Format Block update: Immediates

  • 立即数生成:U型格式的立即数生成,使用指令的高20位生成一个32位的立即数。
    • Imm. Gen:立即数生成模块(Imm. Gen)负责从指令的高20位生成32位立即数。

image-20240804144955117

数据路径解释:

  • PC:程序计数器,持有当前指令的地址。
    • PC+4:PC的值加4,用于指向下一条指令。
  • IMEM:指令内存,从PC读取指令。
    • addr:指令地址。
    • inst:当前指令。
  • Imm. Gen:立即数生成模块,从指令的高20位生成32位立即数。
    • inst[31:12]:指令的高20位用于生成立即数。
    • imm[31:0]:生成的32位立即数。

控制信号:

  • ImmSel:选择立即数生成模式。
    • U:表示选择U型立即数生成模式。

执行过程:

  • lui指令:加载上部立即数到目标寄存器。
    • PC -> IMEM:从程序计数器读取指令。
    • Imm. Gen:从指令的高20位生成立即数。
    • Reg[]:将生成的立即数写入目标寄存器。
  • auipc指令:将上部立即数加到程序计数器(PC)上,然后写入目标寄存器。
    • PC -> IMEM:从程序计数器读取指令。
    • Imm. Gen:从指令的高20位生成立即数。
    • ALU:将生成的立即数加到PC上。
    • Reg[]:将结果写入目标寄存器。

Lighting the LUI Datapath

LUI指令的数据路径点亮

操作步骤

  1. PC增加
    • 将程序计数器PC增加4,指向下一条指令。
  2. 生成高20位立即数
    • 通过立即数生成模块(Immediate Generation Block)生成U型格式的高20位立即数imm
  3. 写入目的寄存器
    • 使用ALUSel=B信号,选择仅抓取立即数imm,并将结果写入目的寄存器rd
  4. 数据路径控制
    • PCSel:选择PC未跳转(0)。
    • ImmSel:选择U型格式的立即数。
    • RegWEn:使能寄存器写入(1)。
    • WBsel:选择立即数写回寄存器。

image-20240804145047577

关键控制信号

  • PCSel:控制PC的更新逻辑
  • ImmSel:选择立即数类型为U型
  • RegWEn:寄存器写使能
  • WBsel:选择写回数据为立即数

Lighting the AUIPC Datapath

AUIPC指令的数据路径点亮

操作步骤

  1. PC增加
    • 将程序计数器PC增加4,指向下一条指令。
  2. 生成高20位立即数
    • 通过立即数生成模块(Immediate Generation Block)生成U型格式的高20位立即数imm
  3. 计算PC + imm
    • 使用ALU计算PC + imm,将结果写入目的寄存器rd
    • 控制信号ALUSel=Add选择ALU执行加法操作。
  4. 数据路径控制
    • PCSel:选择PC未跳转(0)。
    • ImmSel:选择U型格式的立即数。
    • RegWEn:使能寄存器写入(1)。
    • WBsel:选择ALU结果写回寄存器。

image-20240804145246951

关键控制信号

  • PCSel:控制PC的更新逻辑
  • ImmSel:选择立即数类型为U型
  • RegWEn:寄存器写使能
  • WBsel:选择写回数据为ALU计算结果

总结

对于LUI和AUIPC指令,它们的数据路径都需要生成高20位的立即数并将其用于更新寄存器。LUI指令直接将立即数写入寄存器,而AUIPC指令则将PC与立即数相加后写入寄存器。这两种操作通过不同的控制信号来实现对数据路径的正确控制。

Complete RV32I Datapath!

完整的RV32I数据路径

数据路径概述

在此幻灯片中,我们展示了RV321指令集架构(ISA)中所有指令的完整数据路径。这个数据路径展示了如何通过组合不同的模块来实现处理器的所有功能。

各模块功能

  1. 程序计数器(PC)
    • 负责存储当前执行的指令地址。
    • 每次指令执行后,PC增加4以指向下一条指令。
  2. 指令存储器(IMEM)
    • 用于存储指令并根据PC值取出当前指令。
  3. 立即数生成模块(Imm. Gen)
    • 生成立即数,用于各种指令格式(I, S, B, J, U型)。
  4. 寄存器文件(RegFile)
    • 包含32个寄存器,用于存储操作数和结果。
    • 可以同时进行两个读操作和一个写操作。
  5. ALU(算术逻辑单元)
    • 执行所有的算术和逻辑操作。
    • ALU的操作由ALUSel控制信号决定(例如加法、减法、与、或等)。
  6. 数据存储器(DMEM)
    • 用于存储数据,支持读写操作。
    • 由MemRW信号控制读写操作。
  7. 分支比较器(Branch Comp.)
    • 用于比较两个寄存器的值,以确定是否进行分支跳转。
    • 根据分支条件设置PCSel信号。

image-20240804145320251

控制信号

  • PCSel:选择PC的来源(当前PC + 4 或 分支目标地址)。
  • ImmSel:选择立即数的类型(I, S, B, J, U)。
  • RegWEn:使能寄存器写入。
  • BrUn:控制分支比较器进行无符号比较。
  • BrLT:分支条件标志,表示比较结果小于。
  • BrEq:分支条件标志,表示比较结果等于。
  • Bsel:选择ALU的第二个操作数来源(寄存器或立即数)。
  • Asel:选择ALU的第一个操作数来源(PC或寄存器)。
  • ALUSel:选择ALU的操作类型(加法、减法等)。
  • MemRW:控制数据存储器的读写操作。
  • WBSel:选择写回数据的来源(ALU结果或内存数据)。

© 2024 LzzsSite
该笔记由 LzzsG 基于 CS 61C / Garcia, Yan 的作品创作,采用的是 CC BY-NC-SA 许可。