//----------------------------------------------------------------------
//   Copyright 2010 Mentor Graphics Corporation
//   Copyright 2010-2011 Synopsys, Inc.
//   All Rights Reserved Worldwide
//
//   Licensed under the Apache License, Version 2.0 (the
//   "License"); you may not use this file except in
//   compliance with the License.  You may obtain a copy of
//   the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in
//   writing, software distributed under the License is
//   distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
//   CONDITIONS OF ANY KIND, either express or implied.  See
//   the License for the specific language governing
//   permissions and limitations under the License.
//----------------------------------------------------------------------

//----------------------------------------------------------------------
// Title: TLM Generic Payload & Extensions
//----------------------------------------------------------------------
// The Generic Payload transaction represents a generic 
// bus read/write access. It is used as the default transaction in
// TLM2 blocking and nonblocking transport interfaces.
//----------------------------------------------------------------------


//---------------
// Group: Globals
//---------------
//
// Defines, Constants, enums.


// Enum: uvm_tlm_command_e
//
// Command attribute type definition
//
// UVM_TLM_READ_COMMAND      - Bus read operation
//
// UVM_TLM_WRITE_COMMAND     - Bus write operation
//
// UVM_TLM_IGNORE_COMMAND    - No bus operation.

typedef enum
{
    UVM_TLM_READ_COMMAND,
    UVM_TLM_WRITE_COMMAND,
    UVM_TLM_IGNORE_COMMAND
} [docs]uvm_tlm_command_e;


// Enum: uvm_tlm_response_status_e
//
// Response status attribute type definition
//
// UVM_TLM_OK_RESPONSE                - Bus operation completed successfully
//
// UVM_TLM_INCOMPLETE_RESPONSE        - Transaction was not delivered to target
//
// UVM_TLM_GENERIC_ERROR_RESPONSE     - Bus operation had an error
//
// UVM_TLM_ADDRESS_ERROR_RESPONSE     - Invalid address specified
//
// UVM_TLM_COMMAND_ERROR_RESPONSE     - Invalid command specified
//
// UVM_TLM_BURST_ERROR_RESPONSE       - Invalid burst specified
//
// UVM_TLM_BYTE_ENABLE_ERROR_RESPONSE - Invalid byte enabling specified
//

typedef enum
{
    UVM_TLM_OK_RESPONSE = 1,
    UVM_TLM_INCOMPLETE_RESPONSE = 0,
    UVM_TLM_GENERIC_ERROR_RESPONSE = -1,
    UVM_TLM_ADDRESS_ERROR_RESPONSE = -2,
    UVM_TLM_COMMAND_ERROR_RESPONSE = -3,
    UVM_TLM_BURST_ERROR_RESPONSE = -4,
    UVM_TLM_BYTE_ENABLE_ERROR_RESPONSE = -5
} [docs]uvm_tlm_response_status_e;


typedef class [docs]uvm_tlm_extension_base;


//-----------------------
// Group: Generic Payload
//-----------------------

//----------------------------------------------------------------------
// Class: uvm_tlm_generic_payload
//
// This class provides a transaction definition commonly used in
// memory-mapped bus-based systems.  It's intended to be a general
// purpose transaction class that lends itself to many applications. The
// class is derived from uvm_sequence_item which enables it to be
// generated in sequences and transported to drivers through sequencers.
//----------------------------------------------------------------------

