1
0
mirror of https://github.com/olofk/serv.git synced 2026-01-11 23:42:50 +00:00

csr, verilator, traps

This commit is contained in:
Olof Kindgren 2018-11-14 12:16:20 +01:00
parent c33d97d80f
commit a92c933af1
13 changed files with 587 additions and 203 deletions

57
bench/serv_soc_tb.cpp Normal file
View File

@ -0,0 +1,57 @@
#include <stdint.h>
#include <signal.h>
#include "verilated_vcd_c.h"
#include "Vserv_wrapper.h"
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)
{
uint32_t insn = 0;
uint32_t ex_pc = 0;
Verilated::commandArgs(argc, argv);
Vserv_wrapper* top = new Vserv_wrapper;
//const char *vcd = Verilated::commandArgsPlusMatch("vcd=");
//if (vcd[0]) == '\0' || atoi(arg + 11) != 0)
Verilated::traceEverOn(true);
VerilatedVcdC* tfp = new VerilatedVcdC;
top->trace (tfp, 99);
tfp->open ("trace.vcd");
signal(SIGINT, INThandler);
top->wb_clk = 1;
top->wb_rst = 1;
while (!(done || Verilated::gotFinish())) {
top->eval();
tfp->dump(main_time);
top->wb_clk = !top->wb_clk;
main_time+=5;
if (main_time > 100)
top->wb_rst = false;
}
tfp->close();
exit(0);
}

View File

@ -1,73 +1,16 @@
`default_nettype none
module serv_top_tb;
reg clk = 1'b1;
parameter firmware = "firmware.hex";
reg wb_clk = 1'b1;
reg wb_rst = 1'b1;
reg [1023:0] firmware_file;
wire wb_clk = clk;
always #5 clk <= !clk;
always #5 wb_clk <= !wb_clk;
initial #100 wb_rst = 1'b0;
`include "wb_intercon.vh"
localparam MEMORY_SIZE = 16384*4;
wb_ram
#(.memfile ("firmware.hex"),
.depth (MEMORY_SIZE))
ram
(// Wishbone interface
.wb_clk_i (clk),
.wb_rst_i (wb_rst),
.wb_adr_i (wb_m2s_mem_adr[$clog2(MEMORY_SIZE)-1:0]),
.wb_stb_i (wb_m2s_mem_stb),
.wb_cyc_i (wb_m2s_mem_cyc),
.wb_cti_i (wb_m2s_mem_cti),
.wb_bte_i (wb_m2s_mem_bte),
.wb_we_i (wb_m2s_mem_we) ,
.wb_sel_i (wb_m2s_mem_sel),
.wb_dat_i (wb_m2s_mem_dat),
.wb_dat_o (wb_s2m_mem_dat),
.wb_ack_o (wb_s2m_mem_ack),
.wb_err_o ());
vlog_tb_utils vtu();
testprint testprint
(
.i_wb_clk (clk),
.i_wb_dat (wb_m2s_testprint_dat),
.i_wb_we (wb_m2s_testprint_we),
.i_wb_cyc (wb_m2s_testprint_cyc),
.i_wb_stb (wb_m2s_testprint_stb),
.o_wb_ack (wb_s2m_testprint_ack));
serv_wrapper #(firmware) dut(wb_clk, wb_rst);
serv_top
#(.RESET_PC (32'd8))
dut
(
.clk (clk),
.o_ibus_adr (wb_m2s_cpu_ibus_adr),
.o_ibus_cyc (wb_m2s_cpu_ibus_cyc),
.o_ibus_stb (wb_m2s_cpu_ibus_stb),
.i_ibus_rdt (wb_s2m_cpu_ibus_dat),
.i_ibus_ack (wb_s2m_cpu_ibus_ack),
.o_dbus_adr (wb_m2s_cpu_dbus_adr),
.o_dbus_dat (wb_m2s_cpu_dbus_dat),
.o_dbus_sel (wb_m2s_cpu_dbus_sel),
.o_dbus_we (wb_m2s_cpu_dbus_we),
.o_dbus_cyc (wb_m2s_cpu_dbus_cyc),
.o_dbus_stb (wb_m2s_cpu_dbus_stb),
.i_dbus_rdt (wb_s2m_cpu_dbus_dat),
.i_dbus_ack (wb_s2m_cpu_dbus_ack));
assign wb_m2s_cpu_ibus_dat = 32'd0;
assign wb_m2s_cpu_ibus_we = 1'b0;
assign wb_m2s_cpu_ibus_sel = 4'b1111;
assign wb_m2s_cpu_ibus_cti = 3'b000;
assign wb_m2s_cpu_ibus_bte = 2'b00;
endmodule

97
bench/serv_wrapper.v Normal file
View File

