//----------------------------------------------------------------------
// Copyright 2018 Cadence Design Systems, Inc.
// Copyright 2018 Cisco Systems, Inc.
// Copyright 2018-2021 NVIDIA Corporation
// Copyright 2018 Qualcomm, 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.
//----------------------------------------------------------------------

`ifndef UVM_PACKER_DEFINES_SVH
 `define UVM_PACKER_DEFINES_SVH

//------------------------------------------------------------------------------
//
// MACROS for uvm_packer usage
//
// Provides a set of packing/unpacking macros that will call appropriate methods
// inside of a uvm_packer object.
//
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
// Group -- NODOCS -- Packing Macros
//
// The packing macros assist users who implement the <uvm_object::do_pack>
// method. They help ensure that the pack operation is the exact inverse of the
// unpack operation. See also <Unpacking Macros>.
//
//| virtual function void do_pack(uvm_packer packer);
//|   `uvm_pack_int(cmd)
//|   `uvm_pack_int(addr)
//|   `uvm_pack_array(data)
//| endfunction
//
// The 'N' versions of these macros take a explicit size argument, which must
// be compile-time constant value greater than 0.
//------------------------------------------------------------------------------

//--------------------------------
// Group -- NODOCS -- Packing - With Size Info
//--------------------------------

// Macro -- NODOCS -- `uvm_pack_intN
//
// Pack an integral variable.
//
//| `uvm_pack_intN(VAR,SIZE)
//

// Group: Packing Macros
//
// The packing macros are implemented as described in section B.2.4 of the
// 1800.2 specification.
//
// The Accellera implementation adds an additional ~PACKER~ argument to 
// these macros with a default value of 'packer'.  This allows the macros
// to be used in environments with alternative packer names.
//
// For example, <`uvm_pack_intN> is defined in the LRM as
// | `define uvm_pack_intN(VAR,SIZE)
//
// Whereas the implementation is
// | `define uvm_pack_intN(VAR,SIZE,PACKER=packer)
//
// This allows for usage such as
// | function void pack_foo( uvm_packer other_packer );
// |   `uvm_pack_intN(foo, 32, other_packer)
// | endfunction : pack_foo
//
// @uvm-contrib This API is being considered for potential contribution to 1800.2


// @uvm-ieee 1800.2-2020 auto B.2.4.1
`define uvm_pack_intN(VAR,SIZE,PACKER=packer) \
  if (SIZE <= $bits(uvm_integral_t)) begin \
     PACKER.pack_field_int(VAR, SIZE); \
  end \
  else if (SIZE <= $bits(uvm_bitstream_t)) begin \
     PACKER.pack_field(VAR, SIZE); \
  end \
  else begin \
    bit __array[]; \
    { << bit { __array}} = VAR; \
    __array = new [SIZE] (__array); \
    PACKER.pack_bits(__array, SIZE); \
  end

// @uvm-ieee 1800.2-2020 auto B.2.4.2
`define uvm_pack_enumN(VAR,SIZE,PACKER=packer) \
   `uvm_pack_intN(VAR,SIZE,PACKER)



// @uvm-ieee 1800.2-2020 auto B.2.4.3
`define uvm_pack_sarrayN(VAR,SIZE,PACKER=packer) \
    begin \
    foreach (VAR `` [index]) \
      `uvm_pack_intN(VAR[index],SIZE,PACKER) \
    end



// @uvm-ieee 1800.2-2020 auto B.2.4.4
`define uvm_pack_arrayN(VAR,SIZE,PACKER=packer) \
    begin \
      `uvm_pack_intN(VAR.size(),32,PACKER) \
      `uvm_pack_sarrayN(VAR,SIZE,PACKER) \
    end



// @uvm-ieee 1800.2-2020 auto B.2.4.5
`define uvm_pack_queueN(VAR,SIZE,PACKER=packer) \
   `uvm_pack_arrayN(VAR,SIZE,PACKER)


//------------------------------
// Group -- NODOCS -- Packing - No Size Info
//------------------------------


// @uvm-ieee 1800.2-2020 auto B.2.4.6
`define uvm_pack_int(VAR,PACKER=packer) \
   `uvm_pack_intN(VAR,$bits(VAR),PACKER)

