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):
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)
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])
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"
])
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:
if os.path.exists(settings):
return settings
- raise OSError("no settings file found")
+ raise OSError("no Xilinx tools settings file found")
class XilinxNoRetimingVivadoImpl(Module):
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)
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)
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)
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 *
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"]
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 = []
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:
- ns.get_name(signal)
+ 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
def transform_fragment(self, i, f):
newspecials = set()
+ processed_ports = set()
for mem in f.specials:
if not isinstance(mem, Memory):
sync.append(If(port.we,
storage[port.adr].eq(port.dat_w)))
+ processed_ports.add(port)
+
+ newspecials -= processed_ports
f.specials = newspecials
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")
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
for k, v in cases.items():
if isinstance(k, (bool, int)):
k = Constant(k)
- if (not isinstance(k, Constant)
+ if (not isinstance(k, Constant)
and not (isinstance(k, str) and k == "default")):
raise TypeError("Case object is not a Migen constant")
if not isinstance(v, _collections.Iterable):
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
(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)
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)
self.sync = newsync
self.specials |= other.specials
self.clock_domains += other.clock_domains
- self.sim += other.sim
return self
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
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
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
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",
(_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 = " = "
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):
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
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,
- display_run,
- dummy_signal,
- blocking_assign):
+def _printcomb(f, ns,
+ display_run,
+ dummy_signal,
+ blocking_assign):
r = ""
if f.comb:
if dummy_signal:
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")
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"
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)):
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
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)
from copy import copy
+from operator import itemgetter
from litex.gen.fhdl.structure import *
from litex.gen.fhdl.structure import (_Operator, _Slice, _Assign, _ArrayProxy,
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):
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):
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
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],
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
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)
+ finst = Signal(fsize, name=prefix + fname)
elif isinstance(f[1], list): # case 3
fname, fsublayout = f
finst = Record(fsublayout, prefix + fname)
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
+from litex.gen.sim.core import Simulator, run_simulation, passive
+++ /dev/null
-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)
-
+++ /dev/null
-# 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()
+++ /dev/null
-# 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()
+++ /dev/null
-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