boilerplate for external interrupts

Signed-off-by: Alfred Persson Forsberg <cat@catcream.org>
This commit is contained in:
Alfred Persson Forsberg 2025-01-27 17:09:16 +01:00 committed by Olof Kindgren
parent a72c1e8737
commit 41c0d44e5f
34 changed files with 1337 additions and 44 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

@ -0,0 +1,42 @@
`default_nettype none
module servant_external_sim
(input wire wb_clk,
input wire wb_rst,
input wire ext_irq,
output wire [31:0] pc_adr,
output wire pc_vld,
output wire q,
output wire mret
);
parameter memfile = "";
parameter memsize = 8192;
parameter width = 1;
parameter with_csr = 1;
parameter compressed = 0;
parameter align = compressed;
parameter interrupt_time = 3000;
reg [1023:0] firmware_file;
initial
if ($value$plusargs("firmware=%s", firmware_file)) begin
$display("Loading RAM from %0s", firmware_file);
$readmemh(firmware_file, dut.servant.ram.mem);
end
servant_sleep_dummy
#(.memfile (memfile),
.memsize (memsize),
.width (width),
.debug (1'b1),
.sim (1),
.with_csr (with_csr),
.compress (compressed[0:0]),
.align (align[0:0]))
dut(wb_clk, wb_rst, ext_irq, q);
assign pc_adr = dut.servant.wb_mem_adr;
assign pc_vld = dut.servant.wb_mem_ack;
assign mret = dut.servant.cpu.cpu.mret;
endmodule

View file

@ -0,0 +1,126 @@
#include <fcntl.h>
#include <stdint.h>
#include <signal.h>
#include "verilated_vcd_c.h"
#include "Vservant_external_sim.h"
#include <ctime>
using namespace std;
static bool done;
vluint64_t main_time = 0; // Current simulation time
// This is a 64-bit integer to reduce wrap over issues and
// allow modulus. You can also use a double, if you wish.
double sc_time_stamp () { // Called by $time in Verilog
return main_time; // converts to double, to match
// what SystemC does
}
void INThandler(int signal) {
printf("\nCaught ctrl-c\n");
done = true;
}
int reset(Vservant_external_sim *, VerilatedVcdC *);
int timer_test(Vservant_external_sim *, VerilatedVcdC *,
vluint64_t, vluint64_t);
int main(int argc, char **argv, char **env) {
Verilated::commandArgs(argc, argv);
Vservant_external_sim* top = new Vservant_external_sim;
VerilatedVcdC * tfp = 0;
const char *vcd = Verilated::commandArgsPlusMatch("vcd=");
if (vcd[0]) {
Verilated::traceEverOn(true);
tfp = new VerilatedVcdC;
top->trace (tfp, 99);
tfp->open ("trace.vcd");
}
signal(SIGINT, INThandler);
vluint64_t timeout = 0;
const char *arg_timeout = Verilated::commandArgsPlusMatch("timeout=");
if (arg_timeout[0])
timeout = atoi(arg_timeout+9);
vluint64_t interrupt_time = 1500;
const char *arg_interrupt_time =
Verilated::commandArgsPlusMatch("interrupt_time=");
if (arg_interrupt_time[0]) {
interrupt_time = atoi(arg_interrupt_time);
}
vluint64_t vcd_start = 0;
const char *arg_vcd_start = Verilated::commandArgsPlusMatch("vcd_start=");
if (arg_vcd_start[0])
vcd_start = atoi(arg_vcd_start+11);
int cur_cycle = 0;
int last_cycle = 0;
std::time_t last_time = std::time(nullptr);
top->wb_clk = 1;
top->ext_irq = 0;
bool q = top->q;
int clock = 0;
reset(top, tfp);
timer_test(top, tfp, timeout, interrupt_time);
if (tfp) {
tfp->close();
}
exit(0);
}
int reset(Vservant_external_sim *top, VerilatedVcdC *tfp) {
top->wb_rst = 1;
for (int i = 0; i < 10; i++) {
top->wb_clk = !top->wb_clk;
top->eval();
}
top->wb_clk = !top->wb_clk;
top->wb_rst = 0;
return 0;
}
int timer_test(Vservant_external_sim *top, VerilatedVcdC *tfp,
vluint64_t timeout, vluint64_t interrupt_time) {
int clock = 0;
while (Verilated::gotFinish()) {
top->eval();
if (top->wb_clk) {
clock++;
}
if (tfp && top->wb_clk) {
tfp->dump(clock);
}
if (clock >= interrupt_time && clock <= interrupt_time + 100) {
if (top->ext_irq == 0) {
printf("interrupting %d\n", clock);
}
top->ext_irq = 1;
} else {
top->ext_irq = 0;
}
if (top->wb_clk && top->pc_vld && top->pc_adr) {
std::this_thread::sleep_for(std::chrono::milliseconds(500));
printf("%d | %d\n", clock, top->pc_adr);
if (top->mret) {
printf("mret detected, exiting\n");
exit(0);
}
}
if (timeout && (clock >= timeout)) {
printf("Timeout: Exiting at time %d\n", clock);
exit(0);
}
top->wb_clk = !top->wb_clk;
}
}

View file

@ -29,7 +29,7 @@ module servant_sim
.with_csr (with_csr), .with_csr (with_csr),
.compress (compressed[0:0]), .compress (compressed[0:0]),
.align (align[0:0])) .align (align[0:0]))
dut(wb_clk, wb_rst, q); dut(wb_clk, wb_clk, wb_rst, q);
assign pc_adr = dut.wb_mem_adr; assign pc_adr = dut.wb_mem_adr;
assign pc_vld = dut.wb_mem_ack; assign pc_vld = dut.wb_mem_ack;

43
bench/servant_timer_sim.v Normal file
View file

@ -0,0 +1,43 @@
`default_nettype none
module servant_timer_sim
(input wire wb_clk,
input wire wb_rst,
input wire timer_clk,
output wire [31:0] pc_adr,
output wire pc_vld,
output wire q,
output wire timer_irq
);
parameter memfile = "";
parameter memsize = 8192;
parameter width = 1;
parameter with_csr = 1;
parameter compressed = 0;
parameter align = compressed;
wire sleep;
wire ext_irq;
reg [1023:0] firmware_file;
initial
if ($value$plusargs("firmware=%s", firmware_file)) begin
$display("Loading RAM from %0s", firmware_file);
$readmemh(firmware_file, dut.servant.ram.mem);
end
servant_sleep_dummy
#(.memfile (memfile),
.memsize (memsize),
.width (width),
.debug (1'b1),
.sim (1),
.with_csr (with_csr),
.compress (compressed[0:0]),
.align (align[0:0]))
dut(wb_clk, wb_rst, ext_irq, q);
assign pc_adr = dut.servant.wb_mem_adr;
assign pc_vld = dut.servant.wb_mem_ack;
assign timer_irq = dut.servant.timer_irq;
endmodule

View file

