| // |
| //------------------------------------------------------------------------------ |
| // Copyright 2007-2014 Mentor Graphics Corporation |
| // Copyright 2014 Semifore |
| // Copyright 2018 Qualcomm, Inc. |
| // Copyright 2014 Intel Corporation |
| // Copyright 2018 Synopsys, Inc. |
| // Copyright 2007-2018 Cadence Design Systems, Inc. |
| // Copyright 2013-2018 NVIDIA Corporation |
| // Copyright 2017-2018 Cisco Systems, 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. |
| //------------------------------------------------------------------------------ |
| |
| |
| //------------------------------------------------------------------------------ |
| // CLASS -- NODOCS -- uvm_packer |
| // |
| // The uvm_packer class provides a policy object for packing and unpacking |
| // uvm_objects. The policies determine how packing and unpacking should be done. |
| // Packing an object causes the object to be placed into a bit (byte or int) |
| // array. If the `uvm_field_* macro are used to implement pack and unpack, |
| // by default no metadata information is stored for the packing of dynamic |
| // objects (strings, arrays, class objects). |
| // |
| //------------------------------------------------------------------------------- |
| |
| typedef bit signed [(`UVM_PACKER_MAX_BYTES*8)-1:0] uvm_pack_bitstream_t; |
| |
| // Class: uvm_packer |
| // Implementation of uvm_packer, as defined in section |
| // 16.5.1 of 1800.2-2017 |
| |
| // @uvm-ieee 1800.2-2017 auto 16.5.1 |
| class uvm_packer extends uvm_policy; |
| |
| // @uvm-ieee 1800.2-2017 auto 16.5.2.3 |
| `uvm_object_utils(uvm_packer) |
| |
| uvm_factory m_factory; |
| local uvm_object m_object_references[int]; |
| |
| |
| // Function: set_packed_* |
| // Implementation of P1800.2 16.5.3.1 |
| // |
| // The LRM specifies the set_packed_* methods as being |
| // signed, whereas the <uvm_object::unpack> methods are specified |
| // as unsigned. This is being tracked in Mantis 6423. |
| // |
| // The reference implementation has implemented these methods |
| // as unsigned so as to remain consistent. |
| // |
| //| virtual function void set_packed_bits( ref bit unsigned stream[] ); |
| //| virtual function void set_packed_bytes( ref byte unsigned stream[] ); |
| //| virtual function void set_packed_ints( ref int unsigned stream[] ); |
| //| virtual function void set_packed_longints( ref longint unsigned stream[] ); |
| // |
| // @uvm-contrib This API is being considered for potential contribution to 1800.2 |
| |
| // @uvm-ieee 1800.2-2017 auto 16.5.3.1 |
| extern virtual function void set_packed_bits (ref bit unsigned stream[]); |
| |
| // @uvm-ieee 1800.2-2017 auto 16.5.3.1 |
| extern virtual function void set_packed_bytes (ref byte unsigned stream[]); |
| |
| // @uvm-ieee 1800.2-2017 auto 16.5.3.1 |
| extern virtual function void set_packed_ints (ref int unsigned stream[]); |
| |
| // @uvm-ieee 1800.2-2017 auto 16.5.3.1 |
| extern virtual function void set_packed_longints (ref longint unsigned stream[]); |
| |
| // Function: get_packed_* |
| // Implementation of P1800.2 16.5.3.2 |
| // |
| // The LRM specifies the get_packed_* methods as being |
| // signed, whereas the <uvm_object::pack> methods are specified |
| // as unsigned. This is being tracked in Mantis 6423. |
| // |
| // The reference implementation has implemented these methods |
| // as unsigned so as to remain consistent. |
| // |
| //| virtual function void get_packed_bits( ref bit unsigned stream[] ); |
| //| virtual function void get_packed_bytes( ref byte unsigned stream[] ); |
| //| virtual function void get_packed_ints( ref int unsigned stream[] ); |
| //| virtual function void get_packed_longints( ref longint unsigned stream[] ); |
| // |
| // @uvm-contrib This API is being considered for potential contribution to 1800.2 |
| |
| // @uvm-ieee 1800.2-2017 auto 16.5.3.2 |
| extern virtual function void get_packed_bits (ref bit unsigned stream[]); |
| |
| // @uvm-ieee 1800.2-2017 auto 16.5.3.2 |
| extern virtual function void get_packed_bytes (ref byte unsigned stream[]); |
| |
| // @uvm-ieee 1800.2-2017 auto 16.5.3.2 |
| extern virtual function void get_packed_ints (ref int unsigned stream[]); |
| |
| // @uvm-ieee 1800.2-2017 auto 16.5.3.2 |
| extern virtual function void get_packed_longints (ref longint unsigned stream[]); |
| |
| //----------------// |
| // Group -- NODOCS -- Packing // |
| //----------------// |
| |
| // @uvm-ieee 1800.2-2017 auto 16.5.2.4 |
| static function void set_default (uvm_packer packer) ; |
| uvm_coreservice_t coreservice ; |
| coreservice = uvm_coreservice_t::get() ; |
| coreservice.set_default_packer(packer) ; |
| endfunction |
| |
| // @uvm-ieee 1800.2-2017 auto 16.5.2.5 |
| static function uvm_packer get_default () ; |
| uvm_coreservice_t coreservice ; |
| coreservice = uvm_coreservice_t::get() ; |
| return coreservice.get_default_packer() ; |
| endfunction |
| |
| |
| // @uvm-ieee 1800.2-2017 auto 16.5.2.2 |
| extern virtual function void flush (); |
| // Function -- NODOCS -- pack_field |
| // |
| // Packs an integral value (less than or equal to 4096 bits) into the |
| // packed array. ~size~ is the number of bits of ~value~ to pack. |
| |
| // @uvm-ieee 1800.2-2017 auto 16.5.4.8 |
| extern virtual function void pack_field (uvm_bitstream_t value, int size); |
| |
| |
| // Function -- NODOCS -- pack_field_int |
| // |
| // Packs the integral value (less than or equal to 64 bits) into the |
| // pack array. The ~size~ is the number of bits to pack, usually obtained by |
| // ~$bits~. This optimized version of <pack_field> is useful for sizes up |
| // to 64 bits. |
| |
| // @uvm-ieee 1800.2-2017 auto 16.5.2.1 |
| extern function new(string name=""); |
| |
| // @uvm-ieee 1800.2-2017 auto 16.5.4.9 |
| extern virtual function void pack_field_int (uvm_integral_t value, int size); |
| |
| |
| // @uvm-ieee 1800.2-2017 auto 16.5.4.1 |
| extern virtual function void pack_bits(ref bit value[], input int size = -1); |
| |
| |
| // @uvm-ieee 1800.2-2017 auto 16.5.4.10 |
| extern virtual function void pack_bytes(ref byte value[], input int size = -1); |
| |
| |
| // @uvm-ieee 1800.2-2017 auto 16.5.4.11 |
| extern virtual function void pack_ints(ref int value[], input int size = -1); |
| |
| // recursion functions |
| |
| |
| |
| // Function -- NODOCS -- pack_string |
| // |
| // Packs a string value into the pack array. |
| // |
| // When the metadata flag is set, the packed string is terminated by a ~null~ |
| // character to mark the end of the string. |
| // |
| // This is useful for mixed language communication where unpacking may occur |
| // outside of SystemVerilog UVM. |
| |
| // @uvm-ieee 1800.2-2017 auto 16.5.4.5 |
| extern virtual function void pack_string (string value); |
| |
| |
| // Function -- NODOCS -- pack_time |
| // |
| // Packs a time ~value~ as 64 bits into the pack array. |
| |
| // @uvm-ieee 1800.2-2017 auto 16.5.4.6 |
| extern virtual function void pack_time (time value); |
| |
| |
| // Function -- NODOCS -- pack_real |
| // |
| // Packs a real ~value~ as 64 bits into the pack array. |
| // |
| // The real ~value~ is converted to a 6-bit scalar value using the function |
| // $real2bits before it is packed into the array. |
| |
| // @uvm-ieee 1800.2-2017 auto 16.5.4.7 |
| extern virtual function void pack_real (real value); |
| |
| |
| // Function -- NODOCS -- pack_object |
| // |
| // Packs an object value into the pack array. |
| // |
| // A 4-bit header is inserted ahead of the string to indicate the number of |
| // bits that was packed. If a ~null~ object was packed, then this header will |
| // be 0. |
| // |
| // This is useful for mixed-language communication where unpacking may occur |
| // outside of SystemVerilog UVM. |
| |
| // @uvm-ieee 1800.2-2017 auto 16.5.4.2 |
| extern virtual function void pack_object (uvm_object value); |
| |
| extern virtual function void pack_object_with_meta (uvm_object value); |
| |
| extern virtual function void pack_object_wrapper (uvm_object_wrapper value); |
| |
| |
| //------------------// |
| // Group -- NODOCS -- Unpacking // |
| //------------------// |
| |
| // Function -- NODOCS -- is_null |
| // |
| // This method is used during unpack operations to peek at the next 4-bit |
| // chunk of the pack data and determine if it is 0. |
| // |
| // If the next four bits are all 0, then the return value is a 1; otherwise |
| // it is 0. |
| // |
| // This is useful when unpacking objects, to decide whether a new object |
| // needs to be allocated or not. |
| |
| // @uvm-ieee 1800.2-2017 auto 16.5.4.3 |
| extern virtual function bit is_null (); |
| |
| |
| extern virtual function bit is_object_wrapper(); |
| // Function -- NODOCS -- unpack_field |
| // |
| // Unpacks bits from the pack array and returns the bit-stream that was |
| // unpacked. ~size~ is the number of bits to unpack; the maximum is 4096 bits. |
| |
| // @uvm-ieee 1800.2-2017 auto 16.5.4.16 |
| extern virtual function uvm_bitstream_t unpack_field (int size); |
| |
| // Function -- NODOCS -- unpack_field_int |
| // |
| // Unpacks bits from the pack array and returns the bit-stream that was |
| // unpacked. |
| // |
| // ~size~ is the number of bits to unpack; the maximum is 64 bits. |
| // This is a more efficient variant than unpack_field when unpacking into |
| // smaller vectors. |
| |
| // @uvm-ieee 1800.2-2017 auto 16.5.4.17 |
| extern virtual function uvm_integral_t unpack_field_int (int size); |
| |
| |
| // @uvm-ieee 1800.2-2017 auto 16.5.4.18 |
| extern virtual function void unpack_bits(ref bit value[], input int size = -1); |
| |
| |
| // @uvm-ieee 1800.2-2017 auto 16.5.4.19 |
| extern virtual function void unpack_bytes(ref byte value[], input int size = -1); |
| |
| |
| // @uvm-ieee 1800.2-2017 auto 16.5.4.12 |
| extern virtual function void unpack_ints(ref int value[], input int size = -1); |
| |
| |
| // Function -- NODOCS -- unpack_string |
| // |
| // Unpacks a string. |
| // |
| // num_chars bytes are unpacked into a string. If num_chars is -1 then |
| // unpacking stops on at the first ~null~ character that is encountered. |
| |
| // @uvm-ieee 1800.2-2017 auto 16.5.4.13 |
| extern virtual function string unpack_string (); |
| |
| |
| // Function -- NODOCS -- unpack_time |
| // |
| // Unpacks the next 64 bits of the pack array and places them into a |
| // time variable. |
| |
| // @uvm-ieee 1800.2-2017 auto 16.5.4.14 |
| extern virtual function time unpack_time (); |
| |
| |
| // Function -- NODOCS -- unpack_real |
| // |
| // Unpacks the next 64 bits of the pack array and places them into a |
| // real variable. |
| // |
| // The 64 bits of packed data are converted to a real using the $bits2real |
| // system function. |
| |
| // @uvm-ieee 1800.2-2017 auto 16.5.4.15 |
| extern virtual function real unpack_real (); |
| |
| |
| // Function -- NODOCS -- unpack_object |
| // |
| // Unpacks an object and stores the result into ~value~. |
| // |
| // ~value~ must be an allocated object that has enough space for the data |
| // being unpacked. The first four bits of packed data are used to determine |
| // if a ~null~ object was packed into the array. |
| // |
| // The <is_null> function can be used to peek at the next four bits in |
| // the pack array before calling this method. |
| |
| // @uvm-ieee 1800.2-2017 auto 16.5.4.4 |
| extern virtual function void unpack_object (uvm_object value); |
| |
| extern virtual function void unpack_object_with_meta (inout uvm_object value); |
| |
| extern virtual function uvm_object_wrapper unpack_object_wrapper(); |
| |
| |
| // Function -- NODOCS -- get_packed_size |
| // |
| // Returns the number of bits that were packed. |
| |
| // @uvm-ieee 1800.2-2017 auto 16.5.3.3 |
| extern virtual function int get_packed_size(); |
| |
| |
| //------------------// |
| // Group -- NODOCS -- Variables // |
| //------------------// |
| |
| `ifdef UVM_ENABLE_DEPRECATED_API |
| // Variable -- NODOCS -- physical |
| // |
| // This bit provides a filtering mechanism for fields. |
| // |
| // The <abstract> and physical settings allow an object to distinguish between |
| // two different classes of fields. It is up to you, in the |
| // <uvm_object::do_pack> and <uvm_object::do_unpack> methods, to test the |
| // setting of this field if you want to use it as a filter. |
| |
| bit physical = 1; |
| |
| |
| // Variable -- NODOCS -- abstract |
| // |
| // This bit provides a filtering mechanism for fields. |
| // |
| // The abstract and physical settings allow an object to distinguish between |
| // two different classes of fields. It is up to you, in the |
| // <uvm_object::do_pack> and <uvm_object::do_unpack> routines, to test the |
| // setting of this field if you want to use it as a filter. |
| |
| bit abstract; |
| |
| |
| // Variable -- NODOCS -- big_endian |
| // |
| // This bit determines the order that integral data is packed (using |
| // <pack_field>, <pack_field_int>, <pack_time>, or <pack_real>) and how the |
| // data is unpacked from the pack array (using <unpack_field>, |
| // <unpack_field_int>, <unpack_time>, or <unpack_real>). When the bit is set, |
| // data is associated msb to lsb; otherwise, it is associated lsb to msb. |
| // |
| // The following code illustrates how data can be associated msb to lsb and |
| // lsb to msb: |
| // |
| //| class mydata extends uvm_object; |
| //| |
| //| logic[15:0] value = 'h1234; |
| //| |
| //| function void do_pack (uvm_packer packer); |
| //| packer.pack_field_int(value, 16); |
| //| endfunction |
| //| |
| //| function void do_unpack (uvm_packer packer); |
| //| value = packer.unpack_field_int(16); |
| //| endfunction |
| //| endclass |
| //| |
| //| mydata d = new; |
| //| bit bits[]; |
| //| |
| //| initial begin |
| //| d.pack(bits); // 'b0001001000110100 |
| //| uvm_default_packer.big_endian = 0; |
| //| d.pack(bits); // 'b0010110001001000 |
| //| end |
| |
| bit big_endian = 0; |
| `endif |
| |
| // variables and methods primarily for internal use |
| |
| static bit bitstream[]; // local bits for (un)pack_bytes |
| static bit fabitstream[]; // field automation bits for (un)pack_bytes |
| int m_pack_iter; // Used to track the bit of the next pack |
| int m_unpack_iter; // Used to track the bit of the next unpack |
| |
| bit reverse_order; //flip the bit order around |
| byte byte_size = 8; //set up bytesize for endianess |
| int word_size = 16; //set up worksize for endianess |
| bit nopack; //only count packable bits |
| |
| uvm_pack_bitstream_t m_bits; |
| |
| |
| `ifdef UVM_ENABLE_DEPRECATED_API |
| extern virtual function bit unsigned get_bit (int unsigned index); |
| extern virtual function byte unsigned get_byte (int unsigned index); |
| extern virtual function int unsigned get_int (int unsigned index); |
| |
| extern virtual function void get_bits (ref bit unsigned bits[]); |
| extern virtual function void get_bytes(ref byte unsigned bytes[]); |
| extern virtual function void get_ints (ref int unsigned ints[]); |
| |
| extern virtual function void put_bits (ref bit unsigned bitstream[]); |
| extern virtual function void put_bytes(ref byte unsigned bytestream[]); |
| extern virtual function void put_ints (ref int unsigned intstream[]); |
| |
| extern virtual function void set_packed_size(); |
| `endif |
| |
| extern function void index_error(int index, string id, int sz); |
| extern function bit enough_bits(int needed, string id); |
| |
| `ifdef UVM_ENABLE_DEPRECATED_API |
| extern function void reset(); |
| `endif |
| |
| endclass |
| |
| |
| |
| //------------------------------------------------------------------------------ |
| // IMPLEMENTATION |
| //------------------------------------------------------------------------------ |
| |
| // NOTE- max size limited to BITSTREAM bits parameter (default: 4096) |
| |
| |
| // index_ok |
| // -------- |
| |
| function void uvm_packer::index_error(int index, string id, int sz); |
| uvm_report_error("PCKIDX", |
| $sformatf("index %0d for get_%0s too large; valid index range is 0-%0d.", |
| index,id,((m_pack_iter+sz-1)/sz)-1), UVM_NONE); |
| endfunction |
| |
| |
| // enough_bits |
| // ----------- |
| |
| function bit uvm_packer::enough_bits(int needed, string id); |
| if ((m_pack_iter - m_unpack_iter) < needed) begin |
| uvm_report_error("PCKSZ", |
| $sformatf("%0d bits needed to unpack %0s, yet only %0d available.", |
| needed, id, (m_pack_iter - m_unpack_iter)), UVM_NONE); |
| return 0; |
| end |
| return 1; |
| endfunction |
| |
| |
| // get_packed_size |
| // --------------- |
| |
| function int uvm_packer::get_packed_size(); |
| return m_pack_iter - m_unpack_iter; |
| endfunction |
| |
| |
| `ifdef UVM_ENABLE_DEPRECATED_API |
| // set_packed_size |
| // --------------- |
| |
| function void uvm_packer::set_packed_size(); |
| /* doesn't actually do anything now */ |
| endfunction |
| |
| // reset |
| // ----- |
| |
| function void uvm_packer::reset(); |
| flush(); |
| endfunction |
| |
| function void uvm_packer::get_bits( ref bit bits [] ); get_packed_bits(bits); endfunction |
| function void uvm_packer::get_bytes( ref byte unsigned bytes [] ); get_packed_bytes(bytes); endfunction |
| function void uvm_packer::get_ints( ref int unsigned ints [] ); get_packed_ints(ints); endfunction |
| `endif |
| |
| function void uvm_packer::flush(); |
| // The iterators are spaced 64b from the beginning, enough to store |
| // the iterators during get_packed_* and retrieve them during |
| // set_packed_*. Without this, set_packed_[byte|int|longint] will |
| // move the iterators too far. |
| m_pack_iter = 64; |
| m_unpack_iter = 64; |
| m_bits = 0; |
| m_object_references.delete(); |
| m_object_references[0] = null; |
| m_factory = null; |
| super.flush(); |
| endfunction : flush |
| |
| // get_packed_bits |
| // -------- |
| |
| function void uvm_packer::get_packed_bits(ref bit unsigned stream[]); |
| stream = new[m_pack_iter]; |
| m_bits[31:0] = m_pack_iter; /* Reserved bits */ |
| m_bits[63:32] = m_unpack_iter; /* Reserved bits */ |
| for (int i=0;i<m_pack_iter;i++) |
| stream[i] = m_bits[i]; |
| endfunction |
| |
| `ifdef UVM_ENABLE_DEPRECATED_API |
| // When deprecated, we support big_endian |
| `define M__UVM_GET_PACKED(T) \ |
| function void uvm_packer::get_packed_``T``s (ref T unsigned stream[] ); \ |
| int sz; \ |
| T v; \ |
| sz = (m_pack_iter + $high(v)) / $bits(T); \ |
| stream = new[sz]; \ |
| m_bits[31:0] = m_pack_iter; /* Reserved Bits */ \ |
| m_bits[63:32] = m_unpack_iter; /* Reserved Bits */ \ |
| foreach (stream[i]) begin \ |
| if (i != sz-1 || (m_pack_iter % $bits(T)) == 0) \ |
| v = m_bits[ i* $bits(T) +: $bits(T) ]; \ |
| else \ |
| v = m_bits[ i* $bits(T) +: $bits(T) ] & ({$bits(T){1'b1}} >> ($bits(T)-(m_pack_iter%$bits(T)))); \ |
| if(big_endian) \ |
| v = {<<{v}}; \ |
| stream[i] = v; \ |
| end \ |
| endfunction |
| `else // !`ifdef UVM_ENABLE_DEPRECATED_API |
| `define M__UVM_GET_PACKED(T) \ |
| function void uvm_packer::get_packed_``T``s (ref T unsigned stream[] ); \ |
| int sz; \ |
| T v; \ |
| sz = (m_pack_iter + $high(v)) / $bits(T); \ |
| m_bits[31:0] = m_pack_iter; /* Reserved Bits */ \ |
| m_bits[63:32] = m_unpack_iter; /* Reserved Bits */ \ |
| stream = new[sz]; \ |
| foreach (stream[i]) begin \ |
| if (i != sz-1 || (m_pack_iter % $bits(T)) == 0) \ |
| v = m_bits[ i* $bits(T) +: $bits(T) ]; \ |
| else \ |
| v = m_bits[ i* $bits(T) +: $bits(T) ] & ({$bits(T){1'b1}} >> ($bits(T)-(m_pack_iter%$bits(T)))); \ |
| stream[i] = v; \ |
| end \ |
| endfunction |
| `endif // !`ifdef UVM_ENABLE_DEPRECATED_API |
| |
| `M__UVM_GET_PACKED(byte) |
| `M__UVM_GET_PACKED(int) |
| `M__UVM_GET_PACKED(longint) |
| |
| `undef M__UVM_GET_PACKED |
| |
| `ifdef UVM_ENABLE_DEPRECATED_API |
| function void uvm_packer::put_bits( ref bit bitstream [] ); set_packed_bits(bitstream); endfunction |
| function void uvm_packer::put_bytes( ref byte unsigned bytestream [] ); set_packed_bytes(bytestream); endfunction |
| function void uvm_packer::put_ints( ref int unsigned intstream [] ); set_packed_ints(intstream); endfunction |
| `endif |
| |
| // set_packed_bits |
| // -------- |
| |
| function void uvm_packer::set_packed_bits (ref bit stream []); |
| |
| int bit_size; |
| |
| bit_size = stream.size(); |
| |
| `ifdef UVM_ENABLE_DEPRECATED_API |
| if(big_endian) |
| for (int i=bit_size-1;i>=0;i--) |
| m_bits[i] = stream[i]; |
| else |
| `endif |
| for (int i=0;i<bit_size;i++) |
| m_bits[i] = stream[i]; |
| |
| m_pack_iter = m_bits[31:0]; /* Reserved Bits */ |
| m_unpack_iter = m_bits[63:32]; /* Reserved Bits */ |
| |
| endfunction |
| |
| `ifdef UVM_ENABLE_DEPRECATED_API |
| // In deprecated mode we support big_endian |
| `define M__UVM_SET_PACKED(T) \ |
| function void uvm_packer::set_packed_``T``s (ref T unsigned stream []); \ |
| int count; \ |
| foreach(stream[i]) begin \ |
| if (big_endian) \ |
| m_bits[count +: $bits(T)] = {<<{stream[i]}}; \ |
| else \ |
| m_bits[count +: $bits(T)] = stream[i]; \ |
| count += $bits(T); \ |
| end \ |
| m_pack_iter = m_bits[31:0]; /* Reserved Bits */ \ |
| m_unpack_iter = m_bits[63:32]; /* Reserved Bits */ \ |
| endfunction |
| `else // !`ifdef UVM_ENABLE_DEPRECATED_API |
| `define M__UVM_SET_PACKED(T) \ |
| function void uvm_packer::set_packed_``T``s (ref T unsigned stream []); \ |
| int count; \ |
| foreach(stream[i]) begin \ |
| m_bits[count +: $bits(T)] = stream[i]; \ |
| count += $bits(T); \ |
| end \ |
| m_pack_iter = m_bits[31:0]; /* Reserved Bits */ \ |
| m_unpack_iter = m_bits[63:32]; /* Reserved Bits */ \ |
| endfunction |
| `endif |
| |
| `M__UVM_SET_PACKED(byte) |
| `M__UVM_SET_PACKED(int) |
| `M__UVM_SET_PACKED(longint) |
| |
| `undef M__UVM_SET_PACKED |
| |
| `ifdef UVM_ENABLE_DEPRECATED_API |
| // get_bit |
| // ------- |
| |
| function bit unsigned uvm_packer::get_bit(int unsigned index); |
| if (index >= m_pack_iter) |
| index_error(index, "bit",1); |
| return m_bits[index]; |
| endfunction |
| |
| |
| // get_byte |
| // -------- |
| |
| function byte unsigned uvm_packer::get_byte(int unsigned index); |
| if (index >= (m_pack_iter+7)/8) |
| index_error(index, "byte",8); |
| return m_bits[index*8 +: 8]; |
| endfunction |
| |
| |
| // get_int |
| // ------- |
| |
| function int unsigned uvm_packer::get_int(int unsigned index); |
| if (index >= (m_pack_iter+31)/32) |
| index_error(index, "int",32); |
| return m_bits[(index*32) +: 32]; |
| endfunction |
| `endif |
| |
| // PACK |
| |
| |
| // pack_object |
| // --------- |
| |
| function void uvm_packer::pack_object(uvm_object value); |
| uvm_field_op field_op; |
| if (value == null ) begin |
| m_bits[m_pack_iter +: 4] = 0; |
| m_pack_iter += 4; |
| return ; |
| end |
| else begin |
| m_bits[m_pack_iter +: 4] = 4'hF; |
| m_pack_iter += 4; |
| end |
| |
| push_active_object(value); |
| field_op = uvm_field_op::m_get_available_op() ; |
| field_op.set(UVM_PACK,this,value); |
| value.do_execute_op(field_op); |
| if (field_op.user_hook_enabled()) begin |
| value.do_pack(this); |
| end |
| field_op.m_recycle(); |
| void'(pop_active_object()); |
| endfunction |
| |
| // Function: pack_object_with_meta |
| // Packs ~obj~ into the packer data stream, such that |
| // it can be unpacked via an associated <unpack_object_with_meta> |
| // call. |
| // |
| // Unlike <pack_object>, the pack_object_with_meta method keeps track |
| // of what objects have already been packed in this call chain. The |
| // first time an object is passed to pack_object_with_meta after a |
| // call to <flush>, the object is assigned a unique id. Subsequent |
| // calls to pack_object_with_meta will only add the unique id to the |
| // stream. This allows structural information to be maintained through |
| // pack/unpack operations. |
| // |
| // Note: pack_object_with_meta is not compatible with <unpack_object> |
| // and <is_null>. The object can only be unpacked via |
| // <unpack_object_with_meta>. |
| // |
| // @uvm-contrib This API is being considered for potential contribution to 1800.2 |
| function void uvm_packer::pack_object_with_meta(uvm_object value); |
| int reference_id; |
| foreach(m_object_references[i]) begin |
| if (m_object_references[i] == value) begin |
| pack_field_int(i,32); |
| return; |
| end |
| end |
| |
| // Size will always be >0 because 0 is the null |
| reference_id = m_object_references.size(); |
| pack_field_int(reference_id,32); |
| m_object_references[reference_id] = value; |
| pack_object_wrapper(value.get_object_type()); |
| |
| pack_object(value); |
| endfunction |
| |
| |
| function void uvm_packer::pack_object_wrapper(uvm_object_wrapper value); |
| string type_name; |
| if (value != null) begin |
| pack_string(value.get_type_name()); |
| end |
| endfunction |
| // pack_real |
| // --------- |
| |
| function void uvm_packer::pack_real(real value); |
| pack_field_int($realtobits(value), 64); |
| endfunction |
| |
| |
| // pack_time |
| // --------- |
| |
| function void uvm_packer::pack_time(time value); |
| pack_field_int(value, 64); |
| //m_bits[m_pack_iter +: 64] = value; this overwrites endian adjustments |
| endfunction |
| |
| |
| // pack_field |
| // ---------- |
| |
| function void uvm_packer::pack_field(uvm_bitstream_t value, int size); |
| for (int i=0; i<size; i++) |
| `ifdef UVM_ENABLE_DEPRECATED_API |
| if(big_endian == 1) |
| m_bits[m_pack_iter+i] = value[size-1-i]; |
| else |
| `endif |
| m_bits[m_pack_iter+i] = value[i]; |
| m_pack_iter += size; |
| endfunction |
| |
| |
| // pack_field_int |
| // -------------- |
| |
| function void uvm_packer::pack_field_int(uvm_integral_t value, int size); |
| for (int i=0; i<size; i++) |
| `ifdef UVM_ENABLE_DEPRECATED_API |
| if(big_endian == 1) |
| m_bits[m_pack_iter+i] = value[size-1-i]; |
| else |
| `endif |
| m_bits[m_pack_iter+i] = value[i]; |
| m_pack_iter += size; |
| endfunction |
| |
| // pack_bits |
| // ----------------- |
| |
| function void uvm_packer::pack_bits(ref bit value[], input int size = -1); |
| if (size < 0) |
| size = value.size(); |
| |
| if (size > value.size()) begin |
| `uvm_error("UVM/BASE/PACKER/BAD_SIZE", |
| $sformatf("pack_bits called with size '%0d', which exceeds value.size() of '%0d'", |
| size, |
| value.size())) |
| return; |
| end |
| |
| for (int i=0; i<size; i++) |
| `ifdef UVM_ENABLE_DEPRECATED_API |
| if (big_endian == 1) |
| m_bits[m_pack_iter+i] = value[size-1-i]; |
| else |
| `endif |
| m_bits[m_pack_iter+i] = value[i]; |
| m_pack_iter += size; |
| endfunction |
| |
| // pack_bytes |
| // ----------------- |
| |
| function void uvm_packer::pack_bytes(ref byte value[], input int size = -1); |
| int max_size = value.size() * $bits(byte); |
| |
| if (size < 0) |
| size = max_size; |
| |
| if (size > max_size) begin |
| `uvm_error("UVM/BASE/PACKER/BAD_SIZE", |
| $sformatf("pack_bytes called with size '%0d', which exceeds value size of '%0d'", |
| size, |
| max_size)) |
| return; |
| end |
| else begin |
| int idx_select; |
| |
| for (int i=0; i<size; i++) begin |
| `ifdef UVM_ENABLE_DEPRECATED_API |
| if (big_endian == 1) |
| idx_select = size-1-i; |
| else |
| `endif |
| idx_select = i; |
| |
| m_bits[m_pack_iter+i] = value[idx_select / $bits(byte)][idx_select % $bits(byte)]; |
| end |
| |
| m_pack_iter += size; |
| end |
| endfunction |
| |
| // pack_ints |
| // ----------------- |
| |
| function void uvm_packer::pack_ints(ref int value[], input int size = -1); |
| int max_size = value.size() * $bits(int); |
| |
| if (size < 0) |
| size = max_size; |
| |
| if (size > max_size) begin |
| `uvm_error("UVM/BASE/PACKER/BAD_SIZE", |
| $sformatf("pack_ints called with size '%0d', which exceeds value size of '%0d'", |
| size, |
| max_size)) |
| return; |
| end |
| else begin |
| int idx_select; |
| |
| for (int i=0; i<size; i++) begin |
| `ifdef UVM_ENABLE_DEPRECATED_API |
| if (big_endian == 1) |
| idx_select = size-1-i; |
| else |
| `endif |
| idx_select = i; |
| |
| m_bits[m_pack_iter+i] = value[idx_select / $bits(int)][idx_select % $bits(int)]; |
| end |
| |
| m_pack_iter += size; |
| end |
| endfunction |
| |
| |
| // pack_string |
| // ----------- |
| |
| function void uvm_packer::pack_string(string value); |
| byte b; |
| `ifdef UVM_ENABLE_DEPRECATED_API |
| foreach (value[index]) begin |
| if(big_endian == 1) begin |
| b = value[index]; |
| for(int i=0; i<8; ++i) |
| m_bits[m_pack_iter+i] = b[7-i]; |
| end |
| else |
| m_bits[m_pack_iter +: 8] = value[index]; |
| m_pack_iter += 8; |
| end |
| `else // !`ifdef UVM_ENABLE_DEPRECATED_API |
| foreach (value[index]) begin |
| m_bits[m_pack_iter +: 8] = value[index]; |
| m_pack_iter += 8; |
| end |
| `endif // !`ifdef UVM_ENABLE_DEPRECATED_API |
| m_bits[m_pack_iter +: 8] = 0; |
| m_pack_iter += 8; |
| endfunction |
| |
| |
| // UNPACK |
| |
| |
| // is_null |
| // ------- |
| |
| function bit uvm_packer::is_null(); |
| return (m_bits[m_unpack_iter+:4]==0); |
| endfunction |
| |
| |
| function bit uvm_packer::is_object_wrapper(); |
| return (m_bits[m_unpack_iter+:4]==1); |
| endfunction |
| // unpack_object |
| // ------------- |
| |
| function void uvm_packer::unpack_object(uvm_object value); |
| uvm_field_op field_op; |
| |
| if (is_null()) begin |
| if (value != null) begin |
| `uvm_error("UVM/BASE/PACKER/UNPACK/N2NN", "attempt to unpack a null object into a not-null object!") |
| return; |
| end |
| m_unpack_iter += 4; // advance past the null |
| return; |
| end |
| else begin |
| if (value == null) begin |
| `uvm_error("UVM/BASE/PACKER/UNPACK/NN2N", "attempt to unpack a non-null object into a null object!") |
| return; |
| end |
| m_unpack_iter += 4; // advance past the !null |
| push_active_object(value); |
| field_op = uvm_field_op::m_get_available_op() ; |
| field_op.set(UVM_UNPACK,this,value); |
| value.do_execute_op(field_op); |
| if (field_op.user_hook_enabled()) begin |
| value.do_unpack(this); |
| end |
| field_op.m_recycle(); |
| void'(pop_active_object()); |
| end |
| |
| endfunction |
| |
| // Function: unpack_object_with_meta |
| // Unpacks an object which was packed into the packer data |
| // stream using <pack_object_with_meta>. |
| // |
| // Unlike <unpack_object>, the unpack_object_with_meta method keeps track |
| // of what objects have already been unpacked in this call chain. If the |
| // packed object was null, then ~value~ is set to null. Otherwise, if this |
| // is the first time the object's unique id |
| // has been encountered since a call to <flush>, |
| // then unpack_object_with_meta checks ~value~ to determine if it is the |
| // correct type. If it is not the correct type, or if ~value~ is null, |
| // then the packer shall create a new object instance for the unpack operation, |
| // using the data provided by <pack_object_with_meta>. If ~value~ is of the |
| // correct type, then it is used as the object instance for the unpack operation. |
| // Subsequent calls to unpack_object_with_meta for this unique id shall |
| // simply set ~value~ to this object instance. |
| // |
| // Note: unpack_object_with_meta is not compatible with <pack_object> |
| // or <is_null>. The object must have been packed via |
| // <pack_object_with_meta>. |
| // |
| // @uvm-contrib This API is being considered for potential contribution to 1800.2 |
| function void uvm_packer::unpack_object_with_meta(inout uvm_object value); |
| int reference_id; |
| reference_id = unpack_field_int(32); |
| if (m_object_references.exists(reference_id)) begin |
| value = m_object_references[reference_id]; |
| return; |
| end |
| else begin |
| uvm_object_wrapper __wrapper = unpack_object_wrapper(); |
| if ((__wrapper != null) && |
| ((value == null) || (value.get_object_type() != __wrapper))) begin |
| value = __wrapper.create_object(""); |
| if (value == null) begin |
| value = __wrapper.create_component("",null); |
| end |
| end |
| end |
| m_object_references[reference_id] = value; |
| unpack_object(value); |
| endfunction |
| |
| |
| function uvm_object_wrapper uvm_packer::unpack_object_wrapper(); |
| string type_name; |
| type_name = unpack_string(); |
| if (m_factory == null) |
| m_factory = uvm_factory::get(); |
| if (m_factory.is_type_name_registered(type_name)) begin |
| return m_factory.find_wrapper_by_name(type_name); |
| end |
| return null; |
| |
| endfunction |
| |
| // unpack_real |
| // ----------- |
| |
| function real uvm_packer::unpack_real(); |
| if (enough_bits(64,"real")) begin |
| return $bitstoreal(unpack_field_int(64)); |
| end |
| endfunction |
| |
| |
| // unpack_time |
| // ----------- |
| |
| function time uvm_packer::unpack_time(); |
| if (enough_bits(64,"time")) begin |
| return unpack_field_int(64); |
| end |
| endfunction |
| |
| |
| // unpack_field |
| // ------------ |
| |
| function uvm_bitstream_t uvm_packer::unpack_field(int size); |
| unpack_field = 'b0; |
| if (enough_bits(size,"integral")) begin |
| m_unpack_iter += size; |
| for (int i=0; i<size; i++) |
| `ifdef UVM_ENABLE_DEPRECATED_API |
| if(big_endian == 1) |
| unpack_field[i] = m_bits[m_unpack_iter-i-1]; |
| else |
| `endif |
| unpack_field[i] = m_bits[m_unpack_iter-size+i]; |
| end |
| endfunction |
| |
| |
| // unpack_field_int |
| // ---------------- |
| |
| function uvm_integral_t uvm_packer::unpack_field_int(int size); |
| unpack_field_int = 'b0; |
| if (enough_bits(size,"integral")) begin |
| m_unpack_iter += size; |
| for (int i=0; i<size; i++) |
| `ifdef UVM_ENABLE_DEPRECATED_API |
| if(big_endian == 1) |
| unpack_field_int[i] = m_bits[m_unpack_iter-i-1]; |
| else |
| `endif |
| unpack_field_int[i] = m_bits[m_unpack_iter-size+i]; |
| end |
| endfunction |
| |
| // unpack_bits |
| // ------------------- |
| |
| function void uvm_packer::unpack_bits(ref bit value[], input int size = -1); |
| if (size < 0) |
| size = value.size(); |
| |
| if (size > value.size()) begin |
| `uvm_error("UVM/BASE/PACKER/BAD_SIZE", |
| $sformatf("unpack_bits called with size '%0d', which exceeds value.size() of '%0d'", |
| size, |
| value.size())) |
| return; |
| end |
| |
| if (enough_bits(size, "integral")) begin |
| m_unpack_iter += size; |
| for (int i=0; i<size; i++) |
| `ifdef UVM_ENABLE_DEPRECATED_API |
| if (big_endian == 1) |
| value[i] = m_bits[m_unpack_iter-i-1]; |
| else |
| `endif |
| value[i] = m_bits[m_unpack_iter-size+i]; |
| end |
| endfunction |
| |
| // unpack_bytes |
| // ------------------- |
| |
| function void uvm_packer::unpack_bytes(ref byte value[], input int size = -1); |
| int max_size = value.size() * $bits(byte); |
| if (size < 0) |
| size = max_size; |
| |
| if (size > max_size) begin |
| `uvm_error("UVM/BASE/PACKER/BAD_SIZE", |
| $sformatf("unpack_bytes called with size '%0d', which exceeds value size of '%0d'", |
| size, |
| value.size())) |
| return; |
| end |
| else begin |
| if (enough_bits(size, "integral")) begin |
| m_unpack_iter += size; |
| |
| for (int i=0; i<size; i++) begin |
| `ifdef UVM_ENABLE_DEPRECATED_API |
| if (big_endian == 1) |
| value[ i / $bits(byte) ][ i % $bits(byte) ] = m_bits[m_unpack_iter-i-1]; |
| else |
| `endif |
| value[ i / $bits(byte) ][ i % $bits(byte) ] = m_bits[m_unpack_iter-size+i]; |
| |
| end |
| end // if (enough_bits(size, "integral")) |
| end |
| endfunction |
| |
| // unpack_ints |
| // ------------------- |
| |
| function void uvm_packer::unpack_ints(ref int value[], input int size = -1); |
| int max_size = value.size() * $bits(int); |
| if (size < 0) |
| size = max_size; |
| |
| if (size > max_size) begin |
| `uvm_error("UVM/BASE/PACKER/BAD_SIZE", |
| $sformatf("unpack_ints called with size '%0d', which exceeds value size of '%0d'", |
| size, |
| value.size())) |
| return; |
| end |
| else begin |
| if (enough_bits(size, "integral")) begin |
| m_unpack_iter += size; |
| |
| for (int i=0; i<size; i++) begin |
| `ifdef UVM_ENABLE_DEPRECATED_API |
| if (big_endian == 1) |
| value[ i / $bits(int) ][ i % $bits(int) ] = m_bits[m_unpack_iter-i-1]; |
| else |
| `endif |
| value[ i / $bits(int) ][ i % $bits(int) ] = m_bits[m_unpack_iter-size+i]; |
| end |
| end |
| end |
| endfunction |
| |
| |
| // unpack_string |
| // ------------- |
| |
| // If num_chars is not -1, then the user only wants to unpack a |
| // specific number of bytes into the string. |
| function string uvm_packer::unpack_string(); |
| byte b; |
| int i; i=0; |
| |
| while(enough_bits(8,"string") && |
| (m_bits[m_unpack_iter+:8] != 0) ) |
| begin |
| // silly, because cannot append byte/char to string |
| unpack_string = {unpack_string," "}; |
| `ifdef UVM_ENABLE_DEPRECATED_API |
| if(big_endian == 1) begin |
| for(int j=0; j<8; ++j) |
| b[7-j] = m_bits[m_unpack_iter+j]; |
| unpack_string[i] = b; |
| end |
| else |
| `endif |
| unpack_string[i] = m_bits[m_unpack_iter +: 8]; |
| m_unpack_iter += 8; |
| ++i; |
| end |
| if(enough_bits(8,"string")) |
| m_unpack_iter += 8; |
| endfunction |
| |
| |
| // Constructor implementation |
| function uvm_packer::new(string name=""); |
| super.new(name); |
| flush(); |
| endfunction |
| |
| |