Hog v10.13.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  Msg Info "Handling IPbus XMLs for $project_name..."
489 
490  set proj_dir $repo_path/Top/$project_name
491 
492  if {$options(generate) == 1} {
493  set xml_gen 1
494  } else {
495  set xml_gen 0
496  }
497 
498  if {$options(dst_dir) != ""} {
499  set dst_dir $options(dst_dir)
500  }
501  set xml_dst "$dst_dir/xml"
502 
503 
504  if {[llength [glob -nocomplain $proj_dir/list/*.ipb]] > 0} {
505  if {![file exists $xml_dst]} {
506  Msg Info "$xml_dst directory not found, creating it..."
507  file mkdir $xml_dst
508  }
509  } else {
510  Msg Error "No .ipb files found in $proj_dir/list/"
511  exit
512  }
513 
514  set ret [GetRepoVersions $proj_dir $repo_path ""]
515  set sha [lindex $ret 13]
516  set hex_ver [lindex $ret 14]
517 
518  set ver [HexVersionToString $hex_ver]
519  CopyIPbusXMLs $proj_dir $repo_path $xml_dst $ver $sha 1 $xml_gen
520 
521  exit 0
522  }
523 
524  if {$do_list_file_parse == 1} {
525  set proj_dir $repo_path/Top/$project_name
526  set proj_list_dir $repo_path/Top/$project_name/list
527  GetHogFiles -print_log -list_files {.src,.con,.sim,.ext,.ipb} $proj_list_dir $repo_path
528  Msg Status " "
529  Msg Info "All Done."
530  exit 0
531  }
532 
533  if {$do_hierarchy == 1} {
534  source $tcl_path/utils/hierarchy.tcl
535  set proj_dir $repo_path/Top/$project_name
536  set proj_list_dir $repo_path/Top/$project_name/list
537  lassign [GetHogFiles -ext_path $ext_path \
538  -list_files ".src,.ext" $proj_list_dir $repo_path]\
539  listLibraries listProperties listSrcSets
540  set hierarchy_result [Hierarchy $listProperties $listLibraries $repo_path $output_path $compile_order \
541  $light_hierarchy $top_module $ignored_hierarchy $include_ieee $include_gen_prods]
542  puts $hierarchy_result
543  exit 0
544  }
545  if {$do_sigasi == 1} {
546  cd $repo_path
547  Msg Info "Creating Sigasi CSV files for project $project_name..."
548  set proj_dir $repo_path/Top/$project_name
549  set proj_list_dir $repo_path/Top/$project_name/list
550  set project [file tail $project_name]
551  lassign [GetHogFiles -list_files {.src} $proj_list_dir $repo_path] libraries
552  set csv_file [open "sigasi_$project.csv" w]
553  foreach lib $libraries {
554  set source_files [DictGet $libraries $lib]
555  foreach source_file $source_files {
556  if {[file extension $source_file] == ".vhd" ||
557  [file extension $source_file] == ".vhdl" ||
558  [file extension $source_file] == ".sv" ||
559  [file extension $source_file] == ".v" } {
560  puts $csv_file [ concat [file rootname $lib] "," $source_file ]
561  }
562  }
563  }
564  close $csv_file
565  Msg Info "Sigasi CSV file created: sigasi_$project.csv"
566  Msg Info "You can use the python script provided by Sigasi to convert the generated csv file into a Sigasi project."
567  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"
568  exit 0
569  }
570 
571  if {$do_vhdl_ls == 1} {
572  cd $repo_path
573  Msg Info "Creating VHDL-LS configuration file for project $project_name..."
574  set proj_dir $repo_path/Top/$project_name
575  set proj_list_dir $repo_path/Top/$project_name/list
576  set project [file tail $project_name]
577  lassign [GetHogFiles -list_files {.src} $proj_list_dir $repo_path] libraries
578  set toml_file [open "vhdl_ls_$project.toml" w]
579  puts $toml_file "\[libraries\]"
580  dict for {lib source_files} $libraries {
581  puts $toml_file "[file rootname $lib].files = \["
582  foreach source_file $source_files {
583  if {[file extension $source_file] == ".vhd" ||
584  [file extension $source_file] == ".vhdl"
585  } {
586  # puts [Relative $repo_path $source_file ]
587  puts $toml_file "\'[Relative $repo_path $source_file ]\',"
588  }
589  }
590  puts $toml_file "\]\n"
591  }
592  close $toml_file
593  Msg Info "VHDL-LS TOML File created: vhdl_ls_$project.toml"
594  Msg Info "You can copy the content of this file into your VHDL-LS configuration vhdl_ls.toml, to import all Hog libraries."
595  exit 0
596  }
597 
598  if {$do_cocotb == 1} {
599  source $tcl_path/utils/cocotb.tcl
600  source $tcl_path/utils/hierarchy.tcl
601  WriteCocoTbTemplate $project_name $repo_path $lib_path $ext_path
602  exit 0
603  }
604 
605  if {$do_check_yaml_ref == 1} {
606  Msg Info "Checking if \"ref\" in .gitlab-ci.yml actually matches the included yml file in Hog submodule"
607  CheckYmlRef $repo_path false
608  exit 0
609  }
610 
611  if {$do_buttons == 1} {
612  Msg Info "Adding Hog buttons to Vivado bar (will use the vivado currently in PATH)..."
613  set ide vivado
614  set cmd "vivado -mode batch -notrace -source $repo_path/Hog/Tcl/utils/add_hog_custom_button.tcl"
615  }
616 
617  if {$do_compile_lib == 1} {
618  if {$project eq ""} {
619  Msg Error "You need to specify a simulator as first argument."
620  exit 1
621  } else {
622  set simulator $project
623  Msg Info "Selecting $simulator simulator..."
624  }
625  if {$options(dst_dir) != ""} {
626  set output_dir $options(dst_dir)
627  } else {
628  Msg Info "No destination directory defined. Using default: SimulationLib/"
629  set output_dir "SimulationLib"
630  }
631 
632  set ide vivado
633  set cmd "vivado -mode batch -notrace -source $repo_path/Hog/Tcl/utils/compile_simlib.tcl -tclargs -simulator $simulator -output_dir $output_dir"
634  }
635 
636  set simsets ""
637  if {$do_simulation == 1} {
638  # Filter out HLS simsets (csim:*/cosim:*) -- GHDL only needs HDL simsets
639  set hdl_simsets_pre [list]
640  if {$options(simset) ne ""} {
641  foreach s $options(simset) {
642  if {![regexp {^(csim|cosim):} $s]} {
643  lappend hdl_simsets_pre $s
644  }
645  }
646  }
647 
648  # Get all simsets in the project that run with GHDL
649  set ghdl_simsets [GetSimSets $project_name $repo_path "$hdl_simsets_pre" 1]
650  set ghdl_import 0
651  dict for {simset_name simset_dict} $ghdl_simsets {
652  if {$ghdl_import == 0} {
653  ImportGHDL $project_name $repo_path $simset_name $simset_dict $ext_path
654  set ghdl_import 1
655  }
656  LaunchGHDL $project_name $repo_path $simset_name $simset_dict $ext_path
657  }
658  set ide_simsets [GetSimSets $project_name $repo_path $hdl_simsets_pre 0 1]
659 
660  if {[dict size $ide_simsets] == 0} {
661  # Check if there are HLS simsets to run before exiting
662  set has_hls [expr {$options(simset) eq ""}]
663  if {!$has_hls} {
664  foreach s $options(simset) {
665  if {[regexp {^(csim|cosim):} $s]} {
666  set has_hls 1
667  break
668  }
669  }
670  }
671  if {!$has_hls} {
672  Msg Info "All simulations have been run, exiting..."
673  exit 0
674  }
675  }
676  }
677 
678  if {$do_version == 1} {
679  cd $repo_path
680  set proj_dir $repo_path/Top/$project_name
681  lassign [GetRepoVersions $proj_dir $repo_path $ext_path] sha ver
682  if {$options(describe) == 1} {
683  puts [GetHogDescribe $proj_dir $repo_path]
684  } else {
685  puts "v[HexVersionToString $ver]"
686  }
687  exit 0
688  }
689  # if {$do_new_directive ==1 } {
690  #
691  # # Do things here
692  #
693  # exit 0
694  #}
695 
696  #### END of tclsh commands ####
697  Msg Info "Launching command: $cmd..."
698 
699  # Check if the IDE is actually in the path...
700  set ret [catch {exec which $ide}]
701  if {$ret != 0} {
702  if {[string match "*vitis_unified*" $ide_name]} {
703  Msg Error "This is a '$ide_name' project: make sure to add both Vivado and Vitis to your PATH environment variable."
704  } else {
705  Msg Error "$ide not found in your system. Make sure to add $ide to your PATH environment variable."
706  }
707  exit $ret
708  }
709 
710  if {[string first libero $cmd] >= 0} {
711  # The SCRIPT_ARGS: flag of libero makes tcl crazy...
712  # Let's pipe the command into a shell script and remove it later
713  set libero_script [open "launch-libero-hog.sh" w]
714  puts $libero_script "#!/bin/sh"
715  puts $libero_script $cmd
716  close $libero_script
717  set cmd "sh launch-libero-hog.sh"
718  }
719 
720  set ret [catch {exec -ignorestderr {*}$cmd >@ stdout} result]
721 
722  if {$ret != 0} {
723  Msg Error "IDE returned an error state."
724  } else {
725  Msg Info "All done."
726  exit 0
727  }
728 
729  if {[string first libero $cmd] >= 0} {
730  file delete "launch-libero-hog.sh"
731  }
732 
733  exit $ret
734 }
735 
736 #After this line, we are in the IDE
737 ##################################################################################
738 
739 
740 # We need to Import tcllib if we are using Libero
741 if {[IsLibero] || [IsDiamond]} {
742  if {[info exists env(HOG_TCLLIB_PATH)]} {
743  lappend auto_path $env(HOG_TCLLIB_PATH)
744  } else {
745  puts "ERROR: To run Hog with Microsemi Libero SoC or Lattice Diamond,\
746  you need to define the HOG_TCLLIB_PATH variable."
747  return
748  }
749 }
750 
751 if {[catch {package require cmdline} ERROR] || [catch {package require struct::matrix} ERROR]} {
752  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'"
753  exit 1
754 }
755 
756 ## CHECK PROJECT VERSION
757 if {$do_checkproj_ver == 1} {
758  CheckProjVer $repo_path $project_name $options(simcheck) $options(ext_path)
759  exit 0
760 }
761 
762 set run_folder [file normalize "$repo_path/Projects/$project_name/$project.runs/"]
763 if {[IsLibero]} {
764  set run_folder [file normalize "$repo_path/Projects/$project_name/"]
765 }
766 
767 # Only for quartus, not used otherwise
768 set project_path [file normalize "$repo_path/Projects/$project_name/"]
769 
770 # Get IDE name from project config file
771 set proj_conf [ProjectExists $project_name $repo_path]
772 set ide_name_and_ver [string tolower [GetIDEFromConf $proj_conf]]
773 set ide_name [lindex [regexp -all -inline {\S+} $ide_name_and_ver] 0]
774 
775 # Validate IDE name
776 set supported_ides [list vivado vivado_vitis_classic vivado_vitis_unified vitis_classic vitis_unified quartus planahead libero diamond ghdl]
777 if {$ide_name ni $supported_ides} {
778  if {$ide_name eq "vitis"} {
779  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 {, }]"
780  } else {
781  Msg Error "The IDE set in hog.conf ('$ide_name') is not supported. Supported IDEs: [join $supported_ides {, }]"
782  }
783  exit 1
784 }
785 
786 # Vitis IDE detection
787 if {([string tolower $ide_name] eq "vivado_vitis_classic" || [string tolower $ide_name] eq "vitis_classic") && ($options(vivado_only) != 1)} {
788  set globalSettings::vitis_classic 1
789  set globalSettings::vitis_unified 0
790 } elseif {([string tolower $ide_name] eq "vivado_vitis_unified" || [string tolower $ide_name] eq "vitis_unified") && ($options(vivado_only) != 1)} {
791  set globalSettings::vitis_classic 0
792  set globalSettings::vitis_unified 1
793  if {[auto_execok vitis] eq ""} {
794  Msg Error "Vitis Unified IDE is required for project $project_name but 'vitis' was not found in PATH. Please source Vitis settings first."
795  }
796 } else {
797  set globalSettings::vitis_classic 0
798  set globalSettings::vitis_unified 0
799 }
800 
801 # Standalone vitis_unified / vitis_classic projects are implicitly vitis-only
802 if {$ide_name eq "vitis_unified" || $ide_name eq "vitis_classic"} {
803  set options(vitis_only) 1
804 }
805 
806 set is_vitis_ide [expr {$globalSettings::vitis_classic == 1 || $globalSettings::vitis_unified == 1}]
807 set is_build_step [expr {$do_synthesis == 1 || $do_implementation == 1 || $do_compile == 1}]
808 if {$is_vitis_ide && $options(vitis_only) == 1 && $is_build_step} {
809  set do_vitis_build 1
810 }
811 
812 
813 if {$options(no_bitstream) == 1} {
814  set do_bitstream 0
815  set do_compile 0
816 }
817 
818 if {$options(recreate) == 1} {
819  set recreate 1
820 }
821 
822 if {$options(synth_only) == 1} {
823  set do_implementation 0
824  set do_synthesis 1
825  set do_bitstream 0
826  set do_create 1
827  set do_compile 1
828 }
829 
830 if {$options(impl_only) == 1} {
831  set do_implementation 1
832  set do_synthesis 0
833  set do_bitstream 0
834  set do_create 0
835  set do_compile 1
836 }
837 
838 if {$options(vitis_only) == 1 || $ide_name eq "vitis_classic" || $ide_name eq "vitis_unified"} {
839  set do_implementation 0
840  set do_synthesis 0
841  set do_bitstream 0
842  set do_compile 0
843 }
844 
845 if {$options(bitstream_only) == 1} {
846  set do_bitstream_only 1
847  set do_bitstream 0
848  set do_implementation 0
849  set do_synthesis 0
850  set do_create 0
851  set do_compile 0
852 } else {
853  set do_bitstream_only 0
854 }
855 
856 if {$options(no_reset) == 1} {
857  set do_reset 0
858 }
859 
860 if {$options(check_syntax) == 1} {
861  set do_check_syntax 1
862 }
863 
864 if {$options(scripts_only) == 1} {
865  set scripts_only 1
866 }
867 
868 if {$options(compile_only) == 1} {
869  set compile_only 1
870 }
871 
872 
873 
874 
875 
876 Msg Info "Number of jobs set to $options(njobs)."
877 
878 ############## Quartus ########################
879 set argv ""
880 
881 ############# CREATE or OPEN project ############
882 if {$options(vitis_only) == 1 && ($ide_name eq "vitis_unified" || $ide_name eq "vivado_vitis_unified")} {
883  cd $tcl_path
884  set project_file [file normalize $repo_path/Projects/$project_name/vitis_unified/_ide/settings.json]
885  Msg Info "Setting project file for Vitis Unified project $project_name to $project_file"
886 } elseif {$options(vitis_only) == 1 && ($ide_name eq "vitis_classic" || $ide_name eq "vivado_vitis_classic")} {
887  cd $tcl_path
888  set project_file [file normalize $repo_path/Projects/$project_name/vitis_classic/.metadata/]
889  Msg Info "Setting project file for Vitis Classic project $project_name to $project_file"
890 } elseif {[IsISE]} {
891  cd $tcl_path
892  set project_file [file normalize $repo_path/Projects/$project_name/$project.ppr]
893 } elseif {[IsVivado]} {
894  cd $tcl_path
895  set project_file [file normalize $repo_path/Projects/$project_name/$project.xpr]
896 } elseif {[IsVitisClassic]} {
897  cd $tcl_path
898  set project_file [file normalize $repo_path/Projects/$project_name/vitis_classic/.metadata/]
899  Msg Info "Setting project file for Vitis Classic project $project_name to $project_file"
900 } elseif {[IsVitisUnified]} {
901  cd $tcl_path
902  set project_file [file normalize $repo_path/Projects/$project_name/vitis_unified/_ide/settings.json]
903  Msg Info "Setting project file for Vitis Unified project $project_name to $project_file"
904 } elseif {[IsQuartus]} {
905  if {[catch {package require ::quartus::project} ERROR]} {
906  Msg Error "$ERROR\n Can not find package ::quartus::project"
907  cd $old_path
908  return 1
909  } else {
910  Msg Info "Loaded package ::quartus::project"
911  load_package flow
912  }
913  set project_file "$project_path/$project.qpf"
914 } elseif {[IsLibero]} {
915  set project_file [file normalize $repo_path/Projects/$project_name/$project.prjx]
916 } elseif {[IsDiamond]} {
917  sys_install version
918  set project_file [file normalize $repo_path/Projects/$project_name/$project.ldf]
919 }
920 
921 if {[file exists $project_file]} {
922  Msg Info "Found project file $project_file for $project_name."
923  set proj_found 1
924 } else {
925  # Path from InitLauncher may resolve to a different mount for the same repo.
926  # Discover repo root and use first path where project exists (file or, for Vitis Unified, project dir).
927  set repo_norm [file normalize $repo_path]
928  set rel [string trimleft [string range $project_file [string length $repo_norm] end] "/"]
929  set proj_found 0
930  foreach start_dir [list [file dirname [info script]] [pwd]] {
931  set repo_candidate [FindRepoRoot $start_dir]
932  Msg Debug "FindRepoRoot([list $start_dir]) => [list $repo_candidate]"
933  if {$repo_candidate ne ""} {
934  set project_file_alt [file join $repo_candidate $rel]
935  set found 0
936  if {[file exists $project_file_alt]} {
937  set found 1
938  } elseif {$options(vitis_only) == 1 && [string match "*vitis_unified*" $rel]} {
939  set ide_dir [file join $repo_candidate Projects $project_name vitis_unified _ide]
940  if {[file exists $ide_dir]} {
941  set found 1
942  }
943  }
944  if {$options(vitis_only) == 1 && [string match "*vitis_unified*" $rel]} {
945  Msg Debug "Checking file [list $project_file_alt] exists=[file exists $project_file_alt]; _ide dir [list $ide_dir] exists=[file exists $ide_dir]"
946  } else {
947  Msg Debug "Checking [list $project_file_alt] exists=[file exists $project_file_alt]"
948  }
949  if {$found} {
950  set project_file $project_file_alt
951  set repo_path $repo_candidate
952  Msg Info "Found project file $project_file for $project_name."
953  set proj_found 1
954  break
955  }
956  }
957  }
958  if {!$proj_found} {
959  Msg Info "Project file not found for $project_name."
960  }
961 }
962 
963 if {($proj_found == 0 || $recreate == 1)} {
964  set do_create 1
965  Msg Info "Creating (possibly replacing) the project $project_name..."
966  Msg Debug "launch.tcl: calling GetConfFiles with $repo_path/Top/$project_name"
967  lassign [GetConfFiles $repo_path/Top/$project_name] conf sim pre post pre_rtl post_rtl
968 
969  if {[file exists $conf]} {
970  set globalSettings::vitis_only_pass $options(vitis_only)
971  if {$options(vivado_only) == 1} {
972  CreateProject -simlib_path $lib_path -xsa $options(xsa) -vivado_only $project_name $repo_path
973  } elseif {$options(vitis_only) == 1} {
974  CreateProject -simlib_path $lib_path -xsa $options(xsa) -vitis_only $project_name $repo_path
975  } else {
976  CreateProject -simlib_path $lib_path -xsa $options(xsa) $project_name $repo_path
977  }
978  Msg Info "Done creating project $project_name."
979  if {$options(vitis_only) == 1 && ($ide_name eq "vitis_unified" || $ide_name eq "vivado_vitis_unified")} {
980  set project_file [file join $repo_path Projects $project_name vitis_unified _ide settings.json]
981  }
982  } else {
983  Msg Error "Project $project_name is incomplete: no hog.conf file found, please create one..."
984  }
985 } elseif {$proj_found == 0} {
986  Msg Error "Project $project_name not found. Please create it first using the 'CREATE' or 'C' directive."
987  exit 1
988 } else {
989  Msg Info "Opening existing project file $project_file..."
990  if {$options(vitis_only) == 1 && ($ide_name eq "vitis_unified" || $ide_name eq "vivado_vitis_unified")} {
991  set vitis_workspace [file normalize $repo_path/Projects/$project_name/vitis_unified/]
992  Msg Info "Setting Vitis Unified workspace to $vitis_workspace"
993  } elseif {[IsXilinx]} {
994  file mkdir "$repo_path/Projects/$project_name/$project.gen/sources_1"
995  OpenProject $project_file $repo_path
996  } elseif {[IsVitisClassic]} {
997  set vitis_workspace [file normalize $repo_path/Projects/$project_name/vitis_classic/]
998  Msg Info "Setting workspace to $vitis_workspace"
999  } elseif {[IsVitisUnified]} {
1000  set vitis_workspace [file normalize $repo_path/Projects/$project_name/vitis_unified/]
1001  Msg Info "Setting workspace to $vitis_workspace"
1002  } else {
1003  OpenProject $project_file $repo_path
1004  }
1005 }
1006 
1007 
1008 
1009 ########## CHECK SYNTAX ###########
1010 if {$do_check_syntax == 1} {
1011  if {$ide_name eq "vitis_unified" || $ide_name eq "vitis_classic"} {
1012  Msg Info "Skipping syntax check for $project_name: pure Vitis project has no HDL syntax to check"
1013  } else {
1014  Msg Info "Checking syntax for project $project_name..."
1015  CheckSyntax $project_name $repo_path $project_file
1016  }
1017 }
1018 
1019 ######### RTL ANALYSIS ########
1020 if {$do_rtl == 1} {
1021  lassign [GetConfFiles $repo_path/Top/$project_name] conf sim pre post pre_rtl post_rtl
1022  LaunchRTLAnalysis $repo_path $pre_rtl $post_rtl
1023 }
1024 
1025 if {$do_vitis_build == 1} {
1026  if {[IsVitisClassic] || [IsVitisUnified]} {
1027  # Check for HLS components and build them
1028  set conf_file_path [file normalize "$repo_path/Top/$project_name/hog.conf"]
1029  if {[file exists $conf_file_path]} {
1030  set proj_properties [ReadConf $conf_file_path]
1031  set hls_components [dict filter $proj_properties key {hls:*}]
1032  if {[dict size $hls_components] > 0} {
1033  Msg Info "Found [dict size $hls_components] HLS component(s), launching HLS build..."
1034  LaunchHlsBuild $project_name $repo_path
1035  }
1036  # Build apps/platforms if any exist
1037  set has_apps [expr {[dict size [dict filter $proj_properties key {app:*}]] > 0}]
1038  if {$has_apps} {
1039  LaunchVitisBuild $project_name $repo_path
1040  }
1041  } else {
1042  LaunchVitisBuild $project_name $repo_path
1043  }
1044  } else {
1045  Msg Error "Vitis build is not supported for $ide_name (only Vitis Classic and Vitis Unified are supported)"
1046  exit 1
1047  }
1048 }
1049 
1050 ######### LaunchSynthesis ########
1051 if {$do_synthesis == 1} {
1052  LaunchSynthesis $do_reset $do_create $run_folder $project_name $repo_path $ext_path $options(njobs)
1053 }
1054 
1055 if {$do_implementation == 1} {
1056  LaunchImplementation $do_reset $do_create $run_folder $project_name $repo_path $options(njobs) $do_bitstream
1057 }
1058 
1059 if {$do_bitstream_only == 1 && [IsXilinx]} {
1060  GenerateBitstreamOnly $project_name $repo_path
1061 } elseif {$do_bitstream_only == 1 && ![IsXilinx]} {
1062  Msg Error "Bitstream only option is not supported for this IDE."
1063 }
1064 
1065 if {$do_bitstream == 1 && ![IsXilinx]} {
1066  GenerateBitstream $run_folder $repo_path $options(njobs)
1067 }
1068 
1069 if {$do_simulation == 1} {
1070  # Separate HLS simsets (csim:*/cosim:*) from HDL simsets
1071  set hdl_simsets [list]
1072  set hls_simsets [list]
1073  if {$options(simset) ne ""} {
1074  foreach s $options(simset) {
1075  if {[regexp {^(csim|cosim):} $s]} {
1076  lappend hls_simsets $s
1077  } else {
1078  lappend hdl_simsets $s
1079  }
1080  }
1081  }
1082  set run_hdl [expr {[llength $hdl_simsets] > 0 || $options(simset) eq ""}]
1083  set run_hls [expr {[llength $hls_simsets] > 0 || $options(simset) eq ""}]
1084 
1085  # Run HDL simulations
1086  if {$run_hdl} {
1087  set simsets [GetSimSets $project_name $repo_path $hdl_simsets]
1088  if {[dict size $simsets] > 0} {
1089  LaunchSimulation $project_name $lib_path $simsets $repo_path $scripts_only $compile_only
1090  }
1091  }
1092 
1093  # Run HLS simulations (csim/cosim)
1094  if {$run_hls} {
1095  LaunchHlsSimulation $project_name $repo_path $hls_simsets
1096  }
1097 }
1098 
1099 
1100 if {$do_check_list_files} {
1101  Msg Info "Running list file checker..."
1102 
1103  #if {![file exists $dst_dir]} {
1104  # Msg Info "$dst_dir directory not found, creating it..."
1105  # file mkdir $dst_dir
1106  # }
1107 
1108 
1109  set argv0 check_list_files
1110  if {$ext_path ne ""} {
1111  set argv [list "-ext_path" "$ext_path" "-outDir" "$dst_dir" "-pedantic"]
1112  } else {
1113  set argv [list "-outDir" "$dst_dir" "-pedantic"]
1114  }
1115 
1116  source $tcl_path/utils/check_list_files.tcl
1117 }
1118 ## CLOSE Project
1120 
1121 Msg Info "All done."
1122 cd $old_path