diff options
| author | Wade Fife <wade.fife@ettus.com> | 2020-05-07 14:43:32 -0500 | 
|---|---|---|
| committer | Aaron Rossetto <aaron.rossetto@ni.com> | 2020-05-19 14:22:55 -0500 | 
| commit | a40f2a4a5d04aad3ef3e222033fbacc521233782 (patch) | |
| tree | 98137f9d7e2b8a00f20b6c2dd9366185ec9bf2d1 /fpga/usrp3/lib/rfnoc | |
| parent | eb4bedf3133ce1ed275d03b36839ec61d75f2e60 (diff) | |
| download | uhd-a40f2a4a5d04aad3ef3e222033fbacc521233782.tar.gz uhd-a40f2a4a5d04aad3ef3e222033fbacc521233782.tar.bz2 uhd-a40f2a4a5d04aad3ef3e222033fbacc521233782.zip  | |
fpga: rfnoc: Add Vector IIR RFNoC block
Diffstat (limited to 'fpga/usrp3/lib/rfnoc')
7 files changed, 1393 insertions, 17 deletions
diff --git a/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_vector_iir/Makefile b/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_vector_iir/Makefile new file mode 100644 index 000000000..656b4d5c0 --- /dev/null +++ b/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_vector_iir/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. 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 Makefile.srcs + +DESIGN_SRCS += $(abspath \ +$(RFNOC_CORE_SRCS) \ +$(RFNOC_UTIL_SRCS) \ +$(RFNOC_OOT_SRCS)  \ +) + +#------------------------------------------------- +# Testbench Specific +#------------------------------------------------- +SIM_TOP = rfnoc_block_vector_iir_tb +SIM_SRCS = \ +$(abspath rfnoc_block_vector_iir_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_vector_iir/Makefile.srcs b/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_vector_iir/Makefile.srcs new file mode 100644 index 000000000..4fe877305 --- /dev/null +++ b/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_vector_iir/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_vector_iir.v \ +noc_shell_vector_iir.v \ +) diff --git a/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_vector_iir/noc_shell_vector_iir.v b/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_vector_iir/noc_shell_vector_iir.v new file mode 100644 index 000000000..959ec4124 --- /dev/null +++ b/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_vector_iir/noc_shell_vector_iir.v @@ -0,0 +1,308 @@ +// +// Copyright 2020 Ettus Research, a National Instruments Brand +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// +// Module: noc_shell_vector_iir +// +// Description: +// +//   This is a tool-generated NoC-shell for the vector_iir 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_vector_iir #( +  parameter [9:0] THIS_PORTID = 10'd0, +  parameter       CHDR_W      = 64, +  parameter [5:0] MTU         = 10, +  parameter       NUM_PORTS   = 1 +) ( +  //--------------------- +  // 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 [(0+NUM_PORTS)*CHDR_W-1:0] s_rfnoc_chdr_tdata, +  input  wire [(0+NUM_PORTS)-1:0]        s_rfnoc_chdr_tlast, +  input  wire [(0+NUM_PORTS)-1:0]        s_rfnoc_chdr_tvalid, +  output wire [(0+NUM_PORTS)-1:0]        s_rfnoc_chdr_tready, +  // AXIS-CHDR Output Ports (to framework) +  output wire [(0+NUM_PORTS)*CHDR_W-1:0] m_rfnoc_chdr_tdata, +  output wire [(0+NUM_PORTS)-1:0]        m_rfnoc_chdr_tlast, +  output wire [(0+NUM_PORTS)-1:0]        m_rfnoc_chdr_tvalid, +  input  wire [(0+NUM_PORTS)-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, + +  // AXI-Stream Payload Context Clock and Reset +  output wire               axis_data_clk, +  output wire               axis_data_rst, +  // Payload Stream to User Logic: in +  output wire [NUM_PORTS*32*1-1:0]   m_in_payload_tdata, +  output wire [NUM_PORTS*1-1:0]      m_in_payload_tkeep, +  output wire [NUM_PORTS-1:0]        m_in_payload_tlast, +  output wire [NUM_PORTS-1:0]        m_in_payload_tvalid, +  input  wire [NUM_PORTS-1:0]        m_in_payload_tready, +  // Context Stream to User Logic: in +  output wire [NUM_PORTS*CHDR_W-1:0] m_in_context_tdata, +  output wire [NUM_PORTS*4-1:0]      m_in_context_tuser, +  output wire [NUM_PORTS-1:0]        m_in_context_tlast, +  output wire [NUM_PORTS-1:0]        m_in_context_tvalid, +  input  wire [NUM_PORTS-1:0]        m_in_context_tready, +  // Payload Stream to User Logic: out +  input  wire [NUM_PORTS*32*1-1:0]   s_out_payload_tdata, +  input  wire [NUM_PORTS*1-1:0]      s_out_payload_tkeep, +  input  wire [NUM_PORTS-1:0]        s_out_payload_tlast, +  input  wire [NUM_PORTS-1:0]        s_out_payload_tvalid, +  output wire [NUM_PORTS-1:0]        s_out_payload_tready, +  // Context Stream to User Logic: out +  input  wire [NUM_PORTS*CHDR_W-1:0] s_out_context_tdata, +  input  wire [NUM_PORTS*4-1:0]      s_out_context_tuser, +  input  wire [NUM_PORTS-1:0]        s_out_context_tlast, +  input  wire [NUM_PORTS-1:0]        s_out_context_tvalid, +  output wire [NUM_PORTS-1:0]        s_out_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'h11120000), +    .NUM_DATA_I    (0+NUM_PORTS), +    .NUM_DATA_O    (0+NUM_PORTS), +    .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) +  ); + +  //--------------------------------------------------------------------------- +  //  Reset Generation +  //--------------------------------------------------------------------------- + +  wire ce_rst_pulse; + +  pulse_synchronizer #(.MODE ("POSEDGE")) pulse_synchronizer_ce ( +    .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(ce_clk), .rst(1'b0), +    .pulse_in(ce_rst_pulse), .pulse_out(ce_rst) +  ); + +  //--------------------------------------------------------------------------- +  //  Control Path +  //--------------------------------------------------------------------------- + +  assign ctrlport_clk = ce_clk; +  assign ctrlport_rst = ce_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_data_clk = ce_clk; +  assign axis_data_rst = ce_rst; + +  //--------------------- +  // Input Data Paths +  //--------------------- + +  for (i = 0; i < NUM_PORTS; i = i + 1) begin: gen_input_in +    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(32)), +      .CONTEXT_PREFETCH_EN (1) +    ) chdr_to_axis_pyld_ctxt_in_in ( +      .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+i)*CHDR_W)+:CHDR_W]), +      .s_axis_chdr_tlast     (s_rfnoc_chdr_tlast[0+i]), +      .s_axis_chdr_tvalid    (s_rfnoc_chdr_tvalid[0+i]), +      .s_axis_chdr_tready    (s_rfnoc_chdr_tready[0+i]), +      .m_axis_payload_tdata  (m_in_payload_tdata[(32*1)*i+:(32*1)]), +      .m_axis_payload_tkeep  (m_in_payload_tkeep[1*i+:1]), +      .m_axis_payload_tlast  (m_in_payload_tlast[i]), +      .m_axis_payload_tvalid (m_in_payload_tvalid[i]), +      .m_axis_payload_tready (m_in_payload_tready[i]), +      .m_axis_context_tdata  (m_in_context_tdata[CHDR_W*i+:CHDR_W]), +      .m_axis_context_tuser  (m_in_context_tuser[4*i+:4]), +      .m_axis_context_tlast  (m_in_context_tlast[i]), +      .m_axis_context_tvalid (m_in_context_tvalid[i]), +      .m_axis_context_tready (m_in_context_tready[i]), +      .flush_en              (data_i_flush_en), +      .flush_timeout         (data_i_flush_timeout), +      .flush_active          (data_i_flush_active[0+i]), +      .flush_done            (data_i_flush_done[0+i]) +    ); +  end + +  //--------------------- +  // Output Data Paths +  //--------------------- + +  for (i = 0; i < NUM_PORTS; i = i + 1) begin: gen_output_out +    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(32)), +      .MTU                 (MTU), +      .CONTEXT_PREFETCH_EN (1) +    ) axis_pyld_ctxt_to_chdr_out_out ( +      .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+i)*CHDR_W+:CHDR_W]), +      .m_axis_chdr_tlast     (m_rfnoc_chdr_tlast[0+i]), +      .m_axis_chdr_tvalid    (m_rfnoc_chdr_tvalid[0+i]), +      .m_axis_chdr_tready    (m_rfnoc_chdr_tready[0+i]), +      .s_axis_payload_tdata  (s_out_payload_tdata[(32*1)*i+:(32*1)]), +      .s_axis_payload_tkeep  (s_out_payload_tkeep[1*i+:1]), +      .s_axis_payload_tlast  (s_out_payload_tlast[i]), +      .s_axis_payload_tvalid (s_out_payload_tvalid[i]), +      .s_axis_payload_tready (s_out_payload_tready[i]), +      .s_axis_context_tdata  (s_out_context_tdata[CHDR_W*i+:CHDR_W]), +      .s_axis_context_tuser  (s_out_context_tuser[4*i+:4]), +      .s_axis_context_tlast  (s_out_context_tlast[i]), +      .s_axis_context_tvalid (s_out_context_tvalid[i]), +      .s_axis_context_tready (s_out_context_tready[i]), +      .framer_errors         (), +      .flush_en              (data_o_flush_en), +      .flush_timeout         (data_o_flush_timeout), +      .flush_active          (data_o_flush_active[0+i]), +      .flush_done            (data_o_flush_done[0+i]) +    ); +  end + +endmodule // noc_shell_vector_iir + + +`default_nettype wire diff --git a/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_vector_iir/rfnoc_block_vector_iir.v b/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_vector_iir/rfnoc_block_vector_iir.v new file mode 100644 index 000000000..58df93b44 --- /dev/null +++ b/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_vector_iir/rfnoc_block_vector_iir.v @@ -0,0 +1,400 @@ +// +// Copyright 2020 Ettus Research, a National Instruments Brand +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// +// Module: rfnoc_block_vector_iir +// +// Description: +// +//   This module implements an IIR filter with a variable length delay line. +//   Transfer Function: +//                                   beta +//                      H(z) = ------------------ +//                             1 - alpha*z^-delay +//   Where: +//   - beta is the feedforward tap +//   - alpha is the feedback tap +//   - delay is the feedback tap delay +// +// 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_PORTS   : Number of Vector IIR instances to instantiate +//   MAX_DELAY   : The maximum supported filter delay. This should correspond +//                 to the maximum SPP. Optimal values are a power of two, minus +//                 one (e.g, 2047). +// + +`default_nettype none + + +module rfnoc_block_vector_iir #( +  parameter [9:0] THIS_PORTID = 10'd0, +  parameter       CHDR_W      = 64, +  parameter [5:0] MTU         = 10, +  parameter       NUM_PORTS   = 1, +  parameter       MAX_DELAY   = (2**MTU*CHDR_W/32-1) +) ( +  // 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 [(0+NUM_PORTS)*CHDR_W-1:0] s_rfnoc_chdr_tdata, +  input  wire [       (0+NUM_PORTS)-1:0] s_rfnoc_chdr_tlast, +  input  wire [       (0+NUM_PORTS)-1:0] s_rfnoc_chdr_tvalid, +  output wire [       (0+NUM_PORTS)-1:0] s_rfnoc_chdr_tready, +  // AXIS-CHDR Output Ports (to framework) +  output wire [(0+NUM_PORTS)*CHDR_W-1:0] m_rfnoc_chdr_tdata, +  output wire [       (0+NUM_PORTS)-1:0] m_rfnoc_chdr_tlast, +  output wire [       (0+NUM_PORTS)-1:0] m_rfnoc_chdr_tvalid, +  input  wire [       (0+NUM_PORTS)-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 +); + +  `include "rfnoc_block_vector_iir_regs.vh" + +  // Make sure MAX_DELAY isn't too big for REG_MAX_DELAY +  if (MAX_DELAY >= 2**REG_MAX_DELAY_LEN) begin +    MAX_DELAY_is_too_large_for_REG_MAX_DELAY(); +  end + + +  //--------------------------------------------------------------------------- +  // Signal Declarations +  //--------------------------------------------------------------------------- + +  // 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; +  wire        m_ctrlport_resp_ack; +  wire [31:0] m_ctrlport_resp_data; +  // Payload Stream to User Logic: in +  wire [NUM_PORTS*32*1-1:0] m_in_payload_tdata; +  wire [     NUM_PORTS-1:0] m_in_payload_tlast; +  wire [     NUM_PORTS-1:0] m_in_payload_tvalid; +  wire [     NUM_PORTS-1:0] m_in_payload_tready; +  // Context Stream to User Logic: in +  wire [NUM_PORTS*CHDR_W-1:0] m_in_context_tdata; +  wire [     NUM_PORTS*4-1:0] m_in_context_tuser; +  wire [       NUM_PORTS-1:0] m_in_context_tlast; +  wire [       NUM_PORTS-1:0] m_in_context_tvalid; +  wire [       NUM_PORTS-1:0] m_in_context_tready; +  // Payload Stream to User Logic: out +  wire [NUM_PORTS*32*1-1:0] s_out_payload_tdata; +  wire [     NUM_PORTS-1:0] s_out_payload_tlast; +  wire [     NUM_PORTS-1:0] s_out_payload_tvalid; +  wire [     NUM_PORTS-1:0] s_out_payload_tready; +  // Context Stream to User Logic: out +  wire [NUM_PORTS*CHDR_W-1:0] s_out_context_tdata; +  wire [     NUM_PORTS*4-1:0] s_out_context_tuser; +  wire [       NUM_PORTS-1:0] s_out_context_tlast; +  wire [       NUM_PORTS-1:0] s_out_context_tvalid; +  wire [       NUM_PORTS-1:0] s_out_context_tready; + + +  //--------------------------------------------------------------------------- +  // NoC Shell +  //--------------------------------------------------------------------------- + +  wire ce_rst; + +  noc_shell_vector_iir #( +    .CHDR_W      (CHDR_W), +    .THIS_PORTID (THIS_PORTID), +    .MTU         (MTU), +    .NUM_PORTS   (NUM_PORTS) +  ) noc_shell_vector_iir_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               (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 +    //--------------------- + +    // CtrlPort Clock and Reset +    .ctrlport_clk         (), +    .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), + +    // AXI-Stream Payload Context Clock and Reset +    .axis_data_clk        (), +    .axis_data_rst        (), +    // Payload Stream to User Logic: in +    .m_in_payload_tdata   (m_in_payload_tdata), +    .m_in_payload_tkeep   (), +    .m_in_payload_tlast   (m_in_payload_tlast), +    .m_in_payload_tvalid  (m_in_payload_tvalid), +    .m_in_payload_tready  (m_in_payload_tready), +    // Context Stream to User Logic: in +    .m_in_context_tdata   (m_in_context_tdata), +    .m_in_context_tuser   (m_in_context_tuser), +    .m_in_context_tlast   (m_in_context_tlast), +    .m_in_context_tvalid  (m_in_context_tvalid), +    .m_in_context_tready  (m_in_context_tready), +    // Payload Stream from User Logic: out +    .s_out_payload_tdata  (s_out_payload_tdata), +    .s_out_payload_tkeep  (), +    .s_out_payload_tlast  (s_out_payload_tlast), +    .s_out_payload_tvalid (s_out_payload_tvalid), +    .s_out_payload_tready (s_out_payload_tready), +    // Context Stream from User Logic: out +    .s_out_context_tdata  (s_out_context_tdata), +    .s_out_context_tuser  (s_out_context_tuser), +    .s_out_context_tlast  (s_out_context_tlast), +    .s_out_context_tvalid (s_out_context_tvalid), +    .s_out_context_tready (s_out_context_tready) +  ); + +  // Context is not used because output packets have the same format as input +  // packets, so we pass through the context unchanged. +  assign s_out_context_tdata  = m_in_context_tdata; +  assign s_out_context_tuser  = m_in_context_tuser; +  assign s_out_context_tlast  = m_in_context_tlast; +  assign s_out_context_tvalid = m_in_context_tvalid; +  assign m_in_context_tready  = s_out_context_tready; + + +  //--------------------------------------------------------------------------- +  // CtrlPort Splitter +  //--------------------------------------------------------------------------- + +  wire [NUM_PORTS* 1-1:0] dec_ctrlport_req_wr; +  wire [NUM_PORTS* 1-1:0] dec_ctrlport_req_rd; +  wire [NUM_PORTS*20-1:0] dec_ctrlport_req_addr; +  wire [NUM_PORTS*32-1:0] dec_ctrlport_req_data; +  wire [NUM_PORTS* 1-1:0] dec_ctrlport_resp_ack; +  wire [NUM_PORTS*32-1:0] dec_ctrlport_resp_data; + +  ctrlport_decoder #( +    .NUM_SLAVES   (NUM_PORTS), +    .SLAVE_ADDR_W (VECTOR_IIR_ADDR_W) +  ) ctrlport_decoder_i ( +    .ctrlport_clk            (ce_clk), +    .ctrlport_rst            (ce_rst), +    .s_ctrlport_req_wr       (m_ctrlport_req_wr), +    .s_ctrlport_req_rd       (m_ctrlport_req_rd), +    .s_ctrlport_req_addr     (m_ctrlport_req_addr), +    .s_ctrlport_req_data     (m_ctrlport_req_data), +    .s_ctrlport_req_byte_en  (4'hF), +    .s_ctrlport_req_has_time (1'b0), +    .s_ctrlport_req_time     (64'b0), +    .s_ctrlport_resp_ack     (m_ctrlport_resp_ack), +    .s_ctrlport_resp_status  (), +    .s_ctrlport_resp_data    (m_ctrlport_resp_data), +    .m_ctrlport_req_wr       (dec_ctrlport_req_wr), +    .m_ctrlport_req_rd       (dec_ctrlport_req_rd), +    .m_ctrlport_req_addr     (dec_ctrlport_req_addr), +    .m_ctrlport_req_data     (dec_ctrlport_req_data), +    .m_ctrlport_req_byte_en  (), +    .m_ctrlport_req_has_time (), +    .m_ctrlport_req_time     (), +    .m_ctrlport_resp_ack     (dec_ctrlport_resp_ack), +    .m_ctrlport_resp_status  ({NUM_PORTS{2'b0}}), +    .m_ctrlport_resp_data    (dec_ctrlport_resp_data) +  ); + + +  //--------------------------------------------------------------------------- +  // Port Instances +  //--------------------------------------------------------------------------- + +  genvar port; +  generate +    for (port = 0; port < NUM_PORTS; port = port+1) begin : gen_ports + +      //----------------------------------------------------------------------- +      // Signal Selection +      //----------------------------------------------------------------------- +      // +      // Grab the appropriate CtrlPort and AXIS payload signals for this port. +      // +      //----------------------------------------------------------------------- + +      wire        ctrlport_req_wr; +      wire        ctrlport_req_rd; +      wire [19:0] ctrlport_req_addr; +      wire [31:0] ctrlport_req_data; +      reg         ctrlport_resp_ack; +      reg  [31:0] ctrlport_resp_data; + +      assign ctrlport_req_wr   = dec_ctrlport_req_wr[port]; +      assign ctrlport_req_rd   = dec_ctrlport_req_rd[port]; +      assign ctrlport_req_addr = dec_ctrlport_req_addr[port*20 +: 20]; +      assign ctrlport_req_data = dec_ctrlport_req_data[port*32 +: 32]; +      // +      assign dec_ctrlport_resp_ack[port]           = ctrlport_resp_ack; +      assign dec_ctrlport_resp_data[port*32 +: 32] = ctrlport_resp_data; + +      wire [31:0] in_tdata; +      wire        in_tlast; +      wire        in_tvalid; +      wire        in_tready; +      wire [31:0] out_tdata; +      wire        out_tlast; +      wire        out_tvalid; +      wire        out_tready; + +      assign in_tdata                  = m_in_payload_tdata [port*32 +: 32]; +      assign in_tlast                  = m_in_payload_tlast [port]; +      assign in_tvalid                 = m_in_payload_tvalid[port]; +      assign m_in_payload_tready[port] = in_tready; +      // +      assign s_out_payload_tdata [port*32+:32] = out_tdata; +      assign s_out_payload_tlast [       port] = out_tlast; +      assign s_out_payload_tvalid[       port] = out_tvalid; +      assign out_tready                        = s_out_payload_tready[port]; + + +      //----------------------------------------------------------------------- +      // Registers +      //----------------------------------------------------------------------- + +      reg [$clog2(MAX_DELAY+1)-1:0] reg_delay; +      reg [      REG_ALPHA_LEN-1:0] reg_alpha; +      reg [       REG_BETA_LEN-1:0] reg_beta; + +      reg reg_changed; + +      always @(posedge ce_clk) begin +        if (ce_rst) begin +          reg_delay   <= 'bX; +          reg_alpha   <= 'bX; +          reg_beta    <= 'bX; +          reg_changed <= 1'b0; +        end else begin +          // Default assignments +          ctrlport_resp_ack  <= 1'b0; +          ctrlport_resp_data <= 32'b0; +          reg_changed        <= 1'b0; + +          //----------------------------------------- +          // Register Reads +          //----------------------------------------- + +          if (ctrlport_req_rd) begin +            ctrlport_resp_ack <= 1; +            case (ctrlport_req_addr) +              REG_DELAY : begin +                ctrlport_resp_data[REG_MAX_DELAY_POS +: REG_DELAY_LEN] <= MAX_DELAY; +                ctrlport_resp_data[REG_DELAY_POS     +: REG_DELAY_LEN] <= reg_delay; +              end +              REG_ALPHA : +                ctrlport_resp_data[REG_ALPHA_POS +: REG_ALPHA_LEN] <= reg_alpha; +              REG_BETA : +                ctrlport_resp_data[REG_BETA_POS +: REG_BETA_LEN] <= reg_beta; +            endcase + +          //----------------------------------------- +          // Register Writes +          //----------------------------------------- + +          end else if (ctrlport_req_wr) begin +            ctrlport_resp_ack <= 1; +            case (ctrlport_req_addr) +              REG_DELAY : begin +                reg_delay <= ctrlport_req_data[REG_DELAY_POS +: REG_DELAY_LEN]; +                reg_changed    <= 1'b1; +              end +              REG_ALPHA : begin +                reg_alpha   <= ctrlport_req_data[REG_ALPHA_POS +: REG_ALPHA_LEN]; +                reg_changed <= 1'b1; +              end +              REG_BETA : begin +                reg_beta    <= ctrlport_req_data[REG_BETA_POS +: REG_BETA_LEN]; +                reg_changed <= 1'b1; +              end +            endcase +          end +        end +      end + + +      //----------------------------------------------------------------------- +      // Vector IIR Block +      //----------------------------------------------------------------------- + +      vector_iir #( +        .MAX_VECTOR_LEN (MAX_DELAY), +        .ALPHA_W        (REG_ALPHA_LEN), +        .BETA_W         (REG_BETA_LEN) +      ) inst_vector_iir ( +        .clk            (ce_clk), +        .reset          (ce_rst | reg_changed), +        .set_vector_len (reg_delay), +        .set_alpha      (reg_alpha), +        .set_beta       (reg_beta), +        .i_tdata        (in_tdata), +        .i_tlast        (in_tlast), +        .i_tvalid       (in_tvalid), +        .i_tready       (in_tready), +        .o_tdata        (out_tdata), +        .o_tlast        (out_tlast), +        .o_tvalid       (out_tvalid), +        .o_tready       (out_tready) +      ); + +    end +  endgenerate + +endmodule // rfnoc_block_vector_iir + + +`default_nettype wire diff --git a/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_vector_iir/rfnoc_block_vector_iir_regs.vh b/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_vector_iir/rfnoc_block_vector_iir_regs.vh new file mode 100644 index 000000000..e3e071d71 --- /dev/null +++ b/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_vector_iir/rfnoc_block_vector_iir_regs.vh @@ -0,0 +1,74 @@ +// +// Copyright 2020 Ettus Research, a National Instruments Brand +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// +// Module: rfnoc_block_vector_iir_regs (Header) +// +// Description: +// +//   This is a header file that contains the register descriptions for the +//   RFNoC Vector IIR block. +// +//   Each RFNoC Vector IIR block consists of NUM_PORTS independent Vector IIR +//   filters. Each one has its own address space that is VECTOR_IIR_ADDR_W bits +//   wide. That is, Vector IIR block N can be addressed starting at byte offset +//   N*(2**VECTOR_IIR_ADDR_W). +// + +//----------------------------------------------------------------------------- +// Register Space +//----------------------------------------------------------------------------- + +// The amount of address space taken up by each Vector IIR filter. That is, the +// address space for port N starts at N*(2^VECTOR_IIR_ADDR_W). +localparam VECTOR_IIR_ADDR_W = 20'h00004; + + +//----------------------------------------------------------------------------- +// Vector IIR Register Descriptions +//----------------------------------------------------------------------------- + +// REG_DELAY (R/W) +// +// This register controls and reports the state of the filter delay.  +// +// [31:16] REG_MAX_DELAY : This field reports the maximum supported vector +//                         length, in samples. That is, it returns the +//                         MAX_DELAY block parameter.  +// [15: 0] REG_DELAY     : This field controls/reports the current vector delay +//                         length in samples. Values of 5 or more are supported. +// +localparam REG_DELAY = 'h00; +// +localparam REG_MAX_DELAY_LEN = 16; +localparam REG_MAX_DELAY_POS = 16; +// +localparam REG_DELAY_LEN = 16; +localparam REG_DELAY_POS = 0; + +// REG_ALPHA (R/W) +// +// This register controls the Alpha value for the filter. This is a signed +// 16-bit value. +// +// [31:0] : Unused +// [15:0] : Alpha value to use +// +localparam REG_ALPHA = 'h04; +// +localparam REG_ALPHA_LEN = 16; +localparam REG_ALPHA_POS = 0; + +// REG_BETA (R/W) +// +// This register controls the Beta value for the filter. This is a signed +// 16-bit value. +// +// [31:0] : Unused +// [15:0] : Beta value to use +// +localparam REG_BETA = 'h08; +// +localparam REG_BETA_LEN = 16; +localparam REG_BETA_POS = 0; diff --git a/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_vector_iir/rfnoc_block_vector_iir_tb.sv b/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_vector_iir/rfnoc_block_vector_iir_tb.sv new file mode 100644 index 000000000..e09640a3b --- /dev/null +++ b/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_vector_iir/rfnoc_block_vector_iir_tb.sv @@ -0,0 +1,528 @@ +// +// Copyright 2020 Ettus Research, a National Instruments Brand +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// +// Module: rfnoc_block_vector_iir_tb +// +// Description: Testbench for the vector_iir RFNoC block. +// + +`default_nettype none + + +module rfnoc_block_vector_iir_tb; + +  `include "test_exec.svh" + +  import PkgTestExec::*; +  import PkgChdrUtils::*; +  import PkgRfnocBlockCtrlBfm::*; +  import PkgRfnocItemUtils::*; + +  `include "rfnoc_block_vector_iir_regs.vh" + + +  //--------------------------------------------------------------------------- +  // Testbench Configuration +  //--------------------------------------------------------------------------- + +  localparam [31:0] NOC_ID          = 32'h11120000; +  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       = 2; +  localparam int    NUM_PORTS_I     = 0+NUM_PORTS; +  localparam int    NUM_PORTS_O     = 0+NUM_PORTS; +  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      = 50;    // 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 + +  localparam int  MAX_DELAY   = (2**MTU)*(CHDR_W/ITEM_W)-1; +  localparam int  NUM_PKTS    = 50;       // Number of packets to test +  localparam int  VECTOR_SIZE = SPP;      // Vector size to test +  localparam real ERROR       = 2.0**-12; // Target 72dB of dynamic range + + +  //--------------------------------------------------------------------------- +  // Clocks and Resets +  //--------------------------------------------------------------------------- + +  bit rfnoc_chdr_clk; +  bit rfnoc_ctrl_clk; +  bit ce_clk; + +  sim_clock_gen #(CHDR_CLK_PER) rfnoc_chdr_clk_gen (.clk(rfnoc_chdr_clk), .rst()); +  sim_clock_gen #(CTRL_CLK_PER) rfnoc_ctrl_clk_gen (.clk(rfnoc_ctrl_clk), .rst()); +  sim_clock_gen #(CE_CLK_PER) 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_vector_iir #( +    .THIS_PORTID         (THIS_PORTID), +    .CHDR_W              (CHDR_W), +    .MTU                 (MTU), +    .NUM_PORTS           (NUM_PORTS), +    .MAX_DELAY           (MAX_DELAY) +  ) 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) +  ); + + +  //--------------------------------------------------------------------------- +  // Filter Model +  //--------------------------------------------------------------------------- + +  task automatic iir_filter ( +    input real  alpha, +    input real  beta, +    input real  in[], +    output real out[] +  ); +    out = new[in.size()]; +    for (int i = 0; i < in.size(); i++) begin +      real yd = i >= 1 ? out[i-1] : 0.0; +      out[i] = in[i]*beta + yd*alpha; +      `ASSERT_FATAL(abs(out[i]) <= 1.0, +        "Expected value for filtered data falls outside allowed range."); +    end +  endtask : iir_filter + + +  //--------------------------------------------------------------------------- +  // 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**VECTOR_IIR_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**VECTOR_IIR_ADDR_W)*port + addr, value[31: 0]); +  endtask : read_reg + +  // Real to fixed-point +  function bit [15:0] real_to_fxp (real x); +    return int'($floor(x * ((2**15)-1))); +  endfunction + +  // Fixed-point to real +  function real fxp_to_real(bit [15:0] x); +    return real'($signed(x))/((2**15)-1); +  endfunction + +  // Absolute value +  function real abs(real x); +    return (x > 0.0) ? x : -x; +  endfunction + + +  //--------------------------------------------------------------------------- +  // Register Test Tasks +  //--------------------------------------------------------------------------- + +  // Test a read/write register for correct functionality +  // +  //   port          : Replay block port to use +  //   addr          : Register byte address +  //   mask          : Mask of the bits we expect to be writable +  //   initial_value : Value we expect to read initially +  // +  task automatic test_read_write_reg( +    int          port, +    bit   [19:0] addr, +    bit   [31:0] mask = 32'hFFFFFFFF, +    logic [31:0] initial_value = '0 +  ); +    string       err_msg; +    logic [31:0] value; +    logic [31:0] expected; + +    err_msg = $sformatf("Register 0x%X failed read/write test: ", addr); + +    // Check initial value +    expected = initial_value; +    read_reg(port, addr, value); +    `ASSERT_ERROR(value === expected, {err_msg, "initial value"}); + +    // Test writing 0 +    expected = (initial_value & ~mask); +    write_reg(port, addr, '0); +    read_reg(port, addr, value); +    `ASSERT_ERROR(value === expected, {err_msg, "write zero"}); + +    // Write maximum value +    expected = (initial_value & ~mask) | mask; +    write_reg(port, addr, '1); +    read_reg(port, addr, value); +    `ASSERT_ERROR(value === expected, {err_msg, "write max value"}); + +    // Restore original value +    write_reg(port, addr, initial_value); +  endtask : test_read_write_reg + + +  //--------------------------------------------------------------------------- +  // Test registers +  //--------------------------------------------------------------------------- + +  task automatic test_registers(int port = 0); +    test.start_test("Test registers", 100us); + +    // Test Delay (Vector Length) register. The MAX_DELAY portion is +    // ready-only. DELAY portion is read/write. +    test_read_write_reg( +      port, +      REG_DELAY, +      {$clog2(MAX_DELAY+1){1'b1}} << REG_DELAY_POS, +      (MAX_DELAY << REG_MAX_DELAY_POS) | ({$clog2(MAX_DELAY+1){1'bX}} << REG_DELAY_POS) +    ); + +    // Test Alpha register +    test_read_write_reg( +      port, +      REG_ALPHA, +      ((1<<REG_ALPHA_LEN)-1) << REG_ALPHA_POS, +      {REG_ALPHA_LEN{1'bX}} << REG_ALPHA_POS +    ); + +    // Test Beta register +    test_read_write_reg( +      port, +      REG_BETA, +      ((1<<REG_BETA_LEN)-1) << REG_BETA_POS, +      {REG_BETA_LEN{1'bX}} << REG_BETA_POS +    ); +    test.end_test(); +  endtask : test_registers + + +  //--------------------------------------------------------------------------- +  // Test impulse and step response +  //--------------------------------------------------------------------------- + +  task automatic test_impulse_and_step(int port = 0); +    real in_I[], in_Q[], out_I[], out_Q[]; +    real alpha, beta; + +    test.start_test("Check impulse and step response", 100us); + +    alpha = 0.7; +    beta = 0.3; +    write_reg(port, REG_DELAY, VECTOR_SIZE); +    write_reg(port, REG_ALPHA, real_to_fxp(alpha)); +    write_reg(port, REG_BETA,  real_to_fxp(beta)); + +    // Generate input and golden output vector +    in_I = new[NUM_PKTS]; +    in_Q = new[NUM_PKTS]; +    for (int n = 0; n < NUM_PKTS; n++) begin +      // First half is an impulse, second half is a step +      in_I[n] = (n == 0 || n >= NUM_PKTS/2) ?  1.0 : 0.0; +      in_Q[n] = (n == 0 || n >= NUM_PKTS/2) ? -1.0 : 0.0; +    end +    iir_filter(alpha, beta, in_I, out_I); +    iir_filter(alpha, beta, in_Q, out_Q); +    // Send, receive and validate data +    fork +      begin : send_packets +        item_t samples[$]; +        for (int n = 0; n < NUM_PKTS; n++) begin +          for (int k = 0; k < VECTOR_SIZE; k++) begin +            samples[k] = {real_to_fxp(in_I[n]), real_to_fxp(in_Q[n])}; +          end +          blk_ctrl.send_items(port, samples); +        end +      end +      begin : check_packets +        item_t samples[$]; +        real recv_i, recv_q; +        for (int n = 0; n < NUM_PKTS; n++) begin +          blk_ctrl.recv_items(port, samples); +          `ASSERT_ERROR(samples.size() == VECTOR_SIZE, +            "Received packet has incorrect number of samples"); +          for (int k = 0; k < VECTOR_SIZE; k++) begin +            recv_i = fxp_to_real(samples[k][31:16]); +            recv_q = fxp_to_real(samples[k][15:0]); +            `ASSERT_ERROR(abs(recv_i - out_I[n]) < ERROR, "Incorrect I value"); +            `ASSERT_ERROR(abs(recv_q - out_Q[n]) < ERROR, "Incorrect Q value"); +          end +        end +      end +    join +    test.end_test(); +  endtask : test_impulse_and_step + + +  //--------------------------------------------------------------------------- +  // Test quarter rate sine response (vector stride) +  //--------------------------------------------------------------------------- + +  task automatic test_vector_stride(int port = 0); +    real in_I[], in_Q[], out_I[], out_Q[]; +    real alpha, beta; + +    test.start_test("Check quarter rate complex sine response (vector stride)", 100us); +    alpha = 0.9; +    beta = 0.1; +    write_reg(port, REG_DELAY, VECTOR_SIZE); +    write_reg(port, REG_ALPHA, real_to_fxp(alpha)); +    write_reg(port, REG_BETA, real_to_fxp(beta)); +    // Generate input and golden output vector +    in_I = new[NUM_PKTS]; +    in_Q = new[NUM_PKTS]; +    for (int n = 0; n < NUM_PKTS; n++) begin +      // First half is an impulse, second half is a step +      in_I[n] = (n % 4 == 1 || n % 4 == 3) ? 0.0 : ((n % 4 == 0) ? 1.0 : -1.0);  // cos +      in_Q[n] = (n % 4 == 0 || n % 4 == 2) ? 0.0 : ((n % 4 == 1) ? 1.0 : -1.0);  // sin +    end +    iir_filter(alpha, beta, in_I, out_I); +    iir_filter(alpha, beta, in_Q, out_Q); +    // Send, receive and validate data +    fork +      begin : send_packets +        item_t samples[$]; +        for (int n = 0; n < NUM_PKTS; n++) begin +          for (int k = 0; k < VECTOR_SIZE; k++) begin +            samples[k] = {real_to_fxp(in_I[n]), real_to_fxp(in_Q[n])}; +          end +          blk_ctrl.send_items(port, samples); +        end +      end +      begin : check_packets +        item_t samples[$]; +        real recv_i, recv_q; +        for (int n = 0; n < NUM_PKTS; n++) begin +          blk_ctrl.recv_items(port, samples); +          `ASSERT_ERROR(samples.size() == VECTOR_SIZE, +            "Received packet has incorrect number of samples"); +          for (int k = 0; k < VECTOR_SIZE; k++) begin +            recv_i = fxp_to_real(samples[k][31:16]); +            recv_q = fxp_to_real(samples[k][15:0]); +            `ASSERT_ERROR(abs(recv_i - out_I[n]) < ERROR, "Incorrect I value"); +            `ASSERT_ERROR(abs(recv_q - out_Q[n]) < ERROR, "Incorrect Q value"); +          end +        end +      end +    join +    test.end_test(); +  endtask : test_vector_stride + + +  //--------------------------------------------------------------------------- +  // Test quarter rate sine response (sample stride) +  //--------------------------------------------------------------------------- + +  task automatic test_sample_stride(int port = 0); +    real in_I[], in_Q[], out_I[], out_Q[]; +    real alpha, beta; + +    test.start_test("Check quarter rate complex sine response (sample stride)", 100us); +    alpha = 0.01; +    beta = 0.99; +    write_reg(port, REG_DELAY, VECTOR_SIZE); +    write_reg(port, REG_ALPHA, real_to_fxp(alpha)); +    write_reg(port, REG_BETA, real_to_fxp(beta)); +    // Generate input and golden output vector +    in_I = new[NUM_PKTS]; +    in_Q = new[NUM_PKTS]; +    for (int n = 0; n < NUM_PKTS; n++) begin +      // First half is an impulse, second half is a step +      in_I[n] = (n % 4 == 1 || n % 4 == 3) ? 0.0 : ((n % 4 == 0) ? 1.0 : -1.0);  // cos +      in_Q[n] = (n % 4 == 0 || n % 4 == 2) ? 0.0 : ((n % 4 == 1) ? 1.0 : -1.0);  // sin +    end +    iir_filter(alpha, beta, in_I, out_I); +    iir_filter(alpha, beta, in_Q, out_Q); +    // Send, receive and validate data +    fork +      begin +        item_t samples[$]; +        for (int n = 0; n < NUM_PKTS; n++) begin +          for (int k = 0; k < VECTOR_SIZE; k++) begin +            if (k % 4 == 0) +              samples[k] = {real_to_fxp(in_I[n]), real_to_fxp(in_Q[n])}; +            else if (k % 4 == 2) +              samples[k] = {real_to_fxp(in_Q[n]), real_to_fxp(in_I[n])}; +            else +              samples[k] = {real_to_fxp(0.0), real_to_fxp(0.0)}; +          end +          blk_ctrl.send_items(port, samples); +        end +      end +      begin +        item_t samples[$]; +        real recv_i, recv_q; +        for (int n = 0; n < NUM_PKTS; n++) begin +          blk_ctrl.recv_items(port, samples); +          `ASSERT_ERROR(samples.size() == VECTOR_SIZE, +            "Received packet has incorrect number of samples"); +          for (int k = 0; k < VECTOR_SIZE; k++) begin +            recv_i = fxp_to_real(samples[k][31:16]); +            recv_q = fxp_to_real(samples[k][15:0]); +            if (k % 4 == 0) begin +              `ASSERT_ERROR(abs(recv_i - out_I[n]) < 0.01, "Incorrect I value"); +              `ASSERT_ERROR(abs(recv_q - out_Q[n]) < 0.01, "Incorrect Q value"); +            end else if (k % 4 == 2) begin +              `ASSERT_ERROR(abs(recv_i - out_Q[n]) < 0.01, "Incorrect I value"); +              `ASSERT_ERROR(abs(recv_q - out_I[n]) < 0.01, "Incorrect Q value"); +            end else begin +              `ASSERT_ERROR(abs(recv_i) < 0.01, "Incorrect I value"); +              `ASSERT_ERROR(abs(recv_q) < 0.01, "Incorrect Q value"); +            end +          end +        end +      end +    join +    test.end_test(); +  endtask : test_sample_stride + + +  //--------------------------------------------------------------------------- +  // Main Test Process +  //--------------------------------------------------------------------------- + +  initial begin : tb_main + +    // Initialize the test exec object for this testbench +    test.start_tb("rfnoc_block_vector_iir_tb"); + +    // 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 +    //-------------------------------- + +    for (int port = 0; port < NUM_PORTS; port++) begin +      // Run these tests on all ports +      test_registers(port); +      test_impulse_and_step(port); +    end +    test_vector_stride(); +    test_sample_stride(); + +    //-------------------------------- +    // Finish Up +    //-------------------------------- + +    // Display final statistics and results +    test.end_tb(); +  end : tb_main + +endmodule : rfnoc_block_vector_iir_tb + + +`default_nettype wire diff --git a/fpga/usrp3/lib/rfnoc/vector_iir.v b/fpga/usrp3/lib/rfnoc/vector_iir.v index a875f34fe..041bb15f3 100644 --- a/fpga/usrp3/lib/rfnoc/vector_iir.v +++ b/fpga/usrp3/lib/rfnoc/vector_iir.v @@ -33,7 +33,7 @@  //  module vector_iir #( -  parameter MAX_VECTOR_LEN  = 1024, +  parameter MAX_VECTOR_LEN  = 1023,    parameter IN_W            = 16,    parameter OUT_W           = 16,    parameter ALPHA_W         = 16, @@ -41,19 +41,19 @@ module vector_iir #(    parameter FEEDBACK_W      = 25,    parameter ACCUM_HEADROOM  = 4  )( -  input  wire                               clk, -  input  wire                               reset, -  input  wire [$clog2(MAX_VECTOR_LEN)-1:0]  set_vector_len, -  input  wire [BETA_W-1:0]                  set_beta, -  input  wire [ALPHA_W-1:0]                 set_alpha, -  input  wire [IN_W*2-1:0]                  i_tdata, -  input  wire                               i_tlast, -  input  wire                               i_tvalid, -  output wire                               i_tready, -  output wire [OUT_W*2-1:0]                 o_tdata, -  output wire                               o_tlast, -  output wire                               o_tvalid, -  input  wire                               o_tready +  input  wire                                clk, +  input  wire                                reset, +  input  wire [$clog2(MAX_VECTOR_LEN+1)-1:0] set_vector_len, +  input  wire [BETA_W-1:0]                   set_beta, +  input  wire [ALPHA_W-1:0]                  set_alpha, +  input  wire [IN_W*2-1:0]                   i_tdata, +  input  wire                                i_tlast, +  input  wire                                i_tvalid, +  output wire                                i_tready, +  output wire [OUT_W*2-1:0]                  o_tdata, +  output wire                                o_tlast, +  output wire                                o_tvalid, +  input  wire                                o_tready  );    // There are four registers between the input and output @@ -70,9 +70,9 @@ module vector_iir #(    localparam MIN_FB_DELAY = 4;    // Pipeline settings for timing -  reg [$clog2(MAX_VECTOR_LEN)-1:0]  reg_fb_delay; -  reg signed [BETA_W-1:0]           reg_beta; -  reg signed [ALPHA_W-1:0]          reg_alpha; +  reg        [$clog2(MAX_VECTOR_LEN-MIN_FB_DELAY)-1:0] reg_fb_delay; +  reg signed [                             BETA_W-1:0] reg_beta; +  reg signed [                            ALPHA_W-1:0] reg_alpha;    always @(posedge clk) begin      reg_fb_delay <= set_vector_len - MIN_FB_DELAY - 1;  //Adjust for pipeline delay  | 