@ -0,0 +1,92 @@
#include <fcntl.h>
#include <stdint.h>
#include <signal.h>
#include "verilated_vcd_c.h"
#include "Vservant_timer_sim.h"
#include <ctime>
using namespace std;
static bool done;
vluint64_t main_time = 0; // Current simulation time
// This is a 64-bit integer to reduce wrap over issues and
// allow modulus. You can also use a double, if you wish.
double sc_time_stamp () { // Called by $time in Verilog
return main_time; // converts to double, to match
// what SystemC does
}
void INThandler(int signal)
{
printf("\nCaught ctrl-c\n");
done = true;
}
int main(int argc, char **argv, char **env)
{
int baud_rate = 0;
Verilated::commandArgs(argc, argv);
Vservant_timer_sim* top = new Vservant_timer_sim;
VerilatedVcdC * tfp = 0;
const char *vcd = Verilated::commandArgsPlusMatch("vcd=");
if (vcd[0]) {
Verilated::traceEverOn(true);
tfp = new VerilatedVcdC;
top->trace (tfp, 99);
tfp->open ("trace.vcd");
}
signal(SIGINT, INThandler);
vluint64_t timeout = 0;
const char *arg_timeout = Verilated::commandArgsPlusMatch("timeout=");
if (arg_timeout[0])
timeout = atoi(arg_timeout+9);
vluint64_t vcd_start = 0;
const char *arg_vcd_start = Verilated::commandArgsPlusMatch("vcd_start=");
if (arg_vcd_start[0])
vcd_start = atoi(arg_vcd_start+11);
int cur_cycle = 0;
int last_cycle = 0;
std::time_t last_time = std::time(nullptr);
top->wb_clk = 0;
top->timer_clk = 0;
bool q = top->q;
int clock = 0;
top->eval();
while (!(done || Verilated::gotFinish())) {
top->eval();
if (top->wb_clk) {
clock++;
}
top->wb_rst = main_time < 1000;
if (tfp) {
tfp->dump(main_time);
}
if (top->wb_clk && top->pc_vld && top->pc_adr) {
std::this_thread::sleep_for(std::chrono::milliseconds(500));
printf("%d | %d\n", clock, top->pc_adr);
}
if (timeout && (main_time >= timeout)) {
printf("Timeout: Exiting at time %lu\n", main_time);
done = true;
}
top->wb_clk = !top->wb_clk;
top->timer_clk = top->wb_clk;
main_time+=31.25;
}
if (tfp) {
tfp->close();
}
exit(0);
}

17
data/nexys_4.xdc Normal file
View file

@ -0,0 +1,17 @@
## 100 MHz Clock Signal (period 10)
set_property -dict { PACKAGE_PIN E3 IOSTANDARD LVCMOS33 } [get_ports { i_clk }];
create_clock -add -name sys_clk_pin -period 10 -waveform {0 5} [get_ports { i_clk }];
## External interrupt (to BTNL)
set_property -dict { PACKAGE_PIN T16 IOSTANDARD LVCMOS33 } [get_ports {ext_irq}];
## LEDs
set_property -dict { PACKAGE_PIN T8 IOSTANDARD LVCMOS33 } [get_ports { q }];
## UART
set_property -dict { PACKAGE_PIN D4 IOSTANDARD LVCMOS33 } [get_ports { o_uart_tx }];
set_property -dict { PACKAGE_PIN C12 IOSTANDARD LVCMOS33 } [get_ports { i_rst }]; # ACTIVE LOW !!!
set_property CFGBVS VCCO [current_design]
set_property CONFIG_VOLTAGE 3.3 [current_design]

View file

@ -1,4 +1,23 @@
set_property -dict {PACKAGE_PIN E3 IOSTANDARD LVCMOS33 } [get_ports i_clk]; ## 100 MHz Clock Signal (period 10)
set_property -dict {PACKAGE_PIN D4 IOSTANDARD LVCMOS33 } [get_ports q] set_property -dict { PACKAGE_PIN E3 IOSTANDARD LVCMOS33 } [get_ports { i_clk }];
create_clock -add -name sys_clk_pin -period 10 -waveform {0 5} [get_ports { i_clk }];
create_clock -add -name sys_clk_pin -period 10.00 -waveform {0 5} [get_ports i_clk]; ## External interrupt (to BTNL)
set_property -dict { PACKAGE_PIN P17 IOSTANDARD LVCMOS33 } [get_ports {ext_irq}];
## LEDs (LED0)
set_property -dict { PACKAGE_PIN H17 IOSTANDARD LVCMOS33 } [get_ports { q }];
## UART
set_property -dict { PACKAGE_PIN D4 IOSTANDARD LVCMOS33 } [get_ports { o_uart_tx }];
set_property -dict { PACKAGE_PIN C12 IOSTANDARD LVCMOS33 } [get_ports { i_rst }]; # ACTIVE LOW !!!
set_property CFGBVS VCCO [current_design]
set_property CONFIG_VOLTAGE 3.3 [current_design]
## DEBUG (JA1)
#set_property -dict { PACKAGE_PIN C17 IOSTANDARD LVCMOS33 } [get_ports { debug_wb_clk }]; #JA1
#set_property -dict { PACKAGE_PIN D18 IOSTANDARD LVCMOS33 } [get_ports { q }]; #JA2
#set_property -dict { PACKAGE_PIN E18 IOSTANDARD LVCMOS33 } [get_ports { debug_sleep_req }]; #JA3
#set_property -dict { PACKAGE_PIN G17 IOSTANDARD LVCMOS33 } [get_ports { debug_wakeup_req }]; #JA4

View file

