URL
https://opencores.org/ocsvn/uart2bus_testbench/uart2bus_testbench/trunk
Subversion Repositories uart2bus_testbench
[/] [uart2bus_testbench/] [trunk/] [tb/] [uvm_src/] [base/] [uvm_packer.svh] - Rev 16
Compare with Previous | Blame | View Log
////------------------------------------------------------------------------------// Copyright 2007-2011 Mentor Graphics Corporation// Copyright 2007-2011 Cadence Design Systems, Inc.// Copyright 2010 Synopsys, Inc.// Copyright 2013 NVIDIA Corporation// 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: 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;//----------------//// Group: Packing ////----------------//// Function: 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.extern virtual function void pack_field (uvm_bitstream_t value, int size);// Function: 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.extern virtual function void pack_field_int (uvm_integral_t value, int size);// Function: pack_bits//// Packs bits from upacked array of bits into the pack array.//// See <pack_ints> for additional information.extern virtual function void pack_bits(ref bit value[], input int size = -1);// Function: pack_bytes//// Packs bits from an upacked array of bytes into the pack array.//// See <pack_ints> for additional information.extern virtual function void pack_bytes(ref byte value[], input int size = -1);// Function: pack_ints//// Packs bits from an unpacked array of ints into the pack array.//// The bits are appended to the internal pack array.// This method allows for fields of arbitrary length to be// passed in, using the SystemVerilog ~stream~ operator.//// For example// | bit[511:0] my_field;// | begin// | int my_stream[];// | { << int {my_stream}} = my_field;// | packer.pack_ints(my_stream);// | end//// When appending the stream to the internal pack array, the packer will obey// the value of <big_endian> (appending the array from MSB to LSB if set).//// An optional ~size~ parameter is provided, which defaults to '-1'. If set// to any value greater than '-1' (including 0), then the packer will use// the size as the number of bits to pack, otherwise the packer will simply// pack the entire stream.//// An error will be asserted if the ~size~ has been specified, and exceeds the// size of the source array.//extern virtual function void pack_ints(ref int value[], input int size = -1);// Function: 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.extern virtual function void pack_string (string value);// Function: pack_time//// Packs a time ~value~ as 64 bits into the pack array.extern virtual function void pack_time (time value);// Function: 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.extern virtual function void pack_real (real value);// Function: 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.extern virtual function void pack_object (uvm_object value);//------------------//// Group: Unpacking ////------------------//// Function: 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.extern virtual function bit is_null ();// Function: 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.extern virtual function uvm_bitstream_t unpack_field (int size);// Function: 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.extern virtual function uvm_integral_t unpack_field_int (int size);// Function: unpack_bits//// Unpacks bits from the pack array into an unpacked array of bits.//extern virtual function void unpack_bits(ref bit value[], input int size = -1);// Function: unpack_bytes//// Unpacks bits from the pack array into an unpacked array of bytes.//extern virtual function void unpack_bytes(ref byte value[], input int size = -1);// Function: unpack_ints//// Unpacks bits from the pack array into an unpacked array of ints.//// The unpacked array is unpacked from the internal pack array.// This method allows for fields of arbitrary length to be// passed in without expanding into a pre-defined integral type first.//// For example// | bit[511:0] my_field;// | begin// | int my_stream[] = new[16]; // 512/32 = 16// | packer.unpack_ints(my_stream);// | my_field = {<<{my_stream}};// | end//// When unpacking the stream from the internal pack array, the packer will obey// the value of <big_endian> (unpacking the array from MSB to LSB if set).//// An optional ~size~ parameter is provided, which defaults to '-1'. If set// to any value greater than '-1' (including 0), then the packer will use// the size as the number of bits to unpack, otherwise the packer will simply// unpack the entire stream.//// An error will be asserted if the ~size~ has been specified, and// exceeds the size of the target array.//extern virtual function void unpack_ints(ref int value[], input int size = -1);// Function: 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.extern virtual function string unpack_string (int num_chars=-1);// Function: unpack_time//// Unpacks the next 64 bits of the pack array and places them into a// time variable.extern virtual function time unpack_time ();// Function: 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.extern virtual function real unpack_real ();// Function: 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.extern virtual function void unpack_object (uvm_object value);// Function: get_packed_size//// Returns the number of bits that were packed.extern virtual function int get_packed_size();//------------------//// Group: Variables ////------------------//// Variable: 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: 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: use_metadata//// This flag indicates whether to encode metadata when packing dynamic data,// or to decode metadata when unpacking. Implementations of <uvm_object::do_pack>// and <uvm_object::do_unpack> should regard this bit when performing their// respective operation. When set, metadata should be encoded as follows://// - For strings, pack an additional ~null~ byte after the string is packed.//// - For objects, pack 4 bits prior to packing the object itself. Use 4'b0000// to indicate the object being packed is ~null~, otherwise pack 4'b0001 (the// remaining 3 bits are reserved).//// - For queues, dynamic arrays, and associative arrays, pack 32 bits// indicating the size of the array prior to packing individual elements.bit use_metadata;// Variable: 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//| endbit big_endian = 1;// variables and methods primarily for internal usestatic bit bitstream[]; // local bits for (un)pack_bytesstatic bit fabitstream[]; // field automation bits for (un)pack_bytesint count; // used to count the number of packed bitsuvm_scope_stack scope= new;bit reverse_order; //flip the bit order aroundbyte byte_size = 8; //set up bytesize for endianessint word_size = 16; //set up worksize for endianessbit nopack; //only count packable bitsuvm_recursion_policy_enum policy = UVM_DEFAULT_POLICY;uvm_pack_bitstream_t m_bits;int m_packed_size;extern virtual function void unpack_object_ext (inout uvm_object value);extern virtual function uvm_pack_bitstream_t get_packed_bits ();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();extern function void index_error(int index, string id, int sz);extern function bit enough_bits(int needed, string id);extern function void reset();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_packed_size+sz-1)/sz)-1), UVM_NONE);endfunction// enough_bits// -----------function bit uvm_packer::enough_bits(int needed, string id);if ((m_packed_size - count) < needed) beginuvm_report_error("PCKSZ",$sformatf("%0d bits needed to unpack %0s, yet only %0d available.",needed, id, (m_packed_size - count)), UVM_NONE);return 0;endreturn 1;endfunction// get_packed_size// ---------------function int uvm_packer::get_packed_size();return m_packed_size;endfunction// set_packed_size// ---------------function void uvm_packer::set_packed_size();m_packed_size = count;count = 0;endfunction// reset// -----function void uvm_packer::reset();count = 0;m_bits = 0;m_packed_size = 0;endfunction// get_packed_bits// ---------------function uvm_pack_bitstream_t uvm_packer::get_packed_bits();//bits = m_bits;return m_bits;endfunction// get_bits// --------function void uvm_packer::get_bits(ref bit unsigned bits[]);bits = new[m_packed_size];for (int i=0;i<m_packed_size;i++)bits[i] = m_bits[i];endfunction// get_bytes// ---------function void uvm_packer::get_bytes(ref byte unsigned bytes[]);int sz;byte v;sz = (m_packed_size+7) / 8;bytes = new[sz];for (int i=0;i<sz;i++) beginif (i != sz-1 || (m_packed_size % 8) == 0)v = m_bits[ i*8 +: 8 ];elsev = m_bits[ i*8 +: 8 ] & ('hFF >> (8-(m_packed_size%8)));if(big_endian) beginbyte tmp; tmp = v;for(int j=0; j<8; ++j) v[j] = tmp[7-j];endbytes[i] = v;endendfunction// get_ints// --------function void uvm_packer::get_ints(ref int unsigned ints[]);int sz, v;sz = (m_packed_size+31) / 32;ints = new[sz];for (int i=0;i<sz;i++) beginif (i != sz-1 || (m_packed_size % 32) == 0)v = m_bits[ i*32 +: 32 ];elsev = m_bits[ i*32 +: 32 ] & ('hFFFFFFFF >> (32-(m_packed_size%32)));if(big_endian) beginint tmp; tmp = v;for(int j=0; j<32; ++j) v[j] = tmp[31-j];endints[i] = v;endendfunction// put_bits// --------function void uvm_packer::put_bits (ref bit bitstream []);int bit_size;bit_size = bitstream.size();if(big_endian)for (int i=bit_size-1;i>=0;i--)m_bits[i] = bitstream[i];elsefor (int i=0;i<bit_size;i++)m_bits[i] = bitstream[i];m_packed_size = bit_size;count = 0;endfunction// put_bytes// ---------function void uvm_packer::put_bytes (ref byte unsigned bytestream []);int byte_size;int index;byte unsigned b;byte_size = bytestream.size();index = 0;for (int i=0;i<byte_size;i++) beginb = bytestream[i];if(big_endian) beginbyte unsigned tb; tb = b;for(int j=0;j<8;++j) b[j] = tb[7-j];endm_bits[index +:8] = b;index += 8;endm_packed_size = byte_size*8;count = 0;endfunction// put_ints// --------function void uvm_packer::put_ints (ref int unsigned intstream []);int int_size;int index;int unsigned v;int_size = intstream.size();index = 0;for (int i=0;i<int_size;i++) beginv = intstream[i];if(big_endian) beginint unsigned tv; tv = v;for(int j=0;j<32;++j) v[j] = tv[31-j];endm_bits[index +:32] = v;index += 32;endm_packed_size = int_size*32;count = 0;endfunction// get_bit// -------function bit unsigned uvm_packer::get_bit(int unsigned index);if (index >= m_packed_size)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_packed_size+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_packed_size+31)/32)index_error(index, "int",32);return m_bits[(index*32) +: 32];endfunction// PACK// pack_object// ---------function void uvm_packer::pack_object(uvm_object value);if(value.__m_uvm_status_container.cycle_check.exists(value)) beginuvm_report_warning("CYCFND", $sformatf("Cycle detected for object @%0d during pack", value.get_inst_id()), UVM_NONE);return;endvalue.__m_uvm_status_container.cycle_check[value] = 1;if((policy != UVM_REFERENCE) && (value != null) ) beginif(use_metadata == 1) beginm_bits[count +: 4] = 1;count += 4; // to better debug when display packed bits in hexadecimalendscope.down(value.get_name());value.__m_uvm_field_automation(null, UVM_PACK,"");value.do_pack(this);scope.up();endelse if(use_metadata == 1) beginm_bits[count +: 4] = 0;count += 4;endvalue.__m_uvm_status_container.cycle_check.delete(value);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[count +: 64] = value; this overwrites endian adjustmentsendfunction// pack_field// ----------function void uvm_packer::pack_field(uvm_bitstream_t value, int size);for (int i=0; i<size; i++)if(big_endian == 1)m_bits[count+i] = value[size-1-i];elsem_bits[count+i] = value[i];count += 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++)if(big_endian == 1)m_bits[count+i] = value[size-1-i];elsem_bits[count+i] = value[i];count += 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;endfor (int i=0; i<size; i++)if (big_endian == 1)m_bits[count+i] = value[size-1-i];elsem_bits[count+i] = value[i];count += 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;endelse beginint idx_select;for (int i=0; i<size; i++) beginif (big_endian == 1)idx_select = size-1-i;elseidx_select = i;m_bits[count+i] = value[idx_select / $bits(byte)][idx_select % $bits(byte)];endcount += size;endendfunction// 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;endelse beginint idx_select;for (int i=0; i<size; i++) beginif (big_endian == 1)idx_select = size-1-i;elseidx_select = i;m_bits[count+i] = value[idx_select / $bits(int)][idx_select % $bits(int)];endcount += size;endendfunction// pack_string// -----------function void uvm_packer::pack_string(string value);byte b;foreach (value[index]) beginif(big_endian == 0)m_bits[count +: 8] = value[index];else beginb = value[index];for(int i=0; i<8; ++i)m_bits[count+i] = b[7-i];endcount += 8;endif(use_metadata == 1) beginm_bits[count +: 8] = 0;count += 8;endendfunction// UNPACK// is_null// -------function bit uvm_packer::is_null();return (m_bits[count+:4]==0);endfunction// unpack_object// -------------function void uvm_packer::unpack_object_ext(inout uvm_object value);unpack_object(value);endfunctionfunction void uvm_packer::unpack_object(uvm_object value);byte is_non_null; is_non_null = 1;if(value.__m_uvm_status_container.cycle_check.exists(value)) beginuvm_report_warning("CYCFND", $sformatf("Cycle detected for object @%0d during unpack", value.get_inst_id()), UVM_NONE);return;endvalue.__m_uvm_status_container.cycle_check[value] = 1;if(use_metadata == 1) beginis_non_null = m_bits[count +: 4];count+=4;end// NOTE- policy is a ~pack~ policy, not unpack policy;// and you can't pack an object by REFERENCEif (value != null)beginif (is_non_null > 0) beginscope.down(value.get_name());value.__m_uvm_field_automation(null, UVM_UNPACK,"");value.do_unpack(this);scope.up();endelse begin// TODO: help do_unpack know whether unpacked result would be null// to avoid new'ing unnecessarily;// this does not nullify argument; need to pass obj by refendendelse if ((is_non_null != 0) && (value == null)) beginuvm_report_error("UNPOBJ","cannot unpack into null object", UVM_NONE);endvalue.__m_uvm_status_container.cycle_check.delete(value);endfunction// unpack_real// -----------function real uvm_packer::unpack_real();if (enough_bits(64,"real")) beginreturn $bitstoreal(unpack_field_int(64));endendfunction// unpack_time// -----------function time uvm_packer::unpack_time();if (enough_bits(64,"time")) beginreturn unpack_field_int(64);endendfunction// unpack_field// ------------function uvm_bitstream_t uvm_packer::unpack_field(int size);unpack_field = 'b0;if (enough_bits(size,"integral")) begincount += size;for (int i=0; i<size; i++)if(big_endian == 1)unpack_field[i] = m_bits[count-i-1];elseunpack_field[i] = m_bits[count-size+i];endendfunction// unpack_field_int// ----------------function uvm_integral_t uvm_packer::unpack_field_int(int size);unpack_field_int = 'b0;if (enough_bits(size,"integral")) begincount += size;for (int i=0; i<size; i++)if(big_endian == 1)unpack_field_int[i] = m_bits[count-i-1];elseunpack_field_int[i] = m_bits[count-size+i];endendfunction// 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;endif (enough_bits(size, "integral")) begincount += size;for (int i=0; i<size; i++)if (big_endian == 1)value[i] = m_bits[count-i-1];elsevalue[i] = m_bits[count-size+i];endendfunction// 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;endelse beginif (enough_bits(size, "integral")) begincount += size;for (int i=0; i<size; i++) beginif (big_endian == 1)value[ i / $bits(byte) ][ i % $bits(byte) ] = m_bits[count-i-1];elsevalue[ i / $bits(byte) ][ i % $bits(byte) ] = m_bits[count-size+i];endend // if (enough_bits(size, "integral"))endendfunction// 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;endelse beginif (enough_bits(size, "integral")) begincount += size;for (int i=0; i<size; i++) beginif (big_endian == 1)value[ i / $bits(int) ][ i % $bits(int) ] = m_bits[count-i-1];elsevalue[ i / $bits(int) ][ i % $bits(int) ] = m_bits[count-size+i];endendendendfunction// 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(int num_chars=-1);byte b;bit is_null_term; // Assumes a ~null~ terminated stringint i; i=0;if(num_chars == -1) is_null_term = 1;else is_null_term = 0;while(enough_bits(8,"string") &&((m_bits[count+:8] != 0) || (is_null_term == 0)) &&((i<num_chars)||(is_null_term==1)) )begin// silly, because cannot append byte/char to stringunpack_string = {unpack_string," "};if(big_endian == 0)unpack_string[i] = m_bits[count +: 8];else beginfor(int j=0; j<8; ++j)b[7-j] = m_bits[count+j];unpack_string[i] = b;endcount += 8;++i;endif(enough_bits(8,"string"))count += 8;endfunction
