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