@@ -51,6 +51,19 @@ class ModelSimInterface(VsimSimulatorMixin, SimulatorInterface): # pylint: disa
5151 BooleanOption ("modelsim.three_step_flow" ),
5252 ]
5353
54+ @staticmethod
55+ def add_arguments (parser ):
56+ """
57+ Add command line arguments
58+ """
59+ group = parser .add_argument_group ("modelsim/questa" , description = "ModelSim/Questa specific flags" )
60+ group .add_argument (
61+ "--debugger" ,
62+ choices = ["original" , "visualizer" ],
63+ default = "original" ,
64+ help = "Debugger to use." ,
65+ )
66+
5467 @classmethod
5568 def from_args (cls , args , output_path , ** kwargs ):
5669 """
@@ -63,6 +76,7 @@ def from_args(cls, args, output_path, **kwargs):
6376 output_path = output_path ,
6477 persistent = persistent ,
6578 gui = args .gui ,
79+ debugger = args .debugger ,
6680 )
6781
6882 @classmethod
@@ -90,7 +104,7 @@ def supports_coverage():
90104 """
91105 return True
92106
93- def __init__ (self , prefix , output_path , persistent = False , gui = False ):
107+ def __init__ (self , prefix , output_path , * , persistent = False , gui = False , debugger = "original" ):
94108 SimulatorInterface .__init__ (self , output_path , gui )
95109 VsimSimulatorMixin .__init__ (
96110 self ,
@@ -102,6 +116,7 @@ def __init__(self, prefix, output_path, persistent=False, gui=False):
102116 self ._coverage_files = set ()
103117 assert not (persistent and gui )
104118 self ._create_modelsim_ini ()
119+ self ._debugger = debugger
105120 # Contains design already optimized, i.e. the optimized design can be reused
106121 self ._optimized_designs = {}
107122 # Contains locks for each library. If locked, a design belonging to the library
@@ -248,6 +263,15 @@ def _optimize_design(self, config):
248263
249264 return config .sim_options .get ("modelsim.three_step_flow" , False )
250265
266+ def _early_load_in_gui_mode (self ): # pylint: disable=unused-argument
267+ """
268+ Return True if design is to be loaded on the first vsim call rather than
269+ in the second vsim call embedded in the script file.
270+
271+ This is required for Questa Visualizer.
272+ """
273+ return self ._debugger == "visualizer"
274+
251275 @staticmethod
252276 def _design_to_optimize (config ):
253277 """
@@ -282,13 +306,28 @@ def _create_optimize_function(self, config):
282306 design_to_optimize = self ._design_to_optimize (config )
283307 optimized_design = self ._to_optimized_design (design_to_optimize )
284308
309+ vopt_library_flags = []
310+ design_file_directory = None
311+ for library in self ._libraries :
312+ vopt_library_flags += ["-L" , library .name ]
313+ if library .name == config .library_name :
314+ design_file_directory = library .directory
315+
316+ if not design_file_directory :
317+ raise RuntimeError (f"Failed to find library directory for { config .library_name } " )
318+
319+ design_file = str (Path (design_file_directory ) / f"{ optimized_design } .bin" )
320+
285321 vopt_flags = [
286322 self ._vopt_extra_args (config ),
287323 f"{ design_to_optimize } " ,
288- f"-work {{{ config .library_name } }}" ,
324+ "-work" ,
325+ f"{{{ config .library_name } }}" ,
289326 "-quiet" ,
290327 f"-floatgenerics+{ config .entity_name } ." ,
291328 f"-o {{{ optimized_design } }}" ,
329+ "-designfile" ,
330+ f"{{{ fix_path (design_file )} }}" ,
292331 ]
293332
294333 # There is a known bug in modelsim that prevents the -modelsimini flag from accepting
@@ -297,8 +336,7 @@ def _create_optimize_function(self, config):
297336 modelsimini_option = f"-modelsimini { fix_path (self ._sim_cfg_file_name )!s} "
298337 vopt_flags .insert (0 , modelsimini_option )
299338
300- for library in self ._libraries :
301- vopt_flags += ["-L" , library .name ]
339+ vopt_flags += vopt_library_flags
302340
303341 tcl = """
304342proc vunit_optimize {{vopt_extra_args ""}} {"""
@@ -478,18 +516,7 @@ def _create_load_function(self, test_suite_name, config, output_path, optimize_d
478516 Create the vunit_load TCL function that runs the vsim command and loads the design
479517 """
480518
481- if optimize_design :
482- simulation_target = self ._to_optimized_design (self ._design_to_optimize (config ))
483- else :
484- simulation_target = self ._design_to_optimize (config )
485-
486- set_generic_str = " " .join (
487- (
488- f"-g/{ config .entity_name !s} /{ name !s} ={ encode_generic_value (value )!s} "
489- for name , value in config .generics .items ()
490- )
491- )
492- pli_str = " " .join (f"-pli {{{ fix_path (name )!s} }}" for name in config .sim_options .get ("pli" , []))
519+ vsim_flags = self ._get_vsim_flags (config , output_path , optimize_design )
493520
494521 if config .sim_options .get ("enable_coverage" , False ):
495522 coverage_file = str (Path (output_path ) / "coverage.ucdb" )
@@ -498,32 +525,8 @@ def _create_load_function(self, test_suite_name, config, output_path, optimize_d
498525 f"coverage save -onexit -testname {{{ test_suite_name !s} }} -assert -directive "
499526 f"-cvg -codeAll {{{ fix_path (coverage_file )!s} }}"
500527 )
501- coverage_args = "-coverage"
502528 else :
503529 coverage_save_cmd = ""
504- coverage_args = ""
505-
506- vsim_flags = [
507- f"-wlf {{{ fix_path (str (Path (output_path ) / 'vsim.wlf' ))!s} }}" ,
508- f"-work {{{ config .library_name } }}" ,
509- "-quiet" ,
510- "-t ps" ,
511- # for correct handling of verilog fatal/finish
512- "-onfinish stop" ,
513- pli_str ,
514- set_generic_str ,
515- simulation_target ,
516- coverage_args ,
517- self ._vsim_extra_args (config ),
518- ]
519-
520- # There is a known bug in modelsim that prevents the -modelsimini flag from accepting
521- # a space in the path even with escaping, see issue #36
522- if " " not in self ._sim_cfg_file_name :
523- vsim_flags .insert (0 , f"-modelsimini { fix_path (self ._sim_cfg_file_name )!s} " )
524-
525- for library in self ._libraries :
526- vsim_flags += ["-L" , library .name ]
527530
528531 vhdl_assert_stop_level_mapping = {"warning" : 1 , "error" : 2 , "failure" : 3 }
529532
@@ -566,6 +569,84 @@ def _create_load_function(self, test_suite_name, config, output_path, optimize_d
566569
567570 return tcl
568571
572+ def _common_vsim_flags (self , config , output_path , optimize_design ):
573+ """Return vsim flags to normal and early load mode."""
574+ if optimize_design :
575+ simulation_target = self ._to_optimized_design (self ._design_to_optimize (config ))
576+ else :
577+ simulation_target = self ._design_to_optimize (config )
578+
579+ pli_str = " " .join (f"-pli {{{ fix_path (name )!s} }}" for name in config .sim_options .get ("pli" , []))
580+
581+ if config .sim_options .get ("enable_coverage" , False ):
582+ coverage_args = "-coverage"
583+ else :
584+ coverage_args = ""
585+
586+ vsim_flags = [
587+ simulation_target ,
588+ "-wlf" ,
589+ f"{ fix_path (str (Path (output_path ) / 'vsim.wlf' ))} " ,
590+ "-work" ,
591+ f"{ config .library_name } " ,
592+ "-quiet" ,
593+ pli_str ,
594+ coverage_args ,
595+ self ._vsim_extra_args (config ),
596+ ]
597+
598+ # There is a known bug in modelsim that prevents the -modelsimini flag from accepting
599+ # a space in the path even with escaping, see issue #36
600+ if " " not in self ._sim_cfg_file_name :
601+ vsim_flags .insert (1 , "-modelsimini" )
602+ vsim_flags .insert (2 , f"{ fix_path (self ._sim_cfg_file_name )} " )
603+
604+ for library in self ._libraries :
605+ vsim_flags += ["-L" , library .name ]
606+
607+ return vsim_flags
608+
609+ def _get_vsim_flags (self , config , output_path , optimize_design ):
610+ """Return vsim flags for load function."""
611+ vsim_flags = self ._common_vsim_flags (config , output_path , optimize_design )
612+
613+ set_generic_str = " " .join (
614+ (
615+ f"-g/{ config .entity_name !s} /{ name !s} ={ encode_generic_value (value )!s} "
616+ for name , value in config .generics .items ()
617+ )
618+ )
619+
620+ vsim_flags += [
621+ set_generic_str ,
622+ "-t ps" ,
623+ # for correct handling of Verilog fatal/finish
624+ "-onfinish stop" ,
625+ ]
626+
627+ return vsim_flags
628+
629+ def _get_load_flags (self , config , output_path , optimize_design ):
630+ """
631+ Return extra flags needed for the first vsim call in GUI mode when early load is enabled.
632+
633+ This is required for Questa Visualizer.
634+ """
635+ vsim_flags = self ._common_vsim_flags (config , output_path , optimize_design )
636+
637+ set_generic_str = " " .join (
638+ (
639+ f"-g/{ config .entity_name !s} /{ name !s} ={ encode_generic_value_for_file (value )!s} "
640+ for name , value in config .generics .items ()
641+ )
642+ )
643+ generics_file_name = Path (output_path ) / "generics.flags"
644+ write_file (str (generics_file_name ), set_generic_str )
645+
646+ vsim_flags += ["-visualizer" , "-f" , f"{ fix_path (str (generics_file_name ))} " ]
647+
648+ return vsim_flags
649+
569650 @staticmethod
570651 def _create_run_function ():
571652 """
@@ -666,7 +747,7 @@ def get_env():
666747
667748def encode_generic_value (value ):
668749 """
669- Ensure values with space in them are quoted
750+ Ensure values with space in them are quoted properly for the command line
670751 """
671752 s_value = str (value )
672753 if " " in s_value :
@@ -676,6 +757,18 @@ def encode_generic_value(value):
676757 return s_value
677758
678759
760+ def encode_generic_value_for_file (value ):
761+ """
762+ Ensure values with space in them are quoted properly for argument files
763+ """
764+ s_value = str (value )
765+ if " " in s_value :
766+ return f"'\" { s_value } \" '"
767+ if "," in s_value :
768+ return f"'\" { s_value } \" '"
769+ return s_value
770+
771+
679772def parse_modelsimini (file_name ):
680773 """
681774 Parse a modelsim.ini file
0 commit comments