`default_nettype none module serv_decode ( input wire clk, //Input input wire i_cnt_en, input wire i_cnt_done, input wire [31:2] i_wb_rdt, input wire i_wb_en, input wire i_alu_cmp, //To state output wire o_take_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, //To bufreg output wire o_bufreg_loop, output wire o_bufreg_rs1_en, output wire o_bufreg_imm_en, output wire o_bufreg_clr_lsb, //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, //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_uns, output wire o_alu_sh_signed, output wire o_alu_sh_right, output wire [3:0] o_alu_rd_sel, //To RF output reg [4:0] o_rf_rd_addr, output reg [4:0] o_rf_rs1_addr, output reg [4:0] o_rf_rs2_addr, //To mem IF output wire o_mem_signed, output wire o_mem_word, output wire o_mem_half, output wire 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, //To top output wire o_imm, output wire o_op_b_source, output wire o_rd_csr_en, output wire o_rd_alu_en); `include "serv_params.vh" reg [4:0] opcode; reg [2:0] funct3; reg op20; reg op21; reg op22; reg op26; reg imm30; wire op_or_opimm = (!opcode[4] & opcode[2] & !opcode[0]); assign o_mem_op = !opcode[4] & !opcode[2] & !opcode[0]; assign o_shift_op = op_or_opimm & (funct3[1:0] == 2'b01); assign o_slt_op = op_or_opimm & (funct3[2:1] == 2'b01); assign o_branch_op = opcode[4] & !opcode[2]; //Matches system opcodes except CSR accesses (funct3 == 0) //No idea anymore why the !op21 condition is needed here assign o_e_op = opcode[4] & opcode[2] & !op21 & !(|funct3); assign o_ebreak = op20; //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]; //Loop bufreg contents for shift operations assign o_bufreg_loop = op_or_opimm; //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)); //Take branch for jump or branch instructions (opcode == 1x0xx) if //a) It's an unconditional branch (opcode[0] == 1) //b) It's a conditional branch (opcode[0] == 0) of type beq,blt,bltu (funct3[0] == 0) and ALU compare is true //c) It's a conditional branch (opcode[0] == 0) of type bne,bge,bgeu (funct3[0] == 1) and ALU compare is false //Only valid during the last cycle of INIT, when the branch condition has //been calculated. assign o_take_branch = opcode[4] & !opcode[2] & (opcode[0] | (i_alu_cmp^funct3[0])); assign o_ctrl_utype = !opcode[4] & opcode[2] & opcode[0]; assign o_ctrl_jal_or_jalr = opcode[4] & opcode[0]; //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); assign o_ctrl_mret = (opcode[4] & opcode[2] & op21 & !(|funct3)); //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])) & (|o_rf_rd_addr); assign o_alu_sub = opcode[3] & imm30/*alu_sub_r*/; /* 300 0_000 mstatus RWSC 304 0_100 mie SCWi 305 0_101 mtvec RW 340 1_000 mscratch 341 1_001 mepc RW 342 1_010 mcause R 343 1_011 mtval 344 1_100 mip CWi */ //true for mtvec,mscratch,mepc and mtval //false for mstatus, mie, mcause, mip wire csr_valid = op20 | (op26 & !op22 & !op21); //Matches system ops except eceall/ebreak wire csr_op = opcode[4] & opcode[2] & (|funct3); assign o_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; assign o_csr_source = funct3[1:0]; assign o_csr_d_sel = funct3[2]; assign o_csr_imm = o_rf_rs1_addr[0]; assign o_csr_addr = (op26 & !op20) ? CSR_MSCRATCH : (op26 & !op21) ? CSR_MEPC : (op26) ? CSR_MTVAL : CSR_MTVEC; assign o_alu_cmp_eq = funct3[2:1] == 2'b00; assign o_alu_cmp_uns = (funct3[0] & funct3[1]) | (funct3[1] & funct3[2]); assign o_alu_sh_signed = imm30; assign o_alu_sh_right = 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]; assign o_alu_bool_op = funct3[1:0]; reg signbit; reg [8:0] imm19_12_20; reg imm7; reg [5:0] imm30_25; reg [4:0] imm24_20; reg [4:0] imm11_7; wire [1:0] m2; //True for OP-IMM, LOAD, STORE, JALR //False for LUI, AUIPC, JAL assign m2[0] = (opcode[1:0] == 2'b00) | (opcode[2:1] == 2'b00); assign m2[1] = opcode[4] & !opcode[0]; wire m3 = opcode[4]; assign o_alu_rd_sel[0] = (funct3 == 3'b000); // Add/sub assign o_alu_rd_sel[1] = (funct3[1:0] == 2'b01); //Shift assign o_alu_rd_sel[2] = (funct3[2:1] == 2'b01); //SLT* assign o_alu_rd_sel[3] = (funct3[2] & !(funct3[1:0] == 2'b01)); //Bool always @(posedge clk) begin if (i_wb_en) begin o_rf_rd_addr <= i_wb_rdt[11:7]; o_rf_rs1_addr <= i_wb_rdt[19:15]; o_rf_rs2_addr <= i_wb_rdt[24:20]; 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]; //Immediate decoder signbit <= i_wb_rdt[31]; imm19_12_20 <= {i_wb_rdt[19:12],i_wb_rdt[20]}; imm7 <= i_wb_rdt[7]; imm30_25 <= i_wb_rdt[30:25]; imm24_20 <= i_wb_rdt[24:20]; imm11_7 <= i_wb_rdt[11:7]; end if (i_cnt_en) begin imm19_12_20 <= {m3 ? signbit : imm24_20[0], imm19_12_20[8:1]}; imm7 <= signbit; imm30_25 <= {m2[1] ? imm7 : m2[0] ? signbit : imm19_12_20[0], imm30_25[5:1]}; imm24_20 <= {imm30_25[0], imm24_20[4:1]}; imm11_7 <= {imm30_25[0], imm11_7[4:1]}; if (csr_op & o_csr_d_sel) o_rf_rs1_addr <= {1'b0,o_rf_rs1_addr[4:1]}; end end //True for S (STORE) or B (BRANCH) type instructions //False for J type instructions wire m1 = opcode[3:0] == 4'b1000; assign o_imm = i_cnt_done ? signbit : m1 ? imm11_7[0] : imm24_20[0]; //0 (OP_B_SOURCE_IMM) when OPIMM //1 (OP_B_SOURCE_RS2) when BRANCH or OP assign o_op_b_source = opcode[3]; assign o_rd_alu_en = !opcode[0] & opcode[2] & !opcode[4]; endmodule