// //------------------------------------------------------------------------------ // Copyright 2007-2018 Cadence Design Systems, Inc. // Copyright 2017-2018 Cisco Systems, Inc. // Copyright 2014 Intel Corporation // Copyright 2007-2014 Mentor Graphics Corporation // Copyright 2013-2020 NVIDIA Corporation // Copyright 2018 Qualcomm, Inc. // Copyright 2014 Semifore // Copyright 2018 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. //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ // 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-2020 // @uvm-ieee 1800.2-2020 auto 16.5.1 class uvm_packer extends uvm_policy; // @uvm-ieee 1800.2-2020 auto 16.5.2.3 `uvm_object_utils(uvm_packer) uvm_factory m_factory; local uvm_object m_object_references[int]; // Function -- NODOCS -- set_packed_* // Implementation of P1800.2 16.5.3.1 // // The LRM specifies the set_packed_* methods as being // signed, whereas the 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-ieee 1800.2-2020 auto 16.5.3.1 extern virtual function void set_packed_bits (ref bit unsigned stream[]); // @uvm-ieee 1800.2-2020 auto 16.5.3.1 extern virtual function void set_packed_bytes (ref byte unsigned stream[]); // @uvm-ieee 1800.2-2020 auto 16.5.3.1 extern virtual function void set_packed_ints (ref int unsigned stream[]); // @uvm-ieee 1800.2-2020 auto 16.5.3.1 extern virtual function void set_packed_longints (ref longint unsigned stream[]); // Function -- NODOCS -- get_packed_* // Implementation of P1800.2 16.5.3.2 // // The LRM specifies the get_packed_* methods as being // signed, whereas the 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-ieee 1800.2-2020 auto 16.5.3.2 extern virtual function void get_packed_bits (ref bit unsigned stream[]); // @uvm-ieee 1800.2-2020 auto 16.5.3.2 extern virtual function void get_packed_bytes (ref byte unsigned stream[]); // @uvm-ieee 1800.2-2020 auto 16.5.3.2 extern virtual function void get_packed_ints (ref int unsigned stream[]); // @uvm-ieee 1800.2-2020 auto 16.5.3.2 extern virtual function void get_packed_longints (ref longint unsigned stream[]); //----------------// // Group -- NODOCS -- Packing // //----------------// // @uvm-ieee 1800.2-2020 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-2020 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-2020 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-2020 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 is useful for sizes up // to 64 bits. // @uvm-ieee 1800.2-2020 auto 16.5.2.1 extern function new(string name=""); // @uvm-ieee 1800.2-2020 auto 16.5.4.9 extern virtual function void pack_field_int (uvm_integral_t value, int size); // @uvm-ieee 1800.2-2020 auto 16.5.4.1 extern virtual function void pack_bits(ref bit value[], input int size = -1); // @uvm-ieee 1800.2-2020 auto 16.5.4.10 extern virtual function void pack_bytes(ref byte value[], input int size = -1); // @uvm-ieee 1800.2-2020 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-2020 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-2020 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-2020 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-2020 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-2020 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-2020 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-2020 auto 16.5.4.17 extern virtual function uvm_integral_t unpack_field_int (int size); // @uvm-ieee 1800.2-2020 auto 16.5.4.18 extern virtual function void unpack_bits(ref bit value[], input int size = -1); // @uvm-ieee 1800.2-2020 auto 16.5.4.19 extern virtual function void unpack_bytes(ref byte value[], input int size = -1); // @uvm-ieee 1800.2-2020 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-2020 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-2020 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-2020 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 function can be used to peek at the next four bits in // the pack array before calling this method. // @uvm-ieee 1800.2-2020 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-2020 auto 16.5.3.3 extern virtual function int get_packed_size(); //------------------// // Group -- NODOCS -- Variables // //------------------// // 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; extern function void index_error(int index, string id, int sz); extern function bit enough_bits(int needed, string id); 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 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> ($bits(T)-(m_pack_iter%$bits(T)))); \ stream[i] = v; \ end \ endfunction `M__UVM_GET_PACKED(byte) `M__UVM_GET_PACKED(int) `M__UVM_GET_PACKED(longint) `undef M__UVM_GET_PACKED // set_packed_bits // -------- function void uvm_packer::set_packed_bits (ref bit stream []); int bit_size; bit_size = stream.size(); for (int i=0;i // call. // // Unlike , 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 , 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 // and . The object can only be unpacked via // . // // @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 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 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 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. // // Unlike , 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 , // 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 . 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 // or . The object must have been packed via // . // // @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 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 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