mirror of
https://github.com/myhdl/myhdl.git
synced 2024-12-14 07:44:38 +08:00
fsm test
This commit is contained in:
parent
418d9ec490
commit
3f6fb7d34d
@ -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()
|
||||
|
@ -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):
|
||||
|
@ -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
|
||||
|
@ -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)) == "<class 'myhdl._enum.Enum'>":
|
||||
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)
|
||||
|
||||
|
||||
|
131
myhdl/test/toVerilog/test_fsm.py
Normal file
131
myhdl/test/toVerilog/test_fsm.py
Normal file
@ -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()
|
Loading…
x
Reference in New Issue
Block a user