Files
gps/hardware/sim/asic/rocket/tb/asic_rocket_tb.sv
T

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