@ -0,0 +1,97 @@
`default_nettype none
module serv_wrapper
(
input wb_clk,
input wb_rst);
parameter firmware = "firmware.hex";
wire timer_irq;
`include "wb_intercon.vh"
localparam MEMORY_SIZE = 16384*4;
reg [1023:0] firmware_file;
initial
if ($value$plusargs("firmware=%s", firmware_file)) begin
$display("Loading RAM from %0s", firmware_file);
$readmemh(firmware_file, ram.ram0.mem);
end
wb_ram
#(/*.memfile (firmware),*/
.depth (MEMORY_SIZE))
ram
(// Wishbone interface
.wb_clk_i (wb_clk),
.wb_rst_i (wb_rst),
.wb_adr_i (wb_m2s_mem_adr[$clog2(MEMORY_SIZE)-1:0]),
.wb_stb_i (wb_m2s_mem_stb),
.wb_cyc_i (wb_m2s_mem_cyc),
.wb_cti_i (wb_m2s_mem_cti),
.wb_bte_i (wb_m2s_mem_bte),
.wb_we_i (wb_m2s_mem_we) ,
.wb_sel_i (wb_m2s_mem_sel),
.wb_dat_i (wb_m2s_mem_dat),
.wb_dat_o (wb_s2m_mem_dat),
.wb_ack_o (wb_s2m_mem_ack),
.wb_err_o ());
testprint testprint
(
.i_wb_clk (wb_clk),
.i_wb_dat (wb_m2s_testprint_dat),
.i_wb_we (wb_m2s_testprint_we),
.i_wb_cyc (wb_m2s_testprint_cyc),
.i_wb_stb (wb_m2s_testprint_stb),
.o_wb_ack (wb_s2m_testprint_ack));
testhalt testhalt
(
.i_wb_clk (wb_clk),
.i_wb_dat (wb_m2s_testhalt_dat),
.i_wb_we (wb_m2s_testhalt_we),
.i_wb_cyc (wb_m2s_testhalt_cyc),
.i_wb_stb (wb_m2s_testhalt_stb),
.o_wb_ack (wb_s2m_testhalt_ack));
riscv_timer riscv_timer
(.i_clk (wb_clk),
.o_irq (timer_irq),
.i_wb_adr (wb_m2s_timer_adr),
.i_wb_stb (wb_m2s_timer_stb),
.i_wb_cyc (wb_m2s_timer_cyc),
.i_wb_we (wb_m2s_timer_we) ,
.i_wb_sel (wb_m2s_timer_sel),
.i_wb_dat (wb_m2s_timer_dat),
.o_wb_dat (wb_s2m_timer_dat),
.o_wb_ack (wb_s2m_timer_ack));
serv_top
#(.RESET_PC (32'h8000_0000))
cpu
(
.clk (wb_clk),
.o_ibus_adr (wb_m2s_cpu_ibus_adr),
.o_ibus_cyc (wb_m2s_cpu_ibus_cyc),
.o_ibus_stb (wb_m2s_cpu_ibus_stb),
.i_ibus_rdt (wb_s2m_cpu_ibus_dat),
.i_ibus_ack (wb_s2m_cpu_ibus_ack),
.o_dbus_adr (wb_m2s_cpu_dbus_adr),
.o_dbus_dat (wb_m2s_cpu_dbus_dat),
.o_dbus_sel (wb_m2s_cpu_dbus_sel),
.o_dbus_we (wb_m2s_cpu_dbus_we),
.o_dbus_cyc (wb_m2s_cpu_dbus_cyc),
.o_dbus_stb (wb_m2s_cpu_dbus_stb),
.i_dbus_rdt (wb_s2m_cpu_dbus_dat),
.i_dbus_ack (wb_s2m_cpu_dbus_ack));
assign wb_m2s_cpu_ibus_dat = 32'd0;
assign wb_m2s_cpu_ibus_we = 1'b0;
assign wb_m2s_cpu_ibus_sel = 4'b1111;
assign wb_m2s_cpu_ibus_cti = 3'b000;
assign wb_m2s_cpu_ibus_bte = 2'b00;
endmodule

43
rtl/riscv_timer.v Normal file
View File

