Merge pull request #1617 from trabucayre/colognechip
build: adding colognechip toolchain
This commit is contained in:
commit
ffc38c0e7c
|
@ -0,0 +1 @@
|
||||||
|
from litex.build.colognechip.platform import CologneChipPlatform
|
|
@ -0,0 +1,156 @@
|
||||||
|
#
|
||||||
|
# This file is part of LiteX.
|
||||||
|
#
|
||||||
|
# Copyright (c) 2023 Gwenhael Goavec-Merou <gwenhael.goavec-merou@trabubucayre.com>
|
||||||
|
# SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import math
|
||||||
|
import subprocess
|
||||||
|
from shutil import which, copyfile
|
||||||
|
|
||||||
|
from migen.fhdl.structure import _Fragment
|
||||||
|
|
||||||
|
from litex.build.generic_platform import *
|
||||||
|
from litex.build import tools
|
||||||
|
from litex.build.generic_toolchain import GenericToolchain
|
||||||
|
from litex.build.yosys_wrapper import YosysWrapper, yosys_args, yosys_argdict
|
||||||
|
|
||||||
|
|
||||||
|
# CologneChipToolchain -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
class CologneChipToolchain(GenericToolchain):
|
||||||
|
attr_translate = {}
|
||||||
|
supported_build_backend = ["litex", "edalize"]
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
self._yosys = None
|
||||||
|
self._yosys_cmds = []
|
||||||
|
self._synth_opts = "-nomx8 "
|
||||||
|
|
||||||
|
def finalize(self):
|
||||||
|
self._yosys = YosysWrapper(
|
||||||
|
platform = self.platform,
|
||||||
|
build_name = self._build_name,
|
||||||
|
target = "gatemate",
|
||||||
|
output_name = self._build_name+"_synth",
|
||||||
|
template = [],
|
||||||
|
yosys_opts = self._synth_opts,
|
||||||
|
yosys_cmds = self._yosys_cmds,
|
||||||
|
synth_format = "v",
|
||||||
|
)
|
||||||
|
|
||||||
|
# IO Constraints (.ccf) ------------------------------------------------------------------------
|
||||||
|
|
||||||
|
def _get_pin_direction(self, pinname):
|
||||||
|
pins = self.platform.constraint_manager.get_io_signals()
|
||||||
|
for pin in sorted(pins, key=lambda x: x.duid):
|
||||||
|
if (pinname.split("[")[0] == pin.name):
|
||||||
|
if pin.direction == "output":
|
||||||
|
return "Pin_out"
|
||||||
|
elif pin.direction == "input":
|
||||||
|
return "Pin_in"
|
||||||
|
else:
|
||||||
|
return "Pin_inout"
|
||||||
|
return "Unknown"
|
||||||
|
|
||||||
|
def build_io_constraints(self):
|
||||||
|
ccf = []
|
||||||
|
|
||||||
|
flat_sc = []
|
||||||
|
for name, pins, other, resource in self.named_sc:
|
||||||
|
if len(pins) > 1:
|
||||||
|
for i, p in enumerate(pins):
|
||||||
|
flat_sc.append((f"{name}[{i}]", p, other))
|
||||||
|
else:
|
||||||
|
flat_sc.append((name, pins[0], other))
|
||||||
|
|
||||||
|
for name, pin, other in flat_sc:
|
||||||
|
pin_cst = ""
|
||||||
|
if pin != "X":
|
||||||
|
direction = self._get_pin_direction(name)
|
||||||
|
pin_cst = f"{direction} \"{name}\" Loc = \"{pin}\""
|
||||||
|
|
||||||
|
for c in other:
|
||||||
|
if isinstance(c, Misc):
|
||||||
|
pin_cst += f" | {c.misc}"
|
||||||
|
pin_cst += ";"
|
||||||
|
ccf.append(pin_cst)
|
||||||
|
|
||||||
|
if self.named_pc:
|
||||||
|
ccf.extend(self.named_pc)
|
||||||
|
|
||||||
|
tools.write_to_file(f"{self._build_name}.ccf", "\n".join(ccf))
|
||||||
|
return (f"{self._build_name}.ccf", "CCF")
|
||||||
|
|
||||||
|
# Project (.ys) --------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
def build_project(self):
|
||||||
|
""" create project files (mainly Yosys ys file)
|
||||||
|
"""
|
||||||
|
self._yosys.build_script()
|
||||||
|
|
||||||
|
# Script ---------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
def build_script(self):
|
||||||
|
""" create build_xxx.yy by using Yosys and p_r instances.
|
||||||
|
Return
|
||||||
|
======
|
||||||
|
the script name (str)
|
||||||
|
"""
|
||||||
|
|
||||||
|
if sys.platform in ("win32", "cygwin"):
|
||||||
|
script_ext = ".bat"
|
||||||
|
script_contents = "@echo off\nrem Autogenerated by LiteX / git: " + tools.get_litex_git_revision() + "\n\n"
|
||||||
|
fail_stmt = " || exit /b"
|
||||||
|
else:
|
||||||
|
script_ext = ".sh"
|
||||||
|
script_contents = "# Autogenerated by LiteX / git: " + tools.get_litex_git_revision() + "\nset -e\n"
|
||||||
|
fail_stmt = ""
|
||||||
|
fail_stmt += "\n"
|
||||||
|
|
||||||
|
# yosys call
|
||||||
|
script_contents += self._yosys.get_yosys_call("script") + fail_stmt
|
||||||
|
# p_r call
|
||||||
|
script_contents += "p_r -ccf {build_name}.ccf -A 1 -i {build_name}_synth.v -o {build_name} -lib ccag\n".format(
|
||||||
|
build_name = self._build_name)
|
||||||
|
|
||||||
|
script_file = "build_" + self._build_name + script_ext
|
||||||
|
tools.write_to_file(script_file, script_contents, force_unix=False)
|
||||||
|
|
||||||
|
return script_file
|
||||||
|
|
||||||
|
def run_script(self, script):
|
||||||
|
""" run build_xxx.yy script
|
||||||
|
Parameters
|
||||||
|
==========
|
||||||
|
script: str
|
||||||
|
script name to use
|
||||||
|
"""
|
||||||
|
if sys.platform in ("win32", "cygwin"):
|
||||||
|
shell = ["cmd", "/c"]
|
||||||
|
else:
|
||||||
|
shell = ["bash"]
|
||||||
|
|
||||||
|
if which("yosys") is None or which("p_r") is None:
|
||||||
|
msg = "Unable to find CologneChip toolchain, please:\n"
|
||||||
|
msg += "- Add Yosys/p_r toolchain to your $PATH."
|
||||||
|
raise OSError(msg)
|
||||||
|
|
||||||
|
if subprocess.call(shell + [script]) != 0:
|
||||||
|
raise OSError("Error occured during Yosys/p_r's script execution.")
|
||||||
|
|
||||||
|
|
||||||
|
def add_period_constraint(self, platform, clk, period):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def colognechip_args(parser):
|
||||||
|
# TODO: yosys (default's yosys aren't supported
|
||||||
|
# TODO: p_r args
|
||||||
|
pass
|
||||||
|
|
||||||
|
def colognechip_argdict(args):
|
||||||
|
# TODO: ditto
|
||||||
|
return {}
|
|
@ -0,0 +1,132 @@
|
||||||
|
#
|
||||||
|
# This file is part of LiteX.
|
||||||
|
#
|
||||||
|
# Copyright (c) 2023 Gwenhael Goavec-Merou <gwenhael.goavec-merou@trabucayre.com>
|
||||||
|
# SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
|
||||||
|
from migen.fhdl.module import Module
|
||||||
|
from migen.genlib.resetsync import AsyncResetSynchronizer
|
||||||
|
|
||||||
|
from litex.build.io import *
|
||||||
|
|
||||||
|
# CologneChip AsyncResetSynchronizer ---------------------------------------------------------------
|
||||||
|
|
||||||
|
class CologneChipAsyncResetSynchronizerImpl(Module):
|
||||||
|
def __init__(self, cd, async_reset):
|
||||||
|
rst1 = Signal()
|
||||||
|
self.specials += [
|
||||||
|
Instance("CC_DFF",
|
||||||
|
p_CLK_INV = 0,
|
||||||
|
p_EN_INV = 0,
|
||||||
|
p_SR_INV = 0,
|
||||||
|
p_SR_VAL = 1,
|
||||||
|
i_D = 0,
|
||||||
|
i_CLK = cd.clk,
|
||||||
|
i_EN = 1,
|
||||||
|
i_SR = async_reset,
|
||||||
|
o_Q = rst1),
|
||||||
|
Instance("CC_DFF",
|
||||||
|
p_CLK_INV = 0,
|
||||||
|
p_EN_INV = 0,
|
||||||
|
p_SR_INV = 0,
|
||||||
|
p_SR_VAL = 1,
|
||||||
|
i_D = rst1,
|
||||||
|
i_CLK = cd.clk,
|
||||||
|
i_EN = 1,
|
||||||
|
i_SR = async_reset,
|
||||||
|
o_Q = cd.rst)
|
||||||
|
]
|
||||||
|
|
||||||
|
class CologneChipAsyncResetSynchronizer:
|
||||||
|
@staticmethod
|
||||||
|
def lower(dr):
|
||||||
|
return CologneChipAsyncResetSynchronizerImpl(dr.cd, dr.async_reset)
|
||||||
|
|
||||||
|
# CologneChip DDR Input ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
class CologneChipDDRInputImpl(Module):
|
||||||
|
def __init__(self, i, o1, o2, clk):
|
||||||
|
self.specials += Instance("CC_IDDR",
|
||||||
|
i_CLK = clk,
|
||||||
|
i_D = i,
|
||||||
|
o_Q0 = o1,
|
||||||
|
o_Q1 = o2,
|
||||||
|
)
|
||||||
|
|
||||||
|
class CologneChipDDRInput:
|
||||||
|
@staticmethod
|
||||||
|
def lower(dr):
|
||||||
|
return CologneChipInputImpl(dr.i, dr.o1, dr.o2, dr.clk)
|
||||||
|
|
||||||
|
# CologneChip DDR Output ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
class CologneChipDDROutputImpl(Module):
|
||||||
|
def __init__(self, i1, i2, o, clk):
|
||||||
|
self.specials += Instance("CC_ODDR",
|
||||||
|
p_CLK_INV = 0,
|
||||||
|
i_CLK = clk,
|
||||||
|
i_DDR = ~clk,
|
||||||
|
i_D0 = i1,
|
||||||
|
i_D1 = i2,
|
||||||
|
o_Q = o,
|
||||||
|
)
|
||||||
|
|
||||||
|
class CologneChipDDROutput:
|
||||||
|
@staticmethod
|
||||||
|
def lower(dr):
|
||||||
|
return CologneChipDDROutputImpl(dr.i1, dr.i2, dr.o, dr.clk)
|
||||||
|
|
||||||
|
# CologneChip Differential Input -------------------------------------------------------------------
|
||||||
|
|
||||||
|
class CologneChipDifferentialInputImpl(Module):
|
||||||
|
def __init__(self, i_p, i_n, o):
|
||||||
|
self.specials += Instance("CC_LVDS_IBUF",
|
||||||
|
i_I_P = i_p,
|
||||||
|
i_I_N = i_n,
|
||||||
|
o_Y = o,
|
||||||
|
)
|
||||||
|
|
||||||
|
class CologneChipDifferentialInput:
|
||||||
|
@staticmethod
|
||||||
|
def lower(dr):
|
||||||
|
return CologneChipDifferentialInputImpl(dr.i_p, dr.i_n, dr.o)
|
||||||
|
|
||||||
|
# CologneChip Differential Output ------------------------------------------------------------------
|
||||||
|
|
||||||
|
class CologneChipDifferentialOutputImpl(Module):
|
||||||
|
def __init__(self, i, o_p, o_n):
|
||||||
|
self.specials += Instance("CC_LVDS_OBUF",
|
||||||
|
i_A = i,
|
||||||
|
o_O_P = o_p,
|
||||||
|
o_O_N = o_n,
|
||||||
|
)
|
||||||
|
|
||||||
|
class CologneChipDifferentialOutput:
|
||||||
|
@staticmethod
|
||||||
|
def lower(dr):
|
||||||
|
return CologneChipDifferentialOutputImpl(dr.i, dr.o_p, dr.o_n)
|
||||||
|
|
||||||
|
# CologneChip SDR Input ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
class CologneChipSDRInputImpl(Module):
|
||||||
|
def __init__(self, i, o):
|
||||||
|
self.specials += Instance("CC_IBUF",
|
||||||
|
i_I = i,
|
||||||
|
o_O = o,
|
||||||
|
)
|
||||||
|
|
||||||
|
class CologneChipSDRInput:
|
||||||
|
@staticmethod
|
||||||
|
def lower(dr):
|
||||||
|
return CologneChipSDRInput(dr.i, dr.o)
|
||||||
|
|
||||||
|
# CologneChip Special Overrides --------------------------------------------------------------------
|
||||||
|
|
||||||
|
colognechip_special_overrides = {
|
||||||
|
AsyncResetSynchronizer: CologneChipAsyncResetSynchronizer,
|
||||||
|
DDRInput: CologneChipDDRInput,
|
||||||
|
DDROutput: CologneChipDDROutput,
|
||||||
|
DifferentialInput: CologneChipDifferentialInput,
|
||||||
|
DifferentialOutput: CologneChipDifferentialOutput,
|
||||||
|
SDRInput: CologneChipSDRInput,
|
||||||
|
}
|
|
@ -0,0 +1,68 @@
|
||||||
|
#
|
||||||
|
# This file is part of LiteX.
|
||||||
|
#
|
||||||
|
# Copyright (c) 2023 Gwenhael Goavec-Merou <gwenhael.goavec-merou@trabubucayre.com>
|
||||||
|
# SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
|
from litex.build.generic_platform import GenericPlatform
|
||||||
|
from litex.build.colognechip import common, colognechip
|
||||||
|
|
||||||
|
# CologneChipPlatform ------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
class CologneChipPlatform(GenericPlatform):
|
||||||
|
bitstream_ext = "_00.cfg.bit"
|
||||||
|
|
||||||
|
_supported_toolchains = ["colognechip"]
|
||||||
|
|
||||||
|
def __init__(self, device, *args, toolchain="colognechip", devicename=None, **kwargs):
|
||||||
|
GenericPlatform.__init__(self, device, *args, **kwargs)
|
||||||
|
|
||||||
|
self.toolchain = colognechip.CologneChipToolchain()
|
||||||
|
|
||||||
|
def get_verilog(self, *args, special_overrides=dict(), **kwargs):
|
||||||
|
so = dict(common.colognechip_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)
|
||||||
|
|
||||||
|
def add_period_constraint(self, clk, period):
|
||||||
|
if clk is None: return
|
||||||
|
self.toolchain.add_period_constraint(self, clk, period)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def fill_args(cls, toolchain, parser):
|
||||||
|
"""
|
||||||
|
pass parser to the specific toolchain to
|
||||||
|
fill this with toolchain args
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
==========
|
||||||
|
toolchain: str
|
||||||
|
toolchain name
|
||||||
|
parser: argparse.ArgumentParser
|
||||||
|
parser to be filled
|
||||||
|
"""
|
||||||
|
colognechip.colognechip_args(parser)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_argdict(cls, toolchain, args):
|
||||||
|
"""
|
||||||
|
return a dict of args
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
==========
|
||||||
|
toolchain: str
|
||||||
|
toolchain name
|
||||||
|
|
||||||
|
Return
|
||||||
|
======
|
||||||
|
a dict of key/value for each args or an empty dict
|
||||||
|
"""
|
||||||
|
return colognechip.colognechip_argdict(args)
|
Loading…
Reference in New Issue