introduce conversion output object (prevents file IO in FHDL backends)

This commit is contained in:
Sebastien Bourdeauducq 2015-04-08 20:28:23 +08:00
parent 8ce683964a
commit e1702c422c
10 changed files with 95 additions and 69 deletions

View File

@ -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

View File

@ -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")

View File

@ -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

View File

@ -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

View File

@ -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))

View File

@ -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
View 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)

View File

@ -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:
return r
src = _write_edif(cells, inouts, instances, connections, cell_library, name, device, vendor)
r = ConvOutput()
r.set_main_source(src)
r.ns = ns
return r

View File

@ -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"

View File

@ -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
return r