@ -0,0 +1,43 @@
`default_nettype none
module riscv_timer
(input i_clk,
output reg o_irq = 1'b0,
input [31:0] i_wb_adr,
input [31:0] i_wb_dat,
input [3:0] i_wb_sel,
input i_wb_we,
input i_wb_cyc,
input i_wb_stb,
output reg [31:0] o_wb_dat,
output reg o_wb_ack = 1'b0);
reg [63:0] mtime = 64'd0;
reg [63:0] mtimecmp = 64'd0;
localparam [1:0]
REG_MTIMELO = 2'd0,
REG_MTIMEHI = 2'd1,
REG_MTIMECMPLO = 2'd2,
REG_MTIMECMPHI = 2'd3;
always @(i_wb_adr)
case (i_wb_adr[3:2])
REG_MTIMELO : o_wb_dat = mtime[31:0];
REG_MTIMEHI : o_wb_dat = mtime[63:32];
REG_MTIMECMPLO : o_wb_dat = mtimecmp[31:0];
REG_MTIMECMPHI : o_wb_dat = mtimecmp[63:32];
endcase
always @(posedge i_clk) begin
o_wb_ack <= 1'b0;
if (i_wb_cyc & i_wb_stb) begin
o_wb_ack <= !o_wb_ack;
if (i_wb_we & (i_wb_adr[3:2] == REG_MTIMECMPLO))
mtimecmp[31:0] <= i_wb_dat;
if (i_wb_we & (i_wb_adr[3:2] == REG_MTIMECMPHI))
mtimecmp[63:32] <= i_wb_dat;
end
mtime <= mtime + 64'd1;
o_irq <= (mtime >= mtimecmp);
end
endmodule

72
rtl/serv_csr.v Normal file
View File

@ -0,0 +1,72 @@
`default_nettype none
module serv_csr
(
input i_clk,
input i_en,
input [2:0] i_csr_sel,
input [1:0] i_csr_source,
input i_trap,
input i_pc,
input i_mtval,
input i_load_misaligned,
input i_store_misaligned,
input i_d,
output o_q);
`include "serv_params.vh"
/*
mtvec RW
mepc RW
mstatus RWSC
mcause R
mip CWi
mie SCWi
*/
reg [31:0] mtvec = 32'h0;
reg [31:0] mepc = 32'h0;
reg [31:0] mtval = 32'h0;
reg [31:0] mcause = 32'h0;
wire mtvec_en = i_en & (i_csr_sel == CSR_SEL_MTVEC);
wire mepc_en = i_en & (i_trap | (i_csr_sel == CSR_SEL_MEPC));
wire mcause_en = i_en & (i_csr_sel == CSR_SEL_MCAUSE);
wire mtval_en = i_en & (i_trap | (i_csr_sel == CSR_SEL_MTVAL));
wire csr_in;
wire csr_out;
assign csr_in = (i_csr_source == CSR_SOURCE_EXT) ? i_d :
(i_csr_source == CSR_SOURCE_SET) ? csr_out | i_d :
(i_csr_source == CSR_SOURCE_CLR) ? csr_out & ~i_d :
(i_csr_source == CSR_SOURCE_CSR) ? csr_out :
1'bx;
assign csr_out = (i_csr_sel == CSR_SEL_MTVEC) ? mtvec[0] :
(i_csr_sel == CSR_SEL_MEPC) ? mepc[0] :
(i_csr_sel == CSR_SEL_MCAUSE) ? mcause[0] :
(i_csr_sel == CSR_SEL_MTVAL) ? mtval[0] :
1'bx;
assign o_q = csr_out;
always @(posedge i_clk) begin
if (i_load_misaligned)
mcause[3:0] <= 4'd4;
if (i_store_misaligned)
mcause[3:0] <= 4'd6;
if (mtvec_en)
mtvec <= {csr_in, mtvec[31:1]};
if (mepc_en)
mepc <= {i_trap ? i_pc : csr_in, mepc[31:1]};
if (mcause_en)
mcause <= {csr_in, mcause[31:1]};
if (mtval_en)
mtval <= {i_trap ? i_mtval : csr_in, mtval[31:1]};
end
endmodule

View File

@ -1,35 +1,37 @@
`default_nettype none
module serv_ctrl
(
input clk,
input i_en,
input i_jump,
input i_offset,
input i_rs1,
input i_jalr,
input i_auipc,
output o_rd,
input clk,
input i_en,
input i_jump,
input i_offset,
input i_rs1,
input i_jalr,
input i_auipc,
input i_trap,
input i_csr_pc,
output o_rd,
output [31:0] o_ibus_adr,
output reg o_ibus_cyc = 1'b0,
input i_ibus_ack);
output reg o_ibus_cyc = 1'b0,
input i_ibus_ack);
parameter RESET_PC = 32'd8;
wire pc_plus_4;
wire pc_plus_offset;
wire plus_4;
wire pc;
wire new_pc;
wire offset_a;
assign plus_4 = en_2r & !en_3r;
assign o_ibus_adr[0] = pc;
ser_add ser_add_pc_plus_4
(
.clk (clk),
@ -52,11 +54,11 @@ module serv_ctrl
.o_par (o_ibus_adr[31:1])
);
assign new_pc = i_jump ? pc_plus_offset : pc_plus_4;
assign o_rd = i_auipc ? pc_plus_offset : pc_plus_4;
assign new_pc = i_trap ? i_csr_pc : i_jump ? pc_plus_offset_aligned : pc_plus_4;
assign o_rd = i_auipc ? pc_plus_offset_aligned : pc_plus_4;
assign offset_a = i_jalr ? i_rs1 : pc;
ser_add ser_add_pc_plus_offset
(
.clk (clk),
@ -66,10 +68,13 @@ module serv_ctrl
.q (pc_plus_offset),
.o_v ());
wire pc_plus_offset_aligned = pc_plus_offset & en_r;
reg en_r = 1'b1;
reg en_2r = 1'b0;
reg en_3r = 1'b0;
always @(posedge clk) begin
en_r <= i_en;
en_2r <= en_r;
@ -80,6 +85,5 @@ module serv_ctrl
else if (o_ibus_cyc & i_ibus_ack)
o_ibus_cyc <= 1'b0;
end
endmodule

