Hog v9.50.0
post-bitstream.tcl
Go to the documentation of this file.
1 #!/usr/bin/env tclsh
2 # Copyright 2018-2025 The University of Birmingham
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
17 # The post bitstream script copies binary files, reports and other files to the bin directory in your repository.
18 # This script is automatically integrated into the Vivado/Quartus workflow by the Create Project script.
19 
20 set old_path [pwd]
21 set tcl_path [file normalize "[file dirname [info script]]/.."]
22 source $tcl_path/hog.tcl
23 set repo_path [file normalize "$tcl_path/../../"]
24 
25 # Import tcllib
26 if {[IsLibero] || [IsDiamond]} {
27  if {[info exists env(HOG_TCLLIB_PATH)]} {
28  lappend auto_path $env(HOG_TCLLIB_PATH)
29  } else {
30  puts "ERROR: To run Hog with Microsemi Libero SoC, you need to define the HOG_TCLLIB_PATH variable."
31  return
32  }
33 }
34 
35 if {[info exists env(HOG_EXTERNAL_PATH)]} {
36  set ext_path $env(HOG_EXTERNAL_PATH)
37  Msg Info "Found environment variable HOG_EXTERNAL_PATH, setting path for external files to $ext_path..."
38 } else {
39  set ext_path ""
40 }
41 
42 set bin_dir [file normalize "$repo_path/bin"]
43 
44 if {[IsXilinx]} {
45  # Binary files are called .bit for ISE and for Vivado unless the chip is a Versal
46  set fw_file_ext "bit"
47 
48  # Vivado + PlanAhead
49  if {[IsISE]} {
50  # planAhead
51  set work_path [get_property DIRECTORY [get_runs impl_1]]
52  } else {
53  # Vivado
54  set work_path $old_path
55  if {[IsVersal [get_property PART [current_design]]]} {
56  #In Vivado if a Versal chip is used, the main binary file is called .pdi
57  set fw_file_ext "pdi"
58  }
59  }
60 
61  set main_files [lsort [glob -nocomplain "$work_path/*.$fw_file_ext"]]
62  if {[llength $main_files] > 1} {
63  #In case of segmented configuration on Versal there are 2 .pdi files: <top>_boot.pdi and <top>_pld.pdi
64  # Main file is the pld, so not the first
65  set main_file [file normalize [lindex $main_files 1]]
66  # Secondary file is the boot, so the first!
67  set secondary_file [file normalize [lindex $main_files 0]]
68  set main_file_suffix "_pld"
69  set secondary_file_suffix "_boot"
70  Msg Info "Found main and secondary binary file main: [file tail $main_file], secondary: [file tail $secondary_file]..."
71  # remove _pld suffix only at the end
72  set top_name [regsub $main_file_suffix\$ [file rootname [file tail $main_file]] ""]
73  if {[llength $main_files] > 2} {
74  Msg Warning "Multiple (more than 2) binary files found: $main_files."
75  }
76  } else {
77  set main_file [file normalize [lindex $main_files 0]]
78  set main_file_suffix ""
79  set secondary_file ""
80  set secondary_file_suffix ""
81  set top_name [file rootname [file tail $main_file]]
82  }
83 
84 
85 
86 
87 
88  set proj_name [file tail [file normalize $work_path/../../]]
89  set proj_dir [file normalize "$work_path/../.."]
90 
91 
92 
93  set additional_ext ".bin .ltx .bif"
94 
95  set xml_dir [file normalize "$work_path/../xml"]
96  set run_dir [file normalize "$work_path/.."]
97 
98 } elseif {[IsQuartus]} {
99  # Quartus
100  ##nagelfar ignore Unknown variable
101  set proj_name [lindex $quartus(args) 1]
102  set proj_dir [pwd]
103  set xml_dir [file normalize "$repo_path/xml"]
104  set run_dir [file normalize "$proj_dir"]
105  set name [file rootname [file tail [file normalize [pwd]]]]
106  # programming object file
107  set pof_file [file normalize "$proj_dir/output_files/$proj_name.pof"]
108  # SRAM Object File
109  set sof_file [file normalize "$proj_dir/output_files/$proj_name.sof"]
110  # raw binary file
111  set rbf_file [file normalize "$proj_dir/output_files/$proj_name.rbf"]
112  #raw programming file
113  set rpd_file [file normalize "$proj_dir/output_files/$proj_name.rpd"]
114  # signal tap file
115  set stp_file [file normalize "$proj_dir/output_files/$proj_name.stp"]
116  #source and probes file
117  set spf_file [file normalize "$proj_dir/output_files/$proj_name.spf"]
118 
119 } elseif {[IsLibero]} {
120  # Libero
121  ##nagelfar ignore Unknown variable
122  set proj_name $project
123  ##nagelfar ignore Unknown variable
124  set proj_dir $main_folder
125  set map_file [file normalize [lindex [glob -nocomplain "$proj_dir/synthesis/*.map"] 0]]
126  set sap_file [file normalize [lindex [glob -nocomplain "$proj_dir/synthesis/*.sap"] 0]]
127  set srd_file [file normalize [lindex [glob -nocomplain "$proj_dir/synthesis/*.srd"] 0]]
128  set srm_file [file normalize [lindex [glob -nocomplain "$proj_dir/synthesis/*.srm"] 0]]
129  set srs_file [file normalize [lindex [glob -nocomplain "$proj_dir/synthesis/*.srs"] 0]]
130  set srr_file [file normalize [lindex [glob -nocomplain "$proj_dir/synthesis/*.srr"] 0]]
131  set top_name [file rootname [file tail $srr_file]]
132  set stxt_files [glob -nocomplain "$proj_dir/synthesis/*.txt"]
133  set scsv_files [glob -nocomplain "$proj_dir/synthesis/*.csv"]
134  set slog_files [glob -nocomplain "$proj_dir/synthesis/*.log"]
135  set srpt_files [glob -nocomplain "$proj_dir/synthesis/*.rpt"]
136  set dtxt_files [glob -nocomplain "$proj_dir/designer/$top_name/*.txt"]
137  set dcsv_files [glob -nocomplain "$proj_dir/designer/$top_name/*.csv"]
138  set dlog_files [glob -nocomplain "$proj_dir/designer/$top_name/*.log"]
139  set drpt_files [glob -nocomplain "$proj_dir/designer/$top_name/*.rpt"]
140  set xml_dir [file normalize "$repo_path/xml"]
141 
142 } elseif {[IsDiamond]} {
143  set proj_dir [file normalize "[pwd]/.."]
144  set proj_name [file tail $proj_dir]
145  set project $proj_name
146  set xml_dir [file normalize "$repo_path/xml"]
147  set main_file [file normalize "$proj_dir/Implementation0/${proj_name}_Implementation0" ]
148 } else {
149  #tcl shell
150  set work_path $old_path
151  set fw_file [file normalize [lindex [glob -nocomplain "$work_path/*.bit"] 0]]
152  set proj_name [file tail [file normalize $work_path/../../]]
153  set proj_dir [file normalize "$work_path/../.."]
154 
155  set top_name [file rootname [file tail $fw_file]]
156 
157  set main_file [file normalize "$work_path/$top_name.bit"]
158  set bin_file [file normalize "$work_path/$top_name.bin"]
159  set ltx_file [file normalize "$work_path/$top_name.ltx"]
160 
161  set xml_dir [file normalize "$work_path/../xml"]
162  set run_dir [file normalize "$work_path/.."]
163 }
164 
165 set group_name [GetGroupName $proj_dir "$tcl_path/../.."]
166 # Go to repository path
167 cd $repo_path
168 
169 Msg Info "Evaluating Git sha for $proj_name..."
170 lassign [GetRepoVersions [file normalize ./Top/$group_name/$proj_name] $repo_path] sha
171 
172 set describe [GetHogDescribe $sha $repo_path]
173 Msg Info "Hog describe set to: $describe"
174 
175 set dst_dir [file normalize "$bin_dir/$group_name/$proj_name\-$describe"]
176 set dst_xml [file normalize "$dst_dir/xml"]
177 
178 Msg Info "Creating $dst_dir..."
179 file mkdir $dst_dir
180 
181 set ts [clock format [clock seconds] -format {%Y-%m-%d-%H-%M}]
182 
183 
184 # Vivado
185 if {[IsXilinx] && [file exists $main_file]} {
186  set dst_main [file normalize "$dst_dir/$proj_name$main_file_suffix\-$describe.$fw_file_ext"]
187  Msg Info "Copying main binary file $main_file into $dst_main..."
188  file copy -force $main_file $dst_main
189  if {$secondary_file != ""} {
190  set dst_secondary [file normalize "$dst_dir/$proj_name$secondary_file_suffix\-$describe.$fw_file_ext"]
191  Msg Info "Copying secondary binary file $secondary_file into $dst_secondary..."
192  file copy -force $secondary_file $dst_secondary
193  }
194 
195 
196 
197 
198  # Additional files
199  # In case of Segmented Configuration, there are 2 files per extension.
200  set ltx_files {}
201  if {$main_file_suffix != ""} {
202  foreach e $additional_ext {
203  lappend new_ext $e
204  lappend new_ext $main_file_suffix$e
205  lappend new_ext $secondary_file_suffix$e
206  lappend ltx_files "$top_name.ltx"
207  lappend ltx_files "$top_name$main_file_suffix.ltx"
208  lappend ltx_files "$top_name$secondary_file_suffix.ltx"
209  }
210  set additional_ext $new_ext
211  }
212 
213 
214  # LTX file for ILA, needs a special treatment...
215  foreach l $ltx_files {
216  set ltx_file "$work_path/$l"
217  if {[file exists $ltx_file]} {
218  Msg Info "Writing debug probes for $ltx_file..."
219  write_debug_probes -quiet $ltx_file
220  }
221  }
222 
223  foreach e $additional_ext {
224  set orig [file normalize "$work_path/$top_name$e"]
225  set dst [file normalize "$dst_dir/$proj_name\-$describe$e"]
226  if {[file exists $orig]} {
227  Msg Info "Copying $orig file into $dst..."
228  file copy -force $orig $dst
229  } else {
230  Msg Debug "File: $orig not found."
231  }
232 
233  }
234 
235 
236 
237 } elseif {[IsQuartus]} {
238 
239  set dst_pof [file normalize "$dst_dir/$name\-$describe.pof"]
240  set dst_sof [file normalize "$dst_dir/$name\-$describe.sof"]
241  set dst_rbf [file normalize "$dst_dir/$name\-$describe.rbf"]
242  set dst_rpd [file normalize "$dst_dir/$name\-$describe.rpd"]
243  set dst_stp [file normalize "$dst_dir/$name\-$describe.stp"]
244  set dst_spf [file normalize "$dst_dir/$name\-$describe.spf"]
245  set dst_xml [file normalize "$dst_dir/xml"]
246 
247  Msg Info "Evaluating differences with last commit..."
248  set found_uncommitted 0
249  set diff [Git diff]
250  if {$diff != ""} {
251  set found_uncommitted 1
252  Msg Warning "Found non committed changes:"
253  Msg Status "$diff"
254  set fp [open "$dst_dir/diff_postbistream.txt" w+]
255  puts $fp "$diff"
256  close $fp
257  }
258 
259  if {$found_uncommitted == 0} {
260  Msg Info "No uncommitted changes found."
261  }
262 
263  #pof file
264  if {[file exists $pof_file]} {
265  Msg Info "Copying pof file $pof_file into $dst_pof..."
266  file copy -force $pof_file $dst_pof
267  } else {
268  Msg Info "No pof file found: $pof_file, that is not a problem"
269  }
270 
271  #Reports
272  file mkdir $dst_dir/reports
273  set reps [glob -nocomplain "$proj_dir/output_files/*.rpt"]
274 
275  if {[file exists [lindex $reps 0]]} {
276  file copy -force {*}$reps $dst_dir/reports
277  } else {
278  Msg Warning "No reports found in $proj_dir/output_files subfolders"
279  }
280 
281  # sof File
282  if {[file exists $sof_file]} {
283  Msg Info "Copying sof file $sof_file into $dst_sof..."
284  file copy -force $sof_file $dst_sof
285  } else {
286  Msg Info "No sof file found: $sof_file, that is not a problem"
287  }
288 
289 
290  #rbf rpd
291  if { [file exists $rbf_file] || [file exists $rpd_file] } {
292  if {[file exists $rbf_file]} {
293  file copy -force $rbf_file $dst_rbf
294  }
295  if {[file exists $rpd_file]} {
296  file copy -force $rpd_file $dst_rpd
297  }
298  } else {
299  Msg Info "No rbf or rpd file found: this is not a problem"
300  }
301 
302  # stp and spf File
303  if {[file exists $stp_file] || [file exists $spf_file]} {
304  if {[file exists $stp_file]} {
305  file copy -force $stp_file $dst_stp
306  }
307  if {[file exists $spf_file]} {
308  file copy -force $spf_file $dst_spf
309  }
310  } else {
311  Msg Info "No stp or spf file found: that is not a problem"
312  }
313 
314 } elseif {[IsLibero] } {
315 
316  set dst_map [file normalize "$dst_dir/$project\-$describe.map"]
317  set dst_sap [file normalize "$dst_dir/$project\-$describe.sap"]
318  set dst_srd [file normalize "$dst_dir/$project\-$describe.srd"]
319  set dst_srm [file normalize "$dst_dir/$project\-$describe.srm"]
320  set dst_srs [file normalize "$dst_dir/$project\-$describe.srs"]
321  set dst_srr [file normalize "$dst_dir/$project\-$describe.srr"]
322  set dst_rpt [file normalize "$dst_dir/reports"]
323  set dst_xml [file normalize "$dst_dir/xml"]
324 
325  file mkdir $dst_dir/reports
326 
327  if {[file exists $map_file]} {
328  Msg Info "Copying map file $map_file into $dst_map..."
329  file copy -force $map_file $dst_map
330  }
331 
332  if {[file exists $sap_file]} {
333  Msg Info "Copying sap file $sap_file into $dst_sap..."
334  file copy -force $sap_file $dst_sap
335  }
336 
337  if {[file exists $srd_file]} {
338  Msg Info "Copying srd file $srd_file into $dst_srd..."
339  file copy -force $srd_file $dst_srd
340  }
341 
342  if {[file exists $srm_file]} {
343  Msg Info "Copying srm file $srm_file into $dst_srm..."
344  file copy -force $srm_file $dst_map
345  }
346 
347  if {[file exists $srs_file]} {
348  Msg Info "Copying srs file $srs_file into $dst_srs..."
349  file copy -force $srs_file $dst_srs
350  }
351 
352  if {[file exists $srr_file]} {
353  Msg Info "Copying srr file $srr_file into $dst_srr..."
354  file copy -force $srr_file $dst_srr
355  }
356 
357 
358  Msg Info "Copying synth txt files $stxt_files into $dst_rpt..."
359  file copy -force {*}$stxt_files $dst_rpt
360  Msg Info "Copying synth csv files $scsv_files into $dst_rpt..."
361  file copy -force {*}$scsv_files $dst_rpt
362  Msg Info "Copying synth log files $slog_files into $dst_rpt..."
363  file copy -force {*}$slog_files $dst_rpt
364  Msg Info "Copying synth rpt files $srpt_files into $dst_rpt..."
365  file copy -force {*}$srpt_files $dst_rpt
366 
367  Msg Info "Copying impl txt files $dtxt_files into $dst_rpt..."
368  file copy -force {*}$dtxt_files $dst_rpt
369  Msg Info "Copying impl csv files $dcsv_files into $dst_rpt..."
370  file copy -force {*}$dcsv_files $dst_rpt
371  Msg Info "Copying impl log files $dlog_files into $dst_rpt..."
372  file copy -force {*}$dlog_files $dst_rpt
373  Msg Info "Copying impl rpt files $drpt_files into $dst_rpt..."
374  file copy -force {*}$drpt_files $dst_rpt
375 
376 } elseif {[IsDiamond] } {
377  set dst_main [file normalize "$dst_dir/$proj_name\-$describe.bit"]
378  Msg Info "Copying main binary file $main_file.bit into $dst_main..."
379  file copy -force $main_file.bit $dst_main
380  Msg Info "Copying binary generation log $main_file.bgn into $dst_dir/reports..."
381  file copy -force $main_file.bgn $dst_dir/reports
382 
383 
384 } else {
385  Msg CriticalWarning "Firmware binary file not found."
386 }
387 
388 
389 # IPbus XML
390 if {[file exists $xml_dir]} {
391  Msg Info "XML directory found, copying xml files from $xml_dir to $dst_xml..."
392  if {[file exists $dst_xml]} {
393  Msg Info "Directory $dst_xml exists, deleting it..."
394  file delete -force $dst_xml
395  }
396  file copy -force $xml_dir $dst_xml
397 }
398 
399 # Zynq XSA Export
400 if {[IsXilinx]} {
401  # Vivado
402  # automatically export for zynqs (checking via regex)
403  set export_xsa "NONE"
404  set part [get_property part [current_project]]
405 
406  # check for explicit EXPORT_XSA flag in hog.conf
407  set properties [ReadConf [lindex [GetConfFiles $repo_path/Top/$group_name/$proj_name] 0]]
408  if {[dict exists $properties "hog"]} {
409  set propDict [dict get $properties "hog"]
410  if {[dict exists $propDict "EXPORT_XSA"]} {
411  set export_xsa [dict get $propDict "EXPORT_XSA"]
412  }
413  }
414 
415  if { $export_xsa == "NONE" } {
416  set export_xsa false
417  if {([IsZynq $part] || [IsVersal $part])} {
418  Msg Info "SoC FPGA detected (Zynq or Versal), automatically enabling XSA file creation. To disable it, add 'EXPORT_XSA = false' in the \[hog\] section of hog.conf."
419  set export_xsa true
420  }
421  }
422 
423  if {[string compare [string tolower $export_xsa] "true"]==0} {
424  # there is a bug in Vivado 2020.1, check for that version and warn
425  # that we can't export XSAs
426  regexp -- {Vivado v([0-9]{4}\.[0-9,A-z,_,\.]*) } [version] -> VIVADO_VERSION
427  if {[string compare "2020.1" $VIVADO_VERSION]==0} {
428  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"
429  } else {
430 
431  set dst_xsa [file normalize "$dst_dir/${proj_name}\-$describe.xsa"]
432  Msg Info "Generating XSA File at $dst_xsa"
433 
434  if { [IsVersal $part] } {
435  # Run user pre-platform file
436  set user_pre_platform_file "./Top/$group_name/$proj_name/pre-platform.tcl"
437  if {[file exists $user_pre_platform_file]} {
438  Msg Info "Sourcing user pre-platform file $user_pre_platform_file"
439  source $user_pre_platform_file
440  }
441 
442  #We do not want to touch the full_pdi_file property if there is a _boot .pdi file
443  if {$secondary_file == ""} {
444  set pdi_post_imp [file normalize "$work_path/$top_name.pdi"]
445  set_property platform.full_pdi_file $pdi_post_imp [current_project]
446  Msg Info "XSA file will be generated for Versal with this PDI: $pdi_post_imp"
447  write_hw_platform -fixed -force -file "$dst_xsa"
448  }
449  Msg Warning "No XSA will be produced in post-bitream for segmented configuration mode. If you're running with the GUI, please type the following on the Tcl console: write_hw_platform -fixed -force -file $dst_xsa."
450 
451  } else {
452  # we leave include bit also for Versal
453  write_hw_platform -include_bit -fixed -force -file "$dst_xsa"
454  }
455  }
456  }
457 }
458 
459 
460 # Run user post-bitstream file
461 set user_post_bitstream_file "./Top/$group_name/$proj_name/post-bitstream.tcl"
462 if {[file exists $user_post_bitstream_file]} {
463  Msg Info "Sourcing user post-bitstream file $user_post_bitstream_file"
464  source $user_post_bitstream_file
465 }
466 
467 cd $old_path
468 Msg Info "All done."