Skip to content

Commit

Permalink
simulator: Let indivdiual simulator handle extra_args
Browse files Browse the repository at this point in the history
This is required for NVC as it has positional arguments. Things like
the VHDL revision must be placed before selecting the step (elaborate,
run, etc.), whereas specific arguments (like waves) must be placed
after the command.

This commit also includes some refactoring to clean up the simulator
class initialization, but does not change any functionality there
besides not concatenating args with extra_args.
  • Loading branch information
m42uko committed Jul 26, 2024
1 parent e3c7f2c commit fd4e803
Showing 1 changed file with 51 additions and 91 deletions.
142 changes: 51 additions & 91 deletions cocotb_test/simulator.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,12 @@ def as_tcl_value(value):

return value

# Return `variable` if not None, else return `default`
def some_or(variable, default):
if variable is None:
return default
else:
return variable

class Simulator:
def __init__(
Expand Down Expand Up @@ -85,103 +91,57 @@ def __init__(
if os.path.isdir(absworkdir):
self.work_dir = absworkdir

if python_search is None:
python_search = []

self.python_search = python_search

# Initialize from arguments
self.python_search = some_or(python_search, [])
self.toplevel = toplevel
self.toplevel_lang = toplevel_lang

if verilog_sources is None:
verilog_sources = []
self.verilog_sources = self.get_abs_paths(verilog_sources)

if vhdl_sources is None:
vhdl_sources = []
self.vhdl_sources = self.get_abs_paths(vhdl_sources)

if includes is None:
includes = []

self.includes = self.get_abs_paths(includes)

if defines is None:
defines = []

self.defines = defines

if parameters is None:
parameters = {}
self.verilog_sources = self.get_abs_paths(some_or(verilog_sources, []))
self.vhdl_sources = self.get_abs_paths(some_or(vhdl_sources, []))
self.includes = self.get_abs_paths(some_or(includes, []))
self.defines = some_or(defines, [])
self.parameters = some_or(parameters, {})
self.compile_args = some_or(compile_args, [])
self.vhdl_compile_args = some_or(vhdl_compile_args, [])
self.verilog_compile_args = some_or(verilog_compile_args, [])
self.extra_args = some_or(extra_args, [])
self.simulation_args = some_or(sim_args, [])
self.plus_args = some_or(plus_args, [])
self.force_compile = force_compile
self.compile_only = compile_only
self.waves = bool(some_or(waves, int(os.getenv("WAVES", 0))))

self.parameters = parameters
# by copy since we modify
self.env = dict(extra_env) if extra_env is not None else {}

if compile_args is None:
compile_args = []
if testcase is not None:
self.env["TESTCASE"] = testcase

if vhdl_compile_args is None:
self.vhdl_compile_args = []
else:
self.vhdl_compile_args = vhdl_compile_args
if seed is not None:
self.env["RANDOM_SEED"] = str(seed)

if verilog_compile_args is None:
self.verilog_compile_args = []
if timescale is None or re.fullmatch("\\d+[npu]?s/\\d+[npu]?s", timescale):
self.timescale = timescale
else:
self.verilog_compile_args = verilog_compile_args

if extra_args is None:
extra_args = []

self.compile_args = compile_args + extra_args

if sim_args is None:
sim_args = []
raise ValueError("Invalid timescale: {}".format(timescale))

# Backwards compatibility
if simulation_args is not None:
sim_args += simulation_args
self.simulation_args += simulation_args
warnings.warn(
"Using simulation_args is deprecated. Please use sim_args instead.",
DeprecationWarning,
stacklevel=2,
)

self.simulation_args = sim_args + extra_args

if plus_args is None:
plus_args = []

self.plus_args = plus_args
self.force_compile = force_compile
self.compile_only = compile_only

if kwargs:
warnings.warn(
"Using kwargs is deprecated. Please explicitly declare or arguments instead.",
DeprecationWarning,
stacklevel=2,
)

for arg in kwargs:
setattr(self, arg, kwargs[arg])

# by copy since we modify
self.env = dict(extra_env) if extra_env is not None else {}

if testcase is not None:
self.env["TESTCASE"] = testcase

if seed is not None:
self.env["RANDOM_SEED"] = str(seed)

if waves is None:
self.waves = bool(int(os.getenv("WAVES", 0)))
else:
self.waves = bool(waves)

if timescale is None or re.fullmatch("\\d+[npu]?s/\\d+[npu]?s", timescale):
self.timescale = timescale
else:
raise ValueError("Invalid timescale: {}".format(timescale))
for arg in kwargs:
setattr(self, arg, kwargs[arg])

self.gui = gui

Expand Down Expand Up @@ -457,7 +417,7 @@ def get_parameter_commands(self, parameters):

def compile_command(self):

compile_args = self.compile_args + self.verilog_compile_args
compile_args = self.compile_args + self.extra_args + self.verilog_compile_args

toplevel = []
for t in self.toplevel_module_list:
Expand Down Expand Up @@ -556,7 +516,7 @@ def build_command(self):
do_script = self.do_script()

if self.vhdl_sources:
compile_args = self.compile_args + self.vhdl_compile_args
compile_args = self.compile_args + self.extra_args + self.vhdl_compile_args

for lib, src in self.vhdl_sources.items():
cmd.append(["vlib", as_tcl_value(lib)])
Expand All @@ -568,7 +528,7 @@ def build_command(self):
)

if self.verilog_sources:
compile_args = self.compile_args + self.verilog_compile_args
compile_args = self.compile_args + self.extra_args + self.verilog_compile_args
if self.timescale:
compile_args += ["-timescale", self.timescale]

Expand Down Expand Up @@ -690,7 +650,7 @@ def build_command(self):
+ self.get_define_commands(self.defines)
+ self.get_include_commands(self.includes)
+ self.get_parameter_commands(self.parameters)
+ self.compile_args
+ self.compile_args + self.extra_args
+ self.verilog_sources_flat
+ self.vhdl_sources_flat
)
Expand Down Expand Up @@ -772,7 +732,7 @@ def build_command(self):
+ self.get_define_commands(self.defines)
+ self.get_include_commands(self.includes)
+ self.get_parameter_commands(self.parameters)
+ self.compile_args
+ self.compile_args + self.extra_args
+ self.verilog_sources_flat
+ self.vhdl_sources_flat
)
Expand Down Expand Up @@ -816,7 +776,7 @@ def build_command(self):
with open(do_file_path, "w") as pli_file:
pli_file.write(pli_cmd)

