mirror of
https://github.com/enjoy-digital/litex.git
synced 2025-01-04 09:52:26 -05:00
introduce conversion output object (prevents file IO in FHDL backends)
This commit is contained in:
parent
8ce683964a
commit
e1702c422c
10 changed files with 95 additions and 69 deletions
|
@ -81,10 +81,10 @@ class AlteraQuartusToolchain:
|
|||
fragment = fragment.get_fragment()
|
||||
platform.finalize(fragment)
|
||||
|
||||
v_src, vns = platform.get_verilog(fragment)
|
||||
named_sc, named_pc = platform.resolve_signals(vns)
|
||||
v_output = platform.get_verilog(fragment)
|
||||
named_sc, named_pc = platform.resolve_signals(v_output.ns)
|
||||
v_file = build_name + ".v"
|
||||
tools.write_to_file(v_file, v_src)
|
||||
v_output.write(v_file)
|
||||
sources = platform.sources | {(v_file, "verilog")}
|
||||
_build_files(platform.device, sources, platform.verilog_include_paths, named_sc, named_pc, build_name)
|
||||
if run:
|
||||
|
@ -92,7 +92,7 @@ class AlteraQuartusToolchain:
|
|||
|
||||
os.chdir("..")
|
||||
|
||||
return vns
|
||||
return v_output.ns
|
||||
|
||||
def add_period_constraint(self, platform, clk, period):
|
||||
# TODO: handle differential clk
|
||||
|
|
|
@ -265,20 +265,11 @@ class GenericPlatform:
|
|||
named_pc.append(template.format(**name_dict))
|
||||
return named_sc, named_pc
|
||||
|
||||
def _get_source(self, fragment, gen_fn):
|
||||
if not isinstance(fragment, _Fragment):
|
||||
fragment = fragment.get_fragment()
|
||||
# generate source
|
||||
src, vns = gen_fn(fragment)
|
||||
return src, vns
|
||||
|
||||
def get_verilog(self, fragment, **kwargs):
|
||||
return self._get_source(fragment, lambda f: verilog.convert(f, self.constraint_manager.get_io_signals(),
|
||||
return_ns=True, create_clock_domains=False, **kwargs))
|
||||
return verilog.convert(fragment, self.constraint_manager.get_io_signals(), create_clock_domains=False, **kwargs)
|
||||
|
||||
def get_edif(self, fragment, cell_library, vendor, device, **kwargs):
|
||||
return self._get_source(fragment, lambda f: edif.convert(f, self.constraint_manager.get_io_signals(),
|
||||
cell_library, vendor, device, return_ns=True, **kwargs))
|
||||
return edif.convert(fragment, self.constraint_manager.get_io_signals(), cell_library, vendor, device, **kwargs)
|
||||
|
||||
def build(self, fragment):
|
||||
raise NotImplementedError("GenericPlatform.build must be overloaded")
|
||||
|
|
|
@ -75,10 +75,10 @@ class LatticeDiamondToolchain:
|
|||
fragment = fragment.get_fragment()
|
||||
platform.finalize(fragment)
|
||||
|
||||
v_src, vns = platform.get_verilog(fragment)
|
||||
named_sc, named_pc = platform.resolve_signals(vns)
|
||||
v_output = platform.get_verilog(fragment)
|
||||
named_sc, named_pc = platform.resolve_signals(v_output.ns)
|
||||
v_file = build_name + ".v"
|
||||
tools.write_to_file(v_file, v_src)
|
||||
v_output.write(v_file)
|
||||
sources = platform.sources + [(v_file, "verilog")]
|
||||
_build_files(platform.device, sources, platform.verilog_include_paths, build_name)
|
||||
|
||||
|
@ -89,7 +89,7 @@ class LatticeDiamondToolchain:
|
|||
|
||||
os.chdir("..")
|
||||
|
||||
return vns
|
||||
return v_output.ns
|
||||
|
||||
def add_period_constraint(self, platform, clk, period):
|
||||
# TODO: handle differential clk
|
||||
|
|
|
@ -127,10 +127,9 @@ class SimVerilatorToolchain:
|
|||
fragment = fragment.get_fragment()
|
||||
platform.finalize(fragment)
|
||||
|
||||
v_src, vns = platform.get_verilog(fragment)
|
||||
named_sc, named_pc = platform.resolve_signals(vns)
|
||||
v_file = "dut.v"
|
||||
tools.write_to_file(v_file, v_src)
|
||||
v_output = platform.get_verilog(fragment)
|
||||
named_sc, named_pc = platform.resolve_signals(v_output.ns)
|
||||
v_output.write("dut.v")
|
||||
|
||||
include_paths = []
|
||||
for source in platform.sources:
|
||||
|
@ -138,11 +137,11 @@ class SimVerilatorToolchain:
|
|||
if path not in include_paths:
|
||||
include_paths.append(path)
|
||||
include_paths += platform.verilog_include_paths
|
||||
_build_sim(platform, vns, build_name, include_paths, sim_path, serial, verbose)
|
||||
_build_sim(platform, v_output.ns, build_name, include_paths, sim_path, serial, verbose)
|
||||
|
||||
if run:
|
||||
_run_sim(build_name)
|
||||
|
||||
os.chdir("..")
|
||||
|
||||
return vns
|
||||
return v_output.ns
|
||||
|
|
|
@ -145,10 +145,11 @@ class XilinxISEToolchain:
|
|||
vns = None
|
||||
|
||||
if mode == "xst" or mode == "yosys":
|
||||
v_src, vns = platform.get_verilog(fragment)
|
||||
v_output = platform.get_verilog(fragment)
|
||||
vns = v_output.ns
|
||||
named_sc, named_pc = platform.resolve_signals(vns)
|
||||
v_file = build_name + ".v"
|
||||
tools.write_to_file(v_file, v_src)
|
||||
v_output.write(v_file)
|
||||
sources = platform.sources | {(v_file, "verilog")}
|
||||
if mode == "xst":
|
||||
_build_xst_files(platform.device, sources, platform.verilog_include_paths, build_name, self.xst_opt)
|
||||
|
@ -163,10 +164,11 @@ class XilinxISEToolchain:
|
|||
synthesize(fragment, platform.constraint_manager.get_io_signals())
|
||||
|
||||
if mode == "edif" or mode == "mist":
|
||||
e_src, vns = platform.get_edif(fragment)
|
||||
e_output = platform.get_edif(fragment)
|
||||
vns = e_output.ns
|
||||
named_sc, named_pc = platform.resolve_signals(vns)
|
||||
e_file = build_name + ".edif"
|
||||
tools.write_to_file(e_file, e_src)
|
||||
e_output.write(e_file)
|
||||
isemode = "edif"
|
||||
|
||||
tools.write_to_file(build_name + ".ucf", _build_ucf(named_sc, named_pc))
|
||||
|
|
|
@ -111,10 +111,10 @@ class XilinxVivadoToolchain:
|
|||
if not isinstance(fragment, _Fragment):
|
||||
fragment = fragment.get_fragment()
|
||||
platform.finalize(fragment)
|
||||
v_src, vns = platform.get_verilog(fragment)
|
||||
named_sc, named_pc = platform.resolve_signals(vns)
|
||||
v_output = platform.get_verilog(fragment)
|
||||
named_sc, named_pc = platform.resolve_signals(v_output.ns)
|
||||
v_file = build_name + ".v"
|
||||
tools.write_to_file(v_file, v_src)
|
||||
v_output.write(v_file)
|
||||
sources = platform.sources | {(v_file, "verilog")}
|
||||
self._build_batch(platform, sources, build_name)
|
||||
tools.write_to_file(build_name + ".xdc", _build_xdc(named_sc, named_pc))
|
||||
|
@ -123,7 +123,7 @@ class XilinxVivadoToolchain:
|
|||
|
||||
os.chdir("..")
|
||||
|
||||
return vns
|
||||
return v_output.ns
|
||||
|
||||
def add_period_constraint(self, platform, clk, period):
|
||||
platform.add_platform_command("""create_clock -name {clk} -period """ + \
|
||||
|
|
35
migen/fhdl/conv_output.py
Normal file
35
migen/fhdl/conv_output.py
Normal file
|
@ -0,0 +1,35 @@
|
|||
from operator import itemgetter
|
||||
|
||||
|
||||
class ConvOutput:
|
||||
def __init__(self):
|
||||
self.main_source = ""
|
||||
self.data_files = dict()
|
||||
|
||||
def set_main_source(self, src):
|
||||
self.main_source = src
|
||||
|
||||
def add_data_file(self, filename_base, content):
|
||||
filename = filename_base
|
||||
i = 1
|
||||
while filename in self.data_files:
|
||||
parts = filename_base.split(".", maxsplit=1)
|
||||
parts[0] += "_" + str(i)
|
||||
filename = ".".join(parts)
|
||||
i += 1
|
||||
self.data_files[filename] = content
|
||||
return filename
|
||||
|
||||
def __str__(self):
|
||||
r = self.main_source + "\n"
|
||||
for filename, content in sorted(self.data_files.items(),
|
||||
key=itemgetter(0)):
|
||||
r += filename + ":\n" + content
|
||||
return r
|
||||
|
||||
def write(self, main_filename):
|
||||
with open(main_filename, "w") as f:
|
||||
f.write(self.main_source)
|
||||
for filename, content in self.data_files.items():
|
||||
with open(filename, "w") as f:
|
||||
f.write(content)
|
|
@ -1,10 +1,12 @@
|
|||
from collections import OrderedDict
|
||||
from collections import namedtuple
|
||||
|
||||
from migen.fhdl.std import *
|
||||
from migen.fhdl.namer import build_namespace
|
||||
from migen.fhdl.tools import list_special_ios
|
||||
from migen.fhdl.structure import _Fragment
|
||||
from migen.fhdl.conv_output import ConvOutput
|
||||
|
||||
from collections import namedtuple
|
||||
|
||||
_Port = namedtuple("_Port", "name direction")
|
||||
_Cell = namedtuple("_Cell", "name ports")
|
||||
|
@ -125,7 +127,7 @@ def _generate_cells(f):
|
|||
else:
|
||||
cell_dict[special.of] = port_list
|
||||
else:
|
||||
raise ValueError("Edif conversion can only handle synthesized fragments")
|
||||
raise ValueError("EDIF conversion can only handle synthesized fragments")
|
||||
return [_Cell(k, v) for k, v in cell_dict.items()]
|
||||
|
||||
def _generate_instances(f,ns):
|
||||
|
@ -146,7 +148,7 @@ def _generate_instances(f,ns):
|
|||
raise NotImplementedError("Unsupported instance item")
|
||||
instances.append(_Instance(name=ns.get_name(special), cell=special.of, properties=props))
|
||||
else:
|
||||
raise ValueError("Edif conversion can only handle synthesized fragments")
|
||||
raise ValueError("EDIF conversion can only handle synthesized fragments")
|
||||
return instances
|
||||
|
||||
def _generate_ios(f, ios, ns):
|
||||
|
@ -174,7 +176,7 @@ def _generate_connections(f, ios, ns):
|
|||
else:
|
||||
raise NotImplementedError("Unsupported instance item")
|
||||
else:
|
||||
raise ValueError("Edif conversion can only handle synthesized fragments")
|
||||
raise ValueError("EDIF conversion can only handle synthesized fragments")
|
||||
for s in ios:
|
||||
io = ns.get_name(s)
|
||||
if io not in r:
|
||||
|
@ -182,11 +184,11 @@ def _generate_connections(f, ios, ns):
|
|||
r[io].append(_NetBranch(portname=io, instancename=""))
|
||||
return r
|
||||
|
||||
def convert(f, ios, cell_library, vendor, device, name="top", return_ns=False):
|
||||
def convert(f, ios, cell_library, vendor, device, name="top"):
|
||||
if not isinstance(f, _Fragment):
|
||||
f = f.get_fragment()
|
||||
if f.comb != [] or f.sync != {}:
|
||||
raise ValueError("Edif conversion can only handle synthesized fragments")
|
||||
raise ValueError("EDIF conversion can only handle synthesized fragments")
|
||||
if ios is None:
|
||||
ios = set()
|
||||
cells = _generate_cells(f)
|
||||
|
@ -194,8 +196,9 @@ def convert(f, ios, cell_library, vendor, device, name="top", return_ns=False):
|
|||
instances = _generate_instances(f, ns)
|
||||
inouts = _generate_ios(f, ios, ns)
|
||||
connections = _generate_connections(f, ios, ns)
|
||||
r = _write_edif(cells, inouts, instances, connections, cell_library, name, device, vendor)
|
||||
if return_ns:
|
||||
return r, ns
|
||||
else:
|
||||
src = _write_edif(cells, inouts, instances, connections, cell_library, name, device, vendor)
|
||||
|
||||
r = ConvOutput()
|
||||
r.set_main_source(src)
|
||||
r.ns = ns
|
||||
return r
|
||||
|
|
|
@ -48,7 +48,7 @@ class Tristate(Special):
|
|||
yield self, attr, target_context
|
||||
|
||||
@staticmethod
|
||||
def emit_verilog(tristate, ns):
|
||||
def emit_verilog(tristate, ns, add_data_file):
|
||||
def pe(e):
|
||||
return verilog_printexpr(ns, e)[0]
|
||||
w, s = value_bits_sign(tristate.target)
|
||||
|
@ -123,7 +123,7 @@ class Instance(Special):
|
|||
yield item, "expr", SPECIAL_INOUT
|
||||
|
||||
@staticmethod
|
||||
def emit_verilog(instance, ns):
|
||||
def emit_verilog(instance, ns, add_data_file):
|
||||
r = instance.of + " "
|
||||
parameters = list(filter(lambda i: isinstance(i, Instance.Parameter), instance.items))
|
||||
if parameters:
|
||||
|
@ -198,7 +198,7 @@ class _MemoryPort(Special):
|
|||
yield self, attr, target_context
|
||||
|
||||
@staticmethod
|
||||
def emit_verilog(port, ns):
|
||||
def emit_verilog(port, ns, add_data_file):
|
||||
return "" # done by parent Memory object
|
||||
|
||||
class Memory(Special):
|
||||
|
@ -237,7 +237,7 @@ class Memory(Special):
|
|||
return mp
|
||||
|
||||
@staticmethod
|
||||
def emit_verilog(memory, ns):
|
||||
def emit_verilog(memory, ns, add_data_file):
|
||||
r = ""
|
||||
def gn(e):
|
||||
if isinstance(e, Memory):
|
||||
|
@ -307,14 +307,10 @@ class Memory(Special):
|
|||
r += "\n"
|
||||
|
||||
if memory.init is not None:
|
||||
memory_filename = gn(memory) + ".init"
|
||||
|
||||
# XXX move I/O to mibuild?
|
||||
# (Implies mem init won't work with simple Migen examples?)
|
||||
f = open(memory_filename, "w")
|
||||
content = ""
|
||||
for d in memory.init:
|
||||
f.write("{:x}\n".format(d))
|
||||
f.close()
|
||||
content += "{:x}\n".format(d)
|
||||
memory_filename = add_data_file(gn(memory) + ".init", content)
|
||||
|
||||
r += "initial begin\n"
|
||||
r += "$readmemh(\"" + memory_filename + "\", " + gn(memory) + ");\n"
|
||||
|
@ -330,7 +326,7 @@ class SynthesisDirective(Special):
|
|||
self.signals = signals
|
||||
|
||||
@staticmethod
|
||||
def emit_verilog(directive, ns):
|
||||
def emit_verilog(directive, ns, add_data_file):
|
||||
name_dict = dict((k, ns.get_name(sig)) for k, sig in directive.signals.items())
|
||||
formatted = directive.template.format(**name_dict)
|
||||
return "// synthesis " + formatted + "\n"
|
||||
|
|
|
@ -6,6 +6,7 @@ from migen.fhdl.structure import _Operator, _Slice, _Assign, _Fragment
|
|||
from migen.fhdl.tools import *
|
||||
from migen.fhdl.bitcontainer import bits_for, flen
|
||||
from migen.fhdl.namer import Namespace, build_namespace
|
||||
from migen.fhdl.conv_output import ConvOutput
|
||||
|
||||
def _printsig(ns, s):
|
||||
if s.signed:
|
||||
|
@ -257,20 +258,20 @@ def _lower_specials(overrides, specials):
|
|||
f.specials -= lowered_specials2
|
||||
return f, lowered_specials
|
||||
|
||||
def _printspecials(overrides, specials, ns):
|
||||
def _printspecials(overrides, specials, ns, add_data_file):
|
||||
r = ""
|
||||
for special in sorted(specials, key=lambda x: x.huid):
|
||||
pr = _call_special_classmethod(overrides, special, "emit_verilog", ns)
|
||||
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
|
||||
return r
|
||||
|
||||
def convert(f, ios=None, name="top",
|
||||
return_ns=False,
|
||||
special_overrides=dict(),
|
||||
create_clock_domains=True,
|
||||
display_run=False):
|
||||
r = ConvOutput()
|
||||
if not isinstance(f, _Fragment):
|
||||
f = f.get_fragment()
|
||||
if ios is None:
|
||||
|
@ -296,15 +297,14 @@ def convert(f, ios=None, name="top",
|
|||
ns = build_namespace(list_signals(f) \
|
||||
| list_special_ios(f, True, True, True) \
|
||||
| ios)
|
||||
r.ns = ns
|
||||
|
||||
r = "/* Machine-generated using Migen */\n"
|
||||
r += _printheader(f, ios, name, ns)
|
||||
r += _printcomb(f, ns, display_run)
|
||||
r += _printsync(f, ns)
|
||||
r += _printspecials(special_overrides, f.specials - lowered_specials, ns)
|
||||
r += "endmodule\n"
|
||||
src = "/* Machine-generated using Migen */\n"
|
||||
src += _printheader(f, ios, name, ns)
|
||||
src += _printcomb(f, ns, display_run)
|
||||
src += _printsync(f, ns)
|
||||
src += _printspecials(special_overrides, f.specials - lowered_specials, ns, r.add_data_file)
|
||||
src += "endmodule\n"
|
||||
r.set_main_source(src)
|
||||
|
||||
if return_ns:
|
||||
return r, ns
|
||||
else:
|
||||
return r
|
||||
|
|
Loading…
Reference in a new issue