diff options
8 files changed, 1252 insertions, 10 deletions
diff --git a/fpga/usrp3/lib/hls/addsub_hls/Makefile.inc b/fpga/usrp3/lib/hls/addsub_hls/Makefile.inc index 0e2f0737a..03976bce8 100644 --- a/fpga/usrp3/lib/hls/addsub_hls/Makefile.inc +++ b/fpga/usrp3/lib/hls/addsub_hls/Makefile.inc @@ -1,22 +1,19 @@  # -# Copyright 2015-2017 Ettus Research -# Copyright 2016 Ettus Research, a National Instruments Company +# Copyright 2020 Ettus Research, a National Instruments Brand  #  # SPDX-License-Identifier: LGPL-3.0-or-later  #  # Add C/C++/tcl files relative to usrp3/lib/hls/<ip> directory -HLS_IP_ADDSUB_HLS_SRCS = \ +HLS_IP_ADDSUB_HLS_LIB_SRCS = $(addprefix $(HLS_IP_DIR)/addsub_hls/, \  addsub_hls.cpp \ -addsub_hls.tcl - -HLS_IP_ADDSUB_HLS_OUTS = $(addprefix $(IP_BUILD_DIR)/addsub_hls/, \ -solution/impl/verilog/addsub_hls.v \ +addsub_hls.tcl \  ) -# Sources in lib directory -HLS_IP_ADDSUB_HLS_LIB_SRCS = $(addprefix $(HLS_IP_DIR)/addsub_hls/, $(HLS_IP_ADDSUB_HLS_SRCS)) +# HLS output artifact points to the ip/hdl/verilog folder. The build process +# will glob all the files in this directory, including *.dat files. +HLS_IP_ADDSUB_HLS_OUTS = $(IP_BUILD_DIR)/addsub_hls/solution/impl/ip/hdl/verilog  # Build with HLS  $(HLS_IP_ADDSUB_HLS_OUTS) : $(HLS_IP_ADDSUB_HLS_LIB_SRCS) -	$(call BUILD_VIVADO_HLS_IP,addsub_hls,$(PART_ID),$(HLS_IP_ADDSUB_HLS_LIB_SRCS),$(HLS_IP_DIR),$(IP_BUILD_DIR),) +	$(call BUILD_VIVADO_HLS_IP,addsub_hls,$(PART_ID),$(HLS_IP_ADDSUB_HLS_LIB_SRCS),$(HLS_IP_DIR),$(IP_BUILD_DIR),)
\ No newline at end of file diff --git a/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_addsub/Makefile b/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_addsub/Makefile new file mode 100644 index 000000000..0c825f41d --- /dev/null +++ b/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_addsub/Makefile @@ -0,0 +1,47 @@ +# +# 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. Note: +# UHD_FPGA_DIR must be passed into this Makefile. +BASE_DIR = ../../../../top +# Include viv_sim_preample 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/rfnoc/core/Makefile.srcs +include $(BASE_DIR)/../lib/rfnoc/utils/Makefile.srcs +include $(BASE_DIR)/../lib/hls/Makefile.inc +include Makefile.srcs + +DESIGN_SRCS += $(abspath \ +$(RFNOC_CORE_SRCS) \ +$(RFNOC_UTIL_SRCS) \ +$(RFNOC_OOT_SRCS) \ +$(HLS_IP_ADDSUB_HLS_OUTS) \ +) + +#------------------------------------------------- +# Testbench Specific +#------------------------------------------------- +SIM_TOP = rfnoc_block_addsub_all_tb +SIM_SRCS = \ +$(abspath rfnoc_block_addsub_tb.sv) \ +$(abspath rfnoc_block_addsub_all_tb.sv) \ + +#------------------------------------------------- +# 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/rfnoc/blocks/rfnoc_block_addsub/Makefile.srcs b/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_addsub/Makefile.srcs new file mode 100644 index 000000000..2fb71b41f --- /dev/null +++ b/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_addsub/Makefile.srcs @@ -0,0 +1,22 @@ +# +# Copyright 2020 Ettus Research, a National Instruments Brand +# +# SPDX-License-Identifier: LGPL-3.0-or-later +# + +################################################## +# RFNoC Block Sources +################################################## +# Here, list all the files that are necessary to synthesize this block. Don't +# include testbenches! +# Make sure that the source files are nicely detectable by a regex. Best to put +# one on each line. +# The first argument to addprefix is the current path to this Makefile, so the +# path list is always absolute, regardless of from where we're including or +# calling this file. RFNOC_OOT_SRCS needs to be a simply expanded variable +# (not a recursively expanded variable), and we take care of that in the build +# infrastructure. +RFNOC_OOT_SRCS += $(addprefix $(dir $(abspath $(lastword $(MAKEFILE_LIST)))), \ +rfnoc_block_addsub.v \ +noc_shell_addsub.v \ +) diff --git a/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_addsub/noc_shell_addsub.v b/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_addsub/noc_shell_addsub.v new file mode 100644 index 000000000..333f6cbfb --- /dev/null +++ b/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_addsub/noc_shell_addsub.v @@ -0,0 +1,345 @@ +// +// Copyright 2020 Ettus Research, a National Instruments Brand +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// +// Module: noc_shell_addsub +// +// Description: +// +//   This is a tool-generated NoC-shell for the addsub block. +//   See the RFNoC specification for more information about NoC shells. +// +// Parameters: +// +//   THIS_PORTID : Control crossbar port to which this block is connected +//   CHDR_W      : AXIS-CHDR data bus width +//   MTU         : Maximum transmission unit (i.e., maximum packet size in +// + +`default_nettype none + + +module noc_shell_addsub #( +  parameter [9:0] THIS_PORTID     = 10'd0, +  parameter       CHDR_W          = 64, +  parameter [5:0] MTU             = 10, +  parameter       USE_IMPL        = "Verilog" + +) ( +  //--------------------- +  // Framework Interface +  //--------------------- + +  // RFNoC Framework Clocks +  input  wire rfnoc_chdr_clk, +  input  wire rfnoc_ctrl_clk, +  input  wire ce_clk, + +  // NoC Shell Generated Resets +  output wire rfnoc_chdr_rst, +  output wire rfnoc_ctrl_rst, +  output wire ce_rst, + +  // RFNoC Backend Interface +  input  wire [511:0]          rfnoc_core_config, +  output wire [511:0]          rfnoc_core_status, + +  // AXIS-CHDR Input Ports (from framework) +  input  wire [(2)*CHDR_W-1:0] s_rfnoc_chdr_tdata, +  input  wire [(2)-1:0]        s_rfnoc_chdr_tlast, +  input  wire [(2)-1:0]        s_rfnoc_chdr_tvalid, +  output wire [(2)-1:0]        s_rfnoc_chdr_tready, +  // AXIS-CHDR Output Ports (to framework) +  output wire [(2)*CHDR_W-1:0] m_rfnoc_chdr_tdata, +  output wire [(2)-1:0]        m_rfnoc_chdr_tlast, +  output wire [(2)-1:0]        m_rfnoc_chdr_tvalid, +  input  wire [(2)-1:0]        m_rfnoc_chdr_tready, + +  // AXIS-Ctrl Control Input Port (from framework) +  input  wire [31:0]           s_rfnoc_ctrl_tdata, +  input  wire                  s_rfnoc_ctrl_tlast, +  input  wire                  s_rfnoc_ctrl_tvalid, +  output wire                  s_rfnoc_ctrl_tready, +  // AXIS-Ctrl Control Output Port (to framework) +  output wire [31:0]           m_rfnoc_ctrl_tdata, +  output wire                  m_rfnoc_ctrl_tlast, +  output wire                  m_rfnoc_ctrl_tvalid, +  input  wire                  m_rfnoc_ctrl_tready, + +  //--------------------- +  // Client Interface +  //--------------------- + +  // AXI-Stream Payload Context Clock and Reset +  output wire               axis_data_clk, +  output wire               axis_data_rst, +  // Payload Stream to User Logic: in_a +  output wire [32*1-1:0]    m_in_a_payload_tdata, +  output wire [1-1:0]       m_in_a_payload_tkeep, +  output wire               m_in_a_payload_tlast, +  output wire               m_in_a_payload_tvalid, +  input  wire               m_in_a_payload_tready, +  // Context Stream to User Logic: in_a +  output wire [CHDR_W-1:0]  m_in_a_context_tdata, +  output wire [3:0]         m_in_a_context_tuser, +  output wire               m_in_a_context_tlast, +  output wire               m_in_a_context_tvalid, +  input  wire               m_in_a_context_tready, +  // Payload Stream to User Logic: in_b +  output wire [32*1-1:0]    m_in_b_payload_tdata, +  output wire [1-1:0]       m_in_b_payload_tkeep, +  output wire               m_in_b_payload_tlast, +  output wire               m_in_b_payload_tvalid, +  input  wire               m_in_b_payload_tready, +  // Context Stream to User Logic: in_b +  output wire [CHDR_W-1:0]  m_in_b_context_tdata, +  output wire [3:0]         m_in_b_context_tuser, +  output wire               m_in_b_context_tlast, +  output wire               m_in_b_context_tvalid, +  input  wire               m_in_b_context_tready, +  // Payload Stream from User Logic: add +  input  wire [32*1-1:0]    s_add_payload_tdata, +  input  wire [0:0]         s_add_payload_tkeep, +  input  wire               s_add_payload_tlast, +  input  wire               s_add_payload_tvalid, +  output wire               s_add_payload_tready, +  // Context Stream from User Logic: add +  input  wire [CHDR_W-1:0]  s_add_context_tdata, +  input  wire [3:0]         s_add_context_tuser, +  input  wire               s_add_context_tlast, +  input  wire               s_add_context_tvalid, +  output wire               s_add_context_tready, +  // Payload Stream from User Logic: sub +  input  wire [32*1-1:0]    s_sub_payload_tdata, +  input  wire [0:0]         s_sub_payload_tkeep, +  input  wire               s_sub_payload_tlast, +  input  wire               s_sub_payload_tvalid, +  output wire               s_sub_payload_tready, +  // Context Stream from User Logic: sub +  input  wire [CHDR_W-1:0]  s_sub_context_tdata, +  input  wire [3:0]         s_sub_context_tuser, +  input  wire               s_sub_context_tlast, +  input  wire               s_sub_context_tvalid, +  output wire               s_sub_context_tready +); + +  //--------------------------------------------------------------------------- +  //  Backend Interface +  //--------------------------------------------------------------------------- + +  wire         data_i_flush_en; +  wire [31:0]  data_i_flush_timeout; +  wire [63:0]  data_i_flush_active; +  wire [63:0]  data_i_flush_done; +  wire         data_o_flush_en; +  wire [31:0]  data_o_flush_timeout; +  wire [63:0]  data_o_flush_active; +  wire [63:0]  data_o_flush_done; + +  backend_iface #( +    .NOC_ID        (32'hADD00000), +    .NUM_DATA_I    (2), +    .NUM_DATA_O    (2), +    .CTRL_FIFOSIZE ($clog2(2)), +    .MTU           (MTU) +  ) backend_iface_i ( +    .rfnoc_chdr_clk       (rfnoc_chdr_clk), +    .rfnoc_chdr_rst       (rfnoc_chdr_rst), +    .rfnoc_ctrl_clk       (rfnoc_ctrl_clk), +    .rfnoc_ctrl_rst       (rfnoc_ctrl_rst), +    .rfnoc_core_config    (rfnoc_core_config), +    .rfnoc_core_status    (rfnoc_core_status), +    .data_i_flush_en      (data_i_flush_en), +    .data_i_flush_timeout (data_i_flush_timeout), +    .data_i_flush_active  (data_i_flush_active), +    .data_i_flush_done    (data_i_flush_done), +    .data_o_flush_en      (data_o_flush_en), +    .data_o_flush_timeout (data_o_flush_timeout), +    .data_o_flush_active  (data_o_flush_active), +    .data_o_flush_done    (data_o_flush_done) +  ); + +  //--------------------------------------------------------------------------- +  //  Reset Generation +  //--------------------------------------------------------------------------- + +  wire ce_rst_pulse; + +  pulse_synchronizer #(.MODE ("POSEDGE")) pulse_synchronizer_ce_clk ( +    .clk_a(rfnoc_chdr_clk), .rst_a(1'b0), .pulse_a (rfnoc_chdr_rst), .busy_a (), +    .clk_b(ce_clk), .pulse_b (ce_rst_pulse) +  ); + +  pulse_stretch_min #(.LENGTH(32)) pulse_stretch_min_ce_clk ( +    .clk(ce_clk), .rst(1'b0), +    .pulse_in(ce_rst_pulse), .pulse_out(ce_rst) +  ); + +  //--------------------------------------------------------------------------- +  //  Control Path +  //--------------------------------------------------------------------------- + +  // No control path for this block +  assign s_rfnoc_ctrl_tready =  1'b1; +  assign m_rfnoc_ctrl_tdata  = 32'b0; +  assign m_rfnoc_ctrl_tlast  =  1'b0; +  assign m_rfnoc_ctrl_tvalid =  1'b0; + +  //--------------------------------------------------------------------------- +  //  Data Path +  //--------------------------------------------------------------------------- + +  genvar i; + +  assign axis_data_clk = ce_clk; +  assign axis_data_rst = ce_rst; + +  //--------------------- +  // Input Data Paths +  //--------------------- + +  chdr_to_axis_pyld_ctxt #( +    .CHDR_W              (CHDR_W), +    .ITEM_W              (32), +    .NIPC                (1), +    .SYNC_CLKS           (0), +    .CONTEXT_FIFO_SIZE   ($clog2(2)), +    .PAYLOAD_FIFO_SIZE   ($clog2(2)), +    .CONTEXT_PREFETCH_EN (1) +  ) chdr_to_axis_pyld_ctxt_in_in_a ( +    .axis_chdr_clk         (rfnoc_chdr_clk), +    .axis_chdr_rst         (rfnoc_chdr_rst), +    .axis_data_clk         (axis_data_clk), +    .axis_data_rst         (axis_data_rst), +    .s_axis_chdr_tdata     (s_rfnoc_chdr_tdata[(0)*CHDR_W+:CHDR_W]), +    .s_axis_chdr_tlast     (s_rfnoc_chdr_tlast[0]), +    .s_axis_chdr_tvalid    (s_rfnoc_chdr_tvalid[0]), +    .s_axis_chdr_tready    (s_rfnoc_chdr_tready[0]), +    .m_axis_payload_tdata  (m_in_a_payload_tdata), +    .m_axis_payload_tkeep  (m_in_a_payload_tkeep), +    .m_axis_payload_tlast  (m_in_a_payload_tlast), +    .m_axis_payload_tvalid (m_in_a_payload_tvalid), +    .m_axis_payload_tready (m_in_a_payload_tready), +    .m_axis_context_tdata  (m_in_a_context_tdata), +    .m_axis_context_tuser  (m_in_a_context_tuser), +    .m_axis_context_tlast  (m_in_a_context_tlast), +    .m_axis_context_tvalid (m_in_a_context_tvalid), +    .m_axis_context_tready (m_in_a_context_tready), +    .flush_en              (data_i_flush_en), +    .flush_timeout         (data_i_flush_timeout), +    .flush_active          (data_i_flush_active[0]), +    .flush_done            (data_i_flush_done[0]) +  ); + +  chdr_to_axis_pyld_ctxt #( +    .CHDR_W              (CHDR_W), +    .ITEM_W              (32), +    .NIPC                (1), +    .SYNC_CLKS           (0), +    .CONTEXT_FIFO_SIZE   ($clog2(2)), +    .PAYLOAD_FIFO_SIZE   ($clog2(2)), +    .CONTEXT_PREFETCH_EN (1) +  ) chdr_to_axis_pyld_ctxt_in_in_b ( +    .axis_chdr_clk         (rfnoc_chdr_clk), +    .axis_chdr_rst         (rfnoc_chdr_rst), +    .axis_data_clk         (axis_data_clk), +    .axis_data_rst         (axis_data_rst), +    .s_axis_chdr_tdata     (s_rfnoc_chdr_tdata[(1)*CHDR_W+:CHDR_W]), +    .s_axis_chdr_tlast     (s_rfnoc_chdr_tlast[1]), +    .s_axis_chdr_tvalid    (s_rfnoc_chdr_tvalid[1]), +    .s_axis_chdr_tready    (s_rfnoc_chdr_tready[1]), +    .m_axis_payload_tdata  (m_in_b_payload_tdata), +    .m_axis_payload_tkeep  (m_in_b_payload_tkeep), +    .m_axis_payload_tlast  (m_in_b_payload_tlast), +    .m_axis_payload_tvalid (m_in_b_payload_tvalid), +    .m_axis_payload_tready (m_in_b_payload_tready), +    .m_axis_context_tdata  (m_in_b_context_tdata), +    .m_axis_context_tuser  (m_in_b_context_tuser), +    .m_axis_context_tlast  (m_in_b_context_tlast), +    .m_axis_context_tvalid (m_in_b_context_tvalid), +    .m_axis_context_tready (m_in_b_context_tready), +    .flush_en              (data_i_flush_en), +    .flush_timeout         (data_i_flush_timeout), +    .flush_active          (data_i_flush_active[1]), +    .flush_done            (data_i_flush_done[1]) +  ); + +  //--------------------- +  // Output Data Paths +  //--------------------- + +  axis_pyld_ctxt_to_chdr #( +    .CHDR_W              (CHDR_W), +    .ITEM_W              (32), +    .NIPC                (1), +    .SYNC_CLKS           (0), +    .CONTEXT_FIFO_SIZE   ($clog2(2)), +    .PAYLOAD_FIFO_SIZE   ($clog2(2)), +    .MTU                 (MTU), +    .CONTEXT_PREFETCH_EN (1) +  ) axis_pyld_ctxt_to_chdr_out_add ( +    .axis_chdr_clk         (rfnoc_chdr_clk), +    .axis_chdr_rst         (rfnoc_chdr_rst), +    .axis_data_clk         (axis_data_clk), +    .axis_data_rst         (axis_data_rst), +    .m_axis_chdr_tdata     (m_rfnoc_chdr_tdata[(0)*CHDR_W+:CHDR_W]), +    .m_axis_chdr_tlast     (m_rfnoc_chdr_tlast[0]), +    .m_axis_chdr_tvalid    (m_rfnoc_chdr_tvalid[0]), +    .m_axis_chdr_tready    (m_rfnoc_chdr_tready[0]), +    .s_axis_payload_tdata  (s_add_payload_tdata), +    .s_axis_payload_tkeep  (s_add_payload_tkeep), +    .s_axis_payload_tlast  (s_add_payload_tlast), +    .s_axis_payload_tvalid (s_add_payload_tvalid), +    .s_axis_payload_tready (s_add_payload_tready), +    .s_axis_context_tdata  (s_add_context_tdata), +    .s_axis_context_tuser  (s_add_context_tuser), +    .s_axis_context_tlast  (s_add_context_tlast), +    .s_axis_context_tvalid (s_add_context_tvalid), +    .s_axis_context_tready (s_add_context_tready), +    .framer_errors         (), +    .flush_en              (data_o_flush_en), +    .flush_timeout         (data_o_flush_timeout), +    .flush_active          (data_o_flush_active[0]), +    .flush_done            (data_o_flush_done[0]) +  ); + +  axis_pyld_ctxt_to_chdr #( +    .CHDR_W              (CHDR_W), +    .ITEM_W              (32), +    .NIPC                (1), +    .SYNC_CLKS           (0), +    .CONTEXT_FIFO_SIZE   ($clog2(2)), +    .PAYLOAD_FIFO_SIZE   ($clog2(2)), +    .MTU                 (MTU), +    .CONTEXT_PREFETCH_EN (1) +  ) axis_pyld_ctxt_to_chdr_out_sub ( +    .axis_chdr_clk         (rfnoc_chdr_clk), +    .axis_chdr_rst         (rfnoc_chdr_rst), +    .axis_data_clk         (axis_data_clk), +    .axis_data_rst         (axis_data_rst), +    .m_axis_chdr_tdata     (m_rfnoc_chdr_tdata[(1)*CHDR_W+:CHDR_W]), +    .m_axis_chdr_tlast     (m_rfnoc_chdr_tlast[1]), +    .m_axis_chdr_tvalid    (m_rfnoc_chdr_tvalid[1]), +    .m_axis_chdr_tready    (m_rfnoc_chdr_tready[1]), +    .s_axis_payload_tdata  (s_sub_payload_tdata), +    .s_axis_payload_tkeep  (s_sub_payload_tkeep), +    .s_axis_payload_tlast  (s_sub_payload_tlast), +    .s_axis_payload_tvalid (s_sub_payload_tvalid), +    .s_axis_payload_tready (s_sub_payload_tready), +    .s_axis_context_tdata  (s_sub_context_tdata), +    .s_axis_context_tuser  (s_sub_context_tuser), +    .s_axis_context_tlast  (s_sub_context_tlast), +    .s_axis_context_tvalid (s_sub_context_tvalid), +    .s_axis_context_tready (s_sub_context_tready), +    .framer_errors         (), +    .flush_en              (data_o_flush_en), +    .flush_timeout         (data_o_flush_timeout), +    .flush_active          (data_o_flush_active[1]), +    .flush_done            (data_o_flush_done[1]) +  ); + +endmodule // noc_shell_addsub + + +`default_nettype wire diff --git a/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_addsub/rfnoc_block_addsub.v b/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_addsub/rfnoc_block_addsub.v new file mode 100644 index 000000000..083bc35b3 --- /dev/null +++ b/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_addsub/rfnoc_block_addsub.v @@ -0,0 +1,336 @@ +// +// Copyright 2020 Ettus Research, a National Instruments Brand +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// +// Module: rfnoc_block_addsub +// +// Description: +// +//   This block takes in two streams and adds and subtracts them, creating two +//   output streams with the sum and difference of the input streams. It +//   assumes the input and output packets are all the same length and use sc16 +//   samples. +// +//   This block also demonstrates how to use Verilog, VHDL and/or +//   high-level-synthesis (HLS) in a design. You can set the USE_IMPL parameter +//   to control which implementation is used. +// +// Parameters: +// +//   THIS_PORTID : Control crossbar port to which this block is connected +//   CHDR_W      : AXIS-CHDR data bus width +//   MTU         : Maximum transmission unit (i.e., maximum packet size in CHDR +//                 words is 2**MTU). +//   USE_IMPL    : Indicates which implementation to use. This is a string that +//                 can be set to "Verilog", "VHDL", or "HLS". +// +`default_nettype none + + +module rfnoc_block_addsub #( +  parameter [9:0] THIS_PORTID = 10'd0, +  parameter       CHDR_W      = 64, +  parameter [5:0] MTU         = 10, +  parameter       USE_IMPL    = "Verilog" +) ( +  // RFNoC Framework Clocks and Resets +  input  wire                rfnoc_chdr_clk, +  input  wire                rfnoc_ctrl_clk, +  input  wire                ce_clk, +  // RFNoC Backend Interface +  input  wire [       511:0] rfnoc_core_config, +  output wire [       511:0] rfnoc_core_status, +  // AXIS-CHDR Input Ports (from framework) +  input  wire [2*CHDR_W-1:0] s_rfnoc_chdr_tdata, +  input  wire [       2-1:0] s_rfnoc_chdr_tlast, +  input  wire [       2-1:0] s_rfnoc_chdr_tvalid, +  output wire [       2-1:0] s_rfnoc_chdr_tready, +  // AXIS-CHDR Output Ports (to framework) +  output wire [2*CHDR_W-1:0] m_rfnoc_chdr_tdata, +  output wire [       2-1:0] m_rfnoc_chdr_tlast, +  output wire [       2-1:0] m_rfnoc_chdr_tvalid, +  input  wire [       2-1:0] m_rfnoc_chdr_tready, +  // AXIS-Ctrl Input Port (from framework) +  input  wire [        31:0] s_rfnoc_ctrl_tdata, +  input  wire                s_rfnoc_ctrl_tlast, +  input  wire                s_rfnoc_ctrl_tvalid, +  output wire                s_rfnoc_ctrl_tready, +  // AXIS-Ctrl Output Port (to framework) +  output wire [        31:0] m_rfnoc_ctrl_tdata, +  output wire                m_rfnoc_ctrl_tlast, +  output wire                m_rfnoc_ctrl_tvalid, +  input  wire                m_rfnoc_ctrl_tready +); + +  // This block currently only supports 64-bit CHDR +  if (CHDR_W != 64) begin +    CHDR_W_must_be_64_for_the_addsub_block(); +  end + + +  //--------------------------------------------------------------------------- +  // Signal Declarations +  //--------------------------------------------------------------------------- + +  // Clocks and Resets +  wire               axis_data_clk; +  wire               axis_data_rst; +  // Payload Stream to User Logic: in_a +  wire [32*1-1:0]    m_in_a_payload_tdata; +  wire               m_in_a_payload_tlast; +  wire               m_in_a_payload_tvalid; +  wire               m_in_a_payload_tready; +  // Context Stream to User Logic: in_a +  wire [CHDR_W-1:0]  m_in_a_context_tdata; +  wire [3:0]         m_in_a_context_tuser; +  wire               m_in_a_context_tlast; +  wire               m_in_a_context_tvalid; +  wire               m_in_a_context_tready; +  // Payload Stream to User Logic: in_b +  wire [32*1-1:0]    m_in_b_payload_tdata; +  wire               m_in_b_payload_tlast; +  wire               m_in_b_payload_tvalid; +  wire               m_in_b_payload_tready; +  // Context Stream to User Logic: in_b +  wire               m_in_b_context_tready; +  // Payload Stream from User Logic: add +  wire [32*1-1:0]    s_add_payload_tdata; +  wire               s_add_payload_tlast; +  wire               s_add_payload_tvalid; +  wire               s_add_payload_tready; +  // Context Stream from User Logic: add +  wire [CHDR_W-1:0]  s_add_context_tdata; +  wire [3:0]         s_add_context_tuser; +  wire               s_add_context_tlast; +  wire               s_add_context_tvalid; +  wire               s_add_context_tready; +  // Payload Stream from User Logic: sub +  wire [32*1-1:0]    s_sub_payload_tdata; +  wire               s_sub_payload_tlast; +  wire               s_sub_payload_tvalid; +  wire               s_sub_payload_tready; +  // Context Stream from User Logic: sub +  wire [CHDR_W-1:0]  s_sub_context_tdata; +  wire [3:0]         s_sub_context_tuser; +  wire               s_sub_context_tlast; +  wire               s_sub_context_tvalid; +  wire               s_sub_context_tready; + + +  //--------------------------------------------------------------------------- +  // NoC Shell +  //--------------------------------------------------------------------------- + +  noc_shell_addsub #( +    .CHDR_W      (CHDR_W), +    .THIS_PORTID (THIS_PORTID), +    .MTU         (MTU), +    .USE_IMPL    (USE_IMPL) +  ) noc_shell_addsub_i ( +    //--------------------- +    // Framework Interface +    //--------------------- + +    // Clock Inputs +    .rfnoc_chdr_clk        (rfnoc_chdr_clk), +    .rfnoc_ctrl_clk        (rfnoc_ctrl_clk), +    .ce_clk                (ce_clk), +    // Reset Outputs +    .rfnoc_chdr_rst        (), +    .rfnoc_ctrl_rst        (), +    .ce_rst                (), +    // RFNoC Backend Interface +    .rfnoc_core_config     (rfnoc_core_config), +    .rfnoc_core_status     (rfnoc_core_status), +    // CHDR Input Ports  (from framework) +    .s_rfnoc_chdr_tdata    (s_rfnoc_chdr_tdata), +    .s_rfnoc_chdr_tlast    (s_rfnoc_chdr_tlast), +    .s_rfnoc_chdr_tvalid   (s_rfnoc_chdr_tvalid), +    .s_rfnoc_chdr_tready   (s_rfnoc_chdr_tready), +    // CHDR Output Ports (to framework) +    .m_rfnoc_chdr_tdata    (m_rfnoc_chdr_tdata), +    .m_rfnoc_chdr_tlast    (m_rfnoc_chdr_tlast), +    .m_rfnoc_chdr_tvalid   (m_rfnoc_chdr_tvalid), +    .m_rfnoc_chdr_tready   (m_rfnoc_chdr_tready), +    // AXIS-Ctrl Input Port (from framework) +    .s_rfnoc_ctrl_tdata    (s_rfnoc_ctrl_tdata), +    .s_rfnoc_ctrl_tlast    (s_rfnoc_ctrl_tlast), +    .s_rfnoc_ctrl_tvalid   (s_rfnoc_ctrl_tvalid), +    .s_rfnoc_ctrl_tready   (s_rfnoc_ctrl_tready), +    // AXIS-Ctrl Output Port (to framework) +    .m_rfnoc_ctrl_tdata    (m_rfnoc_ctrl_tdata), +    .m_rfnoc_ctrl_tlast    (m_rfnoc_ctrl_tlast), +    .m_rfnoc_ctrl_tvalid   (m_rfnoc_ctrl_tvalid), +    .m_rfnoc_ctrl_tready   (m_rfnoc_ctrl_tready), + +    //--------------------- +    // Client Interface +    //--------------------- + +    // AXI-Stream Payload Context Clock and Reset +    .axis_data_clk         (axis_data_clk), +    .axis_data_rst         (axis_data_rst), +    // Payload Stream to User Logic: in_a +    .m_in_a_payload_tdata  (m_in_a_payload_tdata), +    .m_in_a_payload_tkeep  (), +    .m_in_a_payload_tlast  (m_in_a_payload_tlast), +    .m_in_a_payload_tvalid (m_in_a_payload_tvalid), +    .m_in_a_payload_tready (m_in_a_payload_tready), +    // Context Stream to User Logic: in_a +    .m_in_a_context_tdata  (m_in_a_context_tdata), +    .m_in_a_context_tuser  (m_in_a_context_tuser), +    .m_in_a_context_tlast  (m_in_a_context_tlast), +    .m_in_a_context_tvalid (m_in_a_context_tvalid), +    .m_in_a_context_tready (m_in_a_context_tready), +    // Payload Stream to User Logic: in_b +    .m_in_b_payload_tdata  (m_in_b_payload_tdata), +    .m_in_b_payload_tkeep  (), +    .m_in_b_payload_tlast  (m_in_b_payload_tlast), +    .m_in_b_payload_tvalid (m_in_b_payload_tvalid), +    .m_in_b_payload_tready (m_in_b_payload_tready), +    // Context Stream to User Logic: in_b +    .m_in_b_context_tdata  (), +    .m_in_b_context_tuser  (), +    .m_in_b_context_tlast  (), +    .m_in_b_context_tvalid (), +    .m_in_b_context_tready (m_in_b_context_tready), +    // Payload Stream from User Logic: add +    .s_add_payload_tdata   (s_add_payload_tdata), +    .s_add_payload_tkeep   (1'b1), +    .s_add_payload_tlast   (s_add_payload_tlast), +    .s_add_payload_tvalid  (s_add_payload_tvalid), +    .s_add_payload_tready  (s_add_payload_tready), +    // Context Stream from User Logic: add +    .s_add_context_tdata   (s_add_context_tdata), +    .s_add_context_tuser   (s_add_context_tuser), +    .s_add_context_tlast   (s_add_context_tlast), +    .s_add_context_tvalid  (s_add_context_tvalid), +    .s_add_context_tready  (s_add_context_tready), +    // Payload Stream from User Logic: diff +    .s_sub_payload_tdata  (s_sub_payload_tdata), +    .s_sub_payload_tkeep  (1'b1), +    .s_sub_payload_tlast  (s_sub_payload_tlast), +    .s_sub_payload_tvalid (s_sub_payload_tvalid), +    .s_sub_payload_tready (s_sub_payload_tready), +    // Context Stream from User Logic: diff +    .s_sub_context_tdata  (s_sub_context_tdata), +    .s_sub_context_tuser  (s_sub_context_tuser), +    .s_sub_context_tlast  (s_sub_context_tlast), +    .s_sub_context_tvalid (s_sub_context_tvalid), +    .s_sub_context_tready (s_sub_context_tready) +  ); + + +  //--------------------------------------------------------------------------- +  // Context Handling +  //--------------------------------------------------------------------------- + +  // We use the A input to control the packet size and other attributes of the +  // output packets. So we duplicate the A context and discard the B context. +  assign m_in_b_context_tready = 1; + +  axis_split #( +    .DATA_W    (1 + 4 + CHDR_W),    // TLAST + TUSER + TDATA +    .NUM_PORTS (2) +  ) axis_split_i ( +    .clk           (axis_data_clk), +    .rst           (axis_data_rst), +    .s_axis_tdata  ({m_in_a_context_tlast, +                     m_in_a_context_tuser, +                     m_in_a_context_tdata}), +    .s_axis_tvalid (m_in_a_context_tvalid), +    .s_axis_tready (m_in_a_context_tready), +    .m_axis_tdata  ({s_sub_context_tlast, +                     s_sub_context_tuser, +                     s_sub_context_tdata, +                     s_add_context_tlast, +                     s_add_context_tuser, +                     s_add_context_tdata}), +    .m_axis_tvalid ({s_sub_context_tvalid, s_add_context_tvalid}), +    .m_axis_tready ({s_sub_context_tready, s_add_context_tready}) +  ); + + +  //--------------------------------------------------------------------------- +  // Add/Subtract logic +  //--------------------------------------------------------------------------- + +  generate +    if (USE_IMPL == "HLS") begin : gen_hls +      // Use the module generated through Vivado High-Level Synthesis (see +      // addsub_hls.cpp). +      addsub_hls addsub_hls_i ( +        .ap_clk     (axis_data_clk), +        .ap_rst_n   (~axis_data_rst), +        .a_TDATA    (m_in_a_payload_tdata), +        .a_TVALID   (m_in_a_payload_tvalid), +        .a_TREADY   (m_in_a_payload_tready), +        .a_TLAST    (m_in_a_payload_tlast), +        .b_TDATA    (m_in_b_payload_tdata), +        .b_TVALID   (m_in_b_payload_tvalid), +        .b_TREADY   (m_in_b_payload_tready), +        .b_TLAST    (m_in_b_payload_tlast), +        .add_TDATA  (s_add_payload_tdata), +        .add_TVALID (s_add_payload_tvalid), +        .add_TREADY (s_add_payload_tready), +        .add_TLAST  (s_add_payload_tlast), +        .sub_TDATA  (s_sub_payload_tdata), +        .sub_TVALID (s_sub_payload_tvalid), +        .sub_TREADY (s_sub_payload_tready), +        .sub_TLAST  (s_sub_payload_tlast) +      ); +    end else if (USE_IMPL == "VHDL") begin : gen_vhdl +      // Use the VHDL implementation +      addsub_vhdl #( +        .width_g (16) +      ) addsub_vhdl_i ( +        .clk_i       (axis_data_clk), +        .rst_i       (axis_data_rst), +        .i0_tdata    (m_in_a_payload_tdata), +        .i0_tlast    (m_in_a_payload_tlast), +        .i0_tvalid   (m_in_a_payload_tvalid), +        .i0_tready   (m_in_a_payload_tready), +        .i1_tdata    (m_in_b_payload_tdata), +        .i1_tlast    (m_in_b_payload_tlast), +        .i1_tvalid   (m_in_b_payload_tvalid), +        .i1_tready   (m_in_b_payload_tready), +        .sum_tdata   (s_add_payload_tdata), +        .sum_tlast   (s_add_payload_tlast), +        .sum_tvalid  (s_add_payload_tvalid), +        .sum_tready  (s_add_payload_tready), +        .diff_tdata  (s_sub_payload_tdata), +        .diff_tlast  (s_sub_payload_tlast), +        .diff_tvalid (s_sub_payload_tvalid), +        .diff_tready (s_sub_payload_tready) +      ); +    end else begin : gen_verilog +      // Use Verilog implementation +      addsub #( +        .WIDTH (16) +      ) inst_addsub ( +        .clk         (axis_data_clk), +        .reset       (axis_data_rst), +        .i0_tdata    (m_in_a_payload_tdata), +        .i0_tlast    (m_in_a_payload_tlast), +        .i0_tvalid   (m_in_a_payload_tvalid), +        .i0_tready   (m_in_a_payload_tready), +        .i1_tdata    (m_in_b_payload_tdata), +        .i1_tlast    (m_in_b_payload_tlast), +        .i1_tvalid   (m_in_b_payload_tvalid), +        .i1_tready   (m_in_b_payload_tready), +        .sum_tdata   (s_add_payload_tdata), +        .sum_tlast   (s_add_payload_tlast), +        .sum_tvalid  (s_add_payload_tvalid), +        .sum_tready  (s_add_payload_tready), +        .diff_tdata  (s_sub_payload_tdata), +        .diff_tlast  (s_sub_payload_tlast), +        .diff_tvalid (s_sub_payload_tvalid), +        .diff_tready (s_sub_payload_tready) +      ); +    end +  endgenerate + +endmodule // rfnoc_block_addsub + +`default_nettype wire diff --git a/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_addsub/rfnoc_block_addsub_all_tb.sv b/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_addsub/rfnoc_block_addsub_all_tb.sv new file mode 100644 index 000000000..faf871606 --- /dev/null +++ b/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_addsub/rfnoc_block_addsub_all_tb.sv @@ -0,0 +1,28 @@ +// +// Copyright 2020 Ettus Research, a National Instruments Brand +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// +// Module: rfnoc_block_addsub_all_tb +// +// Description: +// +// Top-level testbench for the Add/Sub RFNoC block. This instantiates +// rfnoc_block_addsub_tb with different parameters to test multiple +// configurations. +// + +`default_nettype none + + +module rfnoc_block_addsub_all_tb; + +  // Test all three implementations +  rfnoc_block_addsub_tb #(.USE_IMPL("Verilog")) test_verilog (); +  rfnoc_block_addsub_tb #(.USE_IMPL("VHDL"))    test_vhdl    (); +  rfnoc_block_addsub_tb #(.USE_IMPL("HLS"))     test_hls     (); + +endmodule : rfnoc_block_addsub_all_tb + + +`default_nettype wire diff --git a/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_addsub/rfnoc_block_addsub_tb.sv b/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_addsub/rfnoc_block_addsub_tb.sv new file mode 100644 index 000000000..10e9f968f --- /dev/null +++ b/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_addsub/rfnoc_block_addsub_tb.sv @@ -0,0 +1,405 @@ +// +// Copyright 2020 Ettus Research, a National Instruments Brand +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// +// Module: rfnoc_block_addsub_tb +// +// Description: Testbench for the addsub RFNoC block. +// +// Parameters: +// +//   USE_IMPL : Specifies the implementation string to pass to +//              rfnoc_block_addsub. +// + +`default_nettype none + + +module rfnoc_block_addsub_tb #( +  parameter string USE_IMPL = "Verilog" +); + +  `include "test_exec.svh" + +  import PkgTestExec::*; +  import PkgChdrUtils::*; +  import PkgRfnocBlockCtrlBfm::*; +  import PkgRfnocItemUtils::*; + + +  //--------------------------------------------------------------------------- +  // Testbench Configuration +  //--------------------------------------------------------------------------- + +  localparam [31:0] NOC_ID          = 32'hADD00000; +  localparam [ 9:0] THIS_PORTID     = 10'h123; +  localparam int    CHDR_W          = 64;    // CHDR size in bits +  localparam int    MTU             = 10;    // Log2 of max transmission unit in CHDR words +  localparam int    NUM_PORTS_I     = 2; +  localparam int    NUM_PORTS_O     = 2; +  localparam int    ITEM_W          = 32;    // Sample size in bits +  localparam int    SPP             = 64;    // Samples per packet +  localparam int    PKT_SIZE_BYTES  = SPP * (ITEM_W/8); +  localparam int    STALL_PROB      = 25;    // Default BFM stall probability +  localparam real   CHDR_CLK_PER    = 5.0;   // 200 MHz +  localparam real   CTRL_CLK_PER    = 8.0;   // 125 MHz +  localparam real   CE_CLK_PER      = 4.0;   // 250 MHz + +  // Port numbers for A, B, SUM and DIFF +  localparam IN_PORT_A     = 0; +  localparam IN_PORT_B     = 1; +  localparam OUT_PORT_SUM  = 0; +  localparam OUT_PORT_DIFF = 1; + + +  //--------------------------------------------------------------------------- +  // Clocks and Resets +  //--------------------------------------------------------------------------- + +  bit rfnoc_chdr_clk; +  bit rfnoc_ctrl_clk; +  bit ce_clk; + +  sim_clock_gen #(.PERIOD(CHDR_CLK_PER), .AUTOSTART(0)) +    rfnoc_chdr_clk_gen (.clk(rfnoc_chdr_clk), .rst()); +  sim_clock_gen #(.PERIOD(CTRL_CLK_PER), .AUTOSTART(0)) +    rfnoc_ctrl_clk_gen (.clk(rfnoc_ctrl_clk), .rst()); +  sim_clock_gen #(.PERIOD(CE_CLK_PER), .AUTOSTART(0)) +    ce_clk_gen (.clk(ce_clk), .rst()); + + +  //--------------------------------------------------------------------------- +  // Bus Functional Models +  //--------------------------------------------------------------------------- + +  // Backend Interface +  RfnocBackendIf backend (rfnoc_chdr_clk, rfnoc_ctrl_clk); + +  // AXIS-Ctrl Interface +  AxiStreamIf #(32) m_ctrl (rfnoc_ctrl_clk, 1'b0); +  AxiStreamIf #(32) s_ctrl (rfnoc_ctrl_clk, 1'b0); + +  // AXIS-CHDR Interfaces +  AxiStreamIf #(CHDR_W) m_chdr [NUM_PORTS_I] (rfnoc_chdr_clk, 1'b0); +  AxiStreamIf #(CHDR_W) s_chdr [NUM_PORTS_O] (rfnoc_chdr_clk, 1'b0); + +  // Block Controller BFM +  RfnocBlockCtrlBfm #(CHDR_W, ITEM_W) blk_ctrl = new(backend, m_ctrl, s_ctrl); + +  // CHDR word and item/sample data types +  typedef ChdrData #(CHDR_W, ITEM_W)::chdr_word_t chdr_word_t; +  typedef ChdrData #(CHDR_W, ITEM_W)::item_t      item_t; + +  // Connect block controller to BFMs +  for (genvar i = 0; i < NUM_PORTS_I; i++) begin : gen_bfm_input_connections +    initial begin +      blk_ctrl.connect_master_data_port(i, m_chdr[i], PKT_SIZE_BYTES); +      blk_ctrl.set_master_stall_prob(i, STALL_PROB); +    end +  end +  for (genvar i = 0; i < NUM_PORTS_O; i++) begin : gen_bfm_output_connections +    initial begin +      blk_ctrl.connect_slave_data_port(i, s_chdr[i]); +      blk_ctrl.set_slave_stall_prob(i, STALL_PROB); +    end +  end + + +  //--------------------------------------------------------------------------- +  // Device Under Test (DUT) +  //--------------------------------------------------------------------------- + +  // DUT Slave (Input) Port Signals +  logic [CHDR_W*NUM_PORTS_I-1:0] s_rfnoc_chdr_tdata; +  logic [       NUM_PORTS_I-1:0] s_rfnoc_chdr_tlast; +  logic [       NUM_PORTS_I-1:0] s_rfnoc_chdr_tvalid; +  logic [       NUM_PORTS_I-1:0] s_rfnoc_chdr_tready; + +  // DUT Master (Output) Port Signals +  logic [CHDR_W*NUM_PORTS_O-1:0] m_rfnoc_chdr_tdata; +  logic [       NUM_PORTS_O-1:0] m_rfnoc_chdr_tlast; +  logic [       NUM_PORTS_O-1:0] m_rfnoc_chdr_tvalid; +  logic [       NUM_PORTS_O-1:0] m_rfnoc_chdr_tready; + +  // Map the array of BFMs to a flat vector for the DUT connections +  for (genvar i = 0; i < NUM_PORTS_I; i++) begin : gen_dut_input_connections +    // Connect BFM master to DUT slave port +    assign s_rfnoc_chdr_tdata[CHDR_W*i+:CHDR_W] = m_chdr[i].tdata; +    assign s_rfnoc_chdr_tlast[i]                = m_chdr[i].tlast; +    assign s_rfnoc_chdr_tvalid[i]               = m_chdr[i].tvalid; +    assign m_chdr[i].tready                     = s_rfnoc_chdr_tready[i]; +  end +  for (genvar i = 0; i < NUM_PORTS_O; i++) begin : gen_dut_output_connections +    // Connect BFM slave to DUT master port +    assign s_chdr[i].tdata        = m_rfnoc_chdr_tdata[CHDR_W*i+:CHDR_W]; +    assign s_chdr[i].tlast        = m_rfnoc_chdr_tlast[i]; +    assign s_chdr[i].tvalid       = m_rfnoc_chdr_tvalid[i]; +    assign m_rfnoc_chdr_tready[i] = s_chdr[i].tready; +  end + +  rfnoc_block_addsub #( +    .THIS_PORTID         (THIS_PORTID), +    .CHDR_W              (CHDR_W), +    .MTU                 (MTU), +    .USE_IMPL            (USE_IMPL) +  ) dut ( +    .rfnoc_chdr_clk      (rfnoc_chdr_clk), +    .rfnoc_ctrl_clk      (rfnoc_ctrl_clk), +    .ce_clk          (ce_clk), +    .rfnoc_core_config   (backend.cfg), +    .rfnoc_core_status   (backend.sts), +    .s_rfnoc_chdr_tdata  (s_rfnoc_chdr_tdata), +    .s_rfnoc_chdr_tlast  (s_rfnoc_chdr_tlast), +    .s_rfnoc_chdr_tvalid (s_rfnoc_chdr_tvalid), +    .s_rfnoc_chdr_tready (s_rfnoc_chdr_tready), +    .m_rfnoc_chdr_tdata  (m_rfnoc_chdr_tdata), +    .m_rfnoc_chdr_tlast  (m_rfnoc_chdr_tlast), +    .m_rfnoc_chdr_tvalid (m_rfnoc_chdr_tvalid), +    .m_rfnoc_chdr_tready (m_rfnoc_chdr_tready), +    .s_rfnoc_ctrl_tdata  (m_ctrl.tdata), +    .s_rfnoc_ctrl_tlast  (m_ctrl.tlast), +    .s_rfnoc_ctrl_tvalid (m_ctrl.tvalid), +    .s_rfnoc_ctrl_tready (m_ctrl.tready), +    .m_rfnoc_ctrl_tdata  (s_ctrl.tdata), +    .m_rfnoc_ctrl_tlast  (s_ctrl.tlast), +    .m_rfnoc_ctrl_tvalid (s_ctrl.tvalid), +    .m_rfnoc_ctrl_tready (s_ctrl.tready) +  ); + + +  //--------------------------------------------------------------------------- +  // Helper Logic +  //--------------------------------------------------------------------------- + +  // Rand#(WIDTH)::rand_logic() returns a WIDTH-bit random number. We avoid +  // std::randomize() due to license requirements and limited tool support. +  class Rand #(WIDTH = 32); +    static function logic [WIDTH-1:0] rand_logic(); +      logic [WIDTH-1:0] result; +      int num_rand32 = (WIDTH + 31) / 32; +      for (int i = 0; i < num_rand32; i++) begin +        result = {result, $urandom()}; +      end +      return result; +    endfunction : rand_logic +  endclass : Rand + +  typedef struct { +    item_t        samples[$]; +    chdr_word_t   mdata[$]; +    packet_info_t pkt_info; +  } test_packet_t; + +  typedef struct packed { +    bit [15:0] i; +    bit [15:0] q; +  } sc16_t; + + +  //--------------------------------------------------------------------------- +  // Test Tasks +  //--------------------------------------------------------------------------- + +  task automatic test_rand( +    int num_packets, +    int max_spp   = SPP, +    int prob_a    = STALL_PROB, +    int prob_b    = STALL_PROB, +    int prob_sum  = STALL_PROB, +    int prob_diff = STALL_PROB +  ); +    mailbox #(test_packet_t) packets_mb_a = new(); +    mailbox #(test_packet_t) packets_mb_b = new(); + +    // Set the BFM TREADY behavior +    blk_ctrl.set_master_stall_prob(IN_PORT_A, prob_a); +    blk_ctrl.set_master_stall_prob(IN_PORT_B, prob_b); +    blk_ctrl.set_slave_stall_prob(OUT_PORT_SUM, prob_sum); +    blk_ctrl.set_slave_stall_prob(OUT_PORT_DIFF, prob_diff); + +    fork +      repeat (num_packets) begin : send_process +        test_packet_t packet_a, packet_b; +        int packet_length; + +        packet_length = $urandom_range(1, max_spp); + +        // Generate random data and header +        packet_a.samples = {}; +        packet_b.samples = {}; +        for (int i = 0; i < packet_length; i++) begin +          packet_a.samples.push_back($urandom()); +          packet_b.samples.push_back($urandom()); +        end + +        // Generate random metadata +        packet_a.mdata = {}; +        packet_b.mdata = {}; +        for (int i = 0; i < $urandom_range(0,31); i++) +          packet_a.mdata.push_back(Rand #(CHDR_W)::rand_logic()); +        for (int i = 0; i < $urandom_range(0,31); i++) +          packet_b.mdata.push_back(Rand #(CHDR_W)::rand_logic()); + +        // Generate random header info +        packet_a.pkt_info = Rand #($bits(packet_a.pkt_info))::rand_logic(); +        packet_b.pkt_info = Rand #($bits(packet_b.pkt_info))::rand_logic(); + +        // Enqueue the packets for each port +        blk_ctrl.send_items(IN_PORT_A, packet_a.samples, packet_a.mdata, packet_a.pkt_info); +        blk_ctrl.send_items(IN_PORT_B, packet_b.samples, packet_b.mdata, packet_b.pkt_info); + +        // Enqueue what we sent for the receiver to check the output +        packets_mb_a.put(packet_a); +        packets_mb_b.put(packet_b); +      end +      repeat (num_packets) begin : recv_process +        test_packet_t packet_a, packet_b, packet_add, packet_sub; +        string str; + +        // Grab the next pair of packets that was input +        packets_mb_a.get(packet_a); +        packets_mb_b.get(packet_b); + +        // Receive a packet from each port +        blk_ctrl.recv_items_adv(OUT_PORT_SUM, packet_add.samples, +          packet_add.mdata, packet_add.pkt_info); +        blk_ctrl.recv_items_adv(OUT_PORT_DIFF, packet_sub.samples, +          packet_sub.mdata, packet_sub.pkt_info); + +        // Make sure both output packets have the same length +        `ASSERT_ERROR(packet_add.samples.size() == packet_sub.samples.size(), +          "ADD and SUB packets were not the same length"); + +        // Make sure the output packet length matches the A input +        `ASSERT_ERROR(packet_a.samples.size() == packet_add.samples.size(), +          "Output packet length didn't match A input"); + +        // Check that the output packet header info matches the A input +        `ASSERT_ERROR(packet_info_equal(packet_a.pkt_info, packet_add.pkt_info), +          "ADD output header info didn't match A input"); +        `ASSERT_ERROR(packet_info_equal(packet_a.pkt_info, packet_sub.pkt_info), +          "SUB output header info didn't match A input"); + +        // Check the metdata +        `ASSERT_ERROR(ChdrData #(CHDR_W)::chdr_equal(packet_a.mdata, packet_add.mdata), +          "ADD metadata info didn't match A input"); +        `ASSERT_ERROR(ChdrData #(CHDR_W)::chdr_equal(packet_a.mdata, packet_sub.mdata), +          "SUB metadata info didn't match A input"); + +        // Verify that the data has the expected values +        for (int i = 0; i < packet_add.samples.size(); i++) begin +          sc16_t a, b, a_plus_b, a_min_b, add, sub; + +          // Grab the input and output samples +          a    = packet_a.samples[i]; +          b    = packet_b.samples[i]; +          add  = packet_add.samples[i]; +          sub  = packet_sub.samples[i]; + +          // Compute expected sum and difference +          a_plus_b.i = a.i + b.i; +          a_plus_b.q = a.q + b.q; +          a_min_b.i  = a.i - b.i; +          a_min_b.q  = a.q - b.q; + +          // Check that the results match +          $sformat(str, +            "Incorrect value received on ADD output! Expected: 0x%X, Received: 0x%X", +            a_plus_b, add); +          `ASSERT_ERROR(add == a_plus_b, str); +          $sformat(str, +            "Incorrect value received on SUB output! Expected: 0x%X, Received: 0x%X", +            a_min_b, sub); +          `ASSERT_ERROR(sub == a_min_b, str); +        end +      end +    join +  endtask : test_rand + + +  //--------------------------------------------------------------------------- +  // Main Test Process +  //--------------------------------------------------------------------------- + +  initial begin : tb_main + +    // Initialize the test exec object for this testbench +    test.start_tb("rfnoc_block_addsub_tb"); + +    // Don't start the clocks until after start_tb() returns. This ensures that +    // the clocks aren't toggling while other instances of this testbench are +    // running, which speeds up simulation time. +    rfnoc_chdr_clk_gen.start(); +    rfnoc_ctrl_clk_gen.start(); +    ce_clk_gen.start(); + +    // Start the BFMs running +    blk_ctrl.run(); + +    //-------------------------------- +    // Reset +    //-------------------------------- + +    test.start_test("Flush block then reset it", 10us); +    blk_ctrl.flush_and_reset(); +    test.end_test(); + +    //-------------------------------- +    // Verify Block Info +    //-------------------------------- + +    test.start_test("Verify Block Info", 2us); +    `ASSERT_ERROR(blk_ctrl.get_noc_id() == NOC_ID, "Incorrect NOC_ID Value"); +    `ASSERT_ERROR(blk_ctrl.get_num_data_i() == NUM_PORTS_I, "Incorrect NUM_DATA_I Value"); +    `ASSERT_ERROR(blk_ctrl.get_num_data_o() == NUM_PORTS_O, "Incorrect NUM_DATA_O Value"); +    `ASSERT_ERROR(blk_ctrl.get_mtu() == MTU, "Incorrect MTU Value"); +    test.end_test(); + +    //-------------------------------- +    // Test Sequences +    //-------------------------------- + +    begin +      const int NUM_PACKETS = 100; + +      test.start_test("Test random packets", 1ms); +      test_rand(NUM_PACKETS); +      test.end_test(); + +      test.start_test("Test without back pressure", 1ms); +      test_rand(NUM_PACKETS, SPP, 0, 0, 0, 0); +      test.end_test(); + +      test.start_test("Test back pressure", 1ms); +      test_rand(NUM_PACKETS, SPP, 25, 25, 50, 50); +      test.end_test(); + +      test.start_test("Test underflow", 1ms); +      test_rand(NUM_PACKETS, SPP, 50, 50, 25, 25); +      test.end_test(); + +      test.start_test("Test min packet size", 1ms); +      test_rand(10, 1); +      test.end_test(); +    end + +    //-------------------------------- +    // Finish Up +    //-------------------------------- + +    // 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 +    rfnoc_chdr_clk_gen.kill(); +    rfnoc_ctrl_clk_gen.kill(); +    ce_clk_gen.kill(); + +  end : tb_main + +endmodule : rfnoc_block_addsub_tb + + +`default_nettype wire diff --git a/host/include/uhd/rfnoc/blocks/addsub.yml b/host/include/uhd/rfnoc/blocks/addsub.yml new file mode 100644 index 000000000..6e1bd671e --- /dev/null +++ b/host/include/uhd/rfnoc/blocks/addsub.yml @@ -0,0 +1,62 @@ +schema: rfnoc_modtool_args +module_name: addsub +version: 1.0 +rfnoc_version: 1.0 +chdr_width: 64 +noc_id: 0xADD00000 + +parameters: +  USE_IMPL: '"Verilog"' + +clocks: +  - name: rfnoc_chdr +    freq: "[]" +  - name: rfnoc_ctrl +    freq: "[]" +  - name: ce +    freq: "[]" + +control: +  sw_iface: nocscript +  fpga_iface: axis_ctrl +  interface_direction: slave +  fifo_depth: 2 +  clk_domain: rfnoc_ctrl + +data: +  fpga_iface: axis_pyld_ctxt +  clk_domain: ce +  inputs: +    in_a: +      item_width: 32 +      nipc: 1 +      context_fifo_depth: 2 +      payload_fifo_depth: 2 +      format: sc16 +      mdata_sig: ~ +    in_b: +      item_width: 32 +      nipc: 1 +      context_fifo_depth: 2 +      payload_fifo_depth: 2 +      format: sc16 +      mdata_sig: ~ +  outputs: +    add: +      item_width: 32 +      nipc: 1 +      context_fifo_depth: 2 +      payload_fifo_depth: 2 +      format: sc16 +      mdata_sig: ~ +    sub: +      item_width: 32 +      nipc: 1 +      context_fifo_depth: 2 +      payload_fifo_depth: 2 +      format: sc16 +      mdata_sig: ~ + +registers: + +properties:  | 
