Skip to content

Commit

Permalink
Support running optimization from GUI
Browse files Browse the repository at this point in the history
  • Loading branch information
LarsAsplund committed Nov 16, 2024
1 parent e2393cd commit 5c524d3
Show file tree
Hide file tree
Showing 4 changed files with 122 additions and 52 deletions.
1 change: 0 additions & 1 deletion examples/vhdl/three_step_flow/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,5 @@
test.add_config(name=f"{value}", generics=dict(value=value))

vu.set_sim_option("modelsim.three_step_flow", True)
vu.set_sim_option("modelsim.vsim_flags", ["-novopt", "-suppress", "12110"])

vu.main()
96 changes: 61 additions & 35 deletions vunit/sim_if/modelsim.py
Original file line number Diff line number Diff line change
Expand Up @@ -236,10 +236,47 @@ def _get_mapped_libraries(self):
del libraries["others"]
return libraries

def _create_optimize_script(self, design_to_optimize, optimized_design, config):
def _optimize_design(self, config):
"""
Return if design shall be optimized.
"""

return config.sim_options.get("modelsim.three_step_flow", False)

@staticmethod
def _design_to_optimize(config):
"""
Return the design to optimize.
"""
if config.architecture_name is None:
architecture_suffix = ""
else:
architecture_suffix = f"({config.architecture_name!s})"

return (
config.library_name + "." + config.entity_name + architecture_suffix
if config.vhdl_configuration_name is None
else config.library_name + "." + config.vhdl_configuration_name
)

@staticmethod
def _to_optimized_design(design_to_optimize):
"""
Return name for optimized design.
vopt has limitations on how the optimized design can be named. Simply removing
non-alphanumeric characters is a simple solution to that.
"""

return "opt_" + "".join(ch for ch in design_to_optimize if ch.isalnum())

def _create_optimize_function(self, config):
"""
Create vopt script.
"""
design_to_optimize = self._design_to_optimize(config)
optimized_design = self._to_optimized_design(design_to_optimize)

