Yeah, I agree with that assessment. I don't know what the problem is, either. For reference, though, here's the relevant parts of a two-input-one-output RFNoC block I did. This works for me.
Note that NUM_PORTS can be anything you want. I'm currently using NUM_PORTS=2. NUM_CHANNELS is 4, since I'm putting two streams into each sc16 input. // RFNoC Shell wire [31:0] set_data[0:NUM_PORTS-1]; wire [7:0] set_addr[0:NUM_PORTS-1]; wire [NUM_PORTS-1:0] set_stb; reg [63:0] rb_data[0:NUM_PORTS-1]; wire [7:0] rb_addr[0:NUM_PORTS-1]; wire [63:0] cmdout_tdata, ackin_tdata; wire cmdout_tlast, cmdout_tvalid, cmdout_tready, ackin_tlast, ackin_tvalid, ackin_tready; wire [NUM_PORTS-1:0] clear_tx_seqnum; wire [63:0] str_sink_tdata; wire str_sink_tlast, str_sink_tvalid, str_sink_tready; wire [63:0] str_src_tdata[0:NUM_PORTS-1]; wire [NUM_PORTS-1:0] str_src_tlast, str_src_tvalid, str_src_tready; wire [15:0] src_sid[0:NUM_PORTS-1]; wire [15:0] resp_in_dst_sid; wire [15:0] resp_out_dst_sid[0:NUM_PORTS-1]; // Set next destination in chain wire [15:0] next_dst[0:NUM_PORTS-1]; // AXI Wrapper // input (sink) data wire [31:0] in_tdata; wire [127:0] in_tuser; wire in_tlast, in_tvalid, in_tready; // predistorter output data (four of these) wire [15:0] out_tdata[0:NUM_CHANNELS-1]; wire [NUM_CHANNELS-1:0] out_tlast, out_tvalid, out_tready; wire [127:0] out_tuser[0:NUM_PORTS-1]; //only two of these //---------------------------------------------------------------------------- // Instantiations //---------------------------------------------------------------------------- // RFNoC Shell noc_shell #( .NOC_ID(NOC_ID), .STR_SINK_FIFOSIZE(STR_SINK_FIFOSIZE[7:0]), .INPUT_PORTS(1), .OUTPUT_PORTS(NUM_PORTS)) 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), // Compute Engine Clock Domain .clk(ce_clk), .reset(ce_rst), // Control Sink .set_data({set_data[1], set_data[0]}), .set_addr({set_addr[1], set_addr[0]}), .set_stb({set_stb[1], set_stb[0]}), .rb_data({rb_data[1], rb_data[0]}), .rb_stb({NUM_PORTS{1'b1}}), .rb_addr({rb_addr[1], rb_addr[0]}), // Control Source (unused) .cmdout_tdata(cmdout_tdata), .cmdout_tlast(cmdout_tlast), .cmdout_tvalid(cmdout_tvalid), .cmdout_tready(cmdout_tready), .ackin_tdata(ackin_tdata), .ackin_tlast(ackin_tlast), .ackin_tvalid(ackin_tvalid), .ackin_tready(ackin_tready), .resp_in_dst_sid({resp_in_dst_sid[1], resp_in_dst_sid[0]}), .resp_out_dst_sid({resp_out_dst_sid[1], resp_out_dst_sid[0]}), // Stream Sink .str_sink_tdata(str_sink_tdata), .str_sink_tlast(str_sink_tlast), .str_sink_tvalid(str_sink_tvalid), .str_sink_tready(str_sink_tready), // Stream Sources //TODO ideally should be parameterized for NUM_CHANNELS .str_src_tdata({str_src_tdata[1], str_src_tdata[0]}), .str_src_tlast(str_src_tlast), .str_src_tvalid(str_src_tvalid), .str_src_tready(str_src_tready), .src_sid({src_sid[1], src_sid[0]}), .next_dst_sid({next_dst[1], next_dst[0]}), .clear_tx_seqnum(clear_tx_seqnum), .debug(debug)); assign ackin_tready = 1'b1; <......snip.......> wire [31:0] mux_tdata[0:NUM_PORTS-1]; wire [NUM_PORTS-1:0] mux_tlast, mux_tvalid, mux_tready; axi_wrapper #( .SIMPLE_MODE(0) /* Handle header internally */) axi_wrapper_inst ( .clk(ce_clk), .reset(ce_rst), .clear_tx_seqnum(clear_tx_seqnum[0]), .next_dst(next_dst[0]), .set_stb(), .set_addr(), .set_data(), .i_tdata(str_sink_tdata), .i_tlast(str_sink_tlast), .i_tvalid(str_sink_tvalid), .i_tready(str_sink_tready), .o_tdata(str_src_tdata[0]), .o_tlast(str_src_tlast[0]), .o_tvalid(str_src_tvalid[0]), .o_tready(str_src_tready[0]), .m_axis_data_tdata(in_tdata), .m_axis_data_tlast(in_tlast), .m_axis_data_tvalid(in_tvalid), .m_axis_data_tready(in_tready), .m_axis_data_tuser(in_tuser), .s_axis_data_tdata(mux_tdata[0]), .s_axis_data_tlast(mux_tlast[0]), .s_axis_data_tvalid(mux_tvalid[0]), .s_axis_data_tready(mux_tready[0]), .s_axis_data_tuser(out_tuser[0]), .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()); genvar u; generate for (u = 1; u < NUM_PORTS; u = u + 1) begin axi_wrapper #( .SIMPLE_MODE(0) /* Handle header internally */) axi_wrapper_inst ( .clk(ce_clk), .reset(ce_rst), .clear_tx_seqnum(clear_tx_seqnum[u]), .next_dst(next_dst[u]), .set_stb(), .set_addr(), .set_data(), .i_tdata(), .i_tlast(), .i_tvalid(), .i_tready(), .o_tdata(str_src_tdata[u]), .o_tlast(str_src_tlast[u]), .o_tvalid(str_src_tvalid[u]), .o_tready(str_src_tready[u]), .m_axis_data_tdata(), .m_axis_data_tlast(), .m_axis_data_tvalid(), .m_axis_data_tready(), .m_axis_data_tuser(), .s_axis_data_tdata(mux_tdata[u]), .s_axis_data_tlast(mux_tlast[u]), .s_axis_data_tvalid(mux_tvalid[u]), .s_axis_data_tready(mux_tready[u]), .s_axis_data_tuser(out_tuser[u]), .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()); end endgenerate genvar s; generate for (s = 0; s < NUM_PORTS; s = s + 1) begin // Handle headers cvita_hdr_modify cvita_hdr_modify_inst ( .header_in(in_tuser), .header_out(out_tuser[s]), .use_pkt_type(1'b0), .pkt_type(), .use_has_time(1'b0), .has_time(), .use_eob(1'b0), .eob(), .use_seqnum(1'b0), .seqnum(), .use_length(1'b0), .length(), .use_src_sid(1'b1), .src_sid(src_sid[s]), .use_dst_sid(1'b1), .dst_sid(next_dst[s]), .use_vita_time(1'b0), .vita_time()); end endgenerate <.....snip.......> Nick On Tue, Sep 26, 2017 at 8:24 AM Dario Pennisi <da...@iptronix.com> wrote: > Hi Nick, > > Sure. The block is a demodulator so basically it inputs samples and > outputs packet bytes in bursts so of course we have rate change. > > The relevant code is below: > > > > cvita_hdr_decoder cvita_hdr_decoder0 ( > > .header(m_axis0_data_tuser), > > .pkt_type(), .eob(), .has_time(), > > .seqnum(), .length(), .payload_length(), > > .src_sid(), .dst_sid(), > > .vita_time(vita_time_in[0]) > > ); > > cvita_hdr_decoder cvita_hdr_decoder1 ( > > .header(m_axis01_data_tuser), > > .pkt_type(), .eob(), .has_time(), > > .seqnum(), .length(), .payload_length(), > > .src_sid(), .dst_sid(), > > .vita_time(vita_time_in[1]) > > ); > > > > cvita_hdr_encoder cvita_hdr_encoder ( > > .pkt_type(2'd0), .eob(1'b1), .has_time(1'b1), > > .seqnum(0), .payload_length(0), .dst_sid(next_dst_sid[0]), > .src_sid(src_sid[0]), > > .vita_time(vita_time_out), > > .header(s_axis0_data_tuser)); > > > > Basically I extract the time from incoming packets and then use that to > feed timestamp to the processing logic which outputs its timestamp in > vita_time_out. > > Since I am outputting bursts I am setting eob and has time and since I > don’t know packet length in advance I set length to 0. > > src_sid and dst_sid are set equal to those decoded by noc shell for the > first channel. > > > > The one thing I don’t understand here is what has this to do with the fact > that one input channel is not streaming… > > As I mentioned in this condition my first input channel is streaming data > and processing logic connected to it is working perfectly and outputting > decoded data which I can receive correctly on the host. The problem is that > data is not being streamed to the second input channel (or at least if it > is then it’s not being demultiplexed by noc shell). I can’t see any logic > that makes cvita hdr, which is sent to the output, dependent on what’s on > the input…. > > > > Dario Pennisi > > > > *From:* Nick Foster [mailto:bistrom...@gmail.com] > *Sent:* Tuesday, September 26, 2017 5:16 PM > *To:* Dario Pennisi <da...@iptronix.com>; usrp-users@lists.ettus.com > > > *Subject:* Re: [USRP-users] rfnoc block with two inputs > > > > Dario, > > > > Glad simulation appears to be working. > > > > Since you aren't using simple mode in the AXI wrapper (I assume because > you're rate-changing inside the block, or some such) can you post the > section of your code which handles the VITA headers? > > > > Nick > > > > On Tue, Sep 26, 2017 at 5:15 AM Dario Pennisi <da...@iptronix.com> wrote: > > Hi, > > I managed to get a good simulation for the two inputs. I did it by > modifying default test bench this way: > > - localparam NUM_STREAMS = 2; // Number of test bench streams > - modified RFNOC_CONNECT to two RFNOC_CONNECT_BLOCK_PORT calls each > with a different port. Port 0 of TB connected to port 0 of DUT and port 1 > of TB connected to port 1 of DUT > - modified data streaming part with two calls to tb_streamer.send each > with a different channel > > > > this way I can see data being pumped in on both ports, at least in > simulation. IP does what it should so at this point I tend to think there > is no issue on the FPGA side. > > > > Since I am connecting to two radio blocks and since internal bus is 166 > MHz/64 bit I modified the device3 arguments to "master_clock_rate=120e6", > this way I would have 120MSPS at 32 bit x 2 muxed on the input bus of the > IP. This should leave enough room for overhead. > > > > Now. In these conditions I still don’t see data coming from the second > channel so am thinking that the issue must be on the software side. > > > > Any help would be greatly appreciated. > > Thanks, > > > > Dario Pennisi > > *From:* Dario Pennisi > *Sent:* Tuesday, September 26, 2017 12:00 PM > > > *To:* usrp-users@lists.ettus.com; Nick Foster <bistrom...@gmail.com> > > *Subject:* RE: [USRP-users] rfnoc block with two inputs > > > > Hi, > > I moved forward a bit but didn’t really come up to a solution. > > In my block I doublechecked the signals which are replicated for each > input and made sure they are connected at top level. This turned out to be > apparently useless because I only have one output so src_sid and dst_sid > for the second input channel are basically not going anywhere as there is > no second output. > > Is it at all possible to have 2 inputs and 1 output or there is a strict > need to have the same number of inputs and outputs? > > On the host side which are the points I can tap into to check what’s going > on? > > > > I also would be interested in trying simulation but didn’t find any > example of simulation with 2 inputs. > > Thanks, > > > > Dario Pennisi > > *From:* Dario Pennisi > *Sent:* Monday, September 25, 2017 11:11 PM > *To:* usrp-users@lists.ettus.com; Nick Foster <bistrom...@gmail.com> > *Subject:* Re: [USRP-users] rfnoc block with two inputs > > > > Hi Nick, > > Thank you for your feedback. I didn't notice src and data Sid are per > input however looking at code I don't think this is the problem. My > understanding is that src Sid is used to form cvita packet going out of the > block. In simple mode axis wrapper doesn't seem to use while it is used by > cvita encoder used for tuser. In my case I have 2 inputs and 1 output. I am > using Sid form channel 0 to create cvita header for the output. > > Since I don't have a second output it seems to me src and day Sid for 2nd > input are not used anyway... > > For the rest there doesn't seem to be any other connection. > > Am I missing something? > > Btw is there any example of a block with 2 in and 1 out? I found only > addsub which has 2 out and is not even using axis wrapper... > > Thanks > > Dario Pennisi > > > > > > > > On Mon, Sep 25, 2017 at 9:28 PM +0200, "Nick Foster" <bistrom...@gmail.com> > wrote: > > Couple of problems just offhand. > > > > * src_sid is a one-per-input signal. See noc_shell.v for details. > > * Settings buses and readback buses are one-per (max(input, output)). > Again, see noc_shell.v. I don't think this is a problem for you, though. > > > > You should be getting errors in simulation (or warnings in synthesis) > right now. Look very carefully through these warnings to see which signals > are undriven. My guess is src_sid is undriven on the top 16 bits and so you > can't set src_sid correctly for input 1. > > > > Nick > > > > On Mon, Sep 25, 2017 at 12:00 PM Dario Pennisi <da...@iptronix.com> wrote: > > Hi, > > It’s quite complex and long… posting the initial part with shell and > wrappers > > > > module noc_block_demod #( > > parameter NOC_ID = 64'h1408E12980FDE75E, > > parameter MAX_PACKET_SIZE = 64) > > ( > > input bus_clk, input bus_rst, > > input ce_clk, input ce_rst, > > 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, > > output [63:0] debug > > ); > > > > //////////////////////////////////////////////////////////// > > // > > // RFNoC Shell > > // > > //////////////////////////////////////////////////////////// > > wire [31:0] set_data; > > wire [7:0] set_addr; > > wire set_stb; > > reg rb_stb; > > reg [63:0] rb_data; > > wire [7:0] rb_addr; > > > > wire [63:0] cmdout_tdata, ackin_tdata; > > wire cmdout_tlast, cmdout_tvalid, cmdout_tready, ackin_tlast, > ackin_tvalid, ackin_tready; > > > > wire [2*64-1:0] str_sink_tdata; > > wire [1:0] str_sink_tlast, str_sink_tvalid, str_sink_tready; > > > > wire [63:0] str_src_tdata; > > wire str_src_tlast, str_src_tvalid, str_src_tready; > > > > wire [15:0] src_sid; > > wire [15:0] next_dst_sid, resp_out_dst_sid; > > wire [15:0] resp_in_dst_sid; > > > > wire clear_tx_seqnum; > > > > noc_shell #( > > .NOC_ID(NOC_ID), > > .INPUT_PORTS(2) > > ) > > 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), > > .rb_stb(rb_stb), .rb_data(rb_data), .rb_addr(rb_addr), > > // Control Source > > .cmdout_tdata(cmdout_tdata), .cmdout_tlast(cmdout_tlast), > .cmdout_tvalid(cmdout_tvalid), .cmdout_tready(cmdout_tready), > > .ackin_tdata(ackin_tdata), .ackin_tlast(ackin_tlast), > .ackin_tvalid(ackin_tvalid), .ackin_tready(ackin_tready), > > // Stream Sink > > .str_sink_tdata(str_sink_tdata), .str_sink_tlast(str_sink_tlast), > .str_sink_tvalid(str_sink_tvalid), .str_sink_tready(str_sink_tready), > > // Stream Source > > .str_src_tdata(str_src_tdata), .str_src_tlast(str_src_tlast), > .str_src_tvalid(str_src_tvalid), .str_src_tready(str_src_tready), > > // Stream IDs set by host > > .src_sid(src_sid), // SID of this block > > .next_dst_sid(next_dst_sid), // Next destination SID > > .resp_in_dst_sid(resp_in_dst_sid), // Response destination SID for > input stream responses / errors > > .resp_out_dst_sid(resp_out_dst_sid), // Response destination SID for > output stream responses / errors > > // Misc > > .vita_time('d0), .clear_tx_seqnum(clear_tx_seqnum), > > .debug(debug)); > > > > //////////////////////////////////////////////////////////// > > // > > // AXI Wrapper > > // Convert RFNoC Shell interface into AXI stream interface > > // > > //////////////////////////////////////////////////////////// > > wire [31:0] m_axis0_data_tdata; > > wire m_axis0_data_tlast; > > wire m_axis0_data_tvalid; > > wire m_axis0_data_tready; > > wire [127:0] m_axis0_data_tuser; > > > > wire [31:0] m_axis1_data_tdata; > > wire m_axis1_data_tlast; > > wire m_axis1_data_tvalid; > > wire m_axis1_data_tready; > > wire [127:0] m_axis1_data_tuser; > > > > wire [31:0] s_axis0_data_tdata; > > wire s_axis0_data_tlast; > > wire s_axis0_data_tvalid; > > wire s_axis0_data_tready; > > wire [127:0] s_axis0_data_tuser; > > > > wire [31:0] s_axis1_data_tdata; > > wire s_axis1_data_tlast; > > wire s_axis1_data_tvalid; > > wire s_axis1_data_tready; > > wire [127:0] s_axis1_data_tuser; > > wire [63:0] vita_time_in; > > wire [63:0] vita_time_out; > > // reg [11:0] seq_num; > > > > axi_wrapper #( > > .SIMPLE_MODE(0)) > > axi_wrapper0 ( > > .clk(ce_clk), .reset(ce_rst), > > .clear_tx_seqnum(clear_tx_seqnum), > > .next_dst(next_dst_sid), > > .set_stb(set_stb), .set_addr(set_addr), .set_data(set_data), > > .i_tdata(str_sink_tdata[63:0]), .i_tlast(str_sink_tlast[0]), > .i_tvalid(str_sink_tvalid[0]), .i_tready(str_sink_tready[0]), > > .o_tdata(str_src_tdata), .o_tlast(str_src_tlast), > .o_tvalid(str_src_tvalid), .o_tready(str_src_tready), > > .m_axis_data_tdata(m_axis0_data_tdata), > > .m_axis_data_tlast(m_axis0_data_tlast), > > .m_axis_data_tvalid(m_axis0_data_tvalid), > > .m_axis_data_tready(m_axis0_data_tready), > > .m_axis_data_tuser(m_axis0_data_tuser), > > .s_axis_data_tdata(s_axis0_data_tdata), > > .s_axis_data_tlast(s_axis0_data_tlast), > > .s_axis_data_tvalid(s_axis0_data_tvalid), > > .s_axis_data_tready(s_axis0_data_tready), > > .s_axis_data_tuser(s_axis0_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()); > > > > axi_wrapper #( > > .SIMPLE_MODE(0)) > > axi_wrapper1 ( > > .clk(ce_clk), .reset(ce_rst), > > .clear_tx_seqnum(clear_tx_seqnum), > > .next_dst(next_dst_sid), > > .set_stb(set_stb), .set_addr(set_addr), .set_data(set_data), > > .i_tdata(str_sink_tdata[127:64]), .i_tlast(str_sink_tlast[1]), > .i_tvalid(str_sink_tvalid[1]), .i_tready(str_sink_tready[1]), > > // .o_tdata(str_src_tdata), .o_tlast(str_src_tlast), > .o_tvalid(str_src_tvalid), .o_tready(str_src_tready), > > .m_axis_data_tdata(m_axis1_data_tdata), > > .m_axis_data_tlast(m_axis1_data_tlast), > > .m_axis_data_tvalid(m_axis1_data_tvalid), > > .m_axis_data_tready(m_axis1_data_tready), > > .m_axis_data_tuser(), > > .s_axis_data_tdata(), > > .s_axis_data_tlast(), > > .s_axis_data_tvalid(), > > .s_axis_data_tready(), > > .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()); > > … > > > > As I mentioned I checked with ILA and ready is high for str_sink_tready so > input is ready to accept data but I never see the valid go high. > > Thanks, > > > > Dario Pennisi > > > >
_______________________________________________ USRP-users mailing list USRP-users@lists.ettus.com http://lists.ettus.com/mailman/listinfo/usrp-users_lists.ettus.com