From f63dfd70285d2da064ae259317a2f7d07d775052 Mon Sep 17 00:00:00 2001 From: Matthew Ballance Date: Tue, 19 Nov 2019 22:43:45 -0500 Subject: [PATCH] Fix VPI timed callbacks to be one-shot, pull5. Signed-off-by: Matthew Ballance Signed-off-by: Wilson Snyder --- Changes | 2 + include/verilated_vpi.cpp | 4 +- test_regress/t/t_vpi_time_cb.cpp | 256 ++++++++++++++++++++++++++ test_regress/t/t_vpi_time_cb.pl | 30 +++ test_regress/t/t_vpi_time_cb.v | 116 ++++++++++++ test_regress/t/t_vpi_zero_time_cb.cpp | 212 +++++++++++++++++++++ test_regress/t/t_vpi_zero_time_cb.pl | 30 +++ test_regress/t/t_vpi_zero_time_cb.v | 116 ++++++++++++ 8 files changed, 765 insertions(+), 1 deletion(-) create mode 100644 test_regress/t/t_vpi_time_cb.cpp create mode 100755 test_regress/t/t_vpi_time_cb.pl create mode 100644 test_regress/t/t_vpi_time_cb.v create mode 100644 test_regress/t/t_vpi_zero_time_cb.cpp create mode 100755 test_regress/t/t_vpi_zero_time_cb.pl create mode 100644 test_regress/t/t_vpi_zero_time_cb.v diff --git a/Changes b/Changes index 0e71b3323..c316e3a48 100644 --- a/Changes +++ b/Changes @@ -20,6 +20,8 @@ The contributors that suggested a given feature are shown in []. Thanks! **** Fix hang on concat error, bug1608. [Bogdan Vukobratovic] +**** Fix VPI timed callbacks to be one-shot, pull5. [Matthew Ballance] + * Verilator 4.022 2019-11-10 diff --git a/include/verilated_vpi.cpp b/include/verilated_vpi.cpp index fd2a5da8c..f6c780dcd 100644 --- a/include/verilated_vpi.cpp +++ b/include/verilated_vpi.cpp @@ -416,7 +416,9 @@ public: for (VpioTimedCbs::iterator it=s_s.m_timedCbs.begin(); it!=s_s.m_timedCbs.end(); ) { if (VL_UNLIKELY(it->first <= time)) { VerilatedVpioCb* vop = it->second; - ++it; // iterator may be deleted by callback + VpioTimedCbs::iterator last_it = it; + ++it; // Timed callbacks are one-shot + s_s.m_timedCbs.erase(last_it); VL_DEBUG_IF_PLI(VL_DBG_MSGF("- vpi: timed_callback %p\n", vop);); (vop->cb_rtnp()) (vop->cb_datap()); } diff --git a/test_regress/t/t_vpi_time_cb.cpp b/test_regress/t/t_vpi_time_cb.cpp new file mode 100644 index 000000000..aae0044f6 --- /dev/null +++ b/test_regress/t/t_vpi_time_cb.cpp @@ -0,0 +1,256 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +//************************************************************************* +// +// Copyright 2010-2011 by Wilson Snyder. This program is free software; you can +// redistribute it and/or modify it under the terms of either the GNU +// Lesser General Public License Version 3 or the Perl Artistic License. +// Version 2.0. +// +// Verilator is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +//************************************************************************* + +#ifdef IS_VPI + +#include "vpi_user.h" + +#else + +#include "Vt_vpi_time_cb.h" +#include "verilated.h" +#include "svdpi.h" +#include + +#include "Vt_vpi_time_cb__Dpi.h" + +#include "verilated_vpi.h" +#include "verilated_vcd_c.h" + +#endif + +#include +#include +#include +#include +using namespace std; + +#include "TestSimulator.h" +#include "TestVpi.h" + +// __FILE__ is too long +#define FILENM "t_vpi_time_cb.cpp" + +#define TEST_MSG \ + if (0) printf + +unsigned int main_time = false; +unsigned int callback_count_time1 = 3; +unsigned int callback_count_time2 = 4; +unsigned int callback_count_start_of_sim = 0; + +//====================================================================== + +#define CHECK_RESULT_VH(got, exp) \ + if ((got) != (exp)) { \ + printf("%%Error: %s:%d: GOT = %p EXP = %p\n", FILENM, __LINE__, (got), (exp)); \ + return __LINE__; \ + } + +#define CHECK_RESULT_NZ(got) \ + if (!(got)) { \ + printf("%%Error: %s:%d: GOT = NULL EXP = !NULL\n", FILENM, __LINE__); \ + return __LINE__; \ + } + +// Use cout to avoid issues with %d/%lx etc +#define CHECK_RESULT(got, exp) \ + if ((got) != (exp)) { \ + cout << dec << "%Error: " << FILENM << ":" << __LINE__ << ": GOT = " << (got) \ + << " EXP = " << (exp) << endl; \ + return __LINE__; \ + } + +#define CHECK_RESULT_HEX(got, exp) \ + if ((got) != (exp)) { \ + cout << dec << "%Error: " << FILENM << ":" << __LINE__ << hex << ": GOT = " << (got) \ + << " EXP = " << (exp) << endl; \ + return __LINE__; \ + } + +#define CHECK_RESULT_CSTR(got, exp) \ + if (strcmp((got), (exp))) { \ + printf("%%Error: %s:%d: GOT = '%s' EXP = '%s'\n", FILENM, __LINE__, \ + (got) ? (got) : "", (exp) ? (exp) : ""); \ + return __LINE__; \ + } + +#define CHECK_RESULT_CSTR_STRIP(got, exp) CHECK_RESULT_CSTR(got + strspn(got, " "), exp) + +#define STRINGIFY(x) STRINGIFY2(x) +#define STRINGIFY2(x) #x + +//====================================================================== + +#ifdef IS_VPI + +static int _time_cb1(p_cb_data cb_data) { + s_vpi_time t; + t.type = vpiSimTime; + vpi_get_time(0, &t); + // fprintf(stdout, "time_cb1: %d\n", t.low); + CHECK_RESULT(callback_count_time1, t.low); + callback_count_time1++; + + t_cb_data cb_data_n; + + cb_data_n.reason = cbAfterDelay; + t.type = vpiSimTime; + t.high = 0; + t.low = 1; + cb_data_n.time = &t; + cb_data_n.cb_rtn = _time_cb1; + vpi_register_cb(&cb_data_n); + return 0; +} + +static int _time_cb2(p_cb_data cb_data) { + s_vpi_time t; + t.type = vpiSimTime; + vpi_get_time(0, &t); + // fprintf(stdout, "time_cb2: %d\n", t.low); + CHECK_RESULT(callback_count_time2, t.low); + callback_count_time2++; + + t_cb_data cb_data_n; + + cb_data_n.reason = cbAfterDelay; + t.type = vpiSimTime; + t.high = 0; + t.low = 1; + cb_data_n.time = &t; + cb_data_n.cb_rtn = _time_cb2; + vpi_register_cb(&cb_data_n); + return 0; +} + +static int _start_of_sim_cb(p_cb_data cb_data) { + t_cb_data cb_data_n1, cb_data_n2; + s_vpi_time t1, t2; + + cb_data_n1.reason = cbAfterDelay; + t1.type = vpiSimTime; + t1.high = 0; + t1.low = 3; + cb_data_n1.time = &t1; + cb_data_n1.cb_rtn = _time_cb1; + vpi_register_cb(&cb_data_n1); + + cb_data_n2.reason = cbAfterDelay; + t2.type = vpiSimTime; + t2.high = 0; + t2.low = 4; + cb_data_n2.time = &t2; + cb_data_n2.cb_rtn = _time_cb2; + vpi_register_cb(&cb_data_n2); + callback_count_start_of_sim++; + return 0; +} + +static int _end_of_sim_cb(p_cb_data cb_data) { + CHECK_RESULT(callback_count_start_of_sim, 1); + fprintf(stdout, "*-* All Finished *-*\n"); + return 0; +} + +// cver entry +#ifdef __cplusplus +extern "C" +#endif + +void vpi_compat_bootstrap(void) { + t_cb_data cb_data; + + // VL_PRINTF("register start-of-sim callback\n"); + cb_data.reason = cbStartOfSimulation; + cb_data.time = 0; + cb_data.cb_rtn = _start_of_sim_cb; + vpi_register_cb(&cb_data); + + cb_data.reason = cbEndOfSimulation; + cb_data.time = 0; + cb_data.cb_rtn = _end_of_sim_cb; + vpi_register_cb(&cb_data); +} + +// icarus entry +void (*vlog_startup_routines[])() = {vpi_compat_bootstrap, 0}; + +#else + +double sc_time_stamp() { return main_time; } + +int main(int argc, char** argv, char** env) { + double sim_time = 1100; + Verilated::commandArgs(argc, argv); + Verilated::debug(0); + + VM_PREFIX* topp = new VM_PREFIX(""); // Note null name - we're flattening it out + +#ifdef VERILATOR +# ifdef TEST_VERBOSE + Verilated::scopesDump(); +# endif +#endif + +#if VM_TRACE + Verilated::traceEverOn(true); + VL_PRINTF("Enabling waves...\n"); + VerilatedVcdC* tfp = new VerilatedVcdC; + topp->trace(tfp, 99); + tfp->open(STRINGIFY(TEST_OBJ_DIR) "/simx.vcd"); +#endif + + // Load and initialize the PLI application + { + void* lib = dlopen("./obj_vlt/t_vpi_time_cb/libvpi.so", RTLD_LAZY); + void* bootstrap = dlsym(lib, "vpi_compat_bootstrap"); + ((void (*)(void))bootstrap)(); + } + + VerilatedVpi::callCbs(cbStartOfSimulation); + + topp->eval(); + topp->clk = 0; + main_time += 1; + + while (sc_time_stamp() < sim_time && !Verilated::gotFinish()) { + main_time += 1; + topp->eval(); + VerilatedVpi::callValueCbs(); + VerilatedVpi::callTimedCbs(); + topp->clk = !topp->clk; + // mon_do(); +#if VM_TRACE + if (tfp) tfp->dump(main_time); +#endif + } + + VerilatedVpi::callCbs(cbEndOfSimulation); + + if (!Verilated::gotFinish()) { + vl_fatal(FILENM, __LINE__, "main", "%Error: Timeout; never got a $finish"); + } + topp->final(); + +#if VM_TRACE + if (tfp) tfp->close(); +#endif + + delete topp; VL_DANGLING(topp); + exit(0L); +} + +#endif diff --git a/test_regress/t/t_vpi_time_cb.pl b/test_regress/t/t_vpi_time_cb.pl new file mode 100755 index 000000000..4c2bcfcf1 --- /dev/null +++ b/test_regress/t/t_vpi_time_cb.pl @@ -0,0 +1,30 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2010 by Wilson Snyder. This program is free software; you can +# redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. + +scenarios(simulator => 1, iv => 1); + +compile( + make_top_shell => 0, + make_main => 0, + make_pli => 1, + sim_time => 2100, + iv_flags2 => ["-g2005-sv -D USE_VPI_NOT_DPI -DWAVES -Diverilog"], + v_flags2 => ["+define+USE_VPI_NOT_DPI"], + verilator_flags2 => ["-CFLAGS '-DVL_DEBUG -ggdb' --exe --vpi --no-l2name $Self->{t_dir}/t_vpi_time_cb.cpp -LDFLAGS '-ldl -rdynamic'"], + ); + +execute( + iv_pli => 1, + ms_pli => 1, + check_finished => 1, + all_run_flags => ['+PLUS +INT=1234 +STRSTR'] + ); + +ok(1); +1; diff --git a/test_regress/t/t_vpi_time_cb.v b/test_regress/t/t_vpi_time_cb.v new file mode 100644 index 000000000..56502dce3 --- /dev/null +++ b/test_regress/t/t_vpi_time_cb.v @@ -0,0 +1,116 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// Copyright 2010 by Wilson Snyder. This program is free software; you can +// redistribute it and/or modify it under the terms of either the GNU +// Lesser General Public License Version 3 or the Perl Artistic License +// Version 2.0. + +module t (/*AUTOARG*/ + // Inputs + input clk + ); + +`ifndef VERILATOR + reg clk_r = 0; + always #10 clk_r = ~clk_r; + assign clk = clk_r; +`endif + + reg onebit /*verilator public_flat_rw @(posedge clk) */; + reg [2:1] twoone /*verilator public_flat_rw @(posedge clk) */; + reg [2:1] fourthreetwoone[4:3] /*verilator public_flat_rw @(posedge clk) */; + + reg [61:0] quads[3:2] /*verilator public_flat_rw @(posedge clk) */; + + reg [31:0] count /*verilator public_flat_rd */; + reg [31:0] half_count /*verilator public_flat_rd */; + + reg [7:0] text_byte /*verilator public_flat_rw @(posedge clk) */; + reg [15:0] text_half /*verilator public_flat_rw @(posedge clk) */; + reg [31:0] text_word /*verilator public_flat_rw @(posedge clk) */; + reg [63:0] text_long /*verilator public_flat_rw @(posedge clk) */; + reg [511:0] text /*verilator public_flat_rw @(posedge clk) */; + + integer status; + + sub sub(); + + // Test loop + initial begin + count = 0; + onebit = 1'b0; + fourthreetwoone[3] = 0; // stop icarus optimizing away + text_byte = "B"; + text_half = "Hf"; + text_word = "Word"; + text_long = "Long64b"; + text = "Verilog Test module"; + +/* + if (status!=0) begin + $write("%%Error: t_vpi_var.cpp:%0d: C Test failed\n", status); + $stop; + end + $write("%%Info: Checking results\n"); + if (onebit != 1'b1) $stop; + if (quads[2] != 62'h12819213_abd31a1c) $stop; + if (quads[3] != 62'h1c77bb9b_3784ea09) $stop; + if (text_byte != "A") $stop; + if (text_half != "T2") $stop; + if (text_word != "Tree") $stop; + if (text_long != "44Four44") $stop; + if (text != "lorem ipsum") $stop; + */ + end + + always @(posedge clk) begin + count <= count + 2; + if (count[1]) + half_count <= half_count + 2; + + if (count == 1000) begin +// $write("*-* All Finished *-*\n"); + $finish; + end + end + + genvar i; + generate + for (i=1; i<=128; i=i+1) begin : arr + arr #(.LENGTH(i)) arr(); + end + endgenerate + +endmodule : t + +module sub; + reg subsig1 /*verilator public_flat_rd*/; + reg subsig2 /*verilator public_flat_rd*/; +`ifdef iverilog + // stop icarus optimizing signals away + wire redundant = subsig1 | subsig2; +`endif +endmodule : sub + +module arr; + + parameter LENGTH = 1; + + reg [LENGTH-1:0] sig /*verilator public_flat_rw*/; + reg [LENGTH-1:0] rfr /*verilator public_flat_rw*/; + + reg check /*verilator public_flat_rw*/; + reg verbose /*verilator public_flat_rw*/; + + initial begin + sig = {LENGTH{1'b0}}; + rfr = {LENGTH{1'b0}}; + end + + always @(posedge check) begin + if (verbose) $display("%m : %x %x", sig, rfr); + if (check && sig != rfr) $stop; + check <= 0; + end + +endmodule : arr diff --git a/test_regress/t/t_vpi_zero_time_cb.cpp b/test_regress/t/t_vpi_zero_time_cb.cpp new file mode 100644 index 000000000..b134021d9 --- /dev/null +++ b/test_regress/t/t_vpi_zero_time_cb.cpp @@ -0,0 +1,212 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +//************************************************************************* +// +// Copyright 2010-2011 by Wilson Snyder. This program is free software; you can +// redistribute it and/or modify it under the terms of either the GNU +// Lesser General Public License Version 3 or the Perl Artistic License. +// Version 2.0. +// +// Verilator is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +//************************************************************************* + +#ifdef IS_VPI + +#include "vpi_user.h" + +#else + +#include "Vt_vpi_zero_time_cb.h" +#include "verilated.h" +#include "svdpi.h" +#include + +#include "Vt_vpi_zero_time_cb__Dpi.h" + +#include "verilated_vpi.h" +#include "verilated_vcd_c.h" + +#endif + +#include +#include +#include +#include +using namespace std; + +#include "TestSimulator.h" +#include "TestVpi.h" + +// __FILE__ is too long +#define FILENM "t_vpi_zero_time_cb.cpp" + +#define TEST_MSG \ + if (0) printf + +unsigned int main_time = false; +unsigned int callback_count_zero_time = 0; +unsigned int callback_count_start_of_sim = 0; + +//====================================================================== + +#define CHECK_RESULT_VH(got, exp) \ + if ((got) != (exp)) { \ + printf("%%Error: %s:%d: GOT = %p EXP = %p\n", FILENM, __LINE__, (got), (exp)); \ + return __LINE__; \ + } + +#define CHECK_RESULT_NZ(got) \ + if (!(got)) { \ + printf("%%Error: %s:%d: GOT = NULL EXP = !NULL\n", FILENM, __LINE__); \ + return __LINE__; \ + } + +// Use cout to avoid issues with %d/%lx etc +#define CHECK_RESULT(got, exp) \ + if ((got) != (exp)) { \ + cout << dec << "%Error: " << FILENM << ":" << __LINE__ << ": GOT = " << (got) \ + << " EXP = " << (exp) << endl; \ + return __LINE__; \ + } + +#define CHECK_RESULT_HEX(got, exp) \ + if ((got) != (exp)) { \ + cout << dec << "%Error: " << FILENM << ":" << __LINE__ << hex << ": GOT = " << (got) \ + << " EXP = " << (exp) << endl; \ + return __LINE__; \ + } + +#define CHECK_RESULT_CSTR(got, exp) \ + if (strcmp((got), (exp))) { \ + printf("%%Error: %s:%d: GOT = '%s' EXP = '%s'\n", FILENM, __LINE__, \ + (got) ? (got) : "", (exp) ? (exp) : ""); \ + return __LINE__; \ + } + +#define CHECK_RESULT_CSTR_STRIP(got, exp) CHECK_RESULT_CSTR(got + strspn(got, " "), exp) + +#define STRINGIFY(x) STRINGIFY2(x) +#define STRINGIFY2(x) #x + +//====================================================================== + +#ifdef IS_VPI + +static int _zero_time_cb(p_cb_data cb_data) { + callback_count_zero_time++; + return 0; +} + +static int _start_of_sim_cb(p_cb_data cb_data) { + t_cb_data cb_data_n; + s_vpi_time t; + + cb_data_n.reason = cbAfterDelay; + t.type = vpiSimTime; + t.high = 0; + t.low = 0; + cb_data_n.time = &t; + cb_data_n.cb_rtn = _zero_time_cb; + vpi_register_cb(&cb_data_n); + callback_count_start_of_sim++; + return 0; +} + +static int _end_of_sim_cb(p_cb_data cb_data) { + CHECK_RESULT(callback_count_start_of_sim, 1); + CHECK_RESULT(callback_count_zero_time, 1); + fprintf(stdout, "*-* All Finished *-*\n"); + return 0; +} + +// cver entry +#ifdef __cplusplus +extern "C" +#endif + +void vpi_compat_bootstrap(void) { + t_cb_data cb_data; + + // VL_PRINTF("register start-of-sim callback\n"); + cb_data.reason = cbStartOfSimulation; + cb_data.time = 0; + cb_data.cb_rtn = _start_of_sim_cb; + vpi_register_cb(&cb_data); + + cb_data.reason = cbEndOfSimulation; + cb_data.time = 0; + cb_data.cb_rtn = _end_of_sim_cb; + vpi_register_cb(&cb_data); +} + +// icarus entry +void (*vlog_startup_routines[])() = {vpi_compat_bootstrap, 0}; + +#else + +double sc_time_stamp() { return main_time; } +int main(int argc, char** argv, char** env) { + double sim_time = 1100; + Verilated::commandArgs(argc, argv); + Verilated::debug(0); + + VM_PREFIX* topp = new VM_PREFIX(""); // Note null name - we're flattening it out + +#ifdef VERILATOR +#ifdef TEST_VERBOSE + Verilated::scopesDump(); +#endif +#endif + +#if VM_TRACE + Verilated::traceEverOn(true); + VL_PRINTF("Enabling waves...\n"); + VerilatedVcdC* tfp = new VerilatedVcdC; + topp->trace(tfp, 99); + tfp->open(STRINGIFY(TEST_OBJ_DIR) "/simx.vcd"); +#endif + + // Load and initialize the PLI application + { + void* lib = dlopen("./obj_vlt/t_vpi_zero_time_cb/libvpi.so", RTLD_LAZY); + void* bootstrap = dlsym(lib, "vpi_compat_bootstrap"); + ((void (*)(void))bootstrap)(); + } + + VerilatedVpi::callCbs(cbStartOfSimulation); + + topp->eval(); + topp->clk = 0; + main_time += 10; + + while (sc_time_stamp() < sim_time && !Verilated::gotFinish()) { + main_time += 1; + topp->eval(); + VerilatedVpi::callValueCbs(); + VerilatedVpi::callTimedCbs(); + topp->clk = !topp->clk; + // mon_do(); +#if VM_TRACE + if (tfp) tfp->dump(main_time); +#endif + } + + VerilatedVpi::callCbs(cbEndOfSimulation); + + if (!Verilated::gotFinish()) { + vl_fatal(FILENM, __LINE__, "main", "%Error: Timeout; never got a $finish"); + } + topp->final(); + +#if VM_TRACE + if (tfp) tfp->close(); +#endif + + delete topp; VL_DANGLING(topp); + exit(0L); +} + +#endif diff --git a/test_regress/t/t_vpi_zero_time_cb.pl b/test_regress/t/t_vpi_zero_time_cb.pl new file mode 100755 index 000000000..51b2ff9f6 --- /dev/null +++ b/test_regress/t/t_vpi_zero_time_cb.pl @@ -0,0 +1,30 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2010 by Wilson Snyder. This program is free software; you can +# redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. + +scenarios(simulator => 1, iv => 1); + +compile( + make_top_shell => 0, + make_main => 0, + make_pli => 1, + sim_time => 2100, + iv_flags2 => ["-g2005-sv -D USE_VPI_NOT_DPI -DWAVES -Diverilog"], + v_flags2 => ["+define+USE_VPI_NOT_DPI"], + verilator_flags2 => ["-CFLAGS '-DVL_DEBUG -ggdb' --exe --vpi --no-l2name $Self->{t_dir}/t_vpi_zero_time_cb.cpp -LDFLAGS '-ldl -rdynamic'"], + ); + +execute( + iv_pli => 1, + ms_pli => 1, + check_finished => 1, + all_run_flags => ['+PLUS +INT=1234 +STRSTR'] + ); + +ok(1); +1; diff --git a/test_regress/t/t_vpi_zero_time_cb.v b/test_regress/t/t_vpi_zero_time_cb.v new file mode 100644 index 000000000..d07b88af7 --- /dev/null +++ b/test_regress/t/t_vpi_zero_time_cb.v @@ -0,0 +1,116 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// Copyright 2010 by Wilson Snyder. This program is free software; you can +// redistribute it and/or modify it under the terms of either the GNU +// Lesser General Public License Version 3 or the Perl Artistic License +// Version 2.0. + +module t (/*AUTOARG*/ + // Inputs + input clk + ); + +`ifndef VERILATOR + reg clk_r = 0; + always #10 clk_r = ~clk_r; + assign clk = clk_r; +`endif + + reg onebit /*verilator public_flat_rw @(posedge clk) */; + reg [2:1] twoone /*verilator public_flat_rw @(posedge clk) */; + reg [2:1] fourthreetwoone[4:3] /*verilator public_flat_rw @(posedge clk) */; + + reg [61:0] quads[3:2] /*verilator public_flat_rw @(posedge clk) */; + + reg [31:0] count /*verilator public_flat_rd */; + reg [31:0] half_count /*verilator public_flat_rd */; + + reg [7:0] text_byte /*verilator public_flat_rw @(posedge clk) */; + reg [15:0] text_half /*verilator public_flat_rw @(posedge clk) */; + reg [31:0] text_word /*verilator public_flat_rw @(posedge clk) */; + reg [63:0] text_long /*verilator public_flat_rw @(posedge clk) */; + reg [511:0] text /*verilator public_flat_rw @(posedge clk) */; + + integer status; + + sub sub(); + + // Test loop + initial begin + count = 0; + onebit = 1'b0; + fourthreetwoone[3] = 0; // stop icarus optimizing away + text_byte = "B"; + text_half = "Hf"; + text_word = "Word"; + text_long = "Long64b"; + text = "Verilog Test module"; + +/* + if (status!=0) begin + $write("%%Error: t_vpi_var.cpp:%0d: C Test failed\n", status); + $stop; + end + $write("%%Info: Checking results\n"); + if (onebit != 1'b1) $stop; + if (quads[2] != 62'h12819213_abd31a1c) $stop; + if (quads[3] != 62'h1c77bb9b_3784ea09) $stop; + if (text_byte != "A") $stop; + if (text_half != "T2") $stop; + if (text_word != "Tree") $stop; + if (text_long != "44Four44") $stop; + if (text != "lorem ipsum") $stop; + */ + end + + always @(posedge clk) begin + count <= count + 2; + if (count[1]) + half_count <= half_count + 2; + + if (count == 1000) begin +// $write("*-* All Finished *-*\n"); + $finish; + end + end + + genvar i; + generate + for (i=1; i<=128; i=i+1) begin : arr + arr #(.LENGTH(i)) arr(); + end + endgenerate + +endmodule : t + +module sub; + reg subsig1 /*verilator public_flat_rd*/; + reg subsig2 /*verilator public_flat_rd*/; +`ifdef iverilog + // stop icarus optimizing signals away + wire redundant = subsig1 | subsig2; +`endif +endmodule : sub + +module arr; + + parameter LENGTH = 1; + + reg [LENGTH-1:0] sig /*verilator public_flat_rw*/; + reg [LENGTH-1:0] rfr /*verilator public_flat_rw*/; + + reg check /*verilator public_flat_rw*/; + reg verbose /*verilator public_flat_rw*/; + + initial begin + sig = {LENGTH{1'b0}}; + rfr = {LENGTH{1'b0}}; + end + + always @(posedge check) begin + if (verbose) $display("%m : %x %x", sig, rfr); + if (check && sig != rfr) $stop; + check <= 0; + end + +endmodule : arr