Hog Hog2024.2-4
pre-synthesis.tcl
Go to the documentation of this file.
1 #!/usr/bin/env tclsh
2 # Copyright 2018-2024 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 pre synthesis script checks the status of your git repository and stores into a set of variables that are fed as generics to the HDL project.
18 # This script is automatically integrated into the Vivado/Quartus workflow by the Create Project script.
19 
20 ##nagelfar variable quartus
21 ##nagelfar variable project
22 
23 set tcl_path [file normalize "[file dirname [info script]]/.."]
24 source $tcl_path/hog.tcl
25 
26 # Import tcllib
27 if {[IsSynplify]} {
28  if {[info exists env(HOG_TCLLIB_PATH)]} {
29  lappend auto_path $env(HOG_TCLLIB_PATH)
30  } else {
31  puts "ERROR: To run Hog with Microsemi Libero SoC, you need to define the HOG_TCLLIB_PATH variable."
32  return
33  }
34 }
35 
36 if {[IsLibero]} {
37  puts "I am running Libero"
38 }
39 
40 if {[catch {package require struct::matrix} ERROR]} {
41  puts "$ERROR\n If you are running this script on tclsh, you can fix this by installing 'tcllib'"
42  return
43 }
44 
45 
46 
47 if {[IsISE]} {
48  # Vivado + PlanAhead
49  set old_path [file normalize "../../Projects/$project/$project.runs/synth_1"]
50  file mkdir $old_path
51 } else {
52  set old_path [pwd]
53 }
54 
55 if {[info exists env(HOG_EXTERNAL_PATH)]} {
56  set ext_path $env(HOG_EXTERNAL_PATH)
57  Msg Info "Found environment variable HOG_EXTERNAL_PATH, setting path for external files to $ext_path..."
58 } else {
59  set ext_path ""
60 }
61 
62 if {[IsXilinx]} {
63  # Vivado + PlanAhead
64  if {[IsISE]} {
65  set proj_file [get_property DIRECTORY [current_project]]
66  } else {
67  set proj_file [get_property parent.project_path [current_project]]
68  }
69  set proj_dir [file normalize [file dirname $proj_file]]
70  set proj_name [file rootname [file tail $proj_file]]
71 } elseif {[IsQuartus]} {
72  # Quartus
73  set proj_name [lindex $quartus(args) 1]
74  #set proj_dir [file normalize "$repo_path/Projects/$proj_name"]
75  set proj_dir [pwd]
76  set proj_file [file normalize "$proj_dir/$proj_name.qpf"]
77  # Test generated files
78  set hogQsysFileName [file normalize "$proj_dir/.hog/.hogQsys.md5"]
79  if { [file exists $hogQsysFileName] != 0} {
80  set hogQsysFile [open $hogQsysFileName r]
81  set hogQsysFileLines [split [read $hogQsysFile] "\n"]
82  foreach line $hogQsysFileLines {
83  set fileEntry [split $line "\t"]
84  set fileEntryName [lindex $fileEntry 0]
85  if {$fileEntryName != ""} {
86  if {[file exists $fileEntryName]} {
87  set newMd5Sum [Md5Sum $fileEntryName]
88  set oldMd5Sum [lindex $fileEntry 1]
89  if { $newMd5Sum != $oldMd5Sum } {
90  Msg Warning "The checksum for file $fileEntryName not equal to the one saved in $hogQsysFileName: new checksum $newMd5Sum, old checksum $oldMd5Sum. Please check the any changes in the file are correctly propagated to git!"
91  }
92  } else {
93  Msg Warning "File $fileEntryName not found... Will not check Md5Sum!"
94  }
95  }
96  }
97 
98  }
99 } elseif {[IsSynplify]} {
100  set proj_dir [file normalize [file dirname "[project_data -dir]/../.."] ]
101  set proj_name [file tail $proj_dir]
102  set project $proj_name
103 } else {
104  #Tclssh
105  set proj_file $old_path/[file tail $old_path].xpr
106  set proj_dir [file normalize [file dirname $proj_file]]
107  set proj_name [file rootname [file tail $proj_file]]
108  Msg CriticalWarning "You seem to be running locally on tclsh, so this is a debug, the project file will be set to $proj_file and was derived from the path you launched this script from: $old_path. If you want this script to work properly in debug mode, please launch it from the top folder of one project, for example Repo/Projects/fpga1/ or Repo/Top/fpga1/"
109 }
110 
111 # Go to repository path
112 set repo_path [file normalize "$tcl_path/../.."]
113 cd $repo_path
114 
115 set group [GetGroupName $proj_dir "$tcl_path/../.."]
116 
117 # Calculating flavour if any
118 set flavour [string map {. ""} [file extension $proj_name]]
119 if {$flavour != ""} {
120  if {[string is integer $flavour]} {
121  Msg Info "Project $proj_name has flavour = $flavour, the generic variable FLAVOUR will be set to $flavour"
122  } else {
123  Msg Warning "Project name has a unexpected non numeric extension, flavour will be set to -1"
124  set flavour -1
125  }
126 
127 } else {
128  set flavour -1
129 }
130 
131 ######## Reset files before synthesis ###########
132 ResetRepoFiles "./Projects/hog_reset_files"
133 
134 # Getting all the versions and SHAs of the repository
135 lassign [GetRepoVersions [file normalize $repo_path/Top/$group/$proj_name] $repo_path $ext_path] commit version hog_hash hog_ver top_hash top_ver libs hashes vers cons_ver cons_hash ext_names ext_hashes xml_hash xml_ver user_ip_repos user_ip_hashes user_ip_vers
136 
137 
138 set describe [GetHogDescribe $commit $repo_path]
139 set dst_dir [file normalize "bin/$group/$proj_name\-$describe"]
140 Msg Info "Creating $dst_dir..."
141 file mkdir $dst_dir/reports
142 
143 
144 #check list files and project properties
145 set confDict [dict create]
146 set allow_fail_on_conf 0
147 set allow_fail_on_list 0
148 set allow_fail_on_git 0
149 set full_diff_log 0
150 if {[file exists "$tcl_path/../../Top/$group/$proj_name/hog.conf"]} {
151  set confDict [ReadConf "$tcl_path/../../Top/$group/$proj_name/hog.conf"]
152  set allow_fail_on_check [DictGet [DictGet $confDict "hog"] "ALLOW_FAIL_ON_CHECK" 0]
153  set allow_fail_on_git [DictGet [DictGet $confDict "hog"] "ALLOW_FAIL_ON_GIT" 0]
154  set full_diff_log [DictGet [DictGet $confDict "hog"] "FULL_DIFF_LOG" 0]
155 }
156 
157 
158 set this_commit [GetSHA]
159 
160 if {[IsVivado]} {
161  ##nagelfar ignore
162  if {![string equal ext_path ""]} {
163  set argv [list "-ext_path" "$ext_path" "-project" "$group/$proj_name" "-outDir" "$dst_dir" "-log" "[expr {!$allow_fail_on_check}]"]
164  } else {
165  set argv [list "-project" "$group/$proj_name" "-outDir" "$dst_dir" "-log" "[expr {!$allow_fail_on_check}]"]
166  }
167  source $tcl_path/utils/check_list_files.tcl
168  if {[file exists "$dst_dir/diff_list_and_conf.txt"]} {
169  Msg CriticalWarning "Project list or hog.conf mismatch, will use current SHA ($this_commit) and version will be set to 0."
170  set commit 0000000
171  set version 00000000
172  }
173 } elseif {[IsQuartus]} {
174  # Quartus
175  #TO BE IMPLEMENTED
176 } else {
177  #Tclssh
178 }
179 
180 Msg Info "Evaluating non committed changes..."
181 set found_uncommitted 0
182 set diff [Git diff]
183 set diff_stat [Git "diff --stat"]
184 if {$diff != ""} {
185  set found_uncommitted 1
186  Msg Warning "Found non committed changes:..."
187  if {$full_diff_log} {
188  Msg Status "$diff"
189  } else {
190  Msg Status "$diff_stat"
191  }
192  set fp [open "$dst_dir/diff_presynthesis.txt" w+]
193  puts $fp "$diff"
194  close $fp
195  Msg CriticalWarning "Repository is not clean, will use current SHA ($this_commit) and create a dirty bitfile..."
196 }
197 
198 lassign [GetHogFiles -ext_path "$ext_path" "$tcl_path/../../Top/$group/$proj_name/list/" "$tcl_path/../../"] listLibraries listProperties
199 
200 if {!$allow_fail_on_git} {
201  foreach library [dict keys $listLibraries] {
202  set fileNames [dict get $listLibraries $library]
203  foreach fileName $fileNames {
204  if {[FileCommitted $fileName] == 0} {
205  set fp [open "$dst_dir/diff_presynthesis.txt" a+]
206  set found_uncommitted 1
207  puts $fp "\n[Relative $tcl_path/../../ $fileName] is not in the git repository"
208  Msg CriticalWarning "[Relative $tcl_path/../../ $fileName] is not in the git repository. Will use current SHA ($this_commit) and version will be set to 0."
209  close $fp
210  }
211  }
212  }
213 }
214 if {$found_uncommitted == 0} {
215  Msg Info "No uncommitted changes found."
216 } else {
217  set commit 0000000
218  set version 00000000
219 }
220 
221 
222 # Check if repository has v0.0.1 tag
223 lassign [GitRet "tag -l v0.0.1" ] status result
224 if {$status == 1} {
225  Msg CriticalWarning "Repository does not have an initial v0.0.1 tag yet. Please create it with \"git tag v0.0.1\" "
226 }
227 
228 
229 Msg Info "Git describe for $commit is: $describe"
230 
231 if {$commit == 0 } {
232  set commit $this_commit
233 } else {
234  Msg Info "Found last SHA for $proj_name: $commit"
235  if {$commit != $this_commit} {
236  set count [Git "rev-list --count $commit..$this_commit"]
237  Msg Info "The commit in which project $proj_name was last modified is $commit, that is $count commits older than current commit $this_commit."
238  }
239 }
240 
241 if {$xml_hash != ""} {
242  set xml_dst [file normalize $old_path/../xml]
243  Msg Info "Creating XML directory $xml_dst..."
244  file mkdir $xml_dst
245  Msg Info "Copying xml files to $xml_dst and replacing placeholders with xml version $xml_ver..."
246  CopyXMLsFromListFile ./Top/$group/$proj_name/list/xml.lst ./ $xml_dst [HexVersionToString $xml_ver] $xml_hash
247  set use_ipbus 1
248 } else {
249  set use_ipbus 0
250 }
251 
252 #number of threads
253 set maxThreads [GetMaxThreads [file normalize ./Top/$group/$proj_name/]]
254 if {$maxThreads != 1} {
255  Msg CriticalWarning "Multithreading enabled. Bitfile will not be deterministic. Number of threads: $maxThreads"
256 } else {
257  Msg Info "Disabling multithreading to assure deterministic bitfile"
258 }
259 
260 if {[IsXilinx]} {
261  ### Vivado
262  set_param general.maxThreads $maxThreads
263 } elseif {[IsQuartus]} {
264  # QUARTUS
265  if { [catch {package require ::quartus::project} ERROR] } {
266  Msg Error "$ERROR\n Can not find package ::quartus::project"
267  cd $old_path
268  return 1
269  }
270  set this_dir [pwd]
271  cd $proj_dir
272  project_open $proj_name -current_revision
273  cd $this_dir
274  set_global_assignment -name NUM_PARALLEL_PROCESSORS $maxThreads
275  project_close
276 } elseif {[IsSynplify]} {
277  set_option -max_parallel_jobs $maxThreads
278 } else {
279  ### Tcl Shell
280  puts "Hog:DEBUG MaxThread is set to: $maxThreads"
281 }
282 
283 set clock_seconds [clock seconds]
284 set tt [clock format $clock_seconds -format {%d/%m/%Y at %H:%M:%S}]
285 
286 if {[GitVersion 2.9.3]} {
287  set date [Git "log -1 --format=%cd --date=format:%d%m%Y $commit"]
288  set timee [Git "log -1 --format=%cd --date=format:00%H%M%S $commit"]
289 } else {
290  Msg Warning "Found Git version older than 2.9.3. Using current date and time instead of commit time."
291  set date [clock format $clock_seconds -format {%d%m%Y}]
292  set timee [clock format $clock_seconds -format {00%H%M%S}]
293 }
294 
295 ##### Passing Hog generic to top file
296 if {[IsXilinx] || [IsSynplify]} {
297  ### VIVADO
298  set proj_path "$group/$proj_name"
299  # set global generic variables
300  WriteGenerics "synth" $proj_path $date $timee $commit $version $top_hash $top_ver $hog_hash $hog_ver $cons_ver $cons_hash $libs $vers $hashes $ext_names $ext_hashes $user_ip_repos $user_ip_vers $user_ip_hashes $flavour $xml_ver $xml_hash
301  set status_file [file normalize "$old_path/../versions.txt"]
302 
303 } elseif {[IsQuartus]} {
304  #Quartus
305  if { [catch {package require ::quartus::project} ERROR] } {
306  Msg Error "$ERROR\n Can not find package ::quartus::project"
307  cd $old_path
308  return 1
309  }
310  set this_dir [pwd]
311  cd $proj_dir
312  project_open $proj_name -current_revision
313  cd $this_dir
314 
315  set zero_ttb 00000000
316 
317  binary scan [binary format H* [string map {{'} {}} $date]] B32 bits
318  set_parameter -name GLOBAL_DATE $bits
319  binary scan [binary format H* [string map {{'} {}} $timee]] B32 bits
320  set_parameter -name GLOBAL_TIME $bits
321  binary scan [binary format H* [string map {{'} {}} $version]] B32 bits
322  set_parameter -name GLOBAL_VER $bits
323  binary scan [binary format H* [string map {{'} {}} $commit]] B32 bits
324  set_parameter -name GLOBAL_SHA $bits
325  binary scan [binary format H* [string map {{'} {}} $top_hash]] B32 bits
326  set_parameter -name TOP_SHA $bits
327  binary scan [binary format H* [string map {{'} {}} $top_ver]] B32 bits
328  set_parameter -name TOP_VER $bits
329  binary scan [binary format H* [string map {{'} {}} $hog_hash]] B32 bits
330  set_parameter -name HOG_SHA $bits
331  binary scan [binary format H* [string map {{'} {}} $hog_ver]] B32 bits
332  set_parameter -name HOG_VER $bits
333  binary scan [binary format H* [string map {{'} {}} $cons_ver]] B32 bits
334  set_parameter -name CON_VER $bits
335  binary scan [binary format H* [string map {{'} {}} $cons_hash]] B32 bits
336  set_parameter -name CON_SHA $bits
337 
338  if {$use_ipbus == 1} {
339  binary scan [binary format H* [string map {{'} {}} $xml_ver]] B32 bits
340  set_parameter -name XML_VER $bits
341  binary scan [binary format H* [string map {{'} {}} $xml_hash]] B32 bits
342  set_parameter -name XML_SHA $bits
343  }
344 
345  #set project specific lists
346  foreach l $libs v $vers h $hashes {
347  binary scan [binary format H* [string map {{'} {}} $v]] B32 bits
348  set_parameter -name "[string toupper $l]_VER" $bits
349  binary scan [binary format H* [string map {{'} {}} $h]] B32 bits
350  set_parameter -name "[string toupper $l]_SHA" $bits
351  }
352 
353  foreach e $ext_names h $ext_hashes {
354  binary scan [binary format H* [string map {{'} {}} $h]] B32 bits
355  set_parameter -name "[string toupper $e]_SHA" $bits
356  }
357 
358  if {$flavour != -1} {
359  set_parameter -name FLAVOUR $flavour
360  }
361 
362  if {![file exists "$old_path/output_files"]} {
363  file mkdir "$old_path/output_files"
364  }
365 
366  set status_file "$old_path/output_files/versions.txt"
367  project_close
368 
369 } else {
370  ### Tcl Shell
371  puts "Hog:DEBUG GLOBAL_DATE=$date GLOBAL_TIME=$timee"
372  puts "Hog:DEBUG GLOBAL_SHA=$commit TOP_SHA=$top_hash"
373  puts "Hog:DEBUG CON_VER=$cons_ver CON_SHA=$cons_hash"
374  puts "Hog:DEBUG XML_SHA=$xml_hash GLOBAL_VER=$version TOP_VER=$top_ver"
375  puts "Hog:DEBUG XML_VER=$xml_ver HOG_SHA=$hog_hash HOG_VER=$hog_ver"
376  puts "Hog:DEBUG LIBS: $libs $vers $hashes"
377  puts "Hog:DEBUG EXT: $ext_names $ext_hashes"
378  puts "Hog:DEBUG FLAVOUR: $flavour"
379  set status_file "$old_path/versions.txt"
380 
381 }
382 Msg Info "Opening version file $status_file..."
383 set status_file [open $status_file "w+"]
384 
385 Msg Status " ------------------------- PRE SYNTHESIS -------------------------"
386 Msg Status " $tt"
387 Msg Status " Firmware date and time: $date, $timee"
388 if {$flavour != -1} {
389  Msg Status " Project flavour: $flavour"
390 }
391 
392 set version [HexVersionToString $version]
393 if {$group != ""} {
394  puts $status_file "## $group/$proj_name Version Table\n"
395 } else {
396  puts $status_file "## $proj_name Version Table\n"
397 }
398 
399 struct::matrix m
400 m add columns 7
401 
402 m add row "| \"**File set**\" | \"**Commit SHA**\" | **Version** |"
403 m add row "| --- | --- | --- |"
404 Msg Status " Global SHA: $commit, VER: $version"
405 m add row "| Global | $commit | $version |"
406 
407 set cons_ver [HexVersionToString $cons_ver]
408 Msg Status " Constraints SHA: $cons_hash, VER: $cons_ver"
409 m add row "| Constraints | $cons_hash | $cons_ver |"
410 
411 if {$use_ipbus == 1} {
412  set xml_ver [HexVersionToString $xml_ver]
413  Msg Status " IPbus XML SHA: $xml_hash, VER: $xml_ver"
414  m add row "| \"IPbus XML\" | $xml_hash | $xml_ver |"
415 }
416 set top_ver [HexVersionToString $top_ver]
417 Msg Status " Top SHA: $top_hash, VER: $top_ver"
418 m add row "| \"Top Directory\" | $top_hash | $top_ver |"
419 
420 set hog_ver [HexVersionToString $hog_ver]
421 Msg Status " Hog SHA: $hog_hash, VER: $hog_ver"
422 m add row "| Hog | $hog_hash | $hog_ver |"
423 
424 Msg Status " --- Libraries ---"
425 foreach l $libs v $vers h $hashes {
426  set v [HexVersionToString $v]
427  Msg Status " $l SHA: $h, VER: $v"
428  m add row "| \"**Lib:** $l\" | $h | $v |"
429 }
430 
431 if {[llength $user_ip_repos] > 0} {
432 
433  Msg Status " --- User IP Repositories ---"
434  foreach r $user_ip_repos v $user_ip_vers h $user_ip_hashes {
435  set v [HexVersionToString $v]
436  set repo_name [file tail $r]
437  Msg Status " $repo_name SHA: $h, VER: $v"
438  m add row "| \"**Repo:** $repo_name\" | $h | $v |"
439  }
440 }
441 
442 if {[llength $ext_names] > 0} {
443  Msg Status " --- External Libraries ---"
444  foreach e $ext_names eh $ext_hashes {
445  Msg Status " $e SHA: $eh"
446  m add row "| \"**Ext:** $e\" | $eh | \" \" |"
447  }
448 }
449 
450 Msg Status " -----------------------------------------------------------------"
451 
452 puts $status_file [m format 2string]
453 puts $status_file "\n\n"
454 close $status_file
455 
456 if {[IsXilinx]} {
457  CheckYmlRef [file normalize $tcl_path/../..] true
458 }
459 
460 set user_pre_synthesis_file "./Top/$group/$proj_name/pre-synthesis.tcl"
461 if {[file exists $user_pre_synthesis_file]} {
462  Msg Info "Sourcing user pre-synthesis file $user_pre_synthesis_file"
463  source $user_pre_synthesis_file
464 }
465 
466 cd $old_path
467 
468 Msg Info "All done."