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: |