diff --git a/myhdl/_Signal.py b/myhdl/_Signal.py index 3fd9478a..da8f94a3 100644 --- a/myhdl/_Signal.py +++ b/myhdl/_Signal.py @@ -112,6 +112,8 @@ class Signal(object): else: self._type = type(val) self._setNextVal = self._setNextType + if hasattr(val, '_nrbits'): + self._nrbits = val._nrbits self._eventWaiters = _WaiterList() self._posedgeWaiters = _WaiterList() self._negedgeWaiters = _WaiterList() diff --git a/myhdl/_enum.py b/myhdl/_enum.py index 3f5a1725..c8c710d7 100644 --- a/myhdl/_enum.py +++ b/myhdl/_enum.py @@ -27,6 +27,7 @@ __date__ = "$Date$" from types import StringType +from myhdl._util import bin def enum(*args): @@ -34,6 +35,7 @@ def enum(*args): # only default encoding for now argdict = {} encoding = {} + nrbits = len(bin(len(args))) i = 0 for arg in args: if type(arg) is not StringType: @@ -41,20 +43,25 @@ def enum(*args): if encoding.has_key(arg): raise ValueError("enum literals should be unique") argdict[i] = arg - encoding[arg] = i + encoding[arg] = bin(i, nrbits) i += 1 - + class EnumItem(object): - def __init__(self, arg): + def __init__(self, index, arg): + self._index = index self._val = encoding[arg] + self._nrbits = nrbits def __repr__(self): - return argdict[self._val] + return argdict[self._index] + def __hex__(self): + return hex(int(self._val, 2)) __str__ = __repr__ class Enum(object): def __init__(self): - for slot in args: - self.__dict__[slot] = EnumItem(slot) + for index, slot in enumerate(args): + self.__dict__[slot] = EnumItem(index, slot) + self.__dict__['_nrbits'] = nrbits def __setattr__(self, attr, val): raise AttributeError("Cannot assign to enum attributes") def __len__(self): diff --git a/myhdl/_extractHierarchy.py b/myhdl/_extractHierarchy.py index f033c26b..115bd1bb 100644 --- a/myhdl/_extractHierarchy.py +++ b/myhdl/_extractHierarchy.py @@ -30,6 +30,7 @@ from __future__ import generators import sys from inspect import currentframe, getframeinfo, getouterframes import re +import string from types import GeneratorType import compiler from compiler import ast @@ -123,9 +124,10 @@ class _HierExtr(object): global _profileFunc self.skipNames = ('always_comb', 'instances', 'processes') self.skip = 0 - self.names = [name] + self.names = [] self.instNamesStack = [Set()] self.hierarchy = hierarchy = [] + self.gennames = gennames = {} self.level = 0 # handle special case of a top-level generator separately if _isGenFunc(dut): @@ -165,6 +167,8 @@ class _HierExtr(object): self.level += 1 self.instNamesStack.append(Set()) elif event == "return": + truenames = [n for n in self.names[1:] if n is not None] + prefix = '_'.join(truenames) if not self.skip: name = self.names.pop() if name: @@ -189,6 +193,10 @@ class _HierExtr(object): gsigdict[n] = v inst = [self.level+1, gname, gsigdict] self.hierarchy.append(inst) + absgname = gname + if prefix: + absgname = prefix + "_" + gname + self.gennames[id(g)] = absgname inst = [self.level, name, sigdict] self.hierarchy.append(inst) self.level -= 1 diff --git a/myhdl/_toVerilog.py b/myhdl/_toVerilog.py index dfafe3e1..2a80a8d6 100644 --- a/myhdl/_toVerilog.py +++ b/myhdl/_toVerilog.py @@ -30,9 +30,10 @@ import inspect import compiler from compiler import ast from sets import Set -from types import GeneratorType +from types import GeneratorType, ClassType from cStringIO import StringIO + from myhdl import Signal, intbv from myhdl._extractHierarchy import _HierExtr, _findInstanceName @@ -99,13 +100,13 @@ def toVerilog(func, *args, **kwargs): tbfile = open(tbpath, 'w') siglist = _analyzeSigs(h.hierarchy) - astlist = _analyzeGens(_flatten(h.top)) + genlist = _analyzeGens(_flatten(h.top), h.gennames) intf = _analyzeTopFunc(func, *args, **kwargs) intf.name = name _writeModuleHeader(vfile, intf) _writeSigDecls(vfile, intf, siglist) - _convertGens(astlist, vfile) + _convertGens(genlist, vfile) _writeModuleFooter(vfile) _writeTestBench(tbfile, intf) @@ -143,15 +144,21 @@ def _analyzeSigs(hierarchy): return siglist -def _analyzeGens(top): +def LabelGenerator(): + i = 1 + while 1: + yield "_MYHDL_LABEL_%s" % i + i += 1 + + +def _analyzeGens(top, gennames): + genLabel = LabelGenerator() genlist = [] for g in top: f = g.gi_frame s = inspect.getsource(f) s = s.lstrip() ast = compiler.parse(s) - ast.locals = f.f_locals - ast.globals = f.f_globals symdict = f.f_globals.copy() symdict.update(f.f_locals) sigdict = {} @@ -160,6 +167,10 @@ def _analyzeGens(top): sigdict[n] = v ast.sigdict = sigdict ast.symdict = symdict + if gennames.has_key(id(g)): + ast.name = gennames[id(g)] + else: + ast.name = genLabel.next() v = _AnalyzeGenVisitor(sigdict) compiler.walk(ast, v) genlist.append(ast) @@ -371,6 +382,8 @@ def _getRangeString(s): return '' elif s._type is intbv: return "[%s:0] " % (s._nrbits-1) + elif s._nrbits is not None: + return "[%s:0] " % (s._nrbits-1) else: raise AssertionError @@ -379,8 +392,9 @@ def _getRangeString(s): class _convertGenVisitor(object): - def __init__(self, f, sigdict, symdict): + def __init__(self, f, sigdict, symdict, name): self.buf = self.fileBuf = f + self.name = name self.declBuf = StringIO() self.codeBuf = StringIO() self.sigdict = sigdict @@ -388,13 +402,7 @@ class _convertGenVisitor(object): self.ind = '' self.inYield = False self.isSigAss = False - self.genLabel = self.LabelGenerator() - def LabelGenerator(self): - i = 1 - while 1: - yield "LABEL_%s" % i - i += 1 def write(self, arg): self.buf.write("%s" % arg) @@ -442,17 +450,32 @@ class _convertGenVisitor(object): def visitCallFunc(self, node): - self.visit(node.node) - self.write(' ') - self.visit(node.args[0]) + f = node.node + assert isinstance(f, ast.Name) + self.visit(f) + if f.name in self.symdict: + obj = self.symdict[f.name] + elif f.name in __builtins__: + obj = __builtins__[f.name] + else: + raise AssertionError + if type(obj) in (ClassType, type) and issubclass(obj, Exception): + self.write(": ") + else: + self.write(' ') + if node.args: + self.visit(node.args[0]) + # XXX def visitCompare(self, node): + self.write("(") self.visit(node.expr) assert len(node.ops) == 1 op, code = node.ops[0] self.write(" %s " % op) self.visit(code) + self.write(")") def visitConst(self, node): self.write(node.value) @@ -497,7 +520,7 @@ class _convertGenVisitor(object): self.write("always @(") self.visit(sl) self.inYield = False - self.write(") begin: %s" % self.genLabel.next()) + self.write(") begin: %s" % self.name) self.indent() self.buf = self.codeBuf for s in w.body.nodes[1:]: @@ -512,21 +535,31 @@ class _convertGenVisitor(object): self.writeline() def visitGetattr(self, node): - if node.attrname == 'next': - self.isSigAss = True - self.visit(node.expr) + assert isinstance(node.expr, ast.Name) + assert node.expr.name in self.symdict + obj = self.symdict[node.expr.name] + if type(obj) is Signal: + if node.attrname == 'next': + self.isSigAss = True + self.visit(node.expr) + elif str(type(obj)) == "": + assert hasattr(obj, node.attrname) + e = getattr(obj, node.attrname) + self.write("%d'b%s" % (obj._nrbits, e._val)) def visitIf(self, node): - self.writeline() - self.write("if (") - test, suite = node.tests[0] - self.visit(test) - self.write(") begin") - self.indent() - self.visit(suite) - self.dedent() - self.writeline() - self.write("end") + ifstring = "if (" + for test, suite in node.tests: + self.writeline() + self.write(ifstring) + self.visit(test) + self.write(") begin") + self.indent() + self.visit(suite) + self.dedent() + self.writeline() + self.write("end") + ifstring = "else if (" if node.else_: self.writeline() self.write("else begin") @@ -537,10 +570,12 @@ class _convertGenVisitor(object): self.write("end") def visitMod(self, node): + self.write("(") self.visit(node.left) self.write(" % ") self.visit(node.right) - + self.write(")") + def visitName(self, node): if node.name in self.symdict: obj = self.symdict[node.name] @@ -553,6 +588,27 @@ class _convertGenVisitor(object): else: self.write(node.name) + def visitNot(self, node): + self.write("(!") + self.visit(node.expr) + self.write(")") + + def visitRaise(self, node): + self.writeline() + self.write('$display("') + self.visit(node.expr1) + self.write('");') + self.writeline() + self.write("$finish;") + + + def visitSub(self, node): + self.write("(") + self.visit(node.left) + self.write(" - ") + self.visit(node.right) + self.write(")") + def visitSubscript(self, node): self.visit(node.expr) self.write("[") @@ -580,7 +636,7 @@ class _convertGenVisitor(object): def _convertGens(astlist, vfile): for ast in astlist: - v = _convertGenVisitor(vfile, ast.sigdict, ast.symdict) + v = _convertGenVisitor(vfile, ast.sigdict, ast.symdict, ast.name) compiler.walk(ast, v) diff --git a/myhdl/test/toVerilog/test_fsm.py b/myhdl/test/toVerilog/test_fsm.py new file mode 100644 index 00000000..4fdbb00c --- /dev/null +++ b/myhdl/test/toVerilog/test_fsm.py @@ -0,0 +1,131 @@ +import os +path = os.path +import unittest +from unittest import TestCase + +from myhdl import * + +# SEARCH, CONFIRM, SYNC = range(3) +ACTIVE_LOW = 0 +FRAME_SIZE = 8 +t_State = enum('SEARCH', 'CONFIRM', 'SYNC') + +def FramerCtrl(SOF, state, syncFlag, clk, reset_n): + + """ Framing control FSM. + + SOF -- start-of-frame output bit + state -- FramerState output + syncFlag -- sync pattern found indication input + clk -- clock input + reset_n -- active low reset + + """ + + index = Signal(intbv(0)[8:]) # position in frame + + def FSM(): + while 1: + yield posedge(clk), negedge(reset_n) + + if reset_n == ACTIVE_LOW: + SOF.next = 0 + index.next = 0 + state.next = t_State.SEARCH + + else: + index.next = (index + 1) % FRAME_SIZE + SOF.next = 0 + + if state == t_State.SEARCH: + index.next = 1 + if syncFlag: + state.next = t_State.CONFIRM + + elif state == t_State.CONFIRM: + if index == 0: + if syncFlag: + state.next = t_State.SYNC + else: + state.next = t_State.SEARCH + + elif state == t_State.SYNC: + if index == 0: + if not syncFlag: + state.next = t_State.SEARCH + SOF.next = (index == FRAME_SIZE-1) + + else: + raise ValueError("Undefined state") + + FSM_1 = FSM() + return FSM_1 + + +analyze_cmd = "iverilog -o framerctrl framerctrl.v tb_framerctrl.v" +simulate_cmd = "vvp -m ../../../cosimulation/icarus/myhdl.vpi framerctrl" + + +def FramerCtrl_v(SOF, state, syncFlag, clk, reset_n): + if path.exists("framectrl"): + os.remove("framectrl") + os.system(analyze_cmd) + return Cosimulation(simulate_cmd, **locals()) + + +class FramerCtrlTest(TestCase): + + def bench(self): + + SOF = Signal(bool(0)) + SOF_v = Signal(bool(0)) + syncFlag = Signal(bool(0)) + clk = Signal(bool(0)) + reset_n = Signal(bool(1)) + state = Signal(t_State.SEARCH) + state_v = Signal(intbv(0)[2:]) + + framerctrl = toVerilog(FramerCtrl, SOF, state, syncFlag, clk, reset_n) + framerctrl_v = FramerCtrl_v(SOF_v, state_v, syncFlag, clk, reset_n) + + def clkgen(): + reset_n.next = 1 + yield delay(10) + reset_n.next = 0 + yield delay(10) + reset_n.next = 1 + yield delay(10) + while 1: + yield delay(10) + clk.next = not clk + + def stimulus(): + for i in range(3): + yield posedge(clk) + for n in (12, 8, 8, 4, 11, 8, 8, 7, 6, 8, 8): + syncFlag.next = 1 + yield posedge(clk) + syncFlag.next = 0 + for i in range(n-1): + yield posedge(clk) + raise StopSimulation + + def check(): + while 1: + yield negedge(clk) + self.assertEqual(SOF, SOF_v) + self.assertEqual(eval(hex(state)), eval(hex(state_v))) + # print "MyHDL: %s %s" % (SOF, hex(state)) + # print "Verilog: %s %s" % (SOF_v, hex(state_v)) + + return framerctrl, framerctrl_v, clkgen(), stimulus(), check() + + + def test(self): + tb_fsm = self.bench() + sim = Simulation(tb_fsm) + sim.run() + + +if __name__ == '__main__': + unittest.main()