diff options
8 files changed, 1162 insertions, 0 deletions
diff --git a/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_switchboard/Makefile b/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_switchboard/Makefile new file mode 100644 index 000000000..7615450b6 --- /dev/null +++ b/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_switchboard/Makefile @@ -0,0 +1,44 @@ +# +# 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_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 Makefile.srcs + +DESIGN_SRCS += $(abspath \ +$(RFNOC_CORE_SRCS) \ +$(RFNOC_UTIL_SRCS) \ +$(RFNOC_OOT_SRCS)  \ +) + +#------------------------------------------------- +# Testbench Specific +#------------------------------------------------- +SIM_TOP = rfnoc_block_switchboard_all_tb +SIM_SRCS = \ +$(abspath rfnoc_block_switchboard_tb.sv) \ +$(abspath rfnoc_block_switchboard_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_switchboard/Makefile.srcs b/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_switchboard/Makefile.srcs new file mode 100644 index 000000000..2b44c0416 --- /dev/null +++ b/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_switchboard/Makefile.srcs @@ -0,0 +1,23 @@ +# +# 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_switchboard.v \ +rfnoc_block_switchboard_regs.vh \ +noc_shell_switchboard.v \ +) diff --git a/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_switchboard/noc_shell_switchboard.v b/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_switchboard/noc_shell_switchboard.v new file mode 100644 index 000000000..9d66ad908 --- /dev/null +++ b/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_switchboard/noc_shell_switchboard.v @@ -0,0 +1,247 @@ +// +// Copyright 2020 Ettus Research, a National Instruments Brand +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// +// Module: noc_shell_switchboard +// +// Description: +// +//   This is a tool-generated NoC-shell for the switchboard 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_switchboard #( +  parameter [9:0] THIS_PORTID     = 10'd0, +  parameter       CHDR_W          = 64, +  parameter [5:0] MTU             = 10, +  parameter       NUM_INPUTS      = 1, +  parameter       NUM_OUTPUTS     = 1 +) ( +  //--------------------- +  // Framework Interface +  //--------------------- + +  // RFNoC Framework Clocks +  input  wire rfnoc_chdr_clk, +  input  wire rfnoc_ctrl_clk, + +  // NoC Shell Generated Resets +  output wire rfnoc_chdr_rst, +  output wire rfnoc_ctrl_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 [(NUM_INPUTS)*CHDR_W-1:0] s_rfnoc_chdr_tdata, +  input  wire [(NUM_INPUTS)-1:0]        s_rfnoc_chdr_tlast, +  input  wire [(NUM_INPUTS)-1:0]        s_rfnoc_chdr_tvalid, +  output wire [(NUM_INPUTS)-1:0]        s_rfnoc_chdr_tready, +  // AXIS-CHDR Output Ports (to framework) +  output wire [(NUM_OUTPUTS)*CHDR_W-1:0] m_rfnoc_chdr_tdata, +  output wire [(NUM_OUTPUTS)-1:0]        m_rfnoc_chdr_tlast, +  output wire [(NUM_OUTPUTS)-1:0]        m_rfnoc_chdr_tvalid, +  input  wire [(NUM_OUTPUTS)-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 +  //--------------------- + +  // CtrlPort Clock and Reset +  output wire               ctrlport_clk, +  output wire               ctrlport_rst, +  // CtrlPort Master +  output wire               m_ctrlport_req_wr, +  output wire               m_ctrlport_req_rd, +  output wire [19:0]        m_ctrlport_req_addr, +  output wire [31:0]        m_ctrlport_req_data, +  input  wire               m_ctrlport_resp_ack, +  input  wire [31:0]        m_ctrlport_resp_data, + +  // AXIS-CHDR Clock and Reset +  output wire               axis_chdr_clk, +  output wire               axis_chdr_rst, +  // Framework to User Logic: in +  output wire [NUM_INPUTS*CHDR_W-1:0]  m_in_chdr_tdata, +  output wire [NUM_INPUTS-1:0]         m_in_chdr_tlast, +  output wire [NUM_INPUTS-1:0]         m_in_chdr_tvalid, +  input  wire [NUM_INPUTS-1:0]         m_in_chdr_tready, +  // User Logic to Framework: out +  input  wire [NUM_OUTPUTS*CHDR_W-1:0]  s_out_chdr_tdata, +  input  wire [NUM_OUTPUTS-1:0]         s_out_chdr_tlast, +  input  wire [NUM_OUTPUTS-1:0]         s_out_chdr_tvalid, +  output wire [NUM_OUTPUTS-1:0]         s_out_chdr_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'hBE110000), +    .NUM_DATA_I    (NUM_INPUTS), +    .NUM_DATA_O    (NUM_OUTPUTS), +    .CTRL_FIFOSIZE ($clog2(32)), +    .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) +  ); + +  //--------------------------------------------------------------------------- +  //  Control Path +  //--------------------------------------------------------------------------- + +  assign ctrlport_clk = rfnoc_chdr_clk; +  assign ctrlport_rst = rfnoc_chdr_rst; + +  ctrlport_endpoint #( +    .THIS_PORTID      (THIS_PORTID), +    .SYNC_CLKS        (0), +    .AXIS_CTRL_MST_EN (0), +    .AXIS_CTRL_SLV_EN (1), +    .SLAVE_FIFO_SIZE  ($clog2(32)) +  ) ctrlport_endpoint_i ( +    .rfnoc_ctrl_clk            (rfnoc_ctrl_clk), +    .rfnoc_ctrl_rst            (rfnoc_ctrl_rst), +    .ctrlport_clk              (ctrlport_clk), +    .ctrlport_rst              (ctrlport_rst), +    .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), +    .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), +    .m_ctrlport_req_wr         (m_ctrlport_req_wr), +    .m_ctrlport_req_rd         (m_ctrlport_req_rd), +    .m_ctrlport_req_addr       (m_ctrlport_req_addr), +    .m_ctrlport_req_data       (m_ctrlport_req_data), +    .m_ctrlport_req_byte_en    (), +    .m_ctrlport_req_has_time   (), +    .m_ctrlport_req_time       (), +    .m_ctrlport_resp_ack       (m_ctrlport_resp_ack), +    .m_ctrlport_resp_status    (2'b0), +    .m_ctrlport_resp_data      (m_ctrlport_resp_data), +    .s_ctrlport_req_wr         (1'b0), +    .s_ctrlport_req_rd         (1'b0), +    .s_ctrlport_req_addr       (20'b0), +    .s_ctrlport_req_portid     (10'b0), +    .s_ctrlport_req_rem_epid   (16'b0), +    .s_ctrlport_req_rem_portid (10'b0), +    .s_ctrlport_req_data       (32'b0), +    .s_ctrlport_req_byte_en    (4'hF), +    .s_ctrlport_req_has_time   (1'b0), +    .s_ctrlport_req_time       (64'b0), +    .s_ctrlport_resp_ack       (), +    .s_ctrlport_resp_status    (), +    .s_ctrlport_resp_data      () +  ); + +  //--------------------------------------------------------------------------- +  //  Data Path +  //--------------------------------------------------------------------------- + +  genvar i; + +  assign axis_chdr_clk = rfnoc_chdr_clk; +  assign axis_chdr_rst = rfnoc_chdr_rst; + +  //--------------------- +  // Input Data Paths +  //--------------------- + +  for (i = 0; i < NUM_INPUTS; i = i + 1) begin: gen_input_in +    chdr_to_chdr_data #( +      .CHDR_W (CHDR_W) +    ) chdr_to_chdr_data_in_in ( +      .axis_chdr_clk      (rfnoc_chdr_clk), +      .axis_chdr_rst      (rfnoc_chdr_rst), +      .s_axis_chdr_tdata  (s_rfnoc_chdr_tdata[(i)*CHDR_W+:CHDR_W]), +      .s_axis_chdr_tlast  (s_rfnoc_chdr_tlast[i]), +      .s_axis_chdr_tvalid (s_rfnoc_chdr_tvalid[i]), +      .s_axis_chdr_tready (s_rfnoc_chdr_tready[i]), +      .m_axis_chdr_tdata  (m_in_chdr_tdata[i*CHDR_W+:CHDR_W]), +      .m_axis_chdr_tlast  (m_in_chdr_tlast[i]), +      .m_axis_chdr_tvalid (m_in_chdr_tvalid[i]), +      .m_axis_chdr_tready (m_in_chdr_tready[i]), +      .flush_en           (data_i_flush_en), +      .flush_timeout      (data_i_flush_timeout), +      .flush_active       (data_i_flush_active[i]), +      .flush_done         (data_i_flush_done[i]) +    ); +  end + +  //--------------------- +  // Output Data Paths +  //--------------------- + +  for (i = 0; i < NUM_OUTPUTS; i = i + 1) begin: gen_output_out +    chdr_to_chdr_data #( +      .CHDR_W (CHDR_W) +    ) chdr_to_chdr_data_out_out ( +      .axis_chdr_clk      (rfnoc_chdr_clk), +      .axis_chdr_rst      (rfnoc_chdr_rst), +      .m_axis_chdr_tdata  (m_rfnoc_chdr_tdata[(i)*CHDR_W+:CHDR_W]), +      .m_axis_chdr_tlast  (m_rfnoc_chdr_tlast[i]), +      .m_axis_chdr_tvalid (m_rfnoc_chdr_tvalid[i]), +      .m_axis_chdr_tready (m_rfnoc_chdr_tready[i]), +      .s_axis_chdr_tdata  (s_out_chdr_tdata[i*CHDR_W+:CHDR_W]), +      .s_axis_chdr_tlast  (s_out_chdr_tlast[i]), +      .s_axis_chdr_tvalid (s_out_chdr_tvalid[i]), +      .s_axis_chdr_tready (s_out_chdr_tready[i]), +      .flush_en           (data_o_flush_en), +      .flush_timeout      (data_o_flush_timeout), +      .flush_active       (data_o_flush_active[i]), +      .flush_done         (data_o_flush_done[i]) +    ); +  end + +endmodule // noc_shell_switchboard + + +`default_nettype wire diff --git a/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_switchboard/rfnoc_block_switchboard.v b/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_switchboard/rfnoc_block_switchboard.v new file mode 100644 index 000000000..3308b8260 --- /dev/null +++ b/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_switchboard/rfnoc_block_switchboard.v @@ -0,0 +1,328 @@ +// +// Copyright 2020 Ettus Research, a National Instruments Brand +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// +// Module: rfnoc_block_switchboard +// +// Description: +// +//   The Switchboard RFNoC block routes any input CHDR stream to any output port. +//   Routing is 1 to 1, that is, an input port can only be connected to one +//   output port, and vice versa. Data sent on disconnected inputs will stall. +// +//       Input Port                        Output Port +//               ┌───────┐            ┌───────┐ +//               │       ├────────────┤       │ +//           0 ──┤ Demux │    ┌───────┤  Mux  ├─ 0 +//               │       ├─┐  │  ┌────┤       │ +//               └───────┘ │  │  │    └───────┘ +//               ┌───────┐ │  │  │ +//               │       ├─┼──┘  │    ┌───────┐ +//           1 ──┤ Demux │ └─────┼────┤       │ +//               │       ├───────┼────┤  Mux  ├─ 1 +//               └───────┘       │  ┌─┤       │ +//               ┌───────┐       │  │ └───────┘ +//               │       ├───────┘  │ +//           2 ──┤ Demux │          │ +//               │       ├──────────┘ +//               └───────┘ +// 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). +//   NUM_INPUTS  : The number of input ports +//   NUM_OUTPUTS : The number of output ports +// + +`default_nettype none + + +module rfnoc_block_switchboard #( +  parameter [9:0] THIS_PORTID     = 10'd0, +  parameter       CHDR_W          = 64, +  parameter [5:0] MTU             = 10, +  parameter       NUM_INPUTS      = 1, +  parameter       NUM_OUTPUTS     = 1 +)( +  // RFNoC Framework Clocks and Resets +  input  wire                   rfnoc_chdr_clk, +  input  wire                   rfnoc_ctrl_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 [(NUM_INPUTS)*CHDR_W-1:0] s_rfnoc_chdr_tdata, +  input  wire [(NUM_INPUTS)-1:0]        s_rfnoc_chdr_tlast, +  input  wire [(NUM_INPUTS)-1:0]        s_rfnoc_chdr_tvalid, +  output wire [(NUM_INPUTS)-1:0]        s_rfnoc_chdr_tready, +  // AXIS-CHDR Output Ports (to framework) +  output wire [(NUM_OUTPUTS)*CHDR_W-1:0] m_rfnoc_chdr_tdata, +  output wire [(NUM_OUTPUTS)-1:0]        m_rfnoc_chdr_tlast, +  output wire [(NUM_OUTPUTS)-1:0]        m_rfnoc_chdr_tvalid, +  input  wire [(NUM_OUTPUTS)-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 +); + +  //--------------------------------------------------------------------------- +  // Signal Declarations +  //--------------------------------------------------------------------------- + +  // Clocks and Resets +  wire               ctrlport_clk; +  wire               ctrlport_rst; +  wire               axis_chdr_clk; +  wire               axis_chdr_rst; +  // CtrlPort Master +  wire               m_ctrlport_req_wr; +  wire               m_ctrlport_req_rd; +  wire [19:0]        m_ctrlport_req_addr; +  wire [31:0]        m_ctrlport_req_data; +  reg                m_ctrlport_resp_ack; +  reg [31:0]         m_ctrlport_resp_data; +  // Framework to User Logic: in +  wire [NUM_INPUTS*CHDR_W-1:0]  m_in_chdr_tdata; +  wire [NUM_INPUTS-1:0]         m_in_chdr_tlast; +  wire [NUM_INPUTS-1:0]         m_in_chdr_tvalid; +  wire [NUM_INPUTS-1:0]         m_in_chdr_tready; +  // User Logic to Framework: out +  wire [NUM_OUTPUTS*CHDR_W-1:0]  s_out_chdr_tdata; +  wire [NUM_OUTPUTS-1:0]         s_out_chdr_tlast; +  wire [NUM_OUTPUTS-1:0]         s_out_chdr_tvalid; +  wire [NUM_OUTPUTS-1:0]         s_out_chdr_tready; + +  //--------------------------------------------------------------------------- +  // NoC Shell +  //--------------------------------------------------------------------------- + +  noc_shell_switchboard #( +    .CHDR_W              (CHDR_W), +    .THIS_PORTID         (THIS_PORTID), +    .MTU                 (MTU), +    .NUM_INPUTS          (NUM_INPUTS), +    .NUM_OUTPUTS         (NUM_OUTPUTS) +  ) noc_shell_switchboard_i ( +    //--------------------- +    // Framework Interface +    //--------------------- + +    // Clock Inputs +    .rfnoc_chdr_clk      (rfnoc_chdr_clk), +    .rfnoc_ctrl_clk      (rfnoc_ctrl_clk), +    // Reset Outputs +    .rfnoc_chdr_rst      (), +    .rfnoc_ctrl_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 +    //--------------------- + +    // CtrlPort Clock and Reset +    .ctrlport_clk              (ctrlport_clk), +    .ctrlport_rst              (ctrlport_rst), +    // CtrlPort Master +    .m_ctrlport_req_wr         (m_ctrlport_req_wr), +    .m_ctrlport_req_rd         (m_ctrlport_req_rd), +    .m_ctrlport_req_addr       (m_ctrlport_req_addr), +    .m_ctrlport_req_data       (m_ctrlport_req_data), +    .m_ctrlport_resp_ack       (m_ctrlport_resp_ack), +    .m_ctrlport_resp_data      (m_ctrlport_resp_data), + +    // AXIS-CHDR Clock and Reset +    .axis_chdr_clk (axis_chdr_clk), +    .axis_chdr_rst (axis_chdr_rst), +    // AXIS-CHDR to User Logic +    .m_in_chdr_tdata  (m_in_chdr_tdata), +    .m_in_chdr_tlast  (m_in_chdr_tlast), +    .m_in_chdr_tvalid (m_in_chdr_tvalid), +    .m_in_chdr_tready (m_in_chdr_tready), +    // AXIS-CHDR from User Logic +    .s_out_chdr_tdata  (s_out_chdr_tdata), +    .s_out_chdr_tlast  (s_out_chdr_tlast), +    .s_out_chdr_tvalid (s_out_chdr_tvalid), +    .s_out_chdr_tready (s_out_chdr_tready) +  ); + +  //--------------------------------------------------------------------------- +  // Registers +  //--------------------------------------------------------------------------- + +  `include "rfnoc_block_switchboard_regs.vh" + +  localparam INPUT_W    = (NUM_INPUTS < 3) ? 1 : $clog2(NUM_INPUTS); +  localparam OUTPUT_W   = (NUM_OUTPUTS < 3) ? 1 : $clog2(NUM_OUTPUTS); +  localparam MAX_W      = (INPUT_W > OUTPUT_W) ? INPUT_W : OUTPUT_W; +  reg [NUM_INPUTS*OUTPUT_W-1:0] reg_demux_select    = 0; +  reg [NUM_OUTPUTS*INPUT_W-1:0] reg_mux_select      = 0; + +  wire [MAX_W-1:0] addr_port; +  wire [SWITCH_ADDR_W-1:0] addr_offset; +  assign addr_port =  +    (NUM_OUTPUTS < 2) ? 0 : m_ctrlport_req_addr[SWITCH_ADDR_W +: MAX_W]; +  assign addr_offset = m_ctrlport_req_addr[0 +: SWITCH_ADDR_W]; + +  always @(posedge ctrlport_clk) begin +    if (ctrlport_rst) begin +      m_ctrlport_resp_ack    <= 0; +      m_ctrlport_resp_data   <= 'bX; +      reg_demux_select <= 0; +      reg_mux_select <= 0; +     +    end else begin +      // Default assignments +      m_ctrlport_resp_ack    <= 0; +      m_ctrlport_resp_data   <= 0; + +      // Handle register reads +      if (m_ctrlport_req_rd) begin +        m_ctrlport_resp_ack <= 1; +        case (addr_offset) +          REG_DEMUX_SELECT  : m_ctrlport_resp_data[0 +: OUTPUT_W] +            <= reg_demux_select[addr_port*OUTPUT_W +: OUTPUT_W]; +          REG_MUX_SELECT    : m_ctrlport_resp_data[0 +: INPUT_W]  +            <= reg_mux_select[addr_port*INPUT_W +: INPUT_W]; +        endcase +       +      // Handle register writes +      end else if (m_ctrlport_req_wr) begin +        m_ctrlport_resp_ack <= 1; +        case (addr_offset) +          REG_DEMUX_SELECT  : reg_demux_select[addr_port*OUTPUT_W +: OUTPUT_W] +            <= m_ctrlport_req_data[0 +: OUTPUT_W]; +          REG_MUX_SELECT    : reg_mux_select[addr_port*INPUT_W +: INPUT_W]  +            <= m_ctrlport_req_data[0 +: INPUT_W]; +        endcase +      end +    end +  end + +  //--------------------------------------------------------------------------- +  // User Logic +  //--------------------------------------------------------------------------- + +  wire [NUM_OUTPUTS*CHDR_W-1:0] tdata_demux [NUM_INPUTS-1:0]; +  wire [NUM_OUTPUTS-1:0]        tlast_demux [NUM_INPUTS-1:0]; +  wire [NUM_OUTPUTS-1:0]        tvalid_demux [NUM_INPUTS-1:0]; +  wire [NUM_OUTPUTS-1:0]        tready_demux [NUM_INPUTS-1:0]; + +  wire [NUM_INPUTS*CHDR_W-1:0]  tdata_mux [NUM_OUTPUTS-1:0]; +  wire [NUM_INPUTS-1:0]         tlast_mux [NUM_OUTPUTS-1:0]; +  wire [NUM_INPUTS-1:0]         tvalid_mux [NUM_OUTPUTS-1:0]; +  wire [NUM_INPUTS-1:0]         tready_mux [NUM_OUTPUTS-1:0]; + +  generate +    genvar in_m; +    genvar out_m; +    for (in_m = 0; in_m < NUM_INPUTS; in_m = in_m + 1) begin : gen_medium_in +      for (out_m = 0; out_m < NUM_OUTPUTS; out_m = out_m + 1) begin : gen_medium_out +        assign tdata_mux[out_m][in_m*CHDR_W +: CHDR_W] +          = tdata_demux[in_m][out_m*CHDR_W +: CHDR_W]; +        assign tlast_mux[out_m][in_m] = tlast_demux[in_m][out_m]; +        assign tvalid_mux[out_m][in_m] = tvalid_demux[in_m][out_m]; +        assign tready_demux[in_m][out_m] = tready_mux[out_m][in_m]; +      end +    end +   +    genvar in;   +    if (NUM_OUTPUTS < 2) begin : gen_static_in +      for (in = 0; in < NUM_INPUTS; in = in + 1) begin : gen_static_in_loop +        assign tdata_demux[in] = m_in_chdr_tdata[in*CHDR_W +: CHDR_W]; +        assign tlast_demux[in] = m_in_chdr_tlast[in]; +        assign tvalid_demux[in] = m_in_chdr_tvalid[in]; +        assign m_in_chdr_tready[in] = tready_demux[in]; +      end +   +    end else begin : gen_demux +      for (in = 0; in < NUM_INPUTS; in = in + 1) begin : gen_demux_loop +        axi_demux #( +          .WIDTH(CHDR_W), +          .SIZE(NUM_OUTPUTS) +        ) axi_demux_i ( +          .clk(axis_chdr_clk), +          .reset(axis_chdr_rst), +          .clear(1'b0), +          .header(), +          .dest(reg_demux_select[in*OUTPUT_W +: OUTPUT_W]), +          .i_tdata(m_in_chdr_tdata[in*CHDR_W +: CHDR_W]), +          .i_tlast(m_in_chdr_tlast[in]), +          .i_tvalid(m_in_chdr_tvalid[in]), +          .i_tready(m_in_chdr_tready[in]), +          .o_tdata(tdata_demux[in]), +          .o_tlast(tlast_demux[in]), +          .o_tvalid(tvalid_demux[in]), +          .o_tready(tready_demux[in]) +        ); +      end +    end +   +    genvar out; +    if (NUM_INPUTS < 2) begin : gen_static_out +      for (out = 0; out < NUM_OUTPUTS; out = out + 1) begin : gen_static_out_loop +        assign s_out_chdr_tdata[out*CHDR_W +: CHDR_W] = tdata_mux[out]; +        assign s_out_chdr_tlast[out] = tlast_mux[out]; +        assign s_out_chdr_tvalid[out] = tvalid_mux[out]; +        assign tready_mux[out] = s_out_chdr_tready[out]; +      end +   +    end else begin : gen_mux +      for (out = 0; out < NUM_OUTPUTS; out = out + 1) begin : gen_mux_loop +        axi_mux_select #( +          .WIDTH(CHDR_W), +          .SWITCH_ON_LAST(1'b0), +          .SIZE(NUM_INPUTS) +        ) axi_mux_select_i ( +          .clk(axis_chdr_clk), +          .reset(axis_chdr_rst), +          .clear(1'b0), +        .select(reg_mux_select[out*INPUT_W +: INPUT_W]), +          .i_tdata(tdata_mux[out]), +          .i_tlast(tlast_mux[out]), +          .i_tvalid(tvalid_mux[out]), +          .i_tready(tready_mux[out]), +          .o_tdata(s_out_chdr_tdata[out*CHDR_W +: CHDR_W]), +          .o_tlast(s_out_chdr_tlast[out]), +          .o_tvalid(s_out_chdr_tvalid[out]), +          .o_tready(s_out_chdr_tready[out]) +        ); +      end +    end +  endgenerate + +endmodule // rfnoc_block_switchboard + + +`default_nettype wire diff --git a/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_switchboard/rfnoc_block_switchboard_all_tb.sv b/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_switchboard/rfnoc_block_switchboard_all_tb.sv new file mode 100644 index 000000000..cb6c73618 --- /dev/null +++ b/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_switchboard/rfnoc_block_switchboard_all_tb.sv @@ -0,0 +1,37 @@ +// +// Copyright 2020 Ettus Research, a National Instruments Brand +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// +// Module: rfnoc_block_switchboard_all_tb +// +// Description: +// +// Top-level testbench for the Switchboard RFNoC block. This instantiates +// rfnoc_block_switchboard_tb with different parameters to test multiple  +// configurations. +// + +`default_nettype none + + +module rfnoc_block_switchboard_all_tb; + +  // Standard test: +  rfnoc_block_switchboard_tb #(.CHDR_W( 64), .NUM_INPUTS(2), .NUM_OUTPUTS(2)) dut_0 (); +  // Multiplexer test: +  rfnoc_block_switchboard_tb #(.CHDR_W( 64), .NUM_INPUTS(2), .NUM_OUTPUTS(1)) dut_1 (); +  // Demultiplexer test: +  rfnoc_block_switchboard_tb #(.CHDR_W( 64), .NUM_INPUTS(1), .NUM_OUTPUTS(2)) dut_2 (); +  // Test multiple ports: +  rfnoc_block_switchboard_tb #(.CHDR_W( 64), .NUM_INPUTS(3), .NUM_OUTPUTS(9)) dut_3 (); +  rfnoc_block_switchboard_tb #(.CHDR_W( 64), .NUM_INPUTS(4), .NUM_OUTPUTS(12)) dut_4 (); +  rfnoc_block_switchboard_tb #(.CHDR_W( 64), .NUM_INPUTS(8), .NUM_OUTPUTS(4)) dut_5 (); +  // Test CHDR_W > 64: +  rfnoc_block_switchboard_tb #(.CHDR_W(128), .NUM_INPUTS(2), .NUM_OUTPUTS(2)) dut_6 (); +  rfnoc_block_switchboard_tb #(.CHDR_W(128), .NUM_INPUTS(16), .NUM_OUTPUTS(16)) dut_7 (); + +endmodule : rfnoc_block_switchboard_all_tb + + +`default_nettype wire diff --git a/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_switchboard/rfnoc_block_switchboard_regs.vh b/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_switchboard/rfnoc_block_switchboard_regs.vh new file mode 100644 index 000000000..336766659 --- /dev/null +++ b/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_switchboard/rfnoc_block_switchboard_regs.vh @@ -0,0 +1,29 @@ +// +// Copyright 2020 Ettus Research, a National Instruments Brand +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// +// Module:  rfnoc_block_switchboard_regs (Header) +// +// Description:  Register definitions for the switchboard RFNoC block. +// + +//----------------------------------------------------------------------------- +// Register Space +//----------------------------------------------------------------------------- + +// The amount of address space taken up by each switchboard port. +// That is, the address space for output port N starts at N*(2^SWITCH_ADDR_W). +localparam SWITCH_ADDR_W = 'h3; + +// REG_DEMUX_SELECT (R/W) +// +// Contains the zero-index of which output port each demux is connected to. +// +localparam REG_DEMUX_SELECT = 'h0; + +// REG_MUX_SELECT (R/W) +// +// Contains the zero-index of which input port each mux is connected to. +// +localparam REG_MUX_SELECT = 'h4; diff --git a/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_switchboard/rfnoc_block_switchboard_tb.sv b/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_switchboard/rfnoc_block_switchboard_tb.sv new file mode 100644 index 000000000..5a2e51233 --- /dev/null +++ b/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_switchboard/rfnoc_block_switchboard_tb.sv @@ -0,0 +1,413 @@ +// +// Copyright 2020 Ettus Research, a National Instruments Brand +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// +// Module: rfnoc_block_switchboard_tb +// +// Description: Testbench for the switchboard RFNoC block. +// + +`default_nettype none + + +module rfnoc_block_switchboard_tb #( +  parameter int CHDR_W              = 64,    // CHDR size in bits +  parameter int NUM_INPUTS          = 1, +  parameter int NUM_OUTPUTS         = 1   +); + +  `include "test_exec.svh" + +  import PkgTestExec::*; +  import PkgChdrUtils::*; +  import PkgRfnocBlockCtrlBfm::*; +  import PkgRfnocItemUtils::*; + +  `include "rfnoc_block_switchboard_regs.vh" + +  //--------------------------------------------------------------------------- +  // Testbench Configuration +  //--------------------------------------------------------------------------- + +  localparam [31:0] NOC_ID          = 32'hBE110000; +  localparam [ 9:0] THIS_PORTID     = 10'h123; +  localparam int    MTU             = 10;    // Log2 of max transmission unit in CHDR words +  localparam int    NUM_PORTS_I     = NUM_INPUTS; +  localparam int    NUM_PORTS_O     = NUM_OUTPUTS; +  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 + +  //--------------------------------------------------------------------------- +  // Clocks and Resets +  //--------------------------------------------------------------------------- + +  bit rfnoc_chdr_clk; +  bit rfnoc_ctrl_clk; + +  // Don't start the clocks automatically (AUTOSTART=0), since we expect +  // multiple instances of this testbench to run in sequence. They will be +  // started before the first test. +  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()); + +  //--------------------------------------------------------------------------- +  // 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 + +  typedef ChdrPacket #(CHDR_W) ChdrPacket_t; + +  //--------------------------------------------------------------------------- +  // 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_switchboard #( +    .THIS_PORTID         (THIS_PORTID), +    .CHDR_W              (CHDR_W), +    .MTU                 (MTU), +    .NUM_INPUTS          (NUM_INPUTS), +    .NUM_OUTPUTS         (NUM_OUTPUTS) +  ) dut ( +    .rfnoc_chdr_clk      (rfnoc_chdr_clk), +    .rfnoc_ctrl_clk      (rfnoc_ctrl_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 Tasks +  //--------------------------------------------------------------------------- + +  // Write a 32-bit register +  task automatic write_reg(int port, bit [19:0] addr, bit [31:0] value); +    blk_ctrl.reg_write((2**SWITCH_ADDR_W)*port + addr, value); +  endtask : write_reg + +  // Read a 32-bit register +  task automatic read_reg(int port, bit [19:0] addr, output logic [63:0] value); +    blk_ctrl.reg_read((2**SWITCH_ADDR_W)*port + addr, value[31:0]); +  endtask : read_reg + +  // 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 + +  // Generate a random CHDR packet with the given number of samples +  function automatic ChdrPacket_t gen_rand_chdr_pkt(int num_samps); +    ChdrPacket_t  packet = new(); +    chdr_header_t header; +    chdr_word_t   data[$]; + +    // Generate a random CHDR packet. I'm not going to randomly change the +    // timestamp or metadata, because the split-stream block doesn't look +    // at any of that. + +    // Mostly random header +    header = Rand#($bits(header))::rand_logic(); +    header.pkt_type  = CHDR_DATA_NO_TS; +    header.num_mdata = 0; +    header.length    = CHDR_W/8 + num_samps*ITEM_W/8;  // Header + payload + +    // Random payload +    repeat (num_samps * ITEM_W / CHDR_W)  +      data.push_back(Rand#(CHDR_W)::rand_logic()); +    // Round up to nearest CHDR word +    if (num_samps * ITEM_W % CHDR_W != 0) +      data.push_back(Rand#(CHDR_W)::rand_logic()); + +    // Build packet +    packet.write_raw(header, data); + +    return packet; +  endfunction : gen_rand_chdr_pkt + +  // Performs a randomized test, inputting random packets then checking the +  // outputs. +  // +  //   input_port:   Input port to use +  //   output_port:  Output port to use +  //   num_packets:  Number of packets to input +  //   max_samps:    Maximum length of packet to simulate in samples. Packet  +  //                 length is randomly chosen using a uniform distribution. +  // +  task automatic test_stream( +    int input_port    = 0, +    int output_port   = 0, +    int num_packets   = 100, +    int max_samps     = SPP +  ); +    // References to the simulation BFMs +    ChdrIfaceBfm #(CHDR_W, ITEM_W) master_bfm; +    ChdrIfaceBfm #(CHDR_W, ITEM_W) slave_bfm; + +    // Use mailbox to communicate packets between master and slave processes +    mailbox #(ChdrPacket_t) packets = new(); + +    // Grab references to the underlying CHDR BFMs +    master_bfm = blk_ctrl.get_master_data_bfm(input_port); +    slave_bfm = blk_ctrl.get_slave_data_bfm(output_port); + +    write_reg(input_port, REG_DEMUX_SELECT, output_port); +    write_reg(output_port, REG_MUX_SELECT, input_port); + +    fork +      //----------------------------------------- +      // Master +      //----------------------------------------- +      begin : master +        ChdrPacket_t packet; +        repeat (num_packets) begin +          packet = gen_rand_chdr_pkt($urandom_range(max_samps)); +          packets.put(packet); +          master_bfm.put_chdr(packet);  +        end +      end + +      //----------------------------------------- +      // Slaves +      //----------------------------------------- +      begin : slaves +        ChdrPacket_t expected, packet; + +        repeat (num_packets) begin +          // Get the expected packet from the mailbox +          packets.get(expected); +          slave_bfm.get_chdr(packet); +          `ASSERT_ERROR(packet.equal(expected), "Does not match"); +        end +      end +    join +  endtask : test_stream + +  // Tests 2 connections concurrently +  task automatic test_concurrent( +    int num_packets = 100, +    int max_samps = SPP +  ); +    fork +      begin : Stream_A +        test_stream(0, 0, num_packets, max_samps); +      end + +      begin : Stream_B +        test_stream(NUM_INPUTS-1, NUM_OUTPUTS-1, num_packets, max_samps); +      end +    join +  endtask : test_concurrent + +  // Randomized register test +  task automatic test_reg( +    int port = 0, +    int offset = 0, +    int limit = 0 +  ); +    int rand_select = $urandom_range(0, limit); +    int read_output; +    write_reg(port, offset, 0); +    read_reg(port, offset, read_output); +    `ASSERT_ERROR(read_output == 0, "Register data does not match"); + +    write_reg(port, offset, rand_select); +    read_reg(port, offset, read_output); +    `ASSERT_ERROR(read_output == rand_select, "Register data does not match"); + +    write_reg(port, offset, limit); +    read_reg(port, offset, read_output); +    `ASSERT_ERROR(read_output == limit, "Register data does not match"); +  endtask : test_reg + +  //--------------------------------------------------------------------------- +  // Main Test Process +  //--------------------------------------------------------------------------- + +  initial begin : tb_main +    string tb_name; + +    // Initialize the test exec object for this testbench +    tb_name = $sformatf( +      "rfnoc_block_switch_tb\nCHDR_W = %0D, NUM_INPUTS = %0D, NUM_OUTPUTS = %0D", +      CHDR_W, NUM_INPUTS, NUM_OUTPUTS +    ); +    test.start_tb(tb_name); + +    // 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(); + +    // 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 +    //-------------------------------- + +    // Register Test + +    test.start_test("Test Register RW", 10us); +    test_reg(0,             REG_DEMUX_SELECT,   NUM_OUTPUTS-1); +    test_reg(NUM_INPUTS-1,  REG_DEMUX_SELECT,   NUM_OUTPUTS-1); +    test_reg(0,             REG_MUX_SELECT,     NUM_INPUTS-1); +    test_reg(NUM_OUTPUTS-1, REG_MUX_SELECT,     NUM_INPUTS-1); +    test.end_test(); + +    // Stream Test + +    test.start_test("Test short packets", 1ms); +    test_stream($urandom_range(0, NUM_INPUTS-1), $urandom_range(0, NUM_OUTPUTS-1),  +      1000, 4*CHDR_W/ITEM_W); +    test_stream($urandom_range(0, NUM_INPUTS-1), $urandom_range(0, NUM_OUTPUTS-1),  +      1000, 4*CHDR_W/ITEM_W); +    test_stream($urandom_range(0, NUM_INPUTS-1), $urandom_range(0, NUM_OUTPUTS-1),  +      1000, 4*CHDR_W/ITEM_W); +    test.end_test(); + +    test.start_test("Test long packets", 1ms); +    test_stream($urandom_range(0, NUM_INPUTS-1), $urandom_range(0, NUM_OUTPUTS-1),  +      100, SPP); +    test.end_test(); + +    test.start_test("Test short packets, fast source, slow sink", 1ms); +    test_stream($urandom_range(0, NUM_INPUTS-1), $urandom_range(0, NUM_OUTPUTS-1),  +      1000, 4*CHDR_W/ITEM_W); +    test.end_test(); + +    test.start_test("Test long packets, fast source, slow sink", 1ms); +    test_stream($urandom_range(0, NUM_INPUTS-1), $urandom_range(0, NUM_OUTPUTS-1),  +      200, SPP); +    test.end_test(); + +    if(NUM_INPUTS > 1 && NUM_OUTPUTS > 1) begin +      test.start_test("Test concurrent streams", 1ms); +      test_concurrent(100, 4*CHDR_W/ITEM_W); +      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(); +  end : tb_main + +endmodule : rfnoc_block_switchboard_tb + + +`default_nettype wire diff --git a/host/include/uhd/rfnoc/blocks/switchboard.yml b/host/include/uhd/rfnoc/blocks/switchboard.yml new file mode 100644 index 000000000..d2e5665fa --- /dev/null +++ b/host/include/uhd/rfnoc/blocks/switchboard.yml @@ -0,0 +1,41 @@ +schema: rfnoc_modtool_args +module_name: switchboard +version: 1.0 +rfnoc_version: 1.0 +chdr_width: 64 +noc_id: 0xBE110000 + +parameters: +  NUM_INPUTS: 1 +  NUM_OUTPUTS: 1  + +clocks: +  - name: rfnoc_chdr +    freq: "[]" +  - name: rfnoc_ctrl +    freq: "[]" + +control: +  sw_iface: nocscript +  fpga_iface: ctrlport +  interface_direction: slave +  fifo_depth: 32 +  clk_domain: rfnoc_chdr +  ctrlport: +    byte_mode: False +    timed: False +    has_status: False + +data: +  fpga_iface: axis_chdr +  clk_domain: rfnoc_chdr +  inputs: +    in: +      num_ports: NUM_INPUTS +  outputs: +    out: +      num_ports: NUM_OUTPUTS + +registers: + +properties:  | 
