Loading files
This file is pinned to the selected release. Download the original to open it in your design tool.
#
# This file is part of LiteX.
#
# Copyright (c) 2012-2022 Florent Kermarrec <florent@enjoy-digital.fr>
# Copyright (c) 2022 Gwenhael Goavec-Merou <gwenhael.goavec-merou@trabucayre.com>
# SPDX-License-Identifier: BSD-2-Clause
import os
import math
from migen.fhdl.structure import Signal, _Fragment
from litex.gen import LiteXContext
# Generic Toolchain --------------------------------------------------------------------------------
class GenericToolchain:
attr_translate = {
"keep": ("keep", "true"),
}
supported_build_backend = ["litex"]
_support_mixed_language = True
def __init__(self):
self.clocks = dict()
self.false_paths = set()
self.named_pc = []
self.named_sc = []
self._vns = None
self._synth_opts = ""
# Set Toolchain to LiteXContext.
LiteXContext.toolchain = self
@property
def support_mixed_language(self):
return self._support_mixed_language
def finalize(self):
pass # Pass since optional.
def build_io_constraints(self):
raise NotImplementedError("GenericToolchain.build_io_constraints must be overloaded.")
def build_placement_constraints(self):
return ("","") # Empty since optional.
def build_timing_constraints(self, vns):
return ("","") # Empty since optional.
def build_project(self):
pass # Pass since optional.
def build_script(self):
raise NotImplementedError("GenericToolchain.build_script must be overloaded.")
def run_script(self, script):
raise NotImplementedError("GenericToolchain.run_script must be overloaded.")
def get_tool_options(self):
return ("",{}) # empty since optional.
def build(self, platform, fragment,
build_dir = "build",
build_name = "top",
synth_opts = "",
run = True,
build_backend = "litex",
**kwargs):
self._build_name = build_name
self._build_dir = build_dir
self._synth_opts += synth_opts
self.platform = platform
self.fragment = fragment
# Create Build Directory.
os.makedirs(self._build_dir, exist_ok=True)
cwd = os.getcwd()
os.chdir(self._build_dir)
try:
# Finalize Design.
if not isinstance(self.fragment, _Fragment):
self.fragment = self.fragment.get_fragment()
platform.finalize(self.fragment)
# Generate Verilog.
v_output = platform.get_verilog(self.fragment, name=build_name, **kwargs)
self._vns = v_output.ns
v_file = build_name + ".v"
v_output.write(v_file)
# Finalize toolchain (after gateware is complete)
self.finalize()
# Get signals and platform constraints
self.named_sc, self.named_pc = platform.resolve_signals(self._vns)
platform.add_source(v_file)
# Generate Design Timing Constraints File.
tim_cst_file = self.build_timing_constraints(v_output.ns)
# Generate Design IO Constraints File.
io_cst_file = self.build_io_constraints()
# Generate Design Placement Constraints File.
place_cst_file = self.build_placement_constraints()
if build_backend not in self.supported_build_backend:
raise NotImplementedError("Build backend {build_backend} is not supported by {toolchain} toolchain".format(
build_backend = build_backend,
toolchain = type(self).__name__)
)
# LiteX backend.
if build_backend == "litex":
# Generate project.
self.build_project()
# Generate build script.
script = self.build_script()
# Run.
if run:
self.run_script(script)
# Edalize backend.
else:
from edalize import get_edatool
# Get tool name and options
(tool, tool_options) = self.get_tool_options()
# Files list
files = []
for filename, language, library, *copy in self.platform.sources:
if language is None:
continue
ext = {
"verilog" : "verilogSource",
"systemverilog": "systemVerilogSource",
"vhdl" : "vhdlSource"
}[language]
files.append({'name': filename, 'file_type': ext})
# IO/timings constraints
files.append({'name':os.path.abspath(io_cst_file[0]), 'file_type':io_cst_file[1]})
if tim_cst_file[0] != "":
files.append({'name':os.path.abspath(tim_cst_file[0]), 'file_type':tim_cst_file[1]})
if place_cst_file[0] != "":
files.append({'name':os.path.abspath(place_cst_file[0]), 'file_type':place_cst_file[1]})
edam = {
'name' : self._build_name,
'files' : files,
**tool_options,
'toplevel' : self._build_name,
}
backend = get_edatool(tool)(edam=edam, work_root=self._build_dir)
backend.configure()
if run:
backend.build()
return v_output.ns
finally:
os.chdir(cwd)
def add_period_constraint(self, platform, clk, period, keep=True, name=None):
if clk is None:
return
if hasattr(clk, "p"):
clk = clk.p
if keep:
clk.attr.add("keep")
period = math.floor(period*1e3)/1e3 # Round to lowest picosecond.
if clk in self.clocks:
if period != self.clocks[clk][0]:
raise ValueError("Clock already constrained to {:.2f}ns, new constraint to {:.2f}ns"
.format(self.clocks[clk][0], period))
self.clocks[clk] = [period, name]
def add_false_path_constraint(self, platform, from_, to, keep=True):
if keep:
if isinstance(from_, Signal):
from_.attr.add("keep")
if isinstance(to, Signal):
to.attr.add("keep")
self.false_paths.add((from_, to))
d368afb60This file is pinned to the selected release. Download the original to open it in your design tool.