1
0
mirror of https://github.com/myhdl/myhdl.git synced 2025-01-24 21:52:56 +08:00
This commit is contained in:
forumulator 2016-03-03 17:15:49 +05:30
commit 68302ecc6a
14 changed files with 124 additions and 44 deletions

View File

@ -9,13 +9,19 @@ python:
- "3.4" - "3.4"
- "3.5" - "3.5"
# binary install as per travis instructions
# used to install latest version of ghdl
before_script:
- ./scripts/install_ghdl.sh
- export PATH=$PATH:$PWD/ghdl-0.33/bin/
addons: addons:
apt: apt:
sources: # sources:
- pgavin-ghdl # - pgavin-ghdl
packages: packages:
- iverilog - iverilog
- ghdl # - ghdl
install: install:
- pip install . - pip install .

View File

@ -41,6 +41,14 @@ A :class:`Simulation` object has the following method:
Run the simulation forever (by default) or for a specified duration. Run the simulation forever (by default) or for a specified duration.
.. method:: Simulation.quit()
Quit the simulation after it has run for a specified duration. The method should
be called (the simulation instance must be quit) before another simulation
instance is created. The method is called by default when the simulation is run
forever.
.. _ref-simsupport: .. _ref-simsupport:
Simulation support functions Simulation support functions
@ -90,6 +98,11 @@ Waveform tracing
This attribute is used to set the directory to which VCD files are written. By This attribute is used to set the directory to which VCD files are written. By
default, the current working directory is used. default, the current working directory is used.
.. attribute:: filename
This attribute is used to set the filename to which VCD files are written. By
default, the name attribbute is used.
.. attribute:: timescale .. attribute:: timescale
This attribute is used to set the timescale corresponding to unit steps, This attribute is used to set the timescale corresponding to unit steps,

View File

@ -33,6 +33,7 @@ def simulate(timesteps):
tb = traceSignals(test_dff) tb = traceSignals(test_dff)
sim = Simulation(tb) sim = Simulation(tb)
sim.run(timesteps) sim.run(timesteps)
sim.quit()
simulate(2000) simulate(2000)

View File

@ -44,6 +44,7 @@ def simulate(timesteps):
tb = traceSignals(test_dffa) tb = traceSignals(test_dffa)
sim = Simulation(tb) sim = Simulation(tb)
sim.run(timesteps) sim.run(timesteps)
sim.quit()
simulate(20000) simulate(20000)

View File

@ -33,6 +33,7 @@ def simulate(timesteps):
tb = traceSignals(test_latch) tb = traceSignals(test_latch)
sim = Simulation(tb) sim = Simulation(tb)
sim.run(timesteps) sim.run(timesteps)
sim.quit()
simulate(20000) simulate(20000)

View File

@ -45,6 +45,7 @@ class _error:
_error.ArgType = "Inappriopriate argument type" _error.ArgType = "Inappriopriate argument type"
_error.MultipleCosim = "Only a single cosimulator argument allowed" _error.MultipleCosim = "Only a single cosimulator argument allowed"
_error.DuplicatedArg = "Duplicated argument" _error.DuplicatedArg = "Duplicated argument"
_error.MultipleSim = "Only a single Simulation instance is allowed"
class Simulation(object): class Simulation(object):
@ -54,6 +55,7 @@ class Simulation(object):
run -- run a simulation for some duration run -- run a simulation for some duration
""" """
_no_of_instances = 0
def __init__(self, *args): def __init__(self, *args):
""" Construct a simulation object. """ Construct a simulation object.
@ -65,13 +67,16 @@ class Simulation(object):
_simulator._time = 0 _simulator._time = 0
arglist = _flatten(*args) arglist = _flatten(*args)
self._waiters, self._cosim = _makeWaiters(arglist) self._waiters, self._cosim = _makeWaiters(arglist)
if Simulation._no_of_instances > 0:
raise SimulationError(_error.MultipleSim)
Simulation._no_of_instances += 1
if not self._cosim and _simulator._cosim: if not self._cosim and _simulator._cosim:
warn("Cosimulation not registered as Simulation argument") warn("Cosimulation not registered as Simulation argument")
self._finished = False self._finished = False
del _futureEvents[:] del _futureEvents[:]
del _siglist[:] del _siglist[:]
def _finalize(self): def _finalize(self):
cosim = self._cosim cosim = self._cosim
if cosim: if cosim:
@ -85,9 +90,12 @@ class Simulation(object):
# clean up for potential new run with same signals # clean up for potential new run with same signals
for s in _signals: for s in _signals:
s._clear() s._clear()
Simulation._no_of_instances = 0
self._finished = True self._finished = True
def quit(self):
self._finalize()
def runc(self, duration=0, quiet=0): def runc(self, duration=0, quiet=0):
simrunc.run(sim=self, duration=duration, quiet=quiet) simrunc.run(sim=self, duration=duration, quiet=quiet)
@ -201,7 +209,7 @@ class Simulation(object):
self._finalize() self._finalize()
# now reraise the exepction # now reraise the exepction
raise raise
def _makeWaiters(arglist): def _makeWaiters(arglist):
waiters = [] waiters = []
@ -231,4 +239,4 @@ def _makeWaiters(arglist):
if hasattr(sig, '_waiter'): if hasattr(sig, '_waiter'):
waiters.append(sig._waiter) waiters.append(sig._waiter)
return waiters, cosim return waiters, cosim

