284 lines
9.2 KiB
Systemverilog
284 lines
9.2 KiB
Systemverilog
`timescale 1ns/1ps
|
|
|
|
module asic_rocket_tb;
|
|
localparam int CLOCK_HZ = 100000000;
|
|
localparam real CLOCK_HALF_PERIOD_NS = 5.000000000;
|
|
localparam real RF_CLOCK_HALF_PERIOD_NS = 30.547409;
|
|
|
|
reg board_clock = 1'b0;
|
|
reg board_reset = 1'b1;
|
|
reg gps_rf_clk = 1'b0;
|
|
reg [3:0] gps_rf_data = 4'h0;
|
|
reg pmod_irq = 1'b0;
|
|
wire core_clk = board_clock;
|
|
wire core_reset;
|
|
|
|
wire uart_txd;
|
|
wire spi_sck;
|
|
wire spi_csn;
|
|
wire [3:0] spi_dq_i;
|
|
wire [3:0] spi_dq_o;
|
|
wire [3:0] spi_dq_oe;
|
|
wire jtag_tck;
|
|
wire jtag_tms;
|
|
wire jtag_tdi;
|
|
wire jtag_trst_n;
|
|
wire simjtag_tck;
|
|
wire simjtag_tms;
|
|
wire simjtag_tdi;
|
|
wire simjtag_trst_n;
|
|
wire jtag_tdo_data;
|
|
wire jtag_tdo_driven;
|
|
wire debug_ndreset;
|
|
wire debug_dmactive;
|
|
wire [31:0] jtag_exit;
|
|
wire uart_valid;
|
|
wire [7:0] uart_data;
|
|
reg simjtag_enable = 1'b0;
|
|
reg pmod_irq_rtl_only = 1'b0;
|
|
reg [7:0] last_uart_byte = 8'h00;
|
|
integer app_match_count = 0;
|
|
integer gps_match_count = 0;
|
|
integer uart_toggle_count = 0;
|
|
integer pmod_irq_rise_count = 0;
|
|
reg main_return_seen = 1'b0;
|
|
reg [15:0] main_return_code_q = 16'hffff;
|
|
reg pmod_irq_pulse_done = 1'b0;
|
|
reg pmod_irq_pending_seen = 1'b0;
|
|
reg uart_txd_q = 1'b1;
|
|
wire core_wfi;
|
|
wire [63:0] main_return_status;
|
|
wire [15:0] main_return_code;
|
|
|
|
initial begin
|
|
simjtag_enable = $test$plusargs("jtag_rbb_enable");
|
|
pmod_irq_rtl_only = $test$plusargs("pmod_irq_rtl_only");
|
|
end
|
|
|
|
always #(CLOCK_HALF_PERIOD_NS) board_clock = ~board_clock;
|
|
always #(RF_CLOCK_HALF_PERIOD_NS) gps_rf_clk = ~gps_rf_clk;
|
|
|
|
always @(posedge gps_rf_clk or posedge board_reset) begin
|
|
if (board_reset) begin
|
|
gps_rf_data <= 4'h0;
|
|
end else begin
|
|
gps_rf_data <= gps_rf_data + 4'h1;
|
|
end
|
|
end
|
|
|
|
assign jtag_tck = simjtag_enable ? simjtag_tck : 1'b1;
|
|
assign jtag_tms = simjtag_enable ? simjtag_tms : 1'b1;
|
|
assign jtag_tdi = simjtag_enable ? simjtag_tdi : 1'b1;
|
|
assign jtag_trst_n = simjtag_enable ? simjtag_trst_n : 1'b1;
|
|
|
|
initial begin
|
|
repeat (32) @(posedge board_clock);
|
|
board_reset = 1'b0;
|
|
end
|
|
|
|
// Model an asynchronous, active-high sensor interrupt. Four square-wave
|
|
// periods deliberately straddle core clock edges and exercise the Rocket
|
|
// interrupt synchronizer before reaching PLIC device 11.
|
|
initial begin
|
|
wait (core_reset === 1'b0);
|
|
repeat (32) @(posedge core_clk);
|
|
repeat (4) begin
|
|
#(3.0) pmod_irq = 1'b1;
|
|
repeat (8) @(posedge core_clk);
|
|
#(2.0) pmod_irq = 1'b0;
|
|
repeat (8) @(posedge core_clk);
|
|
end
|
|
pmod_irq_pulse_done = 1'b1;
|
|
end
|
|
|
|
always @(posedge pmod_irq) begin
|
|
pmod_irq_rise_count = pmod_irq_rise_count + 1;
|
|
end
|
|
|
|
always @(posedge core_clk) begin
|
|
uart_txd_q <= uart_txd;
|
|
if (!core_reset && uart_txd_q !== uart_txd) begin
|
|
uart_toggle_count <= uart_toggle_count + 1;
|
|
end
|
|
end
|
|
|
|
asic_rocket_top dut (
|
|
.board_clock(board_clock),
|
|
.board_reset(board_reset),
|
|
.gps_rf_clk(gps_rf_clk),
|
|
.gps_rf_data(gps_rf_data),
|
|
.pmod_irq(pmod_irq),
|
|
.uart_rxd(1'b1),
|
|
.uart_txd(uart_txd),
|
|
.spi_sck(spi_sck),
|
|
.spi_csn(spi_csn),
|
|
.spi_dq_i(spi_dq_i),
|
|
.spi_dq_o(spi_dq_o),
|
|
.spi_dq_oe(spi_dq_oe),
|
|
.jtag_tck(jtag_tck),
|
|
.jtag_tms(jtag_tms),
|
|
.jtag_tdi(jtag_tdi),
|
|
.jtag_trst_n(jtag_trst_n),
|
|
.jtag_tdo_data(jtag_tdo_data),
|
|
.jtag_tdo_driven(jtag_tdo_driven),
|
|
.debug_ndreset(debug_ndreset),
|
|
.debug_dmactive(debug_dmactive)
|
|
);
|
|
|
|
assign core_reset = dut.core_reset;
|
|
|
|
assign core_wfi = dut.u_rocket.tile_prci_domain.element_reset_domain.rockettile.core.io_wfi;
|
|
assign main_return_status = dut.u_rocket.tile_prci_domain.element_reset_domain.rockettile.core.csr.reg_mscratch;
|
|
assign main_return_code = main_return_status[15:0];
|
|
|
|
// pmod_irq is source 10 in the zero-based TLPLIC arrays, corresponding to
|
|
// architectural PLIC device ID 11.
|
|
always @(posedge core_clk) begin
|
|
if (core_reset) begin
|
|
pmod_irq_pending_seen <= 1'b0;
|
|
end else if (dut.u_rocket.plic_domain.plic.pending_10 === 1'b1) begin
|
|
if (!pmod_irq_pending_seen) begin
|
|
$display("ASIC PMOD IRQ: PLIC device 11 pending observed");
|
|
end
|
|
pmod_irq_pending_seen <= 1'b1;
|
|
end
|
|
end
|
|
|
|
SimJTAG #(.TICK_DELAY(3)) sim_jtag (
|
|
.clock(core_clk),
|
|
.reset(core_reset),
|
|
.enable(simjtag_enable),
|
|
.init_done(~core_reset),
|
|
.jtag_TCK(simjtag_tck),
|
|
.jtag_TMS(simjtag_tms),
|
|
.jtag_TDI(simjtag_tdi),
|
|
.jtag_TRSTn(simjtag_trst_n),
|
|
.jtag_TDO_data(jtag_tdo_data),
|
|
.jtag_TDO_driven(jtag_tdo_driven),
|
|
.exit(jtag_exit)
|
|
);
|
|
|
|
spi_flash_model #(
|
|
.IMAGE(""),
|
|
.LOAD_OFFSET(32'h06000000)
|
|
) u_flash (
|
|
.sck(spi_sck),
|
|
.csn(spi_csn),
|
|
.dq_o(spi_dq_o),
|
|
.dq_oe(spi_dq_oe),
|
|
.dq_i(spi_dq_i)
|
|
);
|
|
|
|
uart_console_model #(
|
|
.CLOCK_HZ(CLOCK_HZ),
|
|
.BAUD(115200)
|
|
) u_uart_console (
|
|
.clk(core_clk),
|
|
.reset(core_reset),
|
|
.rxd(uart_txd),
|
|
.valid(uart_valid),
|
|
.data(uart_data)
|
|
);
|
|
|
|
always @(posedge core_clk) begin
|
|
if (core_reset) begin
|
|
app_match_count <= 0;
|
|
gps_match_count <= 0;
|
|
last_uart_byte <= 8'h00;
|
|
end else if (uart_valid) begin
|
|
last_uart_byte <= uart_data;
|
|
case (app_match_count)
|
|
0: app_match_count <= (uart_data == "R") ? 1 : 0;
|
|
1: app_match_count <= (uart_data == "o") ? 2 : ((uart_data == "R") ? 1 : 0);
|
|
2: app_match_count <= (uart_data == "c") ? 3 : ((uart_data == "R") ? 1 : 0);
|
|
3: app_match_count <= (uart_data == "k") ? 4 : ((uart_data == "R") ? 1 : 0);
|
|
4: app_match_count <= (uart_data == "e") ? 5 : ((uart_data == "R") ? 1 : 0);
|
|
5: app_match_count <= (uart_data == "t") ? 6 : ((uart_data == "R") ? 1 : 0);
|
|
6: app_match_count <= (uart_data == " ") ? 7 : ((uart_data == "R") ? 1 : 0);
|
|
7: app_match_count <= (uart_data == "C") ? 8 : ((uart_data == "R") ? 1 : 0);
|
|
8: app_match_count <= (uart_data == "h") ? 9 : ((uart_data == "R") ? 1 : 0);
|
|
9: app_match_count <= (uart_data == "i") ? 10 : ((uart_data == "R") ? 1 : 0);
|
|
10: app_match_count <= (uart_data == "p") ? 11 : ((uart_data == "R") ? 1 : 0);
|
|
default: app_match_count <= app_match_count;
|
|
endcase
|
|
|
|
case (gps_match_count)
|
|
0: gps_match_count <= (uart_data == "G") ? 1 : 0;
|
|
1: gps_match_count <= (uart_data == "P") ? 2 : ((uart_data == "G") ? 1 : 0);
|
|
2: gps_match_count <= (uart_data == "S") ? 3 : ((uart_data == "G") ? 1 : 0);
|
|
3: gps_match_count <= (uart_data == " ") ? 4 : ((uart_data == "G") ? 1 : 0);
|
|
4: gps_match_count <= (uart_data == "S") ? 5 : ((uart_data == "G") ? 1 : 0);
|
|
5: gps_match_count <= (uart_data == "y") ? 6 : ((uart_data == "G") ? 1 : 0);
|
|
6: gps_match_count <= (uart_data == "s") ? 7 : ((uart_data == "G") ? 1 : 0);
|
|
7: gps_match_count <= (uart_data == "t") ? 8 : ((uart_data == "G") ? 1 : 0);
|
|
8: gps_match_count <= (uart_data == "e") ? 9 : ((uart_data == "G") ? 1 : 0);
|
|
9: gps_match_count <= (uart_data == "m") ? 10 : ((uart_data == "G") ? 1 : 0);
|
|
default: gps_match_count <= gps_match_count;
|
|
endcase
|
|
end
|
|
end
|
|
|
|
always @(posedge core_clk) begin
|
|
if (!core_reset && gps_match_count == 10 && pmod_irq_pulse_done &&
|
|
pmod_irq_pending_seen && pmod_irq_rise_count == 4) begin
|
|
$display("ASIC PMOD IRQ PASS: rises=%0d pending_seen=%0d",
|
|
pmod_irq_rise_count, pmod_irq_pending_seen);
|
|
$display("ASIC sanity PASS");
|
|
$finish;
|
|
end
|
|
end
|
|
|
|
// The RTL-only mode bypasses the intentionally slow SPI-flash boot path.
|
|
// It proves the complete hardware route from the asynchronous ASIC input to
|
|
// architectural PLIC device 11; sim-pmod-irq retains the CPU/ISR check.
|
|
always @(posedge core_clk) begin
|
|
if (!core_reset && pmod_irq_rtl_only && pmod_irq_pulse_done) begin
|
|
if (pmod_irq_pending_seen && pmod_irq_rise_count == 4) begin
|
|
$display("ASIC PMOD IRQ RTL PASS: rises=%0d plic_device=11 pending_seen=%0d",
|
|
pmod_irq_rise_count, pmod_irq_pending_seen);
|
|
$display("ASIC sanity PASS");
|
|
end else begin
|
|
$display("ASIC PMOD IRQ RTL FAIL: rises=%0d plic_device=11 pending_seen=%0d",
|
|
pmod_irq_rise_count, pmod_irq_pending_seen);
|
|
$display("ASIC sanity FAIL");
|
|
end
|
|
$finish;
|
|
end
|
|
end
|
|
|
|
always @(posedge core_clk) begin
|
|
if (core_reset) begin
|
|
main_return_seen <= 1'b0;
|
|
main_return_code_q <= 16'hffff;
|
|
end else if (!main_return_seen && main_return_status[31:16] == 16'h5a5a) begin
|
|
main_return_seen <= 1'b1;
|
|
main_return_code_q <= main_return_code;
|
|
$display("C main returned %0d", main_return_code);
|
|
end
|
|
end
|
|
|
|
always @(posedge core_clk) begin
|
|
if (!core_reset && main_return_seen && pmod_irq_pulse_done) begin
|
|
if (main_return_code_q == 16'h0000 && pmod_irq_pending_seen &&
|
|
pmod_irq_rise_count == 4) begin
|
|
$display("ASIC PMOD IRQ PASS: rises=%0d pending_seen=%0d",
|
|
pmod_irq_rise_count, pmod_irq_pending_seen);
|
|
$display("ASIC sanity PASS");
|
|
end else begin
|
|
$display("ASIC PMOD IRQ FAIL: rises=%0d pending_seen=%0d",
|
|
pmod_irq_rise_count, pmod_irq_pending_seen);
|
|
$display("ASIC sanity FAIL");
|
|
end
|
|
$finish;
|
|
end
|
|
end
|
|
|
|
always @(posedge core_clk) begin
|
|
if (jtag_exit[0]) begin
|
|
$display("SimJTAG exit code: %0d", jtag_exit >> 1);
|
|
$finish;
|
|
end
|
|
end
|
|
|
|
endmodule
|