Source code for uvm.base.uvm_packer

#//
#//------------------------------------------------------------------------------
#//   Copyright 2007-2011 Mentor Graphics Corporation
#//   Copyright 2007-2011 Cadence Design Systems, Inc.
#//   Copyright 2010 Synopsys, Inc.
#//   Copyright 2013 NVIDIA Corporation
#//   Copyright 2019-2020 Tuomas Poikela (tpoikela)
#//   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.
#//------------------------------------------------------------------------------

from .uvm_object_globals import *
from .uvm_scope_stack import UVMScopeStack
from .sv import sv
from ..macros.uvm_message_defines import uvm_error, uvm_warning
from typing import List


SIZEOF_INT = 32
MASK_INT = 0xFFFFFFFF


[docs]class UVMPacker(object): """ The UVMPacker 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). """ bitstream = [] # local bits for (un)pack_bytes fabitstream = [] # field automation bits for (un)pack_bytes # //----------------// # // Group: Packing // # //----------------// def __init__(self): # //------------------// # // 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 # // `UVMObject.do_pack` and `UVMObject.do_unpack` methods, to test the # // setting of this field if you want to use it as a filter. # bit physical = 1 self.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 # // `UVMObject.do_pack` and `UVMObject.do_unpack` routines, to test the # // setting of this field if you want to use it as a filter. # bit abstract self.abstract = 0 # // Variable: use_metadata # // # // This flag indicates whether to encode metadata when packing dynamic data, # // or to decode metadata when unpacking. Implementations of `UVMObject.do_pack` # // and `UVMObject.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 self.use_metadata = 0 # // 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 (UVMPacker packer); # //| packer.pack_field_int(value, 16); # //| endfunction # //| # //| function void do_unpack (UVMPacker 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 = 1 self.big_endian = 1 # variables and methods primarily for internal use self.count = 0 # used to count the number of packed bits self.scope = UVMScopeStack() self.reverse_order = 0 # flip the bit order around self.byte_size = 8 # set up bytesize for endianess self.word_size = 16 # set up worksize for endianess self.nopack = 0 # only count packable bits self.policy = UVM_DEFAULT_POLICY self.m_bits = 0x0 # uvm_pack_bitstream_t self.m_packed_size = 0 # // 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 def pack_field(self,uvm_bitstream_t value, int size):
[docs] def pack_field(self, value, size) -> None: # for (int i=0; i<size; i++) if self.big_endian == 1: flipped = self.flip_bit_order(value, size) self.m_bits |= flipped << self.count # self.m_bits[count+i] = value[size-1-i] else: self.m_bits |= value << self.count self.count += 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.
[docs] def pack_field_int(self, value: int, size: int) -> None: if self.big_endian == 1: flipped = self.flip_bit_order(value, size) self.m_bits |= flipped << self.count #self.m_bits[self.count+i] = value[size-1-i] else: self.m_bits |= value << self.count #self.m_bits[self.count+i] = value[i] self.count += size
# // Function: pack_bits # // # // Packs bits from upacked array of bits into the pack array. # // # // See <pack_ints> for additional information. # extern def pack_bits(self,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 def pack_bytes(self,ref byte value[], input int size = -1):
[docs] def pack_bytes(self, value, size=-1) -> None: max_size = len(value) * 8 if size < 0: size = max_size if size > max_size: uvm_error("UVM/BASE/PACKER/BAD_SIZE", sv.sformatf("pack_bytes called with size '%0d', which exceeds value size of '%0d'", size, max_size)) return else: for i in range(len(value)): byte = value[i] if self.big_endian == 1: byte = self.flip_bit_order(value[len(value)-1-i], 8) self.m_bits |= byte << self.count self.count += 8
# // 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 def pack_ints(self,ref int value[], input int size = -1):
[docs] def pack_ints(self, value, size=-1) -> None: max_size = len(value) * SIZEOF_INT if size < 0: size = max_size if size > max_size: uvm_error("UVM/BASE/PACKER/BAD_SIZE", sv.sformatf("pack_ints called with size '%0d', which exceeds value size of '%0d'", size, max_size)) return else: for i in range(len(value)): int_num = value[i] if self.big_endian == 1: int_num = self.flip_bit_order(value[len(value)-1-i], SIZEOF_INT) self.m_bits |= int_num << self.count self.count += SIZEOF_INT
# // 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 def pack_string(self,string value):
[docs] def pack_string(self, value) -> None: bytearr = value.encode() size = 8 * len(bytearr) bits = int(bytearr.hex(), 16) if self.big_endian == 1: bits = self.flip_bit_order(bits, -1) self.m_bits |= bits << self.count self.count += size if self.use_metadata == 1: pass
# TODO self.m_bits |= 0 << self.count # byte b # foreach (value[index]): # if(self.big_endian == 0) # self.m_bits[count +: 8] = value[index] # else begin # b = value[index] # for(int i=0; i<8; ++i) # self.m_bits[count+i] = b[7-i] # end # count += 8 # end # if(use_metadata == 1): # self.m_bits[count +: 8] = 0 # count += 8 # end #endfunction # // Function: pack_time # // # // Packs a time ~value~ as 64 bits into the pack array. # # extern def pack_time(self,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 def pack_real(self,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 UVM. # # extern def pack_object(self,uvm_object value):
[docs] def pack_object(self, value) -> None: if value in value._m_uvm_status_container.cycle_check: uvm_warning("CYCFND", sv.sformatf("Cycle detected for object @%0d during pack", value.get_inst_id())) return value._m_uvm_status_container.cycle_check[value] = 1 if((self.policy != UVM_REFERENCE) and value is not None): if self.use_metadata == 1: pass #self.m_bits[count +: 4] = 1 #count += 4; // to better debug when display packed bits in hexadecimal self.scope.down(value.get_name()) value._m_uvm_field_automation(None, UVM_PACK,"") value.do_pack(self) self.scope.up() elif self.use_metadata == 1: pass #self.m_bits[count +: 4] = 0 #count += 4 del value._m_uvm_status_container.cycle_check[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 def is_null(self): # // 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 def unpack_field(self,int size):
[docs] def unpack_field(self, size): return self.unpack_field_int(size)
# unpack_field = 0b0 # if (self.enough_bits(size,"integral")): # count += size # for (int i=0; i<size; i++) # if(self.big_endian == 1) # unpack_field[i] = self.m_bits[count-i-1] # else # unpack_field[i] = self.m_bits[count-size+i] # end #endfunction # // 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 def unpack_field_int(self,int size):
[docs] def unpack_field_int(self, size) -> int: unpack_field_int = 0x0 count_before = self.count if self.enough_bits(size,"integral"): self.count += size for i in range(size): if self.big_endian: bit_sel = self.count-i-1 bit_sel = (1 << bit_sel) unpack_field_int |= self.m_bits & bit_sel else: bit_sel = self.count-size+i bit_sel = (1 << bit_sel) unpack_field_int |= self.m_bits & bit_sel unpack_field_int >>= count_before if self.big_endian: unpack_field_int = self.flip_bit_order(unpack_field_int, size) return unpack_field_int
# // Function: unpack_bits # // # // Unpacks bits from the pack array into an unpacked array of bits. # // # extern def unpack_bits(self,ref bit value[], input int size = -1): # # // Function: unpack_bytes # // # // Unpacks bits from the pack array into an unpacked array of bytes. # // # extern def unpack_bytes(self,ref byte value[], input int size = -1):
[docs] def unpack_bytes(self, value, size=-1): max_size = len(value) * 8 if size < 0: size = max_size if size > max_size: uvm_error("UVM/BASE/PACKER/BAD_SIZE", sv.sformatf("unpack_bytes called with size '%0d', which exceeds value size of '%0d'", size, len(value))) return [] else: if self.enough_bits(size, "integral"): self.count += size for b in range(len(value)): byte = (self.m_bits >> b * 8) & 0xFF if self.big_endian == 1: byte = self.flip_bit_order(byte, 8) value[len(value)-1-b] = byte else: value[b] = byte return value
# // 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 def unpack_ints(self,ref int value[], input int size = -1):
[docs] def unpack_ints(self, value, size=-1): max_size = len(value) * SIZEOF_INT if size < 0: size = max_size if size > max_size: uvm_error("UVM/BASE/PACKER/BAD_SIZE", sv.sformatf("unpack_ints called with size '%0d', which exceeds value size of '%0d'", size, len(value))) return else: if self.enough_bits(size, "integral"): self.count += size for i in range(len(value)): int_num = (self.m_bits >> i * SIZEOF_INT) & 0xFFFFFFFF if self.big_endian == 1: int_num = self.flip_bit_order(int_num, SIZEOF_INT) value[len(value)-1-i] = int_num else: value[i] = int_num return value
# // 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. #// If num_chars is not -1, then the user only wants to unpack a #// specific number of bytes into the string.
[docs] def unpack_string(self, num_chars=-1): # byte b i = 0 is_null_term = 0 # Assumes a ~None~ terminated string # int i; i=0 if num_chars == -1: is_null_term = 1 #val_to_decode = 0x0 # We'll use bytearray to decode this, so need to find the num of bytes byte_arr = bytearray() #unpack_string = 0 curr_byte = (self.m_bits >> self.count) & 0xFF while (self.enough_bits(8,"string", is_error=False) and ((curr_byte != 0) or (is_null_term == 0)) and ((i < num_chars) or (is_null_term == 1))): # silly, because cannot append byte/char to string #unpack_string = unpack_string + " " #if self.big_endian == 0: # unpack_string[i] = self.m_bits[count +: 8] #else: # for(int j=0; j<8; ++j) # b[7-j] = self.m_bits[count+j] # unpack_string[i] = b i += 1 byte_arr.insert(0, curr_byte) self.count += 8 curr_byte = (self.m_bits >> self.count) & 0xFF if self.enough_bits(8,"string", is_error=False): self.count += 8 return byte_arr.decode()
#return unpack_string # // Function: unpack_time # // # // Unpacks the next 64 bits of the pack array and places them into a # // time variable. # # extern def unpack_time(self):; # // 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 def unpack_real(self): # // 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 def unpack_object(self,uvm_object value):
[docs] def unpack_object(self, value): is_non_null = 1 if value in value._m_uvm_status_container.cycle_check: uvm_warning("CYCFND", sv.sformatf( "Cycle detected for object @%0d during unpack", value.get_inst_id())) return value._m_uvm_status_container.cycle_check[value] = 1 if self.use_metadata == 1: is_non_null = get_bits(self.m_bits, self.count, 4) != 0 # [count +: 4] self.count += 4 # NOTE- policy is a ~pack~ policy, not unpack policy; # and you can't pack an object by REFERENCE if value is not None: if is_non_null > 0: self.scope.down(value.get_name()) value._m_uvm_field_automation(None, UVM_UNPACK,"") value.do_unpack(self) self.scope.up() else: pass # 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 ref elif ((is_non_null != 0) and (value is None)): uvm_error("UNPOBJ","cannot unpack into None object") del value._m_uvm_status_container.cycle_check[value]
# // Function: get_packed_size # // # // Returns the number of bits that were packed.
[docs] def get_packed_size(self) -> int: return self.m_packed_size
# extern def unpack_object_ext(self,inout uvm_object value): # extern def get_packed_bits(self):
[docs] def get_packed_bits(self) -> int: return self.m_bits
# extern def bit unsigned get_bit (self,int unsigned index):
[docs] def get_bit(self, index) -> int: if index >= self.m_packed_size: self.index_error(index, "bit",1) return (self.m_bits >> index) & 0x1
# extern def byte unsigned get_byte (self,int unsigned index): # extern def int unsigned get_int (self,int unsigned index): # extern def get_bits(self,ref bit unsigned bits[]):
[docs] def get_bits(self) -> int: return self.m_bits
# extern def get_bytes(self,ref byte unsigned bytes[]):
[docs] def get_bytes(self) -> List[int]: sz = 0 v = 0x00 sz = int((self.m_packed_size+7) / 8) bytes = [0] * sz for i in range(sz): if (i != sz-1 or (self.m_packed_size % 8) == 0): v = (self.m_bits >> (i * 8)) & 0xFF else: sel = (0xFF >> (8-(self.m_packed_size % 8))) v = (self.m_bits >> (i * 8)) & sel if self.big_endian: v = self.flip_bit_order(v, 8) bytes[i] = v return bytes
# extern def get_ints(self):
[docs] def get_ints(self) -> List[int]: sz = 0 v = 0 sz = int((self.m_packed_size+31) / SIZEOF_INT) ints = [0] * sz for i in range(sz): if i != sz-1 or (self.m_packed_size % 32) == 0: v = (self.m_bits >> (i * SIZEOF_INT)) & 0xFFFFFFFF else: sel = (0xFFFFFFFF >> (32-(self.m_packed_size % 32))) v = (self.m_bits >> (i * SIZEOF_INT)) & sel if self.big_endian: v = self.flip_bit_order(v, SIZEOF_INT) ints[i] = v return ints
# extern def put_bits(self,ref bit unsigned bitstream[]):
[docs] def put_bits(self, bitstream): # int bit_size # bit_size = bitstream.size() # # if(self.big_endian) # for (int i=bit_size-1;i>=0;i--) # self.m_bits[i] = bitstream[i] # else # for (int i=0;i<bit_size;i++) # self.m_bits[i] = bitstream[i] # self.m_bits = bitstream self.m_packed_size = len(bin(self.m_bits)) - 2 self.count = 0
# extern def put_bytes(self,ref byte unsigned bytestream[]): # extern def put_ints(self,ref int unsigned intstream[]):
[docs] def set_packed_size(self): self.m_packed_size = self.count self.count = 0
# extern def index_error(self,int index, string id, int sz):
[docs] def index_error(self, index, id, sz): uvm_error("PCKIDX", sv.sformatf("index %0d for get_%0s too large; valid index range is 0-%0d.", index,id,((self.m_packed_size+sz-1)/sz)-1))
# extern def enough_bits(self,int needed, string id):
[docs] def enough_bits(self, needed, id, is_error=True): if ((self.m_packed_size - self.count) < needed): if is_error is True: uvm_error("PCKSZ", sv.sformatf("%0d bits needed to unpack %0s, yet only %0d available.", needed, id, (self.m_packed_size - self.count))) return 0 return 1
[docs] def reset(self): self.count = 0 self.m_bits = 0 self.m_packed_size = 0
[docs] def flip_bit_order(self, value, size: int) -> int: flipped = 0x0 num_bits = len(bin(value)) - 2 while value: flipped = (flipped << 1) + (value & 0x1) # Choose LSB value = value >> 1 # For packing, need to add some right-padding if size != -1: rem_bits = size - num_bits if rem_bits >= 0: flipped <<= rem_bits else: raise Exception("rem_bits negative. size: {}, value: {}".format( size, hex(value))) return flipped
#//------------------------------------------------------------------------------ #// IMPLEMENTATION #//------------------------------------------------------------------------------ # #// NOTE- max size limited to BITSTREAM bits parameter (default: 4096) # # #// put_bytes #// --------- # #def void UVMPacker::put_bytes (self,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++): # b = bytestream[i] # if(self.big_endian): # byte unsigned tb; tb = b # for(int j=0;j<8;++j) b[j] = tb[7-j] # end # self.m_bits[index +:8] = b # index += 8 # end # # m_packed_size = byte_size*8 # count = 0 #endfunction # # #// put_ints #// -------- # #def void UVMPacker::put_ints (self,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++): # v = intstream[i] # if(self.big_endian): # v = self.flip_bit_order(v) # self.m_bits[index +:32] = v # index += 32 # end # # m_packed_size = int_size*32 # count = 0 #endfunction # # # # # # #// get_byte #// -------- # #def byte unsigned UVMPacker::get_byte(self,int unsigned index): # if (index >= (m_packed_size+7)/8) # index_error(index, "byte",8) # return self.m_bits[index*8 +: 8] #endfunction # # #// get_int #// ------- # #def int unsigned UVMPacker::get_int(self,int unsigned index): # if (index >= (m_packed_size+31)/32) # index_error(index, "int",32) # return self.m_bits[(index*32) +: 32] #endfunction # # #// PACK # # # # #// pack_real #// --------- # #def void UVMPacker::pack_real(self,real value): # pack_field_int($realtobits(value), 64) #endfunction # # #// pack_time #// --------- # #def void UVMPacker::pack_time(self,time value): # pack_field_int(value, 64) # //m_bits[count +: 64] = value; this overwrites endian adjustments #endfunction # # # # # #// pack_bits #// ----------------- # #def void UVMPacker::pack_bits(self,ref bit value[], input int size = -1): # if (size < 0) # size = len(value) # # if (size > len(value)): # uvm_error("UVM/BASE/PACKER/BAD_SIZE", # sv.sformatf("pack_bits called with size '%0d', which exceeds len(value) of '%0d'", # size, # len(value))) # return # end # # for (int i=0; i<size; i++) # if (self.big_endian == 1) # self.m_bits[count+i] = value[size-1-i] # else # self.m_bits[count+i] = value[i] # count += size #endfunction # # # # # # #// UNPACK # # #// is_null #// ------- # #def bit UVMPacker::is_null(self): # return (m_bits[count+:4]==0) #endfunction # #// unpack_object #// ------------- # #def void UVMPacker::unpack_object_ext(self,inout uvm_object value): # unpack_object(value) #endfunction # # # #// unpack_real #// ----------- # #def real UVMPacker::unpack_real(self): # if (self.enough_bits(64,"real")): # return $bitstoreal(unpack_field_int(64)) # end #endfunction # # #// unpack_time #// ----------- # #def time UVMPacker::unpack_time(self): # if (self.enough_bits(64,"time")): # return unpack_field_int(64) # end #endfunction # # # # # #// unpack_bits #// ------------------- # #def void UVMPacker::unpack_bits(self,ref bit value[], input int size = -1): # if (size < 0) # size = len(value) # # if (size > len(value)): # uvm_error("UVM/BASE/PACKER/BAD_SIZE", # sv.sformatf("unpack_bits called with size '%0d', which exceeds len(value) of '%0d'", # size, # len(value))) # return # end # # if (self.enough_bits(size, "integral")): # count += size # for (int i=0; i<size; i++) # if (self.big_endian == 1) # value[i] = self.m_bits[count-i-1] # else # value[i] = self.m_bits[count-size+i] # end #endfunction # #
[docs]def get_bits(bits, count, nbits): # [count +: 4] val = 0x0 idx = 0 for i in range(count, count + nbits + 1): val |= (1 << (nbits - idx)) & (bits >> (i-idx)) idx += 1 return val