Hog v10.48.0
create_project.tcl
Go to the documentation of this file.
1 # Copyright 2018-2026 The University of Birmingham
2 # Copyright 2018-2026 Max-Planck-Institute for Physics
3 #
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 # You may obtain a copy of the License at
7 #
8 # http://www.apache.org/licenses/LICENSE-2.0
9 #
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
15 
16 ## @file create_project.tcl
17 # @brief contains all functions needed to create a new project
18 # @todo This file will need to be fully documented
19 #
20 
21 
22 ##nagelfar variable quartus
23 
24 ## @namespace globalSettings
25 # @brief Namespace of all the project settings
26 #
27 # Variables in upper case are expected to be passed by the caller.
28 # Variables lower case are evaluated in the script defined in create_project.tcl
29 #
30 namespace eval globalSettings {
31  #The project name (including flavour if any)
32  variable DESIGN
33 
34  variable PART
35 
36  # Quartus only
37  variable FAMILY
38  # Libero only
39  variable DIE
40  variable PACKAGE
41  variable ADV_OPTIONS
42  variable SPEED
43  variable LIBERO_MANDATORY_VARIABLES
44  # Diamond only
45  variable DEVICE
46 
47  variable PROPERTIES
48  variable HOG_EXTERNAL_PATH
49  variable HOG_IP_PATH
50  variable TARGET_SIMULATOR
51 
52  variable pre_synth_file
53  variable post_synth_file
54  variable pre_impl_file
55  variable post_impl_file
56  variable pre_bit_file
57  variable post_bit_file
58  variable quartus_post_module_file
59  variable tcl_path
60  variable repo_path
61  variable top_path
62  variable list_path
63  variable build_dir
64  variable simlib_path
65  variable top_name
66  variable synth_top_module
67  variable user_ip_repo
68 
69  variable vitis_classic
70  variable vitis_unified
71  variable pre_synth
72  variable post_synth
73  variable pre_impl
74  variable post_impl
75  variable pre_bit
76  variable post_bit
77  variable quartus_post_module
78 }
79 
80 ################# FUNCTIONS ################################
81 proc InitProject {{vitis_only 0}} {
82  if {$vitis_only == 1 && [IsVitisClassic]} {
83  if {[file exists $globalSettings::build_dir/vitis_classic]} {
84  file delete -force $globalSettings::build_dir/vitis_classic
85  }
86  setws $globalSettings::build_dir/vitis_classic
87  } elseif {$vitis_only == 1 && [IsVitisUnified]} {
88  if {[file exists $globalSettings::build_dir/vitis_unified]} {
89  file delete -force $globalSettings::build_dir/vitis_unified
90  }
91  file mkdir $globalSettings::build_dir/vitis_unified
92  } elseif {[IsXilinx]} {
93  if {[IsVivado]} {
94  # Suppress unnecessary warnings
95  # tclint-disable-next-line line-length
96  set_msg_config -suppress -regexp -string {".*The IP file '.*' has been moved from its original location, as a result the outputs for this IP will now be generated in '.*'. Alternatively a copy of the IP can be imported into the project using one of the 'import_ip' or 'import_files' commands..*"}
97  set_msg_config -suppress -regexp -string {".*File '.*.xci' referenced by design '.*' could not be found..*"}
98 
99  # File inside .bd
100  set_msg_config -suppress -id {IP_Flow 19-3664}
101  # This is due to simulations in project with NoC
102  # tclint-disable-next-line line-length
103  set_msg_config -suppress -id {Vivado 12-23660} -string {{ERROR: [Vivado 12-23660] Simulation is not supported for the target language VHDL when design contains NoC (Network-on-Chip) blocks} }
104  }
105  # Create project
106  create_project -force [file tail $globalSettings::DESIGN] $globalSettings::build_dir -part $globalSettings::PART
107  file mkdir "$globalSettings::build_dir/[file tail $globalSettings::DESIGN].gen/sources_1"
108  if {[IsVersal $globalSettings::PART]} {
109  Msg Info "This project uses a Versal device."
110  }
111 
112  ## Set project properties
113  set obj [get_projects [file tail $globalSettings::DESIGN]]
114  set_property "target_language" "VHDL" $obj
115 
116  if {[IsVivado]} {
117  set_property "simulator_language" "Mixed" $obj
118  foreach simulator [GetSimulators] {
119  set_property "compxlib.${simulator}_compiled_library_dir" $globalSettings::simlib_path $obj
120  }
121  set_property "default_lib" "xil_defaultlib" $obj
122  ## Enable VHDL 2008
123  set_param project.enableVHDL2008 1
124  set_property "enable_vhdl_2008" 1 $obj
125  ## Enable Automatic compile order mode, otherwise we cannot find the right top module...
126  set_property source_mgmt_mode All [current_project]
127  # Set PART Immediately
128  Msg Debug "Setting PART = $globalSettings::PART"
129  set_property PART $globalSettings::PART [current_project]
130  }
131 
133  } elseif {[IsQuartus]} {
134  package require ::quartus::project
135  #QUARTUS_ONLY
136  if {[string equal $globalSettings::FAMILY "quartus_only"]} {
137  Msg Error "You must specify a device Family for Quartus"
138  } else {
139  file mkdir $globalSettings::build_dir
140  cd $globalSettings::build_dir
141  if {[is_project_open]} {
142  project_close
143  }
144 
145  file delete {*}[glob -nocomplain $globalSettings::DESIGN.q*]
146 
147  project_new -family $globalSettings::FAMILY -overwrite -part $globalSettings::PART $globalSettings::DESIGN
148  set_global_assignment -name PROJECT_OUTPUT_DIRECTORY output_files
149 
151  }
152  } elseif {[IsLibero]} {
153  if {[file exists $globalSettings::build_dir]} {
154  file delete -force $globalSettings::build_dir
155  }
156  new_project -location $globalSettings::build_dir \
157  -name [file tail $globalSettings::DESIGN] \
158  -die $globalSettings::DIE \
159  -package $globalSettings::PACKAGE \
160  -family $globalSettings::FAMILY \
161  -hdl VHDL
162  } elseif {[IsDiamond]} {
163  if {[file exists $globalSettings::build_dir]} {
164  file delete -force $globalSettings::build_dir
165  }
166  set old_dir [pwd]
167  file mkdir $globalSettings::build_dir
168  cd $globalSettings::build_dir
169  prj_project new -name [file tail $globalSettings::DESIGN] -dev $globalSettings::DEVICE -synthesis $globalSettings::SYNTHESIS_TOOL
170  cd $old_dir
172  } else {
173  puts "Creating project for $globalSettings::DESIGN part $globalSettings::PART"
174  puts "Configuring project settings:"
175  puts " - simulator_language: Mixed"
176  puts " - target_language: VHDL"
177  puts " - simulator: QuestaSim"
178  puts "Adding IP directory \"$globalSettings::user_ip_repo\" to the project "
179  }
180 }
181 
182 proc AddProjectFiles {} {
183  if {[IsXilinx]} {
184  #VIVADO_ONLY
185  ## Create fileset src
186  if {[string equal [get_filesets -quiet sources_1] ""]} {
187  create_fileset -srcset sources_1
188  }
189  set sources "sources_1"
190  } else {
191  set sources 0
192  }
193 
194 
195  ###############
196  # CONSTRAINTS #
197  ###############
198  if {[IsXilinx]} {
199  #VIVADO_ONLY
200  # Create 'constrs_1' fileset (if not found)
201  if {[string equal [get_filesets -quiet constrs_1] ""]} {
202  create_fileset -constrset constrs_1
203  }
204 
205  # Set 'constrs_1' fileset object
206  set constraints [get_filesets constrs_1]
207  }
208 
209  ##############
210  # READ FILES #
211  ##############
212 
213  if {[file isdirectory $globalSettings::list_path]} {
214  set list_files [glob -directory $globalSettings::list_path "*"]
215  } else {
216  Msg Error "No list directory found at $globalSettings::list_path"
217  }
218 
219  if {[IsISE]} {
220  source $globalSettings::tcl_path/utils/cmdline.tcl
221  }
222 
223  # Add first .src, .sim, and .ext list files
224  AddHogFiles {*}[GetHogFiles -list_files {.src,.sim,.ext} -ext_path $globalSettings::HOG_EXTERNAL_PATH $globalSettings::list_path $globalSettings::repo_path]
225 
226  ## Set synthesis TOP
227  SetTopProperty $globalSettings::synth_top_module $sources
228 
229  # Libero needs the top files to be set before adding the constraints
230  AddHogFiles {*}[GetHogFiles -list_files {.con} -ext_path $globalSettings::HOG_EXTERNAL_PATH $globalSettings::list_path $globalSettings::repo_path]
231  ## Set simulation Properties
232 
233  ## Libero Properties must be set after that root has been defined
234  if {[IsLibero]} {
236  }
237 }
238 
239 
240 ## @brief Set Vivado Report strategy for implementation
241 #
242 # @param[in] obj the project object
243 #
244 proc CreateReportStrategy {obj} {
245  #TODO: Add ReportStrategy for Quartus/Libero and Diamond
246 
247  if {[IsVivado]} {
248  ## Vivado Report Strategy
249  if {[string equal [get_property -quiet report_strategy $obj] ""]} {
250  # No report strategy needed
251  Msg Info "No report strategy needed for implementation"
252  } else {
253  # Report strategy needed since version 2017.3
254  set_property set_report_strategy_name 1 $obj
255  set_property report_strategy {Vivado Implementation Default Reports} $obj
256  set_property set_report_strategy_name 0 $obj
257 
258  set reports [get_report_configs -of_objects $obj]
259  # Create 'impl_1_place_report_utilization_0' report (if not found)
260  if {[string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_utilization_0] ""]} {
261  create_report_config -report_name impl_1_place_report_utilization_0 -report_type report_utilization:1.0 -steps place_design -runs impl_1
262  }
263  set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_utilization_0]
264  if {$obj != ""} {
265 
266  }
267 
268  # Create 'impl_1_route_report_drc_0' report (if not found)
269  if {[string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_drc_0] ""]} {
270  create_report_config -report_name impl_1_route_report_drc_0 -report_type report_drc:1.0 -steps route_design -runs impl_1
271  }
272  set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_drc_0]
273  if {$obj != ""} {
274 
275  }
276 
277  # Create 'impl_1_route_report_power_0' report (if not found)
278  if {[string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_power_0] ""]} {
279  create_report_config -report_name impl_1_route_report_power_0 -report_type report_power:1.0 -steps route_design -runs impl_1
280  }
281  set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_power_0]
282  if {$obj != ""} {
283 
284  }
285 
286  # Create 'impl_1_route_report_timing_summary' report (if not found)
287  if {[string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_timing_summary] ""]} {
288  create_report_config -report_name impl_1_route_report_timing_summary -report_type report_timing_summary:1.0 -steps route_design -runs impl_1
289  }
290  set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_timing_summary]
291  if {$obj != ""} {
292  Msg Info "Report timing created successfully"
293  }
294 
295  # Create 'impl_1_route_report_utilization' report (if not found)
296  if {[string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_utilization] ""]} {
297  create_report_config -report_name impl_1_route_report_utilization -report_type report_utilization:1.0 -steps route_design -runs impl_1
298  }
299  set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_utilization]
300  if {$obj != ""} {
301  Msg Info "Report utilization created successfully"
302  }
303 
304 
305  # Create 'impl_1_post_route_phys_opt_report_timing_summary_0' report (if not found)
306  if {[string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_post_route_phys_opt_report_timing_summary_0] ""]} {
307  create_report_config -report_name impl_1_post_route_phys_opt_report_timing_summary_0 \
308  -report_type report_timing_summary:1.0 \
309  -steps post_route_phys_opt_design -runs impl_1
310  }
311  set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_post_route_phys_opt_report_timing_summary_0]
312  if {$obj != ""} {
313  set_property -name "options.max_paths" -value "10" -objects $obj
314  set_property -name "options.warn_on_violation" -value "1" -objects $obj
315  }
316  }
317  } else {
318  Msg Info "Won't create any report strategy, not in Vivado"
319  }
320 }
321 
322 
323 ## @brief configure synthesis.
324 #
325 # The method uses the content of globalSettings::SYNTH_FLOW and globalSettings::SYNTH_STRATEGY to set the implementation strategy and flow.
326 # The function also sets Hog specific pre and post synthesis scripts
327 #
328 proc ConfigureSynthesis {} {
329  if {[IsXilinx]} {
330  #VIVADO ONLY
331  ## Create 'synthesis ' run (if not found)
332  if {[string equal [get_runs -quiet synth_1] ""]} {
333  create_run -name synth_1 -part $globalSettings::PART -constrset constrs_1
334  } else {
335 
336  }
337 
338  set obj [get_runs synth_1]
339  set_property "part" $globalSettings::PART $obj
340  }
341 
342  ## set pre synthesis script
343  if {$globalSettings::pre_synth_file ne ""} {
344  if {[IsXilinx]} {
345  #Vivado Only
346  if {[IsVivado]} {
347  if {[get_filesets -quiet utils_1] != ""} {
348  AddFile $globalSettings::pre_synth [get_filesets -quiet utils_1]
349  }
350  set_property STEPS.SYNTH_DESIGN.TCL.PRE $globalSettings::pre_synth $obj
351  }
352  } elseif {[IsQuartus]} {
353  #QUARTUS only
354  set_global_assignment -name PRE_FLOW_SCRIPT_FILE quartus_sh:$globalSettings::pre_synth
355  } elseif {[IsLibero]} {
356  configure_tool -name {SYNTHESIZE} -params SYNPLIFY_TCL_FILE:$globalSettings::pre_synth
357  } elseif {[IsDiamond]} {
358  prj_impl pre_script "syn" $globalSettings::pre_synth
359  }
360 
361  Msg Debug "Setting $globalSettings::pre_synth to be run before synthesis"
362  }
363 
364  ## set post synthesis script
365  if {$globalSettings::post_synth_file ne ""} {
366  if {[IsXilinx]} {
367  #Vivado Only
368  if {[IsVivado]} {
369  if {[get_filesets -quiet utils_1] != ""} {
370  AddFile $globalSettings::post_synth [get_filesets -quiet utils_1]
371  }
372  set_property STEPS.SYNTH_DESIGN.TCL.POST $globalSettings::post_synth $obj
373  }
374  } elseif {[IsQuartus]} {
375  #QUARTUS only
376  set_global_assignment -name POST_MODULE_SCRIPT_FILE quartus_sh:$globalSettings::quartus_post_module
377  } elseif {[IsDiamond]} {
378  prj_impl post_script "syn" $globalSettings::post_synth
379  }
380  Msg Debug "Setting $globalSettings::post_synth to be run after synthesis"
381  }
382 
383 
384  if {[IsXilinx]} {
385  #VIVADO ONLY
386  ## set the current synth run
387  current_run -synthesis $obj
388 
389  ## Report Strategy
390  if {[string equal [get_property -quiet report_strategy $obj] ""]} {
391  # No report strategy needed
392  Msg Debug "No report strategy needed for synthesis"
393  } else {
394  # Report strategy needed since version 2017.3
395  set_property set_report_strategy_name 1 $obj
396  set_property report_strategy {Vivado Synthesis Default Reports} $obj
397  set_property set_report_strategy_name 0 $obj
398  # Create 'synth_1_synth_report_utilization_0' report (if not found)
399  if {[string equal [get_report_configs -of_objects [get_runs synth_1] synth_1_synth_report_utilization_0] ""]} {
400  create_report_config -report_name synth_1_synth_report_utilization_0 -report_type report_utilization:1.0 -steps synth_design -runs synth_1
401  }
402  set reports [get_report_configs -of_objects [get_runs synth_1] synth_1_synth_report_utilization_0]
403  }
404  } elseif {[IsQuartus]} {
405  #QUARTUS only
406  #TO BE DONE
407  } elseif {[IsLibero]} {
408  #TODO: LIBERO
409  } elseif {[IsDiamond]} {
410  #TODO: Diamond
411  } else {
412  Msg info "Reporting strategy for synthesis"
413  }
414 }
415 
416 ## @brief configure implementation.
417 #
418 # The configuration is based on the content of globalSettings::IMPL_FLOW and globalSettings::IMPL_STRATEGY
419 # The function also sets Hog specific pre- and- post implementation and, pre- and post- implementation scripts
420 #
421 proc ConfigureImplementation {} {
422  set obj ""
423  if {[IsXilinx]} {
424  # Create 'impl_1' run (if not found)
425  if {[string equal [get_runs -quiet impl_1] ""]} {
426  create_run -name impl_1 -part $globalSettings::PART -constrset constrs_1 -parent_run synth_1
427  }
428 
429  set obj [get_runs impl_1]
430  set_property "part" $globalSettings::PART $obj
431 
432  set_property "steps.[BinaryStepName $globalSettings::PART].args.readback_file" "0" $obj
433  set_property "steps.[BinaryStepName $globalSettings::PART].args.verbose" "0" $obj
434  } elseif {[IsQuartus]} {
435  #QUARTUS only
436  set obj ""
437  }
438 
439 
440  ## set pre implementation script
441  if {$globalSettings::pre_impl_file ne ""} {
442  if {[IsXilinx]} {
443  #Vivado Only
444  if {[IsVivado]} {
445  if {[get_filesets -quiet utils_1] != ""} {
446  AddFile $globalSettings::pre_impl [get_filesets -quiet utils_1]
447  }
448  set_property STEPS.INIT_DESIGN.TCL.POST $globalSettings::pre_impl $obj
449  }
450  } elseif {[IsQuartus]} {
451  #QUARTUS only
452  #set_global_assignment -name PRE_FLOW_SCRIPT_FILE quartus_sh:$globalSettings::pre_impl
453  } elseif {[IsDiamond]} {
454  prj_impl pre_script "par" $globalSettings::pre_impl
455  }
456  Msg Debug "Setting $globalSettings::pre_impl to be run after implementation"
457  }
458 
459 
460  ## set post routing script
461  if {$globalSettings::post_impl_file ne ""} {
462  if {[IsXilinx]} {
463  #Vivado Only
464  if {[IsVivado]} {
465  if {[get_filesets -quiet utils_1] != ""} {
466  AddFile $globalSettings::post_impl [get_filesets -quiet utils_1]
467  }
468  set_property STEPS.ROUTE_DESIGN.TCL.POST $globalSettings::post_impl $obj
469  # Move post-implementation after the post_route_phys_opt_design step if it is enabled
470  if {[get_property STEPS.POST_ROUTE_PHYS_OPT_DESIGN.IS_ENABLED $obj]} {
471  set_property STEPS.POST_ROUTE_PHYS_OPT_DESIGN.TCL.POST $globalSettings::post_impl $obj
472  set_property STEPS.ROUTE_DESIGN.TCL.POST "" $obj
473  }
474  }
475  } elseif {[IsQuartus]} {
476  #QUARTUS only
477  set_global_assignment -name POST_MODULE_SCRIPT_FILE quartus_sh:$globalSettings::quartus_post_module
478  } elseif {[IsDiamond]} {
479  prj_impl post_script "par" $globalSettings::post_impl
480  }
481  Msg Debug "Setting $globalSettings::post_impl to be run after implementation"
482  }
483 
484  ## set pre write bitstream script
485  if {$globalSettings::pre_bit_file ne ""} {
486  if {[IsXilinx]} {
487  #Vivado Only
488  if {[IsVivado]} {
489  if {[get_filesets -quiet utils_1] != ""} {
490  AddFile $globalSettings::pre_bit [get_filesets -quiet utils_1]
491  }
492  set_property STEPS.[BinaryStepName $globalSettings::PART].TCL.PRE $globalSettings::pre_bit $obj
493  }
494  } elseif {[IsQuartus]} {
495  #QUARTUS only
496  #set_global_assignment -name PRE_FLOW_SCRIPT_FILE quartus_sh:$globalSettings::pre_bit
497  } elseif {[IsDiamond]} {
498  prj_impl pre_script "export" $globalSettings::pre_bit
499  }
500  Msg Debug "Setting $globalSettings::pre_bit to be run after bitfile generation"
501  }
502 
503  ## set post write bitstream script
504  if {$globalSettings::post_bit_file ne ""} {
505  if {[IsXilinx]} {
506  #Vivado Only
507  if {[IsVivado]} {
508  if {[get_filesets -quiet utils_1] != ""} {
509  AddFile $globalSettings::post_bit [get_filesets -quiet utils_1]
510  }
511  set_property STEPS.[BinaryStepName $globalSettings::PART].TCL.POST $globalSettings::post_bit $obj
512  }
513  } elseif {[IsQuartus]} {
514  #QUARTUS only
515  set_global_assignment -name POST_MODULE_SCRIPT_FILE quartus_sh:$globalSettings::quartus_post_module
516  } elseif {[IsDiamond]} {
517  prj_impl post_script "export" $globalSettings::post_bit
518  }
519  Msg Debug "Setting $globalSettings::post_bit to be run after bitfile generation"
520  }
521 
523 }
524 
525 
526 ## @brief configure simulation
527 #
528 proc ConfigureSimulation {} {
529  set simsets_dict [GetSimSets "$globalSettings::group_name/$globalSettings::DESIGN" $globalSettings::repo_path]
530 
531  if {[IsXilinx]} {
532  ##############
533  # SIMULATION #
534  ##############
535  Msg Debug "Setting load_glbl parameter to true for every fileset..."
536  foreach simset [get_filesets -quiet] {
537  if {[get_property FILESET_TYPE $simset] != "SimulationSrcs"} {
538  continue
539  }
540  if {[IsVivado]} {
541  set_property -name {xsim.elaborate.load_glbl} -value {true} -objects [get_filesets $simset]
542  }
543  # Setting Simulation Properties
544  set sim_dict [DictGet $simsets_dict $simset]
545  set sim_props [DictGet $sim_dict "properties"]
546 
547  if {$sim_props != ""} {
548  Msg Info "Setting properties for simulation set: $simset..."
549  dict for {prop_name prop_val} $sim_props {
550  set prop_name [string toupper $prop_name]
551  if {$prop_name == "ACTIVE" && $prop_val == 1} {
552  Msg Info "Setting $simset as active simulation set..."
553  current_fileset -simset [get_filesets $simset]
554  } else {
555  Msg Debug "Setting $prop_name = $prop_val"
556  if {[IsInList [string toupper $prop_name] [VIVADO_PATH_PROPERTIES] 1]} {
557  # Check that the file exists before setting these properties
558  if {[file exists $globalSettings::repo_path/$prop_val]} {
559  set_property -name $prop_name -value $globalSettings::repo_path/$prop_val -objects [get_filesets $simset]
560  } else {
561  Msg Warning "Impossible to set property $prop_name to $prop_val. File is missing"
562  }
563  } else {
564  set_property -name $prop_name -value $prop_val -objects [get_filesets $simset]
565  }
566  }
567  }
568  }
569  }
570  }
571 }
572 
573 ## @brief uses the content of globalSettings::PROPERTIES to set additional project properties
574 #
575 proc ConfigureProperties {} {
576  set cur_dir [pwd]
577  cd $globalSettings::repo_path
578  if {[IsXilinx]} {
579  set user_repo "0"
580  # Setting Main Properties
581  if {[info exists globalSettings::PROPERTIES]} {
582  if {[dict exists $globalSettings::PROPERTIES main]} {
583  Msg Info "Setting project-wide properties..."
584  set proj_props [dict get $globalSettings::PROPERTIES main]
585  dict for {prop_name prop_val} $proj_props {
586  if {[string tolower $prop_name] != "ip_repo_paths"} {
587  if {[string tolower $prop_name] != "part"} {
588  # Part is already set
589  Msg Debug "Setting $prop_name = $prop_val"
590  set_property -name $prop_name -value $prop_val -objects [current_project]
591  }
592  } else {
593  set ip_repo_list [regsub -all {\s+} $prop_val " $globalSettings::repo_path/"]
594  set ip_repo_list $globalSettings::repo_path/$ip_repo_list
595  set user_repo "1"
596  Msg Info "Setting $ip_repo_list as user IP repository..."
597  if {[IsISE]} {
598  set_property ip_repo_paths "$ip_repo_list" [current_fileset]
599  } else {
600  set_property ip_repo_paths "$ip_repo_list" [current_project]
601  }
602  update_ip_catalog
603  }
604  }
605  }
606  # Setting Run Properties
607  foreach run [get_runs -quiet] {
608  if {[dict exists $globalSettings::PROPERTIES $run]} {
609  Msg Info "Setting properties for run: $run..."
610  set run_props [dict get $globalSettings::PROPERTIES $run]
611  #set_property -dict $run_props $run
612  set stragety_str "STRATEGY strategy Strategy"
613  Msg Debug "Setting Strategy and Flow for run $run (if specified in hog.conf)"
614  foreach s $stragety_str {
615  if {[dict exists $run_props $s]} {
616  set prop [dict get $run_props $s]
617  set_property -name $s -value $prop -objects $run
618  set run_props [dict remove $run_props $s]
619  Msg Warning "A strategy for run $run has been defined inside hog.conf. This prevents Hog to compare the project properties. \
620  Please regenerate your hog.conf file using the dedicated Hog button."
621  Msg Info "Setting $s = $prop"
622  }
623  }
624 
625  dict for {prop_name prop_val} $run_props {
626  Msg Debug "Setting $prop_name = $prop_val"
627  if {[string trim $prop_val] == ""} {
628  Msg Warning "Property $prop_name has empty value. Skipping..."
629  continue
630  }
631  if {[IsInList [string toupper $prop_name] [VIVADO_PATH_PROPERTIES] 1]} {
632  # Check that the file exists before setting these properties
633  set utility_file $globalSettings::repo_path/$prop_val
634  if {[file exists $utility_file]} {
635  lassign [GetHogFiles -ext_path $globalSettings::HOG_EXTERNAL_PATH $globalSettings::list_path $globalSettings::repo_path] lib prop dummy
636  foreach {l f} $lib {
637  foreach ff $f {
638  lappend hog_files $ff
639  }
640  }
641  if {[lsearch $hog_files $utility_file] < 0} {
642  Msg CriticalWarning "The file: $utility_file is set as a property in hog.conf, \
643  but is not added to the project in any list file. Hog cannot track it."
644  } else {
645  #Add file tu utils_1 to avoid warning
646  AddFile $globalSettings::repo_path/$prop_val [get_filesets -quiet utils_1]
647  }
648  set_property -name $prop_name -value $utility_file -objects $run
649  } else {
650  Msg Warning "Impossible to set property $prop_name to $prop_val. File is missing"
651  }
652  } else {
653  set_property -name $prop_name -value $prop_val -objects $run
654  }
655  }
656  }
657  }
658  }
659  } elseif {[IsQuartus]} {
660  #QUARTUS only
661  #TO BE DONE
662  } elseif {[IsLibero]} {
663  # Setting Properties
664  if {[info exists globalSettings::PROPERTIES]} {
665  # Device Properties
666  if {[dict exists $globalSettings::PROPERTIES main]} {
667  Msg Info "Setting device properties..."
668  set dev_props [dict get $globalSettings::PROPERTIES main]
669  dict for {prop_name prop_val} $dev_props {
670  if {!([string toupper $prop_name] in $globalSettings::LIBERO_MANDATORY_VARIABLES)} {
671  Msg Debug "Setting $prop_name = $prop_val"
672  set_device -[string tolower $prop_name] $prop_val
673  }
674  }
675  }
676  # Project Properties
677  if {[dict exists $globalSettings::PROPERTIES project]} {
678  Msg Info "Setting project-wide properties..."
679  set dev_props [dict get $globalSettings::PROPERTIES project]
680  dict for {prop_name prop_val} $dev_props {
681  Msg Debug "Setting $prop_name = $prop_val"
682  project_settings -[string tolower $prop_name] $prop_val
683  }
684  }
685  # Synthesis Properties
686  if {[dict exists $globalSettings::PROPERTIES synth]} {
687  Msg Info "Setting Synthesis properties..."
688  set synth_props [dict get $globalSettings::PROPERTIES synth]
689  dict for {prop_name prop_val} $synth_props {
690  Msg Debug "Setting $prop_name = $prop_val"
691  configure_tool -name {SYNTHESIZE} -params "[string toupper $prop_name]:$prop_val"
692  }
693  }
694  # Implementation Properties
695  if {[dict exists $globalSettings::PROPERTIES impl]} {
696  Msg Info "Setting Implementation properties..."
697  set impl_props [dict get $globalSettings::PROPERTIES impl]
698  dict for {prop_name prop_val} $impl_props {
699  Msg Debug "Setting $prop_name = $prop_val"
700  configure_tool -name {PLACEROUTE} -params "[string toupper $prop_name]:$prop_val"
701  }
702  }
703 
704  # Bitstream Properties
705  if {[dict exists $globalSettings::PROPERTIES bitstream]} {
706  Msg Info "Setting Bitstream properties..."
707  set impl_props [dict get $globalSettings::PROPERTIES impl]
708  dict for {prop_name prop_val} $impl_props {
709  Msg Debug "Setting $prop_name = $prop_val"
710  configure_tool -name {GENERATEPROGRAMMINGFILE} -params "[string toupper $prop_name]:$prop_val"
711  }
712  }
713  # Configure VERIFYTIMING tool to generate a txt file report
714  configure_tool -name {VERIFYTIMING} -params {FORMAT:TEXT}
715  }
716  } elseif {[IsDiamond]} {
717  if {[info exists globalSettings::PROPERTIES]} {
718  # Project (main) Properties
719  if {[dict exists $globalSettings::PROPERTIES main]} {
720  Msg Info "Setting project-wide properties..."
721  set dev_props [dict get $globalSettings::PROPERTIES main]
722  dict for {prop_name prop_val} $dev_props {
723  # Device is already set
724  if {[string toupper $prop_name] != "DEVICE"} {
725  Msg Debug "Setting $prop_name = $prop_val"
726  prj_project option $prop_name $prop_val
727  }
728  }
729  }
730  # Implementation properties
731  if {[dict exists $globalSettings::PROPERTIES impl]} {
732  Msg Info "Setting Implementation properties..."
733  set dev_props [dict get $globalSettings::PROPERTIES impl]
734  dict for {prop_name prop_val} $dev_props {
735  # Device is already set
736  Msg Debug "Setting $prop_name = $prop_val"
737  prj_impl option $prop_name $prop_val
738  }
739  }
740  }
741  } else {
742  Msg info "Configuring Properties"
743  }
744  cd $cur_dir
745 }
746 
747 
748 proc ConfigurePlatforms {{xsa ""}} {
749  dict for {key value} [dict filter $globalSettings::PROPERTIES key {platform:*}] {
750  set value_lower [dict create]
751  dict for {vkey vvalue} $value {
752  dict set value_lower [string tolower $vkey] $vvalue
753  }
754  dict set platforms $key $value_lower
755  }
756 
757  set platforms2 [GetPlatformsFromProps $globalSettings::PROPERTIES 0 1]
758  Msg Info "Platform Names: [GetPlatformsFromProps $globalSettings::PROPERTIES 1 1]"
759 
760  dict for {key value} $platforms2 {
761  Msg Info "Key: $key, Value: $value"
762  }
763 
764  if {[dict size $platforms] == 0} {
765  Msg Info "No platforms found in the configuration file"
766  return
767  }
768 
769  dict for {platform_key platform_config} $platforms {
770  Msg Info "Found platform with key: $platform_key with configuration: $platform_config"
771  if {[regexp {^platform:(.+)$} $platform_key -> platform_name]} {
772  set platform_name [string trim $platform_name]
773  Msg Info "Configuring platform: $platform_name"
774  CreatePlatform $platform_name $platform_config $xsa
775  } else {
776  Msg Warning "Invalid platform key format: $platform_key. Expected format: platform:<name>"
777  }
778  }
779 }
780 
781 proc CreatePlatform {platform_name platform_conf {xsa ""}} {
782 
783  set platform_create_options {
784  "desc" "hw" "out" "prebuilt" "proc" "arch"
785  "samples" "os" "xpfm" "no-boot-bsp"
786  }
787 
788  # XSCT/Vitis Classic switches that do not take a value
789  set platform_create_flags {
790  "no-boot-bsp" "prebuilt"
791  }
792 
793  Msg Info "Creating platform configuration..."
794  append platform_options " -name $platform_name"
795 
796  # Remove existing platform if it exists
797  if {[catch {set ws_platforms [platform list -dict]}]} { set ws_platforms "" }
798  if {[lsearch -exact $ws_platforms $platform_name] != -1} {
799  Msg Info "Platform $platform_name already exists, removing it..."
800  platform remove $platform_name
801  }
802 
803  dict for {p v} $platform_conf {
804  if {[IsInList [string toupper $p] [VITIS_PATH_PROPERTIES] 1]} {
805 
806  if {[IsRelativePath $v] == 1} {
807  set v "$globalSettings::repo_path/$v"
808  }
809 
810  if {[file exists $v]} {
811  if {$p == "hw"} {
812  set xsa $v
813  }
814  } else {
815  Msg Warning "Impossible to set property $p to $v. File is missing"
816  continue;
817  }
818  }
819 
820  set p_lower [string tolower $p]
821  if {[IsInList $p_lower $platform_create_options]} {
822  if {[IsVitisClassic] && [IsInList $p_lower $platform_create_flags]} {
823  if {[string is true -strict $v]} {
824  append platform_options " -$p_lower"
825  }
826  } else {
827  append platform_options " -$p_lower $v"
828  }
829  } else {
830  if {$p_lower ne "bif"} {
831  Msg Warning "Attempting to use unknown platform option: $p_lower"
832  append platform_options " -$p_lower $v"
833  }
834  }
835  }
836 
837 
838  # If hw is not in platform conf, use vivado presynth xsa
839  if {$xsa != ""} {
840  if {[IsRelativePath $xsa] == 1} {
841  set xsa [file normalize "$globalSettings::repo_path/$xsa"]
842  } else {
843  set xsa [file normalize $xsa]
844  }
845  set platform_options "$platform_options -hw $xsa"
846  } elseif {![dict exists $platform_conf hw]} {
847  set xsa [file normalize "$globalSettings::build_dir/$globalSettings::DESIGN-presynth.xsa"]
848  set platform_options "$platform_options -hw $xsa"
849  } else {
850  set platform_options "$platform_options"
851  }
852 
853 
854  if {[IsVitisClassic]} {
855  Msg Info "Opening hardware design to check if proc to cell mapping needs to be extracted for soft processors..."
856  # Use HSI commands for Vitis Classic
857  hsi::open_hw_design $xsa
858  set proc_cells [hsi::get_cells -filter { IP_TYPE == "PROCESSOR" }]
859  set proc_map_path [file normalize "$globalSettings::build_dir/vitis_classic/$platform_name.PROC_MAP"]
860  set proc_map_file [open $proc_map_path "w"]
861 
862  foreach proc $proc_cells {
863  # If soft processor, save mapping from proc to cell to be used later when updating mem
864  Msg Debug "Processor found in xsa: $proc"
865  if {[regexp -nocase {microblaze|risc} $proc]} {
866  Msg Info "Extracting processor cells for soft processor: $proc"
867  set proc_hier_name [hsi::get_property HIER_NAME $proc]
868  set proc_address_tag [hsi::get_property ADDRESS_TAG $proc]
869 
870  # updatemem -proc needs the instance path from the MMI (usually HIER_NAME).
871  # ADDRESS_TAG is preferred when present (may be "tag:path"), otherwise fall back
872  set proc_updatemem_path $proc_hier_name
873  if {$proc_address_tag ne ""} {
874  if {[string match "*:*" $proc_address_tag]} {
875  set proc_updatemem_path [lindex [split $proc_address_tag ":"] end]
876  } else {
877  set proc_updatemem_path $proc_address_tag
878  }
879  } else {
880  Msg Warning "Processor $proc ($proc_hier_name) does not have an ADDRESS_TAG property set. Using HIER_NAME for updatemem."
881  }
882  if {$proc_updatemem_path eq ""} {
883  set proc_updatemem_path $proc
884  }
885 
886  # Index by HSI cell name (matches hog.conf proc=) and by hierarchy name
887  puts $proc_map_file "$proc $proc_updatemem_path"
888  if {$proc_hier_name ne "" && $proc_hier_name ne $proc} {
889  puts $proc_map_file "$proc_hier_name $proc_updatemem_path"
890  }
891  }
892  }
893 
894  hsi::close_hw_design [hsi::current_hw_design]
895  close $proc_map_file
896  Msg Info "Wrote soft-processor map to $proc_map_path"
897  }
898 
899 
900  Msg Info "Creating platform \[$platform_name\] with options: \{$platform_options\}"
901  if {[IsVitisClassic]} {
902  set plat_create "platform create $platform_options"
903  eval $plat_create
904  platform active $platform_name
905  platform generate
906  } elseif {[IsVitisUnified]} {
907  # Use Python script to create the platform with new Vitis Unified Python command-line tool
908  set python_script "$globalSettings::repo_path/Hog/Other/Python/VitisUnified/PlatformCommands.py"
909  Msg Info "Running Vitis Unified platform creation script..."
910  # The options contain spaces: pass them in the environment, as a command line
911  # argument they would be split by the Windows shell that runs vitis.bat
912  set ::env(HOG_VITIS_PLATFORM_OPTIONS) "{ $platform_options }"
913  set error_msg "Failed to create platform $platform_name"
914  if {![ExecuteVitisUnifiedCommand $python_script "create_platform" \
915  [list "$globalSettings::build_dir/vitis_unified"] \
916  $error_msg]} {
917  return
918  }
919  }
920 }
921 
922 
923 proc ConfigureApps {} {
924  set apps [dict filter $globalSettings::PROPERTIES key {app:*}]
925 
926  if {[dict size $apps] == 0} {
927  Msg Info "No apps found in the configuration file"
928  return
929  }
930 
931  dict for {app_key app_config} $apps {
932  Msg Info "Found app with key: $app_key with configuration: $app_config"
933  if {[regexp {^app:(.+)$} $app_key -> app_name]} {
934  set app_name [string trim $app_name]
935  Msg Info "Configuring app: $app_name"
936  if {[IsVitisClassic]} {
937  ConfigureApp $app_name $app_config
938  } elseif {[IsVitisUnified]} {
939  set python_script "$globalSettings::repo_path/Hog/Other/Python/VitisUnified/AppCommands.py"
940  Msg Info "Running Vitis Unified app configuration script..."
941  # Build app config string from app_config dict
942  set app_config_str "{"
943  dict for {p v} $app_config {
944  append app_config_str " -[string toupper $p] \{$v\}"
945  }
946  append app_config_str " }"
947  # The options contain spaces: pass them in the environment, as a command line
948  # argument they would be split by the Windows shell that runs vitis.bat
949  set ::env(HOG_VITIS_APP_OPTIONS) $app_config_str
950  set error_msg "Failed to configure app $app_name"
951  if {![ExecuteVitisUnifiedCommand $python_script "configure_app" \
952  [list $app_name "$globalSettings::build_dir/vitis_unified"] \
953  $error_msg]} {
954  continue
955  }
956  }
957  } else {
958  Msg Warning "Invalid app key format: $app_key. Expected format: app:<name>"
959  }
960  }
961 }
962 
963 proc ConfigureApp {app_name app_conf} {
964 
965  set create_options {
966  "platform" "domain" "sysproj" "hw"
967  "proc" "template" "os" "lang" "arch" "name"
968  }
969 
970  set conf_options {
971  "assembler-flags" "build-config" "compiler-misc" "compiler-optimization"
972  "define-compiler-symbols" "include-path" "libraries" "library-search-path"
973  "linker-misc" "linker-script" "undef-compiler-symbols"
974  }
975 
976  Msg Info "Configuring app..."
977  append app_options " -name $app_name"
978 
979  # A sysproj may have been created before, we must remove it
980  if {[catch {set sys_projs [sysproj list -dict]}]} { set sys_projs "" }
981  if {[dict exists $app_name sysproj]} {
982  set sys_proj_name [dict get $app_name sysproj]
983  if {[lsearch -exact $sys_projs "Name $sys_proj_name"] != -1} {
984  Msg Info "Removing $sys_proj_name..."
985  sysproj remove $sys_proj_name
986  }
987  } else {
988  set sys_proj_name "$app_name\_system"
989  if {[lsearch -exact $sys_projs "Name $sys_proj_name"] != -1} {
990  Msg Info "Removing $sys_proj_name..."
991  sysproj remove $sys_proj_name
992  }
993  }
994 
995  # An app may have been created before, we must remove it
996  if {[catch {set ws_apps [app list -dict]}]} { set ws_apps "" }
997  if {[lsearch -exact $ws_apps $app_name] != -1} {
998  Msg Info "app $app_name already exists, removing it..."
999  app remove $app_name
1000  }
1001 
1002  set app_create_options [dict create]
1003  set app_conf_options [dict create]
1004 
1005 
1006  dict for {p v} $app_conf {
1007  set p_lower [string tolower $p]
1008 
1009  if {[IsInList [string toupper $p] [VITIS_PATH_PROPERTIES] 1]} {
1010  if {[IsRelativePath $v] == 1} {
1011  set v "$globalSettings::repo_path/$v"
1012  #"
1013  }
1014  if {![file exists $v]} {
1015  Msg Warning "Impossible to set property $p to $v. File is missing"
1016  continue
1017  }
1018  }
1019 
1020  if {[IsInList $p_lower $create_options]} {
1021  Msg Info "$p_lower is in create options"
1022  dict append app_create_options $p_lower $v
1023  } elseif {[IsInList $p_lower $conf_options]} {
1024  Msg Info "$p_lower is in conf options"
1025  dict append app_conf_options $p_lower $v
1026  } else {
1027  Msg Warning "Unknown app option: $p_lower"
1028  }
1029  }
1030 
1031 
1032  dict for {p v} $app_create_options {
1033  if {[string equal $p "platform"]} {
1034  Msg Info "Setting App $app_name platform to $v"
1035  platform active $v
1036  }
1037  append app_options " -$p $v"
1038  }
1039 
1040  if {![dict exists $app_name template]} {
1041  if {[CompareVersions $globalSettings::c_v "2022 1 0"] == -1} {
1042  # Check if lang is defined in create_options
1043  if {[dict exists $app_create_options "lang"]} {
1044  set lang [dict get $app_create_options "lang"]
1045  if {[string equal -nocase $lang "C++"] || [string equal -nocase $lang "cpp"]} {
1046  append app_options " -template \{Empty Application (C++)\}"
1047  } else {
1048  append app_options " -template \{Empty Application(C)\}"
1049  }
1050  } else {
1051  # Default to Empty Application if lang is not specified
1052  append app_options " -template \{Empty Application(C)\}"
1053  }
1054  } else {
1055  # For newer versions, use the generic template
1056  append app_options " -template \{Empty Application\}"
1057  }
1058  }
1059 
1060  Msg Info "Creating application \[$app_name\] with options: \{$app_options\}"
1061  set app_create "app create $app_options"
1062  eval $app_create
1063  app config -name $app_name -set build-config Release
1064 
1065  # App config options
1066  dict for {p v} $app_conf_options {
1067  Msg Info "Configuring app option $p to $v"
1068  app config -name $app_name -set $p $v
1069  }
1070 }
1071 
1072 
1073 proc AddAppFiles {} {
1074  AddHogFiles {*}[GetHogFiles -list_files {.src,.header} -ext_path $globalSettings::HOG_EXTERNAL_PATH $globalSettings::list_path $globalSettings::repo_path ]
1075 }
1076 
1077 
1078 ## @brief Configure the Vitis components (HLS, platforms and apps) of a project
1079 #
1080 # This is the work of the "-vitis_only" pass. It runs both from the standalone
1081 # "-vitis_only" entry point and, in the same interpreter, at the end of the
1082 # Vivado pass of a vivado_vitis_* project. It must not be run by spawning a
1083 # second Vivado: on Windows the nested process dies with an access violation
1084 # during Vivado start-up, before it can source any Hog script.
1085 #
1086 # @param[in] xsa_option The -xsa option, empty to derive the XSA from the Vivado project
1087 # @param[in] ide The IDE name, as written in hog.conf
1088 # @param[in] post_file The post-creation Tcl script, sourced if it exists
1089 #
1090 # @return 0 on success, 1 if no usable XSA could be found
1091 #
1092 proc ConfigureVitisComponents {xsa_option ide post_file} {
1093 
1094  if {[IsVitisUnified]} {
1095  set vitis_ws [file normalize "$globalSettings::build_dir/vitis_unified"]
1096  if {[file exists $vitis_ws]} {
1097  Msg Info "Removing existing Vitis Unified workspace $vitis_ws..."
1098  file delete -force $vitis_ws
1099  }
1100  file mkdir $vitis_ws
1101  }
1102 
1103  set has_hls [expr {[dict size [dict filter $globalSettings::PROPERTIES key {hls:*}]] > 0}]
1104  set has_platforms [expr {[dict size [dict filter $globalSettings::PROPERTIES key {platform:*}]] > 0}]
1105  set has_apps [expr {[dict size [dict filter $globalSettings::PROPERTIES key {app:*}]] > 0}]
1106 
1107  if {$has_hls} {
1108  Msg Info "Found HLS component(s) in configuration, configuring HLS..."
1110  }
1111 
1112  if {!$has_platforms && !$has_apps} {
1113  Msg Info "vitis unified HLS-only project, skipping Vivado project setup."
1114  return 0
1115  }
1116 
1117  set xsa_path $xsa_option
1118 
1119  if {$xsa_path == ""} {
1120  if {[string match "vivado_*" [string tolower $ide]]} {
1121  # vivado_vitis project: generate pre-synth XSA from existing Vivado project
1122  set xpr_file [file normalize "$globalSettings::build_dir/[file tail $globalSettings::DESIGN].xpr"]
1123  if {[file exists $xpr_file]} {
1124  Msg Info "Opening existing Vivado project to generate pre-synth XSA..."
1125  open_project $xpr_file
1126  set xsa_path [file normalize "$globalSettings::build_dir/$globalSettings::DESIGN-presynth.xsa"]
1128  write_hw_platform -fixed -force -file $xsa_path
1129  Msg Info "Pre-synth XSA generated: $xsa_path"
1130  close_project
1131  } else {
1132  # tclint-disable-next-line line-length
1133  Msg Error "Vivado project not found at $xpr_file. Please run CREATE without -vitis_only first to create the Vivado project or provide an XSA file via the -xsa option."
1134  return 1
1135  }
1136  } else {
1137  # Standalone vitis project: XSA is mandatory for platform/app
1138  Msg Error "This is a $ide only project with platform/app sections, an XSA file must be provided via the -xsa option."
1139  return 1
1140  }
1141  } elseif {[IsRelativePath $xsa_path] == 1} {
1142  # Relative -xsa is repo-relative; do not resolve against Hog/Tcl (cwd)
1143  set xsa_path [file normalize "$globalSettings::repo_path/$xsa_path"]
1144  } else {
1145  set xsa_path [file normalize $xsa_path]
1146  }
1147 
1148  Msg Info "Configuring platforms with XSA: $xsa_path"
1149  ConfigurePlatforms "$xsa_path"
1151  AddAppFiles
1152 
1153  if {[file exists $post_file]} {
1154  if {[string match "vivado_*" [string tolower $ide]]} {
1155  Msg Info "Skipping post-creation.tcl in -vitis_only pass for $ide \
1156  (already executed during Vivado project creation)."
1157  } else {
1158  Msg Info "Found post-creation Tcl script $post_file, executing it..."
1159  source $post_file
1160  }
1161  }
1162 
1163  return 0
1164 }
1165 
1166 ## @brief Configure HLS components defined in hog.conf [hls:*] sections
1167 #
1168 # For each [hls:<component_name>] section, this proc:
1169 # 1. Reads the HLS_CONFIG path from hog.conf (mandatory, repo-relative)
1170 # 2. Validates that the hls_config.cfg file exists and is well-formed
1171 # 3. Creates a Vitis-compatible workspace so the project can be opened in the GUI
1172 #
1173 # The hls_config.cfg is the single source of truth for HLS settings.
1174 # It is committed to the repo and directly used/edited by Vitis.
1175 #
1176 proc ConfigureHlsComponents {} {
1177  set hls_components [dict filter $globalSettings::PROPERTIES key {hls:*}]
1178 
1179  if {[dict size $hls_components] == 0} {
1180  Msg Info "No HLS components found in the configuration file"
1181  return
1182  }
1183 
1184  set python_script "$globalSettings::repo_path/Hog/Other/Python/VitisUnified/HlsCommands.py"
1185  set ws_dir [file normalize "$globalSettings::build_dir/vitis_unified"]
1186 
1187  dict for {hls_key hls_config} $hls_components {
1188  if {[regexp {^hls:(.+)$} $hls_key -> component_name]} {
1189  set component_name [string trim $component_name]
1190  Msg Info "Configuring HLS component: $component_name"
1191 
1192  # Get HLS_CONFIG path from hog.conf (mandatory)
1193  set hls_cfg_rel ""
1194  if {[dict exists $hls_config hls_config]} {
1195  set hls_cfg_rel [dict get $hls_config hls_config]
1196  } elseif {[dict exists $hls_config HLS_CONFIG]} {
1197  set hls_cfg_rel [dict get $hls_config HLS_CONFIG]
1198  }
1199  if {$hls_cfg_rel eq ""} {
1200  Msg Error "HLS component '$component_name' missing HLS_CONFIG in hog.conf \[hls:$component_name\] section"
1201  continue
1202  }
1203 
1204  set hls_cfg_file [file normalize "$globalSettings::repo_path/$hls_cfg_rel"]
1205  if {![file exists $hls_cfg_file]} {
1206  Msg Error "HLS config file not found: $hls_cfg_file (from HLS_CONFIG=$hls_cfg_rel)"
1207  continue
1208  }
1209 
1210  Msg Info " HLS config: $hls_cfg_file"
1211 
1212  # Validate the config file
1213  set error_msg "Failed to validate HLS config for $component_name"
1214  if {![ExecuteVitisUnifiedCommand $python_script "validate" \
1215  [list $hls_cfg_file] \
1216  $error_msg]} {
1217  Msg Error $error_msg
1218  continue
1219  }
1220 
1221  # Create Vitis workspace with HLS component for GUI compatibility
1222  set hls_work_dir [file normalize "$ws_dir/hls_$component_name"]
1223  Msg Info "Creating Vitis HLS workspace component '$component_name' in $ws_dir ..."
1224  if {![ExecuteVitisUnifiedCommand $python_script "create_workspace" \
1225  [list $ws_dir $component_name $hls_cfg_file $hls_work_dir] \
1226  "Failed to create HLS workspace for $component_name"]} {
1227  Msg Warning "Could not create Vitis workspace for HLS component '$component_name'"
1228  }
1229 
1230  Msg Info "HLS component '$component_name' configured successfully"
1231  } else {
1232  Msg Warning "Invalid HLS key format: $hls_key. Expected format: hls:<name>"
1233  }
1234  }
1235 }
1236 
1237 ## @brief upgrade IPs in the project and copy them from HOG_IP_PATH if defined
1238 #
1239 proc ManageIPs {} {
1240  # set the current impl run
1241  current_run -implementation [get_runs impl_1]
1242 
1243  ##############
1244  # UPGRADE IP #
1245  ##############
1246  set ips [get_ips *]
1247 
1248  Msg Info "Running report_ip_status, before upgrading and handling IPs..."
1249  report_ip_status
1250  # Pull ips from repo
1251  if {$globalSettings::HOG_IP_PATH != ""} {
1252  set ip_repo_path $globalSettings::HOG_IP_PATH
1253  Msg Info "HOG_IP_PATH is set, will pull/push synthesised IPs from/to $ip_repo_path."
1254 
1255  lassign [CheckRemoteIpPath $globalSettings::repo_path $ip_repo_path] system_ready on_eos on_rclone rclone_config_path
1256  if {$system_ready == 1} {
1257  foreach ip $ips {
1258  HandleIP pull [get_property IP_FILE $ip] $ip_repo_path $globalSettings::repo_path [get_property IP_OUTPUT_DIR $ip]\
1259  $on_eos $on_rclone $rclone_config_path
1260  }
1261  }
1262  } else {
1263  Msg Info "HOG_IP_PATH not set, will not push/pull synthesised IPs."
1264  }
1265 }
1266 
1267 ## @brief Upgrade locked IPs with an available catalog version
1268 proc UpgradeIPs {} {
1269  set upgraded 0
1270 
1271  foreach ip [get_ips] {
1272  set locked [get_property -quiet IS_LOCKED $ip]
1273  set upgrade_versions [get_property -quiet UPGRADE_VERSIONS $ip]
1274  if {$locked && $upgrade_versions ne ""} {
1275  Msg Info "Upgrading IP $ip..."
1276  upgrade_ip $ip
1277  incr upgraded
1278  }
1279  }
1280 
1281  if {$upgraded == 0} {
1282  Msg Info "No locked IPs with available upgrades found."
1283  } else {
1284  Msg Info "Upgraded $upgraded IP(s)."
1285  }
1286 }
1287 
1288 proc SetGlobalVar {var {default_value HOG_NONE}} {
1289  ##nagelfar ignore
1290  if {[info exists ::$var]} {
1291  Msg Debug "Setting $var to [subst $[subst ::$var]]"
1292  ##nagelfar ignore
1293  set globalSettings::$var [subst $[subst ::$var]]
1294  } elseif {$default_value == "HOG_NONE"} {
1295  Msg Error "Mandatory variable $var was not defined. Please define it in hog.conf or in project tcl script."
1296  } else {
1297  Msg Info "Setting $var to default value: \"$default_value\""
1298  ##nagelfar ignore
1299  set globalSettings::$var $default_value
1300  }
1301 }
1302 
1303 proc CreateProject {args} {
1304  global env
1305  # set tcl_path [file normalize "[file dirname [info script]]"]
1306  # set repo_path [file normalize $tcl_path/../..]
1307 
1308  if {[catch {package require cmdline} ERROR]} {
1309  puts "ERROR: If you are running this script on tclsh, you can fix this by installing 'tcllib'"
1310  return
1311  }
1312  set parameters {
1313  {simlib_path.arg "" "Path of simulation libs"}
1314  {verbose "If set, launch the script in verbose mode."}
1315  {xsa.arg "" "xsa for creating platforms without a defined hw."}
1316  {vivado_only "If set, and project is vivado-vitis, vitis project will not be created."}
1317  {vitis_only "If set, and project is vivado-vitis, only vitis project will be created."}
1318  }
1319 
1320  set usage "Create Vivado/Vitis/ISE/Quartus/Libero/Diamond project.\nUsage: CreateProject \[OPTIONS\] <project> <repository path>\n Options:"
1321 
1322  if {[catch {array set options [cmdline::getoptions args $parameters $usage]}] || [llength $args] < 2 || [lindex $args 0] eq ""} {
1323  Msg Info [cmdline::usage $parameters $usage]
1324  return 1
1325  }
1326 
1327  set globalSettings::DESIGN [lindex $args 0]
1328  if {[file exists [lindex $args 1]]} {
1329  set globalSettings::repo_path [file normalize [lindex $args 1]]
1330  } else {
1331  Msg Error "The second argument, [lindex $args 1], should be the repository path."
1332  }
1333  set globalSettings::tcl_path $globalSettings::repo_path/Hog/Tcl
1334 
1335 
1336  if {$options(verbose) == 1} {
1337  variable ::DEBUG_MODE 1
1338  }
1339 
1340  if {[IsVivado]} {
1341  if {$options(simlib_path) != ""} {
1342  if {[IsRelativePath $options(simlib_path)] == 0} {
1343  set globalSettings::simlib_path "$options(simlib_path)"
1344  } else {
1345  set globalSettings::simlib_path "${globalSettings::repo_path}/$options(simlib_path)"
1346  }
1347  Msg Info "Simulation library path set to $options(simlib_path)"
1348  } else {
1349  set globalSettings::simlib_path "${globalSettings::repo_path}/SimulationLib"
1350  Msg Info "Simulation library path set to default ${globalSettings::repo_path}/SimulationLib"
1351  }
1352  }
1353 
1354  # Derived variables from now on...
1355 
1356  set build_dir_name "Projects"
1357  set globalSettings::group_name [file dirname ${globalSettings::DESIGN}]
1358  set globalSettings::project_name ${globalSettings::DESIGN}
1359  set globalSettings::pre_synth_file "pre-synthesis.tcl"
1360  set globalSettings::post_synth_file "post-synthesis.tcl"
1361  set globalSettings::pre_impl_file "pre-implementation.tcl"
1362  set globalSettings::post_impl_file "post-implementation.tcl"
1363  set globalSettings::pre_bit_file "pre-bitstream.tcl"
1364  set globalSettings::post_bit_file "post-bitstream.tcl"
1365  set globalSettings::quartus_post_module_file "quartus-post-module.tcl"
1366  set globalSettings::top_path "${globalSettings::repo_path}/Top/${globalSettings::DESIGN}"
1367  set globalSettings::list_path "${globalSettings::top_path}/list"
1368  set globalSettings::build_dir "${globalSettings::repo_path}/${build_dir_name}/${globalSettings::DESIGN}"
1369  set globalSettings::DESIGN [file tail ${globalSettings::DESIGN}]
1370  set globalSettings::top_name [file tail ${globalSettings::DESIGN}]
1371  set globalSettings::top_name [file rootname ${globalSettings::top_name}]
1372  set globalSettings::synth_top_module "top_${globalSettings::top_name}"
1373  set globalSettings::user_ip_repo ""
1374 
1375  set globalSettings::pre_synth [file normalize "${globalSettings::tcl_path}/integrated/${globalSettings::pre_synth_file}"]
1376  set globalSettings::post_synth [file normalize "${globalSettings::tcl_path}/integrated/${globalSettings::post_synth_file}"]
1377  set globalSettings::pre_impl [file normalize "${globalSettings::tcl_path}/integrated/${globalSettings::pre_impl_file}"]
1378  set globalSettings::post_impl [file normalize "${globalSettings::tcl_path}/integrated/${globalSettings::post_impl_file}"]
1379  set globalSettings::pre_bit [file normalize "${globalSettings::tcl_path}/integrated/${globalSettings::pre_bit_file}"]
1380  set globalSettings::post_bit [file normalize "${globalSettings::tcl_path}/integrated/${globalSettings::post_bit_file}"]
1381  set globalSettings::quartus_post_module [file normalize "${globalSettings::tcl_path}/integrated/${globalSettings::quartus_post_module_file}"]
1382  set globalSettings::LIBERO_MANDATORY_VARIABLES {"FAMILY" "PACKAGE" "DIE" }
1383 
1384  set proj_dir [file normalize "${globalSettings::repo_path}/Top/${globalSettings::project_name}"]
1385  Msg Debug "Calling GetConfFiles with proj_dir=$proj_dir (project_name=${globalSettings::project_name})"
1386  lassign [GetConfFiles $proj_dir] conf_file sim_file pre_file post_file pre_rtl_file
1387 
1388  set user_repo 0
1389  if {[file exists $conf_file]} {
1390  Msg Info "Parsing configuration file $conf_file..."
1391  SetGlobalVar PROPERTIES [ReadConf $conf_file]
1392 
1393  # Checking Vivado/Vitis/Quartus/ISE/Libero version
1394  set actual_version [GetIDEVersion]
1395  lassign [GetIDEFromConf $conf_file] ide conf_version
1396 
1397  if {$conf_version != "0.0.0"} {
1398  set globalSettings::a_v [split $actual_version "."]
1399  set globalSettings::c_v [split $conf_version "."]
1400 
1401  if {[llength $globalSettings::a_v] < 2} {
1402  Msg Error "Couldn't parse IDE version: $actual_version."
1403  } elseif {[llength $globalSettings::a_v] == 2} {
1404  lappend globalSettings::a_v 0
1405  }
1406  if {[llength $globalSettings::c_v] < 2} {
1407  Msg Error "Wrong version format in hog.conf: $conf_version."
1408  } elseif {[llength $globalSettings::c_v] == 2} {
1409  lappend globalSettings::c_v 0
1410  }
1411 
1412  set comp [CompareVersions $globalSettings::a_v $globalSettings::c_v]
1413  if {$comp == 0} {
1414  Msg Info "Project version and $ide version match: $conf_version."
1415  } elseif {$comp == 1} {
1416  Msg CriticalWarning "The $ide version in use is $actual_version, that is newer than $conf_version, as specified in the first line of $conf_file.\n\
1417  If you want update this project to version $actual_version, please update the configuration file."
1418  } else {
1419  # tclint-disable-next-line line-length
1420  Msg Error "The $ide version in use is $actual_version, that is older than $conf_version as specified in $conf_file. The project will not be created.\nIf you absolutely want to create this project that was meant for version $conf_version with $ide version $actual_version, you can change the version from the first line of $conf_file.\nThis is HIGHLY discouraged as there could be unrecognised properties in the configuration file and IPs created with a newer $ide version cannot be downgraded."
1421  }
1422  } else {
1423  Msg CriticalWarning "No version found in the first line of $conf_file. \
1424  It is HIGHLY recommended to replace the first line of $conf_file with: \#$ide $actual_version"
1425  }
1426 
1427  if {$globalSettings::vitis_classic == 1} {
1428  if {[CompareVersions $globalSettings::a_v "2020 2 0"] == -1 || [CompareVersions $globalSettings::c_v "2020 2 0"] == -1} {
1429  Msg Error "Vitis Classic flow is not supported for versions < 2020.2. Please use Vitis 2020.2 or newer." }
1430  }
1431  if {$globalSettings::vitis_unified == 1} {
1432  if {[CompareVersions $globalSettings::a_v "2019 2 0"] == -1 || [CompareVersions $globalSettings::c_v "2019 2 0"] == -1} {
1433  Msg Error "Vitis Unified flow is not supported for versions < 2019.2. Please use Vitis 2019.2 or newer." }
1434  }
1435 
1436  if {[dict exists $globalSettings::PROPERTIES main]} {
1437  set main [dict get $globalSettings::PROPERTIES main]
1438  dict for {p v} $main {
1439  # notice the dollar in front of p: creates new variables and fill them with the value
1440  Msg Info "Main property $p set to $v"
1441  ##nagelfar ignore
1442  set ::$p $v
1443  }
1444  } else {
1445  Msg Error "No main section found in $conf_file, make sure it has a section called \[main\] containing the mandatory properties."
1446  }
1447  } else {
1448  Msg Error "$conf_file was not found in your project directory, please create one."
1449  }
1450 
1451 
1452  if {[IsXilinx] || [IsQuartus]} {
1453  SetGlobalVar PART
1454  }
1455  #Family is needed in quartus and libero only
1456  if {[IsQuartus] || [IsLibero]} {
1457  #Quartus only
1458  SetGlobalVar FAMILY
1459  if {[IsLibero]} {
1460  SetGlobalVar DIE
1461  SetGlobalVar PACKAGE
1462  }
1463  }
1464 
1465  if {[IsDiamond]} {
1466  SetGlobalVar DEVICE
1467  SetGlobalVar SYNTHESIS_TOOL "lse"
1468  }
1469 
1470  if {[IsVivado]} {
1471  SetGlobalVar TARGET_SIMULATOR "XSim"
1472  }
1473 
1474  if {[info exists env(HOG_EXTERNAL_PATH)]} {
1475  set globalSettings::HOG_EXTERNAL_PATH $env(HOG_EXTERNAL_PATH)
1476  } else {
1477  set globalSettings::HOG_EXTERNAL_PATH ""
1478  }
1479 
1480  set user_hog_file "${globalSettings::repo_path}/Top/hog.tcl"
1481  if {[file exists $user_hog_file]} {
1482  Msg Info "Sourcing user hog.tcl file..."
1483  source $user_hog_file
1484  }
1485 
1486  if {[file exists $pre_file]} {
1487  Msg Info "Found pre-creation Tcl script $pre_file, executing it..."
1488  source $pre_file
1489  }
1490 
1491  if {[info exists env(HOG_IP_PATH)]} {
1492  set globalSettings::HOG_IP_PATH $env(HOG_IP_PATH)
1493  } else {
1494  set globalSettings::HOG_IP_PATH ""
1495  }
1496 
1497  InitProject $options(vitis_only)
1498 
1499  if {([IsVitisClassic] || [IsVitisUnified]) && $options(vitis_only) == 1} {
1500  if {[ConfigureVitisComponents $options(xsa) $ide $post_file] != 0} {
1501  return 1
1502  }
1503  return
1504  }
1505 
1506  # If the project is a vitis-only project, skip creating the Vivado project
1507  if {([string tolower $ide] eq "vitis_classic" || [string tolower $ide] eq "vitis_unified") && $options(vitis_only) == 1} {
1508  if {$options(xsa) == ""} {
1509  Msg Error "This is a $ide only project, an XSA file must be provided via -xsa option."
1510  return 1
1511  }
1512  return
1513  }
1514 
1519 
1520 
1521  if {[IsVivado]} {
1522  # Use HandleIP to pull IPs from HOG_IP_PATH if specified
1523  ManageIPs
1524  }
1525 
1526  if {[IsQuartus]} {
1527  set fileName_old [file normalize "./hogTmp/.hogQsys.md5"]
1528  set fileDir [file normalize "${globalSettings::build_dir}/.hog/"]
1529  file mkdir $fileDir
1530  set fileName_new [file normalize "$fileDir/.hogQsys.md5"]
1531  if {[file exists $fileName_new]} {
1532  file delete $fileName_new
1533  }
1534  if {[file exists $fileName_old]} {
1535  file rename -force $fileName_old $fileName_new
1536  file delete -force -- "./hogTmp"
1537  }
1538  }
1539 
1540  if {[file exists $post_file]} {
1541  Msg Info "Found post-creation Tcl script $post_file, executing it..."
1542  source $post_file
1543  if {[IsLibero]} {
1544  # Regenerate the hierarchy in case a new file has been added
1545  build_design_hierarchy
1546  }
1547  }
1548 
1549  # Check extra IPs
1550  # Get project libraries and properties from list files
1551  lassign [GetHogFiles \
1552  -ext_path "$globalSettings::HOG_EXTERNAL_PATH" \
1553  -list_files ".src,.ext" \
1554  "$globalSettings::repo_path/Top/$globalSettings::project_name/list/" \
1555  $globalSettings::repo_path] \
1556  listLibraries listProperties listSrcSets
1557  # Get project constraints and properties from list files
1558  lassign [GetHogFiles \
1559  -ext_path "$globalSettings::HOG_EXTERNAL_PATH" \
1560  -list_files ".con" \
1561  "$globalSettings::repo_path/Top/$globalSettings::project_name/list/" \
1562  $globalSettings::repo_path] \
1563  listConstraints listConProperties listConSets
1564 
1565  lassign [GetHogFiles \
1566  -ext_path "$globalSettings::HOG_EXTERNAL_PATH" \
1567  -list_files ".sim" \
1568  "$globalSettings::repo_path/Top/$globalSettings::project_name/list/" \
1569  $globalSettings::repo_path] \
1570  listSimLibraries listSimProperties listSimSets
1571 
1572  set old_path [pwd]
1573  cd $globalSettings::build_dir
1574  CheckExtraFiles $listLibraries $listConstraints $listSimLibraries
1575  cd $old_path
1576 
1577  if {[IsXilinx]} {
1578  set old_path [pwd]
1579  cd $globalSettings::repo_path
1580  set flavour [GetProjectFlavour $globalSettings::DESIGN]
1581  # Getting all the versions and SHAs of the repository
1582  lassign [GetRepoVersions \
1583  [file normalize $globalSettings::repo_path/Top/$globalSettings::project_name] \
1584  $globalSettings::repo_path \
1585  $globalSettings::HOG_EXTERNAL_PATH \
1586  ] commit version hog_hash hog_ver top_hash top_ver libs hashes vers cons_ver cons_hash ext_names ext_hashes \
1587  xml_hash xml_ver user_ip_repos user_ip_hashes user_ip_vers cheby_hash cheby_ver
1588 
1589  set this_commit [GetSHA]
1590 
1591  if {$commit == 0} {
1592  set commit $this_commit
1593  }
1594 
1595  if {$xml_hash != ""} {
1596  set use_ipbus 1
1597  } else {
1598  set use_ipbus 0
1599  }
1600 
1601 
1602  lassign [GetDateAndTime $commit] date timee
1603  WriteGenerics "create" \
1604  $globalSettings::repo_path \
1605  $globalSettings::project_name \
1606  $date $timee $commit $version \
1607  $top_hash $top_ver $hog_hash $hog_ver \
1608  $cons_ver $cons_hash $libs $vers $hashes \
1609  $ext_names $ext_hashes $user_ip_repos $user_ip_vers \
1610  $user_ip_hashes $flavour $xml_ver $xml_hash $cheby_ver $cheby_hash
1611  cd $old_path
1612  }
1613 
1614  if {[IsLibero]} {
1615  save_project
1616  }
1617 
1618  if {[IsDiamond]} {
1619  prj_project save
1620  }
1621 
1622 
1623  if {($globalSettings::vitis_classic == 1 || $globalSettings::vitis_unified == 1)} {
1624  # Presynth hw platform, let's keep it in the build directory
1626  write_hw_platform -fixed -force -file [file normalize "$globalSettings::build_dir/$globalSettings::DESIGN-presynth.xsa"]
1627 
1628  if {$options(xsa) == ""} {
1629  set vitis_xsa [file normalize "$globalSettings::build_dir/$globalSettings::DESIGN-presynth.xsa"]
1630  } elseif {[IsRelativePath $options(xsa)] == 1} {
1631  set vitis_xsa [file normalize "$globalSettings::repo_path/$options(xsa)"]
1632  } else {
1633  set vitis_xsa [file normalize $options(xsa)]
1634  }
1635 
1636  if {$globalSettings::vitis_classic == 1} {
1637  # Launch xsct to build the project
1638  set xsct_cmd "xsct $globalSettings::tcl_path/launch.tcl C -xsa $vitis_xsa -vitis_only $globalSettings::project_name"
1639  Msg Info "Running Vitis Classic project creation script with command: $xsct_cmd"
1640  set ret [catch {exec -ignorestderr {*}$xsct_cmd >@ stdout} result]
1641  if {$ret != 0} {
1642  Msg Error "xsct (vitis classic) returned an error state: $result"
1643  }
1644  } elseif {$globalSettings::vitis_unified == 1} {
1645  Msg Info "Configuring Vitis Unified components..."
1646  set previous_pass 0
1647  if {[info exists globalSettings::vitis_only_pass]} {
1648  set previous_pass $globalSettings::vitis_only_pass
1649  }
1650  # Make AddHogFiles add the sources to the Vitis apps rather than to the
1651  # Vivado project, which already has them
1652  set globalSettings::vitis_only_pass 1
1653  set ret [catch {ConfigureVitisComponents $vitis_xsa $ide $post_file} result]
1654  set globalSettings::vitis_only_pass $previous_pass
1655  if {$ret != 0} {
1656  Msg Error "Failed to configure the Vitis Unified components: $result"
1657  } elseif {$result != 0} {
1658  Msg Error "Failed to configure the Vitis Unified components."
1659  }
1660  }
1661  }
1662 
1663 
1664  Msg Info "Project $globalSettings::project_name created successfully in [Relative $globalSettings::repo_path $globalSettings::build_dir]."
1665  Notify Info "Created project $globalSettings::project_name."
1666 }