1
0
mirror of https://github.com/olofk/serv.git synced 2026-03-10 20:23:22 +00:00

decode: Add option to pre or post register during decoding

Either the input from instruction bus is registered and the
outputs are generated combinatorially (PRE_REGISTER mode), or
the input from the instruction bus is decoded combinatorially
and the result of decoding is registered (POST_REGISTER mode).

First is smaller because it allows synthesis to optimize decoding
logic with its users, but is slow. The second one is faster but
slightly bigger.

Signed-off-by: Sylvain Munaut <tnt@246tNt.com>
This commit is contained in:
Sylvain Munaut
2021-05-28 21:19:33 +02:00
committed by Olof Kindgren
parent 06653f52b2
commit 259d5a10ed

View File

@@ -1,138 +1,139 @@
`default_nettype none
module serv_decode
(
input wire clk,
module serv_decode #(
parameter integer PRE_REGISTER = 1
)(
input wire clk,
//Input
input wire [31:2] i_wb_rdt,
input wire i_wb_en,
input wire i_wb_en,
//To state
output wire o_sh_right,
output wire o_bne_or_bge,
output wire o_cond_branch,
output wire o_e_op,
output wire o_ebreak,
output wire o_branch_op,
output wire o_mem_op,
output wire o_shift_op,
output wire o_slt_op,
output wire o_rd_op,
output reg o_sh_right,
output reg o_bne_or_bge,
output reg o_cond_branch,
output reg o_e_op,
output reg o_ebreak,
output reg o_branch_op,
output reg o_mem_op,
output reg o_shift_op,
output reg o_slt_op,
output reg o_rd_op,
//To bufreg
output wire o_bufreg_rs1_en,
output wire o_bufreg_imm_en,
output wire o_bufreg_clr_lsb,
output wire o_bufreg_sh_signed,
output reg o_bufreg_rs1_en,
output reg o_bufreg_imm_en,
output reg o_bufreg_clr_lsb,
output reg o_bufreg_sh_signed,
//To ctrl
output wire o_ctrl_jal_or_jalr,
output wire o_ctrl_utype,
output wire o_ctrl_pc_rel,
output wire o_ctrl_mret,
output reg o_ctrl_jal_or_jalr,
output reg o_ctrl_utype,
output reg o_ctrl_pc_rel,
output reg o_ctrl_mret,
//To alu
output wire o_alu_sub,
output wire [1:0] o_alu_bool_op,
output wire o_alu_cmp_eq,
output wire o_alu_cmp_sig,
output wire [2:0] o_alu_rd_sel,
output reg o_alu_sub,
output reg [1:0] o_alu_bool_op,
output reg o_alu_cmp_eq,
output reg o_alu_cmp_sig,
output reg [2:0] o_alu_rd_sel,
//To mem IF
output wire o_mem_signed,
output wire o_mem_word,
output wire o_mem_half,
output wire o_mem_cmd,
output reg o_mem_signed,
output reg o_mem_word,
output reg o_mem_half,
output reg o_mem_cmd,
//To CSR
output wire o_csr_en,
output wire [1:0] o_csr_addr,
output wire o_csr_mstatus_en,
output wire o_csr_mie_en,
output wire o_csr_mcause_en,
output wire [1:0] o_csr_source,
output wire o_csr_d_sel,
output wire o_csr_imm_en,
output reg o_csr_en,
output reg [1:0] o_csr_addr,
output reg o_csr_mstatus_en,
output reg o_csr_mie_en,
output reg o_csr_mcause_en,
output reg [1:0] o_csr_source,
output reg o_csr_d_sel,
output reg o_csr_imm_en,
//To top
output wire [3:0] o_immdec_ctrl,
output wire [3:0] o_immdec_en,
output wire o_op_b_source,
output wire o_rd_csr_en,
output wire o_rd_alu_en);
output reg [3:0] o_immdec_ctrl,
output reg [3:0] o_immdec_en,
output reg o_op_b_source,
output reg o_rd_csr_en,
output reg o_rd_alu_en);
reg [4:0] opcode;
reg [2:0] funct3;
reg op20;
reg op21;
reg op22;
reg op26;
reg op20;
reg op21;
reg op22;
reg op26;
reg imm30;
//opcode
wire op_or_opimm = (!opcode[4] & opcode[2] & !opcode[0]);
wire op_or_opimm = (!opcode[4] & opcode[2] & !opcode[0]);
assign o_mem_op = !opcode[4] & !opcode[2] & !opcode[0];
assign o_branch_op = opcode[4] & !opcode[2];
wire co_mem_op = !opcode[4] & !opcode[2] & !opcode[0];
wire co_branch_op = opcode[4] & !opcode[2];
//jal,branch = imm
//jalr = rs1+imm
//mem = rs1+imm
//shift = rs1
assign o_bufreg_rs1_en = !opcode[4] | (!opcode[1] & opcode[0]);
assign o_bufreg_imm_en = !opcode[2];
wire co_bufreg_rs1_en = !opcode[4] | (!opcode[1] & opcode[0]);
wire co_bufreg_imm_en = !opcode[2];
//Clear LSB of immediate for BRANCH and JAL ops
//True for BRANCH and JAL
//False for JALR/LOAD/STORE/OP/OPIMM?
assign o_bufreg_clr_lsb = opcode[4] & ((opcode[1:0] == 2'b00) | (opcode[1:0] == 2'b11));
wire co_bufreg_clr_lsb = opcode[4] & ((opcode[1:0] == 2'b00) | (opcode[1:0] == 2'b11));
//Conditional branch
//True for BRANCH
//False for JAL/JALR
assign o_cond_branch = !opcode[0];
wire co_cond_branch = !opcode[0];
assign o_ctrl_utype = !opcode[4] & opcode[2] & opcode[0];
assign o_ctrl_jal_or_jalr = opcode[4] & opcode[0];
wire co_ctrl_utype = !opcode[4] & opcode[2] & opcode[0];
wire co_ctrl_jal_or_jalr = opcode[4] & opcode[0];
//PC-relative operations
//True for jal, b* auipc
//False for jalr, lui
assign o_ctrl_pc_rel = (opcode[2:0] == 3'b000) |
(opcode[1:0] == 2'b11) |
(opcode[4:3] == 2'b00);
wire co_ctrl_pc_rel = (opcode[2:0] == 3'b000) |
(opcode[1:0] == 2'b11) |
(opcode[4:3] == 2'b00);
//Write to RD
//True for OP-IMM, AUIPC, OP, LUI, SYSTEM, JALR, JAL, LOAD
//False for STORE, BRANCH, MISC-MEM
assign o_rd_op = (opcode[2] |
(!opcode[2] & opcode[4] & opcode[0]) |
(!opcode[2] & !opcode[3] & !opcode[0]));
wire co_rd_op = (opcode[2] |
(!opcode[2] & opcode[4] & opcode[0]) |
(!opcode[2] & !opcode[3] & !opcode[0]));
//
//funct3
//
assign o_sh_right = funct3[2];
assign o_bne_or_bge = funct3[0];
wire co_sh_right = funct3[2];
wire co_bne_or_bge = funct3[0];
//
// opcode & funct3
//
assign o_shift_op = op_or_opimm & (funct3[1:0] == 2'b01);
assign o_slt_op = op_or_opimm & (funct3[2:1] == 2'b01);
wire co_shift_op = op_or_opimm & (funct3[1:0] == 2'b01);
wire co_slt_op = op_or_opimm & (funct3[2:1] == 2'b01);
//Matches system ops except eceall/ebreak/mret
wire csr_op = opcode[4] & opcode[2] & (|funct3);
//op20
assign o_ebreak = op20;
wire co_ebreak = op20;
//opcode & funct3 & op21
assign o_ctrl_mret = opcode[4] & opcode[2] & op21 & !(|funct3);
wire co_ctrl_mret = opcode[4] & opcode[2] & op21 & !(|funct3);
//Matches system opcodes except CSR accesses (funct3 == 0)
//and mret (!op21)
assign o_e_op = opcode[4] & opcode[2] & !op21 & !(|funct3);
wire co_e_op = opcode[4] & opcode[2] & !op21 & !(|funct3);
//opcode & funct3 & imm30
assign o_bufreg_sh_signed = imm30;
wire co_bufreg_sh_signed = imm30;
/*
True for sub, b*, slt*
@@ -144,16 +145,16 @@ module serv_decode
add 01100 000 0 f
sub 01100 000 1 t
*/
assign o_alu_sub = funct3[1] | funct3[0] | (opcode[3] & imm30) | opcode[4];
wire co_alu_sub = funct3[1] | funct3[0] | (opcode[3] & imm30) | opcode[4];
/*
Bits 26, 22, 21 and 20 are enough to uniquely identify the eight supported CSR regs
mtvec, mscratch, mepc and mtval are stored externally (normally in the RF) and are
treated differently from mstatus, mie and mcause which are stored in serv_csr.
The former get a 2-bit address as seen below while the latter get a
one-hot enable signal each.
Hex|2 222|Reg |csr
adr|6 210|name |addr
---|-----|--------|----
@@ -164,70 +165,179 @@ module serv_decode
341|1_001|mepc | 10
342|1_010|mcause | xx
343|1_011|mtval | 11
*/
//true for mtvec,mscratch,mepc and mtval
//false for mstatus, mie, mcause
wire csr_valid = op20 | (op26 & !op21);
assign o_rd_csr_en = csr_op;
wire co_rd_csr_en = csr_op;
assign o_csr_en = csr_op & csr_valid;
assign o_csr_mstatus_en = csr_op & !op26 & !op22;
assign o_csr_mie_en = csr_op & !op26 & op22 & !op20;
assign o_csr_mcause_en = csr_op & op21 & !op20;
wire co_csr_en = csr_op & csr_valid;
wire co_csr_mstatus_en = csr_op & !op26 & !op22;
wire co_csr_mie_en = csr_op & !op26 & op22 & !op20;
wire co_csr_mcause_en = csr_op & op21 & !op20;
assign o_csr_source = funct3[1:0];
assign o_csr_d_sel = funct3[2];
assign o_csr_imm_en = opcode[4] & opcode[2] & funct3[2];
assign o_csr_addr = {op26 & op20, !op26 | op21};
wire [1:0] co_csr_source = funct3[1:0];
wire co_csr_d_sel = funct3[2];
wire co_csr_imm_en = opcode[4] & opcode[2] & funct3[2];
wire [1:0] co_csr_addr = {op26 & op20, !op26 | op21};
assign o_alu_cmp_eq = funct3[2:1] == 2'b00;
wire co_alu_cmp_eq = funct3[2:1] == 2'b00;
assign o_alu_cmp_sig = ~((funct3[0] & funct3[1]) | (funct3[1] & funct3[2]));
wire co_alu_cmp_sig = ~((funct3[0] & funct3[1]) | (funct3[1] & funct3[2]));
assign o_mem_cmd = opcode[3];
assign o_mem_signed = ~funct3[2];
assign o_mem_word = funct3[1];
assign o_mem_half = funct3[0];
wire co_mem_cmd = opcode[3];
wire co_mem_signed = ~funct3[2];
wire co_mem_word = funct3[1];
wire co_mem_half = funct3[0];
assign o_alu_bool_op = funct3[1:0];
wire [1:0] co_alu_bool_op = funct3[1:0];
wire [3:0] co_immdec_ctrl;
//True for S (STORE) or B (BRANCH) type instructions
//False for J type instructions
assign o_immdec_ctrl[0] = opcode[3:0] == 4'b1000;
assign co_immdec_ctrl[0] = opcode[3:0] == 4'b1000;
//True for OP-IMM, LOAD, STORE, JALR (I S)
//False for LUI, AUIPC, JAL (U J)
assign o_immdec_ctrl[1] = (opcode[1:0] == 2'b00) | (opcode[2:1] == 2'b00);
assign o_immdec_ctrl[2] = opcode[4] & !opcode[0];
assign o_immdec_ctrl[3] = opcode[4];
//False for LUI, AUIPC, JAL (U J)
assign co_immdec_ctrl[1] = (opcode[1:0] == 2'b00) | (opcode[2:1] == 2'b00);
assign co_immdec_ctrl[2] = opcode[4] & !opcode[0];
assign co_immdec_ctrl[3] = opcode[4];
assign o_immdec_en[3] = opcode[4] | opcode[3] | opcode[2] | !opcode[0]; //B I J S U
assign o_immdec_en[2] = (opcode[4] & opcode[2]) | !opcode[3] | opcode[0]; // I J U
assign o_immdec_en[1] = (opcode[2:1] == 2'b01) | (opcode[2] & opcode[0]) | o_csr_imm_en;// J U
assign o_immdec_en[0] = ~o_rd_op; //B S
wire [3:0] co_immdec_en;
assign co_immdec_en[3] = opcode[4] | opcode[3] | opcode[2] | !opcode[0]; //B I J S U
assign co_immdec_en[2] = (opcode[4] & opcode[2]) | !opcode[3] | opcode[0]; // I J U
assign co_immdec_en[1] = (opcode[2:1] == 2'b01) | (opcode[2] & opcode[0]) | co_csr_imm_en;// J U
assign co_immdec_en[0] = ~co_rd_op; //B S
assign o_alu_rd_sel[0] = (funct3 == 3'b000); // Add/sub
assign o_alu_rd_sel[1] = (funct3[2:1] == 2'b01); //SLT*
assign o_alu_rd_sel[2] = funct3[2]; //Bool
always @(posedge clk) begin
if (i_wb_en) begin
funct3 <= i_wb_rdt[14:12];
imm30 <= i_wb_rdt[30];
opcode <= i_wb_rdt[6:2];
op20 <= i_wb_rdt[20];
op21 <= i_wb_rdt[21];
op22 <= i_wb_rdt[22];
op26 <= i_wb_rdt[26];
end
end
wire [2:0] co_alu_rd_sel;
assign co_alu_rd_sel[0] = (funct3 == 3'b000); // Add/sub
assign co_alu_rd_sel[1] = (funct3[2:1] == 2'b01); //SLT*
assign co_alu_rd_sel[2] = funct3[2]; //Bool
//0 (OP_B_SOURCE_IMM) when OPIMM
//1 (OP_B_SOURCE_RS2) when BRANCH or OP
assign o_op_b_source = opcode[3];
wire co_op_b_source = opcode[3];
assign o_rd_alu_en = !opcode[0] & opcode[2] & !opcode[4];
wire co_rd_alu_en = !opcode[0] & opcode[2] & !opcode[4];
generate
if (PRE_REGISTER) begin
always @(posedge clk) begin
if (i_wb_en) begin
funct3 <= i_wb_rdt[14:12];
imm30 <= i_wb_rdt[30];
opcode <= i_wb_rdt[6:2];
op20 <= i_wb_rdt[20];
op21 <= i_wb_rdt[21];
op22 <= i_wb_rdt[22];
op26 <= i_wb_rdt[26];
end
end
always @(*) begin
o_sh_right = co_sh_right;
o_bne_or_bge = co_bne_or_bge;
o_cond_branch = co_cond_branch;
o_e_op = co_e_op;
o_ebreak = co_ebreak;
o_branch_op = co_branch_op;
o_mem_op = co_mem_op;
o_shift_op = co_shift_op;
o_slt_op = co_slt_op;
o_rd_op = co_rd_op;
o_bufreg_rs1_en = co_bufreg_rs1_en;
o_bufreg_imm_en = co_bufreg_imm_en;
o_bufreg_clr_lsb = co_bufreg_clr_lsb;
o_bufreg_sh_signed = co_bufreg_sh_signed;
o_ctrl_jal_or_jalr = co_ctrl_jal_or_jalr;
o_ctrl_utype = co_ctrl_utype;
o_ctrl_pc_rel = co_ctrl_pc_rel;
o_ctrl_mret = co_ctrl_mret;
o_alu_sub = co_alu_sub;
o_alu_bool_op = co_alu_bool_op;
o_alu_cmp_eq = co_alu_cmp_eq;
o_alu_cmp_sig = co_alu_cmp_sig;
o_alu_rd_sel = co_alu_rd_sel;
o_mem_signed = co_mem_signed;
o_mem_word = co_mem_word;
o_mem_half = co_mem_half;
o_mem_cmd = co_mem_cmd;
o_csr_en = co_csr_en;
o_csr_addr = co_csr_addr;
o_csr_mstatus_en = co_csr_mstatus_en;
o_csr_mie_en = co_csr_mie_en;
o_csr_mcause_en = co_csr_mcause_en;
o_csr_source = co_csr_source;
o_csr_d_sel = co_csr_d_sel;
o_csr_imm_en = co_csr_imm_en;
o_immdec_ctrl = co_immdec_ctrl;
o_immdec_en = co_immdec_en;
o_op_b_source = co_op_b_source;
o_rd_csr_en = co_rd_csr_en;
o_rd_alu_en = co_rd_alu_en;
end
end else begin
always @(*) begin
funct3 = i_wb_rdt[14:12];
imm30 = i_wb_rdt[30];
opcode = i_wb_rdt[6:2];
op20 = i_wb_rdt[20];
op21 = i_wb_rdt[21];
op22 = i_wb_rdt[22];
op26 = i_wb_rdt[26];
end
always @(posedge clk) begin
if (i_wb_en) begin
o_sh_right <= co_sh_right;
o_bne_or_bge <= co_bne_or_bge;
o_cond_branch <= co_cond_branch;
o_e_op <= co_e_op;
o_ebreak <= co_ebreak;
o_branch_op <= co_branch_op;
o_mem_op <= co_mem_op;
o_shift_op <= co_shift_op;
o_slt_op <= co_slt_op;
o_rd_op <= co_rd_op;
o_bufreg_rs1_en <= co_bufreg_rs1_en;
o_bufreg_imm_en <= co_bufreg_imm_en;
o_bufreg_clr_lsb <= co_bufreg_clr_lsb;
o_bufreg_sh_signed <= co_bufreg_sh_signed;
o_ctrl_jal_or_jalr <= co_ctrl_jal_or_jalr;
o_ctrl_utype <= co_ctrl_utype;
o_ctrl_pc_rel <= co_ctrl_pc_rel;
o_ctrl_mret <= co_ctrl_mret;
o_alu_sub <= co_alu_sub;
o_alu_bool_op <= co_alu_bool_op;
o_alu_cmp_eq <= co_alu_cmp_eq;
o_alu_cmp_sig <= co_alu_cmp_sig;
o_alu_rd_sel <= co_alu_rd_sel;
o_mem_signed <= co_mem_signed;
o_mem_word <= co_mem_word;
o_mem_half <= co_mem_half;
o_mem_cmd <= co_mem_cmd;
o_csr_en <= co_csr_en;
o_csr_addr <= co_csr_addr;
o_csr_mstatus_en <= co_csr_mstatus_en;
o_csr_mie_en <= co_csr_mie_en;
o_csr_mcause_en <= co_csr_mcause_en;
o_csr_source <= co_csr_source;
o_csr_d_sel <= co_csr_d_sel;
o_csr_imm_en <= co_csr_imm_en;
o_immdec_ctrl <= co_immdec_ctrl;
o_immdec_en <= co_immdec_en;
o_op_b_source <= co_op_b_source;
o_rd_csr_en <= co_rd_csr_en;
o_rd_alu_en <= co_rd_alu_en;
end
end
end
endgenerate
endmodule