25 set CI_STAGES {"generate_project" "simulate_project"}
26 set CI_PROPS {"-synth_only"}
28 proc ALLOWED_PROPS {} {
29 return [dict create ".vhd" [list "93" "nosynth" "noimpl" "nosim" "1987" "1993" "2008"]\
30 ".vhdl" [list "93" "nosynth" "noimpl" "nosim" "1987" "1993" "2008"]\
31 ".v" [list "SystemVerilog" "verilog_header" "nosynth" "noimpl" "nosim" "1995" "2001"]\
32 ".sv" [list "verilog" "verilog_header" "nosynth" "noimpl" "nosim" "2005" "2009"]\
34 ".udo" [list "nosim"]\
35 ".xci" [list "nosynth" "noimpl" "nosim" "locked"]\
36 ".xdc" [list "nosynth" "noimpl"]\
37 ".tcl" [list "nosynth" "noimpl" "nosim" "source" "qsys" "noadd" "--block-symbol-file" "--clear-output-directory" "--example-design" "--export-qsys-script" "--family" "--greybox" "--ipxact" "--jvm-max-heap-size" "--parallel" "--part" "--search-path" "--simulation" "--synthesis" "--testbench" "--testbench-simulation" "--upgrade-ip-cores" "--upgrade-variation-file"]\
38 ".qsys" [list "nogenerate" "noadd" "--block-symbol-file" "--clear-output-directory" "--example-design" "--export-qsys-script" "--family" "--greybox" "--ipxact" "--jvm-max-heap-size" "--parallel" "--part" "--search-path" "--simulation" "--synthesis" "--testbench" "--testbench-simulation" "--upgrade-ip-cores" "--upgrade-variation-file"]\
39 ".sdc" [list "notiming" "nosynth" "noplace"]\
40 ".pdc" [list "nosynth" "noplace"]]
46 proc GetSimulators {} {
47 set SIMULATORS [list "modelsim" "questa" "riviera" "activehdl" "ies" "vcs"]
53 return [
expr {[info commands get_libero_version] != ""}]
58 return [
expr {[info commands program_version] != ""}]
64 return [
expr {[info commands get_property] != ""}]
70 return [
expr {[string first Vivado [version]] == 0}]
79 return [
expr {[string first PlanAhead [version]] == 0}]
87 return [
expr {[info commands project_new] != ""}]
92 return [
expr {![IsQuartus] && ![IsXilinx] && ![IsLibero] && ![IsSynplify]}]
100 proc IsVersal {part} {
101 if { [regexp {^(xcvp|xcvm|xcve|xcvc|xqvc|xqvm).*} $part] } {
114 if { [regexp {^(xc7z|xczu).*} $part] } {
131 proc BinaryStepName {part} {
133 return "WRITE_DEVICE_IMAGE"
135 return "WRITE_BITSTREAM"
140 proc Msg {level msg {title ""}} {
142 set level [
string tolower $level]
144 if {$title == ""} {
set title [
lindex [
info level [
expr {[info level]-1}]] 0]}
146 if {$level == 0 || $level == "status" || $level == "extra_info"} {
149 }
elseif {$level == 1 || $level == "info"} {
152 }
elseif {$level == 2 || $level == "warning"} {
155 }
elseif {$level == 3 || [
string first "critical" $level] !=-1} {
156 set vlevel {CRITICAL WARNING}
157 set qlevel critical_warning
158 }
elseif {$level == 4 || $level == "error"} {
161 }
elseif {$level == 5 || $level == "debug"} {
162 if {([
info exists ::DEBUG_MODE] && $::DEBUG_MODE == 1) || ([
info exists ::env(HOG_DEBUG_MODE)] && $::env(HOG_DEBUG_MODE) == 1)} {
164 set qlevel extra_info
165 set msg "DEBUG: \[Hog:$title\] $msg"
171 puts "Hog Error: level $level not defined"
178 set status [
catch {send_msg_id Hog:$title-0 $vlevel $msg}]
184 post_message -type $qlevel "Hog:$title $msg"
185 if { $qlevel == "error"} {
190 if {$vlevel != "STATUS"} {
191 puts "$vlevel: \[Hog:$title\] $msg"
196 if {$qlevel == "error"} {
207 proc WriteToFile {File msg} {
208 set f [open $File a+]
221 proc SetProperty {property value object} {
224 set_property $property $value $object
231 puts "***DEBUG Hog:SetProperty $property to $value of $object"
246 proc GetProperty {property object} {
249 return [get_property -quiet $property $object]
256 puts "***DEBUG Hog:GetProperty $property of $object"
257 return "DEBUG_property_value"
268 proc SetParameter {parameter value } {
269 set_param $parameter $value
279 proc AddTopFile {top_module top_file sources} {
282 add_files -norecurse -fileset $sources $top_file
287 set_global_assignment -name $file_type $top_file
289 puts "Adding project top module $top_module"
300 proc SetTopProperty {top_module sources} {
301 Msg Info "Setting TOP property to $top_module module"
304 set_property "top" $top_module $sources
307 set_global_assignment -name TOP_LEVEL_ENTITY $top_module
309 set_root -module $top_module
322 proc GetProject {proj} {
325 return [get_projects $proj]
332 puts "***DEBUG Hog:GetProject $proj"
333 return "DEBUG_project"
349 return [get_runs -quiet $run]
356 puts "***DEBUG Hog:GetRun $run"
370 proc GetFile {file} {
373 set Files [get_files -all $file]
374 set f [
lindex $Files 0]
383 puts "***DEBUG Hog:GetFile $file"
396 proc CreateFileSet {fileset} {
397 set a [create_fileset -srcset $fileset]
410 proc GetFileSet {fileset} {
411 set a [get_filesets $fileset]
420 proc AddFile {file fileset} {
421 add_files -norecurse -fileset $fileset $file
428 proc GetRepoPath {} {
429 return "[
file normalize [
file dirname [
info script]]]/../../"
442 proc CompareVersions {ver1 ver2} {
451 if {[regexp {v(\d+)\.(\d+)\.(\d+)} $ver1 - x y z]} {
452 set ver1 [list $x $y $z]
454 if {[regexp {v(\d+)\.(\d+)\.(\d+)} $ver2 - x y z]} {
455 set ver2 [list $x $y $z]
459 set v1 [
join $ver1 ""]
461 set v2 [
join $ver2 ""]
464 if {[
string is integer $v1] && [
string is integer $v2]} {
466 set ver1 [
expr {[scan [lindex $ver1 0] %d]*100000 + [scan [lindex $ver1 1] %d]*1000 + [scan [lindex $ver1 2] %d]}]
467 set ver2 [
expr {[scan [lindex $ver2 0] %d]*100000 + [scan [lindex $ver2 1] %d]*1000 + [scan [lindex $ver2 2] %d]}]
469 if {$ver1 > $ver2 } {
471 }
elseif {$ver1 == $ver2} {
478 Msg Warning "Version is not numeric: $ver1, $ver2"
490 proc GitVersion {target_version} {
491 set ver [
split $target_version "."]
492 set v [
Git --version]
494 set current_ver [
split [
lindex $v 2] "."]
495 set target [
expr {[lindex $ver 0]*100000 + [lindex $ver 1]*100 + [lindex $ver 2]}]
496 set current [
expr {[lindex $current_ver 0]*100000 + [lindex $current_ver 1]*100 + [lindex $current_ver 2]}]
497 return [
expr {$target <= $current}]
506 proc DoxygenVersion {target_version} {
507 set ver [
split $target_version "."]
508 set v [
Execute doxygen --version]
509 Msg Info "Found doxygen version: $v"
510 set current_ver [
split $v ". "]
511 set target [
expr {[lindex $ver 0]*100000 + [lindex $ver 1]*100 + [lindex $ver 2]}]
512 set current [
expr {[lindex $current_ver 0]*100000 + [lindex $current_ver 1]*100 + [lindex $current_ver 2]}]
514 return [
expr {$target <= $current}]
521 proc FindFileType {file_name} {
522 set extension [
file extension $file_name]
525 set file_extension "USE_SIGNALTAP_FILE"
528 set file_extension "VHDL_FILE"
531 set file_extension "VHDL_FILE"
534 set file_extension "VERILOG_FILE"
537 set file_extension "SYSTEMVERILOG_FILE"
540 set file_extension "SDC_FILE"
543 set file_extension "PDC_FILE"
546 set file_extension "NDC_FILE"
549 set file_extension "FDC_FILE"
552 set file_extension "SOURCE_FILE"
555 set file_extension "IP_FILE"
558 set file_extension "QSYS_FILE"
561 set file_extension "QIP_FILE"
564 set file_extension "SIP_FILE"
567 set file_extension "BSF_FILE"
570 set file_extension "BDF_FILE"
573 set file_extension "COMMAND_MACRO_FILE"
576 set file_extension "VQM_FILE"
579 set file_extension "ERROR"
580 Msg Error "Unknown file extension $extension"
583 return $file_extension
591 proc FindVhdlVersion {file_name} {
592 set extension [
file extension $file_name]
595 set vhdl_version "-hdl_version VHDL_2008"
598 set vhdl_version "-hdl_version VHDL_2008"
621 proc ReadListFile args {
625 if { [
catch {
package require cmdline} ERROR] } {
626 puts "$ERROR\n If you are running this script on tclsh, you can fix this by installing 'tcllib'"
632 {lib.arg "" "The name of the library files will be added to, if not given will be extracted from the file name."}
633 {fileset.arg "" The name of the library, from the main list file}
634 {sha_mode "If set, the list files will be added as well and the IPs will be added to the file rather than to the special ip library. The sha mode should be used when you use the lists to calculate the git SHA, rather than to add the files to the project."}
636 set usage "USAGE: ReadListFile \[options\] <list file> <path>"
637 if {[
catch {
array set options [
cmdline::getoptions args $parameters $usage]}] || [
llength $args] != 2 } {
641 set list_file [
lindex $args 0]
642 set path [
lindex $args 1]
643 set sha_mode $options(sha_mode)
644 set lib $options(lib)
645 set fileset $options(fileset)
647 if { $sha_mode == 1} {
648 set sha_mode_opt "-sha_mode"
655 set lib [
file rootname [
file tail $list_file]]
657 set fp [open $list_file r]
658 set file_data [read $fp]
660 set list_file_ext [
file extension $list_file]
661 switch $list_file_ext {
663 if {$fileset eq ""} {
669 set fileset "constrs_1"
672 set fileset "sources_1"
676 set libraries [dict create]
677 set filesets [dict create]
678 set properties [dict create]
680 set data [
split $file_data "\n"]
681 set n [
llength $data]
682 Msg Debug "$n lines read from $list_file."
687 if {![regexp {^ *$} $line] & ![regexp {^ *\#} $line] } {
688 set file_and_prop [regexp -all -inline {\S+} $line]
689 set srcfile [
lindex $file_and_prop 0]
690 set srcfile "$path/$srcfile"
692 set srcfiles [glob -nocomplain $srcfile]
695 if {$srcfiles != $srcfile && ! [
string equal $srcfiles ""]} {
696 Msg Debug "Wildcard source expanded from $srcfile to $srcfiles"
698 if {![
file exists $srcfile]} {
699 Msg CriticalWarning "File: $srcfile (from list file: $list_file) does not exist."
704 foreach vhdlfile $srcfiles {
705 if {[
file exists $vhdlfile]} {
706 set vhdlfile [
file normalize $vhdlfile]
707 set extension [
file extension $vhdlfile]
709 set prop [
lrange $file_and_prop 1 end]
710 set library [
lindex [regexp -inline {lib\s*=\s*(.+?)\y.*} $prop] 1]
711 if { $library == "" } {
715 if { $extension == $list_file_ext } {
717 Msg Debug "List file $vhdlfile found in list file, recursively opening it..."
718 lassign [
ReadListFile {*}"-lib $library -fileset $fileset $sha_mode_opt $vhdlfile $path"] l p fs
720 set properties [
MergeDict $p $properties]
722 }
elseif {[lsearch {.src .sim .con ReadExtraFileList} $extension] >= 0 } {
724 Msg Error "$vhdlfile cannot be included into $list_file, $extension files must be included into $extension files."
727 regsub -all " *= *" $prop "=" prop
731 if { [
string first "lib=" $p] == -1} {
733 set pos [
string first "=" $p]
737 set prop_name [
string range $p 0 [
expr {$pos - 1}]]
740 dict lappend properties $vhdlfile $p
741 Msg Debug "Adding property $p to $vhdlfile..."
742 }
elseif { $list_file_ext != ".lst" } {
743 Msg Warning "Setting Property $p is not supported for file $vhdlfile or it is already its default. The allowed properties for this file type are \[ [
DictGet [
ALLOWED_PROPS] $extension]\]"
747 if { [lsearch {.xci .ip .bd .xcix} $extension] >= 0} {
749 set lib_name "ips.src"
750 }
elseif { [
IsInList $extension {.vhd .vhdl}] || $list_file_ext == ".sim"} {
752 if { ![
IsInList $extension {.vhd .vhdl}]} {
753 set lib_name "others.sim"
755 set lib_name "$library$list_file_ext"
757 }
elseif { $list_file_ext == ".con" } {
758 set lib_name "sources.con"
759 }
elseif { [
string first "xml.lst" $list_file] != -1 } {
760 set lib_name "xml.lst"
763 set lib_name "others.src"
765 Msg Debug "Appending $vhdlfile to $lib_name list..."
766 dict lappend libraries $lib_name $vhdlfile
767 if {[
file type $vhdlfile] eq "link"} {
770 dict lappend libraries $lib_name $real_file
771 Msg Debug "File $vhdlfile is a soft link, also adding the real file: $real_file"
776 if {[dict exists $filesets $fileset] == 0} {
778 Msg Debug "Adding $fileset to the fileset dictionary..."
779 Msg Debug "Adding library $lib_name to fileset $fileset..."
780 dict set filesets $fileset $lib_name
784 Msg Debug "Adding library $lib_name to fileset $fileset..."
785 dict lappend filesets $fileset $lib_name
791 Msg CriticalWarning "File $vhdlfile not found."
797 if {$sha_mode != 0} {
799 dict lappend libraries $lib$list_file_ext [
file normalize $list_file]
800 if {[
file type $list_file] eq "link"} {
803 dict lappend libraries $lib$list_file_ext $real_file
804 Msg Debug "List file $list_file is a soft link, also adding the real file: $real_file"
807 return [list $libraries $properties $filesets]
813 return $tcl_platform(platform)
822 proc GetLinkedFile {link_file} {
823 if {[
file type $link_file] eq "link"} {
824 if {[
OS] == "windows" } {
826 lassign [
ExecuteRet realpath $link_file] ret msg
827 lassign [
ExecuteRet cygpath -m $msg] ret2 msg2
828 if {$ret == 0 && $ret2 == 0} {
830 Msg Debug "Found link file $link_file on Windows, the linked file is: $real_file"
832 Msg CriticalWarning "[
file normalize $link_file] is a soft link. Soft link are not supported on Windows and readlink.exe or cygpath.exe did not work: readlink=$ret: $msg, cygpath=$ret2: $msg2."
833 set real_file $link_file
837 set linked_file [
file link $link_file]
838 set real_file [
file normalize [
file dirname $link_file]/$linked_file]
841 if {![
file exists $real_file]} {
842 Msg Warning "$link_file is a broken link, because the linked file: $real_file does not exist."
845 Msg Warning "$link file is not a soft link"
846 set real_file $link_file
861 proc MergeDict {dict0 dict1} {
862 set outdict [dict merge $dict1 $dict0]
863 foreach key [dict keys $dict1] {
864 if {[dict exists $dict0 $key]} {
865 set temp_list [dict get $dict1 $key]
866 foreach vhdfile $temp_list {
869 dict lappend outdict $key $vhdfile
885 proc DictGet {dictName keyName {default ""}} {
886 if {[dict exists $dictName $keyName]} {
887 return [dict get $dictName $keyName]
901 proc GetHashLib {lib} {
905 set ff [get_files -filter LIBRARY==$lib]
920 proc GetModifiedFiles {{repo_path "."} {pattern "."}} {
923 set ret [
Git "ls-files --modified $pattern"]
933 proc RestoreModifiedFiles {{repo_path "."} {pattern "."}} {
936 set ret [
Git checkout $pattern]
950 proc GetFileList {FILE path} {
951 set fp [open $FILE r]
952 set file_data [read $fp]
956 set data [
split $file_data "\n"]
958 if {![regexp {^ *$} $line] & ![regexp {^ *\#} $line] } {
960 set file_and_prop [regexp -all -inline {\S+} $line]
961 set vhdlfile [
lindex $file_and_prop 0]
962 set vhdlfile "$path/$vhdlfile"
963 if {[
file exists $vhdlfile]} {
964 set extension [
file extension $vhdlfile]
965 if { [
IsInList $extension {.src .sim .con}] } {
968 lappend file_list $vhdlfile
971 Msg Warning "File $vhdlfile not found"
985 proc GetSHA {{path ""}} {
987 lassign [
GitRet {log --format=%h --abbrev=7 -1}] status result
989 return [
string tolower $result]
991 Msg Error "Something went wrong while finding the latest SHA. Does the repository have a commit?"
997 set repo_path [
lindex [
Git {rev-parse --show-toplevel}] 0]
1001 set file_in_module 0
1002 if {[
file exists $repo_path/.gitmodules]} {
1003 lassign [
GitRet "config --file $repo_path/.gitmodules --get-regexp path"] status result
1005 set submodules [
split $result "\n"]
1008 Msg Warning "Something went wrong while trying to find submodules: $result"
1011 foreach mod $submodules {
1012 set module [
lindex $mod 1]
1013 if {[
string first "$repo_path/$module" $f] == 0} {
1015 set file_in_module 1
1016 lappend paths "$repo_path/$module"
1022 if {$file_in_module == 0} {
1028 lassign [
GitRet {log --format=%h --abbrev=7 -1} $paths] status result
1030 return [
string tolower $result]
1032 Msg Error "Something went wrong while finding the latest SHA. Does the repository have a commit?"
1035 return [
string tolower $result]
1044 proc GetVer {path {force_develop 0}} {
1048 Msg CriticalWarning "Empty SHA found for ${path}. Commit to Git to resolve this warning."
1051 set p [
lindex $path 0]
1052 if {[
file isdirectory $p]} {
1055 cd [
file dirname $p]
1057 set repo_path [
Git {rev-parse --show-toplevel}]
1060 return [list [
GetVerFromSHA $SHA $repo_path $force_develop] $SHA]
1071 proc GetVerFromSHA {SHA repo_path {force_develop 0}} {
1073 Msg CriticalWarning "Empty SHA found"
1076 lassign [
GitRet "tag --sort=creatordate --contain $SHA -l v*.*.* -l b*v*.*.*"] status result
1079 if {[regexp {^ *$} $result]} {
1081 lassign [
GitRet "log --oneline --pretty=\"%d\""] status2 tag_list
1084 set pattern {tag: v\d+\.\d+\.\d+}
1085 set real_tag_list {}
1086 foreach x $tag_list {
1087 set x_untrimmed [regexp -all -inline $pattern $x]
1088 regsub "tag: " $x_untrimmed "" x_trimmed
1089 set tt [
lindex $x_trimmed 0]
1090 if {![
string equal $tt ""]} {
1091 lappend real_tag_list $tt
1097 set sorted_tags [lsort -decreasing -command CompareVersions $real_tag_list]
1101 set tag [
lindex $sorted_tags 0]
1104 set pattern {v\d+\.\d+\.\d+}
1105 if {![regexp $pattern $tag]} {
1106 Msg CriticalWarning "No Hog version tags found in this repository."
1112 set repo_conf $repo_path/Top/repo.conf
1116 set hotfix_prefix "hotfix/"
1117 set minor_prefix "minor_version/"
1118 set major_prefix "major_version/"
1120 set enable_develop_branch $force_develop
1122 set branch_name [
Git {rev-parse --abbrev-ref HEAD}]
1124 if {[
file exists $repo_conf]} {
1125 set PROPERTIES [
ReadConf $repo_conf]
1127 if {[dict exists $PROPERTIES main]} {
1128 set mainDict [dict get $PROPERTIES main]
1131 if {[dict exists $mainDict ENABLE_DEVELOP_BRANCH]} {
1132 set enable_develop_branch [dict get $mainDict ENABLE_DEVELOP_BRANCH]
1139 if {[dict exists $PROPERTIES prefixes]} {
1140 set prefixDict [dict get $PROPERTIES prefixes]
1142 if {[dict exists $prefixDict HOTFIX]} {
1143 set hotfix_prefix [dict get $prefixDict HOTFIX]
1145 if {[dict exists $prefixDict MINOR_VERSION]} {
1146 set minor_prefix [dict get $prefixDict MINOR_VERSION]
1148 if {[dict exists $prefixDict MAJOR_VERSION]} {
1149 set major_prefix [dict get $prefixDict MAJOR_VERSION]
1155 if {$enable_develop_branch == 1 } {
1156 if {[
string match "$hotfix_prefix*" $branch_name]} {
1161 if {[
string match "$major_prefix*" $branch_name]} {
1163 set version_level major
1164 }
elseif {[
string match "$minor_prefix*" $branch_name] || ($enable_develop_branch == 1 && $is_hotfix == 0)} {
1166 set version_level minor
1169 set version_level patch
1177 Msg CriticalWarning "Tag $tag does not contain a Hog compatible version in this repository."
1180 }
elseif {$mr == 0} {
1182 switch $version_level {
1198 Msg Info "No tag contains $SHA, will use most recent tag $tag. As this is a candidate tag, the patch level will be kept at $p."
1204 set vers [
split $result "\n"]
1205 set ver [
lindex $vers 0]
1207 if {[regexp {^v.*$} $v]} {
1215 Msg CriticalWarning "Error while trying to find tag for $SHA"
1223 set M [
format %02X $M]
1224 set m [
format %02X $m]
1225 set c [
format %04X $c]
1227 }
elseif { $M > -1 } {
1229 set M [
format %02X $M]
1230 set m [
format %02X $m]
1231 set c [
format %04X $c]
1234 Msg Warning "Tag does not contain a properly formatted version: $ver"
1235 set M [
format %02X 0]
1236 set m [
format %02X 0]
1237 set c [
format %04X 0]
1252 proc GetProjectVersion {proj_dir repo_path {ext_path ""} {sim 0}} {
1253 if { ![
file exists $proj_dir] } {
1254 Msg CriticalWarning "$proj_dir not found"
1264 Msg Warning "Repository is not clean"
1273 Msg Info "The specified project was modified since official version."
1280 Msg Info "The specified project was modified in the latest official version $ret"
1281 }
elseif {$comp == -1} {
1282 Msg Info "The specified project was modified in a past official version $ret"
1297 proc GetHogDescribe {sha {repo_path .}} {
1300 set new_sha "[
string toupper [
GetSHA]]"
1303 set new_sha [
string toupper $sha]
1317 proc GetSubmodule {path_file} {
1319 set directory [
file normalize [
file dirname $path_file]]
1321 lassign [
GitRet {rev-parse --show-superproject-working-tree}] ret base
1323 Msg CriticalWarning "Git repository error: $base"
1330 lassign [
GitRet {rev-parse --show-toplevel}] ret sub
1332 Msg CriticalWarning "Git submodule error: $sub"
1336 set submodule [
Relative $base $sub]
1350 proc GetConfFiles {proj_dir} {
1351 if {![
file isdirectory $proj_dir]} {
1352 Msg Error "$proj_dir is supposed to be the top project directory"
1355 set conf_file [
file normalize $proj_dir/hog.conf]
1356 set sim_file [
file normalize $proj_dir/sim.conf]
1357 set pre_tcl [
file normalize $proj_dir/pre-creation.tcl]
1358 set post_tcl [
file normalize $proj_dir/post-creation.tcl]
1360 return [list $conf_file $sim_file $pre_tcl $post_tcl]
1372 proc GetRepoVersions {proj_dir repo_path {ext_path ""} {sim 0}} {
1373 if { [
catch {
package require cmdline} ERROR] } {
1374 puts "$ERROR\n If you are running this script on tclsh, you can fix this by installing 'tcllib'"
1389 lappend SHAs [
GetSHA {Hog}]
1393 if {[
Git {status --untracked-files=no --porcelain}] eq ""} {
1394 Msg Info "Hog submodule [
pwd] clean."
1395 lassign [
GetVer ./] hog_ver hog_hash
1397 Msg CriticalWarning "Hog submodule [
pwd] not clean, commit hash will be set to 0."
1398 set hog_hash "0000000"
1399 set hog_ver "00000000"
1404 if {[
Git {status --untracked-files=no --porcelain}] eq ""} {
1405 Msg Info "Git working directory [
pwd] clean."
1408 Msg CriticalWarning "Git working directory [
pwd] not clean, commit hash, and version will be set to 0."
1413 lassign [
GetVer [
join $conf_files]] top_ver top_hash
1414 lappend SHAs $top_hash
1415 lappend versions $top_ver
1422 lassign [
GetHogFiles -list_files "*.src" -sha_mode "./list/" $repo_path] src_files dummy
1423 dict for {f files} $src_files {
1424 # library names have a .src extension in values returned by GetHogFiles
1425 set name [file rootname [file tail $f]]
1426 if {[file ext $f] == ".oth"} {
1429 lassign [GetVer $files] ver hash
1430 # Msg Info "Found source list file $f, version: $ver commit SHA: $hash"
1432 lappend versions $ver
1434 lappend hashes $hash
1441 lassign [
GetHogFiles -list_files "*.con" -sha_mode "./list/" $repo_path] cons_files dummy
1442 dict for {f files} $cons_files {
1443 #library names have a .con extension in values returned by GetHogFiles
1444 set name [file rootname [file tail $f]]
1445 lassign [GetVer $files] ver hash
1446 #Msg Info "Found constraint list file $f, version: $ver commit SHA: $hash"
1448 Msg CriticalWarning "Constraints file $f not found in Git."
1450 lappend cons_hashes $hash
1452 lappend versions $ver
1459 lassign [
GetHogFiles -list_files "*.sim" -sha_mode "./list/" $repo_path] sim_files dummy
1460 dict for {f files} $sim_files {
1461 #library names have a .sim extension in values returned by GetHogFiles
1462 set name [file rootname [file tail $f]]
1463 lassign [GetVer $files] ver hash
1464 #Msg Info "Found simulation list file $f, version: $ver commit SHA: $hash"
1465 lappend sim_hashes $hash
1467 lappend versions $ver
1473 if {"{}" eq $cons_hashes} {
1475 Msg CriticalWarning "No hashes found for constraints files (not in git)"
1478 set cons_hash [
string tolower [
Git "log --format=%h -1 $cons_hashes"]]
1485 set ext_files [glob -nocomplain "./list/*.ext"]
1488 foreach f $ext_files {
1489 set name [
file rootname [
file tail $f]]
1492 lappend ext_names $name
1493 lappend ext_hashes $hash
1496 lappend versions $ext_ver
1499 set file_data [read $fp]
1501 set data [
split $file_data "\n"]
1503 foreach line $data {
1504 if {![regexp {^ *$} $line] & ![regexp {^ *\#} $line] } {
1506 set file_and_prop [regexp -all -inline {\S+} $line]
1507 set hdlfile [
lindex $file_and_prop 0]
1508 set hdlfile $ext_path/$hdlfile
1509 if { [
file exists $hdlfile] } {
1510 set hash [
lindex $file_and_prop 1]
1511 set current_hash [
Md5Sum $hdlfile]
1512 if {[
string first $hash $current_hash] == -1} {
1513 Msg CriticalWarning "File $hdlfile has a wrong hash. Current checksum: $current_hash, expected: $hash"
1521 if {[
file exists ./list/xml.lst]} {
1523 lassign [
GetHogFiles -list_files "xml.lst" -sha_mode "./list/" $repo_path] xml_files dummy
1524 lassign [
GetVer [dict get $xml_files "xml.lst"]] xml_ver xml_hash
1525 lappend SHAs $xml_hash
1526 lappend versions $xml_ver
1531 Msg Info "This project does not use IPbus XMLs"
1536 set user_ip_repos ""
1537 set user_ip_repo_hashes ""
1538 set user_ip_repo_vers ""
1540 if {[
file exists [
lindex $conf_files 0]]} {
1541 set PROPERTIES [
ReadConf [
lindex $conf_files 0]]
1542 if {[dict exists $PROPERTIES main]} {
1543 set main [dict get $PROPERTIES main]
1544 dict for {p v} $main {
1545 if { [ string tolower $p ] == "ip_repo_paths" } {
1547 lappend user_ip_repos "$repo_path/$repo"
1554 foreach repo $user_ip_repos {
1555 if {[
file isdirectory $repo]} {
1556 set repo_file_list [glob -nocomplain "$repo/*"]
1557 if {[
llength $repo_file_list] != 0} {
1558 lassign [
GetVer $repo] ver sha
1559 lappend user_ip_repo_hashes $sha
1560 lappend user_ip_repo_vers $ver
1561 lappend versions $ver
1563 Msg Warning "IP_REPO_PATHS property set to $repo in hog.conf but directory is empty."
1566 Msg Warning "IP_REPO_PATHS property set to $repo in hog.conf but directory does not exist."
1575 while {$found == 0} {
1576 set global_commit [
Git "log --format=%h -1 --abbrev=7 $SHAs"]
1581 if {$common_child == 0} {
1582 Msg CriticalWarning "The commit $sha is not an ancestor of the global commit $global_commit, which is OK. But $sha and $global_commit do not have any common child, which is NOT OK. This is probably do to a REBASE that is forbidden in Hog methodology as it changes git history. Hog cannot gaurantee the accuracy of the SHAs. A way to fix this is to make a commit that touches all the projects in the repositories (e.g. change the Hog version) but please do not rebase in the official branches in the future."
1584 Msg Info "The commit $sha is not an ancestor of the global commit $global_commit, adding the first common child $common_child instead..."
1585 lappend SHAs $common_child
1595 set global_commit "0000000"
1596 set global_version "00000000"
1601 set top_hash [
format %+07s $top_hash]
1602 set cons_hash [
format %+07s $cons_hash]
1603 return [list $global_commit $global_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_repo_hashes $user_ip_repo_vers]
1614 proc HexVersionToString {version} {
1615 scan [
string range $version 0 1] %x M
1616 scan [
string range $version 2 3] %x m
1617 scan [
string range $version 4 7] %x c
1627 proc ExtractVersionFromTag {tag} {
1628 if {[regexp {^(?:b(\d+))?v(\d+)\.(\d+).(\d+)(?:-\d+)?$} $tag -> mr M m p]} {
1633 Msg Warning "Repository tag $tag is not in a Hog-compatible format."
1639 return [list $M $m $p $mr]
1653 proc CopyXMLsFromListFile {list_file path dst {xml_version "0.0.0"} {xml_sha "00000000"} {generate 0} } {
1655 lassign [
ExecuteRet python -c "from __future__ import print_function; from sys import path;print(':'.join(path\[1:\]))"] ret msg
1657 set ::env(PYTHONPATH) $msg
1658 lassign [
ExecuteRet gen_ipbus_addr_decode -h] ret msg
1665 Msg Warning "Error while trying to run python: $msg"
1668 set dst [
file normalize $dst]
1669 if {$can_generate == 0} {
1670 if {$generate == 1} {
1671 Msg Error "Cannot generate IPbus address files, IPbus executable gen_ipbus_addr_decode not found or not working: $msg"
1675 Msg Warning "IPbus executable gen_ipbus_addr_decode not found or not working, will not verify IPbus address tables."
1680 set fp [open $list_file r]
1681 set file_data [read $fp]
1684 set data [
split $file_data "\n"]
1685 set n [
llength $data]
1686 Msg Info "$n lines read from $list_file"
1690 foreach line $data {
1691 if {![regexp {^ *$} $line] & ![regexp {^ *\#} $line] } {
1693 set file_and_prop [regexp -all -inline {\S+} $line]
1694 set xmlfiles [glob "$path/[
lindex $file_and_prop 0]"]
1698 if {[
llength $xmlfiles]==1 && [
llength $file_and_prop] > 1} {
1699 set vhdlfile [
lindex $file_and_prop 1]
1700 set vhdlfile "$path/$vhdlfile"
1705 set xml_list_error 0
1706 foreach xmlfile $xmlfiles {
1708 if {[
file isdirectory $xmlfile]} {
1709 Msg CriticalWarning "Directory $xmlfile listed in xml.lst. Directories are not supported!"
1710 set xml_list_error 1
1713 if {[
file exists $xmlfile]} {
1714 set xmlfile [
file normalize $xmlfile]
1715 Msg Info "Copying $xmlfile to $dst..."
1716 set in [open $xmlfile r]
1717 set out [open $dst/[
file tail $xmlfile] w]
1719 while {[
gets $in line] != -1} {
1720 set new_line [regsub {(.*)__VERSION__(.*)} $line "\\1$xml_version\\2"]
1721 set new_line2 [regsub {(.*)__GIT_SHA__(.*)} $new_line "\\1$xml_sha\\2"]
1722 puts $out $new_line2
1726 lappend xmls [
file tail $xmlfile]
1727 if {$vhdlfile == 0 } {
1730 lappend vhdls [
file normalize $vhdlfile]
1734 Msg Warning "XML file $xmlfile not found"
1737 if {${xml_list_error}} {
1738 Msg Error "Invalid files added to xml.lst!"
1742 set cnt [
llength $xmls]
1743 Msg Info "$cnt file/s copied"
1745 if {$can_generate == 1} {
1748 file mkdir "address_decode"
1750 foreach x $xmls v $vhdls {
1752 set x [
file normalize ../$x]
1753 if {[
file exists $x]} {
1754 lassign [
ExecuteRet gen_ipbus_addr_decode $x 2>&1] status log
1756 set generated_vhdl ./ipbus_decode_[
file rootname [
file tail $x]].vhd
1757 if {$generate == 1} {
1758 Msg Info "Copying generated VHDL file $generated_vhdl into $v (replacing if necessary)"
1759 file copy -force -- $generated_vhdl $v
1761 if {[
file exists $v]} {
1763 if {[
llength $diff] > 0} {
1764 Msg CriticalWarning "$v does not correspond to its XML $x, [
expr {$n/3}] line/s differ:"
1765 Msg Status [
join $diff "\n"]
1766 set diff_file [open ../diff_[
file rootname [
file tail $x]].txt w]
1767 puts $diff_file $diff
1770 Msg Info "[
file tail $x] and $v match."
1773 Msg Warning "VHDL address map file $v not found."
1777 Msg Warning "Address map generation failed for [
file tail $x]: $log"
1780 Msg Warning "Copied XML file $x not found."
1783 Msg Info "Skipped verification of [
file tail $x] as no VHDL file was specified."
1787 file delete -force address_decode
1799 proc CompareVHDL {file1 file2} {
1800 set a [open $file1 r]
1801 set b [open $file2 r]
1803 while {[
gets $a line] != -1} {
1804 set line [regsub {^[\t\s]*(.*)?\s*} $line "\\1"]
1805 if {![regexp {^$} $line] & ![regexp {^--} $line] } {
1811 while {[
gets $b line] != -1} {
1812 set line [regsub {^[\t\s]*(.*)?\s*} $line "\\1"]
1813 if {![regexp {^$} $line] & ![regexp {^--} $line] } {
1822 foreach x $f1 y $f2 {
1824 lappend diff "> $x\n< $y\n\n"
1836 proc Relative {base dst} {
1837 if {![
string equal [
file pathtype $base] [
file pathtype $dst]]} {
1838 Msg CriticalWarning "Unable to compute relation for paths of different pathtypes: [
file pathtype $base] vs. [
file pathtype $dst], ($base vs. $dst)"
1842 set base [
file normalize [
file join [
pwd] $base]]
1843 set dst [
file normalize [
file join [
pwd] $dst]]
1846 set base [
file split $base]
1847 set dst [
file split $dst]
1849 while {[
string equal [
lindex $dst 0] [
lindex $base 0]]} {
1850 set dst [
lrange $dst 1 end]
1851 set base [
lrange $base 1 end]
1852 if {![
llength $dst]} {break}
1855 set dstlen [
llength $dst]
1856 set baselen [
llength $base]
1858 if {($dstlen == 0) && ($baselen == 0)} {
1861 while {$baselen > 0} {
1862 set dst [
linsert $dst 0 ..]
1865 set dst [
eval [
linsert $dst 0 file join]]
1876 proc RelativeLocal {pathName filePath} {
1877 if {[
string first [
file normalize $pathName] [
file normalize $filePath]] != -1} {
1878 return [
Relative $pathName $filePath]
1890 proc MsgAndLog {msg {severity "CriticalWarning"} {outFile ""}} {
1892 if {$outFile != ""} {
1893 set oF [open "$outFile" a+]
1906 proc GetProjectFiles {} {
1908 set all_filesets [get_filesets]
1909 set libraries [dict create]
1910 set simlibraries [dict create]
1911 set constraints [dict create]
1912 set properties [dict create]
1913 set consets [dict create]
1914 set srcsets [dict create]
1915 set simsets [dict create]
1916 set simulator [get_property target_simulator [current_project]]
1917 set top [get_property "top" [current_fileset]]
1918 set topfile [
lindex [get_files -compile_order sources -used_in synthesis] end]
1919 dict lappend properties $topfile "top=$top"
1921 foreach fs $all_filesets {
1922 if {$fs == "utils_1"} {
1927 set all_files [get_files -quiet -of_objects [get_filesets $fs]]
1928 set fs_type [get_property FILESET_TYPE [get_filesets $fs]]
1930 if {$fs_type == "BlockSrcs"} {
1934 foreach f $all_files {
1941 if { [
lindex [get_property IS_GENERATED [
GetFile $f]] 0] != 0} {
1946 if {[get_property CORE_CONTAINER [
GetFile $f]] != ""} {
1947 if { [
file extension $f] == ".xcix"} {
1948 set f [get_property CORE_CONTAINER [
GetFile $f]]
1955 if {[
IsInList "PARENT_COMPOSITE_FILE" [list_property [
GetFile $f]]]} {
1960 if {[
file tail $f] == "nocattrs.dat"} {
1965 if {[
file extension $f] != ".coe"} {
1966 set f [
file normalize $f]
1969 set type [get_property FILE_TYPE [
GetFile $f]]
1971 set lib [get_property -quiet LIBRARY [
GetFile $f]]
1974 Msg Debug "File $f Extension [
file extension $f] Type [
lindex $type 0]"
1976 if {[
string equal [
lindex $type 0] "VHDL"] && [
llength $type] == 1} {
1978 }
elseif {[
string equal [
lindex $type 0] "Block"] && [
string equal [
lindex $type 1] "Designs"]} {
1981 }
elseif {[
string equal $type "SystemVerilog"] && [
file extension $f] != ".sv"} {
1982 set prop "SystemVerilog"
1983 }
elseif {[
string equal [
lindex $type 0] "XDC"] && [
file extension $f] != ".xdc"} {
1985 }
elseif {[
string equal $type "Verilog Header"] && [
file extension $f] != ".vh" && [
file extension $f] != ".svh"} {
1986 set prop "verilog_header"
1987 }
elseif {[
string equal $type "Verilog Template"] && [
file extension $f] == ".v" && [
file extension $f] != ".sv"} {
1988 set prop "verilog_template"
1990 set type [
lindex $type 0]
1995 if {![
string equal $prop ""]} {
1996 dict lappend properties $f $prop
1999 if {[
string equal $fs_type "SimulationSrcs"]} {
2001 if {[
string equal $type "VHDL"] } {
2002 set library "${lib}.sim"
2004 set library "others.sim"
2008 dict lappend simsets $fs $library
2011 dict lappend simlibraries $library $f
2013 }
elseif {[
string equal $type "VHDL"] } {
2016 dict lappend srcsets $fs "${lib}.src"
2018 dict lappend libraries "${lib}.src" $f
2019 }
elseif {[
string first "IP" $type] != -1} {
2022 dict lappend srcsets $fs "ips.src"
2024 dict lappend libraries "ips.src" $f
2025 Msg Debug "Appending $f to ips.src"
2026 }
elseif {[
string equal $fs_type "Constrs"]} {
2029 dict lappend consets $fs "sources.con"
2031 dict lappend constraints "sources.con" $f
2035 dict lappend srcsets $fs "others.src"
2037 dict lappend libraries "others.src" $f
2038 Msg Debug "Appending $f to others.src"
2041 if {[
lindex [get_property -quiet used_in_synthesis [
GetFile $f]] 0] == 0} {
2042 dict lappend properties $f "nosynth"
2044 if {[
lindex [get_property -quiet used_in_implementation [
GetFile $f]] 0] == 0} {
2045 dict lappend properties $f "noimpl"
2047 if {[
lindex [get_property -quiet used_in_simulation [
GetFile $f]] 0] == 0} {
2048 dict lappend properties $f "nosim"
2050 if {[
lindex [get_property -quiet IS_MANAGED [
GetFile $f]] 0] == 0 && [
file extension $f] != ".xcix" } {
2051 dict lappend properties $f "locked"
2057 dict lappend properties "Simulator" [get_property target_simulator [current_project]]
2059 return [list $libraries $properties $simlibraries $constraints $srcsets $simsets $consets]
2078 proc GetHogFiles args {
2082 if { [
catch {
package require cmdline} ERROR] } {
2083 puts "$ERROR\n If you are running this script on tclsh, you can fix this by installing 'tcllib'"
2090 {list_files.arg "" "The file wildcard, if not specified all Hog list files will be looked for."}
2091 {sha_mode "Forwarded to ReadListFile, see there for info."}
2092 {ext_path.arg "" "Path for the external libraries forwarded to ReadListFile."}
2094 set usage "USAGE: GetHogFiles \[options\] <list path> <repository path>"
2095 if {[
catch {
array set options [
cmdline::getoptions args $parameters $usage]}] || [
llength $args] != 2 } {
2099 set list_path [
lindex $args 0]
2100 set repo_path [
lindex $args 1]
2102 set list_files $options(list_files)
2103 set sha_mode $options(sha_mode)
2104 set ext_path $options(ext_path)
2107 if { $sha_mode == 1 } {
2108 set sha_mode_opt "-sha_mode"
2113 if { $list_files == "" } {
2114 set list_files {.src,.con,.sim,.ext}
2116 set libraries [dict create]
2117 set properties [dict create]
2118 set list_files [glob -nocomplain -directory $list_path "*{$list_files}"]
2119 set filesets [dict create]
2121 foreach f $list_files {
2122 set ext [
file extension $f]
2123 if {$ext == ".ext"} {
2124 lassign [
ReadListFile {*}"$sha_mode_opt $f $ext_path"] l p fs
2126 lassign [
ReadListFile {*}"$sha_mode_opt $f $repo_path"] l p fs
2129 set properties [
MergeDict $p $properties]
2130 Msg Debug "list file $f, filesets: $fs"
2132 Msg Debug "Merged filesets $filesets"
2134 return [list $libraries $properties $filesets]
2147 proc ParseFirstLineHogFiles {list_path list_file} {
2148 set repo_path [
file normalize $list_path/../../..]
2149 if {![
file exists $list_path/$list_file]} {
2150 Msg Error "list file $list_path/$list_file does not exist!"
2153 set fp [open $list_path/$list_file r]
2154 set line [
lindex [
split [read $fp] "\n"] 0]
2157 if {[
string match "#*" $line]} {
2158 return [
string trim [
string range $line 1 end]]
2170 proc AddHogFiles { libraries properties filesets } {
2171 Msg Info "Adding source files to project..."
2172 Msg Debug "Filesets: $filesets"
2173 Msg Debug "Libraries: $libraries"
2174 Msg Debug "Properties: $properties"
2177 set synth_conf_command "organize_tool_files -tool {SYNTHESIZE} -input_type {constraint}"
2179 set timing_conf_command "organize_tool_files -tool {VERIFYTIMING} -input_type {constraint}"
2181 set place_conf_command "organize_tool_files -tool {PLACEROUTE} -input_type {constraint}"
2185 foreach fileset [dict keys $filesets] {
2186 Msg Debug "Fileset: $fileset"
2189 if {[
string equal [get_filesets -quiet $fileset] ""]} {
2191 create_fileset -simset $fileset
2193 current_fileset -simset [ get_filesets $fileset]
2194 set simulation [get_filesets $fileset]
2196 set_property -name {$simulator.compile.vhdl_syntax} -value {2008} -objects $simulation
2198 set_property SOURCE_SET sources_1 $simulation
2202 set libs_in_fileset [
DictGet $filesets $fileset]
2203 if { [
IsInList "ips.src" $libs_in_fileset] } {
2208 foreach lib $libs_in_fileset {
2209 Msg Debug "lib: $lib \n"
2210 set lib_files [
DictGet $libraries $lib]
2211 Msg Debug "Files in $lib: $lib_files"
2212 set rootlib [
file rootname [
file tail $lib]]
2213 set ext [
file extension $lib]
2214 Msg Debug "lib: $lib ext: $ext fileset: $fileset"
2217 Msg Debug "Adding $lib to $fileset"
2218 add_files -norecurse -fileset $fileset $lib_files
2220 foreach f $lib_files {
2221 set file_obj [get_files -of_objects [get_filesets $fileset] [list "*$f"]]
2223 if {[
file extension $f] == ".vhd" || [
file extension $f] == ".vhdl"} {
2224 set_property -name "library" -value $rootlib -objects $file_obj
2228 set props [
DictGet $properties $f]
2229 if {[
file extension $f] == ".vhd" || [
file extension $f] == ".vhdl"} {
2231 if {[lsearch -inline -regexp $props "93"] < 0} {
2234 set_property -name "file_type" -value "VHDL 2008" -objects $file_obj
2237 Msg Debug "Filetype is VHDL 93 for $f"
2242 if {[lsearch -inline -regexp $props "SystemVerilog"] > 0 } {
2245 set_property -name "file_type" -value "SystemVerilog" -objects $file_obj
2246 Msg Debug "Filetype is SystemVerilog for $f"
2248 Msg Warning "Xilinx PlanAhead/ISE does not support SystemVerilog. Property not set for $f"
2253 set top [
lindex [regexp -inline {top\s*=\s*(.+?)\y.*} $props] 1]
2255 Msg Info "Setting $top as top module for file set $fileset..."
2256 set globalSettings::synth_top_module $top
2261 if {[lsearch -inline -regexp $props "verilog_header"] >= 0} {
2262 Msg Debug "Setting verilog header type for $f..."
2263 set_property file_type {Verilog Header} [get_files $f]
2264 }
elseif {[lsearch -inline -regexp $props "verilog_template"] >= 0} {
2266 Msg Debug "Setting verilog template type for $f..."
2267 set_property file_type {Verilog Template} [get_files $f]
2268 }
elseif {[lsearch -inline -regexp $props "verilog"] >= 0} {
2270 Msg Debug "Setting verilog type for $f..."
2271 set_property file_type {Verilog} [get_files $f]
2275 if {[lsearch -inline -regexp $props "nosynth"] >= 0} {
2276 Msg Debug "Setting not used in synthesis for $f..."
2277 set_property -name "used_in_synthesis" -value "false" -objects $file_obj
2281 if {[lsearch -inline -regexp $props "noimpl"] >= 0} {
2282 Msg Debug "Setting not used in implementation for $f..."
2283 set_property -name "used_in_implementation" -value "false" -objects $file_obj
2287 if {[lsearch -inline -regexp $props "nosim"] >= 0} {
2288 Msg Debug "Setting not used in simulation for $f..."
2289 set_property -name "used_in_simulation" -value "false" -objects $file_obj
2294 set top_sim [
lindex [regexp -inline {topsim\s*=\s*(.+?)\y.*} $props] 1]
2295 if { $top_sim != "" } {
2296 Msg Warning "Setting the simulation top module from simulation list files is now deprecated. Please set this property in the sim.conf file, by adding the following line under the \[$fileset\] section.\ntop=$top_sim"
2300 set sim_runtime [
lindex [regexp -inline {runtime\s*=\s*(.+?)\y.*} $props] 1]
2301 if { $sim_runtime != "" } {
2302 Msg Warning "Setting the simulation runtime from simulation list files is now deprecated. Please set this property in the sim.conf file, by adding the following line under the \[$fileset\] section.\n<simulator_name>.simulate.runtime=$sim_runtime"
2310 if {[lsearch -inline -regexp $props "wavefile"] >= 0} {
2311 Msg Warning "Setting a wave do file from simulation list files is now deprecated. Set this property in the sim.conf file, by adding the following line under the \[$fileset\] section.\n<simulator_name>.simulate.custom_wave_do=[
file tail $f]"
2326 if {[lsearch -inline -regexp $props "dofile"] >= 0} {
2327 Msg Warning "Setting a custom do file from simulation list files is now deprecated. Set this property in the sim.conf file, by adding the following line under the \[$fileset\] section.\n<simulator_name>.simulate.custom_do=[
file tail $f]"
2340 if {[lsearch -inline -regexp $props "locked"] >= 0 && $ext == ".ip"} {
2341 Msg Info "Locking IP $f..."
2342 set_property IS_MANAGED 0 [get_files $f]
2346 if {[
file extension $f] == ".bd"} {
2347 Msg Info "Generating Target for [
file tail $f], please remember to commit the (possible) changed file."
2348 generate_target all [get_files $f]
2353 if {[
file extension $f] == ".tcl" && $ext != ".con"} {
2354 if { [lsearch -inline -regexp $props "source"] >= 0} {
2355 Msg Info "Sourcing Tcl script $f, and setting it not used in synthesis, implementation and simulation..."
2357 set_property -name "used_in_synthesis" -value "false" -objects $file_obj
2358 set_property -name "used_in_implementation" -value "false" -objects $file_obj
2359 set_property -name "used_in_simulation" -value "false" -objects $file_obj
2363 Msg Info "[
llength $lib_files] file/s added to library $rootlib..."
2366 if { $ext == ".sim"} {
2367 Msg Warning "Simulation files not supported in Quartus Prime mode... Skipping $lib"
2369 if {! [is_project_open] } {
2370 Msg Error "Project is closed"
2372 foreach cur_file $lib_files {
2376 set props [
DictGet $properties $cur_file]
2379 set top [
lindex [regexp -inline {top\s*=\s*(.+?)\y.*} $props] 1]
2381 Msg Info "Setting $top as top module for file set $fileset..."
2382 set globalSettings::synth_top_module $top
2385 if {[
string first "VHDL" $file_type] != -1 } {
2386 if {[
string first "1987" $props] != -1 } {
2387 set hdl_version "VHDL_1987"
2388 }
elseif {[
string first "1993" $props] != -1 } {
2389 set hdl_version "VHDL_1993"
2390 }
elseif {[
string first "2008" $props] != -1 } {
2391 set hdl_version "VHDL_2008"
2393 set hdl_version "default"
2395 if { $hdl_version == "default" } {
2396 set_global_assignment -name $file_type $cur_file -library $rootlib
2398 set_global_assignment -name $file_type $cur_file -hdl_version $hdl_version -library $rootlib
2400 }
elseif {[
string first "SYSTEMVERILOG" $file_type] != -1 } {
2402 if {[
string first "2005" $props] != -1 } {
2403 set hdl_version "systemverilog_2005"
2404 }
elseif {[
string first "2009" $props] != -1 } {
2405 set hdl_version "systemverilog_2009"
2407 set hdl_version "default"
2409 if { $hdl_version == "default" } {
2410 set_global_assignment -name $file_type $cur_file
2412 set_global_assignment -name $file_type $cur_file -hdl_version $hdl_version
2414 }
elseif {[
string first "VERILOG" $file_type] != -1 } {
2416 if {[
string first "1995" $props] != -1 } {
2417 set hdl_version "verilog_1995"
2418 }
elseif {[
string first "2001" $props] != -1 } {
2419 set hdl_version "verilog_2001"
2421 set hdl_version "default"
2423 if { $hdl_version == "default" } {
2424 set_global_assignment -name $file_type $cur_file
2426 set_global_assignment -name $file_type $cur_file -hdl_version $hdl_version
2428 }
elseif {[
string first "SOURCE" $file_type] != -1 || [
string first "COMMAND_MACRO" $file_type] != -1 } {
2429 set_global_assignment -name $file_type $cur_file
2430 if { $ext == ".con"} {
2432 }
elseif { $ext == ".src"} {
2434 if {[
string first "qsys" $props] != -1 } {
2437 regsub -all {\{||qsys||\}} $props $emptyString props
2439 set qsysPath [
file dirname $cur_file]
2440 set qsysName "[
file rootname [
file tail $cur_file]].qsys"
2441 set qsysFile "$qsysPath/$qsysName"
2442 set qsysLogFile "$qsysPath/[
file rootname [
file tail $cur_file]].qsys-script.log"
2445 if {! [
info exists ::env(QSYS_ROOTDIR)] } {
2446 if {[
info exists ::env(QUARTUS_ROOTDIR)] } {
2447 set qsys_rootdir "$::env(QUARTUS_ROOTDIR)/sopc_builder/bin"
2448 Msg Warning "The QSYS_ROOTDIR environment variable is not set! I will use $qsys_rootdir"
2450 Msg CriticalWarning "The QUARTUS_ROOTDIR environment variable is not set! Assuming all quartus executables are contained in your PATH!"
2453 set qsys_rootdir $::env(QSYS_ROOTDIR)
2456 set cmd "$qsys_rootdir/qsys-script"
2457 set cmd_options " --script=$cur_file"
2458 if {![
catch {"exec $cmd -version"}] || [
lindex $::errorCode 0] eq "NONE"} {
2459 Msg Info "Executing: $cmd $cmd_options"
2460 Msg Info "Saving logfile in: $qsysLogFile"
2461 if { [
catch {
eval exec -ignorestderr "$cmd $cmd_options >>& $qsysLogFile"} ret opt]} {
2462 set makeRet [
lindex [dict get $opt -errorcode] end]
2463 Msg CriticalWarning "$cmd returned with $makeRet"
2466 Msg Error " Could not execute command $cmd"
2470 if { [
file exists $qsysName] != 0} {
2471 file rename -force $qsysName $qsysFile
2473 set qsysMd5Sum [
Md5Sum $qsysFile]
2475 set fileDir [
file normalize "./hogTmp"]
2476 set fileName "$fileDir/.hogQsys.md5"
2477 if {![
file exists $fileDir]} {
2480 set hogQsysFile [open $fileName "a"]
2481 set fileEntry "$qsysFile\t$qsysMd5Sum"
2482 puts $hogQsysFile $fileEntry
2485 Msg ERROR "Error while moving the generated qsys file to final location: $qsysName not found!"
2487 if { [
file exists $qsysFile] != 0} {
2488 if {[
string first "noadd" $props] == -1} {
2490 set_global_assignment -name $qsysFileType $qsysFile
2492 regsub -all {noadd} $props $emptyString props
2494 if {[
string first "nogenerate" $props] == -1} {
2499 Msg ERROR "Error while generating ip variations from qsys: $qsysFile not found!"
2503 }
elseif { [
string first "QSYS" $file_type] != -1 } {
2505 regsub -all {\{||\}} $props $emptyString props
2506 if {[
string first "noadd" $props] == -1} {
2507 set_global_assignment -name $file_type $cur_file
2509 regsub -all {noadd} $props $emptyString props
2513 if {[
string first "nogenerate" $props] == -1} {
2517 set_global_assignment -name $file_type $cur_file -library $rootlib
2522 if {$ext == ".con"} {
2523 set vld_exts {.sdc .pin .dcf .gcf .pdc .ndc .fdc .crt .vcd }
2524 foreach con_file $lib_files {
2526 set con_ext [
file extension $con_file]
2527 if {[
IsInList [
file extension $con_file] $vld_exts]} {
2528 set option [
string map {. -} $con_ext]
2529 set option [
string map {fdc net_fdc} $option]
2530 set option [
string map {pdc io_pdc} $option]
2531 create_links -convert_EDN_to_HDL 0 -library {work} $option $con_file
2533 set props [
DictGet $properties $con_file]
2535 if {$con_ext == ".sdc"} {
2536 if { [lsearch $props "notiming"] >= 0 } {
2537 Msg Info "Excluding $con_file from timing verification..."
2539 Msg Info "Adding $con_file to time verification"
2540 append timing_conf_command " -file $con_file"
2544 if { [lsearch $props "nosynth"] >= 0 } {
2545 Msg Info "Excluding $con_file from synthesis..."
2547 Msg Info "Adding $con_file to synthesis"
2548 append synth_conf_command " -file $con_file"
2553 if {$con_ext == ".pdc" || $con_ext == ".sdc"} {
2554 if { [lsearch $props "noplace"] >= 0 } {
2555 Msg Info "Excluding $con_file from place and route..."
2557 Msg Info "Adding $con_file to place and route"
2558 append place_conf_command " -file $con_file"
2564 Msg CriticalWarning "Constraint file $con_file does not have a valid extension. Allowed extensions are: \n $vld_exts"
2567 }
elseif {$ext == ".src"} {
2568 foreach f $lib_files {
2569 Msg Debug "Adding source $f to library $rootlib..."
2570 create_links -library $rootlib -hdl_source $f
2573 build_design_hierarchy
2574 foreach cur_file $lib_files {
2578 set props [
DictGet $properties $cur_file]
2581 set top [
lindex [regexp -inline {top\s*=\s*(.+?)\y.*} $props] 1]
2583 Msg Info "Setting $top as top module for file set $rootlib..."
2584 set globalSettings::synth_top_module "${top}::$rootlib"
2595 if {[
DictGet $filesets "sim_1"] == ""} {
2596 delete_fileset -quiet [ get_filesets "sim_1"]
2602 if {$synth_conf == 1} {
2603 Msg Info $synth_conf_command
2604 eval $synth_conf_command
2606 if {$timing_conf == 1} {
2607 Msg Info $timing_conf_command
2608 eval $timing_conf_command
2610 if {$place_conf == 1} {
2611 Msg Info $place_conf_command
2612 eval $place_conf_command
2623 proc CheckExtraFiles {libraries} {
2626 lassign [
GetProjectFiles] prjLibraries prjProperties prjSimLibraries prjConstraints
2627 set prjLibraries [
MergeDict $prjLibraries $prjSimLibraries]
2628 set prjLibraries [
MergeDict $prjLibraries $prjConstraints]
2629 set prj_dir [get_property DIRECTORY [current_project]]
2630 file mkdir "$prj_dir/.hog"
2631 set extra_file_name "$prj_dir/.hog/extra.files"
2632 set new_extra_file [open $extra_file_name "w"]
2634 dict for {prjLib prjFiles} $prjLibraries {
2635 foreach prjFile $prjFiles {
2636 if {[file extension $prjFile] == ".xcix"} {
2637 Msg Warning "IP $prjFile is packed in a .xcix core container. This files are not suitable for version control systems. We recommend to use .xci files instead."
2640 if {[file extension $prjFile] == ".xci" && [get_property CORE_CONTAINER [get_files $prjFile]] != ""} {
2641 Msg Info "$prjFile is a virtual IP file in a core container. Ignoring it..."
2645 if {[IsInList $prjFile [DictGet $libraries $prjLib]]==0} {
2646 if { [file extension $prjFile] == ".bd"} {
2647 # Generating BD products to save md5sum of already modified BD
2648 Msg Info "Generating targets of $prjFile..."
2649 generate_target all [get_files $prjFile]
2651 puts $new_extra_file "$prjFile [Md5Sum $prjFile]"
2652 Msg Info "$prjFile (lib: $prjLib) has been generated by an external script. Adding to $extra_file_name..."
2656 close $new_extra_file
2665 proc ReadExtraFileList { extra_file_name } {
2666 set extra_file_dict [dict create]
2667 if {[
file exists $extra_file_name]} {
2668 set file [open $extra_file_name "r"]
2669 set file_data [read $file]
2672 set data [
split $file_data "\n"]
2673 foreach line $data {
2674 if {![regexp {^ *$} $line] & ![regexp {^ *\#} $line] } {
2675 set ip_and_md5 [regexp -all -inline {\S+} $line]
2676 dict lappend extra_file_dict "[
lindex $ip_and_md5 0]" "[
lindex $ip_and_md5 1]"
2680 return $extra_file_dict
2689 proc GenerateQsysSystem {qsysFile commandOpts} {
2690 if { [
file exists $qsysFile] != 0} {
2691 set qsysPath [
file dirname $qsysFile]
2692 set qsysName [
file rootname [
file tail $qsysFile]]
2693 set qsysIPDir "$qsysPath/$qsysName"
2694 set qsysLogFile "$qsysPath/$qsysName.qsys-generate.log"
2697 if {! [
info exists ::env(QSYS_ROOTDIR)] } {
2698 if {[
info exists ::env(QUARTUS_ROOTDIR)] } {
2699 set qsys_rootdir "$::env(QUARTUS_ROOTDIR)/sopc_builder/bin"
2700 Msg Warning "The QSYS_ROOTDIR environment variable is not set! I will use $qsys_rootdir"
2702 Msg CriticalWarning "The QUARTUS_ROOTDIR environment variable is not set! Assuming all quartus executables are contained in your PATH!"
2705 set qsys_rootdir $::env(QSYS_ROOTDIR)
2708 set cmd "$qsys_rootdir/qsys-generate"
2709 set cmd_options "$qsysFile --output-directory=$qsysIPDir $commandOpts"
2710 if {![
catch {"exec $cmd -version"}] || [
lindex $::errorCode 0] eq "NONE"} {
2711 Msg Info "Executing: $cmd $cmd_options"
2712 Msg Info "Saving logfile in: $qsysLogFile"
2713 if {[
catch {
eval exec -ignorestderr "$cmd $cmd_options >>& $qsysLogFile"} ret opt]} {
2714 set makeRet [
lindex [dict get $opt -errorcode] end]
2715 Msg CriticalWarning "$cmd returned with $makeRet"
2718 Msg Error " Could not execute command $cmd"
2722 set qsysIPFileList [
concat [glob -nocomplain -directory $qsysIPDir -types f *.ip *.qip] [glob -nocomplain -directory "$qsysIPDir/synthesis" -types f *.ip *.qip *.vhd *.vhdl]]
2723 foreach qsysIPFile $qsysIPFileList {
2724 if { [
file exists $qsysIPFile] != 0} {
2726 set_global_assignment -name $qsysIPFileType $qsysIPFile
2728 set IpMd5Sum [
Md5Sum $qsysIPFile]
2730 set fileDir [
file normalize "./hogTmp"]
2731 set fileName "$fileDir/.hogQsys.md5"
2732 if {![
file exists $fileDir]} {
2735 set hogQsysFile [open $fileName "a"]
2736 set fileEntry "$qsysIPFile\t$IpMd5Sum"
2737 puts $hogQsysFile $fileEntry
2742 Msg ERROR "Error while generating ip variations from qsys: $qsysFile not found!"
2748 proc ForceUpToDate {} {
2749 Msg Info "Forcing all the runs to look up to date..."
2752 Msg Info "Forcing $r..."
2753 set_property needs_refresh false [get_runs $r]
2767 proc HandleIP {what_to_do xci_file ip_path repo_path {gen_dir "."} {force 0}} {
2768 if {!($what_to_do eq "push") && !($what_to_do eq "pull")} {
2769 Msg Error "You must specify push or pull as first argument."
2772 if { [
catch {
package require tar} TARPACKAGE]} {
2773 Msg CriticalWarning "Cannot find package tar. You can fix this by installing package \"tcllib\""
2782 if {[
string first "/eos/" $ip_path] == 0} {
2790 lassign [
eos "ls $ip_path"] ret result
2792 Msg CriticalWarning "Could not run ls for for EOS path: $ip_path (error: $result). Either the drectory does not exist or there are (temporary) problem with EOS."
2796 Msg Info "IP remote directory path, on EOS, is set to: $ip_path"
2803 if {!([
file exists $xci_file])} {
2804 Msg CriticalWarning "Could not find $xci_file."
2810 set xci_path [
file dirname $xci_file]
2811 set xci_name [
file tail $xci_file]
2812 set xci_ip_name [
file rootname [
file tail $xci_file]]
2813 set xci_dir_name [
file tail $xci_path]
2814 set gen_path $gen_dir
2816 set hash [
Md5Sum $xci_file]
2817 set file_name $xci_name\_$hash
2819 Msg Info "Preparing to $what_to_do IP: $xci_name..."
2821 if {$what_to_do eq "push"} {
2825 lassign [
eos "ls $ip_path/$file_name.tar"] ret result
2830 Msg Info "IP already in the EOS repository, will not copy..."
2832 Msg Info "IP already in the EOS repository, will forcefully replace..."
2838 if {[
file exists "$ip_path/$file_name.tar"]} {
2840 Msg Info "IP already in the local repository, will not copy..."
2842 Msg Info "IP already in the local repository, will forcefully replace..."
2851 if {$will_copy == 1} {
2853 Msg Info "Looking for generated files in $gen_path..."
2854 set ip_gen_files [glob -nocomplain $gen_path/*]
2858 if {[
llength $ip_gen_files] > 0} {
2859 Msg Info "Found some IP synthesised files matching $xci_ip_name"
2860 if {$will_remove == 1} {
2861 Msg Info "Removing old synthesised directory $ip_path/$file_name.tar..."
2863 eos "rm -rf $ip_path/$file_name.tar" 5
2865 file delete -force "$ip_path/$file_name.tar"
2869 Msg Info "Creating local archive with IP generated files..."
2871 foreach f $ip_gen_files {
2872 if {$first_file == 0} {
2873 ::tar::create $file_name.tar "[
Relative [
file normalize $repo_path] $f]"
2876 ::tar::add $file_name.tar "[
Relative [
file normalize $repo_path] $f]"
2880 Msg Info "Copying IP generated files for $xci_name..."
2882 lassign [
ExecuteRet xrdcp -f -s $file_name.tar $::env(EOS_MGM_URL)//$ip_path/] ret msg
2884 Msg CriticalWarning "Something went wrong when copying the IP files to EOS. Error message: $msg"
2887 Copy "$file_name.tar" "$ip_path/"
2889 Msg Info "Removing local archive"
2890 file delete $file_name.tar
2893 Msg Warning "Could not find synthesized files matching $gen_path/$file_name*"
2896 }
elseif {$what_to_do eq "pull"} {
2898 lassign [
eos "ls $ip_path/$file_name.tar"] ret result
2900 Msg Info "Nothing for $xci_name was found in the EOS repository, cannot pull."
2905 set remote_tar "$::env(EOS_MGM_URL)//$ip_path/$file_name.tar"
2906 Msg Info "IP $xci_name found in the repository $remote_tar, copying it locally to $repo_path..."
2908 lassign [
ExecuteRet xrdcp -f -r -s $remote_tar $repo_path] ret msg
2910 Msg CriticalWarning "Something went wrong when copying the IP files to EOS. Error message: $msg"
2914 if {[
file exists "$ip_path/$file_name.tar"]} {
2915 Msg Info "IP $xci_name found in local repository $ip_path/$file_name.tar, copying it locally to $repo_path..."
2916 Copy $ip_path/$file_name.tar $repo_path
2919 Msg Info "Nothing for $xci_name was found in the local IP repository, cannot pull."
2926 if {[
file exists $file_name.tar]} {
2927 remove_files $xci_file
2928 Msg Info "Extracting IP files from archive to $repo_path..."
2929 ::tar::untar $file_name.tar -dir $repo_path -noperms
2930 Msg Info "Removing local archive"
2931 file delete $file_name.tar
2932 add_files -norecurse -fileset sources_1 $xci_file
2942 proc Md5Sum {file_name} {
2943 if {!([
file exists $file_name])} {
2944 Msg Warning "Could not find $file_name."
2947 if {[
catch {
package require md5 2.0.7} result]} {
2948 Msg Warning "Tcl package md5 version 2.0.7 not found ($result), will use command line..."
2949 set hash [
lindex [
Execute md5sum $file_name] 0]
2951 set file_hash [
string tolower [md5::md5 -hex -file $file_name]]
2961 proc CheckYmlRef {repo_path allow_failure} {
2963 if {$allow_failure} {
2964 set MSG_TYPE CriticalWarning
2969 if { [
catch {
package require yaml 0.3.3} YAMLPACKAGE]} {
2970 Msg CriticalWarning "Cannot find package YAML, skipping consistency check of \"ref\" in gilab-ci.yaml file.\n Error message: $YAMLPACKAGE
2971 You can fix this by installing package \"tcllib\""
2979 if {[
file exists .gitlab-ci.yml]} {
2983 if { [
file exists .gitlab-ci.yml] } {
2984 set fp [open ".gitlab-ci.yml" r]
2985 set file_data [read $fp]
2988 Msg $MSG_TYPE "Cannot open file .gitlab-ci.yml"
2992 set file_data "\n$file_data\n\n"
2994 if { [
catch {::yaml::yaml2dict -stream $file_data} yamlDict]} {
2995 Msg $MSG_TYPE "Parsing $repo_path/.gitlab-ci.yml failed. To fix this, check that yaml syntax is respected, remember not to use tabs."
2999 dict for {dictKey dictValue} $yamlDict {
3000 #looking for Hog include in .gitlab-ci.yml
3001 if {"$dictKey" == "include" && ([lsearch [split $dictValue " {}"] "/hog.yml" ] != "-1" || [lsearch [split $dictValue " {}"] "/hog-dynamic.yml" ] != "-1")} {
3002 set YML_REF [lindex [split $dictValue " {}"] [expr {[lsearch -dictionary [split $dictValue " {}"] "ref"]+1} ] ]
3003 set YML_NAME [lindex [split $dictValue " {}"] [expr {[lsearch -dictionary [split $dictValue " {}"] "file"]+1} ] ]
3007 if {$YML_REF == ""} {
3008 Msg Warning "Hog version not specified in the .gitlab-ci.yml. Assuming that master branch is used."
3010 set YML_REF_F [
Git {name-rev --tags --name-only origin/master}]
3013 set YML_REF_F [regsub -all "'" $YML_REF ""]
3016 if {$YML_NAME == ""} {
3017 Msg $MSG_TYPE "Hog included yml file not specified, assuming hog.yml"
3018 set YML_NAME_F hog.yml
3020 set YML_NAME_F [regsub -all "^/" $YML_NAME ""]
3023 lappend YML_FILES $YML_NAME_F
3029 if { [
catch {::yaml::yaml2dict -file $YML_NAME_F} yamlDict]} {
3030 Msg $MSG_TYPE "Parsing $YML_NAME_F failed."
3034 dict for {dictKey dictValue} $yamlDict {
3035 #looking for included files
3036 if {"$dictKey" == "include"} {
3037 foreach v $dictValue {
3038 lappend YML_FILES [lindex [split $v " "] [expr {[lsearch -dictionary [split $v " "] "local"]+1} ] ]
3044 Msg Info "Found the following yml files: $YML_FILES"
3046 set HOGYML_SHA [
GetSHA $YML_FILES]
3047 lassign [
GitRet "log --format=%h -1 --abbrev=7 $YML_REF_F" $YML_FILES] ret EXPECTEDYML_SHA
3049 lassign [
GitRet "log --format=%h -1 --abbrev=7 origin/$YML_REF_F" $YML_FILES] ret EXPECTEDYML_SHA
3051 Msg $MSG_TYPE "Error in project .gitlab-ci.yml. ref: $YML_REF not found"
3052 set EXPECTEDYML_SHA ""
3055 if {!($EXPECTEDYML_SHA eq "")} {
3056 if {$HOGYML_SHA == $EXPECTEDYML_SHA} {
3057 Msg Info "Hog included file $YML_FILES matches with $YML_REF in .gitlab-ci.yml."
3060 Msg $MSG_TYPE "HOG $YML_FILES SHA mismatch.
3061 From Hog submodule: $HOGYML_SHA
3062 From ref in .gitlab-ci.yml: $EXPECTEDYML_SHA
3063 You can fix this in 2 ways: by changing the ref in your repository or by changing the Hog submodule commit"
3066 Msg $MSG_TYPE "One or more of the following files could not be found $YML_FILES in Hog at $YML_REF"
3069 Msg Info ".gitlab-ci.yml not found in $repo_path. Skipping this step"
3079 proc ParseJSON {JSON_FILE JSON_KEY} {
3080 set result [
catch {
package require Tcl 8.4} TclFound]
3081 if {"$result" != "0"} {
3082 Msg CriticalWarning "Cannot find Tcl package version equal or higher than 8.4.\n $TclFound\n Exiting"
3086 set result [
catch {
package require json} JsonFound]
3087 if {"$result" != "0"} {
3088 Msg CriticalWarning "Cannot find JSON package equal or higher than 1.0.\n $JsonFound\n Exiting"
3091 set JsonDict [json::json2dict $JSON_FILE]
3092 set result [
catch {dict get $JsonDict $JSON_KEY} RETURNVALUE]
3093 if {"$result" != "0"} {
3094 Msg CriticalWarning "Cannot find $JSON_KEY in $JSON_FILE\n Exiting"
3110 proc eos {command {attempt 1}} {
3112 if {![
info exists env(EOS_MGM_URL)]} {
3113 Msg Warning "Environment variable EOS_MGM_URL not set, setting it to default value root://eosuser.cern.ch"
3114 set ::env(EOS_MGM_URL) "root://eosuser.cern.ch"
3117 Msg Warning "The value of attempt should be 1 or more, not $attempt, setting it to 1 as default"
3120 for {
set i 0} {$i < $attempt} {
incr i} {
3121 set ret [
catch {
exec -ignorestderr eos {*}$command} result]
3126 set wait [
expr {1+int(rand()*29)}]
3127 Msg Warning "Command $command failed ($i/$attempt): $result, trying again in $wait seconds..."
3128 after [
expr {$wait*1000}]
3132 return [list $ret $result]
3142 proc Git {command {files ""}} {
3143 lassign [
GitRet $command $files] ret result
3145 Msg Error "Code $ret returned by git running: $command -- $files"
3160 proc GitRet {command {files ""}} {
3163 set ret [
catch {
exec -ignorestderr git {*}$command} result]
3165 set ret [
catch {
exec -ignorestderr git {*}$command -- {*}$files} result]
3169 return [list $ret $result]
3178 proc FileCommitted {File } {
3180 set currentDir [
pwd]
3181 cd [
file dirname [
file normalize $File]]
3182 set GitLog [
Git ls-files [
file tail $File]]
3183 if {$GitLog == ""} {
3184 Msg CriticalWarning "File [
file normalize $File] is not in the git repository. Please add it with:\n git add [
file normalize $File]\n"
3199 proc ExecuteRet {args} {
3201 if {[
llength $args] == 0} {
3202 Msg CriticalWarning "No argument given"
3206 set ret [
catch {
exec -ignorestderr {*}$args} result]
3209 return [list $ret $result]
3219 proc Execute {args} {
3223 Msg Error "Command [
join $args] returned error code: $ret"
3238 proc GetMaxThreads {proj_dir} {
3240 if {[
file exists $proj_dir/hog.conf]} {
3242 if {[dict exists $properties parameters]} {
3243 set propDict [dict get $properties parameters]
3244 if {[dict exists $propDict MAX_THREADS]} {
3245 set maxThreads [dict get $propDict MAX_THREADS]
3249 Msg Warning "File $proj_dir/hog.conf not found. Max threads will be set to default value 1"
3261 proc WriteGitLabCIYAML {proj_name {ci_conf ""}} {
3262 if { [
catch {
package require yaml 0.3.3} YAMLPACKAGE]} {
3263 Msg CriticalWarning "Cannot find package YAML.\n Error message: $YAMLPACKAGE. If you are tunning on tclsh, you can fix this by installing package \"tcllib\""
3268 if {$ci_conf != ""} {
3270 foreach sec [dict keys $ci_confs] {
3271 if {[
string first : $sec] == -1} {
3272 lappend job_list $sec
3276 set job_list {"generate_project" "simulate_project"}
3280 set out_yaml [huddle create]
3281 foreach job $job_list {
3283 set huddle_tags [huddle list]
3285 set sec_dict [dict create]
3287 if {$ci_confs != ""} {
3288 foreach var [dict keys [dict get $ci_confs $job]] {
3289 if {$var == "tags"} {
3290 set tag_section "tags"
3291 set tags [dict get [dict get $ci_confs $job] $var]
3292 set tags [
split $tags ","]
3294 set tag_list [huddle list $tag]
3295 set huddle_tags [huddle combine $huddle_tags $tag_list]
3298 dict set sec_dict $var [dict get [dict get $ci_confs $job] $var]
3304 set huddle_variables [huddle create "PROJECT_NAME" $proj_name "extends" ".vars"]
3305 if {[dict exists $ci_confs "$job:variables"]} {
3306 set var_dict [dict get $ci_confs $job:variables]
3307 foreach var [dict keys $var_dict] {
3309 set value [dict get $var_dict "$var"]
3310 set var_inner [huddle create "$var" "$value"]
3311 set huddle_variables [huddle combine $huddle_variables $var_inner]
3316 set middle [huddle create "extends" ".$job" "variables" $huddle_variables]
3317 foreach sec [dict keys $sec_dict] {
3318 set value [dict get $sec_dict $sec]
3319 set var_inner [huddle create "$sec" "$value"]
3320 set middle [huddle combine $middle $var_inner]
3322 if {$tag_section != ""} {
3323 set middle2 [huddle create "$tag_section" $huddle_tags]
3324 set middle [huddle combine $middle $middle2]
3327 set outer [huddle create "$job:$proj_name" $middle]
3328 set out_yaml [huddle combine $out_yaml $outer]
3331 return [
string trimleft [ yaml::huddle2yaml $out_yaml] "-"]
3335 proc FindNewestVersion { versions } {
3336 set new_ver 00000000
3337 foreach ver $versions {
3339 if {[
expr 0x$ver > 0x$new_ver] } {
3352 proc ResetRepoFiles {reset_file} {
3353 if {[
file exists $reset_file]} {
3354 Msg Info "Found $reset_file, opening it..."
3355 set fp [open $reset_file r]
3356 set wild_cards [lsearch -all -inline -not -regexp [
split [read $fp] "\n"] "^ *$"]
3358 Msg Info "Found the following files/wild cards to restore if modified: $wild_cards..."
3359 foreach w $wild_cards {
3361 if {[
llength $mod_files] > 0} {
3362 Msg Info "Found modified $w files: $mod_files, will restore them..."
3365 Msg Info "No modified $w files found."
3377 proc SearchHogProjects {dir} {
3378 set projects_list {}
3379 if {[
file exists $dir]} {
3380 if {[
file isdirectory $dir]} {
3381 foreach proj_dir [glob -nocomplain -types d $dir/*] {
3382 if {![regexp {^.*Top/+(.*)$} $proj_dir dummy proj_name]} {
3383 Msg Warning "Could not parse Top directory $dir"
3386 if { [
file exists "$proj_dir/hog.conf"] } {
3387 lappend projects_list $proj_name
3390 lappend projects_list $p
3396 Msg Error "Input $dir is not a directory!"
3399 Msg Error "Directory $dir doesn't exist!"
3401 return $projects_list
3411 proc GetGroupName {proj_dir repo_dir} {
3412 if {[regexp {^(.*)/(Top|Projects)/+(.*?)/*$} $proj_dir dummy possible_repo_dir proj_or_top dir]} {
3414 if {[
file normalize $repo_dir] eq [
file normalize $possible_repo_dir]} {
3415 set group [
file dir $dir]
3416 if { $group == "." } {
3421 Msg Warning "Project directory $proj_dir seems to be in $possible_repo_dir which is not a the main Git repository $repo_dir."
3424 Msg Warning "Could not parse project directory $proj_dir"
3436 proc ReadConf {file_name} {
3438 if { [
catch {
package require inifile 0.2.3} ERROR] } {
3439 puts "$ERROR\n If you are running this script on tclsh, you can fix this by installing 'tcllib'"
3444 ::ini::commentchar "#"
3445 set f [::ini::open $file_name]
3446 set properties [dict create]
3447 foreach sec [::ini::sections $f] {
3449 set key_pairs [::ini::get $f $sec]
3452 regsub -all {\{\"} $key_pairs "\{" key_pairs
3453 regsub -all {\"\}} $key_pairs "\}" key_pairs
3455 dict set properties $new_sec [dict create {*}$key_pairs]
3470 proc WriteConf {file_name config {comment ""}} {
3471 if { [
catch {
package require inifile 0.2.3} ERROR] } {
3472 puts "$ERROR\n If you are running this script on tclsh, you can fix this by installing 'tcllib'"
3476 ::ini::commentchar "#"
3477 set f [::ini::open $file_name w]
3479 foreach sec [dict keys $config] {
3480 set section [dict get $config $sec]
3481 dict for {p v} $section {
3482 if {[string trim $v] == ""} {
3483 Msg Warning "Property $p has empty value. Skipping..."
3486 ::ini::set $f $sec $p $v
3491 if {![
string equal "$comment" ""]} {
3492 ::ini::comment $f [
lindex [::ini::sections $f] 0] "" $comment
3505 proc IsRelativePath {path} {
3506 if {[
string index $path 0] == "/" || [
string index $path 0] == "~"} {
3516 Msg Error "Found Git version older than 2.7.2. Hog will not work as expected, exiting now."
3526 proc WriteUtilizationSummary {input output project_name run} {
3527 set f [open $input "r"]
3528 set o [open $output "a"]
3529 puts $o "## $project_name $run Utilization report\n\n"
3530 struct::matrix util_m
3531 util_m add columns 14
3534 util_m add row "| **Site Type** | **Used** | **Fixed** | **Prohibited** | **Available** | **Util%** |"
3535 util_m add row "| --- | --- | --- | --- | --- | --- |"
3537 util_m add row "| **Site Type** | **Used** | **Fixed** | **Available** | **Util%** |"
3538 util_m add row "| --- | --- | --- | --- | --- |"
3548 while {[
gets $f line] >= 0} {
3549 if { ( [
string first "| CLB LUTs" $line] >= 0 || [
string first "| Slice LUTs" $line] >= 0 ) && $luts == 0 } {
3550 util_m add row $line
3553 if { ( [
string first "| CLB Registers" $line] >= 0 || [
string first "| Slice Registers" $line] >= 0 ) && $regs == 0} {
3554 util_m add row $line
3557 if { [
string first "| Block RAM Tile" $line] >= 0 && $bram == 0 } {
3558 util_m add row $line
3561 if { [
string first "URAM " $line] >= 0 && $uram == 0} {
3562 util_m add row $line
3565 if { [
string first "DSPs" $line] >= 0 && $dsps == 0 } {
3566 util_m add row $line
3569 if { [
string first "Bonded IOB" $line] >= 0 && $ios == 0 } {
3570 util_m add row $line
3577 puts $o [util_m format 2string]
3584 proc GetDateAndTime {commit} {
3585 set clock_seconds [
clock seconds]
3588 set date [
Git "log -1 --format=%cd --date=format:%d%m%Y $commit"]
3589 set timee [
Git "log -1 --format=%cd --date=format:00%H%M%S $commit"]
3591 Msg Warning "Found Git version older than 2.9.3. Using current date and time instead of commit time."
3592 set date [
clock format $clock_seconds -format {%d%m%Y}]
3593 set timee [
clock format $clock_seconds -format {00%H%M%S}]
3595 return [list $date $timee]
3601 proc GetProjectFlavour {proj_name} {
3603 set flavour [
string map {. ""} [
file extension $proj_name]]
3604 if {$flavour != ""} {
3605 if {[
string is integer $flavour]} {
3606 Msg Info "Project $proj_name has flavour = $flavour, the generic variable FLAVOUR will be set to $flavour"
3608 Msg Warning "Project name has a unexpected non numeric extension, flavour will be set to -1"
3622 proc FormatGeneric {generic} {
3623 if {[
string is integer "0x$generic"]} {
3624 return [
format "32'h%08X" "0x$generic"]
3627 return [
format "32'h%08X" 0]
3638 proc GetGenericFromConf {proj_dir target {sim 0}} {
3640 set top_dir "Top/$proj_dir"
3641 set conf_file "$top_dir/hog.conf"
3644 set conf_file "$top_dir/sim.conf"
3649 if {[
file exists $conf_file]} {
3651 if {[dict exists $properties generics]} {
3652 set propDict [dict get $properties generics]
3653 dict for {theKey theValue} $propDict {
3662 regexp {([0-9]*)('h)([0-9a-fA-F]*)} $theValue valueHexFull valueNumBits valueHexFlag valueHex
3663 regexp {^([0-9]*)$} $theValue valueIntFull ValueInt
3664 regexp {(?!^\d+$)^.+$} $theValue valueStrFull ValueStr
3665 if { [string tolower $target] == "vivado" || [string tolower $target] == "xsim" } {
3666 if {$valueNumBits != "" && $valueHexFlag != "" && $valueHex != ""} {
3667 set prj_generics "$prj_generics $theKey=$valueHexFull"
3668 } elseif { $valueIntFull != "" && $ValueInt != "" } {
3669 set prj_generics "$prj_generics $theKey=$ValueInt"
3670 } elseif { $valueStrFull != "" && $ValueStr != "" } {
3671 set prj_generics "$prj_generics $theKey=\"$ValueStr\""
3673 set prj_generics "$prj_generics $theKey=\"$theValue\""
3675 } elseif { [lsearch -exact [GetSimulators] [string tolower $target] ] >= 0 } {
3676 if {$valueNumBits != "" && $valueHexFlag != "" && $valueHex != ""} {
3678 scan $valueNumBits %d numBits
3680 scan $valueHex %x numHex
3681 binary scan [binary format "I" $numHex] "B*" binval
3682 set numBits [expr {$numBits-1}]
3683 set numBin [string range $binval end-$numBits end]
3684 set prj_generics "$prj_generics $theKey=\"$numBin\""
3686 } elseif { $valueIntFull != "" && $ValueInt != "" } {
3687 set prj_generics "$prj_generics $theKey=$ValueInt"
3688 } elseif { $valueStrFull != "" && $ValueStr != "" } {
3689 set prj_generics "$prj_generics {$theKey=\"$ValueStr\"}"
3692 set prj_generics "$prj_generics {$theKey=\"$theValue\"}"
3695 Msg Warning "Target : $target not implemented"
3700 Msg Warning "File $top_dir/hog.conf not found."
3702 return $prj_generics
3711 proc SetGenericsSimulation {proj_dir target} {
3713 set top_dir "Top/$proj_dir"
3715 set sim_cfg_index [lsearch -regexp -index 0 $read_aux ".*sim.conf"]
3716 set sim_cfg_index [lsearch -regexp -index 0 [
GetConfFiles $top_dir] ".*sim.conf"]
3717 set simsets [get_filesets]
3718 if { $simsets != "" } {
3719 if {[
file exists $top_dir/sim.conf]} {
3721 if {$sim_generics != ""} {
3722 foreach simset $simsets {
3723 if {[get_property FILESET_TYPE $simset] != "SimulationSrcs" } {
3726 set_property generic $sim_generics [get_filesets $simset]
3727 Msg Debug "Setting generics $sim_generics for simulator $target and simulation file-set $simset..."
3731 Msg Warning "Simulation sets are present in the project but no sim.conf found in $top_dir. Please refer to Hog's manual to create one."
3737 proc GetTopFile {} {
3742 return [
lindex [get_files -quiet -compile_order sources -used_in synthesis -filter {FILE_TYPE =~ "VHDL*" || FILE_TYPE =~ "*Verilog*" }] end]
3743 }
elseif {[
IsISE]} {
3744 debug::design_graph_mgr -create [current_fileset]
3745 debug::design_graph -add_fileset [current_fileset]
3746 debug::design_graph -update_all
3747 return [
lindex [debug::design_graph -get_compile_order] end]
3749 Msg Error "GetTopFile not yet implemented for this IDE"
3754 proc GetTopModule {} {
3756 return [get_property top [current_fileset]]
3758 Msg Error "GetTopModule not yet implemented for this IDE"
3765 proc GetVerilogGenerics {file} {
3766 set fp [open $file r]
3772 foreach line [
split $data "\n"] {
3773 regsub "^\\s*\/\/.*" $line "" line
3774 regsub "(.*)\/\/.*" $line {\1} line
3775 if {![
string equal $line ""]} {
3776 append lines $line " "
3781 regsub -all {/\*.*\*/} $lines "" lines
3784 set punctuation [list]
3785 foreach char [list "(" ")" ";" "," " " "!" "<=" ":=" "=" "\[" "\]"] {
3786 lappend punctuation $char "\000$char\000"
3790 set tokens [
split [
string map $punctuation $lines] \000]
3792 set parameters [dict create]
3801 foreach token $tokens {
3802 set token [
string trim $token]
3803 if {![
string equal "" $token]} {
3804 if {[
string equal [
string tolower $token] "parameter"]} {
3805 set state $PARAM_NAME
3806 }
elseif {[
string equal $token ")"] || [
string equal $token ";"]} {
3808 }
elseif {$state == $PARAM_WIDTH} {
3809 if {[
string equal $token "\]"]} {
3810 set state $PARAM_NAME
3812 }
elseif {$state == $PARAM_VALUE} {
3813 if {[
string equal $token ","]} {
3814 set state $PARAM_NAME
3815 }
elseif {[
string equal $token ";"]} {
3819 }
elseif {$state == $PARAM_NAME} {
3821 if {[
string equal $token "="]} {
3822 set state $PARAM_VALUE
3823 }
elseif {[
string equal $token "\["]} {
3824 set state $PARAM_WIDTH
3825 }
elseif {[
string equal $token ","]} {
3826 set state $PARAM_NAME
3827 }
elseif {[
string equal $token ";"]} {
3829 }
elseif {[
string equal $token ")"]} {
3832 dict set parameters $token "integer"
3842 proc GetVhdlGenerics {file {entity ""} } {
3843 set fp [open $file r]
3849 foreach line [
split $data "\n"] {
3850 regsub "^\\s*--.*" $line "" line
3851 regsub "(.*)--.*" $line {\1} line
3852 if {![
string equal $line ""]} {
3853 append lines $line " "
3858 set generic_block ""
3859 set generics [dict create]
3861 if {1==[
string equal $entity ""]} {
3862 regexp {(?i).*entity\s+([^\s]+)\s+is} $lines _ entity
3865 set generics_regexp "(?i).*entity\\s+$entity\\s+is\\s+generic\\s*\\((.*)\\)\\s*;\\s*port.*end.*$entity"
3867 if {[regexp $generics_regexp $lines _ generic_block]} {
3870 foreach line [
split $generic_block ";"] {
3873 regexp {(.*):\s*([A-Za-z0-9_]+).*} $line _ generic type
3876 set splits [
split $generic ","]
3877 foreach split $splits {
3878 dict set generics [
string trim $split] [
string trim $type]
3885 proc GetFileGenerics {filename {entity ""}} {
3887 if {[
string equal $file_type "VERILOG_FILE"] || [
string equal $file_type "SYSTEMVERILOG_FILE"]} {
3889 }
elseif {[
string equal $file_type "VHDL_FILE"]} {
3892 Msg CriticalWarning "Could not determine extension of top level file."
3899 proc WriteGenerics {mode design 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 ""}} {
3900 Msg Info "Passing parameters/generics to project's top module..."
3903 set generic_string [
concat \
3915 if {$xml_hash != "" && $xml_ver != ""} {
3916 lappend generic_string \
3921 foreach l $libs v $vers h $hashes {
3924 lappend generic_string "$ver" "$hash"
3927 foreach e $ext_names h $ext_hashes {
3929 lappend generic_string "$hash"
3932 foreach repo $user_ip_repos v $user_ip_vers h $user_ip_hashes {
3933 set repo_name [
file tail $repo]
3934 set ver "[
string toupper $repo_name]_VER=[
FormatGeneric $v]"
3935 set hash "[
string toupper $repo_name]_SHA=[
FormatGeneric $h]"
3936 lappend generic_string "$ver" "$hash"
3939 if {$flavour != -1} {
3940 lappend generic_string "FLAVOUR=$flavour"
3945 set generic_string "$prj_generics $generic_string"
3950 if {$mode == "create" || [
IsISE]} {
3954 Msg Debug "$top_file"
3955 if {[
file exists $top_file]} {
3958 Msg Debug "Found top level generics $generics in $top_file"
3960 set filtered_generic_string ""
3962 foreach generic_to_set [
split [
string trim $generic_string]] {
3963 set key [
lindex [
split $generic_to_set "="] 0]
3964 if {[dict exists $generics $key]} {
3965 Msg Debug "Hog generic $key found in $top_name"
3966 lappend filtered_generic_string "$generic_to_set"
3968 Msg Warning "Generic $key is passed by Hog but is NOT present in $top_name."
3974 set generic_string $filtered_generic_string
3979 set_property generic $generic_string [current_fileset]
3980 Msg Info "Setting parameters/generics..."
3981 Msg Debug "Detailed parameters/generics: $generic_string"
3985 set simulator [get_property target_simulator [current_project]]
3986 if {$mode == "create"} {
3991 Msg Info "Setting Synplify parameters/generics one by one..."
3992 foreach generic $generic_string {
3993 Msg Debug "Setting Synplify generic: $generic"
3994 set_option -hdl_param -set "$generic"
4003 proc GetIDEVersion {} {
4006 regexp {\d+\.\d+(\.\d+)?} [version -short] ver
4012 regexp {[\.0-9]+} $quartus(version) ver
4015 set ver [get_libero_version]
4023 proc GetIDEFromConf {conf_file} {
4024 set f [open $conf_file "r"]
4027 if {[regexp -all {^\# *(\w*) *(\d+\.\d+(?:\.\d+)?(?:\.\d+)?)?(_.*)? *$} $line dummy ide version patch]} {
4028 if {[
info exists version] && $version != ""} {
4034 set ret [list $ide $ver]
4036 Msg CriticalWarning "The first line of hog.conf should be \#<IDE name> <version>, where <IDE name>. is quartus, vivado, planahead and <version> the tool version, e.g. \#vivado 2020.2. Will assume vivado."
4037 set ret [list "vivado" "0.0.0"]
4049 if {[
file exists $dir] && [
file isdirectory $dir]} {
4063 proc Copy {i_dirs o_dir} {
4064 foreach i_dir $i_dirs {
4065 if {[
file isdirectory $i_dir] && [
file isdirectory $o_dir]} {
4066 if {([
file tail $i_dir] == [
file tail $o_dir]) || ([
file exists $o_dir/[
file tail $i_dir]] && [
file isdirectory $o_dir/[
file tail $i_dir]])} {
4067 file delete -force $o_dir/[
file tail $i_dir]
4071 file copy -force $i_dir $o_dir
4080 proc RemoveDuplicates {mydict} {
4081 set new_dict [dict create]
4082 foreach key [dict keys $mydict] {
4083 set values [
DictGet $mydict $key]
4084 foreach value $values {
4085 set idxs [
lreverse [
lreplace [lsearch -exact -all $values $value] 0 0]]
4087 set values [
lreplace $values $idx $idx]
4090 dict set new_dict $key $values
4110 proc CompareLibDicts {proj_libs list_libs proj_sets list_sets proj_props list_props {severity "CriticalWarning"} {outFile ""} {extraFiles ""} } {
4111 set extra_files $extraFiles
4113 set out_prjlibs $proj_libs
4114 set out_prjprops $proj_props
4116 dict for {prjSet prjLibraries} $proj_sets {
4117 # Check if sets is also in list files
4118 if {[IsInList $prjSet $list_sets]} {
4119 set listLibraries [DictGet $list_sets $prjSet]
4120 # Loop over libraries in fileset
4121 foreach prjLib $prjLibraries {
4122 set prjFiles [DictGet $proj_libs $prjLib]
4123 # Check if library exists in list files
4124 if {[IsInList $prjLib $listLibraries]} {
4125 # Loop over files in library
4126 set listFiles [DictGet $list_libs $prjLib]
4127 foreach prjFile $prjFiles {
4128 set idx [lsearch -exact $listFiles $prjFile]
4129 set listFiles [lreplace $listFiles $idx $idx]
4131 # File is in project but not in list libraries, check if it was generated at creation time...
4132 if { [dict exists $extra_files $prjFile] } {
4133 # File was generated at creation time, checking the md5sum
4134 # Removing the file from the prjFiles list
4135 set idx2 [lsearch -exact $prjFiles $prjFile]
4136 set prjFiles [lreplace $prjFiles $idx2 $idx2]
4137 set new_md5sum [Md5Sum $prjFile]
4138 set old_md5sum [DictGet $extra_files $prjFile]
4139 if {$new_md5sum != $old_md5sum} {
4140 MsgAndLog "$prjFile in project has been modified from creation time. Please update the script you used to create the file and regenerate the project, or save the file outside the Projects/ directory and add it to a project list file" $severity $outFile
4143 set extra_files [dict remove $extra_files $prjFile]
4145 # File is neither in list files nor in extra_files
4146 MsgAndLog "$prjFile was found in project but not in list files or .hog/extra.files" $severity $outFile
4150 # File is both in list files and project, checking properties...
4151 set prjProps [DictGet $proj_props $prjFile]
4152 set listProps [DictGet $list_props $prjFile]
4153 # Check if it is a potential sourced file
4154 if {[IsInList "nosynth" $prjProps] && [IsInList "noimpl" $prjProps] && [IsInList "nosim" $prjProps]} {
4155 # Check if it is sourced
4156 set idx_source [lsearch -exact $listProps "source"]
4157 if {$idx_source >= 0 } {
4158 # It is sourced, let's replace the individual properties with source
4159 set idx [lsearch -exact $prjProps "noimpl"]
4160 set prjProps [lreplace $prjProps $idx $idx]
4161 set idx [lsearch -exact $prjProps "nosynth"]
4162 set prjProps [lreplace $prjProps $idx $idx]
4163 set idx [lsearch -exact $prjProps "nosim"]
4164 set prjProps [lreplace $prjProps $idx $idx]
4165 lappend prjProps "source"
4169 foreach prjProp $prjProps {
4170 set idx [lsearch -exact $listProps $prjProp]
4171 set listProps [lreplace $listProps $idx $idx]
4173 MsgAndLog "Property $prjProp of $prjFile was set in project but not in list files" $severity $outFile
4178 foreach listProp $listProps {
4179 if {[string first $listProp "topsim="] == -1} {
4180 MsgAndLog "Property $listProp of $prjFile was found in list files but not set in project." $severity $outFile
4185 # Update project prjProps
4186 dict set out_prjprops $prjFile $prjProps
4189 # Loop over remaining files in list libraries
4190 foreach listFile $listFiles {
4191 MsgAndLog "$listFile was found in list files but not in project." $severity $outFile
4195 # Check extra files again...
4196 foreach prjFile $prjFiles {
4197 if { [dict exists $extra_files $prjFile] } {
4198 # File was generated at creation time, checking the md5sum
4199 # Removing the file from the prjFiles list
4200 set idx2 [lsearch -exact $prjFiles $prjFile]
4201 set prjFiles [lreplace $prjFiles $idx2 $idx2]
4202 set new_md5sum [Md5Sum $prjFile]
4203 set old_md5sum [DictGet $extra_files $prjFile]
4204 if {$new_md5sum != $old_md5sum} {
4205 MsgAndLog "$prjFile in project has been modified from creation time. Please update the script you used to create the file and regenerate the project, or save the file outside the Projects/ directory and add it to a project list file" $severity $outFile
4208 set extra_files [dict remove $extra_files $prjFile]
4210 # File is neither in list files nor in extra_files
4211 MsgAndLog "$prjFile was found in project but not in list files or .hog/extra.files" $severity $outFile
4216 # Update prjLibraries
4217 dict set out_prjlibs $prjLib $prjFiles
4220 MsgAndLog "Fileset $prjSet found in project but not in list files" $severity $outFile
4225 return [list $n_diffs $extra_files $out_prjlibs $out_prjprops]
4235 proc WriteSimListFiles {libs props simsets list_path repo_path } {
4237 foreach simset [dict keys $simsets] {
4238 set list_file_name $list_path/${simset}.sim
4239 set list_file [open $list_file_name w]
4240 Msg Info "Writing $list_file_name..."
4241 foreach lib [
DictGet $simsets $simset] {
4242 foreach file [
DictGet $libs $lib] {
4244 set prop [
DictGet $props $file]
4248 set lib_name [
file rootname $lib]
4249 if {$lib_name != $simset} {
4250 lappend prop "lib=$lib_name"
4252 puts $list_file "$file_path $prop"
4255 Msg Warning "The path of file $file is not relative to your repository. Please check!"
4270 proc WriteListFiles {libs props list_path repo_path {$ext_path ""} } {
4272 foreach lib [dict keys $libs] {
4273 if {[
llength [
DictGet $libs $lib]] > 0} {
4274 set list_file_name $list_path$lib
4275 set list_file [open $list_file_name w]
4276 Msg Info "Writing $list_file_name..."
4277 foreach file [
DictGet $libs $lib] {
4279 set prop [
DictGet $props $file]
4283 puts $list_file "$file_path $prop"
4286 set ext_list_file [open "[
file rootname $list_file].ext" a]
4287 puts $ext_list_file "$file_path $prop"
4288 close $ext_list_file
4291 Msg Warning "The path of file $file is not relative to your repository. Please check!"
4300 proc RemoveEmptyKeys {d} {
4302 foreach {k v} $newDict {
4303 if {$v == {{}} || $v == "" } {
4304 set newDict [dict remove $newDict $k]
4311 proc Logo { {repo_path .} } {
4312 if {[
info exists ::env(HOG_COLORED)] && [
string match "ENABLED" $::env(HOG_COLORED)]} {
4313 set logo_file "$repo_path/Hog/images/hog_logo_color.txt"
4315 set logo_file "$repo_path/Hog/images/hog_logo.txt"
4321 set ver [
Git {describe --always}]
4324 if {[
file exists $logo_file]} {
4325 set f [open $logo_file "r"]
4328 set lines [
split $data "\n"]
4334 Msg CriticalWarning "Logo file: $logo_file not found"
4337 Msg Status "Version: $ver"
4341 proc CheckLatestHogRelease {{repo_path .}} {
4344 set current_ver [
Git {describe --always}]
4345 Msg Debug "Current version: $current_ver"
4346 set current_sha [
Git "log $current_ver -1 --format=format:%H"]
4347 Msg Debug "Current SHA: $current_sha"
4350 if {[
OS] == "windows" } {
4351 Msg Info "On windows we cannot set a timeout on 'git fetch', hopefully nothing will go wrong..."
4354 Msg Info "Checking for latest Hog release, can take up to 5 seconds..."
4357 set master_ver [
Git "describe origin/master"]
4358 Msg Debug "Master version: $master_ver"
4359 set master_sha [
Git "log $master_ver -1 --format=format:%H"]
4360 Msg Debug "Master SHA: $master_sha"
4361 set merge_base [
Git "merge-base $current_sha $master_sha"]
4362 Msg Debug "merge base: $merge_base"
4365 if {$merge_base != $master_sha} {
4367 Msg Info "Version $master_ver has been released (https://gitlab.com/hog-cern/Hog/-/releases/$master_ver)"
4368 Msg Status "You should consider updating Hog submodule with the following instructions:"
4370 Msg Status "cd Hog && git checkout master && git pull"
4372 Msg Status "Also pdate the ref: in your .gitlab-ci.yml to $master_ver"
4377 Msg Info "Latest official version is $master_ver, nothing to do."
4386 proc GetOptions {argv parameters usage} {
4389 set param_list [list]
4390 set option_list [list]
4392 foreach p $parameters {
4393 lappend param_list [
lindex $p 0]
4397 while {$index < [
llength $argv]} {
4398 set arg [
lindex $argv $index]
4399 if {[
string first - $arg] == 0} {
4400 set option [
string trimleft $arg "-"]
4402 lappend option_list $arg
4403 if {[lsearch $param_list ${option}*] >= 0 && [
string first ".arg" [lsearch -inline $param_list ${option}*]] >= 0} {
4404 lappend option_list [
lindex $argv $index]
4408 lappend arg_list $arg
4412 Msg Debug "Argv: $argv"
4413 Msg Debug "Options: $option_list"
4414 Msg Debug "Arguments: $arg_list"
4415 return [list $option_list $arg_list]
4418 proc InitLauncher {script tcl_path parameters usage argv} {
4419 set repo_path [
file normalize "$tcl_path/../.."]
4421 set bin_path [
file normalize "$tcl_path/../../bin"]
4422 set top_path [
file normalize "$tcl_path/../../Top"]
4429 if {[
catch {
package require cmdline} ERROR]} {
4430 Msg Debug "The cmdline Tcl package was not found, sourcing it from Hog..."
4431 source $tcl_path/utils/cmdline.tcl
4434 lassign [
GetOptions $argv $parameters $usage] option_list arg_list
4441 if {[
catch {
array set options [
cmdline::getoptions option_list $parameters $usage]} err] } {
4442 Msg Status "\nERROR: Syntax error, probably unknown option.\n\n USAGE: $err"
4446 set directive [
string toupper [
lindex $arg_list 0]]
4448 if { [
llength $arg_list] == 1 && ($directive == "L" || $directive == "LIST")} {
4449 Msg Status "\n** The projects in this repository are:"
4454 }
elseif { [
llength $arg_list] == 0 || [
llength $arg_list] > 2} {
4455 Msg Status "\nERROR: Wrong number of arguments: [
llength $argv].\n\n"
4460 set project [
lindex $arg_list 1]
4462 regsub "^(\./)?Top/" $project "" project
4464 regsub "/? *\$" $project "" project
4467 Msg Debug "Option list:"
4468 foreach {key value} [
array get options] {
4469 Msg Debug "$key => $value"
4476 if {$proj_conf != 0} {
4479 lassign [
GetIDECommand $proj_conf] cmd before_tcl_script after_tcl_script end_marker
4480 Msg Info "Project $project uses $cmd IDE"
4483 set command "$cmd $before_tcl_script$script$after_tcl_script$argv$end_marker"
4486 if {$project != ""} {
4499 set project_group [
file dirname $project]
4500 set project [
file tail $project]
4501 if { $project_group != "." } {
4502 set project_name "$project_group/$project"
4504 set project_name "$project"
4509 return [list $directive $project $project_name $project_group $repo_path $old_path $bin_path $top_path $command $cmd]
4515 proc ListProjects {{repo_path .} {print 1} {ret_conf 0}} {
4516 set top_path [
file normalize $repo_path/Top]
4517 set confs [
findFiles [
file normalize $top_path] hog.conf]
4521 set p [
Relative $top_path [
file dirname $c]]
4529 if {$ret_conf == 0} {
4542 proc ProjectExists {project {repo_path .}} {
4543 set index [lsearch -exact [
ListProjects $repo_path 0] $project]
4554 proc GetIDECommand {proj_conf} {
4556 if {[
file exists $proj_conf]} {
4557 set ide_name_and_ver [
string tolower [
GetIDEFromConf $proj_conf]]
4558 set ide_name [
lindex [regexp -all -inline {\S+} $ide_name_and_ver] 0]
4560 if {$ide_name eq "vivado"} {
4561 set command "vivado"
4563 set before_tcl_script " -nojournal -nolog -mode batch -notrace -source "
4564 set after_tcl_script " -tclargs "
4567 }
elseif {$ide_name eq "planahead"} {
4568 set command "planAhead"
4570 set before_tcl_script " -nojournal -nolog -mode batch -notrace -source "
4571 set after_tcl_script " -tclargs "
4574 }
elseif {$ide_name eq "quartus"} {
4575 set command "quartus_sh"
4577 set before_tcl_script " -t "
4578 set after_tcl_script " "
4581 }
elseif {$ide_name eq "libero"} {
4584 set command "libero"
4585 set before_tcl_script "SCRIPT:"
4586 set after_tcl_script " SCRIPT_ARGS:\""
4589 Msg Error "IDE: $ide_name not known."
4593 Msg Error "Configuration file $proj_conf not found."
4596 return [list $command $before_tcl_script $after_tcl_script $end_marker]
4604 proc findFiles { basedir pattern } {
4608 set basedir [
string trimright [
file join [
file normalize $basedir] { }]]
4614 foreach fileName [glob -nocomplain -type {f r} -path $basedir $pattern] {
4615 lappend fileList $fileName
4619 foreach dirName [glob -nocomplain -type {d r} -path $basedir *] {
4622 set subDirList [
findFiles $dirName $pattern]
4623 if { [
llength $subDirList] > 0 } {
4624 foreach subDirFile $subDirList {
4625 lappend fileList $subDirFile
4633 proc IsInList {element list} {
4634 if {[lsearch -exact $list $element] >= 0} {
4642 proc IsCommitAncestor {ancestor commit} {
4643 lassign [
GitRet "merge-base --is-ancestor $ancestor $commit"] status result
4644 if {$status == 0 } {
4651 proc FindCommonGitChild {SHA1 SHA2} {
4653 set commits [
Git {log --oneline --merges}]
4656 foreach line [
split $commits "\n"] {
4657 set commit [
lindex [
split $line] 0]
4661 set ancestor $commit
4670 proc moveElementToEnd {inputList element} {
4671 set index [lsearch $inputList $element]
4673 set inputList [
lreplace $inputList $index $index]
4674 lappend inputList $element
4680 source [
file dirname [
info script]]/create_project.tcl