1
0
mirror of https://github.com/myhdl/myhdl.git synced 2024-12-14 07:44:38 +08:00

Use to_string to support long vectors; with various implications...

This commit is contained in:
Jan Decaluwe 2016-03-04 17:42:50 +01:00
parent 0d9dc8f45a
commit 86ec7e81c9
8 changed files with 224 additions and 139 deletions

View File

@ -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) - 1
retVal = self._val & mask
# if sign bit is set, subtract the value of the sign bit
if sign:
retVal -= 1<<msb
# get 2's complement value of bits
msb = self._nrbits-1
else: # value is returned just as is
retVal = self._val
sign = ((self._val >> msb) & 0x1) > 0
return retVal
# mask off the bits msb-1:lsb, they are always positive
mask = (1<<msb) - 1
retVal = self._val & mask
# if sign bit is set, subtract the value of the sign bit
if sign:
retVal -= 1<<msb
else: # value is returned just as is
retVal = self._val
if self._nrbits:
M = 2**(self._nrbits-1)
return intbv(retVal, min=-M, max=M)
else:
return intbv(retVal)

View File

@ -469,6 +469,7 @@ class _AnalyzeVisitor(ast.NodeVisitor, _ConversionMixin):
self.tree.kind = _kind.TASK
# self.access = _access.OUTPUT
self.visit(node.value)
node.obj = node.value.obj
# self.access = _access.INPUT
def getAttr(self, node):
@ -480,6 +481,7 @@ class _AnalyzeVisitor(ast.NodeVisitor, _ConversionMixin):
raise AssertionError("attribute target: %s" % n)
obj = node.value.obj
if isinstance(obj, _Signal):
print ('analyze', node.value.id)
if node.attr == 'posedge':
node.obj = obj.posedge
elif node.attr == 'negedge':
@ -590,7 +592,12 @@ class _AnalyzeVisitor(ast.NodeVisitor, _ConversionMixin):
node.obj = delay(0)
### suprize: identity comparison on unbound methods doesn't work in python 2.5??
elif f == intbv.signed:
node.obj = int(-1)
obj = node.func.value.obj
if len(obj):
M = 2 ** (len(obj)-1)
node.obj = intbv(-1, min=-M, max=M)
else:
node.obj = intbv(-1)
elif f in myhdlObjects:
pass
elif f in builtinObjects:

View File

@ -1347,14 +1347,19 @@ class _ConvertVisitor(ast.NodeVisitor, _ConversionMixin):
else:
a = node.args[argnr]
argnr += 1
to_string = "to_string"
if s.conv is int:
a.vhd = vhd_int()
else:
if isinstance(a.vhdOri, vhd_vector):
a.vhd = vhd_int()
to_string = "to_hstring"
# to_hstring correctly does sign extension
# however, Verilog doesn not: therefore, interprete
# print values as unsigned...
a.vhd = vhd_unsigned(a.vhd.size)
elif isinstance(a.vhdOri, vhd_std_logic):
a.vhd = vhd_boolean()
self.write("write(L, to_string(")
self.write("write(L, %s(" % to_string)
self.visit(a)
self.write("))")
self.write(';')
@ -1987,7 +1992,7 @@ class _AnnotateTypesVisitor(ast.NodeVisitor, _ConversionMixin):
def visit_Attribute(self, node):
self.generic_visit(node)
node.vhd = copy(node.value.vhd)
node.vhd = inferVhdlObj(node.obj)
node.vhdOri = copy(node.vhd)
def visit_Assert(self, node):
@ -2036,6 +2041,7 @@ class _AnnotateTypesVisitor(ast.NodeVisitor, _ConversionMixin):
node.vhd = vhd_nat()
elif f == intbv.signed: # note equality comparison
# this comes from a getattr
# node.vhd = vhd_int()
node.vhd = vhd_signed(fn.value.vhd.size)
elif hasattr(node, 'tree'):
v = _AnnotateTypesVisitor(node.tree)

View File

@ -1061,7 +1061,10 @@ class _ConvertVisitor(ast.NodeVisitor, _ConversionMixin):
a = node.args[argnr]
argnr += 1
obj = a.obj
fs = "%0d"
if s.conv is int or isinstance(obj, int):
fs = "%0d"
else:
fs = "%h"
self.context =_context.PRINT
if isinstance(obj, str):
self.write('$write(')
@ -1092,6 +1095,7 @@ class _ConvertVisitor(ast.NodeVisitor, _ConversionMixin):
self.writeline()
self.write("endcase")
else:
print (type(obj), type(a))
self.write('$write("%s", ' % fs)
self.visit(a)
self.write(');')

View File

@ -57,80 +57,80 @@ def PlainIntbv():
# intbv with positive range, pos number, and msb not set, return signed()
# Expect the number to be returned
a1 = intbv(0x3b, min=0, max=0x7c)
b = a1.signed()
assert b == 0x3b
b1 = a1.signed()
assert b1 == 0x3b
# intbv with positive range, pos number, and msb set, return signed()
# test various bit patterns to see that the 2's complement
# conversion works correct
# Expect the number to be converted to a negative number
a2 = intbv(7, min=0, max=8)
b = a2.signed()
assert b == -1
b2 = a2.signed()
assert b2 == -1
a3 = intbv(6, min=0, max=8)
b = a3.signed()
assert b == -2
b3 = a3.signed()
assert b3 == -2
a4 = intbv(5, min=0, max=8)
b = a4.signed()
assert b == -3
b4 = a4.signed()
assert b4 == -3
# set bit #3 and increase the range so that the set bit is considered
# the sign bit. Here min = 0
# Expect to return -4
a5 = intbv(4, min=0, max=5)
b = a5.signed()
assert b == -4
b5 = a5.signed()
assert b5 == -4
a6 = intbv(4, min=0, max=6)
b = a6.signed()
assert b == -4
b6 = a6.signed()
assert b6 == -4
a7 = intbv(4, min=0, max=7)
b = a7.signed()
assert b == -4
b7 = a7.signed()
assert b7 == -4
a8 = intbv(4, min=0, max=8)
b = a8.signed()
assert b == -4
b8 = a8.signed()
assert b8 == -4
# here it is not the sign bit anymore
# Expect the value to be 4
a9 = intbv(4, min=0, max=9)
b = a9.signed()
assert b == 4
b9 = a9.signed()
assert b9 == 4
# set bit #3 and increase the range so that the set bit is considered
# the sign bit. Here min > 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

View File

@ -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():

View File

@ -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

View File

@ -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