module exe ( input logic clk, input logic rst, //----------------- // Decode Interface //----------------- input logic idu_exe_rs1Vld_EXE, input logic [REG_IDX-1:0] idu_exe_rs1Idx_EXE, input logic idu_exe_rs2Vld_EXE, input logic [REG_IDX-1:0] idu_exe_rs2Idx_EXE, input alu_op_t idu_exe_aluOp_EXE, //----------------- // Memory Interface //----------------- output logic [WORD_WID-1:0] exe_mem_aluOpOut_EXE, //----------------------- // Fetch Branch Interface //----------------------- output logic exe_ifu_brRes_EXE, output logic exe_ifu_brTaken_EXE, output logic [WORD_WID-1:0] exe_ifu_brPC_EXE, //-------------------- // Writeback Interface //-------------------- input logic wb_exe_rdVld_WB, input logic [ REG_IDX-1:0] wb_exe_rdIdx_WB, input logic [WORD_WID-1:0] wb_exe_rdData_WB ); // Alu logic [WORD_WID-1:0] aluSumDiff_EXE; logic [WORD_WID-1:0] aluSumDiffIn1_EXE; logic [WORD_WID-1:0] aluSumDiffIn2_EXE; logic [WORD_WID-1:0] aluLeftShft_EXE; logic [WORD_WID-1:0] aluRightShft_EXE; logic [WORD_WID-1:0] aluRightShftUsign_EXE; logic [WORD_WID-1:0] aluRightShftSext_EXE; logic [WORD_WID-1:0] aluCmp_EXE; logic [WORD_WID-1:0] aluCmpSign_EXE; logic [WORD_WID-1:0] aluCmpUsign_EXE; logic aluCmpMsbDiff_EXE; logic aluCmpLowUsign_EXE; // Branch Resolution logic [ 5:0] brResChoice_EXE; //-------------------- // Decode Output Flops //-------------------- assign stallVld_ID = ~exe_idu_exeRdy_EXE; // Flop Decode information AFF #( .DTYPE(alu_op_t) ) AFF_EXE_aluOp ( .q(idu_exe_aluOp_EXE), .d(idu_exe_aluOp_ID), .en(stallVld_ID), .clk(clk) ); AFF #( .WIDTH(WORD_WID) ) AFF_EXE_pc ( .q(idu_exe_pc_EXE), .d(idu_exe_pc_ID), .en(stallVld_ID), .clk(clk) ); AFF #( .WIDTH(1) ) AFF_EXE_instrJmp ( .q(idu_exe_instrJmp_EXE), .d(idu_exe_instrJmp_ID), .en(stallVld_ID), .clk(clk) ); AFF #( .WIDTH(1) ) AFF_EXE_brRes ( .q(idu_exe_brRes_EXE), .d(brResNxt_EXEM1), .en(stallVld_ID), .clk(clk) ); //-------------- // Register File //-------------- // FIXME: Add support for the zero register always_ff @(posedge clk) begin // RS1 Read Port with Forwarding if (instrRs1Vld_ID) begin idu_exe_rs1Data_EXE <= (wb_exe_rdVld_WB & (idu_exe_rs1Idx_ID == wb_exe_rdIdx_WB)) ? wb_exe_rdData_WB : regData_XXX[idu_exe_rs1Idx_ID]; end // RS2 Read Port with Forwarding if (instrRdVld_ID) begin idu_exe_rs2Data_EXE <= (wb_exe_rdVld_WB & (idu_exe_rs1Idx_ID == wb_exe_rdIdx_WB)) ? wb_exe_rdData_WB : regData_XXX[idu_exe_rs2Idx_ID]; end // RD Write Port if (wb_exe_rdData_WB) begin regData_XXX[wb_exe_rdIdx_WB] <= wb_exe_rdData_WB; end end //---- // ALU //---- // Operand Selection assign aluIn1_EXE = (aluOp_EXE.rs1Sel == PC) ? pc_EXE : // PC for AUIPC, JAL (aluOp_EXE.rs1Sel == ZERO) ? WORD_WID'(0) : // 0 for LUI rs1Data_EXE; // RS1 for other operations assign aluIn2_EXE = (aluOp_EXE.rs2Sel == RS2) ? rs2Data_EXE : // RS2 for R type operations aluOp_EXE.immediate; // Immediate for all other operations // Two's complement negation of aluIn2 if func7 is set (subtract) assign aluSumDiffIn1_EXE = aluIn1_EXE; assign aluSumDiffIn2_EXE = ({WORD_WID{aluOp_EXE.func7}} ^ aluIn2_EXE) + aluOp_EXE.func7; assign aluSumDiff_EXE = aluSumDiffIn1_EXE + aluSumDiffIn2_EXE; // Shifter, TODO: Explicit signed barrel shifter assign aluRightShftUsign_EXE = aluIn1_EXE >> aluIn2_EXE[4:0]; assign aluRightShftSext_EXE = ~({WORD_WID{1'b1}} >> aluIn2_EXE[4:0]); assign aluRightShft_EXE = aluRightShftUsgn_EXE | (aluRightShftSext_EXE & {WORD_WID{aluOp_EXE.func7}}); FLIP #( .WIDTH(WORD_WID) ) EXE_aluLeftShft ( .in (aluRightShftUsign_EXE), .out(aluLeftShft_EXE) ); // Set Less Than assign aluCmpMsbDiff_EXE = aluIn2_EXE ^ aluIn1_EXE; assign aluCmpLowUsign_EXE = aluIn1_EXE[WORD_WID-2:0] < aluIn2_EXE[WORD_WID-2:0]; assign aluCmpSign_EXE = aluCmpMsbDiff_EXE ? aluIn1_EXE[WORD_WID-1] : aluCmpLowUsign_EXE; // If diff signs (MSB) and in1 negative, then in1 < 0 < in2, else compare low bits assign aluCmpUSign_EXE = aluCmpMsbDiff_EXE ? aluIn2_EXE[WORD_WID-1] : aluCmpLowUsign_EXE; // If diff MSB and MSB in2[31] == 1, then in1 < in2, else compare low bits // Bitwise Operations assign aluXor_EXE = aluIn1_EXE ^ aluIn2_EXE; assign aluOr_EXE = aluIn1_EXE | aluIn2_EXE; assign aluAnd_EXE = aluIn1_EXE & aluIn2_EXE; // ALU Operation Select assign aluOpRes_EXE[0] = aluSumDiff_EXE; assign aluOpRes_EXE[1] = aluLeftShft_EXE; assign aluOpRes_EXE[2] = {(WORD_WID - 1)'(0), aluCmpSign_EXE}; assign aluOpRes_EXE[3] = {(WORD_WID - 1)'(0), aluCmpUSign_EXE}; assign aluOpRes_EXE[4] = aluXor_EXE; assign aluOpRes_EXE[5] = aluRightShft_EXE; assign aluOpRes_EXE[6] = aluOr_EXE; assign aluOpRes_EXE[7] = aluAnd_EXE; EMUX #( .WIDTH (WORD_WID), .INPUTS(8) ) EMUX_exe_aluOpSel ( .in (aluOpResults_EXE), .out(aluOpOut_EXE), .sel(aluOp_EXE.func3) ); // rd is either PC from jump instr or alu output assign exe_mem_rdData_EXE = instrJmp_EXE ? pc_EXE : aluOpOut_EXE; //------------------ // Branch Resolution //------------------ assign exe_ifu_brPC_EXE = aluOpOut_EXE; assign exe_ifu_brRes_EXE = brRes_EXE; // FIXME: Only send this once after a branch is processed until stall is lifted assign brResChoice_EXE[0] = ~|aluXor_EXE; assign brResChoice_EXE[1] = |aluXor_EXE; assign brResChoice_EXE[2] = aluCmpSign_EXE; assign brResChoice_EXE[3] = ~aluCmpSign_EXE; assign brResChoice_EXE[4] = aluCmpUSign_EXE; assign brResChoice_EXE[5] = ~aluCmpUSign_EXE; EMUX #( .WIDTH (1), .INPUTS(6) ) EMUX_exe_aluOpSel ( .in (brResChoice_EXE), .out(exe_ifu_brTaken_EXE), .sel(idu_exe_brOp_ID) ); //--------------------- // Pipeline passthrough //--------------------- endmodule