From 7b6f0273e74987d33111f683484c3e957de8ceab Mon Sep 17 00:00:00 2001 From: Sergi Granell Date: Fri, 12 Oct 2018 09:49:41 +0200 Subject: [PATCH] Re-structure pipeline --- alu.sv | 2 - control.sv | 217 +++++---------------------------------------- datapath.sv | 201 +++++++++++++++++++++++------------------ decode.sv | 236 +++++++++++++++++++++++++++++++++++-------------- definitions.sv | 134 +++++++++++++++------------- tb/modelsim.do | 8 +- 6 files changed, 386 insertions(+), 412 deletions(-) diff --git a/alu.sv b/alu.sv index 12436cb..9c94f92 100644 --- a/alu.sv +++ b/alu.sv @@ -10,8 +10,6 @@ module alu( priority case (alu_op_i) ALU_OP_IN1_PASSTHROUGH: out_o = in1_i; - ALU_OP_IN2_PASSTHROUGH: - out_o = in2_i; ALU_OP_ADD: out_o = in1_i + in2_i; ALU_OP_SUB: diff --git a/control.sv b/control.sv index 01be9d2..ab6d512 100644 --- a/control.sv +++ b/control.sv @@ -5,231 +5,54 @@ module control( input pipeline_ex_reg_t ex_reg_i, input pipeline_mem_reg_t mem_reg_i, input pipeline_wb_reg_t wb_reg_i, - output pipeline_if_ctrl_t if_ctrl_o, - output pipeline_id_ctrl_t id_ctrl_o, - output pipeline_ex_ctrl_t ex_ctrl_o, - output pipeline_mem_ctrl_t mem_ctrl_o, - output pipeline_wb_ctrl_t wb_ctrl_o + output pipeline_control_t control_o ); - /* Check data hazards */ + /* Check data hazards with the current instruction being decoded */ logic ex_data_hazard; logic mem_data_hazard; logic wb_data_hazard; logic data_hazard; - assign ex_data_hazard = ex_reg_i.valid && data_hazard_raw_check(id_reg_i.instr, ex_reg_i.regfile_rd); - assign mem_data_hazard = mem_reg_i.valid && data_hazard_raw_check(id_reg_i.instr, mem_reg_i.regfile_rd); - assign wb_data_hazard = wb_reg_i.valid && data_hazard_raw_check(id_reg_i.instr, wb_reg_i.regfile_rd); + assign ex_data_hazard = ex_reg_i.valid && data_hazard_raw_check(id_reg_i.instr, ex_reg_i.regfile_wr_addr); + assign mem_data_hazard = mem_reg_i.valid && data_hazard_raw_check(id_reg_i.instr, mem_reg_i.regfile_wr_addr); + assign wb_data_hazard = wb_reg_i.valid && data_hazard_raw_check(id_reg_i.instr, wb_reg_i.regfile_wr_addr); assign data_hazard = ex_data_hazard || mem_data_hazard || wb_data_hazard; - /* IF stage */ + /* IF stage control signals */ logic control_hazard; - assign if_ctrl_o.pc_we = 1; - always_comb begin control_hazard = 0; - if_ctrl_o.next_pc_sel = NEXT_PC_SEL_PC_4; + control_o.next_pc_sel = NEXT_PC_SEL_PC_4; if (mem_reg_i.valid) begin - priority case (mem_reg_i.instr.common.opcode) - OPCODE_JAL, - OPCODE_JALR: begin + if (mem_reg_i.is_jump) begin control_hazard = 1; - if_ctrl_o.next_pc_sel = NEXT_PC_SEL_ALU_OUT; - end - OPCODE_BRANCH: begin + control_o.next_pc_sel = NEXT_PC_SEL_ALU_OUT; + end else if (mem_reg_i.is_branch) begin if (mem_reg_i.cmp_unit_res) begin control_hazard = 1; - if_ctrl_o.next_pc_sel = NEXT_PC_SEL_ALU_OUT; + control_o.next_pc_sel = NEXT_PC_SEL_ALU_OUT; end else begin - if_ctrl_o.next_pc_sel = NEXT_PC_SEL_PC_4; + control_o.next_pc_sel = NEXT_PC_SEL_PC_4; end end - endcase end end - assign if_ctrl_o.pc_reg_stall = data_hazard && !control_hazard; - assign if_ctrl_o.id_reg_stall = data_hazard && !control_hazard; - assign if_ctrl_o.id_reg_valid = !control_hazard; + assign control_o.pc_reg_stall = data_hazard && !control_hazard; + assign control_o.id_reg_stall = data_hazard && !control_hazard; + assign control_o.id_reg_valid = !control_hazard; - /* ID stage */ - logic decode_regfile_we; - logic decode_csr_we; - alu_op_t decode_alu_op; + /* ID stage control signals */ decode decode( .instr_i(id_reg_i.instr), - .regfile_we_o(decode_regfile_we), - .csr_we_o(decode_csr_we), - .alu_op_o(decode_alu_op) + .decode_o(control_o.decode_out) ); - assign id_ctrl_o.ex_reg_valid = id_reg_i.valid && !data_hazard && !control_hazard; - assign id_ctrl_o.regfile_we = id_reg_i.valid ? decode_regfile_we : 0; - assign id_ctrl_o.csr_we = id_reg_i.valid ? decode_csr_we : 0; - assign id_ctrl_o.alu_op = decode_alu_op; - - /* EX stage */ - assign ex_ctrl_o.mem_reg_valid = ex_reg_i.valid && !control_hazard; - - always_comb begin - priority case (ex_reg_i.instr.common.opcode) - OPCODE_LUI: begin - ex_ctrl_o.alu_in2_sel = ALU_IN2_SEL_IMM; - end - OPCODE_AUIPC: begin - ex_ctrl_o.alu_in1_sel = ALU_IN1_SEL_PC; - ex_ctrl_o.alu_in2_sel = ALU_IN2_SEL_IMM; - end - OPCODE_JAL: begin - ex_ctrl_o.alu_in1_sel = ALU_IN1_SEL_PC; - ex_ctrl_o.alu_in2_sel = ALU_IN2_SEL_IMM; - end - OPCODE_JALR: begin - ex_ctrl_o.alu_in1_sel = ALU_IN1_SEL_REGFILE_OUT1; - ex_ctrl_o.alu_in2_sel = ALU_IN2_SEL_IMM; - end - OPCODE_BRANCH: begin - ex_ctrl_o.alu_in1_sel = ALU_IN1_SEL_PC; - ex_ctrl_o.alu_in2_sel = ALU_IN2_SEL_IMM; - - priority case (ex_reg_i.instr.btype.funct3) - FUNCT3_BRANCH_BEQ: - ex_ctrl_o.compare_unit_op = COMPARE_UNIT_OP_EQ; - FUNCT3_BRANCH_BNE: - ex_ctrl_o.compare_unit_op = COMPARE_UNIT_OP_NE; - FUNCT3_BRANCH_BLT: - ex_ctrl_o.compare_unit_op = COMPARE_UNIT_OP_LT; - FUNCT3_BRANCH_BGE: - ex_ctrl_o.compare_unit_op = COMPARE_UNIT_OP_GE; - FUNCT3_BRANCH_BLTU: - ex_ctrl_o.compare_unit_op = COMPARE_UNIT_OP_LTU; - FUNCT3_BRANCH_BGEU: - ex_ctrl_o.compare_unit_op = COMPARE_UNIT_OP_GEU; - endcase - end - OPCODE_LOAD: begin - ex_ctrl_o.alu_in1_sel = ALU_IN1_SEL_REGFILE_OUT1; - ex_ctrl_o.alu_in2_sel = ALU_IN2_SEL_IMM; - end - OPCODE_STORE: begin - ex_ctrl_o.alu_in1_sel = ALU_IN1_SEL_REGFILE_OUT1; - ex_ctrl_o.alu_in2_sel = ALU_IN2_SEL_IMM; - end - OPCODE_OP_IMM: begin - ex_ctrl_o.alu_in1_sel = ALU_IN1_SEL_REGFILE_OUT1; - ex_ctrl_o.alu_in2_sel = ALU_IN2_SEL_IMM; - end - OPCODE_OP: begin - ex_ctrl_o.alu_in1_sel = ALU_IN1_SEL_REGFILE_OUT1; - ex_ctrl_o.alu_in2_sel = ALU_IN2_SEL_REGFILE_OUT2; - end - OPCODE_SYSTEM: begin - priority case (ex_reg_i.instr.itype.funct3) - FUNCT3_SYSTEM_CSRRW: begin - ex_ctrl_o.alu_in1_sel = ALU_IN1_SEL_REGFILE_OUT1; - end - FUNCT3_SYSTEM_CSRRS: begin - ex_ctrl_o.alu_in1_sel = ALU_IN1_SEL_REGFILE_OUT1; - ex_ctrl_o.alu_in2_sel = ALU_IN2_SEL_CSR_OUT; - end - FUNCT3_SYSTEM_CSRRC: begin - ex_ctrl_o.alu_in1_sel = ALU_IN1_SEL_REGFILE_OUT1; - ex_ctrl_o.alu_in2_sel = ALU_IN2_SEL_CSR_OUT; - end - FUNCT3_SYSTEM_CSRRWI: begin - ex_ctrl_o.alu_in2_sel = ALU_IN2_SEL_IMM; - end - FUNCT3_SYSTEM_CSRRSI: begin - ex_ctrl_o.alu_in1_sel = ALU_IN1_SEL_CSR_OUT; - ex_ctrl_o.alu_in2_sel = ALU_IN2_SEL_IMM; - end - FUNCT3_SYSTEM_CSRRCI: begin - ex_ctrl_o.alu_in1_sel = ALU_IN1_SEL_CSR_OUT; - ex_ctrl_o.alu_in2_sel = ALU_IN2_SEL_IMM; - end - endcase - end - endcase - end - - /* MEM stage */ - always_comb begin - mem_ctrl_o.dmem_rd_size = MEM_ACCESS_SIZE_WORD; - mem_ctrl_o.dmem_wr_size = MEM_ACCESS_SIZE_WORD; - mem_ctrl_o.dmem_wr_enable = 0; - - priority case (mem_reg_i.instr.common.opcode) - OPCODE_LOAD: begin - priority case (mem_reg_i.instr.itype.funct3) - FUNCT3_LOAD_LB, FUNCT3_LOAD_LBU: - mem_ctrl_o.dmem_rd_size = MEM_ACCESS_SIZE_BYTE; - FUNCT3_LOAD_LH, FUNCT3_LOAD_LHU: - mem_ctrl_o.dmem_rd_size = MEM_ACCESS_SIZE_HALF; - FUNCT3_LOAD_LW: - mem_ctrl_o.dmem_rd_size = MEM_ACCESS_SIZE_WORD; - endcase - end - OPCODE_STORE: begin - mem_ctrl_o.dmem_wr_enable = 1; + assign control_o.ex_reg_valid = id_reg_i.valid && !data_hazard && !control_hazard; - priority case (mem_reg_i.instr.itype.funct3) - FUNCT3_STORE_SB: - mem_ctrl_o.dmem_wr_size = MEM_ACCESS_SIZE_BYTE; - FUNCT3_STORE_SH: - mem_ctrl_o.dmem_wr_size = MEM_ACCESS_SIZE_HALF; - FUNCT3_STORE_SW: - mem_ctrl_o.dmem_wr_size = MEM_ACCESS_SIZE_WORD; - endcase - end - endcase - - if (!mem_reg_i.valid) - mem_ctrl_o.dmem_wr_enable = 0; - end - - /* WB stage */ - always_comb begin - priority case (wb_reg_i.instr.common.opcode) - OPCODE_LUI: begin - wb_ctrl_o.regfile_in_sel = REGFILE_IN_SEL_ALU_OUT; - end - OPCODE_AUIPC: begin - wb_ctrl_o.regfile_in_sel = REGFILE_IN_SEL_ALU_OUT; - end - OPCODE_JAL: begin - wb_ctrl_o.regfile_in_sel = REGFILE_IN_SEL_PC_4; - end - OPCODE_JALR: begin - wb_ctrl_o.regfile_in_sel = REGFILE_IN_SEL_PC_4; - end - OPCODE_LOAD: begin - priority case (wb_reg_i.instr.itype.funct3) - FUNCT3_LOAD_LB: - wb_ctrl_o.regfile_in_sel = REGFILE_IN_SEL_MEM_RD_SEXT8; - FUNCT3_LOAD_LH: - wb_ctrl_o.regfile_in_sel = REGFILE_IN_SEL_MEM_RD_SEXT16; - FUNCT3_LOAD_LW, FUNCT3_LOAD_LBU, FUNCT3_LOAD_LHU: - wb_ctrl_o.regfile_in_sel = REGFILE_IN_SEL_MEM_RD; - endcase - end - OPCODE_OP_IMM: begin - wb_ctrl_o.regfile_in_sel = REGFILE_IN_SEL_ALU_OUT; - end - OPCODE_OP: begin - wb_ctrl_o.regfile_in_sel = REGFILE_IN_SEL_ALU_OUT; - end - OPCODE_SYSTEM: begin - priority case (wb_reg_i.instr.itype.funct3) - FUNCT3_SYSTEM_CSRRW, FUNCT3_SYSTEM_CSRRS, - FUNCT3_SYSTEM_CSRRC, FUNCT3_SYSTEM_CSRRWI, - FUNCT3_SYSTEM_CSRRSI, FUNCT3_SYSTEM_CSRRCI: begin - wb_ctrl_o.regfile_in_sel = REGFILE_IN_SEL_CSR_OUT; - end - endcase - end - endcase - end + /* EX stage control signals */ + assign control_o.mem_reg_valid = ex_reg_i.valid && !control_hazard; endmodule diff --git a/datapath.sv b/datapath.sv index b0f072c..c65bc0c 100644 --- a/datapath.sv +++ b/datapath.sv @@ -13,47 +13,42 @@ module datapath( pipeline_mem_reg_t mem_reg; pipeline_wb_reg_t wb_reg; - /* Pipeline registers next state */ + /* Pipeline next state signals */ logic [31:0] next_pc; pipeline_id_reg_t next_id_reg; pipeline_ex_reg_t next_ex_reg; pipeline_mem_reg_t next_mem_reg; pipeline_wb_reg_t next_wb_reg; - /* Pipeline per-stage control signals (control output) */ - pipeline_if_ctrl_t if_ctrl; - pipeline_id_ctrl_t id_ctrl; - pipeline_ex_ctrl_t ex_ctrl; - pipeline_mem_ctrl_t mem_ctrl; - pipeline_wb_ctrl_t wb_ctrl; + /* Pipeline control signal */ + pipeline_control_t control; - logic [31:0] regfile_wr_data; - logic [31:0] alu_in1; - logic [31:0] alu_in2; + /* Inter-stage signals */ + logic [31:0] wb_regfile_wr_data; - control control( + /* Control unit */ + control control_unit( .id_reg_i(id_reg), .ex_reg_i(ex_reg), .mem_reg_i(mem_reg), .wb_reg_i(wb_reg), - .if_ctrl_o(if_ctrl), - .id_ctrl_o(id_ctrl), - .ex_ctrl_o(ex_ctrl), - .mem_ctrl_o(mem_ctrl), - .wb_ctrl_o(wb_ctrl) + .control_o(control) ); /* IF stage */ + always_ff @(posedge clk_i) begin + if (reset_i) + pc <= 'h00010000; + else + pc <= control.pc_reg_stall ? pc : next_pc; + end + assign imemif.rd_addr = pc; assign imemif.rd_size = MEM_ACCESS_SIZE_WORD; assign imemif.wr_enable = 0; - assign next_id_reg.pc = pc; - assign next_id_reg.instr = imemif.rd_data; - assign next_id_reg.valid = if_ctrl.id_reg_valid; - always_comb begin - priority case (if_ctrl.next_pc_sel) + priority case (control.next_pc_sel) NEXT_PC_SEL_PC_4: next_pc = pc + 4; NEXT_PC_SEL_ALU_OUT: @@ -61,36 +56,25 @@ module datapath( endcase end - always_ff @(posedge clk_i) begin - if (reset_i) - pc <= 'h00010000; - else if (if_ctrl.pc_we) - pc <= if_ctrl.pc_reg_stall ? pc : next_pc; - end + assign next_id_reg.pc = pc; + assign next_id_reg.instr = imemif.rd_data; + assign next_id_reg.valid = control.id_reg_valid; + /* ID stage */ always_ff @(posedge clk_i) begin if (reset_i) id_reg <= 'b0; else - id_reg <= if_ctrl.id_reg_stall ? id_reg : next_id_reg; + id_reg <= control.id_reg_stall ? id_reg : next_id_reg; end - /* ID stage */ - assign next_ex_reg.pc = id_reg.pc; - assign next_ex_reg.instr = id_reg.instr; - assign next_ex_reg.regfile_rd = id_reg.instr.common.rd; - assign next_ex_reg.regfile_we = id_ctrl.regfile_we; - assign next_ex_reg.csr_we = id_ctrl.csr_we; - assign next_ex_reg.alu_op = id_ctrl.alu_op; - assign next_ex_reg.valid = id_ctrl.ex_reg_valid; - regfile regfile( .clk_i(clk_i), .rd_addr1_i(id_reg.instr.common.rs1), .rd_addr2_i(id_reg.instr.common.rs2), - .wr_addr_i(wb_reg.regfile_rd), - .wr_data_i(regfile_wr_data), - .wr_en_i(wb_reg.regfile_we & wb_reg.valid), + .wr_addr_i(wb_reg.regfile_wr_addr), + .wr_data_i(wb_regfile_wr_data), + .wr_en_i(wb_reg.regfile_we && wb_reg.valid), .rd_data1_o(next_ex_reg.regfile_out1), .rd_data2_o(next_ex_reg.regfile_out2) ); @@ -99,9 +83,9 @@ module datapath( .clk_i(clk_i), .reset_i(reset_i), .rd_addr_i(id_reg.instr.itype.imm), - .wr_addr_i(wb_reg.instr.itype.imm), + .wr_addr_i(wb_reg.csr_wr_addr), .wr_data_i(wb_reg.alu_out), - .wr_en_i(wb_reg.csr_we & wb_reg.valid), + .wr_en_i(wb_reg.csr_we && wb_reg.valid), .rd_data_o(next_ex_reg.csr_out) ); @@ -110,6 +94,26 @@ module datapath( .imm_o(next_ex_reg.imm) ); + assign next_ex_reg.pc = id_reg.pc; + assign next_ex_reg.regfile_wr_addr = id_reg.instr.common.rd; + assign next_ex_reg.csr_wr_addr = id_reg.instr.itype.imm; + assign next_ex_reg.regfile_we = control.decode_out.regfile_we; + assign next_ex_reg.csr_we = control.decode_out.csr_we; + assign next_ex_reg.alu_op = control.decode_out.alu_op; + assign next_ex_reg.alu_in1_sel = control.decode_out.alu_in1_sel; + assign next_ex_reg.alu_in2_sel = control.decode_out.alu_in2_sel; + assign next_ex_reg.compare_unit_op = control.decode_out.compare_unit_op; + assign next_ex_reg.regfile_wr_sel = control.decode_out.regfile_wr_sel; + assign next_ex_reg.dmem_rd_size = control.decode_out.dmem_rd_size; + assign next_ex_reg.dmem_wr_size = control.decode_out.dmem_wr_size; + assign next_ex_reg.dmem_wr_enable = control.decode_out.dmem_wr_enable; + assign next_ex_reg.dmem_rd_signed = control.decode_out.dmem_rd_signed; + assign next_ex_reg.is_branch = control.decode_out.is_branch; + assign next_ex_reg.is_jump = control.decode_out.is_jump; + assign next_ex_reg.is_ecall = control.decode_out.is_ecall; + assign next_ex_reg.valid = control.ex_reg_valid; + + /* EX stage */ always_ff @(posedge clk_i) begin if (reset_i) ex_reg <= 'b0; @@ -117,50 +121,61 @@ module datapath( ex_reg <= next_ex_reg; end - /* EX stage */ - assign next_mem_reg.pc = ex_reg.pc; - assign next_mem_reg.instr = ex_reg.instr; - assign next_mem_reg.regfile_out2 = ex_reg.regfile_out2; - assign next_mem_reg.csr_out = ex_reg.csr_out; - assign next_mem_reg.regfile_rd = ex_reg.regfile_rd; - assign next_mem_reg.regfile_we = ex_reg.regfile_we; - assign next_mem_reg.csr_we = ex_reg.csr_we; - assign next_mem_reg.valid = ex_ctrl.mem_reg_valid; + logic [31:0] ex_alu_in1; + logic [31:0] ex_alu_in2; always_comb begin - priority case (ex_ctrl.alu_in1_sel) + priority case (ex_reg.alu_in1_sel) ALU_IN1_SEL_REGFILE_OUT1: - alu_in1 = ex_reg.regfile_out1; - ALU_IN1_SEL_PC: - alu_in1 = ex_reg.pc; - ALU_IN1_SEL_CSR_OUT: - alu_in1 = ex_reg.csr_out; + ex_alu_in1 = ex_reg.regfile_out1; + ALU_IN1_SEL_IMM: + ex_alu_in1 = ex_reg.imm; endcase - priority case (ex_ctrl.alu_in2_sel) + priority case (ex_reg.alu_in2_sel) ALU_IN2_SEL_REGFILE_OUT2: - alu_in2 = ex_reg.regfile_out2; + ex_alu_in2 = ex_reg.regfile_out2; ALU_IN2_SEL_IMM: - alu_in2 = ex_reg.imm; + ex_alu_in2 = ex_reg.imm; + ALU_IN2_SEL_PC: + ex_alu_in2 = ex_reg.pc; ALU_IN2_SEL_CSR_OUT: - alu_in2 = ex_reg.csr_out; + ex_alu_in2 = ex_reg.csr_out; endcase end alu alu( .alu_op_i(ex_reg.alu_op), - .in1_i(alu_in1), - .in2_i(alu_in2), + .in1_i(ex_alu_in1), + .in2_i(ex_alu_in2), .out_o(next_mem_reg.alu_out) ); compare_unit cmp_unit( - .compare_unit_op_i(ex_ctrl.compare_unit_op), + .compare_unit_op_i(ex_reg.compare_unit_op), .in1_i(ex_reg.regfile_out1), .in2_i(ex_reg.regfile_out2), .res_o(next_mem_reg.cmp_unit_res) ); + assign next_mem_reg.pc = ex_reg.pc; + assign next_mem_reg.regfile_out2 = ex_reg.regfile_out2; + assign next_mem_reg.csr_out = ex_reg.csr_out; + assign next_mem_reg.regfile_wr_addr = ex_reg.regfile_wr_addr; + assign next_mem_reg.csr_wr_addr = ex_reg.csr_wr_addr; + assign next_mem_reg.regfile_we = ex_reg.regfile_we; + assign next_mem_reg.csr_we = ex_reg.csr_we; + assign next_mem_reg.regfile_wr_sel = ex_reg.regfile_wr_sel; + assign next_mem_reg.dmem_rd_size = ex_reg.dmem_rd_size; + assign next_mem_reg.dmem_wr_size = ex_reg.dmem_wr_size; + assign next_mem_reg.dmem_wr_enable = ex_reg.dmem_wr_enable; + assign next_mem_reg.dmem_rd_signed = ex_reg.dmem_rd_signed; + assign next_mem_reg.is_branch = ex_reg.is_branch; + assign next_mem_reg.is_jump = ex_reg.is_jump; + assign next_mem_reg.is_ecall = ex_reg.is_ecall; + assign next_mem_reg.valid = control.mem_reg_valid; + + /* MEM stage */ always_ff @(posedge clk_i) begin if (reset_i) mem_reg <= 'b0; @@ -168,24 +183,43 @@ module datapath( mem_reg <= next_mem_reg; end - /* MEM stage */ assign dmemif.rd_addr = mem_reg.alu_out; - assign dmemif.rd_size = mem_ctrl.dmem_rd_size; + assign dmemif.rd_size = mem_reg.dmem_rd_size; assign dmemif.wr_addr = mem_reg.alu_out; assign dmemif.wr_data = mem_reg.regfile_out2; - assign dmemif.wr_size = mem_ctrl.dmem_wr_size; - assign dmemif.wr_enable = mem_ctrl.dmem_wr_enable; + assign dmemif.wr_size = mem_reg.dmem_wr_size; + assign dmemif.wr_enable = mem_reg.dmem_wr_enable && mem_reg.valid; + + logic [31:0] mem_dmem_rd_data_sext; + + always_comb begin + if (mem_reg.dmem_rd_signed) begin + priority case (mem_reg.dmem_rd_size) + MEM_ACCESS_SIZE_WORD: + mem_dmem_rd_data_sext = dmemif.rd_data; + MEM_ACCESS_SIZE_HALF: + mem_dmem_rd_data_sext = {{16{dmemif.rd_data[15]}}, dmemif.rd_data[15:0]}; + MEM_ACCESS_SIZE_BYTE: + mem_dmem_rd_data_sext = {{24{dmemif.rd_data[7]}}, dmemif.rd_data[7:0]}; + endcase + end else begin + mem_dmem_rd_data_sext = dmemif.rd_data; + end + end assign next_wb_reg.pc = mem_reg.pc; - assign next_wb_reg.instr = mem_reg.instr; assign next_wb_reg.csr_out = mem_reg.csr_out; - assign next_wb_reg.alu_out = mem_reg.alu_out; - assign next_wb_reg.dmem_rd_data = dmemif.rd_data; - assign next_wb_reg.regfile_rd = mem_reg.regfile_rd; + assign next_wb_reg.regfile_wr_addr = mem_reg.regfile_wr_addr; + assign next_wb_reg.csr_wr_addr = mem_reg.csr_wr_addr; assign next_wb_reg.regfile_we = mem_reg.regfile_we; assign next_wb_reg.csr_we = mem_reg.csr_we; + assign next_wb_reg.alu_out = mem_reg.alu_out; + assign next_wb_reg.regfile_wr_sel = mem_reg.regfile_wr_sel; + assign next_wb_reg.dmem_rd_data = mem_dmem_rd_data_sext; + assign next_wb_reg.is_ecall = mem_reg.is_ecall; assign next_wb_reg.valid = mem_reg.valid; + /* WB stage */ always_ff @(posedge clk_i) begin if (reset_i) wb_reg <= 'b0; @@ -193,21 +227,16 @@ module datapath( wb_reg <= next_wb_reg; end - /* WB stage */ always_comb begin - priority case (wb_ctrl.regfile_in_sel) - REGFILE_IN_SEL_ALU_OUT: - regfile_wr_data = wb_reg.alu_out; - REGFILE_IN_SEL_PC_4: - regfile_wr_data = wb_reg.pc + 4; - REGFILE_IN_SEL_MEM_RD: - regfile_wr_data = wb_reg.dmem_rd_data; - REGFILE_IN_SEL_MEM_RD_SEXT8: - regfile_wr_data = {{24{wb_reg.dmem_rd_data[7]}}, wb_reg.dmem_rd_data[7:0]}; - REGFILE_IN_SEL_MEM_RD_SEXT16: - regfile_wr_data = {{16{wb_reg.dmem_rd_data[15]}}, wb_reg.dmem_rd_data[15:0]}; - REGFILE_IN_SEL_CSR_OUT: - regfile_wr_data = wb_reg.csr_out; + priority case (wb_reg.regfile_wr_sel) + REGFILE_WR_SEL_ALU_OUT: + wb_regfile_wr_data = wb_reg.alu_out; + REGFILE_WR_SEL_PC_4: + wb_regfile_wr_data = wb_reg.pc + 4; + REGFILE_WR_SEL_DMEM_RD_DATA: + wb_regfile_wr_data = wb_reg.dmem_rd_data; + REGFILE_WR_SEL_CSR_OUT: + wb_regfile_wr_data = wb_reg.csr_out; endcase end endmodule diff --git a/decode.sv b/decode.sv index 4859fc0..e03dc5d 100644 --- a/decode.sv +++ b/decode.sv @@ -2,111 +2,219 @@ import definitions::*; module decode( input instruction_t instr_i, - output logic regfile_we_o, - output logic csr_we_o, - output alu_op_t alu_op_o + output decode_out_t decode_o ); always_comb begin - regfile_we_o = 0; + decode_o.regfile_we = 0; + decode_o.csr_we = 0; + decode_o.dmem_wr_enable = 0; + decode_o.dmem_rd_signed = 0; + decode_o.is_branch = 0; + decode_o.is_jump = 0; + decode_o.is_ecall = 0; + priority case (instr_i.common.opcode) - OPCODE_LUI, OPCODE_AUIPC, OPCODE_JAL, OPCODE_JALR, - OPCODE_LOAD, OPCODE_OP_IMM, OPCODE_OP: begin - regfile_we_o = 1; + OPCODE_LUI: begin + decode_o.regfile_we = 1; + decode_o.regfile_wr_sel = REGFILE_WR_SEL_ALU_OUT; + decode_o.alu_op = ALU_OP_IN1_PASSTHROUGH; + decode_o.alu_in1_sel = ALU_IN1_SEL_IMM; end - OPCODE_SYSTEM: begin - priority case (instr_i.itype.funct3) - FUNCT3_SYSTEM_CSRRW, FUNCT3_SYSTEM_CSRRS, - FUNCT3_SYSTEM_CSRRC, FUNCT3_SYSTEM_CSRRWI, - FUNCT3_SYSTEM_CSRRSI, FUNCT3_SYSTEM_CSRRCI: begin - regfile_we_o = 1; - end + OPCODE_AUIPC: begin + decode_o.regfile_we = 1; + decode_o.regfile_wr_sel = REGFILE_WR_SEL_ALU_OUT; + decode_o.alu_op = ALU_OP_ADD; + decode_o.alu_in1_sel = ALU_IN1_SEL_IMM; + decode_o.alu_in2_sel = ALU_IN2_SEL_PC; + end + OPCODE_JAL: begin + decode_o.regfile_we = 1; + decode_o.regfile_wr_sel = REGFILE_WR_SEL_PC_4; + decode_o.alu_op = ALU_OP_ADD; + decode_o.alu_in1_sel = ALU_IN1_SEL_IMM; + decode_o.alu_in2_sel = ALU_IN2_SEL_PC; + decode_o.is_jump = 1; + end + OPCODE_JALR: begin + decode_o.regfile_we = 1; + decode_o.regfile_wr_sel = REGFILE_WR_SEL_PC_4; + decode_o.alu_op = ALU_OP_ADD; + decode_o.alu_in1_sel = ALU_IN1_SEL_REGFILE_OUT1; + decode_o.alu_in2_sel = ALU_IN2_SEL_IMM; + decode_o.is_jump = 1; + end + OPCODE_BRANCH: begin + decode_o.alu_op = ALU_OP_ADD; + decode_o.alu_in1_sel = ALU_IN1_SEL_IMM; + decode_o.alu_in2_sel = ALU_IN2_SEL_PC; + decode_o.is_branch = 1; + + priority case (instr_i.btype.funct3) + FUNCT3_BRANCH_BEQ: + decode_o.compare_unit_op = COMPARE_UNIT_OP_EQ; + FUNCT3_BRANCH_BNE: + decode_o.compare_unit_op = COMPARE_UNIT_OP_NE; + FUNCT3_BRANCH_BLT: + decode_o.compare_unit_op = COMPARE_UNIT_OP_LT; + FUNCT3_BRANCH_BGE: + decode_o.compare_unit_op = COMPARE_UNIT_OP_GE; + FUNCT3_BRANCH_BLTU: + decode_o.compare_unit_op = COMPARE_UNIT_OP_LTU; + FUNCT3_BRANCH_BGEU: + decode_o.compare_unit_op = COMPARE_UNIT_OP_GEU; endcase end - endcase - end + OPCODE_LOAD: begin + decode_o.regfile_we = 1; + decode_o.regfile_wr_sel = REGFILE_WR_SEL_DMEM_RD_DATA; + decode_o.alu_op = ALU_OP_ADD; + decode_o.alu_in1_sel = ALU_IN1_SEL_REGFILE_OUT1; + decode_o.alu_in2_sel = ALU_IN2_SEL_IMM; - always_comb begin - csr_we_o = 0; - priority case (instr_i.common.opcode) - OPCODE_SYSTEM: begin priority case (instr_i.itype.funct3) - FUNCT3_SYSTEM_CSRRW, FUNCT3_SYSTEM_CSRRS, - FUNCT3_SYSTEM_CSRRC, FUNCT3_SYSTEM_CSRRWI, - FUNCT3_SYSTEM_CSRRSI, FUNCT3_SYSTEM_CSRRCI: begin - csr_we_o = 1; - end + FUNCT3_LOAD_LB, FUNCT3_LOAD_LBU: + decode_o.dmem_rd_size = MEM_ACCESS_SIZE_BYTE; + FUNCT3_LOAD_LH, FUNCT3_LOAD_LHU: + decode_o.dmem_rd_size = MEM_ACCESS_SIZE_HALF; + FUNCT3_LOAD_LW: + decode_o.dmem_rd_size = MEM_ACCESS_SIZE_WORD; + endcase + + priority case (instr_i.itype.funct3) + FUNCT3_LOAD_LB, FUNCT3_LOAD_LH, FUNCT3_LOAD_LW: + decode_o.dmem_rd_signed = 1; endcase end - endcase - end + OPCODE_STORE: begin + decode_o.dmem_wr_enable = 1; + decode_o.alu_op = ALU_OP_ADD; + decode_o.alu_in1_sel = ALU_IN1_SEL_REGFILE_OUT1; + decode_o.alu_in2_sel = ALU_IN2_SEL_IMM; - always_comb begin - priority case (instr_i.common.opcode) - OPCODE_LUI: - alu_op_o = ALU_OP_IN2_PASSTHROUGH; - OPCODE_AUIPC, OPCODE_JAL, OPCODE_JALR, OPCODE_BRANCH, - OPCODE_LOAD, OPCODE_STORE: - alu_op_o = ALU_OP_ADD; + priority case (instr_i.itype.funct3) + FUNCT3_STORE_SB: + decode_o.dmem_wr_size = MEM_ACCESS_SIZE_BYTE; + FUNCT3_STORE_SH: + decode_o.dmem_wr_size = MEM_ACCESS_SIZE_HALF; + FUNCT3_STORE_SW: + decode_o.dmem_wr_size = MEM_ACCESS_SIZE_WORD; + endcase + end OPCODE_OP_IMM: begin + decode_o.regfile_we = 1; + decode_o.regfile_wr_sel = REGFILE_WR_SEL_ALU_OUT; + decode_o.alu_in1_sel = ALU_IN1_SEL_REGFILE_OUT1; + decode_o.alu_in2_sel = ALU_IN2_SEL_IMM; + priority case (instr_i.itype.funct3) FUNCT3_OP_IMM_ADDI: - alu_op_o = ALU_OP_ADD; + decode_o.alu_op = ALU_OP_ADD; FUNCT3_OP_IMM_SLTI: - alu_op_o = ALU_OP_SLT; + decode_o.alu_op = ALU_OP_SLT; FUNCT3_OP_IMM_SLTIU: - alu_op_o = ALU_OP_SLTU; + decode_o.alu_op = ALU_OP_SLTU; FUNCT3_OP_IMM_XORI: - alu_op_o = ALU_OP_XOR; + decode_o.alu_op = ALU_OP_XOR; FUNCT3_OP_IMM_ORI: - alu_op_o = ALU_OP_OR; + decode_o.alu_op = ALU_OP_OR; FUNCT3_OP_IMM_ANDI: - alu_op_o = ALU_OP_AND; + decode_o.alu_op = ALU_OP_AND; FUNCT3_OP_IMM_SLLI: - alu_op_o = ALU_OP_SLL; + decode_o.alu_op = ALU_OP_SLL; FUNCT3_OP_IMM_SRI: - if (instr_i.itype.imm[10] == 0) - alu_op_o = ALU_OP_SRL; + if (instr_i.itype.imm[10]) + decode_o.alu_op = ALU_OP_SRA; else - alu_op_o = ALU_OP_SRA; + decode_o.alu_op = ALU_OP_SRL; endcase end OPCODE_OP: begin + decode_o.regfile_we = 1; + decode_o.regfile_wr_sel = REGFILE_WR_SEL_ALU_OUT; + decode_o.alu_in1_sel = ALU_IN1_SEL_REGFILE_OUT1; + decode_o.alu_in2_sel = ALU_IN2_SEL_REGFILE_OUT2; + priority case (instr_i.rtype.funct3) FUNCT3_OP_ADD_SUB: begin - if (instr_i.rtype.funct7[5] == 0) - alu_op_o = ALU_OP_ADD; + if (instr_i.rtype.funct7[5]) + decode_o.alu_op = ALU_OP_SUB; else - alu_op_o = ALU_OP_SUB; + decode_o.alu_op = ALU_OP_ADD; end FUNCT3_OP_SLL: - alu_op_o = ALU_OP_SLL; + decode_o.alu_op = ALU_OP_SLL; FUNCT3_OP_SLT: - alu_op_o = ALU_OP_SLT; + decode_o.alu_op = ALU_OP_SLT; FUNCT3_OP_SLTU: - alu_op_o = ALU_OP_SLTU; + decode_o.alu_op = ALU_OP_SLTU; FUNCT3_OP_XOR: - alu_op_o = ALU_OP_XOR; + decode_o.alu_op = ALU_OP_XOR; FUNCT3_OP_SR: - if (instr_i.rtype.funct7[5] == 0) - alu_op_o = ALU_OP_SRL; + if (instr_i.rtype.funct7[5]) + decode_o.alu_op = ALU_OP_SRA; else - alu_op_o = ALU_OP_SRA; + decode_o.alu_op = ALU_OP_SRL; FUNCT3_OP_OR: - alu_op_o = ALU_OP_OR; + decode_o.alu_op = ALU_OP_OR; FUNCT3_OP_AND: - alu_op_o = ALU_OP_AND; + decode_o.alu_op = ALU_OP_AND; + endcase + end + OPCODE_MISC_MEM: begin + priority case (instr_i.itype.funct3) + FUNCT3_MISC_MEM_FENCE: + ; /* TODO */ + FUNCT3_MISC_MEM_FENCE_I: + ; /* TODO */ endcase end OPCODE_SYSTEM: begin + decode_o.regfile_we = 1; + decode_o.csr_we = 1; + decode_o.regfile_wr_sel = REGFILE_WR_SEL_CSR_OUT; + priority case (instr_i.itype.funct3) - FUNCT3_SYSTEM_CSRRW: - alu_op_o = ALU_OP_IN1_PASSTHROUGH; - FUNCT3_SYSTEM_CSRRS, FUNCT3_SYSTEM_CSRRSI: - alu_op_o = ALU_OP_OR; - FUNCT3_SYSTEM_CSRRC, FUNCT3_SYSTEM_CSRRCI: - alu_op_o = ALU_OP_XOR; - FUNCT3_SYSTEM_CSRRWI: - alu_op_o = ALU_OP_IN2_PASSTHROUGH; + FUNCT3_SYSTEM_PRIV: begin + decode_o.regfile_we = 0; + decode_o.csr_we = 0; + + priority case (instr_i.itype.imm) + FUNCT12_SYSTEM_PRIV_ECALL: + /* TODO */ + decode_o.is_ecall = 1; + FUNCT12_SYSTEM_PRIV_EBREAK: + /* TODO */ + ; + endcase + end + FUNCT3_SYSTEM_CSRRW: begin + decode_o.alu_in1_sel = ALU_IN1_SEL_REGFILE_OUT1; + decode_o.alu_op = ALU_OP_IN1_PASSTHROUGH; + end + FUNCT3_SYSTEM_CSRRS: begin + decode_o.alu_in1_sel = ALU_IN1_SEL_REGFILE_OUT1; + decode_o.alu_in2_sel = ALU_IN2_SEL_CSR_OUT; + decode_o.alu_op = ALU_OP_OR; + end + FUNCT3_SYSTEM_CSRRC: begin + decode_o.alu_in1_sel = ALU_IN1_SEL_REGFILE_OUT1; + decode_o.alu_in2_sel = ALU_IN2_SEL_CSR_OUT; + decode_o.alu_op = ALU_OP_XOR; + end + FUNCT3_SYSTEM_CSRRWI: begin + decode_o.alu_in1_sel = ALU_IN1_SEL_IMM; + decode_o.alu_op = ALU_OP_IN1_PASSTHROUGH; + end + FUNCT3_SYSTEM_CSRRSI: begin + decode_o.alu_in1_sel = ALU_IN1_SEL_IMM; + decode_o.alu_in2_sel = ALU_IN2_SEL_CSR_OUT; + decode_o.alu_op = ALU_OP_OR; + end + FUNCT3_SYSTEM_CSRRCI: begin + decode_o.alu_in1_sel = ALU_IN1_SEL_IMM; + decode_o.alu_in2_sel = ALU_IN2_SEL_CSR_OUT; + decode_o.alu_op = ALU_OP_XOR; + end endcase end endcase diff --git a/definitions.sv b/definitions.sv index 5278b5d..195e24d 100644 --- a/definitions.sv +++ b/definitions.sv @@ -162,37 +162,8 @@ typedef enum logic [11:0] { /* tiny5 definitions */ -/* Multiplexer select */ - -typedef enum logic { - NEXT_PC_SEL_PC_4, - NEXT_PC_SEL_ALU_OUT -} next_pc_sel_t; - -typedef enum logic [2:0] { - REGFILE_IN_SEL_ALU_OUT, - REGFILE_IN_SEL_PC_4, - REGFILE_IN_SEL_MEM_RD, - REGFILE_IN_SEL_MEM_RD_SEXT8, - REGFILE_IN_SEL_MEM_RD_SEXT16, - REGFILE_IN_SEL_CSR_OUT -} regfile_in_sel_t; - -typedef enum logic [1:0] { - ALU_IN1_SEL_REGFILE_OUT1, - ALU_IN1_SEL_PC, - ALU_IN1_SEL_CSR_OUT -} alu_in1_sel_t; - -typedef enum logic [1:0] { - ALU_IN2_SEL_REGFILE_OUT2, - ALU_IN2_SEL_IMM, - ALU_IN2_SEL_CSR_OUT -} alu_in2_sel_t; - typedef enum logic [3:0] { ALU_OP_IN1_PASSTHROUGH, - ALU_OP_IN2_PASSTHROUGH, ALU_OP_ADD, ALU_OP_SUB, ALU_OP_SLL, @@ -220,6 +191,32 @@ typedef enum logic [1:0] { MEM_ACCESS_SIZE_WORD } mem_access_size_t; +/* Multiplexer select */ + +typedef enum logic { + NEXT_PC_SEL_PC_4, + NEXT_PC_SEL_ALU_OUT +} next_pc_sel_t; + +typedef enum logic [1:0] { + REGFILE_WR_SEL_ALU_OUT, + REGFILE_WR_SEL_DMEM_RD_DATA, + REGFILE_WR_SEL_PC_4, + REGFILE_WR_SEL_CSR_OUT +} regfile_wr_sel_t; + +typedef enum logic { + ALU_IN1_SEL_REGFILE_OUT1, + ALU_IN1_SEL_IMM +} alu_in1_sel_t; + +typedef enum logic [1:0] { + ALU_IN2_SEL_REGFILE_OUT2, + ALU_IN2_SEL_IMM, + ALU_IN2_SEL_PC, + ALU_IN2_SEL_CSR_OUT +} alu_in2_sel_t; + /* Pipeline stage registers (IF - ID - EX - MEM - WB) */ typedef struct packed { @@ -230,76 +227,95 @@ typedef struct packed { typedef struct packed { logic [31:0] pc; - instruction_t instr; logic [31:0] imm; logic [31:0] regfile_out1; logic [31:0] regfile_out2; logic [31:0] csr_out; - logic [4:0] regfile_rd; + logic [4:0] regfile_wr_addr; + logic [11:0] csr_wr_addr; logic regfile_we; logic csr_we; alu_op_t alu_op; + alu_in1_sel_t alu_in1_sel; + alu_in2_sel_t alu_in2_sel; + compare_unit_op_t compare_unit_op; + regfile_wr_sel_t regfile_wr_sel; + mem_access_size_t dmem_rd_size; + mem_access_size_t dmem_wr_size; + logic dmem_wr_enable; + logic dmem_rd_signed; + logic is_branch; + logic is_jump; + logic is_ecall; logic valid; } pipeline_ex_reg_t; typedef struct packed { logic [31:0] pc; - instruction_t instr; logic [31:0] regfile_out2; logic [31:0] csr_out; - logic [31:0] alu_out; - logic cmp_unit_res; - logic [4:0] regfile_rd; + logic [4:0] regfile_wr_addr; + logic [11:0] csr_wr_addr; logic regfile_we; logic csr_we; + logic [31:0] alu_out; + logic cmp_unit_res; + regfile_wr_sel_t regfile_wr_sel; + mem_access_size_t dmem_rd_size; + mem_access_size_t dmem_wr_size; + logic dmem_wr_enable; + logic dmem_rd_signed; + logic is_branch; + logic is_jump; + logic is_ecall; logic valid; } pipeline_mem_reg_t; typedef struct packed { logic [31:0] pc; - instruction_t instr; logic [31:0] csr_out; - logic [31:0] alu_out; - logic [31:0] dmem_rd_data; - logic [4:0] regfile_rd; + logic [4:0] regfile_wr_addr; + logic [11:0] csr_wr_addr; logic regfile_we; logic csr_we; + logic [31:0] alu_out; + regfile_wr_sel_t regfile_wr_sel; + logic [31:0] dmem_rd_data; + logic is_ecall; logic valid; } pipeline_wb_reg_t; -/* Pipeline per-stage control signals */ - -typedef struct packed { - logic pc_we; - next_pc_sel_t next_pc_sel; - logic pc_reg_stall; - logic id_reg_stall; - logic id_reg_valid; -} pipeline_if_ctrl_t; +/* Pipeline decode and control signals */ typedef struct packed { - logic ex_reg_valid; logic regfile_we; logic csr_we; alu_op_t alu_op; -} pipeline_id_ctrl_t; - -typedef struct packed { alu_in1_sel_t alu_in1_sel; alu_in2_sel_t alu_in2_sel; compare_unit_op_t compare_unit_op; - logic mem_reg_valid; -} pipeline_ex_ctrl_t; - -typedef struct packed { + regfile_wr_sel_t regfile_wr_sel; mem_access_size_t dmem_rd_size; mem_access_size_t dmem_wr_size; logic dmem_wr_enable; -} pipeline_mem_ctrl_t; + logic dmem_rd_signed; + logic is_branch; + logic is_jump; + logic is_ecall; +} decode_out_t; typedef struct packed { - regfile_in_sel_t regfile_in_sel; -} pipeline_wb_ctrl_t; + /* IF stage */ + next_pc_sel_t next_pc_sel; + logic pc_reg_stall; + logic id_reg_stall; + logic id_reg_valid; + /* ID stage */ + decode_out_t decode_out; + logic ex_reg_valid; + /* EX stage */ + logic mem_reg_valid; +} pipeline_control_t; /* Helper functions */ diff --git a/tb/modelsim.do b/tb/modelsim.do index 616530c..2c5443c 100644 --- a/tb/modelsim.do +++ b/tb/modelsim.do @@ -4,8 +4,8 @@ force -freeze sim:/top_simple_mem/reset_i 1 0, 0 {100 ps} -freeze add wave -radix 16 sim:/top_simple_mem/reset_i add wave -radix 16 sim:/top_simple_mem/clk_i add wave -radix 16 sim:/top_simple_mem/dp/pc -add wave -radix 16 sim:/top_simple_mem/dp/if_id_reg -add wave -radix 16 sim:/top_simple_mem/dp/id_ex_reg -add wave -radix 16 sim:/top_simple_mem/dp/ex_mem_reg -add wave -radix 16 sim:/top_simple_mem/dp/mem_wb_reg +add wave -radix 16 sim:/top_simple_mem/dp/id_reg +add wave -radix 16 sim:/top_simple_mem/dp/ex_reg +add wave -radix 16 sim:/top_simple_mem/dp/mem_reg +add wave -radix 16 sim:/top_simple_mem/dp/wb_reg add wave -radix 16 sim:/top_simple_mem/dp/regfile/registers