// uvm_pack_object
`define uvm_pack_object(VAR,PACKER=packer) \
  PACKER.pack_object_with_meta(VAR);

// @uvm-ieee 1800.2-2020 auto B.2.4.7
`define uvm_pack_enum(VAR,PACKER=packer) \
   `uvm_pack_enumN(VAR,$bits(VAR),PACKER)



// @uvm-ieee 1800.2-2020 auto B.2.4.8
`define uvm_pack_string(VAR,PACKER=packer) \
  PACKER.pack_string(VAR);



// @uvm-ieee 1800.2-2020 auto B.2.4.9
`define uvm_pack_real(VAR,PACKER=packer) \
  PACKER.pack_real(VAR);



// @uvm-ieee 1800.2-2020 auto B.2.4.10
`define uvm_pack_sarray(VAR,PACKER=packer)  \
   `uvm_pack_sarrayN(VAR,$bits(VAR[0]),PACKER)



// @uvm-ieee 1800.2-2020 auto B.2.4.11
`define uvm_pack_array(VAR,PACKER=packer) \
   `uvm_pack_arrayN(VAR,$bits(VAR[0]),PACKER)

`define uvm_pack_da(VAR,PACKER=packer) \
  `uvm_pack_array(VAR,PACKER)

// @uvm-ieee 1800.2-2020 auto B.2.4.12
`define uvm_pack_queue(VAR,PACKER=packer) \
   `uvm_pack_queueN(VAR,$bits(VAR[0]),PACKER)

//------------------------------------------------------------------------------
// Group -- NODOCS -- Unpacking Macros
//
// The unpacking macros assist users who implement the <uvm_object::do_unpack>
// method. They help ensure that the unpack operation is the exact inverse of
// the pack operation. See also <Packing Macros>.
//
//| virtual function void do_unpack(uvm_packer packer);
//|   `uvm_unpack_enum(cmd,cmd_t)
//|   `uvm_unpack_int(addr)
//|   `uvm_unpack_array(data)
//| endfunction
//
// The 'N' versions of these macros take a explicit size argument, which must
// be a compile-time constant value greater than 0.
//------------------------------------------------------------------------------

//----------------------------------
// Group -- NODOCS -- Unpacking - With Size Info
//----------------------------------


// @uvm-ieee 1800.2-2020 auto B.2.5.1
`define uvm_unpack_intN(VAR,SIZE,PACKER=packer) \
  if (SIZE <= $bits(uvm_integral_t)) begin \
    VAR = PACKER.unpack_field_int(SIZE); \
  end \
  else if (SIZE <= $bits(uvm_bitstream_t)) begin \
    VAR = PACKER.unpack_field(SIZE); \
  end \
  else begin \
    bit __array[] = new [SIZE]; \
    PACKER.unpack_bits(__array, SIZE); \
    __array = new [$bits(VAR)] (__array); \
    VAR = { << bit { __array }}; \
  end



// @uvm-ieee 1800.2-2020 auto B.2.5.2
`define uvm_unpack_enumN(VAR,SIZE,TYPE,PACKER=packer) \
  begin \
    bit __array[] = new [SIZE]; \
    PACKER.unpack_bits(__array, SIZE); \
    __array = new [$bits(VAR)] (__array); \
    VAR = TYPE'({ << bit { __array }}); \
  end



// @uvm-ieee 1800.2-2020 auto B.2.5.3
`define uvm_unpack_sarrayN(VAR,SIZE,PACKER=packer) \
    begin \
    foreach (VAR `` [i]) \
      `uvm_unpack_intN(VAR``[i], SIZE, PACKER) \
    end



// @uvm-ieee 1800.2-2020 auto B.2.5.4
`define uvm_unpack_arrayN(VAR,SIZE,PACKER=packer) \
    begin \
      int sz__; \
      `uvm_unpack_intN(sz__,32,PACKER) \
      VAR = new[sz__]; \
      `uvm_unpack_sarrayN(VAR,SIZE,PACKER) \
    end



// @uvm-ieee 1800.2-2020 auto B.2.5.5
`define uvm_unpack_queueN(VAR,SIZE,PACKER=packer) \
    begin \
      int sz__; \
      `uvm_unpack_intN(sz__,32,PACKER) \
      while (VAR.size() > sz__) \
        void'(VAR.pop_back()); \
      for (int i=0; i<sz__; i++) \
        `uvm_unpack_intN(VAR[i],SIZE,PACKER) \
    end


//--------------------------------
// Group -- NODOCS -- Unpacking - No Size Info
//--------------------------------



