1//
2// Copyright 2019 Ettus Research, a National Instruments Company
3// Copyright 2020 Ettus Research, a National Instruments Brand
4//
5// SPDX-License-Identifier: LGPL-3.0-or-later
6//
7// Module: rfnoc_block_duc
8//
9// Description:  An digital up-converter block for RFNoC.
10//
11// Parameters:
12//
13//   THIS_PORTID    : Control crossbar port to which this block is connected
14//   CHDR_W         : AXIS CHDR interface data width
15//   NUM_PORTS      : Number of DUC signal processing chains
16//   MTU            : Maximum transmission unit (i.e., maximum packet size) in
17//                    CHDR words is 2**MTU.
18//   NUM_HB         : Number of half-band filter blocks to include (0-3)
19//   CIC_MAX_INTERP : Maximum interpolation to support in the CIC filter
20//
21
22module rfnoc_block_duc #(
23  parameter THIS_PORTID    = 0,
24  parameter CHDR_W         = 64,
25  parameter NUM_PORTS      = 2,
26  parameter MTU            = 10,
27  parameter NUM_HB         = 2,
28  parameter CIC_MAX_INTERP = 128
29) (
30  //---------------------------------------------------------------------------
31  // AXIS CHDR Port
32  //---------------------------------------------------------------------------
33
34  input wire rfnoc_chdr_clk,
35  input wire ce_clk,
36
37  // CHDR inputs from framework
38  input  wire [NUM_PORTS*CHDR_W-1:0] s_rfnoc_chdr_tdata,
39  input  wire [       NUM_PORTS-1:0] s_rfnoc_chdr_tlast,
40  input  wire [       NUM_PORTS-1:0] s_rfnoc_chdr_tvalid,
41  output wire [       NUM_PORTS-1:0] s_rfnoc_chdr_tready,
42
43  // CHDR outputs to framework
44  output wire [NUM_PORTS*CHDR_W-1:0] m_rfnoc_chdr_tdata,
45  output wire [       NUM_PORTS-1:0] m_rfnoc_chdr_tlast,
46  output wire [       NUM_PORTS-1:0] m_rfnoc_chdr_tvalid,
47  input  wire [       NUM_PORTS-1:0] m_rfnoc_chdr_tready,
48
49  // Backend interface
50  input  wire [511:0] rfnoc_core_config,
51  output wire [511:0] rfnoc_core_status,
52
53  //---------------------------------------------------------------------------
54  // AXIS CTRL Port
55  //---------------------------------------------------------------------------
56
57  input wire rfnoc_ctrl_clk,
58
59  // CTRL port requests 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
65  // CTRL port requests to framework
66  output wire [31:0] m_rfnoc_ctrl_tdata,
67  output wire        m_rfnoc_ctrl_tlast,
68  output wire        m_rfnoc_ctrl_tvalid,
69  input  wire        m_rfnoc_ctrl_tready
70);
71
72  // These are the only supported values for now
73  localparam ITEM_W = 32;
74  localparam NIPC   = 1;
75
76  localparam COMPAT_MAJOR  = 16'h0;
77  localparam COMPAT_MINOR  = 16'h1;
78
79  `include "rfnoc_block_duc_regs.vh"
80  `include "../../core/rfnoc_axis_ctrl_utils.vh"
81
82
83  //---------------------------------------------------------------------------
84  // Signal Declarations
85  //---------------------------------------------------------------------------
86
87  wire        ctrlport_req_wr;
88  wire        ctrlport_req_rd;
89  wire [19:0] ctrlport_req_addr;
90  wire [31:0] ctrlport_req_data;
91  wire        ctrlport_req_has_time;
92  wire [63:0] ctrlport_req_time;
93  wire        ctrlport_resp_ack;
94  wire [31:0] ctrlport_resp_data;
95
96  wire [NUM_PORTS*ITEM_W-1:0] m_axis_data_tdata;
97  wire [       NUM_PORTS-1:0] m_axis_data_tlast;
98  wire [       NUM_PORTS-1:0] m_axis_data_tvalid;
99  wire [       NUM_PORTS-1:0] m_axis_data_tready;
100  wire [    NUM_PORTS*64-1:0] m_axis_data_ttimestamp;
101  wire [       NUM_PORTS-1:0] m_axis_data_thas_time;
102  wire [    NUM_PORTS*16-1:0] m_axis_data_tlength;
103  wire [       NUM_PORTS-1:0] m_axis_data_teob;
104  wire [   NUM_PORTS*128-1:0] m_axis_data_tuser;
105
106  wire [NUM_PORTS*ITEM_W-1:0] s_axis_data_tdata;
107  wire [       NUM_PORTS-1:0] s_axis_data_tlast;
108  wire [       NUM_PORTS-1:0] s_axis_data_tvalid;
109  wire [       NUM_PORTS-1:0] s_axis_data_tready;
110  wire [   NUM_PORTS*128-1:0] s_axis_data_tuser;
111  wire [       NUM_PORTS-1:0] s_axis_data_teob;
112  wire [    NUM_PORTS*64-1:0] s_axis_data_ttimestamp;
113  wire [       NUM_PORTS-1:0] s_axis_data_thas_time;
114
115
116  //---------------------------------------------------------------------------
117  // NoC Shell
118  //---------------------------------------------------------------------------
119
120  wire ce_rst;
121
122  noc_shell_duc #(
123    .THIS_PORTID (THIS_PORTID),
124    .CHDR_W      (CHDR_W),
125    .MTU         (MTU),
126    .NUM_PORTS   (NUM_PORTS)
127  ) noc_shell_duc_i (
128    .rfnoc_chdr_clk          (rfnoc_chdr_clk),
129    .rfnoc_ctrl_clk          (rfnoc_ctrl_clk),
130    .ce_clk                  (ce_clk),
131    .rfnoc_chdr_rst          (),
132    .rfnoc_ctrl_rst          (),
133    .ce_rst                  (ce_rst),
134    .rfnoc_core_config       (rfnoc_core_config),
135    .rfnoc_core_status       (rfnoc_core_status),
136    .s_rfnoc_chdr_tdata      (s_rfnoc_chdr_tdata),
137    .s_rfnoc_chdr_tlast      (s_rfnoc_chdr_tlast),
138    .s_rfnoc_chdr_tvalid     (s_rfnoc_chdr_tvalid),
139    .s_rfnoc_chdr_tready     (s_rfnoc_chdr_tready),
140    .m_rfnoc_chdr_tdata      (m_rfnoc_chdr_tdata),
141    .m_rfnoc_chdr_tlast      (m_rfnoc_chdr_tlast),
142    .m_rfnoc_chdr_tvalid     (m_rfnoc_chdr_tvalid),
143    .m_rfnoc_chdr_tready     (m_rfnoc_chdr_tready),
144    .s_rfnoc_ctrl_tdata      (s_rfnoc_ctrl_tdata),
145    .s_rfnoc_ctrl_tlast      (s_rfnoc_ctrl_tlast),
146    .s_rfnoc_ctrl_tvalid     (s_rfnoc_ctrl_tvalid),
147    .s_rfnoc_ctrl_tready     (s_rfnoc_ctrl_tready),
148    .m_rfnoc_ctrl_tdata      (m_rfnoc_ctrl_tdata),
149    .m_rfnoc_ctrl_tlast      (m_rfnoc_ctrl_tlast),
150    .m_rfnoc_ctrl_tvalid     (m_rfnoc_ctrl_tvalid),
151    .m_rfnoc_ctrl_tready     (m_rfnoc_ctrl_tready),
152    .ctrlport_clk            (),
153    .ctrlport_rst            (),
154    .m_ctrlport_req_wr       (ctrlport_req_wr),
155    .m_ctrlport_req_rd       (ctrlport_req_rd),
156    .m_ctrlport_req_addr     (ctrlport_req_addr),
157    .m_ctrlport_req_data     (ctrlport_req_data),
158    .m_ctrlport_req_has_time (ctrlport_req_has_time),
159    .m_ctrlport_req_time     (ctrlport_req_time),
160    .m_ctrlport_resp_ack     (ctrlport_resp_ack),
161    .m_ctrlport_resp_data    (ctrlport_resp_data),
162    .axis_data_clk           (),
163    .axis_data_rst           (),
164    .m_in_axis_tdata         (m_axis_data_tdata),
165    .m_in_axis_tkeep         (),
166    .m_in_axis_tlast         (m_axis_data_tlast),
167    .m_in_axis_tvalid        (m_axis_data_tvalid),
168    .m_in_axis_tready        (m_axis_data_tready),
169    .m_in_axis_ttimestamp    (m_axis_data_ttimestamp),
170    .m_in_axis_thas_time     (m_axis_data_thas_time),
171    .m_in_axis_tlength       (m_axis_data_tlength),
172    .m_in_axis_teov          (),
173    .m_in_axis_teob          (m_axis_data_teob),
174    .s_out_axis_tdata        (s_axis_data_tdata),
175    .s_out_axis_tkeep        ({NUM_PORTS*NIPC{1'b1}}),
176    .s_out_axis_tlast        (s_axis_data_tlast),
177    .s_out_axis_tvalid       (s_axis_data_tvalid),
178    .s_out_axis_tready       (s_axis_data_tready),
179    .s_out_axis_ttimestamp   (s_axis_data_ttimestamp),
180    .s_out_axis_thas_time    (s_axis_data_thas_time),
181    .s_out_axis_teov         ({NUM_PORTS{1'b0}}),
182    .s_out_axis_teob         (s_axis_data_teob)
183  );
184
185
186  //---------------------------------------------------------------------------
187  // Register Translation
188  //---------------------------------------------------------------------------
189  //
190  // Each DUC block is allocated an address spaces. This block translates CTRL
191  // port transactions in that space to settings bus.
192  //
193  //---------------------------------------------------------------------------
194
195  wire [ 8*NUM_PORTS-1:0] set_addr;
196  wire [32*NUM_PORTS-1:0] set_data;
197  wire [   NUM_PORTS-1:0] set_has_time;
198  wire [   NUM_PORTS-1:0] set_stb;
199  wire [64*NUM_PORTS-1:0] set_time;
200  wire [ 8*NUM_PORTS-1:0] rb_addr;
201  reg  [64*NUM_PORTS-1:0] rb_data;
202
203  ctrlport_to_settings_bus # (
204    .NUM_PORTS (NUM_PORTS)
205  ) ctrlport_to_settings_bus_i (
206    .ctrlport_clk             (ce_clk),
207    .ctrlport_rst             (ce_rst),
208    .s_ctrlport_req_wr        (ctrlport_req_wr),
209    .s_ctrlport_req_rd        (ctrlport_req_rd),
210    .s_ctrlport_req_addr      (ctrlport_req_addr),
211    .s_ctrlport_req_data      (ctrlport_req_data),
212    .s_ctrlport_req_has_time  (ctrlport_req_has_time),
213    .s_ctrlport_req_time      (ctrlport_req_time),
214    .s_ctrlport_resp_ack      (ctrlport_resp_ack),
215    .s_ctrlport_resp_data     (ctrlport_resp_data),
216    .set_data                 (set_data),
217    .set_addr                 (set_addr),
218    .set_stb                  (set_stb),
219    .set_time                 (set_time),
220    .set_has_time             (set_has_time),
221    .rb_stb                   ({NUM_PORTS{1'b1}}),
222    .rb_addr                  (rb_addr),
223    .rb_data                  (rb_data),
224    .timestamp                (64'b0)
225  );
226
227
228  //---------------------------------------------------------------------------
229  // DUC Implementation
230  //---------------------------------------------------------------------------
231
232  // Unused signals
233  wire [   NUM_PORTS-1:0] clear_tx_seqnum = 0;
234  wire [16*NUM_PORTS-1:0] src_sid         = 0;
235  wire [16*NUM_PORTS-1:0] next_dst_sid    = 0;
236
237  localparam MAX_M = CIC_MAX_INTERP * 2<<(NUM_HB-1);
238
239  genvar i;
240  generate
241    for (i = 0; i < NUM_PORTS; i = i + 1) begin : gen_duc_chains
242      wire clear_user;
243      wire clear_duc = clear_tx_seqnum[i] | clear_user;
244
245      wire        set_stb_int      = set_stb[i];
246      wire [7:0]  set_addr_int     = set_addr[8*i+7:8*i];
247      wire [31:0] set_data_int     = set_data[32*i+31:32*i];
248      wire [63:0] set_time_int     = set_time[64*i+63:64*i];
249      wire        set_has_time_int = set_has_time[i];
250
251      // Build the expected tuser CHDR header
252      cvita_hdr_encoder cvita_hdr_encoder_i (
253        .pkt_type       (2'b0),
254        .eob            (m_axis_data_teob[i]),
255        .has_time       (m_axis_data_thas_time[i]),
256        .seqnum         (12'b0),
257        .payload_length (m_axis_data_tlength[16*i +: 16]),
258        .src_sid        (16'b0),
259        .dst_sid        (16'b0),
260        .vita_time      (m_axis_data_ttimestamp[64*i +: 64]),
261        .header         (m_axis_data_tuser[128*i+:128])
262      );
263
264      // Extract bit fields from outgoing tuser CHDR header
265      assign s_axis_data_teob[i]              = s_axis_data_tuser[128*i+124 +:  1];
266      assign s_axis_data_thas_time[i]         = s_axis_data_tuser[128*i+125 +:  1];
267      assign s_axis_data_ttimestamp[64*i+:64] = s_axis_data_tuser[128*i+  0 +: 64];
268
269      // TODO Readback register for number of FIR filter taps
270      always @(*) begin
271        case(rb_addr[i*8+7:i*8])
272          RB_COMPAT_NUM     : rb_data[i*64+63:i*64] <= {COMPAT_MAJOR, COMPAT_MINOR};
273          RB_NUM_HB         : rb_data[i*64+63:i*64] <= NUM_HB;
274          RB_CIC_MAX_INTERP : rb_data[i*64+63:i*64] <= CIC_MAX_INTERP;
275          default           : rb_data[i*64+63:i*64] <= 64'h0BADC0DE0BADC0DE;
276        endcase
277      end
278
279      ////////////////////////////////////////////////////////////
280      //
281      // Timed CORDIC
282      // - Implements timed cordic tunes. Placed between AXI Wrapper
283      //   and AXI Rate Change due to it needing access to the
284      //   vita time of the samples.
285      //
286      ////////////////////////////////////////////////////////////
287      wire [31:0]  m_axis_rc_tdata;
288      wire         m_axis_rc_tlast;
289      wire         m_axis_rc_tvalid;
290      wire         m_axis_rc_tready;
291      wire [127:0] m_axis_rc_tuser;
292
293      dds_timed #(
294        .SR_FREQ_ADDR(SR_FREQ_ADDR),
295        .SR_SCALE_IQ_ADDR(SR_SCALE_IQ_ADDR))
296      dds_timed (
297        .clk(ce_clk), .reset(ce_rst), .clear(clear_tx_seqnum[i]),
298        .timed_cmd_fifo_full(),
299        .set_stb(set_stb_int), .set_addr(set_addr_int), .set_data(set_data_int),
300        .set_time(set_time_int), .set_has_time(set_has_time_int),
301        .i_tdata(m_axis_rc_tdata), .i_tlast(m_axis_rc_tlast), .i_tvalid(m_axis_rc_tvalid),
302        .i_tready(m_axis_rc_tready), .i_tuser(m_axis_rc_tuser),
303        .o_tdata(s_axis_data_tdata[ITEM_W*i+:ITEM_W]), .o_tlast(s_axis_data_tlast[i]), .o_tvalid(s_axis_data_tvalid[i]),
304        .o_tready(s_axis_data_tready[i]), .o_tuser(s_axis_data_tuser[128*i+:128]));
305
306      ////////////////////////////////////////////////////////////
307      //
308      // Increase Rate
309      //
310      ////////////////////////////////////////////////////////////
311      wire [31:0] sample_tdata, sample_duc_tdata;
312      wire sample_tvalid, sample_tready;
313      wire sample_duc_tvalid, sample_duc_tready;
314      axi_rate_change #(
315        .WIDTH(32),
316        .MAX_N(1),
317        .MAX_M(MAX_M),
318        .SR_N_ADDR(SR_N_ADDR),
319        .SR_M_ADDR(SR_M_ADDR),
320        .SR_CONFIG_ADDR(SR_CONFIG_ADDR),
321        .SR_TIME_INCR_ADDR(SR_TIME_INCR_ADDR))
322      axi_rate_change (
323        .clk(ce_clk), .reset(ce_rst), .clear(clear_tx_seqnum[i]), .clear_user(clear_user),
324        .src_sid(src_sid[16*i+15:16*i]), .dst_sid(next_dst_sid[16*i+15:16*i]),
325        .set_stb(set_stb_int), .set_addr(set_addr_int), .set_data(set_data_int),
326        .i_tdata(m_axis_data_tdata[ITEM_W*i+:ITEM_W]), .i_tlast(m_axis_data_tlast[i]), .i_tvalid(m_axis_data_tvalid[i]),
327        .i_tready(m_axis_data_tready[i]), .i_tuser(m_axis_data_tuser[128*i+:128]),
328        .o_tdata(m_axis_rc_tdata), .o_tlast(m_axis_rc_tlast), .o_tvalid(m_axis_rc_tvalid),
329        .o_tready(m_axis_rc_tready), .o_tuser(m_axis_rc_tuser),
330        .m_axis_data_tdata({sample_tdata}), .m_axis_data_tlast(), .m_axis_data_tvalid(sample_tvalid),
331        .m_axis_data_tready(sample_tready),
332        .s_axis_data_tdata(sample_duc_tdata), .s_axis_data_tlast(1'b0), .s_axis_data_tvalid(sample_duc_tvalid),
333        .s_axis_data_tready(sample_duc_tready),
334        .warning_long_throttle(), .error_extra_outputs(), .error_drop_pkt_lockup());
335
336      ////////////////////////////////////////////////////////////
337      //
338      // Digital Up Converter
339      //
340      ////////////////////////////////////////////////////////////
341      duc #(
342        .SR_INTERP_ADDR(SR_INTERP_ADDR),
343        .NUM_HB(NUM_HB),
344        .CIC_MAX_INTERP(CIC_MAX_INTERP))
345      duc (
346        .clk(ce_clk), .reset(ce_rst), .clear(clear_duc),
347        .set_stb(set_stb_int), .set_addr(set_addr_int), .set_data(set_data_int),
348        .i_tdata(sample_tdata), .i_tuser(128'b0), .i_tvalid(sample_tvalid), .i_tready(sample_tready),
349        .o_tdata(sample_duc_tdata), .o_tuser(), .o_tvalid(sample_duc_tvalid), .o_tready(sample_duc_tready));
350
351    end
352  endgenerate
353
354endmodule
355