26 set CI_STAGES {"generate_project" "simulate_project"}
27 set CI_PROPS {"-synth_only"}
29 proc ALLOWED_PROPS {} {
30 return [dict create ".vhd" [list "93" "nosynth" "noimpl" "nosim" "1987" "1993" "2008"]\
31 ".vhdl" [list "93" "nosynth" "noimpl" "nosim" "1987" "1993" "2008"]\
32 ".v" [list "SystemVerilog" "verilog_header" "nosynth" "noimpl" "nosim" "1995" "2001"]\
33 ".sv" [list "verilog" "verilog_header" "nosynth" "noimpl" "nosim" "2005" "2009"]\
35 ".udo" [list "nosim"]\
36 ".xci" [list "nosynth" "noimpl" "nosim" "locked"]\
37 ".xdc" [list "nosynth" "noimpl"]\
38 ".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"]\
39 ".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"]\
40 ".sdc" [list "notiming" "nosynth" "noplace"]\
41 ".pdc" [list "nosynth" "noplace"]]
47 proc GetSimulators {} {
48 set SIMULATORS [list "modelsim" "questa" "riviera" "activehdl" "ies" "vcs"]
54 return [
expr {[info commands get_libero_version] != ""}]
59 return [
expr {[info commands program_version] != ""}]
65 return [
expr {[info commands get_property] != ""}]
71 return [
expr {[string first Vivado [version]] == 0}]
80 return [
expr {[string first PlanAhead [version]] == 0}]
88 return [
expr {[info commands project_new] != ""}]
93 return [
expr {![IsQuartus] && ![IsXilinx] && ![IsLibero] && ![IsSynplify]}]
101 proc IsVersal {part} {
102 if { [regexp {^(xcvp|xcvm|xcve|xcvc|xqvc|xqvm).*} $part] } {
115 if { [regexp {^(xc7z|xczu).*} $part] } {
132 proc BinaryStepName {part} {
134 return "WRITE_DEVICE_IMAGE"
136 return "WRITE_BITSTREAM"
141 proc Msg {level msg {title ""}} {
143 set level [
string tolower $level]
145 if {$title == ""} {
set title [
lindex [
info level [
expr {[info level]-1}]] 0]}
147 if {$level == 0 || $level == "status" || $level == "extra_info"} {
150 }
elseif {$level == 1 || $level == "info"} {
153 }
elseif {$level == 2 || $level == "warning"} {
156 }
elseif {$level == 3 || [
string first "critical" $level] !=-1} {
157 set vlevel {CRITICAL WARNING}
158 set qlevel critical_warning
159 }
elseif {$level == 4 || $level == "error"} {
162 }
elseif {$level == 5 || $level == "debug"} {
163 if {([
info exists ::DEBUG_MODE] && $::DEBUG_MODE == 1) || ([
info exists ::env(HOG_DEBUG_MODE)] && $::env(HOG_DEBUG_MODE) == 1)} {
165 set qlevel extra_info
166 set msg "DEBUG: \[Hog:$title\] $msg"
172 puts "Hog Error: level $level not defined"
179 set status [
catch {send_msg_id Hog:$title-0 $vlevel $msg}]
185 post_message -type $qlevel "Hog:$title $msg"
186 if { $qlevel == "error"} {
191 if {$vlevel != "STATUS"} {
192 puts "$vlevel: \[Hog:$title\] $msg"
197 if {$qlevel == "error"} {
208 proc WriteToFile {File msg} {
209 set f [open $File a+]
222 proc SetProperty {property value object} {
225 set_property $property $value $object
232 puts "***DEBUG Hog:SetProperty $property to $value of $object"
247 proc GetProperty {property object} {
250 return [get_property -quiet $property $object]
257 puts "***DEBUG Hog:GetProperty $property of $object"
258 return "DEBUG_property_value"
269 proc SetParameter {parameter value } {
270 set_param $parameter $value
280 proc AddTopFile {top_module top_file sources} {
283 add_files -norecurse -fileset $sources $top_file
288 set_global_assignment -name $file_type $top_file
290 puts "Adding project top module $top_module"
301 proc SetTopProperty {top_module sources} {
302 Msg Info "Setting TOP property to $top_module module"
305 set_property "top" $top_module $sources
308 set_global_assignment -name TOP_LEVEL_ENTITY $top_module
310 set_root -module $top_module
323 proc GetProject {proj} {
326 return [get_projects $proj]
333 puts "***DEBUG Hog:GetProject $proj"
334 return "DEBUG_project"
350 return [get_runs -quiet $run]
357 puts "***DEBUG Hog:GetRun $run"
371 proc GetFile {file} {
374 set Files [get_files -all $file]
375 set f [
lindex $Files 0]
384 puts "***DEBUG Hog:GetFile $file"
397 proc CreateFileSet {fileset} {
398 set a [create_fileset -srcset $fileset]
411 proc GetFileSet {fileset} {
412 set a [get_filesets $fileset]
421 proc AddFile {file fileset} {
422 add_files -norecurse -fileset $fileset $file
429 proc GetRepoPath {} {
430 return "[
file normalize [
file dirname [
info script]]]/../../"
443 proc CompareVersions {ver1 ver2} {
452 if {[regexp {v(\d+)\.(\d+)\.(\d+)} $ver1 - x y z]} {
453 set ver1 [list $x $y $z]
455 if {[regexp {v(\d+)\.(\d+)\.(\d+)} $ver2 - x y z]} {
456 set ver2 [list $x $y $z]
460 set v1 [
join $ver1 ""]
462 set v2 [
join $ver2 ""]
465 if {[
string is integer $v1] && [
string is integer $v2]} {
467 set ver1 [
expr {[scan [lindex $ver1 0] %d]*100000 + [scan [lindex $ver1 1] %d]*1000 + [scan [lindex $ver1 2] %d]}]
468 set ver2 [
expr {[scan [lindex $ver2 0] %d]*100000 + [scan [lindex $ver2 1] %d]*1000 + [scan [lindex $ver2 2] %d]}]
470 if {$ver1 > $ver2 } {
472 }
elseif {$ver1 == $ver2} {
479 Msg Warning "Version is not numeric: $ver1, $ver2"
491 proc GitVersion {target_version} {
492 set ver [
split $target_version "."]
493 set v [
Git --version]
495 set current_ver [
split [
lindex $v 2] "."]
496 set target [
expr {[lindex $ver 0]*100000 + [lindex $ver 1]*100 + [lindex $ver 2]}]
497 set current [
expr {[lindex $current_ver 0]*100000 + [lindex $current_ver 1]*100 + [lindex $current_ver 2]}]
498 return [
expr {$target <= $current}]
507 proc DoxygenVersion {target_version} {
508 set ver [
split $target_version "."]
509 set v [
Execute doxygen --version]
510 Msg Info "Found doxygen version: $v"
511 set current_ver [
split $v ". "]
512 set target [
expr {[lindex $ver 0]*100000 + [lindex $ver 1]*100 + [lindex $ver 2]}]
513 set current [
expr {[lindex $current_ver 0]*100000 + [lindex $current_ver 1]*100 + [lindex $current_ver 2]}]
515 return [
expr {$target <= $current}]
522 proc FindFileType {file_name} {
523 set extension [
file extension $file_name]
526 set file_extension "USE_SIGNALTAP_FILE"
529 set file_extension "VHDL_FILE"
532 set file_extension "VHDL_FILE"
535 set file_extension "VERILOG_FILE"
538 set file_extension "SYSTEMVERILOG_FILE"
541 set file_extension "SDC_FILE"
544 set file_extension "PDC_FILE"
547 set file_extension "NDC_FILE"
550 set file_extension "FDC_FILE"
553 set file_extension "SOURCE_FILE"
556 set file_extension "IP_FILE"
559 set file_extension "QSYS_FILE"
562 set file_extension "QIP_FILE"
565 set file_extension "SIP_FILE"
568 set file_extension "BSF_FILE"
571 set file_extension "BDF_FILE"
574 set file_extension "COMMAND_MACRO_FILE"
577 set file_extension "VQM_FILE"
580 set file_extension "ERROR"
581 Msg Error "Unknown file extension $extension"
584 return $file_extension
592 proc FindVhdlVersion {file_name} {
593 set extension [
file extension $file_name]
596 set vhdl_version "-hdl_version VHDL_2008"
599 set vhdl_version "-hdl_version VHDL_2008"
622 proc ReadListFile args {
626 if { [
catch {
package require cmdline} ERROR] } {
627 puts "$ERROR\n If you are running this script on tclsh, you can fix this by installing 'tcllib'"
633 {lib.arg "" "The name of the library files will be added to, if not given will be extracted from the file name."}
634 {fileset.arg "" "The name of the library, from the main list file"}
635 {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."}
637 set usage "USAGE: ReadListFile \[options\] <list file> <path>"
638 if {[
catch {
array set options [
cmdline::getoptions args $parameters $usage]}] || [
llength $args] != 2 } {
642 set list_file [
lindex $args 0]
643 set path [
lindex $args 1]
644 set sha_mode $options(sha_mode)
645 set lib $options(lib)
646 set fileset $options(fileset)
648 if { $sha_mode == 1} {
649 set sha_mode_opt "-sha_mode"
656 set lib [
file rootname [
file tail $list_file]]
658 set fp [open $list_file r]
659 set file_data [read $fp]
661 set list_file_ext [
file extension $list_file]
662 switch $list_file_ext {
664 if {$fileset eq ""} {
670 set fileset "constrs_1"
673 set fileset "sources_1"
677 set libraries [dict create]
678 set filesets [dict create]
679 set properties [dict create]
681 set data [
split $file_data "\n"]
682 set n [
llength $data]
683 Msg Debug "$n lines read from $list_file."
688 if {![regexp {^ *$} $line] & ![regexp {^ *\#} $line] } {
689 set file_and_prop [regexp -all -inline {\S+} $line]
690 set srcfile [
lindex $file_and_prop 0]
691 set srcfile "$path/$srcfile"
693 set srcfiles [glob -nocomplain $srcfile]
696 if {$srcfiles != $srcfile && ! [
string equal $srcfiles ""]} {
697 Msg Debug "Wildcard source expanded from $srcfile to $srcfiles"
699 if {![
file exists $srcfile]} {
700 Msg CriticalWarning "File: $srcfile (from list file: $list_file) does not exist."
705 foreach vhdlfile $srcfiles {
706 if {[
file exists $vhdlfile]} {
707 set vhdlfile [
file normalize $vhdlfile]
708 set extension [
file extension $vhdlfile]
710 set prop [
lrange $file_and_prop 1 end]
713 set library [
lindex [regexp -inline {lib\s*=\s*(.+?)\y.*} $prop] 1]
714 if { $library == "" } {
718 if { $extension == $list_file_ext } {
720 set ref_path [
lindex [regexp -inline {path\s*=\s*(.+?)\y.*} $prop] 1]
721 if { $ref_path eq "" } {
724 set ref_path [
file normalize $path/$ref_path]
726 Msg Debug "List file $vhdlfile found in list file, recursively opening it using path \"$ref_path\"..."
727 lassign [
ReadListFile {*}"-lib $library -fileset $fileset $sha_mode_opt $vhdlfile $ref_path"] l p fs
729 set properties [
MergeDict $p $properties]
731 }
elseif {[lsearch {.src .sim .con ReadExtraFileList} $extension] >= 0 } {
733 Msg Error "$vhdlfile cannot be included into $list_file, $extension files must be included into $extension files."
736 regsub -all " *= *" $prop "=" prop
740 if { [
string first "lib=" $p] == -1} {
742 set pos [
string first "=" $p]
746 set prop_name [
string range $p 0 [
expr {$pos - 1}]]
749 dict lappend properties $vhdlfile $p
750 Msg Debug "Adding property $p to $vhdlfile..."
751 }
elseif { $list_file_ext != ".ipb" } {
752 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]\]"
756 if { [lsearch {.xci .ip .bd .xcix} $extension] >= 0} {
758 set lib_name "ips.src"
759 }
elseif { [
IsInList $extension {.vhd .vhdl}] || $list_file_ext == ".sim"} {
761 if { ![
IsInList $extension {.vhd .vhdl}]} {
762 set lib_name "others.sim"
764 set lib_name "$library$list_file_ext"
766 }
elseif { $list_file_ext == ".con" } {
767 set lib_name "sources.con"
768 }
elseif { $list_file_ext == ".ipb" } {
769 set lib_name "xml.ipb"
772 set lib_name "others.src"
775 Msg Debug "Appending $vhdlfile to $lib_name list..."
776 dict lappend libraries $lib_name $vhdlfile
777 if { $sha_mode != 0 && [
file type $vhdlfile] eq "link"} {
780 dict lappend libraries $lib_name $real_file
781 Msg Debug "File $vhdlfile is a soft link, also adding the real file: $real_file"
786 if {[dict exists $filesets $fileset] == 0} {
788 Msg Debug "Adding $fileset to the fileset dictionary..."
789 Msg Debug "Adding library $lib_name to fileset $fileset..."
790 dict set filesets $fileset $lib_name
794 Msg Debug "Adding library $lib_name to fileset $fileset..."
795 dict lappend filesets $fileset $lib_name
801 Msg CriticalWarning "File $vhdlfile not found."
807 if {$sha_mode != 0} {
809 if {$list_file_ext eq ".ipb"} {
810 set sha_lib "xml.ipb"
812 set sha_lib $lib$list_file_ext
814 dict lappend libraries $sha_lib [
file normalize $list_file]
815 if {[
file type $list_file] eq "link"} {
818 dict lappend libraries $lib$list_file_ext $real_file
819 Msg Debug "List file $list_file is a soft link, also adding the real file: $real_file"
822 return [list $libraries $properties $filesets]
828 return $tcl_platform(platform)
837 proc GetLinkedFile {link_file} {
838 if {[
file type $link_file] eq "link"} {
839 if {[
OS] == "windows" } {
841 lassign [
ExecuteRet realpath $link_file] ret msg
842 lassign [
ExecuteRet cygpath -m $msg] ret2 msg2
843 if {$ret == 0 && $ret2 == 0} {
845 Msg Debug "Found link file $link_file on Windows, the linked file is: $real_file"
847 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."
848 set real_file $link_file
852 set linked_file [
file link $link_file]
853 set real_file [
file normalize [
file dirname $link_file]/$linked_file]
856 if {![
file exists $real_file]} {
857 Msg Warning "$link_file is a broken link, because the linked file: $real_file does not exist."
860 Msg Warning "$link file is not a soft link"
861 set real_file $link_file
876 proc MergeDict {dict0 dict1} {
877 set outdict [dict merge $dict1 $dict0]
878 foreach key [dict keys $dict1] {
879 if {[dict exists $dict0 $key]} {
880 set temp_list [dict get $dict1 $key]
881 foreach vhdfile $temp_list {
884 dict lappend outdict $key $vhdfile
900 proc DictGet {dictName keyName {default ""}} {
901 if {[dict exists $dictName $keyName]} {
902 return [dict get $dictName $keyName]
916 proc GetHashLib {lib} {
920 set ff [get_files -filter LIBRARY==$lib]
935 proc GetModifiedFiles {{repo_path "."} {pattern "."}} {
938 set ret [
Git "ls-files --modified $pattern"]
948 proc RestoreModifiedFiles {{repo_path "."} {pattern "."}} {
951 set ret [
Git checkout $pattern]
965 proc GetFileList {FILE path} {
966 set fp [open $FILE r]
967 set file_data [read $fp]
971 set data [
split $file_data "\n"]
973 if {![regexp {^ *$} $line] & ![regexp {^ *\#} $line] } {
975 set file_and_prop [regexp -all -inline {\S+} $line]
976 set vhdlfile [
lindex $file_and_prop 0]
977 set vhdlfile "$path/$vhdlfile"
978 if {[
file exists $vhdlfile]} {
979 set extension [
file extension $vhdlfile]
980 if { [
IsInList $extension {.src .sim .con}] } {
983 lappend file_list $vhdlfile
986 Msg Warning "File $vhdlfile not found"
1000 proc GetSHA {{path ""}} {
1002 lassign [
GitRet {log --format=%h --abbrev=7 -1}] status result
1004 return [
string tolower $result]
1006 Msg Error "Something went wrong while finding the latest SHA. Does the repository have a commit?"
1012 set repo_path [
lindex [
Git {rev-parse --show-toplevel}] 0]
1016 set file_in_module 0
1017 if {[
file exists $repo_path/.gitmodules]} {
1018 lassign [
GitRet "config --file $repo_path/.gitmodules --get-regexp path"] status result
1020 set submodules [
split $result "\n"]
1023 Msg Warning "Something went wrong while trying to find submodules: $result"
1026 foreach mod $submodules {
1027 set module [
lindex $mod 1]
1028 if {[
string first "$repo_path/$module" $f] == 0} {
1030 set file_in_module 1
1031 lappend paths "$repo_path/$module"
1037 if {$file_in_module == 0} {
1043 lassign [
GitRet {log --format=%h --abbrev=7 -1} $paths] status result
1045 return [
string tolower $result]
1047 Msg Error "Something went wrong while finding the latest SHA. Does the repository have a commit?"
1050 return [
string tolower $result]
1059 proc GetVer {path {force_develop 0}} {
1063 Msg CriticalWarning "Empty SHA found for ${path}. Commit to Git to resolve this warning."
1066 set p [
lindex $path 0]
1067 if {[
file isdirectory $p]} {
1070 cd [
file dirname $p]
1072 set repo_path [
Git {rev-parse --show-toplevel}]
1075 return [list [
GetVerFromSHA $SHA $repo_path $force_develop] $SHA]
1086 proc GetVerFromSHA {SHA repo_path {force_develop 0}} {
1088 Msg CriticalWarning "Empty SHA found"
1091 lassign [
GitRet "tag --sort=creatordate --contain $SHA -l v*.*.* -l b*v*.*.*"] status result
1094 if {[regexp {^ *$} $result]} {
1096 lassign [
GitRet "log --oneline --pretty=\"%d\""] status2 tag_list
1099 set pattern {tag: v\d+\.\d+\.\d+}
1100 set real_tag_list {}
1101 foreach x $tag_list {
1102 set x_untrimmed [regexp -all -inline $pattern $x]
1103 regsub "tag: " $x_untrimmed "" x_trimmed
1104 set tt [
lindex $x_trimmed 0]
1105 if {![
string equal $tt ""]} {
1106 lappend real_tag_list $tt
1112 set sorted_tags [lsort -decreasing -command CompareVersions $real_tag_list]
1116 set tag [
lindex $sorted_tags 0]
1119 set pattern {v\d+\.\d+\.\d+}
1120 if {![regexp $pattern $tag]} {
1121 Msg CriticalWarning "No Hog version tags found in this repository."
1127 set repo_conf $repo_path/Top/repo.conf
1131 set hotfix_prefix "hotfix/"
1132 set minor_prefix "minor_version/"
1133 set major_prefix "major_version/"
1135 set enable_develop_branch $force_develop
1137 set branch_name [
Git {rev-parse --abbrev-ref HEAD}]
1139 if {[
file exists $repo_conf]} {
1140 set PROPERTIES [
ReadConf $repo_conf]
1142 if {[dict exists $PROPERTIES main]} {
1143 set mainDict [dict get $PROPERTIES main]
1146 if {[dict exists $mainDict ENABLE_DEVELOP_BRANCH]} {
1147 set enable_develop_branch [dict get $mainDict ENABLE_DEVELOP_BRANCH]
1154 if {[dict exists $PROPERTIES prefixes]} {
1155 set prefixDict [dict get $PROPERTIES prefixes]
1157 if {[dict exists $prefixDict HOTFIX]} {
1158 set hotfix_prefix [dict get $prefixDict HOTFIX]
1160 if {[dict exists $prefixDict MINOR_VERSION]} {
1161 set minor_prefix [dict get $prefixDict MINOR_VERSION]
1163 if {[dict exists $prefixDict MAJOR_VERSION]} {
1164 set major_prefix [dict get $prefixDict MAJOR_VERSION]
1170 if {$enable_develop_branch == 1 } {
1171 if {[
string match "$hotfix_prefix*" $branch_name]} {
1176 if {[
string match "$major_prefix*" $branch_name]} {
1178 set version_level major
1179 }
elseif {[
string match "$minor_prefix*" $branch_name] || ($enable_develop_branch == 1 && $is_hotfix == 0)} {
1181 set version_level minor
1184 set version_level patch
1192 Msg CriticalWarning "Tag $tag does not contain a Hog compatible version in this repository."
1195 }
elseif {$mr == 0} {
1197 switch $version_level {
1213 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."
1219 set vers [
split $result "\n"]
1220 set ver [
lindex $vers 0]
1222 if {[regexp {^v.*$} $v]} {
1230 Msg CriticalWarning "Error while trying to find tag for $SHA"
1238 set M [
format %02X $M]
1239 set m [
format %02X $m]
1240 set c [
format %04X $c]
1242 }
elseif { $M > -1 } {
1244 set M [
format %02X $M]
1245 set m [
format %02X $m]
1246 set c [
format %04X $c]
1249 Msg Warning "Tag does not contain a properly formatted version: $ver"
1250 set M [
format %02X 0]
1251 set m [
format %02X 0]
1252 set c [
format %04X 0]
1267 proc GetProjectVersion {proj_dir repo_path {ext_path ""} {sim 0}} {
1268 if { ![
file exists $proj_dir] } {
1269 Msg CriticalWarning "$proj_dir not found"
1279 Msg Warning "Repository is not clean"
1288 Msg Info "The specified project was modified since official version."
1295 Msg Info "The specified project was modified in the latest official version $ret"
1296 }
elseif {$comp == -1} {
1297 Msg Info "The specified project was modified in a past official version $ret"
1312 proc GetHogDescribe {sha {repo_path .}} {
1315 set new_sha "[
string toupper [
GetSHA]]"
1318 set new_sha [
string toupper $sha]
1332 proc GetSubmodule {path_file} {
1334 set directory [
file normalize [
file dirname $path_file]]
1336 lassign [
GitRet {rev-parse --show-superproject-working-tree}] ret base
1338 Msg CriticalWarning "Git repository error: $base"
1345 lassign [
GitRet {rev-parse --show-toplevel}] ret sub
1347 Msg CriticalWarning "Git submodule error: $sub"
1351 set submodule [
Relative $base $sub]
1365 proc GetConfFiles {proj_dir} {
1366 if {![
file isdirectory $proj_dir]} {
1367 Msg Error "$proj_dir is supposed to be the top project directory"
1370 set conf_file [
file normalize $proj_dir/hog.conf]
1371 set sim_file [
file normalize $proj_dir/sim.conf]
1372 set pre_tcl [
file normalize $proj_dir/pre-creation.tcl]
1373 set post_tcl [
file normalize $proj_dir/post-creation.tcl]
1375 return [list $conf_file $sim_file $pre_tcl $post_tcl]
1387 proc GetRepoVersions {proj_dir repo_path {ext_path ""} {sim 0}} {
1388 if { [
catch {
package require cmdline} ERROR] } {
1389 puts "$ERROR\n If you are running this script on tclsh, you can fix this by installing 'tcllib'"
1404 lappend SHAs [
GetSHA {Hog}]
1408 if {[
Git {status --untracked-files=no --porcelain}] eq ""} {
1409 Msg Info "Hog submodule [
pwd] clean."
1410 lassign [
GetVer ./] hog_ver hog_hash
1412 Msg CriticalWarning "Hog submodule [
pwd] not clean, commit hash will be set to 0."
1413 set hog_hash "0000000"
1414 set hog_ver "00000000"
1419 if {[
Git {status --untracked-files=no --porcelain}] eq ""} {
1420 Msg Info "Git working directory [
pwd] clean."
1423 Msg CriticalWarning "Git working directory [
pwd] not clean, commit hash, and version will be set to 0."
1428 lassign [
GetVer [
join $conf_files]] top_ver top_hash
1429 lappend SHAs $top_hash
1430 lappend versions $top_ver
1437 lassign [
GetHogFiles -list_files "*.src" -sha_mode "./list/" $repo_path] src_files dummy
1438 dict for {f files} $src_files {
1439 # library names have a .src extension in values returned by GetHogFiles
1440 set name [file rootname [file tail $f]]
1441 if {[file ext $f] == ".oth"} {
1444 lassign [GetVer $files] ver hash
1445 # Msg Info "Found source list file $f, version: $ver commit SHA: $hash"
1447 lappend versions $ver
1449 lappend hashes $hash
1456 lassign [
GetHogFiles -list_files "*.con" -sha_mode "./list/" $repo_path] cons_files dummy
1457 dict for {f files} $cons_files {
1458 #library names have a .con extension in values returned by GetHogFiles
1459 set name [file rootname [file tail $f]]
1460 lassign [GetVer $files] ver hash
1461 #Msg Info "Found constraint list file $f, version: $ver commit SHA: $hash"
1463 Msg CriticalWarning "Constraints file $f not found in Git."
1465 lappend cons_hashes $hash
1467 lappend versions $ver
1474 lassign [
GetHogFiles -list_files "*.sim" -sha_mode "./list/" $repo_path] sim_files dummy
1475 dict for {f files} $sim_files {
1476 #library names have a .sim extension in values returned by GetHogFiles
1477 set name [file rootname [file tail $f]]
1478 lassign [GetVer $files] ver hash
1479 #Msg Info "Found simulation list file $f, version: $ver commit SHA: $hash"
1480 lappend sim_hashes $hash
1482 lappend versions $ver
1488 if {"{}" eq $cons_hashes} {
1490 Msg CriticalWarning "No hashes found for constraints files (not in git)"
1493 set cons_hash [
string tolower [
Git "log --format=%h -1 $cons_hashes"]]
1500 set ext_files [glob -nocomplain "./list/*.ext"]
1503 foreach f $ext_files {
1504 set name [
file rootname [
file tail $f]]
1507 lappend ext_names $name
1508 lappend ext_hashes $hash
1511 lappend versions $ext_ver
1514 set file_data [read $fp]
1516 set data [
split $file_data "\n"]
1518 foreach line $data {
1519 if {![regexp {^ *$} $line] & ![regexp {^ *\#} $line] } {
1521 set file_and_prop [regexp -all -inline {\S+} $line]
1522 set hdlfile [
lindex $file_and_prop 0]
1523 set hdlfile $ext_path/$hdlfile
1524 if { [
file exists $hdlfile] } {
1525 set hash [
lindex $file_and_prop 1]
1526 set current_hash [
Md5Sum $hdlfile]
1527 if {[
string first $hash $current_hash] == -1} {
1528 Msg CriticalWarning "File $hdlfile has a wrong hash. Current checksum: $current_hash, expected: $hash"
1536 if {[
llength [glob -nocomplain ./list/*.ipb]] > 0 } {
1538 lassign [
GetHogFiles -list_files "*.ipb" -sha_mode "./list/" $repo_path] xml_files dummy
1539 lassign [
GetVer [dict get $xml_files "xml.ipb"]] xml_ver xml_hash
1540 lappend SHAs $xml_hash
1541 lappend versions $xml_ver
1546 Msg Info "This project does not use IPbus XMLs"
1551 set user_ip_repos ""
1552 set user_ip_repo_hashes ""
1553 set user_ip_repo_vers ""
1555 if {[
file exists [
lindex $conf_files 0]]} {
1556 set PROPERTIES [
ReadConf [
lindex $conf_files 0]]
1557 if {[dict exists $PROPERTIES main]} {
1558 set main [dict get $PROPERTIES main]
1559 dict for {p v} $main {
1560 if { [ string tolower $p ] == "ip_repo_paths" } {
1562 lappend user_ip_repos "$repo_path/$repo"
1569 foreach repo $user_ip_repos {
1570 if {[
file isdirectory $repo]} {
1571 set repo_file_list [glob -nocomplain "$repo/*"]
1572 if {[
llength $repo_file_list] != 0} {
1573 lassign [
GetVer $repo] ver sha
1574 lappend user_ip_repo_hashes $sha
1575 lappend user_ip_repo_vers $ver
1576 lappend versions $ver
1578 Msg Warning "IP_REPO_PATHS property set to $repo in hog.conf but directory is empty."
1581 Msg Warning "IP_REPO_PATHS property set to $repo in hog.conf but directory does not exist."
1590 while {$found == 0} {
1591 set global_commit [
Git "log --format=%h -1 --abbrev=7 $SHAs"]
1596 if {$common_child == 0} {
1597 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."
1599 Msg Info "The commit $sha is not an ancestor of the global commit $global_commit, adding the first common child $common_child instead..."
1600 lappend SHAs $common_child
1610 set global_commit "0000000"
1611 set global_version "00000000"
1616 set top_hash [
format %+07s $top_hash]
1617 set cons_hash [
format %+07s $cons_hash]
1618 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]
1629 proc HexVersionToString {version} {
1630 scan [
string range $version 0 1] %x M
1631 scan [
string range $version 2 3] %x m
1632 scan [
string range $version 4 7] %x c
1642 proc ExtractVersionFromTag {tag} {
1643 if {[regexp {^(?:b(\d+))?v(\d+)\.(\d+).(\d+)(?:-\d+)?$} $tag -> mr M m p]} {
1648 Msg Warning "Repository tag $tag is not in a Hog-compatible format."
1654 return [list $M $m $p $mr]
1668 proc CopyIPbusXMLs {proj_dir path dst {xml_version "0.0.0"} {xml_sha "00000000"} {generate 0} } {
1670 lassign [
ExecuteRet python -c "from __future__ import print_function; from sys import path;print(':'.join(path\[1:\]))"] ret msg
1672 set ::env(PYTHONPATH) $msg
1673 lassign [
ExecuteRet gen_ipbus_addr_decode -h] ret msg
1680 Msg Warning "Error while trying to run python: $msg"
1683 set dst [
file normalize $dst]
1684 if {$can_generate == 0} {
1685 if {$generate == 1} {
1686 Msg Error "Cannot generate IPbus address files, IPbus executable gen_ipbus_addr_decode not found or not working: $msg"
1690 Msg Warning "IPbus executable gen_ipbus_addr_decode not found or not working, will not verify IPbus address tables."
1694 set ipb_files [glob -nocomplain $proj_dir/list/*.ipb]
1695 set n_ipb_files [
llength $ipb_files]
1696 if {$n_ipb_files == 0} {
1697 Msg CriticalWarning "No files with .ipb extension found in $proj_dir/list."
1700 set libraries [dict create]
1701 set vhdl_dict [dict create]
1703 foreach ipb_file $ipb_files {
1709 set xmlfiles [dict get $libraries "xml.ipb"]
1712 set xml_list_error 0
1713 foreach xmlfile $xmlfiles {
1715 if {[
file isdirectory $xmlfile]} {
1716 Msg CriticalWarning "Directory $xmlfile listed in xml list file $list_file. Directories are not supported!"
1717 set xml_list_error 1
1720 if {[
file exists $xmlfile]} {
1721 lappend vhdls [
file normalize [dict get $vhdl_dict $xmlfile]]
1722 set xmlfile [
file normalize $xmlfile]
1723 Msg Info "Copying $xmlfile to $dst and replacing place holders..."
1724 set in [open $xmlfile r]
1725 set out [open $dst/[
file tail $xmlfile] w]
1727 while {[
gets $in line] != -1} {
1728 set new_line [regsub {(.*)__VERSION__(.*)} $line "\\1$xml_version\\2"]
1729 set new_line2 [regsub {(.*)__GIT_SHA__(.*)} $new_line "\\1$xml_sha\\2"]
1730 puts $out $new_line2
1734 lappend xmls [
file tail $xmlfile]
1736 Msg Warning "XML file $xmlfile not found"
1739 if {${xml_list_error}} {
1740 Msg Error "Invalid files added to $list_file!"
1743 set cnt [
llength $xmls]
1744 Msg Info "$cnt xml file/s copied"
1747 if {$can_generate == 1} {
1750 file mkdir "address_decode"
1753 foreach x $xmls v $vhdls{
1755 set x [
file normalize ../$x]
1756 if {[
file exists $x]} {
1757 lassign [
ExecuteRet gen_ipbus_addr_decode $x 2>&1] status log
1759 set generated_vhdl ./ipbus_decode_[
file rootname [
file tail $x]].vhd
1760 if {$generate == 1} {
1761 Msg Info "Copying generated VHDL file $generated_vhdl into $v (replacing if necessary)"
1762 file copy -force -- $generated_vhdl $v
1764 if {[
file exists $v]} {
1766 if {[
llength $diff] > 0} {
1767 Msg CriticalWarning "$v does not correspond to its XML $x, [
expr {$n/3}] line/s differ:"
1768 Msg Status [
join $diff "\n"]
1769 set diff_file [open ../diff_[
file rootname [
file tail $x]].txt w]
1770 puts $diff_file $diff
1773 Msg Info "[
file tail $x] and $v match."
1776 Msg Warning "VHDL address map file $v not found."
1780 Msg Warning "Address map generation failed for [
file tail $x]: $log"
1783 Msg Warning "Copied XML file $x not found."
1786 Msg Info "Skipped verification of [
file tail $x] as no VHDL file was specified."
1790 file delete -force address_decode
1802 proc CompareVHDL {file1 file2} {
1803 set a [open $file1 r]
1804 set b [open $file2 r]
1806 while {[
gets $a line] != -1} {
1807 set line [regsub {^[\t\s]*(.*)?\s*} $line "\\1"]
1808 if {![regexp {^$} $line] & ![regexp {^--} $line] } {
1814 while {[
gets $b line] != -1} {
1815 set line [regsub {^[\t\s]*(.*)?\s*} $line "\\1"]
1816 if {![regexp {^$} $line] & ![regexp {^--} $line] } {
1825 foreach x $f1 y $f2 {
1827 lappend diff "> $x\n< $y\n\n"
1839 proc Relative {base dst} {
1840 if {![
string equal [
file pathtype $base] [
file pathtype $dst]]} {
1841 Msg CriticalWarning "Unable to compute relation for paths of different pathtypes: [
file pathtype $base] vs. [
file pathtype $dst], ($base vs. $dst)"
1845 set base [
file normalize [
file join [
pwd] $base]]
1846 set dst [
file normalize [
file join [
pwd] $dst]]
1849 set base [
file split $base]
1850 set dst [
file split $dst]
1852 while {[
string equal [
lindex $dst 0] [
lindex $base 0]]} {
1853 set dst [
lrange $dst 1 end]
1854 set base [
lrange $base 1 end]
1855 if {![
llength $dst]} {break}
1858 set dstlen [
llength $dst]
1859 set baselen [
llength $base]
1861 if {($dstlen == 0) && ($baselen == 0)} {
1864 while {$baselen > 0} {
1865 set dst [
linsert $dst 0 ..]
1868 set dst [
eval [
linsert $dst 0 file join]]
1879 proc RelativeLocal {pathName filePath} {
1880 if {[
string first [
file normalize $pathName] [
file normalize $filePath]] != -1} {
1881 return [
Relative $pathName $filePath]
1893 proc MsgAndLog {msg {severity "CriticalWarning"} {outFile ""}} {
1895 if {$outFile != ""} {
1896 set oF [open "$outFile" a+]
1909 proc GetProjectFiles {} {
1911 set all_filesets [get_filesets]
1912 set libraries [dict create]
1913 set simlibraries [dict create]
1914 set constraints [dict create]
1915 set properties [dict create]
1916 set consets [dict create]
1917 set srcsets [dict create]
1918 set simsets [dict create]
1919 set simulator [get_property target_simulator [current_project]]
1920 set top [get_property "top" [current_fileset]]
1922 dict lappend properties $topfile "top=$top"
1924 foreach fs $all_filesets {
1925 if {$fs == "utils_1"} {
1930 set all_files [get_files -quiet -of_objects [get_filesets $fs]]
1931 set fs_type [get_property FILESET_TYPE [get_filesets $fs]]
1933 if {$fs_type == "BlockSrcs"} {
1937 foreach f $all_files {
1944 if { [
lindex [get_property IS_GENERATED [
GetFile $f]] 0] != 0} {
1949 if {[get_property CORE_CONTAINER [
GetFile $f]] != ""} {
1950 if { [
file extension $f] == ".xcix"} {
1951 set f [get_property CORE_CONTAINER [
GetFile $f]]
1958 if {[
IsInList "PARENT_COMPOSITE_FILE" [list_property [
GetFile $f]]]} {
1963 if {[
file tail $f] == "nocattrs.dat"} {
1968 if {[
file extension $f] != ".coe"} {
1969 set f [
file normalize $f]
1972 set type [get_property FILE_TYPE [
GetFile $f]]
1974 set lib [get_property -quiet LIBRARY [
GetFile $f]]
1977 Msg Debug "File $f Extension [
file extension $f] Type [
lindex $type 0]"
1979 if {[
string equal [
lindex $type 0] "VHDL"] && [
llength $type] == 1} {
1981 }
elseif {[
string equal [
lindex $type 0] "Block"] && [
string equal [
lindex $type 1] "Designs"]} {
1984 }
elseif {[
string equal $type "SystemVerilog"] && [
file extension $f] != ".sv"} {
1985 set prop "SystemVerilog"
1986 }
elseif {[
string equal [
lindex $type 0] "XDC"] && [
file extension $f] != ".xdc"} {
1988 }
elseif {[
string equal $type "Verilog Header"] && [
file extension $f] != ".vh" && [
file extension $f] != ".svh"} {
1989 set prop "verilog_header"
1990 }
elseif {[
string equal $type "Verilog Template"] && [
file extension $f] == ".v" && [
file extension $f] != ".sv"} {
1991 set prop "verilog_template"
1993 set type [
lindex $type 0]
1998 if {![
string equal $prop ""]} {
1999 dict lappend properties $f $prop
2002 if {[
string equal $fs_type "SimulationSrcs"]} {
2004 if {[
string equal $type "VHDL"] } {
2005 set library "${lib}.sim"
2007 set library "others.sim"
2011 dict lappend simsets $fs $library
2014 dict lappend simlibraries $library $f
2016 }
elseif {[
string equal $type "VHDL"] } {
2019 dict lappend srcsets $fs "${lib}.src"
2021 dict lappend libraries "${lib}.src" $f
2022 }
elseif {[
string first "IP" $type] != -1} {
2025 dict lappend srcsets $fs "ips.src"
2027 dict lappend libraries "ips.src" $f
2028 Msg Debug "Appending $f to ips.src"
2029 }
elseif {[
string equal $fs_type "Constrs"]} {
2032 dict lappend consets $fs "sources.con"
2034 dict lappend constraints "sources.con" $f
2038 dict lappend srcsets $fs "others.src"
2040 dict lappend libraries "others.src" $f
2041 Msg Debug "Appending $f to others.src"
2044 if {[
lindex [get_property -quiet used_in_synthesis [
GetFile $f]] 0] == 0} {
2045 dict lappend properties $f "nosynth"
2047 if {[
lindex [get_property -quiet used_in_implementation [
GetFile $f]] 0] == 0} {
2048 dict lappend properties $f "noimpl"
2050 if {[
lindex [get_property -quiet used_in_simulation [
GetFile $f]] 0] == 0} {
2051 dict lappend properties $f "nosim"
2053 if {[
lindex [get_property -quiet IS_MANAGED [
GetFile $f]] 0] == 0 && [
file extension $f] != ".xcix" } {
2054 dict lappend properties $f "locked"
2060 dict lappend properties "Simulator" [get_property target_simulator [current_project]]
2062 return [list $libraries $properties $simlibraries $constraints $srcsets $simsets $consets]
2081 proc GetHogFiles args {
2085 if { [
catch {
package require cmdline} ERROR] } {
2086 puts "$ERROR\n If you are running this script on tclsh, you can fix this by installing 'tcllib'"
2093 {list_files.arg "" "The file wildcard, if not specified all Hog list files will be looked for."}
2094 {sha_mode "Forwarded to ReadListFile, see there for info."}
2095 {ext_path.arg "" "Path for the external libraries forwarded to ReadListFile."}
2097 set usage "USAGE: GetHogFiles \[options\] <list path> <repository path>"
2098 if {[
catch {
array set options [
cmdline::getoptions args $parameters $usage]}] || [
llength $args] != 2 } {
2102 set list_path [
lindex $args 0]
2103 set repo_path [
lindex $args 1]
2105 set list_files $options(list_files)
2106 set sha_mode $options(sha_mode)
2107 set ext_path $options(ext_path)
2110 if { $sha_mode == 1 } {
2111 set sha_mode_opt "-sha_mode"
2116 if { $list_files == "" } {
2117 set list_files {.src,.con,.sim,.ext}
2119 set libraries [dict create]
2120 set properties [dict create]
2121 set list_files [glob -nocomplain -directory $list_path "*{$list_files}"]
2122 set filesets [dict create]
2124 foreach f $list_files {
2125 set ext [
file extension $f]
2126 if {$ext == ".ext"} {
2127 lassign [
ReadListFile {*}"$sha_mode_opt $f $ext_path"] l p fs
2129 lassign [
ReadListFile {*}"$sha_mode_opt $f $repo_path"] l p fs
2132 set properties [
MergeDict $p $properties]
2133 Msg Debug "list file $f, filesets: $fs"
2135 Msg Debug "Merged filesets $filesets"
2137 return [list $libraries $properties $filesets]
2150 proc ParseFirstLineHogFiles {list_path list_file} {
2151 set repo_path [
file normalize $list_path/../../..]
2152 if {![
file exists $list_path/$list_file]} {
2153 Msg Error "list file $list_path/$list_file does not exist!"
2156 set fp [open $list_path/$list_file r]
2157 set line [
lindex [
split [read $fp] "\n"] 0]
2160 if {[
string match "#*" $line]} {
2161 return [
string trim [
string range $line 1 end]]
2173 proc AddHogFiles { libraries properties filesets } {
2174 Msg Info "Adding source files to project..."
2175 Msg Debug "Filesets: $filesets"
2176 Msg Debug "Libraries: $libraries"
2177 Msg Debug "Properties: $properties"
2180 set synth_conf_command "organize_tool_files -tool {SYNTHESIZE} -input_type {constraint}"
2182 set timing_conf_command "organize_tool_files -tool {VERIFYTIMING} -input_type {constraint}"
2184 set place_conf_command "organize_tool_files -tool {PLACEROUTE} -input_type {constraint}"
2188 foreach fileset [dict keys $filesets] {
2189 Msg Debug "Fileset: $fileset"
2192 if {[
string equal [get_filesets -quiet $fileset] ""]} {
2194 create_fileset -simset $fileset
2196 current_fileset -simset [ get_filesets $fileset]
2197 set simulation [get_filesets $fileset]
2199 set_property -name {$simulator.compile.vhdl_syntax} -value {2008} -objects $simulation
2201 set_property SOURCE_SET sources_1 $simulation
2205 set libs_in_fileset [
DictGet $filesets $fileset]
2206 if { [
IsInList "ips.src" $libs_in_fileset] } {
2211 foreach lib $libs_in_fileset {
2212 Msg Debug "lib: $lib \n"
2213 set lib_files [
DictGet $libraries $lib]
2214 Msg Debug "Files in $lib: $lib_files"
2215 set rootlib [
file rootname [
file tail $lib]]
2216 set ext [
file extension $lib]
2217 Msg Debug "lib: $lib ext: $ext fileset: $fileset"
2220 Msg Debug "Adding $lib to $fileset"
2221 add_files -norecurse -fileset $fileset $lib_files
2223 foreach f $lib_files {
2224 set file_obj [get_files -of_objects [get_filesets $fileset] [list "*$f"]]
2226 if {[
file extension $f] == ".vhd" || [
file extension $f] == ".vhdl"} {
2227 set_property -name "library" -value $rootlib -objects $file_obj
2231 set props [
DictGet $properties $f]
2232 if {[
file extension $f] == ".vhd" || [
file extension $f] == ".vhdl"} {
2234 if {[lsearch -inline -regexp $props "93"] < 0} {
2237 set_property -name "file_type" -value "VHDL 2008" -objects $file_obj
2240 Msg Debug "Filetype is VHDL 93 for $f"
2245 if {[lsearch -inline -regexp $props "SystemVerilog"] > 0 } {
2248 set_property -name "file_type" -value "SystemVerilog" -objects $file_obj
2249 Msg Debug "Filetype is SystemVerilog for $f"
2251 Msg Warning "Xilinx PlanAhead/ISE does not support SystemVerilog. Property not set for $f"
2256 set top [
lindex [regexp -inline {top\s*=\s*(.+?)\y.*} $props] 1]
2258 Msg Info "Setting $top as top module for file set $fileset..."
2259 set globalSettings::synth_top_module $top
2264 if {[lsearch -inline -regexp $props "verilog_header"] >= 0} {
2265 Msg Debug "Setting verilog header type for $f..."
2266 set_property file_type {Verilog Header} [get_files $f]
2267 }
elseif {[lsearch -inline -regexp $props "verilog_template"] >= 0} {
2269 Msg Debug "Setting verilog template type for $f..."
2270 set_property file_type {Verilog Template} [get_files $f]
2271 }
elseif {[lsearch -inline -regexp $props "verilog"] >= 0} {
2273 Msg Debug "Setting verilog type for $f..."
2274 set_property file_type {Verilog} [get_files $f]
2278 if {[lsearch -inline -regexp $props "nosynth"] >= 0} {
2279 Msg Debug "Setting not used in synthesis for $f..."
2280 set_property -name "used_in_synthesis" -value "false" -objects $file_obj
2284 if {[lsearch -inline -regexp $props "noimpl"] >= 0} {
2285 Msg Debug "Setting not used in implementation for $f..."
2286 set_property -name "used_in_implementation" -value "false" -objects $file_obj
2290 if {[lsearch -inline -regexp $props "nosim"] >= 0} {
2291 Msg Debug "Setting not used in simulation for $f..."
2292 set_property -name "used_in_simulation" -value "false" -objects $file_obj
2297 set top_sim [
lindex [regexp -inline {topsim\s*=\s*(.+?)\y.*} $props] 1]
2298 if { $top_sim != "" } {
2299 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"
2303 set sim_runtime [
lindex [regexp -inline {runtime\s*=\s*(.+?)\y.*} $props] 1]
2304 if { $sim_runtime != "" } {
2305 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"
2313 if {[lsearch -inline -regexp $props "wavefile"] >= 0} {
2314 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]"
2329 if {[lsearch -inline -regexp $props "dofile"] >= 0} {
2330 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]"
2343 if {[lsearch -inline -regexp $props "locked"] >= 0 && $ext == ".ip"} {
2344 Msg Info "Locking IP $f..."
2345 set_property IS_MANAGED 0 [get_files $f]
2349 if {[
file extension $f] == ".bd"} {
2350 Msg Info "Generating Target for [
file tail $f], please remember to commit the (possible) changed file."
2351 generate_target all [get_files $f]
2356 if {[
file extension $f] == ".tcl" && $ext != ".con"} {
2357 if { [lsearch -inline -regexp $props "source"] >= 0} {
2358 Msg Info "Sourcing Tcl script $f, and setting it not used in synthesis, implementation and simulation..."
2360 set_property -name "used_in_synthesis" -value "false" -objects $file_obj
2361 set_property -name "used_in_implementation" -value "false" -objects $file_obj
2362 set_property -name "used_in_simulation" -value "false" -objects $file_obj
2366 Msg Info "[
llength $lib_files] file/s added to library $rootlib..."
2369 if { $ext == ".sim"} {
2370 Msg Warning "Simulation files not supported in Quartus Prime mode... Skipping $lib"
2372 if {! [is_project_open] } {
2373 Msg Error "Project is closed"
2375 foreach cur_file $lib_files {
2379 set props [
DictGet $properties $cur_file]
2382 set top [
lindex [regexp -inline {top\s*=\s*(.+?)\y.*} $props] 1]
2384 Msg Info "Setting $top as top module for file set $fileset..."
2385 set globalSettings::synth_top_module $top
2388 if {[
string first "VHDL" $file_type] != -1 } {
2389 if {[
string first "1987" $props] != -1 } {
2390 set hdl_version "VHDL_1987"
2391 }
elseif {[
string first "1993" $props] != -1 } {
2392 set hdl_version "VHDL_1993"
2393 }
elseif {[
string first "2008" $props] != -1 } {
2394 set hdl_version "VHDL_2008"
2396 set hdl_version "default"
2398 if { $hdl_version == "default" } {
2399 set_global_assignment -name $file_type $cur_file -library $rootlib
2401 set_global_assignment -name $file_type $cur_file -hdl_version $hdl_version -library $rootlib
2403 }
elseif {[
string first "SYSTEMVERILOG" $file_type] != -1 } {
2405 if {[
string first "2005" $props] != -1 } {
2406 set hdl_version "systemverilog_2005"
2407 }
elseif {[
string first "2009" $props] != -1 } {
2408 set hdl_version "systemverilog_2009"
2410 set hdl_version "default"
2412 if { $hdl_version == "default" } {
2413 set_global_assignment -name $file_type $cur_file
2415 set_global_assignment -name $file_type $cur_file -hdl_version $hdl_version
2417 }
elseif {[
string first "VERILOG" $file_type] != -1 } {
2419 if {[
string first "1995" $props] != -1 } {
2420 set hdl_version "verilog_1995"
2421 }
elseif {[
string first "2001" $props] != -1 } {
2422 set hdl_version "verilog_2001"
2424 set hdl_version "default"
2426 if { $hdl_version == "default" } {
2427 set_global_assignment -name $file_type $cur_file
2429 set_global_assignment -name $file_type $cur_file -hdl_version $hdl_version
2431 }
elseif {[
string first "SOURCE" $file_type] != -1 || [
string first "COMMAND_MACRO" $file_type] != -1 } {
2432 set_global_assignment -name $file_type $cur_file
2433 if { $ext == ".con"} {
2435 }
elseif { $ext == ".src"} {
2437 if {[
string first "qsys" $props] != -1 } {
2440 regsub -all {\{||qsys||\}} $props $emptyString props
2442 set qsysPath [
file dirname $cur_file]
2443 set qsysName "[
file rootname [
file tail $cur_file]].qsys"
2444 set qsysFile "$qsysPath/$qsysName"
2445 set qsysLogFile "$qsysPath/[
file rootname [
file tail $cur_file]].qsys-script.log"
2448 if {! [
info exists ::env(QSYS_ROOTDIR)] } {
2449 if {[
info exists ::env(QUARTUS_ROOTDIR)] } {
2450 set qsys_rootdir "$::env(QUARTUS_ROOTDIR)/sopc_builder/bin"
2451 Msg Warning "The QSYS_ROOTDIR environment variable is not set! I will use $qsys_rootdir"
2453 Msg CriticalWarning "The QUARTUS_ROOTDIR environment variable is not set! Assuming all quartus executables are contained in your PATH!"
2456 set qsys_rootdir $::env(QSYS_ROOTDIR)
2459 set cmd "$qsys_rootdir/qsys-script"
2460 set cmd_options " --script=$cur_file"
2461 if {![
catch {"exec $cmd -version"}] || [
lindex $::errorCode 0] eq "NONE"} {
2462 Msg Info "Executing: $cmd $cmd_options"
2463 Msg Info "Saving logfile in: $qsysLogFile"
2464 if { [
catch {
eval exec -ignorestderr "$cmd $cmd_options >>& $qsysLogFile"} ret opt]} {
2465 set makeRet [
lindex [dict get $opt -errorcode] end]
2466 Msg CriticalWarning "$cmd returned with $makeRet"
2469 Msg Error " Could not execute command $cmd"
2473 if { [
file exists $qsysName] != 0} {
2474 file rename -force $qsysName $qsysFile
2476 set qsysMd5Sum [
Md5Sum $qsysFile]
2478 set fileDir [
file normalize "./hogTmp"]
2479 set fileName "$fileDir/.hogQsys.md5"
2480 if {![
file exists $fileDir]} {
2483 set hogQsysFile [open $fileName "a"]
2484 set fileEntry "$qsysFile\t$qsysMd5Sum"
2485 puts $hogQsysFile $fileEntry
2488 Msg ERROR "Error while moving the generated qsys file to final location: $qsysName not found!"
2490 if { [
file exists $qsysFile] != 0} {
2491 if {[
string first "noadd" $props] == -1} {
2493 set_global_assignment -name $qsysFileType $qsysFile
2495 regsub -all {noadd} $props $emptyString props
2497 if {[
string first "nogenerate" $props] == -1} {
2502 Msg ERROR "Error while generating ip variations from qsys: $qsysFile not found!"
2506 }
elseif { [
string first "QSYS" $file_type] != -1 } {
2508 regsub -all {\{||\}} $props $emptyString props
2509 if {[
string first "noadd" $props] == -1} {
2510 set_global_assignment -name $file_type $cur_file
2512 regsub -all {noadd} $props $emptyString props
2516 if {[
string first "nogenerate" $props] == -1} {
2520 set_global_assignment -name $file_type $cur_file -library $rootlib
2525 if {$ext == ".con"} {
2526 set vld_exts {.sdc .pin .dcf .gcf .pdc .ndc .fdc .crt .vcd }
2527 foreach con_file $lib_files {
2529 set con_ext [
file extension $con_file]
2530 if {[
IsInList [
file extension $con_file] $vld_exts]} {
2531 set option [
string map {. -} $con_ext]
2532 set option [
string map {fdc net_fdc} $option]
2533 set option [
string map {pdc io_pdc} $option]
2534 create_links -convert_EDN_to_HDL 0 -library {work} $option $con_file
2536 set props [
DictGet $properties $con_file]
2538 if {$con_ext == ".sdc"} {
2539 if { [lsearch $props "notiming"] >= 0 } {
2540 Msg Info "Excluding $con_file from timing verification..."
2542 Msg Info "Adding $con_file to time verification"
2543 append timing_conf_command " -file $con_file"
2547 if { [lsearch $props "nosynth"] >= 0 } {
2548 Msg Info "Excluding $con_file from synthesis..."
2550 Msg Info "Adding $con_file to synthesis"
2551 append synth_conf_command " -file $con_file"
2556 if {$con_ext == ".pdc" || $con_ext == ".sdc"} {
2557 if { [lsearch $props "noplace"] >= 0 } {
2558 Msg Info "Excluding $con_file from place and route..."
2560 Msg Info "Adding $con_file to place and route"
2561 append place_conf_command " -file $con_file"
2567 Msg CriticalWarning "Constraint file $con_file does not have a valid extension. Allowed extensions are: \n $vld_exts"
2570 }
elseif {$ext == ".src"} {
2571 foreach f $lib_files {
2572 Msg Debug "Adding source $f to library $rootlib..."
2573 create_links -library $rootlib -hdl_source $f
2576 build_design_hierarchy
2577 foreach cur_file $lib_files {
2581 set props [
DictGet $properties $cur_file]
2584 set top [
lindex [regexp -inline {top\s*=\s*(.+?)\y.*} $props] 1]
2586 Msg Info "Setting $top as top module for file set $rootlib..."
2587 set globalSettings::synth_top_module "${top}::$rootlib"
2598 if {[
DictGet $filesets "sim_1"] == ""} {
2599 delete_fileset -quiet [get_filesets -quiet "sim_1"]
2605 if {$synth_conf == 1} {
2606 Msg Info $synth_conf_command
2607 eval $synth_conf_command
2609 if {$timing_conf == 1} {
2610 Msg Info $timing_conf_command
2611 eval $timing_conf_command
2613 if {$place_conf == 1} {
2614 Msg Info $place_conf_command
2615 eval $place_conf_command
2626 proc CheckExtraFiles {libraries} {
2629 lassign [
GetProjectFiles] prjLibraries prjProperties prjSimLibraries prjConstraints
2630 set prjLibraries [
MergeDict $prjLibraries $prjSimLibraries]
2631 set prjLibraries [
MergeDict $prjLibraries $prjConstraints]
2632 set prj_dir [get_property DIRECTORY [current_project]]
2633 file mkdir "$prj_dir/.hog"
2634 set extra_file_name "$prj_dir/.hog/extra.files"
2635 set new_extra_file [open $extra_file_name "w"]
2637 dict for {prjLib prjFiles} $prjLibraries {
2638 foreach prjFile $prjFiles {
2639 if {[file extension $prjFile] == ".xcix"} {
2640 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."
2643 if {[file extension $prjFile] == ".xci" && [get_property CORE_CONTAINER [get_files $prjFile]] != ""} {
2644 Msg Info "$prjFile is a virtual IP file in a core container. Ignoring it..."
2648 if {[IsInList $prjFile [DictGet $libraries $prjLib]]==0} {
2649 if { [file extension $prjFile] == ".bd"} {
2650 # Generating BD products to save md5sum of already modified BD
2651 Msg Info "Generating targets of $prjFile..."
2652 generate_target all [get_files $prjFile]
2654 puts $new_extra_file "$prjFile [Md5Sum $prjFile]"
2655 Msg Info "$prjFile (lib: $prjLib) has been generated by an external script. Adding to $extra_file_name..."
2659 close $new_extra_file
2668 proc ReadExtraFileList { extra_file_name } {
2669 set extra_file_dict [dict create]
2670 if {[
file exists $extra_file_name]} {
2671 set file [open $extra_file_name "r"]
2672 set file_data [read $file]
2675 set data [
split $file_data "\n"]
2676 foreach line $data {
2677 if {![regexp {^ *$} $line] & ![regexp {^ *\#} $line] } {
2678 set ip_and_md5 [regexp -all -inline {\S+} $line]
2679 dict lappend extra_file_dict "[
lindex $ip_and_md5 0]" "[
lindex $ip_and_md5 1]"
2683 return $extra_file_dict
2692 proc GenerateQsysSystem {qsysFile commandOpts} {
2693 if { [
file exists $qsysFile] != 0} {
2694 set qsysPath [
file dirname $qsysFile]
2695 set qsysName [
file rootname [
file tail $qsysFile]]
2696 set qsysIPDir "$qsysPath/$qsysName"
2697 set qsysLogFile "$qsysPath/$qsysName.qsys-generate.log"
2700 if {! [
info exists ::env(QSYS_ROOTDIR)] } {
2701 if {[
info exists ::env(QUARTUS_ROOTDIR)] } {
2702 set qsys_rootdir "$::env(QUARTUS_ROOTDIR)/sopc_builder/bin"
2703 Msg Warning "The QSYS_ROOTDIR environment variable is not set! I will use $qsys_rootdir"
2705 Msg CriticalWarning "The QUARTUS_ROOTDIR environment variable is not set! Assuming all quartus executables are contained in your PATH!"
2708 set qsys_rootdir $::env(QSYS_ROOTDIR)
2711 set cmd "$qsys_rootdir/qsys-generate"
2712 set cmd_options "$qsysFile --output-directory=$qsysIPDir $commandOpts"
2713 if {![
catch {"exec $cmd -version"}] || [
lindex $::errorCode 0] eq "NONE"} {
2714 Msg Info "Executing: $cmd $cmd_options"
2715 Msg Info "Saving logfile in: $qsysLogFile"
2716 if {[
catch {
eval exec -ignorestderr "$cmd $cmd_options >>& $qsysLogFile"} ret opt]} {
2717 set makeRet [
lindex [dict get $opt -errorcode] end]
2718 Msg CriticalWarning "$cmd returned with $makeRet"
2721 Msg Error " Could not execute command $cmd"
2725 set qsysIPFileList [
concat [glob -nocomplain -directory $qsysIPDir -types f *.ip *.qip] [glob -nocomplain -directory "$qsysIPDir/synthesis" -types f *.ip *.qip *.vhd *.vhdl]]
2726 foreach qsysIPFile $qsysIPFileList {
2727 if { [
file exists $qsysIPFile] != 0} {
2729 set_global_assignment -name $qsysIPFileType $qsysIPFile
2731 set IpMd5Sum [
Md5Sum $qsysIPFile]
2733 set fileDir [
file normalize "./hogTmp"]
2734 set fileName "$fileDir/.hogQsys.md5"
2735 if {![
file exists $fileDir]} {
2738 set hogQsysFile [open $fileName "a"]
2739 set fileEntry "$qsysIPFile\t$IpMd5Sum"
2740 puts $hogQsysFile $fileEntry
2745 Msg ERROR "Error while generating ip variations from qsys: $qsysFile not found!"
2751 proc ForceUpToDate {} {
2752 Msg Info "Forcing all the runs to look up to date..."
2755 Msg Info "Forcing $r..."
2756 set_property needs_refresh false [get_runs $r]
2770 proc HandleIP {what_to_do xci_file ip_path repo_path {gen_dir "."} {force 0}} {
2771 if {!($what_to_do eq "push") && !($what_to_do eq "pull")} {
2772 Msg Error "You must specify push or pull as first argument."
2775 if { [
catch {
package require tar} TARPACKAGE]} {
2776 Msg CriticalWarning "Cannot find package tar. You can fix this by installing package \"tcllib\""
2785 if {[
string first "/eos/" $ip_path] == 0} {
2793 lassign [
eos "ls $ip_path"] ret result
2795 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."
2799 Msg Info "IP remote directory path, on EOS, is set to: $ip_path"
2806 if {!([
file exists $xci_file])} {
2807 Msg CriticalWarning "Could not find $xci_file."
2813 set xci_path [
file dirname $xci_file]
2814 set xci_name [
file tail $xci_file]
2815 set xci_ip_name [
file rootname [
file tail $xci_file]]
2816 set xci_dir_name [
file tail $xci_path]
2817 set gen_path $gen_dir
2819 set hash [
Md5Sum $xci_file]
2820 set file_name $xci_name\_$hash
2822 Msg Info "Preparing to $what_to_do IP: $xci_name..."
2824 if {$what_to_do eq "push"} {
2828 lassign [
eos "ls $ip_path/$file_name.tar"] ret result
2833 Msg Info "IP already in the EOS repository, will not copy..."
2835 Msg Info "IP already in the EOS repository, will forcefully replace..."
2841 if {[
file exists "$ip_path/$file_name.tar"]} {
2843 Msg Info "IP already in the local repository, will not copy..."
2845 Msg Info "IP already in the local repository, will forcefully replace..."
2854 if {$will_copy == 1} {
2856 Msg Info "Looking for generated files in $gen_path..."
2857 set ip_gen_files [glob -nocomplain $gen_path/*]
2861 if {[
llength $ip_gen_files] > 0} {
2862 Msg Info "Found some IP synthesised files matching $xci_ip_name"
2863 if {$will_remove == 1} {
2864 Msg Info "Removing old synthesised directory $ip_path/$file_name.tar..."
2866 eos "rm -rf $ip_path/$file_name.tar" 5
2868 file delete -force "$ip_path/$file_name.tar"
2872 Msg Info "Creating local archive with IP generated files..."
2874 foreach f $ip_gen_files {
2875 if {$first_file == 0} {
2876 ::tar::create $file_name.tar "[
Relative [
file normalize $repo_path] $f]"
2879 ::tar::add $file_name.tar "[
Relative [
file normalize $repo_path] $f]"
2883 Msg Info "Copying IP generated files for $xci_name..."
2885 lassign [
ExecuteRet xrdcp -f -s $file_name.tar $::env(EOS_MGM_URL)//$ip_path/] ret msg
2887 Msg CriticalWarning "Something went wrong when copying the IP files to EOS. Error message: $msg"
2890 Copy "$file_name.tar" "$ip_path/"
2892 Msg Info "Removing local archive"
2893 file delete $file_name.tar
2896 Msg Warning "Could not find synthesized files matching $gen_path/$file_name*"
2899 }
elseif {$what_to_do eq "pull"} {
2901 lassign [
eos "ls $ip_path/$file_name.tar"] ret result
2903 Msg Info "Nothing for $xci_name was found in the EOS repository, cannot pull."
2908 set remote_tar "$::env(EOS_MGM_URL)//$ip_path/$file_name.tar"
2909 Msg Info "IP $xci_name found in the repository $remote_tar, copying it locally to $repo_path..."
2911 lassign [
ExecuteRet xrdcp -f -r -s $remote_tar $repo_path] ret msg
2913 Msg CriticalWarning "Something went wrong when copying the IP files to EOS. Error message: $msg"
2917 if {[
file exists "$ip_path/$file_name.tar"]} {
2918 Msg Info "IP $xci_name found in local repository $ip_path/$file_name.tar, copying it locally to $repo_path..."
2919 Copy $ip_path/$file_name.tar $repo_path
2922 Msg Info "Nothing for $xci_name was found in the local IP repository, cannot pull."
2929 if {[
file exists $file_name.tar]} {
2930 remove_files $xci_file
2931 Msg Info "Extracting IP files from archive to $repo_path..."
2932 ::tar::untar $file_name.tar -dir $repo_path -noperms
2933 Msg Info "Removing local archive"
2934 file delete $file_name.tar
2935 add_files -norecurse -fileset sources_1 $xci_file
2945 proc Md5Sum {file_name} {
2946 if {!([
file exists $file_name])} {
2947 Msg Warning "Could not find $file_name."
2950 if {[
catch {
package require md5 2.0.7} result]} {
2951 Msg Warning "Tcl package md5 version 2.0.7 not found ($result), will use command line..."
2952 set hash [
lindex [
Execute md5sum $file_name] 0]
2954 set file_hash [
string tolower [md5::md5 -hex -file $file_name]]
2964 proc CheckYmlRef {repo_path allow_failure} {
2966 if {$allow_failure} {
2967 set MSG_TYPE CriticalWarning
2972 if { [
catch {
package require yaml 0.3.3} YAMLPACKAGE]} {
2973 Msg CriticalWarning "Cannot find package YAML, skipping consistency check of \"ref\" in gilab-ci.yaml file.\n Error message: $YAMLPACKAGE
2974 You can fix this by installing package \"tcllib\""
2982 if {[
file exists .gitlab-ci.yml]} {
2986 if { [
file exists .gitlab-ci.yml] } {
2987 set fp [open ".gitlab-ci.yml" r]
2988 set file_data [read $fp]
2991 Msg $MSG_TYPE "Cannot open file .gitlab-ci.yml"
2995 set file_data "\n$file_data\n\n"
2997 if { [
catch {::yaml::yaml2dict -stream $file_data} yamlDict]} {
2998 Msg $MSG_TYPE "Parsing $repo_path/.gitlab-ci.yml failed. To fix this, check that yaml syntax is respected, remember not to use tabs."
3002 dict for {dictKey dictValue} $yamlDict {
3003 #looking for Hog include in .gitlab-ci.yml
3004 if {"$dictKey" == "include" && ([lsearch [split $dictValue " {}"] "/hog.yml" ] != "-1" || [lsearch [split $dictValue " {}"] "/hog-dynamic.yml" ] != "-1")} {
3005 set YML_REF [lindex [split $dictValue " {}"] [expr {[lsearch -dictionary [split $dictValue " {}"] "ref"]+1} ] ]
3006 set YML_NAME [lindex [split $dictValue " {}"] [expr {[lsearch -dictionary [split $dictValue " {}"] "file"]+1} ] ]
3010 if {$YML_REF == ""} {
3011 Msg Warning "Hog version not specified in the .gitlab-ci.yml. Assuming that master branch is used."
3013 set YML_REF_F [
Git {name-rev --tags --name-only origin/master}]
3016 set YML_REF_F [regsub -all "'" $YML_REF ""]
3019 if {$YML_NAME == ""} {
3020 Msg $MSG_TYPE "Hog included yml file not specified, assuming hog.yml"
3021 set YML_NAME_F hog.yml
3023 set YML_NAME_F [regsub -all "^/" $YML_NAME ""]
3026 lappend YML_FILES $YML_NAME_F
3032 if { [
catch {::yaml::yaml2dict -file $YML_NAME_F} yamlDict]} {
3033 Msg $MSG_TYPE "Parsing $YML_NAME_F failed."
3037 dict for {dictKey dictValue} $yamlDict {
3038 #looking for included files
3039 if {"$dictKey" == "include"} {
3040 foreach v $dictValue {
3041 lappend YML_FILES [lindex [split $v " "] [expr {[lsearch -dictionary [split $v " "] "local"]+1} ] ]
3047 Msg Info "Found the following yml files: $YML_FILES"
3049 set HOGYML_SHA [
GetSHA $YML_FILES]
3050 lassign [
GitRet "log --format=%h -1 --abbrev=7 $YML_REF_F" $YML_FILES] ret EXPECTEDYML_SHA
3052 lassign [
GitRet "log --format=%h -1 --abbrev=7 origin/$YML_REF_F" $YML_FILES] ret EXPECTEDYML_SHA
3054 Msg $MSG_TYPE "Error in project .gitlab-ci.yml. ref: $YML_REF not found"
3055 set EXPECTEDYML_SHA ""
3058 if {!($EXPECTEDYML_SHA eq "")} {
3059 if {$HOGYML_SHA == $EXPECTEDYML_SHA} {
3060 Msg Info "Hog included file $YML_FILES matches with $YML_REF in .gitlab-ci.yml."
3063 Msg $MSG_TYPE "HOG $YML_FILES SHA mismatch.
3064 From Hog submodule: $HOGYML_SHA
3065 From ref in .gitlab-ci.yml: $EXPECTEDYML_SHA
3066 You can fix this in 2 ways: by changing the ref in your repository or by changing the Hog submodule commit"
3069 Msg $MSG_TYPE "One or more of the following files could not be found $YML_FILES in Hog at $YML_REF"
3072 Msg Info ".gitlab-ci.yml not found in $repo_path. Skipping this step"
3082 proc ParseJSON {JSON_FILE JSON_KEY} {
3083 set result [
catch {
package require Tcl 8.4} TclFound]
3084 if {"$result" != "0"} {
3085 Msg CriticalWarning "Cannot find Tcl package version equal or higher than 8.4.\n $TclFound\n Exiting"
3089 set result [
catch {
package require json} JsonFound]
3090 if {"$result" != "0"} {
3091 Msg CriticalWarning "Cannot find JSON package equal or higher than 1.0.\n $JsonFound\n Exiting"
3094 set JsonDict [json::json2dict $JSON_FILE]
3095 set result [
catch {dict get $JsonDict $JSON_KEY} RETURNVALUE]
3096 if {"$result" != "0"} {
3097 Msg CriticalWarning "Cannot find $JSON_KEY in $JSON_FILE\n Exiting"
3113 proc eos {command {attempt 1}} {
3115 if {![
info exists env(EOS_MGM_URL)]} {
3116 Msg Warning "Environment variable EOS_MGM_URL not set, setting it to default value root://eosuser.cern.ch"
3117 set ::env(EOS_MGM_URL) "root://eosuser.cern.ch"
3120 Msg Warning "The value of attempt should be 1 or more, not $attempt, setting it to 1 as default"
3123 for {
set i 0} {$i < $attempt} {
incr i} {
3124 set ret [
catch {
exec -ignorestderr eos {*}$command} result]
3129 set wait [
expr {1+int(rand()*29)}]
3130 Msg Warning "Command $command failed ($i/$attempt): $result, trying again in $wait seconds..."
3131 after [
expr {$wait*1000}]
3135 return [list $ret $result]
3145 proc Git {command {files ""}} {
3146 lassign [
GitRet $command $files] ret result
3148 Msg Error "Code $ret returned by git running: $command -- $files"
3163 proc GitRet {command {files ""}} {
3166 set ret [
catch {
exec -ignorestderr git {*}$command} result]
3168 set ret [
catch {
exec -ignorestderr git {*}$command -- {*}$files} result]
3172 return [list $ret $result]
3181 proc FileCommitted {File } {
3183 set currentDir [
pwd]
3184 cd [
file dirname [
file normalize $File]]
3185 set GitLog [
Git ls-files [
file tail $File]]
3186 if {$GitLog == ""} {
3187 Msg CriticalWarning "File [
file normalize $File] is not in the git repository. Please add it with:\n git add [
file normalize $File]\n"
3202 proc ExecuteRet {args} {
3204 if {[
llength $args] == 0} {
3205 Msg CriticalWarning "No argument given"
3209 set ret [
catch {
exec -ignorestderr {*}$args} result]
3212 return [list $ret $result]
3222 proc Execute {args} {
3226 Msg Error "Command [
join $args] returned error code: $ret"
3241 proc GetMaxThreads {proj_dir} {
3243 if {[
file exists $proj_dir/hog.conf]} {
3245 if {[dict exists $properties parameters]} {
3246 set propDict [dict get $properties parameters]
3247 if {[dict exists $propDict MAX_THREADS]} {
3248 set maxThreads [dict get $propDict MAX_THREADS]
3252 Msg Warning "File $proj_dir/hog.conf not found. Max threads will be set to default value 1"
3264 proc WriteGitLabCIYAML {proj_name {ci_conf ""}} {
3265 if { [
catch {
package require yaml 0.3.3} YAMLPACKAGE]} {
3266 Msg CriticalWarning "Cannot find package YAML.\n Error message: $YAMLPACKAGE. If you are tunning on tclsh, you can fix this by installing package \"tcllib\""
3271 if {$ci_conf != ""} {
3273 foreach sec [dict keys $ci_confs] {
3274 if {[
string first : $sec] == -1} {
3275 lappend job_list $sec
3279 set job_list {"generate_project" "simulate_project"}
3283 set out_yaml [huddle create]
3284 foreach job $job_list {
3286 set huddle_tags [huddle list]
3288 set sec_dict [dict create]
3290 if {$ci_confs != ""} {
3291 foreach var [dict keys [dict get $ci_confs $job]] {
3292 if {$var == "tags"} {
3293 set tag_section "tags"
3294 set tags [dict get [dict get $ci_confs $job] $var]
3295 set tags [
split $tags ","]
3297 set tag_list [huddle list $tag]
3298 set huddle_tags [huddle combine $huddle_tags $tag_list]
3301 dict set sec_dict $var [dict get [dict get $ci_confs $job] $var]
3307 set huddle_variables [huddle create "PROJECT_NAME" $proj_name "extends" ".vars"]
3308 if {[dict exists $ci_confs "$job:variables"]} {
3309 set var_dict [dict get $ci_confs $job:variables]
3310 foreach var [dict keys $var_dict] {
3312 set value [dict get $var_dict "$var"]
3313 set var_inner [huddle create "$var" "$value"]
3314 set huddle_variables [huddle combine $huddle_variables $var_inner]
3319 set middle [huddle create "extends" ".$job" "variables" $huddle_variables]
3320 foreach sec [dict keys $sec_dict] {
3321 set value [dict get $sec_dict $sec]
3322 set var_inner [huddle create "$sec" "$value"]
3323 set middle [huddle combine $middle $var_inner]
3325 if {$tag_section != ""} {
3326 set middle2 [huddle create "$tag_section" $huddle_tags]
3327 set middle [huddle combine $middle $middle2]
3330 set outer [huddle create "$job:$proj_name" $middle]
3331 set out_yaml [huddle combine $out_yaml $outer]
3334 return [
string trimleft [ yaml::huddle2yaml $out_yaml] "-"]
3338 proc FindNewestVersion { versions } {
3339 set new_ver 00000000
3340 foreach ver $versions {
3342 if {[
expr 0x$ver > 0x$new_ver] } {
3355 proc ResetRepoFiles {reset_file} {
3356 if {[
file exists $reset_file]} {
3357 Msg Info "Found $reset_file, opening it..."
3358 set fp [open $reset_file r]
3359 set wild_cards [lsearch -all -inline -not -regexp [
split [read $fp] "\n"] "^ *$"]
3361 Msg Info "Found the following files/wild cards to restore if modified: $wild_cards..."
3362 foreach w $wild_cards {
3364 if {[
llength $mod_files] > 0} {
3365 Msg Info "Found modified $w files: $mod_files, will restore them..."
3368 Msg Info "No modified $w files found."
3380 proc SearchHogProjects {dir} {
3381 set projects_list {}
3382 if {[
file exists $dir]} {
3383 if {[
file isdirectory $dir]} {
3384 foreach proj_dir [glob -nocomplain -types d $dir/*] {
3385 if {![regexp {^.*Top/+(.*)$} $proj_dir dummy proj_name]} {
3386 Msg Warning "Could not parse Top directory $dir"
3389 if { [
file exists "$proj_dir/hog.conf"] } {
3390 lappend projects_list $proj_name
3393 lappend projects_list $p
3399 Msg Error "Input $dir is not a directory!"
3402 Msg Error "Directory $dir doesn't exist!"
3404 return $projects_list
3414 proc GetGroupName {proj_dir repo_dir} {
3415 if {[regexp {^(.*)/(Top|Projects)/+(.*?)/*$} $proj_dir dummy possible_repo_dir proj_or_top dir]} {
3417 if {[
file normalize $repo_dir] eq [
file normalize $possible_repo_dir]} {
3418 set group [
file dir $dir]
3419 if { $group == "." } {
3424 Msg Warning "Project directory $proj_dir seems to be in $possible_repo_dir which is not a the main Git repository $repo_dir."
3427 Msg Warning "Could not parse project directory $proj_dir"
3439 proc ReadConf {file_name} {
3441 if { [
catch {
package require inifile 0.2.3} ERROR] } {
3442 puts "$ERROR\n If you are running this script on tclsh, you can fix this by installing 'tcllib'"
3447 ::ini::commentchar "#"
3448 set f [::ini::open $file_name]
3449 set properties [dict create]
3450 foreach sec [::ini::sections $f] {
3452 set key_pairs [::ini::get $f $sec]
3455 regsub -all {\{\"} $key_pairs "\{" key_pairs
3456 regsub -all {\"\}} $key_pairs "\}" key_pairs
3458 dict set properties $new_sec [dict create {*}$key_pairs]
3473 proc WriteConf {file_name config {comment ""}} {
3474 if { [
catch {
package require inifile 0.2.3} ERROR] } {
3475 puts "$ERROR\n If you are running this script on tclsh, you can fix this by installing 'tcllib'"
3479 ::ini::commentchar "#"
3480 set f [::ini::open $file_name w]
3482 foreach sec [dict keys $config] {
3483 set section [dict get $config $sec]
3484 dict for {p v} $section {
3485 if {[string trim $v] == ""} {
3486 Msg Warning "Property $p has empty value. Skipping..."
3489 ::ini::set $f $sec $p $v
3494 if {![
string equal "$comment" ""]} {
3495 ::ini::comment $f [
lindex [::ini::sections $f] 0] "" $comment
3508 proc IsRelativePath {path} {
3509 if {[
string index $path 0] == "/" || [
string index $path 0] == "~"} {
3519 Msg Error "Found Git version older than 2.7.2. Hog will not work as expected, exiting now."
3529 proc WriteUtilizationSummary {input output project_name run} {
3530 set f [open $input "r"]
3531 set o [open $output "a"]
3532 puts $o "## $project_name $run Utilization report\n\n"
3533 struct::matrix util_m
3534 util_m add columns 14
3537 util_m add row "| **Site Type** | **Used** | **Fixed** | **Prohibited** | **Available** | **Util%** |"
3538 util_m add row "| --- | --- | --- | --- | --- | --- |"
3540 util_m add row "| **Site Type** | **Used** | **Fixed** | **Available** | **Util%** |"
3541 util_m add row "| --- | --- | --- | --- | --- |"
3551 while {[
gets $f line] >= 0} {
3552 if { ( [
string first "| CLB LUTs" $line] >= 0 || [
string first "| Slice LUTs" $line] >= 0 ) && $luts == 0 } {
3553 util_m add row $line
3556 if { ( [
string first "| CLB Registers" $line] >= 0 || [
string first "| Slice Registers" $line] >= 0 ) && $regs == 0} {
3557 util_m add row $line
3560 if { [
string first "| Block RAM Tile" $line] >= 0 && $bram == 0 } {
3561 util_m add row $line
3564 if { [
string first "URAM " $line] >= 0 && $uram == 0} {
3565 util_m add row $line
3568 if { [
string first "DSPs" $line] >= 0 && $dsps == 0 } {
3569 util_m add row $line
3572 if { [
string first "Bonded IOB" $line] >= 0 && $ios == 0 } {
3573 util_m add row $line
3580 puts $o [util_m format 2string]
3587 proc GetDateAndTime {commit} {
3588 set clock_seconds [
clock seconds]
3591 set date [
Git "log -1 --format=%cd --date=format:%d%m%Y $commit"]
3592 set timee [
Git "log -1 --format=%cd --date=format:00%H%M%S $commit"]
3594 Msg Warning "Found Git version older than 2.9.3. Using current date and time instead of commit time."
3595 set date [
clock format $clock_seconds -format {%d%m%Y}]
3596 set timee [
clock format $clock_seconds -format {00%H%M%S}]
3598 return [list $date $timee]
3604 proc GetProjectFlavour {proj_name} {
3606 set flavour [
string map {. ""} [
file extension $proj_name]]
3607 if {$flavour != ""} {
3608 if {[
string is integer $flavour]} {
3609 Msg Info "Project $proj_name has flavour = $flavour, the generic variable FLAVOUR will be set to $flavour"
3611 Msg Warning "Project name has a unexpected non numeric extension, flavour will be set to -1"
3625 proc FormatGeneric {generic} {
3626 if {[
string is integer "0x$generic"]} {
3627 return [
format "32'h%08X" "0x$generic"]
3630 return [
format "32'h%08X" 0]
3641 proc GetGenericFromConf {proj_dir target {sim 0}} {
3643 set top_dir "Top/$proj_dir"
3644 set conf_file "$top_dir/hog.conf"
3647 set conf_file "$top_dir/sim.conf"
3652 if {[
file exists $conf_file]} {
3654 if {[dict exists $properties generics]} {
3655 set propDict [dict get $properties generics]
3656 dict for {theKey theValue} $propDict {
3665 regexp {([0-9]*)('h)([0-9a-fA-F]*)} $theValue valueHexFull valueNumBits valueHexFlag valueHex
3666 regexp {^([0-9]*)$} $theValue valueIntFull ValueInt
3667 regexp {(?!^\d+$)^.+$} $theValue valueStrFull ValueStr
3668 if { [string tolower $target] == "vivado" || [string tolower $target] == "xsim" } {
3669 if {$valueNumBits != "" && $valueHexFlag != "" && $valueHex != ""} {
3670 set prj_generics "$prj_generics $theKey=$valueHexFull"
3671 } elseif { $valueIntFull != "" && $ValueInt != "" } {
3672 set prj_generics "$prj_generics $theKey=$ValueInt"
3673 } elseif { $valueStrFull != "" && $ValueStr != "" } {
3674 set prj_generics "$prj_generics $theKey=\"$ValueStr\""
3676 set prj_generics "$prj_generics $theKey=\"$theValue\""
3678 } elseif { [lsearch -exact [GetSimulators] [string tolower $target] ] >= 0 } {
3679 if {$valueNumBits != "" && $valueHexFlag != "" && $valueHex != ""} {
3681 scan $valueNumBits %d numBits
3683 scan $valueHex %x numHex
3684 binary scan [binary format "I" $numHex] "B*" binval
3685 set numBits [expr {$numBits-1}]
3686 set numBin [string range $binval end-$numBits end]
3687 set prj_generics "$prj_generics $theKey=\"$numBin\""
3689 } elseif { $valueIntFull != "" && $ValueInt != "" } {
3690 set prj_generics "$prj_generics $theKey=$ValueInt"
3691 } elseif { $valueStrFull != "" && $ValueStr != "" } {
3692 set prj_generics "$prj_generics {$theKey=\"$ValueStr\"}"
3695 set prj_generics "$prj_generics {$theKey=\"$theValue\"}"
3698 Msg Warning "Target : $target not implemented"
3703 Msg Warning "File $top_dir/hog.conf not found."
3705 return $prj_generics
3715 proc SetGenericsSimulation {repo_path proj_dir target} {
3717 set top_dir "$repo_path/Top/$proj_dir"
3719 set sim_cfg_index [lsearch -regexp -index 0 $read_aux ".*sim.conf"]
3720 set sim_cfg_index [lsearch -regexp -index 0 [
GetConfFiles $top_dir] ".*sim.conf"]
3721 set simsets [get_filesets]
3722 if { $simsets != "" } {
3723 if {[
file exists $top_dir/sim.conf]} {
3725 if {$sim_generics != ""} {
3726 foreach simset $simsets {
3727 if {[get_property FILESET_TYPE $simset] != "SimulationSrcs" } {
3730 set_property generic $sim_generics [get_filesets $simset]
3731 Msg Debug "Setting generics $sim_generics for simulator $target and simulation file-set $simset..."
3735 if {[glob -nocomplain "$top_dir/list/*.sim"] ne "" } {
3736 Msg CriticalWarning "Simulation sets and .sim files are present in the project but no sim.conf found in $top_dir. Please refer to Hog's manual to create one."
3743 proc GetTopFile {} {
3745 set compile_order_prop [get_property source_mgmt_mode [current_project]]
3746 if {$compile_order_prop ne "All"} {
3747 Msg CriticalWarning "Compile order is not set to automatic, setting it now..."
3748 set_property source_mgmt_mode All [current_project]
3749 update_compile_order -fileset sources_1
3751 return [
lindex [get_files -quiet -compile_order sources -used_in synthesis -filter {FILE_TYPE =~ "VHDL*" || FILE_TYPE =~ "*Verilog*" }] end]
3752 }
elseif {[
IsISE]} {
3753 debug::design_graph_mgr -create [current_fileset]
3754 debug::design_graph -add_fileset [current_fileset]
3755 debug::design_graph -update_all
3756 return [
lindex [debug::design_graph -get_compile_order] end]
3758 Msg Error "GetTopFile not yet implemented for this IDE"
3763 proc GetTopModule {} {
3765 return [get_property top [current_fileset]]
3767 Msg Error "GetTopModule not yet implemented for this IDE"
3774 proc GetVerilogGenerics {file} {
3775 set fp [open $file r]
3781 foreach line [
split $data "\n"] {
3782 regsub "^\\s*\/\/.*" $line "" line
3783 regsub "(.*)\/\/.*" $line {\1} line
3784 if {![
string equal $line ""]} {
3785 append lines $line " "
3790 regsub -all {/\*.*\*/} $lines "" lines
3793 set punctuation [list]
3794 foreach char [list "(" ")" ";" "," " " "!" "<=" ":=" "=" "\[" "\]"] {
3795 lappend punctuation $char "\000$char\000"
3799 set tokens [
split [
string map $punctuation $lines] \000]
3801 set parameters [dict create]
3810 foreach token $tokens {
3811 set token [
string trim $token]
3812 if {![
string equal "" $token]} {
3813 if {[
string equal [
string tolower $token] "parameter"]} {
3814 set state $PARAM_NAME
3815 }
elseif {[
string equal $token ")"] || [
string equal $token ";"]} {
3817 }
elseif {$state == $PARAM_WIDTH} {
3818 if {[
string equal $token "\]"]} {
3819 set state $PARAM_NAME
3821 }
elseif {$state == $PARAM_VALUE} {
3822 if {[
string equal $token ","]} {
3823 set state $PARAM_NAME
3824 }
elseif {[
string equal $token ";"]} {
3828 }
elseif {$state == $PARAM_NAME} {
3830 if {[
string equal $token "="]} {
3831 set state $PARAM_VALUE
3832 }
elseif {[
string equal $token "\["]} {
3833 set state $PARAM_WIDTH
3834 }
elseif {[
string equal $token ","]} {
3835 set state $PARAM_NAME
3836 }
elseif {[
string equal $token ";"]} {
3838 }
elseif {[
string equal $token ")"]} {
3841 dict set parameters $token "integer"
3851 proc GetVhdlGenerics {file {entity ""} } {
3852 set fp [open $file r]
3858 foreach line [
split $data "\n"] {
3859 regsub "^\\s*--.*" $line "" line
3860 regsub "(.*)--.*" $line {\1} line
3861 if {![
string equal $line ""]} {
3862 append lines $line " "
3867 set generic_block ""
3868 set generics [dict create]
3870 if {1==[
string equal $entity ""]} {
3871 regexp {(?i).*entity\s+([^\s]+)\s+is} $lines _ entity
3874 set generics_regexp "(?i).*entity\\s+$entity\\s+is\\s+generic\\s*\\((.*)\\)\\s*;\\s*port.*end.*$entity"
3876 if {[regexp $generics_regexp $lines _ generic_block]} {
3879 foreach line [
split $generic_block ";"] {
3882 regexp {(.*):\s*([A-Za-z0-9_]+).*} $line _ generic type
3885 set splits [
split $generic ","]
3886 foreach split $splits {
3887 dict set generics [
string trim $split] [
string trim $type]
3894 proc GetFileGenerics {filename {entity ""}} {
3896 if {[
string equal $file_type "VERILOG_FILE"] || [
string equal $file_type "SYSTEMVERILOG_FILE"]} {
3898 }
elseif {[
string equal $file_type "VHDL_FILE"]} {
3901 Msg CriticalWarning "Could not determine extension of top level file."
3913 proc WriteGenerics {mode repo_path 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 ""}} {
3914 Msg Info "Passing parameters/generics to project's top module..."
3917 set generic_string [
concat \
3929 if {$xml_hash != "" && $xml_ver != ""} {
3930 lappend generic_string \
3935 foreach l $libs v $vers h $hashes {
3938 lappend generic_string "$ver" "$hash"
3941 foreach e $ext_names h $ext_hashes {
3943 lappend generic_string "$hash"
3946 foreach repo $user_ip_repos v $user_ip_vers h $user_ip_hashes {
3947 set repo_name [
file tail $repo]
3948 set ver "[
string toupper $repo_name]_VER=[
FormatGeneric $v]"
3949 set hash "[
string toupper $repo_name]_SHA=[
FormatGeneric $h]"
3950 lappend generic_string "$ver" "$hash"
3953 if {$flavour != -1} {
3954 lappend generic_string "FLAVOUR=$flavour"
3959 set generic_string "$prj_generics $generic_string"
3964 if {$mode == "create" || [
IsISE]} {
3968 if {[
file exists $top_file]} {
3971 Msg Debug "Found top level generics $generics in $top_file"
3973 set filtered_generic_string ""
3975 foreach generic_to_set [
split [
string trim $generic_string]] {
3976 set key [
lindex [
split $generic_to_set "="] 0]
3977 if {[dict exists $generics $key]} {
3978 Msg Debug "Hog generic $key found in $top_name"
3979 lappend filtered_generic_string "$generic_to_set"
3981 Msg Warning "Generic $key is passed by Hog but is NOT present in $top_name."
3987 set generic_string $filtered_generic_string
3992 set_property generic $generic_string [current_fileset]
3993 Msg Info "Setting parameters/generics..."
3994 Msg Debug "Detailed parameters/generics: $generic_string"
3998 set simulator [get_property target_simulator [current_project]]
3999 if {$mode == "create"} {
4004 Msg Info "Setting Synplify parameters/generics one by one..."
4005 foreach generic $generic_string {
4006 Msg Debug "Setting Synplify generic: $generic"
4007 set_option -hdl_param -set "$generic"
4016 proc GetIDEVersion {} {
4019 regexp {\d+\.\d+(\.\d+)?} [version -short] ver
4025 regexp {[\.0-9]+} $quartus(version) ver
4028 set ver [get_libero_version]
4036 proc GetIDEFromConf {conf_file} {
4037 set f [open $conf_file "r"]
4040 if {[regexp -all {^\# *(\w*) *(\d+\.\d+(?:\.\d+)?(?:\.\d+)?)?(_.*)? *$} $line dummy ide version patch]} {
4041 if {[
info exists version] && $version != ""} {
4047 set ret [list $ide $ver]
4049 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."
4050 set ret [list "vivado" "0.0.0"]
4062 if {[
file exists $dir] && [
file isdirectory $dir]} {
4076 proc Copy {i_dirs o_dir} {
4077 foreach i_dir $i_dirs {
4078 if {[
file isdirectory $i_dir] && [
file isdirectory $o_dir]} {
4079 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]])} {
4080 file delete -force $o_dir/[
file tail $i_dir]
4084 file copy -force $i_dir $o_dir
4093 proc RemoveDuplicates {mydict} {
4094 set new_dict [dict create]
4095 foreach key [dict keys $mydict] {
4096 set values [
DictGet $mydict $key]
4097 foreach value $values {
4098 set idxs [
lreverse [
lreplace [lsearch -exact -all $values $value] 0 0]]
4100 set values [
lreplace $values $idx $idx]
4103 dict set new_dict $key $values
4123 proc CompareLibDicts {proj_libs list_libs proj_sets list_sets proj_props list_props {severity "CriticalWarning"} {outFile ""} {extraFiles ""} } {
4124 set extra_files $extraFiles
4126 set out_prjlibs $proj_libs
4127 set out_prjprops $proj_props
4129 dict for {prjSet prjLibraries} $proj_sets {
4130 # Check if sets is also in list files
4131 if {[IsInList $prjSet $list_sets]} {
4132 set listLibraries [DictGet $list_sets $prjSet]
4133 # Loop over libraries in fileset
4134 foreach prjLib $prjLibraries {
4135 set prjFiles [DictGet $proj_libs $prjLib]
4136 # Check if library exists in list files
4137 if {[IsInList $prjLib $listLibraries]} {
4138 # Loop over files in library
4139 set listFiles [DictGet $list_libs $prjLib]
4140 foreach prjFile $prjFiles {
4141 set idx [lsearch -exact $listFiles $prjFile]
4142 set listFiles [lreplace $listFiles $idx $idx]
4144 # File is in project but not in list libraries, check if it was generated at creation time...
4145 if { [dict exists $extra_files $prjFile] } {
4146 # File was generated at creation time, checking the md5sum
4147 # Removing the file from the prjFiles list
4148 set idx2 [lsearch -exact $prjFiles $prjFile]
4149 set prjFiles [lreplace $prjFiles $idx2 $idx2]
4150 set new_md5sum [Md5Sum $prjFile]
4151 set old_md5sum [DictGet $extra_files $prjFile]
4152 if {$new_md5sum != $old_md5sum} {
4153 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
4156 set extra_files [dict remove $extra_files $prjFile]
4158 # File is neither in list files nor in extra_files
4159 MsgAndLog "$prjFile was found in project but not in list files or .hog/extra.files" $severity $outFile
4163 # File is both in list files and project, checking properties...
4164 set prjProps [DictGet $proj_props $prjFile]
4165 set listProps [DictGet $list_props $prjFile]
4166 # Check if it is a potential sourced file
4167 if {[IsInList "nosynth" $prjProps] && [IsInList "noimpl" $prjProps] && [IsInList "nosim" $prjProps]} {
4168 # Check if it is sourced
4169 set idx_source [lsearch -exact $listProps "source"]
4170 if {$idx_source >= 0 } {
4171 # It is sourced, let's replace the individual properties with source
4172 set idx [lsearch -exact $prjProps "noimpl"]
4173 set prjProps [lreplace $prjProps $idx $idx]
4174 set idx [lsearch -exact $prjProps "nosynth"]
4175 set prjProps [lreplace $prjProps $idx $idx]
4176 set idx [lsearch -exact $prjProps "nosim"]
4177 set prjProps [lreplace $prjProps $idx $idx]
4178 lappend prjProps "source"
4182 foreach prjProp $prjProps {
4183 set idx [lsearch -exact $listProps $prjProp]
4184 set listProps [lreplace $listProps $idx $idx]
4186 MsgAndLog "Property $prjProp of $prjFile was set in project but not in list files" $severity $outFile
4191 foreach listProp $listProps {
4192 if {[string first $listProp "topsim="] == -1} {
4193 MsgAndLog "Property $listProp of $prjFile was found in list files but not set in project." $severity $outFile
4198 # Update project prjProps
4199 dict set out_prjprops $prjFile $prjProps
4202 # Loop over remaining files in list libraries
4203 foreach listFile $listFiles {
4204 MsgAndLog "$listFile was found in list files but not in project." $severity $outFile
4208 # Check extra files again...
4209 foreach prjFile $prjFiles {
4210 if { [dict exists $extra_files $prjFile] } {
4211 # File was generated at creation time, checking the md5sum
4212 # Removing the file from the prjFiles list
4213 set idx2 [lsearch -exact $prjFiles $prjFile]
4214 set prjFiles [lreplace $prjFiles $idx2 $idx2]
4215 set new_md5sum [Md5Sum $prjFile]
4216 set old_md5sum [DictGet $extra_files $prjFile]
4217 if {$new_md5sum != $old_md5sum} {
4218 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
4221 set extra_files [dict remove $extra_files $prjFile]
4223 # File is neither in list files nor in extra_files
4224 MsgAndLog "$prjFile was found in project but not in list files or .hog/extra.files" $severity $outFile
4229 # Update prjLibraries
4230 dict set out_prjlibs $prjLib $prjFiles
4233 MsgAndLog "Fileset $prjSet found in project but not in list files" $severity $outFile
4238 return [list $n_diffs $extra_files $out_prjlibs $out_prjprops]
4248 proc WriteSimListFiles {libs props simsets list_path repo_path } {
4250 foreach simset [dict keys $simsets] {
4251 set list_file_name $list_path/${simset}.sim
4252 set list_file [open $list_file_name w]
4253 Msg Info "Writing $list_file_name..."
4254 foreach lib [
DictGet $simsets $simset] {
4255 foreach file [
DictGet $libs $lib] {
4257 set prop [
DictGet $props $file]
4261 set lib_name [
file rootname $lib]
4262 if {$lib_name != $simset} {
4263 lappend prop "lib=$lib_name"
4265 puts $list_file "$file_path $prop"
4268 Msg Warning "The path of file $file is not relative to your repository. Please check!"
4283 proc WriteListFiles {libs props list_path repo_path {$ext_path ""} } {
4285 foreach lib [dict keys $libs] {
4286 if {[
llength [
DictGet $libs $lib]] > 0} {
4287 set list_file_name $list_path$lib
4288 set list_file [open $list_file_name w]
4289 Msg Info "Writing $list_file_name..."
4290 foreach file [
DictGet $libs $lib] {
4292 set prop [
DictGet $props $file]
4296 puts $list_file "$file_path $prop"
4299 set ext_list_file [open "[
file rootname $list_file].ext" a]
4300 puts $ext_list_file "$file_path $prop"
4301 close $ext_list_file
4304 Msg Warning "The path of file $file is not relative to your repository. Please check!"
4313 proc RemoveEmptyKeys {d} {
4315 foreach {k v} $newDict {
4316 if {$v == {{}} || $v == "" } {
4317 set newDict [dict remove $newDict $k]
4324 proc Logo { {repo_path .} } {
4325 if {[
info exists ::env(HOG_COLORED)] && [
string match "ENABLED" $::env(HOG_COLORED)]} {
4326 set logo_file "$repo_path/Hog/images/hog_logo_color.txt"
4328 set logo_file "$repo_path/Hog/images/hog_logo.txt"
4334 set ver [
Git {describe --always}]
4337 if {[
file exists $logo_file]} {
4338 set f [open $logo_file "r"]
4341 set lines [
split $data "\n"]
4347 Msg CriticalWarning "Logo file: $logo_file not found"
4350 Msg Status "Version: $ver"
4354 proc CheckLatestHogRelease {{repo_path .}} {
4357 set current_ver [
Git {describe --always}]
4358 Msg Debug "Current version: $current_ver"
4359 set current_sha [
Git "log $current_ver -1 --format=format:%H"]
4360 Msg Debug "Current SHA: $current_sha"
4363 if {[
OS] == "windows" } {
4364 Msg Info "On windows we cannot set a timeout on 'git fetch', hopefully nothing will go wrong..."
4367 Msg Info "Checking for latest Hog release, can take up to 5 seconds..."
4370 set master_ver [
Git "describe origin/master"]
4371 Msg Debug "Master version: $master_ver"
4372 set master_sha [
Git "log $master_ver -1 --format=format:%H"]
4373 Msg Debug "Master SHA: $master_sha"
4374 set merge_base [
Git "merge-base $current_sha $master_sha"]
4375 Msg Debug "merge base: $merge_base"
4378 if {$merge_base != $master_sha} {
4380 Msg Info "Version $master_ver has been released (https://gitlab.com/hog-cern/Hog/-/releases/$master_ver)"
4381 Msg Status "You should consider updating Hog submodule with the following instructions:"
4383 Msg Status "cd Hog && git checkout master && git pull"
4385 Msg Status "Also update the ref: in your .gitlab-ci.yml to $master_ver"
4390 Msg Info "Latest official version is $master_ver, nothing to do."
4399 proc GetOptions {argv parameters usage} {
4402 set param_list [list]
4403 set option_list [list]
4405 foreach p $parameters {
4406 lappend param_list [
lindex $p 0]
4410 while {$index < [
llength $argv]} {
4411 set arg [
lindex $argv $index]
4412 if {[
string first - $arg] == 0} {
4413 set option [
string trimleft $arg "-"]
4415 lappend option_list $arg
4416 if {[lsearch $param_list ${option}*] >= 0 && [
string first ".arg" [lsearch -inline $param_list ${option}*]] >= 0} {
4417 lappend option_list [
lindex $argv $index]
4421 lappend arg_list $arg
4425 Msg Debug "Argv: $argv"
4426 Msg Debug "Options: $option_list"
4427 Msg Debug "Arguments: $arg_list"
4428 return [list $option_list $arg_list]
4431 proc InitLauncher {script tcl_path parameters usage argv} {
4432 set repo_path [
file normalize "$tcl_path/../.."]
4434 set bin_path [
file normalize "$tcl_path/../../bin"]
4435 set top_path [
file normalize "$tcl_path/../../Top"]
4436 set commands_path [
file normalize "$tcl_path/../../hog-commands/"]
4443 if {[
catch {
package require cmdline} ERROR]} {
4444 Msg Debug "The cmdline Tcl package was not found, sourcing it from Hog..."
4445 source $tcl_path/utils/cmdline.tcl
4449 append usage "\n** Options:"
4451 lassign [
GetOptions $argv $parameters $usage] option_list arg_list
4458 if {[
catch {
array set options [
cmdline::getoptions option_list $parameters $usage]} err] } {
4459 Msg Status "\nERROR: Syntax error, probably unknown option.\n\n USAGE: $err"
4463 set directive [
string toupper [
lindex $arg_list 0]]
4465 if { [
llength $arg_list] == 1 && ($directive == "L" || $directive == "LIST")} {
4466 Msg Status "\n** The projects in this repository are:"
4471 }
elseif { [
llength $arg_list] == 0 || [
llength $arg_list] > 2} {
4472 Msg Status "\nERROR: Wrong number of arguments: [
llength $argv].\n\n"
4477 set project [
lindex $arg_list 1]
4479 regsub "^(\./)?Top/" $project "" project
4481 regsub "/? *\$" $project "" project
4484 Msg Debug "Option list:"
4485 foreach {key value} [
array get options] {
4486 Msg Debug "$key => $value"
4493 if {$proj_conf != 0} {
4496 lassign [
GetIDECommand $proj_conf] cmd before_tcl_script after_tcl_script end_marker
4497 Msg Info "Project $project uses $cmd IDE"
4500 set command "$cmd $before_tcl_script$script$after_tcl_script$argv$end_marker"
4503 if {$project != ""} {
4516 set project_group [
file dirname $project]
4517 set project [
file tail $project]
4518 if { $project_group != "." } {
4519 set project_name "$project_group/$project"
4521 set project_name "$project"
4526 return [list $directive $project $project_name $project_group $repo_path $old_path $bin_path $top_path $commands_path $command $cmd]
4532 proc GetCustomCommands {{directory .} {ret_commands 0}} {
4533 set commands_dict [dict create]
4534 set commands_files [glob -nocomplain $directory/*.tcl]
4535 set commands_string ""
4537 if {[
llength $commands_files] == 0} {
4541 if {$ret_commands == 0} {
4542 append commands_string "\n** Custom Commands:\n"
4545 foreach file $commands_files {
4546 set base_name [
string toupper [
file rootname [
file tail $file]]]
4547 if {$ret_commands == 1} {
4548 append commands_string "
4550 Msg Info \"Running custom script: $file\"
4552 Msg Info \"Done running custom script...\"
4557 append commands_string "- $base_name: runs $file \n"
4560 return $commands_string
4566 proc ListProjects {{repo_path .} {print 1} {ret_conf 0}} {
4567 set top_path [
file normalize $repo_path/Top]
4568 set confs [
findFiles [
file normalize $top_path] hog.conf]
4572 set p [
Relative $top_path [
file dirname $c]]
4580 if {$ret_conf == 0} {
4593 proc ProjectExists {project {repo_path .}} {
4594 set index [lsearch -exact [
ListProjects $repo_path 0] $project]
4605 proc GetIDECommand {proj_conf} {
4607 if {[
file exists $proj_conf]} {
4608 set ide_name_and_ver [
string tolower [
GetIDEFromConf $proj_conf]]
4609 set ide_name [
lindex [regexp -all -inline {\S+} $ide_name_and_ver] 0]
4611 if {$ide_name eq "vivado"} {
4612 set command "vivado"
4614 set before_tcl_script " -nojournal -nolog -mode batch -notrace -source "
4615 set after_tcl_script " -tclargs "
4618 }
elseif {$ide_name eq "planahead"} {
4619 set command "planAhead"
4621 set before_tcl_script " -nojournal -nolog -mode batch -notrace -source "
4622 set after_tcl_script " -tclargs "
4625 }
elseif {$ide_name eq "quartus"} {
4626 set command "quartus_sh"
4628 set before_tcl_script " -t "
4629 set after_tcl_script " "
4632 }
elseif {$ide_name eq "libero"} {
4635 set command "libero"
4636 set before_tcl_script "SCRIPT:"
4637 set after_tcl_script " SCRIPT_ARGS:\""
4640 Msg Error "IDE: $ide_name not known."
4644 Msg Error "Configuration file $proj_conf not found."
4647 return [list $command $before_tcl_script $after_tcl_script $end_marker]
4655 proc findFiles { basedir pattern } {
4659 set basedir [
string trimright [
file join [
file normalize $basedir] { }]]
4665 foreach fileName [glob -nocomplain -type {f r} -path $basedir $pattern] {
4666 lappend fileList $fileName
4670 foreach dirName [glob -nocomplain -type {d r} -path $basedir *] {
4673 set subDirList [
findFiles $dirName $pattern]
4674 if { [
llength $subDirList] > 0 } {
4675 foreach subDirFile $subDirList {
4676 lappend fileList $subDirFile
4684 proc IsInList {element list} {
4685 if {[lsearch -exact $list $element] >= 0} {
4693 proc IsCommitAncestor {ancestor commit} {
4694 lassign [
GitRet "merge-base --is-ancestor $ancestor $commit"] status result
4695 if {$status == 0 } {
4702 proc FindCommonGitChild {SHA1 SHA2} {
4704 set commits [
Git {log --oneline --merges}]
4707 foreach line [
split $commits "\n"] {
4708 set commit [
lindex [
split $line] 0]
4712 set ancestor $commit
4721 proc moveElementToEnd {inputList element} {
4722 set index [lsearch $inputList $element]
4724 set inputList [
lreplace $inputList $index $index]
4725 lappend inputList $element
4731 source [
file dirname [
info script]]/create_project.tcl