// @uvm-ieee 1800.2-2020 auto B.2.5.6
`define uvm_unpack_int(VAR,PACKER=packer) \
   `uvm_unpack_intN(VAR,$bits(VAR),PACKER)

// uvm_unpack_object
`define uvm_unpack_object(VAR,PACKER=packer) \
  begin \
    uvm_object __ref = VAR; \
    PACKER.unpack_object_with_meta(__ref); \
    if ((__ref != VAR) && !$cast(VAR,__ref)) begin \
      `uvm_fatal("UVM/UNPACK_EXT/OBJ_CAST_FAILED", \
                {"Could not cast object of type '", __ref.get_type_name(), \
                 "' into '", `"LVALUE`"}) \
    end \
  end


// @uvm-ieee 1800.2-2020 auto B.2.5.7
`define uvm_unpack_enum(VAR,TYPE,PACKER=packer) \
   `uvm_unpack_enumN(VAR,$bits(VAR),TYPE,PACKER)



// @uvm-ieee 1800.2-2020 auto B.2.5.8
`define uvm_unpack_string(VAR,PACKER=packer) \
  VAR = PACKER.unpack_string();


// @uvm-ieee 1800.2-2020 auto B.2.5.9
`define uvm_unpack_real(VAR,PACKER=packer) \
  VAR = PACKER.unpack_real();



// @uvm-ieee 1800.2-2020 auto B.2.5.10
`define uvm_unpack_sarray(VAR,PACKER=packer)  \
   `uvm_unpack_sarrayN(VAR,$bits(VAR[0]),PACKER)



// @uvm-ieee 1800.2-2020 auto B.2.5.11
`define uvm_unpack_array(VAR,PACKER=packer) \
   `uvm_unpack_arrayN(VAR,$bits(VAR[0]),PACKER)

// Implementation artifact.  Simplifies field macros.
`define uvm_unpack_da(VAR,PACKER=packer) \
  `uvm_unpack_array(VAR,PACKER)


// @uvm-ieee 1800.2-2020 auto B.2.5.12
`define uvm_unpack_queue(VAR,PACKER=packer) \
   `uvm_unpack_queueN(VAR,$bits(VAR[0]),PACKER)


//--

`define uvm_pack_aa_int_intN(VAR, SIZE, PACKER=packer) \
begin \
  `uvm_pack_intN(VAR.num(), 32, PACKER) \
  if (VAR.num()) begin \
    `uvm_pack_intN(SIZE, 32, PACKER) \
    foreach(VAR[i]) begin \
      `uvm_pack_intN(i, SIZE, PACKER) \
      `uvm_pack_int(VAR[i],PACKER) \
    end \
  end \
end

`define uvm_unpack_aa_int_intN(VAR, SIZE, PACKER=packer) \
begin \
  int __num__; \
  `uvm_unpack_intN(__num__, 32, PACKER) \
  if (__num__ == 0) \
    VAR.delete(); \
  else begin \
    bit[SIZE-1:0] __index__; \
    int __sz__; \
    `uvm_unpack_intN(__sz__, 32, PACKER) \
    if (SIZE != __sz__) \
      `uvm_error("UVM/UNPACK/AA_INT_SZ", $sformatf("Unpack size '%0d' different from pack size '%0d'", \
                                                   SIZE, \
                                                   __sz__)) \
    for (int __i__ = 0; __i__ < __num__; __i__++) begin \
      `uvm_unpack_intN(__index__, SIZE, PACKER) \
      `uvm_unpack_int(VAR[__index__], PACKER) \
    end \
  end \
end
   
//--

`define uvm_pack_aa_object_intN(VAR, SIZE, PACKER=packer) \
begin \
  PACKER.pack_field_int(VAR.num(), 32); \
  if (VAR.num()) begin \
    PACKER.pack_field_int(SIZE, 32); \
    foreach(VAR[i]) begin \
      `uvm_pack_intN(i, SIZE, PACKER) \
      `uvm_pack_object(VAR[i], PACKER) \
    end \
  end \
end

`define uvm_unpack_aa_object_intN(VAR, SIZE, PACKER=packer) \
begin \
  int __num__; \
  `uvm_unpack_intN(__num__, 32, PACKER) \
  if (__num__ == 0) \
    VAR.delete(); \
  else begin \
    bit[SIZE-1:0] __index__; \
    int __sz__; \
    `uvm_unpack_intN(__sz__, 32, PACKER) \
    if (SIZE != __sz__) \
      `uvm_error("UVM/UNPACK/AA_INT_SZ", $sformatf("Size '%d' insufficient to store '%d' bits", \
                                                   SIZE, \
                                                   __sz__)) \
    for (int __i__ = 0; __i__ < __num__; __i__++) begin \
      `uvm_unpack_intN(__index__, __sz__, PACKER) \
      `uvm_unpack_object(VAR[__index__],PACKER) \
    end \
  end \
end
   
//--

`define uvm_pack_aa_string_intN(VAR, SIZE, PACKER=packer) \
begin \
  PACKER.pack_field_int(VAR.num(), 32); \
  if (VAR.num()) begin \
    PACKER.pack_field_int(SIZE, 32); \
    foreach(VAR[i]) begin \
      `uvm_pack_intN(i, SIZE, PACKER) \
      `uvm_pack_string(VAR[i], PACKER) \
    end \
  end \
end

`define uvm_unpack_aa_string_intN(VAR, SIZE, PACKER=packer) \
begin \
  int __num__; \
  `uvm_unpack_intN(__num__, 32, PACKER) \
  if (__num__ == 0) \
    VAR.delete(); \
  else begin \
    bit[SIZE-1:0] __index__; \
    int __sz__; \
    `uvm_unpack_intN(__sz__, 32, PACKER) \
    if (SIZE != __sz__) \
      `uvm_error("UVM/UNPACK/AA_INT_SZ", $sformatf("Size '%d' insufficient to store '%d' bits", \
                                                   SIZE, \
                                                   __sz__)) \
    for (int __i__ = 0; __i__ < __num__; __i__++) begin \
      `uvm_unpack_intN(__index__, __sz__, PACKER) \
      `uvm_unpack_string(VAR[__index__], PACKER) \
    end \
  end \
end
   
//--

`define uvm_pack_aa_object_string(VAR, PACKER=packer) \
begin \
  PACKER.pack_field_int(VAR.num(), 32); \
  if (VAR.num()) begin \
    foreach(VAR[i]) begin \
      `uvm_pack_string(i, PACKER) \
      `uvm_pack_object(VAR[i], PACKER) \
    end \
  end \
end

`define uvm_unpack_aa_object_string(VAR, PACKER=packer) \
begin \
  int __num__ = PACKER.unpack_field_int(32); \
  if (__num__ == 0) \
    VAR.delete(); \
  else begin \
    string __index__; \
    for (int __i__ = 0; __i__ < __num__; __i__++) begin \
      `uvm_unpack_string(__index__, PACKER) \
      `uvm_unpack_object(VAR[__index__], PACKER) \
    end \
  end \
end

//--

`define uvm_pack_aa_int_string(VAR, PACKER=packer) \
begin \
  PACKER.pack_field_int(VAR.num(), 32); \
  if (VAR.num()) begin \
    foreach(VAR[i]) begin \
      `uvm_pack_string(i, PACKER) \
      `uvm_pack_int(VAR[i], PACKER) \
    end \
  end \
end

`define uvm_unpack_aa_int_string(VAR, PACKER=packer) \
begin \
  int __num__ = PACKER.unpack_field_int(32); \
  if (__num__ == 0) \
    VAR.delete(); \
  else begin \
    string __index__; \
    for (int __i__ = 0; __i__ < __num__; __i__++) begin \
      `uvm_unpack_string(__index__, PACKER) \
      `uvm_unpack_int(VAR[__index__], PACKER) \
    end \
  end \
end

//--

`define uvm_pack_aa_string_string(VAR, PACKER=packer) \
begin \
  PACKER.pack_field_int(VAR.num(), 32); \
  if (VAR.num()) begin \
    foreach(VAR[i]) begin \
      `uvm_pack_string(i, PACKER) \
      `uvm_pack_string(VAR[i], PACKER) \
    end \
  end \
end

`define uvm_unpack_aa_string_string(VAR, PACKER=packer) \
begin \
  int __num__ = PACKER.unpack_field_int(32); \
  if (__num__ == 0) \
    VAR.delete(); \
  else begin \
    string __index__; \
    for (int __i__ = 0; __i__ < __num__; __i__++) begin \
      `uvm_unpack_string(__index__, PACKER) \
      `uvm_unpack_string(VAR[__index__], PACKER) \
    end \
  end \
end

//--

`define uvm_pack_aa_int_enum(VAR, TYPE, PACKER=packer) \
begin \
  PACKER.pack_field_int(VAR.num(), 32); \
  if (VAR.num()) begin \
    foreach(VAR[i]) begin \
      `uvm_pack_enum(i, PACKER) \
      `uvm_pack_int(VAR[i], PACKER) \
    end \
  end \
end

`define uvm_unpack_aa_int_enum(VAR, TYPE, PACKER=packer) \
begin \
  int __num__ = PACKER.unpack_field_int(32); \
  if (__num__ == 0) \
    VAR.delete(); \
  else begin \
    TYPE __index__; \
    for (int __i__ = 0; __i__ < __num__; __i__++) begin \
      `uvm_unpack_enum(__index__, TYPE, PACKER) \
      `uvm_unpack_int(VAR[__index__], PACKER) \
    end \
  end \
end
   
//--

`define uvm_pack_aa_object_enum(VAR, TYPE, PACKER=packer) \
begin \
  PACKER.pack_field_int(VAR.num(), 32); \
  if (VAR.num()) begin \
    foreach(VAR[i]) begin \
      `uvm_pack_enum(i, PACKER) \
      `uvm_pack_object(VAR[i], PACKER) \
    end \
  end \
end

`define uvm_unpack_aa_object_enum(VAR, TYPE, PACKER=packer) \
begin \
  int __num__ = PACKER.unpack_field_int(32); \
  if (__num__ == 0) \
    VAR.delete(); \
  else begin \
    TYPE __index__; \
    for (int __i__ = 0; __i__ < __num__; __i__++) begin \
      `uvm_unpack_enum(__index__, TYPE, PACKER) \
      `uvm_unpack_object(VAR[__index__], PACKER) \
    end \
  end \
end
   
//--

`define uvm_pack_aa_string_enum(VAR, TYPE, PACKER=packer) \
begin \
  PACKER.pack_field_int(VAR.num(), 32); \
  if (VAR.num()) begin \
    foreach(VAR[i]) begin \
      `uvm_pack_intN(i, SIZE, PACKER) \
      `uvm_pack_string(VAR[i], PACKER) \
    end \
  end \
end

`define uvm_unpack_aa_string_enum(VAR, TYPE, PACKER=packer) \
begin \
  int __num__ = PACKER.unpack_field_int(32); \
  if (__num__ == 0) \
    VAR.delete(); \
  else begin \
    TYPE __index__; \
    for (int __i__ = 0; __i__ < __num__; __i__++) begin \
      `uvm_unpack_enum(__index__, TYPE, PACKER) \
      `uvm_unpack_string(VAR[__index__], PACKER) \
    end \
  end \
end
   
//--

`define uvm_pack_sarray_real(VAR, PACKER=packer) \
  foreach(VAR[index]) \
    `uvm_pack_real(VAR[index], PACKER)

`define m_uvm_pack_qda_real(VAR, PACKER=packer) \
  `uvm_pack_intN(VAR.size(), 32, PACKER) \
  `uvm_pack_sarray_real(VAR, PACKER)

`define uvm_pack_queue_real(VAR, PACKER=packer) \
  `m_uvm_pack_qda_real(VAR, PACKER)

`define uvm_pack_da_real(VAR, PACKER=packer) \
  `m_uvm_pack_qda_real(VAR, PACKER)

`define uvm_unpack_sarray_real(VAR, PACKER=packer) \
  foreach(VAR[index]) \
    `uvm_unpack_real(VAR[index], PACKER)

`define uvm_unpack_da_real(VAR, PACKER=packer) \
  begin \
    int tmp_size__; \
    `uvm_unpack_intN(tmp_size__, 32, PACKER) \
    VAR = new [tmp_size__]; \
    `uvm_unpack_sarray_real(VAR, PACKER) \
  end

`define uvm_unpack_queue_real(VAR, PACKER=packer) \
  begin \
    int tmp_size__; \
    `uvm_unpack_intN(tmp_size__, 32, PACKER) \
    while (VAR.size() > tmp_size__) \
      void'(VAR.pop_back()); \
    for (int i = 0; i < tmp_size__; i++) \
      `uvm_unpack_real(VAR[i], PACKER) \
  end

`endif //  `ifndef UVM_PACKER_DEFINES_SVH
