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