@ -19,6 +19,7 @@ module serv_csr
input wire i_cnt_done, input wire i_cnt_done,
input wire i_mem_op, input wire i_mem_op,
input wire i_mtip, input wire i_mtip,
input wire i_meip,
input wire i_trap, input wire i_trap,
output reg o_new_irq, output reg o_new_irq,
//Control //Control
@ -36,7 +37,9 @@ module serv_csr
output wire [B:0] o_csr_in, output wire [B:0] o_csr_in,
input wire [B:0] i_csr_imm, input wire [B:0] i_csr_imm,
input wire [B:0] i_rs1, input wire [B:0] i_rs1,
output wire [B:0] o_q); output wire [B:0] o_q,
output wire o_meie,
output wire o_mtie);
localparam [1:0] localparam [1:0]
CSR_SOURCE_CSR = 2'b00, CSR_SOURCE_CSR = 2'b00,
@ -47,6 +50,10 @@ module serv_csr
reg mstatus_mie; reg mstatus_mie;
reg mstatus_mpie; reg mstatus_mpie;
reg mie_mtie; reg mie_mtie;
reg mie_meie;
assign o_meie = mie_meie;
assign o_mtie = mie_mtie;
reg mcause31; reg mcause31;
reg [3:0] mcause3_0; reg [3:0] mcause3_0;
@ -55,7 +62,7 @@ module serv_csr
wire [B:0] csr_in; wire [B:0] csr_in;
wire [B:0] csr_out; wire [B:0] csr_out;
reg timer_irq_r; reg irq_r;
wire [B:0] d = i_csr_d_sel ? i_csr_imm : i_rs1; wire [B:0] d = i_csr_d_sel ? i_csr_imm : i_rs1;
@ -81,7 +88,9 @@ module serv_csr
assign o_q = csr_out; assign o_q = csr_out;
wire timer_irq = i_mtip & mstatus_mie & mie_mtie; wire timer_irq = i_mtip & mie_mtie;
wire ext_irq = i_meip & mie_meie;
wire irq = (timer_irq | ext_irq) & mstatus_mie;
assign mcause = i_cnt0to3 ? mcause3_0[B:0] : //[3:0] assign mcause = i_cnt0to3 ? mcause3_0[B:0] : //[3:0]
i_cnt_done ? {mcause31,{B{1'b0}}} //[31] i_cnt_done ? {mcause31,{B{1'b0}}} //[31]
@ -91,13 +100,16 @@ module serv_csr
always @(posedge i_clk) begin always @(posedge i_clk) begin
if (i_trig_irq) begin if (i_trig_irq) begin
timer_irq_r <= timer_irq; irq_r <= irq;
o_new_irq <= timer_irq & !timer_irq_r; o_new_irq <= (irq & !irq_r);
end end
if (i_mie_en & i_cnt7) if (i_mie_en & i_cnt7)
mie_mtie <= csr_in[B]; mie_mtie <= csr_in[B];
if(i_mie_en & i_cnt11)
mie_meie <= csr_in[B];
/* /*
The mie bit in mstatus gets updated under three conditions The mie bit in mstatus gets updated under three conditions
@ -126,8 +138,8 @@ module serv_csr
During an mcause CSR access function, they are assigned when During an mcause CSR access function, they are assigned when
bits 0 to 3 gets updated bits 0 to 3 gets updated
During an external interrupt the exception code is set to During an interrupt, the exception code is assigned to indicate
7, since SERV only support timer interrupts if it was caused by a timer interrupt (7) or an external interrupt (11).
During an exception, the exception code is assigned to indicate During an exception, the exception code is assigned to indicate
if it was caused by an ebreak instruction (3), if it was caused by an ebreak instruction (3),
@ -135,14 +147,15 @@ module serv_csr
or misaligned jump (0) or misaligned jump (0)
The expressions below are derived from the following truth table The expressions below are derived from the following truth table
irq => 0111 (timer=7) timer_irq => 0111 (timer=7)
ext_irq => 1011 (ext=11)
e_op => x011 (ebreak=3, ecall=11) e_op => x011 (ebreak=3, ecall=11)
mem => 01x0 (store=6, load=4) mem => 01x0 (store=6, load=4)
ctrl => 0000 (jump=0) ctrl => 0000 (jump=0)
*/ */
if (i_mcause_en & i_en & i_cnt0to3 | (i_trap & i_cnt_done)) begin if (i_mcause_en & i_en & i_cnt0to3 | (i_trap & i_cnt_done)) begin
mcause3_0[3] <= (i_e_op & !i_ebreak) | (!i_trap & csr_in[B]); mcause3_0[3] <= (o_new_irq & ext_irq) | (i_e_op & !i_ebreak) | (!i_trap & csr_in[B]);
mcause3_0[2] <= o_new_irq | i_mem_op | (!i_trap & ((W == 1) ? mcause3_0[3] : csr_in[(W == 1) ? 0 : 2])); mcause3_0[2] <= (o_new_irq & !ext_irq) | i_mem_op | (!i_trap & ((W == 1) ? mcause3_0[3] : csr_in[(W == 1) ? 0 : 2]));
mcause3_0[1] <= o_new_irq | i_e_op | (i_mem_op & i_mem_cmd) | (!i_trap & ((W == 1) ? mcause3_0[2] : csr_in[(W == 1) ? 0 : 1])); mcause3_0[1] <= o_new_irq | i_e_op | (i_mem_op & i_mem_cmd) | (!i_trap & ((W == 1) ? mcause3_0[2] : csr_in[(W == 1) ? 0 : 1]));
mcause3_0[0] <= o_new_irq | i_e_op | (!i_trap & ((W == 1) ? mcause3_0[1] : csr_in[0])); mcause3_0[0] <= o_new_irq | i_e_op | (!i_trap & ((W == 1) ? mcause3_0[1] : csr_in[0]));
end end
@ -152,6 +165,7 @@ module serv_csr
if (RESET_STRATEGY != "NONE") begin if (RESET_STRATEGY != "NONE") begin
o_new_irq <= 1'b0; o_new_irq <= 1'b0;
mie_mtie <= 1'b0; mie_mtie <= 1'b0;
mie_meie <= 1'b0;
end end
end end

View file

@ -176,7 +176,7 @@ module serv_debug
if (update_mcause) dbg_mcause <= dbg_csr; if (update_mcause) dbg_mcause <= dbg_csr;
end 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 CSRRW, CSRRS, CSRRC, CSRRWI, CSRRSI, CSRRCI;
reg OTHER; reg OTHER;
@ -222,6 +222,7 @@ module serv_debug
FENCE <= 1'b0; FENCE <= 1'b0;
ECALL <= 1'b0; ECALL <= 1'b0;
EBREAK <= 1'b0; EBREAK <= 1'b0;
WFI <= 1'b0;
CSRRW <= 1'b0; CSRRW <= 1'b0;
CSRRS <= 1'b0; CSRRS <= 1'b0;
CSRRC <= 1'b0; CSRRC <= 1'b0;
@ -273,6 +274,7 @@ module serv_debug
32'b???????_?????_?????_000_?????_00011_11 : FENCE <= 1'b1; 32'b???????_?????_?????_000_?????_00011_11 : FENCE <= 1'b1;
32'b0000000_00000_00000_000_00000_11100_11 : ECALL <= 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'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???????_?????_?????_001_?????_11100_11 : CSRRW <= 1'b1;
32'b???????_?????_?????_010_?????_11100_11 : CSRRS <= 1'b1; 32'b???????_?????_?????_010_?????_11100_11 : CSRRS <= 1'b1;
32'b???????_?????_?????_011_?????_11100_11 : CSRRC <= 1'b1; 32'b???????_?????_?????_011_?????_11100_11 : CSRRC <= 1'b1;

View file

