build: Add initial/minimal QuickLogic build support.

This commit is contained in:
Florent Kermarrec 2021-10-01 11:00:36 +02:00
parent 16702c44fe
commit cb6861e1c8
4 changed files with 159 additions and 0 deletions

View File

@ -0,0 +1 @@
from litex.build.quicklogic.platform import QuickLogicPlatform

View File

@ -0,0 +1,9 @@
#
# This file is part of LiteX.
#
# Copyright (c) 2021 Florent Kermarrec <florent@enjoy-digital.fr>
# SPDX-License-Identifier: BSD-2-Clause
# QuickLogic Special Overrides ---------------------------------------------------------------------
quicklogic_special_overrides = {}

View File

@ -0,0 +1,33 @@
#
# This file is part of LiteX.
#
# Copyright (c) 2021 Florent Kermarrec <florent@enjoy-digital.fr>
# SPDX-License-Identifier: BSD-2-Clause
import os
from litex.build.generic_platform import GenericPlatform
from litex.build.quicklogic import common, symbiflow
# QuickLogicPlatform -------------------------------------------------------------------------------
class QuickLogicPlatform(GenericPlatform):
bitstream_ext = ".bit"
def __init__(self, device, *args, toolchain="symbiflow", **kwargs):
GenericPlatform.__init__(self, device, *args, **kwargs)
if toolchain == "symbiflow":
self.toolchain = symbiflow.SymbiflowToolchain()
else:
raise ValueError("Unknown toolchain")
def get_verilog(self, *args, special_overrides=dict(), **kwargs):
so = dict(common.quicklogic_special_overrides)
so.update(special_overrides)
return GenericPlatform.get_verilog(self, *args,
special_overrides = so,
attr_translate = self.toolchain.attr_translate,
**kwargs)
def build(self, *args, **kwargs):
return self.toolchain.build(self, *args, **kwargs)

View File

@ -0,0 +1,116 @@
#
# This file is part of LiteX.
#
# Copyright (c) 2021 Florent Kermarrec <florent@enjoy-digital.fr>
# SPDX-License-Identifier: BSD-2-Clause
import os
import sys
import subprocess
from shutil import which
from migen.fhdl.structure import _Fragment
from litex.build.generic_platform import *
from litex.build import tools
from litex.build.quicklogic import common
# IO Constraints (.pcf) ----------------------------------------------------------------------------
def _format_io_pcf(signame, pin, others):
r = f"set_io {signame} {Pins(pin).identifiers[0]}\n"
return r
def _build_io_pcf(named_sc, named_pc, build_name):
pcf = ""
for sig, pins, others, resname in named_sc:
if len(pins) > 1:
for i, p in enumerate(pins):
pcf += _format_io_pcf(sig + "(" + str(i) + ")", p, others)
else:
pcf += _format_io_pcf(sig, pins[0], others)
tools.write_to_file(build_name + ".pcf", pcf)
# Build Makefile -----------------------------------------------------------------------------------
def _build_makefile(platform, sources, build_dir, build_name):
makefile = []
# Define Paths.
makefile.append("mkfile_path := $(abspath $(lastword $(MAKEFILE_LIST)))")
makefile.append("current_dir := $(patsubst %/,%,$(dir $(mkfile_path)))")
# Create Project.
# FIXME: Only use top file for now and ignore .init files.
makefile.append("all:")
makefile.append("\tql_symbiflow -compile -d {device} -P {part} -v {verilog} -t {top} -p {pcf}".format(
device = platform.device,
part = {"ql-eos-s3": "pd64"}.get(platform.device),
verilog = f"{build_name}.v",
top = build_name,
pcf = f"{build_name}.pcf"
))
# Generate Makefile.
tools.write_to_file("Makefile", "\n".join(makefile))
def _run_make():
make_cmd = ["make", "-j1"]
if which("ql_symbiflow") is None:
msg = "Unable to find QuickLogic Symbiflow toolchain, please:\n"
msg += "- Add QuickLogic Symbiflow toolchain to your $PATH."
raise OSError(msg)
if subprocess.call(make_cmd) != 0:
raise OSError("Error occured during QuickLogic Symbiflow's script execution.")
# SymbiflowToolchain -------------------------------------------------------------------------------
class SymbiflowToolchain:
attr_translate = {}
special_overrides = common.quicklogic_special_overrides
def __init__(self):
self.clocks = dict()
self.false_paths = set()
def build(self, platform, fragment,
build_dir = "build",
build_name = "top",
run = False,
**kwargs):
# Create build directory.
os.makedirs(build_dir, exist_ok=True)
cwd = os.getcwd()
os.chdir(build_dir)
# Finalize design.
if not isinstance(fragment, _Fragment):
fragment = fragment.get_fragment()
platform.finalize(fragment)
# Generate verilog.
v_output = platform.get_verilog(fragment, name=build_name, **kwargs)
named_sc, named_pc = platform.resolve_signals(v_output.ns)
top_file = build_name + ".v"
v_output.write(top_file)
platform.add_source(top_file)
# Generate .pcf IO constraints file.
_build_io_pcf(named_sc, named_pc, build_name)
# Generate Makefie.
_build_makefile(platform, platform.sources, build_dir, build_name)
# Run.
if run:
_run_make()
os.chdir(cwd)
return v_output.ns