指令译码模块的主要作用是从机器码中解析出指令,并根据解析结果输出各种控制信号。ID模块主要有指令译码(Decode)、寄存器堆(Registers)、冒险监测、分支检测和加法器等组成。ID模块的接口信息如下表所示:
引脚名称 clk Instruction_id[31:0] NextPC_id[31:0] RegWrite_wb RegWriteAddr_wb[4:0] RegWriteData_wb[31:0] MemRead_ex RegWriteAddr_ex[4:0] MemtoReg_id RegWrite_id MemWrite_id MemRead_id ALUCode_id[4:0] ALUSrcA_id ALUSrcB_id RegDst_id Stall Z J JR PC_IFWrite BranchAddr[31:0] JumpAddr[31:0] Imm_id[31:0] Sa_id[31:0] RsData_id[31:0] RtData_id[31:0] RdAddr_id[4:0] RsAddr_id[4:0] RtAddr_id[4:0] 方向 说 明 系统时钟 指令机器码 指令指针 寄存器写允许信号,高电平有效 寄存器的写地址 写入寄存器的数据 冒险检测的输入 Input 决定回写的数据来源(0:ALU 1:存储器) 寄存器写允许信号,高电平有效 存储器写允许信号,高电平有效 存储器读允许信号,高电平有效 决定ALU采用何种运算 决定ALU的A操作数的来源(0:rs 1:Sa) 决定ALU的B操作数的来源(0:rt 1:Imm) 决定Register回写是采用的地址(rt/rd) ID/EX寄存器清空信号,高电平插入一个流水线气泡 分支指令的条件判断结果 跳转指令 Output 寄存器跳转指令 阻塞流水线的信号,低电平有效 条件分支地址 跳转地址 符号扩展成32位的立即数 0扩展成32位的移位立即数 Rs寄存器数据 Rt寄存器数据 Rd寄存器地址 Rs寄存器地址 Rt寄存器地址
(1) 指令译码(Decode)子模块的设计
Decode控制器的主要作用是根据指令确定各个控制信号的值,是一个组合电路。我们将指令分成八类:
11
R_type1:ADD、ADDU、SUB、SUBU、AND、OR、
NOR、XOR 、SLT、SLTU、SLLV、SRLV、SRAV R型指令
R_type2:SLL、SRL、SRA JR_type:JR
J_type:J J型指令
I_type:ADDI、ADDIU、ANDI、ORI、XORI、SLTI、SLTIU
Branch:BEQ、BNE、BGEZ、BGTZ、BLEZ、BLTZ I型指令 LW:LW SW:SW
Decode输出的九组控制信号: ① RegWrite
决定是否对寄存器(Registers)进行写操作。当RegWrite高电平有效时,将数据写入指定的寄存器中。
需要写回寄存器的指令有:LW、R_type1、R_type2和I_type,则
RegWrite_id= LW || R_type1 || R_type2 || I_type ② RegDst
决定目标寄存器是rt还是rd。当RegDst=0时,rt为目标寄存器;当RegDst=1时,rd为目标寄存器。
需要写回寄存器的指令类型有:LW、R_type1、R_type2和I_type。其中, R_type1和R_type2的目标寄存器是rd,而LW和I_type的目标寄存器是rt。所以:
RegDst_id= R_type1 || R_type2 ③ MemWrite
决定是否对数据存储器进行写操作。当MemWrite有效时,将数据写入数据存储器指定的位置。
需要对写存储器的指令只有SW,所以:
MemWrite_id= SW ④ MemRead
决定是否对数据存储器进行读操作。当MemRead有效时,读取数据存储器指定位置的数据。
需要对读存储器的指令只有LW,所以:
MemRead_id= LW ⑤ MemtoReg
决定写入寄存器(registers)的数据来自ALU还是数据存储器。?当MemtoReg=0时,数据来自ALU;当MemtoReg=1时,数据来自数据存储器。
需要写回寄存器的指令类型有:LW、R_type1、R_type2和I_type。其中,只有LW写回寄存器的数据取自存储器,所以:
MemtoReg_id= LW ⑥ ALUSrcA
决定ALU第一操作数来源。当ALUSrcA=0时,ALU第一操作数A(详见转发电路设计);当ALUSrcA=1时,ALU第一操作数来源于0扩展的用于移位指令的5位sa。
12
八种指令类型中J_tpye、JR_tpye及Branch类型指令没有使用ALU;其他使用ALU的指令类型中LW、SW、R_type1和I_type均采用的rs作为ALU第一操作数,只有R_type2的第一操作数采用的是0扩展的sa,所以:
ALUSrcA_id= R_type2 ⑦ ALUSrcB
决定ALU第二操作数来源。当ALUSrcB=0时,ALU第二操作数B。当ALUSrcB=1时,ALU第二操作数来源于符号扩展的16位Imm。
八种指令类型中J_tpye、JR_tpye及Branch类型指令没有使用ALU。其他使用ALU的指令类型中R_type1和R_type2 采用rt作为ALU第二操作数,而LW、SW、I_type的第二操作数采用的是符号扩展的立即数Imm段,所以:
ALUSrcB_id= LW || SW || I_type ⑧ PCSource
决定写入PC寄存器的来源。PCSource由JR_tpye 、J_tpye及Z决定:即:PCSource={JR, J, Z}
?PCSource=000时, 写入值为下一条指令的地址PC+4; ?PCSource=001时, 写入值为Branch指令的分支地址; ?PCSource=010时,写入值为J指令的跳转地址; ?PCSource=100时,写入值为JR指令的跳转地址。
⑨ ALUCode
决定ALU的功能,由指令中的op段、rt段和funct段决定。功能表如下: op BEQ_op BNE_op BGEZ_op BGTZ_op BLEZ_op BLTZ_op R_type_op funct ×××××× ×××××× ×××××× ×××××× ×××××× ×××××× ADD_funct ADDU_funct AND_funct XOR_funct OR_funct NOR_funct SUB_funct SUBU_funct SLT_funct SLTU_funct SLL_funct SLLV_funct SRL_funct SRLV_funct SRA_funct SRAV_funct rt ×××××× ×××××× 5'd1 5'd0 5'd0 5'd0 ×××××× ×××××× ×××××× ×××××× ×××××× ×××××× ×××××× ×××××× ×××××× ×××××× ×××××× ×××××× ×××××× ×××××× ×××××× ×××××× 运算 Z=(A==B) Z=~(A==B) Z=(A≥0) Z=(A>0) Z=(A≤0) Z=(A<0) 加 与 异或 或 或非 减 AA B>>>A ALUCode 5'd10 5'd11 5'd12 5'd13 5'd14 5'd15 5'd0 5'd1 5'd2 5'd3 5'd4 5'd5 5'd19 5'd20 5'd16 5'd17 5'd18 13
op ADDI_op ADDIU_op ANDI_op XORI_op ORI_op SLTI_op SLTIU_op SW_op LW_op funct ×××××× ×××××× ×××××× ×××××× ×××××× ×××××× ×××××× ×××××× ×××××× rt ×××××× ×××××× ×××××× ×××××× ×××××× ×××××× ×××××× ×××××× ×××××× 运算 加 与 异或 或 A
Zero检测电路主要用于判断Branch指令的分支条件是否成立,其中BEQ、BNE两个操作数为RsData与RtData,而BGEZ、BGTZ、BLEZ和BLTZ指令则为RsData与常数0比较,所以输出信号Z的表达式为:
RsData[31] || ~ (| RsData[31: 0]) ; ALUCode=alu _blez RsData[31] ; ALUCode=alu _bltz ~ RsData[31] && (| RsData[31: 0]) ; ALUCode=alu _bgtz Z= ~ RsData[31]; ALUCode=alu _bgez
| ( RsData[31: 0] ^ RtData[31: 0]) ; ALUCode=alu_bne & ( RsData[31: 0] ~^ RtData[31: 0] ); ALUCode=alu_beq 0; ALUCode=OTHER
(3) 寄存器堆(Registers)的设计 寄存器堆由32个32位寄存器组成,这些寄存器通过寄存器号进行读写存取。寄存器堆的原理框图如图3.13所示。因为读取寄存器不会更改其内容,故只需提供寄存号即可读出该寄存器内容。读取端口采用数据选择器即可实现读取功能。应注意“0”号寄存器为常数0.
14
对于往寄存器里写数据,需要目标寄存器号(WriteRegister)、待写入数据(WriteData)、写允许信号(RegWrite)三个变量。图3.13中5位二进制译码器完成地址译码,其输出控制目标寄存器的写使能信号EN,决定将数据WriteData写入哪个寄存器。
在流水线CPU设计中,寄存器堆设计还应解决三阶数据相关的数据转发问题。当满足三阶数据相关条件时,寄存器具有Read after Write的特性。为实现该功能,在寄存器堆的基础上加一转发电路。如图3.14所示。图中转发检测电路的输出表达式为
RsSel=RegWrite_wb&&(~(RegWriteAddr_wb==0))&&(RegWriteAddr_wb==RsAddr_id) RtSel=RegWrite_wb&&(~(RegWriteAddr_wb==0))&&(RegWriteAddr_wb==RtAddr_id)
(4) 冒险检测功能(Hazard Deterctor)的设计 由前面分析可知,冒险成立的条件为:
① 上一条指令是LW指令,即MemRead_ex=1;
② 在EX级的LW指令与在ID级的指令读写的是同一个寄存器,即
RegWriteAddr_ex=RsAddr_id 或 RegWriteAddr_ex=RtAddr_id 解决冒险的方法为:
① 插入一个流水线气泡Stall清空ID/EX寄存器并且阻塞流水线ID级、IF级流水线,
有:
Stall=((RegWriteAddr_ex==RsAddr_id)||
(RegWriteAddr_ex==RtAddr_id))&&MemRead_ex
② 保持PC寄存器和IF/ID流水线寄存器不变,有:
PC_IFWrite=~Stall
(5) 其它单元电路的设计
① Branch指令分支地址的计算电路:
BranchAddr=NextPC_id+(sign-extend(Imm_id)<<2)
② JR指令跳转地址的计算电路:
JRAddr=RsData_id
15