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