18 set CI_STAGES {"generate_project" "simulate_project"}
19 set CI_PROPS {"-synth_only"}
28 proc AddFile {file fileset} {
30 add_files -norecurse -fileset $fileset $file
40 proc AddHogFiles { libraries properties filesets } {
41 Msg Info "Adding source files to project..."
42 Msg Debug "Filesets: $filesets"
43 Msg Debug "Libraries: $libraries"
44 Msg Debug "Properties: $properties"
47 set synth_conf_command "organize_tool_files -tool {SYNTHESIZE} -input_type {constraint}"
49 set timing_conf_command "organize_tool_files -tool {VERIFYTIMING} -input_type {constraint}"
51 set place_conf_command "organize_tool_files -tool {PLACEROUTE} -input_type {constraint}"
55 foreach fileset [dict keys $filesets] {
56 Msg Debug "Fileset: $fileset"
59 if {[
string equal [get_filesets -quiet $fileset] ""]} {
61 create_fileset -simset $fileset
63 current_fileset -simset [ get_filesets $fileset]
64 set simulation [get_filesets $fileset]
66 set_property -name {$simulator.compile.vhdl_syntax} -value {2008} -objects $simulation
68 set_property SOURCE_SET sources_1 $simulation
72 set libs_in_fileset [
DictGet $filesets $fileset]
73 if { [
IsInList "ips.src" $libs_in_fileset] } {
78 foreach lib $libs_in_fileset {
79 Msg Debug "lib: $lib \n"
80 set lib_files [
DictGet $libraries $lib]
81 Msg Debug "Files in $lib: $lib_files"
82 set rootlib [
file rootname [
file tail $lib]]
83 set ext [
file extension $lib]
84 Msg Debug "lib: $lib ext: $ext fileset: $fileset"
87 Msg Debug "Adding $lib to $fileset"
88 add_files -norecurse -fileset $fileset $lib_files
90 foreach f $lib_files {
91 set file_obj [get_files -of_objects [get_filesets $fileset] [list "*$f"]]
93 if {[
file extension $f] == ".vhd" || [
file extension $f] == ".vhdl"} {
94 set_property -name "library" -value $rootlib -objects $file_obj
98 set props [
DictGet $properties $f]
99 if {[
file extension $f] == ".vhd" || [
file extension $f] == ".vhdl"} {
101 if {[lsearch -inline -regexp $props "93"] < 0} {
104 if {[lsearch -inline -regexp $props "2008"] >= 0} {
105 set vhdl_year "VHDL 2008"
106 }
elseif {[lsearch -inline -regexp $props "2019"] >= 0} {
108 set vhdl_year "VHDL 2019"
110 Msg CriticalWarning "VHDL 2019 is not supported in Vivado version older than 2023.2, using vhdl 2008, but this might not work."
111 set vhdl_year "VHDL 2008"
115 set vhdl_year "VHDL 2008"
117 Msg Debug "File type for $f is $vhdl_year"
118 set_property -name "file_type" -value $vhdl_year -objects $file_obj
121 Msg Debug "Filetype is VHDL 93 for $f"
126 if {[lsearch -inline -regexp $props "SystemVerilog"] > 0 } {
129 set_property -name "file_type" -value "SystemVerilog" -objects $file_obj
130 Msg Debug "Filetype is SystemVerilog for $f"
132 Msg Warning "Xilinx PlanAhead/ISE does not support SystemVerilog. Property not set for $f"
137 set top [
lindex [regexp -inline {\ytop\s*=\s*(.+?)\y.*} $props] 1]
139 Msg Info "Setting $top as top module for file set $fileset..."
140 set globalSettings::synth_top_module $top
145 if {[lsearch -inline -regexp $props "verilog_header"] >= 0} {
146 Msg Debug "Setting verilog header type for $f..."
147 set_property file_type {Verilog Header} [get_files $f]
148 }
elseif {[lsearch -inline -regexp $props "verilog_template"] >= 0} {
150 Msg Debug "Setting verilog template type for $f..."
151 set_property file_type {Verilog Template} [get_files $f]
152 }
elseif {[lsearch -inline -regexp $props "verilog"] >= 0} {
154 Msg Debug "Setting verilog type for $f..."
155 set_property file_type {Verilog} [get_files $f]
159 if {[lsearch -inline -regexp $props "nosynth"] >= 0} {
160 Msg Debug "Setting not used in synthesis for $f..."
161 set_property -name "used_in_synthesis" -value "false" -objects $file_obj
165 if {[lsearch -inline -regexp $props "noimpl"] >= 0} {
166 Msg Debug "Setting not used in implementation for $f..."
167 set_property -name "used_in_implementation" -value "false" -objects $file_obj
171 if {[lsearch -inline -regexp $props "nosim"] >= 0} {
172 Msg Debug "Setting not used in simulation for $f..."
173 set_property -name "used_in_simulation" -value "false" -objects $file_obj
178 set top_sim [
lindex [regexp -inline {\ytopsim\s*=\s*(.+?)\y.*} $props] 1]
179 if { $top_sim != "" } {
180 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"
184 set sim_runtime [
lindex [regexp -inline {\yruntime\s*=\s*(.+?)\y.*} $props] 1]
185 if { $sim_runtime != "" } {
186 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"
194 if {[lsearch -inline -regexp $props "wavefile"] >= 0} {
195 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]"
210 if {[lsearch -inline -regexp $props "dofile"] >= 0} {
211 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]"
224 if {[lsearch -inline -regexp $props "locked"] >= 0 && $ext == ".ip"} {
225 Msg Info "Locking IP $f..."
226 set_property IS_MANAGED 0 [get_files $f]
230 if {[
file extension $f] == ".bd"} {
231 Msg Info "Generating Target for [
file tail $f], please remember to commit the (possible) changed file."
232 generate_target all [get_files $f]
237 if {[
file extension $f] == ".tcl" && $ext != ".con"} {
238 if { [lsearch -inline -regexp $props "source"] >= 0} {
239 Msg Info "Sourcing Tcl script $f, and setting it not used in synthesis, implementation and simulation..."
241 set_property -name "used_in_synthesis" -value "false" -objects $file_obj
242 set_property -name "used_in_implementation" -value "false" -objects $file_obj
243 set_property -name "used_in_simulation" -value "false" -objects $file_obj
248 set ref [
lindex [regexp -inline {\yscoped_to_ref\s*=\s*(.+?)\y.*} $props] 1]
249 set cell [
lindex [regexp -inline {\yscoped_to_cells\s*=\s*(.+?)\y.*} $props] 1]
250 if {([
file extension $f] == ".tcl" || [
file extension $f] == ".xdc") && $ext == ".con"} {
252 set_property SCOPED_TO_REF $ref $file_obj
255 set_property SCOPED_TO_CELLS $cell $file_obj
260 Msg Info "[
llength $lib_files] file/s added to library $rootlib..."
263 if { $ext == ".sim"} {
264 Msg Warning "Simulation files not supported in Quartus Prime mode... Skipping $lib"
266 if {! [is_project_open] } {
267 Msg Error "Project is closed"
269 foreach cur_file $lib_files {
273 set props [
DictGet $properties $cur_file]
276 set top [
lindex [regexp -inline {\ytop\s*=\s*(.+?)\y.*} $props] 1]
278 Msg Info "Setting $top as top module for file set $fileset..."
279 set globalSettings::synth_top_module $top
282 if {[
string first "VHDL" $file_type] != -1 } {
283 if {[
string first "1987" $props] != -1 } {
284 set hdl_version "VHDL_1987"
285 }
elseif {[
string first "1993" $props] != -1 } {
286 set hdl_version "VHDL_1993"
287 }
elseif {[
string first "2008" $props] != -1 } {
288 set hdl_version "VHDL_2008"
290 set hdl_version "default"
292 if { $hdl_version == "default" } {
293 set_global_assignment -name $file_type $cur_file -library $rootlib
295 set_global_assignment -name $file_type $cur_file -hdl_version $hdl_version -library $rootlib
297 }
elseif {[
string first "SYSTEMVERILOG" $file_type] != -1 } {
299 if {[
string first "2005" $props] != -1 } {
300 set hdl_version "systemverilog_2005"
301 }
elseif {[
string first "2009" $props] != -1 } {
302 set hdl_version "systemverilog_2009"
304 set hdl_version "default"
306 if { $hdl_version == "default" } {
307 set_global_assignment -name $file_type $cur_file
309 set_global_assignment -name $file_type $cur_file -hdl_version $hdl_version
311 }
elseif {[
string first "VERILOG" $file_type] != -1 } {
313 if {[
string first "1995" $props] != -1 } {
314 set hdl_version "verilog_1995"
315 }
elseif {[
string first "2001" $props] != -1 } {
316 set hdl_version "verilog_2001"
318 set hdl_version "default"
320 if { $hdl_version == "default" } {
321 set_global_assignment -name $file_type $cur_file
323 set_global_assignment -name $file_type $cur_file -hdl_version $hdl_version
325 }
elseif {[
string first "SOURCE" $file_type] != -1 || [
string first "COMMAND_MACRO" $file_type] != -1 } {
326 set_global_assignment -name $file_type $cur_file
327 if { $ext == ".con"} {
329 }
elseif { $ext == ".src"} {
331 if {[
string first "qsys" $props] != -1 } {
334 regsub -all {\{||qsys||\}} $props $emptyString props
336 set qsysPath [
file dirname $cur_file]
337 set qsysName "[
file rootname [
file tail $cur_file]].qsys"
338 set qsysFile "$qsysPath/$qsysName"
339 set qsysLogFile "$qsysPath/[
file rootname [
file tail $cur_file]].qsys-script.log"
342 if {! [
info exists ::env(QSYS_ROOTDIR)] } {
343 if {[
info exists ::env(QUARTUS_ROOTDIR)] } {
344 set qsys_rootdir "$::env(QUARTUS_ROOTDIR)/sopc_builder/bin"
345 Msg Warning "The QSYS_ROOTDIR environment variable is not set! I will use $qsys_rootdir"
347 Msg CriticalWarning "The QUARTUS_ROOTDIR environment variable is not set! Assuming all quartus executables are contained in your PATH!"
350 set qsys_rootdir $::env(QSYS_ROOTDIR)
353 set cmd "$qsys_rootdir/qsys-script"
354 set cmd_options " --script=$cur_file"
355 if {![
catch {"exec $cmd -version"}] || [
lindex $::errorCode 0] eq "NONE"} {
356 Msg Info "Executing: $cmd $cmd_options"
357 Msg Info "Saving logfile in: $qsysLogFile"
358 if { [
catch {
eval exec -ignorestderr "$cmd $cmd_options >>& $qsysLogFile"} ret opt]} {
359 set makeRet [
lindex [dict get $opt -errorcode] end]
360 Msg CriticalWarning "$cmd returned with $makeRet"
363 Msg Error " Could not execute command $cmd"
367 if { [
file exists $qsysName] != 0} {
368 file rename -force $qsysName $qsysFile
370 set qsysMd5Sum [
Md5Sum $qsysFile]
372 set fileDir [
file normalize "./hogTmp"]
373 set fileName "$fileDir/.hogQsys.md5"
374 if {![
file exists $fileDir]} {
377 set hogQsysFile [open $fileName "a"]
378 set fileEntry "$qsysFile\t$qsysMd5Sum"
379 puts $hogQsysFile $fileEntry
382 Msg ERROR "Error while moving the generated qsys file to final location: $qsysName not found!"
384 if { [
file exists $qsysFile] != 0} {
385 if {[
string first "noadd" $props] == -1} {
387 set_global_assignment -name $qsysFileType $qsysFile
389 regsub -all {noadd} $props $emptyString props
391 if {[
string first "nogenerate" $props] == -1} {
396 Msg ERROR "Error while generating ip variations from qsys: $qsysFile not found!"
400 }
elseif { [
string first "QSYS" $file_type] != -1 } {
402 regsub -all {\{||\}} $props $emptyString props
403 if {[
string first "noadd" $props] == -1} {
404 set_global_assignment -name $file_type $cur_file
406 regsub -all {noadd} $props $emptyString props
410 if {[
string first "nogenerate" $props] == -1} {
414 set_global_assignment -name $file_type $cur_file -library $rootlib
419 if {$ext == ".con"} {
420 set vld_exts {.sdc .pin .dcf .gcf .pdc .ndc .fdc .crt .vcd }
421 foreach con_file $lib_files {
423 set con_ext [
file extension $con_file]
424 if {[
IsInList [
file extension $con_file] $vld_exts]} {
425 set option [
string map {. -} $con_ext]
426 set option [
string map {fdc net_fdc} $option]
427 set option [
string map {pdc io_pdc} $option]
428 create_links -convert_EDN_to_HDL 0 -library {work} $option $con_file
430 set props [
DictGet $properties $con_file]
432 if {$con_ext == ".sdc"} {
433 if { [lsearch $props "notiming"] >= 0 } {
434 Msg Info "Excluding $con_file from timing verification..."
436 Msg Info "Adding $con_file to time verification"
437 append timing_conf_command " -file $con_file"
441 if { [lsearch $props "nosynth"] >= 0 } {
442 Msg Info "Excluding $con_file from synthesis..."
444 Msg Info "Adding $con_file to synthesis"
445 append synth_conf_command " -file $con_file"
450 if {$con_ext == ".pdc" || $con_ext == ".sdc"} {
451 if { [lsearch $props "noplace"] >= 0 } {
452 Msg Info "Excluding $con_file from place and route..."
454 Msg Info "Adding $con_file to place and route"
455 append place_conf_command " -file $con_file"
461 Msg CriticalWarning "Constraint file $con_file does not have a valid extension. Allowed extensions are: \n $vld_exts"
464 }
elseif {$ext == ".src"} {
465 foreach f $lib_files {
466 Msg Debug "Adding source $f to library $rootlib..."
467 create_links -library $rootlib -hdl_source $f
469 }
elseif {$ext == ".sim"} {
470 Msg Debug "Adding stimulus file $f to library..."
471 create_links -library $rootlib -stimulus $f
473 build_design_hierarchy
474 foreach cur_file $lib_files {
478 set props [
DictGet $properties $cur_file]
481 set top [
lindex [regexp -inline {\ytop\s*=\s*(.+?)\y.*} $props] 1]
483 Msg Info "Setting $top as top module for file set $rootlib..."
484 set globalSettings::synth_top_module "${top}::$rootlib"
489 if {$ext == ".src" || $ext == ".con" || $ext == ".ext"} {
490 foreach f $lib_files {
491 Msg Debug "Diamond: adding source file $f to library $rootlib..."
492 prj_src add -work $rootlib $f
493 set props [
DictGet $properties $f]
495 set top [
lindex [regexp -inline {\ytop\s*=\s*(.+?)\y.*} $props] 1]
497 Msg Info "Setting $top as top module for the project..."
498 set globalSettings::synth_top_module $top
502 if {[lsearch -inline -regexp $props "enable"] >= 0} {
503 Msg Debug "Setting $f as active Logic Preference file"
508 }
elseif {$ext == ".sim"} {
509 foreach f $lib_files {
510 Msg Debug "Diamond Adding simulation file $f to library $rootlib..."
511 prj_src add -work $rootlib -simulate_only $f
523 if {[
DictGet $filesets "sim_1"] == ""} {
524 delete_fileset -quiet [get_filesets -quiet "sim_1"]
530 if {$synth_conf == 1} {
531 Msg Info $synth_conf_command
532 eval $synth_conf_command
534 if {$timing_conf == 1} {
535 Msg Info $timing_conf_command
536 eval $timing_conf_command
538 if {$place_conf == 1} {
539 Msg Info $place_conf_command
540 eval $place_conf_command
546 proc ALLOWED_PROPS {} {
547 return [dict create ".vhd" [list "93" "nosynth" "noimpl" "nosim" "1987" "1993" "2008" "2019"]\
548 ".vhdl" [list "93" "nosynth" "noimpl" "nosim" "1987" "1993" "2008" "2019"]\
549 ".v" [list "SystemVerilog" "verilog_header" "nosynth" "noimpl" "nosim" "1995" "2001"]\
550 ".sv" [list "verilog" "verilog_header" "nosynth" "noimpl" "nosim" "2005" "2009"]\
551 ".do" [list "nosim"]\
552 ".udo" [list "nosim"]\
553 ".xci" [list "nosynth" "noimpl" "nosim" "locked"]\
554 ".xdc" [list "nosynth" "noimpl"]\
555 ".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"]\
556 ".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"]\
557 ".sdc" [list "notiming" "nosynth" "noplace"]\
558 ".elf" [list "scoped_to_ref" "scoped_to_cells" "nosim" "noimpl"]\
559 ".pdc" [list "nosynth" "noplace"] \
560 ".lpf" [list "enable"]
572 proc BinaryStepName {part} {
574 return "WRITE_DEVICE_IMAGE"
578 return "WRITE_BITSTREAM"
587 proc CheckSyntax { project_name repo_path {project_file ""}} {
589 set syntax [check_syntax -return_string]
590 if {[
string first "CRITICAL" $syntax] != -1} {
595 lassign [
GetHogFiles -list_files "*.src" "$repo_path/Top/$project_name/list/" $repo_path] src_files dummy
596 dict for {lib files} $src_files {
598 set file_extension [file extension $f]
599 if { $file_extension == ".vhd" || $file_extension == ".vhdl" || $file_extension == ".v" || $file_extension == ".sv" } {
600 if { [catch {execute_module -tool map -args "--analyze_file=$f"} result]} {
601 Msg Error "\nResult: $result\n"
602 Msg Error "Check syntax failed.\n"
604 if { $result == "" } {
605 Msg Info "Check syntax was successful for $f.\n"
607 Msg Warning "Found syntax error in file $f:\n $result\n"
614 lassign [
GetProjectFiles $project_file] prjLibraries prjProperties prjSimLibraries prjConstraints prjSrcSets prjSimSets prjConSets
615 dict for {lib sources} $prjLibraries {
616 if {[file extension $lib] == ".src"} {
618 Msg Info "Checking Syntax of $f"
624 Msg Info "The Checking Syntax is not supported by this IDE. Skipping..."
629 proc CloseProject {} {
651 proc CompareVersions {ver1 ver2} {
660 if {[regexp {v(\d+)\.(\d+)\.(\d+)} $ver1 - x y z]} {
661 set ver1 [list $x $y $z]
663 if {[regexp {v(\d+)\.(\d+)\.(\d+)} $ver2 - x y z]} {
664 set ver2 [list $x $y $z]
668 set v1 [
join $ver1 ""]
670 set v2 [
join $ver2 ""]
673 if {[
string is integer $v1] && [
string is integer $v2]} {
675 set ver1 [
expr {[scan [lindex $ver1 0] %d]*1000000 + [scan [lindex $ver1 1] %d]*1000 + [scan [lindex $ver1 2] %d]}]
676 set ver2 [
expr {[scan [lindex $ver2 0] %d]*1000000 + [scan [lindex $ver2 1] %d]*1000 + [scan [lindex $ver2 2] %d]}]
678 if {$ver1 > $ver2 } {
680 }
elseif {$ver1 == $ver2} {
687 Msg Warning "Version is not numeric: $ver1, $ver2"
697 proc CheckExtraFiles {libraries} {
700 lassign [
GetProjectFiles] prjLibraries prjProperties prjSimLibraries prjConstraints
701 set prjLibraries [
MergeDict $prjLibraries $prjSimLibraries]
702 set prjLibraries [
MergeDict $prjLibraries $prjConstraints]
703 set prj_dir [get_property DIRECTORY [current_project]]
704 file mkdir "$prj_dir/.hog"
705 set extra_file_name "$prj_dir/.hog/extra.files"
706 set new_extra_file [open $extra_file_name "w"]
708 dict for {prjLib prjFiles} $prjLibraries {
709 foreach prjFile $prjFiles {
710 if {[file extension $prjFile] == ".xcix"} {
711 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."
714 if {[file extension $prjFile] == ".xci" && [get_property CORE_CONTAINER [get_files $prjFile]] != ""} {
715 Msg Info "$prjFile is a virtual IP file in a core container. Ignoring it..."
719 if {[IsInList $prjFile [DictGet $libraries $prjLib]]==0} {
720 if { [file extension $prjFile] == ".bd"} {
721 # Generating BD products to save md5sum of already modified BD
722 Msg Info "Generating targets of $prjFile..."
723 generate_target all [get_files $prjFile]
725 puts $new_extra_file "$prjFile [Md5Sum $prjFile]"
726 Msg Info "$prjFile (lib: $prjLib) has been generated by an external script. Adding to $extra_file_name..."
730 close $new_extra_file
737 proc CheckLatestHogRelease {{repo_path .}} {
740 set current_ver [
Git {describe --always}]
741 Msg Debug "Current version: $current_ver"
742 set current_sha [
Git "log $current_ver -1 --format=format:%H"]
743 Msg Debug "Current SHA: $current_sha"
746 if {[
OS] == "windows" } {
747 Msg Info "On windows we cannot set a timeout on 'git fetch', hopefully nothing will go wrong..."
750 Msg Info "Checking for latest Hog release, can take up to 5 seconds..."
753 set master_ver [
Git "describe origin/master"]
754 Msg Debug "Master version: $master_ver"
755 set master_sha [
Git "log $master_ver -1 --format=format:%H"]
756 Msg Debug "Master SHA: $master_sha"
757 set merge_base [
Git "merge-base $current_sha $master_sha"]
758 Msg Debug "merge base: $merge_base"
761 if {$merge_base != $master_sha} {
763 Msg Info "Version $master_ver has been released (https://gitlab.com/hog-cern/Hog/-/releases/$master_ver)"
764 Msg Status "You should consider updating Hog submodule with the following instructions:"
766 Msg Status "cd Hog && git checkout master && git pull"
768 Msg Status "Also update the ref: in your .gitlab-ci.yml to $master_ver"
773 Msg Info "Latest official version is $master_ver, nothing to do."
786 proc CheckYmlRef {repo_path allow_failure} {
788 if {$allow_failure} {
789 set MSG_TYPE CriticalWarning
794 if { [
catch {
package require yaml 0.3.3} YAMLPACKAGE]} {
795 Msg CriticalWarning "Cannot find package YAML, skipping consistency check of \"ref\" in gilab-ci.yaml file.\n Error message: $YAMLPACKAGE
796 You can fix this by installing package \"tcllib\""
804 if {[
file exists .gitlab-ci.yml]} {
808 if { [
file exists .gitlab-ci.yml] } {
809 set fp [open ".gitlab-ci.yml" r]
810 set file_data [read $fp]
813 Msg $MSG_TYPE "Cannot open file .gitlab-ci.yml"
817 set file_data "\n$file_data\n\n"
819 if { [
catch {::yaml::yaml2dict -stream $file_data} yamlDict]} {
820 Msg $MSG_TYPE "Parsing $repo_path/.gitlab-ci.yml failed. To fix this, check that yaml syntax is respected, remember not to use tabs."
824 dict for {dictKey dictValue} $yamlDict {
825 #looking for Hog include in .gitlab-ci.yml
826 if {"$dictKey" == "include" && ([lsearch [split $dictValue " {}"] "/hog.yml" ] != "-1" || [lsearch [split $dictValue " {}"] "/hog-dynamic.yml" ] != "-1")} {
827 set YML_REF [lindex [split $dictValue " {}"] [expr {[lsearch -dictionary [split $dictValue " {}"] "ref"]+1} ] ]
828 set YML_NAME [lindex [split $dictValue " {}"] [expr {[lsearch -dictionary [split $dictValue " {}"] "file"]+1} ] ]
832 if {$YML_REF == ""} {
833 Msg Warning "Hog version not specified in the .gitlab-ci.yml. Assuming that master branch is used."
835 set YML_REF_F [
Git {name-rev --tags --name-only origin/master}]
838 set YML_REF_F [regsub -all "'" $YML_REF ""]
841 if {$YML_NAME == ""} {
842 Msg $MSG_TYPE "Hog included yml file not specified, assuming hog.yml"
843 set YML_NAME_F hog.yml
845 set YML_NAME_F [regsub -all "^/" $YML_NAME ""]
848 lappend YML_FILES $YML_NAME_F
854 if { [
catch {::yaml::yaml2dict -file $YML_NAME_F} yamlDict]} {
855 Msg $MSG_TYPE "Parsing $YML_NAME_F failed."
859 dict for {dictKey dictValue} $yamlDict {
860 #looking for included files
861 if {"$dictKey" == "include"} {
862 foreach v $dictValue {
863 lappend YML_FILES [lindex [split $v " "] [expr {[lsearch -dictionary [split $v " "] "local"]+1} ] ]
869 Msg Info "Found the following yml files: $YML_FILES"
871 set HOGYML_SHA [
GetSHA $YML_FILES]
872 lassign [
GitRet "log --format=%h -1 --abbrev=7 $YML_REF_F" $YML_FILES] ret EXPECTEDYML_SHA
874 lassign [
GitRet "log --format=%h -1 --abbrev=7 origin/$YML_REF_F" $YML_FILES] ret EXPECTEDYML_SHA
876 Msg $MSG_TYPE "Error in project .gitlab-ci.yml. ref: $YML_REF not found"
877 set EXPECTEDYML_SHA ""
880 if {!($EXPECTEDYML_SHA eq "")} {
881 if {$HOGYML_SHA == $EXPECTEDYML_SHA} {
882 Msg Info "Hog included file $YML_FILES matches with $YML_REF in .gitlab-ci.yml."
885 Msg $MSG_TYPE "HOG $YML_FILES SHA mismatch.
886 From Hog submodule: $HOGYML_SHA
887 From ref in .gitlab-ci.yml: $EXPECTEDYML_SHA
888 You can fix this in 2 ways: by changing the ref in your repository or by changing the Hog submodule commit"
891 Msg $MSG_TYPE "One or more of the following files could not be found $YML_FILES in Hog at $YML_REF"
894 Msg Info ".gitlab-ci.yml not found in $repo_path. Skipping this step"
916 proc CompareLibDicts {proj_libs list_libs proj_sets list_sets proj_props list_props {severity "CriticalWarning"} {outFile ""} {extraFiles ""} } {
917 set extra_files $extraFiles
919 set out_prjlibs $proj_libs
920 set out_prjprops $proj_props
922 dict for {prjSet prjLibraries} $proj_sets {
923 # Check if sets is also in list files
924 if {[IsInList $prjSet $list_sets]} {
925 set listLibraries [DictGet $list_sets $prjSet]
926 # Loop over libraries in fileset
927 foreach prjLib $prjLibraries {
928 set prjFiles [DictGet $proj_libs $prjLib]
929 # Check if library exists in list files
930 if {[IsInList $prjLib $listLibraries]} {
931 # Loop over files in library
932 set listFiles [DictGet $list_libs $prjLib]
933 foreach prjFile $prjFiles {
934 set idx [lsearch -exact $listFiles $prjFile]
935 set listFiles [lreplace $listFiles $idx $idx]
937 # File is in project but not in list libraries, check if it was generated at creation time...
938 if { [dict exists $extra_files $prjFile] } {
939 # File was generated at creation time, checking the md5sum
940 # Removing the file from the prjFiles list
941 set idx2 [lsearch -exact $prjFiles $prjFile]
942 set prjFiles [lreplace $prjFiles $idx2 $idx2]
943 set new_md5sum [Md5Sum $prjFile]
944 set old_md5sum [DictGet $extra_files $prjFile]
945 if {$new_md5sum != $old_md5sum} {
946 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
949 set extra_files [dict remove $extra_files $prjFile]
951 # File is neither in list files nor in extra_files
952 MsgAndLog "$prjFile was found in project but not in list files or .hog/extra.files" $severity $outFile
956 # File is both in list files and project, checking properties...
957 set prjProps [DictGet $proj_props $prjFile]
958 set listProps [DictGet $list_props $prjFile]
959 # Check if it is a potential sourced file
960 if {[IsInList "nosynth" $prjProps] && [IsInList "noimpl" $prjProps] && [IsInList "nosim" $prjProps]} {
961 # Check if it is sourced
962 set idx_source [lsearch -exact $listProps "source"]
963 if {$idx_source >= 0 } {
964 # It is sourced, let's replace the individual properties with source
965 set idx [lsearch -exact $prjProps "noimpl"]
966 set prjProps [lreplace $prjProps $idx $idx]
967 set idx [lsearch -exact $prjProps "nosynth"]
968 set prjProps [lreplace $prjProps $idx $idx]
969 set idx [lsearch -exact $prjProps "nosim"]
970 set prjProps [lreplace $prjProps $idx $idx]
971 lappend prjProps "source"
975 foreach prjProp $prjProps {
976 set idx [lsearch -exact $listProps $prjProp]
977 set listProps [lreplace $listProps $idx $idx]
979 MsgAndLog "Property $prjProp of $prjFile was set in project but not in list files" $severity $outFile
984 foreach listProp $listProps {
985 if {[string first $listProp "topsim="] == -1 && [string first $listProp "enable"] == -1} {
986 MsgAndLog "Property $listProp of $prjFile was found in list files but not set in project." $severity $outFile
991 # Update project prjProps
992 dict set out_prjprops $prjFile $prjProps
995 # Loop over remaining files in list libraries
996 foreach listFile $listFiles {
997 MsgAndLog "$listFile was found in list files but not in project." $severity $outFile
1001 # Check extra files again...
1002 foreach prjFile $prjFiles {
1003 if { [dict exists $extra_files $prjFile] } {
1004 # File was generated at creation time, checking the md5sum
1005 # Removing the file from the prjFiles list
1006 set idx2 [lsearch -exact $prjFiles $prjFile]
1007 set prjFiles [lreplace $prjFiles $idx2 $idx2]
1008 set new_md5sum [Md5Sum $prjFile]
1009 set old_md5sum [DictGet $extra_files $prjFile]
1010 if {$new_md5sum != $old_md5sum} {
1011 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
1014 set extra_files [dict remove $extra_files $prjFile]
1016 # File is neither in list files nor in extra_files
1017 MsgAndLog "$prjFile was found in project but not in list files or .hog/extra.files" $severity $outFile
1022 # Update prjLibraries
1023 dict set out_prjlibs $prjLib $prjFiles
1026 MsgAndLog "Fileset $prjSet found in project but not in list files" $severity $outFile
1031 return [list $n_diffs $extra_files $out_prjlibs $out_prjprops]
1041 proc CompareVHDL {file1 file2} {
1042 set a [open $file1 r]
1043 set b [open $file2 r]
1045 while {[
gets $a line] != -1} {
1046 set line [regsub {^[\t\s]*(.*)?\s*} $line "\\1"]
1047 if {![regexp {^$} $line] & ![regexp {^--} $line] } {
1053 while {[
gets $b line] != -1} {
1054 set line [regsub {^[\t\s]*(.*)?\s*} $line "\\1"]
1055 if {![regexp {^$} $line] & ![regexp {^--} $line] } {
1064 foreach x $f1 y $f2 {
1066 lappend diff "> $x\n< $y\n\n"
1079 proc Copy {i_dirs o_dir} {
1080 foreach i_dir $i_dirs {
1081 if {[
file isdirectory $i_dir] && [
file isdirectory $o_dir]} {
1082 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]])} {
1083 file delete -force $o_dir/[
file tail $i_dir]
1087 file copy -force $i_dir $o_dir
1102 proc CopyIPbusXMLs {proj_dir path dst {xml_version "0.0.0"} {xml_sha "00000000"} {use_ipbus_sw 0} {generate 0} } {
1103 if {$use_ipbus_sw == 1} {
1104 lassign [
ExecuteRet python -c "from __future__ import print_function; from sys import path;print(':'.join(path\[1:\]))"] ret msg
1106 set ::env(PYTHONPATH) $msg
1107 lassign [
ExecuteRet gen_ipbus_addr_decode -h] ret msg
1114 Msg CriticalWarning "Problem while trying to run python: $msg"
1117 set dst [
file normalize $dst]
1118 if {$can_generate == 0} {
1119 if {$generate == 1} {
1120 Msg Error "Cannot generate IPbus address files, IPbus executable gen_ipbus_addr_decode not found or not working: $msg"
1124 Msg Warning "IPbus executable gen_ipbus_addr_decode not found or not working, will not verify IPbus address tables."
1131 set ipb_files [glob -nocomplain $proj_dir/list/*.ipb]
1132 set n_ipb_files [
llength $ipb_files]
1133 if {$n_ipb_files == 0} {
1134 Msg CriticalWarning "No files with .ipb extension found in $proj_dir/list."
1137 set libraries [dict create]
1138 set vhdl_dict [dict create]
1140 foreach ipb_file $ipb_files {
1146 set xmlfiles [dict get $libraries "xml.ipb"]
1149 set xml_list_error 0
1150 foreach xmlfile $xmlfiles {
1152 if {[
file isdirectory $xmlfile]} {
1153 Msg CriticalWarning "Directory $xmlfile listed in xml list file $list_file. Directories are not supported!"
1154 set xml_list_error 1
1157 if {[
file exists $xmlfile]} {
1158 if {[dict exists $vhdl_dict $xmlfile]} {
1159 set vhdl_file [
file normalize [dict get $vhdl_dict $xmlfile]]
1163 lappend vhdls $vhdl_file
1165 set xmlfile [
file normalize $xmlfile]
1166 Msg Info "Copying $xmlfile to $dst and replacing place holders..."
1167 set in [open $xmlfile r]
1168 set out [open $dst/[
file tail $xmlfile] w]
1170 while {[
gets $in line] != -1} {
1171 set new_line [regsub {(.*)__VERSION__(.*)} $line "\\1$xml_version\\2"]
1172 set new_line2 [regsub {(.*)__GIT_SHA__(.*)} $new_line "\\1$xml_sha\\2"]
1173 puts $out $new_line2
1177 lappend xmls [
file tail $xmlfile]
1179 Msg Warning "XML file $xmlfile not found"
1182 if {${xml_list_error}} {
1183 Msg Error "Invalid files added to $list_file!"
1186 set cnt [
llength $xmls]
1187 Msg Info "$cnt xml file/s copied"
1190 if {$can_generate == 1} {
1193 file mkdir "address_decode"
1196 foreach x $xmls v $vhdls {
1198 set x [
file normalize ../$x]
1199 if {[
file exists $x]} {
1200 lassign [
ExecuteRet gen_ipbus_addr_decode $x 2>&1] status log
1202 set generated_vhdl ./ipbus_decode_[
file rootname [
file tail $x]].vhd
1203 if {$generate == 1} {
1204 Msg Info "Copying generated VHDL file $generated_vhdl into $v (replacing if necessary)"
1205 file copy -force -- $generated_vhdl $v
1207 if {[
file exists $v]} {
1209 set n [
llength $diff]
1211 Msg CriticalWarning "$v does not correspond to its XML $x, [
expr {$n/3}] line/s differ:"
1212 Msg Status [
join $diff "\n"]
1213 set diff_file [open ../diff_[
file rootname [
file tail $x]].txt w]
1214 puts $diff_file $diff
1217 Msg Info "[
file tail $x] and $v match."
1220 Msg Warning "VHDL address map file $v not found."
1224 Msg Warning "Address map generation failed for [
file tail $x]: $log"
1227 Msg Warning "Copied XML file $x not found."
1230 Msg Info "Skipped verification of [
file tail $x] as no VHDL file was specified."
1234 file delete -force address_decode
1246 proc DescriptionFromConf {conf_file} {
1247 set f [open $conf_file "r"]
1248 set lines [
split [read $f] "\n"]
1250 set second_line [
lindex $lines 1]
1253 if {![regexp {\#+ *(.+)} $second_line - description]} {
1257 if {[regexp -all {test|Test|TEST} $description]} {
1258 set description "test"
1271 proc DictGet {dictName keyName {default ""}} {
1272 if {[dict exists $dictName $keyName]} {
1273 return [dict get $dictName $keyName]
1284 proc DoxygenVersion {target_version} {
1285 set ver [
split $target_version "."]
1286 set v [
Execute doxygen --version]
1287 Msg Info "Found Doxygen version: $v"
1288 set current_ver [
split $v ". "]
1289 set target [
expr {[lindex $ver 0]*100000 + [lindex $ver 1]*100 + [lindex $ver 2]}]
1290 set current [
expr {[lindex $current_ver 0]*100000 + [lindex $current_ver 1]*100 + [lindex $current_ver 2]}]
1292 return [
expr {$target <= $current}]
1303 proc eos {command {attempt 1}} {
1305 if {![
info exists env(EOS_MGM_URL)]} {
1306 Msg Warning "Environment variable EOS_MGM_URL not set, setting it to default value root://eosuser.cern.ch"
1307 set ::env(EOS_MGM_URL) "root://eosuser.cern.ch"
1310 Msg Warning "The value of attempt should be 1 or more, not $attempt, setting it to 1 as default"
1313 for {
set i 0} {$i < $attempt} {
incr i} {
1314 set ret [
catch {
exec -ignorestderr eos {*}$command} result]
1319 set wait [
expr {1+int(rand()*29)}]
1320 Msg Warning "Command $command failed ($i/$attempt): $result, trying again in $wait seconds..."
1321 after [
expr {$wait*1000}]
1325 return [list $ret $result]
1335 proc Execute {args} {
1339 Msg Error "Command [
join $args] returned error code: $ret"
1353 proc ExecuteRet {args} {
1355 if {[
llength $args] == 0} {
1356 Msg CriticalWarning "No argument given"
1360 set ret [
catch {
exec -ignorestderr {*}$args} result]
1363 return [list $ret $result]
1372 proc ExtractVersionFromTag {tag} {
1373 if {[regexp {^(?:b(\d+))?v(\d+)\.(\d+).(\d+)(?:-\d+)?$} $tag -> mr M m p]} {
1378 Msg Warning "Repository tag $tag is not in a Hog-compatible format."
1384 return [list $M $m $p $mr]
1394 proc FileCommitted {File } {
1396 set currentDir [
pwd]
1397 cd [
file dirname [
file normalize $File]]
1398 set GitLog [
Git ls-files [
file tail $File]]
1399 if {$GitLog == ""} {
1400 Msg CriticalWarning "File [
file normalize $File] is not in the git repository. Please add it with:\n git add [
file normalize $File]\n"
1411 proc FindCommonGitChild {SHA1 SHA2} {
1413 set commits [
Git {log --oneline --merges}]
1416 foreach line [
split $commits "\n"] {
1417 set commit [
lindex [
split $line] 0]
1421 set ancestor $commit
1434 proc findFiles { basedir pattern } {
1438 set basedir [
string trimright [
file join [
file normalize $basedir] { }]]
1444 foreach fileName [glob -nocomplain -type {f r} -path $basedir $pattern] {
1445 lappend fileList $fileName
1449 foreach dirName [glob -nocomplain -type {d r} -path $basedir *] {
1452 set subDirList [
findFiles $dirName $pattern]
1453 if { [
llength $subDirList] > 0 } {
1454 foreach subDirFile $subDirList {
1455 lappend fileList $subDirFile
1466 proc FindFileType {file_name} {
1467 set extension [
file extension $file_name]
1470 set file_extension "USE_SIGNALTAP_FILE"
1473 set file_extension "VHDL_FILE"
1476 set file_extension "VHDL_FILE"
1479 set file_extension "VERILOG_FILE"
1482 set file_extension "SYSTEMVERILOG_FILE"
1485 set file_extension "SDC_FILE"
1488 set file_extension "PDC_FILE"
1491 set file_extension "NDC_FILE"
1494 set file_extension "FDC_FILE"
1497 set file_extension "SOURCE_FILE"
1500 set file_extension "IP_FILE"
1503 set file_extension "QSYS_FILE"
1506 set file_extension "QIP_FILE"
1509 set file_extension "SIP_FILE"
1512 set file_extension "BSF_FILE"
1515 set file_extension "BDF_FILE"
1518 set file_extension "COMMAND_MACRO_FILE"
1521 set file_extension "VQM_FILE"
1524 set file_extension "ERROR"
1525 Msg Error "Unknown file extension $extension"
1528 return $file_extension
1535 proc FindNewestVersion { versions } {
1536 set new_ver 00000000
1537 foreach ver $versions {
1539 if {[
expr 0x$ver > 0x$new_ver] } {
1551 proc FindVhdlVersion {file_name} {
1552 set extension [
file extension $file_name]
1555 set vhdl_version "-hdl_version VHDL_2008"
1558 set vhdl_version "-hdl_version VHDL_2008"
1565 return $vhdl_version
1572 proc FormatGeneric {generic} {
1573 if {[
string is integer "0x$generic"]} {
1574 return [
format "32'h%08X" "0x$generic"]
1577 return [
format "32'h%08X" 0]
1587 proc GenerateBitstream { {run_folder ""} {repo_path .} {njobs 1} } {
1588 Msg Info "Starting write bitstream flow..."
1590 set revision [get_current_revision]
1591 if {[
catch {execute_module -tool asm} result]} {
1592 Msg Error "Result: $result\n"
1593 Msg Error "Generate bitstream failed. See the report file.\n"
1595 Msg Info "Generate bitstream was successful for revision $revision.\n"
1598 Msg Info "Run GENERATEPROGRAMMINGDATA ..."
1599 if {[
catch {run_tool -name {GENERATEPROGRAMMINGDATA}}] } {
1600 Msg Error "GENERATEPROGRAMMINGDATA FAILED!"
1602 Msg Info "GENERATEPROGRAMMINGDATA PASSED."
1604 Msg Info "Sourcing Hog/Tcl/integrated/post-bitstream.tcl"
1605 source $repo_path/Hog/Tcl/integrated/post-bitstream.tcl
1607 prj_run Export -impl Implementation0 -task Bitgen
1617 proc GenerateQsysSystem {qsysFile commandOpts} {
1618 if { [
file exists $qsysFile] != 0} {
1619 set qsysPath [
file dirname $qsysFile]
1620 set qsysName [
file rootname [
file tail $qsysFile]]
1621 set qsysIPDir "$qsysPath/$qsysName"
1622 set qsysLogFile "$qsysPath/$qsysName.qsys-generate.log"
1625 if {! [
info exists ::env(QSYS_ROOTDIR)] } {
1626 if {[
info exists ::env(QUARTUS_ROOTDIR)] } {
1627 set qsys_rootdir "$::env(QUARTUS_ROOTDIR)/sopc_builder/bin"
1628 Msg Warning "The QSYS_ROOTDIR environment variable is not set! I will use $qsys_rootdir"
1630 Msg CriticalWarning "The QUARTUS_ROOTDIR environment variable is not set! Assuming all quartus executables are contained in your PATH!"
1633 set qsys_rootdir $::env(QSYS_ROOTDIR)
1636 set cmd "$qsys_rootdir/qsys-generate"
1637 set cmd_options "$qsysFile --output-directory=$qsysIPDir $commandOpts"
1638 if {![
catch {"exec $cmd -version"}] || [
lindex $::errorCode 0] eq "NONE"} {
1639 Msg Info "Executing: $cmd $cmd_options"
1640 Msg Info "Saving logfile in: $qsysLogFile"
1641 if {[
catch {
eval exec -ignorestderr "$cmd $cmd_options >>& $qsysLogFile"} ret opt]} {
1642 set makeRet [
lindex [dict get $opt -errorcode] end]
1643 Msg CriticalWarning "$cmd returned with $makeRet"
1646 Msg Error " Could not execute command $cmd"
1650 set qsysIPFileList [
concat [glob -nocomplain -directory $qsysIPDir -types f *.ip *.qip] [glob -nocomplain -directory "$qsysIPDir/synthesis" -types f *.ip *.qip *.vhd *.vhdl]]
1651 foreach qsysIPFile $qsysIPFileList {
1652 if { [
file exists $qsysIPFile] != 0} {
1654 set_global_assignment -name $qsysIPFileType $qsysIPFile
1656 set IpMd5Sum [
Md5Sum $qsysIPFile]
1658 set fileDir [
file normalize "./hogTmp"]
1659 set fileName "$fileDir/.hogQsys.md5"
1660 if {![
file exists $fileDir]} {
1663 set hogQsysFile [open $fileName "a"]
1664 set fileEntry "$qsysIPFile\t$IpMd5Sum"
1665 puts $hogQsysFile $fileEntry
1670 Msg ERROR "Error while generating ip variations from qsys: $qsysFile not found!"
1680 proc GenericToSimulatorString {prop_dict target} {
1682 dict for {theKey theValue} $prop_dict {
1691 regexp {([0-9]*)('h)([0-9a-fA-F]*)} $theValue valueHexFull valueNumBits valueHexFlag valueHex
1692 regexp {^([0-9]*)$} $theValue valueIntFull ValueInt
1693 regexp {(?!^\d+$)^.+$} $theValue valueStrFull ValueStr
1694 if { [string tolower $target] == "vivado" || [string tolower $target] == "xsim" } {
1695 if {$valueNumBits != "" && $valueHexFlag != "" && $valueHex != ""} {
1696 set prj_generics "$prj_generics $theKey=$valueHexFull"
1697 } elseif { $valueIntFull != "" && $ValueInt != "" } {
1698 set prj_generics "$prj_generics $theKey=$ValueInt"
1699 } elseif { $valueStrFull != "" && $ValueStr != "" } {
1700 set prj_generics "$prj_generics $theKey=\"$ValueStr\""
1702 set prj_generics "$prj_generics $theKey=\"$theValue\""
1704 } elseif { [lsearch -exact [GetSimulators] [string tolower $target] ] >= 0 } {
1705 if {$valueNumBits != "" && $valueHexFlag != "" && $valueHex != ""} {
1707 scan $valueNumBits %d numBits
1709 scan $valueHex %x numHex
1710 binary scan [binary format "I" $numHex] "B*" binval
1711 set numBits [expr {$numBits-1}]
1712 set numBin [string range $binval end-$numBits end]
1713 set prj_generics "$prj_generics $theKey=\"$numBin\""
1715 } elseif { $valueIntFull != "" && $ValueInt != "" } {
1716 set prj_generics "$prj_generics $theKey=$ValueInt"
1717 } elseif { $valueStrFull != "" && $ValueStr != "" } {
1718 set prj_generics "$prj_generics {$theKey=\"$ValueStr\"}"
1721 set prj_generics "$prj_generics {$theKey=\"$theValue\"}"
1724 Msg Warning "Target : $target not implemented"
1727 return $prj_generics
1735 proc GetConfFiles {proj_dir} {
1736 if {![
file isdirectory $proj_dir]} {
1737 Msg Error "$proj_dir is supposed to be the top project directory"
1740 set conf_file [
file normalize $proj_dir/hog.conf]
1741 set sim_file [
file normalize $proj_dir/sim.conf]
1742 set pre_tcl [
file normalize $proj_dir/pre-creation.tcl]
1743 set post_tcl [
file normalize $proj_dir/post-creation.tcl]
1745 return [list $conf_file $sim_file $pre_tcl $post_tcl]
1754 proc GetCustomCommands {{directory .} {ret_commands 0}} {
1755 set commands_dict [dict create]
1756 set commands_files [glob -nocomplain $directory/*.tcl]
1757 set commands_string ""
1759 if {[
llength $commands_files] == 0} {
1763 if {$ret_commands == 0} {
1764 append commands_string "\n** Custom Commands:\n"
1767 foreach file $commands_files {
1768 set base_name [
string toupper [
file rootname [
file tail $file]]]
1769 if {$ret_commands == 1} {
1770 append commands_string "
1772 Msg Info \"Running custom script: $file\"
1774 Msg Info \"Done running custom script...\"
1779 set f [open $file r]
1780 set first_line [
gets $f]
1782 if {[regexp -nocase "^#\s*$base_name:\s*(.*)" $first_line full_match script_des]} {
1783 append commands_string "- $base_name: $script_des\n"
1785 append commands_string "- $base_name: runs $file\n"
1789 return $commands_string
1795 proc GetDateAndTime {commit} {
1796 set clock_seconds [
clock seconds]
1799 set date [
Git "log -1 --format=%cd --date=format:%d%m%Y $commit"]
1800 set timee [
Git "log -1 --format=%cd --date=format:00%H%M%S $commit"]
1802 Msg Warning "Found Git version older than 2.9.3. Using current date and time instead of commit time."
1803 set date [
clock format $clock_seconds -format {%d%m%Y}]
1804 set timee [
clock format $clock_seconds -format {00%H%M%S}]
1806 return [list $date $timee]
1818 proc GetFile {file fileset} {
1821 set Files [get_files -all $file -of_object [get_filesets $fileset]]
1822 set f [
lindex $Files 0]
1831 puts "***DEBUG Hog:GetFile $file"
1840 proc GetFileGenerics {filename {entity ""}} {
1842 if {[
string equal $file_type "VERILOG_FILE"] || [
string equal $file_type "SYSTEMVERILOG_FILE"]} {
1844 }
elseif {[
string equal $file_type "VHDL_FILE"]} {
1847 Msg CriticalWarning "Could not determine extension of top level file."
1856 proc GetGenericsFromConf {proj_dir {sim 0}} {
1857 set generics_dict [dict create]
1858 set top_dir "Top/$proj_dir"
1859 set conf_file "$top_dir/hog.conf"
1862 set conf_file "$top_dir/sim.conf"
1866 if {[
file exists $conf_file]} {
1868 if {[dict exists $properties generics]} {
1869 set generics_dict [dict get $properties generics]
1872 Msg Warning "File $conf_file not found."
1874 return $generics_dict
1882 proc GetSimsetGenericsFromConf {proj_dir} {
1883 set simsets_generics_dict [dict create]
1884 set top_dir "Top/$proj_dir"
1885 set conf_file "$top_dir/sim.conf"
1888 if {[
file exists $conf_file]} {
1891 set simsets_generics_dict [dict filter $properties key *:generics]
1893 Msg Warning "File $conf_file not found."
1895 return $simsets_generics_dict
1906 proc GetGroupName {proj_dir repo_dir} {
1907 if {[regexp {^(.*)/(Top|Projects)/+(.*?)/*$} $proj_dir dummy possible_repo_dir proj_or_top dir]} {
1909 if {[
file normalize $repo_dir] eq [
file normalize $possible_repo_dir]} {
1910 set group [
file dir $dir]
1911 if { $group == "." } {
1916 Msg Warning "Project directory $proj_dir seems to be in $possible_repo_dir which is not a the main Git repository $repo_dir."
1919 Msg Warning "Could not parse project directory $proj_dir"
1932 proc GetHogDescribe {sha {repo_path .}} {
1935 set new_sha "[
string toupper [
GetSHA]]"
1938 set new_sha [
string toupper $sha]
1958 proc GetHogFiles args {
1962 if { [
catch {
package require cmdline} ERROR] } {
1963 puts "$ERROR\n If you are running this script on tclsh, you can fix this by installing 'tcllib'"
1970 {list_files.arg "" "The file wildcard, if not specified all Hog list files will be looked for."}
1971 {sha_mode "Forwarded to ReadListFile, see there for info."}
1972 {ext_path.arg "" "Path for the external libraries forwarded to ReadListFile."}
1974 set usage "USAGE: GetHogFiles \[options\] <list path> <repository path>"
1975 if {[
catch {
array set options [
cmdline::getoptions args $parameters $usage]}] || [
llength $args] != 2 } {
1979 set list_path [
lindex $args 0]
1980 set repo_path [
lindex $args 1]
1982 set list_files $options(list_files)
1983 set sha_mode $options(sha_mode)
1984 set ext_path $options(ext_path)
1987 if { $sha_mode == 1 } {
1988 set sha_mode_opt "-sha_mode"
1993 if { $list_files == "" } {
1994 set list_files {.src,.con,.sim,.ext}
1996 set libraries [dict create]
1997 set properties [dict create]
1998 set list_files [glob -nocomplain -directory $list_path "*{$list_files}"]
1999 set filesets [dict create]
2001 foreach f $list_files {
2002 set ext [
file extension $f]
2003 if {$ext == ".ext"} {
2004 lassign [
ReadListFile {*}"$sha_mode_opt $f $ext_path"] l p fs
2006 lassign [
ReadListFile {*}"$sha_mode_opt $f $repo_path"] l p fs
2009 set properties [
MergeDict $p $properties]
2010 Msg Debug "list file $f, filesets: $fs"
2012 Msg Debug "Merged filesets $filesets"
2014 return [list $libraries $properties $filesets]
2020 proc GetIDECommand {proj_conf} {
2022 if {[
file exists $proj_conf]} {
2023 set ide_name_and_ver [
string tolower [
GetIDEFromConf $proj_conf]]
2024 set ide_name [
lindex [regexp -all -inline {\S+} $ide_name_and_ver] 0]
2026 if {$ide_name eq "vivado"} {
2027 set command "vivado"
2029 set before_tcl_script " -nojournal -nolog -mode batch -notrace -source "
2030 set after_tcl_script " -tclargs "
2033 }
elseif {$ide_name eq "planahead"} {
2034 set command "planAhead"
2036 set before_tcl_script " -nojournal -nolog -mode batch -notrace -source "
2037 set after_tcl_script " -tclargs "
2040 }
elseif {$ide_name eq "quartus"} {
2041 set command "quartus_sh"
2043 set before_tcl_script " -t "
2044 set after_tcl_script " "
2047 }
elseif {$ide_name eq "libero"} {
2050 set command "libero"
2051 set before_tcl_script "SCRIPT:"
2052 set after_tcl_script " SCRIPT_ARGS:\""
2054 }
elseif {$ide_name eq "diamond"} {
2055 set command "diamondc"
2056 set before_tcl_script " "
2057 set after_tcl_script " "
2060 Msg Error "IDE: $ide_name not known."
2064 Msg Error "Configuration file $proj_conf not found."
2067 return [list $command $before_tcl_script $after_tcl_script $end_marker]
2073 proc GetIDEFromConf {conf_file} {
2074 set f [open $conf_file "r"]
2077 if {[regexp -all {^\# *(\w*) *(\d+\.\d+(?:\.\d+)?(?:\.\d+)?)?(_.*)? *$} $line dummy ide version patch]} {
2078 if {[
info exists version] && $version != ""} {
2084 set ret [list $ide $ver]
2086 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."
2087 set ret [list "vivado" "0.0.0"]
2094 proc GetIDEName {} {
2096 return "ISE/PlanAhead"
2114 proc GetIDEVersion {} {
2117 regexp {\d+\.\d+(\.\d+)?} [version -short] ver
2123 regexp {[\.0-9]+} $quartus(version) ver
2126 set ver [get_libero_version]
2128 regexp {\d+\.\d+(\.\d+)?} [sys_install version] ver
2141 proc GetLinkedFile {link_file} {
2142 if {[
file type $link_file] eq "link"} {
2143 if {[
OS] == "windows" } {
2145 lassign [
ExecuteRet realpath $link_file] ret msg
2146 lassign [
ExecuteRet cygpath -m $msg] ret2 msg2
2147 if {$ret == 0 && $ret2 == 0} {
2149 Msg Debug "Found link file $link_file on Windows, the linked file is: $real_file"
2151 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."
2152 set real_file $link_file
2156 set linked_file [
file link $link_file]
2157 set real_file [
file normalize [
file dirname $link_file]/$linked_file]
2160 if {![
file exists $real_file]} {
2161 Msg Warning "$link_file is a broken link, because the linked file: $real_file does not exist."
2164 Msg Warning "$link file is not a soft link"
2165 set real_file $link_file
2178 proc GetMaxThreads {proj_dir} {
2180 if {[
file exists $proj_dir/hog.conf]} {
2182 if {[dict exists $properties parameters]} {
2183 set propDict [dict get $properties parameters]
2184 if {[dict exists $propDict MAX_THREADS]} {
2185 set maxThreads [dict get $propDict MAX_THREADS]
2189 Msg Warning "File $proj_dir/hog.conf not found. Max threads will be set to default value 1"
2202 proc GetModifiedFiles {{repo_path "."} {pattern "."}} {
2205 set ret [
Git "ls-files --modified $pattern"]
2214 proc GetOptions {argv parameters} {
2217 set param_list [list]
2218 set option_list [list]
2220 foreach p $parameters {
2221 lappend param_list [
lindex $p 0]
2225 while {$index < [
llength $argv]} {
2226 set arg [
lindex $argv $index]
2227 if {[
string first - $arg] == 0} {
2228 set option [
string trimleft $arg "-"]
2230 lappend option_list $arg
2231 if {[lsearch $param_list ${option}*] >= 0 && [
string first ".arg" [lsearch -inline $param_list ${option}*]] >= 0} {
2232 lappend option_list [
lindex $argv $index]
2236 lappend arg_list $arg
2240 Msg Debug "Argv: $argv"
2241 Msg Debug "Options: $option_list"
2242 Msg Debug "Arguments: $arg_list"
2243 return [list $option_list $arg_list]
2261 proc GetProjectFiles {{project_file ""}} {
2263 set libraries [dict create]
2264 set simlibraries [dict create]
2265 set constraints [dict create]
2266 set properties [dict create]
2267 set consets [dict create]
2268 set srcsets [dict create]
2269 set simsets [dict create]
2272 set all_filesets [get_filesets]
2273 set simulator [get_property target_simulator [current_project]]
2274 set top [get_property "top" [current_fileset]]
2276 dict lappend properties $topfile "top=$top"
2278 foreach fs $all_filesets {
2279 if {$fs == "utils_1"} {
2284 set all_files [get_files -quiet -of_objects [get_filesets $fs]]
2285 set fs_type [get_property FILESET_TYPE [get_filesets $fs]]
2287 if {$fs_type == "BlockSrcs"} {
2289 set dict_fs "sources_1"
2293 foreach f $all_files {
2300 if { [
lindex [get_property IS_GENERATED [
GetFile $f $fs]] 0] != 0} {
2305 if {[get_property FILE_TYPE [
GetFile $f $fs]] == "Configuration Files"} {
2311 if {[get_property CORE_CONTAINER [
GetFile $f $fs]] != ""} {
2312 if { [
file extension $f] == ".xcix"} {
2313 set f [get_property CORE_CONTAINER [
GetFile $f $fs]]
2321 if {[get_property SCOPED_TO_REF [
GetFile $f $fs]] != ""} {
2322 dict lappend properties $f "scoped_to_ref=[get_property SCOPED_TO_REF [
GetFile $f $fs]]"
2327 if {[get_property SCOPED_TO_CELLS [
GetFile $f $fs]] != ""} {
2328 dict lappend properties $f "scoped_to_cells=[get_property SCOPED_TO_CELLS [
GetFile $f $fs]]"
2332 if {[
IsInList "PARENT_COMPOSITE_FILE" [list_property [
GetFile $f $fs]]]} {
2337 if {[
file tail $f] == "nocattrs.dat"} {
2342 if {[
file extension $f] != ".coe"} {
2343 set f [
file normalize $f]
2346 set type [get_property FILE_TYPE [
GetFile $f $fs]]
2348 set lib [get_property -quiet LIBRARY [
GetFile $f $fs]]
2351 Msg Debug "File $f Extension [
file extension $f] Type [
lindex $type 0]"
2353 if {[
string equal [
lindex $type 0] "VHDL"] && [
llength $type] == 1} {
2355 }
elseif {[
string equal [
lindex $type 0] "Block"] && [
string equal [
lindex $type 1] "Designs"]} {
2358 }
elseif {[
string equal $type "SystemVerilog"] && [
file extension $f] != ".sv"} {
2359 set prop "SystemVerilog"
2360 }
elseif {[
string equal [
lindex $type 0] "XDC"] && [
file extension $f] != ".xdc"} {
2362 }
elseif {[
string equal $type "Verilog Header"] && [
file extension $f] != ".vh" && [
file extension $f] != ".svh"} {
2363 set prop "verilog_header"
2364 }
elseif {[
string equal $type "Verilog Template"] && [
file extension $f] == ".v" && [
file extension $f] != ".sv"} {
2365 set prop "verilog_template"
2367 set type [
lindex $type 0]
2371 if {![
string equal $prop ""]} {
2372 dict lappend properties $f $prop
2375 if {[
string equal $fs_type "SimulationSrcs"]} {
2377 if {[
string equal $type "VHDL"] } {
2378 set library "${lib}.sim"
2380 set library "others.sim"
2384 dict lappend simsets $dict_fs $library
2387 dict lappend simlibraries $library $f
2389 }
elseif {[
string equal $type "VHDL"] } {
2392 dict lappend srcsets $dict_fs "${lib}.src"
2394 dict lappend libraries "${lib}.src" $f
2395 }
elseif {[
string first "IP" $type] != -1} {
2398 dict lappend srcsets $dict_fs "ips.src"
2400 dict lappend libraries "ips.src" $f
2401 Msg Debug "Appending $f to ips.src"
2402 }
elseif {[
string equal $fs_type "Constrs"]} {
2405 dict lappend consets $dict_fs "sources.con"
2407 dict lappend constraints "sources.con" $f
2411 dict lappend srcsets $dict_fs "others.src"
2413 dict lappend libraries "others.src" $f
2414 Msg Debug "Appending $f to others.src"
2417 if {[
lindex [get_property -quiet used_in_synthesis [
GetFile $f $fs]] 0] == 0} {
2418 dict lappend properties $f "nosynth"
2420 if {[
lindex [get_property -quiet used_in_implementation [
GetFile $f $fs]] 0] == 0} {
2421 dict lappend properties $f "noimpl"
2423 if {[
lindex [get_property -quiet used_in_simulation [
GetFile $f $fs]] 0] == 0} {
2424 dict lappend properties $f "nosim"
2426 if {[
lindex [get_property -quiet IS_MANAGED [
GetFile $f $fs]] 0] == 0 && [
file extension $f] != ".xcix" } {
2427 dict lappend properties $f "locked"
2433 dict lappend properties "Simulator" [get_property target_simulator [current_project]]
2437 set file [open $project_file r]
2438 set in_file_manager 0
2440 while {[
gets $file line] >= 0} {
2442 if {[regexp {^KEY ActiveRoot \"([^\"]+)\"} $line -> value]} {
2443 set top [
string range $value 0 [
expr {[string first "::" $value] - 1}]]
2447 if {[regexp {^LIST FileManager} $line]} {
2448 set in_file_manager 1
2453 if {$in_file_manager && [regexp {^ENDLIST} $line]} {
2458 if {$in_file_manager && [regexp {^VALUE \"([^\"]+)} $line -> value]} {
2461 lassign [
split $value ,] file_path file_type
2464 set library "others"
2465 while {[
gets $file line] >= 0} {
2466 if {$line == "ENDFILE"} {
2469 regexp {^LIBRARY=\"([^\"]+)} $line -> library
2470 regexp {^PARENT=\"([^\"]+)} $line -> parent_file
2472 Msg Debug "Found file ${file_path} in project.."
2473 if {$parent_file == ""} {
2474 if {$file_type == "hdl"} {
2477 dict lappend srcsets "sources_1" "${library}.src"
2479 dict lappend libraries "${library}.src" $file_path
2483 if {[
GetModuleName $file_path] == [
string tolower $top] && $top != ""} {
2484 Msg Debug "Found top module $top in $file_path"
2485 dict lappend properties $file_path "top=$top"
2488 }
elseif {$file_type == "tb_hdl"} {
2490 dict lappend simsets "sim_1" "${library}.sim"
2492 dict lappend simlibraries "${library}.sim" $file_path
2493 }
elseif {$file_type == "io_pdc" || $file_type == "sdc"} {
2495 dict lappend consets "constrs_1" "sources.con"
2497 dict lappend constraints "sources.con" $file_path
2504 set fileData [read [open $project_file]]
2506 set project_path [
file dirname $project_file]
2509 regsub {<\?xml.*\?>} $fileData "" fileData
2512 regexp {<Implementation.*?>(.*)</Implementation>} $fileData -> implementationContent
2516 set sourceRegex {<Source name="([^"]*?)" type="([^"]*?)" type_short="([^"]*?)".*?>(.*?)</Source>}
2518 set optionsRegex {<Options(.*?)\/>}
2519 regexp $optionsRegex $implementationContent -> prj_options
2520 foreach option $prj_options {
2521 if {[regexp {^top=\"([^\"]+)\"} $option match result]} {
2526 while {[regexp $sourceRegex $implementationContent match name type type_short optionsContent]} {
2527 Msg Debug "Found file ${name} in project..."
2528 set file_path [
file normalize $project_path/$name]
2530 set optionsRegex {<Options(.*?)\/>}
2531 regexp $optionsRegex $optionsContent -> options
2532 set library "others"
2534 foreach option $options {
2535 if {[
string first "System Verilog" $option]} {
2538 if {[regexp {^lib=\"([^\"]+)\"} $option match1 result]} {
2543 if {[regexp {syn_sim="([^"]*?)"} $match match_sim simonly]} {
2548 if { $type_short == "VHDL" || $type_short == "Verilog" || $type_short == "IPX"} {
2549 if { $ext == ".src"} {
2550 if {[
IsInList "${library}${ext}" [
DictGet $srcsets "sources_1"]]==0} {
2551 dict lappend srcsets "sources_1" "${library}${ext}"
2553 dict lappend libraries "${library}${ext}" $file_path
2554 }
elseif { $ext == ".sim"} {
2556 dict lappend simsets "sim_1" "${library}.sim"
2558 dict lappend simlibraries "${library}.sim" $file_path
2564 Msg Debug "Found top module $top in $file_path"
2565 dict lappend properties $file_path "top=$top"
2567 }
elseif { $type_short == "SDC"} {
2569 dict lappend consets "constrs_1" "sources.con"
2571 dict lappend constraints "sources.con" $file_path
2575 regsub -- $match $implementationContent "" implementationContent
2578 return [list $libraries $properties $simlibraries $constraints $srcsets $simsets $consets]
2584 proc GetProjectFlavour {proj_name} {
2586 set flavour [
string map {. ""} [
file extension $proj_name]]
2587 if {$flavour != ""} {
2588 if {[
string is integer $flavour]} {
2589 Msg Info "Project $proj_name has flavour = $flavour, the generic variable FLAVOUR will be set to $flavour"
2591 Msg Warning "Project name has a unexpected non numeric extension, flavour will be set to -1"
2609 proc GetProjectVersion {proj_dir repo_path {ext_path ""} {sim 0}} {
2610 if { ![
file exists $proj_dir] } {
2611 Msg CriticalWarning "$proj_dir not found"
2621 Msg Warning "Repository is not clean"
2629 Msg Debug "Project version $v_proj, latest tag $v_last"
2631 Msg Info "The specified project was modified since official version."
2638 Msg Info "The specified project was modified in the latest official version $ret"
2639 }
elseif {$comp == -1} {
2640 Msg Info "The specified project was modified in a past official version $ret"
2655 proc GetRepoVersions {proj_dir repo_path {ext_path ""} {sim 0}} {
2656 if { [
catch {
package require cmdline} ERROR] } {
2657 puts "$ERROR\n If you are running this script on tclsh, you can fix this by installing 'tcllib'"
2672 lappend SHAs [
GetSHA {Hog}]
2676 if {[
Git {status --untracked-files=no --porcelain}] eq ""} {
2677 Msg Info "Hog submodule [
pwd] clean."
2678 lassign [
GetVer ./] hog_ver hog_hash
2680 Msg CriticalWarning "Hog submodule [
pwd] not clean, commit hash will be set to 0."
2681 set hog_hash "0000000"
2682 set hog_ver "00000000"
2687 if {[
Git {status --untracked-files=no --porcelain}] eq ""} {
2688 Msg Info "Git working directory [
pwd] clean."
2691 Msg CriticalWarning "Git working directory [
pwd] not clean, commit hash, and version will be set to 0."
2696 lassign [
GetVer [
join $conf_files]] top_ver top_hash
2697 lappend SHAs $top_hash
2698 lappend versions $top_ver
2705 lassign [
GetHogFiles -list_files "*.src" -sha_mode "./list/" $repo_path] src_files dummy
2706 dict for {f files} $src_files {
2707 # library names have a .src extension in values returned by GetHogFiles
2708 set name [file rootname [file tail $f]]
2709 if {[file ext $f] == ".oth"} {
2712 lassign [GetVer $files] ver hash
2713 # Msg Info "Found source list file $f, version: $ver commit SHA: $hash"
2715 lappend versions $ver
2717 lappend hashes $hash
2724 lassign [
GetHogFiles -list_files "*.con" -sha_mode "./list/" $repo_path] cons_files dummy
2725 dict for {f files} $cons_files {
2726 #library names have a .con extension in values returned by GetHogFiles
2727 set name [file rootname [file tail $f]]
2728 lassign [GetVer $files] ver hash
2729 #Msg Info "Found constraint list file $f, version: $ver commit SHA: $hash"
2731 Msg CriticalWarning "Constraints file $f not found in Git."
2733 lappend cons_hashes $hash
2735 lappend versions $ver
2742 lassign [
GetHogFiles -list_files "*.sim" -sha_mode "./list/" $repo_path] sim_files dummy
2743 dict for {f files} $sim_files {
2744 #library names have a .sim extension in values returned by GetHogFiles
2745 set name [file rootname [file tail $f]]
2746 lassign [GetVer $files] ver hash
2747 #Msg Info "Found simulation list file $f, version: $ver commit SHA: $hash"
2748 lappend sim_hashes $hash
2750 lappend versions $ver
2756 if {"{}" eq $cons_hashes} {
2758 Msg CriticalWarning "No hashes found for constraints files (not in git)"
2761 set cons_hash [
string tolower [
Git "log --format=%h -1 $cons_hashes"]]
2768 set ext_files [glob -nocomplain "./list/*.ext"]
2771 foreach f $ext_files {
2772 set name [
file rootname [
file tail $f]]
2775 lappend ext_names $name
2776 lappend ext_hashes $hash
2779 lappend versions $ext_ver
2782 set file_data [read $fp]
2784 set data [
split $file_data "\n"]
2786 foreach line $data {
2787 if {![regexp {^ *$} $line] & ![regexp {^ *\#} $line] } {
2789 set file_and_prop [regexp -all -inline {\S+} $line]
2790 set hdlfile [
lindex $file_and_prop 0]
2791 set hdlfile $ext_path/$hdlfile
2792 if { [
file exists $hdlfile] } {
2793 set hash [
lindex $file_and_prop 1]
2794 set current_hash [
Md5Sum $hdlfile]
2795 if {[
string first $hash $current_hash] == -1} {
2796 Msg CriticalWarning "File $hdlfile has a wrong hash. Current checksum: $current_hash, expected: $hash"
2804 if {[
llength [glob -nocomplain ./list/*.ipb]] > 0 } {
2806 lassign [
GetHogFiles -list_files "*.ipb" -sha_mode "./list/" $repo_path] xml_files dummy
2807 lassign [
GetVer [dict get $xml_files "xml.ipb"]] xml_ver xml_hash
2808 lappend SHAs $xml_hash
2809 lappend versions $xml_ver
2814 Msg Info "This project does not use IPbus XMLs"
2819 set user_ip_repos ""
2820 set user_ip_repo_hashes ""
2821 set user_ip_repo_vers ""
2823 if {[
file exists [
lindex $conf_files 0]]} {
2824 set PROPERTIES [
ReadConf [
lindex $conf_files 0]]
2825 if {[dict exists $PROPERTIES main]} {
2826 set main [dict get $PROPERTIES main]
2827 dict for {p v} $main {
2828 if { [ string tolower $p ] == "ip_repo_paths" } {
2830 lappend user_ip_repos "$repo_path/$repo"
2837 foreach repo $user_ip_repos {
2838 if {[
file isdirectory $repo]} {
2839 set repo_file_list [glob -nocomplain "$repo/*"]
2840 if {[
llength $repo_file_list] != 0} {
2841 lassign [
GetVer $repo] ver sha
2842 lappend user_ip_repo_hashes $sha
2843 lappend user_ip_repo_vers $ver
2844 lappend versions $ver
2846 Msg Warning "IP_REPO_PATHS property set to $repo in hog.conf but directory is empty."
2849 Msg Warning "IP_REPO_PATHS property set to $repo in hog.conf but directory does not exist."
2858 while {$found == 0} {
2859 set global_commit [
Git "log --format=%h -1 --abbrev=7 $SHAs"]
2864 if {$common_child == 0} {
2865 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 guarantee 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."
2867 Msg Info "The commit $sha is not an ancestor of the global commit $global_commit, adding the first common child $common_child instead..."
2868 lappend SHAs $common_child
2878 set global_commit "0000000"
2879 set global_version "00000000"
2884 set top_hash [
format %+07s $top_hash]
2885 set cons_hash [
format %+07s $cons_hash]
2886 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]
2895 proc GetSHA {{path ""}} {
2897 lassign [
GitRet {log --format=%h --abbrev=7 -1}] status result
2899 return [
string tolower $result]
2901 Msg Error "Something went wrong while finding the latest SHA. Does the repository have a commit?"
2907 set repo_path [
lindex [
Git {rev-parse --show-toplevel}] 0]
2911 set file_in_module 0
2912 if {[
file exists $repo_path/.gitmodules]} {
2913 lassign [
GitRet "config --file $repo_path/.gitmodules --get-regexp path"] status result
2915 set submodules [
split $result "\n"]
2918 Msg Warning "Something went wrong while trying to find submodules: $result"
2921 foreach mod $submodules {
2922 set module [
lindex $mod 1]
2923 if {[
string first "$repo_path/$module" $f] == 0} {
2925 set file_in_module 1
2926 lappend paths "$repo_path/$module"
2932 if {$file_in_module == 0} {
2938 lassign [
GitRet {log --format=%h --abbrev=7 -1} $paths] status result
2940 return [
string tolower $result]
2942 Msg Error "Something went wrong while finding the latest SHA. Does the repository have a commit?"
2945 return [
string tolower $result]
2949 proc GetSimulators {} {
2950 set SIMULATORS [list "modelsim" "questa" "riviera" "activehdl" "ies" "vcs"]
2955 proc GetTopFile {} {
2957 set compile_order_prop [get_property source_mgmt_mode [current_project]]
2958 if {$compile_order_prop ne "All"} {
2959 Msg CriticalWarning "Compile order is not set to automatic, setting it now..."
2960 set_property source_mgmt_mode All [current_project]
2961 update_compile_order -fileset sources_1
2963 return [
lindex [get_files -quiet -compile_order sources -used_in synthesis -filter {FILE_TYPE =~ "VHDL*" || FILE_TYPE =~ "*Verilog*" }] end]
2964 }
elseif {[
IsISE]} {
2965 debug::design_graph_mgr -create [current_fileset]
2966 debug::design_graph -add_fileset [current_fileset]
2967 debug::design_graph -update_all
2968 return [
lindex [debug::design_graph -get_compile_order] end]
2970 Msg Error "GetTopFile not yet implemented for this IDE"
2975 proc GetTopModule {} {
2977 return [get_property top [current_fileset]]
2979 Msg Error "GetTopModule not yet implemented for this IDE"
2989 proc GetVer {path {force_develop 0}} {
2993 Msg CriticalWarning "Empty SHA found for ${path}. Commit to Git to resolve this warning."
2996 set p [
lindex $path 0]
2997 if {[
file isdirectory $p]} {
3000 cd [
file dirname $p]
3002 set repo_path [
Git {rev-parse --show-toplevel}]
3005 return [list [
GetVerFromSHA $SHA $repo_path $force_develop] $SHA]
3016 proc GetVerFromSHA {SHA repo_path {force_develop 0}} {
3018 Msg CriticalWarning "Empty SHA found"
3021 lassign [
GitRet "tag --sort=creatordate --contain $SHA -l v*.*.* -l b*v*.*.*"] status result
3024 if {[regexp {^ *$} $result]} {
3026 lassign [
GitRet "log --oneline --pretty=\"%d\""] status2 tag_list
3029 set pattern {tag: v\d+\.\d+\.\d+}
3030 set real_tag_list {}
3031 foreach x $tag_list {
3032 set x_untrimmed [regexp -all -inline $pattern $x]
3033 regsub "tag: " $x_untrimmed "" x_trimmed
3034 set tt [
lindex $x_trimmed 0]
3035 if {![
string equal $tt ""]} {
3036 lappend real_tag_list $tt
3040 Msg Debug "Cleaned up list: $real_tag_list."
3042 set sorted_tags [lsort -decreasing -command CompareVersions $real_tag_list]
3044 Msg Debug "Sorted Tag list: $sorted_tags"
3046 set tag [
lindex $sorted_tags 0]
3049 set pattern {v\d+\.\d+\.\d+}
3050 if {![regexp $pattern $tag]} {
3051 Msg CriticalWarning "No Hog version tags found in this repository."
3057 set repo_conf $repo_path/Top/repo.conf
3061 set hotfix_prefix "hotfix/"
3062 set minor_prefix "minor_version/"
3063 set major_prefix "major_version/"
3065 set enable_develop_branch $force_develop
3067 set branch_name [
Git {rev-parse --abbrev-ref HEAD}]
3069 if {[
file exists $repo_conf]} {
3070 set PROPERTIES [
ReadConf $repo_conf]
3072 if {[dict exists $PROPERTIES main]} {
3073 set mainDict [dict get $PROPERTIES main]
3076 if {[dict exists $mainDict ENABLE_DEVELOP_BRANCH]} {
3077 set enable_develop_branch [dict get $mainDict ENABLE_DEVELOP_BRANCH]
3084 if {[dict exists $PROPERTIES prefixes]} {
3085 set prefixDict [dict get $PROPERTIES prefixes]
3087 if {[dict exists $prefixDict HOTFIX]} {
3088 set hotfix_prefix [dict get $prefixDict HOTFIX]
3090 if {[dict exists $prefixDict MINOR_VERSION]} {
3091 set minor_prefix [dict get $prefixDict MINOR_VERSION]
3093 if {[dict exists $prefixDict MAJOR_VERSION]} {
3094 set major_prefix [dict get $prefixDict MAJOR_VERSION]
3100 if {$enable_develop_branch == 1 } {
3101 if {[
string match "$hotfix_prefix*" $branch_name]} {
3106 if {[
string match "$major_prefix*" $branch_name]} {
3108 set version_level major
3109 }
elseif {[
string match "$minor_prefix*" $branch_name] || ($enable_develop_branch == 1 && $is_hotfix == 0)} {
3111 set version_level minor
3114 set version_level patch
3122 Msg CriticalWarning "Tag $tag does not contain a Hog compatible version in this repository."
3125 }
elseif {$mr == 0} {
3127 switch $version_level {
3143 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."
3149 set vers [
split $result "\n"]
3150 set ver [
lindex $vers 0]
3152 if {[regexp {^v.*$} $v]} {
3160 Msg CriticalWarning "Error while trying to find tag for $SHA"
3168 set M [
format %02X $M]
3169 set m [
format %02X $m]
3170 set c [
format %04X $c]
3172 }
elseif { $M > -1 } {
3174 set M [
format %02X $M]
3175 set m [
format %02X $m]
3176 set c [
format %04X $c]
3179 Msg Warning "Tag does not contain a properly formatted version: $ver"
3180 set M [
format %02X 0]
3181 set m [
format %02X 0]
3182 set c [
format %04X 0]
3195 proc Git {command {files ""}} {
3196 lassign [
GitRet $command $files] ret result
3198 Msg Error "Code $ret returned by git running: $command -- $files"
3209 proc GetModuleName {filename} {
3211 if {![
file exists $filename]} {
3212 Msg CriticalWarning "Error: File $filename does not exist."
3217 set fileId [open $filename r]
3220 set file_content [read $fileId]
3226 if {[
file extension $filename] == ".vhd" || [
file extension $filename] == ".vhdl"} {
3228 set file_content [
string tolower $file_content]
3230 set pattern {(?m)^\s*entity\s+(\S+)\s+is}
3231 }
elseif {[
file extension $filename] == ".v" || [
file extension $filename] == ".sv"} {
3233 set pattern {\n\s*module\s*(\w+)(\s*|\(|\n)}
3235 Msg Debug "File is neither VHDL nor Verilog... Returning empty string..."
3240 if {[regexp $pattern $file_content match module_name]} {
3243 Msg Debug "No module was found in $filename. Returning an empty string..."
3251 proc GetVerilogGenerics {file} {
3252 set fp [open $file r]
3258 foreach line [
split $data "\n"] {
3259 regsub "^\\s*\/\/.*" $line "" line
3260 regsub "(.*)\/\/.*" $line {\1} line
3261 if {![
string equal $line ""]} {
3262 append lines $line " "
3267 regsub -all {/\*.*\*/} $lines "" lines
3270 set punctuation [list]
3271 foreach char [list "(" ")" ";" "," " " "!" "<=" ":=" "=" "\[" "\]"] {
3272 lappend punctuation $char "\000$char\000"
3276 set tokens [
split [
string map $punctuation $lines] \000]
3278 set parameters [dict create]
3287 foreach token $tokens {
3288 set token [
string trim $token]
3289 if {![
string equal "" $token]} {
3290 if {[
string equal [
string tolower $token] "parameter"]} {
3291 set state $PARAM_NAME
3292 }
elseif {[
string equal $token ")"] || [
string equal $token ";"]} {
3294 }
elseif {$state == $PARAM_WIDTH} {
3295 if {[
string equal $token "\]"]} {
3296 set state $PARAM_NAME
3298 }
elseif {$state == $PARAM_VALUE} {
3299 if {[
string equal $token ","]} {
3300 set state $PARAM_NAME
3301 }
elseif {[
string equal $token ";"]} {
3305 }
elseif {$state == $PARAM_NAME} {
3307 if {[
string equal $token "="]} {
3308 set state $PARAM_VALUE
3309 }
elseif {[
string equal $token "\["]} {
3310 set state $PARAM_WIDTH
3311 }
elseif {[
string equal $token ","]} {
3312 set state $PARAM_NAME
3313 }
elseif {[
string equal $token ";"]} {
3315 }
elseif {[
string equal $token ")"]} {
3318 dict set parameters $token "integer"
3331 proc GetVhdlGenerics {file {entity ""} } {
3332 set fp [open $file r]
3338 foreach line [
split $data "\n"] {
3339 regsub "^\\s*--.*" $line "" line
3340 regsub "(.*)--.*" $line {\1} line
3341 if {![
string equal $line ""]} {
3342 append lines $line " "
3347 set generic_block ""
3348 set generics [dict create]
3350 if {1==[
string equal $entity ""]} {
3351 regexp {(?i).*entity\s+([^\s]+)\s+is} $lines _ entity
3354 set generics_regexp "(?i).*entity\\s+$entity\\s+is\\s+generic\\s*\\((.*)\\)\\s*;\\s*port.*end.*$entity"
3356 if {[regexp $generics_regexp $lines _ generic_block]} {
3358 foreach line [
split $generic_block ";"] {
3360 regexp {(.*):\s*([A-Za-z0-9_]+).*} $line _ generic type
3363 set splits [
split $generic ","]
3364 foreach split $splits {
3365 dict set generics [
string trim $split] [
string trim $type]
3381 proc GitRet {command {files ""}} {
3384 set ret [
catch {
exec -ignorestderr git {*}$command} result]
3386 set ret [
catch {
exec -ignorestderr git {*}$command -- {*}$files} result]
3390 return [list $ret $result]
3398 proc GitVersion {target_version} {
3399 set ver [
split $target_version "."]
3400 set v [
Git --version]
3402 set current_ver [
split [
lindex $v 2] "."]
3403 set target [
expr {[lindex $ver 0]*100000 + [lindex $ver 1]*100 + [lindex $ver 2]}]
3404 set current [
expr {[lindex $current_ver 0]*100000 + [lindex $current_ver 1]*100 + [lindex $current_ver 2]}]
3405 return [
expr {$target <= $current}]
3417 proc HandleIP {what_to_do xci_file ip_path repo_path {gen_dir "."} {force 0}} {
3418 if {!($what_to_do eq "push") && !($what_to_do eq "pull")} {
3419 Msg Error "You must specify push or pull as first argument."
3422 if { [
catch {
package require tar} TARPACKAGE]} {
3423 Msg CriticalWarning "Cannot find package tar. You can fix this by installing package \"tcllib\""
3432 if {[
string first "/eos/" $ip_path] == 0} {
3440 lassign [
eos "ls $ip_path"] ret result
3442 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."
3446 Msg Info "IP remote directory path, on EOS, is set to: $ip_path"
3453 if {!([
file exists $xci_file])} {
3454 Msg CriticalWarning "Could not find $xci_file."
3460 set xci_path [
file dirname $xci_file]
3461 set xci_name [
file tail $xci_file]
3462 set xci_ip_name [
file rootname [
file tail $xci_file]]
3463 set xci_dir_name [
file tail $xci_path]
3464 set gen_path $gen_dir
3466 set hash [
Md5Sum $xci_file]
3467 set file_name $xci_name\_$hash
3469 Msg Info "Preparing to $what_to_do IP: $xci_name..."
3471 if {$what_to_do eq "push"} {
3475 lassign [
eos "ls $ip_path/$file_name.tar"] ret result
3480 Msg Info "IP already in the EOS repository, will not copy..."
3482 Msg Info "IP already in the EOS repository, will forcefully replace..."
3488 if {[
file exists "$ip_path/$file_name.tar"]} {
3490 Msg Info "IP already in the local repository, will not copy..."
3492 Msg Info "IP already in the local repository, will forcefully replace..."
3501 if {$will_copy == 1} {
3503 Msg Info "Looking for generated files in $gen_path..."
3504 set ip_gen_files [glob -nocomplain $gen_path/*]
3508 if {[
llength $ip_gen_files] > 0} {
3509 Msg Info "Found some IP synthesised files matching $xci_ip_name"
3510 if {$will_remove == 1} {
3511 Msg Info "Removing old synthesised directory $ip_path/$file_name.tar..."
3513 eos "rm -rf $ip_path/$file_name.tar" 5
3515 file delete -force "$ip_path/$file_name.tar"
3519 Msg Info "Creating local archive with IP generated files..."
3521 foreach f $ip_gen_files {
3522 if {$first_file == 0} {
3523 ::tar::create $file_name.tar "[
Relative [
file normalize $repo_path] $f]"
3526 ::tar::add $file_name.tar "[
Relative [
file normalize $repo_path] $f]"
3530 Msg Info "Copying IP generated files for $xci_name..."
3532 lassign [
ExecuteRet xrdcp -f -s $file_name.tar $::env(EOS_MGM_URL)//$ip_path/] ret msg
3534 Msg CriticalWarning "Something went wrong when copying the IP files to EOS. Error message: $msg"
3537 Copy "$file_name.tar" "$ip_path/"
3539 Msg Info "Removing local archive"
3540 file delete $file_name.tar
3543 Msg Warning "Could not find synthesized files matching $gen_path/$file_name*"
3546 }
elseif {$what_to_do eq "pull"} {
3548 lassign [
eos "ls $ip_path/$file_name.tar"] ret result
3550 Msg Info "Nothing for $xci_name was found in the EOS repository, cannot pull."
3555 set remote_tar "$::env(EOS_MGM_URL)//$ip_path/$file_name.tar"
3556 Msg Info "IP $xci_name found in the repository $remote_tar, copying it locally to $repo_path..."
3558 lassign [
ExecuteRet xrdcp -f -r -s $remote_tar $repo_path] ret msg
3560 Msg CriticalWarning "Something went wrong when copying the IP files to EOS. Error message: $msg"
3564 if {[
file exists "$ip_path/$file_name.tar"]} {
3565 Msg Info "IP $xci_name found in local repository $ip_path/$file_name.tar, copying it locally to $repo_path..."
3566 Copy $ip_path/$file_name.tar $repo_path
3569 Msg Info "Nothing for $xci_name was found in the local IP repository, cannot pull."
3576 if {[
file exists $file_name.tar]} {
3577 remove_files $xci_file
3578 Msg Info "Extracting IP files from archive to $repo_path..."
3579 ::tar::untar $file_name.tar -dir $repo_path -noperms
3580 Msg Info "Removing local archive"
3581 file delete $file_name.tar
3582 add_files -norecurse -fileset sources_1 $xci_file
3595 proc HexVersionToString {version} {
3596 scan [
string range $version 0 1] %x M
3597 scan [
string range $version 2 3] %x m
3598 scan [
string range $version 4 7] %x c
3603 proc ImportTclLib {} {
3605 if {[
info exists env(HOG_TCLLIB_PATH)]} {
3606 lappend auto_path $env(HOG_TCLLIB_PATH)
3609 puts "ERROR: To run Hog with Microsemi Libero SoC or Lattice Diamond, you need to define the HOG_TCLLIB_PATH variable."
3622 proc InitLauncher {script tcl_path parameters usage argv} {
3623 set repo_path [
file normalize "$tcl_path/../.."]
3625 set bin_path [
file normalize "$tcl_path/../../bin"]
3626 set top_path [
file normalize "$tcl_path/../../Top"]
3627 set commands_path [
file normalize "$tcl_path/../../hog-commands/"]
3634 if {[
catch {
package require cmdline} ERROR]} {
3635 Msg Debug "The cmdline Tcl package was not found, sourcing it from Hog..."
3636 source $tcl_path/utils/cmdline.tcl
3640 append usage "\n** Options:"
3642 lassign [
GetOptions $argv $parameters] option_list arg_list
3649 if { [
IsInList "-all" $option_list] } {
3656 if {[
catch {
array set options [
cmdline::getoptions option_list $parameters $usage]} err] } {
3657 Msg Status "\nERROR: Syntax error, probably unknown option.\n\n USAGE: $err"
3661 set directive [
string toupper [
lindex $arg_list 0]]
3663 if { [
llength $arg_list] == 1 && ($directive == "L" || $directive == "LIST")} {
3665 Msg Status "\n** The projects in this repository are:"
3670 }
elseif { [
llength $arg_list] == 0 || [
llength $arg_list] > 2} {
3671 Msg Status "\nERROR: Wrong number of arguments: [
llength $argv].\n\n"
3676 set project [
lindex $arg_list 1]
3678 regsub "^(\./)?Top/" $project "" project
3680 regsub "/? *\$" $project "" project
3683 Msg Debug "Option list:"
3684 foreach {key value} [
array get options] {
3685 Msg Debug "$key => $value"
3692 if {$proj_conf != 0} {
3695 lassign [
GetIDECommand $proj_conf] cmd before_tcl_script after_tcl_script end_marker
3696 Msg Info "Project $project uses $cmd IDE"
3699 set command "$cmd $before_tcl_script$script$after_tcl_script$argv$end_marker"
3702 if {$project != ""} {
3715 set project_group [
file dirname $project]
3716 set project [
file tail $project]
3717 if { $project_group != "." } {
3718 set project_name "$project_group/$project"
3720 set project_name "$project"
3723 if { $options(generate) == 1 } {
3729 if { $options(xml_dir) != "" } {
3730 set xml_dst $options(xml_dir)
3735 return [list $directive $project $project_name $project_group $repo_path $old_path $bin_path $top_path $commands_path $command $cmd [
array get options]]
3742 proc IsCommitAncestor {ancestor commit} {
3743 lassign [
GitRet "merge-base --is-ancestor $ancestor $commit"] status result
3744 if {$status == 0 } {
3752 return [
expr {[info commands sys_install] != ""}]
3757 return [
expr {[info commands get_libero_version] != ""}]
3765 proc IsInList {element list {regex 0}} {
3767 if {$regex == 1 && [regexp $x $element] } {
3769 }
elseif { $regex == 0 && $x eq $element } {
3780 return [
expr {[string first PlanAhead [version]] == 0}]
3788 if {[
catch {
package require ::quartus::flow} result]} {
3801 proc IsRelativePath {path} {
3802 if {[
string index $path 0] == "/" || [
string index $path 0] == "~"} {
3810 proc IsSynplify {} {
3811 return [
expr {[info commands program_version] != ""}]
3816 return [
expr {![IsQuartus] && ![IsXilinx] && ![IsLibero] && ![IsSynplify] && ![IsDiamond]}]
3824 proc IsVersal {part} {
3825 if {[get_property ARCHITECTURE [get_parts $part]] eq "versal"} {
3835 return [
expr {[string first Vivado [version]] == 0}]
3843 if {[
info commands version] != ""} {
3844 set current_version [version]
3845 if {[
string first PlanAhead $current_version] == 0 || [
string first Vivado $current_version] == 0} {
3848 Msg Warning "This IDE has the version command but it is not PlanAhead or Vivado: $current_version"
3861 proc IsZynq {part} {
3862 if { [regexp {^(xc7z|xczu).*} $part] } {
3877 proc LaunchImplementation {reset do_create run_folder project_name {repo_path .} {njobs 4} {do_bitstream 0}} {
3878 Msg Info "Starting implementation flow..."
3880 if { $reset == 1 && $do_create == 0} {
3881 Msg Info "Resetting run before launching implementation..."
3886 source $repo_path/Hog/Tcl/integrated/pre-implementation.tcl
3889 if {$do_bitstream == 1} {
3890 launch_runs impl_1 -to_step [
BinaryStepName [get_property PART [current_project]]] $njobs -dir $run_folder
3892 launch_runs impl_1 -jobs $njobs -dir $run_folder
3897 Msg Info "running post-implementation"
3898 source $repo_path/Hog/Tcl/integrated/post-implementation.tcl
3899 if {$do_bitstream == 1} {
3900 Msg Info "running pre-bitstream"
3901 source $repo_path/Hog/Tcl/integrated/pre-bitstream.tcl
3902 Msg Info "running post-bitstream"
3903 source $repo_path/Hog/Tcl/integrated/post-bitstream.tcl
3907 set prog [get_property PROGRESS [get_runs impl_1]]
3908 set status [get_property STATUS [get_runs impl_1]]
3909 Msg Info "Run: impl_1 progress: $prog, status : $status"
3913 set status_file [open "$run_folder/timing.txt" "w"]
3914 puts $status_file "## $project_name Timing summary"
3916 set f [open [
lindex [glob "$run_folder/impl_1/*.twr" 0]]]
3918 while {[
gets $f line] >= 0} {
3919 if { [
string match "Timing summary:" $line] } {
3920 while {[
gets $f line] >= 0} {
3921 if { [
string match "Timing errors:*" $line] } {
3922 set errs [regexp -inline -- {[0-9]+} $line]
3924 if { [
string match "*Footnotes*" $line] } {
3927 puts $status_file "$line"
3936 Msg Info "Time requirements are met"
3937 file rename -force "$run_folder/timing.txt" "$run_folder/timing_ok.txt"
3940 Msg CriticalWarning "Time requirements are NOT met"
3941 file rename -force "$run_folder/timing.txt" "$run_folder/timing_error.txt"
3947 set wns [get_property STATS.WNS [get_runs [current_run]]]
3948 set tns [get_property STATS.TNS [get_runs [current_run]]]
3949 set whs [get_property STATS.WHS [get_runs [current_run]]]
3950 set ths [get_property STATS.THS [get_runs [current_run]]]
3951 set tpws [get_property STATS.TPWS [get_runs [current_run]]]
3953 if {$wns >= 0 && $whs >= 0 && $tpws >= 0} {
3954 Msg Info "Time requirements are met"
3955 set status_file [open "$run_folder/timing_ok.txt" "w"]
3958 Msg CriticalWarning "Time requirements are NOT met"
3959 set status_file [open "$run_folder/timing_error.txt" "w"]
3963 Msg Status "*** Timing summary ***"
3964 Msg Status "WNS: $wns"
3965 Msg Status "TNS: $tns"
3966 Msg Status "WHS: $whs"
3967 Msg Status "THS: $ths"
3968 Msg Status "TPWS: $tpws"
3974 puts $status_file "## $project_name Timing summary"
3976 m add row "| **Parameter** | \"**value (ns)**\" |"
3977 m add row "| --- | --- |"
3978 m add row "| WNS: | $wns |"
3979 m add row "| TNS: | $tns |"
3980 m add row "| WHS: | $whs |"
3981 m add row "| THS: | $ths |"
3982 m add row "| TPWS: | $tpws |"
3984 puts $status_file [m format 2string]
3985 puts $status_file "\n"
3986 if {$timing_ok == 1} {
3987 puts $status_file " Time requirements are met."
3989 puts $status_file "Time requirements are **NOT** met."
3991 puts $status_file "\n\n"
3995 if {$prog ne "100%"} {
3996 Msg Error "Implementation error"
4001 lassign [
GetRepoVersions [
file normalize ./Top/$project_name] $repo_path] sha
4003 Msg Info "Git describe set to $describe"
4005 set dst_dir [
file normalize "$repo_path/bin/$project_name\-$describe"]
4010 if {[
file exists $run_folder/versions.txt]} {
4011 file copy -force $run_folder/versions.txt $dst_dir
4013 Msg Warning "No versions file found in $run_folder/versions.txt"
4016 set timing_files [ glob -nocomplain "$run_folder/timing_*.txt"]
4017 set timing_file [
file normalize [
lindex $timing_files 0]]
4019 if {[
file exists $timing_file]} {
4020 file copy -force $timing_file $dst_dir/
4022 Msg Warning "No timing file found, not a problem if running locally"
4026 set revision [get_current_revision]
4028 if {[
catch {execute_module -tool fit} result]} {
4029 Msg Error "Result: $result\n"
4030 Msg Error "Place & Route failed. See the report file.\n"
4032 Msg Info "\nINFO: Place & Route was successful for revision $revision.\n"
4035 if {[
catch {execute_module -tool sta -args "--do_report_timing"} result]} {
4036 Msg Error "Result: $result\n"
4037 Msg Error "Time Quest failed. See the report file.\n"
4039 Msg Info "Time Quest was successfully run for revision $revision.\n"
4042 set panel "Timing Analyzer||Timing Analyzer Summary"
4043 set device [ get_report_panel_data -name $panel -col 1 -row_name "Device Name"]
4044 set timing_model [ get_report_panel_data -name $panel -col 1 -row_name "Timing Models"]
4045 set delay_model [ get_report_panel_data -name $panel -col 1 -row_name "Delay Model"]
4047 Msg Info "*******************************************************************"
4048 Msg Info "Device: $device"
4049 Msg Info "Timing Models: $timing_model"
4050 Msg Info "Delay Model: $delay_model"
4053 Msg Info "*******************************************************************"
4056 Msg Info "Starting implementation flow..."
4057 if {[
catch {run_tool -name {PLACEROUTE}}] } {
4058 Msg Error "PLACEROUTE FAILED!"
4060 Msg Info "PLACEROUTE PASSED."
4064 Msg Info "Run VERIFYTIMING ..."
4065 if {[
catch {run_tool -name {VERIFYTIMING} -script {Hog/Tcl/integrated/libero_timing.tcl}}] } {
4066 Msg CriticalWarning "VERIFYTIMING FAILED!"
4068 Msg Info "VERIFYTIMING PASSED \n"
4074 lassign [
GetRepoVersions [
file normalize ./Top/$project_name] $repo_path] sha
4076 Msg Info "Git describe set to $describe"
4078 set dst_dir [
file normalize "$repo_path/bin/$project_name\-$describe"]
4079 file mkdir $dst_dir/reports
4082 if {[
file exists $run_folder/versions.txt]} {
4083 file copy -force $run_folder/versions.txt $dst_dir
4085 Msg Warning "No versions file found in $run_folder/versions.txt"
4088 set timing_file_path [
file normalize "$repo_path/Projects/timing_libero.txt"]
4089 if {[
file exists $timing_file_path]} {
4090 file copy -force $timing_file_path $dst_dir/reports/Timing.txt
4091 set timing_file [open $timing_file_path "r"]
4092 set status_file [open "$dst_dir/timing.txt" "w"]
4093 puts $status_file "## $project_name Timing summary\n\n"
4094 puts $status_file "| | |"
4095 puts $status_file "| --- | --- |"
4096 while {[
gets $timing_file line] >= 0} {
4097 if { [
string match "SUMMARY" $line] } {
4098 while {[
gets $timing_file line] >= 0} {
4099 if { [
string match "END SUMMARY" $line] } {
4102 if {[
string first ":" $line] == -1} {
4105 set out_string "| [
string map {: | } $line] |"
4106 puts $status_file "$out_string"
4111 Msg Warning "No timing file found, not a problem if running locally"
4116 set force_rst "-forceOne"
4118 prj_run Map $force_rst
4119 prj_run PAR $force_rst
4132 proc LaunchSimulation {project_name lib_path {simsets ""} {repo_path .}} {
4135 set project [
file tail $project_name]
4136 set main_sim_folder [
file normalize "$repo_path/Projects/$project_name/$project.sim/"]
4138 if {$simsets != ""} {
4139 set simsets_todo [
split $simsets ","]
4140 Msg Info "Will run only the following simsets (if they exist): $simsets_todo"
4145 set sim_dic [dict create]
4147 set use_simpass_str 0
4150 set proj_dir [
file normalize $repo_path/Top/$project_name]
4151 set sim_file [
file normalize $proj_dir/sim.conf]
4152 if {[
file exists $sim_file]} {
4153 Msg Info "Parsing simulation configuration file $sim_file..."
4160 if {[dict exists $globalSettings::SIM_PROPERTIES hog]} {
4161 set hog_sim_props [dict get $globalSettings::SIM_PROPERTIES hog]
4162 dict for {prop_name prop_val} $hog_sim_props {
4163 # If HOG_SIMPASS_STR is set, use the HOG_SIMPASS_STR string to search for in logs, after simulation is done
4164 if { $prop_name == "HOG_SIMPASS_STR" && $prop_val != "" } {
4165 Msg Info "Setting simulation pass string as '$prop_val'"
4166 set use_simpass_str 1
4167 set simpass_str $prop_val
4172 Msg Info "Retrieving list of simulation sets..."
4173 foreach s [get_filesets] {
4174 set type [get_property FILESET_TYPE $s]
4175 if {$type eq "SimulationSrcs"} {
4176 if {$simsets_todo != "" && $s ni $simsets_todo} {
4177 Msg Info "Skipping $s as it was not specified with the -simset option..."
4180 if {[
file exists "$repo_path/Top/$project_name/list/$s.sim"]} {
4181 set fp [open "$repo_path/Top/$project_name/list/$s.sim" r]
4182 set file_data [read $fp]
4184 set data [
split $file_data "\n"]
4185 set n [
llength $data]
4186 Msg Info "$n lines read from $s.sim"
4188 set firstline [
lindex $data 0]
4190 if { [regexp {^ *\#Simulator} $firstline] } {
4191 set simulator_prop [regexp -all -inline {\S+} $firstline]
4192 set simulator [
string tolower [
lindex $simulator_prop 1]]
4194 Msg Warning "Simulator not set in $s.sim. The first line of $s.sim should be #Simulator <SIMULATOR_NAME>, where <SIMULATOR_NAME> can be xsim, questa, modelsim, riviera, activehdl, ies, or vcs, e.g. #Simulator questa. Setting simulator by default as xsim."
4195 set simulator "xsim"
4197 if {$simulator eq "skip_simulation"} {
4198 Msg Info "Skipping simulation for $s"
4201 set_property "target_simulator" $simulator [current_project]
4202 Msg Info "Creating simulation scripts for $s..."
4203 if { [
file exists $repo_path/Top/$project_name/pre-simulation.tcl] } {
4204 Msg Info "Running $repo_path/Top/$project_name/pre-simulation.tcl"
4205 source $repo_path/Top/$project_name/pre-simulation.tcl
4207 if { [
file exists $repo_path/Top/$project_name/pre-$s-simulation.tcl] } {
4208 Msg Info "Running $repo_path/Top/$project_name/pre-$s-simulation.tcl"
4209 source Running $repo_path/Top/$project_name/pre-$s-simulation.tcl
4211 current_fileset -simset $s
4212 set sim_dir $main_sim_folder/$s/behav
4213 set sim_output_logfile $sim_dir/xsim/simulate.log
4214 if { ([
string tolower $simulator] eq "xsim") } {
4215 set sim_name "xsim:$s"
4216 if { [
catch { launch_simulation -simset [get_filesets $s]} log] } {
4219 Msg CriticalWarning "Simulation failed for $s, error info: $::errorInfo"
4220 lappend failed $sim_name
4225 if {$use_simpass_str == 1} {
4228 set file_desc [open $sim_output_logfile r]
4229 set log [read $file_desc]
4232 Msg Info "Searching for simulation pass string: '$simpass_str'"
4233 if {[
string first $simpass_str $log] == -1} {
4234 Msg CriticalWarning "Simulation failed for $s, error info: '$simpass_str' NOT found!"
4235 lappend failed $sim_name
4238 lappend success $sim_name
4241 lappend success $sim_name
4245 Msg Info "Simulation library path is set to $lib_path."
4247 if {!([
file exists $lib_path])} {
4248 Msg Warning "Could not find simulation library path: $lib_path, $simulator simulation will not work."
4252 if {$simlib_ok == 1} {
4253 set_property "compxlib.${simulator}_compiled_library_dir" [
file normalize $lib_path] [current_project]
4254 launch_simulation -scripts_only -simset [get_filesets $s]
4255 set top_name [get_property TOP $s]
4256 set sim_script [
file normalize $sim_dir/$simulator/]
4257 Msg Info "Adding simulation script location $sim_script for $s..."
4258 lappend sim_scripts $sim_script
4259 dict append sim_dic $sim_script $s
4261 Msg Error "Cannot run $simulator simulations without a valid library path"
4269 if {[
info exists sim_scripts]} {
4271 Msg Info "Generating IP simulation targets, if any..."
4273 foreach ip [get_ips] {
4274 generate_target simulation -quiet $ip
4279 Msg Info "====== Starting simulations runs ======"
4282 foreach s $sim_scripts {
4284 set cmd ./compile.sh
4285 Msg Info " ************* Compiling: $s ************* "
4287 set sim_name "comp:[dict get $sim_dic $s]"
4289 Msg CriticalWarning "Compilation failed for $s, error info: $::errorInfo"
4290 lappend failed $sim_name
4292 lappend success $sim_name
4294 Msg Info "###################### Compilation log starts ######################"
4295 Msg Info "\n\n$log\n\n"
4296 Msg Info "###################### Compilation log ends ######################"
4299 if { [
file exists "./elaborate.sh"] } {
4300 set cmd ./elaborate.sh
4301 Msg Info " ************* Elaborating: $s ************* "
4303 set sim_name "elab:[dict get $sim_dic $s]"
4305 Msg CriticalWarning "Elaboration failed for $s, error info: $::errorInfo"
4306 lappend failed $sim_name
4308 lappend success $sim_name
4310 Msg Info "###################### Elaboration log starts ######################"
4311 Msg Info "\n\n$log\n\n"
4312 Msg Info "###################### Elaboration log ends ######################"
4314 set cmd ./simulate.sh
4315 Msg Info " ************* Simulating: $s ************* "
4320 if {$use_simpass_str == 1} {
4321 if {[
string first $simpass_str $log] == -1} {
4325 Msg Debug "Simulation pass string not set, relying on simulator exit code."
4330 set sim_name "sim:[dict get $sim_dic $s]"
4332 Msg CriticalWarning "Simulation failed for $s, error info: $::errorInfo"
4333 lappend failed $sim_name
4335 lappend success $sim_name
4337 Msg Info "###################### Simulation log starts ######################"
4338 Msg Info "\n\n$log\n\n"
4339 Msg Info "###################### Simulation log ends ######################"
4345 if {[
llength $success] > 0} {
4346 set successes [
join $success "\n"]
4347 Msg Info "The following simulation sets were successful:\n\n$successes\n\n"
4350 if {[
llength $failed] > 0} {
4351 set failures [
join $failed "\n"]
4352 Msg Error "The following simulation sets have failed:\n\n$failures\n\n"
4354 }
elseif {[
llength $success] > 0} {
4355 Msg Info "All the [
llength $success] compilations, elaborations and simulations were successful."
4358 Msg Info "Simulation done."
4360 Msg Warning "Simulation is not yet supported for [
GetIDEName]."
4373 proc LaunchSynthesis {reset do_create run_folder project_name {repo_path .} {ext_path ""} {njobs 4}} {
4375 if {$reset == 1 && $do_create == 0} {
4376 Msg Info "Resetting run before launching synthesis..."
4380 source $repo_path/Hog/Tcl/integrated/pre-synthesis.tcl
4382 launch_runs synth_1 -jobs $njobs -dir $run_folder
4384 set prog [get_property PROGRESS [get_runs synth_1]]
4385 set status [get_property STATUS [get_runs synth_1]]
4386 Msg Info "Run: synth_1 progress: $prog, status : $status"
4393 lassign [
GetRepoVersions [
file normalize ./Top/$project_name] $repo_path $ext_path] sha
4395 Msg Info "Git describe set to $describe"
4398 set xci_file [get_property IP_FILE $ip]
4400 set xci_path [
file dirname $xci_file]
4401 set xci_ip_name [
file rootname [
file tail $xci_file]]
4402 foreach rptfile [glob -nocomplain -directory $xci_path *.rpt] {
4403 file copy $rptfile $repo_path/bin/$project_name-$describe/reports
4427 if {$prog ne "100%"} {
4428 Msg Error "Synthesis error, status is: $status"
4432 set project [
file tail [
file rootname $project_name]]
4434 Msg Info "Number of jobs set to $njobs."
4435 set_global_assignment -name NUM_PARALLEL_PROCESSORS $njobs
4439 lassign [
GetRepoVersions [
file normalize $repo_path/Top/$project_name] $repo_path] sha
4442 set revision [get_current_revision]
4445 set tool_and_command [
split [get_global_assignment -name PRE_FLOW_SCRIPT_FILE] ":"]
4446 set tool [
lindex $tool_and_command 0]
4447 set pre_flow_script [
lindex $tool_and_command 1]
4448 set cmd "$tool -t $pre_flow_script quartus_map $project $revision"
4454 Msg Warning "Can not execute command $cmd"
4455 Msg Warning "LOG: $log"
4457 Msg Info "Pre flow script executed!"
4461 if { ![is_project_open] } {
4462 Msg Info "Re-opening project file $project_name..."
4463 project_open $project -current_revision
4467 if {[
catch {execute_module -tool ipg -args "--clean"} result]} {
4468 Msg Error "Result: $result\n"
4469 Msg Error "IP Generation failed. See the report file.\n"
4471 Msg Info "IP Generation was successful for revision $revision.\n"
4475 if {[
catch {execute_module -tool map -args "--parallel"} result]} {
4476 Msg Error "Result: $result\n"
4477 Msg Error "Analysis & Synthesis failed. See the report file.\n"
4479 Msg Info "Analysis & Synthesis was successful for revision $revision.\n"
4483 defvar_set -name RWNETLIST_32_64_MIXED_FLOW -value 0
4485 Msg Info "Run SYNTHESIS..."
4486 if {[
catch {run_tool -name {SYNTHESIZE}}] } {
4487 Msg Error "SYNTHESIZE FAILED!"
4489 Msg Info "SYNTHESIZE PASSED!"
4495 set force_rst "-forceOne"
4497 prj_run Synthesis $force_rst
4498 if {[prj_syn] == "synplify"} {
4499 prj_run Translate $force_rst
4502 Msg Error "Impossible condition. You need to run this in an IDE."
4513 proc ListProjects {{repo_path .} {print 1} {ret_conf 0}} {
4514 set top_path [
file normalize $repo_path/Top]
4515 set confs [
findFiles [
file normalize $top_path] hog.conf]
4517 set confs [lsort $confs]
4521 set p [
Relative $top_path [
file dirname $c]]
4524 if { $description eq "test"} {
4525 set description " - Test project"
4526 }
elseif { $description ne ""} {
4527 set description " - $description"
4530 if {$print == 1 || $description ne " - Test project"} {
4532 set g [
file dirname $p]
4543 if {$ret_conf == 0} {
4558 proc Logo { {repo_path .} } {
4559 if {[
info exists ::env(HOG_COLORED)] && [
string match "ENABLED" $::env(HOG_COLORED)]} {
4560 set logo_file "$repo_path/Hog/images/hog_logo_color.txt"
4562 set logo_file "$repo_path/Hog/images/hog_logo.txt"
4567 set ver [
Git {describe --always}]
4570 if {[
file exists $logo_file]} {
4571 set f [open $logo_file "r"]
4574 set lines [
split $data "\n"]
4580 Msg CriticalWarning "Logo file: $logo_file not found"
4583 Msg Status "Version: $ver"
4589 proc Md5Sum {file_name} {
4590 if {!([
file exists $file_name])} {
4591 Msg Warning "Could not find $file_name."
4594 if {[
catch {
package require md5 2.0.7} result]} {
4595 Msg Warning "Tcl package md5 version 2.0.7 not found ($result), will use command line..."
4596 set hash [
lindex [
Execute md5sum $file_name] 0]
4598 set file_hash [
string tolower [md5::md5 -hex -file $file_name]]
4611 proc MergeDict {dict0 dict1} {
4612 set outdict [dict merge $dict1 $dict0]
4613 foreach key [dict keys $dict1] {
4614 if {[dict exists $dict0 $key]} {
4615 set temp_list [dict get $dict1 $key]
4616 foreach vhdfile $temp_list {
4619 dict lappend outdict $key $vhdfile
4631 proc MoveElementToEnd {inputList element} {
4632 set index [lsearch $inputList $element]
4634 set inputList [
lreplace $inputList $index $index]
4635 lappend inputList $element
4645 proc Msg {level msg {title ""}} {
4646 set level [
string tolower $level]
4647 if {$title == ""} {
set title [
lindex [
info level [
expr {[info level]-1}]] 0]}
4648 if {$level == 0 || $level == "status" || $level == "extra_info"} {
4651 }
elseif {$level == 1 || $level == "info"} {
4654 }
elseif {$level == 2 || $level == "warning"} {
4655 set vlevel {WARNING}
4657 }
elseif {$level == 3 || [
string first "critical" $level] !=-1} {
4658 set vlevel {CRITICAL WARNING}
4659 set qlevel critical_warning
4660 }
elseif {$level == 4 || $level == "error"} {
4663 }
elseif {$level == 5 || $level == "debug"} {
4664 if {([
info exists ::DEBUG_MODE] && $::DEBUG_MODE == 1) || ([
info exists ::env(HOG_DEBUG_MODE)] && $::env(HOG_DEBUG_MODE) == 1)} {
4666 set qlevel extra_info
4667 set msg "DEBUG: \[Hog:$title\] $msg"
4672 puts "Hog Error: level $level not defined"
4679 set status [
catch {send_msg_id Hog:$title-0 $vlevel $msg}]
4685 post_message -type $qlevel "Hog:$title $msg"
4686 if { $qlevel == "error"} {
4691 if {$vlevel != "STATUS"} {
4692 puts "$vlevel: \[Hog:$title\] $msg"
4697 if {$qlevel == "error"} {
4709 proc MsgAndLog {msg {severity "CriticalWarning"} {outFile ""}} {
4711 if {$outFile != ""} {
4712 set oF [open "$outFile" a+]
4722 proc OpenProject {project_file repo_path} {
4724 open_project $project_file
4726 set project_folder [
file dirname $project_file]
4727 set project [
file tail [
file rootname $project_file]]
4728 if {[
file exists $project_folder]} {
4730 if { ![is_project_open] } {
4731 Msg Info "Opening existing project file $project_file..."
4732 project_open $project -current_revision
4735 Msg Error "Project directory not found for $project_file."
4739 Msg Info "Opening existing project file $project_file..."
4741 open_project -file $project_file -do_backup_on_convert 1 -backup_file {./Projects/$project_file.zip}
4743 Msg Info "Opening existing project file $project_file..."
4744 prj_project open $project_file
4746 Msg Error "This IDE is currently not supported by Hog. Exiting!"
4753 return $tcl_platform(platform)
4763 proc ParseJSON {JSON_FILE JSON_KEY} {
4764 set result [
catch {
package require Tcl 8.4} TclFound]
4765 if {"$result" != "0"} {
4766 Msg CriticalWarning "Cannot find Tcl package version equal or higher than 8.4.\n $TclFound\n Exiting"
4770 set result [
catch {
package require json} JsonFound]
4771 if {"$result" != "0"} {
4772 Msg CriticalWarning "Cannot find JSON package equal or higher than 1.0.\n $JsonFound\n Exiting"
4775 set JsonDict [json::json2dict $JSON_FILE]
4776 set result [
catch {dict get $JsonDict $JSON_KEY} RETURNVALUE]
4777 if {"$result" != "0"} {
4778 Msg CriticalWarning "Cannot find $JSON_KEY in $JSON_FILE\n Exiting"
4790 proc ProjectExists {project {repo_path .}} {
4791 set index [lsearch -exact [
ListProjects $repo_path 0] $project]
4807 proc ReadConf {file_name} {
4809 if { [
catch {
package require inifile 0.2.3} ERROR] } {
4810 puts "$ERROR\n If you are running this script on tclsh, you can fix this by installing 'tcllib'"
4815 ::ini::commentchar "#"
4816 set f [::ini::open $file_name]
4817 set properties [dict create]
4818 foreach sec [::ini::sections $f] {
4820 set key_pairs [::ini::get $f $sec]
4823 regsub -all {\{\"} $key_pairs "\{" key_pairs
4824 regsub -all {\"\}} $key_pairs "\}" key_pairs
4826 dict set properties $new_sec [dict create {*}$key_pairs]
4839 proc ReadExtraFileList { extra_file_name } {
4840 set extra_file_dict [dict create]
4841 if {[
file exists $extra_file_name]} {
4842 set file [open $extra_file_name "r"]
4843 set file_data [read $file]
4846 set data [
split $file_data "\n"]
4847 foreach line $data {
4848 if {![regexp {^ *$} $line] & ![regexp {^ *\#} $line] } {
4849 set ip_and_md5 [regexp -all -inline {\S+} $line]
4850 dict lappend extra_file_dict "[
lindex $ip_and_md5 0]" "[
lindex $ip_and_md5 1]"
4854 return $extra_file_dict
4869 proc ReadListFile args {
4873 if { [
catch {
package require cmdline} ERROR] } {
4874 puts "$ERROR\n If you are running this script on tclsh, you can fix this by installing 'tcllib'"
4880 {lib.arg "" "The name of the library files will be added to, if not given will be extracted from the file name."}
4881 {fileset.arg "" "The name of the library, from the main list file"}
4882 {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."}
4884 set usage "USAGE: ReadListFile \[options\] <list file> <path>"
4885 if {[
catch {
array set options [
cmdline::getoptions args $parameters $usage]}] || [
llength $args] != 2 } {
4889 set list_file [
lindex $args 0]
4890 set path [
lindex $args 1]
4891 set sha_mode $options(sha_mode)
4892 set lib $options(lib)
4893 set fileset $options(fileset)
4895 if { $sha_mode == 1} {
4896 set sha_mode_opt "-sha_mode"
4903 set lib [
file rootname [
file tail $list_file]]
4905 set fp [open $list_file r]
4906 set file_data [read $fp]
4908 set list_file_ext [
file extension $list_file]
4909 switch $list_file_ext {
4911 if {$fileset eq ""} {
4917 set fileset "constrs_1"
4920 set fileset "sources_1"
4924 set libraries [dict create]
4925 set filesets [dict create]
4926 set properties [dict create]
4928 set data [
split $file_data "\n"]
4929 set n [
llength $data]
4930 Msg Debug "$n lines read from $list_file."
4933 foreach line $data {
4935 if {![regexp {^ *$} $line] & ![regexp {^ *\#} $line] } {
4936 set file_and_prop [regexp -all -inline {\S+} $line]
4937 set srcfile [
lindex $file_and_prop 0]
4938 set srcfile "$path/$srcfile"
4940 set srcfiles [glob -nocomplain $srcfile]
4943 if {$srcfiles != $srcfile && ! [
string equal $srcfiles ""]} {
4944 Msg Debug "Wildcard source expanded from $srcfile to $srcfiles"
4946 if {![
file exists $srcfile]} {
4947 Msg CriticalWarning "File: $srcfile (from list file: $list_file) does not exist."
4952 foreach vhdlfile $srcfiles {
4953 if {[
file exists $vhdlfile]} {
4954 set vhdlfile [
file normalize $vhdlfile]
4955 set extension [
file extension $vhdlfile]
4957 set prop [
lrange $file_and_prop 1 end]
4960 set library [
lindex [regexp -inline {\ylib\s*=\s*(.+?)\y.*} $prop] 1]
4961 if { $library == "" } {
4965 if { $extension == $list_file_ext } {
4968 set ref_path [
lindex [regexp -inline {\ypath\s*=\s*(\S+).*} $prop] 1]
4969 if { $ref_path eq "" } {
4972 set ref_path [
file normalize $path/$ref_path]
4974 Msg Debug "List file $vhdlfile found in list file, recursively opening it using path \"$ref_path\"..."
4975 lassign [
ReadListFile {*}"-lib $library -fileset $fileset $sha_mode_opt $vhdlfile $ref_path"] l p fs
4977 set properties [
MergeDict $p $properties]
4979 }
elseif {[lsearch {.src .sim .con ReadExtraFileList} $extension] >= 0 } {
4981 Msg Error "$vhdlfile cannot be included into $list_file, $extension files must be included into $extension files."
4984 regsub -all " *= *" $prop "=" prop
4988 if { [
string first "lib=" $p] == -1} {
4990 set pos [
string first "=" $p]
4994 set prop_name [
string range $p 0 [
expr {$pos - 1}]]
4997 dict lappend properties $vhdlfile $p
4998 Msg Debug "Adding property $p to $vhdlfile..."
4999 }
elseif { $list_file_ext != ".ipb" } {
5000 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]\]"
5004 if { [lsearch {.xci .ip .bd .xcix} $extension] >= 0} {
5006 set lib_name "ips.src"
5007 }
elseif { [
IsInList $extension {.vhd .vhdl}] || $list_file_ext == ".sim"} {
5009 if { ![
IsInList $extension {.vhd .vhdl}]} {
5010 set lib_name "others.sim"
5012 set lib_name "$library$list_file_ext"
5014 }
elseif { $list_file_ext == ".con" } {
5015 set lib_name "sources.con"
5016 }
elseif { $list_file_ext == ".ipb" } {
5017 set lib_name "xml.ipb"
5020 set lib_name "others.src"
5023 Msg Debug "Appending $vhdlfile to $lib_name list..."
5024 dict lappend libraries $lib_name $vhdlfile
5025 if { $sha_mode != 0 && [
file type $vhdlfile] eq "link"} {
5028 dict lappend libraries $lib_name $real_file
5029 Msg Debug "File $vhdlfile is a soft link, also adding the real file: $real_file"
5034 if {[dict exists $filesets $fileset] == 0} {
5036 Msg Debug "Adding $fileset to the fileset dictionary..."
5037 Msg Debug "Adding library $lib_name to fileset $fileset..."
5038 dict set filesets $fileset $lib_name
5042 Msg Debug "Adding library $lib_name to fileset $fileset..."
5043 dict lappend filesets $fileset $lib_name
5049 Msg CriticalWarning "File $vhdlfile not found."
5055 if {$sha_mode != 0} {
5057 if {$list_file_ext eq ".ipb"} {
5058 set sha_lib "xml.ipb"
5060 set sha_lib $lib$list_file_ext
5062 dict lappend libraries $sha_lib [
file normalize $list_file]
5063 if {[
file type $list_file] eq "link"} {
5066 dict lappend libraries $lib$list_file_ext $real_file
5067 Msg Debug "List file $list_file is a soft link, also adding the real file: $real_file"
5070 return [list $libraries $properties $filesets]
5078 proc Relative {base dst} {
5079 if {![
string equal [
file pathtype $base] [
file pathtype $dst]]} {
5080 Msg CriticalWarning "Unable to compute relation for paths of different path types: [
file pathtype $base] vs. [
file pathtype $dst], ($base vs. $dst)"
5084 set base [
file normalize [
file join [
pwd] $base]]
5085 set dst [
file normalize [
file join [
pwd] $dst]]
5088 set base [
file split $base]
5089 set dst [
file split $dst]
5091 while {[
string equal [
lindex $dst 0] [
lindex $base 0]]} {
5092 set dst [
lrange $dst 1 end]
5093 set base [
lrange $base 1 end]
5094 if {![
llength $dst]} {break}
5097 set dstlen [
llength $dst]
5098 set baselen [
llength $base]
5100 if {($dstlen == 0) && ($baselen == 0)} {
5103 while {$baselen > 0} {
5104 set dst [
linsert $dst 0 ..]
5107 set dst [
eval [
linsert $dst 0 file join]]
5118 proc RelativeLocal {pathName filePath} {
5119 if {[
string first [
file normalize $pathName] [
file normalize $filePath]] != -1} {
5120 return [
Relative $pathName $filePath]
5131 proc RemoveDuplicates {mydict} {
5132 set new_dict [dict create]
5133 foreach key [dict keys $mydict] {
5134 set values [
DictGet $mydict $key]
5135 foreach value $values {
5136 set idxs [
lreverse [
lreplace [lsearch -exact -all $values $value] 0 0]]
5138 set values [
lreplace $values $idx $idx]
5141 dict set new_dict $key $values
5152 proc ResetRepoFiles {reset_file} {
5153 if {[
file exists $reset_file]} {
5154 Msg Info "Found $reset_file, opening it..."
5155 set fp [open $reset_file r]
5156 set wild_cards [lsearch -all -inline -not -regexp [
split [read $fp] "\n"] "^ *$"]
5158 Msg Info "Found the following files/wild cards to restore if modified: $wild_cards..."
5159 foreach w $wild_cards {
5161 if {[
llength $mod_files] > 0} {
5162 Msg Info "Found modified $w files: $mod_files, will restore them..."
5165 Msg Info "No modified $w files found."
5176 proc RestoreModifiedFiles {{repo_path "."} {pattern "."}} {
5179 set ret [
Git checkout $pattern]
5190 proc SearchHogProjects {dir} {
5191 set projects_list {}
5192 if {[
file exists $dir]} {
5193 if {[
file isdirectory $dir]} {
5194 foreach proj_dir [glob -nocomplain -types d $dir/*] {
5195 if {![regexp {^.*Top/+(.*)$} $proj_dir dummy proj_name]} {
5196 Msg Warning "Could not parse Top directory $dir"
5199 if { [
file exists "$proj_dir/hog.conf"] } {
5200 lappend projects_list $proj_name
5203 lappend projects_list $p
5209 Msg Error "Input $dir is not a directory!"
5212 Msg Error "Directory $dir doesn't exist!"
5214 return $projects_list
5223 proc SetGenericsSimulation {repo_path proj_dir target} {
5224 set top_dir "$repo_path/Top/$proj_dir"
5226 set sim_cfg_index [lsearch -regexp -index 0 $read_aux ".*sim.conf"]
5227 set sim_cfg_index [lsearch -regexp -index 0 [
GetConfFiles $top_dir] ".*sim.conf"]
5228 set simsets [get_filesets]
5229 if { $simsets != "" } {
5230 if {[
file exists $top_dir/sim.conf]} {
5234 if {[dict size $sim_generics_dict] > 0 || [dict size $simsets_generics_dict] > 0} {
5235 foreach simset $simsets {
5237 if {[get_property FILESET_TYPE $simset] != "SimulationSrcs" } {
5241 if {[dict exists $simsets_generics_dict $simset:generics]} {
5242 set simset_generics_dict [dict get $simsets_generics_dict $simset:generics]
5244 set merged_generics_dict [dict merge $sim_generics_dict $simset_generics_dict]
5246 set_property generic $generic_str [get_filesets $simset]
5247 Msg Debug "Setting generics $generic_str for simulator $target and simulation file-set $simset..."
5248 }
elseif {[dict size $sim_generics_dict] > 0} {
5250 set_property generic $generic_str [get_filesets $simset]
5251 Msg Debug "Setting generics $generic_str for simulator $target and simulation file-set $simset..."
5256 if {[glob -nocomplain "$top_dir/list/*.sim"] ne ""} {
5257 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."
5270 proc SetTopProperty {top_module fileset} {
5271 Msg Info "Setting TOP property to $top_module module"
5274 set_property "top" $top_module [get_filesets $fileset]
5277 set_global_assignment -name TOP_LEVEL_ENTITY $top_module
5279 set_root -module $top_module
5281 prj_impl option top $top_module
5286 proc VIVADO_PATH_PROPERTIES {} {
5287 return {"\.*\.TCL\.PRE$" "^.*\.TCL\.POST$" "^RQS_FILES$" "^INCREMENTAL\_CHECKPOINT$"}
5297 proc WriteConf {file_name config {comment ""}} {
5298 if { [
catch {
package require inifile 0.2.3} ERROR] } {
5299 puts "$ERROR\n If you are running this script on tclsh, you can fix this by installing 'tcllib'"
5303 ::ini::commentchar "#"
5304 set f [::ini::open $file_name w]
5306 foreach sec [dict keys $config] {
5307 set section [dict get $config $sec]
5308 dict for {p v} $section {
5309 if {[string trim $v] == ""} {
5310 Msg Warning "Property $p has empty value. Skipping..."
5313 ::ini::set $f $sec $p $v
5318 if {![
string equal "$comment" ""]} {
5319 ::ini::comment $f [
lindex [::ini::sections $f] 0] "" $comment
5335 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 ""}} {
5336 Msg Info "Passing parameters/generics to project's top module..."
5339 set generic_string [
concat \
5351 if {$xml_hash != "" && $xml_ver != ""} {
5352 lappend generic_string \
5357 foreach l $libs v $vers h $hashes {
5360 lappend generic_string "$ver" "$hash"
5363 foreach e $ext_names h $ext_hashes {
5365 lappend generic_string "$hash"
5368 foreach repo $user_ip_repos v $user_ip_vers h $user_ip_hashes {
5369 set repo_name [
file tail $repo]
5370 set ver "[
string toupper $repo_name]_VER=[
FormatGeneric $v]"
5371 set hash "[
string toupper $repo_name]_SHA=[
FormatGeneric $h]"
5372 lappend generic_string "$ver" "$hash"
5375 if {$flavour != -1} {
5376 lappend generic_string "FLAVOUR=$flavour"
5382 set generic_string "$prj_generics $generic_string"
5388 if {$mode == "create" || [
IsISE]} {
5392 if {[
file exists $top_file]} {
5395 Msg Debug "Found top level generics $generics in $top_file"
5397 set filtered_generic_string ""
5399 foreach generic_to_set [
split [
string trim $generic_string]] {
5400 set key [
lindex [
split $generic_to_set "="] 0]
5401 if {[dict exists $generics $key]} {
5402 Msg Debug "Hog generic $key found in $top_name"
5403 lappend filtered_generic_string "$generic_to_set"
5405 Msg Warning "Generic $key is passed by Hog but is NOT present in $top_name."
5411 set generic_string $filtered_generic_string
5416 set_property generic $generic_string [current_fileset]
5417 Msg Info "Setting parameters/generics..."
5418 Msg Debug "Detailed parameters/generics: $generic_string"
5423 set simulator [get_property target_simulator [current_project]]
5424 if {$mode == "create"} {
5431 Msg Info "Setting Synplify parameters/generics one by one..."
5432 foreach generic $generic_string {
5433 Msg Debug "Setting Synplify generic: $generic"
5434 set_option -hdl_param -set "$generic"
5437 Msg Info "Setting Diamond parameters/generics one by one..."
5438 prj_impl option -impl Implementation0 HDL_PARAM "$generic_string"
5448 proc WriteGenericsToBdIPs {mode repo_path proj generic_string} {
5449 Msg Debug "Parameters/generics passed to WriteGenericsToIP: $generic_string"
5451 set bd_ip_generics false
5453 if {[dict exists $properties "hog"]} {
5454 set propDict [dict get $properties "hog"]
5455 if {[dict exists $propDict "PASS_GENERICS_TO_BD_IPS"]} {
5456 set bd_ip_generics [dict get $propDict "PASS_GENERICS_TO_BD_IPS"]
5460 if {[
string compare [
string tolower $bd_ip_generics] "false"]==0} {
5464 if {$mode == "synth"} {
5465 Msg Info "Attempting to apply generics pre-synthesis..."
5466 set PARENT_PRJ [get_property "PARENT.PROJECT_PATH" [current_project]]
5467 set workaround [open "$repo_path/Projects/$proj/.hog/presynth_workaround.tcl" "w"]
5468 puts $workaround "source \[lindex \$argv 0\];"
5469 puts $workaround "open_project \[lindex \$argv 1\];"
5470 puts $workaround "WriteGenericsToBdIPs \[lindex \$argv 2\] \[lindex \$argv 3\] \[lindex \$argv 4\] \[lindex \$argv 5\];"
5471 puts $workaround "close_project"
5474 exec vivado -mode batch -source $repo_path/Projects/$proj/.hog/presynth_workaround.tcl \
5475 -tclargs $repo_path/Hog/Tcl/hog.tcl $PARENT_PRJ \
5476 "childprocess" $repo_path $proj $generic_string
5478 Msg Error "Encountered an error while attempting workaround: $errMsg"
5480 file delete $repo_path/Projects/$proj/.hog/presynth_workaround.tcl
5482 Msg Info "Done applying generics pre-synthesis."
5486 Msg Info "Looking for IPs to add generics to..."
5487 set ips_generic_string ""
5488 foreach generic_to_set [
split [
string trim $generic_string]] {
5489 set key [
lindex [
split $generic_to_set "="] 0]
5490 set value [
lindex [
split $generic_to_set "="] 1]
5491 append ips_generic_string "CONFIG.$key $value "
5495 if {[
string compare [
string tolower $bd_ip_generics] "true"]==0} {
5498 set ip_regex $bd_ip_generics
5501 set ip_list [get_ips -regex $ip_regex]
5502 Msg Debug "IPs found with regex \{$ip_regex\}: $ip_list"
5504 set regen_targets {}
5506 foreach {ip} $ip_list {
5507 set WARN_ABOUT_IP false
5508 set ip_props [list_property [get_ips $ip]]
5511 if {[lsearch -exact $ip_props "IS_BD_CONTEXT"] == -1} {
5515 if {[get_property "IS_BD_CONTEXT" [get_ips $ip]] eq "1"} {
5516 foreach {ip_prop} $ip_props {
5517 if {[dict exists $ips_generic_string $ip_prop]} {
5518 if {$WARN_ABOUT_IP == false} {
5519 lappend regen_targets [get_property SCOPE [get_ips $ip]]
5520 Msg Warning "The ip \{$ip\} contains generics that are set by Hog.\
5521 If this is IP is apart of a block design, the .bd file may contain stale, unused, values.\
5522 Hog will always apply the most up-to-date values to the IP during synthesis,\
5523 however these values may or may not be reflected in the .bd file."
5524 set WARN_ABOUT_IP true
5529 set xci_path [get_property IP_FILE [get_ips $ip]]
5531 if {[
string equal $generic_format "ERROR"]} {
5532 Msg Warning "Could not find format for generic $ip_prop in IP $ip. Skipping..."
5536 set value_to_set [dict get $ips_generic_string $ip_prop]
5537 switch -exact $generic_format {
5539 if {[
string match "32'h*" $value_to_set]} {
5540 scan [
string map {"32'h" ""} $value_to_set] "%x" value_to_set
5544 set value_to_set [
expr {$value_to_set ? "true" : "false"}]
5547 if {[
string match "32'h*" $value_to_set]} {
5548 binary scan [
binary format H* [
string map {"32'h" ""} $value_to_set]] d value_to_set
5552 if {[
string match "32'h*" $value_to_set]} {
5553 set value_to_set [
string map {"32'h" "0x"} $value_to_set]
5557 set value_to_set [
format "%s" $value_to_set]
5560 Msg Warning "Unknown generic format $generic_format for IP $ip. Will attempt to pass as string..."
5565 Msg Info "The IP \{$ip\} contains: $ip_prop ($generic_format), setting it to $value_to_set."
5566 if {[
catch {set_property -name $ip_prop -value $value_to_set -objects [ get_ips $ip]} prop_error]} {
5567 Msg CriticalWarning "Failed to set property $ip_prop to $value_to_set for IP \{$ip\}: $prop_error"
5574 foreach {regen_target} [lsort -unique $regen_targets] {
5575 Msg Info "Regenerating target: $regen_target"
5576 if {[
catch {generate_target -force all [get_files $regen_target]} prop_error]} {
5577 Msg CriticalWarning "Failed to regen targets: $prop_error"
5586 proc GetGenericFormatFromXciXML {generic_name xml_file} {
5588 if {![
file exists $xml_file]} {
5589 Msg Error "Could not find XML file: $xml_file"
5593 set fp [open $xml_file r]
5594 set xci_data [read $fp]
5597 set paramType "string"
5598 set modelparam_regex [
format {^.*\y%s\y.*$} [
string map {"CONFIG." "MODELPARAM_VALUE."} $generic_name]]
5599 set format_regex {format="([^"]+)"}
5601 set line [
lindex [regexp -inline -line $modelparam_regex $xci_data] 0]
5602 Msg Debug "line: $line"
5604 if {[regexp $format_regex $line match format_value]} {
5605 Msg Debug "Extracted: $format_value format from xml"
5606 set paramType $format_value
5608 Msg Debug "No format found, using string"
5617 proc GetGenericFormatFromXci {generic_name xci_file} {
5619 if {! [
file exists $xci_file]} {
5620 Msg Error "Could not find XCI file: $xci_file"
5624 set fp [open $xci_file r]
5625 set xci_data [read $fp]
5628 set paramType "string"
5629 if {[
string first "xilinx.com:schema:json_instance:1.0" $xci_data] == -1} {
5630 Msg Debug "XCI format is not JSON, trying XML..."
5631 set xml_file "[
file rootname $xci_file].xml"
5636 set generic_name [
string map {"CONFIG." ""} $generic_name]
5637 set ip_inst [
ParseJSON $xci_data "ip_inst"]
5638 set parameters [dict get $ip_inst parameters]
5639 set component_parameters [dict get $parameters component_parameters]
5640 if {[dict exists $component_parameters $generic_name]} {
5641 set generic_info [dict get $component_parameters $generic_name]
5642 if {[dict exists [
lindex $generic_info 0] format]} {
5643 set paramType [dict get [
lindex $generic_info 0] format]
5644 Msg Debug "Extracted: $paramType format from xci"
5647 Msg Debug "No format found, using string"
5660 proc WriteGitLabCIYAML {proj_name {ci_conf ""}} {
5661 if { [
catch {
package require yaml 0.3.3} YAMLPACKAGE]} {
5662 Msg CriticalWarning "Cannot find package YAML.\n Error message: $YAMLPACKAGE. If you are running on tclsh, you can fix this by installing package \"tcllib\""
5667 if {$ci_conf != ""} {
5669 foreach sec [dict keys $ci_confs] {
5670 if {[
string first : $sec] == -1} {
5671 lappend job_list $sec
5675 set job_list {"generate_project" "simulate_project"}
5679 set out_yaml [huddle create]
5680 foreach job $job_list {
5682 set huddle_tags [huddle list]
5684 set sec_dict [dict create]
5686 if {$ci_confs != ""} {
5687 foreach var [dict keys [dict get $ci_confs $job]] {
5688 if {$var == "tags"} {
5689 set tag_section "tags"
5690 set tags [dict get [dict get $ci_confs $job] $var]
5691 set tags [
split $tags ","]
5693 set tag_list [huddle list $tag]
5694 set huddle_tags [huddle combine $huddle_tags $tag_list]
5697 dict set sec_dict $var [dict get [dict get $ci_confs $job] $var]
5703 set huddle_variables [huddle create "PROJECT_NAME" $proj_name "extends" ".vars"]
5704 if {[dict exists $ci_confs "$job:variables"]} {
5705 set var_dict [dict get $ci_confs $job:variables]
5706 foreach var [dict keys $var_dict] {
5708 set value [dict get $var_dict "$var"]
5709 set var_inner [huddle create "$var" "$value"]
5710 set huddle_variables [huddle combine $huddle_variables $var_inner]
5715 set middle [huddle create "extends" ".$job" "variables" $huddle_variables]
5716 foreach sec [dict keys $sec_dict] {
5717 set value [dict get $sec_dict $sec]
5718 set var_inner [huddle create "$sec" "$value"]
5719 set middle [huddle combine $middle $var_inner]
5721 if {$tag_section != ""} {
5722 set middle2 [huddle create "$tag_section" $huddle_tags]
5723 set middle [huddle combine $middle $middle2]
5726 set outer [huddle create "$job:$proj_name" $middle]
5727 set out_yaml [huddle combine $out_yaml $outer]
5730 return [
string trimleft [ yaml::huddle2yaml $out_yaml] "-"]
5740 proc WriteListFiles {libs props list_path repo_path {ext_path ""} } {
5742 foreach lib [dict keys $libs] {
5743 if {[
llength [
DictGet $libs $lib]] > 0} {
5744 set list_file_name $list_path$lib
5745 set list_file [open $list_file_name w]
5746 Msg Info "Writing $list_file_name..."
5747 foreach file [
DictGet $libs $lib] {
5749 set prop [
DictGet $props $file]
5753 puts $list_file "$file_path $prop"
5756 set ext_list_file [open "[
file rootname $list_file].ext" a]
5757 puts $ext_list_file "$file_path $prop"
5758 close $ext_list_file
5761 Msg Warning "The path of file $file is not relative to your repository. Please check!"
5776 proc WriteSimListFiles {libs props simsets list_path repo_path } {
5778 foreach simset [dict keys $simsets] {
5779 set list_file_name $list_path/${simset}.sim
5780 set list_file [open $list_file_name w]
5781 Msg Info "Writing $list_file_name..."
5782 foreach lib [
DictGet $simsets $simset] {
5783 foreach file [
DictGet $libs $lib] {
5785 set prop [
DictGet $props $file]
5789 set lib_name [
file rootname $lib]
5790 if {$lib_name != $simset} {
5791 lappend prop "lib=$lib_name"
5793 puts $list_file "$file_path $prop"
5796 Msg Warning "The path of file $file is not relative to your repository. Please check!"
5808 proc WriteToFile {File msg} {
5809 set f [open $File a+]
5820 proc WriteUtilizationSummary {input output project_name run} {
5821 set f [open $input "r"]
5822 set o [open $output "a"]
5823 puts $o "## $project_name $run Utilization report\n\n"
5824 struct::matrix util_m
5825 util_m add columns 14
5828 util_m add row "| **Site Type** | **Used** | **Fixed** | **Prohibited** | **Available** | **Util%** |"
5829 util_m add row "| --- | --- | --- | --- | --- | --- |"
5831 util_m add row "| **Site Type** | **Used** | **Fixed** | **Available** | **Util%** |"
5832 util_m add row "| --- | --- | --- | --- | --- |"
5842 while {[
gets $f line] >= 0} {
5843 if { ( [
string first "| CLB LUTs" $line] >= 0 || [
string first "| Slice LUTs" $line] >= 0 ) && $luts == 0 } {
5844 util_m add row $line
5847 if { ( [
string first "| CLB Registers" $line] >= 0 || [
string first "| Slice Registers" $line] >= 0 ) && $regs == 0} {
5848 util_m add row $line
5851 if { [
string first "| Block RAM Tile" $line] >= 0 && $bram == 0 } {
5852 util_m add row $line
5855 if { [
string first "URAM " $line] >= 0 && $uram == 0} {
5856 util_m add row $line
5859 if { [
string first "DSPs" $line] >= 0 && $dsps == 0 } {
5860 util_m add row $line
5863 if { [
string first "Bonded IOB" $line] >= 0 && $ios == 0 } {
5864 util_m add row $line
5871 puts $o [util_m format 2string]
5877 Msg Error "Found Git version older than 2.7.2. Hog will not work as expected, exiting now."