gen/build: merge with migen 0575c749e35a7180f0dca408e426af8eef22b568 and reintegrate migen simulator
* fhdl/visit: determinism * structure/Case/makedefault: fix corner cases * fhdl/tools: apply lowerer to specials in deterministic order * fhdl/verilog: fix variable name conflict * fhdl/verilog: simpler names for IOs. Closes #40 * fhdl/namer: deterministic naming of signals with name_override * use https url for m-labs.hk * pipistrello: make PMOD an extension header * vivado: find clock nets by get_nets, not get_ports * build: support platform-independent false path designation * sim: add more signals to VCD (#36) * build/xilinx: fix error message when Xilinx toolchain directory exists but does not contain a ISE version directory. Closes #39 * kc705: make xadc an extension header * kc705: add xadc/ams gpios * Merge branch 'master' of github.com:m-labs/migen * conda: fix for conda-build > 1.19 * platforms/kc705: enable on-die termination for user_sma_clock * README: update * Revert "conda: use BUILDNUMBER from environment." This reverts commit b2eedfd2e24f0b83c2fb118a3f98cf349b256e91. * conda: use BUILDNUMBER from environment. * typo * Exception now has helpful string. * README: remove outdated build badge * sim: run MemoryToArray before lowering specials * fhdl/simplify/MemoryToArray: remove spurious memory ports from specials * sim: make unlowered specials an error * sim: lower specials, closes #34 * sim: support evaluating Replicate() * Revert "README.md->rst" * Prevent backslashes in (Windows) paths from being escaped by OpenOCD's TCL implementation. * Revert "conda: run tests as a part of package build." * Revert "setuptools: include examples as migen.examples." * Revert "test: also look for examples in [.../dist-packages]/migen/examples/." * conda: use source from the current checkout. * travis: disable (superseded by our buildbot). * test: also look for examples in [.../dist-packages]/migen/examples/. * setuptools: include examples as migen.examples. * conda: run tests as a part of package build. * build: return to current working directory after building * sim/vcd: support signals not appearing in FHDL * sim: deterministic clock iteration * sim: add support for passive generators * fhdl/structure: fix last test in _Value.__bool__ (a instead of b)
This commit is contained in:
parent
71a719be44
commit
703b30e078
|
@ -168,7 +168,7 @@ class ConstraintManager:
|
|||
if isinstance(rt, int):
|
||||
obj = Signal(rt, name_override=resource_name)
|
||||
else:
|
||||
obj = Record(rt, name=resource_name, use_name_override=True)
|
||||
obj = Record(rt, name=resource_name)
|
||||
|
||||
for element in resource[2:]:
|
||||
if isinstance(element, PlatformInfo):
|
||||
|
@ -253,6 +253,15 @@ class GenericPlatform:
|
|||
def add_period_constraint(self, clk, period):
|
||||
raise NotImplementedError
|
||||
|
||||
def add_false_path_constraint(self, from_, to):
|
||||
raise NotImplementedError
|
||||
|
||||
def add_false_path_constraints(self, *clk):
|
||||
for a in clk:
|
||||
for b in clk:
|
||||
if a is not b:
|
||||
self.add_false_path_constraint(a, b)
|
||||
|
||||
def add_platform_command(self, *args, **kwargs):
|
||||
return self.constraint_manager.add_platform_command(*args, **kwargs)
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ class OpenOCD(GenericProgrammer):
|
|||
def load_bitstream(self, bitstream):
|
||||
script = "; ".join([
|
||||
"init",
|
||||
"pld load 0 {}".format(bitstream),
|
||||
"pld load 0 {{{}}}".format(bitstream),
|
||||
"exit",
|
||||
])
|
||||
subprocess.call(["openocd", "-f", self.config, "-c", script])
|
||||
|
@ -22,8 +22,8 @@ class OpenOCD(GenericProgrammer):
|
|||
flash_proxy = self.find_flash_proxy()
|
||||
script = "; ".join([
|
||||
"init",
|
||||
"jtagspi_init 0 {}".format(flash_proxy),
|
||||
"jtagspi_program {} 0x{:x}".format(data, address),
|
||||
"jtagspi_init 0 {{{}}}".format(flash_proxy),
|
||||
"jtagspi_program {{{}}} 0x{:x}".format(data, address),
|
||||
"fpga_program",
|
||||
"exit"
|
||||
])
|
||||
|
|
|
@ -14,12 +14,12 @@ from litex.build import tools
|
|||
|
||||
|
||||
def settings(path, ver=None, sub=None):
|
||||
vers = list(tools.versions(path))
|
||||
if ver is None:
|
||||
vers = list(tools.versions(path))
|
||||
if not vers:
|
||||
raise OSError("no version directory for Xilinx tools found in "
|
||||
+ path)
|
||||
ver = max(vers)
|
||||
else:
|
||||
ver = StrictVersion(ver)
|
||||
assert ver in vers
|
||||
|
||||
full = os.path.join(path, str(ver))
|
||||
if sub:
|
||||
|
@ -39,7 +39,7 @@ def settings(path, ver=None, sub=None):
|
|||
if os.path.exists(settings):
|
||||
return settings
|
||||
|
||||
raise OSError("no settings file found")
|
||||
raise OSError("no Xilinx tools settings file found")
|
||||
|
||||
|
||||
class XilinxNoRetimingVivadoImpl(Module):
|
||||
|
|
|
@ -181,4 +181,10 @@ class XilinxISEToolchain:
|
|||
|
||||
def add_period_constraint(self, platform, clk, period):
|
||||
platform.add_platform_command("""NET "{clk}" TNM_NET = "GRP{clk}";
|
||||
TIMESPEC "TS{clk}" = PERIOD "GRP{clk}" """+str(period)+""" ns HIGH 50%;""", clk=clk)
|
||||
TIMESPEC "TS{clk}" = PERIOD "GRP{clk}" """ + str(period) + """ ns HIGH 50%;""",
|
||||
clk=clk)
|
||||
|
||||
def add_false_path_constraint(self, platform, from_, to):
|
||||
platform.add_platform_command(
|
||||
"""TIMESPEC "TS{from_}TO{to}" = FROM "GRP{from_}" TO "GRP{to}" TIG;""",
|
||||
from_=from_, to=to)
|
||||
|
|
|
@ -32,3 +32,10 @@ class XilinxPlatform(GenericPlatform):
|
|||
if hasattr(clk, "p"):
|
||||
clk = clk.p
|
||||
self.toolchain.add_period_constraint(self, clk, period)
|
||||
|
||||
def add_false_path_constraint(self, from_, to):
|
||||
if hasattr(from_, "p"):
|
||||
from_ = from_.p
|
||||
if hasattr(to, "p"):
|
||||
to = to.p
|
||||
self.toolchain.add_false_path_constraint(self, from_, to)
|
||||
|
|
|
@ -135,5 +135,11 @@ class XilinxVivadoToolchain:
|
|||
return v_output.ns
|
||||
|
||||
def add_period_constraint(self, platform, clk, period):
|
||||
platform.add_platform_command("""create_clock -name {clk} -period """ + \
|
||||
str(period) + """ [get_ports {clk}]""", clk=clk)
|
||||
platform.add_platform_command(
|
||||
"create_clock -name {clk} -period " + str(period) +
|
||||
" [get_nets {clk}]", clk=clk)
|
||||
|
||||
def add_false_path_constraint(self, platform, from_, to):
|
||||
platform.add_platform_command(
|
||||
"set_false_path -from [get_clocks {from_}] -to [get_clocks {to}]",
|
||||
from_=from_, to=to)
|
||||
|
|
|
@ -4,5 +4,7 @@ from litex.gen.fhdl.specials import *
|
|||
from litex.gen.fhdl.bitcontainer import *
|
||||
from litex.gen.fhdl.decorators import *
|
||||
|
||||
from litex.gen.sim import *
|
||||
|
||||
from litex.gen.genlib.record import *
|
||||
from litex.gen.genlib.fsm import *
|
||||
|
|
|
@ -5,7 +5,7 @@ from litex.gen.util.misc import flat_iteration
|
|||
from litex.gen.fhdl.structure import *
|
||||
from litex.gen.fhdl.structure import _Fragment
|
||||
from litex.gen.fhdl.tools import rename_clock_domain
|
||||
from litex.gen.sim.upper import gen_sim, proxy_sim
|
||||
|
||||
|
||||
__all__ = ["Module", "FinalizeError"]
|
||||
|
||||
|
@ -120,20 +120,7 @@ class Module:
|
|||
self.finalized = False
|
||||
return self.finalized
|
||||
elif name == "_fragment":
|
||||
simf = None
|
||||
try:
|
||||
simf = self.do_simulation
|
||||
except AttributeError:
|
||||
try:
|
||||
simg = self.gen_simulation
|
||||
except AttributeError:
|
||||
pass
|
||||
else:
|
||||
simf = gen_sim(simg)
|
||||
if simf is not None:
|
||||
simf = proxy_sim(self, simf)
|
||||
sim = [] if simf is None else [simf]
|
||||
self._fragment = _Fragment(sim=sim)
|
||||
self._fragment = _Fragment()
|
||||
return self._fragment
|
||||
elif name == "_submodules":
|
||||
self._submodules = []
|
||||
|
|
|
@ -217,8 +217,8 @@ def build_namespace(signals, reserved_keywords=set()):
|
|||
pnd = _build_pnd(signals)
|
||||
ns = Namespace(pnd, reserved_keywords)
|
||||
# register signals with name_override
|
||||
for signal in signals:
|
||||
if signal.name_override is not None:
|
||||
swno = {signal for signal in signals if signal.name_override is not None}
|
||||
for signal in sorted(swno, key=lambda x: x.duid):
|
||||
ns.get_name(signal)
|
||||
return ns
|
||||
|
||||
|
|
|
@ -55,6 +55,7 @@ class MemoryToArray(ModuleTransformer):
|
|||
|
||||
def transform_fragment(self, i, f):
|
||||
newspecials = set()
|
||||
processed_ports = set()
|
||||
|
||||
for mem in f.specials:
|
||||
if not isinstance(mem, Memory):
|
||||
|
@ -111,4 +112,7 @@ class MemoryToArray(ModuleTransformer):
|
|||
sync.append(If(port.we,
|
||||
storage[port.adr].eq(port.dat_w)))
|
||||
|
||||
processed_ports.add(port)
|
||||
|
||||
newspecials -= processed_ports
|
||||
f.specials = newspecials
|
||||
|
|
|
@ -34,7 +34,7 @@ class _Value(DUID):
|
|||
if isinstance(a, Signal) and isinstance(b, Signal):
|
||||
return a is b
|
||||
if (isinstance(a, Constant) and isinstance(b, Signal)
|
||||
or isinstance(a, Signal) and isinstance(a, Constant)):
|
||||
or isinstance(a, Signal) and isinstance(b, Constant)):
|
||||
return False
|
||||
raise TypeError("Attempted to convert Migen value to boolean")
|
||||
|
||||
|
@ -107,7 +107,8 @@ class _Value(DUID):
|
|||
return Cat(self[i] for i in range(start, stop, step))
|
||||
return _Slice(self, start, stop)
|
||||
else:
|
||||
raise TypeError
|
||||
raise TypeError("Cannot use type {} ({}) as key".format(
|
||||
type(key), repr(key)))
|
||||
|
||||
def eq(self, r):
|
||||
"""Assignment
|
||||
|
@ -542,16 +543,21 @@ class Case(_Statement):
|
|||
|
||||
Parameters
|
||||
----------
|
||||
key : int or None
|
||||
key : int, Constant or None
|
||||
Key to use as default case if no other key matches.
|
||||
By default, the largest key is the default key.
|
||||
"""
|
||||
if key is None:
|
||||
for choice in self.cases.keys():
|
||||
if key is None or choice.value > key.value:
|
||||
if (key is None
|
||||
or (isinstance(choice, str) and choice == "default")
|
||||
or choice.value > key.value):
|
||||
key = choice
|
||||
self.cases["default"] = self.cases[key]
|
||||
if not isinstance(key, str) or key != "default":
|
||||
key = wrap(key)
|
||||
stmts = self.cases[key]
|
||||
del self.cases[key]
|
||||
self.cases["default"] = stmts
|
||||
return self
|
||||
|
||||
|
||||
|
@ -679,23 +685,17 @@ class _ClockDomainList(list):
|
|||
(SPECIAL_INPUT, SPECIAL_OUTPUT, SPECIAL_INOUT) = range(3)
|
||||
|
||||
|
||||
class StopSimulation(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class _Fragment:
|
||||
def __init__(self, comb=None, sync=None, specials=None, clock_domains=None, sim=None):
|
||||
def __init__(self, comb=None, sync=None, specials=None, clock_domains=None):
|
||||
if comb is None: comb = []
|
||||
if sync is None: sync = dict()
|
||||
if specials is None: specials = set()
|
||||
if clock_domains is None: clock_domains = _ClockDomainList()
|
||||
if sim is None: sim = []
|
||||
|
||||
self.comb = comb
|
||||
self.sync = sync
|
||||
self.specials = specials
|
||||
self.clock_domains = _ClockDomainList(clock_domains)
|
||||
self.sim = sim
|
||||
|
||||
def __add__(self, other):
|
||||
newsync = _collections.defaultdict(list)
|
||||
|
@ -705,8 +705,7 @@ class _Fragment:
|
|||
newsync[k].extend(v)
|
||||
return _Fragment(self.comb + other.comb, newsync,
|
||||
self.specials | other.specials,
|
||||
self.clock_domains + other.clock_domains,
|
||||
self.sim + other.sim)
|
||||
self.clock_domains + other.clock_domains)
|
||||
|
||||
def __iadd__(self, other):
|
||||
newsync = _collections.defaultdict(list)
|
||||
|
@ -718,5 +717,4 @@ class _Fragment:
|
|||
self.sync = newsync
|
||||
self.specials |= other.specials
|
||||
self.clock_domains += other.clock_domains
|
||||
self.sim += other.sim
|
||||
return self
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
from litex.gen.fhdl.structure import *
|
||||
from litex.gen.fhdl.structure import _Slice, _Assign
|
||||
from litex.gen.fhdl.structure import _Slice, _Assign, _Fragment
|
||||
from litex.gen.fhdl.visit import NodeVisitor, NodeTransformer
|
||||
from litex.gen.fhdl.bitcontainer import value_bits_sign
|
||||
from litex.gen.util.misc import flat_iteration
|
||||
|
@ -236,7 +236,7 @@ def _apply_lowerer(l, f):
|
|||
f = l.visit(f)
|
||||
f.comb += l.comb
|
||||
|
||||
for special in f.specials:
|
||||
for special in sorted(f.specials, key=lambda s: s.duid):
|
||||
for obj, attr, direction in special.iter_expressions():
|
||||
if direction != SPECIAL_INOUT:
|
||||
# inouts are only supported by Migen when connected directly to top-level
|
||||
|
@ -296,3 +296,44 @@ def rename_clock_domain(f, old, new):
|
|||
pass
|
||||
else:
|
||||
cd.rename(new)
|
||||
|
||||
|
||||
def call_special_classmethod(overrides, obj, method, *args, **kwargs):
|
||||
cl = obj.__class__
|
||||
if cl in overrides:
|
||||
cl = overrides[cl]
|
||||
if hasattr(cl, method):
|
||||
return getattr(cl, method)(obj, *args, **kwargs)
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
def _lower_specials_step(overrides, specials):
|
||||
f = _Fragment()
|
||||
lowered_specials = set()
|
||||
for special in sorted(specials, key=lambda x: x.duid):
|
||||
impl = call_special_classmethod(overrides, special, "lower")
|
||||
if impl is not None:
|
||||
f += impl.get_fragment()
|
||||
lowered_specials.add(special)
|
||||
return f, lowered_specials
|
||||
|
||||
|
||||
def _can_lower(overrides, specials):
|
||||
for special in specials:
|
||||
cl = special.__class__
|
||||
if cl in overrides:
|
||||
cl = overrides[cl]
|
||||
if hasattr(cl, "lower"):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def lower_specials(overrides, specials):
|
||||
f, lowered_specials = _lower_specials_step(overrides, specials)
|
||||
while _can_lower(overrides, f.specials):
|
||||
f2, lowered_specials2 = _lower_specials_step(overrides, f.specials)
|
||||
f += f2
|
||||
lowered_specials |= lowered_specials2
|
||||
f.specials -= lowered_specials2
|
||||
return f, lowered_specials
|
||||
|
|
|
@ -5,11 +5,9 @@ import collections
|
|||
from litex.gen.fhdl.structure import *
|
||||
from litex.gen.fhdl.structure import _Operator, _Slice, _Assign, _Fragment
|
||||
from litex.gen.fhdl.tools import *
|
||||
from litex.gen.fhdl.bitcontainer import bits_for
|
||||
from litex.gen.fhdl.namer import build_namespace
|
||||
from litex.gen.fhdl.conv_output import ConvOutput
|
||||
|
||||
# TODO: remove printcomb_simulation when we will be using new migen simulator
|
||||
|
||||
_reserved_keywords = {
|
||||
"always", "and", "assign", "automatic", "begin", "buf", "bufif0", "bufif1",
|
||||
|
@ -117,11 +115,9 @@ def _printexpr(ns, node):
|
|||
(_AT_BLOCKING, _AT_NONBLOCKING, _AT_SIGNAL) = range(3)
|
||||
|
||||
|
||||
def _printnode(ns, at, level, node, target_filter=None):
|
||||
def _printnode(ns, at, level, node):
|
||||
if node is None:
|
||||
return ""
|
||||
elif target_filter is not None and target_filter not in list_targets(node):
|
||||
return ""
|
||||
elif isinstance(node, _Assign):
|
||||
if at == _AT_BLOCKING:
|
||||
assignment = " = "
|
||||
|
@ -133,13 +129,13 @@ def _printnode(ns, at, level, node, target_filter=None):
|
|||
assignment = " <= "
|
||||
return "\t"*level + _printexpr(ns, node.l)[0] + assignment + _printexpr(ns, node.r)[0] + ";\n"
|
||||
elif isinstance(node, collections.Iterable):
|
||||
return "".join(_printnode(ns, at, level, n, target_filter) for n in node)
|
||||
return "".join(list(map(partial(_printnode, ns, at, level), node)))
|
||||
elif isinstance(node, If):
|
||||
r = "\t"*level + "if (" + _printexpr(ns, node.cond)[0] + ") begin\n"
|
||||
r += _printnode(ns, at, level + 1, node.t, target_filter)
|
||||
r += _printnode(ns, at, level + 1, node.t)
|
||||
if node.f:
|
||||
r += "\t"*level + "end else begin\n"
|
||||
r += _printnode(ns, at, level + 1, node.f, target_filter)
|
||||
r += _printnode(ns, at, level + 1, node.f)
|
||||
r += "\t"*level + "end\n"
|
||||
return r
|
||||
elif isinstance(node, Case):
|
||||
|
@ -149,11 +145,11 @@ def _printnode(ns, at, level, node, target_filter=None):
|
|||
css = sorted(css, key=lambda x: x[0].value)
|
||||
for choice, statements in css:
|
||||
r += "\t"*(level + 1) + _printexpr(ns, choice)[0] + ": begin\n"
|
||||
r += _printnode(ns, at, level + 2, statements, target_filter)
|
||||
r += _printnode(ns, at, level + 2, statements)
|
||||
r += "\t"*(level + 1) + "end\n"
|
||||
if "default" in node.cases:
|
||||
r += "\t"*(level + 1) + "default: begin\n"
|
||||
r += _printnode(ns, at, level + 2, node.cases["default"], target_filter)
|
||||
r += _printnode(ns, at, level + 2, node.cases["default"])
|
||||
r += "\t"*(level + 1) + "end\n"
|
||||
r += "\t"*level + "endcase\n"
|
||||
return r
|
||||
|
@ -196,21 +192,18 @@ def _printheader(f, ios, name, ns,
|
|||
r += "\tinput " + _printsig(ns, sig)
|
||||
r += "\n);\n\n"
|
||||
for sig in sorted(sigs - ios, key=lambda x: x.duid):
|
||||
attributes = ""
|
||||
if sig.attribute != "":
|
||||
attributes = "(*" + sig.attribute[:-1] + "*) "
|
||||
if sig in wires:
|
||||
r += attributes + "wire " + _printsig(ns, sig) + ";\n"
|
||||
r += "wire " + _printsig(ns, sig) + ";\n"
|
||||
else:
|
||||
if reg_initialization:
|
||||
r += attributes + "reg " + _printsig(ns, sig) + " = " + _printexpr(ns, sig.reset)[0] + ";\n"
|
||||
r += "reg " + _printsig(ns, sig) + " = " + _printexpr(ns, sig.reset)[0] + ";\n"
|
||||
else:
|
||||
r += attributes + "reg " + _printsig(ns, sig) + ";\n"
|
||||
r += "reg " + _printsig(ns, sig) + ";\n"
|
||||
r += "\n"
|
||||
return r
|
||||
|
||||
|
||||
def _printcomb_simulation(f, ns,
|
||||
def _printcomb(f, ns,
|
||||
display_run,
|
||||
dummy_signal,
|
||||
blocking_assign):
|
||||
|
@ -227,22 +220,11 @@ def _printcomb_simulation(f, ns,
|
|||
r += "initial " + ns.get_name(dummy_s) + " <= 1'd0;\n"
|
||||
r += syn_on
|
||||
|
||||
|
||||
from collections import defaultdict
|
||||
|
||||
target_stmt_map = defaultdict(list)
|
||||
|
||||
for statement in flat_iteration(f.comb):
|
||||
targets = list_targets(statement)
|
||||
for t in targets:
|
||||
target_stmt_map[t].append(statement)
|
||||
|
||||
groups = group_by_targets(f.comb)
|
||||
|
||||
for n, (t, stmts) in enumerate(target_stmt_map.items()):
|
||||
assert isinstance(t, Signal)
|
||||
if len(stmts) == 1 and isinstance(stmts[0], _Assign):
|
||||
r += "assign " + _printnode(ns, _AT_BLOCKING, 0, stmts[0])
|
||||
for n, g in enumerate(groups):
|
||||
if len(g[1]) == 1 and isinstance(g[1][0], _Assign):
|
||||
r += "assign " + _printnode(ns, _AT_BLOCKING, 0, g[1][0])
|
||||
else:
|
||||
if dummy_signal:
|
||||
dummy_d = Signal(name_override="dummy_d")
|
||||
|
@ -253,31 +235,6 @@ def _printcomb_simulation(f, ns,
|
|||
r += "always @(*) begin\n"
|
||||
if display_run:
|
||||
r += "\t$display(\"Running comb block #" + str(n) + "\");\n"
|
||||
if blocking_assign:
|
||||
r += "\t" + ns.get_name(t) + " = " + _printexpr(ns, t.reset)[0] + ";\n"
|
||||
r += _printnode(ns, _AT_BLOCKING, 1, stmts, t)
|
||||
else:
|
||||
r += "\t" + ns.get_name(t) + " <= " + _printexpr(ns, t.reset)[0] + ";\n"
|
||||
r += _printnode(ns, _AT_NONBLOCKING, 1, stmts, t)
|
||||
if dummy_signal:
|
||||
r += syn_off
|
||||
r += "\t" + ns.get_name(dummy_d) + " = " + ns.get_name(dummy_s) + ";\n"
|
||||
r += syn_on
|
||||
r += "end\n"
|
||||
r += "\n"
|
||||
return r
|
||||
|
||||
|
||||
def _printcomb_regular(f, ns, blocking_assign):
|
||||
r = ""
|
||||
if f.comb:
|
||||
groups = group_by_targets(f.comb)
|
||||
|
||||
for n, g in enumerate(groups):
|
||||
if len(g[1]) == 1 and isinstance(g[1][0], _Assign):
|
||||
r += "assign " + _printnode(ns, _AT_BLOCKING, 0, g[1][0])
|
||||
else:
|
||||
r += "always @(*) begin\n"
|
||||
if blocking_assign:
|
||||
for t in g[0]:
|
||||
r += "\t" + ns.get_name(t) + " = " + _printexpr(ns, t.reset)[0] + ";\n"
|
||||
|
@ -286,12 +243,15 @@ def _printcomb_regular(f, ns, blocking_assign):
|
|||
for t in g[0]:
|
||||
r += "\t" + ns.get_name(t) + " <= " + _printexpr(ns, t.reset)[0] + ";\n"
|
||||
r += _printnode(ns, _AT_NONBLOCKING, 1, g[1])
|
||||
if dummy_signal:
|
||||
r += syn_off
|
||||
r += "\t" + ns.get_name(dummy_d) + " <= " + ns.get_name(dummy_s) + ";\n"
|
||||
r += syn_on
|
||||
r += "end\n"
|
||||
r += "\n"
|
||||
return r
|
||||
|
||||
|
||||
|
||||
def _printsync(f, ns):
|
||||
r = ""
|
||||
for k, v in sorted(f.sync.items(), key=itemgetter(0)):
|
||||
|
@ -301,51 +261,10 @@ def _printsync(f, ns):
|
|||
return r
|
||||
|
||||
|
||||
def _call_special_classmethod(overrides, obj, method, *args, **kwargs):
|
||||
cl = obj.__class__
|
||||
if cl in overrides:
|
||||
cl = overrides[cl]
|
||||
if hasattr(cl, method):
|
||||
return getattr(cl, method)(obj, *args, **kwargs)
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
def _lower_specials_step(overrides, specials):
|
||||
f = _Fragment()
|
||||
lowered_specials = set()
|
||||
for special in sorted(specials, key=lambda x: x.duid):
|
||||
impl = _call_special_classmethod(overrides, special, "lower")
|
||||
if impl is not None:
|
||||
f += impl.get_fragment()
|
||||
lowered_specials.add(special)
|
||||
return f, lowered_specials
|
||||
|
||||
|
||||
def _can_lower(overrides, specials):
|
||||
for special in specials:
|
||||
cl = special.__class__
|
||||
if cl in overrides:
|
||||
cl = overrides[cl]
|
||||
if hasattr(cl, "lower"):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def _lower_specials(overrides, specials):
|
||||
f, lowered_specials = _lower_specials_step(overrides, specials)
|
||||
while _can_lower(overrides, f.specials):
|
||||
f2, lowered_specials2 = _lower_specials_step(overrides, f.specials)
|
||||
f += f2
|
||||
lowered_specials |= lowered_specials2
|
||||
f.specials -= lowered_specials2
|
||||
return f, lowered_specials
|
||||
|
||||
|
||||
def _printspecials(overrides, specials, ns, add_data_file):
|
||||
r = ""
|
||||
for special in sorted(specials, key=lambda x: x.duid):
|
||||
pr = _call_special_classmethod(overrides, special, "emit_verilog", ns, add_data_file)
|
||||
pr = call_special_classmethod(overrides, special, "emit_verilog", ns, add_data_file)
|
||||
if pr is None:
|
||||
raise NotImplementedError("Special " + str(special) + " failed to implement emit_verilog")
|
||||
r += pr
|
||||
|
@ -380,25 +299,24 @@ def convert(f, ios=None, name="top",
|
|||
f = lower_complex_slices(f)
|
||||
insert_resets(f)
|
||||
f = lower_basics(f)
|
||||
fs, lowered_specials = _lower_specials(special_overrides, f.specials)
|
||||
fs, lowered_specials = lower_specials(special_overrides, f.specials)
|
||||
f += lower_basics(fs)
|
||||
|
||||
for io in sorted(ios, key=lambda x: x.duid):
|
||||
if io.name_override is None:
|
||||
io_name = io.backtrace[-1][0]
|
||||
if io_name:
|
||||
io.name_override = io_name
|
||||
ns = build_namespace(list_signals(f) \
|
||||
| list_special_ios(f, True, True, True) \
|
||||
| ios, _reserved_keywords)
|
||||
ns.clock_domains = f.clock_domains
|
||||
r.ns = ns
|
||||
|
||||
src = "/* Machine-generated using LiteX gen "
|
||||
src += "(regular)" if regular_comb else "(simulation)"
|
||||
src += " */\n"
|
||||
src = "/* Machine-generated using LiteX gen */\n"
|
||||
src += _printheader(f, ios, name, ns,
|
||||
reg_initialization=reg_initialization)
|
||||
if regular_comb:
|
||||
src += _printcomb_regular(f, ns,
|
||||
blocking_assign=blocking_assign)
|
||||
else:
|
||||
src += _printcomb_simulation(f, ns,
|
||||
src += _printcomb(f, ns,
|
||||
display_run=display_run,
|
||||
dummy_signal=dummy_signal,
|
||||
blocking_assign=blocking_assign)
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
from copy import copy
|
||||
from operator import itemgetter
|
||||
|
||||
from litex.gen.fhdl.structure import *
|
||||
from litex.gen.fhdl.structure import (_Operator, _Slice, _Assign, _ArrayProxy,
|
||||
|
@ -77,7 +78,8 @@ class NodeVisitor:
|
|||
|
||||
def visit_Case(self, node):
|
||||
self.visit(node.test)
|
||||
for v, statements in node.cases.items():
|
||||
for v, statements in sorted(node.cases.items(),
|
||||
key=lambda x: str(x[0])):
|
||||
self.visit(statements)
|
||||
|
||||
def visit_Fragment(self, node):
|
||||
|
@ -89,7 +91,7 @@ class NodeVisitor:
|
|||
self.visit(statement)
|
||||
|
||||
def visit_clock_domains(self, node):
|
||||
for clockname, statements in node.items():
|
||||
for clockname, statements in sorted(node.items(), key=itemgetter(0)):
|
||||
self.visit(statements)
|
||||
|
||||
def visit_ArrayProxy(self, node):
|
||||
|
@ -177,7 +179,9 @@ class NodeTransformer:
|
|||
return r
|
||||
|
||||
def visit_Case(self, node):
|
||||
cases = dict((v, self.visit(statements)) for v, statements in node.cases.items())
|
||||
cases = {v: self.visit(statements)
|
||||
for v, statements in sorted(node.cases.items(),
|
||||
key=lambda x: str(x[0]))}
|
||||
r = Case(self.visit(node.test), cases)
|
||||
return r
|
||||
|
||||
|
@ -192,7 +196,9 @@ class NodeTransformer:
|
|||
return [self.visit(statement) for statement in node]
|
||||
|
||||
def visit_clock_domains(self, node):
|
||||
return dict((clockname, self.visit(statements)) for clockname, statements in node.items())
|
||||
return {clockname: self.visit(statements)
|
||||
for clockname, statements in sorted(node.items(),
|
||||
key=itemgetter(0))}
|
||||
|
||||
def visit_ArrayProxy(self, node):
|
||||
return _ArrayProxy([self.visit(choice) for choice in node.choices],
|
||||
|
|
|
@ -86,7 +86,7 @@ def layout_partial(layout, *elements):
|
|||
|
||||
|
||||
class Record:
|
||||
def __init__(self, layout, name=None, use_name_override=False):
|
||||
def __init__(self, layout, name=None):
|
||||
self.name = get_obj_var_name(name, "")
|
||||
self.layout = layout
|
||||
|
||||
|
@ -100,9 +100,6 @@ class Record:
|
|||
fname, fsize, fdirection = f
|
||||
else:
|
||||
fname, fsize = f
|
||||
if use_name_override:
|
||||
finst = Signal(fsize, name_override=prefix + fname)
|
||||
else:
|
||||
finst = Signal(fsize, name=prefix + fname)
|
||||
elif isinstance(f[1], list): # case 3
|
||||
fname, fsublayout = f
|
||||
|
|
|
@ -12,7 +12,7 @@ class BitonicSort(Module):
|
|||
|
||||
http://www.dps.uibk.ac.at/~cosenza/teaching/gpu/sort-batcher.pdf
|
||||
|
||||
http://www.inf.fh-lensburg.de/lang/algorithmen/sortieren/bitonic/bitonicen.htm
|
||||
http://www.inf.fh-flensburg.de/lang/algorithmen/sortieren/bitonic/bitonicen.htm
|
||||
|
||||
http://www.myhdl.org/doku.php/cookbook:bitonic
|
||||
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
from litex.gen.sim.core import Simulator, run_simulation, passive
|
|
@ -1,231 +0,0 @@
|
|||
import warnings
|
||||
import sys
|
||||
|
||||
from litex.gen import *
|
||||
from litex.gen.fhdl.structure import _Fragment
|
||||
|
||||
from litex.gen.fhdl import verilog
|
||||
from litex.gen.sim.ipc import *
|
||||
from litex.gen.sim import icarus
|
||||
|
||||
|
||||
class TopLevel:
|
||||
def __init__(self, vcd_name=None, vcd_level=1,
|
||||
top_name="top", dut_type="dut", dut_name="dut",
|
||||
cd_name="sys", clk_period=10):
|
||||
self.vcd_name = vcd_name
|
||||
self.vcd_level = vcd_level
|
||||
self.top_name = top_name
|
||||
self.dut_type = dut_type
|
||||
self.dut_name = dut_name
|
||||
|
||||
self._cd_name = cd_name
|
||||
self._clk_period = clk_period
|
||||
|
||||
cd = ClockDomain(self._cd_name)
|
||||
self.clock_domains = [cd]
|
||||
self.ios = {cd.clk, cd.rst}
|
||||
|
||||
def get(self, sockaddr):
|
||||
if sys.platform == "win32":
|
||||
sockaddr = sockaddr[0] # Get the IP address only
|
||||
|
||||
template1 = """`timescale 1ns / 1ps
|
||||
|
||||
module {top_name}();
|
||||
|
||||
reg {clk_name};
|
||||
reg {rst_name};
|
||||
|
||||
initial begin
|
||||
{rst_name} <= 1'b1;
|
||||
@(posedge {clk_name});
|
||||
{rst_name} <= 1'b0;
|
||||
end
|
||||
|
||||
always begin
|
||||
{clk_name} <= 1'b0;
|
||||
#{hclk_period};
|
||||
{clk_name} <= 1'b1;
|
||||
#{hclk_period};
|
||||
end
|
||||
|
||||
{dut_type} {dut_name}(
|
||||
.{rst_name}({rst_name}),
|
||||
.{clk_name}({clk_name})
|
||||
);
|
||||
|
||||
initial $migensim_connect("{sockaddr}");
|
||||
always @(posedge {clk_name}) $migensim_tick;
|
||||
"""
|
||||
template2 = """
|
||||
initial begin
|
||||
$dumpfile("{vcd_name}");
|
||||
$dumpvars({vcd_level}, {dut_name});
|
||||
end
|
||||
"""
|
||||
r = template1.format(top_name=self.top_name,
|
||||
dut_type=self.dut_type,
|
||||
dut_name=self.dut_name,
|
||||
clk_name=self._cd_name + "_clk",
|
||||
rst_name=self._cd_name + "_rst",
|
||||
hclk_period=str(self._clk_period/2),
|
||||
sockaddr=sockaddr)
|
||||
if self.vcd_name is not None:
|
||||
r += template2.format(vcd_name=self.vcd_name,
|
||||
vcd_level=str(self.vcd_level),
|
||||
dut_name=self.dut_name)
|
||||
r += "\nendmodule"
|
||||
return r
|
||||
|
||||
|
||||
class Simulator:
|
||||
def __init__(self, fragment, top_level=None, sim_runner=None, sockaddr="simsocket", **vopts):
|
||||
if not isinstance(fragment, _Fragment):
|
||||
fragment = fragment.get_fragment()
|
||||
if top_level is None:
|
||||
top_level = TopLevel()
|
||||
if sim_runner is None:
|
||||
sim_runner = icarus.Runner()
|
||||
self.top_level = top_level
|
||||
if sys.platform == "win32":
|
||||
sockaddr = ("127.0.0.1", 50007)
|
||||
self.ipc = Initiator(sockaddr)
|
||||
else:
|
||||
self.ipc = Initiator(sockaddr)
|
||||
|
||||
self.sim_runner = sim_runner
|
||||
|
||||
c_top = self.top_level.get(sockaddr)
|
||||
|
||||
fragment = fragment + _Fragment(clock_domains=top_level.clock_domains)
|
||||
c_fragment = verilog.convert(fragment,
|
||||
ios=self.top_level.ios,
|
||||
name=self.top_level.dut_type,
|
||||
regular_comb=False,
|
||||
**vopts)
|
||||
self.namespace = c_fragment.ns
|
||||
|
||||
self.cycle_counter = -1
|
||||
|
||||
self.sim_runner = sim_runner
|
||||
self.sim_runner.start(c_top, c_fragment)
|
||||
self.ipc.accept()
|
||||
reply = self.ipc.recv()
|
||||
assert(isinstance(reply, MessageTick))
|
||||
|
||||
self.sim_functions = fragment.sim
|
||||
self.active_sim_functions = set(f for f in fragment.sim if not hasattr(f, "passive") or not f.passive)
|
||||
self.unreferenced = {}
|
||||
|
||||
def run(self, ncycles=None):
|
||||
counter = 0
|
||||
|
||||
if self.active_sim_functions:
|
||||
if ncycles is None:
|
||||
def continue_simulation():
|
||||
return bool(self.active_sim_functions)
|
||||
else:
|
||||
def continue_simulation():
|
||||
return self.active_sim_functions and counter < ncycles
|
||||
else:
|
||||
if ncycles is None:
|
||||
raise ValueError("No active simulation function present - must specify ncycles to end simulation")
|
||||
def continue_simulation():
|
||||
return counter < ncycles
|
||||
|
||||
while continue_simulation():
|
||||
self.cycle_counter += 1
|
||||
counter += 1
|
||||
self.ipc.send(MessageGo())
|
||||
reply = self.ipc.recv()
|
||||
assert(isinstance(reply, MessageTick))
|
||||
|
||||
del_list = []
|
||||
for s in self.sim_functions:
|
||||
try:
|
||||
s(self)
|
||||
except StopSimulation:
|
||||
del_list.append(s)
|
||||
for s in del_list:
|
||||
self.sim_functions.remove(s)
|
||||
try:
|
||||
self.active_sim_functions.remove(s)
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
def get_unreferenced(self, item, index):
|
||||
try:
|
||||
return self.unreferenced[(item, index)]
|
||||
except KeyError:
|
||||
if isinstance(item, Memory):
|
||||
try:
|
||||
init = item.init[index]
|
||||
except (TypeError, IndexError):
|
||||
init = 0
|
||||
else:
|
||||
init = item.reset
|
||||
self.unreferenced[(item, index)] = init
|
||||
return init
|
||||
|
||||
def rd(self, item, index=0):
|
||||
try:
|
||||
name = self.top_level.top_name + "." \
|
||||
+ self.top_level.dut_name + "." \
|
||||
+ self.namespace.get_name(item)
|
||||
self.ipc.send(MessageRead(name, Int32(index)))
|
||||
reply = self.ipc.recv()
|
||||
assert(isinstance(reply, MessageReadReply))
|
||||
value = reply.value
|
||||
except KeyError:
|
||||
value = self.get_unreferenced(item, index)
|
||||
if isinstance(item, Memory):
|
||||
signed = False
|
||||
nbits = item.width
|
||||
else:
|
||||
signed = item.signed
|
||||
nbits = len(item)
|
||||
value = value & (2**nbits - 1)
|
||||
if signed and (value & 2**(nbits - 1)):
|
||||
value -= 2**nbits
|
||||
return value
|
||||
|
||||
def wr(self, item, value, index=0):
|
||||
if isinstance(item, Memory):
|
||||
nbits = item.width
|
||||
else:
|
||||
nbits = len(item)
|
||||
if value < 0:
|
||||
value += 2**nbits
|
||||
assert(value >= 0 and value < 2**nbits)
|
||||
try:
|
||||
name = self.top_level.top_name + "." \
|
||||
+ self.top_level.dut_name + "." \
|
||||
+ self.namespace.get_name(item)
|
||||
self.ipc.send(MessageWrite(name, Int32(index), value))
|
||||
except KeyError:
|
||||
self.unreferenced[(item, index)] = value
|
||||
|
||||
def __del__(self):
|
||||
if hasattr(self, "ipc"):
|
||||
warnings.warn("call Simulator.close() to clean up "
|
||||
"or use it as a contextmanager", DeprecationWarning)
|
||||
self.close()
|
||||
|
||||
def close(self):
|
||||
self.ipc.close()
|
||||
self.sim_runner.close()
|
||||
del self.ipc
|
||||
del self.sim_runner
|
||||
|
||||
def __enter__(self):
|
||||
return self
|
||||
|
||||
def __exit__(self, type, value, traceback):
|
||||
self.close()
|
||||
|
||||
|
||||
def run_simulation(fragment, ncycles=None, vcd_name=None, **kwargs):
|
||||
with Simulator(fragment, TopLevel(vcd_name), icarus.Runner(**kwargs)) as s:
|
||||
s.run(ncycles)
|
||||
|
|
@ -1,43 +0,0 @@
|
|||
# Copyright (C) 2012 Vermeer Manufacturing Co.
|
||||
# License: GPLv3 with additional permissions (see README).
|
||||
|
||||
import subprocess
|
||||
import os
|
||||
import time
|
||||
|
||||
|
||||
class Runner:
|
||||
def __init__(self, options=None, extra_files=None, top_file="migensim_top.v", dut_file="migensim_dut.v", vvp_file=None, keep_files=False):
|
||||
if extra_files is None: extra_files = []
|
||||
if vvp_file is None: vvp_file = dut_file + "vp"
|
||||
if options is None: options = []
|
||||
self.options = options
|
||||
self.extra_files = extra_files
|
||||
self.top_file = top_file
|
||||
self.dut_file = dut_file
|
||||
self.vvp_file = vvp_file
|
||||
self.data_files = []
|
||||
self.keep_files = keep_files
|
||||
|
||||
def start(self, c_top, c_dut):
|
||||
with open(self.top_file, "w") as f:
|
||||
f.write(c_top)
|
||||
c_dut.write(self.dut_file)
|
||||
self.data_files += c_dut.data_files.keys()
|
||||
subprocess.check_call(["iverilog", "-o", self.vvp_file] + self.options + [self.top_file, self.dut_file] + self.extra_files)
|
||||
self.process = subprocess.Popen(["vvp", "-mmigensim", "-Mvpi", self.vvp_file])
|
||||
|
||||
def close(self):
|
||||
if hasattr(self, "process"):
|
||||
self.process.terminate()
|
||||
if self.process.poll() is None:
|
||||
time.sleep(.1)
|
||||
self.process.kill()
|
||||
self.process.wait()
|
||||
if not self.keep_files:
|
||||
for f in [self.top_file, self.dut_file, self.vvp_file] + self.data_files:
|
||||
try:
|
||||
os.remove(f)
|
||||
except OSError:
|
||||
pass
|
||||
self.data_files.clear()
|
|
@ -1,228 +0,0 @@
|
|||
# Copyright (C) 2012 Vermeer Manufacturing Co.
|
||||
# License: GPLv3 with additional permissions (see README).
|
||||
|
||||
import socket
|
||||
import os
|
||||
import sys
|
||||
import struct
|
||||
|
||||
if sys.platform == "win32":
|
||||
header_len = 2
|
||||
|
||||
#
|
||||
# Message classes
|
||||
#
|
||||
|
||||
class Int32(int):
|
||||
pass
|
||||
|
||||
|
||||
class Message:
|
||||
def __init__(self, *pvalues):
|
||||
for parameter, value in zip(self.parameters, pvalues):
|
||||
setattr(self, parameter[1], parameter[0](value))
|
||||
|
||||
def __str__(self):
|
||||
p = []
|
||||
for parameter in self.parameters:
|
||||
p.append(parameter[1] + "=" + str(getattr(self, parameter[1])))
|
||||
if p:
|
||||
pf = " " + " ".join(p)
|
||||
else:
|
||||
pf = ""
|
||||
return "<" + self.__class__.__name__ + pf + ">"
|
||||
|
||||
|
||||
class MessageTick(Message):
|
||||
code = 0
|
||||
parameters = []
|
||||
|
||||
|
||||
class MessageGo(Message):
|
||||
code = 1
|
||||
parameters = []
|
||||
|
||||
|
||||
class MessageWrite(Message):
|
||||
code = 2
|
||||
parameters = [(str, "name"), (Int32, "index"), (int, "value")]
|
||||
|
||||
|
||||
class MessageRead(Message):
|
||||
code = 3
|
||||
parameters = [(str, "name"), (Int32, "index")]
|
||||
|
||||
|
||||
class MessageReadReply(Message):
|
||||
code = 4
|
||||
parameters = [(int, "value")]
|
||||
|
||||
message_classes = [MessageTick, MessageGo, MessageWrite, MessageRead, MessageReadReply]
|
||||
|
||||
|
||||
#
|
||||
# Packing
|
||||
#
|
||||
|
||||
def _pack_int(v):
|
||||
if v == 0:
|
||||
p = [1, 0]
|
||||
else:
|
||||
p = []
|
||||
while v != 0:
|
||||
p.append(v & 0xff)
|
||||
v >>= 8
|
||||
p.insert(0, len(p))
|
||||
return p
|
||||
|
||||
|
||||
def _pack_str(v):
|
||||
p = [ord(c) for c in v]
|
||||
p.append(0)
|
||||
return p
|
||||
|
||||
|
||||
def _pack_int16(v):
|
||||
return [v & 0xff,
|
||||
(v & 0xff00) >> 8]
|
||||
|
||||
|
||||
def _pack_int32(v):
|
||||
return [
|
||||
v & 0xff,
|
||||
(v & 0xff00) >> 8,
|
||||
(v & 0xff0000) >> 16,
|
||||
(v & 0xff000000) >> 24
|
||||
]
|
||||
|
||||
|
||||
def _pack(message):
|
||||
r = [message.code]
|
||||
for t, p in message.parameters:
|
||||
value = getattr(message, p)
|
||||
assert(isinstance(value, t))
|
||||
if t == int:
|
||||
r += _pack_int(value)
|
||||
elif t == str:
|
||||
r += _pack_str(value)
|
||||
elif t == Int32:
|
||||
r += _pack_int32(value)
|
||||
else:
|
||||
raise TypeError
|
||||
if sys.platform == "win32":
|
||||
size = _pack_int16(len(r) + header_len)
|
||||
r = size + r
|
||||
return bytes(r)
|
||||
|
||||
|
||||
#
|
||||
# Unpacking
|
||||
#
|
||||
|
||||
def _unpack_int(i, nchunks=None):
|
||||
v = 0
|
||||
power = 1
|
||||
if nchunks is None:
|
||||
nchunks = next(i)
|
||||
for j in range(nchunks):
|
||||
v += power*next(i)
|
||||
power *= 256
|
||||
return v
|
||||
|
||||
|
||||
def _unpack_str(i):
|
||||
v = ""
|
||||
c = next(i)
|
||||
while c:
|
||||
v += chr(c)
|
||||
c = next(i)
|
||||
return v
|
||||
|
||||
|
||||
def _unpack(message):
|
||||
i = iter(message)
|
||||
code = next(i)
|
||||
msgclass = next(filter(lambda x: x.code == code, message_classes))
|
||||
pvalues = []
|
||||
for t, p in msgclass.parameters:
|
||||
if t == int:
|
||||
v = _unpack_int(i)
|
||||
elif t == str:
|
||||
v = _unpack_str(i)
|
||||
elif t == Int32:
|
||||
v = _unpack_int(i, 4)
|
||||
else:
|
||||
raise TypeError
|
||||
pvalues.append(v)
|
||||
return msgclass(*pvalues)
|
||||
|
||||
|
||||
#
|
||||
# I/O
|
||||
#
|
||||
|
||||
class PacketTooLarge(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class Initiator:
|
||||
def __init__(self, sockaddr):
|
||||
self.sockaddr = sockaddr
|
||||
if sys.platform == "win32":
|
||||
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
else:
|
||||
self.socket = socket.socket(socket.AF_UNIX, socket.SOCK_SEQPACKET)
|
||||
self._cleanup_file()
|
||||
self.socket.bind(self.sockaddr)
|
||||
self.socket.listen(1)
|
||||
|
||||
self.ipc_rxbuffer = bytearray()
|
||||
|
||||
def _cleanup_file(self):
|
||||
try:
|
||||
os.remove(self.sockaddr)
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
def accept(self):
|
||||
self.conn, addr = self.socket.accept()
|
||||
|
||||
def send(self, message):
|
||||
self.conn.send(_pack(message))
|
||||
|
||||
def recv_packet(self, maxlen):
|
||||
if sys.platform == "win32":
|
||||
while len(self.ipc_rxbuffer) < header_len:
|
||||
self.ipc_rxbuffer += self.conn.recv(maxlen)
|
||||
packet_len = struct.unpack("<H", self.ipc_rxbuffer[:header_len])[0]
|
||||
while len(self.ipc_rxbuffer) < packet_len:
|
||||
self.ipc_rxbuffer += self.conn.recv(maxlen)
|
||||
packet = self.ipc_rxbuffer[header_len:packet_len]
|
||||
self.ipc_rxbuffer = self.ipc_rxbuffer[packet_len:]
|
||||
else:
|
||||
packet = self.conn.recv(maxlen)
|
||||
return packet
|
||||
|
||||
def recv(self):
|
||||
maxlen = 2048
|
||||
packet = self.recv_packet(maxlen)
|
||||
if len(packet) < 1:
|
||||
return None
|
||||
if len(packet) >= maxlen:
|
||||
raise PacketTooLarge
|
||||
return _unpack(packet)
|
||||
|
||||
def close(self):
|
||||
if hasattr(self, "conn"):
|
||||
self.conn.shutdown(socket.SHUT_RDWR)
|
||||
self.conn.close()
|
||||
if hasattr(self, "socket"):
|
||||
if sys.platform == "win32":
|
||||
# don't shutdown our socket since closing connection
|
||||
# seems to already have done it. (trigger an error
|
||||
# otherwise)
|
||||
self.socket.close()
|
||||
else:
|
||||
self.socket.shutdown(socket.SHUT_RDWR)
|
||||
self.socket.close()
|
||||
self._cleanup_file()
|
|
@ -1,112 +0,0 @@
|
|||
from litex.gen.fhdl.structure import Signal, StopSimulation
|
||||
from litex.gen.fhdl.specials import Memory
|
||||
|
||||
|
||||
class MemoryProxy:
|
||||
def __init__(self, simulator, obj):
|
||||
self.simulator = simulator
|
||||
self._simproxy_obj = obj
|
||||
|
||||
def __getitem__(self, key):
|
||||
if isinstance(key, int):
|
||||
return self.simulator.rd(self._simproxy_obj, key)
|
||||
else:
|
||||
start, stop, step = key.indices(self._simproxy_obj.depth)
|
||||
return [self.simulator.rd(self._simproxy_obj, i) for i in range(start, stop, step)]
|
||||
|
||||
def __setitem__(self, key, value):
|
||||
if isinstance(key, int):
|
||||
self.simulator.wr(self._simproxy_obj, key, value)
|
||||
else:
|
||||
start, stop, step = key.indices(self.__obj.depth)
|
||||
if len(value) != (stop - start)//step:
|
||||
raise ValueError
|
||||
for i, v in zip(range(start, stop, step), value):
|
||||
self.simulator.wr(self._simproxy_obj, i, v)
|
||||
|
||||
|
||||
class Proxy:
|
||||
def __init__(self, simulator, obj):
|
||||
object.__setattr__(self, "simulator", simulator)
|
||||
object.__setattr__(self, "_simproxy_obj", obj)
|
||||
|
||||
def __process_get(self, item):
|
||||
if isinstance(item, Signal):
|
||||
return self.simulator.rd(item)
|
||||
elif isinstance(item, Memory):
|
||||
return MemoryProxy(self.simulator, item)
|
||||
else:
|
||||
return Proxy(self.simulator, item)
|
||||
|
||||
def __getattr__(self, name):
|
||||
return self.__process_get(getattr(self._simproxy_obj, name))
|
||||
|
||||
def __setattr__(self, name, value):
|
||||
item = getattr(self._simproxy_obj, name)
|
||||
assert(isinstance(item, Signal))
|
||||
self.simulator.wr(item, value)
|
||||
|
||||
def __getitem__(self, key):
|
||||
return self.__process_get(self._simproxy_obj[key])
|
||||
|
||||
def __setitem__(self, key, value):
|
||||
item = self._simproxy_obj[key]
|
||||
assert(isinstance(item, Signal))
|
||||
self.simulator.wr(item, value)
|
||||
|
||||
|
||||
def gen_sim(simg):
|
||||
gens = dict()
|
||||
resume_cycle = 0
|
||||
|
||||
def do_simulation(s):
|
||||
nonlocal resume_cycle, gens
|
||||
|
||||
if isinstance(s, Proxy):
|
||||
simulator = s.simulator
|
||||
else:
|
||||
simulator = s
|
||||
|
||||
if simulator.cycle_counter >= resume_cycle:
|
||||
try:
|
||||
gen = gens[simulator]
|
||||
except KeyError:
|
||||
gen = simg(s)
|
||||
gens[simulator] = gen
|
||||
try:
|
||||
n = next(gen)
|
||||
except StopIteration:
|
||||
del gens[simulator]
|
||||
raise StopSimulation
|
||||
else:
|
||||
if n is None:
|
||||
n = 1
|
||||
resume_cycle = simulator.cycle_counter + n
|
||||
|
||||
if hasattr(simg, "passive"):
|
||||
do_simulation.passive = simg.passive
|
||||
|
||||
return do_simulation
|
||||
|
||||
|
||||
def proxy_sim(target, simf):
|
||||
proxies = dict()
|
||||
|
||||
def do_simulation(simulator):
|
||||
nonlocal proxies
|
||||
|
||||
try:
|
||||
proxy = proxies[simulator]
|
||||
except KeyError:
|
||||
proxy = Proxy(simulator, target)
|
||||
proxies[simulator] = proxy
|
||||
try:
|
||||
simf(proxy)
|
||||
except StopSimulation:
|
||||
del proxies[simulator]
|
||||
raise
|
||||
|
||||
if hasattr(simf, "passive"):
|
||||
do_simulation.passive = simf.passive
|
||||
|
||||
return do_simulation
|
Loading…
Reference in New Issue