commit
c700f9d0ef
|
@ -0,0 +1,144 @@
|
|||
#
|
||||
# This file is part of LiteX.
|
||||
#
|
||||
# Copyright (c) 2022 Gwenhael Goavec-Merou <gwenhael.goavec-merou@trabucayre.com>
|
||||
# Copyright (c) 2022 Florent Kermarrec <florent@enjoy-digital.fr>
|
||||
# SPDX-License-Identifier: BSD-2-Clause
|
||||
|
||||
import os
|
||||
|
||||
from migen import *
|
||||
|
||||
# VHDLWrapper --------------------------------------------------------------------------------------
|
||||
|
||||
class VHDLWrapper(Module):
|
||||
"""
|
||||
VHDLWrapper simplify use of VHDL code: used to convert with ghdl the code if
|
||||
needed or simply pass list of files to platform. May also add an Instance.
|
||||
Attributes
|
||||
==========
|
||||
_top_entity: str
|
||||
name of the core highest level entity
|
||||
_build_dir: str
|
||||
directory where .ys and .v must be written and where to build
|
||||
_work_package: str
|
||||
when package is not default one, used to provides its name
|
||||
_platform: subclass of GenericPlatform
|
||||
current platform
|
||||
_sources: list
|
||||
list of files contained into the core (relative or absolute path)
|
||||
_params: dict
|
||||
Instance like params (p_ generics, o_ output, ...) when add_instance,
|
||||
generics without prefix otherwise
|
||||
_add_instance: bool
|
||||
add if True an Instance()
|
||||
_force_convert: bool
|
||||
force use of GHDL even if the platform supports VHDL
|
||||
_ghdl_opts: str
|
||||
options to pass to ghdl
|
||||
"""
|
||||
def __init__(self, platform, top_entity, build_dir,
|
||||
work_package = None,
|
||||
force_convert = False,
|
||||
add_instance = False,
|
||||
params = dict(),
|
||||
files = list()):
|
||||
"""
|
||||
constructor (see class attributes)
|
||||
"""
|
||||
self._top_entity = top_entity
|
||||
self._build_dir = build_dir
|
||||
self._work_package = work_package
|
||||
self._platform = platform
|
||||
self._sources = files
|
||||
self._params = params
|
||||
self._force_convert = force_convert
|
||||
self._add_instance = add_instance
|
||||
|
||||
self._ghdl_opts = "--ieee=synopsys -fexplicit -frelaxed-rules --std=08 "
|
||||
if work_package is not None:
|
||||
self._ghdl_opts += f"--work={self._work_package} "
|
||||
self._ghdl_opts += "\\"
|
||||
|
||||
def add_source(self, filename):
|
||||
"""
|
||||
append the source list with the path + name of a file
|
||||
Parameters
|
||||
==========
|
||||
filename: str
|
||||
file name + path
|
||||
"""
|
||||
self._sources.append(filename)
|
||||
|
||||
def add_sources(self, path, filenames):
|
||||
"""
|
||||
append the source list with a list of file after adding path
|
||||
Parameters
|
||||
==========
|
||||
path: str
|
||||
absolute or relative path for all files
|
||||
filenames: list
|
||||
list of file to add
|
||||
"""
|
||||
self._sources += [os.path.join(path, f) for f in filenames]
|
||||
|
||||
def do_finalize(self):
|
||||
"""
|
||||
- convert vhdl to verilog when toolchain can't deal with VHDL or
|
||||
when force_convert is set to true
|
||||
- appends platform file's list with the list of VHDL sources or
|
||||
with resulting verilog
|
||||
- add an Instance for this core
|
||||
"""
|
||||
inst_name = self._top_entity
|
||||
|
||||
# platform able to synthesis verilog and vhdl -> no conversion
|
||||
if self._platform.support_mixed_language and not self._force_convert:
|
||||
ip_params = self._params
|
||||
for file in self._files:
|
||||
platform.add_source(file)
|
||||
else: # platform is only able to synthesis verilog -> convert vhdl to verilog
|
||||
# check if more than one core is instanciated
|
||||
# if so -> append with _X
|
||||
# FIXME: better solution ?
|
||||
v_list = []
|
||||
for file, _, _ in self._platform.sources:
|
||||
if self._top_entity in file:
|
||||
v_list.append(file)
|
||||
if len(v_list) != 0:
|
||||
inst_name += f"_{len(v_list)}"
|
||||
|
||||
verilog_out = os.path.join(self._build_dir, f"{inst_name}.v")
|
||||
script = os.path.join(self._build_dir, f"{inst_name}.ys")
|
||||
ys = []
|
||||
ys.append("ghdl " + self._ghdl_opts)
|
||||
|
||||
ip_params = dict()
|
||||
generics = []
|
||||
if self._add_instance:
|
||||
for k, v in self._params.items():
|
||||
if k.startswith("p_"):
|
||||
ys.append("-g" + k[2:] + "=" + str(v) + " \\")
|
||||
else:
|
||||
ip_params[k] = v
|
||||
else:
|
||||
ip_params = self._params
|
||||
|
||||
from litex.build import tools
|
||||
import subprocess
|
||||
for source in self._sources:
|
||||
ys.append(source + " \\")
|
||||
ys.append(f"-e {self._top_entity}")
|
||||
ys.append("chformal -assert -remove")
|
||||
ys.append("write_verilog {}".format(verilog_out))
|
||||
tools.write_to_file(script, "\n".join(ys))
|
||||
if subprocess.call(["yosys", "-q", "-m", "ghdl", script]):
|
||||
raise OSError(f"Unable to convert {inst_name} to verilog, please check your GHDL-Yosys-plugin install")
|
||||
|
||||
# more than one instance of this core? rename top entity to avoid conflict
|
||||
if inst_name != self._top_entity:
|
||||
tools.replace_in_file(verilog_out, f"module {self._top_entity}(", f"module {inst_name}(")
|
||||
self._platform.add_source(verilog_out)
|
||||
|
||||
if self._add_instance:
|
||||
self.specials += Instance(inst_name, **ip_params)
|
|
@ -323,6 +323,7 @@ class ConstraintManager:
|
|||
|
||||
class GenericPlatform:
|
||||
def __init__(self, device, io, connectors=[], name=None):
|
||||
self.toolchain = None
|
||||
self.device = device
|
||||
self.constraint_manager = ConstraintManager(io, connectors)
|
||||
if name is None:
|
||||
|
@ -462,3 +463,7 @@ class GenericPlatform:
|
|||
|
||||
def create_programmer(self):
|
||||
raise NotImplementedError
|
||||
|
||||
@property
|
||||
def support_mixed_language(self):
|
||||
return self.toolchain.support_mixed_language
|
||||
|
|
|
@ -18,6 +18,7 @@ class GenericToolchain:
|
|||
}
|
||||
|
||||
supported_build_backend = ["litex"]
|
||||
_support_mixed_language = True
|
||||
|
||||
def __init__(self):
|
||||
self.clocks = dict()
|
||||
|
@ -27,6 +28,10 @@ class GenericToolchain:
|
|||
self._vns = None
|
||||
self._synth_opts = ""
|
||||
|
||||
@property
|
||||
def support_mixed_language(self):
|
||||
return self._support_mixed_language
|
||||
|
||||
def finalize(self):
|
||||
pass # Pass since optional.
|
||||
|
||||
|
|
|
@ -57,10 +57,13 @@ class YosysNextPNRToolchain(GenericToolchain):
|
|||
target package (optional/target dependant)
|
||||
_speed_grade: str
|
||||
target speed grade (optional/target dependant)
|
||||
_support_mixed_language: bool
|
||||
informs if toolchain is able to use only verilog or verilog + vhdl
|
||||
"""
|
||||
attr_translate = {
|
||||
"keep": ("keep", "true"),
|
||||
}
|
||||
_support_mixed_language = False
|
||||
|
||||
family = ""
|
||||
synth_fmt = ""
|
||||
|
|
|
@ -8,6 +8,8 @@ import os
|
|||
|
||||
from migen import *
|
||||
|
||||
from litex.build.VHDLWrapper import *
|
||||
|
||||
from litex.soc.interconnect import wishbone
|
||||
from litex.soc.cores.cpu import CPU, CPU_GCC_TRIPLE_RISCV32
|
||||
|
||||
|
@ -97,15 +99,21 @@ class NEORV32(CPU):
|
|||
i_wb_err_i = idbus.err,
|
||||
)
|
||||
|
||||
self.submodules.vhdlwrapper = VHDLWrapper(platform,
|
||||
top_entity = "neorv32_litex_core_complex",
|
||||
build_dir = os.path.abspath(os.path.dirname(__file__)),
|
||||
work_package = "neorv32",
|
||||
force_convert = True,
|
||||
)
|
||||
|
||||
# Add Verilog sources
|
||||
self.add_sources(platform, variant)
|
||||
self.add_sources(variant)
|
||||
|
||||
def set_reset_address(self, reset_address):
|
||||
self.reset_address = reset_address
|
||||
assert reset_address == 0x0000_0000
|
||||
|
||||
@staticmethod
|
||||
def add_sources(platform, variant):
|
||||
def add_sources(self, variant):
|
||||
cdir = os.path.abspath(os.path.dirname(__file__))
|
||||
# List VHDL sources.
|
||||
sources = {
|
||||
|
@ -152,6 +160,7 @@ class NEORV32(CPU):
|
|||
# Download VHDL sources (if not already present).
|
||||
for directory, vhds in sources.items():
|
||||
for vhd in vhds:
|
||||
self.vhdlwrapper.add_source(os.path.join(cdir, vhd))
|
||||
if not os.path.exists(os.path.join(cdir, vhd)):
|
||||
os.system(f"wget https://raw.githubusercontent.com/stnolting/neorv32/main/rtl/{directory}/{vhd} -P {cdir}")
|
||||
|
||||
|
@ -188,22 +197,6 @@ class NEORV32(CPU):
|
|||
variant = variant,
|
||||
)
|
||||
|
||||
# Convert VHDL to Verilog through GHDL/Yosys.
|
||||
from litex.build import tools
|
||||
import subprocess
|
||||
cdir = os.path.dirname(__file__)
|
||||
ys = []
|
||||
ys.append("ghdl --ieee=synopsys -fexplicit -frelaxed-rules --std=08 --work=neorv32 \\")
|
||||
for directory, vhds in sources.items():
|
||||
for vhd in vhds:
|
||||
ys.append(os.path.join(cdir, vhd) + " \\")
|
||||
ys.append("-e neorv32_litex_core_complex")
|
||||
ys.append("chformal -assert -remove")
|
||||
ys.append("write_verilog {}".format(os.path.join(cdir, "neorv32_litex_core_complex.v")))
|
||||
tools.write_to_file(os.path.join(cdir, "neorv32_litex_core_complex.ys"), "\n".join(ys))
|
||||
if subprocess.call(["yosys", "-q", "-m", "ghdl", os.path.join(cdir, "neorv32_litex_core_complex.ys")]):
|
||||
raise OSError("Unable to convert NEORV32 CPU to verilog, please check your GHDL-Yosys-plugin install.")
|
||||
platform.add_source(os.path.join(cdir, "neorv32_litex_core_complex.v"))
|
||||
|
||||
def do_finalize(self):
|
||||
assert hasattr(self, "reset_address")
|
||||
|
|
Loading…
Reference in New Issue