Hog Hog2026.2-1
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  Msg Info "Creating platform configuration..."
784  append platform_options " -name $platform_name"
785 
786  # Remove existing platform if it exists
787  if {[catch {set ws_platforms [platform list -dict]}]} { set ws_platforms "" }
788  if {[lsearch -exact $ws_platforms $platform_name] != -1} {
789  Msg Info "Platform $platform_name already exists, removing it..."
790  platform remove $platform_name
791  }
792 
793  dict for {p v} $platform_conf {
794  if {[IsInList [string toupper $p] [VITIS_PATH_PROPERTIES] 1]} {
795 
796  if {[IsRelativePath $v] == 1} {
797  set v "$globalSettings::repo_path/$v"
798  }
799 
800  if {[file exists $v]} {
801  if {$p == "hw"} {
802  set xsa $v
803  }
804  } else {
805  Msg Warning "Impossible to set property $p to $v. File is missing"
806  continue;
807  }
808  }
809 
810  set p_lower [string tolower $p]
811  if {[IsInList $p_lower $platform_create_options]} {
812  append platform_options " -$p_lower $v"
813  } else {
814  if {$p_lower ne "bif"} {
815  Msg Warning "Attempting to use unknown platform option: $p_lower"
816  append platform_options " -$p_lower $v"
817  }
818  }
819  }
820 
821 
822  # If hw is not in platform conf, use vivado presynth xsa
823  if {$xsa != ""} {
824  set platform_options "$platform_options -hw $xsa"
825  } elseif {![dict exists $platform_conf hw]} {
826  set xsa "$globalSettings::build_dir/$globalSettings::DESIGN-presynth.xsa"
827  set platform_options "$platform_options -hw $xsa"
828  } else {
829  set platform_options "$platform_options"
830  }
831 
832 
833  if {[IsVitisClassic]} {
834  Msg Info "Opening hardware design to check if proc to cell mapping needs to be extracted for soft processors..."
835  # Use HSI commands for Vitis Classic
836  hsi::open_hw_design $xsa
837  set proc_cells [hsi::get_cells -filter { IP_TYPE == "PROCESSOR" }]
838  set proc_map_file [open "$globalSettings::build_dir/vitis_classic/$platform_name.PROC_MAP" "w"]
839 
840  foreach proc $proc_cells {
841  # If soft processor, save mapping from proc to cell to be used later when updating mem
842  Msg Debug "Processor found in xsa: $proc"
843  if {[regexp -nocase {microblaze|risc} $proc]} {
844  Msg Info "Extracting processor cells for soft processor: $proc"
845  set proc_hier_name [hsi::get_property HIER_NAME $proc]
846  set proc_address_tag [hsi::get_property ADDRESS_TAG $proc]
847 
848  if {$proc_address_tag eq ""} {
849  Msg Warning "Processor $proc ($proc_hier_name) does not have an ADDRESS_TAG property set. \
850  This may cause issues when configuring the platform."
851  } else {
852  set proc_map_entry "$proc_hier_name $proc_address_tag"
853  puts $proc_map_file "$proc_map_entry\n"
854  }
855  }
856  }
857 
858  hsi::close_hw_design [hsi::current_hw_design]
859  close $proc_map_file
860  }
861 
862 
863  Msg Info "Creating platform \[$platform_name\] with options: \{$platform_options\}"
864  if {[IsVitisClassic]} {
865  set plat_create "platform create $platform_options"
866  eval $plat_create
867  platform active $platform_name
868  platform generate
869  } elseif {[IsVitisUnified]} {
870  # Use Python script to create the platform with new Vitis Unified Python command-line tool
871  set python_script "$globalSettings::repo_path/Hog/Other/Python/VitisUnified/PlatformCommands.py"
872  Msg Info "Running Vitis Unified platform creation script..."
873  set platform_options_str "{ $platform_options }"
874  set error_msg "Failed to create platform $platform_name"
875  if {![ExecuteVitisUnifiedCommand $python_script "create_platform" \
876  [list $platform_options_str "$globalSettings::build_dir/vitis_unified"] \
877  $error_msg]} {
878  return
879  }
880  }
881 }
882 
883 
884 proc ConfigureApps {} {
885  set apps [dict filter $globalSettings::PROPERTIES key {app:*}]
886 
887  if {[dict size $apps] == 0} {
888  Msg Info "No apps found in the configuration file"
889  return
890  }
891 
892  dict for {app_key app_config} $apps {
893  Msg Info "Found app with key: $app_key with configuration: $app_config"
894  if {[regexp {^app:(.+)$} $app_key -> app_name]} {
895  set app_name [string trim $app_name]
896  Msg Info "Configuring app: $app_name"
897  if {[IsVitisClassic]} {
898  ConfigureApp $app_name $app_config
899  } elseif {[IsVitisUnified]} {
900  set python_script "$globalSettings::repo_path/Hog/Other/Python/VitisUnified/AppCommands.py"
901  Msg Info "Running Vitis Unified app configuration script..."
902  # Build app config string from app_config dict
903  set app_config_str "{"
904  dict for {p v} $app_config {
905  append app_config_str " -[string toupper $p] \{$v\}"
906  }
907  append app_config_str " }"
908  set error_msg "Failed to configure app $app_name"
909  if {![ExecuteVitisUnifiedCommand $python_script "configure_app" \
910  [list $app_name $app_config_str "$globalSettings::build_dir/vitis_unified"] \
911  $error_msg]} {
912  continue
913  }
914  }
915  } else {
916  Msg Warning "Invalid app key format: $app_key. Expected format: app:<name>"
917  }
918  }
919 }
920 
921 proc ConfigureApp {app_name app_conf} {
922 
923  set create_options {
924  "platform" "domain" "sysproj" "hw"
925  "proc" "template" "os" "lang" "arch" "name"
926  }
927 
928  set conf_options {
929  "assembler-flags" "build-config" "compiler-misc" "compiler-optimization"
930  "define-compiler-symbols" "include-path" "libraries" "library-search-path"
931  "linker-misc" "linker-script" "undef-compiler-symbols"
932  }
933 
934  Msg Info "Configuring app..."
935  append app_options " -name $app_name"
936 
937  # A sysproj may have been created before, we must remove it
938  if {[catch {set sys_projs [sysproj list -dict]}]} { set sys_projs "" }
939  if {[dict exists $app_name sysproj]} {
940  set sys_proj_name [dict get $app_name sysproj]
941  if {[lsearch -exact $sys_projs "Name $sys_proj_name"] != -1} {
942  Msg Info "Removing $sys_proj_name..."
943  sysproj remove $sys_proj_name
944  }
945  } else {
946  set sys_proj_name "$app_name\_system"
947  if {[lsearch -exact $sys_projs "Name $sys_proj_name"] != -1} {
948  Msg Info "Removing $sys_proj_name..."
949  sysproj remove $sys_proj_name
950  }
951  }
952 
953  # An app may have been created before, we must remove it
954  if {[catch {set ws_apps [app list -dict]}]} { set ws_apps "" }
955  if {[lsearch -exact $ws_apps $app_name] != -1} {
956  Msg Info "app $app_name already exists, removing it..."
957  app remove $app_name
958  }
959 
960  set app_create_options [dict create]
961  set app_conf_options [dict create]
962 
963 
964  dict for {p v} $app_conf {
965  set p_lower [string tolower $p]
966 
967  if {[IsInList [string toupper $p] [VITIS_PATH_PROPERTIES] 1]} {
968  if {[IsRelativePath $v] == 1} {
969  set v "$globalSettings::repo_path/$v"
970  #"
971  }
972  if {![file exists $v]} {
973  Msg Warning "Impossible to set property $p to $v. File is missing"
974  continue
975  }
976  }
977 
978  if {[IsInList $p_lower $create_options]} {
979  Msg Info "$p_lower is in create options"
980  dict append app_create_options $p_lower $v
981  } elseif {[IsInList $p_lower $conf_options]} {
982  Msg Info "$p_lower is in conf options"
983  dict append app_conf_options $p_lower $v
984  } else {
985  Msg Warning "Unknown app option: $p_lower"
986  }
987  }
988 
989 
990  dict for {p v} $app_create_options {
991  if {[string equal $p "platform"]} {
992  Msg Info "Setting App $app_name platform to $v"
993  platform active $v
994  }
995  append app_options " -$p $v"
996  }
997 
998  if {![dict exists $app_name template]} {
999  if {[CompareVersions $globalSettings::c_v "2022 1 0"] == -1} {
1000  # Check if lang is defined in create_options
1001  if {[dict exists $app_create_options "lang"]} {
1002  set lang [dict get $app_create_options "lang"]
1003  if {[string equal -nocase $lang "C++"] || [string equal -nocase $lang "cpp"]} {
1004  append app_options " -template \{Empty Application (C++)\}"
1005  } else {
1006  append app_options " -template \{Empty Application(C)\}"
1007  }
1008  } else {
1009  # Default to Empty Application if lang is not specified
1010  append app_options " -template \{Empty Application(C)\}"
1011  }
1012  } else {
1013  # For newer versions, use the generic template
1014  append app_options " -template \{Empty Application\}"
1015  }
1016  }
1017 
1018  Msg Info "Creating application \[$app_name\] with options: \{$app_options\}"
1019  set app_create "app create $app_options"
1020  eval $app_create
1021  app config -name $app_name -set build-config Release
1022 
1023  # App config options
1024  dict for {p v} $app_conf_options {
1025  Msg Info "Configuring app option $p to $v"
1026  app config -name $app_name -set $p $v
1027  }
1028 }
1029 
1030 
1031 proc AddAppFiles {} {
1032  AddHogFiles {*}[GetHogFiles -list_files {.src,.header} -ext_path $globalSettings::HOG_EXTERNAL_PATH $globalSettings::list_path $globalSettings::repo_path ]
1033 }
1034 
1035 ## @brief Configure HLS components defined in hog.conf [hls:*] sections
1036 #
1037 # For each [hls:<component_name>] section, this proc:
1038 # 1. Reads the HLS_CONFIG path from hog.conf (mandatory, repo-relative)
1039 # 2. Validates that the hls_config.cfg file exists and is well-formed
1040 # 3. Creates a Vitis-compatible workspace so the project can be opened in the GUI
1041 #
1042 # The hls_config.cfg is the single source of truth for HLS settings.
1043 # It is committed to the repo and directly used/edited by Vitis.
1044 #
1045 proc ConfigureHlsComponents {} {
1046  set hls_components [dict filter $globalSettings::PROPERTIES key {hls:*}]
1047 
1048  if {[dict size $hls_components] == 0} {
1049  Msg Info "No HLS components found in the configuration file"
1050  return
1051  }
1052 
1053  set python_script "$globalSettings::repo_path/Hog/Other/Python/VitisUnified/HlsCommands.py"
1054  set ws_dir [file normalize "$globalSettings::build_dir/vitis_unified"]
1055 
1056  dict for {hls_key hls_config} $hls_components {
1057  if {[regexp {^hls:(.+)$} $hls_key -> component_name]} {
1058  set component_name [string trim $component_name]
1059  Msg Info "Configuring HLS component: $component_name"
1060 
1061  # Get HLS_CONFIG path from hog.conf (mandatory)
1062  set hls_cfg_rel ""
1063  if {[dict exists $hls_config hls_config]} {
1064  set hls_cfg_rel [dict get $hls_config hls_config]
1065  } elseif {[dict exists $hls_config HLS_CONFIG]} {
1066  set hls_cfg_rel [dict get $hls_config HLS_CONFIG]
1067  }
1068  if {$hls_cfg_rel eq ""} {
1069  Msg Error "HLS component '$component_name' missing HLS_CONFIG in hog.conf \[hls:$component_name\] section"
1070  continue
1071  }
1072 
1073  set hls_cfg_file [file normalize "$globalSettings::repo_path/$hls_cfg_rel"]
1074  if {![file exists $hls_cfg_file]} {
1075  Msg Error "HLS config file not found: $hls_cfg_file (from HLS_CONFIG=$hls_cfg_rel)"
1076  continue
1077  }
1078 
1079  Msg Info " HLS config: $hls_cfg_file"
1080 
1081  # Validate the config file
1082  set error_msg "Failed to validate HLS config for $component_name"
1083  if {![ExecuteVitisUnifiedCommand $python_script "validate" \
1084  [list $hls_cfg_file] \
1085  $error_msg]} {
1086  Msg Error $error_msg
1087  continue
1088  }
1089 
1090  # Create Vitis workspace with HLS component for GUI compatibility
1091  set hls_work_dir [file normalize "$ws_dir/hls_$component_name"]
1092  Msg Info "Creating Vitis HLS workspace component '$component_name' in $ws_dir ..."
1093  if {![ExecuteVitisUnifiedCommand $python_script "create_workspace" \
1094  [list $ws_dir $component_name $hls_cfg_file $hls_work_dir] \
1095  "Failed to create HLS workspace for $component_name"]} {
1096  Msg Warning "Could not create Vitis workspace for HLS component '$component_name'"
1097  }
1098 
1099  Msg Info "HLS component '$component_name' configured successfully"
1100  } else {
1101  Msg Warning "Invalid HLS key format: $hls_key. Expected format: hls:<name>"
1102  }
1103  }
1104 }
1105 
1106 ## @brief upgrade IPs in the project and copy them from HOG_IP_PATH if defined
1107 #
1108 proc ManageIPs {} {
1109  # set the current impl run
1110  current_run -implementation [get_runs impl_1]
1111 
1112  ##############
1113  # UPGRADE IP #
1114  ##############
1115  set ips [get_ips *]
1116 
1117  Msg Info "Running report_ip_status, before upgrading and handling IPs..."
1118  report_ip_status
1119  # Pull ips from repo
1120  if {$globalSettings::HOG_IP_PATH != ""} {
1121  set ip_repo_path $globalSettings::HOG_IP_PATH
1122  Msg Info "HOG_IP_PATH is set, will pull/push synthesised IPs from/to $ip_repo_path."
1123  foreach ip $ips {
1124  HandleIP pull [get_property IP_FILE $ip] $ip_repo_path $globalSettings::repo_path [get_property IP_OUTPUT_DIR $ip]
1125  }
1126  } else {
1127  Msg Info "HOG_IP_PATH not set, will not push/pull synthesised IPs."
1128  }
1129 }
1130 
1131 proc SetGlobalVar {var {default_value HOG_NONE}} {
1132  ##nagelfar ignore
1133  if {[info exists ::$var]} {
1134  Msg Debug "Setting $var to [subst $[subst ::$var]]"
1135  ##nagelfar ignore
1136  set globalSettings::$var [subst $[subst ::$var]]
1137  } elseif {$default_value == "HOG_NONE"} {
1138  Msg Error "Mandatory variable $var was not defined. Please define it in hog.conf or in project tcl script."
1139  } else {
1140  Msg Info "Setting $var to default value: \"$default_value\""
1141  ##nagelfar ignore
1142  set globalSettings::$var $default_value
1143  }
1144 }
1145 
1146 ################################################################################################################################################################
1147 
1148 proc CreateProject {args} {
1149  global env
1150  # set tcl_path [file normalize "[file dirname [info script]]"]
1151  # set repo_path [file normalize $tcl_path/../..]
1152 
1153  if {[catch {package require cmdline} ERROR]} {
1154  puts "ERROR: If you are running this script on tclsh, you can fix this by installing 'tcllib'"
1155  return
1156  }
1157  set parameters {
1158  {simlib_path.arg "" "Path of simulation libs"}
1159  {verbose "If set, launch the script in verbose mode."}
1160  {xsa.arg "" "xsa for creating platforms without a defined hw."}
1161  {vivado_only "If set, and project is vivado-vitis, vitis project will not be created."}
1162  {vitis_only "If set, and project is vivado-vitis, only vitis project will be created."}
1163  }
1164 
1165  set usage "Create Vivado/Vitis/ISE/Quartus/Libero/Diamond project.\nUsage: CreateProject \[OPTIONS\] <project> <repository path>\n Options:"
1166 
1167  if {[catch {array set options [cmdline::getoptions args $parameters $usage]}] || [llength $args] < 2 || [lindex $args 0] eq ""} {
1168  Msg Info [cmdline::usage $parameters $usage]
1169  return 1
1170  }
1171 
1172  set globalSettings::DESIGN [lindex $args 0]
1173  if {[file exists [lindex $args 1]]} {
1174  set globalSettings::repo_path [file normalize [lindex $args 1]]
1175  } else {
1176  Msg Error "The second argument, [lindex $args 1], should be the repository path."
1177  }
1178  set globalSettings::tcl_path $globalSettings::repo_path/Hog/Tcl
1179 
1180 
1181  if {$options(verbose) == 1} {
1182  variable ::DEBUG_MODE 1
1183  }
1184 
1185  if {[IsVivado]} {
1186  if {$options(simlib_path) != ""} {
1187  if {[IsRelativePath $options(simlib_path)] == 0} {
1188  set globalSettings::simlib_path "$options(simlib_path)"
1189  } else {
1190  set globalSettings::simlib_path "${globalSettings::repo_path}/$options(simlib_path)"
1191  }
1192  Msg Info "Simulation library path set to $options(simlib_path)"
1193  } else {
1194  set globalSettings::simlib_path "${globalSettings::repo_path}/SimulationLib"
1195  Msg Info "Simulation library path set to default ${globalSettings::repo_path}/SimulationLib"
1196  }
1197  }
1198 
1199  # Derived variables from now on...
1200 
1201  set build_dir_name "Projects"
1202  set globalSettings::group_name [file dirname ${globalSettings::DESIGN}]
1203  set globalSettings::project_name ${globalSettings::DESIGN}
1204  set globalSettings::pre_synth_file "pre-synthesis.tcl"
1205  set globalSettings::post_synth_file "post-synthesis.tcl"
1206  set globalSettings::pre_impl_file "pre-implementation.tcl"
1207  set globalSettings::post_impl_file "post-implementation.tcl"
1208  set globalSettings::pre_bit_file "pre-bitstream.tcl"
1209  set globalSettings::post_bit_file "post-bitstream.tcl"
1210  set globalSettings::quartus_post_module_file "quartus-post-module.tcl"
1211  set globalSettings::top_path "${globalSettings::repo_path}/Top/${globalSettings::DESIGN}"
1212  set globalSettings::list_path "${globalSettings::top_path}/list"
1213  set globalSettings::build_dir "${globalSettings::repo_path}/${build_dir_name}/${globalSettings::DESIGN}"
1214  set globalSettings::DESIGN [file tail ${globalSettings::DESIGN}]
1215  set globalSettings::top_name [file tail ${globalSettings::DESIGN}]
1216  set globalSettings::top_name [file rootname ${globalSettings::top_name}]
1217  set globalSettings::synth_top_module "top_${globalSettings::top_name}"
1218  set globalSettings::user_ip_repo ""
1219 
1220  set globalSettings::pre_synth [file normalize "${globalSettings::tcl_path}/integrated/${globalSettings::pre_synth_file}"]
1221  set globalSettings::post_synth [file normalize "${globalSettings::tcl_path}/integrated/${globalSettings::post_synth_file}"]
1222  set globalSettings::pre_impl [file normalize "${globalSettings::tcl_path}/integrated/${globalSettings::pre_impl_file}"]
1223  set globalSettings::post_impl [file normalize "${globalSettings::tcl_path}/integrated/${globalSettings::post_impl_file}"]
1224  set globalSettings::pre_bit [file normalize "${globalSettings::tcl_path}/integrated/${globalSettings::pre_bit_file}"]
1225  set globalSettings::post_bit [file normalize "${globalSettings::tcl_path}/integrated/${globalSettings::post_bit_file}"]
1226  set globalSettings::quartus_post_module [file normalize "${globalSettings::tcl_path}/integrated/${globalSettings::quartus_post_module_file}"]
1227  set globalSettings::LIBERO_MANDATORY_VARIABLES {"FAMILY" "PACKAGE" "DIE" }
1228 
1229  set proj_dir [file normalize "${globalSettings::repo_path}/Top/${globalSettings::project_name}"]
1230  Msg Debug "Calling GetConfFiles with proj_dir=$proj_dir (project_name=${globalSettings::project_name})"
1231  lassign [GetConfFiles $proj_dir] conf_file sim_file pre_file post_file pre_rtl_file
1232 
1233  set user_repo 0
1234  if {[file exists $conf_file]} {
1235  Msg Info "Parsing configuration file $conf_file..."
1236  SetGlobalVar PROPERTIES [ReadConf $conf_file]
1237 
1238  # Checking Vivado/Vitis/Quartus/ISE/Libero version
1239  set actual_version [GetIDEVersion]
1240  lassign [GetIDEFromConf $conf_file] ide conf_version
1241 
1242  if {$conf_version != "0.0.0"} {
1243  set globalSettings::a_v [split $actual_version "."]
1244  set globalSettings::c_v [split $conf_version "."]
1245 
1246  if {[llength $globalSettings::a_v] < 2} {
1247  Msg Error "Couldn't parse IDE version: $actual_version."
1248  } elseif {[llength $globalSettings::a_v] == 2} {
1249  lappend globalSettings::a_v 0
1250  }
1251  if {[llength $globalSettings::c_v] < 2} {
1252  Msg Error "Wrong version format in hog.conf: $conf_version."
1253  } elseif {[llength $globalSettings::c_v] == 2} {
1254  lappend globalSettings::c_v 0
1255  }
1256 
1257  set comp [CompareVersions $globalSettings::a_v $globalSettings::c_v]
1258  if {$comp == 0} {
1259  Msg Info "Project version and $ide version match: $conf_version."
1260  } elseif {$comp == 1} {
1261  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\
1262  If you want update this project to version $actual_version, please update the configuration file."
1263  } else {
1264  # tclint-disable-next-line line-length
1265  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."
1266  }
1267  } else {
1268  Msg CriticalWarning "No version found in the first line of $conf_file. \
1269  It is HIGHLY recommended to replace the first line of $conf_file with: \#$ide $actual_version"
1270  }
1271 
1272  if {$globalSettings::vitis_classic == 1} {
1273  if {[CompareVersions $globalSettings::a_v "2020 2 0"] == -1 || [CompareVersions $globalSettings::c_v "2020 2 0"] == -1} {
1274  Msg Error "Vitis Classic flow is not supported for versions < 2020.2. Please use Vitis 2020.2 or newer." }
1275  }
1276  if {$globalSettings::vitis_unified == 1} {
1277  if {[CompareVersions $globalSettings::a_v "2019 2 0"] == -1 || [CompareVersions $globalSettings::c_v "2019 2 0"] == -1} {
1278  Msg Error "Vitis Unified flow is not supported for versions < 2019.2. Please use Vitis 2019.2 or newer." }
1279  }
1280 
1281  if {[dict exists $globalSettings::PROPERTIES main]} {
1282  set main [dict get $globalSettings::PROPERTIES main]
1283  dict for {p v} $main {
1284  # notice the dollar in front of p: creates new variables and fill them with the value
1285  Msg Info "Main property $p set to $v"
1286  ##nagelfar ignore
1287  set ::$p $v
1288  }
1289  } else {
1290  Msg Error "No main section found in $conf_file, make sure it has a section called \[main\] containing the mandatory properties."
1291  }
1292  } else {
1293  Msg Error "$conf_file was not found in your project directory, please create one."
1294  }
1295 
1296 
1297  if {[IsXilinx] || [IsQuartus]} {
1298  SetGlobalVar PART
1299  }
1300  #Family is needed in quartus and libero only
1301  if {[IsQuartus] || [IsLibero]} {
1302  #Quartus only
1303  SetGlobalVar FAMILY
1304  if {[IsLibero]} {
1305  SetGlobalVar DIE
1306  SetGlobalVar PACKAGE
1307  }
1308  }
1309 
1310  if {[IsDiamond]} {
1311  SetGlobalVar DEVICE
1312  SetGlobalVar SYNTHESIS_TOOL "lse"
1313  }
1314 
1315  if {[IsVivado]} {
1316  SetGlobalVar TARGET_SIMULATOR "XSim"
1317  }
1318 
1319  if {[info exists env(HOG_EXTERNAL_PATH)]} {
1320  set globalSettings::HOG_EXTERNAL_PATH $env(HOG_EXTERNAL_PATH)
1321  } else {
1322  set globalSettings::HOG_EXTERNAL_PATH ""
1323  }
1324 
1325  set user_hog_file "${globalSettings::repo_path}/Top/hog.tcl"
1326  if {[file exists $user_hog_file]} {
1327  Msg Info "Sourcing user hog.tcl file..."
1328  source $user_hog_file
1329  }
1330 
1331  if {[file exists $pre_file]} {
1332  Msg Info "Found pre-creation Tcl script $pre_file, executing it..."
1333  source $pre_file
1334  }
1335 
1336  if {[info exists env(HOG_IP_PATH)]} {
1337  set globalSettings::HOG_IP_PATH $env(HOG_IP_PATH)
1338  } else {
1339  set globalSettings::HOG_IP_PATH ""
1340  }
1341 
1342  InitProject $options(vitis_only)
1343 
1344  if {([IsVitisClassic] || [IsVitisUnified]) && $options(vitis_only) == 1} {
1345  # Check if this project has HLS components
1346  set has_hls [expr {[dict size [dict filter $globalSettings::PROPERTIES key {hls:*}]] > 0}]
1347  set has_platforms [expr {[dict size [dict filter $globalSettings::PROPERTIES key {platform:*}]] > 0}]
1348  set has_apps [expr {[dict size [dict filter $globalSettings::PROPERTIES key {app:*}]] > 0}]
1349 
1350  if {$has_hls} {
1351  Msg Info "Found HLS component(s) in configuration, configuring HLS..."
1353  }
1354 
1355  if {!$has_platforms && !$has_apps} {
1356  Msg Info "vitis unified HLS-only project, skipping Vivado project setup."
1357  return
1358  }
1359 
1360  if {$has_platforms || $has_apps} {
1361  set xsa_path $options(xsa)
1362 
1363  if {$xsa_path == ""} {
1364  if {[string match "vivado_*" [string tolower $ide]]} {
1365  # vivado_vitis project: generate pre-synth XSA from existing Vivado project
1366  set xpr_file [file normalize "$globalSettings::build_dir/[file tail $globalSettings::DESIGN].xpr"]
1367  if {[file exists $xpr_file]} {
1368  Msg Info "Opening existing Vivado project to generate pre-synth XSA..."
1369  open_project $xpr_file
1370  set xsa_path [file normalize "$globalSettings::build_dir/$globalSettings::DESIGN-presynth.xsa"]
1371  write_hw_platform -fixed -force -file $xsa_path
1372  Msg Info "Pre-synth XSA generated: $xsa_path"
1373  close_project
1374  } else {
1375  # tclint-disable-next-line line-length
1376  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."
1377  return 1
1378  }
1379  } else {
1380  # Standalone vitis project: XSA is mandatory for platform/app
1381  Msg Error "This is a $ide only project with platform/app sections, an XSA file must be provided via the -xsa option."
1382  return 1
1383  }
1384  }
1385 
1386  Msg Info "Configuring platforms with XSA: $xsa_path"
1387  ConfigurePlatforms "$xsa_path"
1389  AddAppFiles
1390  if {[file exists $post_file]} {
1391  Msg Info "Found post-creation Tcl script $post_file, executing it..."
1392  source $post_file
1393  }
1394  }
1395 
1396  return
1397  }
1398 
1399  # If the project is a vitis-only project, skip creating the Vivado project
1400  if {([string tolower $ide] eq "vitis_classic" || [string tolower $ide] eq "vitis_unified") && $options(vitis_only) == 1} {
1401  if {$options(xsa) == ""} {
1402  Msg Error "This is a $ide only project, an XSA file must be provided via -xsa option."
1403  return 1
1404  }
1405  return
1406  }
1407 
1412 
1413 
1414  if {[IsVivado]} {
1415  # Use HandleIP to pull IPs from HOG_IP_PATH if specified
1416  ManageIPs
1417  }
1418 
1419  if {[IsQuartus]} {
1420  set fileName_old [file normalize "./hogTmp/.hogQsys.md5"]
1421  set fileDir [file normalize "${globalSettings::build_dir}/.hog/"]
1422  file mkdir $fileDir
1423  set fileName_new [file normalize "$fileDir/.hogQsys.md5"]
1424  if {[file exists $fileName_new]} {
1425  file delete $fileName_new
1426  }
1427  if {[file exists $fileName_old]} {
1428  file rename -force $fileName_old $fileName_new
1429  file delete -force -- "./hogTmp"
1430  }
1431  }
1432 
1433  if {[file exists $post_file]} {
1434  Msg Info "Found post-creation Tcl script $post_file, executing it..."
1435  source $post_file
1436  if {[IsLibero]} {
1437  # Regenerate the hierarchy in case a new file has been added
1438  build_design_hierarchy
1439  }
1440  }
1441 
1442  # Check extra IPs
1443  # Get project libraries and properties from list files
1444  lassign [GetHogFiles \
1445  -ext_path "$globalSettings::HOG_EXTERNAL_PATH" \
1446  -list_files ".src,.ext" \
1447  "$globalSettings::repo_path/Top/$globalSettings::project_name/list/" \
1448  $globalSettings::repo_path] \
1449  listLibraries listProperties listSrcSets
1450  # Get project constraints and properties from list files
1451  lassign [GetHogFiles \
1452  -ext_path "$globalSettings::HOG_EXTERNAL_PATH" \
1453  -list_files ".con" \
1454  "$globalSettings::repo_path/Top/$globalSettings::project_name/list/" \
1455  $globalSettings::repo_path] \
1456  listConstraints listConProperties listConSets
1457 
1458  lassign [GetHogFiles \
1459  -ext_path "$globalSettings::HOG_EXTERNAL_PATH" \
1460  -list_files ".sim" \
1461  "$globalSettings::repo_path/Top/$globalSettings::project_name/list/" \
1462  $globalSettings::repo_path] \
1463  listSimLibraries listSimProperties listSimSets
1464 
1465  set old_path [pwd]
1466  cd $globalSettings::build_dir
1467  CheckExtraFiles $listLibraries $listConstraints $listSimLibraries
1468  cd $old_path
1469 
1470  if {[IsXilinx]} {
1471  set old_path [pwd]
1472  cd $globalSettings::repo_path
1473  set flavour [GetProjectFlavour $globalSettings::DESIGN]
1474  # Getting all the versions and SHAs of the repository
1475  lassign [GetRepoVersions \
1476  [file normalize $globalSettings::repo_path/Top/$globalSettings::project_name] \
1477  $globalSettings::repo_path \
1478  $globalSettings::HOG_EXTERNAL_PATH \
1479  ] commit version hog_hash hog_ver top_hash top_ver libs hashes vers cons_ver cons_hash ext_names ext_hashes \
1480  xml_hash xml_ver user_ip_repos user_ip_hashes user_ip_vers
1481 
1482  set this_commit [GetSHA]
1483 
1484  if {$commit == 0} {
1485  set commit $this_commit
1486  }
1487 
1488  if {$xml_hash != ""} {
1489  set use_ipbus 1
1490  } else {
1491  set use_ipbus 0
1492  }
1493 
1494 
1495  lassign [GetDateAndTime $commit] date timee
1496  WriteGenerics "create" \
1497  $globalSettings::repo_path \
1498  $globalSettings::project_name \
1499  $date $timee $commit $version \
1500  $top_hash $top_ver $hog_hash $hog_ver \
1501  $cons_ver $cons_hash $libs $vers $hashes \
1502  $ext_names $ext_hashes $user_ip_repos $user_ip_vers \
1503  $user_ip_hashes $flavour $xml_ver $xml_hash
1504  cd $old_path
1505  }
1506 
1507  if {[IsLibero]} {
1508  save_project
1509  }
1510 
1511  if {[IsDiamond]} {
1512  prj_project save
1513  }
1514 
1515 
1516  if {($globalSettings::vitis_classic == 1 || $globalSettings::vitis_unified == 1)} {
1517  # Presynth hw platform, let's keep it in the build directory
1518  write_hw_platform -fixed -force -file [file normalize "$globalSettings::build_dir/$globalSettings::DESIGN-presynth.xsa"]
1519 
1520  if {$options(xsa) == ""} {
1521  set presynth_xsa [file normalize "$globalSettings::build_dir/$globalSettings::DESIGN-presynth.xsa"]
1522  set xsa_opt "-xsa $presynth_xsa"
1523  } else {
1524  if {[IsRelativePath $options(xsa)] == 0} {
1525  set xsa_opt "-xsa $options(xsa)"
1526  } else {
1527  set xsa_opt "-xsa $globalSettings::repo_path/$options(xsa)"
1528  }
1529  }
1530 
1531  if {$globalSettings::vitis_classic == 1} {
1532  # Launch xsct to build the project
1533  set xsct_cmd "xsct $globalSettings::tcl_path/launch.tcl C $xsa_opt -vitis_only $globalSettings::project_name"
1534  Msg Info "Running Vitis Classic project creation script with command: $xsct_cmd"
1535  set ret [catch {exec -ignorestderr {*}$xsct_cmd >@ stdout} result]
1536  if {$ret != 0} {
1537  Msg Error "xsct (vitis classic) returned an error state."
1538  }
1539  } elseif {$globalSettings::vitis_unified == 1} {
1540  # Launch vivado in batch mode to build the project
1541  set vivado_cmd "vivado -nojournal -nolog -mode batch -notrace \
1542  -source $globalSettings::tcl_path/launch.tcl \
1543  -tclargs C $xsa_opt -vitis_only $globalSettings::project_name"
1544  Msg Info "Running Vitis Unified project creation script with command: $vivado_cmd"
1545  set ret [catch {exec -ignorestderr {*}$vivado_cmd >@ stdout} result]
1546  if {$ret != 0} {
1547  Msg Error "vivado (vitis unified) returned an error state."
1548  }
1549  }
1550  }
1551 
1552 
1553  Msg Info "Project $globalSettings::project_name created successfully in [Relative $globalSettings::repo_path $globalSettings::build_dir]."
1554 }