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 {top\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 {topsim\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 {runtime\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 {scoped_to_ref\s*=\s*(.+?)\y.*} $props] 1]
249 set cell [
lindex [regexp -inline {scoped_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 {top\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 {top\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 {top\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 return [
expr {[info commands project_new] != ""}]
3795 proc IsRelativePath {path} {
3796 if {[
string index $path 0] == "/" || [
string index $path 0] == "~"} {
3804 proc IsSynplify {} {
3805 return [
expr {[info commands program_version] != ""}]
3810 return [
expr {![IsQuartus] && ![IsXilinx] && ![IsLibero] && ![IsSynplify] && ![IsDiamond]}]
3818 proc IsVersal {part} {
3819 if { [regexp {^(xcvp|xcvm|xcve|xcvc|xqvc|xqvm).*} $part] } {
3829 return [
expr {[string first Vivado [version]] == 0}]
3837 return [
expr {[info commands get_property] != ""}]
3845 proc IsZynq {part} {
3846 if { [regexp {^(xc7z|xczu).*} $part] } {
3861 proc LaunchImplementation {reset do_create run_folder project_name {repo_path .} {njobs 4} {do_bitstream 0}} {
3862 Msg Info "Starting implementation flow..."
3864 if { $reset == 1 && $do_create == 0} {
3865 Msg Info "Resetting run before launching implementation..."
3870 source $repo_path/Hog/Tcl/integrated/pre-implementation.tcl
3873 if {$do_bitstream == 1} {
3874 launch_runs impl_1 -to_step [
BinaryStepName [get_property PART [current_project]]] $njobs -dir $run_folder
3876 launch_runs impl_1 -jobs $njobs -dir $run_folder
3881 Msg Info "running post-implementation"
3882 source $repo_path/Hog/Tcl/integrated/post-implementation.tcl
3883 if {$do_bitstream == 1} {
3884 Msg Info "running pre-bitstream"
3885 source $repo_path/Hog/Tcl/integrated/pre-bitstream.tcl
3886 Msg Info "running post-bitstream"
3887 source $repo_path/Hog/Tcl/integrated/post-bitstream.tcl
3891 set prog [get_property PROGRESS [get_runs impl_1]]
3892 set status [get_property STATUS [get_runs impl_1]]
3893 Msg Info "Run: impl_1 progress: $prog, status : $status"
3897 set status_file [open "$run_folder/timing.txt" "w"]
3898 puts $status_file "## $project_name Timing summary"
3900 set f [open [
lindex [glob "$run_folder/impl_1/*.twr" 0]]]
3902 while {[
gets $f line] >= 0} {
3903 if { [
string match "Timing summary:" $line] } {
3904 while {[
gets $f line] >= 0} {
3905 if { [
string match "Timing errors:*" $line] } {
3906 set errs [regexp -inline -- {[0-9]+} $line]
3908 if { [
string match "*Footnotes*" $line] } {
3911 puts $status_file "$line"
3920 Msg Info "Time requirements are met"
3921 file rename -force "$run_folder/timing.txt" "$run_folder/timing_ok.txt"
3924 Msg CriticalWarning "Time requirements are NOT met"
3925 file rename -force "$run_folder/timing.txt" "$run_folder/timing_error.txt"
3931 set wns [get_property STATS.WNS [get_runs [current_run]]]
3932 set tns [get_property STATS.TNS [get_runs [current_run]]]
3933 set whs [get_property STATS.WHS [get_runs [current_run]]]
3934 set ths [get_property STATS.THS [get_runs [current_run]]]
3935 set tpws [get_property STATS.TPWS [get_runs [current_run]]]
3937 if {$wns >= 0 && $whs >= 0 && $tpws >= 0} {
3938 Msg Info "Time requirements are met"
3939 set status_file [open "$run_folder/timing_ok.txt" "w"]
3942 Msg CriticalWarning "Time requirements are NOT met"
3943 set status_file [open "$run_folder/timing_error.txt" "w"]
3947 Msg Status "*** Timing summary ***"
3948 Msg Status "WNS: $wns"
3949 Msg Status "TNS: $tns"
3950 Msg Status "WHS: $whs"
3951 Msg Status "THS: $ths"
3952 Msg Status "TPWS: $tpws"
3958 puts $status_file "## $project_name Timing summary"
3960 m add row "| **Parameter** | \"**value (ns)**\" |"
3961 m add row "| --- | --- |"
3962 m add row "| WNS: | $wns |"
3963 m add row "| TNS: | $tns |"
3964 m add row "| WHS: | $whs |"
3965 m add row "| THS: | $ths |"
3966 m add row "| TPWS: | $tpws |"
3968 puts $status_file [m format 2string]
3969 puts $status_file "\n"
3970 if {$timing_ok == 1} {
3971 puts $status_file " Time requirements are met."
3973 puts $status_file "Time requirements are **NOT** met."
3975 puts $status_file "\n\n"
3979 if {$prog ne "100%"} {
3980 Msg Error "Implementation error"
3985 lassign [
GetRepoVersions [
file normalize ./Top/$project_name] $repo_path] sha
3987 Msg Info "Git describe set to $describe"
3989 set dst_dir [
file normalize "$repo_path/bin/$project_name\-$describe"]
3994 if {[
file exists $run_folder/versions.txt]} {
3995 file copy -force $run_folder/versions.txt $dst_dir
3997 Msg Warning "No versions file found in $run_folder/versions.txt"
4000 set timing_files [ glob -nocomplain "$run_folder/timing_*.txt"]
4001 set timing_file [
file normalize [
lindex $timing_files 0]]
4003 if {[
file exists $timing_file]} {
4004 file copy -force $timing_file $dst_dir/
4006 Msg Warning "No timing file found, not a problem if running locally"
4010 set revision [get_current_revision]
4012 if {[
catch {execute_module -tool fit} result]} {
4013 Msg Error "Result: $result\n"
4014 Msg Error "Place & Route failed. See the report file.\n"
4016 Msg Info "\nINFO: Place & Route was successful for revision $revision.\n"
4019 if {[
catch {execute_module -tool sta -args "--do_report_timing"} result]} {
4020 Msg Error "Result: $result\n"
4021 Msg Error "Time Quest failed. See the report file.\n"
4023 Msg Info "Time Quest was successfully run for revision $revision.\n"
4026 set panel "Timing Analyzer||Timing Analyzer Summary"
4027 set device [ get_report_panel_data -name $panel -col 1 -row_name "Device Name"]
4028 set timing_model [ get_report_panel_data -name $panel -col 1 -row_name "Timing Models"]
4029 set delay_model [ get_report_panel_data -name $panel -col 1 -row_name "Delay Model"]
4031 Msg Info "*******************************************************************"
4032 Msg Info "Device: $device"
4033 Msg Info "Timing Models: $timing_model"
4034 Msg Info "Delay Model: $delay_model"
4037 Msg Info "*******************************************************************"
4040 Msg Info "Starting implementation flow..."
4041 if {[
catch {run_tool -name {PLACEROUTE}}] } {
4042 Msg Error "PLACEROUTE FAILED!"
4044 Msg Info "PLACEROUTE PASSED."
4048 Msg Info "Run VERIFYTIMING ..."
4049 if {[
catch {run_tool -name {VERIFYTIMING} -script {Hog/Tcl/integrated/libero_timing.tcl}}] } {
4050 Msg CriticalWarning "VERIFYTIMING FAILED!"
4052 Msg Info "VERIFYTIMING PASSED \n"
4058 lassign [
GetRepoVersions [
file normalize ./Top/$project_name] $repo_path] sha
4060 Msg Info "Git describe set to $describe"
4062 set dst_dir [
file normalize "$repo_path/bin/$project_name\-$describe"]
4063 file mkdir $dst_dir/reports
4066 if {[
file exists $run_folder/versions.txt]} {
4067 file copy -force $run_folder/versions.txt $dst_dir
4069 Msg Warning "No versions file found in $run_folder/versions.txt"
4072 set timing_file_path [
file normalize "$repo_path/Projects/timing_libero.txt"]
4073 if {[
file exists $timing_file_path]} {
4074 file copy -force $timing_file_path $dst_dir/reports/Timing.txt
4075 set timing_file [open $timing_file_path "r"]
4076 set status_file [open "$dst_dir/timing.txt" "w"]
4077 puts $status_file "## $project_name Timing summary\n\n"
4078 puts $status_file "| | |"
4079 puts $status_file "| --- | --- |"
4080 while {[
gets $timing_file line] >= 0} {
4081 if { [
string match "SUMMARY" $line] } {
4082 while {[
gets $timing_file line] >= 0} {
4083 if { [
string match "END SUMMARY" $line] } {
4086 if {[
string first ":" $line] == -1} {
4089 set out_string "| [
string map {: | } $line] |"
4090 puts $status_file "$out_string"
4095 Msg Warning "No timing file found, not a problem if running locally"
4100 set force_rst "-forceOne"
4102 prj_run Map $force_rst
4103 prj_run PAR $force_rst
4116 proc LaunchSimulation {project_name lib_path {simsets ""} {repo_path .}} {
4119 set project [
file tail $project_name]
4120 set main_sim_folder [
file normalize "$repo_path/Projects/$project_name/$project.sim/"]
4122 if {$simsets != ""} {
4123 set simsets_todo [
split $simsets ","]
4124 Msg Info "Will run only the following simsets (if they exist): $simsets_todo"
4129 set sim_dic [dict create]
4131 set use_simpass_str 0
4134 set proj_dir [
file normalize $repo_path/Top/$project_name]
4135 set sim_file [
file normalize $proj_dir/sim.conf]
4136 if {[
file exists $sim_file]} {
4137 Msg Info "Parsing simulation configuration file $sim_file..."
4144 if {[dict exists $globalSettings::SIM_PROPERTIES hog]} {
4145 set hog_sim_props [dict get $globalSettings::SIM_PROPERTIES hog]
4146 dict for {prop_name prop_val} $hog_sim_props {
4147 # If HOG_SIMPASS_STR is set, use the HOG_SIMPASS_STR string to search for in logs, after simulation is done
4148 if { $prop_name == "HOG_SIMPASS_STR" && $prop_val != "" } {
4149 Msg Info "Setting simulation pass string as '$prop_val'"
4150 set use_simpass_str 1
4151 set simpass_str $prop_val
4156 Msg Info "Retrieving list of simulation sets..."
4157 foreach s [get_filesets] {
4158 set type [get_property FILESET_TYPE $s]
4159 if {$type eq "SimulationSrcs"} {
4160 if {$simsets_todo != "" && $s ni $simsets_todo} {
4161 Msg Info "Skipping $s as it was not specified with the -simset option..."
4164 if {[
file exists "$repo_path/Top/$project_name/list/$s.sim"]} {
4165 set fp [open "$repo_path/Top/$project_name/list/$s.sim" r]
4166 set file_data [read $fp]
4168 set data [
split $file_data "\n"]
4169 set n [
llength $data]
4170 Msg Info "$n lines read from $s.sim"
4172 set firstline [
lindex $data 0]
4174 if { [regexp {^ *\#Simulator} $firstline] } {
4175 set simulator_prop [regexp -all -inline {\S+} $firstline]
4176 set simulator [
string tolower [
lindex $simulator_prop 1]]
4178 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."
4179 set simulator "xsim"
4181 if {$simulator eq "skip_simulation"} {
4182 Msg Info "Skipping simulation for $s"
4185 set_property "target_simulator" $simulator [current_project]
4186 Msg Info "Creating simulation scripts for $s..."
4187 if { [
file exists $repo_path/Top/$project_name/pre-simulation.tcl] } {
4188 Msg Info "Running $repo_path/Top/$project_name/pre-simulation.tcl"
4189 source $repo_path/Top/$project_name/pre-simulation.tcl
4191 if { [
file exists $repo_path/Top/$project_name/pre-$s-simulation.tcl] } {
4192 Msg Info "Running $repo_path/Top/$project_name/pre-$s-simulation.tcl"
4193 source Running $repo_path/Top/$project_name/pre-$s-simulation.tcl
4195 current_fileset -simset $s
4196 set sim_dir $main_sim_folder/$s/behav
4197 set sim_output_logfile $sim_dir/xsim/simulate.log
4198 if { ([
string tolower $simulator] eq "xsim") } {
4199 set sim_name "xsim:$s"
4200 if { [
catch { launch_simulation -simset [get_filesets $s]} log] } {
4203 Msg CriticalWarning "Simulation failed for $s, error info: $::errorInfo"
4204 lappend failed $sim_name
4209 if {$use_simpass_str == 1} {
4212 set file_desc [open $sim_output_logfile r]
4213 set log [read $file_desc]
4216 Msg Info "Searching for simulation pass string: '$simpass_str'"
4217 if {[
string first $simpass_str $log] == -1} {
4218 Msg CriticalWarning "Simulation failed for $s, error info: '$simpass_str' NOT found!"
4219 lappend failed $sim_name
4222 lappend success $sim_name
4225 lappend success $sim_name
4229 Msg Info "Simulation library path is set to $lib_path."
4231 if {!([
file exists $lib_path])} {
4232 Msg Warning "Could not find simulation library path: $lib_path, $simulator simulation will not work."
4236 if {$simlib_ok == 1} {
4237 set_property "compxlib.${simulator}_compiled_library_dir" [
file normalize $lib_path] [current_project]
4238 launch_simulation -scripts_only -simset [get_filesets $s]
4239 set top_name [get_property TOP $s]
4240 set sim_script [
file normalize $sim_dir/$simulator/]
4241 Msg Info "Adding simulation script location $sim_script for $s..."
4242 lappend sim_scripts $sim_script
4243 dict append sim_dic $sim_script $s
4245 Msg Error "Cannot run $simulator simulations without a valid library path"
4253 if {[
info exists sim_scripts]} {
4255 Msg Info "Generating IP simulation targets, if any..."
4257 foreach ip [get_ips] {
4258 generate_target simulation -quiet $ip
4263 Msg Info "====== Starting simulations runs ======"
4266 foreach s $sim_scripts {
4268 set cmd ./compile.sh
4269 Msg Info " ************* Compiling: $s ************* "
4271 set sim_name "comp:[dict get $sim_dic $s]"
4273 Msg CriticalWarning "Compilation failed for $s, error info: $::errorInfo"
4274 lappend failed $sim_name
4276 lappend success $sim_name
4278 Msg Info "###################### Compilation log starts ######################"
4279 Msg Info "\n\n$log\n\n"
4280 Msg Info "###################### Compilation log ends ######################"
4283 if { [
file exists "./elaborate.sh"] } {
4284 set cmd ./elaborate.sh
4285 Msg Info " ************* Elaborating: $s ************* "
4287 set sim_name "elab:[dict get $sim_dic $s]"
4289 Msg CriticalWarning "Elaboration failed for $s, error info: $::errorInfo"
4290 lappend failed $sim_name
4292 lappend success $sim_name
4294 Msg Info "###################### Elaboration log starts ######################"
4295 Msg Info "\n\n$log\n\n"
4296 Msg Info "###################### Elaboration log ends ######################"
4298 set cmd ./simulate.sh
4299 Msg Info " ************* Simulating: $s ************* "
4304 if {$use_simpass_str == 1} {
4305 if {[
string first $simpass_str $log] == -1} {
4309 Msg Debug "Simulation pass string not set, relying on simulator exit code."
4314 set sim_name "sim:[dict get $sim_dic $s]"
4316 Msg CriticalWarning "Simulation failed for $s, error info: $::errorInfo"
4317 lappend failed $sim_name
4319 lappend success $sim_name
4321 Msg Info "###################### Simulation log starts ######################"
4322 Msg Info "\n\n$log\n\n"
4323 Msg Info "###################### Simulation log ends ######################"
4329 if {[
llength $success] > 0} {
4330 set successes [
join $success "\n"]
4331 Msg Info "The following simulation sets were successful:\n\n$successes\n\n"
4334 if {[
llength $failed] > 0} {
4335 set failures [
join $failed "\n"]
4336 Msg Error "The following simulation sets have failed:\n\n$failures\n\n"
4338 }
elseif {[
llength $success] > 0} {
4339 Msg Info "All the [
llength $success] compilations, elaborations and simulations were successful."
4342 Msg Info "Simulation done."
4344 Msg Warning "Simulation is not yet supported for [
GetIDEName]."
4357 proc LaunchSynthesis {reset do_create run_folder project_name {repo_path .} {ext_path ""} {njobs 4}} {
4359 if {$reset == 1 && $do_create == 0} {
4360 Msg Info "Resetting run before launching synthesis..."
4364 source $repo_path/Hog/Tcl/integrated/pre-synthesis.tcl
4366 launch_runs synth_1 -jobs $njobs -dir $run_folder
4368 set prog [get_property PROGRESS [get_runs synth_1]]
4369 set status [get_property STATUS [get_runs synth_1]]
4370 Msg Info "Run: synth_1 progress: $prog, status : $status"
4377 lassign [
GetRepoVersions [
file normalize ./Top/$project_name] $repo_path $ext_path] sha
4379 Msg Info "Git describe set to $describe"
4382 set xci_file [get_property IP_FILE $ip]
4384 set xci_path [
file dirname $xci_file]
4385 set xci_ip_name [
file rootname [
file tail $xci_file]]
4386 foreach rptfile [glob -nocomplain -directory $xci_path *.rpt] {
4387 file copy $rptfile $repo_path/bin/$project_name-$describe/reports
4411 if {$prog ne "100%"} {
4412 Msg Error "Synthesis error, status is: $status"
4416 set project [
file tail [
file rootname $project_name]]
4418 Msg Info "Number of jobs set to $njobs."
4419 set_global_assignment -name NUM_PARALLEL_PROCESSORS $njobs
4423 lassign [
GetRepoVersions [
file normalize $repo_path/Top/$project_name] $repo_path] sha
4426 set revision [get_current_revision]
4429 set tool_and_command [
split [get_global_assignment -name PRE_FLOW_SCRIPT_FILE] ":"]
4430 set tool [
lindex $tool_and_command 0]
4431 set pre_flow_script [
lindex $tool_and_command 1]
4432 set cmd "$tool -t $pre_flow_script quartus_map $project $revision"
4438 Msg Warning "Can not execute command $cmd"
4439 Msg Warning "LOG: $log"
4441 Msg Info "Pre flow script executed!"
4445 if { ![is_project_open] } {
4446 Msg Info "Re-opening project file $project_name..."
4447 project_open $project -current_revision
4451 if {[
catch {execute_module -tool map -args "--parallel"} result]} {
4452 Msg Error "Result: $result\n"
4453 Msg Error "Analysis & Synthesis failed. See the report file.\n"
4455 Msg Info "Analysis & Synthesis was successful for revision $revision.\n"
4459 defvar_set -name RWNETLIST_32_64_MIXED_FLOW -value 0
4461 Msg Info "Run SYNTHESIS..."
4462 if {[
catch {run_tool -name {SYNTHESIZE}}] } {
4463 Msg Error "SYNTHESIZE FAILED!"
4465 Msg Info "SYNTHESIZE PASSED!"
4471 set force_rst "-forceOne"
4473 prj_run Synthesis $force_rst
4474 if {[prj_syn] == "synplify"} {
4475 prj_run Translate $force_rst
4478 Msg Error "Impossible condition. You need to run this in an IDE."
4489 proc ListProjects {{repo_path .} {print 1} {ret_conf 0}} {
4490 set top_path [
file normalize $repo_path/Top]
4491 set confs [
findFiles [
file normalize $top_path] hog.conf]
4493 set confs [lsort $confs]
4497 set p [
Relative $top_path [
file dirname $c]]
4500 if { $description eq "test"} {
4501 set description " - Test project"
4502 }
elseif { $description ne ""} {
4503 set description " - $description"
4506 if {$print == 1 || $description ne " - Test project"} {
4508 set g [
file dirname $p]
4519 if {$ret_conf == 0} {
4534 proc Logo { {repo_path .} } {
4535 if {[
info exists ::env(HOG_COLORED)] && [
string match "ENABLED" $::env(HOG_COLORED)]} {
4536 set logo_file "$repo_path/Hog/images/hog_logo_color.txt"
4538 set logo_file "$repo_path/Hog/images/hog_logo.txt"
4543 set ver [
Git {describe --always}]
4546 if {[
file exists $logo_file]} {
4547 set f [open $logo_file "r"]
4550 set lines [
split $data "\n"]
4556 Msg CriticalWarning "Logo file: $logo_file not found"
4559 Msg Status "Version: $ver"
4565 proc Md5Sum {file_name} {
4566 if {!([
file exists $file_name])} {
4567 Msg Warning "Could not find $file_name."
4570 if {[
catch {
package require md5 2.0.7} result]} {
4571 Msg Warning "Tcl package md5 version 2.0.7 not found ($result), will use command line..."
4572 set hash [
lindex [
Execute md5sum $file_name] 0]
4574 set file_hash [
string tolower [md5::md5 -hex -file $file_name]]
4587 proc MergeDict {dict0 dict1} {
4588 set outdict [dict merge $dict1 $dict0]
4589 foreach key [dict keys $dict1] {
4590 if {[dict exists $dict0 $key]} {
4591 set temp_list [dict get $dict1 $key]
4592 foreach vhdfile $temp_list {
4595 dict lappend outdict $key $vhdfile
4607 proc MoveElementToEnd {inputList element} {
4608 set index [lsearch $inputList $element]
4610 set inputList [
lreplace $inputList $index $index]
4611 lappend inputList $element
4621 proc Msg {level msg {title ""}} {
4622 set level [
string tolower $level]
4623 if {$title == ""} {
set title [
lindex [
info level [
expr {[info level]-1}]] 0]}
4624 if {$level == 0 || $level == "status" || $level == "extra_info"} {
4627 }
elseif {$level == 1 || $level == "info"} {
4630 }
elseif {$level == 2 || $level == "warning"} {
4631 set vlevel {WARNING}
4633 }
elseif {$level == 3 || [
string first "critical" $level] !=-1} {
4634 set vlevel {CRITICAL WARNING}
4635 set qlevel critical_warning
4636 }
elseif {$level == 4 || $level == "error"} {
4639 }
elseif {$level == 5 || $level == "debug"} {
4640 if {([
info exists ::DEBUG_MODE] && $::DEBUG_MODE == 1) || ([
info exists ::env(HOG_DEBUG_MODE)] && $::env(HOG_DEBUG_MODE) == 1)} {
4642 set qlevel extra_info
4643 set msg "DEBUG: \[Hog:$title\] $msg"
4648 puts "Hog Error: level $level not defined"
4655 set status [
catch {send_msg_id Hog:$title-0 $vlevel $msg}]
4661 post_message -type $qlevel "Hog:$title $msg"
4662 if { $qlevel == "error"} {
4667 if {$vlevel != "STATUS"} {
4668 puts "$vlevel: \[Hog:$title\] $msg"
4673 if {$qlevel == "error"} {
4685 proc MsgAndLog {msg {severity "CriticalWarning"} {outFile ""}} {
4687 if {$outFile != ""} {
4688 set oF [open "$outFile" a+]
4698 proc OpenProject {project_file repo_path} {
4700 open_project $project_file
4702 set project_folder [
file dirname $project_file]
4703 set project [
file tail [
file rootname $project_file]]
4704 if {[
file exists $project_folder]} {
4706 if { ![is_project_open] } {
4707 Msg Info "Opening existing project file $project_file..."
4708 project_open $project -current_revision
4711 Msg Error "Project directory not found for $project_file."
4715 Msg Info "Opening existing project file $project_file..."
4717 open_project -file $project_file -do_backup_on_convert 1 -backup_file {./Projects/$project_file.zip}
4719 Msg Info "Opening existing project file $project_file..."
4720 prj_project open $project_file
4722 Msg Error "This IDE is currently not supported by Hog. Exiting!"
4729 return $tcl_platform(platform)
4739 proc ParseJSON {JSON_FILE JSON_KEY} {
4740 set result [
catch {
package require Tcl 8.4} TclFound]
4741 if {"$result" != "0"} {
4742 Msg CriticalWarning "Cannot find Tcl package version equal or higher than 8.4.\n $TclFound\n Exiting"
4746 set result [
catch {
package require json} JsonFound]
4747 if {"$result" != "0"} {
4748 Msg CriticalWarning "Cannot find JSON package equal or higher than 1.0.\n $JsonFound\n Exiting"
4751 set JsonDict [json::json2dict $JSON_FILE]
4752 set result [
catch {dict get $JsonDict $JSON_KEY} RETURNVALUE]
4753 if {"$result" != "0"} {
4754 Msg CriticalWarning "Cannot find $JSON_KEY in $JSON_FILE\n Exiting"
4766 proc ProjectExists {project {repo_path .}} {
4767 set index [lsearch -exact [
ListProjects $repo_path 0] $project]
4783 proc ReadConf {file_name} {
4785 if { [
catch {
package require inifile 0.2.3} ERROR] } {
4786 puts "$ERROR\n If you are running this script on tclsh, you can fix this by installing 'tcllib'"
4791 ::ini::commentchar "#"
4792 set f [::ini::open $file_name]
4793 set properties [dict create]
4794 foreach sec [::ini::sections $f] {
4796 set key_pairs [::ini::get $f $sec]
4799 regsub -all {\{\"} $key_pairs "\{" key_pairs
4800 regsub -all {\"\}} $key_pairs "\}" key_pairs
4802 dict set properties $new_sec [dict create {*}$key_pairs]
4815 proc ReadExtraFileList { extra_file_name } {
4816 set extra_file_dict [dict create]
4817 if {[
file exists $extra_file_name]} {
4818 set file [open $extra_file_name "r"]
4819 set file_data [read $file]
4822 set data [
split $file_data "\n"]
4823 foreach line $data {
4824 if {![regexp {^ *$} $line] & ![regexp {^ *\#} $line] } {
4825 set ip_and_md5 [regexp -all -inline {\S+} $line]
4826 dict lappend extra_file_dict "[
lindex $ip_and_md5 0]" "[
lindex $ip_and_md5 1]"
4830 return $extra_file_dict
4845 proc ReadListFile args {
4849 if { [
catch {
package require cmdline} ERROR] } {
4850 puts "$ERROR\n If you are running this script on tclsh, you can fix this by installing 'tcllib'"
4856 {lib.arg "" "The name of the library files will be added to, if not given will be extracted from the file name."}
4857 {fileset.arg "" "The name of the library, from the main list file"}
4858 {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."}
4860 set usage "USAGE: ReadListFile \[options\] <list file> <path>"
4861 if {[
catch {
array set options [
cmdline::getoptions args $parameters $usage]}] || [
llength $args] != 2 } {
4865 set list_file [
lindex $args 0]
4866 set path [
lindex $args 1]
4867 set sha_mode $options(sha_mode)
4868 set lib $options(lib)
4869 set fileset $options(fileset)
4871 if { $sha_mode == 1} {
4872 set sha_mode_opt "-sha_mode"
4879 set lib [
file rootname [
file tail $list_file]]
4881 set fp [open $list_file r]
4882 set file_data [read $fp]
4884 set list_file_ext [
file extension $list_file]
4885 switch $list_file_ext {
4887 if {$fileset eq ""} {
4893 set fileset "constrs_1"
4896 set fileset "sources_1"
4900 set libraries [dict create]
4901 set filesets [dict create]
4902 set properties [dict create]
4904 set data [
split $file_data "\n"]
4905 set n [
llength $data]
4906 Msg Debug "$n lines read from $list_file."
4909 foreach line $data {
4911 if {![regexp {^ *$} $line] & ![regexp {^ *\#} $line] } {
4912 set file_and_prop [regexp -all -inline {\S+} $line]
4913 set srcfile [
lindex $file_and_prop 0]
4914 set srcfile "$path/$srcfile"
4916 set srcfiles [glob -nocomplain $srcfile]
4919 if {$srcfiles != $srcfile && ! [
string equal $srcfiles ""]} {
4920 Msg Debug "Wildcard source expanded from $srcfile to $srcfiles"
4922 if {![
file exists $srcfile]} {
4923 Msg CriticalWarning "File: $srcfile (from list file: $list_file) does not exist."
4928 foreach vhdlfile $srcfiles {
4929 if {[
file exists $vhdlfile]} {
4930 set vhdlfile [
file normalize $vhdlfile]
4931 set extension [
file extension $vhdlfile]
4933 set prop [
lrange $file_and_prop 1 end]
4936 set library [
lindex [regexp -inline {lib\s*=\s*(.+?)\y.*} $prop] 1]
4937 if { $library == "" } {
4941 if { $extension == $list_file_ext } {
4943 set ref_path [
lindex [regexp -inline {path\s*=\s*(.+?)\y.*} $prop] 1]
4944 if { $ref_path eq "" } {
4947 set ref_path [
file normalize $path/$ref_path]
4949 Msg Debug "List file $vhdlfile found in list file, recursively opening it using path \"$ref_path\"..."
4950 lassign [
ReadListFile {*}"-lib $library -fileset $fileset $sha_mode_opt $vhdlfile $ref_path"] l p fs
4952 set properties [
MergeDict $p $properties]
4954 }
elseif {[lsearch {.src .sim .con ReadExtraFileList} $extension] >= 0 } {
4956 Msg Error "$vhdlfile cannot be included into $list_file, $extension files must be included into $extension files."
4959 regsub -all " *= *" $prop "=" prop
4963 if { [
string first "lib=" $p] == -1} {
4965 set pos [
string first "=" $p]
4969 set prop_name [
string range $p 0 [
expr {$pos - 1}]]
4972 dict lappend properties $vhdlfile $p
4973 Msg Debug "Adding property $p to $vhdlfile..."
4974 }
elseif { $list_file_ext != ".ipb" } {
4975 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]\]"
4979 if { [lsearch {.xci .ip .bd .xcix} $extension] >= 0} {
4981 set lib_name "ips.src"
4982 }
elseif { [
IsInList $extension {.vhd .vhdl}] || $list_file_ext == ".sim"} {
4984 if { ![
IsInList $extension {.vhd .vhdl}]} {
4985 set lib_name "others.sim"
4987 set lib_name "$library$list_file_ext"
4989 }
elseif { $list_file_ext == ".con" } {
4990 set lib_name "sources.con"
4991 }
elseif { $list_file_ext == ".ipb" } {
4992 set lib_name "xml.ipb"
4995 set lib_name "others.src"
4998 Msg Debug "Appending $vhdlfile to $lib_name list..."
4999 dict lappend libraries $lib_name $vhdlfile
5000 if { $sha_mode != 0 && [
file type $vhdlfile] eq "link"} {
5003 dict lappend libraries $lib_name $real_file
5004 Msg Debug "File $vhdlfile is a soft link, also adding the real file: $real_file"
5009 if {[dict exists $filesets $fileset] == 0} {
5011 Msg Debug "Adding $fileset to the fileset dictionary..."
5012 Msg Debug "Adding library $lib_name to fileset $fileset..."
5013 dict set filesets $fileset $lib_name
5017 Msg Debug "Adding library $lib_name to fileset $fileset..."
5018 dict lappend filesets $fileset $lib_name
5024 Msg CriticalWarning "File $vhdlfile not found."
5030 if {$sha_mode != 0} {
5032 if {$list_file_ext eq ".ipb"} {
5033 set sha_lib "xml.ipb"
5035 set sha_lib $lib$list_file_ext
5037 dict lappend libraries $sha_lib [
file normalize $list_file]
5038 if {[
file type $list_file] eq "link"} {
5041 dict lappend libraries $lib$list_file_ext $real_file
5042 Msg Debug "List file $list_file is a soft link, also adding the real file: $real_file"
5045 return [list $libraries $properties $filesets]
5053 proc Relative {base dst} {
5054 if {![
string equal [
file pathtype $base] [
file pathtype $dst]]} {
5055 Msg CriticalWarning "Unable to compute relation for paths of different path types: [
file pathtype $base] vs. [
file pathtype $dst], ($base vs. $dst)"
5059 set base [
file normalize [
file join [
pwd] $base]]
5060 set dst [
file normalize [
file join [
pwd] $dst]]
5063 set base [
file split $base]
5064 set dst [
file split $dst]
5066 while {[
string equal [
lindex $dst 0] [
lindex $base 0]]} {
5067 set dst [
lrange $dst 1 end]
5068 set base [
lrange $base 1 end]
5069 if {![
llength $dst]} {break}
5072 set dstlen [
llength $dst]
5073 set baselen [
llength $base]
5075 if {($dstlen == 0) && ($baselen == 0)} {
5078 while {$baselen > 0} {
5079 set dst [
linsert $dst 0 ..]
5082 set dst [
eval [
linsert $dst 0 file join]]
5093 proc RelativeLocal {pathName filePath} {
5094 if {[
string first [
file normalize $pathName] [
file normalize $filePath]] != -1} {
5095 return [
Relative $pathName $filePath]
5106 proc RemoveDuplicates {mydict} {
5107 set new_dict [dict create]
5108 foreach key [dict keys $mydict] {
5109 set values [
DictGet $mydict $key]
5110 foreach value $values {
5111 set idxs [
lreverse [
lreplace [lsearch -exact -all $values $value] 0 0]]
5113 set values [
lreplace $values $idx $idx]
5116 dict set new_dict $key $values
5127 proc ResetRepoFiles {reset_file} {
5128 if {[
file exists $reset_file]} {
5129 Msg Info "Found $reset_file, opening it..."
5130 set fp [open $reset_file r]
5131 set wild_cards [lsearch -all -inline -not -regexp [
split [read $fp] "\n"] "^ *$"]
5133 Msg Info "Found the following files/wild cards to restore if modified: $wild_cards..."
5134 foreach w $wild_cards {
5136 if {[
llength $mod_files] > 0} {
5137 Msg Info "Found modified $w files: $mod_files, will restore them..."
5140 Msg Info "No modified $w files found."
5151 proc RestoreModifiedFiles {{repo_path "."} {pattern "."}} {
5154 set ret [
Git checkout $pattern]
5165 proc SearchHogProjects {dir} {
5166 set projects_list {}
5167 if {[
file exists $dir]} {
5168 if {[
file isdirectory $dir]} {
5169 foreach proj_dir [glob -nocomplain -types d $dir/*] {
5170 if {![regexp {^.*Top/+(.*)$} $proj_dir dummy proj_name]} {
5171 Msg Warning "Could not parse Top directory $dir"
5174 if { [
file exists "$proj_dir/hog.conf"] } {
5175 lappend projects_list $proj_name
5178 lappend projects_list $p
5184 Msg Error "Input $dir is not a directory!"
5187 Msg Error "Directory $dir doesn't exist!"
5189 return $projects_list
5198 proc SetGenericsSimulation {repo_path proj_dir target} {
5199 set top_dir "$repo_path/Top/$proj_dir"
5201 set sim_cfg_index [lsearch -regexp -index 0 $read_aux ".*sim.conf"]
5202 set sim_cfg_index [lsearch -regexp -index 0 [
GetConfFiles $top_dir] ".*sim.conf"]
5203 set simsets [get_filesets]
5204 if { $simsets != "" } {
5205 if {[
file exists $top_dir/sim.conf]} {
5209 if {[dict size $sim_generics_dict] > 0 || [dict size $simsets_generics_dict] > 0} {
5210 foreach simset $simsets {
5212 if {[get_property FILESET_TYPE $simset] != "SimulationSrcs" } {
5216 if {[dict exists $simsets_generics_dict $simset:generics]} {
5217 set simset_generics_dict [dict get $simsets_generics_dict $simset:generics]
5219 set merged_generics_dict [dict merge $sim_generics_dict $simset_generics_dict]
5221 set_property generic $generic_str [get_filesets $simset]
5222 Msg Debug "Setting generics $generic_str for simulator $target and simulation file-set $simset..."
5223 }
elseif {[dict size $sim_generics_dict] > 0} {
5225 set_property generic $generic_str [get_filesets $simset]
5226 Msg Debug "Setting generics $generic_str for simulator $target and simulation file-set $simset..."
5231 if {[glob -nocomplain "$top_dir/list/*.sim"] ne ""} {
5232 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."
5245 proc SetTopProperty {top_module fileset} {
5246 Msg Info "Setting TOP property to $top_module module"
5249 set_property "top" $top_module [get_filesets $fileset]
5252 set_global_assignment -name TOP_LEVEL_ENTITY $top_module
5254 set_root -module $top_module
5256 prj_impl option top $top_module
5261 proc VIVADO_PATH_PROPERTIES {} {
5262 return {"\.*\.TCL\.PRE$" "^.*\.TCL\.POST$" "^RQS_FILES$" "^INCREMENTAL\_CHECKPOINT$"}
5272 proc WriteConf {file_name config {comment ""}} {
5273 if { [
catch {
package require inifile 0.2.3} ERROR] } {
5274 puts "$ERROR\n If you are running this script on tclsh, you can fix this by installing 'tcllib'"
5278 ::ini::commentchar "#"
5279 set f [::ini::open $file_name w]
5281 foreach sec [dict keys $config] {
5282 set section [dict get $config $sec]
5283 dict for {p v} $section {
5284 if {[string trim $v] == ""} {
5285 Msg Warning "Property $p has empty value. Skipping..."
5288 ::ini::set $f $sec $p $v
5293 if {![
string equal "$comment" ""]} {
5294 ::ini::comment $f [
lindex [::ini::sections $f] 0] "" $comment
5310 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 ""}} {
5311 Msg Info "Passing parameters/generics to project's top module..."
5314 set generic_string [
concat \
5326 if {$xml_hash != "" && $xml_ver != ""} {
5327 lappend generic_string \
5332 foreach l $libs v $vers h $hashes {
5335 lappend generic_string "$ver" "$hash"
5338 foreach e $ext_names h $ext_hashes {
5340 lappend generic_string "$hash"
5343 foreach repo $user_ip_repos v $user_ip_vers h $user_ip_hashes {
5344 set repo_name [
file tail $repo]
5345 set ver "[
string toupper $repo_name]_VER=[
FormatGeneric $v]"
5346 set hash "[
string toupper $repo_name]_SHA=[
FormatGeneric $h]"
5347 lappend generic_string "$ver" "$hash"
5350 if {$flavour != -1} {
5351 lappend generic_string "FLAVOUR=$flavour"
5357 set generic_string "$prj_generics $generic_string"
5363 if {$mode == "create" || [
IsISE]} {
5367 if {[
file exists $top_file]} {
5370 Msg Debug "Found top level generics $generics in $top_file"
5372 set filtered_generic_string ""
5374 foreach generic_to_set [
split [
string trim $generic_string]] {
5375 set key [
lindex [
split $generic_to_set "="] 0]
5376 if {[dict exists $generics $key]} {
5377 Msg Debug "Hog generic $key found in $top_name"
5378 lappend filtered_generic_string "$generic_to_set"
5380 Msg Warning "Generic $key is passed by Hog but is NOT present in $top_name."
5386 set generic_string $filtered_generic_string
5391 set_property generic $generic_string [current_fileset]
5392 Msg Info "Setting parameters/generics..."
5393 Msg Debug "Detailed parameters/generics: $generic_string"
5398 set simulator [get_property target_simulator [current_project]]
5399 if {$mode == "create"} {
5406 Msg Info "Setting Synplify parameters/generics one by one..."
5407 foreach generic $generic_string {
5408 Msg Debug "Setting Synplify generic: $generic"
5409 set_option -hdl_param -set "$generic"
5412 Msg Info "Setting Diamond parameters/generics one by one..."
5413 prj_impl option -impl Implementation0 HDL_PARAM "$generic_string"
5423 proc WriteGenericsToBdIPs {mode repo_path proj generic_string} {
5424 Msg Debug "Parameters/generics passed to WriteGenericsToIP: $generic_string"
5426 set bd_ip_generics false
5428 if {[dict exists $properties "hog"]} {
5429 set propDict [dict get $properties "hog"]
5430 if {[dict exists $propDict "PASS_GENERICS_TO_BD_IPS"]} {
5431 set bd_ip_generics [dict get $propDict "PASS_GENERICS_TO_BD_IPS"]
5435 if {[
string compare [
string tolower $bd_ip_generics] "false"]==0} {
5439 if {$mode == "synth"} {
5440 Msg Info "Attempting to apply generics pre-synthesis..."
5441 set PARENT_PRJ [get_property "PARENT.PROJECT_PATH" [current_project]]
5442 set workaround [open "$repo_path/Projects/$proj/.hog/presynth_workaround.tcl" "w"]
5443 puts $workaround "source \[lindex \$argv 0\];"
5444 puts $workaround "open_project \[lindex \$argv 1\];"
5445 puts $workaround "WriteGenericsToBdIPs \[lindex \$argv 2\] \[lindex \$argv 3\] \[lindex \$argv 4\] \[lindex \$argv 5\];"
5446 puts $workaround "close_project"
5449 exec vivado -mode batch -source $repo_path/Projects/$proj/.hog/presynth_workaround.tcl \
5450 -tclargs $repo_path/Hog/Tcl/hog.tcl $PARENT_PRJ \
5451 "childprocess" $repo_path $proj $generic_string
5453 Msg Error "Encountered an error while attempting workaround: $errMsg"
5455 file delete $repo_path/Projects/$proj/.hog/presynth_workaround.tcl
5457 Msg Info "Done applying generics pre-synthesis."
5461 Msg Info "Looking for IPs to add generics to..."
5462 set ips_generic_string ""
5463 foreach generic_to_set [
split [
string trim $generic_string]] {
5464 set key [
lindex [
split $generic_to_set "="] 0]
5465 set value [
lindex [
split $generic_to_set "="] 1]
5466 append ips_generic_string "CONFIG.$key $value "
5470 if {[
string compare [
string tolower $bd_ip_generics] "true"]==0} {
5473 set ip_regex $bd_ip_generics
5476 set ip_list [get_ips -regex $ip_regex]
5477 Msg Debug "IPs found with regex \{$ip_regex\}: $ip_list"
5479 set regen_targets {}
5481 foreach {ip} $ip_list {
5482 set WARN_ABOUT_IP false
5483 set ip_props [list_property [get_ips $ip]]
5486 if {[lsearch -exact $ip_props "IS_BD_CONTEXT"] == -1} {
5490 if {[get_property "IS_BD_CONTEXT" [get_ips $ip]] eq "1"} {
5491 foreach {ip_prop} $ip_props {
5492 if {[dict exists $ips_generic_string $ip_prop]} {
5493 if {$WARN_ABOUT_IP == false} {
5494 lappend regen_targets [get_property SCOPE [get_ips $ip]]
5495 Msg Warning "The ip \{$ip\} contains generics that are set by Hog.\
5496 If this is IP is apart of a block design, the .bd file may contain stale, unused, values.\
5497 Hog will always apply the most up-to-date values to the IP during synthesis,\
5498 however these values may or may not be reflected in the .bd file."
5499 set WARN_ABOUT_IP true
5504 set xci_path [get_property IP_FILE [get_ips $ip]]
5506 if {[
string equal $generic_format "ERROR"]} {
5507 Msg Warning "Could not find format for generic $ip_prop in IP $ip. Skipping..."
5511 set value_to_set [dict get $ips_generic_string $ip_prop]
5512 switch -exact $generic_format {
5514 if {[
string match "32'h*" $value_to_set]} {
5515 scan [
string map {"32'h" ""} $value_to_set] "%x" value_to_set
5519 set value_to_set [
expr {$value_to_set ? "true" : "false"}]
5522 if {[
string match "32'h*" $value_to_set]} {
5523 binary scan [
binary format H* [
string map {"32'h" ""} $value_to_set]] d value_to_set
5527 if {[
string match "32'h*" $value_to_set]} {
5528 set value_to_set [
string map {"32'h" "0x"} $value_to_set]
5532 set value_to_set [
format "%s" $value_to_set]
5535 Msg Warning "Unknown generic format $generic_format for IP $ip. Will attempt to pass as string..."
5540 Msg Info "The IP \{$ip\} contains: $ip_prop ($generic_format), setting it to $value_to_set."
5541 if {[
catch {set_property -name $ip_prop -value $value_to_set -objects [ get_ips $ip]} prop_error]} {
5542 Msg CriticalWarning "Failed to set property $ip_prop to $value_to_set for IP \{$ip\}: $prop_error"
5549 foreach {regen_target} [lsort -unique $regen_targets] {
5550 Msg Info "Regenerating target: $regen_target"
5551 if {[
catch {generate_target -force all [get_files $regen_target]} prop_error]} {
5552 Msg CriticalWarning "Failed to regen targets: $prop_error"
5561 proc GetGenericFormatFromXciXML {generic_name xml_file} {
5563 if {![
file exists $xml_file]} {
5564 Msg Error "Could not find XML file: $xml_file"
5568 set fp [open $xml_file r]
5569 set xci_data [read $fp]
5572 set paramType "string"
5573 set modelparam_regex [
format {^.*\y%s\y.*$} [
string map {"CONFIG." "MODELPARAM_VALUE."} $generic_name]]
5574 set format_regex {format="([^"]+)"}
5576 set line [
lindex [regexp -inline -line $modelparam_regex $xci_data] 0]
5577 Msg Debug "line: $line"
5579 if {[regexp $format_regex $line match format_value]} {
5580 Msg Debug "Extracted: $format_value format from xml"
5581 set paramType $format_value
5583 Msg Debug "No format found, using string"
5592 proc GetGenericFormatFromXci {generic_name xci_file} {
5594 if {! [
file exists $xci_file]} {
5595 Msg Error "Could not find XCI file: $xci_file"
5599 set fp [open $xci_file r]
5600 set xci_data [read $fp]
5603 set paramType "string"
5604 if {[
string first "xilinx.com:schema:json_instance:1.0" $xci_data] == -1} {
5605 Msg Debug "XCI format is not JSON, trying XML..."
5606 set xml_file "[
file rootname $xci_file].xml"
5611 set generic_name [
string map {"CONFIG." ""} $generic_name]
5612 set ip_inst [
ParseJSON $xci_data "ip_inst"]
5613 set parameters [dict get $ip_inst parameters]
5614 set component_parameters [dict get $parameters component_parameters]
5615 if {[dict exists $component_parameters $generic_name]} {
5616 set generic_info [dict get $component_parameters $generic_name]
5617 if {[dict exists [
lindex $generic_info 0] format]} {
5618 set paramType [dict get [
lindex $generic_info 0] format]
5619 Msg Debug "Extracted: $paramType format from xci"
5622 Msg Debug "No format found, using string"
5635 proc WriteGitLabCIYAML {proj_name {ci_conf ""}} {
5636 if { [
catch {
package require yaml 0.3.3} YAMLPACKAGE]} {
5637 Msg CriticalWarning "Cannot find package YAML.\n Error message: $YAMLPACKAGE. If you are running on tclsh, you can fix this by installing package \"tcllib\""
5642 if {$ci_conf != ""} {
5644 foreach sec [dict keys $ci_confs] {
5645 if {[
string first : $sec] == -1} {
5646 lappend job_list $sec
5650 set job_list {"generate_project" "simulate_project"}
5654 set out_yaml [huddle create]
5655 foreach job $job_list {
5657 set huddle_tags [huddle list]
5659 set sec_dict [dict create]
5661 if {$ci_confs != ""} {
5662 foreach var [dict keys [dict get $ci_confs $job]] {
5663 if {$var == "tags"} {
5664 set tag_section "tags"
5665 set tags [dict get [dict get $ci_confs $job] $var]
5666 set tags [
split $tags ","]
5668 set tag_list [huddle list $tag]
5669 set huddle_tags [huddle combine $huddle_tags $tag_list]
5672 dict set sec_dict $var [dict get [dict get $ci_confs $job] $var]
5678 set huddle_variables [huddle create "PROJECT_NAME" $proj_name "extends" ".vars"]
5679 if {[dict exists $ci_confs "$job:variables"]} {
5680 set var_dict [dict get $ci_confs $job:variables]
5681 foreach var [dict keys $var_dict] {
5683 set value [dict get $var_dict "$var"]
5684 set var_inner [huddle create "$var" "$value"]
5685 set huddle_variables [huddle combine $huddle_variables $var_inner]
5690 set middle [huddle create "extends" ".$job" "variables" $huddle_variables]
5691 foreach sec [dict keys $sec_dict] {
5692 set value [dict get $sec_dict $sec]
5693 set var_inner [huddle create "$sec" "$value"]
5694 set middle [huddle combine $middle $var_inner]
5696 if {$tag_section != ""} {
5697 set middle2 [huddle create "$tag_section" $huddle_tags]
5698 set middle [huddle combine $middle $middle2]
5701 set outer [huddle create "$job:$proj_name" $middle]
5702 set out_yaml [huddle combine $out_yaml $outer]
5705 return [
string trimleft [ yaml::huddle2yaml $out_yaml] "-"]
5715 proc WriteListFiles {libs props list_path repo_path {$ext_path ""} } {
5717 foreach lib [dict keys $libs] {
5718 if {[
llength [
DictGet $libs $lib]] > 0} {
5719 set list_file_name $list_path$lib
5720 set list_file [open $list_file_name w]
5721 Msg Info "Writing $list_file_name..."
5722 foreach file [
DictGet $libs $lib] {
5724 set prop [
DictGet $props $file]
5728 puts $list_file "$file_path $prop"
5731 set ext_list_file [open "[
file rootname $list_file].ext" a]
5732 puts $ext_list_file "$file_path $prop"
5733 close $ext_list_file
5736 Msg Warning "The path of file $file is not relative to your repository. Please check!"
5751 proc WriteSimListFiles {libs props simsets list_path repo_path } {
5753 foreach simset [dict keys $simsets] {
5754 set list_file_name $list_path/${simset}.sim
5755 set list_file [open $list_file_name w]
5756 Msg Info "Writing $list_file_name..."
5757 foreach lib [
DictGet $simsets $simset] {
5758 foreach file [
DictGet $libs $lib] {
5760 set prop [
DictGet $props $file]
5764 set lib_name [
file rootname $lib]
5765 if {$lib_name != $simset} {
5766 lappend prop "lib=$lib_name"
5768 puts $list_file "$file_path $prop"
5771 Msg Warning "The path of file $file is not relative to your repository. Please check!"
5783 proc WriteToFile {File msg} {
5784 set f [open $File a+]
5795 proc WriteUtilizationSummary {input output project_name run} {
5796 set f [open $input "r"]
5797 set o [open $output "a"]
5798 puts $o "## $project_name $run Utilization report\n\n"
5799 struct::matrix util_m
5800 util_m add columns 14
5803 util_m add row "| **Site Type** | **Used** | **Fixed** | **Prohibited** | **Available** | **Util%** |"
5804 util_m add row "| --- | --- | --- | --- | --- | --- |"
5806 util_m add row "| **Site Type** | **Used** | **Fixed** | **Available** | **Util%** |"
5807 util_m add row "| --- | --- | --- | --- | --- |"
5817 while {[
gets $f line] >= 0} {
5818 if { ( [
string first "| CLB LUTs" $line] >= 0 || [
string first "| Slice LUTs" $line] >= 0 ) && $luts == 0 } {
5819 util_m add row $line
5822 if { ( [
string first "| CLB Registers" $line] >= 0 || [
string first "| Slice Registers" $line] >= 0 ) && $regs == 0} {
5823 util_m add row $line
5826 if { [
string first "| Block RAM Tile" $line] >= 0 && $bram == 0 } {
5827 util_m add row $line
5830 if { [
string first "URAM " $line] >= 0 && $uram == 0} {
5831 util_m add row $line
5834 if { [
string first "DSPs" $line] >= 0 && $dsps == 0 } {
5835 util_m add row $line
5838 if { [
string first "Bonded IOB" $line] >= 0 && $ios == 0 } {
5839 util_m add row $line
5846 puts $o [util_m format 2string]
5852 Msg Error "Found Git version older than 2.7.2. Hog will not work as expected, exiting now."