diff --git a/bench/decoder_sim.v b/bench/decoder_sim.v new file mode 100644 index 0000000..c273cbb --- /dev/null +++ b/bench/decoder_sim.v @@ -0,0 +1,110 @@ +`default_nettype none +module decoder_sim + (input wire wb_clk, + input wire [31:2] wb_rdt, + input wire wb_en, + output wire ebreak, + output wire jal_or_jalr, + output wire mret, + output wire wfi, + output wire sh_right, + output wire bne_or_bge, + output wire cond_branch, + output wire e_op, + output wire branch_op, + output wire shift_op, + output wire slt_or_branch, + output wire rd_op, + output wire two_stage_op, + output wire dbus_en, + output wire mdu_op, + output wire [2:0] ext_funct3, + output wire bufreg_rs1_en, + output wire bufreg_imm_en, + output wire bufreg_clr_lsb, + output wire bufreg_sh_signed, + output wire ctrl_utype, + output wire ctrl_pc_rel, + output wire alu_sub, + output wire [1:0] alu_bool_op, + output wire alu_cmp_eq, + output wire alu_cmp_sig, + output wire [2:0] alu_rd_sel, + output wire mem_signed, + output wire mem_word, + output wire mem_half, + output wire mem_cmd, + output wire csr_en, + output wire [1:0] csr_addr, + output wire csr_mstatus_en, + output wire csr_mie_en, + output wire csr_mcause_en, + output wire [1:0] csr_source, + output wire csr_d_sel, + output wire csr_imm_en, + output wire mtval_pc, + output wire [3:0] immdec_ctrl, + output wire [3:0] immdec_en, + output wire op_b_source, + output wire rd_mem_en, + output wire rd_csr_en, + output wire rd_alu_en +); + + // Instantiate the DUT + serv_decode + #(.PRE_REGISTER (1), + .MDU (0)) + dut ( + .clk(wb_clk), + .i_wb_rdt(wb_rdt), + .i_wb_en(wb_en), + // Outputs + .o_sh_right(sh_right), + .o_bne_or_bge(bne_or_bge), + .o_cond_branch(cond_branch), + .o_e_op(e_op), + .o_ebreak(ebreak), + .o_wfi(wfi), + .o_branch_op(branch_op), + .o_shift_op(shift_op), + .o_rd_op(rd_op), + .o_two_stage_op(two_stage_op), + .o_dbus_en(dbus_en), + .o_mdu_op(mdu_op), + .o_ext_funct3(ext_funct3), + .o_bufreg_rs1_en(bufreg_rs1_en), + .o_bufreg_imm_en(bufreg_imm_en), + .o_bufreg_clr_lsb(bufreg_clr_lsb), + .o_bufreg_sh_signed(bufreg_sh_signed), + .o_ctrl_jal_or_jalr(jal_or_jalr), + .o_ctrl_utype(ctrl_utype), + .o_ctrl_pc_rel(ctrl_pc_rel), + .o_ctrl_mret(mret), + .o_alu_sub(alu_sub), + .o_alu_bool_op(alu_bool_op), + .o_alu_cmp_eq(alu_cmp_eq), + .o_alu_cmp_sig(alu_cmp_sig), + .o_alu_rd_sel(alu_rd_sel), + .o_mem_signed(mem_signed), + .o_mem_word(mem_word), + .o_mem_half(mem_half), + .o_mem_cmd(mem_cmd), + .o_csr_en(csr_en), + .o_csr_addr(csr_addr), + .o_csr_mstatus_en(csr_mstatus_en), + .o_csr_mie_en(csr_mie_en), + .o_csr_mcause_en(csr_mcause_en), + .o_csr_source(csr_source), + .o_csr_d_sel(csr_d_sel), + .o_csr_imm_en(csr_imm_en), + .o_mtval_pc(mtval_pc), + .o_immdec_ctrl(immdec_ctrl), + .o_immdec_en(immdec_en), + .o_op_b_source(op_b_source), + .o_rd_mem_en(rd_mem_en), + .o_rd_csr_en(rd_csr_en), + .o_rd_alu_en(rd_alu_en) + ); + +endmodule diff --git a/bench/decoder_tb.cpp b/bench/decoder_tb.cpp new file mode 100644 index 0000000..6fc0d83 --- /dev/null +++ b/bench/decoder_tb.cpp @@ -0,0 +1,157 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "verilated_vcd_c.h" +#include "Vdecoder_sim.h" + +void INThandler(int signal) { + std::cout << "\nCaught ctrl-c\n"; + std::exit(0); +} + +void test_instruction(Vdecoder_sim *top, const std::string& instr_name, uint32_t instr); +void cycle(Vdecoder_sim *top); + +int main(int argc, char** argv, char** env) { + Verilated::commandArgs(argc, argv); + + Vdecoder_sim *top = new Vdecoder_sim; + std::signal(SIGINT, INThandler); + + top->wb_clk = 0; + top->wb_rdt = 0; + top->wb_en = 0; + + std::cout << "Testing decoder\n"; + test_instruction(top, "jalr", 0x0000006F); + test_instruction(top, "mret", 0x30200073); + test_instruction(top, "ebreak", 0x00100073); + test_instruction(top, "wfi", 0x10500073); + test_instruction(top, "add", 0x00000033); + test_instruction(top, "addi", 0x00000013); + test_instruction(top, "sub", 0x40000033); + test_instruction(top, "and", 0x00007033); + test_instruction(top, "andi", 0x00007013); + test_instruction(top, "or", 0x00006033); + test_instruction(top, "ori", 0x00006013); + test_instruction(top, "xor", 0x00004033); + test_instruction(top, "xori", 0x00004013); + test_instruction(top, "sll", 0x00001033); + test_instruction(top, "slli", 0x00001013); + test_instruction(top, "srl", 0x00005033); + test_instruction(top, "srli", 0x00005013); + test_instruction(top, "sra", 0x40005033); + test_instruction(top, "srai", 0x40005013); + test_instruction(top, "lui", 0x00000037); + test_instruction(top, "auipc", 0x00000017); + test_instruction(top, "lw", 0x00002003); + test_instruction(top, "lh", 0x00001003); + test_instruction(top, "lhu", 0x00005003); + test_instruction(top, "lb", 0x00000003); + test_instruction(top, "lbu", 0x00004003); + test_instruction(top, "sw", 0x00002023); + test_instruction(top, "sh", 0x00001023); + test_instruction(top, "sb", 0x00000023); + test_instruction(top, "jal", 0x0000006F); + test_instruction(top, "jalr", 0x00000067); + test_instruction(top, "beq", 0x00000063); + test_instruction(top, "bne", 0x00001063); + test_instruction(top, "blt", 0x00004063); + test_instruction(top, "bge", 0x00005063); + test_instruction(top, "bltu", 0x00006063); + test_instruction(top, "bgeu", 0x00007063); + test_instruction(top, "slt", 0x00002033); + test_instruction(top, "slti", 0x00002013); + test_instruction(top, "sltu", 0x00003033); + test_instruction(top, "sltiu", 0x00003013); + test_instruction(top, "ecall", 0x00000073); + test_instruction(top, "ebreak", 0x00100073); + test_instruction(top, "fence", 0x0000000F); + test_instruction(top, "fence.i", 0x0000100F); + + test_instruction(top, "csrrw", 0x00001073); + test_instruction(top, "csrrs", 0x00002073); + test_instruction(top, "csrrc", 0x00003073); + test_instruction(top, "csrrwi", 0x00005073); + test_instruction(top, "csrrsi", 0x00006073); + test_instruction(top, "csrrci", 0x00007073); + return 0; +} + +void cycle(Vdecoder_sim *top) { + top->eval(); + top->wb_clk = 0; + top->eval(); + top->wb_clk = 1; + top->eval(); +} + +void test_instruction(Vdecoder_sim *top, const std::string& instr_name, uint32_t instr) { + std::ofstream outfile(instr_name + ".txt"); + + std::cout << "Testing " << instr_name << "\n"; + outfile << "Testing " << instr_name << "\n"; + + top->wb_rdt = instr >> 2; + top->wb_en = 1; + cycle(top); + + outfile << "jal_or_jalr: " << std::to_string(top->jal_or_jalr) << std::endl; + outfile << "ebreak: " << std::to_string(top->ebreak) << std::endl; + outfile << "mret: " << std::to_string(top->mret) << std::endl; + outfile << "wfi: " << std::to_string(top->wfi) << std::endl; + outfile << "sh_right: " << std::to_string(top->sh_right) << std::endl; + outfile << "bne_or_bge: " << std::to_string(top->bne_or_bge) << std::endl; + outfile << "cond_branch: " << std::to_string(top->cond_branch) << std::endl; + outfile << "e_op: " << std::to_string(top->e_op) << std::endl; + outfile << "branch_op: " << std::to_string(top->branch_op) << std::endl; + outfile << "shift_op: " << std::to_string(top->shift_op) << std::endl; + outfile << "slt_or_branch: " << std::to_string(top->slt_or_branch) << std::endl; + outfile << "rd_op: " << std::to_string(top->rd_op) << std::endl; + outfile << "two_stage_op: " << std::to_string(top->two_stage_op) << std::endl; + outfile << "dbus_en: " << std::to_string(top->dbus_en) << std::endl; + outfile << "mdu_op: " << std::to_string(top->mdu_op) << std::endl; + outfile << "ext_funct3: " << std::to_string(top->ext_funct3) << std::endl; + outfile << "bufreg_rs1_en: " << std::to_string(top->bufreg_rs1_en) << std::endl; + outfile << "bufreg_imm_en: " << std::to_string(top->bufreg_imm_en) << std::endl; + outfile << "bufreg_clr_lsb: " << std::to_string(top->bufreg_clr_lsb) << std::endl; + outfile << "bufreg_sh_signed: " << std::to_string(top->bufreg_sh_signed) << std::endl; + outfile << "ctrl_utype: " << std::to_string(top->ctrl_utype) << std::endl; + outfile << "ctrl_pc_rel: " << std::to_string(top->ctrl_pc_rel) << std::endl; + outfile << "alu_sub: " << std::to_string(top->alu_sub) << std::endl; + outfile << "alu_bool_op: " << std::to_string(top->alu_bool_op) << std::endl; + outfile << "alu_cmp_eq: " << std::to_string(top->alu_cmp_eq) << std::endl; + outfile << "alu_cmp_sig: " << std::to_string(top->alu_cmp_sig) << std::endl; + outfile << "alu_rd_sel: " << std::to_string(top->alu_rd_sel) << std::endl; + outfile << "mem_signed: " << std::to_string(top->mem_signed) << std::endl; + outfile << "mem_word: " << std::to_string(top->mem_word) << std::endl; + outfile << "mem_half: " << std::to_string(top->mem_half) << std::endl; + outfile << "mem_cmd: " << std::to_string(top->mem_cmd) << std::endl; + outfile << "csr_en: " << std::to_string(top->csr_en) << std::endl; + outfile << "csr_addr: " << std::to_string(top->csr_addr) << std::endl; + outfile << "csr_mstatus_en: " << std::to_string(top->csr_mstatus_en) << std::endl; + outfile << "csr_mie_en: " << std::to_string(top->csr_mie_en) << std::endl; + outfile << "csr_mcause_en: " << std::to_string(top->csr_mcause_en) << std::endl; + outfile << "csr_source: " << std::to_string(top->csr_source) << std::endl; + outfile << "csr_d_sel: " << std::to_string(top->csr_d_sel) << std::endl; + outfile << "csr_imm_en: " << std::to_string(top->csr_imm_en) << std::endl; + outfile << "mtval_pc: " << std::to_string(top->mtval_pc) << std::endl; + outfile << "immdec_ctrl: " << std::to_string(top->immdec_ctrl) << std::endl; + outfile << "immdec_en: " << std::to_string(top->immdec_en) << std::endl; + outfile << "op_b_source: " << std::to_string(top->op_b_source) << std::endl; + outfile << "rd_mem_en: " << std::to_string(top->rd_mem_en) << std::endl; + outfile << "rd_csr_en: " << std::to_string(top->rd_csr_en) << std::endl; + outfile << "rd_alu_en: " << std::to_string(top->rd_alu_en) << std::endl; + + assert(!(top->wfi && instr_name != "wfi")); + + top->wb_en = 0; + cycle(top); + outfile.close(); +} diff --git a/data/verilator_waiver.vlt b/data/verilator_waiver.vlt index cbaddd1..ae9cf64 100644 --- a/data/verilator_waiver.vlt +++ b/data/verilator_waiver.vlt @@ -1,6 +1,9 @@ `verilator_config // Bits [1:0] in i_wb_rdt are not used at all -lint_off -rule UNUSED -file "*/serv_top.v" -lines 185 +lint_off -rule UNUSED -file "*/serv_top.v" -lines 95 + +// Bits [1:0] in i_wb_rdt are not used at all +lint_off -rule UNUSED -file "*/serv_top.v" -lines 186 //Some bits in the instruction word are not used in serv_decode but it's easier //to just send in the whole word than picking out bits diff --git a/rtl/serv_debug.v b/rtl/serv_debug.v index 1d5ac68..f46cb51 100644 --- a/rtl/serv_debug.v +++ b/rtl/serv_debug.v @@ -182,7 +182,7 @@ module serv_debug if (update_mcause) dbg_mcause <= dbg_csr; end - reg LUI, AUIPC, JAL, JALR, BEQ, BNE, BLT, BGE, BLTU, BGEU, LB, LH, LW, LBU, LHU, SB, SH, SW, ADDI, SLTI, SLTIU, XORI, ORI, ANDI,SLLI, SRLI, SRAI, ADD, SUB, SLL, SLT, SLTU, XOR, SRL, SRA, OR, AND, FENCE, ECALL, EBREAK; + reg LUI, AUIPC, JAL, JALR, BEQ, BNE, BLT, BGE, BLTU, BGEU, LB, LH, LW, LBU, LHU, SB, SH, SW, ADDI, SLTI, SLTIU, XORI, ORI, ANDI,SLLI, SRLI, SRAI, ADD, SUB, SLL, SLT, SLTU, XOR, SRL, SRA, OR, AND, FENCE, ECALL, EBREAK, WFI; reg CSRRW, CSRRS, CSRRC, CSRRWI, CSRRSI, CSRRCI; reg OTHER; @@ -228,6 +228,7 @@ module serv_debug FENCE <= 1'b0; ECALL <= 1'b0; EBREAK <= 1'b0; + WFI <= 1'b0; CSRRW <= 1'b0; CSRRS <= 1'b0; CSRRC <= 1'b0; @@ -279,6 +280,7 @@ module serv_debug 32'b???????_?????_?????_000_?????_00011_11 : FENCE <= 1'b1; 32'b0000000_00000_00000_000_00000_11100_11 : ECALL <= 1'b1; 32'b0000000_00001_00000_000_00000_11100_11 : EBREAK <= 1'b1; + 32'b0001000_00010_00000_000_00000_11100_11 : WFI <= 1'b1; 32'b???????_?????_?????_001_?????_11100_11 : CSRRW <= 1'b1; 32'b???????_?????_?????_010_?????_11100_11 : CSRRS <= 1'b1; 32'b???????_?????_?????_011_?????_11100_11 : CSRRC <= 1'b1; diff --git a/rtl/serv_decode.v b/rtl/serv_decode.v index 5a9c34c..97cbeb2 100644 --- a/rtl/serv_decode.v +++ b/rtl/serv_decode.v @@ -19,6 +19,7 @@ module serv_decode output reg o_cond_branch, output reg o_e_op, output reg o_ebreak, + output reg o_wfi, output reg o_branch_op, output reg o_shift_op, output reg o_rd_op, @@ -82,7 +83,7 @@ module serv_decode 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; + (funct3[1] & ~funct3[2] & ~opcode[0] & ~opcode[4]) | co_mdu_op | o_wfi; wire co_shift_op = (opcode[2] & ~funct3[1]) & !co_mdu_op; wire co_branch_op = opcode[4]; wire co_dbus_en = ~opcode[2] & ~opcode[4]; @@ -133,20 +134,22 @@ module serv_decode wire co_sh_right = funct3[2]; wire co_bne_or_bge = funct3[0]; - //Matches system ops except ecall/ebreak/mret + //Matches system ops except ecall/ebreak/mret/wfi wire csr_op = opcode[4] & opcode[2] & (|funct3); //op20 - wire co_ebreak = op20; + wire co_ebreak = op20 & !op22; + + wire co_wfi = opcode[4] & opcode[2] & op22 & !(|funct3); //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); + //and mret (!op21) and wfi (!op22) + wire co_e_op = opcode[4] & opcode[2] & !op21 & !op22 & !(|funct3); //opcode & funct3 & imm30 @@ -261,6 +264,7 @@ module serv_decode o_two_stage_op = co_two_stage_op; o_e_op = co_e_op; o_ebreak = co_ebreak; + o_wfi = co_wfi; o_branch_op = co_branch_op; o_shift_op = co_shift_op; o_rd_op = co_rd_op; @@ -319,6 +323,7 @@ module serv_decode o_cond_branch <= co_cond_branch; o_e_op <= co_e_op; o_ebreak <= co_ebreak; + o_wfi <= co_wfi; o_two_stage_op <= co_two_stage_op; o_dbus_en <= co_dbus_en; o_mtval_pc <= co_mtval_pc; diff --git a/rtl/serv_top.v b/rtl/serv_top.v index 95e7b1c..17e1ee1 100644 --- a/rtl/serv_top.v +++ b/rtl/serv_top.v @@ -92,6 +92,7 @@ module serv_top wire two_stage_op; wire e_op; wire ebreak; + wire wfi; wire branch_op; wire shift_op; wire rd_op; @@ -304,6 +305,7 @@ module serv_top .o_dbus_en (dbus_en), .o_e_op (e_op), .o_ebreak (ebreak), + .o_wfi (wfi), .o_branch_op (branch_op), .o_shift_op (shift_op), .o_rd_op (rd_op), diff --git a/serv.core b/serv.core index 7dc4167..3c3529b 100644 --- a/serv.core +++ b/serv.core @@ -32,6 +32,19 @@ filesets: - data/params.tcl : {file_type : tclSource} - rtl/serv_synth_wrapper.v : {file_type : verilogSource} + verilator_decoder_tb: + files: + - bench/decoder_sim.v + - "bench/decoder_tb.cpp" : {file_type : cppSource} + file_type : verilogSource + + decoder_tb: + files: + - bench/decoder_sim.v + - bench/decoder_tb.v + file_type : verilogSource + depend : [vlog_tb_utils] + targets: default: filesets : [core] @@ -65,6 +78,18 @@ targets: filesets : [core, openlane] toplevel : serv_synth_wrapper + verilator_decoder_tb: + description: Verilator decoder testbench + filesets : [core, verilator_decoder_tb] + flow: sim + flow_options: + tool: verilator + verilator_options : [--trace] + parameters : + - RISCV_FORMAL + - "mdu? (MDU=1)" + toplevel : decoder_sim + parameters: MDU: datatype : int