View File

@ -1,39 +1,45 @@
module serv_decode
(
input clk,
input clk,
input [31:0] i_wb_rdt,
input i_wb_en,
output o_ibus_active,
output o_ctrl_en,
output o_ctrl_jump,
output o_ctrl_jalr,
output o_ctrl_auipc,
output o_rf_rd_en,
input i_wb_en,
output o_ibus_active,
output o_ctrl_en,
output o_ctrl_jump,
output o_ctrl_jalr,
output o_ctrl_auipc,
output reg o_ctrl_trap = 1'b0,
output o_ctrl_mret,
output o_rf_rd_en,
output reg [4:0] o_rf_rd_addr,
output o_rf_rs_en,
output o_rf_rs_en,
output reg [4:0] o_rf_rs1_addr,
output reg [4:0] o_rf_rs2_addr,
output o_alu_en,
output o_alu_init,
output o_alu_sub,
output reg o_alu_cmp_sel,
output o_alu_cmp_neg,
output reg o_alu_cmp_uns,
input i_alu_cmp,
output o_alu_shamt_en,
output o_alu_sh_signed,
output o_alu_sh_right,
output o_alu_en,
output o_alu_init,
output o_alu_sub,
output reg o_alu_cmp_sel,
output o_alu_cmp_neg,
output reg o_alu_cmp_uns,
input i_alu_cmp,
output o_alu_shamt_en,
output o_alu_sh_signed,
output o_alu_sh_right,
output reg [2:0] o_alu_rd_sel,
output o_mem_en,
output o_mem_cmd,
output o_mem_init,
output reg o_mem_dat_valid,
input i_mem_busy,
output o_mem_en,
output o_mem_cmd,
output o_mem_init,
output reg o_mem_dat_valid,
input i_mem_busy,
input i_mem_misalign,
output o_csr_en,
output reg [2:0] o_csr_sel,
output reg [1:0] o_csr_source,
output reg [2:0] o_funct3,
output reg o_imm,
output o_offset_source,
output o_op_b_source,
output [1:0] o_rd_source);
output reg o_imm,
output o_offset_source,
output o_op_b_source,
output [2:0] o_rd_source);
`include "serv_params.vh"
@ -44,7 +50,7 @@ module serv_decode
MEM_INIT = 3'd3,
MEM_WAIT = 3'd4,
RUN = 3'd5;
localparam [4:0]
OP_LOAD = 5'b00000,
OP_STORE = 5'b01000,
@ -54,7 +60,8 @@ module serv_decode
OP_LUI = 5'b01101,
OP_BRANCH = 5'b11000,
OP_JALR = 5'b11001,
OP_JAL = 5'b11011;
OP_JAL = 5'b11011,
OP_SYSTEM = 5'b11100;
reg [2:0] state = IDLE;
@ -63,11 +70,12 @@ module serv_decode
wire running;
wire mem_op;
wire shift_op;
wire csr_op;
reg signbit;
assign o_ibus_active = (state == IDLE);
assign mem_op = (opcode == OP_LOAD) | (opcode == OP_STORE);
assign shift_op = ((opcode == OP_OPIMM) & (o_funct3[1:0] == 2'b01)) |
((opcode == OP_OP ) & (o_funct3[1:0] == 2'b01));
@ -78,10 +86,12 @@ module serv_decode
((opcode == OP_BRANCH) & i_alu_cmp);
assign o_ctrl_jalr = (opcode == OP_JALR);
assign o_ctrl_auipc = (opcode == OP_AUIPC);
assign o_rf_rd_en = running &
assign o_ctrl_mret = (opcode == OP_SYSTEM) & imm[21] & !(|o_funct3);
assign o_rf_rd_en = running & !o_ctrl_trap &
(opcode != OP_STORE) &
(opcode != OP_BRANCH);
@ -104,6 +114,9 @@ module serv_decode
assign o_alu_cmp_neg = (opcode == OP_BRANCH) & o_funct3[0];
assign o_csr_en = ((opcode == OP_SYSTEM) & (|o_funct3) | o_ctrl_mret | o_ctrl_trap) & running;
always @(o_funct3) begin
casez (o_funct3)
3'b00? : o_alu_cmp_sel = ALU_CMP_EQ;
@ -111,7 +124,7 @@ module serv_decode
3'b1?? : o_alu_cmp_sel = ALU_CMP_LT;
default : o_alu_cmp_sel = 1'bx;
endcase
casez (o_funct3)
3'b00? : o_alu_cmp_uns = 1'b0;
3'b010 : o_alu_cmp_uns = 1'b0;
@ -131,11 +144,39 @@ module serv_decode
3'b111 : o_alu_rd_sel = ALU_RESULT_AND;
default : o_alu_rd_sel = 3'bxx;
endcase
casez(o_funct3[1:0])
2'b01 : o_csr_source = CSR_SOURCE_EXT; //Check for x0
2'b10 : o_csr_source = CSR_SOURCE_SET;
2'b11 : o_csr_source = CSR_SOURCE_CLR;
default : o_csr_source = 2'bxx;
endcase
if ((o_rf_rs1_addr == 5'd0) | o_ctrl_trap | o_ctrl_mret)
o_csr_source = CSR_SOURCE_CSR;
casez(imm[31:20])
12'h305 : o_csr_sel = CSR_SEL_MTVEC;
12'h341 : o_csr_sel = CSR_SEL_MEPC;
12'h342 : o_csr_sel = CSR_SEL_MCAUSE;
12'h343 : o_csr_sel = CSR_SEL_MTVAL;
//12'hf14 : o_csr_sel = CSR_SEL_MHARTID;
default : begin
o_csr_sel = 3'bxxx;
if (o_csr_en) begin
$display("%0t: CSR %03h not implemented", $time, imm[31:20]);
//#100 $finish;
end
end
endcase
if (o_ctrl_trap)
o_csr_sel = CSR_SEL_MTVEC;
if (o_ctrl_mret)
o_csr_sel = CSR_SEL_MEPC;
end
assign o_alu_shamt_en = (state == SH_INIT) & (cnt < 5);
assign o_alu_sh_signed = signbit;
assign o_alu_sh_right = o_funct3[2];
assign o_mem_en = mem_op & cnt_en;
assign o_mem_cmd = (opcode == OP_STORE);
@ -143,7 +184,7 @@ module serv_decode
reg [4:0] opcode;
reg [31:0] imm;
always @(posedge clk) begin
if (i_wb_en) begin
o_rf_rd_addr <= i_wb_rdt[11:7];
@ -153,7 +194,7 @@ module serv_decode
signbit <= i_wb_rdt[30];
opcode <= i_wb_rdt[6:2];
imm <= i_wb_rdt;
end
end
@ -187,8 +228,10 @@ module serv_decode
(opcode == OP_LUI) ? RD_SOURCE_IMM :
(opcode == OP_AUIPC) ? RD_SOURCE_CTRL :
(opcode == OP_JALR) ? RD_SOURCE_CTRL :
(opcode == OP_LOAD) ? RD_SOURCE_MEM : 2'bxx;
(opcode == OP_SYSTEM) ? RD_SOURCE_CSR :
(opcode == OP_LOAD) ? RD_SOURCE_MEM : 3'bxx;
//31, cnt, 20, +20, +7, 7, 1'b0
always @(cnt, opcode, imm) begin
o_imm = 1'bx;
if (opcode == OP_JAL)
@ -232,6 +275,8 @@ module serv_decode
assign running = (state == RUN);
always @(posedge clk) begin
if (cnt_done)
o_ctrl_trap <= i_mem_misalign;
state <= state;
case (state)
IDLE : begin
@ -265,5 +310,24 @@ module serv_decode
cnt <= cnt + {4'd0,cnt_en};
end
`define SERV_DECODE_CHECKS
`ifdef SERV_DECODE_CHECKS
reg unknown_op = 1'b0;
always @(opcode)
if (i_wb_en) begin
if (!((opcode == OP_LOAD) |
(opcode == OP_STORE ) |
(opcode == OP_OPIMM ) |
(opcode == OP_AUIPC ) |
(opcode == OP_OP ) |
(opcode == OP_LUI ) |
(opcode == OP_BRANCH) |
(opcode == OP_JALR ) |
(opcode == OP_SYSTEM ) |
(opcode == OP_JAL ))) begin
$display("Unknown opcode %b at %0t", opcode, $time);
end // if ((opcode != OP_LOAD) |...
end // if (i_wb_en)
`endif
endmodule

