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