I will try to take a stab at your first question. The example I like to look at (which I think makes things look clean) is the noc_block_ddc.v. In there, they use a generate block to create multiple axi_wrappers. It is hard to find examples for things that involve more than one port and I wish there was better documentation on it, but this is one of the few noc blocks that has 2x in and 2x out. Due to the number of people who need mutiple ports, I would love to see a: * 2-in 1-out (I know that a dummy port needs to be there, I would just like to see how it would be handled more) *1-in 2-out (ditto to above's comment) *2-in 2-out sharing the stream *2-in 2-out using different paths for the two streams ~Jason --------- Original Message --------- Subject: [USRP-users] Creating Double Ported Source Block and Running It's Testbench From: "shachar J. brown via USRP-users" <usrp-users@lists.ettus.com> Date: 7/26/18 9:13 am To: "shachar J. brown via USRP-users" <usrp-users@lists.ettus.com> Cc: "ishai alouche" <ishai.alou...@gmail.com>
Hi Everyone, I have created a source block with two output ports using the rfnocmodtool. My first question concerns the implementation of the axi_wrappers: I have inserted two axi_wrappers, one for each port (Full code below). Is there any more preferable way to construct the axi_wrapper interface? My second question regards the testbench: In an effort to mimic the noc_block_addsuboot.sv, I have used the tb_streamer.pull_word, and specified in the last argument which port to pull from - '0' for the first port and '1' for the second (Full code below). unfortunately, I received twice the same signal from the first port, and none of the signals from the second. What have I done wrong? Thanks a lot! #################################################### ----------------------1. Code of axi-wrappers:-------------------------------- ##################################################### //////////////////////////////////////////////////////////// // // RFNoC Shell // //////////////////////////////////////////////////////////// wire [31:0] set_data [0:1]; wire [7:0] set_addr [0:1]; wire set_stb [0:1]; reg [63:0] rb_data [0:1]; // not exist in split stream block wire [7:0] rb_addr [0:1]; // not exist in split stream block wire [63:0] cmdout_tdata, ackin_tdata; wire cmdout_tlast, cmdout_tvalid, cmdout_tready, ackin_tlast, ackin_tvalid, ackin_tready; wire [63:0] str_sink_tdata; wire str_sink_tlast, str_sink_tvalid, str_sink_tready; wire [63:0] str_src_tdata[0:1]; wire [1:0] str_src_tlast, str_src_tvalid, str_src_tready; wire [15:0] resp_out_dst_sid[0:1]; // not exist in split stream block wire [15:0] resp_in_dst_sid; // not exist in split stream block /*wire [31:0] in_tdata; wire [127:0] in_tuser; wire in_tlast, in_tvalid, in_tready; wire [31:0] out_tdata[0:1]; wire [127:0] out_tuser[0:1], out_tuser_pre[0:1]; wire [1:0] out_tlast, out_tvalid, out_tready;*/ wire [1:0] clear_tx_seqnum; wire [15:0] src_sid[0:1], next_dst_sid[0:1]; // wire [15:0] src_sid, next_dst_sid; noc_shell #( .NOC_ID(NOC_ID), .STR_SINK_FIFOSIZE(STR_SINK_FIFOSIZE), .OUTPUT_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[1],set_data[0]}), .set_addr({set_addr[1],set_addr[0]}), .set_stb({set_stb[1],set_stb[0]}), .rb_stb(2'b1), .rb_data({rb_data[1],rb_data[0]}), .rb_addr({rb_addr[1],rb_addr[0]}), //64'b0 // 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[1],str_src_tdata[0]}), .str_src_tlast({str_src_tlast[1],str_src_tlast[0]}), .str_src_tvalid({str_src_tvalid[1],str_src_tvalid[0]}), .str_src_tready({str_src_tready[1],str_src_tready[0]}), // Stream IDs set by host .src_sid({src_sid[1],src_sid[0]}), // SID of this block .next_dst_sid({next_dst_sid[1],next_dst_sid[0]}), // 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[1],resp_out_dst_sid[0]}), // Response destination SID for output stream responses / errors // Misc .vita_time('d0), .clear_tx_seqnum({clear_tx_seqnum[1],clear_tx_seqnum[0]}), .debug(debug)); // Null sink //assign str_sink_tready = 1'b1; // Control Source Unused assign cmdout_tdata = 64'd0; assign cmdout_tlast = 1'b0; assign cmdout_tvalid = 1'b0; assign ackin_tready = 1'b1; //////////////////////////////////////////////////////////// // // AXI Wrapper // Convert RFNoC Shell interface into AXI stream interface // //////////////////////////////////////////////////////////// wire [31:0] m_axis_data_tdata; (* dont_touch="true",mark_debug="true"*) wire m_axis_data_tlast; (* dont_touch="true",mark_debug="true"*) wire m_axis_data_tvalid; (* dont_touch="true",mark_debug="true"*) wire m_axis_data_tready; wire [63:0] s_axis_data_tdata; wire [255:0] s_axis_data_tuser; (* dont_touch="true",mark_debug="true"*) wire s_axis_data_tlast; (* dont_touch="true",mark_debug="true"*) wire [1:0] s_axis_data_tvalid; (* dont_touch="true",mark_debug="true"*) wire [1:0] s_axis_data_tready; wire s_axis_data_tvalid_int; wire s_axis_data_tready_int; axi_wrapper #( .SIMPLE_MODE(0), .RESIZE_OUTPUT_PACKET(1)) axi_wrapper ( .clk(ce_clk), .reset(ce_rst), .clear_tx_seqnum(clear_tx_seqnum[0]), .next_dst(next_dst_sid[0]), .set_stb(set_stb[0]), .set_addr(set_addr[0]), .set_data(set_data[0]), .i_tdata(), .i_tlast(), .i_tvalid(), .i_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(), // I add it for the input signal .m_axis_data_tlast(), // I add it for the input signal .m_axis_data_tvalid(), // I add it for the input signal .m_axis_data_tready(1'b1), //1'b1 .m_axis_data_tuser(), .s_axis_data_tdata(s_axis_data_tdata[31:0]), // .s_axis_data_tlast(), .s_axis_data_tvalid(s_axis_data_tvalid[0]), .s_axis_data_tready(s_axis_data_tready[0]), .s_axis_data_tuser(s_axis_data_tuser[127: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()); axi_wrapper #( .SIMPLE_MODE(0), .RESIZE_OUTPUT_PACKET(1)) axi_wrapper_1 ( .clk(ce_clk), .reset(ce_rst), .clear_tx_seqnum(clear_tx_seqnum[1]), .next_dst(next_dst_sid[1]), .set_stb(set_stb[1]), .set_addr(set_addr[1]), .set_data(set_data[1]), //.i_tdata(str_sink_tdata), .i_tlast(str_sink_tlast), .i_tvalid(str_sink_tvalid), .i_tready(str_sink_tready), .i_tdata(), .i_tlast(), .i_tvalid(), .i_tready(), .o_tdata(str_src_tdata[1]), .o_tlast(str_src_tlast[1]), .o_tvalid(str_src_tvalid[1]), .o_tready(str_src_tready[1]), .m_axis_data_tdata(), .m_axis_data_tlast(), .m_axis_data_tvalid(), .m_axis_data_tready(1'b1), .m_axis_data_tuser(), .s_axis_data_tdata(s_axis_data_tdata[63:32]),// .s_axis_data_tlast(), .s_axis_data_tvalid(s_axis_data_tvalid[1]), .s_axis_data_tready(s_axis_data_tready[1]), .s_axis_data_tuser(s_axis_data_tuser[255:128]), .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()); #################################################### ----------------------2. Code of tb_streamer.pull_word--------------------- ##################################################### module noc_block_TXsource_tb(); `TEST_BENCH_INIT("noc_block_TXsource",`NUM_TEST_CASES,`NS_PER_TICK); localparam BUS_CLK_PERIOD = $ceil(1e9/166.67e6); localparam CE_CLK_PERIOD = $ceil(1e9/200e6); localparam NUM_CE = 1; // Number of Computation Engines / User RFNoC blocks to simulate localparam NUM_STREAMS = 2; // Number of test bench streams (need to be 2 for two ports input or outputs `RFNOC_SIM_INIT(NUM_CE, NUM_STREAMS, BUS_CLK_PERIOD, CE_CLK_PERIOD); `RFNOC_ADD_BLOCK(noc_block_TXsource, 0); /******************************************************** ** Test 3 -- Connect RFNoC blocks ********************************************************/ `TEST_CASE_START("Connect RFNoC blocks"); `RFNOC_CONNECT_BLOCK_PORT(noc_block_TXsource,0,noc_block_tb,0,SC16,SPP); `RFNOC_CONNECT_BLOCK_PORT(noc_block_TXsource,1,noc_block_tb,1,SC16,SPP); `TEST_CASE_DONE(1); /******************************************************** ** Test 5 -- Test sequence betch0 only ********************************************************/ fork begin /* `TEST_CASE_START("Start write"); for (int j = 0; j < TEST_LENGTH_1; j++) begin {carry, Sin_skip} = Sin_skip + phase_step_reg; mem_ind = Sin_skip [acclen-1-:accScale]; tb_streamer.push_word(Sin_table[mem_ind],1'b1); end `TEST_CASE_DONE(1); */ end begin // `TEST_CASE_START("Start read 1"); for (int i = 0; i < TEST_LENGTH_1; ++i) begin tb_streamer.pull_word({recv_value_image_out_1,recv_value_real_out_1},last_out_1,0); tb_streamer.pull_word({recv_value_image_out_2,recv_value_real_out_2},last_out_2,1); expected_value_out_1 = 5; expected_value_out_2 = 5; $sformat(s_1, "The real output value is: %0d, and image is: %0d, i is: %0d", recv_value_real_out_1, recv_value_image_out_1,i); // $sformat(s, "Incorrect value received! Expected: %0d, Received: %0d, i is: %0d", expected_value, {recv_value_image,recv_value_real},i); `ASSERT_ERROR({recv_value_real_out_1, recv_value_image_out_1} == expected_value_out_1, s_2); $sformat(s_2, "The real output value is: %0d, and image is: %0d, i is: %0d", recv_value_real_out_2, recv_value_image_out_2,i); // $sformat(s, "Incorrect value received! Expected: %0d, Received: %0d, i is: %0d", expected_value, {recv_value_image,recv_value_real},i); `ASSERT_ERROR({recv_value_real_out_2, recv_value_image_out_2} == expected_value_out_2, s_2); end end join //`TEST_CASE_DONE(1); `TEST_BENCH_DONE; _______________________________________________ USRP-users mailing list USRP-users@lists.ettus.com http://lists.ettus.com/mailman/listinfo/usrp-users_lists.ettus.com
_______________________________________________ USRP-users mailing list USRP-users@lists.ettus.com http://lists.ettus.com/mailman/listinfo/usrp-users_lists.ettus.com