# Copyright edalize contributors
# Licensed under the 2-Clause BSD License, see LICENSE for details.
# SPDX-License-Identifier: BSD-2-Clause
import os
import logging
from edalize.edatool import Edatool
logger = logging.getLogger(__name__)
MAKE_HEADER = """#Generated by Edalize
ifeq (, $(shell which xmroot))
$(error "No Xcelium installation in $(PATH)")
endif
XCELIUM_HOME = $(shell xmroot)
CC ?= gcc
CFLAGS := -c -std=c99 -fPIC -fno-stack-protector -g
LD ?= ld
LDFLAGS := -shared -E
#Only 32 bits is currently supported
CFLAGS += -m32
LDFLAGS += -melf_i386
RM ?= rm
INCS := -I$(XCELIUM_HOME)/tools/include
XRUN ?= $(XCELIUM_HOME)/tools/bin/xrun
TOPLEVEL := {toplevel}
VPI_MODULES := {modules}
PARAMETERS ?= {parameters}
PLUSARGS ?= {plusargs}
XMSIM_OPTIONS ?= {xmsim_options}
XRUN_OPTIONS ?= {xrun_options}
EXTRA_OPTIONS ?= $(XRUN_OPTIONS) $(if $(XMSIM_OPTIONS),-xmsimargs '$(XMSIM_OPTIONS)',) $(addprefix -defparam ,$(PARAMETERS)) $(addprefix +,$(PLUSARGS))
XRUN_CALL = $(XRUN) -q -f edalize_main.f $(addprefix -pli ,$(VPI_MODULES)) $(EXTRA_OPTIONS) -top $(TOPLEVEL)
all: $(VPI_MODULES)
run: $(VPI_MODULES)
$(XRUN_CALL)
run-gui: $(VPI_MODULES)
$(XRUN_CALL) -gui -access rwc
clean: {clean_targets}
"""
VPI_MAKE_SECTION = """
{name}_OBJS := {objs}
{name}_LIBS := {libs}
{name}_INCS := $(INCS) {incs}
$({name}_OBJS): %.o : %.c
$(CC) $(CFLAGS) $({name}_INCS) -o $@ $<
{name}: $({name}_OBJS)
$(LD) $(LDFLAGS) -o $@ $? $({name}_LIBS)
clean_{name}:
$(RM) $({name}_OBJS) {name}
"""
[docs]
class Xcelium(Edatool):
argtypes = ["plusarg", "vlogdefine", "vlogparam", "generic"]
[docs]
@classmethod
def get_doc(cls, api_ver):
if api_ver == 0:
return {
"description": "Xcelium simulator from Cadence Design Systems",
"lists": [
{
"name": "xmvhdl_options",
"type": "String",
"desc": "Additional options for compilation with xmvhdl",
},
{
"name": "xmvlog_options",
"type": "String",
"desc": "Additional options for compilation with xmvlog",
},
{
"name": "xmsim_options",
"type": "String",
"desc": "Additional run options for xmsim",
},
{
"name": "xrun_options",
"type": "String",
"desc": "Additional run options for xrun",
},
],
}
def _write_build_rtl_f_file(self, tcl_main):
tcl_build_rtl = open(os.path.join(self.work_root, "edalize_build_rtl.f"), "w")
(src_files, incdirs) = self._get_fileset_files()
vlog_include_dirs = ["+incdir+" + d.replace("\\", "/") for d in incdirs]
libs = []
for f in src_files:
if not f.logical_name:
f.logical_name = "worklib"
if f.file_type.startswith("verilogSource") or f.file_type.startswith(
"systemVerilogSource"
):
cmd = "xmvlog"
args = []
args += self.tool_options.get("xmvlog_options", [])
# Sort dictionary items, to ensure stable output, which makes testing easier
for k, v in self.vlogdefine.items():
args += ["+define+{}={}".format(k, self._param_value_str(v))]
if f.file_type.startswith("systemVerilogSource"):
args += ["-sv"]
args += vlog_include_dirs
elif f.file_type.startswith("vhdlSource"):
cmd = "xmvhdl"
if f.file_type.endswith("-93"):
args = ["-v93"]
if f.file_type.endswith("-2008"):
args = ["-v200x"]
else:
args = []
args += self.tool_options.get("xmvhdl_options", [])
elif f.file_type == "tclSource":
cmd = None
tcl_main.write("-input {}\n".format(f.name))
elif f.file_type == "user":
cmd = None
else:
_s = "{} has unknown file type '{}'"
logger.warning(_s.format(f.name, f.file_type))
cmd = None
if cmd:
args += [f.name.replace("\\", "/")]
line = "-makelib {} {} -endlib".format(f.logical_name, " ".join(args))
tcl_build_rtl.write(line + "\n")
def _write_makefile(self):
vpi_make = open(os.path.join(self.work_root, "Makefile"), "w")
_parameters = []
for key, value in self.vlogparam.items():
_parameters += ["{}={}".format(key, self._param_value_str(value))]
for key, value in self.generic.items():
_parameters += [
"{}={}".format(key, self._param_value_str(value, bool_is_str=True))
]
_plusargs = []
for key, value in self.plusarg.items():
_plusargs += ["{}={}".format(key, self._param_value_str(value))]
_xmsim_options = self.tool_options.get("xmsim_options", [])
_xrun_options = self.tool_options.get("xrun_options", [])
_modules = [m["name"] for m in self.vpi_modules]
_clean_targets = " ".join(["clean_" + m for m in _modules])
_s = MAKE_HEADER.format(
toplevel=self.toplevel,
parameters=" ".join(_parameters),
plusargs=" ".join(_plusargs),
xmsim_options=" ".join(_xmsim_options),
xrun_options=" ".join(_xrun_options),
modules=" ".join(_modules),
clean_targets=_clean_targets,
)
vpi_make.write(_s)
for vpi_module in self.vpi_modules:
_name = vpi_module["name"]
_objs = [os.path.splitext(s)[0] + ".o" for s in vpi_module["src_files"]]
_libs = ["-l" + l for l in vpi_module["libs"]]
_incs = ["-I" + d for d in vpi_module["include_dirs"]]
_s = VPI_MAKE_SECTION.format(
name=_name,
objs=" ".join(_objs),
libs=" ".join(_libs),
incs=" ".join(_incs),
)
vpi_make.write(_s)
vpi_make.close()
[docs]
def configure_main(self):
tcl_main = open(os.path.join(self.work_root, "edalize_main.f"), "w")
tcl_main.write("-f edalize_build_rtl.f\n")
self._write_build_rtl_f_file(tcl_main)
self._write_makefile()
tcl_main.close()
[docs]
def run_main(self):
args = ["run"]
# Set plusargs
if self.plusarg:
plusargs = []
for key, value in self.plusarg.items():
plusargs += ["{}={}".format(key, self._param_value_str(value))]
args.append("PLUSARGS=" + " ".join(plusargs))
self._run_tool("make", args)