compile_args = self.compile_args + self.verilog_compile_args
compile_args = self.compile_args + self.extra_args + self.verilog_compile_args
debug_access = "-debug_access"
if self.waves:
debug_access += "+all+dmptf"
Expand Down Expand Up @@ -880,7 +840,7 @@ def build_command(self):
cmd = []

out_file = os.path.join(self.sim_dir, self.toplevel_module)
compile_args = self.compile_args + self.vhdl_compile_args
compile_args = self.compile_args + self.extra_args + self.vhdl_compile_args

if self.outdated(out_file, self.vhdl_sources) or self.force_compile:
for lib, src in self.vhdl_sources.items():
Expand Down Expand Up @@ -922,12 +882,12 @@ def build_command(self):
cmd = []

out_file = os.path.join(self.sim_dir, self.toplevel_module)

compile_args = self.compile_args + self.vhdl_compile_args
if self.outdated(out_file, self.vhdl_sources) or self.force_compile:
for lib, src in self.vhdl_sources.items():
cmd.append(["nvc"] + self.compile_args + [f"--work={lib}", "-L", self.sim_dir, "-a"] + self.vhdl_compile_args + src)
cmd.append(["nvc"] + self.extra_args + [f"--work={lib}", "-L", self.sim_dir, "-a"] + compile_args + src)

cmd_elaborate = ["nvc"] + self.compile_args + [f"--work={self.toplevel_library}", "-L", self.sim_dir, "-e"] + self.vhdl_compile_args + [self.toplevel_module]
cmd_elaborate = ["nvc"] + self.extra_args + [f"--work={self.toplevel_library}", "-L", self.sim_dir, "-e"] + compile_args + [self.toplevel_module]
cmd.append(cmd_elaborate)

if self.waves:
Expand All @@ -937,7 +897,7 @@ def build_command(self):

cmd_run = (
["nvc", f"--work={self.toplevel_library}"]
+ self.compile_args
+ self.extra_args
+ ["-L", self.sim_dir, "--stderr=error"]
+ ["-r"]
+ [self.toplevel_module]
Expand Down Expand Up @@ -975,15 +935,15 @@ def build_command(self):
do_script += f"alib {as_tcl_value(self.rtl_library)} \n"

if self.vhdl_sources:
compile_args = self.compile_args + self.vhdl_compile_args
compile_args = self.compile_args + self.extra_args + self.vhdl_compile_args
do_script += "acom -work {RTL_LIBRARY} {EXTRA_ARGS} {VHDL_SOURCES}\n".format(
RTL_LIBRARY=as_tcl_value(self.rtl_library),
VHDL_SOURCES=" ".join(as_tcl_value(v) for v in self.vhdl_sources_flat),
EXTRA_ARGS=" ".join(as_tcl_value(v) for v in compile_args),
)

if self.verilog_sources:
compile_args = self.compile_args + self.verilog_compile_args
compile_args = self.compile_args + self.extra_args + self.verilog_compile_args
do_script += "alog -work {RTL_LIBRARY} +define+COCOTB_SIM -sv {DEFINES} {INCDIR} {EXTRA_ARGS} {VERILOG_SOURCES} \n".format(
RTL_LIBRARY=as_tcl_value(self.rtl_library),
VERILOG_SOURCES=" ".join(as_tcl_value(v) for v in self.verilog_sources_flat),
Expand Down Expand Up @@ -1053,15 +1013,15 @@ def build_script_compile(self):
do_script += f"alib {as_tcl_value(self.rtl_library)} \n"

if self.vhdl_sources:
compile_args = self.compile_args + self.vhdl_compile_args
compile_args = self.compile_args + self.extra_args + self.vhdl_compile_args
do_script += "acom -work {RTL_LIBRARY} {EXTRA_ARGS} {VHDL_SOURCES}\n".format(
RTL_LIBRARY=as_tcl_value(self.rtl_library),
VHDL_SOURCES=" ".join(as_tcl_value(v) for v in self.vhdl_sources_flat),
EXTRA_ARGS=" ".join(as_tcl_value(v) for v in compile_args),
)

if self.verilog_sources:
compile_args = self.compile_args + self.verilog_compile_args
compile_args = self.compile_args + self.extra_args + self.verilog_compile_args
do_script += "alog {RTL_LIBRARY} +define+COCOTB_SIM -sv {DEFINES} {INCDIR} {EXTRA_ARGS} {VERILOG_SOURCES} \n".format(
RTL_LIBRARY=as_tcl_value(self.rtl_library),
VERILOG_SOURCES=" ".join(as_tcl_value(v) for v in self.verilog_sources_flat),
Expand Down Expand Up @@ -1170,7 +1130,7 @@ def build_command(self):
if verilator_exec is None:
raise ValueError("Verilator executable not found.")

compile_args = self.compile_args + self.verilog_compile_args
compile_args = self.compile_args + self.extra_args + self.verilog_compile_args

if self.waves:
compile_args += ["--trace-fst", "--trace-structs"]
Expand Down

0 comments on commit fd4e803

Please sign in to comment.