Skip to content

Commit

Permalink
Use to_string to support long vectors; with various implications...
Browse files Browse the repository at this point in the history
  • Loading branch information
jandecaluwe committed Mar 4, 2016
1 parent 0d9dc8f commit 86ec7e8
Show file tree
Hide file tree
Showing 8 changed files with 232 additions and 147 deletions.
180 changes: 98 additions & 82 deletions myhdl/_intbv.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@

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
Expand Down Expand Up @@ -60,7 +60,7 @@ def __init__(self, val=0, min=None, max=None, _nrbits=0):
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):
Expand All @@ -79,7 +79,7 @@ def _handleBounds(self):
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:
Expand All @@ -92,7 +92,7 @@ def _hasFullRange(self):
# hash
def __hash__(self):
raise TypeError("intbv objects are unhashable")

# copy methods
def __copy__(self):
c = type(self)(self._val)
Expand Down Expand Up @@ -149,7 +149,7 @@ def __getitem__(self, key):
return res



def __setitem__(self, key, val):
# convert val to int to avoid confusion with intbv or Signals
val = int(val)
Expand Down Expand Up @@ -187,21 +187,21 @@ def __setitem__(self, key, val):
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
else:
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
Expand All @@ -225,15 +225,15 @@ def __truediv__(self, other):
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
else:
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
Expand All @@ -243,7 +243,7 @@ def __rmod__(self, other):
return other % self._val

# divmod

def __pow__(self, other):
if isinstance(other, intbv):
return self._val ** other._val
Expand All @@ -259,15 +259,15 @@ def __lshift__(self, other):
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)
else:
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)
Expand All @@ -283,7 +283,7 @@ def __or__(self, other):
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)
Expand All @@ -299,23 +299,23 @@ def __iadd__(self, other):
self._val += other
self._handleBounds()
return self

def __isub__(self, other):
if isinstance(other, intbv):
self._val -= other._val
else:
self._val -= other
self._handleBounds()
return self

def __imul__(self, other):
if isinstance(other, intbv):
self._val *= other._val
else:
self._val *= other
self._handleBounds()
return self

def __ifloordiv__(self, other):
if isinstance(other, intbv):
self._val //= other._val
Expand All @@ -328,18 +328,18 @@ def __idiv__(self, other):
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
else:
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:
Expand All @@ -348,7 +348,7 @@ def __ipow__(self, other, modulo=None):
raise ValueError("intbv value should be integer")
self._handleBounds()
return self

def __iand__(self, other):
if isinstance(other, intbv):
self._val &= other._val
Expand Down Expand Up @@ -404,27 +404,27 @@ def __invert__(self):
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)

def __float__(self):
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):
Expand Down Expand Up @@ -457,67 +457,83 @@ def __ge__(self, other):
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
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.
''' 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 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
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.
'''

# value is considered unsigned
if self.min is not None and self.min >= 0 and self._nrbits > 0:

# get 2's complement value of bits
msb = self._nrbits-1

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

else: # value is returned just as is
retVal = self._val

return retVal
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.
'''

# value is considered unsigned
if self.min is not None and self.min >= 0 and self._nrbits:

# get 2's complement value of bits
msb = self._nrbits-1

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

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)
9 changes: 8 additions & 1 deletion myhdl/conversion/_analyze.py
Original file line number Diff line number Diff line change
Expand Up @@ -469,6 +469,7 @@ def setAttr(self, node):
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):
Expand All @@ -480,6 +481,7 @@ def getAttr(self, node):
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':
Expand Down Expand Up @@ -590,7 +592,12 @@ def visit_Call(self, node):
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:
Expand Down

0 comments on commit 86ec7e8

Please sign in to comment.