Re: [myhdl-list] intbv wrap
Brought to you by:
jandecaluwe
From: Ben <ben...@gm...> - 2011-05-05 14:22:28
|
Hi Christopher, I took the liberty to review and edit your patch. As you can see, I added some tests, and removed the inclusion of the val property. It became quite smaller ! I left your name in it as the idea and the logic is from you. I also moved the check from the wrap function to the constructor (no need to check every time.). Here is a text version, enclosed a bundle. All tests pass fine. # HG changeset patch # User cfelton # Date 1303212809 18000 # Node ID 145d558e234f363c3e43e9a79ab48ad7e20d7b9b # Parent f77cf2c4a5894013ceb2f5c184d84136ea4f04a3 Add a wrap parameter to intbv. When set, no overflow will occur. diff -r f77cf2c4a589 -r 145d558e234f myhdl/_intbv.py --- a/myhdl/_intbv.py Wed May 04 21:33:14 2011 +0200 +++ b/myhdl/_intbv.py Tue Apr 19 06:33:29 2011 -0500 @@ -31,37 +31,46 @@ from __builtin__ import max as maxfunc class intbv(object): - __slots__ = ('_val', '_min', '_max', '_nrbits') + __slots__ = ('_min', '_max', '_nrbits', '_wrap', '__val') - def __init__(self, val=0, min=None, max=None, _nrbits=0): + def __init__(self, val=0, min=None, max=None, wrap=False, _nrbits=0): if _nrbits: self._min = 0 self._max = 2**_nrbits + self._nrbits = _nrbits else: self._min = min self._max = max if max is not None and min is not None: if min >= 0: - _nrbits = len(bin(max-1)) + self._nrbits = len(bin(max-1)) elif max <= 1: - _nrbits = len(bin(min)) + self._nrbits = len(bin(min)) else: # make sure there is a leading zero bit in positive numbers - _nrbits = maxfunc(len(bin(max-1))+1, len(bin(min))) + self._nrbits = maxfunc(len(bin(max-1))+1, len(bin(min))) + else: + self._nrbits = 0 + + if wrap: + myrange = self._nrbits**2 + if (abs(self.min) != self.max) or ((abs(self.min) + self.max) != myrange): + raise ValueError, "Cannot use wrapping if -min != max (%d != %d)" % (-self.min, self.max) + self._wrap = wrap if isinstance(val, (int, long)): self._val = val elif isinstance(val, StringType): mval = val.replace('_', '') + self._nrbits = len(mval) self._val = long(mval, 2) - _nrbits = len(val) elif isinstance(val, intbv): self._val = val._val self._min = val._min self._max = val._max - _nrbits = val._nrbits + self._wrap = val._wrap + self._nrbits = val._nrbits else: raise TypeError("intbv constructor arg should be int or string") - self._nrbits = _nrbits self._checkBounds() # support for the 'min' and 'max' attribute @@ -82,6 +91,20 @@ raise ValueError("intbv value %s < minimum %s" % (self._val, self._min)) + # val property + def _get_val(self): + return self.__val + + def _set_val(self, pval): + + if self._wrap: + self.__val = self.wrap(pval) + else: + self.__val = pval + + self._checkBounds() + + _val = property(_get_val, _set_val) # hash def __hash__(self): @@ -433,6 +456,21 @@ return "intbv(" + repr(self._val) + ")" + def wrap(self, val): + """ Wrap the value back to the range of the inbv + + The following will check that the defined min-max is the full + range of the binary word. If the full range is specified if + the value is outside the bounds of the range it will be adjusted + to the proper value in bounds. + """ + myrange = 2**self._nrbits + + rval = self.min + ((val +self.max) % myrange) + + return rval + + def signed(self): ''' return integer with the signed value of the intbv instance diff -r f77cf2c4a589 -r 145d558e234f myhdl/test/core/test_intbv.py --- a/myhdl/test/core/test_intbv.py Wed May 04 21:33:14 2011 +0200 +++ b/myhdl/test/core/test_intbv.py Tue Apr 19 06:33:29 2011 -0500 @@ -576,8 +576,50 @@ self.assertEqual(n.max, m.max) self.assertEqual(len(n), len(m)) +class TestIntbvWrap(TestCase): + + def testWrap(self): + x = intbv(0, min=-8, max=8, wrap=True) + x[:] = x + 1 + self.assertEqual(1, x) + x[:] = x + 2 + self.assertEqual(3, x) + x[:] = x + 5 + self.assertEqual(-8, x) + x[:] = x + 1 + self.assertEqual(-7, x) + x[:] = x - 5 + self.assertEqual(4, x) + x[:] = x - 4 + self.assertEqual(0, x) + x[:] += 15 + x[:] = x - 1 + self.assertEqual(-2, x) + + def testInit(self): + self.assertRaises(ValueError, intbv, 15, min=-8, max=8) + x = intbv(15, min=-8, max=8, wrap=True) + self.assertEqual(-1, x) + + self.assertRaises(ValueError, intbv, 5, min=-3, max=8, wrap=True) + intbv(5, min=-3, max=8) + def testNoWrap(self): + x = intbv(0, min=-8, max=8, wrap=False) + try: + x[:] += 15 + self.fail() + except ValueError: + pass + + x = intbv(0, min=-8, max=8) + try: + x[:] += 15 + self.fail() + except ValueError: + pass + if __name__ == "__main__": unittest.main() |