1//
2// Copyright 2020 Ettus Research, a National Instruments Brand
3//
4// SPDX-License-Identifier: LGPL-3.0-or-later
5//
6// Module: rfnoc_block_vector_iir
7//
8// Description:
9//
10//   This module implements an IIR filter with a variable length delay line.
11//   Transfer Function:
12//                                   beta
13//                      H(z) = ------------------
14//                             1 - alpha*z^-delay
15//   Where:
16//   - beta is the feedforward tap
17//   - alpha is the feedback tap
18//   - delay is the feedback tap delay
19//
20// Parameters:
21//
22//   THIS_PORTID : Control crossbar port to which this block is connected
23//   CHDR_W      : AXIS-CHDR data bus width
24//   MTU         : Maximum transmission unit (i.e., maximum packet size in
25//                 CHDR words is 2**MTU).
26//   NUM_PORTS   : Number of Vector IIR instances to instantiate
27//   MAX_DELAY   : The maximum supported filter delay. This should correspond
28//                 to the maximum SPP. Optimal values are a power of two, minus
29//                 one (e.g, 2047).
30//
31
32`default_nettype none
33
34
35module rfnoc_block_vector_iir #(
36  parameter [9:0] THIS_PORTID = 10'd0,
37  parameter       CHDR_W      = 64,
38  parameter [5:0] MTU         = 10,
39  parameter       NUM_PORTS   = 1,
40  parameter       MAX_DELAY   = (2**MTU*CHDR_W/32-1)
41) (
42  // RFNoC Framework Clocks and Resets
43  input  wire                            rfnoc_chdr_clk,
44  input  wire                            rfnoc_ctrl_clk,
45  input  wire                            ce_clk,
46  // RFNoC Backend Interface
47  input  wire [                   511:0] rfnoc_core_config,
48  output wire [                   511:0] rfnoc_core_status,
49  // AXIS-CHDR Input Ports (from framework)
50  input  wire [(0+NUM_PORTS)*CHDR_W-1:0] s_rfnoc_chdr_tdata,
51  input  wire [       (0+NUM_PORTS)-1:0] s_rfnoc_chdr_tlast,
52  input  wire [       (0+NUM_PORTS)-1:0] s_rfnoc_chdr_tvalid,
53  output wire [       (0+NUM_PORTS)-1:0] s_rfnoc_chdr_tready,
54  // AXIS-CHDR Output Ports (to framework)
55  output wire [(0+NUM_PORTS)*CHDR_W-1:0] m_rfnoc_chdr_tdata,
56  output wire [       (0+NUM_PORTS)-1:0] m_rfnoc_chdr_tlast,
57  output wire [       (0+NUM_PORTS)-1:0] m_rfnoc_chdr_tvalid,
58  input  wire [       (0+NUM_PORTS)-1:0] m_rfnoc_chdr_tready,
59  // AXIS-Ctrl Input Port (from framework)
60  input  wire [                    31:0] s_rfnoc_ctrl_tdata,
61  input  wire                            s_rfnoc_ctrl_tlast,
62  input  wire                            s_rfnoc_ctrl_tvalid,
63  output wire                            s_rfnoc_ctrl_tready,
64  // AXIS-Ctrl Output Port (to framework)
65  output wire [                    31:0] m_rfnoc_ctrl_tdata,
66  output wire                            m_rfnoc_ctrl_tlast,
67  output wire                            m_rfnoc_ctrl_tvalid,
68  input  wire                            m_rfnoc_ctrl_tready
69);
70
71  `include "rfnoc_block_vector_iir_regs.vh"
72
73  // Make sure MAX_DELAY isn't too big for REG_MAX_DELAY
74  if (MAX_DELAY >= 2**REG_MAX_DELAY_LEN) begin
75    MAX_DELAY_is_too_large_for_REG_MAX_DELAY();
76  end
77
78
79  //---------------------------------------------------------------------------
80  // Signal Declarations
81  //---------------------------------------------------------------------------
82
83  // CtrlPort Master
84  wire        m_ctrlport_req_wr;
85  wire        m_ctrlport_req_rd;
86  wire [19:0] m_ctrlport_req_addr;
87  wire [31:0] m_ctrlport_req_data;
88  wire        m_ctrlport_resp_ack;
89  wire [31:0] m_ctrlport_resp_data;
90  // Payload Stream to User Logic: in
91  wire [NUM_PORTS*32*1-1:0] m_in_payload_tdata;
92  wire [     NUM_PORTS-1:0] m_in_payload_tlast;
93  wire [     NUM_PORTS-1:0] m_in_payload_tvalid;
94  wire [     NUM_PORTS-1:0] m_in_payload_tready;
95  // Context Stream to User Logic: in
96  wire [NUM_PORTS*CHDR_W-1:0] m_in_context_tdata;
97  wire [     NUM_PORTS*4-1:0] m_in_context_tuser;
98  wire [       NUM_PORTS-1:0] m_in_context_tlast;
99  wire [       NUM_PORTS-1:0] m_in_context_tvalid;
100  wire [       NUM_PORTS-1:0] m_in_context_tready;
101  // Payload Stream to User Logic: out
102  wire [NUM_PORTS*32*1-1:0] s_out_payload_tdata;
103  wire [     NUM_PORTS-1:0] s_out_payload_tlast;
104  wire [     NUM_PORTS-1:0] s_out_payload_tvalid;
105  wire [     NUM_PORTS-1:0] s_out_payload_tready;
106  // Context Stream to User Logic: out
107  wire [NUM_PORTS*CHDR_W-1:0] s_out_context_tdata;
108  wire [     NUM_PORTS*4-1:0] s_out_context_tuser;
109  wire [       NUM_PORTS-1:0] s_out_context_tlast;
110  wire [       NUM_PORTS-1:0] s_out_context_tvalid;
111  wire [       NUM_PORTS-1:0] s_out_context_tready;
112
113
114  //---------------------------------------------------------------------------
115  // NoC Shell
116  //---------------------------------------------------------------------------
117
118  wire ce_rst;
119
120  noc_shell_vector_iir #(
121    .CHDR_W      (CHDR_W),
122    .THIS_PORTID (THIS_PORTID),
123    .MTU         (MTU),
124    .NUM_PORTS   (NUM_PORTS)
125  ) noc_shell_vector_iir_i (
126    //---------------------
127    // Framework Interface
128    //---------------------
129
130    // Clock Inputs
131    .rfnoc_chdr_clk       (rfnoc_chdr_clk),
132    .rfnoc_ctrl_clk       (rfnoc_ctrl_clk),
133    .ce_clk               (ce_clk),
134    // Reset Outputs
135    .rfnoc_chdr_rst       (),
136    .rfnoc_ctrl_rst       (),
137    .ce_rst               (ce_rst),
138    // RFNoC Backend Interface
139    .rfnoc_core_config    (rfnoc_core_config),
140    .rfnoc_core_status    (rfnoc_core_status),
141    // CHDR Input Ports  (from framework)
142    .s_rfnoc_chdr_tdata   (s_rfnoc_chdr_tdata),
143    .s_rfnoc_chdr_tlast   (s_rfnoc_chdr_tlast),
144    .s_rfnoc_chdr_tvalid  (s_rfnoc_chdr_tvalid),
145    .s_rfnoc_chdr_tready  (s_rfnoc_chdr_tready),
146    // CHDR Output Ports (to framework)
147    .m_rfnoc_chdr_tdata   (m_rfnoc_chdr_tdata),
148    .m_rfnoc_chdr_tlast   (m_rfnoc_chdr_tlast),
149    .m_rfnoc_chdr_tvalid  (m_rfnoc_chdr_tvalid),
150    .m_rfnoc_chdr_tready  (m_rfnoc_chdr_tready),
151    // AXIS-Ctrl Input Port (from framework)
152    .s_rfnoc_ctrl_tdata   (s_rfnoc_ctrl_tdata),
153    .s_rfnoc_ctrl_tlast   (s_rfnoc_ctrl_tlast),
154    .s_rfnoc_ctrl_tvalid  (s_rfnoc_ctrl_tvalid),
155    .s_rfnoc_ctrl_tready  (s_rfnoc_ctrl_tready),
156    // AXIS-Ctrl Output Port (to framework)
157    .m_rfnoc_ctrl_tdata   (m_rfnoc_ctrl_tdata),
158    .m_rfnoc_ctrl_tlast   (m_rfnoc_ctrl_tlast),
159    .m_rfnoc_ctrl_tvalid  (m_rfnoc_ctrl_tvalid),
160    .m_rfnoc_ctrl_tready  (m_rfnoc_ctrl_tready),
161
162    //---------------------
163    // Client Interface
164    //---------------------
165
166    // CtrlPort Clock and Reset
167    .ctrlport_clk         (),
168    .ctrlport_rst         (),
169    // CtrlPort Master
170    .m_ctrlport_req_wr    (m_ctrlport_req_wr),
171    .m_ctrlport_req_rd    (m_ctrlport_req_rd),
172    .m_ctrlport_req_addr  (m_ctrlport_req_addr),
173    .m_ctrlport_req_data  (m_ctrlport_req_data),
174    .m_ctrlport_resp_ack  (m_ctrlport_resp_ack),
175    .m_ctrlport_resp_data (m_ctrlport_resp_data),
176
177    // AXI-Stream Payload Context Clock and Reset
178    .axis_data_clk        (),
179    .axis_data_rst        (),
180    // Payload Stream to User Logic: in
181    .m_in_payload_tdata   (m_in_payload_tdata),
182    .m_in_payload_tkeep   (),
183    .m_in_payload_tlast   (m_in_payload_tlast),
184    .m_in_payload_tvalid  (m_in_payload_tvalid),
185    .m_in_payload_tready  (m_in_payload_tready),
186    // Context Stream to User Logic: in
187    .m_in_context_tdata   (m_in_context_tdata),
188    .m_in_context_tuser   (m_in_context_tuser),
189    .m_in_context_tlast   (m_in_context_tlast),
190    .m_in_context_tvalid  (m_in_context_tvalid),
191    .m_in_context_tready  (m_in_context_tready),
192    // Payload Stream from User Logic: out
193    .s_out_payload_tdata  (s_out_payload_tdata),
194    .s_out_payload_tkeep  (),
195    .s_out_payload_tlast  (s_out_payload_tlast),
196    .s_out_payload_tvalid (s_out_payload_tvalid),
197    .s_out_payload_tready (s_out_payload_tready),
198    // Context Stream from User Logic: out
199    .s_out_context_tdata  (s_out_context_tdata),
200    .s_out_context_tuser  (s_out_context_tuser),
201    .s_out_context_tlast  (s_out_context_tlast),
202    .s_out_context_tvalid (s_out_context_tvalid),
203    .s_out_context_tready (s_out_context_tready)
204  );
205
206  // Context is not used because output packets have the same format as input
207  // packets, so we pass through the context unchanged.
208  assign s_out_context_tdata  = m_in_context_tdata;
209  assign s_out_context_tuser  = m_in_context_tuser;
210  assign s_out_context_tlast  = m_in_context_tlast;
211  assign s_out_context_tvalid = m_in_context_tvalid;
212  assign m_in_context_tready  = s_out_context_tready;
213
214
215  //---------------------------------------------------------------------------
216  // CtrlPort Splitter
217  //---------------------------------------------------------------------------
218
219  wire [NUM_PORTS* 1-1:0] dec_ctrlport_req_wr;
220  wire [NUM_PORTS* 1-1:0] dec_ctrlport_req_rd;
221  wire [NUM_PORTS*20-1:0] dec_ctrlport_req_addr;
222  wire [NUM_PORTS*32-1:0] dec_ctrlport_req_data;
223  wire [NUM_PORTS* 1-1:0] dec_ctrlport_resp_ack;
224  wire [NUM_PORTS*32-1:0] dec_ctrlport_resp_data;
225
226  ctrlport_decoder #(
227    .NUM_SLAVES   (NUM_PORTS),
228    .SLAVE_ADDR_W (VECTOR_IIR_ADDR_W)
229  ) ctrlport_decoder_i (
230    .ctrlport_clk            (ce_clk),
231    .ctrlport_rst            (ce_rst),
232    .s_ctrlport_req_wr       (m_ctrlport_req_wr),
233    .s_ctrlport_req_rd       (m_ctrlport_req_rd),
234    .s_ctrlport_req_addr     (m_ctrlport_req_addr),
235    .s_ctrlport_req_data     (m_ctrlport_req_data),
236    .s_ctrlport_req_byte_en  (4'hF),
237    .s_ctrlport_req_has_time (1'b0),
238    .s_ctrlport_req_time     (64'b0),
239    .s_ctrlport_resp_ack     (m_ctrlport_resp_ack),
240    .s_ctrlport_resp_status  (),
241    .s_ctrlport_resp_data    (m_ctrlport_resp_data),
242    .m_ctrlport_req_wr       (dec_ctrlport_req_wr),
243    .m_ctrlport_req_rd       (dec_ctrlport_req_rd),
244    .m_ctrlport_req_addr     (dec_ctrlport_req_addr),
245    .m_ctrlport_req_data     (dec_ctrlport_req_data),
246    .m_ctrlport_req_byte_en  (),
247    .m_ctrlport_req_has_time (),
248    .m_ctrlport_req_time     (),
249    .m_ctrlport_resp_ack     (dec_ctrlport_resp_ack),
250    .m_ctrlport_resp_status  ({NUM_PORTS{2'b0}}),
251    .m_ctrlport_resp_data    (dec_ctrlport_resp_data)
252  );
253
254
255  //---------------------------------------------------------------------------
256  // Port Instances
257  //---------------------------------------------------------------------------
258
259  genvar port;
260  generate
261    for (port = 0; port < NUM_PORTS; port = port+1) begin : gen_ports
262
263      //-----------------------------------------------------------------------
264      // Signal Selection
265      //-----------------------------------------------------------------------
266      //
267      // Grab the appropriate CtrlPort and AXIS payload signals for this port.
268      //
269      //-----------------------------------------------------------------------
270
271      wire        ctrlport_req_wr;
272      wire        ctrlport_req_rd;
273      wire [19:0] ctrlport_req_addr;
274      wire [31:0] ctrlport_req_data;
275      reg         ctrlport_resp_ack;
276      reg  [31:0] ctrlport_resp_data;
277
278      assign ctrlport_req_wr   = dec_ctrlport_req_wr[port];
279      assign ctrlport_req_rd   = dec_ctrlport_req_rd[port];
280      assign ctrlport_req_addr = dec_ctrlport_req_addr[port*20 +: 20];
281      assign ctrlport_req_data = dec_ctrlport_req_data[port*32 +: 32];
282      //
283      assign dec_ctrlport_resp_ack[port]           = ctrlport_resp_ack;
284      assign dec_ctrlport_resp_data[port*32 +: 32] = ctrlport_resp_data;
285
286      wire [31:0] in_tdata;
287      wire        in_tlast;
288      wire        in_tvalid;
289      wire        in_tready;
290      wire [31:0] out_tdata;
291      wire        out_tlast;
292      wire        out_tvalid;
293      wire        out_tready;
294
295      assign in_tdata                  = m_in_payload_tdata [port*32 +: 32];
296      assign in_tlast                  = m_in_payload_tlast [port];
297      assign in_tvalid                 = m_in_payload_tvalid[port];
298      assign m_in_payload_tready[port] = in_tready;
299      //
300      assign s_out_payload_tdata [port*32+:32] = out_tdata;
301      assign s_out_payload_tlast [       port] = out_tlast;
302      assign s_out_payload_tvalid[       port] = out_tvalid;
303      assign out_tready                        = s_out_payload_tready[port];
304
305
306      //-----------------------------------------------------------------------
307      // Registers
308      //-----------------------------------------------------------------------
309
310      reg [$clog2(MAX_DELAY+1)-1:0] reg_delay;
311      reg [      REG_ALPHA_LEN-1:0] reg_alpha;
312      reg [       REG_BETA_LEN-1:0] reg_beta;
313
314      reg reg_changed;
315
316      always @(posedge ce_clk) begin
317        if (ce_rst) begin
318          reg_delay   <= 'bX;
319          reg_alpha   <= 'bX;
320          reg_beta    <= 'bX;
321          reg_changed <= 1'b0;
322        end else begin
323          // Default assignments
324          ctrlport_resp_ack  <= 1'b0;
325          ctrlport_resp_data <= 32'b0;
326          reg_changed        <= 1'b0;
327
328          //-----------------------------------------
329          // Register Reads
330          //-----------------------------------------
331
332          if (ctrlport_req_rd) begin
333            ctrlport_resp_ack <= 1;
334            case (ctrlport_req_addr)
335              REG_DELAY : begin
336                ctrlport_resp_data[REG_MAX_DELAY_POS +: REG_DELAY_LEN] <= MAX_DELAY;
337                ctrlport_resp_data[REG_DELAY_POS     +: REG_DELAY_LEN] <= reg_delay;
338              end
339              REG_ALPHA :
340                ctrlport_resp_data[REG_ALPHA_POS +: REG_ALPHA_LEN] <= reg_alpha;
341              REG_BETA :
342                ctrlport_resp_data[REG_BETA_POS +: REG_BETA_LEN] <= reg_beta;
343            endcase
344
345          //-----------------------------------------
346          // Register Writes
347          //-----------------------------------------
348
349          end else if (ctrlport_req_wr) begin
350            ctrlport_resp_ack <= 1;
351            case (ctrlport_req_addr)
352              REG_DELAY : begin
353                reg_delay <= ctrlport_req_data[REG_DELAY_POS +: REG_DELAY_LEN];
354                reg_changed    <= 1'b1;
355              end
356              REG_ALPHA : begin
357                reg_alpha   <= ctrlport_req_data[REG_ALPHA_POS +: REG_ALPHA_LEN];
358                reg_changed <= 1'b1;
359              end
360              REG_BETA : begin
361                reg_beta    <= ctrlport_req_data[REG_BETA_POS +: REG_BETA_LEN];
362                reg_changed <= 1'b1;
363              end
364            endcase
365          end
366        end
367      end
368
369
370      //-----------------------------------------------------------------------
371      // Vector IIR Block
372      //-----------------------------------------------------------------------
373
374      vector_iir #(
375        .MAX_VECTOR_LEN (MAX_DELAY),
376        .ALPHA_W        (REG_ALPHA_LEN),
377        .BETA_W         (REG_BETA_LEN)
378      ) inst_vector_iir (
379        .clk            (ce_clk),
380        .reset          (ce_rst | reg_changed),
381        .set_vector_len (reg_delay),
382        .set_alpha      (reg_alpha),
383        .set_beta       (reg_beta),
384        .i_tdata        (in_tdata),
385        .i_tlast        (in_tlast),
386        .i_tvalid       (in_tvalid),
387        .i_tready       (in_tready),
388        .o_tdata        (out_tdata),
389        .o_tlast        (out_tlast),
390        .o_tvalid       (out_tvalid),
391        .o_tready       (out_tready)
392      );
393
394    end
395  endgenerate
396
397endmodule // rfnoc_block_vector_iir
398
399
400`default_nettype wire
401