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

Reply via email to