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