From 0013935bb0b3271030e756c6d24532265c496a0e Mon Sep 17 00:00:00 2001 From: Graham Edgecombe Date: Wed, 27 Dec 2017 14:05:09 +0000 Subject: [PATCH] Split decode stage into smaller modules This increases the number of LUTs slightly (by ~20), as the immediate mux is now separate to the main control unit, but I think it's worth the cost. The imm output is also renamed to imm_value. This is consistent with rs1_value and rs2_value, and avoids a collision with the new imm output, which represents the type of immediate. --- Makefile | 2 +- rv32.sv | 6 +- rv32_alu.sv | 4 +- rv32_branch.sv | 4 +- rv32_control.sv | 439 +++++++++++++++++++++++++++++++++++++++++ rv32_decode.sv | 509 +++++++----------------------------------------- rv32_execute.sv | 6 +- rv32_imm.sv | 58 ++++++ 8 files changed, 575 insertions(+), 453 deletions(-) create mode 100644 rv32_control.sv create mode 100644 rv32_imm.sv diff --git a/Makefile b/Makefile index 60bf38d..3b6c897 100644 --- a/Makefile +++ b/Makefile @@ -16,7 +16,7 @@ DEVICE = 8k PACKAGE = ct256 PCF = ice40hx8k-b-evn.pcf FREQ_OSC = 12 -FREQ_PLL = 36 +FREQ_PLL = 32 TARGET = riscv64-unknown-elf AS = $(TARGET)-as ASFLAGS = -march=rv32i -mabi=ilp32 diff --git a/rv32.sv b/rv32.sv index 41b74f8..1085d1d 100644 --- a/rv32.sv +++ b/rv32.sv @@ -70,7 +70,7 @@ module rv32 ( logic [31:0] decode_pc; logic [31:0] decode_rs1_value; logic [31:0] decode_rs2_value; - logic [31:0] decode_imm; + logic [31:0] decode_imm_value; /* execute -> mem control */ logic execute_mem_read; @@ -201,7 +201,7 @@ module rv32 ( .pc_out(decode_pc), .rs1_value_out(decode_rs1_value), .rs2_value_out(decode_rs2_value), - .imm_out(decode_imm) + .imm_value_out(decode_imm_value) ); rv32_execute execute ( @@ -235,7 +235,7 @@ module rv32 ( .pc_in(decode_pc), .rs1_value_in(decode_rs1_value), .rs2_value_in(decode_rs2_value), - .imm_in(decode_imm), + .imm_value_in(decode_imm_value), /* data in (from writeback) */ .writeback_rd_value_in(mem_rd_value), diff --git a/rv32_alu.sv b/rv32_alu.sv index 7841215..a5c7936 100644 --- a/rv32_alu.sv +++ b/rv32_alu.sv @@ -29,7 +29,7 @@ module rv32_alu ( input [31:0] pc_in, input [31:0] rs1_value_in, input [31:0] rs2_value_in, - input [31:0] imm_in, + input [31:0] imm_value_in, /* data out */ output logic [31:0] result_out @@ -62,7 +62,7 @@ module rv32_alu ( case (src2_in) `RV32_ALU_SRC2_REG: src2 = rs2_value_in; - `RV32_ALU_SRC2_IMM: src2 = imm_in; + `RV32_ALU_SRC2_IMM: src2 = imm_value_in; `RV32_ALU_SRC2_FOUR: src2 = 4; default: src2 = 32'bx; endcase diff --git a/rv32_branch.sv b/rv32_branch.sv index bf84e07..a68bd03 100644 --- a/rv32_branch.sv +++ b/rv32_branch.sv @@ -16,14 +16,14 @@ module rv32_branch_pc_mux ( /* data in */ input [31:0] pc_in, input [31:0] rs1_value_in, - input [31:0] imm_in, + input [31:0] imm_value_in, /* data out */ output logic [31:0] pc_out ); logic [31:0] pc; - assign pc = (pc_src_in ? rs1_value_in : pc_in) + imm_in; + assign pc = (pc_src_in ? rs1_value_in : pc_in) + imm_value_in; assign pc_out = {pc[31:1], 1'b0}; endmodule diff --git a/rv32_control.sv b/rv32_control.sv new file mode 100644 index 0000000..3eb3aec --- /dev/null +++ b/rv32_control.sv @@ -0,0 +1,439 @@ +`ifndef RV32_CONTROL +`define RV32_CONTROL + +`include "rv32_alu.sv" +`include "rv32_branch.sv" +`include "rv32_imm.sv" +`include "rv32_mem.sv" +`include "rv32_opcodes.sv" + +module rv32_control_unit ( + /* data in */ + input [31:0] instr_in, + + /* control out */ + output logic valid_out, + output logic [2:0] imm_out, + output logic [2:0] alu_op_out, + output logic alu_sub_sra_out, + output logic [1:0] alu_src1_out, + output logic [1:0] alu_src2_out, + output logic mem_read_out, + output logic mem_write_out, + output logic [1:0] mem_width_out, + output logic mem_zero_extend_out, + output logic mem_fence_out, + output logic [1:0] branch_op_out, + output logic branch_pc_src_out, + output logic rd_write_out +); + always_comb begin + valid_out = 0; + imm_out = 3'bx; + alu_op_out = 3'bx; + alu_sub_sra_out = 1'bx; + alu_src1_out = 2'bx; + alu_src2_out = 2'bx; + mem_read_out = 0; + mem_write_out = 0; + mem_width_out = 2'bx; + mem_zero_extend_out = 1'bx; + mem_fence_out = 0; + branch_op_out = `RV32_BRANCH_OP_NEVER; + branch_pc_src_out = 1'bx; + rd_write_out = 0; + + casez (instr_in) + `RV32_INSTR_LUI: begin + valid_out = 1; + imm_out = `RV32_IMM_U; + alu_op_out = `RV32_ALU_OP_ADD_SUB; + alu_sub_sra_out = 0; + alu_src1_out = `RV32_ALU_SRC1_ZERO; + alu_src2_out = `RV32_ALU_SRC2_IMM; + rd_write_out = 1; + end + `RV32_INSTR_AUIPC: begin + valid_out = 1; + imm_out = `RV32_IMM_U; + alu_op_out = `RV32_ALU_OP_ADD_SUB; + alu_sub_sra_out = 0; + alu_src1_out = `RV32_ALU_SRC1_PC; + alu_src2_out = `RV32_ALU_SRC2_IMM; + rd_write_out = 1; + end + `RV32_INSTR_JAL: begin + valid_out = 1; + imm_out = `RV32_IMM_J; + alu_op_out = `RV32_ALU_OP_ADD_SUB; + alu_sub_sra_out = 0; + alu_src1_out = `RV32_ALU_SRC1_PC; + alu_src2_out = `RV32_ALU_SRC2_FOUR; + branch_op_out = `RV32_BRANCH_OP_ALWAYS; + branch_pc_src_out = `RV32_BRANCH_PC_SRC_IMM; + rd_write_out = 1; + end + `RV32_INSTR_JALR: begin + valid_out = 1; + imm_out = `RV32_IMM_I; + alu_op_out = `RV32_ALU_OP_ADD_SUB; + alu_sub_sra_out = 0; + alu_src1_out = `RV32_ALU_SRC1_PC; + alu_src2_out = `RV32_ALU_SRC2_FOUR; + branch_op_out = `RV32_BRANCH_OP_ALWAYS; + branch_pc_src_out = `RV32_BRANCH_PC_SRC_REG; + rd_write_out = 1; + end + `RV32_INSTR_BEQ: begin + valid_out = 1; + imm_out = `RV32_IMM_B; + alu_op_out = `RV32_ALU_OP_ADD_SUB; + alu_sub_sra_out = 1; + alu_src1_out = `RV32_ALU_SRC1_REG; + alu_src2_out = `RV32_ALU_SRC2_REG; + branch_op_out = `RV32_BRANCH_OP_ZERO; + branch_pc_src_out = `RV32_BRANCH_PC_SRC_IMM; + end + `RV32_INSTR_BNE: begin + valid_out = 1; + imm_out = `RV32_IMM_B; + alu_op_out = `RV32_ALU_OP_ADD_SUB; + alu_sub_sra_out = 1; + alu_src1_out = `RV32_ALU_SRC1_REG; + alu_src2_out = `RV32_ALU_SRC2_REG; + branch_op_out = `RV32_BRANCH_OP_NON_ZERO; + branch_pc_src_out = `RV32_BRANCH_PC_SRC_IMM; + end + `RV32_INSTR_BLT: begin + valid_out = 1; + imm_out = `RV32_IMM_B; + alu_op_out = `RV32_ALU_OP_SLT; + alu_sub_sra_out = 1; + alu_src1_out = `RV32_ALU_SRC1_REG; + alu_src2_out = `RV32_ALU_SRC2_REG; + branch_op_out = `RV32_BRANCH_OP_NON_ZERO; + branch_pc_src_out = `RV32_BRANCH_PC_SRC_IMM; + end + `RV32_INSTR_BGE: begin + valid_out = 1; + imm_out = `RV32_IMM_B; + alu_op_out = `RV32_ALU_OP_SLT; + alu_sub_sra_out = 1; + alu_src1_out = `RV32_ALU_SRC1_REG; + alu_src2_out = `RV32_ALU_SRC2_REG; + branch_op_out = `RV32_BRANCH_OP_ZERO; + branch_pc_src_out = `RV32_BRANCH_PC_SRC_IMM; + end + `RV32_INSTR_BLTU: begin + valid_out = 1; + imm_out = `RV32_IMM_B; + alu_op_out = `RV32_ALU_OP_SLTU; + alu_sub_sra_out = 1; + alu_src1_out = `RV32_ALU_SRC1_REG; + alu_src2_out = `RV32_ALU_SRC2_REG; + branch_op_out = `RV32_BRANCH_OP_NON_ZERO; + branch_pc_src_out = `RV32_BRANCH_PC_SRC_IMM; + end + `RV32_INSTR_BGEU: begin + valid_out = 1; + imm_out = `RV32_IMM_B; + alu_op_out = `RV32_ALU_OP_SLTU; + alu_sub_sra_out = 1; + alu_src1_out = `RV32_ALU_SRC1_REG; + alu_src2_out = `RV32_ALU_SRC2_REG; + branch_op_out = `RV32_BRANCH_OP_ZERO; + branch_pc_src_out = `RV32_BRANCH_PC_SRC_IMM; + end + `RV32_INSTR_LB: begin + valid_out = 1; + imm_out = `RV32_IMM_I; + alu_op_out = `RV32_ALU_OP_ADD_SUB; + alu_sub_sra_out = 0; + alu_src1_out = `RV32_ALU_SRC1_REG; + alu_src2_out = `RV32_ALU_SRC2_IMM; + mem_read_out = 1; + mem_width_out = `RV32_MEM_WIDTH_BYTE; + mem_zero_extend_out = 0; + rd_write_out = 1; + end + `RV32_INSTR_LH: begin + valid_out = 1; + imm_out = `RV32_IMM_I; + alu_op_out = `RV32_ALU_OP_ADD_SUB; + alu_sub_sra_out = 0; + alu_src1_out = `RV32_ALU_SRC1_REG; + alu_src2_out = `RV32_ALU_SRC2_IMM; + mem_read_out = 1; + mem_width_out = `RV32_MEM_WIDTH_HALF; + mem_zero_extend_out = 0; + rd_write_out = 1; + end + `RV32_INSTR_LW: begin + valid_out = 1; + imm_out = `RV32_IMM_I; + alu_op_out = `RV32_ALU_OP_ADD_SUB; + alu_sub_sra_out = 0; + alu_src1_out = `RV32_ALU_SRC1_REG; + alu_src2_out = `RV32_ALU_SRC2_IMM; + mem_read_out = 1; + mem_width_out = `RV32_MEM_WIDTH_WORD; + rd_write_out = 1; + end + `RV32_INSTR_LBU: begin + valid_out = 1; + imm_out = `RV32_IMM_I; + alu_op_out = `RV32_ALU_OP_ADD_SUB; + alu_sub_sra_out = 0; + alu_src1_out = `RV32_ALU_SRC1_REG; + alu_src2_out = `RV32_ALU_SRC2_IMM; + mem_read_out = 1; + mem_width_out = `RV32_MEM_WIDTH_BYTE; + mem_zero_extend_out = 1; + rd_write_out = 1; + end + `RV32_INSTR_LHU: begin + valid_out = 1; + imm_out = `RV32_IMM_I; + alu_op_out = `RV32_ALU_OP_ADD_SUB; + alu_sub_sra_out = 0; + alu_src1_out = `RV32_ALU_SRC1_REG; + alu_src2_out = `RV32_ALU_SRC2_IMM; + mem_read_out = 1; + mem_width_out = `RV32_MEM_WIDTH_HALF; + mem_zero_extend_out = 1; + rd_write_out = 1; + end + `RV32_INSTR_SB: begin + valid_out = 1; + imm_out = `RV32_IMM_S; + alu_op_out = `RV32_ALU_OP_ADD_SUB; + alu_sub_sra_out = 0; + alu_src1_out = `RV32_ALU_SRC1_REG; + alu_src2_out = `RV32_ALU_SRC2_IMM; + mem_write_out = 1; + mem_width_out = `RV32_MEM_WIDTH_BYTE; + end + `RV32_INSTR_SH: begin + valid_out = 1; + imm_out = `RV32_IMM_S; + alu_op_out = `RV32_ALU_OP_ADD_SUB; + alu_sub_sra_out = 0; + alu_src1_out = `RV32_ALU_SRC1_REG; + alu_src2_out = `RV32_ALU_SRC2_IMM; + mem_write_out = 1; + mem_width_out = `RV32_MEM_WIDTH_HALF; + end + `RV32_INSTR_SW: begin + valid_out = 1; + imm_out = `RV32_IMM_S; + alu_op_out = `RV32_ALU_OP_ADD_SUB; + alu_sub_sra_out = 0; + alu_src1_out = `RV32_ALU_SRC1_REG; + alu_src2_out = `RV32_ALU_SRC2_IMM; + mem_write_out = 1; + mem_width_out = `RV32_MEM_WIDTH_WORD; + end + `RV32_INSTR_ADDI: begin + valid_out = 1; + imm_out = `RV32_IMM_I; + alu_op_out = `RV32_ALU_OP_ADD_SUB; + alu_sub_sra_out = 0; + alu_src1_out = `RV32_ALU_SRC1_REG; + alu_src2_out = `RV32_ALU_SRC2_IMM; + rd_write_out = 1; + end + `RV32_INSTR_SLTI: begin + valid_out = 1; + imm_out = `RV32_IMM_I; + alu_op_out = `RV32_ALU_OP_SLT; + alu_sub_sra_out = 1; + alu_src1_out = `RV32_ALU_SRC1_REG; + alu_src2_out = `RV32_ALU_SRC2_IMM; + rd_write_out = 1; + end + `RV32_INSTR_SLTIU: begin + valid_out = 1; + imm_out = `RV32_IMM_I; + alu_op_out = `RV32_ALU_OP_SLTU; + alu_sub_sra_out = 1; + alu_src1_out = `RV32_ALU_SRC1_REG; + alu_src2_out = `RV32_ALU_SRC2_IMM; + rd_write_out = 1; + end + `RV32_INSTR_XORI: begin + valid_out = 1; + imm_out = `RV32_IMM_I; + alu_op_out = `RV32_ALU_OP_XOR; + alu_src1_out = `RV32_ALU_SRC1_REG; + alu_src2_out = `RV32_ALU_SRC2_IMM; + rd_write_out = 1; + end + `RV32_INSTR_ORI: begin + valid_out = 1; + imm_out = `RV32_IMM_I; + alu_op_out = `RV32_ALU_OP_OR; + alu_src1_out = `RV32_ALU_SRC1_REG; + alu_src2_out = `RV32_ALU_SRC2_IMM; + rd_write_out = 1; + end + `RV32_INSTR_ANDI: begin + valid_out = 1; + imm_out = `RV32_IMM_I; + alu_op_out = `RV32_ALU_OP_AND; + alu_src1_out = `RV32_ALU_SRC1_REG; + alu_src2_out = `RV32_ALU_SRC2_IMM; + rd_write_out = 1; + end + `RV32_INSTR_SLLI: begin + valid_out = 1; + imm_out = `RV32_IMM_SHAMT; + alu_op_out = `RV32_ALU_OP_SLL; + alu_src1_out = `RV32_ALU_SRC1_REG; + alu_src2_out = `RV32_ALU_SRC2_IMM; + rd_write_out = 1; + end + `RV32_INSTR_SRLI: begin + valid_out = 1; + imm_out = `RV32_IMM_SHAMT; + alu_op_out = `RV32_ALU_OP_SRL_SRA; + alu_sub_sra_out = 0; + alu_src1_out = `RV32_ALU_SRC1_REG; + alu_src2_out = `RV32_ALU_SRC2_IMM; + rd_write_out = 1; + end + `RV32_INSTR_SRAI: begin + valid_out = 1; + imm_out = `RV32_IMM_SHAMT; + alu_op_out = `RV32_ALU_OP_SRL_SRA; + alu_sub_sra_out = 1; + alu_src1_out = `RV32_ALU_SRC1_REG; + alu_src2_out = `RV32_ALU_SRC2_IMM; + rd_write_out = 1; + end + `RV32_INSTR_ADD: begin + valid_out = 1; + alu_op_out = `RV32_ALU_OP_ADD_SUB; + alu_sub_sra_out = 0; + alu_src1_out = `RV32_ALU_SRC1_REG; + alu_src2_out = `RV32_ALU_SRC2_REG; + rd_write_out = 1; + end + `RV32_INSTR_SUB: begin + valid_out = 1; + alu_op_out = `RV32_ALU_OP_ADD_SUB; + alu_sub_sra_out = 1; + alu_src1_out = `RV32_ALU_SRC1_REG; + alu_src2_out = `RV32_ALU_SRC2_REG; + rd_write_out = 1; + end + `RV32_INSTR_SLL: begin + valid_out = 1; + alu_op_out = `RV32_ALU_OP_SLL; + alu_src1_out = `RV32_ALU_SRC1_REG; + alu_src2_out = `RV32_ALU_SRC2_REG; + rd_write_out = 1; + end + `RV32_INSTR_SLT: begin + valid_out = 1; + alu_op_out = `RV32_ALU_OP_SLT; + alu_sub_sra_out = 1; + alu_src1_out = `RV32_ALU_SRC1_REG; + alu_src2_out = `RV32_ALU_SRC2_REG; + rd_write_out = 1; + end + `RV32_INSTR_SLTU: begin + valid_out = 1; + alu_op_out = `RV32_ALU_OP_SLTU; + alu_sub_sra_out = 1; + alu_src1_out = `RV32_ALU_SRC1_REG; + alu_src2_out = `RV32_ALU_SRC2_REG; + rd_write_out = 1; + end + `RV32_INSTR_XOR: begin + valid_out = 1; + alu_op_out = `RV32_ALU_OP_XOR; + alu_src1_out = `RV32_ALU_SRC1_REG; + alu_src2_out = `RV32_ALU_SRC2_REG; + rd_write_out = 1; + end + `RV32_INSTR_SRL: begin + valid_out = 1; + alu_op_out = `RV32_ALU_OP_SRL_SRA; + alu_sub_sra_out = 0; + alu_src1_out = `RV32_ALU_SRC1_REG; + alu_src2_out = `RV32_ALU_SRC2_REG; + rd_write_out = 1; + end + `RV32_INSTR_SRA: begin + valid_out = 1; + alu_op_out = `RV32_ALU_OP_SRL_SRA; + alu_sub_sra_out = 1; + alu_src1_out = `RV32_ALU_SRC1_REG; + alu_src2_out = `RV32_ALU_SRC2_REG; + rd_write_out = 1; + end + `RV32_INSTR_OR: begin + valid_out = 1; + alu_op_out = `RV32_ALU_OP_OR; + alu_src1_out = `RV32_ALU_SRC1_REG; + alu_src2_out = `RV32_ALU_SRC2_REG; + rd_write_out = 1; + end + `RV32_INSTR_AND: begin + valid_out = 1; + alu_op_out = `RV32_ALU_OP_AND; + alu_src1_out = `RV32_ALU_SRC1_REG; + alu_src2_out = `RV32_ALU_SRC2_REG; + rd_write_out = 1; + end + `RV32_INSTR_FENCE: begin + valid_out = 1; + end + `RV32_INSTR_FENCE_I: begin + valid_out = 1; + mem_fence_out = 1; + end + `RV32_INSTR_ECALL: begin + valid_out = 1; + // TODO + end + `RV32_INSTR_EBREAK: begin + valid_out = 1; + // TODO + end + `RV32_INSTR_MRET: begin + valid_out = 1; + // TODO + end + `RV32_INSTR_WFI: begin + valid_out = 1; + end + `RV32_INSTR_CSRRW: begin + valid_out = 1; + // TODO + end + `RV32_INSTR_CSRRS: begin + valid_out = 1; + // TODO + end + `RV32_INSTR_CSRRC: begin + valid_out = 1; + // TODO + end + `RV32_INSTR_CSRRWI: begin + valid_out = 1; + // TODO + end + `RV32_INSTR_CSRRSI: begin + valid_out = 1; + // TODO + end + `RV32_INSTR_CSRRCI: begin + valid_out = 1; + // TODO + end + endcase + end +endmodule + +`endif diff --git a/rv32_decode.sv b/rv32_decode.sv index adc439c..30612fe 100644 --- a/rv32_decode.sv +++ b/rv32_decode.sv @@ -1,10 +1,7 @@ `ifndef RV32_DECODE `define RV32_DECODE -`include "rv32_alu.sv" -`include "rv32_branch.sv" -`include "rv32_mem.sv" -`include "rv32_opcodes.sv" +`include "rv32_control.sv" `include "rv32_regs.sv" module rv32_decode ( @@ -30,7 +27,6 @@ module rv32_decode ( output logic [4:0] rs2_unreg_out, /* control out */ - output logic valid_out, output logic [4:0] rs1_out, output logic [4:0] rs2_out, output logic [2:0] alu_op_out, @@ -51,43 +47,15 @@ module rv32_decode ( output logic [31:0] pc_out, output logic [31:0] rs1_value_out, output logic [31:0] rs2_value_out, - output logic [31:0] imm_out + output logic [31:0] imm_value_out ); - logic [6:0] funct7; logic [4:0] rs2; logic [4:0] rs1; - logic [2:0] funct3; logic [4:0] rd; - logic [6:0] opcode; - logic sign; - - logic [31:0] imm_i; - logic [31:0] imm_s; - logic [31:0] imm_b; - logic [31:0] imm_u; - logic [31:0] imm_j; - - logic [31:0] shamt; - logic [31:0] zimm; - - assign funct7 = instr_in[31:25]; - assign rs2 = instr_in[24:20]; - assign rs1 = instr_in[19:15]; - assign funct3 = instr_in[14:12]; - assign rd = instr_in[11:7]; - assign opcode = instr_in[6:0]; - - assign sign = instr_in[31]; - - assign imm_i = {{21{sign}}, instr_in[30:25], instr_in[24:21], instr_in[20]}; - assign imm_s = {{21{sign}}, instr_in[30:25], instr_in[11:8], instr_in[7]}; - assign imm_b = {{20{sign}}, instr_in[7], instr_in[30:25], instr_in[11:8], 1'b0}; - assign imm_u = {sign, instr_in[30:20], instr_in[19:12], 12'b0}; - assign imm_j = {{12{sign}}, instr_in[19:12], instr_in[20], instr_in[30:25], instr_in[24:21], 1'b0}; - - assign shamt = {27'bx, rs2}; - assign zimm = {27'b0, rs1}; + assign rs2 = instr_in[24:20]; + assign rs1 = instr_in[19:15]; + assign rd = instr_in[11:7]; assign rs1_unreg_out = rs1; assign rs2_unreg_out = rs2; @@ -110,418 +78,75 @@ module rv32_decode ( .rs2_value_out(rs2_value_out) ); + logic valid; + logic [2:0] imm; + logic [2:0] alu_op; + logic alu_sub_sra; + logic [1:0] alu_src1; + logic [1:0] alu_src2; + logic mem_read; + logic mem_write; + logic [1:0] mem_width; + logic mem_zero_extend; + logic mem_fence; + logic [1:0] branch_op; + logic branch_pc_src; + logic rd_write; + + rv32_control_unit control_unit ( + /* data in */ + .instr_in(instr_in), + + /* control out */ + .valid_out(valid), + .imm_out(imm), + .alu_op_out(alu_op), + .alu_sub_sra_out(alu_sub_sra), + .alu_src1_out(alu_src1), + .alu_src2_out(alu_src2), + .mem_read_out(mem_read), + .mem_write_out(mem_write), + .mem_width_out(mem_width), + .mem_zero_extend_out(mem_zero_extend), + .mem_fence_out(mem_fence), + .branch_op_out(branch_op), + .branch_pc_src_out(branch_pc_src), + .rd_write_out(rd_write) + ); + + logic [31:0] imm_value; + + rv32_imm_mux imm_mux ( + /* control in */ + .imm_in(imm), + + /* data in */ + .instr_in(instr_in), + + /* data out */ + .imm_value_out(imm_value) + ); + always_ff @(posedge clk) begin if (!stall_in) begin - valid_out <= 0; rs1_out <= rs1; rs2_out <= rs2; - alu_op_out <= 3'bx; - alu_sub_sra_out <= 1'bx; - alu_src1_out <= 2'bx; - alu_src2_out <= 2'bx; - mem_read_out <= 0; - mem_write_out <= 0; - mem_width_out <= 2'bx; - mem_zero_extend_out <= 1'bx; - mem_fence_out <= 0; - branch_op_out <= `RV32_BRANCH_OP_NEVER; - branch_pc_src_out <= 1'bx; + alu_op_out <= alu_op; + alu_sub_sra_out <= alu_sub_sra; + alu_src1_out <= alu_src1; + alu_src2_out <= alu_src2; + mem_read_out <= mem_read; + mem_write_out <= mem_write; + mem_width_out <= mem_width; + mem_zero_extend_out <= mem_zero_extend; + mem_fence_out <= mem_fence; + branch_op_out <= branch_op; + branch_pc_src_out <= branch_pc_src; rd_out <= rd; - rd_write_out <= 0; + rd_write_out <= rd_write; pc_out <= pc_in; - imm_out <= 32'bx; - - casez (instr_in) - `RV32_INSTR_LUI: begin - valid_out <= 1; - alu_op_out <= `RV32_ALU_OP_ADD_SUB; - alu_sub_sra_out <= 0; - alu_src1_out <= `RV32_ALU_SRC1_ZERO; - alu_src2_out <= `RV32_ALU_SRC2_IMM; - rd_write_out <= 1; - imm_out <= imm_u; - end - `RV32_INSTR_AUIPC: begin - valid_out <= 1; - alu_op_out <= `RV32_ALU_OP_ADD_SUB; - alu_sub_sra_out <= 0; - alu_src1_out <= `RV32_ALU_SRC1_PC; - alu_src2_out <= `RV32_ALU_SRC2_IMM; - rd_write_out <= 1; - imm_out <= imm_u; - end - `RV32_INSTR_JAL: begin - valid_out <= 1; - alu_op_out <= `RV32_ALU_OP_ADD_SUB; - alu_sub_sra_out <= 0; - alu_src1_out <= `RV32_ALU_SRC1_PC; - alu_src2_out <= `RV32_ALU_SRC2_FOUR; - branch_op_out <= `RV32_BRANCH_OP_ALWAYS; - branch_pc_src_out <= `RV32_BRANCH_PC_SRC_IMM; - rd_write_out <= 1; - imm_out <= imm_j; - end - `RV32_INSTR_JALR: begin - valid_out <= 1; - alu_op_out <= `RV32_ALU_OP_ADD_SUB; - alu_sub_sra_out <= 0; - alu_src1_out <= `RV32_ALU_SRC1_PC; - alu_src2_out <= `RV32_ALU_SRC2_FOUR; - branch_op_out <= `RV32_BRANCH_OP_ALWAYS; - branch_pc_src_out <= `RV32_BRANCH_PC_SRC_REG; - rd_write_out <= 1; - imm_out <= imm_i; - end - `RV32_INSTR_BEQ: begin - valid_out <= 1; - alu_op_out <= `RV32_ALU_OP_ADD_SUB; - alu_sub_sra_out <= 1; - alu_src1_out <= `RV32_ALU_SRC1_REG; - alu_src2_out <= `RV32_ALU_SRC2_REG; - branch_op_out <= `RV32_BRANCH_OP_ZERO; - branch_pc_src_out <= `RV32_BRANCH_PC_SRC_IMM; - imm_out <= imm_b; - end - `RV32_INSTR_BNE: begin - valid_out <= 1; - alu_op_out <= `RV32_ALU_OP_ADD_SUB; - alu_sub_sra_out <= 1; - alu_src1_out <= `RV32_ALU_SRC1_REG; - alu_src2_out <= `RV32_ALU_SRC2_REG; - branch_op_out <= `RV32_BRANCH_OP_NON_ZERO; - branch_pc_src_out <= `RV32_BRANCH_PC_SRC_IMM; - imm_out <= imm_b; - end - `RV32_INSTR_BLT: begin - valid_out <= 1; - alu_op_out <= `RV32_ALU_OP_SLT; - alu_sub_sra_out <= 1; - alu_src1_out <= `RV32_ALU_SRC1_REG; - alu_src2_out <= `RV32_ALU_SRC2_REG; - branch_op_out <= `RV32_BRANCH_OP_NON_ZERO; - branch_pc_src_out <= `RV32_BRANCH_PC_SRC_IMM; - imm_out <= imm_b; - end - `RV32_INSTR_BGE: begin - valid_out <= 1; - alu_op_out <= `RV32_ALU_OP_SLT; - alu_sub_sra_out <= 1; - alu_src1_out <= `RV32_ALU_SRC1_REG; - alu_src2_out <= `RV32_ALU_SRC2_REG; - branch_op_out <= `RV32_BRANCH_OP_ZERO; - branch_pc_src_out <= `RV32_BRANCH_PC_SRC_IMM; - imm_out <= imm_b; - end - `RV32_INSTR_BLTU: begin - valid_out <= 1; - alu_op_out <= `RV32_ALU_OP_SLTU; - alu_sub_sra_out <= 1; - alu_src1_out <= `RV32_ALU_SRC1_REG; - alu_src2_out <= `RV32_ALU_SRC2_REG; - branch_op_out <= `RV32_BRANCH_OP_NON_ZERO; - branch_pc_src_out <= `RV32_BRANCH_PC_SRC_IMM; - imm_out <= imm_b; - end - `RV32_INSTR_BGEU: begin - valid_out <= 1; - alu_op_out <= `RV32_ALU_OP_SLTU; - alu_sub_sra_out <= 1; - alu_src1_out <= `RV32_ALU_SRC1_REG; - alu_src2_out <= `RV32_ALU_SRC2_REG; - branch_op_out <= `RV32_BRANCH_OP_ZERO; - branch_pc_src_out <= `RV32_BRANCH_PC_SRC_IMM; - imm_out <= imm_b; - end - `RV32_INSTR_LB: begin - valid_out <= 1; - alu_op_out <= `RV32_ALU_OP_ADD_SUB; - alu_sub_sra_out <= 0; - alu_src1_out <= `RV32_ALU_SRC1_REG; - alu_src2_out <= `RV32_ALU_SRC2_IMM; - mem_read_out <= 1; - mem_width_out <= `RV32_MEM_WIDTH_BYTE; - mem_zero_extend_out <= 0; - rd_write_out <= 1; - imm_out <= imm_i; - end - `RV32_INSTR_LH: begin - valid_out <= 1; - alu_op_out <= `RV32_ALU_OP_ADD_SUB; - alu_sub_sra_out <= 0; - alu_src1_out <= `RV32_ALU_SRC1_REG; - alu_src2_out <= `RV32_ALU_SRC2_IMM; - mem_read_out <= 1; - mem_width_out <= `RV32_MEM_WIDTH_HALF; - mem_zero_extend_out <= 0; - rd_write_out <= 1; - imm_out <= imm_i; - end - `RV32_INSTR_LW: begin - valid_out <= 1; - alu_op_out <= `RV32_ALU_OP_ADD_SUB; - alu_sub_sra_out <= 0; - alu_src1_out <= `RV32_ALU_SRC1_REG; - alu_src2_out <= `RV32_ALU_SRC2_IMM; - mem_read_out <= 1; - mem_width_out <= `RV32_MEM_WIDTH_WORD; - rd_write_out <= 1; - imm_out <= imm_i; - end - `RV32_INSTR_LBU: begin - valid_out <= 1; - alu_op_out <= `RV32_ALU_OP_ADD_SUB; - alu_sub_sra_out <= 0; - alu_src1_out <= `RV32_ALU_SRC1_REG; - alu_src2_out <= `RV32_ALU_SRC2_IMM; - mem_read_out <= 1; - mem_width_out <= `RV32_MEM_WIDTH_BYTE; - mem_zero_extend_out <= 1; - rd_write_out <= 1; - imm_out <= imm_i; - end - `RV32_INSTR_LHU: begin - valid_out <= 1; - alu_op_out <= `RV32_ALU_OP_ADD_SUB; - alu_sub_sra_out <= 0; - alu_src1_out <= `RV32_ALU_SRC1_REG; - alu_src2_out <= `RV32_ALU_SRC2_IMM; - mem_read_out <= 1; - mem_width_out <= `RV32_MEM_WIDTH_HALF; - mem_zero_extend_out <= 1; - rd_write_out <= 1; - imm_out <= imm_i; - end - `RV32_INSTR_SB: begin - valid_out <= 1; - alu_op_out <= `RV32_ALU_OP_ADD_SUB; - alu_sub_sra_out <= 0; - alu_src1_out <= `RV32_ALU_SRC1_REG; - alu_src2_out <= `RV32_ALU_SRC2_IMM; - mem_write_out <= 1; - mem_width_out <= `RV32_MEM_WIDTH_BYTE; - imm_out <= imm_s; - end - `RV32_INSTR_SH: begin - valid_out <= 1; - alu_op_out <= `RV32_ALU_OP_ADD_SUB; - alu_sub_sra_out <= 0; - alu_src1_out <= `RV32_ALU_SRC1_REG; - alu_src2_out <= `RV32_ALU_SRC2_IMM; - mem_write_out <= 1; - mem_width_out <= `RV32_MEM_WIDTH_HALF; - imm_out <= imm_s; - end - `RV32_INSTR_SW: begin - valid_out <= 1; - alu_op_out <= `RV32_ALU_OP_ADD_SUB; - alu_sub_sra_out <= 0; - alu_src1_out <= `RV32_ALU_SRC1_REG; - alu_src2_out <= `RV32_ALU_SRC2_IMM; - mem_write_out <= 1; - mem_width_out <= `RV32_MEM_WIDTH_WORD; - imm_out <= imm_s; - end - `RV32_INSTR_ADDI: begin - valid_out <= 1; - alu_op_out <= `RV32_ALU_OP_ADD_SUB; - alu_sub_sra_out <= 0; - alu_src1_out <= `RV32_ALU_SRC1_REG; - alu_src2_out <= `RV32_ALU_SRC2_IMM; - rd_write_out <= 1; - imm_out <= imm_i; - end - `RV32_INSTR_SLTI: begin - valid_out <= 1; - alu_op_out <= `RV32_ALU_OP_SLT; - alu_sub_sra_out <= 1; - alu_src1_out <= `RV32_ALU_SRC1_REG; - alu_src2_out <= `RV32_ALU_SRC2_IMM; - rd_write_out <= 1; - imm_out <= imm_i; - end - `RV32_INSTR_SLTIU: begin - valid_out <= 1; - alu_op_out <= `RV32_ALU_OP_SLTU; - alu_sub_sra_out <= 1; - alu_src1_out <= `RV32_ALU_SRC1_REG; - alu_src2_out <= `RV32_ALU_SRC2_IMM; - rd_write_out <= 1; - imm_out <= imm_i; - end - `RV32_INSTR_XORI: begin - valid_out <= 1; - alu_op_out <= `RV32_ALU_OP_XOR; - alu_src1_out <= `RV32_ALU_SRC1_REG; - alu_src2_out <= `RV32_ALU_SRC2_IMM; - rd_write_out <= 1; - imm_out <= imm_i; - end - `RV32_INSTR_ORI: begin - valid_out <= 1; - alu_op_out <= `RV32_ALU_OP_OR; - alu_src1_out <= `RV32_ALU_SRC1_REG; - alu_src2_out <= `RV32_ALU_SRC2_IMM; - rd_write_out <= 1; - imm_out <= imm_i; - end - `RV32_INSTR_ANDI: begin - valid_out <= 1; - alu_op_out <= `RV32_ALU_OP_AND; - alu_src1_out <= `RV32_ALU_SRC1_REG; - alu_src2_out <= `RV32_ALU_SRC2_IMM; - rd_write_out <= 1; - imm_out <= imm_i; - end - `RV32_INSTR_SLLI: begin - valid_out <= 1; - alu_op_out <= `RV32_ALU_OP_SLL; - alu_src1_out <= `RV32_ALU_SRC1_REG; - alu_src2_out <= `RV32_ALU_SRC2_IMM; - rd_write_out <= 1; - imm_out <= shamt; - end - `RV32_INSTR_SRLI: begin - valid_out <= 1; - alu_op_out <= `RV32_ALU_OP_SRL_SRA; - alu_sub_sra_out <= 0; - alu_src1_out <= `RV32_ALU_SRC1_REG; - alu_src2_out <= `RV32_ALU_SRC2_IMM; - rd_write_out <= 1; - imm_out <= shamt; - end - `RV32_INSTR_SRAI: begin - valid_out <= 1; - alu_op_out <= `RV32_ALU_OP_SRL_SRA; - alu_sub_sra_out <= 1; - alu_src1_out <= `RV32_ALU_SRC1_REG; - alu_src2_out <= `RV32_ALU_SRC2_IMM; - rd_write_out <= 1; - imm_out <= shamt; - end - `RV32_INSTR_ADD: begin - valid_out <= 1; - alu_op_out <= `RV32_ALU_OP_ADD_SUB; - alu_sub_sra_out <= 0; - alu_src1_out <= `RV32_ALU_SRC1_REG; - alu_src2_out <= `RV32_ALU_SRC2_REG; - rd_write_out <= 1; - end - `RV32_INSTR_SUB: begin - valid_out <= 1; - alu_op_out <= `RV32_ALU_OP_ADD_SUB; - alu_sub_sra_out <= 1; - alu_src1_out <= `RV32_ALU_SRC1_REG; - alu_src2_out <= `RV32_ALU_SRC2_REG; - rd_write_out <= 1; - end - `RV32_INSTR_SLL: begin - valid_out <= 1; - alu_op_out <= `RV32_ALU_OP_SLL; - alu_src1_out <= `RV32_ALU_SRC1_REG; - alu_src2_out <= `RV32_ALU_SRC2_REG; - rd_write_out <= 1; - end - `RV32_INSTR_SLT: begin - valid_out <= 1; - alu_op_out <= `RV32_ALU_OP_SLT; - alu_sub_sra_out <= 1; - alu_src1_out <= `RV32_ALU_SRC1_REG; - alu_src2_out <= `RV32_ALU_SRC2_REG; - rd_write_out <= 1; - end - `RV32_INSTR_SLTU: begin - valid_out <= 1; - alu_op_out <= `RV32_ALU_OP_SLTU; - alu_sub_sra_out <= 1; - alu_src1_out <= `RV32_ALU_SRC1_REG; - alu_src2_out <= `RV32_ALU_SRC2_REG; - rd_write_out <= 1; - end - `RV32_INSTR_XOR: begin - valid_out <= 1; - alu_op_out <= `RV32_ALU_OP_XOR; - alu_src1_out <= `RV32_ALU_SRC1_REG; - alu_src2_out <= `RV32_ALU_SRC2_REG; - rd_write_out <= 1; - end - `RV32_INSTR_SRL: begin - valid_out <= 1; - alu_op_out <= `RV32_ALU_OP_SRL_SRA; - alu_sub_sra_out <= 0; - alu_src1_out <= `RV32_ALU_SRC1_REG; - alu_src2_out <= `RV32_ALU_SRC2_REG; - rd_write_out <= 1; - end - `RV32_INSTR_SRA: begin - valid_out <= 1; - alu_op_out <= `RV32_ALU_OP_SRL_SRA; - alu_sub_sra_out <= 1; - alu_src1_out <= `RV32_ALU_SRC1_REG; - alu_src2_out <= `RV32_ALU_SRC2_REG; - rd_write_out <= 1; - end - `RV32_INSTR_OR: begin - valid_out <= 1; - alu_op_out <= `RV32_ALU_OP_OR; - alu_src1_out <= `RV32_ALU_SRC1_REG; - alu_src2_out <= `RV32_ALU_SRC2_REG; - rd_write_out <= 1; - end - `RV32_INSTR_AND: begin - valid_out <= 1; - alu_op_out <= `RV32_ALU_OP_AND; - alu_src1_out <= `RV32_ALU_SRC1_REG; - alu_src2_out <= `RV32_ALU_SRC2_REG; - rd_write_out <= 1; - end - `RV32_INSTR_FENCE: begin - valid_out <= 1; - end - `RV32_INSTR_FENCE_I: begin - valid_out <= 1; - mem_fence_out <= 1; - end - `RV32_INSTR_ECALL: begin - valid_out <= 1; - // TODO - end - `RV32_INSTR_EBREAK: begin - valid_out <= 1; - // TODO - end - `RV32_INSTR_MRET: begin - valid_out <= 1; - // TODO - end - `RV32_INSTR_WFI: begin - valid_out <= 1; - end - `RV32_INSTR_CSRRW: begin - valid_out <= 1; - // TODO - end - `RV32_INSTR_CSRRS: begin - valid_out <= 1; - // TODO - end - `RV32_INSTR_CSRRC: begin - valid_out <= 1; - // TODO - end - `RV32_INSTR_CSRRWI: begin - valid_out <= 1; - // TODO - end - `RV32_INSTR_CSRRSI: begin - valid_out <= 1; - // TODO - end - `RV32_INSTR_CSRRCI: begin - valid_out <= 1; - // TODO - end - endcase + imm_value_out <= imm_value; if (flush_in) begin mem_read_out <= 0; diff --git a/rv32_execute.sv b/rv32_execute.sv index 293e87e..fdcbceb 100644 --- a/rv32_execute.sv +++ b/rv32_execute.sv @@ -36,7 +36,7 @@ module rv32_execute ( input [31:0] pc_in, input [31:0] rs1_value_in, input [31:0] rs2_value_in, - input [31:0] imm_in, + input [31:0] imm_value_in, /* data in (from writeback) */ input [31:0] writeback_rd_value_in, @@ -88,7 +88,7 @@ module rv32_execute ( .pc_in(pc_in), .rs1_value_in(rs1_value), .rs2_value_in(rs2_value), - .imm_in(imm_in), + .imm_value_in(imm_value_in), /* data out */ .result_out(result) @@ -103,7 +103,7 @@ module rv32_execute ( /* data in */ .pc_in(pc_in), .rs1_value_in(rs1_value), - .imm_in(imm_in), + .imm_value_in(imm_value_in), /* data out */ .pc_out(branch_pc) diff --git a/rv32_imm.sv b/rv32_imm.sv new file mode 100644 index 0000000..69d035e --- /dev/null +++ b/rv32_imm.sv @@ -0,0 +1,58 @@ +`ifndef RV32_IMM +`define RV32_IMM + +`define RV32_IMM_I 3'b000 +`define RV32_IMM_S 3'b001 +`define RV32_IMM_B 3'b010 +`define RV32_IMM_U 3'b011 +`define RV32_IMM_J 3'b100 +`define RV32_IMM_SHAMT 3'b101 +`define RV32_IMM_ZIMM 3'b110 + +module rv32_imm_mux ( + /* control in */ + input [2:0] imm_in, + + /* data in */ + input [31:0] instr_in, + + /* data out */ + output logic [31:0] imm_value_out +); + logic sign; + + logic [31:0] imm_i; + logic [31:0] imm_s; + logic [31:0] imm_b; + logic [31:0] imm_u; + logic [31:0] imm_j; + + logic [31:0] shamt; + logic [31:0] zimm; + + assign sign = instr_in[31]; + + assign imm_i = {{21{sign}}, instr_in[30:25], instr_in[24:21], instr_in[20]}; + assign imm_s = {{21{sign}}, instr_in[30:25], instr_in[11:8], instr_in[7]}; + assign imm_b = {{20{sign}}, instr_in[7], instr_in[30:25], instr_in[11:8], 1'b0}; + assign imm_u = {sign, instr_in[30:20], instr_in[19:12], 12'b0}; + assign imm_j = {{12{sign}}, instr_in[19:12], instr_in[20], instr_in[30:25], instr_in[24:21], 1'b0}; + + assign shamt = {27'bx, instr_in[24:20]}; + assign zimm = {27'b0, instr_in[19:15]}; + + always_comb begin + case (imm_in) + `RV32_IMM_I: imm_value_out = imm_i; + `RV32_IMM_S: imm_value_out = imm_s; + `RV32_IMM_B: imm_value_out = imm_b; + `RV32_IMM_U: imm_value_out = imm_u; + `RV32_IMM_J: imm_value_out = imm_j; + `RV32_IMM_SHAMT: imm_value_out = shamt; + `RV32_IMM_ZIMM: imm_value_out = zimm; + default: imm_value_out = 32'bx; + endcase + end +endmodule + +`endif