@ -13,6 +13,7 @@ module serv_decode
output reg o_cond_branch, output reg o_cond_branch,
output reg o_e_op, output reg o_e_op,
output reg o_ebreak, output reg o_ebreak,
output reg o_wfi,
output reg o_branch_op, output reg o_branch_op,
output reg o_shift_op, output reg o_shift_op,
output reg o_rd_op, output reg o_rd_op,
@ -76,7 +77,7 @@ module serv_decode
wire co_two_stage_op = wire co_two_stage_op =
~opcode[2] | (funct3[0] & ~funct3[1] & ~opcode[0] & ~opcode[4]) | ~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_shift_op = (opcode[2] & ~funct3[1]) & !co_mdu_op;
wire co_branch_op = opcode[4]; wire co_branch_op = opcode[4];
wire co_dbus_en = ~opcode[2] & ~opcode[4]; wire co_dbus_en = ~opcode[2] & ~opcode[4];
@ -127,20 +128,22 @@ module serv_decode
wire co_sh_right = funct3[2]; wire co_sh_right = funct3[2];
wire co_bne_or_bge = funct3[0]; wire co_bne_or_bge = funct3[0];
//Matches system ops except eceall/ebreak/mret //Matches system ops except ecall/ebreak/mret/wfi
wire csr_op = opcode[4] & opcode[2] & (|funct3); wire csr_op = opcode[4] & opcode[2] & (|funct3);
//op20 //op20
wire co_ebreak = op20; wire co_ebreak = op20 & !op22;
wire co_wfi = opcode[4] & opcode[2] & op22 & !(|funct3);
//opcode & funct3 & op21 //opcode & funct3 & op21
wire co_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) //Matches system opcodes except CSR accesses (funct3 == 0)
//and mret (!op21) //and mret (!op21) and wfi (!op22)
wire co_e_op = opcode[4] & opcode[2] & !op21 & !(|funct3); wire co_e_op = opcode[4] & opcode[2] & !op21 & !op22 & !(|funct3);
//opcode & funct3 & imm30 //opcode & funct3 & imm30
@ -255,6 +258,7 @@ module serv_decode
o_two_stage_op = co_two_stage_op; o_two_stage_op = co_two_stage_op;
o_e_op = co_e_op; o_e_op = co_e_op;
o_ebreak = co_ebreak; o_ebreak = co_ebreak;
o_wfi = co_wfi;
o_branch_op = co_branch_op; o_branch_op = co_branch_op;
o_shift_op = co_shift_op; o_shift_op = co_shift_op;
o_rd_op = co_rd_op; o_rd_op = co_rd_op;
@ -313,6 +317,7 @@ module serv_decode
o_cond_branch <= co_cond_branch; o_cond_branch <= co_cond_branch;
o_e_op <= co_e_op; o_e_op <= co_e_op;
o_ebreak <= co_ebreak; o_ebreak <= co_ebreak;
o_wfi <= co_wfi;
o_two_stage_op <= co_two_stage_op; o_two_stage_op <= co_two_stage_op;
o_dbus_en <= co_dbus_en; o_dbus_en <= co_dbus_en;
o_mtval_pc <= co_mtval_pc; o_mtval_pc <= co_mtval_pc;

View file

