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.
This commit is contained in:
Graham Edgecombe 2017-12-27 14:05:09 +00:00
parent 2b1e0de9de
commit 0013935bb0
8 changed files with 575 additions and 453 deletions

View file

@ -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

View file

@ -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),

View file

@ -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

View file

@ -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

439
rv32_control.sv Normal file
View file

@ -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

View file

@ -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;

View file

@ -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)

58
rv32_imm.sv Normal file
View file

@ -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