-
Mitchel Humpherys authored
register.py is almost ready to handle doctest testing. Fix up one typo and add the necessary call in if __name__ == "__main__". Change-Id: I0a79060bb3bb58e807e7699ec0c21ef0eddb062d
87538b00
register.py 3.61 KiB
# Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 and
# only version 2 as published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
import bitops
class Register(object):
"""Represents a register (or any general field partitioning of
bits). Provides easy read and write access to the fields in the
register by taking care of all bit-shifting automatically. Fields
can be defined at __init__ time using kwargs or can be added
dynamically with `add_field'. Fields are accessible as instance
attributes.
For example:
>>> abc = Register(0x42, stuff=(2, 0))
>>> abc
value: 0x42 {stuff[2:0]=>0x2}
>>> hex(abc.value)
'0x42'
>>> hex(abc.stuff)
'0x2'
>>> abc.stuff = 1
>>> hex(abc.value)
'0x41'
>>> abc.add_field("other", (8, 4))
>>> hex(abc.other)
'0x4'
>>> abc.other = 0x3
>>> hex(abc.value)
'0x31'
You can also overlay fields on top of each other without problems:
>>> abc.add_field("another_other", (8, 0))
>>> abc.another_other = 0x5
>>> hex(abc.value)
'0x5'
We also handle `None' values:
>>> r = Register(None, h=(3,0))
>>> r
value: None
>>> r.h
>>> r.h = 3
>>> r
value: 0x3 {h[3:0]=>0x3}
"""
def __init__(self, value=0, **kwargs):
"""Register constructor.
kwargs should represent the fields in this object. Their
values should be 2-tuples of the form (msb, lsb).
"""
# All the object.__setattr__ stuff is to prevent us from going
# into our __setattr__ method here (which would try to access
# these again and would then recurse inifitely)
object.__setattr__(self, 'value', value)
object.__setattr__(self, '_regs', {})
for (k, v) in kwargs.iteritems():
self.add_field(k, v)
def add_field(self, field, bitrange):
"""Add field to Register.
bitrange should be the same format as the kwargs in __init__
(i.e. (msb, lsb)).
"""
self._regs[field] = bitrange
def __dir__(self):
return self.__dict__.keys() + self._regs.keys()
def __getattr__(self, name):
if name not in self._regs:
raise AttributeError
if self.value is None:
return None
msb, lsb = self._regs[name]
return bitops.bvalsel(msb, lsb, self.value)
def __setattr__(self, name, newvalue):
if name not in self._regs:
raise AttributeError
if self.value is None:
object.__setattr__(self, 'value', 0)
msb, lsb = self._regs[name]
val = self.value & (~bitops.bm(msb, lsb))
val |= newvalue << lsb
# can't access self.value directly since that would cause
# infinite recursion to __setattr__
object.__setattr__(self, 'value', val)
def __repr__(self):
if self.value is None:
return 'value: None'
ret = []
for r in sorted(self._regs, key=self._regs.get, reverse=True):
msb, lsb = self._regs[r]
val = bitops.bvalsel(msb, lsb, self.value)
ret.append('%s[%d:%d]=>0x%0x' % (r, msb, lsb, val))
return 'value: 0x%x {%s}' % (self.value, ', '.join(ret))
if __name__ == "__main__":
import doctest
doctest.testmod()