build/lattice/prjtrellis: generate iowrapper to set constraints and TRELLIS_IO
PrjTrellis does not yet have constraint files support, constraints are set with signal attributes and specific TRELLIS_IO instances are requested. This iowrapper does this work for us automatically. Remove this code and replace with a constraint file generation code when PrjTrellis will have constraint file support.
This commit is contained in:
parent
c506c9752c
commit
27ec2a59e2
|
@ -10,6 +10,11 @@ from litex.build.generic_platform import *
|
|||
from litex.build import tools
|
||||
from litex.build.lattice import common
|
||||
|
||||
# TODO:
|
||||
# - add inout support to iowrapper
|
||||
# - verify iowrapper handle correctly multi-bit signals
|
||||
# - check/document attr_translate
|
||||
|
||||
|
||||
nextpnr_ecp5_architectures = {
|
||||
"lfe5u-25f": "25k",
|
||||
|
@ -24,6 +29,87 @@ nextpnr_ecp5_architectures = {
|
|||
}
|
||||
|
||||
|
||||
def yosys_import_sources(platform):
|
||||
includes = ""
|
||||
reads = []
|
||||
for path in platform.verilog_include_paths:
|
||||
includes += " -I" + path
|
||||
for filename, language, library in platform.sources:
|
||||
reads.append("read_{}{} {}".format(
|
||||
language, includes, filename))
|
||||
return "\n".join(reads)
|
||||
|
||||
|
||||
def generate_prjtrellis_iowrapper(platform, vns):
|
||||
ios, _ = platform.resolve_signals(vns)
|
||||
ios_direction = {}
|
||||
# resolve ios directions
|
||||
cm = platform.constraint_manager
|
||||
for io_name, io_pin, _, _ in ios:
|
||||
for cm_sig, cm_pin, _, _ in cm.get_sig_constraints():
|
||||
if io_pin == cm_pin:
|
||||
ios_direction[io_name] = cm_sig.direction
|
||||
last_io_name = io_name
|
||||
|
||||
iowrapper_contents = []
|
||||
iowrapper_contents.append("module {build_name}_iowrapper(")
|
||||
|
||||
# ios declaration
|
||||
ios_declaration = ""
|
||||
for io_name, io_pin, _, _ in ios:
|
||||
ios_declaration += "\t" + ios_direction[io_name] + " "
|
||||
if len(io_pin) > 1:
|
||||
ios_declaration += "[{}:0] ".format(len(io_pin - 1))
|
||||
ios_declaration += io_name + "_io"
|
||||
ios_declaration += ",\n" if io_name != last_io_name else ""
|
||||
iowrapper_contents.append(ios_declaration)
|
||||
iowrapper_contents.append(");\n")
|
||||
|
||||
# wires declaration
|
||||
wires_declaration = ""
|
||||
for io_name, io_pin, _, _ in ios:
|
||||
wires_declaration += "wire "
|
||||
if len(io_pin) > 1:
|
||||
wires_declaration += "[{}:0] ".format(len(io_pin - 1))
|
||||
wires_declaration += io_name
|
||||
wires_declaration += ";\n"
|
||||
iowrapper_contents.append(wires_declaration)
|
||||
|
||||
# trellis_io declaration
|
||||
trellis_io_declaration = ""
|
||||
for io_name, io_pin, io_others, _ in ios:
|
||||
for io_other in io_others:
|
||||
if isinstance(io_other, IOStandard):
|
||||
io_standard = io_other.name
|
||||
trellis_io_declaration += \
|
||||
"(* LOC=\"{}\" *) (* IO_TYPE=\"{}\" *)\n".format(io_pin[0], io_standard)
|
||||
if ios_direction[io_name] == "input":
|
||||
trellis_io_declaration += \
|
||||
"TRELLIS_IO #(.DIR(\"INPUT\")) {} (.B({}), .O({}));\n".format(
|
||||
io_name + "_buf", io_name + "_io", io_name)
|
||||
elif ios_direction[io_name] == "output":
|
||||
trellis_io_declaration += \
|
||||
"TRELLIS_IO #(.DIR(\"OUTPUT\")) {} (.B({}), .I({}));\n".format(
|
||||
io_name + "_buf", io_name + "_io", io_name)
|
||||
else:
|
||||
raise NotImplementedError
|
||||
iowrapper_contents.append(trellis_io_declaration)
|
||||
|
||||
# top declaration
|
||||
top_declaration = "{build_name} _{build_name}(\n"
|
||||
for io_name, io_pin, _, _ in ios:
|
||||
top_declaration += "\t." + io_name + "(" + io_name + ")"
|
||||
top_declaration += ",\n" if io_name != last_io_name else "\n"
|
||||
top_declaration += ");\n"
|
||||
iowrapper_contents.append(top_declaration)
|
||||
|
||||
iowrapper_contents.append("endmodule")
|
||||
|
||||
iowrapper_contents = "\n".join(iowrapper_contents)
|
||||
|
||||
return iowrapper_contents
|
||||
|
||||
|
||||
class LatticePrjTrellisToolchain:
|
||||
attr_translate = {
|
||||
# FIXME: document
|
||||
|
@ -52,26 +138,23 @@ class LatticePrjTrellisToolchain:
|
|||
platform.finalize(fragment)
|
||||
|
||||
v_output = platform.get_verilog(fragment)
|
||||
named_sc, named_pc = platform.resolve_signals(v_output.ns)
|
||||
v_file = build_name + ".v"
|
||||
v_output.write(v_file)
|
||||
platform.add_source(v_file)
|
||||
|
||||
# generate yosys script
|
||||
def yosys_import_sources(platform):
|
||||
includes = ""
|
||||
reads = []
|
||||
for path in platform.verilog_include_paths:
|
||||
includes += " -I" + path
|
||||
for filename, language, library in platform.sources:
|
||||
reads.append("read_{}{} {}".format(
|
||||
language, includes, filename))
|
||||
return "\n".join(reads)
|
||||
# generate iowrapper (with constraints and trellis_ios)
|
||||
# FIXME: remove when prjtrellis will support constraint files
|
||||
iowrapper_file = build_name + "_iowrapper.v"
|
||||
iowrapper_contents = generate_prjtrellis_iowrapper(platform, v_output.ns)
|
||||
iowrapper_contents = iowrapper_contents.format(build_name=build_name)
|
||||
tools.write_to_file(iowrapper_file, iowrapper_contents)
|
||||
platform.add_source(iowrapper_file)
|
||||
|
||||
# generate yosys script
|
||||
yosys_script_file = build_name + ".ys"
|
||||
yosys_script_contents = [
|
||||
yosys_import_sources(platform),
|
||||
"synth_ecp5 -nomux -json {build_name}.json -top {build_name}"
|
||||
"synth_ecp5 -nomux -json {build_name}.json -top {build_name}_iowrapper"
|
||||
]
|
||||
yosys_script_contents = "\n".join(yosys_script_contents)
|
||||
yosys_script_contents = yosys_script_contents.format(build_name=build_name)
|
||||
|
|
Loading…
Reference in New Issue