Hog v10.48.0
launch.tcl
Go to the documentation of this file.
1 #!/usr/bin/env tclsh
2 # tcl-lsp: disable=W300
3 
4 # @file
5 # Copyright 2018-2026 The University of Birmingham
6 # Copyright 2018-2026 Max-Planck-Institute for Physics
7 #
8 # Licensed under the Apache License, Version 2.0 (the "License");
9 # you may not use this file except in compliance with the License.
10 # You may obtain a copy of the License at
11 #
12 # http://www.apache.org/licenses/LICENSE-2.0
13 #
14 # Unless required by applicable law or agreed to in writing, software
15 # distributed under the License is distributed on an "AS IS" BASIS,
16 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 # See the License for the specific language governing permissions and
18 # limitations under the License.
19 # Launch Xilinx Vivado or ISE implementation and possibly write bitstream in text mode
20 # Developers Tip for new commands
21 # Add a hashtag sign # after the curly brake (e.g. \^C(REATE)?$ {# ...}) if the command requires a project name as an argument
22 set tcl_path [file normalize "[file dirname [info script]]"]
23 source $tcl_path/hog.tcl
24 source $tcl_path/create_project.tcl
25 source $tcl_path/commands.tcl
26 
27 # Initialize Vitis flags before InitLauncher so IsTclsh correctly returns 1
28 set globalSettings::vitis_unified 0
29 set globalSettings::vitis_classic 0
30 
31 # Check if we're already running in xsct (Vitis Classic)
32 # This must be done early, before InitLauncher, to prevent launching Vivado
33 if {[info commands platform] ne ""} {
34  set globalSettings::vitis_classic 1
35  set globalSettings::vitis_unified 0
36 }
37 
38 # Quartus needs extra packages and treats the argv in a different way
39 if {[IsQuartus]} {
40  load_package report
41  # noqa: W210
42  set argv $quartus(args)
43 }
44 
45 
46 # Msg Debug "s: $::argv0 a: $argv"
47 ### CUSTOM COMMANDS ###
48 set commands_path [file normalize "$tcl_path/../../hog-commands/"]
49 set custom_commands [GetCustomCommands $parameters $commands_path]
50 
51 lassign [InitLauncher $::argv0 $tcl_path $parameters $default_commands $argv $custom_commands] directive project \
52  project_name group_name repo_path old_path bin_dir top_path usage short_usage cmd ide list_of_options
53 
54 array set options $list_of_options
55 
56 if {$options(verbose) == 1} {
57  setDebugMode 1
58 }
59 Msg Debug \
60  "Returned by InitLauncher: \n - project: $project \n - project_name $project_name \n - group_name $group_name \n - \
61  repo_path $repo_path \n - old_path $old_path \n - bin_dir $bin_dir \n - top_path $top_path \n - cmd $cmd"
62 
63 set ext_path ""
64 if {$options(ext_path) ne ""} {
65  set ext_path $options(ext_path)
66 }
67 set lib_path ""
68 if {$options(lib) ne ""} {
69  set lib_path [file normalize $options(lib)]
70 } else {
71  if {[info exists env(HOG_SIMULATION_LIB_PATH)]} {
72  set lib_path $env(HOG_SIMULATION_LIB_PATH)
73  } else {
74  if {[file exists "$repo_path/SimulationLib"]} {
75  set lib_path [file normalize "$repo_path/SimulationLib"]
76  } else {
77  set lib_path ""
78  }
79  }
80 }
81 
82 
83 if {$options(verbose) == 1} {
84  setDebugMode 1
85  # Set environment variable for Vitis Unified Python scripts to enable debug output
86  set env(HOG_DEBUG_MODE) "1"
87 }
88 
89 # printDebugMode
90 # Msg Info "Number of jobs set to $options(njobs)."
91 set output_path ""
92 if {$options(output) ne ""} {
93  set output_path $options(output)
94 }
95 
96 set light_hierarchy $options(light)
97 set ignored_hierarchy $options(ignore)
98 set top_module $options(top)
99 set compile_order $options(compile_order)
100 set include_ieee $options(include_ieee)
101 set include_gen_prods $options(include_gen_prods)
102 
103 ######## DEFAULTS #########
104 set do_rtl 0
105 set do_checkproj_env 0
106 set do_check_ci_env 0
107 set do_checkproj_ver 0
108 set do_implementation 0
109 set do_synthesis 0
110 set do_bitstream 0
111 set do_create 0
112 set do_upgrade_ips 0
113 set do_compile 0
114 set do_simulation 0
115 set recreate 0
116 set do_reset 1
117 set do_list_all 2
118 set do_check_syntax 0
119 set do_vitis_build 0
120 set scripts_only 0
121 set compile_only 0
122 set ide_name ""
123 set allow_empty_proj 0
124 
125 ### Hog stand-alone directives ###
126 # The following directives are used WITHOUT ever calling the IDE, they are run in tclsh
127 # A place holder called new_directive can be followed to add new commands
128 set do_ipbus_xml 0
129 set do_cheby 0
130 set do_list_file_parse 0
131 set do_check_yaml_ref 0
132 set do_buttons 0
133 set do_check_list_files 0
134 set do_compile_lib 0
135 set do_sigasi 0
136 set do_vhdl_ls 0
137 set do_cocotb 0
138 set do_hierarchy 0
139 set do_version 0
140 
141 set NO_DIRECTIVE_FOUND 0
142 Msg Debug "Looking for a $directive in : $default_commands"
143 switch -regexp -- $directive $default_commands
144 
145 if {$NO_DIRECTIVE_FOUND == 1} {
146  Msg Debug "No directive found in default commands, looking in custom commands..."
147  if {[string length $custom_commands] > 0 && [dict exists $custom_commands $directive]} {
148  Msg Debug "Directive $directive found in custom commands."
149  if {$cmd == "custom_tcl"} {
150  eval [dict get $custom_commands $directive SCRIPT]
151  exit
152  } else {
153  if {[IsTclsh]} {
154  Msg Info "Launching command: $cmd..."
155 
156  # Check if the IDE is actually in the path...
157  set ret [catch {exec which $ide}]
158  if {$ret != 0} {
159  Msg Error "$ide not found in your system. Make sure to add $ide to your PATH enviromental variable."
160  exit $ret
161  }
162 
163  if {[string first libero $cmd] >= 0} {
164  # The SCRIPT_ARGS: flag of libero makes tcl crazy...
165  # Let's pipe the command into a shell script and remove it later
166  set libero_script [open "launch-libero-hog.sh" w]
167  puts $libero_script "#!/bin/sh"
168  puts $libero_script $cmd
169  close $libero_script
170  set cmd "sh launch-libero-hog.sh"
171  }
172 
173  set ret [catch {exec -ignorestderr {*}$cmd >@ stdout 2>@ stderr} result]
174 
175  if {$ret != 0} {
176  Msg Error "IDE returned an error state: $result"
177  } else {
178  Msg Info "All done."
179  exit 0
180  }
181 
182  if {[string first libero $cmd] >= 0} {
183  file delete "launch-libero-hog.sh"
184  }
185 
186  exit $ret
187  }
188 
189  eval [dict get $custom_commands $directive SCRIPT]
190 
191  set no_exit [dict get $custom_commands $directive NO_EXIT]
192  if {$no_exit == 0} {
193  exit
194  }
195  }
196  } else {
197  Msg Info "No directive found, pre ide exiting..."
198  Msg Status "ERROR: Unknown directive $directive.\n\n"
199  puts $usage
200  exit
201  }
202 }
203 
204 if {$options(all) == 1} {
205  set do_list_all 1
206 } else {
207  set do_list_all 2
208 }
209 
210 set ci_run 0
211 if {$options(ci_run) == 1} {
212  set ci_run 1
213 }
214 
215 if {$options(dst_dir) == "" && ($do_ipbus_xml == 1 || $do_cheby == 1 || $do_check_list_files == 1) && $project != ""} {
216  # Getting all the versions and SHAs of the repository
217  set proj_dir [file normalize $repo_path/Top/$group_name/$project]
218  lassign [GetRepoVersions $proj_dir $repo_path $ext_path] commit version \
219  hog_hash hog_ver top_hash top_ver libs hashes vers cons_ver cons_hash ext_names ext_hashes xml_hash xml_ver \
220  user_ip_repos user_ip_hashes user_ip_vers cheby_hash cheby_ver
221  cd $repo_path
222 
223  set describe [GetHogDescribe $proj_dir $repo_path]
224  set dst_dir [file normalize "$repo_path/bin/$group_name/$project\-$describe"]
225 }
226 
227 if {$cmd == -1} {
228  # This is if the project was not found
229  Msg Status "\n\nPossible projects are:"
230  ListProjects $repo_path $do_list_all
231  Msg Status "\n"
232  exit 1
233 } elseif {$cmd == -2} {
234  # Project not given but needed
235  Msg Status "ERROR: You must specify a project with directive $directive."
236  # \n\n[cmdline::usage $parameters $usage]"
237  Msg Status "Possible projects are:"
238  ListProjects $repo_path $do_list_all
239  exit 1
240 } elseif {$cmd == 0} {
241  #This script was launched within the IDE,: Vivado, Quartus, etc
242  Msg Info "$::argv0 was launched from the IDE."
243 } else {
244  # This script was launched with Tclsh, we need to check the arguments
245  # and if everything is right launch the IDE on this script and return
246  #### Directives to be handled in tclsh should be here ###
247  ### IMPORTANT: Each if block should either end with "exit 0" or
248  ### set both $ide and $cmd to be executed when this script is run again
249  if {$do_checkproj_env == 1} {
250  CheckEnv $project_name $ide
251  exit 0
252  }
253 
254  if {$do_checkproj_ver == 1} {
255  cd $repo_path
256  set ci_config ""
257  if {$ci_run == 1} {
258  # Compile YAML to get list of projects
259  if {[info exists env(GITLAB_CI)] && $env(GITLAB_CI) eq "true" && [auto_execok glab] != ""} {
260  # running in GitLab CI
261  Msg Info "Running in the GitLab CI/CD. I will check only the active projects in the current pipeline..."
262  # Tell glab the host and project explicitly: on SaaS runners the git remote
263  # points to the CI gateway, which glab does not recognise as a GitLab host.
264  if {[info exists env(CI_SERVER_HOST)]} {
265  set env(GITLAB_HOST) $env(CI_SERVER_HOST)
266  }
267  if {[info exists env(CI_PROJECT_PATH)]} {
268  lassign [ExecuteRet glab ci get -p $env(CI_PIPELINE_ID)] ret ci_config
269  } else {
270  lassign [ExecuteRet glab ci get] ret ci_config
271  }
272  if {$ret != 0} {
273  Msg Warning "Failed to get CI config from GitLab, checking all projects instead."
274  set ci_run 0
275  }
276 
277  # Check if we are using the dynamic CI and set ci_run to 0 in case, so we check the version of all projects
278  if {[info exists env(CI_CONFIG_PATH)]} {
279  set ci_config_path $env(CI_CONFIG_PATH)
280  } else {
281  set ci_config_path $repo_path/.gitlab-ci.yml
282  }
283 
284  if {[file exists $ci_config_path]} {
285  set fh [open $ci_config_path r]
286  set content [read $fh]
287  close $fh
288  if {[string first "hog-dynamic.yml" $content] != -1} {
289  set ci_run 0
290  }
291  } else {
292  Msg Warning "CI config file $ci_config_path not found, checking all projects instead."
293  set ci_run 0
294  }
295  } elseif {[info exists env(GITHUB_ACTIONS)] && $env(GITHUB_ACTIONS) eq "true"} {
296  # running in GitHub Actions
297  set workflow_dir "$repo_path/.github/workflows"
298  set ci_run 0
299  foreach workflow_file [glob -nocomplain -directory $workflow_dir -- *.yml *.yaml] {
300  set fh [open $workflow_file r]
301  set content [read $fh]
302  close $fh
303  if {[string first "Hog-pull.yml" $content] != -1} {
304  set ci_config $content
305  set ci_run 1
306  break
307  }
308  }
309  } else {
310  set ci_run 0
311  }
312  }
313 
314  set proj_to_do {}
315  if {$project_name eq ""} {
316  set projects [ListProjects $repo_path 1 0 1]
317  foreach p $projects {
318  if {$ci_run == 0 || ($ci_run == 1 && [string first $p $ci_config] != -1)} {
319  if {[CheckProjVer $repo_path $p $options(simcheck) $options(ext_path)] == 0} {
320  lappend proj_to_do $p
321  }
322  }
323  }
324  } else {
325  if {[CheckProjVer $repo_path $project_name $options(simcheck) $options(ext_path)] == 0} {
326  lappend proj_to_do $project_name
327  }
328  }
329 
330  set n [llength $proj_to_do]
331  if {$n > 0} {
332  Msg Info "The following projects were modified: \n[join $proj_to_do \n]"
333  }
334 
335  Msg Info "$n projects were modified since last official version."
336  exit 0
337  }
338 
339  if {$do_check_ci_env == 1} {
340  CheckCIEnv
341  exit 0
342  }
343 
344 
345  if {$do_ipbus_xml == 1} {
346  if {[llength $project_name] == 0} {
347  Msg Error "XML option needs a project name."
348  exit
349  }
350  Msg Info "Handling IPbus XMLs for $project_name..."
351 
352  set proj_dir $repo_path/Top/$project_name
353 
354  if {$options(generate) == 1} {
355  set xml_gen 1
356  } else {
357  set xml_gen 0
358  }
359 
360  if {$options(dst_dir) != ""} {
361  set dst_dir $options(dst_dir)
362  } else {
363  if {![info exists dst_dir]} {
364  set dst_dir ""
365  }
366  }
367  set xml_dst "$dst_dir/xml"
368 
369 
370  if {[llength [glob -nocomplain $proj_dir/list/*.ipb]] > 0} {
371  if {![file exists $xml_dst]} {
372  Msg Info "$xml_dst directory not found, creating it..."
373  file mkdir $xml_dst
374  }
375  } else {
376  Msg Error "No .ipb files found in $proj_dir/list/"
377  exit
378  }
379 
380  set ret [GetRepoVersions $proj_dir $repo_path ""]
381  set sha [lindex $ret 13]
382  set hex_ver [lindex $ret 14]
383 
384  set ver [HexVersionToString $hex_ver]
385  CopyIPbusXMLs $proj_dir $repo_path $xml_dst $ver $sha 1 $xml_gen
386 
387  exit 0
388  }
389 
390  if {$do_cheby == 1} {
391  Msg Info "Handling Cheby register-map outputs for $project_name..."
392 
393  set proj_dir $repo_path/Top/$project_name
394 
395  if {$options(generate) == 1} {
396  set cheby_gen 1
397  } else {
398  set cheby_gen 0
399  }
400 
401  if {$options(dst_dir) != ""} {
402  set dst_dir $options(dst_dir)
403  }
404  set cheby_dst "$dst_dir/cheby"
405 
406  if {[llength [glob -nocomplain $proj_dir/list/*.chb]] > 0} {
407  if {![file exists $cheby_dst]} {
408  Msg Info "$cheby_dst directory not found, creating it..."
409  file mkdir $cheby_dst
410  }
411  } else {
412  Msg Error "No .chb files found in $proj_dir/list/"
413  exit
414  }
415 
416  set cheby_tool $options(tool)
417  if {$cheby_tool eq ""} {
418  if {[info exists env(HOG_CHEBY_TOOL)]} {
419  set cheby_tool $env(HOG_CHEBY_TOOL)
420  } else {
421  set cheby_tool "cheby"
422  }
423  }
424 
425  set cheby_profile $options(profile)
426  if {$cheby_profile eq ""} {
427  set cheby_profile "all"
428  }
429 
430  set ret [GetRepoVersions $proj_dir $repo_path ""]
431  set sha [lindex $ret 18]
432  set hex_ver [lindex $ret 19]
433  set ver [HexVersionToString $hex_ver]
434 
435  set n_errors [CopyChebyFiles $proj_dir $repo_path $cheby_dst \
436  $ver $sha $cheby_gen $cheby_profile $cheby_tool \
437  $options(strict) $options(verbose)]
438 
439  if {$n_errors > 0} {
440  Msg CriticalWarning "Cheby step finished with $n_errors error(s)."
441  exit 1
442  }
443  exit 0
444  }
445 
446  if {$do_list_file_parse == 1} {
447  set proj_dir $repo_path/Top/$project_name
448  set proj_list_dir $repo_path/Top/$project_name/list
449  GetHogFiles -print_log -list_files {.src,.con,.sim,.ext,.ipb,.chb} $proj_list_dir $repo_path
450  Msg Status " "
451  Msg Info "All Done."
452  exit 0
453  }
454 
455  if {$do_hierarchy == 1} {
456  source $tcl_path/utils/hierarchy.tcl
457  set proj_dir $repo_path/Top/$project_name
458  set proj_list_dir $repo_path/Top/$project_name/list
459  lassign [GetHogFiles -ext_path $ext_path -list_files ".src,.ext" $proj_list_dir $repo_path] listLibraries \
460  listProperties listSrcSets
461  set hierarchy_result \
462  [Hierarchy $listProperties $listLibraries $repo_path $output_path $compile_order $light_hierarchy $top_module \
463  $ignored_hierarchy $include_ieee $include_gen_prods]
464  puts $hierarchy_result
465  exit 0
466  }
467  if {$do_sigasi == 1} {
468  cd $repo_path
469  Msg Info "Creating Sigasi CSV files for project $project_name..."
470  set proj_dir $repo_path/Top/$project_name
471  set proj_list_dir $repo_path/Top/$project_name/list
472  set project [file tail $project_name]
473  lassign [GetHogFiles -list_files {.src} $proj_list_dir $repo_path] libraries
474  set csv_file [open "sigasi_$project.csv" w]
475  foreach lib $libraries {
476  set source_files [DictGet $libraries $lib]
477  foreach source_file $source_files {
478  if {
479  [file extension $source_file] eq ".vhd"
480  || [file extension $source_file] eq ".vhdl"
481  || [file extension $source_file] eq ".sv"
482  || [file extension $source_file] eq ".v"
483  } {
484  puts $csv_file [concat [file rootname $lib] "," $source_file]
485  }
486  }
487  }
488  lassign [GetHogFiles -list_files ".sim" $proj_list_dir $repo_path] \
489  listSimLibraries
490  foreach lib $listSimLibraries {
491  set source_files [DictGet $listSimLibraries $lib]
492  foreach source_file $source_files {
493  if {
494  [file extension $source_file] eq ".vhd"
495  || [file extension $source_file] eq ".vhdl"
496  || [file extension $source_file] eq ".sv"
497  || [file extension $source_file] eq ".v"
498  } {
499  puts $csv_file [concat [file rootname $lib] "," $source_file]
500  }
501  }
502  }
503  close $csv_file
504  Msg Info "Sigasi CSV file created: sigasi_$project.csv"
505  Msg Info "You can use the python script provided by Sigasi to convert the generated csv file into a Sigasi project."
506  Msg Info \
507  "More info at: \
508  https://www.sigasi.com/knowledge/how_tos/generating-sigasi-project-vivado-project/#2-generate-the-sigasi-project-files-from-the-csv-file"
509  exit 0
510  }
511 
512  if {$do_vhdl_ls == 1} {
513  cd $repo_path
514  Msg Info "Creating VHDL-LS configuration file for project $project_name..."
515  set proj_dir $repo_path/Top/$project_name
516  set proj_list_dir $repo_path/Top/$project_name/list
517  set project [file tail $project_name]
518  lassign [GetHogFiles -list_files {.src} $proj_list_dir $repo_path] libraries
519  set toml_file [open "vhdl_ls_$project.toml" w]
520  puts $toml_file "\[libraries\]"
521  dict for {lib source_files} $libraries {
522  puts $toml_file "[file rootname $lib].files = \["
523  foreach source_file $source_files {
524  if {
525  [file extension $source_file] == ".vhd"
526  || [file extension $source_file] == ".vhdl"
527  } {
528  # puts [Relative $repo_path $source_file ]
529  puts $toml_file "\'[Relative $repo_path $source_file]\',"
530  }
531  }
532  puts $toml_file "\]\n"
533  }
534  close $toml_file
535  Msg Info "VHDL-LS TOML File created: vhdl_ls_$project.toml"
536  Msg Info \
537  "You can copy the content of this file into your VHDL-LS configuration vhdl_ls.toml, to import all Hog libraries."
538  exit 0
539  }
540 
541  if {$do_cocotb == 1} {
542  source $tcl_path/utils/cocotb.tcl
543  source $tcl_path/utils/hierarchy.tcl
544  WriteCocoTbTemplate $project_name $repo_path $lib_path $ext_path
545  exit 0
546  }
547 
548  if {$do_check_yaml_ref == 1} {
549  Msg Info "Checking if \"ref\" in .gitlab-ci.yml actually matches the included yml file in Hog submodule"
550  CheckYmlRef $repo_path false
551  exit 0
552  }
553 
554  if {$do_buttons == 1} {
555  Msg Info "Adding Hog buttons to Vivado bar (will use the vivado currently in PATH)..."
556  set ide vivado
557  set cmd "vivado -mode batch -notrace -source $repo_path/Hog/Tcl/utils/add_hog_custom_button.tcl"
558  }
559 
560  if {$do_compile_lib == 1} {
561  if {$project eq ""} {
562  Msg Error "You need to specify a simulator as first argument."
563  exit 1
564  } else {
565  set simulator $project
566  Msg Info "Selecting $simulator simulator..."
567  }
568  if {$options(dst_dir) != ""} {
569  set output_dir $options(dst_dir)
570  } else {
571  Msg Info "No destination directory defined. Using default: SimulationLib/"
572  set output_dir "SimulationLib"
573  }
574 
575  set ide vivado
576  set cmd \
577  "vivado -mode batch -notrace -source $repo_path/Hog/Tcl/utils/compile_simlib.tcl -tclargs -simulator $simulator \
578  -output_dir $output_dir"
579  }
580 
581  set simsets ""
582  if {$do_simulation == 1} {
583  # Filter out HLS simsets (csim:*/cosim:*) -- GHDL only needs HDL simsets
584  set hdl_simsets_pre [list]
585  if {$options(simset) ne ""} {
586  foreach s $options(simset) {
587  if {![regexp {^(csim|cosim):} $s]} {
588  lappend hdl_simsets_pre $s
589  }
590  }
591  }
592 
593  # Get all simsets in the project that run with GHDL
594  set ghdl_simsets [GetSimSets $project_name $repo_path "$hdl_simsets_pre" 1]
595  set ghdl_import 0
596  dict for {simset_name simset_dict} $ghdl_simsets {
597  if {$ghdl_import == 0} {
598  ImportGHDL $project_name $repo_path $simset_name $simset_dict $ext_path
599  set ghdl_import 1
600  }
601  LaunchGHDL $project_name $repo_path $simset_name $simset_dict $ext_path
602  }
603  set ide_simsets [GetSimSets $project_name $repo_path $hdl_simsets_pre 0 1]
604 
605  if {[dict size $ide_simsets] == 0} {
606  # Check if there are HLS simsets to run before exiting
607  set has_hls [expr {$options(simset) eq ""}]
608  if {!$has_hls} {
609  foreach s $options(simset) {
610  if {[regexp {^(csim|cosim):} $s]} {
611  set has_hls 1
612  break
613  }
614  }
615  }
616  if {!$has_hls} {
617  Msg Info "All simulations have been run, exiting..."
618  exit 0
619  }
620  }
621  }
622 
623  if {$do_version == 1} {
624  cd $repo_path
625  set proj_dir $repo_path/Top/$project_name
626  lassign [GetRepoVersions $proj_dir $repo_path $ext_path] sha ver
627  if {$options(describe) == 1} {
628  puts [GetHogDescribe $proj_dir $repo_path]
629  } else {
630  puts "v[HexVersionToString $ver]"
631  }
632  exit 0
633  }
634 
635  # if {$do_new_directive ==1 } {
636  #
637  # # Do things here
638  #
639  # exit 0
640  #}
641  #### END of tclsh commands ####
642  Msg Info "Launching command: $cmd..."
643 
644  # Check if the IDE is actually in the path...
645  set ret [catch {exec which $ide}]
646  if {$ret != 0} {
647  if {[string match "*vitis_unified*" $ide_name]} {
648  Msg Error \
649  "This is a '$ide_name' project: make sure to add both Vivado and Vitis to your PATH environment variable."
650  } else {
651  Msg Error "$ide not found in your system. Make sure to add $ide to your PATH environment variable."
652  }
653  exit $ret
654  }
655 
656  if {[string first libero $cmd] >= 0} {
657  # The SCRIPT_ARGS: flag of libero makes tcl crazy...
658  # Let's pipe the command into a shell script and remove it later
659  set libero_script [open "launch-libero-hog.sh" w]
660  puts $libero_script "#!/bin/sh"
661  puts $libero_script $cmd
662  close $libero_script
663  set cmd "sh launch-libero-hog.sh"
664  }
665 
666  set ret [catch {exec -ignorestderr {*}$cmd >@ stdout 2>@ stderr} result]
667 
668  if {$ret != 0} {
669  Msg Error "IDE returned an error state: $result"
670  } else {
671  Msg Info "All done."
672  exit 0
673  }
674 
675  if {[string first libero $cmd] >= 0} {
676  file delete "launch-libero-hog.sh"
677  }
678 
679  exit $ret
680 }
681 
682 
683 #After this line, we are in the IDE
684 ##################################################################################
685 # We need to Import tcllib if we are using Libero
686 if {[IsLibero] || [IsDiamond]} {
687  if {[info exists env(HOG_TCLLIB_PATH)]} {
688  lappend auto_path $env(HOG_TCLLIB_PATH)
689  } else {
690  puts \
691  "ERROR: To run Hog with Microsemi Libero SoC or Lattice Diamond, you need to define the HOG_TCLLIB_PATH variable."
692  return
693  }
694 }
695 
696 if {[catch {package require cmdline} ERROR] || [catch {package require struct::matrix} ERROR]} {
697  puts \
698  "$ERROR\n Tcllib not found. If you are running this script on tclsh for debuggin purpose ONLY, you can fix this by \
699  installing 'tcllib'"
700  exit 1
701 }
702 
703 set run_folder [file normalize "$repo_path/Projects/$project_name/$project.runs/"]
704 if {[IsLibero]} {
705  set run_folder [file normalize "$repo_path/Projects/$project_name/"]
706 }
707 
708 # Only for quartus, not used otherwise
709 set project_path [file normalize "$repo_path/Projects/$project_name/"]
710 
711 # Get IDE name from project config file
712 if {$allow_empty_proj == 0 || $project_name ne ""} {
713  set proj_conf [ProjectExists $project_name $repo_path]
714 } else {
715  set proj_conf ""
716 }
717 set ide_name_and_ver [string tolower [GetIDEFromConf $proj_conf]]
718 set ide_name [lindex [regexp -all -inline {\S+} $ide_name_and_ver] 0]
719 
720 # Validate IDE name
721 set supported_ides \
722  [list vivado vivado_vitis_classic vivado_vitis_unified vitis_classic vitis_unified quartus planahead libero diamond \
723  ghdl]
724 if {$ide_name ni $supported_ides} {
725  if {$ide_name eq "vitis"} {
726  Msg Error \
727  "The IDE set in hog.conf ('vitis') is not supported. Did you mean 'vitis_unified' or 'vitis_classic'? Supported \
728  IDEs: [join $supported_ides {, }]"
729  } else {
730  Msg Error "The IDE set in hog.conf ('$ide_name') is not supported. Supported IDEs: [join $supported_ides {, }]"
731  }
732  exit 1
733 }
734 
735 # Vitis IDE detection
736 if {
737  ([string tolower $ide_name] eq "vivado_vitis_classic" || [string tolower $ide_name] eq "vitis_classic")
738  && ($options(vivado_only) != 1)
739 } {
740  set globalSettings::vitis_classic 1
741  set globalSettings::vitis_unified 0
742 } elseif {
743  ([string tolower $ide_name] eq "vivado_vitis_unified" || [string tolower $ide_name] eq "vitis_unified")
744  && ($options(vivado_only) != 1)
745 } {
746  set globalSettings::vitis_classic 0
747  set globalSettings::vitis_unified 1
748  if {[auto_execok vitis] eq ""} {
749  Msg Error \
750  "Vitis Unified IDE is required for project $project_name but 'vitis' was not found in PATH. Please source Vitis \
751  settings first."
752  }
753 } else {
754  set globalSettings::vitis_classic 0
755  set globalSettings::vitis_unified 0
756 }
757 
758 # Standalone vitis_unified / vitis_classic projects are implicitly vitis-only
759 if {$ide_name eq "vitis_unified" || $ide_name eq "vitis_classic"} {
760  set options(vitis_only) 1
761 }
762 
763 set is_vitis_ide [expr {$globalSettings::vitis_classic == 1 || $globalSettings::vitis_unified == 1}]
764 set is_build_step [expr {$do_synthesis == 1 || $do_implementation == 1 || $do_compile == 1}]
765 if {$is_vitis_ide && $options(vitis_only) == 1 && $is_build_step} {
766  set do_vitis_build 1
767 }
768 
769 
770 if {$options(no_bitstream) == 1} {
771  set do_bitstream 0
772  set do_compile 0
773 }
774 
775 if {$options(recreate) == 1} {
776  set recreate 1
777 }
778 
779 if {$options(synth_only) == 1} {
780  set do_implementation 0
781  set do_synthesis 1
782  set do_bitstream 0
783  set do_create 1
784  set do_compile 1
785 }
786 
787 if {$options(impl_only) == 1} {
788  set do_implementation 1
789  set do_synthesis 0
790  set do_bitstream 0
791  set do_create 0
792  set do_compile 1
793 }
794 
795 if {$options(vitis_only) == 1 || $ide_name eq "vitis_classic" || $ide_name eq "vitis_unified"} {
796  set do_implementation 0
797  set do_synthesis 0
798  set do_bitstream 0
799  set do_compile 0
800 }
801 
802 if {$options(bitstream_only) == 1} {
803  set do_bitstream_only 1
804  set do_bitstream 0
805  set do_implementation 0
806  set do_synthesis 0
807  set do_create 0
808  set do_compile 0
809 } else {
810  set do_bitstream_only 0
811 }
812 
813 if {$options(no_reset) == 1} {
814  set do_reset 0
815 }
816 
817 if {$options(check_syntax) == 1} {
818  set do_check_syntax 1
819 }
820 
821 if {$options(scripts_only) == 1} {
822  set scripts_only 1
823 }
824 
825 if {$options(compile_only) == 1} {
826  set compile_only 1
827 }
828 
829 
830 Msg Info "Number of jobs set to $options(njobs)."
831 
832 ############## Quartus ########################
833 set argv ""
834 
835 ############# CREATE or OPEN project ############
836 if {$options(vitis_only) == 1 && ($ide_name eq "vitis_unified" || $ide_name eq "vivado_vitis_unified")} {
837  cd $tcl_path
838  set project_file [file normalize $repo_path/Projects/$project_name/vitis_unified/_ide/settings.json]
839  Msg Info "Setting project file for Vitis Unified project $project_name to $project_file"
840 } elseif {$options(vitis_only) == 1 && ($ide_name eq "vitis_classic" || $ide_name eq "vivado_vitis_classic")} {
841  cd $tcl_path
842  set project_file [file normalize $repo_path/Projects/$project_name/vitis_classic/.metadata/]
843  Msg Info "Setting project file for Vitis Classic project $project_name to $project_file"
844 } elseif {[IsISE]} {
845  cd $tcl_path
846  set project_file [file normalize $repo_path/Projects/$project_name/$project.ppr]
847 } elseif {[IsVivado]} {
848  cd $tcl_path
849  set project_file [file normalize $repo_path/Projects/$project_name/$project.xpr]
850 } elseif {[IsVitisClassic]} {
851  cd $tcl_path
852  set project_file [file normalize $repo_path/Projects/$project_name/vitis_classic/.metadata/]
853  Msg Info "Setting project file for Vitis Classic project $project_name to $project_file"
854 } elseif {[IsVitisUnified]} {
855  cd $tcl_path
856  set project_file [file normalize $repo_path/Projects/$project_name/vitis_unified/_ide/settings.json]
857  Msg Info "Setting project file for Vitis Unified project $project_name to $project_file"
858 } elseif {[IsQuartus]} {
859  if {[catch {package require ::quartus::project} ERROR]} {
860  Msg Error "$ERROR\n Can not find package ::quartus::project"
861  cd $old_path
862  return 1
863  } else {
864  Msg Info "Loaded package ::quartus::project"
865  load_package flow
866  }
867  set project_file "$project_path/$project.qpf"
868 } elseif {[IsLibero]} {
869  set project_file [file normalize $repo_path/Projects/$project_name/$project.prjx]
870 } elseif {[IsDiamond]} {
871  sys_install version
872  set project_file [file normalize $repo_path/Projects/$project_name/$project.ldf]
873 } else {
874  Msg Error "Unknown IDE, can't set project file path."
875  exit 1
876 }
877 
878 if {[file exists $project_file]} {
879  Msg Info "Found project file $project_file for $project_name."
880  set proj_found 1
881 } else {
882  # Path from InitLauncher may resolve to a different mount for the same repo.
883  # Discover repo root and use first path where project exists (file or, for Vitis Unified, project dir).
884  set repo_norm [file normalize $repo_path]
885  set rel [string trimleft [string range $project_file [string length $repo_norm] end] "/"]
886  set proj_found 0
887  foreach start_dir [list [file dirname [info script]] [pwd]] {
888  set repo_candidate [FindRepoRoot $start_dir]
889  Msg Debug "FindRepoRoot([list $start_dir]) => [list $repo_candidate]"
890  if {$repo_candidate ne ""} {
891  set project_file_alt [file join $repo_candidate $rel]
892  set found 0
893  if {[file exists $project_file_alt]} {
894  set found 1
895  } elseif {$options(vitis_only) == 1 && [string match "*vitis_unified*" $rel]} {
896  set ide_dir [file join $repo_candidate Projects $project_name vitis_unified _ide]
897  if {[file exists $ide_dir]} {
898  set found 1
899  }
900  }
901  if {$options(vitis_only) == 1 && [string match "*vitis_unified*" $rel]} {
902  Msg Debug \
903  "Checking file [list $project_file_alt] exists=[file exists $project_file_alt]; _ide dir [list $ide_dir] \
904  exists=[file exists $ide_dir]"
905  } else {
906  Msg Debug "Checking [list $project_file_alt] exists=[file exists $project_file_alt]"
907  }
908  if {$found} {
909  set project_file $project_file_alt
910  set repo_path $repo_candidate
911  Msg Info "Found project file $project_file for $project_name."
912  set proj_found 1
913  break
914  }
915  }
916  }
917  if {!$proj_found} {
918  Msg Info "Project file not found for $project_name."
919  }
920 }
921 
922 if {$proj_found == 0 && $do_upgrade_ips == 1} {
923  Msg Error "Project $project_name not found. UPGRADE_IP requires an existing project."
924  exit 1
925 } elseif {($proj_found == 0 || $recreate == 1)} {
926  set do_create 1
927  Msg Info "Creating (possibly replacing) the project $project_name..."
928  Msg Debug "launch.tcl: calling GetConfFiles with $repo_path/Top/$project_name"
929  lassign [GetConfFiles $repo_path/Top/$project_name] conf sim pre post pre_rtl post_rtl
930 
931  if {[file exists $conf]} {
932  set globalSettings::vitis_only_pass $options(vitis_only)
933  if {$options(vivado_only) == 1} {
934  CreateProject -simlib_path $lib_path -xsa $options(xsa) -vivado_only $project_name $repo_path
935  } elseif {$options(vitis_only) == 1} {
936  CreateProject -simlib_path $lib_path -xsa $options(xsa) -vitis_only $project_name $repo_path
937  } else {
938  CreateProject -simlib_path $lib_path -xsa $options(xsa) $project_name $repo_path
939  }
940  Msg Info "Done creating project $project_name."
941  if {$options(vitis_only) == 1 && ($ide_name eq "vitis_unified" || $ide_name eq "vivado_vitis_unified")} {
942  set project_file [file join $repo_path Projects $project_name vitis_unified _ide settings.json]
943  }
944  } else {
945  Msg Error "Project $project_name is incomplete: no hog.conf file found, please create one..."
946  }
947 } elseif {$proj_found == 0} {
948  Msg Error "Project $project_name not found. Please create it first using the 'CREATE' or 'C' directive."
949  exit 1
950 } else {
951  Msg Info "Opening existing project file $project_file..."
952  if {$options(vitis_only) == 1 && ($ide_name eq "vitis_unified" || $ide_name eq "vivado_vitis_unified")} {
953  set vitis_workspace [file normalize $repo_path/Projects/$project_name/vitis_unified/]
954  Msg Info "Setting Vitis Unified workspace to $vitis_workspace"
955  } elseif {[IsXilinx]} {
956  file mkdir "$repo_path/Projects/$project_name/$project.gen/sources_1"
957  OpenProject $project_file $repo_path
958  } elseif {[IsVitisClassic]} {
959  set vitis_workspace [file normalize $repo_path/Projects/$project_name/vitis_classic/]
960  Msg Info "Setting workspace to $vitis_workspace"
961  } elseif {[IsVitisUnified]} {
962  set vitis_workspace [file normalize $repo_path/Projects/$project_name/vitis_unified/]
963  Msg Info "Setting workspace to $vitis_workspace"
964  } else {
965  OpenProject $project_file $repo_path
966  }
967 }
968 
969 if {$do_upgrade_ips == 1} {
970  if {![IsVivado]} {
971  Msg Error "The UPGRADE_IP directive is only supported for Vivado projects."
972  exit 1
973  }
974  UpgradeIPs
975  exit 0
976 }
977 
978 
979 ########## CHECK SYNTAX ###########
980 if {$do_check_syntax == 1} {
981  if {$ide_name eq "vitis_unified" || $ide_name eq "vitis_classic"} {
982  Msg Info "Skipping syntax check for $project_name: pure Vitis project has no HDL syntax to check"
983  } else {
984  Msg Info "Checking syntax for project $project_name..."
985  CheckSyntax $project_name $repo_path $project_file
986  }
987 }
988 
989 ######### RTL ANALYSIS ########
990 if {$do_rtl == 1} {
991  lassign [GetConfFiles $repo_path/Top/$project_name] conf sim pre post pre_rtl post_rtl
992  LaunchRTLAnalysis $repo_path $pre_rtl $post_rtl
993 }
994 
995 if {$do_vitis_build == 1} {
996  if {[IsVitisClassic] || [IsVitisUnified]} {
997  # Check for HLS components and build them
998  set conf_file_path [file normalize "$repo_path/Top/$project_name/hog.conf"]
999  if {[file exists $conf_file_path]} {
1000  set proj_properties [ReadConf $conf_file_path]
1001  set hls_components [dict filter $proj_properties key {hls:*}]
1002  if {[dict size $hls_components] > 0} {
1003  Msg Info "Found [dict size $hls_components] HLS component(s), launching HLS build..."
1004  LaunchHlsBuild $project_name $repo_path
1005  }
1006  # Build apps/platforms if any exist
1007  set has_apps [expr {[dict size [dict filter $proj_properties key {app:*}]] > 0}]
1008  if {$has_apps} {
1009  LaunchVitisBuild $project_name $repo_path
1010  }
1011  } else {
1012  LaunchVitisBuild $project_name $repo_path
1013  }
1014  } else {
1015  Msg Error "Vitis build is not supported for $ide_name (only Vitis Classic and Vitis Unified are supported)"
1016  exit 1
1017  }
1018 }
1019 
1020 ######### LaunchSynthesis ########
1021 if {$do_synthesis == 1} {
1022  LaunchSynthesis $do_reset $do_create $run_folder $project_name $repo_path $ext_path $options(njobs)
1023 }
1024 
1025 if {$do_implementation == 1} {
1026  LaunchImplementation $do_reset $do_create $run_folder $project_name $repo_path $options(njobs) $do_bitstream
1027 }
1028 
1029 if {$do_bitstream_only == 1 && [IsXilinx]} {
1030  GenerateBitstreamOnly $project_name $repo_path
1031 } elseif {$do_bitstream_only == 1 && ![IsXilinx]} {
1032  Msg Error "Bitstream only option is not supported for this IDE."
1033 }
1034 
1035 if {$do_bitstream == 1 && ![IsXilinx]} {
1036  GenerateBitstream $run_folder $repo_path $options(njobs)
1037 }
1038 
1039 if {$do_simulation == 1} {
1040  # Separate HLS simsets (csim:*/cosim:*) from HDL simsets
1041  set hdl_simsets [list]
1042  set hls_simsets [list]
1043  if {$options(simset) ne ""} {
1044  foreach s $options(simset) {
1045  if {[regexp {^(csim|cosim):} $s]} {
1046  lappend hls_simsets $s
1047  } else {
1048  lappend hdl_simsets $s
1049  }
1050  }
1051  }
1052  set run_hdl [expr {[llength $hdl_simsets] > 0 || $options(simset) eq ""}]
1053  set run_hls [expr {[llength $hls_simsets] > 0 || $options(simset) eq ""}]
1054 
1055  # Run HDL simulations
1056  if {$run_hdl} {
1057  set simsets [GetSimSets $project_name $repo_path $hdl_simsets]
1058  if {[dict size $simsets] > 0} {
1059  LaunchSimulation $project_name $lib_path $simsets $repo_path $scripts_only $compile_only
1060  }
1061  }
1062 
1063  # Run HLS simulations (csim/cosim)
1064  if {$run_hls} {
1065  LaunchHlsSimulation $project_name $repo_path $hls_simsets
1066  }
1067 }
1068 
1069 
1070 if {$do_check_list_files} {
1071  Msg Info "Running list file checker..."
1072 
1073 
1074  #if {![file exists $dst_dir]} {
1075  # Msg Info "$dst_dir directory not found, creating it..."
1076  # file mkdir $dst_dir
1077  # }
1078  set argv0 check_list_files
1079  if {$ext_path ne ""} {
1080  set argv [list "-ext_path" "$ext_path" "-outDir" "$dst_dir" "-pedantic"]
1081  } else {
1082  set argv [list "-outDir" "$dst_dir" "-pedantic"]
1083  }
1084 
1085  source $tcl_path/utils/check_list_files.tcl
1086 }
1087 ## CLOSE Project
1089 
1090 Msg Info "All done."
1091 cd $old_path