Hi nick, Thank you.. the example you posted seems a 1 input 2 output block which is the opposite I'm trying to do. Btw, is there any reason why you seem to be excluding software is an issue? Note that in my case I have a cpp controller as I need to do some custom register programming. I noticed that in rfnoc XML block definition it's possible to either specify two sinks or have one sync with nports set to 2 but could not really spot what the difference is other than that setting nports to 2 i see that noc_block_impl is actually setting up just one sink and is raising an error for the mismatch between the two XML files (with the one in GRC) so I guess this setting requires some special stuff in GRC XML as well but could not figure that out Thanks,
Dario Pennisi Da: Nick Foster Inviato: martedì 26 settembre, 20:27 Oggetto: Re: [USRP-users] rfnoc block with two inputs A: Dario Pennisi, usrp-users@lists.ettus.com 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<mailto: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<mailto:bistrom...@gmail.com>] Sent: Tuesday, September 26, 2017 5:16 PM To: Dario Pennisi <da...@iptronix.com<mailto:da...@iptronix.com>>; usrp<mailto:usrp-users@lists.ettus.com>-us...@lists.ettus.com<mailto: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<mailto: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<mailto:usrp-users@lists.ettus.com>-us...@lists.ettus.com<mailto:usrp-users@lists.ettus.com>; Nick Foster <bistromath<mailto:bistrom...@gmail.com>@gmail.com<mailto: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<mailto:usrp-users@lists.ettus.com>-us...@lists.ettus.com<mailto:usrp-users@lists.ettus.com>; Nick Foster <bistromath<mailto:bistrom...@gmail.com>@gmail.com<mailto: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" <bistromath<mailto:bistrom...@gmail.com>@gmail.com<mailto: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<mailto: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