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

fine-grained signed arithmetic

This commit is contained in:
jand 2005-11-19 15:37:59 +00:00
parent 26a43394c4
commit 1c3a13c946
7 changed files with 212 additions and 79 deletions

View File

@ -8,10 +8,10 @@ global-include makefile*
global-include *.v
prune dist
prune doc
graft doc/html/manual
graft doc/html/icons
graft doc/html/whatsnew*
include doc/paper-a4/*.pdf
include doc/paper-letter/*.pdf
#graft doc/html/manual
#graft doc/html/icons
#graft doc/html/whatsnew*
#include doc/paper-a4/*.pdf
#include doc/paper-letter/*.pdf
prune myhdl/experiments
exclude myhdl/test/toVerilog/*.v

View File

@ -71,7 +71,7 @@ _error.ListElementNotUnique = "List contains Signals that are not unique to it"
_access = enum("INPUT", "OUTPUT", "INOUT", "UNKNOWN")
_kind = enum("NORMAL", "DECLARATION", "ALWAYS", "INITIAL", "ALWAYS_COMB", "SIMPLE_ALWAYS_COMB", "ALWAYS_DECO", "TASK", "REG")
_context = enum("BOOLEAN", "YIELD", "PRINT" ,"EXPR", "UNKNOWN")
_context = enum("BOOLEAN", "YIELD", "PRINT" ,"SIGNED", "UNKNOWN")
class _ToVerilogMixin(object):

View File

@ -48,9 +48,6 @@ from myhdl._extractHierarchy import _isMem, _CustomVerilog
myhdlObjects = myhdl.__dict__.values()
builtinObjects = __builtin__.__dict__.values()
_signed = False
def _isSigned():
return _signed
def _makeName(n, prefixes):
if len(prefixes) > 1:
@ -64,7 +61,6 @@ def _makeName(n, prefixes):
return name
def _analyzeSigs(hierarchy):
global _signed
curlevel = 0
siglist = []
memlist = []
@ -74,24 +70,15 @@ def _analyzeSigs(hierarchy):
delta = curlevel - level
curlevel = level
assert(delta >= -1)
#print
#print curlevel
#print delta
#print prefixes
if delta == -1:
prefixes.append(name)
else:
prefixes = prefixes[:curlevel-1]
prefixes.append(name)
assert prefixes[-1] == name
#print prefixes
# signals
#print sigdict
for n, s in sigdict.items():
if s._name is not None:
continue
if s._min is not None and s._min < 0:
_signed = True
s._name = _makeName(n, prefixes)
if not s._nrbits:
raise ToVerilogError(_error.UndefinedBitWidth, s._name)
@ -120,8 +107,6 @@ def _analyzeSigs(hierarchy):
raise ToVerilogError(_error.InconsistentType, s._name)
if s._nrbits != m.elObj._nrbits:
raise ToVerilogError(_error.InconsistentBitWidth, s._name)
if s._min is not None and s._min < 0:
_signed = True
return siglist, memlist
@ -328,6 +313,11 @@ class _Rom(object):
def __init__(self, rom):
self.rom = rom
def _isNegative(obj):
if hasattr(obj, '_min') and (obj._min is not None) and (obj._min < 0):
return True
return False
class _AnalyzeVisitor(_ToVerilogMixin):
@ -350,18 +340,22 @@ class _AnalyzeVisitor(_ToVerilogMixin):
self.visit(node.left)
self.visit(node.right)
node.obj = int()
node.signed = node.left.signed or node.right.signed
visitAdd = binaryOp
visitFloorDiv = binaryOp
visitLeftShift = binaryOp
visitMul = binaryOp
visitPow = binaryOp
visitPower = binaryOp
visitMod = binaryOp
visitRightShift = binaryOp
visitSub = binaryOp
def multiBitOp(self, node, *args):
node.signed = False
for n in node.nodes:
self.visit(n)
if n.signed:
node.signed = True
node.obj = None
for n in node.nodes:
if node.obj is None:
@ -387,15 +381,19 @@ class _AnalyzeVisitor(_ToVerilogMixin):
def visitInvert(self, node, *args):
self.visit(node.expr)
node.obj = node.expr.obj
node.signed = node.expr.signed
def visitNot(self, node, *args):
self.visit(node.expr)
node.obj = bool()
node.signed = node.expr.signed
def visitUnaryAdd(self, node, *args):
self.visit(node.expr)
node.obj = int()
node.signed = node.expr.signed
def visitUnarySub(self, node, *args):
self.visit(node.expr)
node.obj = int()
node.signed = node.expr.signed
def visitAssAttr(self, node, access=_access.OUTPUT, *args):
if node.attrname != 'next':
@ -404,7 +402,6 @@ class _AnalyzeVisitor(_ToVerilogMixin):
self.visit(node.expr, _access.OUTPUT)
def visitAssign(self, node, access=_access.OUTPUT, *args):
global _signed
target, expr = node.nodes[0], node.expr
self.visit(target, _access.OUTPUT)
if isinstance(target, astNode.AssName):
@ -457,6 +454,7 @@ class _AnalyzeVisitor(_ToVerilogMixin):
argsAreInputs = True
f = self.getObj(node.node)
node.obj = None
node.signed = False
if type(f) is type and issubclass(f, intbv):
node.obj = self.getVal(node)
elif f is len:
@ -517,7 +515,11 @@ class _AnalyzeVisitor(_ToVerilogMixin):
def visitCompare(self, node, *args):
node.obj = bool()
self.visitChildNodes(node)
node.signed = False
for n in node.getChildNodes():
self.visit(n, *args)
if n.signed:
node.signed = True
op, arg = node.ops[0]
if op == '==':
if isinstance(node.expr, astNode.Name) and \
@ -525,6 +527,7 @@ class _AnalyzeVisitor(_ToVerilogMixin):
node.case = (node.expr.name, arg.obj)
def visitConst(self, node, *args):
node.signed = False
if isinstance(node.value, int):
node.obj = node.value
else:
@ -557,6 +560,7 @@ class _AnalyzeVisitor(_ToVerilogMixin):
assert isinstance(node.expr, astNode.Name)
assert node.expr.name in self.ast.symdict
node.obj = None
node.signed = False
obj = self.ast.symdict[node.expr.name]
if isinstance(obj, Signal):
if node.attrname in ('posedge', 'negedge'):
@ -645,11 +649,13 @@ class _AnalyzeVisitor(_ToVerilogMixin):
node.obj = __builtin__.__dict__[n]
else:
pass
node.signed = _isNegative(node.obj)
def visitReturn(self, node, *args):
self.raiseError(node, _error.NotSupported, "return statement")
def visitSlice(self, node, access=_access.INPUT, kind=_kind.NORMAL, *args):
node.signed = False
self.visit(node.expr, access)
node.obj = self.getObj(node.expr)
if node.lower:
@ -668,6 +674,7 @@ class _AnalyzeVisitor(_ToVerilogMixin):
def visitSubscript(self, node, access=_access.INPUT, *args):
node.signed = False
self.visit(node.expr, access)
assert len(node.subs) == 1
self.visit(node.subs[0], _access.INPUT)

View File

@ -46,7 +46,7 @@ from myhdl._always import _Always
from myhdl._toVerilog import _error, _access, _kind,_context, \
_ToVerilogMixin, _Label
from myhdl._toVerilog._analyze import _analyzeSigs, _analyzeGens, _analyzeTopFunc, \
_Ram, _Rom, _isSigned
_Ram, _Rom
_converting = 0
_profileFunc = None
@ -234,16 +234,12 @@ def _getRangeString(s):
return ''
elif s._nrbits is not None:
nrbits = s._nrbits
if _isSigned():
# add a sign bit to positive numbers
if s._type is intbv and s._min >=0:
nrbits += 1
return "[%s:0] " % (nrbits-1)
else:
raise AssertionError
def _getSignString(s):
if _isSigned() and s._type is intbv:
if s._min is not None and s._min < 0:
return "signed "
else:
return ''
@ -301,8 +297,9 @@ class _ConvertVisitor(_ToVerilogMixin):
self.write("reg [%s-1:0] %s [0:%s-1]" % (obj.elObj._nrbits, name, obj.depth))
elif hasattr(obj, '_nrbits'):
s = ""
if isinstance(obj, intbv) and obj._min < 0:
s = "signed "
if isinstance(obj, (intbv, Signal)):
if obj._min is not None and obj._min < 0:
s = "signed "
self.write("%s%s[%s-1:0] %s" % (dir, s, obj._nrbits, name))
else:
raise AssertionError("var %s has unexpected type %s" % (name, type(obj)))
@ -331,10 +328,13 @@ class _ConvertVisitor(_ToVerilogMixin):
self.ind = self.ind[:-4]
def binaryOp(self, node, op=None):
context = None
if node.signed:
context = _context.SIGNED
self.write("(")
self.visit(node.left, _context.EXPR)
self.visit(node.left, context)
self.write(" %s " % op)
self.visit(node.right, _context.EXPR)
self.visit(node.right, context)
self.write(")")
def visitAdd(self, node, *args):
self.binaryOp(node, '+')
@ -374,7 +374,7 @@ class _ConvertVisitor(_ToVerilogMixin):
self.visit(node.nodes[0])
for n in node.nodes[1:]:
self.write(" %s " % op)
self.visit(n, _context.EXPR)
self.visit(n)
self.write(")")
def visitAnd(self, node, *args):
self.multiOp(node, '&&')
@ -387,19 +387,19 @@ class _ConvertVisitor(_ToVerilogMixin):
def visitOr(self, node, *args):
self.multiOp(node, '||')
def unaryOp(self, node, op):
def unaryOp(self, node, op, context):
self.checkOpWithNegIntbv(node.expr, op)
self.write("(%s" % op)
self.visit(node.expr, _context.EXPR)
self.visit(node.expr, context)
self.write(")")
def visitInvert(self, node, *args):
self.unaryOp(node, '~')
def visitNot(self, node, *args):
self.unaryOp(node, '!')
def visitUnaryAdd(self, node, *args):
self.unaryOp(node, '+')
def visitUnarySub(self, node, *args):
self.unaryOp(node, '-')
def visitInvert(self, node, context=None, *args):
self.unaryOp(node, '~', context)
def visitNot(self, node, context=None, *args):
self.unaryOp(node, '!', context)
def visitUnaryAdd(self, node, context=None, *args):
self.unaryOp(node, '+', context)
def visitUnarySub(self, node, context=None, *args):
self.unaryOp(node, '-', context)
def visitAssAttr(self, node, *args):
assert node.attrname == 'next'
@ -496,6 +496,9 @@ class _ConvertVisitor(_ToVerilogMixin):
return
elif f in (int, long):
opening, closing = '', ''
elif f is intbv:
self.visit(node.args[0])
return
elif type(f) is ClassType and issubclass(f, Exception):
self.write(f.__name__)
elif f in (posedge, negedge):
@ -523,11 +526,14 @@ class _ConvertVisitor(_ToVerilogMixin):
compiler.walk(node.ast, v)
def visitCompare(self, node, *args):
context = None
if node.signed:
context = _context.SIGNED
self.write("(")
self.visit(node.expr)
self.visit(node.expr, context)
op, code = node.ops[0]
self.write(" %s " % op)
self.visit(code)
self.visit(code, context)
self.write(")")
def visitConst(self, node, context=None, *args):
@ -697,54 +703,50 @@ class _ConvertVisitor(_ToVerilogMixin):
def visitModule(self, node, *args):
for stmt in node.node.nodes:
self.visit(stmt)
def writeName(self, name, context, isBool):
addSignBit = isBool and _isSigned() and context == _context.EXPR
if addSignBit:
self.write("$signed({1'b0, ")
self.write(name)
if addSignBit:
self.write("})")
def visitName(self, node, context=None, *args):
addSignBit = False
isMixedExpr = (not node.signed) and (context == _context.SIGNED)
n = node.name
if n == 'False':
self.write("0")
s = "0"
elif n == 'True':
self.write("1")
s = "1"
elif n in self.ast.vardict:
obj = self.ast.vardict[n]
isBool = isinstance(obj, bool)
self.writeName(n, context, isBool)
addSignBit = isMixedExpr
s = n
elif n in self.ast.argnames:
assert n in self.ast.symdict
obj = self.ast.symdict[n]
isBool = isinstance(obj, bool) or (isinstance(obj, Signal) and obj._type is bool)
self.writeName(n, context, isBool)
addSignBit = isMixedExpr
s = n
elif n in self.ast.symdict:
obj = self.ast.symdict[n]
if isinstance(obj, bool):
self.write("%s" % int(obj))
s = "%s" % int(obj)
elif isinstance(obj, int):
self.write(str(obj))
s = str(obj)
elif isinstance(obj, Signal):
isBool = obj._type is bool
assert obj._name
self.writeName(obj._name, context, isBool)
addSignBit = isMixedExpr
s = str(obj)
elif _isMem(obj):
m = _getMemInfo(obj)
assert m.name
if not m.decl:
self.raiseError(node, _error.ListElementNotUnique, m.name)
self.write(m.name)
s = m.name
elif str(type(obj)) == "<class 'myhdl._enum.EnumItem'>":
self.write(obj._toVerilog())
s = obj._toVerilog()
elif type(obj) is ClassType and issubclass(obj, Exception):
self.write(n)
s = n
else:
self.raiseError(node, _error.UnsupportedType, "%s, %s" % (n, type(obj)))
else:
raise AssertionError("name ref: %s" % n)
if addSignBit:
self.write("$signed({1'b0, ")
self.write(s)
if addSignBit:
self.write("})")
def visitPass(self, node, *args):
self.write("// pass")
@ -774,14 +776,15 @@ class _ConvertVisitor(_ToVerilogMixin):
def visitReturn(self, node, *args):
self.write("disable %s;" % self.returnLabel)
def visitSlice(self, node, *args):
def visitSlice(self, node, context=None, *args):
if isinstance(node.expr, astNode.CallFunc) and \
node.expr.node.obj is intbv:
c = self.getVal(node)
self.write("%s'h" % c._nrbits)
self.write("%x" % c._val)
return
if node.flags == 'OP_APPLY' and _isSigned():
addSignBit = (node.flags == 'OP_APPLY') and (context == _context.SIGNED)
if addSignBit:
self.write("$signed({1'b0, ")
self.visit(node.expr)
# special shortcut case for [:] slice
@ -798,7 +801,7 @@ class _ConvertVisitor(_ToVerilogMixin):
else:
self.visit(node.upper)
self.write("]")
if node.flags == 'OP_APPLY' and _isSigned():
if addSignBit:
self.write("})")
def visitStmt(self, node, *args):
@ -809,15 +812,16 @@ class _ConvertVisitor(_ToVerilogMixin):
if isinstance(stmt, astNode.CallFunc) and hasattr(stmt, 'ast'):
self.write(';')
def visitSubscript(self, node, *args):
if node.flags == 'OP_APPLY' and _isSigned():
def visitSubscript(self, node, context=None, *args):
addSignBit = (node.flags == 'OP_APPLY') and (context == _context.SIGNED)
if addSignBit:
self.write("$signed({1'b0, ")
self.visit(node.expr)
self.write("[")
assert len(node.subs) == 1
self.visit(node.subs[0])
self.write("]")
if node.flags == 'OP_APPLY' and _isSigned():
if addSignBit:
self.write("})")
def visitTuple(self, node, context=None, *args):

View File

@ -54,6 +54,28 @@ def dec(count, enable, clock, reset, n):
count.next = count - 1
return decProcess()
def decFunc(count, enable, clock, reset, n):
def decFuncFunc(cnt):
count_next = intbv(0, min=-n, max=n)
if count == -n:
count_next[:] = n-1
else:
count_next[:] = cnt - 1
return count_next
@always(clock.posedge, reset.negedge)
def decFuncGen():
if reset == ACTIVE_LOW:
count.next = 0
else:
if enable:
count.next = decFuncFunc(count)
return decFuncGen
def decTask(count, enable, clock, reset, n):
def decTaskFunc(cnt, enable, reset, n):
@ -163,14 +185,16 @@ class TestDec(TestCase):
return sim
def testDecRef(self):
""" Check decrement operation """
sim = self.bench(decRef)
sim.run(quiet=1)
def testDec(self):
""" Check decrement operation """
sim = self.bench(dec)
sim.run(quiet=1)
def testDecFunc(self):
sim = self.bench(decFunc)
sim.run(quiet=1)
## signed inout in task doesn't work yet in Icarus
## def testDecTask(self):

View File

@ -47,6 +47,21 @@ def inc(count, enable, clock, reset, n):
count.next = (count + 1) % n
return incProcess
def inc2(count, enable, clock, reset, n):
@always(clock.posedge, reset.negedge)
def incProcess():
if reset == ACTIVE_LOW:
count.next = 0
else:
if enable:
if count == n:
count.next = 0
else:
count.next = count + 1
return incProcess
def incTask(count, enable, clock, reset, n):
def incTaskFunc(cnt, enable, reset, n):
@ -155,6 +170,11 @@ class TestInc(TestCase):
sim = self.bench(inc)
sim.run(quiet=1)
def testInc2(self):
""" Check increment operation """
sim = self.bench(inc2)
sim.run(quiet=1)
def testIncTask(self):
sim = self.bench(incTask)
sim.run(quiet=1)

View File

@ -482,6 +482,84 @@ class TestAugmOps(TestCase):
Simulation(sim).run()
def expressions(a, b, clk):
c = Signal(intbv(0, min=0, max=47))
e = Signal(bool())
@instance
def logic():
d = intbv(0, min=-23, max=43)
d[:] = -17
c.next = 5
yield clk.posedge
a.next = c + 1
b.next = c + 1
yield clk.posedge
a.next = c + -10
b.next = c + -1
yield clk.posedge
a.next = c < -10
b.next = c < -1
yield clk.posedge
a.next = d + c
b.next = d >= c
yield clk.posedge
# a.next = d & c
# b.next = c + (d & c)
yield clk.posedge
a.next = d + -c
b.next = c + (-d)
yield clk.posedge
a.next = -d
yield clk.posedge
a.next = -c
yield clk.posedge
yield clk.posedge
raise StopSimulation
return logic
def expressions_v(a, b, clk):
return setupCosimulation(**locals())
class TestExpressions(TestCase):
def bench(self):
a, a_v = [Signal(intbv(0, min=-34, max=47)) for i in range(2)]
b, b_v = [Signal(intbv(0, min=0, max=47)) for i in range(2)]
clk = Signal(bool())
expr = toVerilog(expressions, a, b, clk)
expr_v = toVerilog(expressions, a_v, b_v, clk)
@instance
def check():
while 1:
yield clk.posedge
yield delay(1)
self.assertEqual(a, a_v)
# print a
# print a_v
self.assertEqual(b, b_v)
@always(delay(10))
def clkgen():
clk.next = not clk
return expr, expr_v, check, clkgen
def testExpressions(self):
sim = self.bench()
Simulation(sim).run()
if __name__ == '__main__':
unittest.main()