View File

@ -50,6 +50,7 @@ class _TraceSignalsClass(object):
__slot__ = ("name", __slot__ = ("name",
"directory", "directory",
"filename",
"timescale", "timescale",
"tracelists" "tracelists"
) )
@ -57,6 +58,7 @@ class _TraceSignalsClass(object):
def __init__(self): def __init__(self):
self.name = None self.name = None
self.directory = None self.directory = None
self.filename = None
self.timescale = "1ns" self.timescale = "1ns"
self.tracelists = True self.tracelists = True
@ -89,8 +91,13 @@ class _TraceSignalsClass(object):
else: else:
directory = self.directory directory = self.directory
if self.filename is None:
filename = name
else:
filename = str(self.filename)
h = _HierExtr(name, dut, *args, **kwargs) h = _HierExtr(name, dut, *args, **kwargs)
vcdpath = os.path.join(directory, name + ".vcd") vcdpath = os.path.join(directory, filename + ".vcd")
if path.exists(vcdpath): if path.exists(vcdpath):
backup = vcdpath + '.' + str(path.getmtime(vcdpath)) backup = vcdpath + '.' + str(path.getmtime(vcdpath))
shutil.copyfile(vcdpath, backup) shutil.copyfile(vcdpath, backup)

View File

@ -578,10 +578,14 @@ class _AnalyzeVisitor(ast.NodeVisitor, _ConversionMixin):
node.obj = int(0) # XXX node.obj = int(0) # XXX
elif f is bool: elif f is bool:
node.obj = bool() node.obj = bool()
elif f in _flatten(integer_types, ord): elif f in _flatten(integer_types):
node.obj = int(-1) node.obj = int(-1)
## elif f in (posedge , negedge): ## elif f in (posedge , negedge):
## node.obj = _EdgeDetector() ## node.obj = _EdgeDetector()
elif f is ord:
node.obj = int(-1)
if not (isinstance(node.args[0], ast.Str) and (len(node.args[0].s) == 1)):
self.raiseError(node, _error.NotSupported, "ord: expect string argument with length 1")
elif f is delay: elif f is delay:
node.obj = delay(0) node.obj = delay(0)
### suprize: identity comparison on unbound methods doesn't work in python 2.5?? ### suprize: identity comparison on unbound methods doesn't work in python 2.5??
@ -915,6 +919,8 @@ class _AnalyzeVisitor(ast.NodeVisitor, _ConversionMixin):
s = s[m.end():] s = s[m.end():]
continue continue
self.raiseError(node, _error.UnsupportedFormatString, "%s" % s) self.raiseError(node, _error.UnsupportedFormatString, "%s" % s)
elif isinstance(n, ast.Str):
f.append(n.s)
else: else:
f.append(defaultConvSpec) f.append(defaultConvSpec)
a.append(n) a.append(n)

View File

