전공 이야기/Digital System Design

#6 MIPS Pipeline Processor Design (4) - Hazard, Top module

[감자] 2023. 12. 26. 20:10

1.9 Forwarding Unit

 

Forwarding Unit 동작 설명

 

 Forwarding Unit은 데이터 하자드를 해결하는 데 사용되는 유닛이다. Forwarding이 필요한 조건은 다음과 같다:

 

1. EX/MEM.RegisterRd가 ID/EX.RegisterRs와 같은 경우

2. EX/MEM.RegisterRd가 ID/EX.RegisterRt와 같은 경우

3. MEM/WB.RegisterRd가 ID/EX.RegisterRs와 같은 경우

4. MEM/WB.RegisterRd가 ID/EX.RegisterRt와 같은 경우

 

1과 2의 경우, 데이터를 가져오기 위해 EX/MEM 파이프라인 레지스터로부터 Forwarding이 필요하며, 3과 4의 경우, MEM/WB 파이프라인 레지스터로부터 Forwarding이 필요하다. 또한, EX/MEM.RegWrite 신호가 0이거나 MEM/WB.RegWrite 신호가 0인 경우에는 Forwarding이 필요없다. 또한, EX/MEM.RegisterRd가 $0이거나 MEM/WB.RegisterRd가 $0인 경우에도 Forwarding이 필요없다. 이러한 조건들을 고려하여 Forwarding Unit이 동작에 대해 다음과 같이 Pseudocode를 작성할 수 있다.

// EX hazard
if (EX/MEM.RegWrite and (EX/MEM.RegisterRd != 0) and (EX/MEM.RegisterRd == ID/EX.RegisterRs))
    ForwardA = 2
if (EX/MEM.RegWrite and (EX/MEM.RegisterRd != 0) and (EX/MEM.RegisterRd == ID/EX.RegisterRs))
    ForwardB = 2
 
// MEM hazard
if (MEM/WB.RegWrite and (MEM/WB.RegisterRd != 0) and not (EX/MEM.RegWrite and (EX/MEM.RegisterRd != 0) and (EX/MEM.RegisterRd == ID/EX.RegisterRs)) and (MEM/WB.RegisterRd == ID/EX.RegisterRs))
    ForwardA = 1
if (MEM/WB.RegWrite and (MEM/WB.RegisterRd != 0) and not (EX/MEM.RegWrite and (EX/MEM.RegisterRd != 0) and (EX/MEM.RegisterRd == ID/EX.RegisterRs)) and (MEM/WB.RegisterRd == ID/EX.RegisterRt))
    ForwardB = 1

 

 

