mirror of
https://github.com/NawfalMotii79/PLFM_RADAR.git
synced 2026-05-14 03:42:00 +00:00
test(mechanics): PR-I.2 — tb_system_mechanics for chirp/RF/safety/CDC
New TB carving G1 (reset & init), G2 (TX chain — minus G2.2 which lives
in dataflow), G3 (safety architecture), G7.1 (rapid chirp toggle CDC),
and G7.3 (TX chirp counter CDC) out of tb_system_e2e into a fast,
focused subsuite. radar_system_top instantiated with USB_MODE=1
(production FT2232H path).
These tests don't need 48-chirp Doppler accumulation, so the sim
budget is ~80 us of stimulus + observation. Watchdog at 1.5 ms.
15/15 PASS. Pairs with tb_system_opcodes (commit 413a01e) to cover
~half of what tb_system_e2e exercised; the heavy data-flow / reset-
recovery groups (G2.2, G4, G5, G8, G9) move to tb_system_dataflow
in PR-I.3.
This commit is contained in:
456
9_Firmware/9_2_FPGA/tb/tb_system_mechanics.v
Normal file
456
9_Firmware/9_2_FPGA/tb/tb_system_mechanics.v
Normal file
@@ -0,0 +1,456 @@
|
||||
`timescale 1ns / 1ps
|
||||
`include "radar_params.vh"
|
||||
|
||||
// ============================================================================
|
||||
// tb_system_mechanics.v (PR-I, replaces tb_system_e2e G1/G2/G3 + G7.1/G7.3)
|
||||
//
|
||||
// Verifies low-level chirp/RF/safety/CDC mechanics that don't require the
|
||||
// 48-chirp Doppler accumulation. Sim runs at production timing (~1 ms).
|
||||
//
|
||||
// Coverage:
|
||||
// G1 Reset & initialization (system_status, ft601_wr_n, adc_pwdn)
|
||||
// G2 Transmitter chain (DAC chirp, RF switch, TX/RX mixer)
|
||||
// — G2.2 (new_chirp_frame) lives in tb_system_dataflow (needs 48 chirps).
|
||||
// G3 Safety architecture (TX/RX mixer mutual exclusion, ADC pwdn, ADAR TR,
|
||||
// mixer-disable propagation)
|
||||
// G7.1 Rapid chirp toggle CDC stress (100MHz STM32 -> 120MHz TX)
|
||||
// G7.3 TX chirp counter CDC (120MHz -> 100MHz)
|
||||
//
|
||||
// DUT is radar_system_top with USB_MODE=1 (production FT2232H path); the
|
||||
// FT2232H ports are wired so a minimal opcode can be sent if needed (none
|
||||
// are needed here — radar_mode defaults to 2'b00 STM32-driven).
|
||||
// ============================================================================
|
||||
|
||||
module tb_system_mechanics;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Clocks (match production)
|
||||
// ----------------------------------------------------------------------------
|
||||
localparam CLK_100M_PERIOD = 10.0; // 100 MHz
|
||||
localparam CLK_120M_PERIOD = 8.333; // 120 MHz DAC
|
||||
localparam FT_CLK_PERIOD = 16.667; // 60 MHz FT2232H
|
||||
localparam ADC_DCO_PERIOD = 2.5; // 400 MHz ADC
|
||||
|
||||
reg clk_100m = 1'b0;
|
||||
reg clk_120m_dac = 1'b0;
|
||||
reg ft601_clk_in = 1'b0;
|
||||
reg adc_dco_p = 1'b0;
|
||||
reg adc_dco_n = 1'b1;
|
||||
|
||||
always #(CLK_100M_PERIOD/2) clk_100m = ~clk_100m;
|
||||
always #(CLK_120M_PERIOD/2) clk_120m_dac = ~clk_120m_dac;
|
||||
always #(FT_CLK_PERIOD/2) ft601_clk_in = ~ft601_clk_in;
|
||||
always #(ADC_DCO_PERIOD/2) begin adc_dco_p = ~adc_dco_p; adc_dco_n = ~adc_dco_n; end
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// DUT signals
|
||||
// ----------------------------------------------------------------------------
|
||||
reg reset_n = 1'b0;
|
||||
|
||||
reg [7:0] adc_d_p = 8'h80;
|
||||
reg [7:0] adc_d_n = 8'h7F;
|
||||
|
||||
reg stm32_new_chirp = 1'b0;
|
||||
reg stm32_new_elevation = 1'b0;
|
||||
reg stm32_new_azimuth = 1'b0;
|
||||
reg stm32_mixers_enable = 1'b0;
|
||||
reg stm32_sclk_3v3 = 1'b0;
|
||||
reg stm32_mosi_3v3 = 1'b0;
|
||||
wire stm32_miso_3v3;
|
||||
reg stm32_cs_adar1_3v3 = 1'b1, stm32_cs_adar2_3v3 = 1'b1;
|
||||
reg stm32_cs_adar3_3v3 = 1'b1, stm32_cs_adar4_3v3 = 1'b1;
|
||||
wire stm32_sclk_1v8, stm32_mosi_1v8;
|
||||
reg stm32_miso_1v8 = 1'b0;
|
||||
wire stm32_cs_adar1_1v8, stm32_cs_adar2_1v8;
|
||||
wire stm32_cs_adar3_1v8, stm32_cs_adar4_1v8;
|
||||
|
||||
wire [7:0] dac_data;
|
||||
wire dac_clk;
|
||||
wire dac_sleep;
|
||||
|
||||
wire fpga_rf_switch;
|
||||
wire rx_mixer_en, tx_mixer_en;
|
||||
wire adc_pwdn;
|
||||
|
||||
wire adar_tx_load_1, adar_rx_load_1;
|
||||
wire adar_tx_load_2, adar_rx_load_2;
|
||||
wire adar_tx_load_3, adar_rx_load_3;
|
||||
wire adar_tx_load_4, adar_rx_load_4;
|
||||
wire adar_tr_1, adar_tr_2, adar_tr_3, adar_tr_4;
|
||||
|
||||
// FT601 ports — unused in USB_MODE=1
|
||||
wire [31:0] ft601_data;
|
||||
wire [3:0] ft601_be;
|
||||
wire ft601_txe_n;
|
||||
wire ft601_rxf_n;
|
||||
reg ft601_txe = 1'b0;
|
||||
reg ft601_rxf = 1'b1;
|
||||
wire ft601_wr_n;
|
||||
wire ft601_rd_n;
|
||||
wire ft601_oe_n;
|
||||
wire ft601_siwu_n;
|
||||
reg [1:0] ft601_srb = 2'b00;
|
||||
reg [1:0] ft601_swb = 2'b00;
|
||||
wire ft601_clk_out;
|
||||
|
||||
// FT2232H ports — used for the (single) opcode we may send to set stream_control
|
||||
wire [7:0] ft_data;
|
||||
reg ft_rxf_n = 1'b1;
|
||||
reg ft_txe_n = 1'b0;
|
||||
wire ft_rd_n;
|
||||
wire ft_wr_n;
|
||||
wire ft_oe_n;
|
||||
wire ft_siwu;
|
||||
|
||||
reg [7:0] ft_data_drive = 8'h00;
|
||||
reg ft_data_drive_en = 1'b0;
|
||||
assign ft_data = ft_data_drive_en ? ft_data_drive : 8'hzz;
|
||||
pulldown pd[7:0] (ft_data);
|
||||
|
||||
wire [5:0] current_elevation, current_azimuth, current_chirp;
|
||||
wire new_chirp_frame;
|
||||
wire [31:0] dbg_doppler_data;
|
||||
wire dbg_doppler_valid;
|
||||
wire [`RP_DOPPLER_BIN_WIDTH-1:0] dbg_doppler_bin;
|
||||
wire [`RP_RANGE_BIN_WIDTH_MAX-1:0] dbg_range_bin;
|
||||
wire [3:0] system_status;
|
||||
wire gpio_dig5, gpio_dig6, gpio_dig7;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// DUT
|
||||
// ----------------------------------------------------------------------------
|
||||
radar_system_top #(.USB_MODE(1)) dut (
|
||||
.clk_100m(clk_100m),
|
||||
.clk_120m_dac(clk_120m_dac),
|
||||
.ft601_clk_in(ft601_clk_in),
|
||||
.reset_n(reset_n),
|
||||
|
||||
.dac_data(dac_data), .dac_clk(dac_clk), .dac_sleep(dac_sleep),
|
||||
.fpga_rf_switch(fpga_rf_switch),
|
||||
.rx_mixer_en(rx_mixer_en), .tx_mixer_en(tx_mixer_en),
|
||||
|
||||
.adar_tx_load_1(adar_tx_load_1), .adar_rx_load_1(adar_rx_load_1),
|
||||
.adar_tx_load_2(adar_tx_load_2), .adar_rx_load_2(adar_rx_load_2),
|
||||
.adar_tx_load_3(adar_tx_load_3), .adar_rx_load_3(adar_rx_load_3),
|
||||
.adar_tx_load_4(adar_tx_load_4), .adar_rx_load_4(adar_rx_load_4),
|
||||
.adar_tr_1(adar_tr_1), .adar_tr_2(adar_tr_2),
|
||||
.adar_tr_3(adar_tr_3), .adar_tr_4(adar_tr_4),
|
||||
|
||||
.stm32_sclk_3v3(stm32_sclk_3v3),
|
||||
.stm32_mosi_3v3(stm32_mosi_3v3),
|
||||
.stm32_miso_3v3(stm32_miso_3v3),
|
||||
.stm32_cs_adar1_3v3(stm32_cs_adar1_3v3),
|
||||
.stm32_cs_adar2_3v3(stm32_cs_adar2_3v3),
|
||||
.stm32_cs_adar3_3v3(stm32_cs_adar3_3v3),
|
||||
.stm32_cs_adar4_3v3(stm32_cs_adar4_3v3),
|
||||
.stm32_sclk_1v8(stm32_sclk_1v8),
|
||||
.stm32_mosi_1v8(stm32_mosi_1v8),
|
||||
.stm32_miso_1v8(stm32_miso_1v8),
|
||||
.stm32_cs_adar1_1v8(stm32_cs_adar1_1v8),
|
||||
.stm32_cs_adar2_1v8(stm32_cs_adar2_1v8),
|
||||
.stm32_cs_adar3_1v8(stm32_cs_adar3_1v8),
|
||||
.stm32_cs_adar4_1v8(stm32_cs_adar4_1v8),
|
||||
|
||||
.adc_d_p(adc_d_p), .adc_d_n(adc_d_n),
|
||||
.adc_dco_p(adc_dco_p), .adc_dco_n(adc_dco_n),
|
||||
.adc_or_p(1'b0), .adc_or_n(1'b1),
|
||||
.adc_pwdn(adc_pwdn),
|
||||
|
||||
.stm32_new_chirp(stm32_new_chirp),
|
||||
.stm32_new_elevation(stm32_new_elevation),
|
||||
.stm32_new_azimuth(stm32_new_azimuth),
|
||||
.stm32_mixers_enable(stm32_mixers_enable),
|
||||
|
||||
.ft601_data(ft601_data),
|
||||
.ft601_be(ft601_be),
|
||||
.ft601_txe_n(ft601_txe_n),
|
||||
.ft601_rxf_n(ft601_rxf_n),
|
||||
.ft601_txe(ft601_txe),
|
||||
.ft601_rxf(ft601_rxf),
|
||||
.ft601_wr_n(ft601_wr_n),
|
||||
.ft601_rd_n(ft601_rd_n),
|
||||
.ft601_oe_n(ft601_oe_n),
|
||||
.ft601_siwu_n(ft601_siwu_n),
|
||||
.ft601_srb(ft601_srb),
|
||||
.ft601_swb(ft601_swb),
|
||||
.ft601_clk_out(ft601_clk_out),
|
||||
|
||||
.ft_data(ft_data),
|
||||
.ft_rxf_n(ft_rxf_n),
|
||||
.ft_txe_n(ft_txe_n),
|
||||
.ft_rd_n(ft_rd_n),
|
||||
.ft_wr_n(ft_wr_n),
|
||||
.ft_oe_n(ft_oe_n),
|
||||
.ft_siwu(ft_siwu),
|
||||
|
||||
.current_elevation(current_elevation),
|
||||
.current_azimuth(current_azimuth),
|
||||
.current_chirp(current_chirp),
|
||||
.new_chirp_frame(new_chirp_frame),
|
||||
.dbg_doppler_data(dbg_doppler_data),
|
||||
.dbg_doppler_valid(dbg_doppler_valid),
|
||||
.dbg_doppler_bin(dbg_doppler_bin),
|
||||
.dbg_range_bin(dbg_range_bin),
|
||||
.system_status(system_status),
|
||||
.gpio_dig5(gpio_dig5),
|
||||
.gpio_dig6(gpio_dig6),
|
||||
.gpio_dig7(gpio_dig7)
|
||||
);
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Helper: STM32 chirp toggle (drives stm32_new_chirp edge)
|
||||
// ----------------------------------------------------------------------------
|
||||
task stm32_chirp_toggle;
|
||||
begin
|
||||
stm32_new_chirp = ~stm32_new_chirp;
|
||||
#40; // hold 4 clk_100m cycles for edge detector
|
||||
end
|
||||
endtask
|
||||
|
||||
// ADC stimulus: ramp around mid-scale (matches tb_system_e2e pattern)
|
||||
integer adc_phase;
|
||||
initial begin
|
||||
adc_phase = 0;
|
||||
forever begin
|
||||
@(posedge adc_dco_p);
|
||||
if (reset_n) begin
|
||||
adc_d_p = 8'h80 + ((adc_phase * 7) & 8'h3F) - 8'h20;
|
||||
adc_d_n = ~adc_d_p;
|
||||
adc_phase = adc_phase + 1;
|
||||
end else begin
|
||||
adc_d_p = 8'h80;
|
||||
adc_d_n = 8'h7F;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// FT2232H send_cmd (carried over from tb_system_opcodes)
|
||||
// Used here only to send opcode 0x04 (stream_control = range-only) at start
|
||||
// so the USB write FSM doesn't deadlock waiting for unused doppler/detect data.
|
||||
// ----------------------------------------------------------------------------
|
||||
task send_cmd;
|
||||
input [7:0] op;
|
||||
input [7:0] addr;
|
||||
input [15:0] val;
|
||||
integer i;
|
||||
begin
|
||||
@(posedge ft601_clk_in); #1;
|
||||
ft_rxf_n = 1'b0;
|
||||
ft_data_drive = op;
|
||||
ft_data_drive_en = 1'b1;
|
||||
@(posedge ft601_clk_in); #1;
|
||||
@(posedge ft601_clk_in); #1;
|
||||
@(posedge ft601_clk_in); #1;
|
||||
ft_data_drive = addr;
|
||||
@(posedge ft601_clk_in); #1;
|
||||
ft_data_drive = val[15:8];
|
||||
@(posedge ft601_clk_in); #1;
|
||||
ft_data_drive = val[7:0];
|
||||
@(posedge ft601_clk_in); #1;
|
||||
ft_rxf_n = 1'b1;
|
||||
ft_data_drive_en = 1'b0;
|
||||
for (i = 0; i < 40; i = i + 1) @(posedge clk_100m);
|
||||
end
|
||||
endtask
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// USB write monitor (count writes during reset; only ft_wr_n in FT2232H mode)
|
||||
// ----------------------------------------------------------------------------
|
||||
integer usb_wr_count_total = 0;
|
||||
always @(posedge ft601_clk_in) begin
|
||||
if (!reset_n) usb_wr_count_total <= 0;
|
||||
else if (!ft_wr_n) usb_wr_count_total <= usb_wr_count_total + 1;
|
||||
end
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Observation counters
|
||||
// ----------------------------------------------------------------------------
|
||||
integer obs_dac_nonzero_count = 0;
|
||||
reg obs_seen_tx_mixer = 1'b0;
|
||||
reg obs_seen_rx_mixer = 1'b0;
|
||||
reg obs_seen_rf_switch = 1'b0;
|
||||
reg [5:0] obs_max_chirp = 6'd0;
|
||||
integer safety_simul_mixer_count = 0;
|
||||
integer safety_mixer_deassert_fail_count = 0;
|
||||
reg [3:0] mixer_disable_timer = 4'd0;
|
||||
|
||||
always @(posedge clk_100m) begin
|
||||
if (reset_n) begin
|
||||
if (tx_mixer_en) obs_seen_tx_mixer <= 1'b1;
|
||||
if (rx_mixer_en) obs_seen_rx_mixer <= 1'b1;
|
||||
if (fpga_rf_switch) obs_seen_rf_switch <= 1'b1;
|
||||
if (current_chirp > obs_max_chirp)
|
||||
obs_max_chirp <= current_chirp;
|
||||
// Safety: TX/RX mixer mutual exclusion
|
||||
if (tx_mixer_en && rx_mixer_en) begin
|
||||
safety_simul_mixer_count <= safety_simul_mixer_count + 1;
|
||||
end
|
||||
// Safety: mixer-disable propagation watchdog
|
||||
if (!stm32_mixers_enable) begin
|
||||
if (mixer_disable_timer < 4'd15)
|
||||
mixer_disable_timer <= mixer_disable_timer + 1'b1;
|
||||
if (mixer_disable_timer >= 4'd12 && (tx_mixer_en || rx_mixer_en))
|
||||
safety_mixer_deassert_fail_count <= safety_mixer_deassert_fail_count + 1;
|
||||
end else begin
|
||||
mixer_disable_timer <= 4'd0;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
always @(posedge clk_120m_dac) begin
|
||||
if (reset_n && dac_data != 8'h80 && dac_data != 8'h00)
|
||||
obs_dac_nonzero_count = obs_dac_nonzero_count + 1;
|
||||
end
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Test infrastructure
|
||||
// ----------------------------------------------------------------------------
|
||||
integer pass_count = 0;
|
||||
integer fail_count = 0;
|
||||
integer test_num = 0;
|
||||
|
||||
task check;
|
||||
input cond;
|
||||
input [80*8-1:0] msg;
|
||||
begin
|
||||
test_num = test_num + 1;
|
||||
if (cond) begin
|
||||
$display(" [PASS] %0d: %0s", test_num, msg);
|
||||
pass_count = pass_count + 1;
|
||||
end else begin
|
||||
$display(" [FAIL] %0d: %0s", test_num, msg);
|
||||
fail_count = fail_count + 1;
|
||||
end
|
||||
end
|
||||
endtask
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Main test sequence
|
||||
// ----------------------------------------------------------------------------
|
||||
integer i;
|
||||
|
||||
initial begin
|
||||
$display("============================================================");
|
||||
$display(" tb_system_mechanics — chirp/RF/safety/CDC mechanics");
|
||||
$display("============================================================");
|
||||
|
||||
// Reset
|
||||
reset_n = 1'b0;
|
||||
repeat (20) @(posedge clk_100m);
|
||||
reset_n = 1'b1;
|
||||
repeat (50) @(posedge clk_100m);
|
||||
|
||||
// Configure stream_control = range-only so the USB write FSM has a clean
|
||||
// exit from IDLE (otherwise it could wait on unused doppler/detect flags).
|
||||
send_cmd(8'h04, 8'h00, 16'h0001);
|
||||
|
||||
// ====================================================================
|
||||
// GROUP 1: RESET & INITIALIZATION
|
||||
// ====================================================================
|
||||
$display("\n--- Group 1: Reset & Initialization ---");
|
||||
|
||||
check(system_status == 4'b0000,
|
||||
"G1.1: system_status == 0 after reset");
|
||||
check(usb_wr_count_total == 0,
|
||||
"G1.2: No USB writes during/after reset");
|
||||
check(ft_wr_n == 1'b1,
|
||||
"G1.3: ft_wr_n == 1 after reset (FT2232H idle)");
|
||||
check(adc_pwdn == 1'b0,
|
||||
"G1.4: adc_pwdn == 0 (ADC enabled)");
|
||||
|
||||
// ====================================================================
|
||||
// GROUP 2: TRANSMITTER CHAIN (G2.2 moved to tb_system_dataflow)
|
||||
// ====================================================================
|
||||
$display("\n--- Group 2: Transmitter Chain ---");
|
||||
|
||||
stm32_mixers_enable = 1'b1;
|
||||
#100;
|
||||
|
||||
// Fire one LONG chirp + 3 follow-ups so DAC, RF switch, and both mixers
|
||||
// are exercised across TX (chirp) and RX (listen) phases.
|
||||
stm32_chirp_toggle;
|
||||
#40000; // 40 us — covers LONG_CHIRP -> LONG_LISTEN
|
||||
for (i = 0; i < 3; i = i + 1) begin
|
||||
stm32_chirp_toggle;
|
||||
#3000;
|
||||
end
|
||||
#5000;
|
||||
|
||||
check(obs_dac_nonzero_count > 0,
|
||||
"G2.1: DAC output non-trivial (chirp generated)");
|
||||
check(obs_seen_rf_switch == 1'b1,
|
||||
"G2.3: fpga_rf_switch activated during chirp");
|
||||
check(obs_seen_tx_mixer == 1'b1,
|
||||
"G2.4: tx_mixer_en seen during chirp sequence");
|
||||
check(obs_seen_rx_mixer == 1'b1,
|
||||
"G2.5: rx_mixer_en seen during listen phase");
|
||||
|
||||
// ====================================================================
|
||||
// GROUP 3: SAFETY ARCHITECTURE
|
||||
// ====================================================================
|
||||
$display("\n--- Group 3: Safety Architecture ---");
|
||||
|
||||
check(safety_simul_mixer_count == 0,
|
||||
"G3.1: TX/RX mixers never simultaneously enabled");
|
||||
check(adc_pwdn == 1'b0,
|
||||
"G3.2: adc_pwdn remains 0 throughout operation");
|
||||
check(adar_tr_1 == adar_tr_2 && adar_tr_2 == adar_tr_3 && adar_tr_3 == adar_tr_4,
|
||||
"G3.3: All ADAR TR pins consistent");
|
||||
|
||||
// G3.4: Disable mixers — verify they deassert within ~12 cycles
|
||||
stm32_mixers_enable = 1'b0;
|
||||
#500;
|
||||
check(tx_mixer_en == 1'b0 && rx_mixer_en == 1'b0,
|
||||
"G3.4: Mixers deassert when stm32_mixers_enable=0");
|
||||
check(safety_mixer_deassert_fail_count == 0,
|
||||
"G3.5: No mixer-still-on-after-12-cycles violations");
|
||||
|
||||
// Re-enable for G7
|
||||
stm32_mixers_enable = 1'b1;
|
||||
#100;
|
||||
|
||||
// ====================================================================
|
||||
// GROUP 7.1 / 7.3: CDC CROSSING STRESS (G7.2/7.4 in tb_system_opcodes)
|
||||
// ====================================================================
|
||||
$display("\n--- Group 7: CDC crossing stress ---");
|
||||
|
||||
// G7.1: rapid chirp toggles — verify DAC stays active (CDC delivered).
|
||||
// host_radar_mode defaults to 2'b00 (STM32-driven) at reset, so toggles
|
||||
// drive the TX directly without an opcode.
|
||||
obs_dac_nonzero_count = 0;
|
||||
for (i = 0; i < 10; i = i + 1) begin
|
||||
stm32_chirp_toggle;
|
||||
#500;
|
||||
end
|
||||
#20000;
|
||||
check(obs_dac_nonzero_count > 0,
|
||||
"G7.1: CDC delivered chirp toggles (DAC active after rapid toggles)");
|
||||
|
||||
// G7.3: TX chirp counter CDC (120 MHz -> 100 MHz). Either the counter
|
||||
// advanced or DAC was active long enough to prove the path is alive.
|
||||
check(obs_max_chirp > 0 || obs_dac_nonzero_count > 100,
|
||||
"G7.3: TX chirp CDC path delivered data (counter or DAC active)");
|
||||
|
||||
// ====================================================================
|
||||
// SUMMARY
|
||||
// ====================================================================
|
||||
$display("\n============================================================");
|
||||
$display(" RESULTS: %0d passed, %0d failed / %0d total",
|
||||
pass_count, fail_count, test_num);
|
||||
$display("============================================================");
|
||||
if (fail_count == 0) $display(" *** ALL TESTS PASSED ***");
|
||||
else $display(" *** %0d TEST(S) FAILED ***", fail_count);
|
||||
$finish;
|
||||
end
|
||||
|
||||
// Watchdog
|
||||
initial begin
|
||||
#1_500_000; // 1.5 ms — comfortably above the ~80 us of stimulus
|
||||
$display("[WATCHDOG] tb_system_mechanics timeout");
|
||||
$display(" Tests: %0d, Pass: %0d, Fail: %0d",
|
||||
test_num, pass_count, fail_count);
|
||||
$finish;
|
||||
end
|
||||
|
||||
endmodule
|
||||
Reference in New Issue
Block a user