@ -602,9 +602,9 @@ class _ConvertVisitor(ast.NodeVisitor, _ConversionMixin):
pre, suf = "", "(0)" pre, suf = "", "(0)"
else: else:
pre, suf = "stdl(", ")" pre, suf = "stdl(", ")"
elif isinstance(vhd, vhd_string): # elif isinstance(vhd, vhd_string):
if isinstance(ori, vhd_enum): # if isinstance(ori, vhd_enum):
pre, suf = "%s'image(" % ori._type._name, ")" # pre, suf = "%s'image(" % ori._type._name, ")"
return pre, suf return pre, suf
@ -654,10 +654,6 @@ class _ConvertVisitor(ast.NodeVisitor, _ConversionMixin):
self.shiftOp(node) self.shiftOp(node)
elif isinstance(node.op, (ast.BitAnd, ast.BitOr, ast.BitXor)): elif isinstance(node.op, (ast.BitAnd, ast.BitOr, ast.BitXor)):
self.BitOp(node) self.BitOp(node)
elif isinstance(node.op, ast.Mod) and (self.context == _context.PRINT):
self.visit(node.left)
self.write(", ")
self.visit(node.right)
else: else:
self.BinOp(node) self.BinOp(node)
@ -953,11 +949,10 @@ class _ConvertVisitor(ast.NodeVisitor, _ConversionMixin):
return return
elif f is ord: elif f is ord:
opening, closing = '', '' opening, closing = '', ''
if isinstance(node.args[0], ast.Str): v = ord(node.args[0].s)
if len(node.args[0].s) > 1: node.args[0].s = v
self.raiseError(node, _error.UnsupportedType, "Strings with length > 1" ) self.write(v)
else: return
node.args[0].s = ord(node.args[0].s)
elif f in integer_types: elif f in integer_types:
opening, closing = '', '' opening, closing = '', ''
pre, suf = self.inferCast(node.vhd, node.vhdOri) pre, suf = self.inferCast(node.vhd, node.vhdOri)
@ -1361,15 +1356,9 @@ class _ConvertVisitor(ast.NodeVisitor, _ConversionMixin):
a.vhd = vhd_boolean() a.vhd = vhd_boolean()
elif isinstance(a.vhdOri, vhd_enum): elif isinstance(a.vhdOri, vhd_enum):
a.vhd = vhd_string() a.vhd = vhd_string()
self.write("write(L, ") self.write("write(L, to_string(")
self.context = _context.PRINT
self.visit(a) self.visit(a)
self.context = None self.write("))")
if s.justified == 'LEFT':
self.write(", justified=>LEFT")
if s.width:
self.write(", field=>%s" % s.width)
self.write(")")
self.write(';') self.write(';')
self.writeline() self.writeline()
self.write("writeline(output, L);") self.write("writeline(output, L);")

View File

@ -151,7 +151,7 @@ class _ToVerilogConvertor(object):
genlist = _analyzeGens(arglist, h.absnames) genlist = _analyzeGens(arglist, h.absnames)
siglist, memlist = _analyzeSigs(h.hierarchy) siglist, memlist = _analyzeSigs(h.hierarchy)
_annotateTypes(genlist) _annotateTypes(genlist)
intf = _analyzeTopFunc(func, *args, **kwargs) intf = _analyzeTopFunc(func, *args, **kwargs)
intf.name = name intf.name = name
doc = _makeDoc(inspect.getdoc(func)) doc = _makeDoc(inspect.getdoc(func))
@ -750,11 +750,7 @@ class _ConvertVisitor(ast.NodeVisitor, _ConversionMixin):
return return
elif f is ord: elif f is ord:
opening, closing = '', '' opening, closing = '', ''
if isinstance(node.args[0], ast.Str): node.args[0].s = str(ord(node.args[0].s))
if len(node.args[0].s) > 1:
self.raiseError(node, _error.UnsupportedType, "Strings with length > 1")
else:
node.args[0].s = str(ord(node.args[0].s))
elif f in integer_types: elif f in integer_types:
opening, closing = '', '' opening, closing = '', ''
# convert number argument to integer # convert number argument to integer

View File