module Forward_Unit(
    input [4:0] EX_MEM_Rd, MEM_WB_Rd,
    input [4:0] ID_EX_Rs, ID_EX_Rt,
    input MEM_WB_RegWrite, EX_MEM_RegWrite,
    output reg [1:0] ForwardA, ForwardB
    );
 
    always @*
    begin
        // Default is 0 (not forwarding)
        ForwardA = 2'b00; ForwardB = 2'b00;
       
        // EX harzard
        if(EX_MEM_RegWrite && (EX_MEM_Rd != 32'd0)) begin
            if(EX_MEM_Rd == ID_EX_Rs)
                ForwardA = 2'b10;
            if(EX_MEM_Rd == ID_EX_Rt)
                ForwardB = 2'b10;
        end
       
        // MEM hazard
        if(MEM_WB_RegWrite && (MEM_WB_Rd != 32'd0)) begin
            if((MEM_WB_Rd == ID_EX_Rs) && !((EX_MEM_RegWrite) && (EX_MEM_Rd != 32'd0) && (EX_MEM_Rd == ID_EX_Rs)))
                ForwardA = 2'b01;
            if((MEM_WB_Rd == ID_EX_Rt) && !((EX_MEM_RegWrite) && (EX_MEM_Rd != 32'd0) && (EX_MEM_Rd == ID_EX_Rt)))
                ForwardB = 2'b01;
        end
       
    end
endmodule

 

 

 

 

 

1.10 Hazard Detection Unit

 

 

 Hazard Detectoin Unit 동작 설명

 

Hazard Detection Unit은 Data Hazard 중에서 Load-Use Hazard가 발생했는지 판단하여 stall을 진행할지 제어하는 유닛이다. lw와 같이 메모리로부터 레지스터로 데이터를 가져와야 하면서 바로 다음 Instruction에서 해당 레지스터를 사용해야 하는 경우 같은 clock cycle에서 Forwarding이 불가능하기 때문에 1 clock cycle은 아무 동작도 하지 않고 PC를 유지하여 다음 clock cycle에서 해당 Instruction을 다시 실행하여 Forwarding을 할 수 있도록 해야 한다. 아무 동작도 하지 않는 것을 Stall이라 하며 MIPS assembly에서는 nop라고 지칭한다. Stall을 삽입해야 하는 조건은 다음과 같다.

 

 

           1. ID/EX.RegisterRt가 IF/ID.RegisterRs와 같은 경우

           2. ID/EX.RegisterRt가 IF/ID.RegisterRt와 같은 경우

 

 

또한, ID/EX.MemRead가 1인 경우 hazard가 발생하는 것이므로 이를 고려하여 다음과 같이 Hazard Detection Unit의 동작을 Psudocode로 작성할 수 있다.

if (ID/EX.MemRead and
((ID/EX.RegisterRt == IF/ID.RegisterRs) or
(ID/EX.RegisterRt == IF/ID.RegisterRt))
    Stall = 1
else
    Stall = 0

 

 

module Hazard_Detection(
    input ID_EX_MemRead,
    input [4:0] ID_EX_Rt, IF_ID_Rs, IF_ID_Rt,
    output reg PCWrite, IF_ID_Write, Stall
    );
   
    always @*
        if(ID_EX_MemRead && ((ID_EX_Rt == IF_ID_Rs) || (ID_EX_Rt == IF_ID_Rt))) begin
            PCWrite = 0; IF_ID_Write = 0; Stall = 1;
        end
        else begin
            PCWrite = 1; IF_ID_Write = 1; Stall = 0;
        end   
endmodule

 

 

 

 

1.11 Branch Forwaridng Unit

 

 Branch Forwarding Unit 동작 설명

 

 기존에는 EX_Stage에서 ALU에서 분기가 일어나는 지 판단하였지만 ID_Stage에서 분기에 대한 연산을 모두 진행하게 되어 branch에 대한 데이터 하자드 문제가 발생한다. 그래서 branch에 대한 forwarding unit 하드웨어를 추가해야 한다. 동작은 기존의 Forwarding Unit과 유사하다. Forwarding 제어 신호는 Equality를 확인하는 Unit의 입력을 결정하게 된다.

 

module Branch_Forward(
    input [4:0] EX_RegDest, MEM_RegDest,
    input [4:0] IF_Rs, IF_Rt,
    input IDtoEX_RegWrite, EXtoMEM_RegWrite,
    output reg [1:0] ForwardA, ForwardB
    );
    always @* begin
        ForwardA = 2'b00; ForwardB = 2'b00;
        
        // EX hazard
if(IDtoEX_RegWrite && (EX_RegDest != 32'd0)) begin
            if(EX_RegDest == IF_Rs)
                ForwardA = 2'b10;
            if(EX_RegDest == IF_Rt)
                ForwardB = 2'b10;
        end
       
        // MEM hazard
        if(EXtoMEM_RegWrite && (MEM_RegDest != 32'd0)) begin
            if((MEM_RegDest == IF_Rs) && !((IDtoEX_RegWrite) && (EX_RegDest != 32'd0) && (EX_RegDest == IF_Rs)))
                ForwardA = 2'b01;
            if((MEM_RegDest == IF_Rt) && !((IDtoEX_RegWrite) && (EX_RegDest != 32'd0) && (EX_RegDest == IF_Rt)))
                ForwardB = 2'b01;
        end
    end

 

 

 

 

1.12 Top Module

 

MIPS_Top module 동작 설명

 

 지금까지 기술한 모든 모듈들을 Top module을 통하여 연결한다. 포트 연결의 정확도가 중요하다. 크게 4부분으로 나뉘어져 있으며, 입출력 포트 선언, 내부 연결 wire 선언, 하위 모듈 선언, 출력 값 연결로 이루어져 있다. 해당 부분들은 각주를 통해 나눠 놓았다.

 

module MIPS (
    input wire clk,
    input wire rst,
   
    output wire [31:0] ProgramCounter_Output,
    output wire [31:0] Register_8, Register_9, Register_10, Register_11,
    output wire [31:0] Register_12, Register_13, Register_14, Register_15,
    output wire [31:0] memory_8, memory_9, memory_10, memory_11,
    output wire [31:0] memory_12, memory_13, memory_14, memory_15,
    output wire [1:0] forward_A, forward_B,
    output wire hazard
    );
 
//~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~~*~*~*~*~*~*~*~*~*~*~~*~*~*~~*~*~*~
 
    //output port
    wire [31:0] pc_current;
    wire [31:0] t0, t1, t2, t3, t4, t5, t6, t7;
 
 
    //use U0 IF_Stage
    wire [31:0] pc_stage1;
    wire [31:0] inst_stage1;
    wire hazard_PCWrite;
   
   
    //use U1 IFID_Register
    wire [31:0] pc_IFID;
    wire [31:0] inst_stage2;
    wire hazard_IF_ID_Write;
   
   
    //use U2 ID_Stage
    wire [31:0] readData1_stage2;
    wire [31:0] readData2_stage2;
    wire [31:0] signExtended_stage2;
    wire [5:0] Op_stage2;
    wire [4:0] Rs_stage2, Rt_stage2, Rd_stage2;
    wire [5:0] funct_stage2;
    wire [31:0] Branch_Addr_stage2;
    wire branch_equal_stage2;
   
   
    //use U3 Control
    wire hazard_stall;
    wire [5:0] opcode;
    wire [1:0] Control_ALUOp;
    wire Control_ALUSrc, Control_RegDst, Control_Branch, Control_MemRead,
          Control_MemWrite, Control_RegWrite, Control_MemtoReg, Control_IF_Flush;
 
 
    //use U4 IDEX_Register
    wire [31:0] pc_stage3;
    wire [31:0] readData1_stage3;
    wire [31:0] readData2_stage3;
    wire [31:0] signExtended_stage3;
    wire [4:0] Rs_stage3, Rt_stage3, Rd_stage3;
    wire [5:0] funct_stage3;
    wire [1:0] IDtoEX_ALUOp;
    wire IDtoEX_ALUSrc, IDtoEX_RegDst, IDtoEX_MemRead, IDtoEX_MemWrite, IDtoEX_RegWrite, IDtoEX_MemtoReg;
 
   
    // branch forward
    wire [1:0] branch_FWA, branch_FWB;
   
    //use U6 EX_Stage
    wire [31:0] ALUresult_stage3;
    wire [31:0] EX_ReadData2_stage3;
    wire [4:0] RegDest_stage3;
    wire [1:0] ForwardA_wire, ForwardB_wire;
 
 
    //use U7 EXMEM_Register
    wire [31:0] EXtoMEM_ReadData2_stage4;
    wire [31:0] ALUresult_stage4;
    wire [4:0] RegDest_stage4;
    wire EXtoMEM_MemRead, EXtoMEM_MemWrite, EXtoMEM_RegWrite, EXtoMEM_MemtoReg;
 
 
    //use U9 MEM_Stage
    wire [31:0] MEM_ReadData_stage4;
    wire [31:0] ALUresult_MEM;
    wire [4:0] RegDest_MEM;
 
 
    // use U10 MEMWB_Register
    wire [31:0] MEMtoWB_ReadData_stage5;
    wire [31:0] ALUresult_WB;
    wire [4:0] RegDest_WB;
    wire MEMtoWB_MemtoReg;
    wire MEMtoWB_RegWrite;
   
   
    // use U11 WB_Stage
    wire [31:0] WriteData_stage5;
    wire [4:0] RegDest_stage5;
 
 
//~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~~*~*~*~*~*~*~*~*~*~*~~*~*~*~~*~*~*~
 
    IF_Stage IF (
//input
        .clk(clk), .rst(rst),
        .PCWrite(hazard_PCWrite),
        .PCSrc(Control_Branch),
        .Branch(Branch_Addr_stage2),
//output
        .IFtoID_PC(pc_stage1),
        .IFtoID_inst(inst_stage1),
        .PC_current(pc_current)
    );
 
 
    IFtoID_Register IF_ID (
//input
        .clk(clk),
        .rst(rst),
        .IF_PC(pc_stage1),
        .IF_inst(inst_stage1),
        .IF_ID_Write(hazard_IF_ID_Write),
        .IF_Flush(Control_IF_Flush),
//output
        .ID_PC(pc_IFID),
        .ID_inst(inst_stage2)
    );
 
 
    ID_Stage ID (
//input
        .clk(clk),
        .rst(rst),
        .IFtoID_PC(pc_IFID),
        .IFtoID_inst(inst_stage2),
        .writeReg(RegDest_stage5),
        .writeData(WriteData_stage5),
        .RegWrite(MEMtoWB_RegWrite),
        .EX_ALUresult(ALUresult_stage3),
        .MEM_ALUresult(ALUresult_MEM),
        .ForwardA(branch_FWA),
        .ForwardB(branch_FWB),
//output
        .IDtoEX_ReadData1(readData1_stage2),
        .IDtoEX_ReadData2(readData2_stage2),
        .IDtoEX_Imm(signExtended_stage2),
        .IFtoID_Op(Op_stage2),
        .IFtoID_Rs(Rs_stage2),
        .IFtoID_Rt(Rt_stage2),
        .IFtoID_Rd(Rd_stage2),
        .funct(funct_stage2),
        .branch_equal(branch_equal_stage2),
        .Branch_Addr(Branch_Addr_stage2),
       
        .output_8(t0), .output_9(t1), .output_10(t2), .output_11(t3),
        .output_12(t4), .output_13(t5), .output_14(t6), .output_15(t7)
    );
 
 
    Control CNTL (
//input
        .rst(rst),
        .hazard_detected(hazard_stall),
        .opcode(Op_stage2),
        .branch_equal(branch_equal_stage2),
        .IF_PC(pc_stage1),
//output
        .ALUOp(Control_ALUOp),
        .ALUSrc(Control_ALUSrc),
        .RegDst(Control_RegDst),
        .MemRead(Control_MemRead),
        .MemWrite(Control_MemWrite),
        .RegWrite(Control_RegWrite),
        .MemtoReg(Control_MemtoReg),
        .Branch(Control_Branch),
        .IF_Flush(Control_IF_Flush)
    );
 
 
    IDtoEX_Register ID_EX (
//input
        .clk(clk), .rst(rst),
        .ID_ReadData1(readData1_stage2),
        .ID_ReadData2(readData2_stage2),
        .ID_Imm(signExtended_stage2),
        .ID_Rs(Rs_stage2),
        .ID_Rt(Rt_stage2),
        .ID_Rd(Rd_stage2),
        .funct(funct_stage2),
        .ALUOp(Control_ALUOp),
        .ALUSrc(Control_ALUSrc),
        .RegDst(Control_RegDst),
        .MemRead(Control_MemRead),
        .MemWrite(Control_MemWrite),
        .RegWrite(Control_RegWrite),
        .MemtoReg(Control_MemtoReg),
//outputs
        .IDtoEX_ReadData1(readData1_stage3),
        .IDtoEX_ReadData2(readData2_stage3),
        .IDtoEX_Imm(signExtended_stage3),
        .IDtoEX_Rt(Rt_stage3),
        .IDtoEX_Rd(Rd_stage3),
        .EX_ALUOp(IDtoEX_ALUOp),
        .EX_ALUSrc(IDtoEX_ALUSrc),
        .EX_RegDst(IDtoEX_RegDst),
        .Forwarding_Rs(Rs_stage3),
        .ALUcontrol_funct(funct_stage3),
        .IDtoEX_MemRead(IDtoEX_MemRead),
        .IDtoEX_MemWrite(IDtoEX_MemWrite),
        .IDtoEX_RegWrite(IDtoEX_RegWrite),
        .IDtoEX_MemtoReg(IDtoEX_MemtoReg)
    );
   
   
    Hazard_Detection HZRD (
//input
        .ID_EX_MemRead(IDtoEX_MemRead),
        .ID_EX_Rt(Rt_stage3),
        .IF_ID_Rs(Rs_stage2),
        .IF_ID_Rt(Rt_stage2),
//output
        .PCWrite(hazard_PCWrite),
        .IF_ID_Write(hazard_IF_ID_Write),
        .Stall(hazard_stall)
    );
   
    Branch_Forward BRN_FWD (
        .EX_RegDest(RegDest_stage3),
        .MEM_RegDest(RegDest_MEM),
        .IF_Rs(Rs_stage2),
        .IF_Rt(Rt_stage2),
        .IDtoEX_RegWrite(IDtoEX_RegWrite),
        .EXtoMEM_RegWrite(EXtoMEM_RegWrite),
        .ForwardA(branch_FWA),
        .ForwardB(branch_FWB)
    );
   
   
    EX_Stage EX (
//input
        .IDtoEX_ReadData1(readData1_stage3),
        .IDtoEX_ReadData2(readData2_stage3),
        .IDtoEX_Imm(signExtended_stage3),
        .IDtoEX_Rt(Rt_stage3),
        .IDtoEX_Rd(Rd_stage3),
        .funct(funct_stage3),
        .ALUop(IDtoEX_ALUOp),
        .ALUSrc(IDtoEX_ALUSrc),
        .RegDst(IDtoEX_RegDst),
        .EXtoMEM_ALUresult(ALUresult_stage4),
        .WB_ALUresult(WriteData_stage5),
        .ForwardA(ForwardA_wire),
        .ForwardB(ForwardB_wire),
//output
        .ALUresult(ALUresult_stage3),
        .EX_ReadData2(EX_ReadData2_stage3),
        .RegDest(RegDest_stage3)
    );
   
    EXtoMEM_Register EX_MEM (
//input
        .clk(clk),
        .rst(rst),
        .EX_ALUresult(ALUresult_stage3),
        .EX_ReadData2(EX_ReadData2_stage3),
        .EX_RegDest(RegDest_stage3),
        .EX_MemRead(IDtoEX_MemRead),
        .EX_MemWrite(IDtoEX_MemWrite),
        .EX_MemtoReg(IDtoEX_MemtoReg),
        .EX_RegWrite(IDtoEX_RegWrite),
//output
        .EXtoMEM_ALUresult(ALUresult_stage4),
        .EXtoMEM_ReadData2(EXtoMEM_ReadData2_stage4),
        .EXtoMEM_RegDest(RegDest_stage4),
        .MEM_MemRead(EXtoMEM_MemRead),
        .MEM_MemWrite(EXtoMEM_MemWrite),
        .MEM_MemtoReg(EXtoMEM_MemtoReg),
        .MEM_RegWrite(EXtoMEM_RegWrite)
    );
 
    Forward_Unit FWD (
//input
        .EX_MEM_Rd(RegDest_MEM),
        .MEM_WB_Rd(RegDest_stage5),
        .ID_EX_Rs(Rs_stage3),
        .ID_EX_Rt(Rt_stage3),
        .MEM_WB_RegWrite(MEMtoWB_RegWrite),
        .EX_MEM_RegWrite(EXtoMEM_RegWrite),
//output
        .ForwardA(ForwardA_wire),
        .ForwardB(ForwardB_wire)
    );
 
    MEM_Stage MEM (
//input
        .clk(clk),
        .EXtoMEM_ALUresult(ALUresult_stage4),
        .EXtoMEM_ReadData2(EXtoMEM_ReadData2_stage4),
        .EXtoMEM_RegDest(RegDest_stage4),
        .MemWrite(EXtoMEM_MemWrite),
        .MemRead(EXtoMEM_MemRead),
//output
        .MEM_ReadData(MEM_ReadData_stage4),
        .MEM_ALU_result(ALUresult_MEM),
        .MEM_RegDest(RegDest_MEM),
        .output_memory8(memory_8),
        .output_memory9(memory_9),
        .output_memory10(memory_10),
        .output_memory11(memory_11),
        .output_memory12(memory_12),
        .output_memory13(memory_13),
        .output_memory14(memory_14),
        .output_memory15(memory_15)
    );
   
    MEMtoWB_Register MEM_WB (
//input
        .clk(clk),
        .rst(rst),
        .MEM_ReadData(MEM_ReadData_stage4),
        .MEM_ALU_result(ALUresult_MEM),
        .MEM_RegDest(RegDest_MEM),
        .MEM_MemtoReg(EXtoMEM_MemtoReg),
        .MEM_RegWrite(EXtoMEM_RegWrite),
        .MEMtoWB_ReadData(MEMtoWB_ReadData_stage5),
        .MEMtoWB_ALU_result(ALUresult_WB),
        .MEMtoWB_RegDest(RegDest_WB),
 //output
        .MEMtoWB_MemtoReg(MEMtoWB_MemtoReg),
        .MEMtoWB_RegWrite(MEMtoWB_RegWrite)
    );
 
    WB_Stage WB (
//input
        .MEMtoWB_ReadData(MEMtoWB_ReadData_stage5),
        .MEMtoWB_ALU_result(ALUresult_WB),
        .MEMtoWB_RegDest(RegDest_WB),
        .MemtoReg(MEMtoWB_MemtoReg),
//output
        .WB_WriteReg(WriteData_stage5),
        .WB_RegDest(RegDest_stage5)
    );
   
//~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~~*~*~*~*~*~*~*~*~*~*~~*~*~*~~*~*~*~~*
 
    assign ProgramCounter_Output = pc_current;
    assign Register_8 = t0;
    assign Register_9 = t1;   
    assign Register_10 = t2;
    assign Register_11 = t3;
    assign Register_12 = t4;
    assign Register_13 = t5;   
    assign Register_14 = t6;
    assign Register_15 = t7;
 
    assign forward_A = ForwardA_wire;
    assign forward_B = ForwardB_wire;
 
    assign hazard = hazard_stall;
 
endmodule