File: noc_block_export_io.v

package info (click to toggle)
uhd 3.13.1.0-3
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 207,120 kB
  • sloc: cpp: 167,245; ansic: 86,841; vhdl: 53,420; python: 40,839; xml: 13,167; tcl: 5,688; makefile: 2,167; sh: 1,719; pascal: 230; csh: 94; asm: 20; perl: 11
file content (256 lines) | stat: -rw-r--r-- 13,491 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
//
// Copyright 2016 Ettus Research LLC
// Copyright 2018 Ettus Research, a National Instruments Company
//
// SPDX-License-Identifier: LGPL-3.0-or-later
//
// Special NoC Block where the internal NoC Shell / AXI Wrapper interfaces are exposed via ports.
// Created for use with RFNoC test benches.

module noc_block_export_io
#(
  parameter NOC_ID = 64'hFFFF_FFFF_FFFF_0000,
  parameter STR_SINK_FIFOSIZE = 11,
  parameter MTU = 11,
  parameter NUM_PORTS = 1,
  parameter USE_SEQ_NUM = 0  // 0: Use sequence number from AXI Wrapper & s_cvita_data header,
                             //    Warning: Sequence number can get out of sync if using both
                             //             s_axis_data and s_cvita_data on the same block port
                             //             which could break flow control / cause a lockup
                             // 1: Recalculate automatically, generally use this option
)(
  input bus_clk, input bus_rst,
  input ce_clk, input ce_rst,
  // Interface to crossbar
  input  [63:0] i_tdata, input  i_tlast, input  i_tvalid, output i_tready,
  output [63:0] o_tdata, output o_tlast, output o_tvalid, input  o_tready,
  /* Export user signals */
  // Settings bus
  output [NUM_PORTS-1:0] set_stb, output [NUM_PORTS*32-1:0] set_data, output [NUM_PORTS*8-1:0] set_addr,
  input [NUM_PORTS-1:0] rb_stb, output [NUM_PORTS*8-1:0] rb_addr,   input [NUM_PORTS*64-1:0] rb_data,
  // CVITA command and response interfaces, interfaces directly to NoC Shell
  input [63:0] s_cvita_cmd_tdata, input s_cvita_cmd_tlast, input s_cvita_cmd_tvalid, output s_cvita_cmd_tready,
  output [63:0] m_cvita_ack_tdata, output m_cvita_ack_tlast, output m_cvita_ack_tvalid, input m_cvita_ack_tready,
  // CVITA data & AXI stream interfaces
  // - One per block port
  // - Share interface with NoC Shell via mux / demux logic
  input [NUM_PORTS*64-1:0] s_cvita_data_tdata, input [NUM_PORTS-1:0] s_cvita_data_tlast,
  input [NUM_PORTS-1:0] s_cvita_data_tvalid, output [NUM_PORTS-1:0] s_cvita_data_tready,
  output [NUM_PORTS*64-1:0] m_cvita_data_tdata, output [NUM_PORTS-1:0] m_cvita_data_tlast,
  output [NUM_PORTS-1:0] m_cvita_data_tvalid, input [NUM_PORTS-1:0] m_cvita_data_tready,
  input [NUM_PORTS*32-1:0] s_axis_data_tdata, input [NUM_PORTS-1:0] s_axis_data_tlast,
  input [NUM_PORTS-1:0] s_axis_data_tvalid, output [NUM_PORTS-1:0] s_axis_data_tready,
  output [NUM_PORTS*32-1:0] m_axis_data_tdata, output [NUM_PORTS-1:0] m_axis_data_tlast,
  output [NUM_PORTS-1:0] m_axis_data_tvalid, input [NUM_PORTS-1:0] m_axis_data_tready,
  output [63:0] debug
);

  ////////////////////////////////////////////////////////////
  //
  // RFNoC Shell
  //
  ////////////////////////////////////////////////////////////
  wire [NUM_PORTS*64-1:0] str_sink_tdata, str_src_tdata;
  wire [NUM_PORTS-1:0]    str_sink_tlast, str_sink_tvalid, str_sink_tready, str_src_tlast, str_src_tvalid, str_src_tready;
  wire [NUM_PORTS*64-1:0] str_sink_tdata_bclk, str_src_tdata_bclk;
  wire [NUM_PORTS-1:0]    str_sink_tlast_bclk, str_sink_tvalid_bclk, str_sink_tready_bclk, str_src_tlast_bclk, str_src_tvalid_bclk, str_src_tready_bclk;

  wire [NUM_PORTS-1:0]         clear_tx_seqnum;
  wire [NUM_PORTS*16-1:0]      src_sid, next_dst_sid;

  noc_shell #(
    .NOC_ID(NOC_ID),
    .INPUT_PORTS(NUM_PORTS),
    .OUTPUT_PORTS(NUM_PORTS),
    .USE_GATE_MASK({NUM_PORTS{1'b1}}),
    .STR_SINK_FIFOSIZE({NUM_PORTS{STR_SINK_FIFOSIZE[7:0]}}))
  noc_shell (
    .bus_clk(bus_clk), .bus_rst(bus_rst),
    .i_tdata(i_tdata), .i_tlast(i_tlast), .i_tvalid(i_tvalid), .i_tready(i_tready),
    .o_tdata(o_tdata), .o_tlast(o_tlast), .o_tvalid(o_tvalid), .o_tready(o_tready),
    // Computer Engine Clock Domain
    .clk(ce_clk), .reset(ce_rst),
    // Control Sink
    .set_data(set_data), .set_addr(set_addr), .set_stb(set_stb), .set_time(), .set_has_time(),
    .rb_stb(rb_stb), .rb_data(rb_data), .rb_addr(rb_addr),
    // Control Source
    .cmdout_tdata(s_cvita_cmd_tdata), .cmdout_tlast(s_cvita_cmd_tlast), .cmdout_tvalid(s_cvita_cmd_tvalid), .cmdout_tready(s_cvita_cmd_tready),
    .ackin_tdata(m_cvita_ack_tdata), .ackin_tlast(m_cvita_ack_tlast), .ackin_tvalid(m_cvita_ack_tvalid), .ackin_tready(m_cvita_ack_tready),
    // Stream Sink
    .str_sink_tdata(str_sink_tdata_bclk), .str_sink_tlast(str_sink_tlast_bclk), .str_sink_tvalid(str_sink_tvalid_bclk), .str_sink_tready(str_sink_tready_bclk),
    // Stream Source
    .str_src_tdata(str_src_tdata_bclk), .str_src_tlast(str_src_tlast_bclk), .str_src_tvalid(str_src_tvalid_bclk), .str_src_tready(str_src_tready_bclk),
    // Misc
    .vita_time(64'd0), .clear_tx_seqnum(clear_tx_seqnum),
    .src_sid(src_sid), .next_dst_sid(next_dst_sid), .resp_in_dst_sid(), .resp_out_dst_sid(),
    .debug(debug));

  ////////////////////////////////////////////////////////////
  //
  // Instantiate AXI Wrapper and Mux / Demux with CVITA interface
  //
  ////////////////////////////////////////////////////////////
  genvar i;
  generate
    for (i = 0; i < NUM_PORTS; i = i + 1) begin
      axi_fifo_2clk #(
        .WIDTH(65), .SIZE(5)
      ) str_sink_2clk_i (
        .reset(bus_rst), .i_aclk(bus_clk),
        .i_tdata({str_sink_tlast_bclk[i], str_sink_tdata_bclk[64*i+63:64*i]}), .i_tvalid(str_sink_tvalid_bclk[i]), .i_tready(str_sink_tready_bclk[i]),
        .o_aclk(ce_clk),
        .o_tdata({str_sink_tlast[i], str_sink_tdata[64*i+63:64*i]}), .o_tvalid(str_sink_tvalid[i]), .o_tready(str_sink_tready[i])
      );
    
      axi_fifo_2clk #(
        .WIDTH(65), .SIZE(5)
      ) str_src_2clk_i (
        .reset(ce_rst), .i_aclk(ce_clk),
        .i_tdata({str_src_tlast[i], str_src_tdata[64*i+63:64*i]}), .i_tvalid(str_src_tvalid[i]), .i_tready(str_src_tready[i]),
        .o_aclk(bus_clk),
        .o_tdata({str_src_tlast_bclk[i], str_src_tdata_bclk[64*i+63:64*i]}), .o_tvalid(str_src_tvalid_bclk[i]), .o_tready(str_src_tready_bclk[i])
      );

      wire [63:0] aw_i_tdata, aw_o_tdata;
      wire        aw_i_tlast, aw_i_tvalid, aw_i_tready, aw_o_tlast, aw_o_tvalid, aw_o_tready;

      wire [127:0] s_axis_data_tuser = {2'd0 /* Data */, 1'b0 /* No time */, 1'b0 /* No EOB */,
                                        28'd0 /* Seq num & length automatically handled */,
                                        src_sid[16*i+15:16*i], next_dst_sid[16*i+15:16*i], 64'd0};

      axi_wrapper #(
        .MTU(MTU),
        .NUM_AXI_CONFIG_BUS(1),
        .SIMPLE_MODE(0))
      axi_wrapper (
        .bus_clk(ce_clk), .bus_rst(ce_rst),
        .clk(ce_clk), .reset(ce_rst),
        .clear_tx_seqnum(clear_tx_seqnum[0]),
        .next_dst(),
        .set_stb(), .set_addr(), .set_data(),
        .i_tdata(aw_i_tdata), .i_tlast(aw_i_tlast), .i_tvalid(aw_i_tvalid), .i_tready(aw_i_tready),
        .o_tdata(aw_o_tdata), .o_tlast(aw_o_tlast), .o_tvalid(aw_o_tvalid), .o_tready(aw_o_tready),
        .m_axis_data_tdata(m_axis_data_tdata[32*i+31:32*i]),
        .m_axis_data_tlast(m_axis_data_tlast[i]),
        .m_axis_data_tvalid(m_axis_data_tvalid[i]),
        .m_axis_data_tready(m_axis_data_tready[i]),
        .m_axis_data_tuser(), // Unused
        .s_axis_data_tdata(s_axis_data_tdata[32*i+31:32*i]),
        .s_axis_data_tlast(s_axis_data_tlast[i]),
        .s_axis_data_tvalid(s_axis_data_tvalid[i]),
        .s_axis_data_tready(s_axis_data_tready[i]),
        .s_axis_data_tuser(s_axis_data_tuser),
        .m_axis_config_tdata(),
        .m_axis_config_tlast(),
        .m_axis_config_tvalid(),
        .m_axis_config_tready(),
        .m_axis_pkt_len_tdata(),
        .m_axis_pkt_len_tvalid(),
        .m_axis_pkt_len_tready());

      // Demux input stream into either CVITA inteface, AXI stream interface, or both depend on their tready state
      // - Wait until header comes in then select whether to output on via AXI Wrapper or CVITA interface
      //   depending on which one is ready. If both are ready, output on both.
      reg hold_until_ready = 1'b1;
      reg [3:0] output_streams;  // 0: Invalid, 1: AXI Wrapper, 2: CVITA, 3: Both AXI Wrapper & CVITA
      always @(posedge ce_clk) begin
        if (ce_rst | clear_tx_seqnum[i]) begin
          hold_until_ready <= 1'b1;
          output_streams   <= 4'b0;
        end else begin
          // Demux to stream that ready to accept data (or both if both are ready)
          if (hold_until_ready & str_sink_tvalid[i] & (m_cvita_data_tready[i] | m_axis_data_tready[i])) begin
            hold_until_ready <= 1'b0;
            output_streams   <= {2'b0, m_cvita_data_tready[i], m_axis_data_tready[i]};
          end
          if (str_sink_tlast[i] & str_sink_tvalid[i] & str_sink_tready[i]) begin
            hold_until_ready <= 1'b1;
            output_streams   <= 4'b0;
          end
        end
      end

      wire str_sink_tvalid_int, str_sink_tready_int;
      assign str_sink_tready[i]  = str_sink_tready_int & ~hold_until_ready;
      assign str_sink_tvalid_int = str_sink_tvalid[i] & ~hold_until_ready;

      wire [63:0] m_cvita_tdata, m_axis_tdata;
      wire m_cvita_tlast, m_cvita_tvalid, m_cvita_tready, m_axis_tlast, m_axis_tvalid, m_axis_tready;
      wire [63:0] invalid_tdata, both_tdata;
      wire invalid_tlast, invalid_tvalid, both_tlast, both_tvalid, both_tready;
      axi_demux #(.WIDTH(64), .PRE_FIFO_SIZE(0), .POST_FIFO_SIZE(0), .SIZE(4)) axi_demux (
        .clk(ce_clk), .reset(ce_rst), .clear(clear_tx_seqnum[i]),
        .header(), .dest(output_streams),
        .i_tdata(str_sink_tdata[64*i+63:64*i]), .i_tlast(str_sink_tlast[i]), .i_tvalid(str_sink_tvalid_int), .i_tready(str_sink_tready_int),
        .o_tdata({both_tdata,m_cvita_tdata,m_axis_tdata,invalid_tdata}),
        .o_tlast({both_tlast,m_cvita_tlast,m_axis_tlast,invalid_tlast}),
        .o_tvalid({both_tvalid,m_cvita_tvalid,m_axis_tvalid,invalid_tvalid}),
        .o_tready({both_tready,m_cvita_tready,m_axis_tready,1'b0 /* Never output on invalid stream */}));

      assign m_cvita_data_tdata[64*i+63:64*i] = both_tvalid ? both_tdata : m_cvita_tdata;
      assign m_cvita_data_tlast[i]            = both_tvalid ? both_tlast : m_cvita_tlast;
      assign m_cvita_data_tvalid[i]           = both_tvalid ? 1'b1       : m_cvita_tvalid;
      assign m_cvita_tready                   = both_tvalid ? 1'b0       : m_cvita_data_tready[i];
      assign aw_i_tdata                       = both_tvalid ? both_tdata : m_axis_tdata;
      assign aw_i_tlast                       = both_tvalid ? both_tlast : m_axis_tlast;
      assign aw_i_tvalid                      = both_tvalid ? 1'b1       : m_axis_tvalid;
      assign m_axis_tready                    = both_tvalid ? 1'b0       : aw_i_tready;
      assign both_tready                      = both_tvalid ? 1'b0       : m_cvita_data_tready[i] & m_axis_data_tready[i];

      // Mux CVITA and AXI stream interfaces
      // - If USE_SEQ_NUM = 1, replace sequence number in header so it is consistent even
      //   if using both the AXI Wrapper and CVITA interfaces.
      wire hdr_stb, vita_time_stb;
      wire [1:0] pkt_type;
      wire eob, has_time;
      wire [15:0] payload_length;
      wire [15:0] src_sid_x;
      wire [15:0] dst_sid;
      wire [63:0] vita_time;
      wire [63:0] str_src_tdata_int, str_src_tdata_mux;
      wire str_src_tlast_mux, str_src_tvalid_mux, str_src_tready_mux;
      reg [11:0] tx_seqnum_cnt;
      // Logic to control replacing sequence number
      always @(posedge ce_clk) begin
        if (ce_rst | clear_tx_seqnum[i]) begin
          tx_seqnum_cnt   <= 'd0;
        end else begin
          if (str_src_tlast[i] & str_src_tvalid[i] & str_src_tready[i]) begin
            tx_seqnum_cnt <= tx_seqnum_cnt + 1'b1;
          end
        end
      end

      cvita_hdr_parser #(.REGISTER(0)) cvita_hdr_parser (
        .clk(ce_clk), .reset(ce_rst), .clear(clear_tx_seqnum[i]),
        .hdr_stb(hdr_stb),
        .pkt_type(pkt_type), .eob(eob), .has_time(has_time),
        .seqnum(), .length(), .payload_length(payload_length),
        .src_sid(src_sid_x), .dst_sid(dst_sid),
        .vita_time_stb(vita_time_stb), .vita_time(vita_time),
        .i_tdata(str_src_tdata_mux), .i_tlast(str_src_tlast_mux), .i_tvalid(str_src_tvalid_mux), .i_tready(str_src_tready_mux),
        .o_tdata(str_src_tdata_int), .o_tlast(str_src_tlast[i]), .o_tvalid(str_src_tvalid[i]), .o_tready(str_src_tready[i]));

      wire [127:0] modified_header;
      cvita_hdr_encoder cvita_hdr_encoder (
        .pkt_type(pkt_type), .eob(eob), .has_time(has_time),
        .seqnum(tx_seqnum_cnt), .payload_length(payload_length),
        .src_sid(src_sid_x), .dst_sid(dst_sid),
        .vita_time(vita_time),
        .header(modified_header));

      assign str_src_tdata[64*i+63:64*i] = (USE_SEQ_NUM == 1) ? str_src_tdata_int :
                                                      hdr_stb ? modified_header[127:64] :
                                                vita_time_stb ? modified_header[63:0] :
                                                                str_src_tdata_int;

      axi_mux #(.PRIO(0), .WIDTH(64), .PRE_FIFO_SIZE(0), .POST_FIFO_SIZE(0), .SIZE(2)) axi_mux (
        .clk(ce_clk), .reset(ce_rst), .clear(clear_tx_seqnum[i]),
        .i_tdata({s_cvita_data_tdata[64*i+63:64*i], aw_o_tdata}), .i_tlast({s_cvita_data_tlast[i], aw_o_tlast}),
        .i_tvalid({s_cvita_data_tvalid[i], aw_o_tvalid}), .i_tready({s_cvita_data_tready[i], aw_o_tready}),
        .o_tdata(str_src_tdata_mux), .o_tlast(str_src_tlast_mux), .o_tvalid(str_src_tvalid_mux), .o_tready(str_src_tready_mux));

    end
  endgenerate

endmodule