diff --git a/MANIFEST.in b/MANIFEST.in index 9d753dc6..004cb570 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -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 diff --git a/myhdl/_toVerilog/__init__.py b/myhdl/_toVerilog/__init__.py index acd855de..bb9b0dea 100644 --- a/myhdl/_toVerilog/__init__.py +++ b/myhdl/_toVerilog/__init__.py @@ -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): diff --git a/myhdl/_toVerilog/_analyze.py b/myhdl/_toVerilog/_analyze.py index a2069a50..e6823f6f 100644 --- a/myhdl/_toVerilog/_analyze.py +++ b/myhdl/_toVerilog/_analyze.py @@ -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) diff --git a/myhdl/_toVerilog/_convert.py b/myhdl/_toVerilog/_convert.py index f19d1f17..904f63e9 100644 --- a/myhdl/_toVerilog/_convert.py +++ b/myhdl/_toVerilog/_convert.py @@ -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)) == "": - 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): diff --git a/myhdl/test/toVerilog/test_dec.py b/myhdl/test/toVerilog/test_dec.py index 5460e332..f4ed41ef 100644 --- a/myhdl/test/toVerilog/test_dec.py +++ b/myhdl/test/toVerilog/test_dec.py @@ -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): diff --git a/myhdl/test/toVerilog/test_inc.py b/myhdl/test/toVerilog/test_inc.py index 652bb7d8..33f44f0c 100644 --- a/myhdl/test/toVerilog/test_inc.py +++ b/myhdl/test/toVerilog/test_inc.py @@ -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) diff --git a/myhdl/test/toVerilog/test_signed.py b/myhdl/test/toVerilog/test_signed.py index e534e1d8..cc94a216 100644 --- a/myhdl/test/toVerilog/test_signed.py +++ b/myhdl/test/toVerilog/test_signed.py @@ -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()