From 86ec7e81c9395c1c94b4b856ad1e588abd19669a Mon Sep 17 00:00:00 2001 From: Jan Decaluwe Date: Fri, 4 Mar 2016 17:42:50 +0100 Subject: [PATCH] Use to_string to support long vectors; with various implications... --- myhdl/_intbv.py | 164 ++++++++++-------- myhdl/conversion/_analyze.py | 9 +- myhdl/conversion/_toVHDL.py | 12 +- myhdl/conversion/_toVerilog.py | 6 +- .../conversion/general/test_intbv_signed.py | 100 +++++------ myhdl/test/conversion/general/test_print.py | 61 +++++-- myhdl/test/conversion/toVHDL/test_ops.py | 8 + myhdl/test/conversion/toVHDL/test_signed.py | 3 + 8 files changed, 224 insertions(+), 139 deletions(-) diff --git a/myhdl/_intbv.py b/myhdl/_intbv.py index accb7f12..0c6b777c 100644 --- a/myhdl/_intbv.py +++ b/myhdl/_intbv.py @@ -29,7 +29,7 @@ from myhdl._bin import bin class intbv(object): #__slots__ = ('_val', '_min', '_max', '_nrbits', '_handleBounds') - + def __init__(self, val=0, min=None, max=None, _nrbits=0): if _nrbits: self._min = 0 @@ -60,7 +60,7 @@ class intbv(object): raise TypeError("intbv constructor arg should be int or string") self._nrbits = _nrbits self._handleBounds() - + # support for the 'min' and 'max' attribute @property def max(self): @@ -79,7 +79,7 @@ class intbv(object): if self._val < self._min: raise ValueError("intbv value %s < minimum %s" % (self._val, self._min)) - + def _hasFullRange(self): min, max = self._min, self._max if max <= 0: @@ -92,7 +92,7 @@ class intbv(object): # hash def __hash__(self): raise TypeError("intbv objects are unhashable") - + # copy methods def __copy__(self): c = type(self)(self._val) @@ -149,7 +149,7 @@ class intbv(object): return res - + def __setitem__(self, key, val): # convert val to int to avoid confusion with intbv or Signals val = int(val) @@ -187,13 +187,13 @@ class intbv(object): else: raise ValueError("intbv[i] = v requires v in (0, 1)\n" \ " i == %s " % i) - + self._handleBounds() - + # integer-like methods - + def __add__(self, other): if isinstance(other, intbv): return self._val + other._val @@ -201,7 +201,7 @@ class intbv(object): return self._val + other def __radd__(self, other): return other + self._val - + def __sub__(self, other): if isinstance(other, intbv): return self._val - other._val @@ -225,7 +225,7 @@ class intbv(object): return self._val / other def __rtruediv__(self, other): return other / self._val - + def __floordiv__(self, other): if isinstance(other, intbv): return self._val // other._val @@ -233,7 +233,7 @@ class intbv(object): return self._val // other def __rfloordiv__(self, other): return other // self._val - + def __mod__(self, other): if isinstance(other, intbv): return self._val % other._val @@ -243,7 +243,7 @@ class intbv(object): return other % self._val # divmod - + def __pow__(self, other): if isinstance(other, intbv): return self._val ** other._val @@ -259,7 +259,7 @@ class intbv(object): return intbv(long(self._val) << other) def __rlshift__(self, other): return other << self._val - + def __rshift__(self, other): if isinstance(other, intbv): return intbv(self._val >> other._val) @@ -267,7 +267,7 @@ class intbv(object): return intbv(self._val >> other) def __rrshift__(self, other): return other >> self._val - + def __and__(self, other): if isinstance(other, intbv): return intbv(self._val & other._val) @@ -283,7 +283,7 @@ class intbv(object): return intbv(self._val | other) def __ror__(self, other): return intbv(other | self._val) - + def __xor__(self, other): if isinstance(other, intbv): return intbv(self._val ^ other._val) @@ -299,7 +299,7 @@ class intbv(object): self._val += other self._handleBounds() return self - + def __isub__(self, other): if isinstance(other, intbv): self._val -= other._val @@ -307,7 +307,7 @@ class intbv(object): self._val -= other self._handleBounds() return self - + def __imul__(self, other): if isinstance(other, intbv): self._val *= other._val @@ -315,7 +315,7 @@ class intbv(object): self._val *= other self._handleBounds() return self - + def __ifloordiv__(self, other): if isinstance(other, intbv): self._val //= other._val @@ -328,7 +328,7 @@ class intbv(object): raise TypeError("intbv: Augmented classic division not supported") def __itruediv__(self, other): raise TypeError("intbv: Augmented true division not supported") - + def __imod__(self, other): if isinstance(other, intbv): self._val %= other._val @@ -336,10 +336,10 @@ class intbv(object): self._val %= other self._handleBounds() return self - + def __ipow__(self, other, modulo=None): # XXX why 3rd param required? - # unused but needed in 2.2, not in 2.3 + # unused but needed in 2.2, not in 2.3 if isinstance(other, intbv): self._val **= other._val else: @@ -348,7 +348,7 @@ class intbv(object): raise ValueError("intbv value should be integer") self._handleBounds() return self - + def __iand__(self, other): if isinstance(other, intbv): self._val &= other._val @@ -404,10 +404,10 @@ class intbv(object): return intbv(~self._val & (long(1) << self._nrbits)-1) else: return intbv(~self._val) - + def __int__(self): return int(self._val) - + def __long__(self): return long(self._val) @@ -415,16 +415,16 @@ class intbv(object): return float(self._val) # XXX __complex__ seems redundant ??? (complex() works as such?) - + def __oct__(self): return oct(self._val) - + def __hex__(self): return hex(self._val) def __index__(self): return int(self._val) - + # comparisons def __eq__(self, other): if isinstance(other, intbv): @@ -457,67 +457,83 @@ class intbv(object): else: return self._val >= other - # representation + # representation def __str__(self): - return str(self._val) + # represent in hex format, to handle VHDL long vectors + v = int(self._val) + nrbits = self._nrbits + if nrbits: + # represent negative values without minus sign + # I would prefer sign extension with hex format, but to + # align with Verilog $display I don't do that + if v < 0: + v = 2**nrbits + v + w = (nrbits-1) // 4 + 1 + return "{:0{w}x}".format(v, w=w) + else: + return "{:x}".format(v) def __repr__(self): return "intbv(" + repr(self._val) + ")" def signed(self): - ''' return integer with the signed value of the intbv instance + ''' Return new intbv with the values interpreted as signed - The intbv.signed() function will classify the value of the intbv - instance either as signed or unsigned. If the value is classified - as signed it will be returned unchanged as integer value. If the - value is considered unsigned, the bits as specified by _nrbits - will be considered as 2's complement number and returned. This - feature will allow to create slices and have the sliced bits be - considered a 2's complement number. + The intbv.signed() function will classify the value of the intbv + instance either as signed or unsigned. If the value is classified + as signed it will be returned unchanged as integer value. If the + value is considered unsigned, the bits as specified by _nrbits + will be considered as 2's complement number and returned. This + feature will allow to create slices and have the sliced bits be + considered a 2's complement number. + + The classification is based on the following possible combinations + of the min and max value. - The classification is based on the following possible combinations - of the min and max value. - ----+----+----+----+----+----+----+---- -3 -2 -1 0 1 2 3 - 1 min max - 2 min max - 3 min max - 4 min max - 5 min max - 6 min max - 7 min max - 8 neither min nor max is set - 9 only max is set - 10 only min is set + 1 min max + 2 min max + 3 min max + 4 min max + 5 min max + 6 min max + 7 min max + 8 neither min nor max is set + 9 only max is set + 10 only min is set - From the above cases, # 1 and 2 are considered unsigned and the - signed() function will convert the value to a signed number. - Decision about the sign will be done based on the msb. The msb is - based on the _nrbits value. - - So the test will be if min >= 0 and _nrbits > 0. Then the instance - is considered unsigned and the value is returned as 2's complement - number. - ''' + From the above cases, # 1 and 2 are considered unsigned and the + signed() function will convert the value to a signed number. + Decision about the sign will be done based on the msb. The msb is + based on the _nrbits value. - # value is considered unsigned - if self.min is not None and self.min >= 0 and self._nrbits > 0: + So the test will be if min >= 0 and _nrbits > 0. Then the instance + is considered unsigned and the value is returned as 2's complement + number. + ''' - # get 2's complement value of bits - msb = self._nrbits-1 + # value is considered unsigned + if self.min is not None and self.min >= 0 and self._nrbits: - sign = ((self._val >> msb) & 0x1) > 0 - - # mask off the bits msb-1:lsb, they are always positive - mask = (1<> msb) & 0x1) > 0 - return retVal + # mask off the bits msb-1:lsb, they are always positive + mask = (1< 0 # Expect to return -4 a10 = intbv(4, min=1, max=5) - b = a10.signed() - assert b == -4 + b10 = a10.signed() + assert b10 == -4 a11 = intbv(4, min=2, max=6) - b = a11.signed() - assert b == -4 + b11 = a11.signed() + assert b11 == -4 a12 = intbv(4, min=3, max=7) - b = a12.signed() - assert b == -4 + b12 = a12.signed() + assert b12 == -4 a13 = intbv(4, min=4, max=8) - b = a13.signed() - assert b == -4 + b13 = a13.signed() + assert b13 == -4 # again with min > 0, here it is not the sign bit anymore # Expect the value to be 4 a14 = intbv(4, min=2, max=9) - b = a14.signed() - assert b == 4 + b14 = a14.signed() + assert b14 == 4 # intbv with positive range, value = 0, return signed() # Expect the number to be returned a15 = intbv(0, min=0, max=0x8) - b = a15.signed() - assert b == 0 + b15 = a15.signed() + assert b15 == 0 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -143,55 +143,55 @@ def PlainIntbv(): # msb, but due to the negative range not considered signed # Expect to return 4 a20 = intbv(4, min=-1, max=5) - b = a20.signed() - assert b == 4 + b20 = a20.signed() + assert b20 == 4 a21 = intbv(4, min=-1, max=6) - b = a21.signed() - assert b == 4 + b21 = a21.signed() + assert b21 == 4 a22 = intbv(4, min=-1, max=7) - b = a22.signed() - assert b == 4 + b22 = a22.signed() + assert b22 == 4 a23 = intbv(4, min=-1, max=8) - b = a23.signed() - assert b == 4 + b23 = a23.signed() + assert b23 == 4 # intbv with negative range, pos number, and msb set, return signed() # Expect the number to returned as is a24 = intbv(7, min=-1, max=8) - b = a24.signed() - assert b == 7 + b24 = a24.signed() + assert b24 == 7 a25 = intbv(6, min=-1, max=8) - b = a25.signed() - assert b == 6 + b25 = a25.signed() + assert b25 == 6 a26 = intbv(5, min=-1, max=8) - b = a26.signed() - assert b == 5 + b26 = a26.signed() + assert b26 == 5 # intbv with symmetric (min = -max) range, pos value, msb set # return signed() # Expect value returned as is a27 = intbv(4, min=-8, max=8) - b = a27.signed() - assert b == 4 + b27 = a27.signed() + assert b27 == 4 # intbv with symmetric (min = -max) range, neg value, # return signed() # Expect value returned as is a28 = intbv(-4, min=-8, max=8) - b = a28.signed() - assert b == -4 + b28 = a28.signed() + assert b28 == -4 # intbv with symmetric (min=-max) range, value = 0, # return signed() # Expect value returned as is a29 = intbv(0, min=-8, max=8) - b = a29.signed() - assert b == 0 + b29 = a29.signed() + assert b29 == 0 return logic diff --git a/myhdl/test/conversion/general/test_print.py b/myhdl/test/conversion/general/test_print.py index 65ef9111..00824ce6 100644 --- a/myhdl/test/conversion/general/test_print.py +++ b/myhdl/test/conversion/general/test_print.py @@ -27,25 +27,25 @@ def PrintBench(): print("%d %d" % (i1, i2)) print(si1) print(si2) - + yield delay(10) print("This is a test") - + yield delay(10) print(int(b)) print(int(sb)) - + yield delay(10) print("i1 is %s" % i1) - + yield delay(10) print("i1 is %s, i2 is %s" % (i1, i2)) print("i1 %s i2 %s b %s si1 %s si2 %s" % (i1, i2, b, si1, si2)) print("i1 %d i2 %d b %d si1 %d si2 %d" % (i1, i2, b, si1, si2)) print(b) #print "%% %s" % i1 - - yield delay(10) + + yield delay(10) print(state) print("the state is %s" % state) print("the state is %s" % (state,)) @@ -68,6 +68,47 @@ def PrintBench(): def testPrint(): assert conversion.verify(PrintBench) == 0 +def PrintLongVectorsBench(): + N84 = 84 + M84 = 2**N84-1 + N85 = 85 + M85 = 2**N85-1 + N86 = 86 + M86 = 2**N86-1 + N87 = 87 + M87 = 2**N87-1 + + si1 = Signal(intbv(0)[N87:]) + si2 = Signal(intbv(0, min=-M85, max=M86)) + + @instance + def logic(): + i1 = intbv(0)[N85:] + i2 = intbv(0, min=-M86, max=M85) + si1.next = 0 + si2.next = 0 + yield delay(10) + print("%s %s %s %s" % (i1, i2, si1, si2)) + i1[:] = M84 + i2[:] = -1 + si1.next = M85 + si2.next = -1 + yield delay(10) + print("%s %s %s %s" % (i1, i2, si1, si2)) + i1[:] = 596854 + i2[:] = -4954502 + si1.next = 232434 + si2.next = -3434355 + yield delay(10) + print("%s %s %s %s" % (i1, i2, si1, si2)) + + return logic + +def testPrintLongVectors(): + assert conversion.verify(PrintLongVectorsBench) == 0 + +def testPrint(): + assert conversion.verify(PrintBench) == 0 # format string errors and unsupported features @@ -86,7 +127,7 @@ def testPrintError1(): assert e.kind == _error.UnsupportedFormatString else: assert False - + def PrintError2(): @instance def logic(): @@ -102,7 +143,7 @@ def testPrintError2(): assert e.kind == _error.FormatString else: assert False - + def PrintError3(): @instance def logic(): @@ -119,7 +160,7 @@ def testPrintError3(): assert e.kind == _error.FormatString else: assert False - + def PrintError4(): @instance def logic(): @@ -135,7 +176,7 @@ def testPrintError4(): assert e.kind == _error.UnsupportedFormatString else: assert False - + def PrintError5(): @instance def logic(): diff --git a/myhdl/test/conversion/toVHDL/test_ops.py b/myhdl/test/conversion/toVHDL/test_ops.py index a41c9db5..5acae8f2 100644 --- a/myhdl/test/conversion/toVHDL/test_ops.py +++ b/myhdl/test/conversion/toVHDL/test_ops.py @@ -39,11 +39,14 @@ def binaryOps( Bitand.next = left & right Bitor.next = left | right Bitxor.next = left ^ right + FloorDiv.next = 0 if right != 0: FloorDiv.next = left // right ## if left < 256 and right < 40: + LeftShift.next = 0 if left < 256 and right < 26: # fails in ghdl for > 26 LeftShift.next = left << right + Modulo.next = 0 if right != 0: Modulo.next = left % right Mul.next = left * right @@ -52,6 +55,7 @@ def binaryOps( # Pow.next = left ** right ## Pow.next = 0 RightShift.next = left >> right + Sub.next = 0 if left >= right: Sub.next = left - right Sum.next = left + right @@ -358,10 +362,12 @@ def augmOps( Bitand, var[:] = left var ^= left Bitxor.next = var + FloorDiv.next = 0 if right != 0: var[:] = left var //= right FloorDiv.next = var + Sub.next = 0 if left >= right: var[:] = left var -= right @@ -369,10 +375,12 @@ def augmOps( Bitand, var[:] = left var += right Sum.next = var + LeftShift.next = 0 if left < 256 and right < 26: var2[:] = left var2 <<= right LeftShift.next = var2 + Modulo.next = 0 if right != 0: var[:] = left var %= right diff --git a/myhdl/test/conversion/toVHDL/test_signed.py b/myhdl/test/conversion/toVHDL/test_signed.py index e493a4a4..891308cf 100644 --- a/myhdl/test/conversion/toVHDL/test_signed.py +++ b/myhdl/test/conversion/toVHDL/test_signed.py @@ -42,6 +42,7 @@ def binaryOps( ## if right != 0: ## FloorDiv.next = left // right # Keep left shifts smaller than 2** 31 for VHDL's to_integer + LeftShift.next = 0 if left < 256 and right < 22 and right >= 0: LeftShift.next = left << right ## if right != 0: @@ -308,6 +309,7 @@ def augmOps( ## var[:] = left ## var //= right ## FloorDiv.next = var + LeftShift.next = 0 if left < 256 and right < 22 and right >= 0: var2[:] = left var2 <<= right @@ -321,6 +323,7 @@ def augmOps( Mul.next = var var[:] = left + RightShift.next = 0 if right >= 0: var >>= right RightShift.next = var