vopt_flags = [
f"{design_to_optimize}",
f"-work {{{config.library_name}}}",
Expand All @@ -261,17 +298,18 @@ def _create_optimize_script(self, design_to_optimize, optimized_design, config):
tcl = """
proc vunit_optimize {{vopt_extra_args ""}} {"""
tcl += """
set vopt_failed [catch {{
eval vopt ${{vopt_extra_args}} {{{vopt_flags}}}
}}]
if {{${{vopt_failed}}}} {{
echo Command 'vopt ${{vopt_extra_args}} {vopt_flags}' failed
echo Bad flag from vopt_extra_args?
return true
}}
echo Optimizing using command 'vopt ${{vopt_extra_args}} {vopt_flags}'
set vopt_failed [catch {{
eval vopt ${{vopt_extra_args}} {{{vopt_flags}}}
}}]
return False
if {{${{vopt_failed}}}} {{
echo Command 'vopt ${{vopt_extra_args}} {vopt_flags}' failed
echo Bad flag from vopt_extra_args?
return true
}}
return False
}}
""".format(
vopt_flags=" ".join(vopt_flags)
Expand Down Expand Up @@ -355,19 +393,7 @@ def _release_library_lock(self, library, config):
self._library_locks[config.library_name].release()

def _optimize(self, config, script_path):
if config.architecture_name is None:
architecture_suffix = ""
else:
architecture_suffix = f"({config.architecture_name!s})"

design_to_optimize = (
config.library_name + "." + config.entity_name + architecture_suffix
if config.vhdl_configuration_name is None
else config.library_name + "." + config.vhdl_configuration_name
)

if not config.sim_options.get("modelsim.three_step_flow", False):
return design_to_optimize
design_to_optimize = self._design_to_optimize(config)

libraries = {lib.name: lib for lib in self._libraries}
library = libraries[config.library_name]
Expand All @@ -392,14 +418,10 @@ def _optimize(self, config, script_path):

LOGGER.debug("Optimizing %s", design_to_optimize)

# vopt has limitations on how the optimized design can be named. Simply removing
# non-alphanumeric characters is a simple solution to that
optimized_design = "opt_" + "".join(ch for ch in design_to_optimize if ch.isalnum())
optimized_design = self._to_optimized_design(design_to_optimize)

optimize_file_name = script_path / "optimize.do"
write_file(
str(optimize_file_name), self._create_optimize_script(design_to_optimize, optimized_design, config)
)
write_file(str(optimize_file_name), self._create_optimize_function(config))

if self._persistent_shell is not None:
status = self._run_persistent_optimize(optimize_file_name)
Expand Down Expand Up @@ -441,13 +463,18 @@ def _optimize(self, config, script_path):
else:
LOGGER.debug("Reusing optimized %s.", design_to_optimize)

return optimized_design
return True

def _create_load_function(self, test_suite_name, config, output_path, simulation_target):
def _create_load_function(self, test_suite_name, config, output_path, optimize_design):
"""
Create the vunit_load TCL function that runs the vsim command and loads the design
"""

if optimize_design:
simulation_target = self._to_optimized_design(self._design_to_optimize(config))
else:
simulation_target = self._design_to_optimize(config)

set_generic_str = " ".join(
(
f"-g/{config.entity_name!s}/{name!s}={encode_generic_value(value)!s}"
Expand Down Expand Up @@ -485,16 +512,15 @@ def _create_load_function(self, test_suite_name, config, output_path, simulation
# There is a known bug in modelsim that prevents the -modelsimini flag from accepting
# a space in the path even with escaping, see issue #36
if " " not in self._sim_cfg_file_name:
modelsimini_option = f"-modelsimini {fix_path(self._sim_cfg_file_name)!s}"
vsim_flags.insert(0, modelsimini_option)
vsim_flags.insert(0, f"-modelsimini {fix_path(self._sim_cfg_file_name)!s}")

for library in self._libraries:
vsim_flags += ["-L", library.name]

vhdl_assert_stop_level_mapping = {"warning": 1, "error": 2, "failure": 3}

tcl = """
proc vunit_load {{vsim_extra_args ""} {vopt_extra_args ""}} {"""
proc vunit_load {{vsim_extra_args ""}} {"""

tcl += """
set vsim_failed [catch {{
Expand Down
2 changes: 1 addition & 1 deletion vunit/sim_if/rivierapro.py
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,7 @@ def _get_mapped_libraries(self, library_cfg_file):
return libraries

def _create_load_function(
self, test_suite_name, config, output_path, simulation_target
self, test_suite_name, config, output_path, optimize_design
): # pylint: disable=unused-argument
"""
Create the vunit_load TCL function that runs the vsim command and loads the design
Expand Down
75 changes: 60 additions & 15 deletions vunit/sim_if/vsim_simulator_mixin.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ def create_process(ident):
self._persistent_shell = None

@staticmethod
def _create_restart_function():
def _create_restart_function(optimize_design):
""" "
Create the vunit_restart function to recompile and restart the simulation
Expand Down Expand Up @@ -92,7 +92,7 @@ def _create_restart_function():
]
recompile_command_eval_tcl = " ".join([f"{{{part}}}" for part in recompile_command_eval])

return f"""
tcl = f"""
proc vunit_compile {{}} {{
set cmd_show {{{recompile_command_visual!s}}}
puts "Re-compiling using command ${{cmd_show}}"
Expand All @@ -112,16 +112,30 @@ def _create_restart_function():
return false
}}
}}
proc vunit_restart {{}} {{
if {{![vunit_compile]}} {{
"""
if optimize_design:
tcl += """
proc vunit_restart {} {
if {![vunit_compile]} {
if {![vunit_optimize]} {
_vunit_sim_restart
vunit_run
}
}
}
"""
else:
tcl += """
proc vunit_restart {} {
if {![vunit_compile]} {
_vunit_sim_restart
vunit_run
}}
}}
}
}
"""
return tcl

def _create_common_script(self, test_suite_name, config, script_path, output_path, simulation_target):
def _create_common_script(self, test_suite_name, config, script_path, output_path, *, optimize_design):
"""
Create tcl script with functions common to interactive and batch modes
"""
Expand All @@ -138,10 +152,27 @@ def _create_common_script(self, test_suite_name, config, script_path, output_pat
puts {vunit_run}
puts { - Run test, must do vunit_load first}
puts {vunit_compile}
puts { - Recompiles the source files}"""

if optimize_design:
tcl += """
puts {vunit_optimize [vopt_extra_args]}
puts { - Optimizes the design. Must be done after vunit_compile}
puts { - Optional first argument are passed as extra flags to vopt}"""

if optimize_design:
tcl += """
puts {vunit_restart}
puts { - Recompiles the source files}
puts { - Reoptimizes the design if the compile was successful}
puts { - and re-runs the simulation if the compile and optimize were successful}"""
else:
tcl += """
puts {vunit_restart}
puts { - Recompiles the source files}
puts { - and re-runs the simulation if the compile was successful}
puts { - and re-runs the simulation if the compile was successful}"""

tcl += """
}
proc vunit_run {} {
Expand All @@ -164,10 +195,14 @@ def _create_common_script(self, test_suite_name, config, script_path, output_pat
"""
tcl += self._create_init_files_after_load(config)
tcl += self._create_init_files_before_run(config)
tcl += self._create_load_function(test_suite_name, config, script_path, simulation_target)
tcl += self._create_load_function(test_suite_name, config, script_path, optimize_design)
tcl += get_is_test_suite_done_tcl(get_result_file_name(output_path))
tcl += self._create_run_function()
tcl += self._create_restart_function()
tcl += self._create_restart_function(optimize_design)

if optimize_design:
tcl += self._create_optimize_function(config)

return tcl

@staticmethod
Expand Down Expand Up @@ -313,6 +348,13 @@ def _optimize(self, config, script_path): # pylint: disable=unused-argument
"""
return "Optimize not supported"

def _optimize_design(self, config): # pylint: disable=unused-argument
"""
Return if design shall be optimized.
"""

return False

def simulate(self, output_path, test_suite_name, config, elaborate_only):
"""
Run a test bench
Expand All @@ -323,13 +365,16 @@ def simulate(self, output_path, test_suite_name, config, elaborate_only):
gui_file_name = script_path / "gui.do"
batch_file_name = script_path / "batch.do"

simulation_target = self._optimize(config, script_path)
if simulation_target is False:
return False
optimize_design = self._optimize_design(config)
if optimize_design:
if not self._optimize(config, script_path):
return False

write_file(
str(common_file_name),
self._create_common_script(test_suite_name, config, script_path, output_path, simulation_target),
self._create_common_script(
test_suite_name, config, script_path, output_path, optimize_design=optimize_design
),
)
write_file(str(gui_file_name), self._create_gui_script(str(common_file_name), config))
write_file(
Expand Down

0 comments on commit 5c524d3

Please sign in to comment.