Hog Hog2026.2-5
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  }
470  } elseif {[IsQuartus]} {
471  #QUARTUS only
472  set_global_assignment -name POST_MODULE_SCRIPT_FILE quartus_sh:$globalSettings::quartus_post_module
473  } elseif {[IsDiamond]} {
474  prj_impl post_script "par" $globalSettings::post_impl
475  }
476  Msg Debug "Setting $globalSettings::post_impl to be run after implementation"
477  }
478 
479  ## set pre write bitstream script
480  if {$globalSettings::pre_bit_file ne ""} {
481  if {[IsXilinx]} {
482  #Vivado Only
483  if {[IsVivado]} {
484  if {[get_filesets -quiet utils_1] != ""} {
485  AddFile $globalSettings::pre_bit [get_filesets -quiet utils_1]
486  }
487  set_property STEPS.[BinaryStepName $globalSettings::PART].TCL.PRE $globalSettings::pre_bit $obj
488  }
489  } elseif {[IsQuartus]} {
490  #QUARTUS only
491  #set_global_assignment -name PRE_FLOW_SCRIPT_FILE quartus_sh:$globalSettings::pre_bit
492  } elseif {[IsDiamond]} {
493  prj_impl pre_script "export" $globalSettings::pre_bit
494  }
495  Msg Debug "Setting $globalSettings::pre_bit to be run after bitfile generation"
496  }
497 
498  ## set post write bitstream script
499  if {$globalSettings::post_bit_file ne ""} {
500  if {[IsXilinx]} {
501  #Vivado Only
502  if {[IsVivado]} {
503  if {[get_filesets -quiet utils_1] != ""} {
504  AddFile $globalSettings::post_bit [get_filesets -quiet utils_1]
505  }
506  set_property STEPS.[BinaryStepName $globalSettings::PART].TCL.POST $globalSettings::post_bit $obj
507  }
508  } elseif {[IsQuartus]} {
509  #QUARTUS only
510  set_global_assignment -name POST_MODULE_SCRIPT_FILE quartus_sh:$globalSettings::quartus_post_module
511  } elseif {[IsDiamond]} {
512  prj_impl post_script "export" $globalSettings::post_bit
513  }
514  Msg Debug "Setting $globalSettings::post_bit to be run after bitfile generation"
515  }
516 
518 }
519 
520 
521 ## @brief configure simulation
522 #
523 proc ConfigureSimulation {} {
524  set simsets_dict [GetSimSets "$globalSettings::group_name/$globalSettings::DESIGN" $globalSettings::repo_path]
525 
526  if {[IsXilinx]} {
527  ##############
528  # SIMULATION #
529  ##############
530  Msg Debug "Setting load_glbl parameter to true for every fileset..."
531  foreach simset [get_filesets -quiet] {
532  if {[get_property FILESET_TYPE $simset] != "SimulationSrcs"} {
533  continue
534  }
535  if {[IsVivado]} {
536  set_property -name {xsim.elaborate.load_glbl} -value {true} -objects [get_filesets $simset]
537  }
538  # Setting Simulation Properties
539  set sim_dict [DictGet $simsets_dict $simset]
540  set sim_props [DictGet $sim_dict "properties"]
541 
542  if {$sim_props != ""} {
543  Msg Info "Setting properties for simulation set: $simset..."
544  dict for {prop_name prop_val} $sim_props {
545  set prop_name [string toupper $prop_name]
546  if {$prop_name == "ACTIVE" && $prop_val == 1} {
547  Msg Info "Setting $simset as active simulation set..."
548  current_fileset -simset [get_filesets $simset]
549  } else {
550  Msg Debug "Setting $prop_name = $prop_val"
551  if {[IsInList [string toupper $prop_name] [VIVADO_PATH_PROPERTIES] 1]} {
552  # Check that the file exists before setting these properties
553  if {[file exists $globalSettings::repo_path/$prop_val]} {
554  set_property -name $prop_name -value $globalSettings::repo_path/$prop_val -objects [get_filesets $simset]
555  } else {
556  Msg Warning "Impossible to set property $prop_name to $prop_val. File is missing"
557  }
558  } else {
559  set_property -name $prop_name -value $prop_val -objects [get_filesets $simset]
560  }
561  }
562  }
563  }
564  }
565  }
566 }
567 
568 ## @brief uses the content of globalSettings::PROPERTIES to set additional project properties
569 #
570 proc ConfigureProperties {} {
571  set cur_dir [pwd]
572  cd $globalSettings::repo_path
573  if {[IsXilinx]} {
574  set user_repo "0"
575  # Setting Main Properties
576  if {[info exists globalSettings::PROPERTIES]} {
577  if {[dict exists $globalSettings::PROPERTIES main]} {
578  Msg Info "Setting project-wide properties..."
579  set proj_props [dict get $globalSettings::PROPERTIES main]
580  dict for {prop_name prop_val} $proj_props {
581  if {[string tolower $prop_name] != "ip_repo_paths"} {
582  if {[string tolower $prop_name] != "part"} {
583  # Part is already set
584  Msg Debug "Setting $prop_name = $prop_val"
585  set_property -name $prop_name -value $prop_val -objects [current_project]
586  }
587  } else {
588  set ip_repo_list [regsub -all {\s+} $prop_val " $globalSettings::repo_path/"]
589  set ip_repo_list $globalSettings::repo_path/$ip_repo_list
590  set user_repo "1"
591  Msg Info "Setting $ip_repo_list as user IP repository..."
592  if {[IsISE]} {
593  set_property ip_repo_paths "$ip_repo_list" [current_fileset]
594  } else {
595  set_property ip_repo_paths "$ip_repo_list" [current_project]
596  }
597  update_ip_catalog
598  }
599  }
600  }
601  # Setting Run Properties
602  foreach run [get_runs -quiet] {
603  if {[dict exists $globalSettings::PROPERTIES $run]} {
604  Msg Info "Setting properties for run: $run..."
605  set run_props [dict get $globalSettings::PROPERTIES $run]
606  #set_property -dict $run_props $run
607  set stragety_str "STRATEGY strategy Strategy"
608  Msg Debug "Setting Strategy and Flow for run $run (if specified in hog.conf)"
609  foreach s $stragety_str {
610  if {[dict exists $run_props $s]} {
611  set prop [dict get $run_props $s]
612  set_property -name $s -value $prop -objects $run
613  set run_props [dict remove $run_props $s]
614  Msg Warning "A strategy for run $run has been defined inside hog.conf. This prevents Hog to compare the project properties. \
615  Please regenerate your hog.conf file using the dedicated Hog button."
616  Msg Info "Setting $s = $prop"
617  }
618  }
619 
620  dict for {prop_name prop_val} $run_props {
621  Msg Debug "Setting $prop_name = $prop_val"
622  if {[string trim $prop_val] == ""} {
623  Msg Warning "Property $prop_name has empty value. Skipping..."
624  continue
625  }
626  if {[IsInList [string toupper $prop_name] [VIVADO_PATH_PROPERTIES] 1]} {
627  # Check that the file exists before setting these properties
628  set utility_file $globalSettings::repo_path/$prop_val
629  if {[file exists $utility_file]} {
630  lassign [GetHogFiles -ext_path $globalSettings::HOG_EXTERNAL_PATH $globalSettings::list_path $globalSettings::repo_path] lib prop dummy
631  foreach {l f} $lib {
632  foreach ff $f {
633  lappend hog_files $ff
634  }
635  }
636  if {[lsearch $hog_files $utility_file] < 0} {
637  Msg CriticalWarning "The file: $utility_file is set as a property in hog.conf, \
638  but is not added to the project in any list file. Hog cannot track it."
639  } else {
640  #Add file tu utils_1 to avoid warning
641  AddFile $globalSettings::repo_path/$prop_val [get_filesets -quiet utils_1]
642  }
643  set_property -name $prop_name -value $utility_file -objects $run
644  } else {
645  Msg Warning "Impossible to set property $prop_name to $prop_val. File is missing"
646  }
647  } else {
648  set_property -name $prop_name -value $prop_val -objects $run
649  }
650  }
651  }
652  }
653  }
654  } elseif {[IsQuartus]} {
655  #QUARTUS only
656  #TO BE DONE
657  } elseif {[IsLibero]} {
658  # Setting Properties
659  if {[info exists globalSettings::PROPERTIES]} {
660  # Device Properties
661  if {[dict exists $globalSettings::PROPERTIES main]} {
662  Msg Info "Setting device properties..."
663  set dev_props [dict get $globalSettings::PROPERTIES main]
664  dict for {prop_name prop_val} $dev_props {
665  if {!([string toupper $prop_name] in $globalSettings::LIBERO_MANDATORY_VARIABLES)} {
666  Msg Debug "Setting $prop_name = $prop_val"
667  set_device -[string tolower $prop_name] $prop_val
668  }
669  }
670  }
671  # Project Properties
672  if {[dict exists $globalSettings::PROPERTIES project]} {
673  Msg Info "Setting project-wide properties..."
674  set dev_props [dict get $globalSettings::PROPERTIES project]
675  dict for {prop_name prop_val} $dev_props {
676  Msg Debug "Setting $prop_name = $prop_val"
677  project_settings -[string tolower $prop_name] $prop_val
678  }
679  }
680  # Synthesis Properties
681  if {[dict exists $globalSettings::PROPERTIES synth]} {
682  Msg Info "Setting Synthesis properties..."
683  set synth_props [dict get $globalSettings::PROPERTIES synth]
684  dict for {prop_name prop_val} $synth_props {
685  Msg Debug "Setting $prop_name = $prop_val"
686  configure_tool -name {SYNTHESIZE} -params "[string toupper $prop_name]:$prop_val"
687  }
688  }
689  # Implementation Properties
690  if {[dict exists $globalSettings::PROPERTIES impl]} {
691  Msg Info "Setting Implementation properties..."
692  set impl_props [dict get $globalSettings::PROPERTIES impl]
693  dict for {prop_name prop_val} $impl_props {
694  Msg Debug "Setting $prop_name = $prop_val"
695  configure_tool -name {PLACEROUTE} -params "[string toupper $prop_name]:$prop_val"
696  }
697  }
698 
699  # Bitstream Properties
700  if {[dict exists $globalSettings::PROPERTIES bitstream]} {
701  Msg Info "Setting Bitstream properties..."
702  set impl_props [dict get $globalSettings::PROPERTIES impl]
703  dict for {prop_name prop_val} $impl_props {
704  Msg Debug "Setting $prop_name = $prop_val"
705  configure_tool -name {GENERATEPROGRAMMINGFILE} -params "[string toupper $prop_name]:$prop_val"
706  }
707  }
708  # Configure VERIFYTIMING tool to generate a txt file report
709  configure_tool -name {VERIFYTIMING} -params {FORMAT:TEXT}
710  }
711  } elseif {[IsDiamond]} {
712  if {[info exists globalSettings::PROPERTIES]} {
713  # Project (main) Properties
714  if {[dict exists $globalSettings::PROPERTIES main]} {
715  Msg Info "Setting project-wide properties..."
716  set dev_props [dict get $globalSettings::PROPERTIES main]
717  dict for {prop_name prop_val} $dev_props {
718  # Device is already set
719  if {[string toupper $prop_name] != "DEVICE"} {
720  Msg Debug "Setting $prop_name = $prop_val"
721  prj_project option $prop_name $prop_val
722  }
723  }
724  }
725  # Implementation properties
726  if {[dict exists $globalSettings::PROPERTIES impl]} {
727  Msg Info "Setting Implementation properties..."
728  set dev_props [dict get $globalSettings::PROPERTIES impl]
729  dict for {prop_name prop_val} $dev_props {
730  # Device is already set
731  Msg Debug "Setting $prop_name = $prop_val"
732  prj_impl option $prop_name $prop_val
733  }
734  }
735  }
736  } else {
737  Msg info "Configuring Properties"
738  }
739  cd $cur_dir
740 }
741 
742 
743 proc ConfigurePlatforms {{xsa ""}} {
744  dict for {key value} [dict filter $globalSettings::PROPERTIES key {platform:*}] {
745  set value_lower [dict create]
746  dict for {vkey vvalue} $value {
747  dict set value_lower [string tolower $vkey] $vvalue
748  }
749  dict set platforms $key $value_lower
750  }
751 
752  set platforms2 [GetPlatformsFromProps $globalSettings::PROPERTIES 0 1]
753  Msg Info "Platform Names: [GetPlatformsFromProps $globalSettings::PROPERTIES 1 1]"
754 
755  dict for {key value} $platforms2 {
756  Msg Info "Key: $key, Value: $value"
757  }
758 
759  if {[dict size $platforms] == 0} {
760  Msg Info "No platforms found in the configuration file"
761  return
762  }
763 
764  dict for {platform_key platform_config} $platforms {
765  Msg Info "Found platform with key: $platform_key with configuration: $platform_config"
766  if {[regexp {^platform:(.+)$} $platform_key -> platform_name]} {
767  set platform_name [string trim $platform_name]
768  Msg Info "Configuring platform: $platform_name"
769  CreatePlatform $platform_name $platform_config $xsa
770  } else {
771  Msg Warning "Invalid platform key format: $platform_key. Expected format: platform:<name>"
772  }
773  }
774 }
775 
776 proc CreatePlatform {platform_name platform_conf {xsa ""}} {
777 
778  set platform_create_options {
779  "desc" "hw" "out" "prebuilt" "proc" "arch"
780  "samples" "os" "xpfm" "no-boot-bsp"
781  }
782 
783  # XSCT/Vitis Classic switches that do not take a value
784  set platform_create_flags {
785  "no-boot-bsp" "prebuilt"
786  }
787 
788  Msg Info "Creating platform configuration..."
789  append platform_options " -name $platform_name"
790 
791  # Remove existing platform if it exists
792  if {[catch {set ws_platforms [platform list -dict]}]} { set ws_platforms "" }
793  if {[lsearch -exact $ws_platforms $platform_name] != -1} {
794  Msg Info "Platform $platform_name already exists, removing it..."
795  platform remove $platform_name
796  }
797 
798  dict for {p v} $platform_conf {
799  if {[IsInList [string toupper $p] [VITIS_PATH_PROPERTIES] 1]} {
800 
801  if {[IsRelativePath $v] == 1} {
802  set v "$globalSettings::repo_path/$v"
803  }
804 
805  if {[file exists $v]} {
806  if {$p == "hw"} {
807  set xsa $v
808  }
809  } else {
810  Msg Warning "Impossible to set property $p to $v. File is missing"
811  continue;
812  }
813  }
814 
815  set p_lower [string tolower $p]
816  if {[IsInList $p_lower $platform_create_options]} {
817  if {[IsVitisClassic] && [IsInList $p_lower $platform_create_flags]} {
818  if {[string is true -strict $v]} {
819  append platform_options " -$p_lower"
820  }
821  } else {
822  append platform_options " -$p_lower $v"
823  }
824  } else {
825  if {$p_lower ne "bif"} {
826  Msg Warning "Attempting to use unknown platform option: $p_lower"
827  append platform_options " -$p_lower $v"
828  }
829  }
830  }
831 
832 
833  # If hw is not in platform conf, use vivado presynth xsa
834  if {$xsa != ""} {
835  if {[IsRelativePath $xsa] == 1} {
836  set xsa [file normalize "$globalSettings::repo_path/$xsa"]
837  } else {
838  set xsa [file normalize $xsa]
839  }
840  set platform_options "$platform_options -hw $xsa"
841  } elseif {![dict exists $platform_conf hw]} {
842  set xsa [file normalize "$globalSettings::build_dir/$globalSettings::DESIGN-presynth.xsa"]
843  set platform_options "$platform_options -hw $xsa"
844  } else {
845  set platform_options "$platform_options"
846  }
847 
848 
849  if {[IsVitisClassic]} {
850  Msg Info "Opening hardware design to check if proc to cell mapping needs to be extracted for soft processors..."
851  # Use HSI commands for Vitis Classic
852  hsi::open_hw_design $xsa
853  set proc_cells [hsi::get_cells -filter { IP_TYPE == "PROCESSOR" }]
854  set proc_map_path [file normalize "$globalSettings::build_dir/vitis_classic/$platform_name.PROC_MAP"]
855  set proc_map_file [open $proc_map_path "w"]
856 
857  foreach proc $proc_cells {
858  # If soft processor, save mapping from proc to cell to be used later when updating mem
859  Msg Debug "Processor found in xsa: $proc"
860  if {[regexp -nocase {microblaze|risc} $proc]} {
861  Msg Info "Extracting processor cells for soft processor: $proc"
862  set proc_hier_name [hsi::get_property HIER_NAME $proc]
863  set proc_address_tag [hsi::get_property ADDRESS_TAG $proc]
864 
865  # updatemem -proc needs the instance path from the MMI (usually HIER_NAME).
866  # ADDRESS_TAG is preferred when present (may be "tag:path"), otherwise fall back
867  set proc_updatemem_path $proc_hier_name
868  if {$proc_address_tag ne ""} {
869  if {[string match "*:*" $proc_address_tag]} {
870  set proc_updatemem_path [lindex [split $proc_address_tag ":"] end]
871  } else {
872  set proc_updatemem_path $proc_address_tag
873  }
874  } else {
875  Msg Warning "Processor $proc ($proc_hier_name) does not have an ADDRESS_TAG property set. Using HIER_NAME for updatemem."
876  }
877  if {$proc_updatemem_path eq ""} {
878  set proc_updatemem_path $proc
879  }
880 
881  # Index by HSI cell name (matches hog.conf proc=) and by hierarchy name
882  puts $proc_map_file "$proc $proc_updatemem_path"
883  if {$proc_hier_name ne "" && $proc_hier_name ne $proc} {
884  puts $proc_map_file "$proc_hier_name $proc_updatemem_path"
885  }
886  }
887  }
888 
889  hsi::close_hw_design [hsi::current_hw_design]
890  close $proc_map_file
891  Msg Info "Wrote soft-processor map to $proc_map_path"
892  }
893 
894 
895  Msg Info "Creating platform \[$platform_name\] with options: \{$platform_options\}"
896  if {[IsVitisClassic]} {
897  set plat_create "platform create $platform_options"
898  eval $plat_create
899  platform active $platform_name
900  platform generate
901  } elseif {[IsVitisUnified]} {
902  # Use Python script to create the platform with new Vitis Unified Python command-line tool
903  set python_script "$globalSettings::repo_path/Hog/Other/Python/VitisUnified/PlatformCommands.py"
904  Msg Info "Running Vitis Unified platform creation script..."
905  # The options contain spaces: pass them in the environment, as a command line
906  # argument they would be split by the Windows shell that runs vitis.bat
907  set ::env(HOG_VITIS_PLATFORM_OPTIONS) "{ $platform_options }"
908  set error_msg "Failed to create platform $platform_name"
909  if {![ExecuteVitisUnifiedCommand $python_script "create_platform" \
910  [list "$globalSettings::build_dir/vitis_unified"] \
911  $error_msg]} {
912  return
913  }
914  }
915 }
916 
917 
918 proc ConfigureApps {} {
919  set apps [dict filter $globalSettings::PROPERTIES key {app:*}]
920 
921  if {[dict size $apps] == 0} {
922  Msg Info "No apps found in the configuration file"
923  return
924  }
925 
926  dict for {app_key app_config} $apps {
927  Msg Info "Found app with key: $app_key with configuration: $app_config"
928  if {[regexp {^app:(.+)$} $app_key -> app_name]} {
929  set app_name [string trim $app_name]
930  Msg Info "Configuring app: $app_name"
931  if {[IsVitisClassic]} {
932  ConfigureApp $app_name $app_config
933  } elseif {[IsVitisUnified]} {
934  set python_script "$globalSettings::repo_path/Hog/Other/Python/VitisUnified/AppCommands.py"
935  Msg Info "Running Vitis Unified app configuration script..."
936  # Build app config string from app_config dict
937  set app_config_str "{"
938  dict for {p v} $app_config {
939  append app_config_str " -[string toupper $p] \{$v\}"
940  }
941  append app_config_str " }"
942  # The options contain spaces: pass them in the environment, as a command line
943  # argument they would be split by the Windows shell that runs vitis.bat
944  set ::env(HOG_VITIS_APP_OPTIONS) $app_config_str
945  set error_msg "Failed to configure app $app_name"
946  if {![ExecuteVitisUnifiedCommand $python_script "configure_app" \
947  [list $app_name "$globalSettings::build_dir/vitis_unified"] \
948  $error_msg]} {
949  continue
950  }
951  }
952  } else {
953  Msg Warning "Invalid app key format: $app_key. Expected format: app:<name>"
954  }
955  }
956 }
957 
958 proc ConfigureApp {app_name app_conf} {
959 
960  set create_options {
961  "platform" "domain" "sysproj" "hw"
962  "proc" "template" "os" "lang" "arch" "name"
963  }
964 
965  set conf_options {
966  "assembler-flags" "build-config" "compiler-misc" "compiler-optimization"
967  "define-compiler-symbols" "include-path" "libraries" "library-search-path"
968  "linker-misc" "linker-script" "undef-compiler-symbols"
969  }
970 
971  Msg Info "Configuring app..."
972  append app_options " -name $app_name"
973 
974  # A sysproj may have been created before, we must remove it
975  if {[catch {set sys_projs [sysproj list -dict]}]} { set sys_projs "" }
976  if {[dict exists $app_name sysproj]} {
977  set sys_proj_name [dict get $app_name sysproj]
978  if {[lsearch -exact $sys_projs "Name $sys_proj_name"] != -1} {
979  Msg Info "Removing $sys_proj_name..."
980  sysproj remove $sys_proj_name
981  }
982  } else {
983  set sys_proj_name "$app_name\_system"
984  if {[lsearch -exact $sys_projs "Name $sys_proj_name"] != -1} {
985  Msg Info "Removing $sys_proj_name..."
986  sysproj remove $sys_proj_name
987  }
988  }
989 
990  # An app may have been created before, we must remove it
991  if {[catch {set ws_apps [app list -dict]}]} { set ws_apps "" }
992  if {[lsearch -exact $ws_apps $app_name] != -1} {
993  Msg Info "app $app_name already exists, removing it..."
994  app remove $app_name
995  }
996 
997  set app_create_options [dict create]
998  set app_conf_options [dict create]
999 
1000 
1001  dict for {p v} $app_conf {
1002  set p_lower [string tolower $p]
1003 
1004  if {[IsInList [string toupper $p] [VITIS_PATH_PROPERTIES] 1]} {
1005  if {[IsRelativePath $v] == 1} {
1006  set v "$globalSettings::repo_path/$v"
1007  #"
1008  }
1009  if {![file exists $v]} {
1010  Msg Warning "Impossible to set property $p to $v. File is missing"
1011  continue
1012  }
1013  }
1014 
1015  if {[IsInList $p_lower $create_options]} {
1016  Msg Info "$p_lower is in create options"
1017  dict append app_create_options $p_lower $v
1018  } elseif {[IsInList $p_lower $conf_options]} {
1019  Msg Info "$p_lower is in conf options"
1020  dict append app_conf_options $p_lower $v
1021  } else {
1022  Msg Warning "Unknown app option: $p_lower"
1023  }
1024  }
1025 
1026 
1027  dict for {p v} $app_create_options {
1028  if {[string equal $p "platform"]} {
1029  Msg Info "Setting App $app_name platform to $v"
1030  platform active $v
1031  }
1032  append app_options " -$p $v"
1033  }
1034 
1035  if {![dict exists $app_name template]} {
1036  if {[CompareVersions $globalSettings::c_v "2022 1 0"] == -1} {
1037  # Check if lang is defined in create_options
1038  if {[dict exists $app_create_options "lang"]} {
1039  set lang [dict get $app_create_options "lang"]
1040  if {[string equal -nocase $lang "C++"] || [string equal -nocase $lang "cpp"]} {
1041  append app_options " -template \{Empty Application (C++)\}"
1042  } else {
1043  append app_options " -template \{Empty Application(C)\}"
1044  }
1045  } else {
1046  # Default to Empty Application if lang is not specified
1047  append app_options " -template \{Empty Application(C)\}"
1048  }
1049  } else {
1050  # For newer versions, use the generic template
1051  append app_options " -template \{Empty Application\}"
1052  }
1053  }
1054 
1055  Msg Info "Creating application \[$app_name\] with options: \{$app_options\}"
1056  set app_create "app create $app_options"
1057  eval $app_create
1058  app config -name $app_name -set build-config Release
1059 
1060  # App config options
1061  dict for {p v} $app_conf_options {
1062  Msg Info "Configuring app option $p to $v"
1063  app config -name $app_name -set $p $v
1064  }
1065 }
1066 
1067 
1068 proc AddAppFiles {} {
1069  AddHogFiles {*}[GetHogFiles -list_files {.src,.header} -ext_path $globalSettings::HOG_EXTERNAL_PATH $globalSettings::list_path $globalSettings::repo_path ]
1070 }
1071 
1072 
1073 ## @brief Configure the Vitis components (HLS, platforms and apps) of a project
1074 #
1075 # This is the work of the "-vitis_only" pass. It runs both from the standalone
1076 # "-vitis_only" entry point and, in the same interpreter, at the end of the
1077 # Vivado pass of a vivado_vitis_* project. It must not be run by spawning a
1078 # second Vivado: on Windows the nested process dies with an access violation
1079 # during Vivado start-up, before it can source any Hog script.
1080 #
1081 # @param[in] xsa_option The -xsa option, empty to derive the XSA from the Vivado project
1082 # @param[in] ide The IDE name, as written in hog.conf
1083 # @param[in] post_file The post-creation Tcl script, sourced if it exists
1084 #
1085 # @return 0 on success, 1 if no usable XSA could be found
1086 #
1087 proc ConfigureVitisComponents {xsa_option ide post_file} {
1088 
1089  if {[IsVitisUnified]} {
1090  set vitis_ws [file normalize "$globalSettings::build_dir/vitis_unified"]
1091  if {[file exists $vitis_ws]} {
1092  Msg Info "Removing existing Vitis Unified workspace $vitis_ws..."
1093  file delete -force $vitis_ws
1094  }
1095  file mkdir $vitis_ws
1096  }
1097 
1098  set has_hls [expr {[dict size [dict filter $globalSettings::PROPERTIES key {hls:*}]] > 0}]
1099  set has_platforms [expr {[dict size [dict filter $globalSettings::PROPERTIES key {platform:*}]] > 0}]
1100  set has_apps [expr {[dict size [dict filter $globalSettings::PROPERTIES key {app:*}]] > 0}]
1101 
1102  if {$has_hls} {
1103  Msg Info "Found HLS component(s) in configuration, configuring HLS..."
1105  }
1106 
1107  if {!$has_platforms && !$has_apps} {
1108  Msg Info "vitis unified HLS-only project, skipping Vivado project setup."
1109  return 0
1110  }
1111 
1112  set xsa_path $xsa_option
1113 
1114  if {$xsa_path == ""} {
1115  if {[string match "vivado_*" [string tolower $ide]]} {
1116  # vivado_vitis project: generate pre-synth XSA from existing Vivado project
1117  set xpr_file [file normalize "$globalSettings::build_dir/[file tail $globalSettings::DESIGN].xpr"]
1118  if {[file exists $xpr_file]} {
1119  Msg Info "Opening existing Vivado project to generate pre-synth XSA..."
1120  open_project $xpr_file
1121  set xsa_path [file normalize "$globalSettings::build_dir/$globalSettings::DESIGN-presynth.xsa"]
1123  write_hw_platform -fixed -force -file $xsa_path
1124  Msg Info "Pre-synth XSA generated: $xsa_path"
1125  close_project
1126  } else {
1127  # tclint-disable-next-line line-length
1128  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."
1129  return 1
1130  }
1131  } else {
1132  # Standalone vitis project: XSA is mandatory for platform/app
1133  Msg Error "This is a $ide only project with platform/app sections, an XSA file must be provided via the -xsa option."
1134  return 1
1135  }
1136  } elseif {[IsRelativePath $xsa_path] == 1} {
1137  # Relative -xsa is repo-relative; do not resolve against Hog/Tcl (cwd)
1138  set xsa_path [file normalize "$globalSettings::repo_path/$xsa_path"]
1139  } else {
1140  set xsa_path [file normalize $xsa_path]
1141  }
1142 
1143  Msg Info "Configuring platforms with XSA: $xsa_path"
1144  ConfigurePlatforms "$xsa_path"
1146  AddAppFiles
1147 
1148  if {[file exists $post_file]} {
1149  if {[string match "vivado_*" [string tolower $ide]]} {
1150  Msg Info "Skipping post-creation.tcl in -vitis_only pass for $ide \
1151  (already executed during Vivado project creation)."
1152  } else {
1153  Msg Info "Found post-creation Tcl script $post_file, executing it..."
1154  source $post_file
1155  }
1156  }
1157 
1158  return 0
1159 }
1160 
1161 ## @brief Configure HLS components defined in hog.conf [hls:*] sections
1162 #
1163 # For each [hls:<component_name>] section, this proc:
1164 # 1. Reads the HLS_CONFIG path from hog.conf (mandatory, repo-relative)
1165 # 2. Validates that the hls_config.cfg file exists and is well-formed
1166 # 3. Creates a Vitis-compatible workspace so the project can be opened in the GUI
1167 #
1168 # The hls_config.cfg is the single source of truth for HLS settings.
1169 # It is committed to the repo and directly used/edited by Vitis.
1170 #
1171 proc ConfigureHlsComponents {} {
1172  set hls_components [dict filter $globalSettings::PROPERTIES key {hls:*}]
1173 
1174  if {[dict size $hls_components] == 0} {
1175  Msg Info "No HLS components found in the configuration file"
1176  return
1177  }
1178 
1179  set python_script "$globalSettings::repo_path/Hog/Other/Python/VitisUnified/HlsCommands.py"
1180  set ws_dir [file normalize "$globalSettings::build_dir/vitis_unified"]
1181 
1182  dict for {hls_key hls_config} $hls_components {
1183  if {[regexp {^hls:(.+)$} $hls_key -> component_name]} {
1184  set component_name [string trim $component_name]
1185  Msg Info "Configuring HLS component: $component_name"
1186 
1187  # Get HLS_CONFIG path from hog.conf (mandatory)
1188  set hls_cfg_rel ""
1189  if {[dict exists $hls_config hls_config]} {
1190  set hls_cfg_rel [dict get $hls_config hls_config]
1191  } elseif {[dict exists $hls_config HLS_CONFIG]} {
1192  set hls_cfg_rel [dict get $hls_config HLS_CONFIG]
1193  }
1194  if {$hls_cfg_rel eq ""} {
1195  Msg Error "HLS component '$component_name' missing HLS_CONFIG in hog.conf \[hls:$component_name\] section"
1196  continue
1197  }
1198 
1199  set hls_cfg_file [file normalize "$globalSettings::repo_path/$hls_cfg_rel"]
1200  if {![file exists $hls_cfg_file]} {
1201  Msg Error "HLS config file not found: $hls_cfg_file (from HLS_CONFIG=$hls_cfg_rel)"
1202  continue
1203  }
1204 
1205  Msg Info " HLS config: $hls_cfg_file"
1206 
1207  # Validate the config file
1208  set error_msg "Failed to validate HLS config for $component_name"
1209  if {![ExecuteVitisUnifiedCommand $python_script "validate" \
1210  [list $hls_cfg_file] \
1211  $error_msg]} {
1212  Msg Error $error_msg
1213  continue
1214  }
1215 
1216  # Create Vitis workspace with HLS component for GUI compatibility
1217  set hls_work_dir [file normalize "$ws_dir/hls_$component_name"]
1218  Msg Info "Creating Vitis HLS workspace component '$component_name' in $ws_dir ..."
1219  if {![ExecuteVitisUnifiedCommand $python_script "create_workspace" \
1220  [list $ws_dir $component_name $hls_cfg_file $hls_work_dir] \
1221  "Failed to create HLS workspace for $component_name"]} {
1222  Msg Warning "Could not create Vitis workspace for HLS component '$component_name'"
1223  }
1224 
1225  Msg Info "HLS component '$component_name' configured successfully"
1226  } else {
1227  Msg Warning "Invalid HLS key format: $hls_key. Expected format: hls:<name>"
1228  }
1229  }
1230 }
1231 
1232 ## @brief upgrade IPs in the project and copy them from HOG_IP_PATH if defined
1233 #
1234 proc ManageIPs {} {
1235  # set the current impl run
1236  current_run -implementation [get_runs impl_1]
1237 
1238  ##############
1239  # UPGRADE IP #
1240  ##############
1241  set ips [get_ips *]
1242 
1243  Msg Info "Running report_ip_status, before upgrading and handling IPs..."
1244  report_ip_status
1245  # Pull ips from repo
1246  if {$globalSettings::HOG_IP_PATH != ""} {
1247  set ip_repo_path $globalSettings::HOG_IP_PATH
1248  Msg Info "HOG_IP_PATH is set, will pull/push synthesised IPs from/to $ip_repo_path."
1249 
1250  lassign [CheckRemoteIpPath $globalSettings::repo_path $ip_repo_path] system_ready on_eos on_rclone rclone_config_path
1251  if {$system_ready == 1} {
1252  foreach ip $ips {
1253  HandleIP pull [get_property IP_FILE $ip] $ip_repo_path $globalSettings::repo_path [get_property IP_OUTPUT_DIR $ip]\
1254  $on_eos $on_rclone $rclone_config_path
1255  }
1256  }
1257  } else {
1258  Msg Info "HOG_IP_PATH not set, will not push/pull synthesised IPs."
1259  }
1260 }
1261 
1262 proc SetGlobalVar {var {default_value HOG_NONE}} {
1263  ##nagelfar ignore
1264  if {[info exists ::$var]} {
1265  Msg Debug "Setting $var to [subst $[subst ::$var]]"
1266  ##nagelfar ignore
1267  set globalSettings::$var [subst $[subst ::$var]]
1268  } elseif {$default_value == "HOG_NONE"} {
1269  Msg Error "Mandatory variable $var was not defined. Please define it in hog.conf or in project tcl script."
1270  } else {
1271  Msg Info "Setting $var to default value: \"$default_value\""
1272  ##nagelfar ignore
1273  set globalSettings::$var $default_value
1274  }
1275 }
1276 
1277 ################################################################################################################################################################
1278 
1279 proc CreateProject {args} {
1280  global env
1281  # set tcl_path [file normalize "[file dirname [info script]]"]
1282  # set repo_path [file normalize $tcl_path/../..]
1283 
1284  if {[catch {package require cmdline} ERROR]} {
1285  puts "ERROR: If you are running this script on tclsh, you can fix this by installing 'tcllib'"
1286  return
1287  }
1288  set parameters {
1289  {simlib_path.arg "" "Path of simulation libs"}
1290  {verbose "If set, launch the script in verbose mode."}
1291  {xsa.arg "" "xsa for creating platforms without a defined hw."}
1292  {vivado_only "If set, and project is vivado-vitis, vitis project will not be created."}
1293  {vitis_only "If set, and project is vivado-vitis, only vitis project will be created."}
1294  }
1295 
1296  set usage "Create Vivado/Vitis/ISE/Quartus/Libero/Diamond project.\nUsage: CreateProject \[OPTIONS\] <project> <repository path>\n Options:"
1297 
1298  if {[catch {array set options [cmdline::getoptions args $parameters $usage]}] || [llength $args] < 2 || [lindex $args 0] eq ""} {
1299  Msg Info [cmdline::usage $parameters $usage]
1300  return 1
1301  }
1302 
1303  set globalSettings::DESIGN [lindex $args 0]
1304  if {[file exists [lindex $args 1]]} {
1305  set globalSettings::repo_path [file normalize [lindex $args 1]]
1306  } else {
1307  Msg Error "The second argument, [lindex $args 1], should be the repository path."
1308  }
1309  set globalSettings::tcl_path $globalSettings::repo_path/Hog/Tcl
1310 
1311 
1312  if {$options(verbose) == 1} {
1313  variable ::DEBUG_MODE 1
1314  }
1315 
1316  if {[IsVivado]} {
1317  if {$options(simlib_path) != ""} {
1318  if {[IsRelativePath $options(simlib_path)] == 0} {
1319  set globalSettings::simlib_path "$options(simlib_path)"
1320  } else {
1321  set globalSettings::simlib_path "${globalSettings::repo_path}/$options(simlib_path)"
1322  }
1323  Msg Info "Simulation library path set to $options(simlib_path)"
1324  } else {
1325  set globalSettings::simlib_path "${globalSettings::repo_path}/SimulationLib"
1326  Msg Info "Simulation library path set to default ${globalSettings::repo_path}/SimulationLib"
1327  }
1328  }
1329 
1330  # Derived variables from now on...
1331 
1332  set build_dir_name "Projects"
1333  set globalSettings::group_name [file dirname ${globalSettings::DESIGN}]
1334  set globalSettings::project_name ${globalSettings::DESIGN}
1335  set globalSettings::pre_synth_file "pre-synthesis.tcl"
1336  set globalSettings::post_synth_file "post-synthesis.tcl"
1337  set globalSettings::pre_impl_file "pre-implementation.tcl"
1338  set globalSettings::post_impl_file "post-implementation.tcl"
1339  set globalSettings::pre_bit_file "pre-bitstream.tcl"
1340  set globalSettings::post_bit_file "post-bitstream.tcl"
1341  set globalSettings::quartus_post_module_file "quartus-post-module.tcl"
1342  set globalSettings::top_path "${globalSettings::repo_path}/Top/${globalSettings::DESIGN}"
1343  set globalSettings::list_path "${globalSettings::top_path}/list"
1344  set globalSettings::build_dir "${globalSettings::repo_path}/${build_dir_name}/${globalSettings::DESIGN}"
1345  set globalSettings::DESIGN [file tail ${globalSettings::DESIGN}]
1346  set globalSettings::top_name [file tail ${globalSettings::DESIGN}]
1347  set globalSettings::top_name [file rootname ${globalSettings::top_name}]
1348  set globalSettings::synth_top_module "top_${globalSettings::top_name}"
1349  set globalSettings::user_ip_repo ""
1350 
1351  set globalSettings::pre_synth [file normalize "${globalSettings::tcl_path}/integrated/${globalSettings::pre_synth_file}"]
1352  set globalSettings::post_synth [file normalize "${globalSettings::tcl_path}/integrated/${globalSettings::post_synth_file}"]
1353  set globalSettings::pre_impl [file normalize "${globalSettings::tcl_path}/integrated/${globalSettings::pre_impl_file}"]
1354  set globalSettings::post_impl [file normalize "${globalSettings::tcl_path}/integrated/${globalSettings::post_impl_file}"]
1355  set globalSettings::pre_bit [file normalize "${globalSettings::tcl_path}/integrated/${globalSettings::pre_bit_file}"]
1356  set globalSettings::post_bit [file normalize "${globalSettings::tcl_path}/integrated/${globalSettings::post_bit_file}"]
1357  set globalSettings::quartus_post_module [file normalize "${globalSettings::tcl_path}/integrated/${globalSettings::quartus_post_module_file}"]
1358  set globalSettings::LIBERO_MANDATORY_VARIABLES {"FAMILY" "PACKAGE" "DIE" }
1359 
1360  set proj_dir [file normalize "${globalSettings::repo_path}/Top/${globalSettings::project_name}"]
1361  Msg Debug "Calling GetConfFiles with proj_dir=$proj_dir (project_name=${globalSettings::project_name})"
1362  lassign [GetConfFiles $proj_dir] conf_file sim_file pre_file post_file pre_rtl_file
1363 
1364  set user_repo 0
1365  if {[file exists $conf_file]} {
1366  Msg Info "Parsing configuration file $conf_file..."
1367  SetGlobalVar PROPERTIES [ReadConf $conf_file]
1368 
1369  # Checking Vivado/Vitis/Quartus/ISE/Libero version
1370  set actual_version [GetIDEVersion]
1371  lassign [GetIDEFromConf $conf_file] ide conf_version
1372 
1373  if {$conf_version != "0.0.0"} {
1374  set globalSettings::a_v [split $actual_version "."]
1375  set globalSettings::c_v [split $conf_version "."]
1376 
1377  if {[llength $globalSettings::a_v] < 2} {
1378  Msg Error "Couldn't parse IDE version: $actual_version."
1379  } elseif {[llength $globalSettings::a_v] == 2} {
1380  lappend globalSettings::a_v 0
1381  }
1382  if {[llength $globalSettings::c_v] < 2} {
1383  Msg Error "Wrong version format in hog.conf: $conf_version."
1384  } elseif {[llength $globalSettings::c_v] == 2} {
1385  lappend globalSettings::c_v 0
1386  }
1387 
1388  set comp [CompareVersions $globalSettings::a_v $globalSettings::c_v]
1389  if {$comp == 0} {
1390  Msg Info "Project version and $ide version match: $conf_version."
1391  } elseif {$comp == 1} {
1392  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\
1393  If you want update this project to version $actual_version, please update the configuration file."
1394  } else {
1395  # tclint-disable-next-line line-length
1396  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."
1397  }
1398  } else {
1399  Msg CriticalWarning "No version found in the first line of $conf_file. \
1400  It is HIGHLY recommended to replace the first line of $conf_file with: \#$ide $actual_version"
1401  }
1402 
1403  if {$globalSettings::vitis_classic == 1} {
1404  if {[CompareVersions $globalSettings::a_v "2020 2 0"] == -1 || [CompareVersions $globalSettings::c_v "2020 2 0"] == -1} {
1405  Msg Error "Vitis Classic flow is not supported for versions < 2020.2. Please use Vitis 2020.2 or newer." }
1406  }
1407  if {$globalSettings::vitis_unified == 1} {
1408  if {[CompareVersions $globalSettings::a_v "2019 2 0"] == -1 || [CompareVersions $globalSettings::c_v "2019 2 0"] == -1} {
1409  Msg Error "Vitis Unified flow is not supported for versions < 2019.2. Please use Vitis 2019.2 or newer." }
1410  }
1411 
1412  if {[dict exists $globalSettings::PROPERTIES main]} {
1413  set main [dict get $globalSettings::PROPERTIES main]
1414  dict for {p v} $main {
1415  # notice the dollar in front of p: creates new variables and fill them with the value
1416  Msg Info "Main property $p set to $v"
1417  ##nagelfar ignore
1418  set ::$p $v
1419  }
1420  } else {
1421  Msg Error "No main section found in $conf_file, make sure it has a section called \[main\] containing the mandatory properties."
1422  }
1423  } else {
1424  Msg Error "$conf_file was not found in your project directory, please create one."
1425  }
1426 
1427 
1428  if {[IsXilinx] || [IsQuartus]} {
1429  SetGlobalVar PART
1430  }
1431  #Family is needed in quartus and libero only
1432  if {[IsQuartus] || [IsLibero]} {
1433  #Quartus only
1434  SetGlobalVar FAMILY
1435  if {[IsLibero]} {
1436  SetGlobalVar DIE
1437  SetGlobalVar PACKAGE
1438  }
1439  }
1440 
1441  if {[IsDiamond]} {
1442  SetGlobalVar DEVICE
1443  SetGlobalVar SYNTHESIS_TOOL "lse"
1444  }
1445 
1446  if {[IsVivado]} {
1447  SetGlobalVar TARGET_SIMULATOR "XSim"
1448  }
1449 
1450  if {[info exists env(HOG_EXTERNAL_PATH)]} {
1451  set globalSettings::HOG_EXTERNAL_PATH $env(HOG_EXTERNAL_PATH)
1452  } else {
1453  set globalSettings::HOG_EXTERNAL_PATH ""
1454  }
1455 
1456  set user_hog_file "${globalSettings::repo_path}/Top/hog.tcl"
1457  if {[file exists $user_hog_file]} {
1458  Msg Info "Sourcing user hog.tcl file..."
1459  source $user_hog_file
1460  }
1461 
1462  if {[file exists $pre_file]} {
1463  Msg Info "Found pre-creation Tcl script $pre_file, executing it..."
1464  source $pre_file
1465  }
1466 
1467  if {[info exists env(HOG_IP_PATH)]} {
1468  set globalSettings::HOG_IP_PATH $env(HOG_IP_PATH)
1469  } else {
1470  set globalSettings::HOG_IP_PATH ""
1471  }
1472 
1473  InitProject $options(vitis_only)
1474 
1475  if {([IsVitisClassic] || [IsVitisUnified]) && $options(vitis_only) == 1} {
1476  if {[ConfigureVitisComponents $options(xsa) $ide $post_file] != 0} {
1477  return 1
1478  }
1479  return
1480  }
1481 
1482  # If the project is a vitis-only project, skip creating the Vivado project
1483  if {([string tolower $ide] eq "vitis_classic" || [string tolower $ide] eq "vitis_unified") && $options(vitis_only) == 1} {
1484  if {$options(xsa) == ""} {
1485  Msg Error "This is a $ide only project, an XSA file must be provided via -xsa option."
1486  return 1
1487  }
1488  return
1489  }
1490 
1495 
1496 
1497  if {[IsVivado]} {
1498  # Use HandleIP to pull IPs from HOG_IP_PATH if specified
1499  ManageIPs
1500  }
1501 
1502  if {[IsQuartus]} {
1503  set fileName_old [file normalize "./hogTmp/.hogQsys.md5"]
1504  set fileDir [file normalize "${globalSettings::build_dir}/.hog/"]
1505  file mkdir $fileDir
1506  set fileName_new [file normalize "$fileDir/.hogQsys.md5"]
1507  if {[file exists $fileName_new]} {
1508  file delete $fileName_new
1509  }
1510  if {[file exists $fileName_old]} {
1511  file rename -force $fileName_old $fileName_new
1512  file delete -force -- "./hogTmp"
1513  }
1514  }
1515 
1516  if {[file exists $post_file]} {
1517  Msg Info "Found post-creation Tcl script $post_file, executing it..."
1518  source $post_file
1519  if {[IsLibero]} {
1520  # Regenerate the hierarchy in case a new file has been added
1521  build_design_hierarchy
1522  }
1523  }
1524 
1525  # Check extra IPs
1526  # Get project libraries and properties from list files
1527  lassign [GetHogFiles \
1528  -ext_path "$globalSettings::HOG_EXTERNAL_PATH" \
1529  -list_files ".src,.ext" \
1530  "$globalSettings::repo_path/Top/$globalSettings::project_name/list/" \
1531  $globalSettings::repo_path] \
1532  listLibraries listProperties listSrcSets
1533  # Get project constraints and properties from list files
1534  lassign [GetHogFiles \
1535  -ext_path "$globalSettings::HOG_EXTERNAL_PATH" \
1536  -list_files ".con" \
1537  "$globalSettings::repo_path/Top/$globalSettings::project_name/list/" \
1538  $globalSettings::repo_path] \
1539  listConstraints listConProperties listConSets
1540 
1541  lassign [GetHogFiles \
1542  -ext_path "$globalSettings::HOG_EXTERNAL_PATH" \
1543  -list_files ".sim" \
1544  "$globalSettings::repo_path/Top/$globalSettings::project_name/list/" \
1545  $globalSettings::repo_path] \
1546  listSimLibraries listSimProperties listSimSets
1547 
1548  set old_path [pwd]
1549  cd $globalSettings::build_dir
1550  CheckExtraFiles $listLibraries $listConstraints $listSimLibraries
1551  cd $old_path
1552 
1553  if {[IsXilinx]} {
1554  set old_path [pwd]
1555  cd $globalSettings::repo_path
1556  set flavour [GetProjectFlavour $globalSettings::DESIGN]
1557  # Getting all the versions and SHAs of the repository
1558  lassign [GetRepoVersions \
1559  [file normalize $globalSettings::repo_path/Top/$globalSettings::project_name] \
1560  $globalSettings::repo_path \
1561  $globalSettings::HOG_EXTERNAL_PATH \
1562  ] commit version hog_hash hog_ver top_hash top_ver libs hashes vers cons_ver cons_hash ext_names ext_hashes \
1563  xml_hash xml_ver user_ip_repos user_ip_hashes user_ip_vers
1564 
1565  set this_commit [GetSHA]
1566 
1567  if {$commit == 0} {
1568  set commit $this_commit
1569  }
1570 
1571  if {$xml_hash != ""} {
1572  set use_ipbus 1
1573  } else {
1574  set use_ipbus 0
1575  }
1576 
1577 
1578  lassign [GetDateAndTime $commit] date timee
1579  WriteGenerics "create" \
1580  $globalSettings::repo_path \
1581  $globalSettings::project_name \
1582  $date $timee $commit $version \
1583  $top_hash $top_ver $hog_hash $hog_ver \
1584  $cons_ver $cons_hash $libs $vers $hashes \
1585  $ext_names $ext_hashes $user_ip_repos $user_ip_vers \
1586  $user_ip_hashes $flavour $xml_ver $xml_hash
1587  cd $old_path
1588  }
1589 
1590  if {[IsLibero]} {
1591  save_project
1592  }
1593 
1594  if {[IsDiamond]} {
1595  prj_project save
1596  }
1597 
1598 
1599  if {($globalSettings::vitis_classic == 1 || $globalSettings::vitis_unified == 1)} {
1600  # Presynth hw platform, let's keep it in the build directory
1602  write_hw_platform -fixed -force -file [file normalize "$globalSettings::build_dir/$globalSettings::DESIGN-presynth.xsa"]
1603 
1604  if {$options(xsa) == ""} {
1605  set vitis_xsa [file normalize "$globalSettings::build_dir/$globalSettings::DESIGN-presynth.xsa"]
1606  } elseif {[IsRelativePath $options(xsa)] == 1} {
1607  set vitis_xsa [file normalize "$globalSettings::repo_path/$options(xsa)"]
1608  } else {
1609  set vitis_xsa [file normalize $options(xsa)]
1610  }
1611 
1612  if {$globalSettings::vitis_classic == 1} {
1613  # Launch xsct to build the project
1614  set xsct_cmd "xsct $globalSettings::tcl_path/launch.tcl C -xsa $vitis_xsa -vitis_only $globalSettings::project_name"
1615  Msg Info "Running Vitis Classic project creation script with command: $xsct_cmd"
1616  set ret [catch {exec -ignorestderr {*}$xsct_cmd >@ stdout} result]
1617  if {$ret != 0} {
1618  Msg Error "xsct (vitis classic) returned an error state: $result"
1619  }
1620  } elseif {$globalSettings::vitis_unified == 1} {
1621  Msg Info "Configuring Vitis Unified components..."
1622  set previous_pass 0
1623  if {[info exists globalSettings::vitis_only_pass]} {
1624  set previous_pass $globalSettings::vitis_only_pass
1625  }
1626  # Make AddHogFiles add the sources to the Vitis apps rather than to the
1627  # Vivado project, which already has them
1628  set globalSettings::vitis_only_pass 1
1629  set ret [catch {ConfigureVitisComponents $vitis_xsa $ide $post_file} result]
1630  set globalSettings::vitis_only_pass $previous_pass
1631  if {$ret != 0} {
1632  Msg Error "Failed to configure the Vitis Unified components: $result"
1633  } elseif {$result != 0} {
1634  Msg Error "Failed to configure the Vitis Unified components."
1635  }
1636  }
1637  }
1638 
1639 
1640  Msg Info "Project $globalSettings::project_name created successfully in [Relative $globalSettings::repo_path $globalSettings::build_dir]."
1641 }