aboutsummaryrefslogtreecommitdiffstats
path: root/fpga/usrp3/lib/axi4s_sv/axi4s_remove_bytes_tb
diff options
context:
space:
mode:
authorAndrew Moch <Andrew.Moch@ni.com>2020-06-22 17:13:36 +0100
committerWade Fife <wade.fife@ettus.com>2020-06-25 14:44:04 -0500
commitc3bca6c87700054c96320de119a58f6a688dbd5a (patch)
tree5caa6aca23b6ea84335ea22398698aa1ea3569ea /fpga/usrp3/lib/axi4s_sv/axi4s_remove_bytes_tb
parent8661f46df66329511ccb3cf083830e19d65ea402 (diff)
downloaduhd-c3bca6c87700054c96320de119a58f6a688dbd5a.tar.gz
uhd-c3bca6c87700054c96320de119a58f6a688dbd5a.tar.bz2
uhd-c3bca6c87700054c96320de119a58f6a688dbd5a.zip
fpga: lib: Add synthesizable AXI4-Stream SV components
Components are connected together with AxiStreamIfc. Some features include: (1) Add bytes to the start of a packet (2) Remove bytes from a packet (3) Wrappers for some older components a. fifo - buffer but imediately pass a packet b. packet_gate - buffer and hold till end of packet c. width_conv - cross clock domains and change width of axi bus The AxiStreamIf was moved from PkgAxiStreamBfm to its own file. It can be used to connect to ports with continuous assignment. AxiStreamPacketIf must be used procedurally but allows the following new methods: - reached_packet_byte - notify when tdata contains a paritcular byte - get_packet_byte/get_packet_field - extract a byte or field from axi - put_packet_byte/put_packet_field - overwrite a byte or field onto axi
Diffstat (limited to 'fpga/usrp3/lib/axi4s_sv/axi4s_remove_bytes_tb')
-rw-r--r--fpga/usrp3/lib/axi4s_sv/axi4s_remove_bytes_tb/Makefile48
-rw-r--r--fpga/usrp3/lib/axi4s_sv/axi4s_remove_bytes_tb/axi4s_remove_bytes_all_tb.sv139
-rw-r--r--fpga/usrp3/lib/axi4s_sv/axi4s_remove_bytes_tb/axi4s_remove_bytes_tb.sv233
3 files changed, 420 insertions, 0 deletions
diff --git a/fpga/usrp3/lib/axi4s_sv/axi4s_remove_bytes_tb/Makefile b/fpga/usrp3/lib/axi4s_sv/axi4s_remove_bytes_tb/Makefile
new file mode 100644
index 000000000..e017851ed
--- /dev/null
+++ b/fpga/usrp3/lib/axi4s_sv/axi4s_remove_bytes_tb/Makefile
@@ -0,0 +1,48 @@
+#
+# Copyright 2020 Ettus Research, a National Instruments Brand
+#
+# SPDX-License-Identifier: LGPL-3.0-or-later
+#
+
+#-------------------------------------------------
+# Top-of-Makefile
+#-------------------------------------------------
+# Define BASE_DIR to point to the "top" dir
+BASE_DIR = $(abspath ../../../top)
+# Include viv_sim_preamble after defining BASE_DIR
+include $(BASE_DIR)/../tools/make/viv_sim_preamble.mak
+
+#-------------------------------------------------
+# Design Specific
+#-------------------------------------------------
+
+# Include makefiles and sources for the DUT and its dependencies
+include $(BASE_DIR)/../lib/axi4s_sv/Makefile.srcs
+
+DESIGN_SRCS = $(abspath \
+$(AXI4S_SV_SRCS) \
+)
+
+#-------------------------------------------------
+# Testbench Specific
+#-------------------------------------------------
+# Define only one toplevel module
+TB_TOP_MODULE = axi4s_remove_bytes_all_tb
+SIM_TOP = $(TB_TOP_MODULE)
+
+SIM_SRCS = \
+$(abspath $(TB_TOP_MODULE).sv )\
+$(abspath axi4s_remove_bytes_tb.sv )
+
+# supressing the following worthless reminder.
+#* Warning: M:/usrp4-hw/oss-repo/fpga/usrp3/lib/axi4s_sv/axi4s_remove_bytes.sv(228): (vlog-2583) [SVCHK] -
+# Extra checking for conflicts with always_comb and always_latch variables is done at vopt time
+SVLOG_ARGS = -suppress 2583
+
+#-------------------------------------------------
+# Bottom-of-Makefile
+#-------------------------------------------------
+# Include all simulator specific makefiles here
+# Each should define a unique target to simulate
+# e.g. xsim, vsim, etc and a common "clean" target
+include $(BASE_DIR)/../tools/make/viv_simulator.mak
diff --git a/fpga/usrp3/lib/axi4s_sv/axi4s_remove_bytes_tb/axi4s_remove_bytes_all_tb.sv b/fpga/usrp3/lib/axi4s_sv/axi4s_remove_bytes_tb/axi4s_remove_bytes_all_tb.sv
new file mode 100644
index 000000000..129c5e65e
--- /dev/null
+++ b/fpga/usrp3/lib/axi4s_sv/axi4s_remove_bytes_tb/axi4s_remove_bytes_all_tb.sv
@@ -0,0 +1,139 @@
+//
+// Copyright 2020 Ettus Research, a National Instruments Brand
+//
+// SPDX-License-Identifier: LGPL-3.0-or-later
+//
+// Module: axi4s_remove_bytes_all_tb
+//
+// Description: Testbench for axi4s_remove_bytes_all_tb
+//
+
+module axi4s_remove_bytes_all_tb #(
+ /* no PARAM */
+)(
+ /* no IO */
+);
+
+ // actual use cases
+ // Strip Ethernet header from a packet includes a preamble
+ axi4s_remove_bytes_tb #(.TEST_NAME("ENET_64_HREMOVE48"),.WIDTH(64),.REM_START(0),.REM_END(47))
+ ENET_64_HREMOVE48 ();
+ axi4s_remove_bytes_tb #(.TEST_NAME("ENET_128_HREMOVE48"),.WIDTH(128),.REM_START(0),.REM_END(47))
+ ENET_128_HREMOVE48 ();
+ axi4s_remove_bytes_tb #(.TEST_NAME("ENET_256_HREMOVE48"),.WIDTH(256),.REM_START(0),.REM_END(47))
+ ENET_256_HREMOVE48 ();
+ axi4s_remove_bytes_tb #(.TEST_NAME("ENET_512_HREMOVE48"),.WIDTH(512),.REM_START(0),.REM_END(47))
+ ENET_512_HREMOVE48 ();
+
+ // Strip Ethernet header from a packet without a preamble
+ axi4s_remove_bytes_tb #(.TEST_NAME("ENET_64_HREMOVE42"),.WIDTH(64),.REM_START(0),.REM_END(41))
+ ENET_64_HREMOVE42 ();
+ axi4s_remove_bytes_tb #(.TEST_NAME("ENET_128_HREMOVE42"),.WIDTH(128),.REM_START(0),.REM_END(41))
+ ENET_128_HREMOVE42 ();
+ axi4s_remove_bytes_tb #(.TEST_NAME("ENET_256_HREMOVE42"),.WIDTH(256),.REM_START(0),.REM_END(41))
+ ENET_256_HREMOVE42 ();
+ axi4s_remove_bytes_tb #(.TEST_NAME("ENET_512_HREMOVE42"),.WIDTH(512),.REM_START(0),.REM_END(41))
+ ENET_512_HREMOVE42 ();
+
+ // Strip Preamble header from a packet
+ axi4s_remove_bytes_tb #(.TEST_NAME("ENET_64_PREMOVE6"),.WIDTH(64),.REM_START(0),.REM_END(5))
+ ENET_64_PREMOVE6 ();
+ axi4s_remove_bytes_tb #(.TEST_NAME("ENET_128_PREMOVE6"),.WIDTH(128),.REM_START(0),.REM_END(5))
+ ENET_128_PREMOVE6 ();
+ axi4s_remove_bytes_tb #(.TEST_NAME("ENET_256_PREMOVE6"),.WIDTH(256),.REM_START(0),.REM_END(5))
+ ENET_256_PREMOVE6 ();
+ axi4s_remove_bytes_tb #(.TEST_NAME("ENET_512_PREMOVE6"),.WIDTH(512),.REM_START(0),.REM_END(5))
+ ENET_512_PREMOVE6 ();
+
+
+ // TRUNCATE cases -
+ axi4s_remove_bytes_tb #(.TEST_NAME("TRUNCATE_32_1:0"),.WIDTH(32),.REM_START(1),.REM_END(-1))
+ TRUNCATE_32_0to1 ();
+ axi4s_remove_bytes_tb #(.TEST_NAME("TRUNCATE_32_2:0"),.WIDTH(32),.REM_START(2),.REM_END(-1))
+ TRUNCATE_32_0to2 ();
+ axi4s_remove_bytes_tb #(.TEST_NAME("TRUNCATE_32_3:0"), .WIDTH(32),.REM_START(3),.REM_END(-1))
+ TRUNCATE_32_0to3 ();
+ axi4s_remove_bytes_tb #(.TEST_NAME("TRUNCATE_32_4:0"),.WIDTH(32),.REM_START(4),.REM_END(-1))
+ TRUNCATE_32_0to4 ();
+ axi4s_remove_bytes_tb #(.TEST_NAME("TRUNCATE_32_5:0"),.WIDTH(32),.REM_START(5),.REM_END(-1))
+ TRUNCATE_32_0to5 ();
+ axi4s_remove_bytes_tb #(.TEST_NAME("TRUNCATE_32_6:0"),.WIDTH(32),.REM_START(6),.REM_END(-1))
+ TRUNCATE_32_0to6 ();
+ axi4s_remove_bytes_tb #(.TEST_NAME("TRUNCATE_32_7:0"), .WIDTH(32),.REM_START(7),.REM_END(-1))
+ TRUNCATE_32_0to7 ();
+
+
+ // START cases - removal starts at LSB of word
+ axi4s_remove_bytes_tb #(.TEST_NAME("SSTART_32_0:0"),.WIDTH(32),.REM_START(0),.REM_END(0))
+ SSTART_32_0to0 ();
+ axi4s_remove_bytes_tb #(.TEST_NAME("SSTART_32_1:0"),.WIDTH(32),.REM_START(0),.REM_END(1))
+ SSTART_32_0to1 ();
+ axi4s_remove_bytes_tb #(.TEST_NAME("SSTART_32_2:0"),.WIDTH(32),.REM_START(0),.REM_END(2))
+ SSTART_32_0to2 ();
+ axi4s_remove_bytes_tb #(.TEST_NAME("EXACT_32_3:0"), .WIDTH(32),.REM_START(0),.REM_END(3))
+ EXACT_32_0to3 ();
+ axi4s_remove_bytes_tb #(.TEST_NAME("MSTART_32_4:0"),.WIDTH(32),.REM_START(0),.REM_END(4))
+ MSTART_32_0to4 ();
+ axi4s_remove_bytes_tb #(.TEST_NAME("MSTART_32_5:0"),.WIDTH(32),.REM_START(0),.REM_END(5))
+ MSTART_32_0to5 ();
+ axi4s_remove_bytes_tb #(.TEST_NAME("MSTART_32_6:0"),.WIDTH(32),.REM_START(0),.REM_END(6))
+ MSTART_32_0to6 ();
+ axi4s_remove_bytes_tb #(.TEST_NAME("EXACT_32_7:0"), .WIDTH(32),.REM_START(0),.REM_END(7))
+ EXACT_32_0to7 ();
+
+
+ // END cases - removal ends at MSB of word
+ axi4s_remove_bytes_tb #(.TEST_NAME("MEND_32_7:1"),.WIDTH(32),.REM_START(1),.REM_END(7))
+ MEND_32_1to7 ();
+ axi4s_remove_bytes_tb #(.TEST_NAME("MEND_32_7:2"),.WIDTH(32),.REM_START(2),.REM_END(7))
+ MEND_32_2to7 ();
+ axi4s_remove_bytes_tb #(.TEST_NAME("MEND_32_7:3"),.WIDTH(32),.REM_START(3),.REM_END(7))
+ MEND_32_3to7 ();
+ axi4s_remove_bytes_tb #(.TEST_NAME("EXACT_32_7:4"),.WIDTH(32),.REM_START(4),.REM_END(7))
+ EXACT_32_4to7 ();
+ axi4s_remove_bytes_tb #(.TEST_NAME("SEND_32_7:5"),.WIDTH(32),.REM_START(5),.REM_END(7))
+ SEND_32_5to7 ();
+ axi4s_remove_bytes_tb #(.TEST_NAME("SEND_32_7:6"),.WIDTH(32),.REM_START(6),.REM_END(7))
+ SEND_32_6to7 ();
+ axi4s_remove_bytes_tb #(.TEST_NAME("SEND_32_7:7"),.WIDTH(32),.REM_START(7),.REM_END(7))
+ SEND_32_7to7 ();
+
+ axi4s_remove_bytes_tb #(.TEST_NAME("SEND_32_3:1"),.WIDTH(32),.REM_START(1),.REM_END(3))
+ SEND_32_1to3 ();
+ axi4s_remove_bytes_tb #(.TEST_NAME("SEND_32_3:2"),.WIDTH(32),.REM_START(2),.REM_END(3))
+ SEND_32_2to3 ();
+ axi4s_remove_bytes_tb #(.TEST_NAME("SEND_32_3:3"),.WIDTH(32),.REM_START(3),.REM_END(3))
+ SEND_32_3to3 ();
+
+ // MIDDLE cases - removal is in the middle of words
+ axi4s_remove_bytes_tb #(.TEST_NAME("SMID_32_1:1"),.WIDTH(32),.REM_START(1),.REM_END(1))
+ SMID_32_1to1 ();
+ axi4s_remove_bytes_tb #(.TEST_NAME("SMID_32_2:1"),.WIDTH(32),.REM_START(1),.REM_END(2))
+ SMID_32_2to1 ();
+ axi4s_remove_bytes_tb #(.TEST_NAME("SMID_32_2:2"),.WIDTH(32),.REM_START(2),.REM_END(2))
+ SMID_32_2to2 ();
+
+ axi4s_remove_bytes_tb #(.TEST_NAME("MMID_32_5:1"),.WIDTH(32),.REM_START(1),.REM_END(5))
+ MMID_32_1to5 ();
+ axi4s_remove_bytes_tb #(.TEST_NAME("MMID_32_6:1"),.WIDTH(32),.REM_START(1),.REM_END(6))
+ MMID_32_1to6 ();
+ axi4s_remove_bytes_tb #(.TEST_NAME("MMID_32_6:2"),.WIDTH(32),.REM_START(2),.REM_END(6))
+ MMID_32_2to6 ();
+
+ // WRAP cases - removal is over word boundary
+ axi4s_remove_bytes_tb #(.TEST_NAME("SWRAP_32_5:2"),.WIDTH(32),.REM_START(2),.REM_END(5))
+ SWRAP_32_2to5 ();
+ axi4s_remove_bytes_tb #(.TEST_NAME("SWRAP_32_5:3"),.WIDTH(32),.REM_START(3),.REM_END(5))
+ SWRAP_32_3to5 ();
+ axi4s_remove_bytes_tb #(.TEST_NAME("SWRAP_32_6:3"),.WIDTH(32),.REM_START(3),.REM_END(6))
+ SWRAP_32_3to6 ();
+
+ axi4s_remove_bytes_tb #(.TEST_NAME("MMID_32_9:2"),.WIDTH(32),.REM_START(2),.REM_END(9))
+ MWRAP_32_2to9 ();
+ axi4s_remove_bytes_tb #(.TEST_NAME("SEND_32_9:3"),.WIDTH(32),.REM_START(3),.REM_END(9))
+ MWRAP_32_3to9 ();
+ axi4s_remove_bytes_tb #(.TEST_NAME("SEND_32_10:3"),.WIDTH(32),.REM_START(3),.REM_END(10))
+ MWRAP_32_3to10();
+
+
+endmodule
diff --git a/fpga/usrp3/lib/axi4s_sv/axi4s_remove_bytes_tb/axi4s_remove_bytes_tb.sv b/fpga/usrp3/lib/axi4s_sv/axi4s_remove_bytes_tb/axi4s_remove_bytes_tb.sv
new file mode 100644
index 000000000..c7b2587c7
--- /dev/null
+++ b/fpga/usrp3/lib/axi4s_sv/axi4s_remove_bytes_tb/axi4s_remove_bytes_tb.sv
@@ -0,0 +1,233 @@
+//
+// Copyright 2020 Ettus Research, a National Instruments Brand
+//
+// SPDX-License-Identifier: LGPL-3.0-or-later
+//
+// Module: axi4s_remove_bytes_tb
+//
+// Description: Testbench for axi_remove_bytes
+//
+
+module axi4s_remove_bytes_tb #(
+ parameter TEST_NAME = "axi_remove_bytes",
+ WIDTH=32,REM_START=0,REM_END=7
+)(
+ /* no IO */
+);
+ // Include macros and time declarations for use with PkgTestExec
+ // To change the name of the TestExec object being used by the assertion
+ // macros, `define TEST_EXEC_OBJ before including this file and `undef it at
+ // the end of your testbench. Otherwise, it defaults to the shared object
+ // "PkgTestExec::test".
+ `define TEST_EXEC_OBJ test
+ `include "test_exec.svh"
+ import PkgAxiStreamBfm::*;
+ import PkgTestExec::*;
+ import PkgEthernet::*;
+
+ //---------------------------------------------------------------------------
+ // Local Parameters
+ //---------------------------------------------------------------------------
+ localparam UWIDTH = $clog2((WIDTH/8)+1);
+ localparam MAX_PACKET_BYTES = 16*1024;
+
+ typedef AxiStreamPacket #(WIDTH, UWIDTH) AxisPacket_t;
+ typedef XportStreamPacket #(WIDTH) XportPacket_t;
+
+ //---------------------------------------------------------------------------
+ // Clocks
+ //---------------------------------------------------------------------------
+
+ bit clk;
+ bit reset;
+
+ sim_clock_gen #(.PERIOD(5.0), .AUTOSTART(1))
+ clk_gen (.clk(clk), .rst(reset));
+
+ //---------------------------------------------------------------------------
+ // Bus Functional Models
+ //---------------------------------------------------------------------------
+ TestExec test = new();
+ AxiStreamIf #(.DATA_WIDTH(WIDTH),.USER_WIDTH(UWIDTH),.TKEEP(0),
+ .MAX_PACKET_BYTES(MAX_PACKET_BYTES))
+ i (clk, reset);
+ AxiStreamIf #(.DATA_WIDTH(WIDTH),.USER_WIDTH(UWIDTH),.TKEEP(0),
+ .MAX_PACKET_BYTES(MAX_PACKET_BYTES))
+ o (clk, reset);
+
+ // Bus functional model for a axi_stream controller
+ AxiStreamBfm #(.DATA_WIDTH(WIDTH),.USER_WIDTH(UWIDTH),.TKEEP(0),
+ .MAX_PACKET_BYTES(MAX_PACKET_BYTES))
+ axis = new(.master(i), .slave(o));
+
+ //----------------------------------------------------
+ // Instantiate DUT
+ //----------------------------------------------------
+
+ axi4s_remove_bytes #(.REM_START(REM_START),.REM_END(REM_END))
+ DUT (.*);
+
+ //---------------------------------------------------------------------------
+ // Reset
+ //---------------------------------------------------------------------------
+
+ task test_reset();
+ test.start_test("Wait for Reset", 10us);
+ clk_gen.reset();
+ wait(!reset);
+ repeat (10) @(posedge clk);
+ test.end_test();
+ endtask : test_reset
+
+ //---------------------------------------------------------------------------
+ // Ethernet to CPU test
+ //---------------------------------------------------------------------------
+
+ task automatic test_samples(int num_samples);
+ localparam PKTS_TO_SEND = 10;
+ localparam LOW_LIM = DUT.EXACT?DUT.START_WORD-1:DUT.START_WORD;
+ localparam HIGH_LIM = REM_END;
+
+ automatic string test_str;
+ automatic raw_pkt_t raw;
+ automatic XportPacket_t send[$];
+ automatic XportPacket_t expected[$];
+ automatic integer last_word_index;
+ test_str = $sformatf({TEST_NAME,"::Remove Bytes L=%3d"},num_samples);
+ test.start_test(test_str, 10us);
+
+ for (int i= 0 ; i < PKTS_TO_SEND; i++) begin
+
+ expected[i] = new;
+ send[i] = new;
+
+ get_ramp_raw_pkt(.num_samps(num_samples),.ramp_start((i*num_samples)%256),.ramp_inc(1),.pkt(raw),.SWIDTH(8));
+ send[i].push_bytes(raw);
+ // Remove the bytes from raw packet to build expected.
+ if (REM_END < 0) begin
+ raw = raw[0:REM_START-1];
+ end else begin
+ for (int i = 0 ; i < REM_END-REM_START+1 ; ++i) begin
+ if (raw.size()-1 >= REM_START) begin
+ raw.delete(REM_START);
+ end
+ end
+ end
+ expected[i].push_bytes(raw);
+ send[i].tkeep_to_tuser(.ERROR_PROB(10));
+ expected[i].tkeep_to_tuser();
+ if (send[i].has_error())
+ expected[i].set_error();
+
+ // if the incoming packet stops at a word
+ // where we have no where to mark an error
+ // then we set an error
+ last_word_index = send[i].data.size()-1;
+ if (last_word_index > LOW_LIM &&
+ num_samples-1 <= HIGH_LIM) begin
+ if (!DUT.TRUNCATE)
+ if (DUT.START_WORD != DUT.END_WORD || DUT.EXACT)
+ expected[i].set_error();
+ end
+ end
+
+ for (int i= PKTS_TO_SEND-1 ; i >= 0; i--) begin
+ if (expected[i].data.size() == 0) expected.delete(i);
+ end
+
+ fork
+ begin : send_thread
+ foreach(send[i])begin
+ axis.put(send[i]);
+ end
+ end
+ begin : expected_thread
+
+ if (expected.size() == 0) begin : no_expected
+ automatic string str;
+ automatic AxisPacket_t actual_a = new();
+ // I need a better way to flush the send queue.
+ #(2*WIDTH); // wait a bit for completion
+ o.tready = 1;
+ axis.wait_send(); // wait complete hung
+ #(2*WIDTH); // wait a bit for completion
+ str = $sformatf("UNEXPECTED_PACKET L=%3d\nREM_START=%3d:%1d REM_END=%3d:%1d SIZE =%3d WIDTH=%3d\nSEND\n%s",
+ num_samples,REM_START,DUT.START_WORD,REM_END,DUT.END_WORD,send[0].data.size(),WIDTH,
+ send[0].sprint());
+ if (axis.try_get(actual_a)) begin
+ $display("ACTUAL");
+ actual_a.print();
+ `ASSERT_ERROR(actual_a.data.size() == 0,str);
+ end
+ $display("Wait completed");
+
+ end else begin : get_expected
+ automatic string str;
+ automatic AxisPacket_t actual_a = new();
+ automatic XportPacket_t actual = new();
+ foreach(expected[i]) begin
+ axis.get(actual_a);
+ actual.import_axis(actual_a);
+ actual.tuser_to_tkeep();
+ str = $sformatf({"L= %3d REM =%2d:%1d WORD=%1d:%1d ERROR_LIM=%1d<%1d %1d<=%1d WIDTH=%3d","\nSEND\n%s"},
+ num_samples,
+ REM_START,REM_END,
+ DUT.START_WORD,DUT.END_WORD,
+ LOW_LIM,last_word_index,num_samples-1,HIGH_LIM,WIDTH,
+ send[i].sprint());
+ `ASSERT_ERROR(!actual.compare_w_error(expected[i],.COMPARE_ERROR_PACKETS(0)),str);
+ end
+ end
+ end
+ join
+ test.end_test();
+
+ endtask : test_samples
+
+
+ //----------------------------------------------------
+ // Main test loop
+ //----------------------------------------------------
+ initial begin : tb_main
+ automatic integer min_length;
+
+ test.tb_name = TEST_NAME;
+
+ if (REM_END == -1)
+ min_length = REM_START-4;
+ else
+ min_length = REM_END-4;
+
+ if ( min_length < 1) min_length = 1;
+
+ axis.run();
+
+ test_reset();
+ // power of 2 from zero
+ for (int i=0 ; i < 6 ; ++i) begin
+ test_samples(2**i);
+ end
+
+ for (int i=1 ; i < (WIDTH/8)*3 ; ++i) begin
+ test_samples(min_length+i);
+ end
+
+ // repeat back to back
+ axis.set_slave_stall_prob(0);
+ axis.set_master_stall_prob(0);
+
+ for (int i=1 ; i < (WIDTH/8)*3 ; ++i) begin
+ test_samples(min_length+i);
+ end
+
+ // End the TB, but don't $finish, since we don't want to kill other
+ // instances of this testbench that may be running.
+ test.end_tb(0);
+
+ // Kill the clocks to end this instance of the testbench
+ clk_gen.kill();
+
+ end // initial begin
+
+endmodule
+`undef TEST_EXEC_OBJ