@@ -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,93 @@ 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+ if config .sim_options .get ("enable_coverage" , False ):
580+ coverage_args = "-coverage"
581+ else :
582+ coverage_args = ""
583+
584+ vsim_flags = [
585+ simulation_target ,
586+ "-work" ,
587+ f"{ config .library_name } " ,
588+ "-quiet" ,
589+ coverage_args ,
590+ self ._vsim_extra_args (config ),
591+ ]
592+
593+ # There is a known bug in modelsim that prevents the -modelsimini flag from accepting
594+ # a space in the path even with escaping, see issue #36
595+ if " " not in self ._sim_cfg_file_name :
596+ vsim_flags .insert (1 , "-modelsimini" )
597+ vsim_flags .insert (2 , f"{ fix_path (self ._sim_cfg_file_name )} " )
598+
599+ for library in self ._libraries :
600+ vsim_flags += ["-L" , library .name ]
601+
602+ return vsim_flags
603+
604+ def _get_vsim_flags (self , config , output_path , optimize_design ):
605+ """Return vsim flags for load function."""
606+ vsim_flags = self ._common_vsim_flags (config , output_path , optimize_design )
607+
608+ pli_str = " " .join (f"-pli {{{ fix_path (name )!s} }}" for name in config .sim_options .get ("pli" , []))
609+
610+ set_generic_str = " " .join (
611+ (
612+ f"-g/{ config .entity_name !s} /{ name !s} ={ encode_generic_value_for_tcl (value )!s} "
613+ for name , value in config .generics .items ()
614+ )
615+ )
616+
617+ vsim_flags += [
618+ "-wlf" ,
619+ f"{{{ fix_path (str (Path (output_path ) / 'vsim.wlf' ))} }}" ,
620+ pli_str ,
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+ pli_str = " " .join (f"-pli { fix_path (name )} " for name in config .sim_options .get ("pli" , []))
638+
639+ set_generic_str = " " .join (
640+ (
641+ f"-g/{ config .entity_name !s} /{ name !s} ={ encode_generic_value_for_args (value )!s} "
642+ for name , value in config .generics .items ()
643+ )
644+ )
645+ generics_file_name = Path (output_path ) / "generics.flags"
646+ write_file (str (generics_file_name ), set_generic_str )
647+
648+ vsim_flags += [
649+ "-wlf" ,
650+ f"{ fix_path (str (Path (output_path ) / 'vsim.wlf' ))} " ,
651+ pli_str ,
652+ "-visualizer" ,
653+ "-f" ,
654+ f"{ fix_path (str (generics_file_name ))} "
655+ ]
656+
657+ return vsim_flags
658+
569659 @staticmethod
570660 def _create_run_function ():
571661 """
@@ -664,9 +754,9 @@ def get_env():
664754 return env
665755
666756
667- def encode_generic_value (value ):
757+ def encode_generic_value_for_tcl (value ):
668758 """
669- Ensure values with space in them are quoted
759+ Ensure values with space and commas in them are quoted properly for TCL files.
670760 """
671761 s_value = str (value )
672762 if " " in s_value :
@@ -676,6 +766,18 @@ def encode_generic_value(value):
676766 return s_value
677767
678768
769+ def encode_generic_value_for_args (value ):
770+ """
771+ Ensure values with space and commas in them are quoted properly for argument files.
772+ """
773+ s_value = str (value )
774+ if " " in s_value :
775+ return f"'\" { s_value } \" '"
776+ if "," in s_value :
777+ return f"'\" { s_value } \" '"
778+ return s_value
779+
780+
679781def parse_modelsimini (file_name ):
680782 """
681783 Parse a modelsim.ini file
0 commit comments