diff options
Diffstat (limited to 'fpga/usrp3')
| -rw-r--r-- | fpga/usrp3/sim/rfnoc/Makefile.srcs | 2 | ||||
| -rw-r--r-- | fpga/usrp3/sim/rfnoc/PkgChdrIfaceBfm.sv | 272 | ||||
| -rw-r--r-- | fpga/usrp3/sim/rfnoc/PkgChdrUtils.sv | 1 | ||||
| -rw-r--r-- | fpga/usrp3/sim/rfnoc/PkgCtrlIfaceBfm.sv | 125 | ||||
| -rw-r--r-- | fpga/usrp3/sim/rfnoc/PkgRfnocBlockCtrlBfm.sv | 418 | 
5 files changed, 418 insertions, 400 deletions
| diff --git a/fpga/usrp3/sim/rfnoc/Makefile.srcs b/fpga/usrp3/sim/rfnoc/Makefile.srcs index 329ffbd27..38bb86655 100644 --- a/fpga/usrp3/sim/rfnoc/Makefile.srcs +++ b/fpga/usrp3/sim/rfnoc/Makefile.srcs @@ -16,6 +16,8 @@ PkgChdrUtils.sv \  PkgChdrBfm.sv \  PkgAxisCtrlBfm.sv \  PkgRfnocItemUtils.sv \ +PkgCtrlIfaceBfm.sv \ +PkgChdrIfaceBfm.sv \  PkgRfnocBlockCtrlBfm.sv \  )) diff --git a/fpga/usrp3/sim/rfnoc/PkgChdrIfaceBfm.sv b/fpga/usrp3/sim/rfnoc/PkgChdrIfaceBfm.sv new file mode 100644 index 000000000..513910ee7 --- /dev/null +++ b/fpga/usrp3/sim/rfnoc/PkgChdrIfaceBfm.sv @@ -0,0 +1,272 @@ +// +// Copyright 2020 Ettus Research, A National Instruments Company +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// +// Module: PkgChdrIfaceBfm +// +// Description: This package includes a high-level bus functional model (BFM) +// for the AXIS-CHDR interface of a Transport Adapter or Stream Endpoint. +// + +package PkgChdrIfaceBfm; + +  import PkgChdrUtils::*; +  import PkgChdrBfm::*; + + +  typedef struct packed { +    chdr_vc_t   vc; +    logic       eob; +    logic       eov; +    logic       has_time; +    chdr_word_t timestamp; +  } packet_info_t; + + +  class ChdrIfaceBfm #(CHDR_W = 64) extends ChdrBfm #(CHDR_W); +    chdr_seq_num_t seq_num;  // Sequence number +     +    protected int max_payload_length;  // Maximum number of payload bytes per packet +    protected int ticks_per_word;      // Timestamp increment per CHDR_W sized word + + +    // Class constructor to create a new BFM instance. +    // +    //   m_chdr:    Interface for the master connection (BFM's CHDR output) +    //   s_chdr:    Interface for the slave connection (BFM's CHDR input) +    // +    function new( +      virtual AxiStreamIf #(CHDR_W).master m_chdr, +      virtual AxiStreamIf #(CHDR_W).slave  s_chdr, +      input   int                          max_payload_length = 2**$bits(chdr_length_t), +      input   int                          ticks_per_word     = CHDR_W/32 +    ); +      super.new(m_chdr, s_chdr); +      this.seq_num = 0; +      set_max_payload_length(max_payload_length); +      set_ticks_per_word(ticks_per_word); +    endfunction : new + + +    // Set the maximum payload size for packets. This value is used to split  +    // large send requests across multiple packets. +    // +    //   max_length:  Maximum payload length in bytes for each packet +    // +    function void set_max_payload_length(int max_payload_length); +      assert (max_payload_length % (CHDR_W/8) == 0) else begin +        $fatal(1, "ChdrIfaceBfm::set_max_payload_length: max_payload_length must be a multiple of CHDR_W in bytes"); +      end +      this.max_payload_length = max_payload_length; +    endfunction + + +    // Return the maximum payload size for packets. This value is used to split  +    // large send requests across multiple packets. +    function int get_max_payload_length(); +      return max_payload_length; +    endfunction + + +    // Set the timestamp ticks per CHDR_W sized word. +    // +    //   ticks_per_word:  Amount to increment the timestamp per CHDR_W sized word +    // +    function void set_ticks_per_word(int ticks_per_word); +      this.ticks_per_word = ticks_per_word; +    endfunction + + +    // Return the timestamp ticks per CHDR_W sized word. +    function int get_ticks_per_word(); +      return ticks_per_word; +    endfunction + + +    // Send a CHDR data packet. +    // +    //   data:       Data words to insert into the CHDR packet. +    //   data_bytes: The number of data bytes in the CHDR packet. This +    //               is useful if the data is not a multiple of the +    //               chdr_word_t size. +    //   metadata:   Metadata words to insert into the CHDR packet. Omit this +    //               argument (or set to an empty array) to not include +    //               metadata. +    //   pkt_info:   Data structure containing packet header information. +    // +    task send ( +      input chdr_word_t   data[$], +      input int           data_bytes  = -1, +      input chdr_word_t   metadata[$] = {}, +      input packet_info_t pkt_info    = 0 +    ); +      ChdrPacket      chdr_packet; +      chdr_header_t   chdr_header; + +      // Build packet +      chdr_packet = new(); +      chdr_header = '{ +        vc       : pkt_info.vc, +        eob      : pkt_info.eob, +        eov      : pkt_info.eov, +        seq_num  : seq_num++, +        pkt_type : pkt_info.has_time ? CHDR_DATA_WITH_TS : CHDR_DATA_NO_TS, +        dst_epid : dst_epid, +        default  : 0 +      }; +      chdr_packet.write_raw(chdr_header, data, metadata, pkt_info.timestamp, data_bytes); + +      // Send the packet +      put_chdr(chdr_packet); +    endtask : send + + +    // Send data as one or more CHDR data packets. The input data and metadata  +    // is automatically broken into max_payload_length'd packets. If multiple  +    // packets are needed, EOB and EOV are only applied to the last packet. +    // +    //   data:       Data words to insert into the CHDR packet. +    //   data_bytes: The number of data bytes in the CHDR packet. This +    //               is useful if the data is not a multiple of the +    //               chdr_word_t size. +    //   metadata:   Metadata words to insert into the CHDR packet. Omit this +    //               argument (or set to an empty array) to not include +    //               metadata. +    //   pkt_info:   Data structure containing packet header information. +    // +    task send_packets ( +      input chdr_word_t   data[$], +      input int           data_bytes  = -1, +      input chdr_word_t   metadata[$] = {}, +      input packet_info_t pkt_info    = 0 +    ); +      ChdrPacket      chdr_packet; +      chdr_header_t   chdr_header; +      chdr_pkt_type_t pkt_type; +      chdr_word_t     timestamp; +      int             num_pkts; +      int             payload_length; +      int             first_dword, last_dword; +      int             first_mword, last_mword; +      bit             eob, eov; +      chdr_word_t     temp_data[$]; +      chdr_word_t     temp_mdata[$]; + +      num_pkts   = $ceil(real'(data.size()*($bits(chdr_word_t)/8)) / max_payload_length); +      pkt_type   = pkt_info.has_time ? CHDR_DATA_WITH_TS : CHDR_DATA_NO_TS; +      timestamp  = pkt_info.timestamp; + +      // Make sure there's not too much metadata for this number of packets +      assert(metadata.size()*$bits(chdr_word_t) < num_pkts * 2**$bits(chdr_num_mdata_t) * CHDR_W) else +        $fatal(1, "ChdrIfaceBfm::send: Too much metadata for this send request"); + +      // Send the data, one packet at a time. +      for (int i = 0; i < num_pkts; i++) begin +        chdr_packet = new(); + +        // Figure out which data chunk to send next +        if (i == num_pkts-1) begin +          // The last packet, which may or may not be full-sized +          eob            = pkt_info.eob; +          eov            = pkt_info.eov; +          payload_length = (data_bytes < 0) ? data_bytes : data_bytes % max_payload_length; +          first_dword    = i*max_payload_length/($bits(chdr_word_t)/8); +          last_dword     = data.size()-1; +          first_mword    = i*(2**$bits(chdr_num_mdata_t) * CHDR_W / $bits(chdr_word_t)); +          last_mword     = metadata.size()-1; +        end else begin +          // A full-sized packet, not the last +          eob            = 1'b0; +          eov            = 1'b0; +          payload_length = max_payload_length; +          first_dword    = (i+0)*max_payload_length / ($bits(chdr_word_t)/8); +          last_dword     = (i+1)*max_payload_length / ($bits(chdr_word_t)/8) - 1; +          first_mword    = (i+0)*(2**$bits(chdr_num_mdata_t) * CHDR_W / $bits(chdr_word_t)); +          last_mword     = (i+1)*(2**$bits(chdr_num_mdata_t) * CHDR_W / $bits(chdr_word_t)) - 1; +          last_mword     = last_mword > metadata.size() ? metadata.size() : last_mword; +        end + +        // Build the packet +        chdr_header = '{ +          vc       : pkt_info.vc, +          eob      : eob, +          eov      : eov, +          seq_num  : seq_num++, +          pkt_type : pkt_type, +          dst_epid : dst_epid, +          default  : 0 +        }; + +        // Copy region of data and metadata to be sent in next packet +        temp_data = data[first_dword : last_dword]; +        if (first_mword < metadata.size()) temp_mdata = metadata[first_mword : last_mword]; +        else temp_mdata = {}; + +        // Build the packet +        chdr_packet.write_raw( +          chdr_header, +          temp_data,  +          temp_mdata, +          timestamp,  +          payload_length +        ); + +        // Send the packet +        put_chdr(chdr_packet); + +        // Update timestamp for next packet (in case this is not the last) +        timestamp += max_payload_length/(CHDR_W/8) * ticks_per_word; +      end +    endtask : send_packets + + +    // Receive a CHDR data packet and extract its contents. +    // +    //   data:        Data words from the received CHDR packet. +    //   data_bytes:  The number of data bytes in the CHDR packet. This +    //                is useful if the data is not a multiple of the +    //                chdr_word_t size. +    //   metadata:    Metadata words from the received CHDR packet. This +    //                will be an empty array if there was no metadata. +    //   pkt_info:    Data structure to receive packet header information. +    // +    task recv_adv ( +      output chdr_word_t   data[$], +      output int           data_bytes, +      output chdr_word_t   metadata[$], +      output packet_info_t pkt_info +    ); +      ChdrPacket chdr_packet; +      get_chdr(chdr_packet); + +      data               = chdr_packet.data; +      data_bytes         = chdr_packet.data_bytes(); +      metadata           = chdr_packet.metadata; +      pkt_info.timestamp = chdr_packet.timestamp; +      pkt_info.vc        = chdr_packet.header.vc; +      pkt_info.eob       = chdr_packet.header.eob; +      pkt_info.eov       = chdr_packet.header.eov; +      pkt_info.has_time  = chdr_packet.header.pkt_type == CHDR_DATA_WITH_TS ? 1 : 0; +    endtask : recv_adv + + +    // Receive a CHDR data packet and extract the data. Any metadata or +    // timestamp, if present, are discarded. +    // +    //   data:        Data words from the received CHDR packet. +    //   data_bytes:  The number of data bytes in the CHDR packet. This +    //                is useful if the data is not a multiple of the +    //                chdr_word_t size. +    // +    task recv(output chdr_word_t data[$], output int data_bytes); +      ChdrPacket chdr_packet; +      get_chdr(chdr_packet); +      data = chdr_packet.data; +      data_bytes = chdr_packet.data_bytes(); +    endtask : recv + +  endclass : ChdrIfaceBfm + + +endpackage : PkgChdrIfaceBfm diff --git a/fpga/usrp3/sim/rfnoc/PkgChdrUtils.sv b/fpga/usrp3/sim/rfnoc/PkgChdrUtils.sv index 95b9d5473..5f7abb46f 100644 --- a/fpga/usrp3/sim/rfnoc/PkgChdrUtils.sv +++ b/fpga/usrp3/sim/rfnoc/PkgChdrUtils.sv @@ -150,7 +150,6 @@ package PkgChdrUtils;      chdr_epid_t      dst_epid;    } chdr_header_t; -    // AXIS-Ctrl packet header    typedef struct packed {      // Word 1 diff --git a/fpga/usrp3/sim/rfnoc/PkgCtrlIfaceBfm.sv b/fpga/usrp3/sim/rfnoc/PkgCtrlIfaceBfm.sv new file mode 100644 index 000000000..0773eeea0 --- /dev/null +++ b/fpga/usrp3/sim/rfnoc/PkgCtrlIfaceBfm.sv @@ -0,0 +1,125 @@ +// +// Copyright 2020 Ettus Research, A National Instruments Company +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// +// Module: PkgCtrlIfaceBfm +// +// Description: This package includes high-level bus functional models (BFM) +// for the AXIS-Ctrl interface of a Stream Endpoint. +// + + +package PkgCtrlIfaceBfm; + +  import PkgChdrUtils::*; +  import PkgAxisCtrlBfm::*; + + +  class CtrlIfaceBfm extends AxisCtrlBfm; +    ctrl_port_t    dst_port; +    ctrl_port_t    src_port; +    ctrl_seq_num_t seq_num; + +    // Class constructor to create a new BFM instance. +    // +    //   m_chdr:    Interface for the master connection (BFM's AXIS output) +    //   s_chdr:    Interface for the slave connection (BFM's AXIS input) +    //   src_port:  Source port to use in generated control packets +    // +    function new( +      virtual AxiStreamIf #(32).master m_chdr, +      virtual AxiStreamIf #(32).slave  s_chdr, +      ctrl_port_t dst_port, +      ctrl_port_t src_port +    ); +      super.new(m_chdr, s_chdr); +      this.dst_port = dst_port; +      this.src_port = src_port; +      this.seq_num  = '0; +    endfunction : new + + +    // Send an AXIS-Ctrl read request packet and get the response. +    // +    //   addr:       Address for the read request +    //   word:       Data word that was returned in response to the read +    // +    task reg_read ( +      input  ctrl_address_t addr, +      output ctrl_word_t    word +    ); +      AxisCtrlPacket ctrl_packet; + +      // Create the AXIS-Ctrl packet +      ctrl_packet = new(); +      ctrl_packet.header = '{ +        seq_num  : seq_num++, +        num_data : 1, +        src_port : src_port, +        dst_port : dst_port, +        default  : 0 +      }; +      ctrl_packet.op_word = '{ +        op_code     : CTRL_OP_READ, +        byte_enable : ~0, +        address     : addr, +        default     : 0 +      }; +      ctrl_packet.data = { 0 }; + +      // Send the control packet and get the response +      put_ctrl(ctrl_packet); +      get_ctrl(ctrl_packet); +      word = ctrl_packet.data[0]; + +      assert(ctrl_packet.header.is_ack == 1 && +             ctrl_packet.op_word.status == CTRL_STS_OKAY) else begin +        $fatal(1, "CtrlIfaceBfm::reg_read: Did not receive CTRL_STS_OKAY status"); +      end +    endtask : reg_read + + +    // Send an AXIS-Ctrl write request packet and get the response. +    // +    //   addr:       Address for the write request +    //   word:       Data word to write +    // +    task reg_write ( +      ctrl_address_t addr, +      ctrl_word_t    word +    ); +      AxisCtrlPacket ctrl_packet; + +      // Create the AXIS-Ctrl packet +      ctrl_packet = new(); +      ctrl_packet.header = '{ +        seq_num  : seq_num++, +        num_data : 1, +        src_port : src_port, +        dst_port : dst_port, +        default  : 0 +      }; +      ctrl_packet.op_word = '{ +        op_code     : CTRL_OP_WRITE, +        byte_enable : ~0, +        address     : addr, +        default     : 0 +      }; + +      // Send the packet and get the response +      ctrl_packet.data = { word }; +      put_ctrl(ctrl_packet); +      get_ctrl(ctrl_packet); +      word = ctrl_packet.data[0]; + +      assert(ctrl_packet.header.is_ack == 1 && +             ctrl_packet.op_word.status == CTRL_STS_OKAY) else begin +        $fatal(1, "CtrlIfaceBfm::reg_write: Did not receive CTRL_STS_OKAY status"); +      end +    endtask : reg_write + +  endclass : CtrlIfaceBfm + + +endpackage : PkgCtrlIfaceBfm diff --git a/fpga/usrp3/sim/rfnoc/PkgRfnocBlockCtrlBfm.sv b/fpga/usrp3/sim/rfnoc/PkgRfnocBlockCtrlBfm.sv index 8712884c0..722299bb6 100644 --- a/fpga/usrp3/sim/rfnoc/PkgRfnocBlockCtrlBfm.sv +++ b/fpga/usrp3/sim/rfnoc/PkgRfnocBlockCtrlBfm.sv @@ -5,16 +5,13 @@  //  // Module: PkgRfnocBlockCtrlBfm  // -// Description: This package includes high-level bus functional models (BFMs) -// for communicating with RFNoC. This includes the following: +// Description: This package includes a high-level bus functional model (BFM) +// for a block controller. This models a software block controller and allows +// communication with a single RFNoC block. It includes the following:  // -//   - ChdrDataStreamBfm: Model for the AXIS CHDR interface of a Transport  -//                        Adapter or Stream Endpoint. -// -//   - RegisterIfaceBfm: Model for the AXIS CTRL interface of a Stream Endpoint. -// -//   - RfnocBlockCtrlBfm: Model for a software block controller, which includes  -//                        both a ChdrDataStreamBfm and a RegisterIfaceBfm. +//   - A CtrlIfaceBfm for an AXIS-Ctrl port connection of a block +//   - One or more ChdrIfaceBfm for the AXIS-CHDR port connections +//   - A connection for the backend interface of a block  // @@ -82,387 +79,10 @@ package PkgRfnocBlockCtrlBfm;    import PkgChdrUtils::*;    import PkgChdrBfm::*; -  import PkgAxisCtrlBfm::*; -  import PkgRfnocItemUtils::*; - - -  typedef struct packed { -    chdr_vc_t   vc; -    logic       eob; -    logic       eov; -    logic       has_time; -    chdr_word_t timestamp; -  } packet_info_t; - - -  //--------------------------------------------------------------------------- -  // CHDR Stream BFM -  //--------------------------------------------------------------------------- -  // -  // This class models an AXIS CHDR interface, such as that on a Transport -  // Adapter or in a Stream Endpoint. -  // -  //--------------------------------------------------------------------------- - -  class ChdrDataStreamBfm #(CHDR_W = 64) extends ChdrBfm #(CHDR_W); -    chdr_seq_num_t seq_num;  // Sequence number -     -    protected int max_payload_length;  // Maximum number of payload bytes per packet -    protected int ticks_per_word;      // Timestamp increment per CHDR_W sized word - - -    // Class constructor to create a new BFM instance. -    // -    //   m_chdr:    Interface for the master connection (BFM's CHDR output) -    //   s_chdr:    Interface for the slave connection (BFM's CHDR input) -    // -    function new( -      virtual AxiStreamIf #(CHDR_W).master m_chdr, -      virtual AxiStreamIf #(CHDR_W).slave  s_chdr, -      input   int                          max_payload_length = 2**$bits(chdr_length_t), -      input   int                          ticks_per_word     = CHDR_W/32 -    ); -      super.new(m_chdr, s_chdr); -      this.seq_num = 0; -      set_max_payload_length(max_payload_length); -      set_ticks_per_word(ticks_per_word); -    endfunction : new - - -    // Set the maximum payload size for packets. This value is used to split  -    // large send requests across multiple packets. -    // -    //   max_length:  Maximum payload length in bytes for each packet -    // -    function void set_max_payload_length(int max_payload_length); -      assert (max_payload_length % (CHDR_W/8) == 0) else begin -        $fatal(1, "ChdrDataStreamBfm::set_max_payload_length: max_payload_length must be a multiple of CHDR_W in bytes"); -      end -      this.max_payload_length = max_payload_length; -    endfunction - - -    // Return the maximum payload size for packets. This value is used to split  -    // large send requests across multiple packets. -    function int get_max_payload_length(); -      return max_payload_length; -    endfunction - - -    // Set the timestamp ticks per CHDR_W sized word. -    // -    //   ticks_per_word:  Amount to increment the timestamp per CHDR_W sized word -    // -    function void set_ticks_per_word(int ticks_per_word); -      this.ticks_per_word = ticks_per_word; -    endfunction - - -    // Return the timestamp ticks per CHDR_W sized word. -    function int get_ticks_per_word(); -      return ticks_per_word; -    endfunction - - -    // Send a CHDR data packet. -    // -    //   data:       Data words to insert into the CHDR packet. -    //   data_bytes: The number of data bytes in the CHDR packet. This -    //               is useful if the data is not a multiple of the -    //               chdr_word_t size. -    //   metadata:   Metadata words to insert into the CHDR packet. Omit this -    //               argument (or set to an empty array) to not include -    //               metadata. -    //   pkt_info:   Data structure containing packet header information. -    // -    task send ( -      input chdr_word_t   data[$], -      input int           data_bytes  = -1, -      input chdr_word_t   metadata[$] = {}, -      input packet_info_t pkt_info    = 0 -    ); -      ChdrPacket      chdr_packet; -      chdr_header_t   chdr_header; - -      // Build packet -      chdr_packet = new(); -      chdr_header = '{ -        vc       : pkt_info.vc, -        eob      : pkt_info.eob, -        eov      : pkt_info.eov, -        seq_num  : seq_num++, -        pkt_type : pkt_info.has_time ? CHDR_DATA_WITH_TS : CHDR_DATA_NO_TS, -        dst_epid : dst_epid, -        default  : 0 -      }; -      chdr_packet.write_raw(chdr_header, data, metadata, pkt_info.timestamp, data_bytes); - -      // Send the packet -      put_chdr(chdr_packet); -    endtask : send - - -    // Send data as one or more CHDR data packets. The input data and metadata  -    // is automatically broken into max_payload_length'd packets. If multiple  -    // packets are needed, EOB and EOV are only applied to the last packet. -    // -    //   data:       Data words to insert into the CHDR packet. -    //   data_bytes: The number of data bytes in the CHDR packet. This -    //               is useful if the data is not a multiple of the -    //               chdr_word_t size. -    //   metadata:   Metadata words to insert into the CHDR packet. Omit this -    //               argument (or set to an empty array) to not include -    //               metadata. -    //   pkt_info:   Data structure containing packet header information. -    // -    task send_packets ( -      input chdr_word_t   data[$], -      input int           data_bytes  = -1, -      input chdr_word_t   metadata[$] = {}, -      input packet_info_t pkt_info    = 0 -    ); -      ChdrPacket      chdr_packet; -      chdr_header_t   chdr_header; -      chdr_pkt_type_t pkt_type; -      chdr_word_t     timestamp; -      int             num_pkts; -      int             payload_length; -      int             first_dword, last_dword; -      int             first_mword, last_mword; -      bit             eob, eov; -      chdr_word_t     temp_data[$]; -      chdr_word_t     temp_mdata[$]; - -      num_pkts   = $ceil(real'(data.size()*($bits(chdr_word_t)/8)) / max_payload_length); -      pkt_type   = pkt_info.has_time ? CHDR_DATA_WITH_TS : CHDR_DATA_NO_TS; -      timestamp  = pkt_info.timestamp; - -      // Make sure there's not too much metadata for this number of packets -      assert(metadata.size()*$bits(chdr_word_t) < num_pkts * 2**$bits(chdr_num_mdata_t) * CHDR_W) else -        $fatal(1, "ChdrDataStreamBfm::send: Too much metadata for this send request"); - -      // Send the data, one packet at a time. -      for (int i = 0; i < num_pkts; i++) begin -        chdr_packet = new(); - -        // Figure out which data chunk to send next -        if (i == num_pkts-1) begin -          // The last packet, which may or may not be full-sized -          eob            = pkt_info.eob; -          eov            = pkt_info.eov; -          payload_length = (data_bytes < 0) ? data_bytes : data_bytes % max_payload_length; -          first_dword    = i*max_payload_length/($bits(chdr_word_t)/8); -          last_dword     = data.size()-1; -          first_mword    = i*(2**$bits(chdr_num_mdata_t) * CHDR_W / $bits(chdr_word_t)); -          last_mword     = metadata.size()-1; -        end else begin -          // A full-sized packet, not the last -          eob            = 1'b0; -          eov            = 1'b0; -          payload_length = max_payload_length; -          first_dword    = (i+0)*max_payload_length / ($bits(chdr_word_t)/8); -          last_dword     = (i+1)*max_payload_length / ($bits(chdr_word_t)/8) - 1; -          first_mword    = (i+0)*(2**$bits(chdr_num_mdata_t) * CHDR_W / $bits(chdr_word_t)); -          last_mword     = (i+1)*(2**$bits(chdr_num_mdata_t) * CHDR_W / $bits(chdr_word_t)) - 1; -          last_mword     = last_mword > metadata.size() ? metadata.size() : last_mword; -        end - -        // Build the packet -        chdr_header = '{ -          vc       : pkt_info.vc, -          eob      : eob, -          eov      : eov, -          seq_num  : seq_num++, -          pkt_type : pkt_type, -          dst_epid : dst_epid, -          default  : 0 -        }; - -        // Copy region of data and metadata to be sent in next packet -        temp_data = data[first_dword : last_dword]; -        if (first_mword < metadata.size()) temp_mdata = metadata[first_mword : last_mword]; -        else temp_mdata = {}; - -        // Build the packet -        chdr_packet.write_raw( -          chdr_header, -          temp_data,  -          temp_mdata, -          timestamp,  -          payload_length -        ); - -        // Send the packet -        put_chdr(chdr_packet); - -        // Update timestamp for next packet (in case this is not the last) -        timestamp += max_payload_length/(CHDR_W/8) * ticks_per_word; -      end -    endtask : send_packets - - -    // Receive a CHDR data packet and extract its contents. -    // -    //   data:        Data words from the received CHDR packet. -    //   data_bytes:  The number of data bytes in the CHDR packet. This -    //                is useful if the data is not a multiple of the -    //                chdr_word_t size. -    //   metadata:    Metadata words from the received CHDR packet. This -    //                will be an empty array if there was no metadata. -    //   pkt_info:    Data structure to receive packet header information. -    // -    task recv_adv ( -      output chdr_word_t   data[$], -      output int           data_bytes, -      output chdr_word_t   metadata[$], -      output packet_info_t pkt_info -    ); -      ChdrPacket chdr_packet; -      get_chdr(chdr_packet); - -      data               = chdr_packet.data; -      data_bytes         = chdr_packet.data_bytes(); -      metadata           = chdr_packet.metadata; -      pkt_info.timestamp = chdr_packet.timestamp; -      pkt_info.vc        = chdr_packet.header.vc; -      pkt_info.eob       = chdr_packet.header.eob; -      pkt_info.eov       = chdr_packet.header.eov; -      pkt_info.has_time  = chdr_packet.header.pkt_type == CHDR_DATA_WITH_TS ? 1 : 0; -    endtask : recv_adv - - -    // Receive a CHDR data packet and extract the data. Any metadata or -    // timestamp, if present, are discarded. -    // -    //   data:        Data words from the received CHDR packet. -    //   data_bytes:  The number of data bytes in the CHDR packet. This -    //                is useful if the data is not a multiple of the -    //                chdr_word_t size. -    // -    task recv(output chdr_word_t data[$], output int data_bytes); -      ChdrPacket chdr_packet; -      get_chdr(chdr_packet); -      data = chdr_packet.data; -      data_bytes = chdr_packet.data_bytes(); -    endtask : recv - -  endclass : ChdrDataStreamBfm - - - -  //--------------------------------------------------------------------------- -  // CTRL Stream BFM -  //--------------------------------------------------------------------------- -  // -  // This class models an AXIS CTRL interface, such as that in a Stream -  // Endpoint. -  // -  //--------------------------------------------------------------------------- - -  class RegisterIfaceBfm extends AxisCtrlBfm; -    ctrl_port_t    dst_port; -    ctrl_port_t    src_port; -    ctrl_seq_num_t seq_num; - -    // Class constructor to create a new BFM instance. -    // -    //   m_chdr:    Interface for the master connection (BFM's AXIS output) -    //   s_chdr:    Interface for the slave connection (BFM's AXIS input) -    //   src_port:  Source port to use in generated control packets -    // -    function new( -      virtual AxiStreamIf #(32).master m_chdr, -      virtual AxiStreamIf #(32).slave  s_chdr, -      ctrl_port_t dst_port, -      ctrl_port_t src_port -    ); -      super.new(m_chdr, s_chdr); -      this.dst_port = dst_port; -      this.src_port = src_port; -      this.seq_num  = '0; -    endfunction : new - - -    // Send an AXIS-Ctrl read request packet and get the response. -    // -    //   addr:       Address for the read request -    //   word:       Data word that was returned in response to the read -    // -    task reg_read ( -      input  ctrl_address_t addr, -      output ctrl_word_t    word -    ); -      AxisCtrlPacket ctrl_packet; - -      // Create the AXIS-Ctrl packet -      ctrl_packet = new(); -      ctrl_packet.header = '{ -        seq_num  : seq_num++, -        num_data : 1, -        src_port : src_port, -        dst_port : dst_port, -        default  : 0 -      }; -      ctrl_packet.op_word = '{ -        op_code     : CTRL_OP_READ, -        byte_enable : ~0, -        address     : addr, -        default     : 0 -      }; -      ctrl_packet.data = { 0 }; - -      // Send the control packet and get the response -      put_ctrl(ctrl_packet); -      get_ctrl(ctrl_packet); -      word = ctrl_packet.data[0]; - -      assert(ctrl_packet.header.is_ack == 1 && -             ctrl_packet.op_word.status == CTRL_STS_OKAY) else begin -        $fatal(1, "RegisterIfaceBfm::reg_read: Did not receive CTRL_STS_OKAY status"); -      end -    endtask : reg_read - - -    // Send an AXIS-Ctrl write request packet and get the response. -    // -    //   addr:       Address for the write request -    //   word:       Data word to write -    // -    task reg_write ( -      ctrl_address_t addr, -      ctrl_word_t    word -    ); -      AxisCtrlPacket ctrl_packet; - -      // Create the AXIS-Ctrl packet -      ctrl_packet = new(); -      ctrl_packet.header = '{ -        seq_num  : seq_num++, -        num_data : 1, -        src_port : src_port, -        dst_port : dst_port, -        default  : 0 -      }; -      ctrl_packet.op_word = '{ -        op_code     : CTRL_OP_WRITE, -        byte_enable : ~0, -        address     : addr, -        default     : 0 -      }; - -      // Send the packet and get the response -      ctrl_packet.data = { word }; -      put_ctrl(ctrl_packet); -      get_ctrl(ctrl_packet); -      word = ctrl_packet.data[0]; - -      assert(ctrl_packet.header.is_ack == 1 && -             ctrl_packet.op_word.status == CTRL_STS_OKAY) else begin -        $fatal(1, "RegisterIfaceBfm::reg_write: Did not receive CTRL_STS_OKAY status"); -      end -    endtask : reg_write +  import PkgCtrlIfaceBfm::*; +  import PkgChdrIfaceBfm::*; -  endclass : RegisterIfaceBfm +  export PkgChdrIfaceBfm::packet_info_t;    //--------------------------------------------------------------------------- @@ -476,9 +96,9 @@ package PkgRfnocBlockCtrlBfm;    class RfnocBlockCtrlBfm #(CHDR_W = 64);      local virtual RfnocBackendIf.master backend; -    local RegisterIfaceBfm              ctrl; -    local ChdrDataStreamBfm #(CHDR_W)   m_data[$]; -    local ChdrDataStreamBfm #(CHDR_W)   s_data[$]; +    local CtrlIfaceBfm              ctrl; +    local ChdrIfaceBfm #(CHDR_W)   m_data[$]; +    local ChdrIfaceBfm #(CHDR_W)   s_data[$];      local bit                           running;      localparam CMD_PROP_CYC = 5; @@ -516,7 +136,7 @@ package PkgRfnocBlockCtrlBfm;        int max_payload_length = 2**$bits(chdr_length_t),        int ticks_per_word     = CHDR_W/32      ); -      ChdrDataStreamBfm #(CHDR_W) bfm = new(m_chdr, null, max_payload_length, ticks_per_word); +      ChdrIfaceBfm #(CHDR_W) bfm = new(m_chdr, null, max_payload_length, ticks_per_word);        m_data.push_back(bfm);        return m_data.size() - 1;      endfunction : add_master_data_port @@ -528,7 +148,7 @@ package PkgRfnocBlockCtrlBfm;      function int add_slave_data_port(        virtual AxiStreamIf #(CHDR_W).slave s_chdr      ); -      ChdrDataStreamBfm #(CHDR_W) bfm = new(null, s_chdr); +      ChdrIfaceBfm #(CHDR_W) bfm = new(null, s_chdr);        s_data.push_back(bfm);        return s_data.size() - 1;      endfunction : add_slave_data_port @@ -550,7 +170,7 @@ package PkgRfnocBlockCtrlBfm;        int max_payload_length = 2**$bits(chdr_length_t),        int ticks_per_word     = CHDR_W/32      ); -      ChdrDataStreamBfm #(CHDR_W) bfm = new(m_chdr, null, max_payload_length, ticks_per_word); +      ChdrIfaceBfm #(CHDR_W) bfm = new(m_chdr, null, max_payload_length, ticks_per_word);        wait (m_data.size() == port_num);        m_data.push_back(bfm);      endtask : connect_master_data_port @@ -566,7 +186,7 @@ package PkgRfnocBlockCtrlBfm;        int port_num,        virtual AxiStreamIf #(CHDR_W).slave s_chdr      ); -      ChdrDataStreamBfm #(CHDR_W) bfm = new(null, s_chdr); +      ChdrIfaceBfm #(CHDR_W) bfm = new(null, s_chdr);        wait (s_data.size() == port_num);        s_data.push_back(bfm);      endtask : connect_slave_data_port @@ -587,12 +207,12 @@ package PkgRfnocBlockCtrlBfm;      endtask : run      // Return a handle to the control BFM -    function RegisterIfaceBfm get_ctrl_bfm(); +    function CtrlIfaceBfm get_ctrl_bfm();        return ctrl;      endfunction : get_ctrl_bfm      // Return a handle to the indicated master port BFM -    function ChdrDataStreamBfm #(CHDR_W) get_master_data_bfm(int port); +    function ChdrIfaceBfm #(CHDR_W) get_master_data_bfm(int port);        assert (port >= 0 && port < m_data.size()) else begin          $fatal(1, "Invalid master port number");        end @@ -600,7 +220,7 @@ package PkgRfnocBlockCtrlBfm;      endfunction : get_master_data_bfm      // Return a handle to the indicated slave port BFM -    function ChdrDataStreamBfm #(CHDR_W) get_slave_data_bfm(int port); +    function ChdrIfaceBfm #(CHDR_W) get_slave_data_bfm(int port);        assert (port >= 0 && port < m_data.size()) else begin          $fatal(1, "Invalid slave port number");        end | 
