1
0
mirror of https://github.com/olofk/serv.git synced 2026-02-27 16:52:43 +00:00

add support for WFI instruction

This commit is contained in:
Alfred Persson Forsberg
2025-05-12 14:40:43 +02:00
committed by Olof Kindgren
parent f5ddfaa637
commit b4216a030d
7 changed files with 311 additions and 7 deletions

110
bench/decoder_sim.v Normal file
View File

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

157
bench/decoder_tb.cpp Normal file
View File

@@ -0,0 +1,157 @@
#include <fcntl.h>
#include <cstdint>
#include <csignal>
#include <iostream>
#include <fstream>
#include <memory>
#include <ctime>
#include <string>
#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();
}

View File

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

View File

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

View File

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

View File

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

View File

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