Source code for corsair.reg

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""Control and status register
"""

from . import utils
from . import config


[docs]class Register(): """Control and status register. :param name: Bit field name :type name: str :param description: Bit field description :type description: str :param address: Register address :type address: int, None """ def __init__(self, name='csr0', description='Control and status register 0', address=None, **args): self._bitfields = [] self.name = name self.description = description self.address = address self.etc = args def __eq__(self, other): if self.__class__ != other.__class__: raise TypeError("Failed to compare '%s' with '%s'!" % (repr(self), repr(other))) else: return self.as_dict() == other.as_dict() def __ne__(self, other): if self.__class__ != other.__class__: raise TypeError("Failed to compare '%s' with '%s'!" % (repr(self), repr(other))) else: return not self.__eq__(other) def __repr__(self): return 'Register(%s, %s, %s)' % (repr(self.name), repr(self.description), repr(self.address)) def __str__(self): return self.as_str()
[docs] def as_str(self, indent=''): """Create an indented string with the information about the register.""" inner_indent = indent + ' ' bitfields = [bf.as_str(inner_indent) for bf in self.bitfields] bitfields_str = '\n'.join(bitfields) if bitfields else inner_indent + 'empty' reg_str = indent + '(0x%x) %s: %s\n' % (self.address, self.name, self.description) reg_str += bitfields_str return reg_str
[docs] def as_dict(self): """Create a dictionary with the key attributes of the register.""" d = { 'name': self.name, 'description': self.description, 'address': self.address, 'bitfields': [bf.as_dict() for bf in self.bitfields] } d.update(self.etc) return d
def __len__(self): """Calculate number of bit fields inside register""" return len(self._bitfields) def __iter__(self): """Create iterator over bit fields """ return iter(self._bitfields) def __getitem__(self, key): """Get bit field by name or index""" try: if utils.is_str(key): key = utils.force_name_case(key) return next(bf for bf in self if bf.name == key) else: return self._bitfields[key] except (StopIteration, TypeError, KeyError, IndexError): raise KeyError("There is no bit field with the name/index '%s' in the '%s' register!" % (key, self.name)) def __setitem__(self, key, value): """Set bit field by key""" raise KeyError("Not able to set '%s' bit field directly in the '%s' register!" " Try to use add_bitfields() method." % (key, self.name)) @property def name(self): """Name of the register.""" return utils.force_name_case(self._name) @name.setter def name(self, value): if not utils.is_str(value): raise ValueError("'name' attribute has to be 'str', but '%s' provided for the register!" % type(value)) self._name = value @property def address(self): """Address of the register.""" return self._address @address.setter def address(self, value): self._address = utils.str2int(value) @property def description(self): """Description of the register.""" return self._description @description.setter def description(self, value): if not utils.is_str(value): raise ValueError("'description' attribute has to be 'str', but '%s' provided for '%s' register!" % (type(value), self.name)) self._description = value @property def bitfield_names(self): """List with all bit field names.""" return [bf.name for bf in self] @property def bitfields(self): """List with bit field objects.""" return self._bitfields
[docs] def add_bitfields(self, new_bitfields): """Add bit field or list of bit feilds. Bit fields are automatically sorted and stored in the ascending order of msb attributes. """ # hack to handle single elements new_bitfields = utils.listify(new_bitfields) # add bit fields to list one by one for bf in new_bitfields: # check existance assert bf.name not in self.bitfield_names, \ "Bit field with name '%s' is already present in '%s' register!" % (bf.name, self.name) # check fields overlapping overlaps = [set(bf.bits).intersection(set(old_bf.bits)) for old_bf in self._bitfields] overlaps_names = [self.bitfield_names[i] for i, ovl in enumerate(overlaps) if ovl] assert not (self.bitfields and overlaps_names), \ "Position of a bit field '%s' conflicts with other bit field(s): %s!" % (bf.name, repr(overlaps_names)) # check bit field conflicts with data width data_width = config.globcfg['data_width'] assert bf.msb < data_width, \ "Field '%s' (msb=%d) exceeds interface data width %d!" % \ (bf.name, bf.msb, data_width) # if we are here - all is ok and bit field can be added try: # find position to insert bit field and not to break ascending order of bit field msb positions bf_idx = next(i for i, old_bf in enumerate(self._bitfields) if old_bf.msb > bf.msb) self._bitfields.insert(bf_idx, bf) except StopIteration: # when bit field list is empty or all bit field msb positions are less than the current one self._bitfields.append(bf) return self
@property def reset(self): """Reset value of the refister after reset.""" init = 0 for bf in self: init |= bf.reset << bf.lsb return init @property def access(self): """Register access mode, based on bitfields.""" accesses = list(set([bf.access for bf in self.bitfields])) if len(accesses) == 1: return accesses[0][:2] else: return 'rw'
[docs] def validate(self): """Validate parameters of the register.""" # name assert self.name, "Empty register name is not allowed!" assert utils.is_first_letter(self.name), \ "'name' value '%s' for the register is wrong! Must start from a letter." % (self.name) # address assert utils.is_non_neg_int(self.address), \ "Address value '%s' for '%s' is wrong! Only non-negative integers are allowed." % (self.address, self.name) # bit fields overlapping for bf in self._bitfields: overlaps = [set(bf.bits).intersection(set(bf_.bits)) for bf_ in self._bitfields] overlaps_names = [self.bitfield_names[i] for i, ovl in enumerate(overlaps) if ovl] overlaps_names.pop(overlaps_names.index(bf.name)) assert not overlaps_names, \ "Position and size of a bit field '%s' conflicts with other bit field(s): %s!" % \ (bf.name, repr(overlaps_names)) # bit fields vs data_width data_width = config.globcfg['data_width'] for bf in self._bitfields: assert bf.msb < data_width, \ "Field '%s' (msb=%d) exceeds interface data width %d!" % \ (bf.name, bf.msb, data_width) # bit fields for bf in self.bitfields: assert self.bitfield_names.count(bf.name) == 1, \ "Bitfield '%s' name is not unique!" % (bf.name) bf.validate()