Skip to content

Commit

Permalink
Merge pull request #1617 from trabucayre/colognechip
Browse files Browse the repository at this point in the history
build: adding colognechip toolchain
  • Loading branch information
enjoy-digital authored Oct 5, 2023
2 parents c0d3766 + 1370f50 commit ffc38c0
Show file tree
Hide file tree
Showing 4 changed files with 357 additions and 0 deletions.
1 change: 1 addition & 0 deletions litex/build/colognechip/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from litex.build.colognechip.platform import CologneChipPlatform
156 changes: 156 additions & 0 deletions litex/build/colognechip/colognechip.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
#
# This file is part of LiteX.
#
# Copyright (c) 2023 Gwenhael Goavec-Merou <[email protected]>
# 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 {}
132 changes: 132 additions & 0 deletions litex/build/colognechip/common.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
#
# This file is part of LiteX.
#
# Copyright (c) 2023 Gwenhael Goavec-Merou <[email protected]>
# 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,
}
68 changes: 68 additions & 0 deletions litex/build/colognechip/platform.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
#
# This file is part of LiteX.
#
# Copyright (c) 2023 Gwenhael Goavec-Merou <[email protected]>
# 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)

0 comments on commit ffc38c0

Please sign in to comment.