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