View File

@ -1,26 +1,28 @@
`default_nettype none
module serv_mem_if
(
input i_clk,
input i_en,
input i_init,
input i_dat_valid,
input i_cmd,
input [2:0] i_funct3,
input i_rs1,
input i_rs2,
input i_imm,
output o_rd,
output reg o_busy = 1'b0,
input i_clk,
input i_en,
input i_init,
input i_dat_valid,
input i_cmd,
input [2:0] i_funct3,
input i_rs1,
input i_rs2,
input i_imm,
output o_rd,
output reg o_busy = 1'b0,
output o_misalign,
input i_trap,
//External interface
output [31:0] o_wb_adr,
output [31:0] o_wb_dat,
output [3:0] o_wb_sel,
output o_wb_we ,
output reg o_wb_cyc = 1'b0,
output o_wb_stb,
output o_wb_we ,
output reg o_wb_cyc = 1'b0,
output o_wb_stb,
input [31:0] i_wb_rdt,
input i_wb_ack);
input i_wb_ack);
wire wb_en = o_wb_cyc & i_wb_ack;
assign o_wb_stb = o_wb_cyc;
@ -30,7 +32,7 @@ module serv_mem_if
wire adr;
reg [31:0] dat = 32'd0;
reg signbit = 1'b0;
ser_add ser_add_rs1_plus_imm
(
.clk (i_clk),
@ -43,7 +45,7 @@ module serv_mem_if
shift_reg #(32) shift_reg_adr
(
.clk (i_clk),
.i_en (i_init),
.i_en (i_init | (i_en & i_trap)),
.i_d (adr),
.o_q (o_wb_adr[0]),
.o_par (o_wb_adr[31:1])
@ -56,6 +58,9 @@ module serv_mem_if
wire is_half = i_funct3[0];
wire is_byte = !(|i_funct3[1:0]);
assign o_misalign = (|misalign);
wire upper_half = bytepos[1];
assign o_wb_dat = dat;
@ -66,7 +71,7 @@ module serv_mem_if
reg [1:0] bytepos;
reg [4:0] cnt = 5'd0;
reg dat_en;
always @(i_funct3, cnt, bytepos)
casez(i_funct3[1:0])
2'b1? : dat_en = 1'b1;
@ -75,21 +80,29 @@ module serv_mem_if
(bytepos == 2'd2) ? (cnt < 16) :
(bytepos == 2'd1) ? (cnt < 24) : 1'b1;
endcase
reg init_2r = 1'b0;
reg [1:0] misalign = 2'b00;
always @(posedge i_clk) begin
cnt <= cnt + {4'd0,i_init};
if (i_init & !init_r)
misalign[0] <= (!is_byte & adr);
if (init_r & !init_2r)
misalign[1] <= (is_word & adr);
if (i_trap)
misalign <= 2'b00;
if (i_en & !en_r)
bytepos[0] <= adr;
if (en_r & !en_2r)
bytepos[1] <= adr;
if (i_dat_valid)
signbit <= dat[0];
if (i_en & i_init)
o_busy <= 1'b1;
else if (wb_en)
else if (wb_en | i_trap)
o_busy <= 1'b0;
if (wb_en & !o_wb_we) begin
@ -105,9 +118,10 @@ module serv_mem_if
en_r <= i_en;
en_2r <= en_r;
init_r <= i_init;
init_2r <= init_r;
if (wb_en)
o_wb_cyc <= 1'b0;
else if (init_r & !i_init) begin //Optimize?
else if (init_r & !i_init & !i_trap) begin //Optimize?
o_wb_cyc <= 1'b1;
end

View File

@ -1,8 +1,9 @@
localparam [1:0]
RD_SOURCE_CTRL = 2'd0,
RD_SOURCE_ALU = 2'd1,
RD_SOURCE_IMM = 2'd2,
RD_SOURCE_MEM = 2'd3;
localparam [2:0]
RD_SOURCE_CTRL = 3'd0,
RD_SOURCE_ALU = 3'd1,
RD_SOURCE_IMM = 3'd2,
RD_SOURCE_MEM = 3'd3,
RD_SOURCE_CSR = 3'd4;
localparam [0:0]
OFFSET_SOURCE_IMM = 1'd0,
@ -11,7 +12,7 @@ localparam [0:0]
localparam [0:0]
OP_B_SOURCE_IMM = 1'd0,
OP_B_SOURCE_RS2 = 1'd1;
localparam[2:0]
ALU_RESULT_ADD = 3'd0,
ALU_RESULT_SR = 3'd1,
@ -33,3 +34,16 @@ localparam [0:0]
OR
AND
*/
localparam [2:0]
CSR_SEL_MTVEC = 3'd0,
CSR_SEL_MEPC = 3'd1,
CSR_SEL_MTVAL = 3'd2,
CSR_SEL_MCAUSE = 3'd3
;
localparam [1:0]
CSR_SOURCE_CSR = 2'b00,
CSR_SOURCE_EXT = 2'b01,
CSR_SOURCE_SET = 2'b10,
CSR_SOURCE_CLR = 2'b11;

View File

@ -46,26 +46,29 @@ module serv_top
input i_dbus_ack);
assign o_ibus_stb = o_ibus_cyc;
`include "serv_params.vh"
wire [4:0] rd_addr;
wire [4:0] rs1_addr;
wire [4:0] rs2_addr;
wire [1:0] rd_source;
wire [2:0] rd_source;
wire ctrl_rd;
wire alu_rd;
wire mem_rd;
wire csr_rd;
wire rd;
wire ctrl_en;
wire jump;
wire jalr;
wire auipc;
wire mret;
wire offset;
wire offset_source;
wire imm;
wire trap;
wire [2:0] funct3;
@ -80,7 +83,7 @@ module serv_top
wire alu_sh_signed;
wire alu_sh_right;
wire [2:0] alu_rd_sel;
wire rs1;
wire rs2;
wire rs_en;
@ -90,14 +93,18 @@ module serv_top
wire op_b;
wire mem_en;
wire mem_cmd;
wire mem_dat_valid;
wire mem_init;
wire mem_busy;
wire mem_misalign;
wire csr_en;
wire [2:0] csr_sel;
wire [1:0] csr_source;
parameter RESET_PC = 32'd8;
serv_decode decode
@ -110,6 +117,8 @@ module serv_top
.o_ctrl_jump (jump),
.o_ctrl_jalr (jalr),
.o_ctrl_auipc (auipc),
.o_ctrl_trap (trap),
.o_ctrl_mret (mret),
.o_funct3 (funct3),
.o_alu_en (alu_en),
.o_alu_init (alu_init),
@ -132,6 +141,10 @@ module serv_top
.o_mem_init (mem_init),
.o_mem_dat_valid (mem_dat_valid),
.i_mem_busy (mem_busy),
.i_mem_misalign (mem_misalign),
.o_csr_en (csr_en),
.o_csr_sel (csr_sel),
.o_csr_source (csr_source),
.o_imm (imm),
.o_offset_source (offset_source),
.o_op_b_source (op_b_source),
@ -148,6 +161,8 @@ module serv_top
.i_rs1 (rs1),
.i_jalr (jalr),
.i_auipc (auipc),
.i_trap (trap | mret),
.i_csr_pc (csr_rd),
.o_rd (ctrl_rd),
.o_ibus_adr (o_ibus_adr),
.o_ibus_cyc (o_ibus_cyc),
@ -156,10 +171,12 @@ module serv_top
assign offset = (offset_source == OFFSET_SOURCE_IMM) ? imm :
(offset_source == OFFSET_SOURCE_RS1) ? rs1 : 1'bx;
//TODO: Pass imm through alu to avoid 5-way mux
assign rd = (rd_source == RD_SOURCE_CTRL) ? ctrl_rd :
(rd_source == RD_SOURCE_ALU) ? alu_rd :
(rd_source == RD_SOURCE_IMM) ? imm :
(rd_source == RD_SOURCE_MEM) ? mem_rd : 1'bx;
(rd_source == RD_SOURCE_MEM) ? mem_rd :
(rd_source == RD_SOURCE_CSR) ? csr_rd : 1'bx;
assign op_b = (op_b_source == OP_B_SOURCE_IMM) ? imm :
(op_b_source == OP_B_SOURCE_RS2) ? rs2 :
@ -208,6 +225,8 @@ module serv_top
.i_imm (imm),
.o_rd (mem_rd),
.o_busy (mem_busy),
.o_misalign (mem_misalign),
.i_trap (trap),
//External interface
.o_wb_adr (o_dbus_adr),
.o_wb_dat (o_dbus_dat),
@ -218,6 +237,20 @@ module serv_top
.i_wb_rdt (i_dbus_rdt),
.i_wb_ack (i_dbus_ack));
serv_csr csr
(
.i_clk (clk),
.i_en (csr_en),
.i_csr_sel (csr_sel),
.i_csr_source (csr_source),
.i_trap (trap),
.i_pc (o_ibus_adr[0]),
.i_mtval (o_dbus_adr[0]),
.i_load_misaligned (mem_misalign & !mem_cmd),
.i_store_misaligned (mem_misalign & mem_cmd),
.i_d (rs1/* FIXME csr_d*/),
.o_q (csr_rd));
`ifdef RISCV_FORMAL
reg [31:0] rs1_fv, rs2_fv, rd_fv;
reg [31:0] pc = RESET_PC;

View File

@ -5,7 +5,6 @@ name : ::serv:0
filesets:
core:
files:
- rtl/camd_ram.v
- rtl/serv_params.vh : {is_include_file : true}
- rtl/shift_reg.v
- rtl/ser_add.v
@ -13,38 +12,37 @@ filesets:
- rtl/ser_lt.v
- rtl/ser_shift.v
- rtl/serv_alu.v
- rtl/serv_csr.v
- rtl/serv_ctrl.v
- rtl/serv_decode.v
- rtl/serv_mem_if.v
- rtl/serv_regfile.v
- rtl/serv_top.v
file_type : verilogSource
depend : [wb_ram]
ser_add_tb:
files:
- ser_add_tb.v
file_type : verilogSource
depend : [vlog_tb_utils]
serv_ctrl_tb:
files:
- bench/serv_ctrl_tb.v : {file_type : verilogSource}
depend : [vlog_tb_utils]
serv_decode_tb:
files: [bench/serv_decode_tb.v : {file_type : verilogSource}]
depend : [vlog_tb_utils]
serv_top_tb:
files:
- firmware.hex : {copyto : firmware.hex, file_type : user}
- testprint.v
- bench/serv_top_tb.v
file_type : verilogSource
depend : [vlog_tb_utils, wb_intercon, "yosys:techlibs:ice40"]
depend : [vlog_tb_utils, "yosys:techlibs:ice40"]
wrapper:
files:
- testhalt.v
- testprint.v
- rtl/riscv_timer.v
- bench/serv_wrapper.v
file_type : verilogSource
depend : [wb_intercon, wb_ram]
pcf:
files: [data/dummy.pcf : {file_type : PCF}]
verilator_tb:
files:
- bench/serv_soc_tb.cpp : {file_type : verilogSource}
depend : ["yosys:techlibs:ice40"]
targets:
default:
filesets : [core]
@ -54,6 +52,7 @@ targets:
default_tool : icestorm
filesets : [core, pcf]
toplevel : serv_top
lint:
default_tool : verilator
filesets : [core]
@ -61,33 +60,37 @@ targets:
verilator:
mode : lint-only
toplevel : serv_top
ser_add_tb:
default_tool : icarus
filesets: [core, ser_add_tb]
toplevel: ser_add_tb
serv_ctrl_tb:
default_tool: icarus
filesets : [core, serv_ctrl_tb]
toplevel : serv_ctrl_tb
serv_decode_tb:
default_tool: icarus
filesets : [core, serv_decode_tb]
toplevel : serv_decode_tb
serv_top_tb:
default_tool: icarus
filesets : [core, serv_top_tb]
filesets : [core, wrapper, serv_top_tb]
generate : [wb_intercon]
parameters : [RISCV_FORMAL=true]
parameters : [RISCV_FORMAL=true, firmware]
toplevel : serv_top_tb
verilator_tb:
default_tool: verilator
filesets : [core, wrapper, verilator_tb]
generate : [wb_intercon]
parameters : [RISCV_FORMAL=true, firmware, signature]
tools:
verilator:
verilator_options : [-Wno-fatal, --trace]
toplevel : serv_wrapper
parameters:
RISCV_FORMAL:
datatype : bool
paramtype : vlogdefine
firmware:
datatype : file
paramtype : plusarg
signature:
datatype : file
paramtype : plusarg
generate:
wb_intercon:
generator: wb_intercon_gen
@ -96,15 +99,17 @@ generate:
cpu_ibus:
slaves : [mem]
cpu_dbus:
slaves : [mem, testprint, testpassed]
slaves : [mem, testprint, testhalt, timer]
slaves:
mem:
offset : 0
offset : 0x80000000
size : 65536
testprint:
offset : 0x10000000
size : 4
testpassed:
testhalt:
offset : 0x20000000
size : 4
timer:
offset : 0xf00fff40
size : 16

20
testhalt.v Normal file
View File

@ -0,0 +1,20 @@
`default_nettype none
module testhalt
(
input i_wb_clk,
input [31:0] i_wb_dat,
input i_wb_we,
input i_wb_cyc,
input i_wb_stb,
output reg o_wb_ack = 1'b0);
always @(posedge i_wb_clk) begin
if (i_wb_cyc & i_wb_stb) begin
$display("Test complete");
$finish;
end
if (i_wb_cyc & i_wb_stb & !o_wb_ack)
o_wb_ack <= 1'b1;
end
endmodule

View File

@ -7,16 +7,34 @@ module testprint
input i_wb_we,
input i_wb_cyc,
input i_wb_stb,
output reg o_wb_ack = 1'b0);
output reg o_wb_ack /* verilator public */ = 1'b0);
wire wb_en /* verilator public */;
wire [7:0] ch /* verilator public */;
assign ch = i_wb_dat[7:0];
assign wb_en = i_wb_cyc & i_wb_stb;
reg [1023:0] signature_file;
integer f = 0;
initial
if ($value$plusargs("signature=%s", signature_file)) begin
$display("Writing signature to %0s", signature_file);
f = $fopen(signature_file, "w");
end
always @(posedge i_wb_clk) begin
if (i_wb_cyc & i_wb_stb) begin
o_wb_ack <= 1'b0;
if (wb_en & o_wb_ack) begin
if (f)
$fwrite(f, "%c", i_wb_dat[7:0]);
$write("%c", i_wb_dat[7:0]);
`ifndef VERILATOR
$fflush();
`endif
end
if (i_wb_cyc & i_wb_stb & !o_wb_ack)
if (wb_en & !o_wb_ack)
o_wb_ack <= 1'b1;
end
endmodule