Revert "feat: integrate flash #1 (neural-network data) RTL into V2 top-level"
This reverts commit 59901a4905.
This commit is contained in:
@@ -77,14 +77,6 @@ module fpga_neural_v2_top #(
|
||||
// see nms_dataflow_core_sdram.v for the full design comment.
|
||||
output wire data_ready,
|
||||
|
||||
// ---- Flash #1 (neural-network weights/graph data): real,
|
||||
// ordinary GPIO SPI bus, physically separate from flash #2 (boot)
|
||||
// -- see decisions.log for the two-flash architecture rationale.
|
||||
output wire flash_sclk,
|
||||
output wire flash_mosi,
|
||||
input wire flash_miso,
|
||||
output wire flash_cs_n,
|
||||
|
||||
output wire pll_locked
|
||||
);
|
||||
|
||||
@@ -122,13 +114,6 @@ module fpga_neural_v2_top #(
|
||||
wire [15:0] host_mem_wdata, host_mem_rdata;
|
||||
wire host_mem_ready;
|
||||
|
||||
wire flash_op_start;
|
||||
wire [2:0] flash_op_code;
|
||||
wire [3:0] flash_slot_id;
|
||||
wire [23:0] flash_new_offset, flash_new_length, flash_ext_length, flash_raw_flash_addr;
|
||||
wire [7:0] flash_new_type;
|
||||
wire [ADDR_WIDTH-1:0] flash_ext_addr;
|
||||
|
||||
spi_host_bridge #(
|
||||
.ADDR_WIDTH(ADDR_WIDTH), .N_NODES(N_NODES), .MAX_DEPS(MAX_DEPS)
|
||||
) u_spi_bridge (
|
||||
@@ -141,13 +126,7 @@ module fpga_neural_v2_top #(
|
||||
.mem_req(host_mem_req), .mem_wr(host_mem_wr), .mem_addr(host_mem_addr),
|
||||
.mem_wdata(host_mem_wdata), .mem_lb_n(host_mem_lb_n), .mem_ub_n(host_mem_ub_n),
|
||||
.mem_rdata(host_mem_rdata), .mem_ready(host_mem_ready),
|
||||
.soft_rst_pulse(soft_rst_pulse),
|
||||
.flash_op_start(flash_op_start), .flash_op_code(flash_op_code),
|
||||
.flash_slot_id(flash_slot_id), .flash_new_offset(flash_new_offset),
|
||||
.flash_new_length(flash_new_length), .flash_new_type(flash_new_type),
|
||||
.flash_ext_addr(flash_ext_addr), .flash_ext_length(flash_ext_length),
|
||||
.flash_raw_flash_addr(flash_raw_flash_addr),
|
||||
.flash_busy(flash1_busy), .flash_done(flash1_done), .flash_err(flash1_err)
|
||||
.soft_rst_pulse(soft_rst_pulse)
|
||||
);
|
||||
|
||||
// ============================================================
|
||||
@@ -204,33 +183,24 @@ module fpga_neural_v2_top #(
|
||||
.m_rdata(arb_m_rdata), .m_ready(arb_m_ready)
|
||||
);
|
||||
|
||||
// ---- AR level 2 (STEP20/STEP21): compute-side AR stream (port0,
|
||||
// highest priority) vs. SPI host raw memory port (port1) vs.
|
||||
// flash #1 (neural-network data) port (port2, lowest priority --
|
||||
// matches V1's own "Port D, lowest priority" convention for this
|
||||
// exact traffic class) -- reuses slot_mem_arbiter completely
|
||||
// unchanged, just at N_PORTS=3, its own already-proven pending-
|
||||
// latch discipline applying equally to a 3-port instance ----
|
||||
wire flash_ar_req, flash_ar_wr, flash_ar_lb_n, flash_ar_ub_n, flash_ar_ready;
|
||||
wire [ADDR_WIDTH-1:0] flash_ar_addr;
|
||||
wire [15:0] flash_ar_wdata, flash_ar_rdata;
|
||||
// ---- AR level 2 (NEW, STEP20): compute-side AR stream (port0)
|
||||
// vs. SPI host raw memory port (port1) -- reuses slot_mem_arbiter
|
||||
// completely unchanged, just at N_PORTS=2, its own already-proven
|
||||
// pending-latch discipline applying equally to a 2-port instance ----
|
||||
wire [1:0] host_arb_s_req, host_arb_s_wr, host_arb_s_lb_n, host_arb_s_ub_n, host_arb_s_ready;
|
||||
wire [ADDR_WIDTH*2-1:0] host_arb_s_addr;
|
||||
wire [16*2-1:0] host_arb_s_wdata, host_arb_s_rdata;
|
||||
|
||||
wire [2:0] host_arb_s_req, host_arb_s_wr, host_arb_s_lb_n, host_arb_s_ub_n, host_arb_s_ready;
|
||||
wire [ADDR_WIDTH*3-1:0] host_arb_s_addr;
|
||||
wire [16*3-1:0] host_arb_s_wdata, host_arb_s_rdata;
|
||||
|
||||
assign host_arb_s_req = {flash_ar_req, host_mem_req, arb_m_req};
|
||||
assign host_arb_s_wr = {flash_ar_wr, host_mem_wr, arb_m_wr};
|
||||
assign host_arb_s_lb_n = {flash_ar_lb_n, host_mem_lb_n, arb_m_lb_n};
|
||||
assign host_arb_s_ub_n = {flash_ar_ub_n, host_mem_ub_n, arb_m_ub_n};
|
||||
assign host_arb_s_addr = {flash_ar_addr, host_mem_addr, arb_m_addr};
|
||||
assign host_arb_s_wdata = {flash_ar_wdata, host_mem_wdata, arb_m_wdata};
|
||||
assign host_arb_s_req = {host_mem_req, arb_m_req};
|
||||
assign host_arb_s_wr = {host_mem_wr, arb_m_wr};
|
||||
assign host_arb_s_lb_n = {host_mem_lb_n, arb_m_lb_n};
|
||||
assign host_arb_s_ub_n = {host_mem_ub_n, arb_m_ub_n};
|
||||
assign host_arb_s_addr = {host_mem_addr, arb_m_addr};
|
||||
assign host_arb_s_wdata = {host_mem_wdata, arb_m_wdata};
|
||||
assign arb_m_ready = host_arb_s_ready[0];
|
||||
assign arb_m_rdata = host_arb_s_rdata[15:0];
|
||||
assign host_mem_ready = host_arb_s_ready[1];
|
||||
assign host_mem_rdata = host_arb_s_rdata[31:16];
|
||||
assign flash_ar_ready = host_arb_s_ready[2];
|
||||
assign flash_ar_rdata = host_arb_s_rdata[47:32];
|
||||
|
||||
wire final_ar_req, final_ar_wr;
|
||||
wire [ADDR_WIDTH-1:0] final_ar_addr;
|
||||
@@ -240,7 +210,7 @@ module fpga_neural_v2_top #(
|
||||
wire final_ar_ready;
|
||||
|
||||
slot_mem_arbiter #(
|
||||
.ADDR_WIDTH(ADDR_WIDTH), .N_PORTS(3)
|
||||
.ADDR_WIDTH(ADDR_WIDTH), .N_PORTS(2)
|
||||
) u_host_arb (
|
||||
.clk(clk), .rst(core_rst),
|
||||
.s_req(host_arb_s_req), .s_wr(host_arb_s_wr), .s_addr(host_arb_s_addr),
|
||||
@@ -251,46 +221,6 @@ module fpga_neural_v2_top #(
|
||||
.m_rdata(final_ar_rdata), .m_ready(final_ar_ready)
|
||||
);
|
||||
|
||||
// ---- Flash #1 (neural-network weights/graph data): real,
|
||||
// unmodified V1 subsystem (flash_slot_manager.v, which owns
|
||||
// flash_copy_engine.v, which owns spi_flash_master.v; crc32.v used
|
||||
// internally too) -- see decisions.log for the integration design.
|
||||
// Command interface driven by spi_host_bridge.v's own new
|
||||
// OP_FLASH_CMD opcode. Data path bridged into the AR arbiter above
|
||||
// via flash_mem_adapter.v (byte<->word, matches nms_memory_
|
||||
// manager_stream_wide.v's own real masking convention). ----
|
||||
wire flash_d_req, flash_d_wr, flash_d_ready;
|
||||
wire [ADDR_WIDTH-1:0] flash_d_addr;
|
||||
wire signed [7:0] flash_d_wdata, flash_d_rdata;
|
||||
wire flash1_busy, flash1_done, flash1_err;
|
||||
|
||||
flash_slot_manager #(
|
||||
.PSRAM_ADDR_WIDTH(ADDR_WIDTH), .CLK_FREQ_MHZ(64), .SCLK_DIV(2)
|
||||
) u_flash1 (
|
||||
.clk(clk), .rst(core_rst),
|
||||
.mosi(flash_mosi), .miso(flash_miso), .cs_n(flash_cs_n), .sclk(flash_sclk),
|
||||
.op_start(flash_op_start), .op_code(flash_op_code), .slot_id(flash_slot_id),
|
||||
.new_offset(flash_new_offset), .new_length(flash_new_length), .new_type(flash_new_type),
|
||||
.ext_psram_addr(flash_ext_addr), .ext_length(flash_ext_length),
|
||||
.raw_flash_addr(flash_raw_flash_addr),
|
||||
.busy(flash1_busy), .done(flash1_done), .err(flash1_err),
|
||||
.cat_read_sel(4'd0), .cat_out_offset(), .cat_out_length(),
|
||||
.cat_out_type(), .cat_out_valid(), .cat_out_crc(),
|
||||
.d_req(flash_d_req), .d_wr(flash_d_wr), .d_addr(flash_d_addr),
|
||||
.d_wdata(flash_d_wdata), .d_rdata(flash_d_rdata), .d_ready(flash_d_ready)
|
||||
);
|
||||
|
||||
flash_mem_adapter #(
|
||||
.ADDR_WIDTH(ADDR_WIDTH), .BYTE_ADDR_WIDTH(ADDR_WIDTH)
|
||||
) u_flash_adapter (
|
||||
.clk(clk), .rst(core_rst),
|
||||
.d_req(flash_d_req), .d_wr(flash_d_wr), .d_addr(flash_d_addr),
|
||||
.d_wdata(flash_d_wdata), .d_rdata(flash_d_rdata), .d_ready(flash_d_ready),
|
||||
.s_req(flash_ar_req), .s_wr(flash_ar_wr), .s_addr(flash_ar_addr),
|
||||
.s_wdata(flash_ar_wdata), .s_lb_n(flash_ar_lb_n), .s_ub_n(flash_ar_ub_n),
|
||||
.s_rdata(flash_ar_rdata), .s_ready(flash_ar_ready)
|
||||
);
|
||||
|
||||
// ---- W: weight fetch (unchanged) ----
|
||||
wire [N_SLOTS-1:0] wide_s_wr = {N_SLOTS{1'b0}};
|
||||
wire [64*N_SLOTS-1:0] wide_s_wdata = {(64*N_SLOTS){1'b0}};
|
||||
|
||||
@@ -1,251 +0,0 @@
|
||||
`timescale 1ns/1ps
|
||||
|
||||
// ================================================================
|
||||
// FPGA-Neural V2 -- Flash #1 (neural-network data) integration smoke
|
||||
// test (2026-09-07)
|
||||
//
|
||||
// Proves the NEW wiring this session adds end-to-end: a real SPI
|
||||
// OP_FLASH_CMD transaction (bit-banged, mode 0) drives
|
||||
// spi_host_bridge.v's own new flash_* command ports, into the real,
|
||||
// UNCHANGED V1 flash_slot_manager.v (which owns flash_copy_engine.v,
|
||||
// which owns spi_flash_master.v -- all three reused byte-for-byte,
|
||||
// zero modifications, per their own header comments), through the
|
||||
// NEW flash_mem_adapter.v (byte<->word bridge), into the NEW third
|
||||
// port of the host-arb slot_mem_arbiter (N_PORTS 2->3), down to the
|
||||
// same real sdram_unified_backend/sdram_controller/AS4C32M16SB-7BIN
|
||||
// chain already used by every other traffic class -- checked against
|
||||
// a real, backdoor-peeked SDRAM result.
|
||||
//
|
||||
// Uses OP_FLASH_READ_BLOCK (op_code=4): the simplest real operation
|
||||
// that exercises the full new path without needing catalog/slot setup
|
||||
// (raw flash_addr -> ext_psram_addr, explicit length) -- flash_slot_
|
||||
// manager.v's own real semantics, confirmed by inspection.
|
||||
//
|
||||
// flash_model.v (real, unmodified V1 SPI-flash simulation model,
|
||||
// erase-state 0xFF, real Winbond command set) is preloaded with a
|
||||
// known byte pattern at a known flash address; after the SPI-
|
||||
// triggered read-block completes, the destination SDRAM region is
|
||||
// backdoor-peeked and compared byte-for-byte against that same known
|
||||
// pattern.
|
||||
// ================================================================
|
||||
|
||||
`define SIM
|
||||
|
||||
module tb_flash_integration_smoke;
|
||||
|
||||
localparam ADDR_WIDTH = 26;
|
||||
localparam N_SLOTS = 2;
|
||||
localparam N_NODES = 16;
|
||||
localparam MAX_DEPS = 4;
|
||||
|
||||
reg osc_clk = 0;
|
||||
always #7.8125 osc_clk = ~osc_clk; // 64MHz, SIM PLL bypass
|
||||
|
||||
reg ext_rst_n = 0;
|
||||
|
||||
reg spi_sclk = 0, spi_mosi = 0, spi_cs_n = 1;
|
||||
wire spi_miso;
|
||||
|
||||
wire sdram_cke, sdram_cs_n, sdram_ras_n, sdram_cas_n, sdram_we_n;
|
||||
wire [1:0] sdram_ba;
|
||||
wire [12:0] sdram_a;
|
||||
wire [15:0] sdram_dq;
|
||||
wire [1:0] sdram_dqm;
|
||||
wire pll_locked, data_ready, sdram_clk;
|
||||
|
||||
wire flash_sclk, flash_mosi, flash_cs_n;
|
||||
wire flash_miso;
|
||||
|
||||
fpga_neural_v2_top #(
|
||||
.ADDR_WIDTH(ADDR_WIDTH), .N_SLOTS(N_SLOTS), .N_NODES(N_NODES), .MAX_DEPS(MAX_DEPS),
|
||||
.CLK_FREQ_MHZ(64)
|
||||
) dut (
|
||||
.osc_clk(osc_clk), .ext_rst_n(ext_rst_n),
|
||||
.spi_sclk(spi_sclk), .spi_mosi(spi_mosi), .spi_miso(spi_miso), .spi_cs_n(spi_cs_n),
|
||||
.sdram_clk(sdram_clk),
|
||||
.sdram_cke(sdram_cke), .sdram_cs_n(sdram_cs_n), .sdram_ras_n(sdram_ras_n),
|
||||
.sdram_cas_n(sdram_cas_n), .sdram_we_n(sdram_we_n),
|
||||
.sdram_ba(sdram_ba), .sdram_a(sdram_a), .sdram_dq(sdram_dq), .sdram_dqm(sdram_dqm),
|
||||
.data_ready(data_ready),
|
||||
.flash_sclk(flash_sclk), .flash_mosi(flash_mosi), .flash_miso(flash_miso), .flash_cs_n(flash_cs_n),
|
||||
.pll_locked(pll_locked)
|
||||
);
|
||||
|
||||
sdram_model #(.CLK_FREQ_MHZ(64)) u_sdram (
|
||||
.clk(dut.clk_sys), .cke(sdram_cke), .cs_n(sdram_cs_n), .ras_n(sdram_ras_n),
|
||||
.cas_n(sdram_cas_n), .we_n(sdram_we_n), .ba(sdram_ba), .a(sdram_a),
|
||||
.dq(sdram_dq), .dqm(sdram_dqm)
|
||||
);
|
||||
|
||||
flash_model u_flash (
|
||||
.sclk(flash_sclk), .mosi(flash_mosi), .miso(flash_miso), .cs_n(flash_cs_n)
|
||||
);
|
||||
|
||||
task poke_byte(input [ADDR_WIDTH-1:0] byte_addr, input signed [7:0] val);
|
||||
reg [24:0] word_addr;
|
||||
begin
|
||||
word_addr = byte_addr[ADDR_WIDTH-1:1];
|
||||
if (byte_addr[0] == 1'b0) u_sdram.mem[word_addr][7:0] = val;
|
||||
else u_sdram.mem[word_addr][15:8] = val;
|
||||
end
|
||||
endtask
|
||||
|
||||
function automatic signed [7:0] peek_byte(input [ADDR_WIDTH-1:0] byte_addr);
|
||||
reg [24:0] word_addr;
|
||||
begin
|
||||
word_addr = byte_addr[ADDR_WIDTH-1:1];
|
||||
peek_byte = (byte_addr[0] == 1'b0) ? u_sdram.mem[word_addr][7:0] : u_sdram.mem[word_addr][15:8];
|
||||
end
|
||||
endfunction
|
||||
|
||||
task spi_byte(input [7:0] tx, output [7:0] rx);
|
||||
integer i;
|
||||
begin
|
||||
rx = 8'h00;
|
||||
for (i = 7; i >= 0; i = i - 1) begin
|
||||
spi_mosi = tx[i];
|
||||
#200; spi_sclk = 1; #50; rx = {rx[6:0], spi_miso}; #50; spi_sclk = 0; #200;
|
||||
end
|
||||
end
|
||||
endtask
|
||||
|
||||
localparam OP_FLASH_CMD = 8'h30;
|
||||
localparam OP_STATUS = 8'h20;
|
||||
localparam OP_FLASH_READ_BLOCK = 3'd4;
|
||||
|
||||
// Sends one OP_FLASH_CMD transaction (19 payload bytes, matching
|
||||
// spi_host_bridge.v's own real field layout), CS held through the
|
||||
// opcode+payload only -- op_start fires the cycle the last byte's
|
||||
// handshake completes, flash_op_start/flash_busy handshake happens
|
||||
// AFTER cs rises (mirrors WRITE_JOB's own real contract).
|
||||
task flash_cmd(input [2:0] op_code, input [3:0] slot_id,
|
||||
input [23:0] new_offset, input [23:0] new_length, input [7:0] new_type,
|
||||
input [ADDR_WIDTH-1:0] ext_addr, input [23:0] ext_length,
|
||||
input [23:0] raw_flash_addr);
|
||||
reg [7:0] rxb;
|
||||
begin
|
||||
spi_cs_n = 0; #20;
|
||||
spi_byte(8'h30, rxb);
|
||||
spi_byte({5'b0, op_code}, rxb);
|
||||
spi_byte({4'b0, slot_id}, rxb);
|
||||
spi_byte(new_offset[23:16], rxb);
|
||||
spi_byte(new_offset[15:8], rxb);
|
||||
spi_byte(new_offset[7:0], rxb);
|
||||
spi_byte(new_length[23:16], rxb);
|
||||
spi_byte(new_length[15:8], rxb);
|
||||
spi_byte(new_length[7:0], rxb);
|
||||
spi_byte(new_type, rxb);
|
||||
spi_byte({{(32-ADDR_WIDTH){1'b0}}, ext_addr[ADDR_WIDTH-1:24]}, rxb);
|
||||
spi_byte(ext_addr[23:16], rxb);
|
||||
spi_byte(ext_addr[15:8], rxb);
|
||||
spi_byte(ext_addr[7:0], rxb);
|
||||
spi_byte(ext_length[23:16], rxb);
|
||||
spi_byte(ext_length[15:8], rxb);
|
||||
spi_byte(ext_length[7:0], rxb);
|
||||
spi_byte(raw_flash_addr[23:16], rxb);
|
||||
spi_byte(raw_flash_addr[15:8], rxb);
|
||||
spi_byte(raw_flash_addr[7:0], rxb);
|
||||
spi_cs_n = 1; #200;
|
||||
end
|
||||
endtask
|
||||
|
||||
// Polls OP_STATUS until flash_busy (bit3) is low; times out loudly
|
||||
// rather than hanging forever if something is wrong.
|
||||
task wait_flash_idle;
|
||||
reg [7:0] status;
|
||||
integer guard;
|
||||
begin
|
||||
guard = 0;
|
||||
status = 8'h08; // force at least one real poll
|
||||
while (status[3] === 1'b1 && guard < 2000) begin
|
||||
spi_cs_n = 0; #20;
|
||||
spi_byte(OP_STATUS, status);
|
||||
spi_byte(8'h00, status);
|
||||
spi_cs_n = 1; #200;
|
||||
guard = guard + 1;
|
||||
end
|
||||
if (guard >= 2000) begin
|
||||
$display("FAIL wait_flash_idle: timed out, flash_busy never cleared");
|
||||
errors = errors + 1;
|
||||
end
|
||||
end
|
||||
endtask
|
||||
|
||||
integer errors, tests;
|
||||
integer i;
|
||||
reg signed [7:0] expect_val, got_val;
|
||||
|
||||
initial begin
|
||||
errors = 0; tests = 0;
|
||||
#100; ext_rst_n = 1;
|
||||
#500;
|
||||
|
||||
// Preload flash_model with a known, non-trivial pattern at
|
||||
// flash byte address 24'h001000 (well clear of the reserved
|
||||
// sector 0 catalog region, matching flash_slot_manager.v's
|
||||
// own CATALOG_SECTOR_ADDR convention).
|
||||
for (i = 0; i < 64; i = i + 1)
|
||||
u_flash.mem[24'h001000 + i] = (i * 7 + 3) & 8'hFF;
|
||||
|
||||
// Pre-poison the SDRAM destination so a no-op would be caught
|
||||
// (backdoor write of a sentinel the real transfer must
|
||||
// overwrite).
|
||||
for (i = 0; i < 64; i = i + 1)
|
||||
poke_byte(26'h050000 + i, 8'sh55);
|
||||
|
||||
tests = tests + 1;
|
||||
flash_cmd(OP_FLASH_READ_BLOCK, 4'd0, 24'd0, 24'd0, 8'd0,
|
||||
26'h050000, 24'd64, 24'h001000);
|
||||
wait_flash_idle;
|
||||
|
||||
for (i = 0; i < 64; i = i + 1) begin
|
||||
expect_val = (i * 7 + 3) & 8'hFF;
|
||||
got_val = peek_byte(26'h050000 + i);
|
||||
if (got_val !== expect_val) begin
|
||||
$display("FAIL flash-read-block byte %0d: expected %0d got %0d", i, expect_val, got_val);
|
||||
errors = errors + 1;
|
||||
end
|
||||
end
|
||||
if (errors == 0)
|
||||
$display("PASS OP_FLASH_READ_BLOCK: 64/64 bytes bit-exact, flash -> SDRAM via new adapter+arbiter path");
|
||||
|
||||
// ---- Regression check: the pre-existing WRITE_JOB path must
|
||||
// still work unchanged with the new 3rd arbiter port added
|
||||
// (same style check as tb_fpga_neural_v2_top_smoke.v, minimal:
|
||||
// just confirm reg_valid/reg_ready handshake completes without
|
||||
// hanging, real functional coverage already lives in that
|
||||
// file and in the full D-Stress regression). ----
|
||||
tests = tests + 1;
|
||||
begin : write_job_regression
|
||||
reg [7:0] rxb;
|
||||
spi_cs_n = 0; #20;
|
||||
spi_byte(8'h10, rxb); // OP_WRITE_JOB
|
||||
spi_byte({4'b0, 4'd0}, rxb); // node_id=0
|
||||
spi_byte({5'b0, 3'd0}, rxb); // required=0 (immediately ready)
|
||||
spi_byte(8'h00, rxb); spi_byte(8'h00, rxb); // producer_ids
|
||||
spi_byte(8'h00, rxb); spi_byte(8'h00, rxb); spi_byte(8'h00, rxb); spi_byte(8'h00, rxb); // x_base=0
|
||||
spi_byte(8'h00, rxb); spi_byte(8'h00, rxb); spi_byte(8'h00, rxb); spi_byte(8'h00, rxb); // w_base=0
|
||||
spi_byte(8'h00, rxb); spi_byte(8'h01, rxb); // n_tiles=1
|
||||
spi_byte(8'h01, rxb); spi_byte(8'h40, rxb); spi_byte(8'h00, rxb); spi_byte(8'h00, rxb); // result_addr
|
||||
#2000;
|
||||
spi_cs_n = 1; #200;
|
||||
end
|
||||
#5000;
|
||||
$display("PASS WRITE_JOB regression: transaction completed without hanging (new 3rd arbiter port did not deadlock existing traffic)");
|
||||
|
||||
$display("========================================");
|
||||
if (errors == 0)
|
||||
$display("ALL %0d FLASH INTEGRATION TESTS PASSED", tests);
|
||||
else
|
||||
$display("FAILED: %0d error(s) -- see messages above", errors);
|
||||
$display("========================================");
|
||||
$finish;
|
||||
end
|
||||
|
||||
initial begin
|
||||
#2000000;
|
||||
$display("FAIL: global timeout, something hung");
|
||||
$finish;
|
||||
end
|
||||
|
||||
endmodule
|
||||
Reference in New Issue
Block a user