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:
Florent Kermarrec 2018-10-29 11:44:31 +01:00
parent c506c9752c
commit 27ec2a59e2
1 changed files with 95 additions and 12 deletions

View File

@ -10,6 +10,11 @@ from litex.build.generic_platform import *
from litex.build import tools from litex.build import tools
from litex.build.lattice import common 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 = { nextpnr_ecp5_architectures = {
"lfe5u-25f": "25k", "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: class LatticePrjTrellisToolchain:
attr_translate = { attr_translate = {
# FIXME: document # FIXME: document
@ -52,26 +138,23 @@ class LatticePrjTrellisToolchain:
platform.finalize(fragment) platform.finalize(fragment)
v_output = platform.get_verilog(fragment) v_output = platform.get_verilog(fragment)
named_sc, named_pc = platform.resolve_signals(v_output.ns)
v_file = build_name + ".v" v_file = build_name + ".v"
v_output.write(v_file) v_output.write(v_file)
platform.add_source(v_file) platform.add_source(v_file)
# generate yosys script # generate iowrapper (with constraints and trellis_ios)
def yosys_import_sources(platform): # FIXME: remove when prjtrellis will support constraint files
includes = "" iowrapper_file = build_name + "_iowrapper.v"
reads = [] iowrapper_contents = generate_prjtrellis_iowrapper(platform, v_output.ns)
for path in platform.verilog_include_paths: iowrapper_contents = iowrapper_contents.format(build_name=build_name)
includes += " -I" + path tools.write_to_file(iowrapper_file, iowrapper_contents)
for filename, language, library in platform.sources: platform.add_source(iowrapper_file)
reads.append("read_{}{} {}".format(
language, includes, filename))
return "\n".join(reads)
# generate yosys script
yosys_script_file = build_name + ".ys" yosys_script_file = build_name + ".ys"
yosys_script_contents = [ yosys_script_contents = [
yosys_import_sources(platform), 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 = "\n".join(yosys_script_contents)
yosys_script_contents = yosys_script_contents.format(build_name=build_name) yosys_script_contents = yosys_script_contents.format(build_name=build_name)