diff options
Diffstat (limited to 'fpga/docs/usrp3/sim')
-rw-r--r-- | fpga/docs/usrp3/sim/libs_axi.md | 266 | ||||
-rw-r--r-- | fpga/docs/usrp3/sim/libs_general.md | 188 | ||||
-rw-r--r-- | fpga/docs/usrp3/sim/running_testbenches.md | 133 | ||||
-rw-r--r-- | fpga/docs/usrp3/sim/writing_testbenches.md | 471 |
4 files changed, 1058 insertions, 0 deletions
diff --git a/fpga/docs/usrp3/sim/libs_axi.md b/fpga/docs/usrp3/sim/libs_axi.md new file mode 100644 index 000000000..a260aabdd --- /dev/null +++ b/fpga/docs/usrp3/sim/libs_axi.md @@ -0,0 +1,266 @@ +# AXI Interface Libraries + +## AXI4 Stream (sim\_axis\_lib.vh) + +Defines ``axis_t``, an AXI Stream bus interface that implements several tasks to send and +receive data on the bus. + +### Definition + + interface axis_t #(parameter DWIDTH = 64) + (input clk); + logic [DWIDTH-1:0] tdata; + logic tvalid; + logic tlast; + logic tready; + + modport master (output tdata, output tvalid, output tlast, input tready); + modport slave (input tdata, input tvalid, input tlast, output tready); + + +### Operations + +#### push\_word + + // Push a word onto the AXI-Stream bus and wait for it to transfer + // Args: + // - word: The data to push onto the bus + // - eop (optional): End of packet (asserts tlast) + +#### push\_bubble + + // Push a bubble cycle onto the AXI-Stream bus + +#### pull\_word + + // Wait for a sample to be transferred on the AXI Stream + // bus and return the data and last + // Args: + // - word: The data pulled from the bus + // - eop: End of packet (tlast) + +#### wait\_for\_bubble + + // Wait for a bubble cycle on the AXI Stream bus + +#### wait\_for\_pkt + + // Wait for a packet to finish on the bus + +#### push\_rand\_pkt + + // Push a packet with random data onto to the AXI Stream bus + // Args: + // - num_samps: Packet size. + +#### push\_ramp\_pkt + + // Push a packet with a ramp on to the AXI Stream bus + // Args: + // - num_samps: Packet size. + // - ramp_start: Start value for the ramp + // - ramp_inc: Increment per clock cycle + +## Compressed VITA [CHDR] (sim\_chdr\_lib.vh) + +Defines ``cvita_stream_t``, an AXI Stream bus interface that implements the CHDR protocol and +several tasks to send and receive data on the bus. + +### CHDR + + typedef enum logic [1:0] { + DATA=2'b00, FC=2'b01, CMD=2'b10, RESP=2'b11 + } cvita_pkt_t; + + typedef struct packed { + logic [31:0] sid; + logic [15:0] length; + logic [11:0] seqno; + logic eob; + logic has_time; + cvita_pkt_t pkt_type; + logic [63:0] timestamp; + } cvita_hdr_t; + +#### Operations + + - ``flatten_chdr_no_ts``: Flatten header struct to a 64-bit bus. No timestamp. + - ``unflatten_chdr_no_ts``: Decode a 64-bit header and populate the ``cvita_hdr_t`` struct. No timestamp. + - ``unflatten_chdr``: Decode a 64-bit header and populate the ``cvita_hdr_t`` struct. Timestamp supported. + +### CVITA Stream Type + +#### Definition + + interface cvita_stream_t (input clk); + axis_t #(.DWIDTH(64)) axis (.clk(clk)); + +#### push\_hdr + + // Push a CVITA header into the stream + // Args: + // - hdr: The header to push + +#### push\_data + + // Push a word onto the AXI-Stream bus and wait for it to transfer + // Args: + // - word: The data to push onto the bus + // - eop: End of packet (asserts tlast) + +#### push\_bubble + + // Push a bubble cycle on the AXI-Stream bus + +#### pull\_word + + // Wait for a sample to be transferred on the AXI Stream + // bus and return the data and last + // Args: + // - word: The data pulled from the bus + // - eop: End of packet (tlast) + +#### wait\_for\_bubble + + // Wait for a bubble cycle on the AXI Stream bus + +#### wait\_for\_pkt + + // Wait for a packet to finish on the bus + +#### wait\_for\_pkt\_get\_info + + // Wait for a packet to finish on the bus and extract the header and payload statistics. + + typedef struct packed { + logic [31:0] count; + logic [63:0] sum; + logic [63:0] min; + logic [63:0] max; + logic [63:0] crc; + } cvita_stats_t; + +#### push\_rand\_pkt + + // Push a packet with random data onto to the AXI Stream bus + // Args: + // - num_samps: Packet size. + // - hdr: Header to attach to packet (length will be ignored) + // - timestamp: Optional timestamp + +#### push\_ramp\_pkt + + // Push a packet with a ramp on to the AXI Stream bus + // Args: + // - num_samps: Packet size. + // - ramp_start: Start value for the ramp + // - ramp_inc: Increment per clock cycle + // - hdr: Header to attach to packet (length will be ignored) + // - timestamp: Optional timestamp + +## Memory Mapped AXI4 (sim\_axi4\_lib.vh) + +Defines the following interfaces to group signals in the AXI4 bus. +WIP: No functions or tasks implemented yet. + +#### Address + + interface axi4_addr_t #(parameter AWIDTH=32, parameter IDWIDTH=4) + (input clk); + + logic [IDWIDTH-1:0] id; + logic [AWIDTH-1:0] addr; + logic [7:0] len; + logic [2:0] size; + logic [1:0] burst; + logic lock; + logic [3:0] cache; + logic [2:0] prot; + logic [3:0] qos; + logic [3:0] region; + logic user; + logic valid; + logic ready; + + modport master (output id,addr,len,size,burst,lock,cache,prot,qos,valid, input ready); + modport slave (input id,addr,len,size,burst,lock,cache,prot,qos,valid, output ready); + + endinterface + +#### Write Data + + interface axi4_wdata_t #(parameter DWIDTH=64) + (input clk); + + logic [DWIDTH-1:0] data; + logic [(DWIDTH/8)-1:0] strb; + logic last; + logic user; + logic valid; + logic ready; + + modport master(output data,strb,last,valid, input ready); + modport slave(input data,strb,last,valid, output ready); + + endinterface + +#### Write Response + + interface axi4_resp_t #(parameter IDWIDTH=4) + (input clk); + + logic ready; + logic [IDWIDTH-1:0] id; + logic [1:0] resp; + logic user; + logic valid; + + modport master(output ready, input id,resp,valid); + modport slave(input ready, output id,resp,valid); + + endinterface + +#### Read Data + + interface axi4_rdata_t #(parameter DWIDTH=64, parameter IDWIDTH=4) + (input clk); + + logic ready; + logic [IDWIDTH-1:0] id; + logic [DWIDTH-1:0] data; + logic [1:0] resp; + logic user; + logic last; + logic valid; + + modport master(output ready, input id,data,resp,last,valid); + modport slave(input ready, output id,data,resp,last,valid); + + endinterface + +#### Meta: AXI4 Writer + + interface axi4_wr_t #(parameter DWIDTH=64, parameter AWIDTH=32, parameter IDWIDTH=4) + (input clk); + + axi4_addr_t #(.AWIDTH(AWIDTH), .IDWIDTH(IDWIDTH)) addr (.clk(clk)); + axi4_wdata_t #(.DWIDTH(DWIDTH)) data (.clk(clk)); + axi4_resp_t #(.IDWIDTH(IDWIDTH)) resp (.clk(clk)); + + modport master(output addr, output data, input resp); + modport slave(input addr, input data, output resp); + + endinterface + +#### Meta: AXI4 Reader + + interface axi4_rd_t #(parameter DWIDTH=64, parameter AWIDTH=32, parameter IDWIDTH=4) + (input clk); + + axi4_addr_t #(.AWIDTH(AWIDTH), .IDWIDTH(IDWIDTH)) addr (.clk(clk)); + axi4_rdata_t #(.DWIDTH(DWIDTH), .IDWIDTH(IDWIDTH)) data (.clk(clk)); + + modport master(output addr, output data); + modport slave(input addr, input data); + + endinterface diff --git a/fpga/docs/usrp3/sim/libs_general.md b/fpga/docs/usrp3/sim/libs_general.md new file mode 100644 index 000000000..4bc154dc2 --- /dev/null +++ b/fpga/docs/usrp3/sim/libs_general.md @@ -0,0 +1,188 @@ +# General Purpose Libraries + +## Execution and Reporting (sim\_exec\_report.vh) + +Macros to do boilerplate testbench initialization and utilities to define test cases + +#### TEST\_BENCH\_INIT + + // Initializes state for a test bench. + // This macro *must be* called within the testbench module but + // outside the primary initial block + // Its sets up boilerplate code for: + // - Logging to console + // - Test execution tracking + // - Gathering test results + // - Bounding execution time based on the SIM_RUNTIME_US vdef + // + // Usage: `TEST_BENCH_INIT(test_name,min_tc_run_count,ns_per_tick) + // where + // - tb_name: Name of the testbench. (Only used during reporting) + // - min_tc_run_count: Number of test cases in testbench. (Used to detect stalls and inf-loops) + // - ns_per_tick: The time_unit_base from the timescale declaration + // + +#### TEST\_CASE\_START + + // Indicates the start of a test case + // This macro *must be* called inside the primary initial block + // + // Usage: `TEST_CASE_START(test_name) + // where + // - test_name: The name of the test. + // + +#### TEST\_CASE\_DONE + // Indicates the end of a test case + // This macro *must be* called inside the primary initial block + // The pass/fail status of test case is determined based on the + // the user specified outcome and the number of fatal or error + // ASSERTs triggered in the test case. + // + // Usage: `TEST_CASE_DONE(test_result) + // where + // - test_result: User specified outcome + // + +#### ASSERT\_FATAL + + // Wrapper around a an assert. + // ASSERT_FATAL throws an error assertion and halts the simulator + // if cond is not satisfied + // + // Usage: `ASSERT_FATAL(cond,msg) + // where + // - cond: Condition for the assert + // - msg: Message for the assert + // + +#### ASSERT\_ERROR + + // Wrapper around a an assert. + // ASSERT_ERROR throws an error assertion and fails the test case + // if cond is not satisfied. The simulator will *not* halt + // + // Usage: `ASSERT_ERROR(cond,msg) + // where + // - cond: Condition for the assert + // - msg: Message for the assert + // + +#### ASSERT\_WARNING + + // Wrapper around a an assert. + // ASSERT_WARNING throws an warning assertion but does not fail the + // test case if cond is not satisfied. The simulator will *not* halt + // + // Usage: `ASSERT_WARNING(cond,msg) + // where + // - cond: Condition for the assert + // - msg: Message for the assert + // + +## Clocks and Resets (sim\_clks\_rsts.vh) + +Shortcut macros to create typical clock and reset signals. + +#### DEFINE\_CLK + + // Generates a persistent clock that starts at t=0 and runs forever + // + // Usage: `DEFINE_CLK(clk_name,period,duty_cycle) + // where + // - clk_name: The clock net to be generated + // - period: Period of the clock in simulator ticks + // - duty_cycle: Percentage duty cycle + // + +#### DEFINE\_LATE\_START\_CLK + + // Generates a clock that starts at the specified time and runs forever + // + // Usage: `DEFINE_LATE_START_CLK(clk_name,period,duty_cycle,start_time,start_time_res) + // where + // - clk_name: The clock net to be generated + // - period: Period of the clock in simulator ticks + // - duty_cycle: Percentage duty cycle + // - start_time: Start time for clock in simulator ticks + // - start_time_res: Start time resolution (must be > timescale increment and < start_time) + // + +#### DEFINE_RESET + + // Generates an active high reset + // + // Usage: `DEFINE_RESET(reset_name,reset_time,reset_duration) + // where + // - reset_name: The reset net to be generated + // - reset_time: Time at which reset will be asserted (i.e. rst=1) + // - reset_duration: Duration of reset assertion + // + +#### DEFINE_RESET_N + + // Generates an active low reset + // + // Usage: `DEFINE_RESET_N(reset_name,reset_time,reset_duration) + // where + // - reset_name: The reset net to be generated + // - reset_time: Time at which reset will be asserted (i.e. rst=0) + // - reset_duration: Duration of reset assertion + // + +## File I/O (sim\_file\_io.sv) + +### interface data\_file\_t + +Defines a ``data_file_t`` interface with the following functions: + +#### ctor + + // Create a handle to a data_file with + // - FILENAME: Name of the file + // - FORMAT: Data format (HEX, DEC, OCT, BIN, FLOAT) + // - DWIDTH: Width of each element stored in the file (one line per word) + // + +#### open + + // Open the data file for reading or writing. + // + // Usage: open(mode) + // where + // - mode: RW mode (Choose from: READ, WRITE, APPEND) + // + +#### close + + // Close an open data file. No-op if file isn't already open + // + // Usage: close() + // + +#### is_eof + + // Is end-of-file reached. + // + // Usage: is_eof() Returns eof + // where + // - eof: A boolean + // + +#### readline + + // Read a line from the datafile + // + // Usage: readline() Returns data + // where + // - data: A logic array of width DWIDTH containing the read word + // + +#### writeline + + // Write a line to the datafile + // + // Usage: writeline(data) + // where + // - data: A logic array of width DWIDTH to write to the file + //
\ No newline at end of file diff --git a/fpga/docs/usrp3/sim/running_testbenches.md b/fpga/docs/usrp3/sim/running_testbenches.md new file mode 100644 index 000000000..2e2068e5e --- /dev/null +++ b/fpga/docs/usrp3/sim/running_testbenches.md @@ -0,0 +1,133 @@ +# Running a Testbench + +Each executable testbench has its own Makefile that automatically pulls in support +for all supported simulators. The build infrastructure supports the following simulators: + + - Xilinx Vivado (XSim) + - Mentor Graphics ModelSim (may require an additional license) + + +In general running ``make <sim_target>`` will run the +simulation and report results in the console. Running ``make help`` will print out +all supported simulator targets. Currently, the following targets will work: + + Supported Targets: + ipclean: Cleanup all IP intermediate files + clean: Cleanup all simulator intermediate files + cleanall: Cleanup everything! + xsim: Run the simulation using the Xilinx Vivado Simulator + xclean: Cleanup Xilinx Vivado Simulator intermediate files + vsim: Run the simulation using Modelsim + vclean: Cleanup Modelsim intermediate files + + +## Using Xilinx Vivado XSim + +XSim is the built-in simulator in the Xilinx Vivado toolchain. If you already met the +prerequisites for building an FPGA image, then you don't need to install anything else. + +Follow these steps to run a testbench: + + - Navigate to the directory that contains the top level testbench and Makefile + - Run the setenv.sh script for the USRP product that you are trying to simulate + + ``$ source <repo>/usrp3/top/<product>/setupenv.sh`` + + This step is required even if the simulation is generic because the toolchain requires + an FPGA part number to load simulation models. + - Run the simulator specific target + + ``$ make xsim`` + + +## Using Mentor Graphics ModelSim + +ModelSim is a third-party simulation tool that is compatible with Vivado and the USRP +FPGA build infrastructure. + +Use the following one-time setup to install and configure Modelsim on your system + + - Install Modelsim from the [Mentor Graphics](http://www.mentor.com/) website. + It is recommended that you install it to the default location (/opt/mentor/modelsim) + - Run the setenv.sh script for the USRP product that you are trying to simulate + + ``$ source <repo>/usrp3/top/<product>/setupenv.sh`` + + This step is required even if the simulation is generic because the toolchain requires + an FPGA part number to load simulation models. + - Build the Xilinx simulation libraries + ``$ build_simlibs`` + + +To validate that everything was install properly run ``setupenv.sh`` again. You should see the following + + Setting up X3x0 FPGA build environment (64-bit)... + - Vivado: Found (/opt/Xilinx/Vivado/2014.4/bin) + - Modelsim: Found (/opt/mentor/modelsim/modeltech/bin) + - Modelsim Compiled Libs: Found (/opt/Xilinx/Vivado/2014.4/modelsim) + + Environment successfully initialized. + +Follow these steps to run a testbench: + + - Navigate to the directory that contains the top level testbench and Makefile + - Run the setenv.sh script for the USRP product that you are trying to simulate + + ``$ source <repo>/usrp3/top/<product>/setupenv.sh`` + + This step is required even if the simulation is generic because the toolchain requires + an FPGA part number to load simulation models. + - Run the simulator specific target + + ``$ make vsim`` + + +## Troubleshooting + +#### Vivado Not Found + +If running the setupenv.sh script return an error like the following: + + Vivado: Not found! (ERROR.. Builds and simulations will not work) + +then it is possible that Vivado was not installed or it was not installed in the default +location. If Vivado is installed in a non-default location, just run the following: + + ``$ source <repo>/usrp3/top/<product>/setupenv.sh --vivado-path=<PATH>`` + +#### Modelsim Not Found + +If running the setupenv.sh script return an error like the following: + + Setting up X3x0 FPGA build environment (64-bit)... + - Vivado: Found (/opt/Xilinx/Vivado/2014.4/bin) + - Modelsim: Not found! (WARNING.. Simulations with vsim will not work) + + Environment successfully initialized. + +or something like this (even when Modelsim is installed) + + Setting up X3x0 FPGA build environment (64-bit)... + - Vivado: Found (/opt/Xilinx/Vivado/2014.4/bin) + + Environment successfully initialized. + +then it is possible that Modelsim was not installed or it was not installed in the default +location. If Modelsim is installed in a non-default location, just run the following: + + ``$ source <repo>/usrp3/top/<product>/setupenv.sh --modelsim-path=<PATH>`` + +#### Modelsim Simulation Libraries Not Found + +If running the setupenv.sh script return an error like the following: + + Setting up X3x0 FPGA build environment (64-bit)... + - Vivado: Found (/opt/Xilinx/Vivado/2014.4/bin) + - Modelsim: Found (/opt/mentor/modelsim/modeltech/bin) + - Modelsim Compiled Libs: Not found! (Run build_simlibs to generate them.) + + Environment successfully initialized. + +just run the following + + $ build_simlibs
\ No newline at end of file diff --git a/fpga/docs/usrp3/sim/writing_testbenches.md b/fpga/docs/usrp3/sim/writing_testbenches.md new file mode 100644 index 000000000..cfbbcdbce --- /dev/null +++ b/fpga/docs/usrp3/sim/writing_testbenches.md @@ -0,0 +1,471 @@ +# Writing a Testbench + +Writing a unit test or system level test is easy with the Vivado makefile infrastructure! +Most of the overhead of building and running a testbench is handled by the build tools. +Even recurring tasks like reporting and monitoring are implemented by framework libraries. + +Each executable FPGA unit test must have the following components: + +1. A Makefile +2. A Testbench top-level module + +## Testbench Makefile + +The Testbench Makefile tell the build tools what to build, where to build it, dependency information and runtime information. +The build infrastructure will handle the how-to part for each supported simulation tool. + +Here is a sample Makefile (you are encouraged to use this as a starting point) + + # + # Copyright 2015 Ettus Research LLC + # + + #------------------------------------------------- + # Top-of-Makefile + #------------------------------------------------- + # Define BASE_DIR to point to the "top" dir + BASE_DIR = $(abspath ../../..) + # Include viv_sim_preample after defining BASE_DIR + include $(BASE_DIR)/../tools/make/viv_sim_preamble.mak + + #------------------------------------------------- + # Design Specific + #------------------------------------------------- + # Define part using PART_ID (<device>/<package>/<speedgrade>) + ARCH = kintex7 + PART_ID = xc7k410t/ffg900/-2 + + # Include makefiles and sources for the DUT and its dependencies + include $(BASE_DIR)/../lib/fifo/Makefile.srcs + include $(BASE_DIR)/../lib/axi/Makefile.srcs + include $(BASE_DIR)/../lib/control/Makefile.srcs + + DESIGN_SRCS = $(abspath \ + $(FIFO_SRCS) \ + $(AXI_SRCS) \ + $(CONTROL_LIB_SRCS) \ + ) + + #------------------------------------------------- + # IP Specific + #------------------------------------------------- + # If simulation contains IP, define the IP_DIR and point + # it to the base level IP directory + IP_DIR = ../../ip + + # Include makefiles and sources for all IP components + # *after* defining the IP_DIR + include $(IP_DIR)/ddr3_32bit/Makefile.inc + include $(IP_DIR)/axi_intercon_2x64_128/Makefile.inc + include $(IP_DIR)/fifo_short_2clk/Makefile.inc + include $(IP_DIR)/fifo_4k_2clk/Makefile.inc + include $(IP_DIR)/axi4_bram_1kx64/Makefile.inc + + DESIGN_SRCS += $(abspath \ + $(IP_DDR3_32BIT_SRCS) \ + $(IP_AXI_INTERCON_2X64_128_SRCS) \ + $(IP_FIFO_4K_2CLK_SRCS) \ + $(IP_FIFO_SHORT_2CLK_SRCS) \ + $(IP_AXI4_BRAM_1KX64_SRCS) \ + ) + + #------------------------------------------------- + # Testbench Specific + #------------------------------------------------- + include $(BASE_DIR)/../sim/general/Makefile.srcs + include $(BASE_DIR)/../sim/axi/Makefile.srcs + + # Define only one toplevel module + SIM_TOP = dram_fifo_tb + # Simulation runtime in microseconds + SIM_RUNTIME_US = 80 + + SIM_SRCS = \ + $(abspath dram_fifo_tb.sv) \ + $(abspath axis_dram_fifo_single.sv) \ + $(IP_DDR3_32BIT_SIM_OUTS) \ + $(SIM_GENERAL_SRCS) \ + $(SIM_AXI_SRCS) + + #------------------------------------------------- + # 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 + +You will notice that the Makefile has 5 distinct sections. + +### Section 1: Boilerplate + + #------------------------------------------------- + # Top-of-Makefile + #------------------------------------------------- + # Define BASE_DIR to point to the "top" dir + BASE_DIR = $(abspath ../../..) + # Include viv_sim_preample after defining BASE_DIR + include $(BASE_DIR)/../tools/make/viv_sim_preamble.mak + +Before declaring any variables or using any recipes, the following must be done (in order): + +- Define `BASE_DIR` to tell the build system where the `<repo>/usrp3/top` directory is relative to the + current testbench directory. +- Include `viv_sim_preamble.mak` to initialize boilerplate variables and functions + +### Section 2: Design Specific + + #------------------------------------------------- + # Design Specific + #------------------------------------------------- + # Define part using PART_ID (<device>/<package>/<speedgrade>) + ARCH = kintex7 + PART_ID = xc7k410t/ffg900/-2 + + # Include makefiles and sources for the DUT and its dependencies + include $(BASE_DIR)/../lib/fifo/Makefile.srcs + include $(BASE_DIR)/../lib/axi/Makefile.srcs + include $(BASE_DIR)/../lib/control/Makefile.srcs + + DESIGN_SRCS = $(abspath \ + $(FIFO_SRCS) \ + $(AXI_SRCS) \ + $(CONTROL_LIB_SRCS) \ + ) + +This section contains pointers to sources and other variables for the DUT to function. In the +example above, we are including all sources from the lib/fifo, lib/axi, lib/control directories. + +The following makefile variables are special and must be defined: + +- `ARCH`: The architecture targeted for the simulation. +- `PART_ID`: The exact part targeted for the simulation. Format: `<device>/<package>/<speedgrade>` +- `DESIGN_SRCS`: Space-separated paths to the DUT and all of its dependencies. + +### Section 3: IP Specific + + #------------------------------------------------- + # IP Specific + #------------------------------------------------- + # If simulation contains IP, define the IP_DIR and point + # it to the base level IP directory + IP_DIR = ../../ip + + # Include makefiles and sources for all IP components + # *after* defining the IP_DIR + include $(IP_DIR)/ddr3_32bit/Makefile.inc + include $(IP_DIR)/axi_intercon_2x64_128/Makefile.inc + include $(IP_DIR)/fifo_short_2clk/Makefile.inc + include $(IP_DIR)/fifo_4k_2clk/Makefile.inc + include $(IP_DIR)/axi4_bram_1kx64/Makefile.inc + + DESIGN_SRCS += $(abspath \ + $(IP_DDR3_32BIT_SRCS) \ + $(IP_AXI_INTERCON_2X64_128_SRCS) \ + $(IP_FIFO_4K_2CLK_SRCS) \ + $(IP_FIFO_SHORT_2CLK_SRCS) \ + $(IP_AXI4_BRAM_1KX64_SRCS) \ + ) + +If the DUT depends on any Xilinx IP then this section is required. It tell the tools +which IP cores need to be built in order to run the simulation. The IP specific Makefile +includes handle the "how" part of building IP. As long as the correct Mafefile is included +and the IP XCI sources are added to `DESIGN_SRCS`, the IP intermediates will be built correctly. + +The `IP_DIR` variable must be defined to point to the base ip directory that contains XCI sources. + +### Section 4: Testbench Specific + + #------------------------------------------------- + # Testbench Specific + #------------------------------------------------- + include $(BASE_DIR)/../sim/general/Makefile.srcs + include $(BASE_DIR)/../sim/axi/Makefile.srcs + + # Define only one toplevel module + SIM_TOP = dram_fifo_tb + # Simulation runtime in microseconds + SIM_RUNTIME_US = 80 + + SIM_SRCS = \ + $(abspath dram_fifo_tb.sv) \ + $(abspath axis_dram_fifo_single.sv) \ + $(IP_DDR3_32BIT_SIM_OUTS) \ + $(SIM_GENERAL_SRCS) \ + $(SIM_AXI_SRCS) + +This section contains all sources and parameters for the actual testbench. Any simulation +dependency makefiles can be included here. + +The following variables must be defined: + +- `SIM_TOP`: The toplevel module name for the simulation project +- `SIM_RUNTIME_US`: The maximum runtime of the simulation in microseconds. At this time $finish will be called to terminate the testbench. +- `SIM_SRCS`: This is similar to DESIGN_SRCS except that that should contain a path to `SIM_TOP` and all of its dependencies. + +### Section 5: Tool Support + + #------------------------------------------------- + # 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 + +Now that the Makefile knows all the basic information about the testbench, include tool-specific +makefiles to implement simulation targets. Currently the following simulator makefiles exits: + +- ``<repo>/tools/make/viv_simulator.mak`` + +Please refer to the next section for more information about targets + + +## Testbench Top Level + +The top-level module will instantiate the DUT and implement self-checking behavior. +Test benches could be written in any language (SystemVerilog, Verilog, VHDL) but +to take advantage of our repository of simulation libraries, it is recommended that SystemVerilog be used. + +Here is a sample SystemVerilog top module (you are encouraged to use this as a starting point) + + // + // Copyright 2015 Ettus Research LLC + // + + `timescale 1ns/1ps + `define NS_PER_TICK 1 + `define NUM_TEST_CASES 3 + + `include "sim_clks_rsts.vh" + `include "sim_exec_report.vh" + `include "sim_cvita_lib.sv" + + module example_fifo_tb(); + `TEST_BENCH_INIT("example_fifo_tb",`NUM_TEST_CASES,`NS_PER_TICK) + + // Define all clocks and resets + `DEFINE_CLK(bus_clk, 1000/166.6667, 50) //166MHz bus_clk + `DEFINE_RESET(bus_rst, 0, 100) //100ns for GSR to deassert + + cvita_stream_t chdr_i (.clk(bus_clk)); + cvita_stream_t chdr_o (.clk(bus_clk)); + + // Initialize DUT + axi_fifo #(.WIDTH(65), .SIZE(24)) dut_single ( + .clk(bus_clk), + .reset(bus_rst), + .clear(1'b0), + + .i_tdata({chdr_i.axis.tlast, chdr_i.axis.tdata}), + .i_tvalid(chdr_i.axis.tvalid), + .i_tready(chdr_i.axis.tready), + + .o_tdata({chdr_o.axis.tlast, chdr_o.axis.tdata}), + .o_tvalid(chdr_o.axis.tvalid), + .o_tready(chdr_o.axis.tready), + + .space(), + .occupied() + ); + + //Testbench variables + cvita_hdr_t header, header_out; + cvita_stats_t stats; + + //------------------------------------------ + //Main thread for testbench execution + //------------------------------------------ + initial begin : tb_main + + `TEST_CASE_START("Wait for reset"); + while (bus_rst) @(posedge bus_clk); + `TEST_CASE_DONE((~bus_rst)); + + repeat (200) @(posedge bus_clk); + + header = '{ + pkt_type:DATA, has_time:0, eob:0, seqno:12'h666, + length:0, sid:$random, timestamp:64'h0}; + + `TEST_CASE_START("Fill up empty FIFO then drain (short packet)"); + chdr_o.axis.tready = 0; + chdr_i.push_ramp_pkt(16, 64'd0, 64'h100, header); + chdr_o.axis.tready = 1; + chdr_o.wait_for_pkt_get_info(header_out, stats); + `ASSERT_ERROR(stats.count==16, "Bad packet: Length mismatch"); + `ASSERT_ERROR(header.sid==header_out.sid, "Bad packet: Wrong SID"); + `ASSERT_ERROR(chdr_i.axis.tready, "Bus not ready"); + `TEST_CASE_DONE(1); + + header = '{ + pkt_type:DATA, has_time:1, eob:0, seqno:12'h666, + length:0, sid:$random, timestamp:64'h0}; + + `TEST_CASE_START("Concurrent read and write (single packet)"); + chdr_o.axis.tready = 1; + fork + begin + chdr_i.push_ramp_pkt(20, 64'd0, 64'h100, header); + end + begin + chdr_o.wait_for_pkt_get_info(header_out, stats); + end + join + `ASSERT_ERROR(stats.count==20, "Bad packet: Length mismatch"); + `TEST_CASE_DONE(1); + end + endmodule + + +Each testbench should have the following basic components: + +### Timescale Defines and Includes + + `timescale 1ns/1ps + `define NS_PER_TICK 1 + `define NUM_TEST_CASES 3 + + `include "sim_clks_rsts.vh" + `include "sim_exec_report.vh" + `include "sim_cvita_lib.sv" + +In addition to the timescale, the infrastructure needs to know the number of +nanoseconds per simulator tick. This can be a floating point number. + + +In addition to the timescale, you may include any Verilog/SystemVerilog headers here. + +### Main Module Definition + + `include "sim_exec_report.vh" + + module example_fifo_tb(); + `TEST_BENCH_INIT("example_fifo_tb",`NUM_TEST_CASES,`NS_PER_TICK) + + ... + + //------------------------------------------ + //Main thread for testbench execution + //------------------------------------------ + initial begin : tb_main + + ... + + end + endmodule + +The name of the main module must match the ``SIM_TOP`` variable value in the Makefile. +To register this module with the framework, the ``TEST_BENCH_INIT`` macro must be called. +This macro is defined in ``<repo>/usrp3/sim/general/sim_exec_report.vh``. + +``TEST_BENCH_INIT``: + + // Initializes state for a test bench. + // This macro *must be* called within the testbench module but + // outside the primary initial block + // Its sets up boilerplate code for: + // - Logging to console + // - Test execution tracking + // - Gathering test results + // - Bounding execution time based on the SIM_RUNTIME_US vdef + // + // Usage: `TEST_BENCH_INIT(test_name,min_tc_run_count,ns_per_tick) + // where + // - tb_name: Name of the testbench. (Only used during reporting) + // - min_tc_run_count: Number of test cases in testbench. (Used to detect stalls and inf-loops) + // - ns_per_tick: The time_unit_base from the timescale declaration + +The testbench must also have at least one initial block that consists tests cases (covered later). +For the sake of convention it should be called ``tb_main``. *All test cases must live in ``tb_main``*. You may +have other initial block but they must not call macros from ``sim_exec_report.vh`` because the code +there is not thread-safe. + +### Test Cases + +A test case in this context is defined as an independent entity that validates an aspect of the DUT behavior +and which is independent from other test cases i.e. the result of one test case should ideally not affect others. + + +Test cases are wrapped in the ``TEST_CASE_START`` and ``TEST_CASE_DONE`` macros: + + `TEST_CASE_START("Fill up empty FIFO then drain (short packet)"); + chdr_o.axis.tready = 0; + chdr_i.push_ramp_pkt(16, 64'd0, 64'h100, header); + chdr_o.axis.tready = 1; + chdr_o.wait_for_pkt_get_info(header_out, stats); + `ASSERT_ERROR(stats.count==16, "Bad packet: Length mismatch"); + `ASSERT_ERROR(header.sid==header_out.sid, "Bad packet: Wrong SID"); + `ASSERT_ERROR(chdr_i.axis.tready, "Bus not ready"); + `TEST_CASE_DONE(1); + +Here are the signatures of the two macros: + +``TEST_CASE_START``: + + // Indicates the start of a test case + // This macro *must be* called inside the primary initial block + // + // Usage: `TEST_CASE_START(test_name) + // where + // - test_name: The name of the test. + // + +``TEST_CASE_DONE``: + + // Indicates the end of a test case + // This macro *must be* called inside the primary initial block + // The pass/fail status of test case is determined based on the + // the user specified outcome and the number of fatal or error + // ASSERTs triggered in the test case. + // + // Usage: `TEST_CASE_DONE(test_result) + // where + // - test_result: User specified outcome + // + +In addition to the test case status, it is also possible to have asserts within +a test case. We have wrappers for the different kinds of SystemVerilog asserts +that additionally fail the test case in case the assert fails. An assert triggered +in a test case will not affect the outcome of another (except for a fatal assert which +halts the simulator). Supported assert macros: + + // Wrapper around a an assert. + // ASSERT_FATAL throws an error assertion and halts the simulator + // if cond is not satisfied + // + // Usage: `ASSERT_FATAL(cond,msg) + // where + // - cond: Condition for the assert + // - msg: Message for the assert + // + + + // Wrapper around a an assert. + // ASSERT_ERROR throws an error assertion and fails the test case + // if cond is not satisfied. The simulator will *not* halt + // + // Usage: `ASSERT_ERROR(cond,msg) + // where + // - cond: Condition for the assert + // - msg: Message for the assert + // + + + // Wrapper around a an assert. + // ASSERT_WARNING throws an warning assertion but does not fail the + // test case if cond is not satisfied. The simulator will *not* halt + // + // Usage: `ASSERT_WARNING(cond,msg) + // where + // - cond: Condition for the assert + // - msg: Message for the assert + // + +### Optional Libraries + +It is encouraged to use (and create) reusable libraries in product specific +test benches. Libraries can provide macros, modules, tasks and functions for +ease-of-use with particular protocols and subsystems. + +The \ref md_usrp3_sim_writing_testbenches page has more information. |