class [docs]uvm_tlm_generic_payload extends uvm_sequence_item;
   
   // Variable: m_address
   //
   // Address for the bus operation.
   // Should be set or read using the <set_address> and <get_address>
   // methods. The variable should be used only when constraining.
   //
   // For a read command or a write command, the target shall
   // interpret the current value of the address attribute as the start
   // address in the system memory map of the contiguous block of data
   // being read or written.
   // The address associated with any given byte in the data array is
   // dependent upon the address attribute, the array index, the
   // streaming width attribute, the endianness and the width of the physical bus.
   //
   // If the target is unable to execute the transaction with
   // the given address attribute (because the address is out-of-range,
   // for example) it shall generate a standard error response. The
   // recommended response status is ~UVM_TLM_ADDRESS_ERROR_RESPONSE~.
   //
   rand bit [63:0]             m_address;

 
   // Variable: m_command
   //
   // Bus operation type.
   // Should be set using the <set_command>, <set_read> or <set_write> methods
   // and read using the <get_command>, <is_read> or <is_write> methods.
   // The variable should be used only when constraining.
   //
   // If the target is unable to execute a read or write command, it
   // shall generate a standard error response. The
   // recommended response status is UVM_TLM_COMMAND_ERROR_RESPONSE.
   //
   // On receipt of a generic payload transaction with the command
   // attribute equal to UVM_TLM_IGNORE_COMMAND, the target shall not execute
   // a write command or a read command not modify any data.
   // The target may, however, use the value of any attribute in
   // the generic payload, including any extensions.
   //
   // The command attribute shall be set by the initiator, and shall
   // not be overwritten by any interconnect
   //
   rand uvm_tlm_command_e          m_command;

   
   // Variable: m_data
   //
   // Data read or to be written.
   // Should be set and read using the <set_data> or <get_data> methods
   // The variable should be used only when constraining.
   //
   // For a read command or a write command, the target shall copy data
   // to or from the data array, respectively, honoring the semantics of
   // the remaining attributes of the generic payload.
   //
   // For a write command or UVM_TLM_IGNORE_COMMAND, the contents of the
   // data array shall be set by the initiator, and shall not be
   // overwritten by any interconnect component or target. For a read
   // command, the contents of the data array shall be overwritten by the
   // target (honoring the semantics of the byte enable) but by no other
   // component.
   //
   // Unlike the OSCI TLM-2.0 LRM, there is no requirement on the endiannes
   // of multi-byte data in the generic payload to match the host endianness.
   // Unlike C++, it is not possible in SystemVerilog to cast an arbitrary
   // data type as an array of bytes. Therefore, matching the host
   // endianness is not necessary. In contrast, arbitrary data types may be
   // converted to and from a byte array using the streaming operator and
   // <uvm_object> objects may be further converted using the
   // <uvm_object::pack_bytes()> and <uvm_object::unpack_bytes()> methods.
   // All that is required is that a consistent mechanism is used to
   // fill the payload data array and later extract data from it.
   //
   // Should a generic payload be transferred to/from a SystemC model,
   // it will be necessary for any multi-byte data in that generic payload
   // to use/be interpreted using the host endianness.
   // However, this process is currently outside the scope of this standard.
   //
   rand byte unsigned             m_data[];


   // Variable: m_length
   //
   // The number of bytes to be copied to or from the <m_data> array,
   // inclusive of any bytes disabled by the <m_byte_enable> attribute.
   //
   // The data length attribute shall be set by the initiator,
   // and shall not be overwritten by any interconnect component or target.
   //
   // The data length attribute shall not be set to 0.
   // In order to transfer zero bytes, the <m_command> attribute
   // should be set to <UVM_TLM_IGNORE_COMMAND>.
   //
   rand int unsigned           m_length;
   

   // Variable: m_response_status
   //
   // Status of the bus operation.
   // Should be set using the <set_response_status> method
   // and read using the <get_response_status>, <get_response_string>,
   // <is_response_ok> or <is_response_error> methods.
   // The variable should be used only when constraining.
   //
   // The response status attribute shall be set to
   // UVM_TLM_INCOMPLETE_RESPONSE by the initiator, and may
   // be overwritten by the target. The response status attribute
   // should not be overwritten by any interconnect
   // component, because the default value UVM_TLM_INCOMPLETE_RESPONSE
   // indicates that the transaction was not delivered to the target.
   //
   // The target may set the response status attribute to UVM_TLM_OK_RESPONSE
   // to indicate that it was able to execute the command
   // successfully, or to one of the five error responses
   // to indicate an error. The target should choose the appropriate
   // error response depending on the cause of the error.
   // If a target detects an error but is unable to select a specific
   // error response, it may set the response status to
   // UVM_TLM_GENERIC_ERROR_RESPONSE.
   //
   // The target shall be responsible for setting the response status
   // attribute at the appropriate point in the
   // lifetime of the transaction. In the case of the blocking
   // transport interface, this means before returning
   // control from b_transport. In the case of the non-blocking
   // transport interface and the base protocol, this
   // means before sending the BEGIN_RESP phase or returning a value of UVM_TLM_COMPLETED.
   //
   // It is recommended that the initiator should always check the
   // response status attribute on receiving a
   // transition to the BEGIN_RESP phase or after the completion of
   // the transaction. An initiator may choose
   // to ignore the response status if it is known in advance that the
   // value will be UVM_TLM_OK_RESPONSE,
   // perhaps because it is known in advance that the initiator is
   // only connected to targets that always return
   // UVM_TLM_OK_RESPONSE, but in general this will not be the case. In
   // other words, the initiator ignores the
   // response status at its own risk.
   //
   rand uvm_tlm_response_status_e  m_response_status;


   // Variable: m_dmi
   //
   // DMI mode is not yet supported in the UVM TLM2 subset.
   // This variable is provided for completeness and interoperability
   // with SystemC.
   //
   bit m_dmi;
   

   // Variable: m_byte_enable
   //
   // Indicates valid <m_data> array elements.
   // Should be set and read using the <set_byte_enable> or <get_byte_enable> methods
   // The variable should be used only when constraining.
   //
   // The elements in the byte enable array shall be interpreted as
   // follows. A value of 8'h00 shall indicate that that
   // corresponding byte is disabled, and a value of 8'hFF shall
   // indicate that the corresponding byte is enabled.
   //
   // Byte enables may be used to create burst transfers where the
   // address increment between each beat is
   // greater than the number of significant bytes transferred on each
   // beat, or to place words in selected byte
   // lanes of a bus. At a more abstract level, byte enables may be
   // used to create "lacy bursts" where the data array of the generic
   // payload has an arbitrary pattern of holes punched in it.
   //
   // The byte enable mask may be defined by a small pattern applied
   // repeatedly or by a large pattern covering the whole data array.
   // The byte enable array may be empty, in which case byte enables
   // shall not be used for the current transaction.
   //
   // The byte enable array shall be set by the initiator and shall
   // not be overwritten by any interconnect component or target.
   //
   // If the byte enable pointer is not empty, the target shall either
   // implement the semantics of the byte enable as defined below or
   // shall generate a standard error response. The recommended response
   // status is UVM_TLM_BYTE_ENABLE_ERROR_RESPONSE.
   //
   // In the case of a write command, any interconnect component or
   // target should ignore the values of any disabled bytes in the
   // <m_data> array. In the case of a read command, any interconnect
   // component or target should not modify the values of disabled
   // bytes in the <m_data> array.
   //
   rand byte unsigned          m_byte_enable[];


   // Variable: m_byte_enable_length
   //
   // The number of elements in the <m_byte_enable> array.
   //
   // It shall be set by the initiator, and shall not be overwritten
   // by any interconnect component or target.
   //
   rand int unsigned m_byte_enable_length;


   // Variable: m_streaming_width
   //    
   // Number of bytes transferred on each beat.
   // Should be set and read using the <set_streaming_width> or
   // <get_streaming_width> methods
   // The variable should be used only when constraining.
   //
   // Streaming affects the way a component should interpret the data
   // array. A stream consists of a sequence of data transfers occurring
   // on successive notional beats, each beat having the same start
   // address as given by the generic payload address attribute. The
   // streaming width attribute shall determine the width of the stream,
   // that is, the number of bytes transferred on each beat. In other
   // words, streaming affects the local address associated with each
   // byte in the data array. In all other respects, the organization of
   // the data array is unaffected by streaming.
   //
   // The bytes within the data array have a corresponding sequence of
   // local addresses within the component accessing the generic payload
   // transaction. The lowest address is given by the value of the
   // address attribute. The highest address is given by the formula
   // address_attribute + streaming_width - 1. The address to or from
   // which each byte is being copied in the target shall be set to the
   // value of the address attribute at the start of each beat.
   //
   // With respect to the interpretation of the data array, a single
   // transaction with a streaming width shall be functionally equivalent
   // to a sequence of transactions each having the same address as the
   // original transaction, each having a data length attribute equal to
   // the streaming width of the original, and each with a data array
   // that is a different subset of the original data array on each
   // beat. This subset effectively steps down the original data array
   // maintaining the sequence of bytes.
   //
   // A streaming width of 0 indicates that a streaming transfer
   // is not required. it is equivalent to a streaming width 
   // value greater than or equal to the size of the <m_data> array.
   //
   // Streaming may be used in conjunction with byte enables, in which
   // case the streaming width would typically be equal to the byte
   // enable length. It would also make sense to have the streaming width
   // a multiple of the byte enable length. Having the byte enable length
   // a multiple of the streaming width would imply that different bytes
   // were enabled on each beat.
   //
   // If the target is unable to execute the transaction with the
   // given streaming width, it shall generate a standard error
   // response. The recommended response status is
   // TLM_BURST_ERROR_RESPONSE.
   //
   rand int unsigned m_streaming_width;

   protected uvm_tlm_extension_base m_extensions [uvm_tlm_extension_base];
   local rand uvm_tlm_extension_base m_rand_exts[];


   `uvm_object_utils(uvm_tlm_generic_payload)


  // Function: new
  //
  // Create a new instance of the generic payload.  Initialize all the
  // members to their default values.

  function [docs]new(string name="");
    super.new(name);
    m_address = 0;
    m_command = UVM_TLM_IGNORE_COMMAND;
    m_length = 0;
    m_response_status = UVM_TLM_INCOMPLETE_RESPONSE;
    m_dmi = 0;
    m_byte_enable_length = 0;
    m_streaming_width = 0;
  endfunction


  // Function- do_print
  //
  function void [docs]do_print(uvm_printer printer);
    byte unsigned be;
    super.do_print(printer);
    printer.print_field_int     ("address", m_address, 64, UVM_HEX);
    printer.print_generic ("command", "uvm_tlm_command_e", 32, m_command.name());
    printer.print_generic ("response_status", "uvm_tlm_response_status_e",
                             32, m_response_status.name());
    printer.print_field_int     ("streaming_width", m_streaming_width, 32, UVM_HEX);

    printer.print_array_header("data", m_length, "darray(byte)");
    for (int i=0; i < m_length && i < m_data.size(); i++) begin
      if (m_byte_enable_length) begin
        be = m_byte_enable[i % m_byte_enable_length];
        printer.print_generic ($sformatf("[%0d]",i), "byte", 8,
            $sformatf("'h%h%s",m_data[i],((be=='hFF) ? "" : " x")));
      end
      else 
        printer.print_generic ($sformatf("[%0d]",i), "byte", 8,
                               $sformatf("'h%h",m_data[i]));
    end
    printer.print_array_footer();

    begin
    string name;
    printer.print_array_header("extensions", m_extensions.num(), "aa(obj,obj)");
    foreach (m_extensions[ext_]) begin
      uvm_tlm_extension_base ext = m_extensions[ext_];
      name = {"[",ext.get_name(),"]"};
      printer.print_object(name, ext, "[");
    end
    printer.print_array_footer();
    end
  endfunction


  // Function- do_copy
  //
  function void [docs]do_copy(uvm_object rhs);
    uvm_tlm_generic_payload gp;
    super.do_copy(rhs);
    $cast(gp, rhs);
    m_address            = gp.m_address;
    m_command            = gp.m_command;
    m_data               = gp.m_data;
    m_dmi                = gp.m_dmi;
    m_length             = gp.m_length;
    m_response_status    = gp.m_response_status;
    m_byte_enable        = gp.m_byte_enable;
    m_streaming_width    = gp.m_streaming_width;
    m_byte_enable_length = gp.m_byte_enable_length;

    m_extensions.delete();
    foreach (gp.m_extensions[ext])
       $cast(m_extensions[ext], gp.m_extensions[ext].clone());
    
  endfunction
   

  // Function- do_compare
  //
  function bit [docs]do_compare(uvm_object rhs, uvm_comparer comparer);
    uvm_tlm_generic_payload gp;
    do_compare = super.do_compare(rhs, comparer);
    $cast(gp, rhs);

    do_compare = (m_address == gp.m_address &&
                  m_command == gp.m_command &&
                  m_length  == gp.m_length  &&
                  m_dmi     == gp.m_dmi &&
                  m_byte_enable_length == gp.m_byte_enable_length  &&
                  m_response_status    == gp.m_response_status &&
                  m_streaming_width    == gp.m_streaming_width );
    
    if (do_compare && m_length == gp.m_length) begin
        byte unsigned lhs_be, rhs_be;
        for (int i=0; do_compare && i < m_length && i < m_data.size(); i++) begin
          if (m_byte_enable_length) begin
            lhs_be = m_byte_enable[i % m_byte_enable_length];
            rhs_be = gp.m_byte_enable[i % gp.m_byte_enable_length];
            do_compare = ((m_data[i] & lhs_be) == (gp.m_data[i] & rhs_be));
          end
          else begin
            do_compare = (m_data[i] == gp.m_data[i]);
          end
        end
     end

    if (do_compare)
      foreach (m_extensions[ext_]) begin
         uvm_tlm_extension_base ext = ext_;
         uvm_tlm_extension_base rhs_ext = gp.m_extensions.exists(ext) ?
                                          gp.m_extensions[ext] : null;
         do_compare = comparer.compare_object(ext.get_name(),
                                               m_extensions[ext], rhs_ext);
         if (!do_compare) break;
      end

    if (do_compare)
      foreach (gp.m_extensions[ext_]) begin
        uvm_tlm_extension_base ext = ext_;
        if (!m_extensions.exists(ext)) begin
              do_compare = comparer.compare_object(ext.get_name(),
                            null, gp.m_extensions[ext]);
          if (!do_compare) break;
        end
      end

    if (!do_compare && comparer.show_max > 0) begin
      string msg = $sformatf("GP miscompare between '%s' and '%s':\nlhs = %s\nrhs = %s",
            get_full_name(), gp.get_full_name(), this.convert2string(), gp.convert2string());
      case (comparer.sev)
        UVM_WARNING: `uvm_warning("MISCMP", msg)
        UVM_ERROR:   `uvm_error("MISCMP", msg)
        default:     `uvm_info("MISCMP", msg, UVM_LOW)
      endcase
    end

  endfunction
   

  // Function- do_pack
  //
  // We only pack m_length bytes of the m_data array, even if m_data is larger
  // than m_length. Same treatment for the byte-enable array. We do not pack
  // the extensions, if any, as we will be unable to unpack them.
  function void [docs]do_pack(uvm_packer packer);
    super.do_pack(packer);
    if (m_length > m_data.size())
       `uvm_fatal("PACK_DATA_ARR",
         $sformatf("Data array m_length property (%0d) greater than m_data.size (%0d)",
         m_length,m_data.size()))
    if (m_byte_enable_length > m_byte_enable.size())
       `uvm_fatal("PACK_DATA_ARR",
         $sformatf("Data array m_byte_enable_length property (%0d) greater than m_byte_enable.size (%0d)",
         m_byte_enable_length,m_byte_enable.size()))
    `uvm_pack_intN  (m_address,64)
    `uvm_pack_enumN (m_command,32)
    `uvm_pack_intN  (m_length,32)
    for (int i=0; i<m_length; i++)
      `uvm_pack_intN(m_data[i],8)
    `uvm_pack_enumN (m_response_status,32)
    `uvm_pack_intN  (m_byte_enable_length,32)
    for (int i=0; i<m_byte_enable_length; i++)
      `uvm_pack_intN(m_byte_enable[i],8)
    `uvm_pack_intN  (m_streaming_width,32)

  endfunction


  // Function- do_unpack
  //
  // We only reallocate m_data/m_byte_enable if the new size
  // is greater than their current size. We do not unpack extensions
  // because we do not know what object types to allocate before we
  // unpack into them. Extensions must be handled by user code.
  function void [docs]do_unpack(uvm_packer packer);
    super.do_unpack(packer);
    `uvm_unpack_intN  (m_address,64)
    `uvm_unpack_enumN (m_command, 32, uvm_tlm_command_e)
    `uvm_unpack_intN  (m_length,32)
    if (m_data.size() < m_length)
      m_data = new[m_length];
    foreach (m_data[i])
      `uvm_unpack_intN(m_data[i],8)
    `uvm_unpack_enumN (m_response_status, 32, uvm_tlm_response_status_e)
    `uvm_unpack_intN  (m_byte_enable_length,32)
    if (m_byte_enable.size() < m_byte_enable_length)
      m_byte_enable = new[m_byte_enable_length];
    for (int i=0; i<m_byte_enable_length; i++)
      `uvm_unpack_intN(m_byte_enable[i],8)
    `uvm_unpack_intN  (m_streaming_width,32)

  endfunction


  // Function- do_record
  //
  function void [docs]do_record(uvm_recorder recorder);
    if (!is_recording_enabled())
      return;
    super.do_record(recorder);
    `uvm_record_int("address",m_address,$bits(m_address))
    `uvm_record_string("command",m_command.name())
    `uvm_record_int("data_length",m_length,$bits(m_length))
    `uvm_record_int("byte_enable_length",m_byte_enable_length,$bits(m_byte_enable_length))
    `uvm_record_string("response_status",m_response_status.name())
    `uvm_record_int("streaming_width",m_streaming_width,$bits(m_streaming_width))

    for (int i=0; i < m_length; i++)
      `uvm_record_int($sformatf("\\data[%0d] ", i), m_data[i], $bits(m_data[i]))

    for (int i=0; i < m_byte_enable_length; i++)
      `uvm_record_int($sformatf("\\byte_en[%0d] ", i), m_byte_enable[i], $bits(m_byte_enable[i]))

    foreach (m_extensions[ext])
      recorder.record_object(ext.get_name(),m_extensions[ext]);
  endfunction


  // Function- convert2string
  //
  function string [docs]convert2string();

    string msg;
    string s;

    $sformat(msg, "%s %s [0x%16x] =", super.convert2string(),
             m_command.name(), m_address);

    for(int unsigned i = 0; i < m_length; i++) begin
      if (!m_byte_enable_length || (m_byte_enable[i % m_byte_enable_length] == 'hFF))
        $sformat(s, " %02x", m_data[i]);
      else
        $sformat(s, " --");
      msg = { msg , s };
    end

    msg = { msg, " (status=", get_response_string(), ")" };

    return msg;

  endfunction


  //--------------------------------------------------------------------
  // Group: Accessors
  //
  // The accessor functions let you set and get each of the members of the 
  // generic payload. All of the accessor methods are virtual. This implies 
  // a slightly different use model for the generic payload than 
  // in SystemC. The way the generic payload is defined in SystemC does 
  // not encourage you to create new transaction types derived from 
  // uvm_tlm_generic_payload. Instead, you would use the extensions mechanism. 
  // Thus in SystemC none of the accessors are virtual.
  //--------------------------------------------------------------------

   // Function: get_command
   //
   // Get the value of the <m_command> variable

  virtual function uvm_tlm_command_e [docs]get_command();
    return m_command;
  endfunction

   // Function: set_command
   //
   // Set the value of the <m_command> variable
   
  virtual function void [docs]set_command(uvm_tlm_command_e command);
    m_command = command;
  endfunction

   // Function: is_read
   //
   // Returns true if the current value of the <m_command> variable
   // is ~UVM_TLM_READ_COMMAND~.
   
  virtual function bit [docs]is_read();
    return (m_command == UVM_TLM_READ_COMMAND);
  endfunction
 
   // Function: set_read
   //
   // Set the current value of the <m_command> variable
   // to ~UVM_TLM_READ_COMMAND~.
   
  virtual function void [docs]set_read();
    set_command(UVM_TLM_READ_COMMAND);
  endfunction

   // Function: is_write
   //
   // Returns true if the current value of the <m_command> variable
   // is ~UVM_TLM_WRITE_COMMAND~.
 
  virtual function bit [docs]is_write();
    return (m_command == UVM_TLM_WRITE_COMMAND);
  endfunction
 
   // Function: set_write
   //
   // Set the current value of the <m_command> variable
   // to ~UVM_TLM_WRITE_COMMAND~.

  virtual function void [docs]set_write();
    set_command(UVM_TLM_WRITE_COMMAND);
  endfunction
  
   // Function: set_address
   //
   // Set the value of the <m_address> variable
  virtual function void [docs]set_address(bit [63:0] addr);
    m_address = addr;
  endfunction

   // Function: get_address
   //
   // Get the value of the <m_address> variable
 
  virtual function bit [63:0] [docs]get_address();
    return m_address;
  endfunction

   // Function: get_data
   //
   // Return the value of the <m_data> array
 
  virtual function void [docs]get_data (output byte unsigned p []);
    p = m_data;
  endfunction

   // Function: set_data
   //
   // Set the value of the <m_data> array  

  virtual function void [docs]set_data(ref byte unsigned p []);
    m_data = p;
  endfunction 
  
   // Function: get_data_length
   //
   // Return the current size of the <m_data> array
   
  virtual function int unsigned [docs]get_data_length();
    return m_length;
  endfunction

  // Function: set_data_length
  // Set the value of the <m_length>
   
   virtual function void [docs]set_data_length(int unsigned length);
    m_length = length;
  endfunction

   // Function: get_streaming_width
   //
   // Get the value of the <m_streaming_width> array
  
  virtual function int unsigned [docs]get_streaming_width();
    return m_streaming_width;
  endfunction

 
   // Function: set_streaming_width
   //
   // Set the value of the <m_streaming_width> array
   
  virtual function void [docs]set_streaming_width(int unsigned width);
    m_streaming_width = width;
  endfunction

   // Function: get_byte_enable
   //
   // Return the value of the <m_byte_enable> array
  virtual function void [docs]get_byte_enable(output byte unsigned p[]);
    p = m_byte_enable;
  endfunction

   // Function: set_byte_enable
   //
   // Set the value of the <m_byte_enable> array
   
  virtual function void [docs]set_byte_enable(ref byte unsigned p[]);
    m_byte_enable = p;
  endfunction

   // Function: get_byte_enable_length
   //
   // Return the current size of the <m_byte_enable> array
   
  virtual function int unsigned [docs]get_byte_enable_length();
    return m_byte_enable_length;
  endfunction

   // Function: set_byte_enable_length
   //
   // Set the size <m_byte_enable_length> of the <m_byte_enable> array
   // i.e.  <m_byte_enable>.size()
   
 virtual function void [docs]set_byte_enable_length(int unsigned length);
    m_byte_enable_length = length;
  endfunction

   // Function: set_dmi_allowed
   //
   // DMI hint. Set the internal flag <m_dmi> to allow dmi access
   
  virtual function void [docs]set_dmi_allowed(bit dmi);
    m_dmi = dmi;
  endfunction
   
   // Function: is_dmi_allowed
   //
   // DMI hint. Query the internal flag <m_dmi> if allowed dmi access 

 virtual function bit [docs]is_dmi_allowed();
    return m_dmi;
  endfunction

   // Function: get_response_status
   //
   // Return the current value of the <m_response_status> variable
   
  virtual function uvm_tlm_response_status_e [docs]get_response_status();
    return m_response_status;
  endfunction

   // Function: set_response_status
   //
   // Set the current value of the <m_response_status> variable

  virtual function void [docs]set_response_status(uvm_tlm_response_status_e status);
    m_response_status = status;
  endfunction

   // Function: is_response_ok
   //
   // Return TRUE if the current value of the <m_response_status> variable
   // is ~UVM_TLM_OK_RESPONSE~

  virtual function bit [docs]is_response_ok();
    return (int'(m_response_status) > 0);
  endfunction

   // Function: is_response_error
   //
   // Return TRUE if the current value of the <m_response_status> variable
   // is not ~UVM_TLM_OK_RESPONSE~

  virtual function bit [docs]is_response_error();
    return !is_response_ok();
  endfunction

   // Function: get_response_string
   //
   // Return the current value of the <m_response_status> variable
   // as a string

  virtual function string [docs]get_response_string();

    case(m_response_status)
      UVM_TLM_OK_RESPONSE                : return "OK";
      UVM_TLM_INCOMPLETE_RESPONSE        : return "INCOMPLETE";
      UVM_TLM_GENERIC_ERROR_RESPONSE     : return "GENERIC_ERROR";
      UVM_TLM_ADDRESS_ERROR_RESPONSE     : return "ADDRESS_ERROR";
      UVM_TLM_COMMAND_ERROR_RESPONSE     : return "COMMAND_ERROR";
      UVM_TLM_BURST_ERROR_RESPONSE       : return "BURST_ERROR";
      UVM_TLM_BYTE_ENABLE_ERROR_RESPONSE : return "BYTE_ENABLE_ERROR";
    endcase

    // we should never get here
    return "UNKNOWN_RESPONSE";

  endfunction

  //--------------------------------------------------------------------
  // Group: Extensions Mechanism
  //
  //--------------------------------------------------------------------

  // Function: set_extension
  //
  // Add an instance-specific extension. Only one instance of any given
  // extension type is allowed. If there is an existing extension
  // instance of the type of ~ext~, ~ext~ replaces it and its handle
  // is returned. Otherwise, ~null~ is returned.
   
  function uvm_tlm_extension_base [docs]set_extension(uvm_tlm_extension_base ext);
    uvm_tlm_extension_base ext_handle = ext.get_type_handle();
    if(!m_extensions.exists(ext_handle))
      set_extension = null;
    else
      set_extension = m_extensions[ext_handle];
    m_extensions[ext_handle] = ext;
  endfunction


  // Function: get_num_extensions
  //
  // Return the current number of instance specific extensions.
   
  function int [docs]get_num_extensions();
    return m_extensions.num();
  endfunction: get_num_extensions
   

  // Function: get_extension
  //
  // Return the instance specific extension bound under the specified key.
  // If no extension is bound under that key, ~null~ is returned.
   
  function uvm_tlm_extension_base [docs]get_extension(uvm_tlm_extension_base ext_handle);
    if(!m_extensions.exists(ext_handle))
      return null;
    return m_extensions[ext_handle];
  endfunction
   

  // Function: clear_extension
  //
  // Remove the instance-specific extension bound under the specified key.
   
  function void [docs]clear_extension(uvm_tlm_extension_base ext_handle);
    if(m_extensions.exists(ext_handle))
      m_extensions.delete(ext_handle);
    else
      `uvm_info("GP_EXT", $sformatf("Unable to find extension to clear"), UVM_MEDIUM);
  endfunction


  // Function: clear_extensions
  //
  // Remove all instance-specific extensions
   
  function void [docs]clear_extensions();
    m_extensions.delete();
  endfunction


  // Function: pre_randomize()
  // Prepare this class instance for randomization
  //
  function void pre_randomize();
    int i;
    m_rand_exts = new [m_extensions.num()];
    foreach (m_extensions[ext_]) begin
      uvm_tlm_extension_base ext = ext_;
      m_rand_exts[i++] = m_extensions[ext];
    end
  endfunction

  // Function: post_randomize()
  // Clean-up this class instance after randomization
  //
  function void post_randomize();
     m_rand_exts.delete();
  endfunction
endclass

//----------------------------------------------------------------------
// Class: uvm_tlm_gp
//
// This typedef provides a short, more convenient name for the
// <uvm_tlm_generic_payload> type.
//----------------------------------------------------------------------

typedef uvm_tlm_generic_payload [docs]uvm_tlm_gp;


//----------------------------------------------------------------------
// Class: uvm_tlm_extension_base
//
// The class uvm_tlm_extension_base is the non-parameterized base class for
// all generic payload extensions.  It includes the utility do_copy()
// and create().  The pure virtual function get_type_handle() allows you
// to get a unique handle that represents the derived type.  This is
// implemented in derived classes.
//
// This class is never used directly by users.
// The <uvm_tlm_extension> class is used instead.
//
virtual class [docs]uvm_tlm_extension_base extends uvm_object;

  // Function: new
  //
  function [docs]new(string name = "");
    super.new(name);
  endfunction

  // Function: get_type_handle
  //
  // An interface to polymorphically retrieve a handle that uniquely
  // identifies the type of the sub-class

  pure virtual function uvm_tlm_extension_base [docs]get_type_handle();

  // Function: get_type_handle_name
  //
  // An interface to polymorphically retrieve the name that uniquely
  // identifies the type of the sub-class

  pure virtual function string [docs]get_type_handle_name();

  virtual function void [docs]do_copy(uvm_object rhs);
    super.do_copy(rhs);
  endfunction

  // Function: create
  //
   
  virtual function uvm_object [docs]create (string name="");
    return null;
  endfunction

endclass


//----------------------------------------------------------------------
// Class: uvm_tlm_extension
//
// TLM extension class. The class is parameterized with arbitrary type
// which represents the type of the extension. An instance of the
// generic payload can contain one extension object of each type; it
// cannot contain two instances of the same extension type.
//
// The extension type can be identified using the <ID()>
// method.
//
// To implement a generic payload extension, simply derive a new class
// from this class and specify the name of the derived class as the
// extension parameter.
//
//|
//| class my_ID extends uvm_tlm_extension#(my_ID);
//|   int ID;
//|
//|   `uvm_object_utils_begin(my_ID)
//|      `uvm_field_int(ID, UVM_ALL_ON)
//|   `uvm_object_utils_end
//|
//|   function new(string name = "my_ID");
//|      super.new(name);
//|   endfunction
//| endclass
//|

class [docs]uvm_tlm_extension #(type T=int) extends uvm_tlm_extension_base;

   typedef uvm_tlm_extension#(T) this_type;

   local static this_type m_my_tlm_ext_type = ID();

   // Function: new
   //
   // creates a new extension object.

   function [docs]new(string name="");
     super.new(name);
   endfunction

   // Function: ID()
   //
   // Return the unique ID of this TLM extension type.
   // This method is used to identify the type of the extension to retrieve
   // from a <uvm_tlm_generic_payload> instance,
   // using the <uvm_tlm_generic_payload::get_extension()> method.
   //
  static function this_type [docs]ID();
    if (m_my_tlm_ext_type == null)
      m_my_tlm_ext_type = new();
    return m_my_tlm_ext_type;
  endfunction

  virtual function uvm_tlm_extension_base [docs]get_type_handle();
     return ID();
  endfunction

  virtual function string [docs]get_type_handle_name();
    return `uvm_typename(T);
  endfunction

  virtual function uvm_object [docs]create (string name="");
    return null;
  endfunction

endclass