@ -22,7 +22,7 @@ _simulators = {}
sim = namedtuple('sim', 'name hdl analyze elaborate simulate skiplines skipchars ignore') sim = namedtuple('sim', 'name hdl analyze elaborate simulate skiplines skipchars ignore')
def registerSimulator(name=None, hdl=None, analyze=None, elaborate=None, simulate=None, def registerSimulator(name=None, hdl=None, analyze=None, elaborate=None, simulate=None,
skiplines=None, skipchars=None, ignore=None): skiplines=None, skipchars=None, ignore=None):
if not isinstance(name, str) or (name.strip() == ""): if not isinstance(name, str) or (name.strip() == ""):
raise ValueError("Invalid simulator name") raise ValueError("Invalid simulator name")
@ -41,8 +41,8 @@ def registerSimulator(name=None, hdl=None, analyze=None, elaborate=None, simulat
registerSimulator( registerSimulator(
name="ghdl", name="ghdl",
hdl="VHDL", hdl="VHDL",
analyze="ghdl -a --workdir=work pck_myhdl_%(version)s.vhd %(topname)s.vhd", analyze="ghdl -a --std=08 --workdir=work pck_myhdl_%(version)s.vhd %(topname)s.vhd",
elaborate="ghdl -e --workdir=work -o %(unitname)s %(topname)s", elaborate="ghdl -e --std=08 --workdir=work %(unitname)s",
simulate="ghdl -r --workdir=work %(unitname)s" simulate="ghdl -r --workdir=work %(unitname)s"
) )
@ -96,7 +96,7 @@ class _VerificationClass(object):
__slots__ = ("simulator", "_analyzeOnly") __slots__ = ("simulator", "_analyzeOnly")
def __init__(self, analyzeOnly=False): def __init__(self, analyzeOnly=False):
self.simulator = None self.simulator = None
self._analyzeOnly = analyzeOnly self._analyzeOnly = analyzeOnly
@ -178,7 +178,7 @@ class _VerificationClass(object):
if ret != 0: if ret != 0:
print("Elaboration failed", file=sys.stderr) print("Elaboration failed", file=sys.stderr)
return ret return ret
g = tempfile.TemporaryFile(mode='w+t') g = tempfile.TemporaryFile(mode='w+t')
#print(simulate) #print(simulate)
ret = subprocess.call(simulate, stdout=g, shell=True) ret = subprocess.call(simulate, stdout=g, shell=True)

View File

@ -0,0 +1,43 @@
from __future__ import print_function
import pytest
from myhdl import Simulation, delay, SimulationError, instance, now
from myhdl._Simulation import _error
from helpers import raises_kind
def test():
@instance
def tbstim():
yield delay(10)
print("{0:<8d} ".format(now()))
yield delay(1000)
print("{0:<8d} ".format(now()))
for _ in range(10):
yield delay(1000)
return tbstim
def issue_104_quit_method():
sim = Simulation(test())
sim.run(1000)
sim.run(500)
sim.quit()
return sim._finished
def issue_104_multiple_instance():
sim1 = Simulation(test())
sim1.run(1000)
# sim1 is "puased"
# try and create a second, third, forth simulation instance
for ii in range(4):
with raises_kind(SimulationError, _error.MultipleSim):
another_sim = Simulation(test())
# generating more sims should have failed
sim1.run(1000)
sim1.quit()
def test_issue_104():
assert issue_104_quit_method() == True
issue_104_multiple_instance()

View File

@ -155,12 +155,16 @@ class TestTraceSigs:
assert not path.exists(psub) assert not path.exists(psub)
def testTristateTrace(self, vcd_dir): def testTristateTrace(self, vcd_dir):
Simulation(topTristate()).run(100, quiet=QUIET) sim = Simulation(topTristate())
sim.run(100, quiet=QUIET)
sim.quit()
def testBackupOutputFile(self, vcd_dir): def testBackupOutputFile(self, vcd_dir):
p = "%s.vcd" % fun.__name__ p = "%s.vcd" % fun.__name__
dut = traceSignals(fun) dut = traceSignals(fun)
Simulation(dut).run(1000, quiet=QUIET) sim = Simulation(dut)
sim.run(1000, quiet=QUIET)
sim.quit()
_simulator._tf.close() _simulator._tf.close()
_simulator._tracing = 0 _simulator._tracing = 0
size = path.getsize(p) size = path.getsize(p)

5
scripts/install_ghdl.sh Executable file
View File

@ -0,0 +1,5 @@
#!/bin/bash
set -evx
wget https://sourceforge.net/projects/ghdl-updates/files/Builds/ghdl-0.33/ghdl-0.33-x86_64-linux.tgz -O /tmp/ghdl.tar.gz
mkdir ghdl-0.33
tar -C ghdl-0.33 -xvf /tmp/ghdl.tar.gz