import logging
LOGGER = logging.getLogger(__name__)
[docs]def clean_fields(parent_name, parent_type, field_str):
"""
Take the Simulink string for a field and return a list
:param parent_name: the BitField that will run this
:param parent_type: register, snapshot, etc
:param field_str: the string to be parsed
"""
_fstr = field_str.replace('[', '').replace(']', '')
_fstr = _fstr.strip().replace(', ', ',')
while _fstr.find(' ') > -1:
_fstr = _fstr.replace(' ', ' ')
if (_fstr.find(' ') > -1) and (_fstr.find(',') > -1):
LOGGER.error('Parameter string %s contains spaces and commas '
'as delimiters. This is confusing.' % field_str)
_fstr = _fstr.replace(',', ' ')
if _fstr.find(' ') > -1:
_flist = _fstr.split(' ')
else:
_flist = _fstr.split(',')
_rv = []
for _fname in _flist:
if _fname.strip() == '':
LOGGER.debug('Throwing away empty field in %s %s' % (
parent_type, parent_name))
else:
_rv.append(_fname)
return _rv
[docs]class Bitfield(object):
"""
Describes a chunk of memory that consists of a number of Fields.
"""
[docs] def __init__(self, name, width_bits, fields=None):
"""
:param name: name of the device
:type name: str
:param width_bits: Bit-width of the Bitfield
:type width_bits: int
:param fields: number of fields - default to None
:type fields: int
"""
self.name = name
self.width_bits = width_bits
self._fields = {}
if fields is not None:
self.fields_add(fields)
LOGGER.debug('New Bitfield(%s) with %i fields' % (self.name,
len(self._fields)))
# def __dir__(self):
# return self._fields.keys()
[docs] def fields_clear(self):
"""
Reset the fields in this bitstruct.
"""
self._fields = {}
[docs] def fields_add(self, fields):
"""
Add a dictionary of Fields to this bitfield.
"""
if not isinstance(fields, dict):
raise TypeError('fields should be a dictionary of Field objects.')
if len(fields) == 0:
raise ValueError('Empty dictionary is not so useful?')
for newfield in fields.itervalues():
self.field_add(newfield)
[docs] def field_add(self, newfield, auto_offset=False):
"""
Add a Field to this bitfield.
"""
if not isinstance(newfield, Field):
raise TypeError('Expecting Field object.')
# add it at the end of the current fields
if auto_offset:
width = 0
for field in self._fields.itervalues():
width += field.width_bits
newfield.offset = width
self._fields[newfield.name] = newfield
[docs] def field_names(self):
return self._fields.keys()
[docs] def field_get_by_name(self, field_name):
"""
Get a field from this bitfield by its name.
:param field_name: name of field to search for
:type field_name: str
"""
try:
return self._fields[field_name]
except KeyError:
return None
[docs] def fields_string_get(self):
"""
Get a string of all the field names.
"""
field_string = ''
for field in self._fields.itervalues():
field_string += '%s, ' % field
field_string = field_string[0:-2]
return field_string
def __str__(self):
"""
Return a string representation of this object.
"""
rv = self.name + '(' + str(self.width_bits) + ',['
rv = rv + self.fields_string_get() + '])'
return rv
[docs]class Field(object):
"""
A Field object is a number of bits somewhere in a Bitfield object.
"""
[docs] def __init__(self, name, numtype, width_bits, binary_pt, lsb_offset):
"""
Initialise a Field object.
:param name: The name of the field
:param numtype: A numerical description of the type:
* 0 is unsigned
* 1 is signed 2's comp
* 2 is boolean
:param width_bits: The width of the field, in bits
:param binary_pt: The binary point position, in bits
:param lsb_offset: The offset in the memory field, in bits:
* 1 means it hasn't been set yet.
"""
if not isinstance(numtype, int):
raise TypeError('Type must be an integer.')
assert name.strip() != '', 'Cannot have a Field with empty name?!'
self.name = name
self.numtype = numtype
self.width_bits = width_bits
self.binary_pt = binary_pt
self.offset = lsb_offset
def __str__(self):
return '{}({}, {}, {}, {})'.format(self.name, self.offset, self.width_bits,
self.binary_pt, self.numtype)
def __repr__(self):
return str(self)
# end