Hog v10.38.0
post-bitstream.tcl
Go to the documentation of this file.
1 #!/usr/bin/env tclsh
2 # Copyright 2018-2026 The University of Birmingham
3 # Copyright 2018-2026 Max-Planck-Institute for Physics
4 #
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
8 #
9 # http://www.apache.org/licenses/LICENSE-2.0
10 #
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
16 
17 # @file
18 # The post bitstream script copies binary files, reports and other files to the bin directory in your repository.
19 # This script is automatically integrated into the Vivado/Quartus workflow by the Create Project script.
20 
21 set old_path [pwd]
22 set tcl_path [file normalize "[file dirname [info script]]/.."]
23 source $tcl_path/hog.tcl
24 set repo_path [file normalize "$tcl_path/../../"]
25 
26 
27 # write_hw_platform has weird behavior when run in post-bitstream hook;
28 # workaround by launching a separate Vivado instance to run it
29 proc WriteHwPlatformWorkaround {proj_dir proj_name work_path hw_platform_args} {
30  set proj_file [file normalize "$proj_dir/$proj_name.xpr"]
31  set impl_run [file tail $work_path]
32  set tmp_script "$work_path/hog_write_hw_platform_tmp.tcl"
33 
34  set fp [open $tmp_script w]
35  puts $fp "open_project {$proj_file}"
36  puts $fp "open_run $impl_run"
37  puts $fp "write_hw_platform $hw_platform_args"
38  puts $fp "close_project"
39  close $fp
40 
41  Msg Info "Launching another Vivado instance to run write_hw_platform for $impl_run..."
42  set ret [catch {exec vivado -mode batch -notrace -source $tmp_script >@ stdout 2>@ stderr} result]
43 
44  if {$ret != 0} {
45  Msg Error "write_hw_platform failed in separate Vivado instance:\n$result"
46  } else {
47  Msg Info "write_hw_platform completed successfully in separate Vivado instance for $impl_run."
48  }
49  return $ret
50 }
51 
52 # Import tcllib
53 if {[IsLibero] || [IsDiamond]} {
54  if {[info exists env(HOG_TCLLIB_PATH)]} {
55  lappend auto_path $env(HOG_TCLLIB_PATH)
56  } else {
57  puts "ERROR: To run Hog with Microsemi Libero SoC, you need to define the HOG_TCLLIB_PATH variable."
58  return
59  }
60 }
61 
62 if {[info exists env(HOG_EXTERNAL_PATH)]} {
63  set ext_path $env(HOG_EXTERNAL_PATH)
64  Msg Info "Found environment variable HOG_EXTERNAL_PATH, setting path for external files to $ext_path..."
65 } else {
66  set ext_path ""
67 }
68 
69 set bin_dir [file normalize "$repo_path/bin"]
70 
71 if {[IsXilinx]} {
72  # Binary files are called .bit for ISE and for Vivado unless the chip is a Versal
73  set fw_file_ext "bit"
74 
75  # Vivado + PlanAhead
76  if {[IsISE]} {
77  # planAhead
78  set work_path [get_property DIRECTORY [get_runs impl_1]]
79  } else {
80  # Vivado
81  set work_path $old_path
82  if {[IsVersal [get_property PART [current_design]]]} {
83  #In Vivado if a Versal chip is used, the main binary file is called .pdi
84  set fw_file_ext "pdi"
85  }
86  }
87 
88  set main_files [lsort [glob -nocomplain "$work_path/*.$fw_file_ext"]]
89  if {[llength $main_files] > 1} {
90  #In case of segmented configuration on Versal there are 2 .pdi files: <top>_boot.pdi and <top>_pld.pdi
91  # Main file is the pld, so not the first
92  set main_file [file normalize [lindex $main_files 1]]
93  # Secondary file is the boot, so the first!
94  set secondary_file [file normalize [lindex $main_files 0]]
95  set main_file_suffix "_pld"
96  set secondary_file_suffix "_boot"
97  Msg Info "Found main and secondary binary file main: [file tail $main_file], secondary: [file tail $secondary_file]..."
98  # remove _pld suffix only at the end
99  set top_name [regsub $main_file_suffix\$ [file rootname [file tail $main_file]] ""]
100  if {[llength $main_files] > 2} {
101  Msg Warning "Multiple (more than 2) binary files found: $main_files."
102  }
103  } else {
104  set main_file [file normalize [lindex $main_files 0]]
105  set main_file_suffix ""
106  set secondary_file ""
107  set secondary_file_suffix ""
108  set top_name [file rootname [file tail $main_file]]
109  }
110 
111 
112  set proj_name [file tail [file normalize $work_path/../../]]
113  set proj_dir [file normalize "$work_path/../.."]
114 
115 
116  set additional_ext ".bin .ltx .bif .mmi"
117 
118  set xml_dir [file normalize "$work_path/../xml"]
119  set run_dir [file normalize "$work_path/.."]
120 } elseif {[IsQuartus]} {
121  # Quartus
122  ##nagelfar ignore Unknown variable
123  set proj_name [lindex $quartus(args) 1]
124  set proj_dir [pwd]
125  set xml_dir [file normalize "$repo_path/xml"]
126  set run_dir [file normalize "$proj_dir"]
127  set name [file rootname [file tail [file normalize [pwd]]]]
128  # programming object file
129  set pof_file [file normalize "$proj_dir/output_files/$proj_name.pof"]
130  # SRAM Object File
131  set sof_file [file normalize "$proj_dir/output_files/$proj_name.sof"]
132  # raw binary file
133  set rbf_file [file normalize "$proj_dir/output_files/$proj_name.rbf"]
134  #raw programming file
135  set rpd_file [file normalize "$proj_dir/output_files/$proj_name.rpd"]
136  # signal tap file
137  set stp_file [file normalize "$proj_dir/output_files/$proj_name.stp"]
138  #source and probes file
139  set spf_file [file normalize "$proj_dir/output_files/$proj_name.spf"]
140 } elseif {[IsLibero]} {
141  # Libero
142  ##nagelfar ignore Unknown variable
143  set proj_name $project
144  ##nagelfar ignore Unknown variable
145  set proj_dir $main_folder
146  set map_file [file normalize [lindex [glob -nocomplain "$proj_dir/synthesis/*.map"] 0]]
147  set sap_file [file normalize [lindex [glob -nocomplain "$proj_dir/synthesis/*.sap"] 0]]
148  set srd_file [file normalize [lindex [glob -nocomplain "$proj_dir/synthesis/*.srd"] 0]]
149  set srm_file [file normalize [lindex [glob -nocomplain "$proj_dir/synthesis/*.srm"] 0]]
150  set srs_file [file normalize [lindex [glob -nocomplain "$proj_dir/synthesis/*.srs"] 0]]
151  set srr_file [file normalize [lindex [glob -nocomplain "$proj_dir/synthesis/*.srr"] 0]]
152  set top_name [file rootname [file tail $srr_file]]
153  set stxt_files [glob -nocomplain "$proj_dir/synthesis/*.txt"]
154  set scsv_files [glob -nocomplain "$proj_dir/synthesis/*.csv"]
155  set slog_files [glob -nocomplain "$proj_dir/synthesis/*.log"]
156  set srpt_files [glob -nocomplain "$proj_dir/synthesis/*.rpt"]
157  set dtxt_files [glob -nocomplain "$proj_dir/designer/$top_name/*.txt"]
158  set dcsv_files [glob -nocomplain "$proj_dir/designer/$top_name/*.csv"]
159  set dlog_files [glob -nocomplain "$proj_dir/designer/$top_name/*.log"]
160  set drpt_files [glob -nocomplain "$proj_dir/designer/$top_name/*.rpt"]
161  set xml_dir [file normalize "$repo_path/xml"]
162 } elseif {[IsDiamond]} {
163  set proj_dir [file normalize "[pwd]/.."]
164  set proj_name [file tail $proj_dir]
165  set project $proj_name
166  set xml_dir [file normalize "$repo_path/xml"]
167  set main_file [file normalize "$proj_dir/Implementation0/${proj_name}_Implementation0"]
168 } else {
169  #tcl shell
170  set work_path $old_path
171  set fw_file [file normalize [lindex [glob -nocomplain "$work_path/*.bit"] 0]]
172  set proj_name [file tail [file normalize $work_path/../../]]
173  set proj_dir [file normalize "$work_path/../.."]
174 
175  set top_name [file rootname [file tail $fw_file]]
176 
177  set main_file [file normalize "$work_path/$top_name.bit"]
178  set bin_file [file normalize "$work_path/$top_name.bin"]
179  set ltx_file [file normalize "$work_path/$top_name.ltx"]
180 
181  set xml_dir [file normalize "$work_path/../xml"]
182  set run_dir [file normalize "$work_path/.."]
183 }
184 
185 set group_name [GetGroupName $proj_dir "$tcl_path/../.."]
186 # Go to repository path
187 cd $repo_path
188 
189 Msg Info "Evaluating Hog describe for $proj_name..."
190 set describe [GetHogDescribe [file normalize ./Top/$group_name/$proj_name] $repo_path]
191 Msg Info "Hog describe set to: $describe"
192 
193 set dst_dir [file normalize "$bin_dir/$group_name/$proj_name\-$describe"]
194 set dst_xml [file normalize "$dst_dir/xml"]
195 
196 Msg Info "Creating $dst_dir..."
197 file mkdir $dst_dir
198 
199 set ts [clock format [clock seconds] -format {%Y-%m-%d-%H-%M}]
200 
201 
202 # Vivado
203 if {[IsXilinx] && [file exists $main_file]} {
204  set dst_main [file normalize "$dst_dir/$proj_name$main_file_suffix\-$describe.$fw_file_ext"]
205  Msg Info "Copying main binary file $main_file into $dst_main..."
206  file copy -force $main_file $dst_main
207  if {$secondary_file != ""} {
208  set dst_secondary [file normalize "$dst_dir/$proj_name$secondary_file_suffix\-$describe.$fw_file_ext"]
209  Msg Info "Copying secondary binary file $secondary_file into $dst_secondary..."
210  file copy -force $secondary_file $dst_secondary
211  }
212 
213 
214  # Additional files
215  # In case of Segmented Configuration, there are 2 files per extension.
216 
217  set ltx_files {}
218  lappend ltx_files "$top_name.ltx"
219 
220  if {$main_file_suffix != ""} {
221  foreach e $additional_ext {
222  lappend new_ext $e
223  lappend new_ext $main_file_suffix$e
224  lappend new_ext $secondary_file_suffix$e
225  lappend ltx_files "$top_name$main_file_suffix.ltx"
226  lappend ltx_files "$top_name$secondary_file_suffix.ltx"
227  }
228  set additional_ext $new_ext
229  }
230 
231 
232  # LTX file for ILA, needs a special treatment...
233  foreach l $ltx_files {
234  set ltx_file "$work_path/$l"
235  Msg Info "Writing debug probes for $ltx_file..."
236  write_debug_probes -quiet $ltx_file
237  }
238 
239  foreach e $additional_ext {
240  set orig [file normalize "$work_path/$top_name$e"]
241  set dst [file normalize "$dst_dir/$proj_name\-$describe$e"]
242  if {[file exists $work_path/$top_name$e] == 1} {
243  Msg Info "Copying $orig file into $dst..."
244  file copy -force $orig $dst
245  } else {
246  Msg Debug "File: $orig not found."
247  }
248  }
249 } elseif {[IsQuartus]} {
250  set dst_pof [file normalize "$dst_dir/$name\-$describe.pof"]
251  set dst_sof [file normalize "$dst_dir/$name\-$describe.sof"]
252  set dst_rbf [file normalize "$dst_dir/$name\-$describe.rbf"]
253  set dst_rpd [file normalize "$dst_dir/$name\-$describe.rpd"]
254  set dst_stp [file normalize "$dst_dir/$name\-$describe.stp"]
255  set dst_spf [file normalize "$dst_dir/$name\-$describe.spf"]
256  set dst_xml [file normalize "$dst_dir/xml"]
257 
258  Msg Info "Evaluating differences with last commit..."
259  set found_uncommitted 0
260  set diff [Git diff]
261  if {$diff != ""} {
262  set found_uncommitted 1
263  Msg Warning "Found non committed changes:"
264  Msg Status "$diff"
265  set fp [open "$dst_dir/diff_postbistream.txt" w+]
266  puts $fp "$diff"
267  close $fp
268  }
269 
270  if {$found_uncommitted == 0} {
271  Msg Info "No uncommitted changes found."
272  }
273 
274  #pof file
275  if {[file exists $pof_file]} {
276  Msg Info "Copying pof file $pof_file into $dst_pof..."
277  file copy -force $pof_file $dst_pof
278  } else {
279  Msg Info "No pof file found: $pof_file, that is not a problem"
280  }
281 
282  #Reports
283  file mkdir $dst_dir/reports
284  set reps [glob -nocomplain "$proj_dir/output_files/*.rpt"]
285 
286  if {[file exists [lindex $reps 0]]} {
287  file copy -force {*}$reps $dst_dir/reports
288  } else {
289  Msg Warning "No reports found in $proj_dir/output_files subfolders"
290  }
291 
292  # sof File
293  if {[file exists $sof_file]} {
294  Msg Info "Copying sof file $sof_file into $dst_sof..."
295  file copy -force $sof_file $dst_sof
296  } else {
297  Msg Info "No sof file found: $sof_file, that is not a problem"
298  }
299 
300 
301  #rbf rpd
302  if {[file exists $rbf_file] || [file exists $rpd_file]} {
303  if {[file exists $rbf_file]} {
304  file copy -force $rbf_file $dst_rbf
305  }
306  if {[file exists $rpd_file]} {
307  file copy -force $rpd_file $dst_rpd
308  }
309  } else {
310  Msg Info "No rbf or rpd file found: this is not a problem"
311  }
312 
313  # stp and spf File
314  if {[file exists $stp_file] || [file exists $spf_file]} {
315  if {[file exists $stp_file]} {
316  file copy -force $stp_file $dst_stp
317  }
318  if {[file exists $spf_file]} {
319  file copy -force $spf_file $dst_spf
320  }
321  } else {
322  Msg Info "No stp or spf file found: that is not a problem"
323  }
324 } elseif {[IsLibero]} {
325  set dst_map [file normalize "$dst_dir/$project\-$describe.map"]
326  set dst_sap [file normalize "$dst_dir/$project\-$describe.sap"]
327  set dst_srd [file normalize "$dst_dir/$project\-$describe.srd"]
328  set dst_srm [file normalize "$dst_dir/$project\-$describe.srm"]
329  set dst_srs [file normalize "$dst_dir/$project\-$describe.srs"]
330  set dst_srr [file normalize "$dst_dir/$project\-$describe.srr"]
331  set dst_rpt [file normalize "$dst_dir/reports"]
332  set dst_xml [file normalize "$dst_dir/xml"]
333 
334  file mkdir $dst_dir/reports
335 
336  if {[file exists $map_file]} {
337  Msg Info "Copying map file $map_file into $dst_map..."
338  file copy -force $map_file $dst_map
339  }
340 
341  if {[file exists $sap_file]} {
342  Msg Info "Copying sap file $sap_file into $dst_sap..."
343  file copy -force $sap_file $dst_sap
344  }
345 
346  if {[file exists $srd_file]} {
347  Msg Info "Copying srd file $srd_file into $dst_srd..."
348  file copy -force $srd_file $dst_srd
349  }
350 
351  if {[file exists $srm_file]} {
352  Msg Info "Copying srm file $srm_file into $dst_srm..."
353  file copy -force $srm_file $dst_map
354  }
355 
356  if {[file exists $srs_file]} {
357  Msg Info "Copying srs file $srs_file into $dst_srs..."
358  file copy -force $srs_file $dst_srs
359  }
360 
361  if {[file exists $srr_file]} {
362  Msg Info "Copying srr file $srr_file into $dst_srr..."
363  file copy -force $srr_file $dst_srr
364  }
365 
366 
367  Msg Info "Copying synth txt files $stxt_files into $dst_rpt..."
368  file copy -force {*}$stxt_files $dst_rpt
369  Msg Info "Copying synth csv files $scsv_files into $dst_rpt..."
370  file copy -force {*}$scsv_files $dst_rpt
371  Msg Info "Copying synth log files $slog_files into $dst_rpt..."
372  file copy -force {*}$slog_files $dst_rpt
373  Msg Info "Copying synth rpt files $srpt_files into $dst_rpt..."
374  file copy -force {*}$srpt_files $dst_rpt
375 
376  Msg Info "Copying impl txt files $dtxt_files into $dst_rpt..."
377  file copy -force {*}$dtxt_files $dst_rpt
378  Msg Info "Copying impl csv files $dcsv_files into $dst_rpt..."
379  file copy -force {*}$dcsv_files $dst_rpt
380  Msg Info "Copying impl log files $dlog_files into $dst_rpt..."
381  file copy -force {*}$dlog_files $dst_rpt
382  Msg Info "Copying impl rpt files $drpt_files into $dst_rpt..."
383  file copy -force {*}$drpt_files $dst_rpt
384 } elseif {[IsDiamond]} {
385  set dst_main [file normalize "$dst_dir/$proj_name\-$describe.bit"]
386  Msg Info "Copying main binary file $main_file.bit into $dst_main..."
387  file copy -force $main_file.bit $dst_main
388  Msg Info "Copying binary generation log $main_file.bgn into $dst_dir/reports..."
389  file copy -force $main_file.bgn $dst_dir/reports
390 } else {
391  Msg CriticalWarning "Firmware binary file not found."
392 }
393 
394 
395 # IPbus XML
396 if {[file exists $xml_dir]} {
397  Msg Info "XML directory found, copying xml files from $xml_dir to $dst_xml..."
398  if {[file exists $dst_xml]} {
399  Msg Info "Directory $dst_xml exists, deleting it..."
400  file delete -force $dst_xml
401  }
402  file copy -force $xml_dir $dst_xml
403 }
404 
405 # XSA export (Zynq/Versal SoCs, or soft processors such as MicroBlaze/RISC-V)
406 if {[IsXilinx]} {
407  # auto-enable for Zynq/Versal parts, or when an app targets a soft processor
408  set export_xsa "NONE"
409  set part [get_property part [current_project]]
410 
411  # check for explicit EXPORT_XSA flag in hog.conf
412  set properties [ReadConf [lindex [GetConfFiles $repo_path/Top/$group_name/$proj_name] 0]]
413  if {[dict exists $properties "hog"]} {
414  set propDict [dict get $properties "hog"]
415  if {[dict exists $propDict "EXPORT_XSA"]} {
416  set export_xsa [dict get $propDict "EXPORT_XSA"]
417  }
418  }
419 
420  if {$export_xsa == "NONE"} {
421  set export_xsa false
422  if {([IsZynq $part] || [IsVersal $part])} {
423  Msg Info "SoC FPGA detected (Zynq or Versal), automatically enabling XSA file creation. \
424  To disable it, add 'EXPORT_XSA = false' in the \[hog\] section of hog.conf."
425  set export_xsa true
426  } else {
427  # MicroBlaze/RISC-V soft processors are not detectable from the part name.
428  # If an app targets one, export XSA so the ELF can be rebuilt and merged
429  # into the bitstream (same flow as Zynq/Versal software rebuild)
430  set apps [GetAppsFromProps $properties]
431  dict for {app_name app_conf} $apps {
432  if {
433  [dict exists $app_conf "proc"] &&
434  [regexp -nocase {microblaze|risc} [dict get $app_conf "proc"]]
435  } {
436  Msg Info "Soft processor ([dict get $app_conf proc]) detected in app '$app_name', \
437  automatically enabling XSA file creation. \
438  To disable it, add 'EXPORT_XSA = false' in the \[hog\] section of hog.conf."
439  set export_xsa true
440  break
441  }
442  }
443  }
444  }
445 
446  if {[string compare [string tolower $export_xsa] "true"] == 0} {
447  set wrote_xsa 0
448 
449  # There is a bug in Vivado 2020.1, check for that version and warn
450  # that we can't export XSAs
451  regexp -- {Vivado v([0-9]{4}\.[0-9,A-z,_,\.]*) } [version] -> VIVADO_VERSION
452  if {[string compare "2020.1" $VIVADO_VERSION] == 0} {
453  Msg Warning "Vivado 2020.1, a patch must be applied to Vivado to export XSA Files, c.f. https://www.xilinx.com/support/answers/75210.html"
454  } else {
455  set dst_xsa [file normalize "$dst_dir/${proj_name}\-$describe.xsa"]
456  Msg Info "Generating XSA File at $dst_xsa"
457 
458  if {[IsVersal $part]} {
459  # Run user pre-platform file
460  set user_pre_platform_file "./Top/$group_name/$proj_name/pre-platform.tcl"
461  if {[file exists $user_pre_platform_file]} {
462  Msg Info "Sourcing user pre-platform file $user_pre_platform_file"
463  source $user_pre_platform_file
464  }
465 
466  # We do not want to touch the full_pdi_file property if there is a _boot .pdi file
467  if {$secondary_file == ""} {
468  set pdi_post_imp [file normalize "$work_path/$top_name.pdi"]
469  set_property platform.full_pdi_file $pdi_post_imp [current_project]
470  Msg Info "XSA file will be generated for Versal with this PDI: $pdi_post_imp"
471  WriteHwPlatformWorkaround $proj_dir $proj_name $work_path "-fixed -force -file {$dst_xsa}"
472  set wrote_xsa 1
473  }
474  Msg Warning "No XSA will be produced in post-bitream for segmented configuration mode. \
475  If you're running with the GUI, please type the following on the Tcl console: write_hw_platform -fixed -force -file $dst_xsa."
476  } else {
477  # We leave include bit also for Versal
478  WriteHwPlatformWorkaround $proj_dir $proj_name $work_path \
479  "-include_bit -fixed -force -file {$dst_xsa}"
480  set wrote_xsa 1
481  }
482  }
483 
484  if {$wrote_xsa == 1} {
485  # Determine project type from configuration file
486  set conf_file [lindex [GetConfFiles $repo_path/Top/$group_name/$proj_name] 0]
487  set is_vitis_classic 0
488  set is_vitis_unified 0
489 
490  if {[file exists $conf_file]} {
491  set ide_name_and_ver [GetIDEFromConf $conf_file]
492  set ide_name [string tolower [lindex $ide_name_and_ver 0]]
493  if {[string match "*vitis_classic*" $ide_name] || [string match "*vivado_vitis_classic*" $ide_name]} {
494  set is_vitis_classic 1
495  } elseif {[string match "*vitis_unified*" $ide_name] || [string match "*vivado_vitis_unified*" $ide_name]} {
496  set is_vitis_unified 1
497  }
498  }
499 
500  if {$is_vitis_classic || $is_vitis_unified} {
501  Msg Info "XSA file written to $dst_xsa"
502 
503  set full_proj_name [file join $group_name $proj_name]
504 
505  # Determine command based on project type
506  if {$is_vitis_classic} {
507  set vitis_cmd "xsct $tcl_path/launch.tcl CW -xsa $dst_xsa -vitis_only $full_proj_name"
508  set vitis_type "Vitis Classic"
509  set error_prefix "xsct (vitis classic)"
510  } elseif {$is_vitis_unified} {
511  set vitis_cmd "$tcl_path/launch.tcl CW -xsa $dst_xsa -vitis_only $full_proj_name"
512  set vitis_type "Vitis Unified"
513  set error_prefix "vivado (for vitis unified)"
514  } else {
515  Msg Error "No Vitis project type found."
516  return
517  }
518 
519  Msg Info "Running $vitis_type to create elf file with cmd: $vitis_cmd"
520  set ret [catch {exec -ignorestderr {*}$vitis_cmd >@ stdout} result]
521  if {$ret != 0} {
522  Msg Error "$error_prefix returned an error state."
523  }
524 
525  # Copy ELF files from Vitis build output into bin directory
526  # Extract app names preserving original case from hog.conf,
527  # since Vitis creates directories matching the original case
528  set app_names [list]
529  foreach prop_key [dict keys $properties] {
530  if {[regexp {^app:(.+)$} $prop_key -> raw_app_name]} {
531  lappend app_names [string trim $raw_app_name]
532  }
533  }
534  foreach app_name $app_names {
535  if {$is_vitis_unified} {
536  set elf_src [file normalize "$repo_path/Projects/$full_proj_name/vitis_unified/$app_name/build/$app_name.elf"]
537  } else {
538  set elf_src [file normalize "$repo_path/Projects/$full_proj_name/vitis_classic/$app_name/Release/$app_name.elf"]
539  }
540  set elf_dst [file normalize "$dst_dir/${proj_name}\-${app_name}\-$describe.elf"]
541  if {[file exists $elf_src]} {
542  Msg Info "Copying ELF $elf_src into $elf_dst..."
543  file copy -force $elf_src $elf_dst
544  } else {
545  Msg Warning "ELF file not found: $elf_src"
546  }
547  }
548 
549  # Process ELF files and update bitstream with memory content
550  set mmi_file [file normalize "$dst_dir/${proj_name}\-$describe.mmi"]
551  GenerateBootArtifacts $properties $repo_path $proj_dir $dst_dir $proj_name $describe $dst_main $mmi_file
552  }
553  }
554  }
555 }
556 
557 
558 # Run user post-bitstream file
559 set user_post_bitstream_file "./Top/$group_name/$proj_name/post-bitstream.tcl"
560 if {[file exists $user_post_bitstream_file]} {
561  Msg Info "Sourcing user post-bitstream file $user_post_bitstream_file"
562  source $user_post_bitstream_file
563 }
564 
565 Notify Info "Completed bitstream of $proj_name."
566 
567 cd $old_path
568 Msg Info "All done."