`default_nettype none module serv_decode #(parameter [0:0] PRE_REGISTER = 1, parameter [0:0] MDU = 0) ( input wire clk, //Input input wire [31:2] i_wb_rdt, input wire i_wb_en, //To state 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_shift_op, output reg o_slt_or_branch, output reg o_rd_op, output reg o_two_stage_op, output reg o_dbus_en, //MDU output reg o_mdu_op, //Extension output reg [2:0] o_ext_funct3, //To bufreg 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 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 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 reg o_mem_signed, output reg o_mem_word, output reg o_mem_half, output reg o_mem_cmd, //To CSR 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, output reg o_mtval_pc, //To top output reg [3:0] o_immdec_ctrl, output reg [3:0] o_immdec_en, output reg o_op_b_source, //To RF IF output reg o_rd_mem_en, 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 imm25; reg imm30; wire co_mdu_op = MDU & (opcode == 5'b01100) & imm25; wire co_two_stage_op = ~opcode[2] | (funct3[0] & ~funct3[1] & ~opcode[0] & ~opcode[4]) | (funct3[1] & ~funct3[2] & ~opcode[0] & ~opcode[4]) | co_mdu_op; wire co_shift_op = (opcode[2] & ~funct3[1]) & !co_mdu_op; wire co_slt_or_branch = (opcode[4] | (funct3[1] & opcode[2]) | (imm30 & opcode[2] & opcode[3] & ~funct3[2])) & !co_mdu_op; wire co_branch_op = opcode[4]; wire co_dbus_en = ~opcode[2] & ~opcode[4]; wire co_mtval_pc = opcode[4]; wire co_mem_word = funct3[1]; wire co_rd_alu_en = !opcode[0] & opcode[2] & !opcode[4] & !co_mdu_op; wire co_rd_mem_en = (!opcode[2] & !opcode[0]) | co_mdu_op; wire [2:0] co_ext_funct3 = funct3; //jal,branch = imm //jalr = rs1+imm //mem = rs1+imm //shift = rs1 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? 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 wire co_cond_branch = !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, ebreak //False for jalr, lui wire co_ctrl_pc_rel = (opcode[2:0] == 3'b000) | (opcode[1:0] == 2'b11) | (opcode[4] & opcode[2]) & op20| (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 wire co_rd_op = (opcode[2] | (!opcode[2] & opcode[4] & opcode[0]) | (!opcode[2] & !opcode[3] & !opcode[0])); // //funct3 // wire co_sh_right = funct3[2]; wire co_bne_or_bge = funct3[0]; //Matches system ops except eceall/ebreak/mret wire csr_op = opcode[4] & opcode[2] & (|funct3); //op20 wire co_ebreak = op20; //opcode & funct3 & op21 wire co_ctrl_mret = opcode[4] & opcode[2] & op21 & !(|funct3); //Matches system opcodes except CSR accesses (funct3 == 0) //and mret (!op21) wire co_e_op = opcode[4] & opcode[2] & !op21 & !(|funct3); //opcode & funct3 & imm30 wire co_bufreg_sh_signed = imm30; /* True for sub, b*, slt* False for add* op opcode f3 i30 b* 11000 xxx x t addi 00100 000 x f slt* 0x100 01x x t add 01100 000 0 f sub 01100 000 1 t */ 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 ---|-----|--------|---- 300|0_000|mstatus | xx 304|0_100|mie | xx 305|0_101|mtvec | 01 340|1_000|mscratch| 00 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); wire co_rd_csr_en = csr_op; 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; 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}; wire co_alu_cmp_eq = funct3[2:1] == 2'b00; wire co_alu_cmp_sig = ~((funct3[0] & funct3[1]) | (funct3[1] & funct3[2])); wire co_mem_cmd = opcode[3]; wire co_mem_signed = ~funct3[2]; wire co_mem_half = funct3[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 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 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]; 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 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 wire co_op_b_source = opcode[3]; generate if (PRE_REGISTER) begin : gen_pre_register always @(posedge clk) begin if (i_wb_en) begin funct3 <= i_wb_rdt[14:12]; imm30 <= i_wb_rdt[30]; imm25 <= i_wb_rdt[25]; 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_dbus_en = co_dbus_en; o_mtval_pc = co_mtval_pc; o_two_stage_op = co_two_stage_op; o_e_op = co_e_op; o_ebreak = co_ebreak; o_branch_op = co_branch_op; o_shift_op = co_shift_op; o_slt_or_branch = co_slt_or_branch; o_rd_op = co_rd_op; o_mdu_op = co_mdu_op; o_ext_funct3 = co_ext_funct3; 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; o_rd_mem_en = co_rd_mem_en; end end else begin : gen_post_register always @(*) begin funct3 = i_wb_rdt[14:12]; imm30 = i_wb_rdt[30]; imm25 = i_wb_rdt[25]; 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_two_stage_op <= co_two_stage_op; o_dbus_en <= co_dbus_en; o_mtval_pc <= co_mtval_pc; o_branch_op <= co_branch_op; o_shift_op <= co_shift_op; o_slt_or_branch <= co_slt_or_branch; o_rd_op <= co_rd_op; o_mdu_op <= co_mdu_op; o_ext_funct3 <= co_ext_funct3; 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; o_rd_mem_en <= co_rd_mem_en; end end end endgenerate endmodule