aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/pkg/riscv_types.sv57
-rw-r--r--core/rtl/decode.sv135
-rw-r--r--core/rtl/exe.sv179
-rw-r--r--core/rtl/fetch.sv22
-rw-r--r--core/rtl/idu.sv160
-rw-r--r--core/rtl/ifu.sv30
-rw-r--r--core/tb/core_tb.sv2
-rw-r--r--primitives/rtl/DMUX.sv0
-rw-r--r--primitives/rtl/FLIP.sv16
9 files changed, 426 insertions, 175 deletions
diff --git a/core/pkg/riscv_types.sv b/core/pkg/riscv_types.sv
index 48ca87b..59c1f74 100644
--- a/core/pkg/riscv_types.sv
+++ b/core/pkg/riscv_types.sv
@@ -1,14 +1,21 @@
package riscv_types;
+ WORD_WIDTH = 32;
+ NUM_REG = 32;
+ REG_IDX = $clog2(NUM_REG);
+
+ //-----------------
+ // Decode Types
+ //-----------------
typedef enum logic [6:0] {
- INSTR_TYPE_LUI = 7'b0110111, // U load upper immediate
- INSTR_TYPE_AUIPC = 7'b0010111, // U add upper immediate PC
- INSTR_TYPE_JAL = 7'b1101111, // J jump and link
- INSTR_TYPE_JALR = 7'b1100111, // I jump and link register
- INSTR_TYPE_BR = 7'b1100011, // B branch
- INSTR_TYPE_LD = 7'b0000011, // I load
- INSTR_TYPE_ST = 7'b0100011, // S store
- INSTR_TYPE_IMM = 7'b0010011, // I arith ops with register/immediate operands
- INSTR_TYPE_REG = 7'b0110011, // R arith ops with register operands
+ INSTR_TYPE_LUI = 7'b0110111, // U load upper immediate
+ INSTR_TYPE_AUIPC = 7'b0010111, // U add upper immediate PC
+ INSTR_TYPE_JAL = 7'b1101111, // J jump and link
+ INSTR_TYPE_JALR = 7'b1100111, // I jump and link register
+ INSTR_TYPE_BR = 7'b1100011, // B branch
+ INSTR_TYPE_LD = 7'b0000011, // I load
+ INSTR_TYPE_ST = 7'b0100011, // S store
+ INSTR_TYPE_IMM = 7'b0010011, // I arith ops with register/immediate operands
+ INSTR_TYPE_REG = 7'b0110011, // R arith ops with register operands
INSTR_TYPE_CSR = 7'b1110011 // I control and status register
} opcode_t;
@@ -18,21 +25,37 @@ package riscv_types;
MEM_OP_NONE
} mem_op_t;
- typedef enum logic [1:0] {
- REG_IMM_OFFSET,
- PC_IMM_OFFSET,
- OFFSET_NONE
- } brjmp_op_t;
+ typedef enum logic [2:0] {
+ BEQ = 0,
+ BNE = 1,
+ BLT = 2,
+ BGE = 3,
+ BLTU = 4,
+ BGEU = 5
+ } br_op_t;
+
+ //------------
+ // ALU Control
+ //------------
typedef enum logic [1:0] {
RS1,
PC,
- OP_NONE
- } aluSelOp1_t;
+ ZERO
+ } alu_sel_op_1_t;
typedef enum logic {
RS2,
IMM
- } aluSelOp2_t;
+ } alu_sel_op_2_t;
+
+ typedef struct packed {
+ logic func7;
+ logic [2:0] func3;
+ logic [WORD_WIDTH-1:0] immediate;
+
+ alu_sel_op_1_t rs1Sel;
+ alu_sel_op_2_t rs2Sel;
+ } alu_op_t;
endpackage
diff --git a/core/rtl/decode.sv b/core/rtl/decode.sv
deleted file mode 100644
index 8642013..0000000
--- a/core/rtl/decode.sv
+++ /dev/null
@@ -1,135 +0,0 @@
-module decode
-import riscv_types::*;
-#(
- )
- (
- input logic clk,
- input logic rst_l,
-
- // I-MEM Interface
- input logic [31:0] imem_id_instr_ID,
-
- // Fetch Interface
- input logic [31:0] imem_id_pc_ID
-
- // Dispatch Interface
- );
-
-// OpCode
-opcode_t instrOpCode_ID;
-
-// Instruction Type
-logic instrTypeR_ID;
-logic instrTypeI_ID;
-logic instrTypeS_ID;
-logic instrTypeB_ID;
-logic instrTypeU_ID;
-logic instrTypeJ_ID;
-
- // Immediate
-logic [31:0] instrImm_ID;
-logic instrImmSign_ID;
-
-// Register Indices
-logic [4:0] instrRs1Idx_ID;
-logic instrRs1Vld_ID;
-logic [4:0] instrRs2Idx_ID;
-logic instrRs2Vld_ID;
-logic [4:0] instrRdIdx_ID;
-logic instrRdVld_ID;
-
-// Funct3 and Funct7
-logic [2:0] instrFunct3_ID;
-logic instrFunct7_ID;
-
-// Control Bits
-
-// Memory Op
-mem_op_t instrMemOp_ID;
-
-// Branch OP
-brjmp_op_t instrBrJmpOp_ID;
-
-// ALU Operand Selection
-aluSelOp1_t instrAluOp1_ID;
-aluSelOp2_t instrAluOp2_ID;
-
-// DEBUG: Display decode instr
-always_ff @(clk) begin : f_print_decode
- $display("OpCode: %s", instrOpCode_ID.name());
- $display("Immediate: %0d", instrImm_ID);
- $display("Memory: %s", instrMemOp_ID.name());
- $display("Branch: %s", instrBrJmpOp_ID.name());
- $display("ALU Sel 1: %s", instrAluOp1_ID.name());
- $display("ALU Sel 2: %s", instrAluOp2_ID.name());
- $display("Funct3: %0x", instrFunct3_ID);
- $display("Funct7: %0x", instrFunct7_ID);
-end
-
-// Instruction Type Decode
-// FIXME: Add support for FENCE + ECALL + EBREAK + CSRs
-assign instrTypeI_ID = (instrOpCode_ID == INSTR_TYPE_IMM)
- | (instrOpCode_ID == INSTR_TYPE_JALR)
- | (instrOpCode_ID == INSTR_TYPE_LD);
-assign instrTypeU_ID = (instrOpCode_ID == INSTR_TYPE_LUI)
- | (instrOpCode_ID == INSTR_TYPE_AUIPC);
-assign instrTypeR_ID = (instrOpCode_ID == INSTR_TYPE_REG);
-assign instrTypeS_ID = (instrOpCode_ID == INSTR_TYPE_ST);
-assign instrTypeB_ID = (instrOpCode_ID == INSTR_TYPE_BR);
-assign instrTypeJ_ID = (instrOpCode_ID == INSTR_TYPE_JAL);
-
-// Register Index Decode
-assign instrRs1Idx_ID = imem_id_instr_ID[19:15];
-assign instrRs1Vld_ID = instrTypeR_ID | instrTypeI_ID | instrTypeS_ID | instrTypeB_ID;
-
-assign instrRs2Idx_ID = imem_id_instr_ID[24:20];
-assign instrRs2Vld_ID = instrTypeR_ID | instrTypeS_ID | instrTypeB_ID;
-
-assign instrRdIdx_ID = imem_id_instr_ID[11:7];
-assign instrRdVld_ID = instrTypeR_ID | instrTypeI_ID | instrTypeU_ID | instrTypeJ_ID;
-
-// Func Bit decode
-assign instrFunct7_ID = imem_id_instr_ID[30];
-assign instrFunct3_ID = imem_id_instr_ID[14:12];
-
-// Instruction Type (OpCode) Decode
-assign instrImmSign_ID = imem_id_instr_ID[31];
-assign instrOpCode_ID = opcode_t'(imem_id_instr_ID[6:0]);
-
-// Immediate Decode
-assign instrImm_ID[0] = instrTypeJ_ID ? imem_id_instr_ID[25] : // Bit 25 for I-Type
- instrTypeS_ID ? imem_id_instr_ID[7] : // Bit 7 for S-Type
- '0; // All other instructions set to 0
-
-assign instrImm_ID[4:1] = instrTypeI_ID ? imem_id_instr_ID[24:21] : // I-Type bits
- (instrTypeS_ID | instrTypeB_ID) ? imem_id_instr_ID[11:8] : // S-Type + B-Type bits
- '0; // All other instructions set to 0
-
-assign instrImm_ID[10:5] = instrTypeU_ID ? '0 : imem_id_instr_ID[30:25]; // Only J type is an immediate instruction that doesn't have it in 30:25
-
-
-assign instrImm_ID[11] = (instrTypeI_ID | instrTypeS_ID) ? imem_id_instr_ID[31] :
- (instrTypeB_ID) ? imem_id_instr_ID[7] :
- (instrTypeJ_ID) ? imem_id_instr_ID[20] :
- '0;
-
-assign instrImm_ID[19:12] = (instrTypeU_ID | instrTypeJ_ID) ? imem_id_instr_ID[19:12] : { 8{instrImmSign_ID}}; // Only J and U types use 19:12 as not sign bit
-assign instrImm_ID[31:20] = (instrTypeU_ID) ? imem_id_instr_ID[31:20] : {12{instrImmSign_ID}}; // Only U type use 31:20 as not sign bit
-
-// Control Bits
-assign instrMemOp_ID = (instrOpCode_ID == INSTR_TYPE_ST) ? MEM_OP_STORE :
- (instrOpCode_ID == INSTR_TYPE_LD) ? MEM_OP_LOAD :
- MEM_OP_NONE;
-
-assign instrBrJmpOp_ID = (instrOpCode_ID == INSTR_TYPE_JALR) ? REG_IMM_OFFSET :
- (instrOpCode_ID == INSTR_TYPE_BR | instrOpCode_ID == INSTR_TYPE_JAL) ? PC_IMM_OFFSET :
- OFFSET_NONE;
-
-assign instrAluOp1_ID = (instrOpCode_ID == INSTR_TYPE_AUIPC) | (instrOpCode_ID == INSTR_TYPE_JAL) ? PC : // Loading PC for AUIPC, PC Offset for JAL
- (instrOpCode_ID == INSTR_TYPE_LUI) ? OP_NONE : // Only loading immediate for LUI
- RS1; // All else use RS1 value
-
-assign instrAluOp2_ID = (instrOpCode_ID == INSTR_TYPE_REG) ? RS2 : IMM; // Only R2R needs non-immediate op in ALU
-
-
-endmodule
diff --git a/core/rtl/exe.sv b/core/rtl/exe.sv
new file mode 100644
index 0000000..4615638
--- /dev/null
+++ b/core/rtl/exe.sv
@@ -0,0 +1,179 @@
+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
diff --git a/core/rtl/fetch.sv b/core/rtl/fetch.sv
deleted file mode 100644
index d2b5ed0..0000000
--- a/core/rtl/fetch.sv
+++ /dev/null
@@ -1,22 +0,0 @@
-module fetch
-import riscv_types::*;
-(
- input logic clk,
- input logic rst_l,
-
- // IMEM interface
- output logic [31:0] if_imem_addr_IF
-);
-
-logic [31:0] pc_IF;
-logic [31:0] pcNxt_IF;
-
-assign if_imem_addr_IF = pc_IF; // Always fetch PC from IMEM, addresses are always 32 bit aligned
- // TODO: Find out if 32 is the best fetching width vs 16
-
-// Program Counter (PC)
-assign pcNxt_IF = pc_IF + 32'd4;
-
-AFFR #(.WIDTH(32)) ff_IF_pc ( .clk(clk), .rst_l(rst_l), .en(1'b1), .q(pc_IF), .d(pcNxt_IF) );
-
-endmodule
diff --git a/core/rtl/idu.sv b/core/rtl/idu.sv
new file mode 100644
index 0000000..0bfd073
--- /dev/null
+++ b/core/rtl/idu.sv
@@ -0,0 +1,160 @@
+module idu
+import riscv_types::*;
+#(
+ )
+ (
+ input logic clk,
+ input logic rst_l,
+
+ // I-MEM Interface
+ input logic [INSTR_SIZE-1:0] imem_id_instr_ID,
+
+ // Fetch Interface
+ input logic [PC_SIZE-1:0] imem_id_pc_ID,
+
+ //------------------
+ // Execute Interface
+ //------------------
+ input logic exe_idu_exeRdy_EXE,
+
+ // Alu information
+ output alu_op_t idu_exe_aluOp_ID,
+
+ // Register Idx
+ output logic idu_exe_rs1Vld_EXE,
+ output logic [REG_IDX-1:0] idu_exe_rs1Idx_EXE,
+
+ output logic idu_exe_rs2Vld_EXE,
+ output logic [REG_IDX-1:0] idu_exe_rs2Idx_EXE
+ );
+
+// OpCode
+opcode_t instrOpCode_ID;
+
+// Instruction Type
+logic instrTypeR_ID;
+logic instrTypeI_ID;
+logic instrTypeS_ID;
+logic instrTypeB_ID;
+logic instrTypeU_ID;
+logic instrTypeJ_ID;
+
+ // Immediate
+logic [WORD_WID-1:0] instrImm_ID;
+logic instrImmSign_ID;
+
+// Register Indices
+logic [REG_IDX-1:0] instrRs1Idx_ID;
+logic instrRs1Vld_ID;
+logic [REG_IDX-1:0] instrRs2Idx_ID;
+logic instrRs2Vld_ID;
+logic [REG_IDX-1:0] instrRdIdx_ID;
+logic instrRdVld_ID;
+
+// Funct3 and Funct7
+logic [2:0] instrFunct3_ID;
+logic instrFunct7_ID;
+
+// Control Bits
+
+// Memory Op
+mem_op_t instrMemOp_ID;
+
+// Branch OP
+brjmp_op_t instrBrJmpOp_ID;
+
+// ALU Operand Selection
+aluSelOp1_t instrAluIn1_ID;
+aluSelOp2_t instrAluIn2_ID;
+
+// Reg File
+logic [NUM_REG-1:0] [WORD_WID-1:0] regData_XXX;
+
+//------------------------
+// Instruction Type Decode
+//------------------------
+
+// FIXME: Add support for FENCE + ECALL + EBREAK + CSRs
+assign instrTypeI_ID = (instrOpCode_ID == INSTR_TYPE_IMM)
+ | (instrOpCode_ID == INSTR_TYPE_JALR)
+ | (instrOpCode_ID == INSTR_TYPE_LD);
+assign instrTypeU_ID = (instrOpCode_ID == INSTR_TYPE_LUI)
+ | (instrOpCode_ID == INSTR_TYPE_AUIPC);
+assign instrTypeR_ID = (instrOpCode_ID == INSTR_TYPE_REG);
+assign instrTypeS_ID = (instrOpCode_ID == INSTR_TYPE_ST);
+assign instrTypeB_ID = (instrOpCode_ID == INSTR_TYPE_BR);
+assign instrTypeJ_ID = (instrOpCode_ID == INSTR_TYPE_JAL);
+
+// Register Index Decode
+assign instrRs1Idx_ID = imem_id_instr_ID[19:15];
+assign instrRs1Vld_ID = instrTypeR_ID | instrTypeI_ID | instrTypeS_ID | instrTypeB_ID;
+
+assign instrRs2Idx_ID = imem_id_instr_ID[24:20];
+assign instrRs2Vld_ID = instrTypeR_ID | instrTypeS_ID | instrTypeB_ID;
+
+assign instrRdIdx_ID = imem_id_instr_ID[11:7];
+assign instrRdVld_ID = instrTypeR_ID | instrTypeI_ID | instrTypeU_ID | instrTypeJ_ID;
+
+// Func Bit decode
+assign instrFunct7_ID = imem_id_instr_ID[30];
+assign instrFunct3_ID = imem_id_instr_ID[14:12];
+
+// Instruction Type (OpCode) Decode
+assign instrImmSign_ID = imem_id_instr_ID[31];
+assign instrOpCode_ID = opcode_t'(imem_id_instr_ID[6:0]);
+
+//----------------
+// ALU Information
+//----------------
+
+// Immediate Decode
+assign idu_exe_aluOp_ID.imm[0] = instrTypeJ_ID ? imem_id_instr_ID[25] : // Bit 25 for I-Type
+ instrTypeS_ID ? imem_id_instr_ID[7] : // Bit 7 for S-Type
+ 1'b0; // All other instructions set to 0
+
+assign idu_exe_aluOp_ID.imm[4:1] = ({3{instrTypeI_ID | instrTypeJ_ID}} & imem_id_instr_ID[24:21]) // I-Type + J-Type bits
+ | ({3{instrTypeS_ID | instrTypeB_ID}} & imem_id_instr_ID[11:8]); // S-Type + B-Type bits
+
+assign idu_exe_aluOp_ID.imm[10:5] = {6{~instrTypeU_ID}} & imem_id_instr_ID[30:25]; // U type is the only instr that doesn't have 10:5
+
+
+assign idu_exe_aluOp_ID.imm[11] = ((instrTypeI_ID | instrTypeS_ID) & imem_id_instr_ID[31]) // I-Type + S-Type bit
+ | ( instrTypeB_ID & imem_id_instr_ID[7]) // B-Type bit
+ | ( instrTypeJ_ID & imem_id_instr_ID[20]); // J-Type bit
+
+assign idu_exe_aluOp_ID.imm[19:12] = (instrTypeU_ID | instrTypeJ_ID) ? imem_id_instr_ID[19:12] : { 8{instrImmSign_ID}}; // Only J and U types use 19:12 as not sign bit
+assign idu_exe_aluOp_ID.imm[31:20] = (instrTypeU_ID) ? imem_id_instr_ID[31:20] : {12{instrImmSign_ID}}; // Only U type use 31:20 as not sign bit
+
+assign idu_exe_aluOp_ID.rs1Sel = (instrOpCode_ID == INSTR_TYPE_AUIPC) | (instrOpCode_ID == INSTR_TYPE_JAL) ? PC : // Loading PC for AUIPC, PC Offset for JAL
+ (instrOpCode_ID == INSTR_TYPE_LUI) ? ZERO : // Only loading immediate for LUI
+ RS1; // All else use RS1 value
+
+assign idu_exe_aluOp_ID.rs2Sel = (instrOpCode_ID == INSTR_TYPE_REG) ? RS2 : IMM; // Only R Type needs non-immediate op in ALU
+
+assign idu_exe_aluOp_ID.func3 = imem_id_instr_ID[14:12];
+assign idu_exe_aluOp_ID.func7 = imem_id_instr_ID[30];
+
+//---------------
+// Branch Control
+//---------------
+assign idu_exe_instrJmp_ID = (instrOpCode_ID == INSTR_TYPE_JALR) | (instrOpCode_ID == INSTR_TYPE_JAL);
+assign idu_exe_brAluOp_ID = (idu_exe_aluOp_ID.func3 == 3'b0) ? BR_ALU_XOR : BR_ALU_CMP; // Only equality needs XOR all other OPs use compare
+assign idu_exe_brCmpSign_ID = (idu_exe_aluOp_ID.func3[2:1] == 2'b11); // Unsigned comparisons have func3 top two bits set
+assign idu_exe_brCmpGreater_ID = (idu_exe_aluOp_ID.func3[2:1] == 2'b11); // Unsigned comparisons have func3 top two bits set
+
+//---------------
+// Memory Control
+//---------------
+assign instrMemOp_ID = (instrOpCode_ID == INSTR_TYPE_ST) ? MEM_OP_STORE :
+ (instrOpCode_ID == INSTR_TYPE_LD) ? MEM_OP_LOAD :
+ MEM_OP_NONE;
+
+//------------------
+// Writeback Control
+//------------------
+
+
+assign instrAluOp_ID = ;
+
+
+endmodule
diff --git a/core/rtl/ifu.sv b/core/rtl/ifu.sv
new file mode 100644
index 0000000..0eb3b1d
--- /dev/null
+++ b/core/rtl/ifu.sv
@@ -0,0 +1,30 @@
+module ifu
+ import riscv_types::*;
+(
+ input logic clk,
+ input logic rst_l,
+
+ // IMEM interface
+ output logic [31:0] if_imem_addr_IF
+);
+
+ logic [31:0] pc_IF;
+ logic [31:0] pcNxt_IF;
+
+ assign if_imem_addr_IF = pc_IF; // Always fetch PC from IMEM, addresses are always 32 bit aligned
+ // TODO: Find out if 32 is the best fetching width vs 16
+
+ // Program Counter (PC)
+ assign pcNxt_IF = pc_IF + 32'd4;
+
+ AFFR #(
+ .WIDTH(32)
+ ) ff_IF_pc (
+ .q(pc_IF),
+ .d(pcNxt_IF),
+ .en(1'b1),
+ .clk(clk),
+ .rst_l(rst_l)
+ );
+
+endmodule
diff --git a/core/tb/core_tb.sv b/core/tb/core_tb.sv
index 3252a13..5824ed8 100644
--- a/core/tb/core_tb.sv
+++ b/core/tb/core_tb.sv
@@ -22,7 +22,7 @@ initial begin
$dumpfile("dump.fst");
$dumpvars;
- // Reset Set up
+ // Reset Set up
rst_l = 1'b0;
repeat (5) @(posedge clk);
rst_l = 1'b1;
diff --git a/primitives/rtl/DMUX.sv b/primitives/rtl/DMUX.sv
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/primitives/rtl/DMUX.sv
diff --git a/primitives/rtl/FLIP.sv b/primitives/rtl/FLIP.sv
new file mode 100644
index 0000000..baf3c2b
--- /dev/null
+++ b/primitives/rtl/FLIP.sv
@@ -0,0 +1,16 @@
+module FLIP
+#(
+ parameter WIDTH = 1
+)
+(
+ input [WIDTH-1:0] in,
+ output [WIDTH-1:0] out
+);
+
+genvar flip_idx;
+
+for (flip_idx = 0, flip_idx < WIDTH; flip_idx++) begin
+ assign out[flip_idx] = in[WIDTH-flip_idx-1];
+end
+
+endmodule