@ -19,6 +19,10 @@ module serv_rf_top
0 : Register after the decoder. Faster but uses more resources 0 : Register after the decoder. Faster but uses more resources
1 : (default) Register before the decoder. Slower but uses less resources 1 : (default) Register before the decoder. Slower but uses less resources
*/ */
parameter [0:0] EI = 0,
/* asd */
parameter PRE_REGISTER = 1, parameter PRE_REGISTER = 1,
/* Amount of reset applied to design /* Amount of reset applied to design
"NONE" : No reset at all. Relies on a POR to set correct initialization "NONE" : No reset at all. Relies on a POR to set correct initialization
@ -36,6 +40,7 @@ module serv_rf_top
input wire clk, input wire clk,
input wire i_rst, input wire i_rst,
input wire i_timer_irq, input wire i_timer_irq,
input wire i_external_irq,
`ifdef RISCV_FORMAL `ifdef RISCV_FORMAL
output wire rvfi_valid, output wire rvfi_valid,
output wire [63:0] rvfi_order, output wire [63:0] rvfi_order,
@ -77,6 +82,11 @@ module serv_rf_top
output wire [ 2:0] o_ext_funct3, output wire [ 2:0] o_ext_funct3,
input wire [31:0] i_ext_rd, input wire [31:0] i_ext_rd,
input wire i_ext_ready, input wire i_ext_ready,
// Sleep functionality
output wire o_sleep_req,
output wire o_wakeup_req,
// MDU // MDU
output wire o_mdu_valid); output wire o_mdu_valid);
@ -150,6 +160,7 @@ module serv_rf_top
.WITH_CSR (WITH_CSR), .WITH_CSR (WITH_CSR),
.DEBUG (DEBUG), .DEBUG (DEBUG),
.MDU(MDU), .MDU(MDU),
.EI(EI),
.COMPRESSED(COMPRESSED), .COMPRESSED(COMPRESSED),
.ALIGN(ALIGN), .ALIGN(ALIGN),
.W(W)) .W(W))
@ -158,6 +169,7 @@ module serv_rf_top
.clk (clk), .clk (clk),
.i_rst (i_rst), .i_rst (i_rst),
.i_timer_irq (i_timer_irq), .i_timer_irq (i_timer_irq),
.i_external_irq (i_external_irq),
`ifdef RISCV_FORMAL `ifdef RISCV_FORMAL
.rvfi_valid (rvfi_valid ), .rvfi_valid (rvfi_valid ),
.rvfi_order (rvfi_order ), .rvfi_order (rvfi_order ),
@ -208,6 +220,11 @@ module serv_rf_top
.i_dbus_rdt (i_dbus_rdt), .i_dbus_rdt (i_dbus_rdt),
.i_dbus_ack (i_dbus_ack), .i_dbus_ack (i_dbus_ack),
// Sleep
.o_sleep_req (o_sleep_req),
.o_wakeup_req (o_wakeup_req),
//Extension //Extension
.o_ext_funct3 (o_ext_funct3), .o_ext_funct3 (o_ext_funct3),
.i_ext_ready (i_ext_ready), .i_ext_ready (i_ext_ready),

20
rtl/serv_sleep.v Normal file
View file

@ -0,0 +1,20 @@
`default_nettype none
module serv_sleep
(
input wire i_clk,
input wire i_rst,
input wire i_timer_irq,
input wire i_external_irq,
input wire i_cnt0,
input wire i_wfi,
input wire i_init,
input wire i_mtie,
input wire i_meie,
output wire o_sleep_req,
output wire o_wakeup_req);
assign o_sleep_req = i_wfi & i_cnt0 & i_init;
assign o_wakeup_req = (i_timer_irq & i_mtie) | (i_external_irq & i_meie);
endmodule

View file

@ -86,7 +86,8 @@ module serv_synth_wrapper
.PRE_REGISTER (PRE_REGISTER), .PRE_REGISTER (PRE_REGISTER),
.RESET_STRATEGY (RESET_STRATEGY), .RESET_STRATEGY (RESET_STRATEGY),
.WITH_CSR (WITH_CSR), .WITH_CSR (WITH_CSR),
.MDU(1'b0)) .MDU(1'b0),
.EI(1'b0))
cpu cpu
( (
.clk (clk), .clk (clk),

View file

@ -9,12 +9,14 @@ module serv_top
parameter RESET_PC = 32'd0, parameter RESET_PC = 32'd0,
parameter [0:0] DEBUG = 1'b0, parameter [0:0] DEBUG = 1'b0,
parameter [0:0] MDU = 1'b0, parameter [0:0] MDU = 1'b0,
parameter [0:0] EI = 1'b0,
parameter [0:0] COMPRESSED=0, parameter [0:0] COMPRESSED=0,
parameter [0:0] ALIGN = COMPRESSED) parameter [0:0] ALIGN = COMPRESSED)
( (
input wire clk, input wire clk,
input wire i_rst, input wire i_rst,
input wire i_timer_irq, input wire i_timer_irq,
input wire i_external_irq,
`ifdef RISCV_FORMAL `ifdef RISCV_FORMAL
output wire rvfi_valid, output wire rvfi_valid,
output wire [63:0] rvfi_order, output wire [63:0] rvfi_order,
@ -70,6 +72,11 @@ module serv_top
input wire [31:0] i_ext_rd, input wire [31:0] i_ext_rd,
output wire [31:0] o_ext_rs1, output wire [31:0] o_ext_rs1,
output wire [31:0] o_ext_rs2, output wire [31:0] o_ext_rs2,
// Sleep functionality
output wire o_sleep_req,
output wire o_wakeup_req,
//MDU //MDU
output wire o_mdu_valid); output wire o_mdu_valid);
@ -86,6 +93,7 @@ module serv_top
wire two_stage_op; wire two_stage_op;
wire e_op; wire e_op;
wire ebreak; wire ebreak;
wire wfi;
wire branch_op; wire branch_op;
wire shift_op; wire shift_op;
wire rd_op; wire rd_op;
@ -183,6 +191,9 @@ module serv_top
wire [31:0] wb_ibus_rdt; wire [31:0] wb_ibus_rdt;
wire wb_ibus_ack; wire wb_ibus_ack;
wire mie_meie;
wire mie_mtie;
generate generate
if (ALIGN) begin : gen_align if (ALIGN) begin : gen_align
serv_aligner align serv_aligner align
@ -222,6 +233,20 @@ module serv_top
end end
endgenerate endgenerate
serv_sleep sleep
(
.i_clk (clk),
.i_rst (i_rst),
.i_timer_irq (i_timer_irq),
.i_external_irq (i_external_irq),
.i_cnt0 (cnt0),
.i_wfi (wfi),
.i_init (init),
.o_sleep_req (o_sleep_req),
.o_wakeup_req (o_wakeup_req),
.i_meie (mie_meie),
.i_mtie (mie_mtie));
serv_state serv_state
#(.RESET_STRATEGY (RESET_STRATEGY), #(.RESET_STRATEGY (RESET_STRATEGY),
.WITH_CSR (WITH_CSR[0:0]), .WITH_CSR (WITH_CSR[0:0]),
@ -298,6 +323,7 @@ module serv_top
.o_dbus_en (dbus_en), .o_dbus_en (dbus_en),
.o_e_op (e_op), .o_e_op (e_op),
.o_ebreak (ebreak), .o_ebreak (ebreak),
.o_wfi (wfi),
.o_branch_op (branch_op), .o_branch_op (branch_op),
.o_shift_op (shift_op), .o_shift_op (shift_op),
.o_rd_op (rd_op), .o_rd_op (rd_op),
@ -563,6 +589,7 @@ module serv_top
.i_cnt_done (cnt_done), .i_cnt_done (cnt_done),
.i_mem_op (!mtval_pc), .i_mem_op (!mtval_pc),
.i_mtip (i_timer_irq), .i_mtip (i_timer_irq),
.i_meip (i_external_irq),
.i_trap (trap), .i_trap (trap),
.o_new_irq (new_irq), .o_new_irq (new_irq),
//Control //Control
@ -580,7 +607,9 @@ module serv_top
.o_csr_in (csr_in), .o_csr_in (csr_in),
.i_csr_imm (csr_imm), .i_csr_imm (csr_imm),
.i_rs1 (rs1), .i_rs1 (rs1),
.o_q (csr_rd)); .o_q (csr_rd),
.o_meie (mie_meie),
.o_mtie (mie_mtie));
end else begin : gen_no_csr end else begin : gen_no_csr
assign csr_in = {W{1'b0}}; assign csr_in = {W{1'b0}};
assign csr_rd = {W{1'b0}}; assign csr_rd = {W{1'b0}};

View file

@ -23,6 +23,7 @@ filesets:
- rtl/serv_rf_top.v - rtl/serv_rf_top.v
- rtl/serv_aligner.v - rtl/serv_aligner.v
- rtl/serv_compdec.v - rtl/serv_compdec.v
- rtl/serv_sleep.v
file_type : verilogSource file_type : verilogSource
openlane: openlane:
@ -30,6 +31,21 @@ filesets:
- data/params.tcl : {file_type : tclSource} - data/params.tcl : {file_type : tclSource}
- rtl/serv_synth_wrapper.v : {file_type : verilogSource} - 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: targets:
default: default:
filesets : [core] filesets : [core]
@ -37,6 +53,7 @@ targets:
- "is_toplevel? (ALIGN)" - "is_toplevel? (ALIGN)"
- "is_toplevel? (COMPRESSED)" - "is_toplevel? (COMPRESSED)"
- "is_toplevel? (MDU)" - "is_toplevel? (MDU)"
- "is_toplevel? (EI)"
- "is_toplevel? (PRE_REGISTER)" - "is_toplevel? (PRE_REGISTER)"
- "is_toplevel? (RESET_STRATEGY)" - "is_toplevel? (RESET_STRATEGY)"
- RISCV_FORMAL - RISCV_FORMAL
@ -63,12 +80,29 @@ targets:
filesets : [core, openlane] filesets : [core, openlane]
toplevel : serv_synth_wrapper 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: parameters:
MDU: MDU:
datatype : int datatype : int
description: Enables interface for RISC-V standard M-extension description: Enables interface for RISC-V standard M-extension
paramtype : vlogparam paramtype : vlogparam
EI:
datatype : int
description : Enable interface for RISC-V external interrupts
paramtype : vlogparam
PRE_REGISTER: PRE_REGISTER:
datatype : int datatype : int
description : Register signals before or after the decoder description : Register signals before or after the decoder

View file

@ -20,6 +20,22 @@ filesets:
file_type : verilogSource file_type : verilogSource
depend : [vlog_tb_utils] depend : [vlog_tb_utils]
servant_timer_tb:
files:
- sw/timer_interrupt.hex : {file_type: user, copyto: .}
- bench/servant_timer_sim.v
- bench/servant_timer_tb.v
file_type : verilogSource
depend : [vlog_tb_utils]
servant_external_tb:
files:
- sw/external_interrupt.hex : {file_type: user, copyto: .}
- bench/servant_external_sim.v
- bench/servant_external_tb.v
file_type : verilogSource
depend : [vlog_tb_utils]
service: service:
files: files:
- servant/ice40_pll.v - servant/ice40_pll.v
@ -37,7 +53,13 @@ filesets:
- "!tool_quartus? (servant/servant_ram.v)" - "!tool_quartus? (servant/servant_ram.v)"
- servant/servant.v - servant/servant.v
file_type : verilogSource file_type : verilogSource
depend : [servile, "mdu? (mdu)"] depend : [servile, "mdu? (mdu)", "ei? (ei)"]
sleep_dummy:
files:
- servant/servant_sleep_dummy.v
file_type : verilogSource
depend : [servile]
verilator_tb: verilator_tb:
files: files:
@ -47,6 +69,18 @@ filesets:
file_type : verilogSource file_type : verilogSource
depend : ["vidbo? (vidbo)"] depend : ["vidbo? (vidbo)"]
verilator_timer_tb:
files:
- bench/servant_timer_sim.v
- "bench/servant_timer_tb.cpp" : {file_type : cppSource}
file_type : verilogSource
verilator_external_tb:
files:
- bench/servant_external_sim.v
- "bench/servant_external_tb.cpp" : {file_type : cppSource}
file_type : verilogSource
# Target-specific filesets. Alphabetically sorted # Target-specific filesets. Alphabetically sorted
ac701: ac701:
@ -96,6 +130,19 @@ filesets:
- servant/servant_cmod_a7.v : {file_type : verilogSource} - servant/servant_cmod_a7.v : {file_type : verilogSource}
- data/cmod_a7_35t.xdc : {file_type : xdc} - data/cmod_a7_35t.xdc : {file_type : xdc}
nexys_4:
files:
- servant/servant_nexys_4_clock_gen.v : {file_type : verilogSource}
- servant/servant_nexys_4.v : {file_type : verilogSource}
- data/nexys_4.xdc : {file_type : xdc}
nexys_a7:
files:
- servant/servant_nexys_a7_clock_gen.v : {file_type : verilogSource}
- servant/servant_nexys_a7.v : {file_type : verilogSource}
- data/nexys_a7.xdc : {file_type : xdc}
cyc1000: cyc1000:
files: files:
- data/cyc1000.sdc : {file_type : SDC} - data/cyc1000.sdc : {file_type : SDC}
@ -188,11 +235,11 @@ filesets:
- data/nexys_2.tcl : {file_type : tclSource} - data/nexys_2.tcl : {file_type : tclSource}
- data/nexys_2.ucf : {file_type : UCF} - data/nexys_2.ucf : {file_type : UCF}
nexys_a7: # nexys_a7:
files: # files:
- servant/servix_clock_gen.v : {file_type : verilogSource} # - servant/servix_clock_gen.v : {file_type : verilogSource}
- servant/servix.v : {file_type : verilogSource} # - servant/servix.v : {file_type : verilogSource}
- data/nexys_a7.xdc : {file_type : xdc} # - data/nexys_a7.xdc : {file_type : xdc}
orangecrab: orangecrab:
files: files:
@ -330,6 +377,24 @@ targets:
parameters : [memfile, memsize] parameters : [memfile, memsize]
toplevel : servant_cmod_a7 toplevel : servant_cmod_a7
nexys_4:
description: Digilent Nexys 4
filesets : [mem_files, soc, nexys_4]
flow: vivado
flow_options:
part : xc7a100tcsg324-1
parameters : [memfile, memsize]
toplevel : servant_nexys_4
nexys_a7:
description: Digilent Nexys A7
filesets : [mem_files, soc, nexys_a7]
flow: vivado
flow_options:
part : xc7a100tcsg324-1
parameters : [memfile, memsize]
toplevel : servant_nexys_a7
cyc1000: cyc1000:
default_tool: quartus default_tool: quartus
description: cyc1000 FPGA board description: cyc1000 FPGA board
@ -536,15 +601,6 @@ targets:
speed : -4 speed : -4
toplevel : servax toplevel : servax
nexys_a7:
description: Digilent Nexys A7
filesets : [mem_files, soc, nexys_a7]
flow: vivado
flow_options:
part : xc7a100tcsg324-1
parameters : [memfile, memsize, frequency=32]
toplevel : servix
orangecrab_r0.2: orangecrab_r0.2:
default_tool: trellis default_tool: trellis
description : OrangeCrab R0.2 description : OrangeCrab R0.2
@ -588,6 +644,7 @@ targets:
- RISCV_FORMAL - RISCV_FORMAL
- width - width
- "mdu? (MDU=1)" - "mdu? (MDU=1)"
- "ei? (EI=1)"
- SERV_CLEAR_RAM=true - SERV_CLEAR_RAM=true
- firmware - firmware
- memsize - memsize
@ -656,6 +713,7 @@ targets:
parameters : parameters :
- RISCV_FORMAL - RISCV_FORMAL
- "mdu? (MDU=1)" - "mdu? (MDU=1)"
- "ei? (EI=1)"
- cps - cps
- firmware - firmware
- memsize - memsize
@ -671,6 +729,54 @@ targets:
- with_csr=1 - with_csr=1
toplevel : servant_sim toplevel : servant_sim
verilator_timer_tb:
description: Verilator timer testbench
filesets : [soc, sleep_dummy, verilator_timer_tb]
flow: sim
flow_options:
tool: verilator
verilator_options : [--trace]
parameters :
- RISCV_FORMAL
- "mdu? (MDU=1)"
- cps
- firmware
- memsize
- signature
- timeout
- trace_pc
- vcd
- vcd_start
- width
- compressed
- align
- with_csr=1
toplevel : servant_timer_sim
verilator_external_tb:
description: Verilator timer testbench
filesets : [soc, sleep_dummy, verilator_external_tb]
flow: sim
flow_options:
tool: verilator
verilator_options : [--trace]
parameters :
- RISCV_FORMAL
- "mdu? (MDU=1)"
- cps
- firmware
- memsize
- signature
- timeout
- trace_pc
- vcd
- vcd_start
- width
- compressed
- align
- with_csr=1
toplevel : servant_external_sim
zcu106: zcu106:
default_tool: vivado default_tool: vivado
description : Zynq UltraScale+ MPSoC ZCU106 Evaluation Kit description : Zynq UltraScale+ MPSoC ZCU106 Evaluation Kit
@ -711,6 +817,11 @@ parameters:
description : Enables RISC-V standard M-extension description : Enables RISC-V standard M-extension
paramtype : vlogdefine paramtype : vlogdefine
EI:
datatype : int
description : Enable interface for RISC-V external interrupts
paramtype : vlogdefine
memfile: memfile:
datatype : file datatype : file
description : Preload RAM with a hex file at compile-time description : Preload RAM with a hex file at compile-time

View file

@ -2,8 +2,11 @@
module servant module servant
( (
input wire wb_clk, input wire wb_clk,
input wire main_clk,
input wire wb_rst, input wire wb_rst,
output wire q); input wire ext_irq,
output wire q,
output reg o_sleep);
parameter memfile = "zephyr_hello.hex"; parameter memfile = "zephyr_hello.hex";
parameter memsize = 8192; parameter memsize = 8192;
@ -22,6 +25,12 @@ module servant
localparam [0:0] with_mdu = 1'b0; localparam [0:0] with_mdu = 1'b0;
`endif `endif
`ifdef EI
localparam [0:0] with_ei = 1'b1;
`else
localparam [0:0] with_ei = 1'b0;
`endif
localparam aw = $clog2(memsize); localparam aw = $clog2(memsize);
localparam csr_regs = with_csr*4; localparam csr_regs = with_csr*4;
@ -63,6 +72,8 @@ module servant
wire [rf_l2d-1:0] rf_raddr; wire [rf_l2d-1:0] rf_raddr;
wire rf_ren; wire rf_ren;
wire [rf_width-1:0] rf_rdata; wire [rf_width-1:0] rf_rdata;
wire sleep_req;
wire wakeup_req;
servant_mux servant_mux servant_mux servant_mux
( (
@ -106,7 +117,7 @@ module servant
#(.RESET_STRATEGY (reset_strategy), #(.RESET_STRATEGY (reset_strategy),
.WIDTH (32)) .WIDTH (32))
timer timer
(.i_clk (wb_clk), (.i_clk (main_clk),
.i_rst (wb_rst), .i_rst (wb_rst),
.o_irq (timer_irq), .o_irq (timer_irq),
.i_wb_cyc (wb_timer_stb), .i_wb_cyc (wb_timer_stb),
@ -140,12 +151,16 @@ module servant
.debug (debug), .debug (debug),
.with_c (compress[0]), .with_c (compress[0]),
.with_csr (with_csr[0]), .with_csr (with_csr[0]),
.with_mdu (with_mdu)) .with_mdu (with_mdu),
.with_ei (with_ei))
cpu cpu
( (
.i_clk (wb_clk), .i_clk (wb_clk),
.i_rst (wb_rst), .i_rst (wb_rst),
.i_timer_irq (timer_irq), .i_timer_irq (timer_irq),
.i_external_irq (ext_irq),
.o_wakeup_req (wakeup_req),
.o_sleep_req (sleep_req),
.o_wb_mem_adr (wb_mem_adr), .o_wb_mem_adr (wb_mem_adr),
.o_wb_mem_dat (wb_mem_dat), .o_wb_mem_dat (wb_mem_dat),
@ -170,4 +185,13 @@ module servant
.o_rf_ren (rf_ren), .o_rf_ren (rf_ren),
.i_rf_rdata (rf_rdata)); .i_rf_rdata (rf_rdata));
always @(posedge main_clk) begin
if (sleep_req)
o_sleep <= 1;
if (wakeup_req)
o_sleep <= 0;
if (wb_rst)
o_sleep <= 0;
end
endmodule endmodule

53
servant/servant_nexys_4.v Normal file
View file

@ -0,0 +1,53 @@
`default_nettype none
module servant_nexys_4
(
input wire i_clk,
input wire i_rst,
input wire ext_irq,
output wire o_uart_tx,
output wire q);
parameter memfile = "zephyr_hello.hex";
parameter memsize = 8192;
wire main_clk;
wire wb_clk;
wire wb_rst;
wire sleep_req;
wire wakeup_req;
reg sleep;
always @(posedge main_clk) begin
if (sleep_req)
sleep <= 0;
if (wakeup_req)
sleep <= 1;
if (wb_rst)
sleep <= 1;
end
assign o_uart_tx = q;
servant_nexys_4_clock_gen
clock_gen
(.i_clk (i_clk),
.i_rst (i_rst),
.i_clk0_en (sleep),
.i_clk1_en (1),
.o_clk0 (main_clk),
.o_clk1 (wb_clk),
.o_rst (wb_rst));
servant
#(.memfile (memfile),
.memsize (memsize))
servant
(.wb_clk (wb_clk),
.wb_rst (wb_rst),
.q (q),
.o_sleep_req (sleep_req),
.o_wakeup_req (wakeup_req));
endmodule
`default_nettype wire

View file

@ -0,0 +1,54 @@
`default_nettype none
module servant_nexys_4_clock_gen
(input wire i_clk,
input wire i_rst,
input wire i_clk0_en,
input wire i_clk1_en,
output wire o_clk0,
output wire o_clk1,
output reg o_rst);
wire clkfb;
wire locked;
wire pll_rst;
wire pll_clk;
reg locked_r;
assign pll_rst = !i_rst;
MMCME2_BASE
#(.CLKIN1_PERIOD (10), //100MHz
/* Set VCO frequency to 100*8.0=800 MHz
Allowed values are 2.0 to 64.0. Resulting VCO freq
needs to be 600-1200MHz */
.CLKFBOUT_MULT_F (8.000),
.CLKOUT0_DIVIDE_F (25.000)) // 800/25 = 32 MHz
pll
(.CLKIN1 (i_clk),
.RST (pll_rst),
.CLKOUT0 (pll_clk),
.LOCKED (locked),
.CLKFBOUT (clkfb),
.CLKFBIN (clkfb));
always @(posedge pll_clk) begin
locked_r <= locked;
o_rst <= !locked_r;
end
BUFGCE clk0_buf
(
.I (pll_clk),
.O (o_clk0),
.CE (i_clk0_en));
BUFGCE clk1_buf
(
.I (pll_clk),
.O (o_clk1),
.CE (i_clk0_en));
endmodule
`default_nettype wire

View file

@ -0,0 +1,42 @@
`default_nettype none
module servant_nexys_a7
(
input wire i_clk,
input wire i_rst,
input wire ext_irq,
output wire o_uart_tx,
output wire q);
parameter memfile = "zephyr_hello.hex";
parameter memsize = 8192;
wire main_clk;
wire wb_clk;
wire wb_rst;
wire sleep;
assign o_uart_tx = q;
servant_nexys_a7_clock_gen
clock_gen
(.i_clk (i_clk),
.i_rst (i_rst),
.i_clk0_en (1),
.i_clk1_en (!sleep),
.o_clk0 (main_clk),
.o_clk1 (wb_clk),
.o_rst (wb_rst));
servant
#(.memfile (memfile),
.memsize (memsize))
servant
(.wb_clk (wb_clk),
.main_clk (main_clk),
.wb_rst (wb_rst),
.q (q),
.ext_irq (ext_irq),
.o_sleep (sleep));
endmodule
`default_nettype wire

View file

@ -0,0 +1,57 @@
`default_nettype none
module servant_nexys_a7_clock_gen
(input wire i_clk,
input wire i_rst,
input wire i_clk0_en,
input wire i_clk1_en,
output wire o_clk0,
output wire o_clk1,
output reg o_rst);
wire clkfb;
wire locked;
wire pll_rst;
wire pll_clk;
reg locked_r;
assign pll_rst = !i_rst;
MMCME2_BASE
#(.CLKIN1_PERIOD (10), //100MHz
/* Set VCO frequency to 100*8.0=800 MHz
Allowed values are 2.0 to 64.0. Resulting VCO freq
needs to be 600-1200MHz */
.CLKFBOUT_MULT_F (6.000),
.CLKOUT0_DIVIDE_F (64.000)) // 800/25 = 32 MHz
pll
(.CLKIN1 (i_clk),
.RST (pll_rst),
.CLKOUT0 (pll_clk),
.LOCKED (locked),
.CLKFBOUT (clkfb),
.CLKFBIN (clkfb));
always @(posedge pll_clk) begin
locked_r <= locked;
o_rst <= !locked_r;
end
BUFGCE clk0_buf
(
.I (pll_clk),
.O (o_clk0),
.CE (i_clk0_en));
BUFGCE clk1_buf
(
.I (pll_clk),
.O (o_clk1),
.CE (i_clk1_en));
endmodule
`default_nettype wire

View file

@ -0,0 +1,47 @@
`default_nettype none
module servant_sleep_dummy
(
input wire i_clk,
input wire i_rst,
input wire ext_irq,
output wire q);
parameter memfile = "zephyr_hello.hex";
parameter memsize = 8192;
parameter reset_strategy = "MINI";
parameter width = 1;
parameter sim = 0;
parameter [0:0] debug = 1'b0;
parameter with_csr = 1;
parameter [0:0] compress = 0;
parameter [0:0] align = compress;
wire sleep;
wire wb_clk;
wire sleep_req;
wire wakeup_req;
assign wb_clk = i_clk & !sleep;
servant #(
.memfile(memfile),
.memsize(memsize),
.reset_strategy(reset_strategy),
.width(width),
.sim(sim),
.debug(debug),
.with_csr(with_csr),
.compress(compress),
.align(align)
)
servant (
.wb_clk (wb_clk),
.main_clk (i_clk),
.wb_rst (i_rst),
.ext_irq (ext_irq),
.q (q),
.o_sleep (sleep));
endmodule
`default_nettype wire

View file

@ -16,6 +16,7 @@ module servile
parameter [0:0] debug = 1'b0, parameter [0:0] debug = 1'b0,
parameter [0:0] with_c = 1'b0, parameter [0:0] with_c = 1'b0,
parameter [0:0] with_csr = 1'b0, parameter [0:0] with_csr = 1'b0,
parameter [0:0] with_ei = 1'b0,
parameter [0:0] with_mdu = 1'b0, parameter [0:0] with_mdu = 1'b0,
//Internally calculated. Do not touch //Internally calculated. Do not touch
parameter B = width-1, parameter B = width-1,
@ -25,6 +26,10 @@ module servile
input wire i_clk, input wire i_clk,
input wire i_rst, input wire i_rst,
input wire i_timer_irq, input wire i_timer_irq,
input wire i_external_irq,
output wire o_sleep_req,
output wire o_wakeup_req,
//Memory (WB) interface //Memory (WB) interface
output wire [31:0] o_wb_mem_adr, output wire [31:0] o_wb_mem_adr,
@ -96,6 +101,8 @@ module servile
wire [31:0] mdu_rd; wire [31:0] mdu_rd;
wire mdu_ready; wire mdu_ready;
wire ei_irq;
servile_mux servile_mux
#(.sim (sim)) #(.sim (sim))
mux mux
@ -194,7 +201,16 @@ module servile
end else begin end else begin
assign mdu_ready = 1'b0; assign mdu_ready = 1'b0;
assign mdu_rd = 32'd0; assign mdu_rd = 32'd0;
end end // else: !if(with_mdu)
if (with_ei) begin : gen_ei
ei_top ei_serv
(.i_clk (i_clk),
.i_rst (i_rst),
.o_eirq (ei_irq));
end else begin
assign ei_irq = 1'b0;
end // else !if(with_ei)
endgenerate endgenerate
serv_top serv_top
@ -206,12 +222,15 @@ module servile
.RESET_PC (reset_pc), .RESET_PC (reset_pc),
.DEBUG (debug), .DEBUG (debug),
.MDU (with_mdu), .MDU (with_mdu),
.EI (with_ei),
.COMPRESSED (with_c)) .COMPRESSED (with_c))
cpu cpu
( (
.clk (i_clk), .clk (i_clk),
.i_rst (i_rst), .i_rst (i_rst),
.i_timer_irq (i_timer_irq), .i_timer_irq (i_timer_irq),
.i_external_irq (i_external_irq),
`ifdef RISCV_FORMAL `ifdef RISCV_FORMAL
.rvfi_valid (), .rvfi_valid (),
@ -266,6 +285,10 @@ module servile
.i_dbus_rdt (wb_dbus_rdt), .i_dbus_rdt (wb_dbus_rdt),
.i_dbus_ack (wb_dbus_ack), .i_dbus_ack (wb_dbus_ack),
// Sleep
.o_sleep_req (o_sleep_req),
.o_wakeup_req (o_wakeup_req),
//Extension IF //Extension IF
.o_ext_rs1 (mdu_rs1), .o_ext_rs1 (mdu_rs1),
.o_ext_rs2 (mdu_rs2), .o_ext_rs2 (mdu_rs2),

View file

@ -1,9 +1,11 @@
TOOLCHAIN_PREFIX?=riscv64-unknown-elf- TOOLCHAIN_PREFIX?=riscv64-unknown-elf-
CC?=$(TOOLCHAIN_PREFIX)gcc
OBJCOPY=$(TOOLCHAIN_PREFIX)objcopy
%.elf: %.S link.ld %.elf: %.S link.ld
$(TOOLCHAIN_PREFIX)gcc -nostartfiles -nostdlib -march=rv32i_zicsr -mabi=ilp32 -Tlink.ld -o$@ $< $(CC) -nostartfiles -nostdlib -march=rv32i_zicsr -mabi=ilp32 -Tlink.ld -o$@ $<
%.bin: %.elf %.bin: %.elf
$(TOOLCHAIN_PREFIX)objcopy -O binary $< $@ $(OBJCOPY) -O binary $< $@
%.hex: %.bin %.hex: %.bin
python3 makehex.py $< > $@ python3 makehex.py $< > $@

18
sw/external_interrupt.S Normal file
View file

@ -0,0 +1,18 @@
.section .text
.global _start
.global handler
_start:
la t0, handler
csrw mtvec, t0
li t0, 0x8
csrrs x0, mstatus, t0
li t0, 0x800
csrrs x0, mie, t0
loop:
j loop
handler:
li t0, 0x8
csrrc x0, mstatus, t0
li t0, 0x800
csrrc x0, mie, t0
mret

16
sw/external_interrupt.hex Normal file
View file

@ -0,0 +1,16 @@
00000297
02428293
30529073
00800293
3002A073
00100293
00B29293
3042A073
0000006F
00800293
3002B073
00100293
00B29293
3042B073
30200073
00000000

View file

@ -0,0 +1,17 @@
.section .text
.global _start
.global handler
_start:
la t0, handler
csrw mtvec, t0
li t0, 0x8
csrrs x0, mstatus, t0
li t0, 0x800
csrrs x0, mie, t0
wfi
handler:
li t0, 0x8
csrrc x0, mstatus, t0
li t0, 0x800
csrrc x0, mie, t0
mret

View file

@ -0,0 +1,16 @@
00000297
02428293
30529073
00800293
3002A073
00100293
00B29293
3042A073
10500073
00800293
3002B073
00100293
00B29293
3042B073
30200073
00000000

22
sw/timer_interrupt.S Normal file
View file

@ -0,0 +1,22 @@
.section .text
.global _start
.global handler
.equ DELAY, 1500
_start:
la t0, handler
csrw mtvec, t0
li t0, 0x80000000
li t1, DELAY
sw t1, 0(t0)
li t0, 0x8
csrrs x0, mstatus, t0
li t0, 0x80
csrrs x0, mie, t0
wait:
j wait
handler:
li t0, 0x8
csrrc x0, mstatus, t0
li t0, 0x80
csrrc x0, mie, t0
mret

17
sw/timer_interrupt.hex Normal file
View file

@ -0,0 +1,17 @@
00000297
02C28293
30529073
800002B7
5DC00313
0062A023
00800293
3002A073
08000293
3042A073
0000006F
00800293
3002B073
08000293
3042B073
30200073
00000000

View file

@ -0,0 +1,17 @@
00000297
02C28293
30529073
800002B7
5DC00313
0062A023
00800293
3002A073
08000293
3042A073
10500073
00800293
3002B073
08000293
3042B073
30200073
00000000

View file

@ -0,0 +1,29 @@
.section .text
.global _start
.global handler
.equ DELAY, 8000
_start:
la t0, handler
csrw mtvec, t0
li t0, 0x80000000
li s2, DELAY
sw s2, 0(t0)
li t0, 0x8
csrrs x0, mstatus, t0
li t0, 0x80
csrrs x0, mie, t0
wait:
wfi
j wait
handler:
li t1, DELAY
add s2, t1, s2
li t0, 0x80000000
sw s2, 0(t0)
mret