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
64 current_fileset -simset [ get_filesets $fileset]
65 set simulation [get_filesets $fileset]
67 set_property -name {$simulator.compile.vhdl_syntax} -value {2008} -objects $simulation
69 set_property SOURCE_SET sources_1 $simulation
73 set libs_in_fileset [
DictGet $filesets $fileset]
74 if { [
IsInList "ips.src" $libs_in_fileset] } {
79 foreach lib $libs_in_fileset {
80 Msg Debug "lib: $lib \n"
81 set lib_files [
DictGet $libraries $lib]
82 Msg Debug "Files in $lib: $lib_files"
83 set rootlib [
file rootname [
file tail $lib]]
84 set ext [
file extension $lib]
85 Msg Debug "lib: $lib ext: $ext fileset: $fileset"
88 Msg Debug "Adding $lib to $fileset"
89 add_files -norecurse -fileset $fileset $lib_files
91 foreach f $lib_files {
92 set file_obj [get_files -of_objects [get_filesets $fileset] [list "*$f"]]
94 if {[
file extension $f] == ".vhd" || [
file extension $f] == ".vhdl"} {
95 set_property -name "library" -value $rootlib -objects $file_obj
99 set props [
DictGet $properties $f]
100 if {[
file extension $f] == ".vhd" || [
file extension $f] == ".vhdl"} {
102 if {[lsearch -inline -regexp $props "93"] < 0} {
105 if {[lsearch -inline -regexp $props "2008"] >= 0} {
106 set vhdl_year "VHDL 2008"
107 }
elseif {[lsearch -inline -regexp $props "2019"] >= 0} {
109 set vhdl_year "VHDL 2019"
111 Msg CriticalWarning "VHDL 2019 is not supported\
112 in Vivado version older than 2023.2.\
113 Using VHDL 2008, but this might not work."
114 set vhdl_year "VHDL 2008"
118 set vhdl_year "VHDL 2008"
120 Msg Debug "File type for $f is $vhdl_year"
121 set_property -name "file_type" -value $vhdl_year -objects $file_obj
124 Msg Debug "Filetype is VHDL 93 for $f"
129 if {[lsearch -inline -regexp $props "SystemVerilog"] > 0 } {
132 set_property -name "file_type" -value "SystemVerilog" -objects $file_obj
133 Msg Debug "Filetype is SystemVerilog for $f"
135 Msg Warning "Xilinx PlanAhead/ISE does not support SystemVerilog.\
136 Property not set for $f"
141 set top [
lindex [regexp -inline {\ytop\s*=\s*(.+?)\y.*} $props] 1]
143 Msg Info "Setting $top as top module for file set $fileset..."
144 set globalSettings::synth_top_module $top
149 if {[lsearch -inline -regexp $props "verilog_header"] >= 0} {
150 Msg Debug "Setting verilog header type for $f..."
151 set_property file_type {Verilog Header} [get_files $f]
152 }
elseif {[lsearch -inline -regexp $props "verilog_template"] >= 0} {
154 Msg Debug "Setting verilog template type for $f..."
155 set_property file_type {Verilog Template} [get_files $f]
156 }
elseif {[lsearch -inline -regexp $props "verilog"] >= 0} {
158 Msg Debug "Setting verilog type for $f..."
159 set_property file_type {Verilog} [get_files $f]
163 if {[lsearch -inline -regexp $props "nosynth"] >= 0} {
164 Msg Debug "Setting not used in synthesis for $f..."
165 set_property -name "used_in_synthesis" -value "false" -objects $file_obj
169 if {[lsearch -inline -regexp $props "noimpl"] >= 0} {
170 Msg Debug "Setting not used in implementation for $f..."
171 set_property -name "used_in_implementation" -value "false" -objects $file_obj
175 if {[lsearch -inline -regexp $props "nosim"] >= 0} {
176 Msg Debug "Setting not used in simulation for $f..."
177 set_property -name "used_in_simulation" -value "false" -objects $file_obj
182 set top_sim [
lindex [regexp -inline {\ytopsim\s*=\s*(.+?)\y.*} $props] 1]
183 if { $top_sim != "" } {
184 Msg Warning "Setting the simulation top module with the topsim property is deprecated.\
185 Please set this property in the \[properties\] section of your .sim list file,
186 or in the \[$fileset\] section of your sim.conf,\
187 by adding the following line.\ntop=$top_sim"
191 set sim_runtime [
lindex [regexp -inline {\yruntime\s*=\s*(.+?)\y.*} $props] 1]
192 if { $sim_runtime != "" } {
193 Msg Warning "Setting the simulation runtime using the runtime= property is deprecated.\
194 Please set this property in the \[properties\] section of your .sim list file,\
195 or in the \[$fileset\] section of your sim.conf,\
196 by adding the following line.\n<simulator_name>.simulate.runtime=$sim_runtime"
200 if {[lsearch -inline -regexp $props "wavefile"] >= 0} {
201 Msg Warning "Setting a wave do file using the wavefile property is deprecated.\
202 Set this property in the sim.conf file under the \[$fileset\] section,\
203 or in the \[properties\] section of the .sim list file,\
204 by adding the following line .\n<simulator_name>.simulate.custom_wave_do=[
file tail $f]"
208 if {[lsearch -inline -regexp $props "dofile"] >= 0} {
209 Msg Warning "Setting a wave do file using the dofile property is deprecated.\
210 Set this property in the sim.conf file under the \[$fileset\] section,\
211 or in the \[properties\] section of the .sim list file,\
212 by adding the following line .\n<simulator_name>.simulate.custom_do=[
file tail $f]"
216 if {[lsearch -inline -regexp $props "locked"] >= 0 && $ext == ".ip"} {
217 Msg Info "Locking IP $f..."
218 set_property IS_MANAGED 0 [get_files $f]
222 if {[
file extension $f] == ".bd"} {
223 Msg Info "Generating Target for [
file tail $f],\
224 please remember to commit the (possible) changed file."
225 generate_target all [get_files $f]
230 if {[
file extension $f] == ".tcl" && $ext != ".con"} {
231 if { [lsearch -inline -regexp $props "source"] >= 0} {
232 Msg Info "Sourcing Tcl script $f,\
233 and setting it not used in synthesis, implementation and simulation..."
235 set_property -name "used_in_synthesis" -value "false" -objects $file_obj
236 set_property -name "used_in_implementation" -value "false" -objects $file_obj
237 set_property -name "used_in_simulation" -value "false" -objects $file_obj
242 set ref [
lindex [regexp -inline {\yscoped_to_ref\s*=\s*(.+?)\y.*} $props] 1]
243 set cell [
lindex [regexp -inline {\yscoped_to_cells\s*=\s*(.+?)\y.*} $props] 1]
244 if {([
file extension $f] == ".tcl" || [
file extension $f] == ".xdc") && $ext == ".con"} {
246 set_property SCOPED_TO_REF $ref $file_obj
249 set_property SCOPED_TO_CELLS $cell $file_obj
254 Msg Info "[
llength $lib_files] file/s added to library $rootlib..."
257 if { $ext == ".sim"} {
258 Msg Warning "Simulation files not supported in Quartus Prime mode... Skipping $lib"
260 if {! [is_project_open] } {
261 Msg Error "Project is closed"
263 foreach cur_file $lib_files {
267 set props [
DictGet $properties $cur_file]
270 set top [
lindex [regexp -inline {\ytop\s*=\s*(.+?)\y.*} $props] 1]
272 Msg Info "Setting $top as top module for file set $fileset..."
273 set globalSettings::synth_top_module $top
276 if {[
string first "VHDL" $file_type] != -1 } {
277 if {[
string first "1987" $props] != -1 } {
278 set hdl_version "VHDL_1987"
279 }
elseif {[
string first "1993" $props] != -1 } {
280 set hdl_version "VHDL_1993"
281 }
elseif {[
string first "2008" $props] != -1 } {
282 set hdl_version "VHDL_2008"
284 set hdl_version "default"
286 if { $hdl_version == "default" } {
287 set_global_assignment -name $file_type $cur_file -library $rootlib
289 set_global_assignment -name $file_type $cur_file -hdl_version $hdl_version -library $rootlib
291 }
elseif {[
string first "SYSTEMVERILOG" $file_type] != -1 } {
293 if {[
string first "2005" $props] != -1 } {
294 set hdl_version "systemverilog_2005"
295 }
elseif {[
string first "2009" $props] != -1 } {
296 set hdl_version "systemverilog_2009"
298 set hdl_version "default"
300 if { $hdl_version == "default" } {
301 set_global_assignment -name $file_type $cur_file
303 set_global_assignment -name $file_type $cur_file -hdl_version $hdl_version
305 }
elseif {[
string first "VERILOG" $file_type] != -1 } {
307 if {[
string first "1995" $props] != -1 } {
308 set hdl_version "verilog_1995"
309 }
elseif {[
string first "2001" $props] != -1 } {
310 set hdl_version "verilog_2001"
312 set hdl_version "default"
314 if { $hdl_version == "default" } {
315 set_global_assignment -name $file_type $cur_file
317 set_global_assignment -name $file_type $cur_file -hdl_version $hdl_version
319 }
elseif {[
string first "SOURCE" $file_type] != -1 || [
string first "COMMAND_MACRO" $file_type] != -1 } {
320 set_global_assignment -name $file_type $cur_file
321 if { $ext == ".con"} {
323 }
elseif { $ext == ".src"} {
325 if {[
string first "qsys" $props] != -1 } {
328 regsub -all {\{||qsys||\}} $props $emptyString props
330 set qsysPath [
file dirname $cur_file]
331 set qsysName "[
file rootname [
file tail $cur_file]].qsys"
332 set qsysFile "$qsysPath/$qsysName"
333 set qsysLogFile "$qsysPath/[
file rootname [
file tail $cur_file]].qsys-script.log"
336 if {! [
info exists ::env(QSYS_ROOTDIR)] } {
337 if {[
info exists ::env(QUARTUS_ROOTDIR)] } {
338 set qsys_rootdir "$::env(QUARTUS_ROOTDIR)/sopc_builder/bin"
339 Msg Warning "The QSYS_ROOTDIR environment variable is not set! I will use $qsys_rootdir"
341 Msg CriticalWarning "The QUARTUS_ROOTDIR environment variable is not set! Assuming all quartus executables are contained in your PATH!"
344 set qsys_rootdir $::env(QSYS_ROOTDIR)
347 set cmd "$qsys_rootdir/qsys-script"
348 set cmd_options " --script=$cur_file"
349 if {![
catch {"exec $cmd -version"}] || [
lindex $::errorCode 0] eq "NONE"} {
350 Msg Info "Executing: $cmd $cmd_options"
351 Msg Info "Saving logfile in: $qsysLogFile"
352 if { [
catch {
eval exec -ignorestderr "$cmd $cmd_options >>& $qsysLogFile"} ret opt]} {
353 set makeRet [
lindex [dict get $opt -errorcode] end]
354 Msg CriticalWarning "$cmd returned with $makeRet"
357 Msg Error " Could not execute command $cmd"
361 if { [
file exists $qsysName] != 0} {
362 file rename -force $qsysName $qsysFile
364 set qsysMd5Sum [
Md5Sum $qsysFile]
366 set fileDir [
file normalize "./hogTmp"]
367 set fileName "$fileDir/.hogQsys.md5"
368 if {![
file exists $fileDir]} {
371 set hogQsysFile [open $fileName "a"]
372 set fileEntry "$qsysFile\t$qsysMd5Sum"
373 puts $hogQsysFile $fileEntry
376 Msg ERROR "Error while moving the generated qsys file to final location: $qsysName not found!"
378 if { [
file exists $qsysFile] != 0} {
379 if {[
string first "noadd" $props] == -1} {
381 set_global_assignment -name $qsysFileType $qsysFile
383 regsub -all {noadd} $props $emptyString props
385 if {[
string first "nogenerate" $props] == -1} {
390 Msg ERROR "Error while generating ip variations from qsys: $qsysFile not found!"
394 }
elseif { [
string first "QSYS" $file_type] != -1 } {
396 regsub -all {\{||\}} $props $emptyString props
397 if {[
string first "noadd" $props] == -1} {
398 set_global_assignment -name $file_type $cur_file
400 regsub -all {noadd} $props $emptyString props
404 if {[
string first "nogenerate" $props] == -1} {
408 set_global_assignment -name $file_type $cur_file -library $rootlib
413 if {$ext == ".con"} {
414 set vld_exts {.sdc .pin .dcf .gcf .pdc .ndc .fdc .crt .vcd }
415 foreach con_file $lib_files {
417 set con_ext [
file extension $con_file]
418 if {[
IsInList [
file extension $con_file] $vld_exts]} {
419 set option [
string map {. -} $con_ext]
420 set option [
string map {fdc net_fdc} $option]
421 set option [
string map {pdc io_pdc} $option]
422 create_links -convert_EDN_to_HDL 0 -library {work} $option $con_file
424 set props [
DictGet $properties $con_file]
426 if {$con_ext == ".sdc"} {
427 if { [lsearch $props "notiming"] >= 0 } {
428 Msg Info "Excluding $con_file from timing verification..."
430 Msg Info "Adding $con_file to time verification"
431 append timing_conf_command " -file $con_file"
435 if { [lsearch $props "nosynth"] >= 0 } {
436 Msg Info "Excluding $con_file from synthesis..."
438 Msg Info "Adding $con_file to synthesis"
439 append synth_conf_command " -file $con_file"
444 if {$con_ext == ".pdc" || $con_ext == ".sdc"} {
445 if { [lsearch $props "noplace"] >= 0 } {
446 Msg Info "Excluding $con_file from place and route..."
448 Msg Info "Adding $con_file to place and route"
449 append place_conf_command " -file $con_file"
455 Msg CriticalWarning "Constraint file $con_file does not have a valid extension. Allowed extensions are: \n $vld_exts"
458 }
elseif {$ext == ".src"} {
459 foreach f $lib_files {
460 Msg Debug "Adding source $f to library $rootlib..."
461 create_links -library $rootlib -hdl_source $f
463 }
elseif {$ext == ".sim"} {
464 Msg Debug "Adding stimulus file $f to library..."
465 create_links -library $rootlib -stimulus $f
467 build_design_hierarchy
468 foreach cur_file $lib_files {
472 set props [
DictGet $properties $cur_file]
475 set top [
lindex [regexp -inline {\ytop\s*=\s*(.+?)\y.*} $props] 1]
477 Msg Info "Setting $top as top module for file set $rootlib..."
478 set globalSettings::synth_top_module "${top}::$rootlib"
483 if {$ext == ".src" || $ext == ".con" || $ext == ".ext"} {
484 foreach f $lib_files {
485 Msg Debug "Diamond: adding source file $f to library $rootlib..."
486 prj_src add -work $rootlib $f
487 set props [
DictGet $properties $f]
489 set top [
lindex [regexp -inline {\ytop\s*=\s*(.+?)\y.*} $props] 1]
491 Msg Info "Setting $top as top module for the project..."
492 set globalSettings::synth_top_module $top
496 if {[lsearch -inline -regexp $props "enable"] >= 0} {
497 Msg Debug "Setting $f as active Logic Preference file"
502 }
elseif {$ext == ".sim"} {
503 foreach f $lib_files {
504 Msg Debug "Diamond Adding simulation file $f to library $rootlib..."
505 prj_src add -work $rootlib -simulate_only $f
517 if {[
DictGet $filesets "sim_1"] == ""} {
518 delete_fileset -quiet [get_filesets -quiet "sim_1"]
524 if {$synth_conf == 1} {
525 Msg Info $synth_conf_command
526 eval $synth_conf_command
528 if {$timing_conf == 1} {
529 Msg Info $timing_conf_command
530 eval $timing_conf_command
532 if {$place_conf == 1} {
533 Msg Info $place_conf_command
534 eval $place_conf_command
540 proc ALLOWED_PROPS {} {
541 return [dict create ".vhd" [list "93" "nosynth" "noimpl" "nosim" "1987" "1993" "2008" "2019"]\
542 ".vhdl" [list "93" "nosynth" "noimpl" "nosim" "1987" "1993" "2008" "2019"]\
543 ".bd" [list "nosim"]\
544 ".v" [list "SystemVerilog" "verilog_header" "nosynth" "noimpl" "nosim" "1995" "2001"]\
545 ".sv" [list "verilog" "verilog_header" "nosynth" "noimpl" "nosim" "2005" "2009"]\
546 ".do" [list "nosim"]\
547 ".udo" [list "nosim"]\
548 ".xci" [list "nosynth" "noimpl" "nosim" "locked"]\
549 ".xdc" [list "nosynth" "noimpl"]\
550 ".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"]\
551 ".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"]\
552 ".sdc" [list "notiming" "nosynth" "noplace"]\
553 ".elf" [list "scoped_to_ref" "scoped_to_cells" "nosim" "noimpl"]\
554 ".pdc" [list "nosynth" "noplace"] \
555 ".lpf" [list "enable"]
567 proc BinaryStepName {part} {
569 return "WRITE_DEVICE_IMAGE"
573 return "WRITE_BITSTREAM"
582 proc CheckSyntax { project_name repo_path {project_file ""}} {
584 set syntax [check_syntax -return_string]
585 if {[
string first "CRITICAL" $syntax] != -1} {
590 lassign [
GetHogFiles -list_files "*.src" "$repo_path/Top/$project_name/list/" $repo_path] src_files dummy
591 dict for {lib files} $src_files {
593 set file_extension [file extension $f]
594 if { $file_extension == ".vhd" || $file_extension == ".vhdl" || $file_extension == ".v" || $file_extension == ".sv" } {
595 if { [catch {execute_module -tool map -args "--analyze_file=$f"} result]} {
596 Msg Error "\nResult: $result\n"
597 Msg Error "Check syntax failed.\n"
599 if { $result == "" } {
600 Msg Info "Check syntax was successful for $f.\n"
602 Msg Warning "Found syntax error in file $f:\n $result\n"
609 lassign [
GetProjectFiles $project_file] prjLibraries prjProperties prjSimLibraries prjConstraints prjSrcSets prjSimSets prjConSets
610 dict for {lib sources} $prjLibraries {
611 if {[file extension $lib] == ".src"} {
613 Msg Info "Checking Syntax of $f"
619 Msg Info "The Checking Syntax is not supported by this IDE. Skipping..."
624 proc CloseProject {} {
646 proc CompareVersions {ver1 ver2} {
655 if {[regexp {v(\d+)\.(\d+)\.(\d+)} $ver1 - x y z]} {
656 set ver1 [list $x $y $z]
658 if {[regexp {v(\d+)\.(\d+)\.(\d+)} $ver2 - x y z]} {
659 set ver2 [list $x $y $z]
663 set v1 [
join $ver1 ""]
665 set v2 [
join $ver2 ""]
668 if {[
string is integer $v1] && [
string is integer $v2]} {
670 set ver1 [
expr {[scan [lindex $ver1 0] %d]*1000000 + [scan [lindex $ver1 1] %d]*1000 + [scan [lindex $ver1 2] %d]}]
671 set ver2 [
expr {[scan [lindex $ver2 0] %d]*1000000 + [scan [lindex $ver2 1] %d]*1000 + [scan [lindex $ver2 2] %d]}]
673 if {$ver1 > $ver2 } {
675 }
elseif {$ver1 == $ver2} {
682 Msg Warning "Version is not numeric: $ver1, $ver2"
692 proc CheckExtraFiles {libraries constraints simlibraries} {
695 lassign [
GetProjectFiles] prjLibraries prjProperties prjSimLibraries prjConstraints
696 set prj_dir [get_property DIRECTORY [current_project]]
697 file mkdir "$prj_dir/.hog"
698 set extra_file_name "$prj_dir/.hog/extra.files"
699 set new_extra_file [open $extra_file_name "w"]
701 dict for {prjLib prjFiles} $prjLibraries {
702 foreach prjFile $prjFiles {
703 if {[file extension $prjFile] == ".xcix"} {
704 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."
707 if {[file extension $prjFile] == ".xci" && [get_property CORE_CONTAINER [get_files $prjFile]] != ""} {
708 Msg Info "$prjFile is a virtual IP file in a core container. Ignoring it..."
712 if {[IsInList $prjFile [DictGet $libraries $prjLib]]==0} {
713 if { [file extension $prjFile] == ".bd"} {
714 # Generating BD products to save md5sum of already modified BD
715 Msg Info "Generating targets of $prjFile..."
716 generate_target all [get_files $prjFile]
718 puts $new_extra_file "$prjFile [Md5Sum $prjFile]"
719 Msg Info "$prjFile (lib: $prjLib) has been generated by an external script. Adding to $extra_file_name..."
723 close $new_extra_file
724 set extra_sim_file "$prj_dir/.hog/extrasim.files"
725 set new_extra_file [open $extra_sim_file "w"]
727 dict for {prjSimLib prjSimFiles} $prjSimLibraries {
728 foreach prjSimFile $prjSimFiles {
729 if {[IsInList $prjSimFile [DictGet $simlibraries $prjSimLib]]==0} {
730 puts $new_extra_file "$prjSimFile [Md5Sum $prjSimFile]"
731 Msg Info "$prjSimFile (lib: $prjSimLib) has been generated by an external script. Adding to $extra_sim_file..."
735 close $new_extra_file
736 set extra_con_file "$prj_dir/.hog/extracon.files"
737 set new_extra_file [open $extra_con_file "w"]
739 dict for {prjConLib prjConFiles} $prjConstraints {
740 foreach prjConFile $prjConFiles {
741 if {[IsInList $prjConFile [DictGet $constraints $prjConLib]]==0} {
742 puts $new_extra_file "$prjConFile [Md5Sum $prjConFile]"
743 Msg Info "$prjConFile has been generated by an external script. Adding to $extra_con_file..."
747 close $new_extra_file
754 proc CheckLatestHogRelease {{repo_path .}} {
757 set current_ver [
Git {describe --always}]
758 Msg Debug "Current version: $current_ver"
759 set current_sha [
Git "log $current_ver -1 --format=format:%H"]
760 Msg Debug "Current SHA: $current_sha"
763 if {[
OS] == "windows" } {
764 Msg Info "On windows we cannot set a timeout on 'git fetch', hopefully nothing will go wrong..."
767 Msg Info "Checking for latest Hog release, can take up to 5 seconds..."
770 set master_ver [
Git "describe origin/master"]
771 Msg Debug "Master version: $master_ver"
772 set master_sha [
Git "log $master_ver -1 --format=format:%H"]
773 Msg Debug "Master SHA: $master_sha"
774 set merge_base [
Git "merge-base $current_sha $master_sha"]
775 Msg Debug "merge base: $merge_base"
778 if {$merge_base != $master_sha} {
780 Msg Info "Version $master_ver has been released (https://gitlab.com/hog-cern/Hog/-/releases/$master_ver)"
781 Msg Status "You should consider updating Hog submodule with the following instructions:"
783 Msg Status "cd Hog && git checkout master && git pull"
785 Msg Status "Also update the ref: in your .gitlab-ci.yml to $master_ver"
790 Msg Info "Latest official version is $master_ver, nothing to do."
803 proc CheckYmlRef {repo_path allow_failure} {
805 if {$allow_failure} {
806 set MSG_TYPE CriticalWarning
811 if { [
catch {
package require yaml 0.3.3} YAMLPACKAGE]} {
812 Msg CriticalWarning "Cannot find package YAML, skipping consistency check of \"ref\" in gilab-ci.yaml file.\n Error message: $YAMLPACKAGE
813 You can fix this by installing package \"tcllib\""
821 if {[
file exists .gitlab-ci.yml]} {
825 if { [
file exists .gitlab-ci.yml] } {
826 set fp [open ".gitlab-ci.yml" r]
827 set file_data [read $fp]
830 Msg $MSG_TYPE "Cannot open file .gitlab-ci.yml"
834 set file_data "\n$file_data\n\n"
836 if { [
catch {::yaml::yaml2dict -stream $file_data} yamlDict]} {
837 Msg $MSG_TYPE "Parsing $repo_path/.gitlab-ci.yml failed. To fix this, check that yaml syntax is respected, remember not to use tabs."
841 dict for {dictKey dictValue} $yamlDict {
842 #looking for Hog include in .gitlab-ci.yml
843 if {"$dictKey" == "include" && ([lsearch [split $dictValue " {}"] "/hog.yml" ] != "-1" || [lsearch [split $dictValue " {}"] "/hog-dynamic.yml" ] != "-1")} {
844 set YML_REF [lindex [split $dictValue " {}"] [expr {[lsearch -dictionary [split $dictValue " {}"] "ref"]+1} ] ]
845 set YML_NAME [lindex [split $dictValue " {}"] [expr {[lsearch -dictionary [split $dictValue " {}"] "file"]+1} ] ]
849 if {$YML_REF == ""} {
850 Msg Warning "Hog version not specified in the .gitlab-ci.yml. Assuming that master branch is used."
852 set YML_REF_F [
Git {name-rev --tags --name-only origin/master}]
855 set YML_REF_F [regsub -all "'" $YML_REF ""]
858 if {$YML_NAME == ""} {
859 Msg $MSG_TYPE "Hog included yml file not specified, assuming hog.yml"
860 set YML_NAME_F hog.yml
862 set YML_NAME_F [regsub -all "^/" $YML_NAME ""]
865 lappend YML_FILES $YML_NAME_F
871 if { [
catch {::yaml::yaml2dict -file $YML_NAME_F} yamlDict]} {
872 Msg $MSG_TYPE "Parsing $YML_NAME_F failed."
876 dict for {dictKey dictValue} $yamlDict {
877 #looking for included files
878 if {"$dictKey" == "include"} {
879 foreach v $dictValue {
880 lappend YML_FILES [lindex [split $v " "] [expr {[lsearch -dictionary [split $v " "] "local"]+1} ] ]
886 Msg Info "Found the following yml files: $YML_FILES"
888 set HOGYML_SHA [
GetSHA $YML_FILES]
889 lassign [
GitRet "log --format=%h -1 --abbrev=7 $YML_REF_F" $YML_FILES] ret EXPECTEDYML_SHA
891 lassign [
GitRet "log --format=%h -1 --abbrev=7 origin/$YML_REF_F" $YML_FILES] ret EXPECTEDYML_SHA
893 Msg $MSG_TYPE "Error in project .gitlab-ci.yml. ref: $YML_REF not found"
894 set EXPECTEDYML_SHA ""
897 if {!($EXPECTEDYML_SHA eq "")} {
898 if {$HOGYML_SHA == $EXPECTEDYML_SHA} {
899 Msg Info "Hog included file $YML_FILES matches with $YML_REF in .gitlab-ci.yml."
902 Msg $MSG_TYPE "HOG $YML_FILES SHA mismatch.
903 From Hog submodule: $HOGYML_SHA
904 From ref in .gitlab-ci.yml: $EXPECTEDYML_SHA
905 You can fix this in 2 ways: by changing the ref in your repository or by changing the Hog submodule commit"
908 Msg $MSG_TYPE "One or more of the following files could not be found $YML_FILES in Hog at $YML_REF"
911 Msg Info ".gitlab-ci.yml not found in $repo_path. Skipping this step"
932 proc CompareLibDicts {proj_libs list_libs proj_sets list_sets proj_props list_props {severity "CriticalWarning"} {outFile ""} {extraFiles ""} } {
933 set extra_files $extraFiles
935 set out_prjlibs $proj_libs
936 set out_prjprops $proj_props
938 dict for {prjSet prjLibraries} $proj_sets {
939 # Check if sets is also in list files
940 if {[IsInList $prjSet $list_sets]} {
941 set listLibraries [DictGet $list_sets $prjSet]
942 # Loop over libraries in fileset
943 foreach prjLib $prjLibraries {
944 set prjFiles [DictGet $proj_libs $prjLib]
945 # Check if library exists in list files
946 if {[IsInList $prjLib $listLibraries]} {
947 # Loop over files in library
948 set listFiles [DictGet $list_libs $prjLib]
949 foreach prjFile $prjFiles {
950 set idx [lsearch -exact $listFiles $prjFile]
951 set listFiles [lreplace $listFiles $idx $idx]
953 # File is in project but not in list libraries, check if it was generated at creation time...
954 if { [dict exists $extra_files $prjFile] } {
955 # File was generated at creation time, checking the md5sum
956 # Removing the file from the prjFiles list
957 set idx2 [lsearch -exact $prjFiles $prjFile]
958 set prjFiles [lreplace $prjFiles $idx2 $idx2]
959 set new_md5sum [Md5Sum $prjFile]
960 set old_md5sum [DictGet $extra_files $prjFile]
961 if {$new_md5sum != $old_md5sum} {
962 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
965 set extra_files [dict remove $extra_files $prjFile]
967 # File is neither in list files nor in extra_files
968 MsgAndLog "$prjFile was found in project but not in list files or .hog/extra.files" $severity $outFile
972 # File is both in list files and project, checking properties...
973 set prjProps [DictGet $proj_props $prjFile]
974 set listProps [DictGet $list_props $prjFile]
975 # Check if it is a potential sourced file
976 if {[IsInList "nosynth" $prjProps] && [IsInList "noimpl" $prjProps] && [IsInList "nosim" $prjProps]} {
977 # Check if it is sourced
978 set idx_source [lsearch -exact $listProps "source"]
979 if {$idx_source >= 0 } {
980 # It is sourced, let's replace the individual properties with source
981 set idx [lsearch -exact $prjProps "noimpl"]
982 set prjProps [lreplace $prjProps $idx $idx]
983 set idx [lsearch -exact $prjProps "nosynth"]
984 set prjProps [lreplace $prjProps $idx $idx]
985 set idx [lsearch -exact $prjProps "nosim"]
986 set prjProps [lreplace $prjProps $idx $idx]
987 lappend prjProps "source"
991 foreach prjProp $prjProps {
992 set idx [lsearch -exact $listProps $prjProp]
993 set listProps [lreplace $listProps $idx $idx]
995 MsgAndLog "Property $prjProp of $prjFile was set in project but not in list files" $severity $outFile
1000 foreach listProp $listProps {
1001 if {[string first $listProp "topsim="] == -1 && [string first $listProp "enable"] == -1} {
1002 MsgAndLog "Property $listProp of $prjFile was found in list files but not set in project." $severity $outFile
1007 # Update project prjProps
1008 dict set out_prjprops $prjFile $prjProps
1011 # Loop over remaining files in list libraries
1012 foreach listFile $listFiles {
1013 MsgAndLog "$listFile was found in list files but not in project." $severity $outFile
1017 # Check extra files again...
1018 foreach prjFile $prjFiles {
1019 if { [dict exists $extra_files $prjFile] } {
1020 # File was generated at creation time, checking the md5sum
1021 # Removing the file from the prjFiles list
1022 set idx2 [lsearch -exact $prjFiles $prjFile]
1023 set prjFiles [lreplace $prjFiles $idx2 $idx2]
1024 set new_md5sum [Md5Sum $prjFile]
1025 set old_md5sum [DictGet $extra_files $prjFile]
1026 if {$new_md5sum != $old_md5sum} {
1027 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
1030 set extra_files [dict remove $extra_files $prjFile]
1032 # File is neither in list files nor in extra_files
1033 MsgAndLog "$prjFile was found in project but not in list files or .hog/extra.files" $severity $outFile
1038 # Update prjLibraries
1039 dict set out_prjlibs $prjLib $prjFiles
1042 MsgAndLog "Fileset $prjSet found in project but not in list files" $severity $outFile
1047 return [list $n_diffs $extra_files $out_prjlibs $out_prjprops]
1057 proc CompareVHDL {file1 file2} {
1058 set a [open $file1 r]
1059 set b [open $file2 r]
1061 while {[
gets $a line] != -1} {
1062 set line [regsub {^[\t\s]*(.*)?\s*} $line "\\1"]
1063 if {![regexp {^$} $line] & ![regexp {^--} $line] } {
1069 while {[
gets $b line] != -1} {
1070 set line [regsub {^[\t\s]*(.*)?\s*} $line "\\1"]
1071 if {![regexp {^$} $line] & ![regexp {^--} $line] } {
1080 foreach x $f1 y $f2 {
1082 lappend diff "> $x\n< $y\n\n"
1095 proc Copy {i_dirs o_dir} {
1096 foreach i_dir $i_dirs {
1097 if {[
file isdirectory $i_dir] && [
file isdirectory $o_dir]} {
1098 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]])} {
1099 file delete -force $o_dir/[
file tail $i_dir]
1103 file copy -force $i_dir $o_dir
1118 proc CopyIPbusXMLs {proj_dir path dst {xml_version "0.0.0"} {xml_sha "00000000"} {use_ipbus_sw 0} {generate 0} } {
1119 if {$use_ipbus_sw == 1} {
1120 lassign [
ExecuteRet python -c "from __future__ import print_function; from sys import path;print(':'.join(path\[1:\]))"] ret msg
1122 set ::env(PYTHONPATH) $msg
1123 lassign [
ExecuteRet gen_ipbus_addr_decode -h] ret msg
1130 Msg CriticalWarning "Problem while trying to run python: $msg"
1133 set dst [
file normalize $dst]
1134 if {$can_generate == 0} {
1135 if {$generate == 1} {
1136 Msg Error "Cannot generate IPbus address files, IPbus executable gen_ipbus_addr_decode not found or not working: $msg"
1140 Msg Warning "IPbus executable gen_ipbus_addr_decode not found or not working, will not verify IPbus address tables."
1147 set ipb_files [glob -nocomplain $proj_dir/list/*.ipb]
1148 set n_ipb_files [
llength $ipb_files]
1149 if {$n_ipb_files == 0} {
1150 Msg CriticalWarning "No files with .ipb extension found in $proj_dir/list."
1153 set libraries [dict create]
1154 set vhdl_dict [dict create]
1156 foreach ipb_file $ipb_files {
1162 set xmlfiles [dict get $libraries "xml.ipb"]
1165 set xml_list_error 0
1166 foreach xmlfile $xmlfiles {
1168 if {[
file isdirectory $xmlfile]} {
1169 Msg CriticalWarning "Directory $xmlfile listed in xml list file $list_file. Directories are not supported!"
1170 set xml_list_error 1
1173 if {[
file exists $xmlfile]} {
1174 if {[dict exists $vhdl_dict $xmlfile]} {
1175 set vhdl_file [
file normalize [dict get $vhdl_dict $xmlfile]]
1179 lappend vhdls $vhdl_file
1181 set xmlfile [
file normalize $xmlfile]
1182 Msg Info "Copying $xmlfile to $dst and replacing place holders..."
1183 set in [open $xmlfile r]
1184 set out [open $dst/[
file tail $xmlfile] w]
1186 while {[
gets $in line] != -1} {
1187 set new_line [regsub {(.*)__VERSION__(.*)} $line "\\1$xml_version\\2"]
1188 set new_line2 [regsub {(.*)__GIT_SHA__(.*)} $new_line "\\1$xml_sha\\2"]
1189 puts $out $new_line2
1193 lappend xmls [
file tail $xmlfile]
1195 Msg Warning "XML file $xmlfile not found"
1198 if {${xml_list_error}} {
1199 Msg Error "Invalid files added to $list_file!"
1202 set cnt [
llength $xmls]
1203 Msg Info "$cnt xml file/s copied"
1206 if {$can_generate == 1} {
1209 file mkdir "address_decode"
1212 foreach x $xmls v $vhdls {
1214 set x [
file normalize ../$x]
1215 if {[
file exists $x]} {
1216 lassign [
ExecuteRet gen_ipbus_addr_decode --no-timestamp $x 2>&1] status log
1218 set generated_vhdl ./ipbus_decode_[
file rootname [
file tail $x]].vhd
1219 if {$generate == 1} {
1220 Msg Info "Copying generated VHDL file $generated_vhdl into $v (replacing if necessary)"
1221 file copy -force -- $generated_vhdl $v
1223 if {[
file exists $v]} {
1225 set n [
llength $diff]
1227 Msg CriticalWarning "$v does not correspond to its XML $x, [
expr {$n/3}] line/s differ:"
1228 Msg Status [
join $diff "\n"]
1229 set diff_file [open ../diff_[
file rootname [
file tail $x]].txt w]
1230 puts $diff_file $diff
1233 Msg Info "[
file tail $x] and $v match."
1236 Msg Warning "VHDL address map file $v not found."
1240 Msg Warning "Address map generation failed for [
file tail $x]: $log"
1243 Msg Warning "Copied XML file $x not found."
1246 Msg Info "Skipped verification of [
file tail $x] as no VHDL file was specified."
1250 file delete -force address_decode
1262 proc DescriptionFromConf {conf_file} {
1263 set f [open $conf_file "r"]
1264 set lines [
split [read $f] "\n"]
1266 set second_line [
lindex $lines 1]
1269 if {![regexp {\#+ *(.+)} $second_line - description]} {
1273 if {[regexp -all {test|Test|TEST} $description]} {
1274 set description "test"
1287 proc DictGet {dictName keyName {default ""}} {
1288 if {[dict exists $dictName $keyName]} {
1289 return [dict get $dictName $keyName]
1300 proc DictSort {dict args} {
1302 foreach key [lsort {*}$args [dict keys $dict]] {
1303 dict set res $key [dict get $dict $key]
1313 proc DoxygenVersion {target_version} {
1314 set ver [
split $target_version "."]
1315 set v [
Execute doxygen --version]
1316 Msg Info "Found Doxygen version: $v"
1317 set current_ver [
split $v ". "]
1318 set target [
expr {[lindex $ver 0]*100000 + [lindex $ver 1]*100 + [lindex $ver 2]}]
1319 set current [
expr {[lindex $current_ver 0]*100000 + [lindex $current_ver 1]*100 + [lindex $current_ver 2]}]
1321 return [
expr {$target <= $current}]
1332 proc eos {command {attempt 1}} {
1334 if {![
info exists env(EOS_MGM_URL)]} {
1335 Msg Warning "Environment variable EOS_MGM_URL not set, setting it to default value root://eosuser.cern.ch"
1336 set ::env(EOS_MGM_URL) "root://eosuser.cern.ch"
1339 Msg Warning "The value of attempt should be 1 or more, not $attempt, setting it to 1 as default"
1342 for {
set i 0} {$i < $attempt} {
incr i} {
1343 set ret [
catch {
exec -ignorestderr eos {*}$command} result]
1348 set wait [
expr {1+int(rand()*29)}]
1349 Msg Warning "Command $command failed ($i/$attempt): $result, trying again in $wait seconds..."
1350 after [
expr {$wait*1000}]
1354 return [list $ret $result]
1364 proc Execute {args} {
1368 Msg Error "Command [
join $args] returned error code: $ret"
1382 proc ExecuteRet {args} {
1384 if {[
llength $args] == 0} {
1385 Msg CriticalWarning "No argument given"
1389 set ret [
catch {
exec -ignorestderr {*}$args} result]
1392 return [list $ret $result]
1399 proc ExtractFilesSection {file_data} {
1400 set in_files_section 0
1403 foreach line $file_data {
1404 if {[regexp {^ *\[ *files *\]} $line]} {
1405 set in_files_section 1
1408 if {$in_files_section} {
1409 if {[regexp {^ *\[.*\]} $line]} {
1412 lappend result $line
1417 if {!$in_files_section} {
1431 proc ExtractVersionFromTag {tag} {
1432 if {[regexp {^(?:b(\d+))?v(\d+)\.(\d+).(\d+)(?:-\d+)?$} $tag -> mr M m p]} {
1437 Msg Warning "Repository tag $tag is not in a Hog-compatible format."
1443 return [list $M $m $p $mr]
1453 proc FileCommitted {File } {
1455 set currentDir [
pwd]
1456 cd [
file dirname [
file normalize $File]]
1457 set GitLog [
Git ls-files [
file tail $File]]
1458 if {$GitLog == ""} {
1459 Msg CriticalWarning "File [
file normalize $File] is not in the git repository. Please add it with:\n git add [
file normalize $File]\n"
1470 proc FindCommonGitChild {SHA1 SHA2} {
1472 set commits [
Git {log --oneline --merges}]
1475 foreach line [
split $commits "\n"] {
1476 set commit [
lindex [
split $line] 0]
1480 set ancestor $commit
1493 proc findFiles { basedir pattern } {
1497 set basedir [
string trimright [
file join [
file normalize $basedir] { }]]
1503 foreach fileName [glob -nocomplain -type {f r} -path $basedir $pattern] {
1504 lappend fileList $fileName
1508 foreach dirName [glob -nocomplain -type {d r} -path $basedir *] {
1511 set subDirList [
findFiles $dirName $pattern]
1512 if { [
llength $subDirList] > 0 } {
1513 foreach subDirFile $subDirList {
1514 lappend fileList $subDirFile
1525 proc FindFileType {file_name} {
1526 set extension [
file extension $file_name]
1529 set file_extension "USE_SIGNALTAP_FILE"
1532 set file_extension "VHDL_FILE"
1535 set file_extension "VHDL_FILE"
1538 set file_extension "VERILOG_FILE"
1541 set file_extension "SYSTEMVERILOG_FILE"
1544 set file_extension "SDC_FILE"
1547 set file_extension "PDC_FILE"
1550 set file_extension "NDC_FILE"
1553 set file_extension "FDC_FILE"
1556 set file_extension "SOURCE_FILE"
1559 set file_extension "IP_FILE"
1562 set file_extension "QSYS_FILE"
1565 set file_extension "QIP_FILE"
1568 set file_extension "SIP_FILE"
1571 set file_extension "BSF_FILE"
1574 set file_extension "BDF_FILE"
1577 set file_extension "COMMAND_MACRO_FILE"
1580 set file_extension "VQM_FILE"
1583 set file_extension "ERROR"
1584 Msg Error "Unknown file extension $extension"
1587 return $file_extension
1594 proc FindNewestVersion { versions } {
1595 set new_ver 00000000
1596 foreach ver $versions {
1598 if {[
expr 0x$ver > 0x$new_ver] } {
1610 proc FindVhdlVersion {file_name} {
1611 set extension [
file extension $file_name]
1614 set vhdl_version "-hdl_version VHDL_2008"
1617 set vhdl_version "-hdl_version VHDL_2008"
1624 return $vhdl_version
1631 proc FormatGeneric {generic} {
1632 if {[
string is integer "0x$generic"]} {
1633 return [
format "32'h%08X" "0x$generic"]
1636 return [
format "32'h%08X" 0]
1646 proc GenerateBitstream { {run_folder ""} {repo_path .} {njobs 1} } {
1647 Msg Info "Starting write bitstream flow..."
1649 set revision [get_current_revision]
1650 if {[
catch {execute_module -tool asm} result]} {
1651 Msg Error "Result: $result\n"
1652 Msg Error "Generate bitstream failed. See the report file.\n"
1654 Msg Info "Generate bitstream was successful for revision $revision.\n"
1657 Msg Info "Run GENERATEPROGRAMMINGDATA ..."
1658 if {[
catch {run_tool -name {GENERATEPROGRAMMINGDATA}}] } {
1659 Msg Error "GENERATEPROGRAMMINGDATA FAILED!"
1661 Msg Info "GENERATEPROGRAMMINGDATA PASSED."
1663 Msg Info "Sourcing Hog/Tcl/integrated/post-bitstream.tcl"
1664 source $repo_path/Hog/Tcl/integrated/post-bitstream.tcl
1666 prj_run Export -impl Implementation0 -task Bitgen
1676 proc GenerateQsysSystem {qsysFile commandOpts} {
1677 if { [
file exists $qsysFile] != 0} {
1678 set qsysPath [
file dirname $qsysFile]
1679 set qsysName [
file rootname [
file tail $qsysFile]]
1680 set qsysIPDir "$qsysPath/$qsysName"
1681 set qsysLogFile "$qsysPath/$qsysName.qsys-generate.log"
1684 if {! [
info exists ::env(QSYS_ROOTDIR)] } {
1685 if {[
info exists ::env(QUARTUS_ROOTDIR)] } {
1686 set qsys_rootdir "$::env(QUARTUS_ROOTDIR)/sopc_builder/bin"
1687 Msg Warning "The QSYS_ROOTDIR environment variable is not set! I will use $qsys_rootdir"
1689 Msg CriticalWarning "The QUARTUS_ROOTDIR environment variable is not set! Assuming all quartus executables are contained in your PATH!"
1692 set qsys_rootdir $::env(QSYS_ROOTDIR)
1695 set cmd "$qsys_rootdir/qsys-generate"
1696 set cmd_options "$qsysFile --output-directory=$qsysIPDir $commandOpts"
1697 if {![
catch {"exec $cmd -version"}] || [
lindex $::errorCode 0] eq "NONE"} {
1698 Msg Info "Executing: $cmd $cmd_options"
1699 Msg Info "Saving logfile in: $qsysLogFile"
1700 if {[
catch {
eval exec -ignorestderr "$cmd $cmd_options >>& $qsysLogFile"} ret opt]} {
1701 set makeRet [
lindex [dict get $opt -errorcode] end]
1702 Msg CriticalWarning "$cmd returned with $makeRet"
1705 Msg Error " Could not execute command $cmd"
1709 set qsysIPFileList [
concat [glob -nocomplain -directory $qsysIPDir -types f *.ip *.qip] [glob -nocomplain -directory "$qsysIPDir/synthesis" -types f *.ip *.qip *.vhd *.vhdl]]
1710 foreach qsysIPFile $qsysIPFileList {
1711 if { [
file exists $qsysIPFile] != 0} {
1713 set_global_assignment -name $qsysIPFileType $qsysIPFile
1715 set IpMd5Sum [
Md5Sum $qsysIPFile]
1717 set fileDir [
file normalize "./hogTmp"]
1718 set fileName "$fileDir/.hogQsys.md5"
1719 if {![
file exists $fileDir]} {
1722 set hogQsysFile [open $fileName "a"]
1723 set fileEntry "$qsysIPFile\t$IpMd5Sum"
1724 puts $hogQsysFile $fileEntry
1729 Msg ERROR "Error while generating ip variations from qsys: $qsysFile not found!"
1739 proc GenericToSimulatorString {prop_dict target} {
1741 dict for {theKey theValue} $prop_dict {
1750 regexp {([0-9]*)('h)([0-9a-fA-F]*)} $theValue valueHexFull valueNumBits valueHexFlag valueHex
1751 regexp {^([0-9]*)$} $theValue valueIntFull ValueInt
1752 regexp {(?!^\d+$)^.+$} $theValue valueStrFull ValueStr
1753 if { [string tolower $target] == "vivado" || [string tolower $target] == "xsim" } {
1754 if {$valueNumBits != "" && $valueHexFlag != "" && $valueHex != ""} {
1755 set prj_generics "$prj_generics $theKey=$valueHexFull"
1756 } elseif { $valueIntFull != "" && $ValueInt != "" } {
1757 set prj_generics "$prj_generics $theKey=$ValueInt"
1758 } elseif { $valueStrFull != "" && $ValueStr != "" } {
1759 set prj_generics "$prj_generics $theKey=\"$ValueStr\""
1761 set prj_generics "$prj_generics $theKey=\"$theValue\""
1763 } elseif { [lsearch -exact [GetSimulators] [string tolower $target] ] >= 0 } {
1764 if {$valueNumBits != "" && $valueHexFlag != "" && $valueHex != ""} {
1766 scan $valueNumBits %d numBits
1768 scan $valueHex %x numHex
1769 binary scan [binary format "I" $numHex] "B*" binval
1770 set numBits [expr {$numBits-1}]
1771 set numBin [string range $binval end-$numBits end]
1772 set prj_generics "$prj_generics $theKey=\"$numBin\""
1774 } elseif { $valueIntFull != "" && $ValueInt != "" } {
1775 set prj_generics "$prj_generics $theKey=$ValueInt"
1776 } elseif { $valueStrFull != "" && $ValueStr != "" } {
1777 set prj_generics "$prj_generics {$theKey=\"$ValueStr\"}"
1780 set prj_generics "$prj_generics {$theKey=\"$theValue\"}"
1783 Msg Warning "Target : $target not implemented"
1786 return $prj_generics
1794 proc GetConfFiles {proj_dir} {
1795 if {![
file isdirectory $proj_dir]} {
1796 Msg Error "$proj_dir is supposed to be the top project directory"
1799 set conf_file [
file normalize $proj_dir/hog.conf]
1800 set sim_file [
file normalize $proj_dir/sim.conf]
1801 set pre_tcl [
file normalize $proj_dir/pre-creation.tcl]
1802 set post_tcl [
file normalize $proj_dir/post-creation.tcl]
1804 return [list $conf_file $sim_file $pre_tcl $post_tcl]
1813 proc GetCustomCommands {{directory .} {ret_commands 0}} {
1814 set commands_dict [dict create]
1815 set commands_files [glob -nocomplain $directory/*.tcl]
1816 set commands_string ""
1818 if {[
llength $commands_files] == 0} {
1822 if {$ret_commands == 0} {
1823 append commands_string "\nCustom Commands:\n"
1826 foreach file $commands_files {
1827 set base_name [
string toupper [
file rootname [
file tail $file]]]
1828 if {$ret_commands == 1} {
1829 append commands_string "
1831 Msg Info \"Running custom script: $file\"
1833 Msg Info \"Done running custom script...\"
1838 set f [open $file r]
1839 set first_line [
gets $f]
1841 if {[regexp -nocase "^#\s*$base_name:\s*(.*)" $first_line full_match script_des]} {
1842 append commands_string " - $base_name: $script_des\n"
1844 append commands_string " - $base_name: runs $file\n"
1848 return $commands_string
1854 proc GetDateAndTime {commit} {
1855 set clock_seconds [
clock seconds]
1858 set date [
Git "log -1 --format=%cd --date=format:%d%m%Y $commit"]
1859 set timee [
Git "log -1 --format=%cd --date=format:00%H%M%S $commit"]
1861 Msg Warning "Found Git version older than 2.9.3. Using current date and time instead of commit time."
1862 set date [
clock format $clock_seconds -format {%d%m%Y}]
1863 set timee [
clock format $clock_seconds -format {00%H%M%S}]
1865 return [list $date $timee]
1877 proc GetFile {file fileset} {
1880 set Files [get_files -all $file -of_object [get_filesets $fileset]]
1881 set f [
lindex $Files 0]
1890 puts "***DEBUG Hog:GetFile $file"
1899 proc GetFileGenerics {filename {entity ""}} {
1901 if {[
string equal $file_type "VERILOG_FILE"] || [
string equal $file_type "SYSTEMVERILOG_FILE"]} {
1903 }
elseif {[
string equal $file_type "VHDL_FILE"]} {
1906 Msg CriticalWarning "Could not determine extension of top level file."
1915 proc GetGenericsFromConf {proj_dir} {
1916 set generics_dict [dict create]
1917 set top_dir "Top/$proj_dir"
1918 set conf_file "$top_dir/hog.conf"
1921 if {[
file exists $conf_file]} {
1923 if {[dict exists $properties generics]} {
1924 set generics_dict [dict get $properties generics]
1927 Msg Warning "File $conf_file not found."
1929 return $generics_dict
1942 proc GetSimSets { project_name repo_path {simsets ""} {ghdl 0} {no_conf 0}} {
1944 set simsets_dict [dict create]
1945 set list_dir "$repo_path/Top/$project_name/list"
1947 if {$simsets != ""} {
1948 foreach s $simsets {
1949 set list_file "$list_dir/$s.sim"
1950 if {[
file exists $list_file]} {
1951 lappend list_files $list_file
1952 }
elseif {$s != "sim_1"} {
1953 Msg CriticalWarning "Simulation set list file $list_file not found."
1958 set list_files [glob -nocomplain -directory $list_dir "*.sim"]
1962 set proj_dir [
file normalize $repo_path/Top/$project_name]
1963 set sim_file [
file normalize $proj_dir/sim.conf]
1965 foreach list_file $list_files {
1966 set file_name [
file tail $list_file]
1967 set simset_name [
file rootname $file_name]
1968 set fp [open $list_file r]
1969 set file_data [read $fp]
1971 set data [
split $file_data "\n"]
1973 set firstline [
lindex $data 0]
1975 if { [regexp {^ *\# *Simulator} $firstline] } {
1976 set simulator_prop [regexp -all -inline {\S+} $firstline]
1977 set simulator [
string tolower [
lindex $simulator_prop end]]
1979 Msg Warning "Simulator not set in $simset_name.sim. \
1980 The first line of $simset_name.sim should be #Simulator <SIMULATOR_NAME>,\
1981 where <SIMULATOR_NAME> can be xsim, questa, modelsim, ghdl, riviera, activehdl,\
1982 ies, or vcs, e.g. #Simulator questa.\
1983 Setting simulator by default to xsim."
1984 set simulator "xsim"
1986 if {$simulator eq "skip_simulation"} {
1987 Msg Info "Skipping simulation for $simset_name"
1990 if {($ghdl == 1 && $simulator != "ghdl") || ($ghdl == 0 && $simulator == "ghdl")} {
1994 set SIM_PROPERTIES ""
1995 if {[
file exists $sim_file] && $no_conf == 0} {
1996 set SIM_PROPERTIES [
ReadConf $sim_file]
1999 set global_sim_props [dict create]
2000 dict set global_sim_props "properties" [
DictGet $SIM_PROPERTIES "sim"]
2001 dict set global_sim_props "generics" [
DictGet $SIM_PROPERTIES "generics"]
2002 dict set global_sim_props "hog" [
DictGet $SIM_PROPERTIES "hog"]
2005 set sim_dict [dict create]
2006 dict set sim_dict "simulator" $simulator
2007 if {[dict exists $SIM_PROPERTIES $simset_name]} {
2008 dict set sim_dict "properties" [
DictGet $SIM_PROPERTIES $simset_name]
2009 dict set sim_dict "generics" [
DictGet $SIM_PROPERTIES "$simset_name:generics"]
2010 dict set sim_dict "hog" [
DictGet $SIM_PROPERTIES "$simset_name:hog"]
2011 }
elseif {$no_conf == 0} {
2013 set conf_dict [
ReadConf $list_file]
2014 set sim_dict [
MergeDict $sim_dict $conf_dict 0]
2016 set sim_dict [
MergeDict $sim_dict $global_sim_props 0]
2017 dict set simsets_dict $simset_name $sim_dict
2019 return $simsets_dict
2027 proc GetSimsetGenericsFromConf {proj_dir} {
2028 set simsets_generics_dict [dict create]
2029 set top_dir "Top/$proj_dir"
2030 set conf_file "$top_dir/sim.conf"
2033 if {[
file exists $conf_file]} {
2036 set simsets_generics_dict [dict filter $properties key *:generics]
2038 Msg Warning "File $conf_file not found."
2040 return $simsets_generics_dict
2051 proc GetGroupName {proj_dir repo_dir} {
2052 if {[regexp {^(.*)/(Top|Projects)/+(.*?)/*$} $proj_dir dummy possible_repo_dir proj_or_top dir]} {
2054 if {[
file normalize $repo_dir] eq [
file normalize $possible_repo_dir]} {
2055 set group [
file dir $dir]
2056 if { $group == "." } {
2061 Msg Warning "Project directory $proj_dir seems to be in $possible_repo_dir which is not a the main Git repository $repo_dir."
2064 Msg Warning "Could not parse project directory $proj_dir"
2077 proc GetHogDescribe {sha {repo_path .}} {
2080 set new_sha "[
string toupper [
GetSHA]]"
2083 set new_sha [
string toupper $sha]
2103 proc GetHogFiles args {
2107 if { [
catch {
package require cmdline} ERROR] } {
2108 puts "$ERROR\n If you are running this script on tclsh, you can fix this by installing 'tcllib'"
2115 {list_files.arg "" "The file wildcard, if not specified all Hog list files will be looked for."}
2116 {sha_mode "Forwarded to ReadListFile, see there for info."}
2117 {ext_path.arg "" "Path for the external libraries forwarded to ReadListFile."}
2118 {print_log "Forwarded to ReadListFile, see there for info."}
2120 set usage "USAGE: GetHogFiles \[options\] <list path> <repository path>"
2121 if {[
catch {
array set options [
cmdline::getoptions args $parameters $usage]}] || [
llength $args] != 2 } {
2125 set list_path [
lindex $args 0]
2126 set repo_path [
lindex $args 1]
2128 set list_files $options(list_files)
2129 set sha_mode $options(sha_mode)
2130 set ext_path $options(ext_path)
2131 set print_log $options(print_log)
2133 if { $sha_mode == 1 } {
2134 set sha_mode_opt "-sha_mode"
2139 if { $print_log == 1 } {
2140 set print_log_opt "-print_log"
2142 set print_log_opt ""
2146 if { $list_files == "" } {
2147 set list_files {.src,.con,.sim,.ext}
2149 set libraries [dict create]
2150 set properties [dict create]
2151 set list_files [glob -nocomplain -directory $list_path "*{$list_files}"]
2152 set filesets [dict create]
2154 foreach f $list_files {
2155 set ext [
file extension $f]
2156 if {$ext == ".ext"} {
2157 lassign [
ReadListFile {*}"$sha_mode_opt $print_log_opt $f $ext_path"] l p fs
2159 lassign [
ReadListFile {*}"$sha_mode_opt $print_log_opt $f $repo_path"] l p fs
2162 set properties [
MergeDict $p $properties]
2163 Msg Debug "list file $f, filesets: $fs"
2165 Msg Debug "Merged filesets $filesets"
2167 return [list $libraries $properties $filesets]
2173 proc GetIDECommand {proj_conf} {
2175 if {[
file exists $proj_conf]} {
2176 set ide_name_and_ver [
string tolower [
GetIDEFromConf $proj_conf]]
2177 set ide_name [
lindex [regexp -all -inline {\S+} $ide_name_and_ver] 0]
2179 if {$ide_name eq "vivado"} {
2180 set command "vivado"
2182 set before_tcl_script " -nojournal -nolog -mode batch -notrace -source "
2183 set after_tcl_script " -tclargs "
2186 }
elseif {$ide_name eq "planahead"} {
2187 set command "planAhead"
2189 set before_tcl_script " -nojournal -nolog -mode batch -notrace -source "
2190 set after_tcl_script " -tclargs "
2193 }
elseif {$ide_name eq "quartus"} {
2194 set command "quartus_sh"
2196 set before_tcl_script " -t "
2197 set after_tcl_script " "
2200 }
elseif {$ide_name eq "libero"} {
2203 set command "libero"
2204 set before_tcl_script "SCRIPT:"
2205 set after_tcl_script " SCRIPT_ARGS:\""
2207 }
elseif {$ide_name eq "diamond"} {
2208 set command "diamondc"
2209 set before_tcl_script " "
2210 set after_tcl_script " "
2212 }
elseif {$ide_name eq "ghdl"} {
2214 set before_tcl_script " "
2215 set after_tcl_script " "
2218 Msg Error "IDE: $ide_name not known."
2222 Msg Error "Configuration file $proj_conf not found."
2225 return [list $command $before_tcl_script $after_tcl_script $end_marker]
2231 proc GetIDEFromConf {conf_file} {
2232 set f [open $conf_file "r"]
2235 if {[regexp -all {^\# *(\w*) *(\d+\.\d+(?:\.\d+)?(?:\.\d+)?)?(_.*)? *$} $line dummy ide version patch]} {
2236 if {[
info exists version] && $version != ""} {
2242 set ret [list $ide $ver]
2244 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."
2245 set ret [list "vivado" "0.0.0"]
2252 proc GetIDEName {} {
2254 return "ISE/PlanAhead"
2272 proc GetIDEVersion {} {
2275 regexp {\d+\.\d+(\.\d+)?} [version -short] ver
2281 regexp {[\.0-9]+} $quartus(version) ver
2284 set ver [get_libero_version]
2286 regexp {\d+\.\d+(\.\d+)?} [sys_install version] ver
2299 proc GetLinkedFile {link_file} {
2300 if {[
file type $link_file] eq "link"} {
2301 if {[
OS] == "windows" } {
2303 lassign [
ExecuteRet realpath $link_file] ret msg
2304 lassign [
ExecuteRet cygpath -m $msg] ret2 msg2
2305 if {$ret == 0 && $ret2 == 0} {
2307 Msg Debug "Found link file $link_file on Windows, the linked file is: $real_file"
2309 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."
2310 set real_file $link_file
2314 set linked_file [
file link $link_file]
2315 set real_file [
file normalize [
file dirname $link_file]/$linked_file]
2318 if {![
file exists $real_file]} {
2319 Msg Warning "$link_file is a broken link, because the linked file: $real_file does not exist."
2322 Msg Warning "$link file is not a soft link"
2323 set real_file $link_file
2336 proc GetMaxThreads {proj_dir} {
2338 if {[
file exists $proj_dir/hog.conf]} {
2340 if {[dict exists $properties parameters]} {
2341 set propDict [dict get $properties parameters]
2342 if {[dict exists $propDict MAX_THREADS]} {
2343 set maxThreads [dict get $propDict MAX_THREADS]
2347 Msg Warning "File $proj_dir/hog.conf not found. Max threads will be set to default value 1"
2360 proc GetModifiedFiles {{repo_path "."} {pattern "."}} {
2363 set ret [
Git "ls-files --modified $pattern"]
2372 proc GetOptions {argv parameters} {
2375 set param_list [list]
2376 set option_list [list]
2378 foreach p $parameters {
2379 lappend param_list [
lindex $p 0]
2383 while {$index < [
llength $argv]} {
2384 set arg [
lindex $argv $index]
2385 if {[
string first - $arg] == 0} {
2386 set option [
string trimleft $arg "-"]
2388 lappend option_list $arg
2389 if {[lsearch $param_list ${option}*] >= 0 && [
string first ".arg" [lsearch -inline $param_list ${option}*]] >= 0} {
2390 lappend option_list [
lindex $argv $index]
2394 lappend arg_list $arg
2398 Msg Debug "Argv: $argv"
2399 Msg Debug "Options: $option_list"
2400 Msg Debug "Arguments: $arg_list"
2401 return [list $option_list $arg_list]
2419 proc GetProjectFiles {{project_file ""}} {
2421 set libraries [dict create]
2422 set simlibraries [dict create]
2423 set constraints [dict create]
2424 set properties [dict create]
2425 set consets [dict create]
2426 set srcsets [dict create]
2427 set simsets [dict create]
2430 set all_filesets [get_filesets]
2431 set simulator [get_property target_simulator [current_project]]
2432 set top [get_property "top" [current_fileset]]
2434 dict lappend properties $topfile "top=$top"
2436 foreach fs $all_filesets {
2437 if {$fs == "utils_1"} {
2442 set all_files [get_files -quiet -of_objects [get_filesets $fs]]
2443 set fs_type [get_property FILESET_TYPE [get_filesets $fs]]
2445 if {$fs_type == "BlockSrcs"} {
2447 set dict_fs "sources_1"
2451 foreach f $all_files {
2458 if { [
lindex [get_property IS_GENERATED [
GetFile $f $fs]] 0] != 0} {
2463 if {[get_property FILE_TYPE [
GetFile $f $fs]] == "Configuration Files"} {
2469 if {[get_property CORE_CONTAINER [
GetFile $f $fs]] != ""} {
2470 if { [
file extension $f] == ".xcix"} {
2471 set f [get_property CORE_CONTAINER [
GetFile $f $fs]]
2479 if {[get_property SCOPED_TO_REF [
GetFile $f $fs]] != ""} {
2480 dict lappend properties $f "scoped_to_ref=[get_property SCOPED_TO_REF [
GetFile $f $fs]]"
2485 if {[get_property SCOPED_TO_CELLS [
GetFile $f $fs]] != ""} {
2486 dict lappend properties $f "scoped_to_cells=[get_property SCOPED_TO_CELLS [
GetFile $f $fs]]"
2490 if {[
IsInList "PARENT_COMPOSITE_FILE" [list_property [
GetFile $f $fs]]]} {
2495 if {[
file tail $f] == "nocattrs.dat"} {
2500 if {[
file extension $f] != ".coe"} {
2501 set f [
file normalize $f]
2504 set type [get_property FILE_TYPE [
GetFile $f $fs]]
2506 set lib [get_property -quiet LIBRARY [
GetFile $f $fs]]
2509 Msg Debug "File $f Extension [
file extension $f] Type [
lindex $type 0]"
2511 if {[
string equal [
lindex $type 0] "VHDL"] && [
llength $type] == 1} {
2513 }
elseif {[
string equal [
lindex $type 0] "Block"] && [
string equal [
lindex $type 1] "Designs"]} {
2516 }
elseif {[
string equal $type "SystemVerilog"] && [
file extension $f] != ".sv"} {
2517 set prop "SystemVerilog"
2518 }
elseif {[
string equal [
lindex $type 0] "XDC"] && [
file extension $f] != ".xdc"} {
2520 }
elseif {[
string equal $type "Verilog Header"] && [
file extension $f] != ".vh" && [
file extension $f] != ".svh"} {
2521 set prop "verilog_header"
2522 }
elseif {[
string equal $type "Verilog Template"] && [
file extension $f] == ".v" && [
file extension $f] != ".sv"} {
2523 set prop "verilog_template"
2525 set type [
lindex $type 0]
2529 if {![
string equal $prop ""]} {
2530 dict lappend properties $f $prop
2533 if {[
string equal $fs_type "SimulationSrcs"]} {
2535 if {[
string equal $type "VHDL"] } {
2536 set library "${lib}.sim"
2538 set library "others.sim"
2542 dict lappend simsets $dict_fs $library
2545 dict lappend simlibraries $library $f
2547 }
elseif {[
string equal $type "VHDL"] } {
2550 dict lappend srcsets $dict_fs "${lib}.src"
2552 dict lappend libraries "${lib}.src" $f
2553 }
elseif {[
string first "IP" $type] != -1} {
2556 dict lappend srcsets $dict_fs "ips.src"
2558 dict lappend libraries "ips.src" $f
2559 Msg Debug "Appending $f to ips.src"
2560 }
elseif {[
string equal $fs_type "Constrs"]} {
2563 dict lappend consets $dict_fs "sources.con"
2565 dict lappend constraints "sources.con" $f
2569 dict lappend srcsets $dict_fs "others.src"
2571 dict lappend libraries "others.src" $f
2572 Msg Debug "Appending $f to others.src"
2575 if {[
lindex [get_property -quiet used_in_synthesis [
GetFile $f $fs]] 0] == 0} {
2576 dict lappend properties $f "nosynth"
2578 if {[
lindex [get_property -quiet used_in_implementation [
GetFile $f $fs]] 0] == 0} {
2579 dict lappend properties $f "noimpl"
2581 if {[
lindex [get_property -quiet used_in_simulation [
GetFile $f $fs]] 0] == 0} {
2582 dict lappend properties $f "nosim"
2584 if {[
lindex [get_property -quiet IS_MANAGED [
GetFile $f $fs]] 0] == 0 && [
file extension $f] != ".xcix" } {
2585 dict lappend properties $f "locked"
2591 dict lappend properties "Simulator" [get_property target_simulator [current_project]]
2595 set file [open $project_file r]
2596 set in_file_manager 0
2598 while {[
gets $file line] >= 0} {
2600 if {[regexp {^KEY ActiveRoot \"([^\"]+)\"} $line -> value]} {
2601 set top [
string range $value 0 [
expr {[string first "::" $value] - 1}]]
2605 if {[regexp {^LIST FileManager} $line]} {
2606 set in_file_manager 1
2611 if {$in_file_manager && [regexp {^ENDLIST} $line]} {
2616 if {$in_file_manager && [regexp {^VALUE \"([^\"]+)} $line -> value]} {
2619 lassign [
split $value ,] file_path file_type
2622 set library "others"
2623 while {[
gets $file line] >= 0} {
2624 if {$line == "ENDFILE"} {
2627 regexp {^LIBRARY=\"([^\"]+)} $line -> library
2628 regexp {^PARENT=\"([^\"]+)} $line -> parent_file
2630 Msg Debug "Found file ${file_path} in project.."
2631 if {$parent_file == ""} {
2632 if {$file_type == "hdl"} {
2635 dict lappend srcsets "sources_1" "${library}.src"
2637 dict lappend libraries "${library}.src" $file_path
2641 if {[
GetModuleName $file_path] == [
string tolower $top] && $top != ""} {
2642 Msg Debug "Found top module $top in $file_path"
2643 dict lappend properties $file_path "top=$top"
2646 }
elseif {$file_type == "tb_hdl"} {
2648 dict lappend simsets "sim_1" "${library}.sim"
2650 dict lappend simlibraries "${library}.sim" $file_path
2651 }
elseif {$file_type == "io_pdc" || $file_type == "sdc"} {
2653 dict lappend consets "constrs_1" "sources.con"
2655 dict lappend constraints "sources.con" $file_path
2662 set fileData [read [open $project_file]]
2664 set project_path [
file dirname $project_file]
2667 regsub {<\?xml.*\?>} $fileData "" fileData
2670 regexp {<Implementation.*?>(.*)</Implementation>} $fileData -> implementationContent
2674 set sourceRegex {<Source name="([^"]*?)" type="([^"]*?)" type_short="([^"]*?)".*?>(.*?)</Source>}
2676 set optionsRegex {<Options(.*?)\/>}
2677 regexp $optionsRegex $implementationContent -> prj_options
2678 foreach option $prj_options {
2679 if {[regexp {^top=\"([^\"]+)\"} $option match result]} {
2684 while {[regexp $sourceRegex $implementationContent match name type type_short optionsContent]} {
2685 Msg Debug "Found file ${name} in project..."
2686 set file_path [
file normalize $project_path/$name]
2688 set optionsRegex {<Options(.*?)\/>}
2689 regexp $optionsRegex $optionsContent -> options
2690 set library "others"
2692 foreach option $options {
2693 if {[
string first "System Verilog" $option]} {
2696 if {[regexp {^lib=\"([^\"]+)\"} $option match1 result]} {
2701 if {[regexp {syn_sim="([^"]*?)"} $match match_sim simonly]} {
2706 if { $type_short == "VHDL" || $type_short == "Verilog" || $type_short == "IPX"} {
2707 if { $ext == ".src"} {
2708 if {[
IsInList "${library}${ext}" [
DictGet $srcsets "sources_1"]]==0} {
2709 dict lappend srcsets "sources_1" "${library}${ext}"
2711 dict lappend libraries "${library}${ext}" $file_path
2712 }
elseif { $ext == ".sim"} {
2714 dict lappend simsets "sim_1" "${library}.sim"
2716 dict lappend simlibraries "${library}.sim" $file_path
2722 Msg Debug "Found top module $top in $file_path"
2723 dict lappend properties $file_path "top=$top"
2725 }
elseif { $type_short == "SDC"} {
2727 dict lappend consets "constrs_1" "sources.con"
2729 dict lappend constraints "sources.con" $file_path
2733 regsub -- $match $implementationContent "" implementationContent
2736 return [list $libraries $properties $simlibraries $constraints $srcsets $simsets $consets]
2743 proc GetProjectFlavour {proj_name} {
2745 set flavour [
string map {. ""} [
file extension $proj_name]]
2746 if {$flavour != ""} {
2747 if {[
string is integer $flavour]} {
2748 Msg Info "Project $proj_name has flavour = $flavour, the generic variable FLAVOUR will be set to $flavour"
2750 Msg Warning "Project name has a unexpected non numeric extension, flavour will be set to -1"
2768 proc GetProjectVersion {proj_dir repo_path {ext_path ""} {sim 0}} {
2769 if { ![
file exists $proj_dir] } {
2770 Msg CriticalWarning "$proj_dir not found"
2780 Msg Warning "Repository is not clean"
2788 Msg Debug "Project version $v_proj, latest tag $v_last"
2790 Msg Info "The specified project was modified since official version."
2797 Msg Info "The specified project was modified in the latest official version $ret"
2798 }
elseif {$comp == -1} {
2799 Msg Info "The specified project was modified in a past official version $ret"
2814 proc GetRepoVersions {proj_dir repo_path {ext_path ""} {sim 0}} {
2815 if { [
catch {
package require cmdline} ERROR] } {
2816 puts "$ERROR\n If you are running this script on tclsh, you can fix this by installing 'tcllib'"
2831 lappend SHAs [
GetSHA {Hog}]
2835 if {[
Git {status --untracked-files=no --porcelain}] eq ""} {
2836 Msg Info "Hog submodule [
pwd] clean."
2837 lassign [
GetVer ./] hog_ver hog_hash
2839 Msg CriticalWarning "Hog submodule [
pwd] not clean, commit hash will be set to 0."
2840 set hog_hash "0000000"
2841 set hog_ver "00000000"
2846 if {[
Git {status --untracked-files=no --porcelain}] eq ""} {
2847 Msg Info "Git working directory [
pwd] clean."
2850 Msg CriticalWarning "Git working directory [
pwd] not clean, commit hash, and version will be set to 0."
2855 lassign [
GetVer [
join $conf_files]] top_ver top_hash
2856 lappend SHAs $top_hash
2857 lappend versions $top_ver
2864 lassign [
GetHogFiles -list_files "*.src" -sha_mode "./list/" $repo_path] src_files dummy
2865 dict for {f files} $src_files {
2866 # library names have a .src extension in values returned by GetHogFiles
2867 set name [file rootname [file tail $f]]
2868 if {[file ext $f] == ".oth"} {
2871 lassign [GetVer $files] ver hash
2872 # Msg Info "Found source list file $f, version: $ver commit SHA: $hash"
2874 lappend versions $ver
2876 lappend hashes $hash
2883 lassign [
GetHogFiles -list_files "*.con" -sha_mode "./list/" $repo_path] cons_files dummy
2884 dict for {f files} $cons_files {
2885 #library names have a .con extension in values returned by GetHogFiles
2886 set name [file rootname [file tail $f]]
2887 lassign [GetVer $files] ver hash
2888 #Msg Info "Found constraint list file $f, version: $ver commit SHA: $hash"
2890 Msg CriticalWarning "Constraints file $f not found in Git."
2892 lappend cons_hashes $hash
2894 lappend versions $ver
2901 lassign [
GetHogFiles -list_files "*.sim" -sha_mode "./list/" $repo_path] sim_files dummy
2902 dict for {f files} $sim_files {
2903 #library names have a .sim extension in values returned by GetHogFiles
2904 set name [file rootname [file tail $f]]
2905 lassign [GetVer $files] ver hash
2906 #Msg Info "Found simulation list file $f, version: $ver commit SHA: $hash"
2907 lappend sim_hashes $hash
2909 lappend versions $ver
2915 if {"{}" eq $cons_hashes} {
2917 Msg CriticalWarning "No hashes found for constraints files (not in git)"
2920 set cons_hash [
string tolower [
Git "log --format=%h -1 $cons_hashes"]]
2927 set ext_files [glob -nocomplain "./list/*.ext"]
2930 foreach f $ext_files {
2931 set name [
file rootname [
file tail $f]]
2934 lappend ext_names $name
2935 lappend ext_hashes $hash
2938 lappend versions $ext_ver
2941 set file_data [read $fp]
2943 set data [
split $file_data "\n"]
2945 foreach line $data {
2946 if {![regexp {^ *$} $line] & ![regexp {^ *\#} $line] } {
2948 set file_and_prop [regexp -all -inline {\S+} $line]
2949 set hdlfile [
lindex $file_and_prop 0]
2950 set hdlfile $ext_path/$hdlfile
2951 if { [
file exists $hdlfile] } {
2952 set hash [
lindex $file_and_prop 1]
2953 set current_hash [
Md5Sum $hdlfile]
2954 if {[
string first $hash $current_hash] == -1} {
2955 Msg CriticalWarning "File $hdlfile has a wrong hash. Current checksum: $current_hash, expected: $hash"
2963 if {[
llength [glob -nocomplain ./list/*.ipb]] > 0 } {
2965 lassign [
GetHogFiles -list_files "*.ipb" -sha_mode "./list/" $repo_path] xml_files dummy
2966 lassign [
GetVer [dict get $xml_files "xml.ipb"]] xml_ver xml_hash
2967 lappend SHAs $xml_hash
2968 lappend versions $xml_ver
2973 Msg Info "This project does not use IPbus XMLs"
2978 set user_ip_repos ""
2979 set user_ip_repo_hashes ""
2980 set user_ip_repo_vers ""
2982 if {[
file exists [
lindex $conf_files 0]]} {
2983 set PROPERTIES [
ReadConf [
lindex $conf_files 0]]
2984 if {[dict exists $PROPERTIES main]} {
2985 set main [dict get $PROPERTIES main]
2986 dict for {p v} $main {
2987 if { [ string tolower $p ] == "ip_repo_paths" } {
2989 lappend user_ip_repos "$repo_path/$repo"
2996 foreach repo $user_ip_repos {
2997 if {[
file isdirectory $repo]} {
2998 set repo_file_list [glob -nocomplain "$repo/*"]
2999 if {[
llength $repo_file_list] != 0} {
3000 lassign [
GetVer $repo] ver sha
3001 lappend user_ip_repo_hashes $sha
3002 lappend user_ip_repo_vers $ver
3003 lappend versions $ver
3005 Msg Warning "IP_REPO_PATHS property set to $repo in hog.conf but directory is empty."
3008 Msg Warning "IP_REPO_PATHS property set to $repo in hog.conf but directory does not exist."
3017 while {$found == 0} {
3018 set global_commit [
Git "log --format=%h -1 --abbrev=7 $SHAs"]
3023 if {$common_child == 0} {
3024 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."
3026 Msg Info "The commit $sha is not an ancestor of the global commit $global_commit, adding the first common child $common_child instead..."
3027 lappend SHAs $common_child
3037 set global_commit "0000000"
3038 set global_version "00000000"
3043 set top_hash [
format %+07s $top_hash]
3044 set cons_hash [
format %+07s $cons_hash]
3045 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]
3054 proc GetSHA {{path ""}} {
3056 lassign [
GitRet {log --format=%h --abbrev=7 -1}] status result
3058 return [
string tolower $result]
3060 Msg Error "Something went wrong while finding the latest SHA. Does the repository have a commit?"
3066 set repo_path [
lindex [
Git {rev-parse --show-toplevel}] 0]
3070 set file_in_module 0
3071 if {[
file exists $repo_path/.gitmodules]} {
3072 lassign [
GitRet "config --file $repo_path/.gitmodules --get-regexp path"] status result
3074 set submodules [
split $result "\n"]
3077 Msg Warning "Something went wrong while trying to find submodules: $result"
3080 foreach mod $submodules {
3081 set module [
lindex $mod 1]
3082 if {[
string first "$repo_path/$module" $f] == 0} {
3084 set file_in_module 1
3085 lappend paths "$repo_path/$module"
3091 if {$file_in_module == 0} {
3097 lassign [
GitRet {log --format=%h --abbrev=7 -1} $paths] status result
3099 return [
string tolower $result]
3101 Msg Error "Something went wrong while finding the latest SHA. Does the repository have a commit?"
3104 return [
string tolower $result]
3108 proc GetSimulators {} {
3109 set SIMULATORS [list "modelsim" "questa" "riviera" "activehdl" "ies" "vcs"]
3114 proc GetTopFile {} {
3116 set compile_order_prop [get_property source_mgmt_mode [current_project]]
3117 if {$compile_order_prop ne "All"} {
3118 Msg CriticalWarning "Compile order is not set to automatic, setting it now..."
3119 set_property source_mgmt_mode All [current_project]
3120 update_compile_order -fileset sources_1
3122 return [
lindex [get_files -quiet -compile_order sources -used_in synthesis -filter {FILE_TYPE =~ "VHDL*" || FILE_TYPE =~ "*Verilog*" }] end]
3123 }
elseif {[
IsISE]} {
3124 debug::design_graph_mgr -create [current_fileset]
3125 debug::design_graph -add_fileset [current_fileset]
3126 debug::design_graph -update_all
3127 return [
lindex [debug::design_graph -get_compile_order] end]
3129 Msg Error "GetTopFile not yet implemented for this IDE"
3134 proc GetTopModule {} {
3136 return [get_property top [current_fileset]]
3138 Msg Error "GetTopModule not yet implemented for this IDE"
3148 proc GetVer {path {force_develop 0}} {
3152 Msg CriticalWarning "Empty SHA found for ${path}. Commit to Git to resolve this warning."
3155 set p [
lindex $path 0]
3156 if {[
file isdirectory $p]} {
3159 cd [
file dirname $p]
3161 set repo_path [
Git {rev-parse --show-toplevel}]
3164 return [list [
GetVerFromSHA $SHA $repo_path $force_develop] $SHA]
3175 proc GetVerFromSHA {SHA repo_path {force_develop 0}} {
3177 Msg CriticalWarning "Empty SHA found"
3180 lassign [
GitRet "tag --sort=creatordate --contain $SHA -l v*.*.* -l b*v*.*.*"] status result
3183 if {[regexp {^ *$} $result]} {
3185 lassign [
GitRet "log --oneline --pretty=\"%d\""] status2 tag_list
3188 set pattern {tag: v\d+\.\d+\.\d+}
3189 set real_tag_list {}
3190 foreach x $tag_list {
3191 set x_untrimmed [regexp -all -inline $pattern $x]
3192 regsub "tag: " $x_untrimmed "" x_trimmed
3193 set tt [
lindex $x_trimmed 0]
3194 if {![
string equal $tt ""]} {
3195 lappend real_tag_list $tt
3199 Msg Debug "Cleaned up list: $real_tag_list."
3201 set sorted_tags [lsort -decreasing -command CompareVersions $real_tag_list]
3203 Msg Debug "Sorted Tag list: $sorted_tags"
3205 set tag [
lindex $sorted_tags 0]
3208 set pattern {v\d+\.\d+\.\d+}
3209 if {![regexp $pattern $tag]} {
3210 Msg CriticalWarning "No Hog version tags found in this repository."
3216 set repo_conf $repo_path/Top/repo.conf
3220 set hotfix_prefix "hotfix/"
3221 set minor_prefix "minor_version/"
3222 set major_prefix "major_version/"
3224 set enable_develop_branch $force_develop
3226 set branch_name [
Git {rev-parse --abbrev-ref HEAD}]
3228 if {[
file exists $repo_conf]} {
3229 set PROPERTIES [
ReadConf $repo_conf]
3231 if {[dict exists $PROPERTIES main]} {
3232 set mainDict [dict get $PROPERTIES main]
3235 if {[dict exists $mainDict ENABLE_DEVELOP_BRANCH]} {
3236 set enable_develop_branch [dict get $mainDict ENABLE_DEVELOP_BRANCH]
3243 if {[dict exists $PROPERTIES prefixes]} {
3244 set prefixDict [dict get $PROPERTIES prefixes]
3246 if {[dict exists $prefixDict HOTFIX]} {
3247 set hotfix_prefix [dict get $prefixDict HOTFIX]
3249 if {[dict exists $prefixDict MINOR_VERSION]} {
3250 set minor_prefix [dict get $prefixDict MINOR_VERSION]
3252 if {[dict exists $prefixDict MAJOR_VERSION]} {
3253 set major_prefix [dict get $prefixDict MAJOR_VERSION]
3259 if {$enable_develop_branch == 1 } {
3260 if {[
string match "$hotfix_prefix*" $branch_name]} {
3265 if {[
string match "$major_prefix*" $branch_name]} {
3267 set version_level major
3268 }
elseif {[
string match "$minor_prefix*" $branch_name] || ($enable_develop_branch == 1 && $is_hotfix == 0)} {
3270 set version_level minor
3273 set version_level patch
3281 Msg CriticalWarning "Tag $tag does not contain a Hog compatible version in this repository."
3284 }
elseif {$mr == 0} {
3286 switch $version_level {
3302 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."
3308 set vers [
split $result "\n"]
3309 set ver [
lindex $vers 0]
3311 if {[regexp {^v.*$} $v]} {
3319 Msg CriticalWarning "Error while trying to find tag for $SHA"
3327 set M [
format %02X $M]
3328 set m [
format %02X $m]
3329 set c [
format %04X $c]
3331 }
elseif { $M > -1 } {
3333 set M [
format %02X $M]
3334 set m [
format %02X $m]
3335 set c [
format %04X $c]
3338 Msg Warning "Tag does not contain a properly formatted version: $ver"
3339 set M [
format %02X 0]
3340 set m [
format %02X 0]
3341 set c [
format %04X 0]
3354 proc Git {command {files ""}} {
3355 lassign [
GitRet $command $files] ret result
3357 Msg Error "Code $ret returned by git running: $command -- $files"
3368 proc GetModuleName {filename} {
3370 if {![
file exists $filename]} {
3371 Msg CriticalWarning "Error: File $filename does not exist."
3376 set fileId [open $filename r]
3379 set file_content [read $fileId]
3385 if {[
file extension $filename] == ".vhd" || [
file extension $filename] == ".vhdl"} {
3387 set file_content [
string tolower $file_content]
3389 set pattern {(?m)^\s*entity\s+(\S+)\s+is}
3390 }
elseif {[
file extension $filename] == ".v" || [
file extension $filename] == ".sv"} {
3392 set pattern {\n\s*module\s*(\w+)(\s*|\(|\n)}
3394 Msg Debug "File is neither VHDL nor Verilog... Returning empty string..."
3399 if {[regexp $pattern $file_content match module_name]} {
3402 Msg Debug "No module was found in $filename. Returning an empty string..."
3410 proc GetVerilogGenerics {file} {
3411 set fp [open $file r]
3417 foreach line [
split $data "\n"] {
3418 regsub "^\\s*\/\/.*" $line "" line
3419 regsub "(.*)\/\/.*" $line {\1} line
3420 if {![
string equal $line ""]} {
3421 append lines $line " "
3426 regsub -all {/\*.*\*/} $lines "" lines
3429 set punctuation [list]
3430 foreach char [list "(" ")" ";" "," " " "!" "<=" ":=" "=" "\[" "\]"] {
3431 lappend punctuation $char "\000$char\000"
3435 set tokens [
split [
string map $punctuation $lines] \000]
3437 set parameters [dict create]
3446 foreach token $tokens {
3447 set token [
string trim $token]
3448 if {![
string equal "" $token]} {
3449 if {[
string equal [
string tolower $token] "parameter"]} {
3450 set state $PARAM_NAME
3451 }
elseif {[
string equal $token ")"] || [
string equal $token ";"]} {
3453 }
elseif {$state == $PARAM_WIDTH} {
3454 if {[
string equal $token "\]"]} {
3455 set state $PARAM_NAME
3457 }
elseif {$state == $PARAM_VALUE} {
3458 if {[
string equal $token ","]} {
3459 set state $PARAM_NAME
3460 }
elseif {[
string equal $token ";"]} {
3464 }
elseif {$state == $PARAM_NAME} {
3466 if {[
string equal $token "="]} {
3467 set state $PARAM_VALUE
3468 }
elseif {[
string equal $token "\["]} {
3469 set state $PARAM_WIDTH
3470 }
elseif {[
string equal $token ","]} {
3471 set state $PARAM_NAME
3472 }
elseif {[
string equal $token ";"]} {
3474 }
elseif {[
string equal $token ")"]} {
3477 dict set parameters $token "integer"
3490 proc GetVhdlGenerics {file {entity ""} } {
3491 set fp [open $file r]
3497 foreach line [
split $data "\n"] {
3498 regsub "^\\s*--.*" $line "" line
3499 regsub "(.*)--.*" $line {\1} line
3500 if {![
string equal $line ""]} {
3501 append lines $line " "
3506 set generic_block ""
3507 set generics [dict create]
3509 if {1==[
string equal $entity ""]} {
3510 regexp {(?i).*entity\s+([^\s]+)\s+is} $lines _ entity
3513 set generics_regexp "(?i).*entity\\s+$entity\\s+is\\s+generic\\s*\\((.*)\\)\\s*;\\s*port.*end.*$entity"
3515 if {[regexp $generics_regexp $lines _ generic_block]} {
3517 foreach line [
split $generic_block ";"] {
3519 regexp {(.*):\s*([A-Za-z0-9_]+).*} $line _ generic type
3522 set splits [
split $generic ","]
3523 foreach split $splits {
3524 dict set generics [
string trim $split] [
string trim $type]
3532 proc GHDL {command} {
3533 set ret [
catch {
exec -ignorestderr ghdl {*}$command} result]
3535 Msg CriticalWarning "GHDL execution failed."
3549 proc GitRet {command {files ""}} {
3552 set ret [
catch {
exec -ignorestderr git {*}$command} result]
3554 set ret [
catch {
exec -ignorestderr git {*}$command -- {*}$files} result]
3556 return [list $ret $result]
3564 proc GitVersion {target_version} {
3565 set ver [
split $target_version "."]
3566 set v [
Git --version]
3568 set current_ver [
split [
lindex $v 2] "."]
3569 set target [
expr {[lindex $ver 0]*100000 + [lindex $ver 1]*100 + [lindex $ver 2]}]
3570 set current [
expr {[lindex $current_ver 0]*100000 + [lindex $current_ver 1]*100 + [lindex $current_ver 2]}]
3571 return [
expr {$target <= $current}]
3583 proc HandleIP {what_to_do xci_file ip_path repo_path {gen_dir "."} {force 0}} {
3584 if {!($what_to_do eq "push") && !($what_to_do eq "pull")} {
3585 Msg Error "You must specify push or pull as first argument."
3588 if { [
catch {
package require tar} TARPACKAGE]} {
3589 Msg CriticalWarning "Cannot find package tar. You can fix this by installing package \"tcllib\""
3598 if {[
string first "/eos/" $ip_path] == 0} {
3606 lassign [
eos "ls $ip_path"] ret result
3608 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."
3612 Msg Info "IP remote directory path, on EOS, is set to: $ip_path"
3619 if {!([
file exists $xci_file])} {
3620 Msg CriticalWarning "Could not find $xci_file."
3626 set xci_path [
file dirname $xci_file]
3627 set xci_name [
file tail $xci_file]
3628 set xci_ip_name [
file rootname [
file tail $xci_file]]
3629 set xci_dir_name [
file tail $xci_path]
3630 set gen_path $gen_dir
3632 set hash [
Md5Sum $xci_file]
3633 set file_name $xci_name\_$hash
3635 Msg Info "Preparing to $what_to_do IP: $xci_name..."
3637 if {$what_to_do eq "push"} {
3641 lassign [
eos "ls $ip_path/$file_name.tar"] ret result
3646 Msg Info "IP already in the EOS repository, will not copy..."
3648 Msg Info "IP already in the EOS repository, will forcefully replace..."
3654 if {[
file exists "$ip_path/$file_name.tar"]} {
3656 Msg Info "IP already in the local repository, will not copy..."
3658 Msg Info "IP already in the local repository, will forcefully replace..."
3667 if {$will_copy == 1} {
3669 Msg Info "Looking for generated files in $gen_path..."
3670 set ip_gen_files [glob -nocomplain $gen_path/*]
3674 if {[
llength $ip_gen_files] > 0} {
3675 Msg Info "Found some IP synthesised files matching $xci_ip_name"
3676 if {$will_remove == 1} {
3677 Msg Info "Removing old synthesised directory $ip_path/$file_name.tar..."
3679 eos "rm -rf $ip_path/$file_name.tar" 5
3681 file delete -force "$ip_path/$file_name.tar"
3685 Msg Info "Creating local archive with IP generated files..."
3687 foreach f $ip_gen_files {
3688 if {$first_file == 0} {
3689 ::tar::create $file_name.tar "[
Relative [
file normalize $repo_path] $f]"
3692 ::tar::add $file_name.tar "[
Relative [
file normalize $repo_path] $f]"
3696 Msg Info "Copying IP generated files for $xci_name..."
3698 lassign [
ExecuteRet xrdcp -f -s $file_name.tar $::env(EOS_MGM_URL)//$ip_path/] ret msg
3700 Msg CriticalWarning "Something went wrong when copying the IP files to EOS. Error message: $msg"
3703 Copy "$file_name.tar" "$ip_path/"
3705 Msg Info "Removing local archive"
3706 file delete $file_name.tar
3709 Msg Warning "Could not find synthesized files matching $gen_path/$file_name*"
3712 }
elseif {$what_to_do eq "pull"} {
3714 lassign [
eos "ls $ip_path/$file_name.tar"] ret result
3716 Msg Info "Nothing for $xci_name was found in the EOS repository, cannot pull."
3721 set remote_tar "$::env(EOS_MGM_URL)//$ip_path/$file_name.tar"
3722 Msg Info "IP $xci_name found in the repository $remote_tar, copying it locally to $repo_path..."
3724 lassign [
ExecuteRet xrdcp -f -r -s $remote_tar $repo_path] ret msg
3726 Msg CriticalWarning "Something went wrong when copying the IP files to EOS. Error message: $msg"
3730 if {[
file exists "$ip_path/$file_name.tar"]} {
3731 Msg Info "IP $xci_name found in local repository $ip_path/$file_name.tar, copying it locally to $repo_path..."
3732 Copy $ip_path/$file_name.tar $repo_path
3735 Msg Info "Nothing for $xci_name was found in the local IP repository, cannot pull."
3742 if {[
file exists $file_name.tar]} {
3743 remove_files $xci_file
3744 Msg Info "Extracting IP files from archive to $repo_path..."
3745 ::tar::untar $file_name.tar -dir $repo_path -noperms
3746 Msg Info "Removing local archive"
3747 file delete $file_name.tar
3748 add_files -norecurse -fileset sources_1 $xci_file
3761 proc HexVersionToString {version} {
3762 scan [
string range $version 0 1] %x M
3763 scan [
string range $version 2 3] %x m
3764 scan [
string range $version 4 7] %x c
3769 proc ImportTclLib {} {
3771 if {[
info exists env(HOG_TCLLIB_PATH)]} {
3772 lappend auto_path $env(HOG_TCLLIB_PATH)
3775 puts "ERROR: To run Hog with Microsemi Libero SoC or Lattice Diamond, you need to define the HOG_TCLLIB_PATH variable."
3790 proc InitLauncher {script tcl_path parameters commands argv {custom_commands ""}} {
3791 set repo_path [
file normalize "$tcl_path/../.."]
3793 set bin_path [
file normalize "$tcl_path/../../bin"]
3794 set top_path [
file normalize "$tcl_path/../../Top"]
3796 set cmd_lines [
split $commands "\n"]
3798 set command_options [dict create]
3799 set directive_descriptions [dict create]
3800 set directive_names [dict create]
3801 set common_directive_names [dict create]
3803 foreach l $cmd_lines {
3806 if { [regexp {\\(.*) \{\#} $l minc d] } {
3807 lappend directives_with_projects $d
3811 if { [regexp {\\(.*) \{} $l minc regular_expression]} {
3812 lappend directive_regex $regular_expression
3816 if { [regexp {\#\s*NAME(\*)?:\s*(.*)\s*} $l minc star name] } {
3817 dict set directive_names $name $regular_expression
3819 dict set common_directive_names $name $regular_expression
3822 set directive_names [
DictSort $directive_names]
3823 set common_directive_names [
DictSort $common_directive_names]
3826 if { [regexp {\#\s*DESCRIPTION:\s*(.*)\s*} $l minc x]} {
3827 dict set directive_descriptions $regular_expression $x
3831 if { [regexp {\#\s*OPTIONS:\s*(.*)\s*} $l minc x]} {
3832 dict set command_options $regular_expression [
split [regsub -all {[ \t\n]+} $x {}] ","]
3837 set short_usage "usage: ./Hog/Do \[OPTIONS\] <directive> \[project\]\n\nMost common directives (case insensitive):"
3839 dict for {key value} $common_directive_names {
3840 set short_usage "$short_usage\n - $key: [dict get $directive_descriptions $value]"
3843 set short_usage "$short_usage\n\nTo see all the available directives, run:\n./Hog/Do HELP\n\nTo list available options for the chosen directive run:\n./Hog/Do <directive> HELP
3847 set usage "usage: ./Hog/Do \[OPTIONS\] <directive> \[project\]\n\nDirectives (case insensitive):"
3849 dict for {key value} $directive_names {
3850 set usage "$usage\n - $key: [dict get $directive_descriptions $value]"
3853 set usage "$usage\n$custom_commands"
3855 set usage "$usage\n\nTo list available options for the chosen directive run:\n./Hog/Do <directive> HELP"
3862 if {[
catch {
package require cmdline} ERROR]} {
3863 Msg Debug "The cmdline Tcl package was not found, sourcing it from Hog..."
3864 source $tcl_path/utils/cmdline.tcl
3867 set argv [regsub -all {(?i) HELP\y} $argv " -help"]
3869 lassign [
GetOptions $argv $parameters] option_list arg_list
3871 if { [
IsInList "-all" $option_list] } {
3880 set directive [
string toupper [
lindex $arg_list 0]]
3883 set argument_is_no_project 0
3885 switch -regexp -- $directive "$commands"
3888 if {$directive != ""} {
3889 if {[
IsInList $directive $directives_with_projects 1]} {
3890 puts "usage: ./Hog/Do \[OPTIONS\] $directive <project>\n"
3891 }
elseif {[regexp "^COMPSIM(LIB)?$" $directive]} {
3892 puts "usage: ./Hog/Do \[OPTIONS\] $directive <simulator>\n"
3894 puts "usage: ./Hog/Do \[OPTIONS\] $directive \n"
3897 dict for {dir desc} $directive_descriptions {
3898 if {[regexp $dir $directive]} {
3904 dict for {dir opts} $command_options {
3905 if {[regexp $dir $directive]} {
3906 puts "Available options:"
3908 foreach par $parameters {
3909 if {$opt == [lindex $par 0]} {
3910 if {[regexp {\.arg$} $opt]} {
3911 set opt_name [regsub {\.arg$} $opt ""]
3912 puts " -$opt_name <argument>"
3916 puts " [lindex $par [llength $par]-1]"
3930 if {[
catch {
array set options [
cmdline::getoptions option_list $parameters $usage]} err] } {
3931 Msg Status "\nERROR: Syntax error, probably unknown option.\n\n USAGE: $err"
3935 if { [
llength $arg_list] <= $min_n_of_args || [
llength $arg_list] > $max_n_of_args} {
3936 Msg Status "\nERROR: Wrong number of arguments: [
llength $argv]"
3941 set project [
lindex $arg_list 1]
3943 if {$argument_is_no_project == 0 } {
3945 regsub "^(\./)?Top/" $project "" project
3947 regsub "/? *\$" $project "" project
3953 Msg Debug "Option list:"
3954 foreach {key value} [
array get options] {
3955 Msg Debug "$key => $value"
3962 if {$proj_conf != 0} {
3965 lassign [
GetIDECommand $proj_conf] cmd before_tcl_script after_tcl_script end_marker
3966 Msg Info "Project $project uses $cmd IDE"
3969 set command "$cmd $before_tcl_script$script$after_tcl_script$argv$end_marker"
3972 if {$argument_is_no_project == 1} {
3974 Msg Debug "$project will be used as first argument"
3975 }
elseif {$project != ""} {
3978 }
elseif {$min_n_of_args < 0} {
3991 set project_group [
file dirname $project]
3992 set project [
file tail $project]
3993 if { $project_group != "." } {
3994 set project_name "$project_group/$project"
3996 set project_name "$project"
3999 return [list $directive $project $project_name $project_group $repo_path $old_path $bin_path $top_path $usage $short_usage $command $cmd [
array get options]]
4006 proc IsCommitAncestor {ancestor commit} {
4007 lassign [
GitRet "merge-base --is-ancestor $ancestor $commit"] status result
4008 if {$status == 0 } {
4016 return [
expr {[info commands sys_install] != ""}]
4021 return [
expr {[info commands get_libero_version] != ""}]
4029 proc IsInList {element list {regex 0}} {
4031 if {$regex == 1 && [regexp $x $element] } {
4033 }
elseif { $regex == 0 && $x eq $element } {
4044 return [
expr {[string first PlanAhead [version]] == 0}]
4052 if {[
catch {
package require ::quartus::flow} result]} {
4065 proc IsRelativePath {path} {
4066 if {[
string index $path 0] == "/" || [
string index $path 0] == "~"} {
4074 proc IsSynplify {} {
4075 return [
expr {[info commands program_version] != ""}]
4080 return [
expr {![IsQuartus] && ![IsXilinx] && ![IsLibero] && ![IsSynplify] && ![IsDiamond]}]
4088 proc IsVersal {part} {
4089 if {[get_property ARCHITECTURE [get_parts $part]] eq "versal"} {
4099 return [
expr {[string first Vivado [version]] == 0}]
4107 if {[
info commands version] != ""} {
4108 set current_version [version]
4109 if {[
string first PlanAhead $current_version] == 0 || [
string first Vivado $current_version] == 0} {
4112 Msg Warning "This IDE has the version command but it is not PlanAhead or Vivado: $current_version"
4125 proc IsZynq {part} {
4126 if { [regexp {^(xc7z|xczu).*} $part] } {
4133 proc ImportGHDL { project_name repo_path simset_name simset_dict {ext_path ""}} {
4134 set list_path "$repo_path/Top/$project_name/list"
4135 lassign [
GetHogFiles -list_files {.src,.ext,.sim} -ext_path $ext_path $list_path $repo_path] src_files properties filesets
4140 set properties [
DictGet $simset_dict "properties"]
4141 set options [
DictGet $properties "options"]
4144 set workdir Projects/$project_name/ghdl
4145 file delete -force $workdir
4147 dict for {lib sources} $src_files {
4148 set libname [file rootname $lib]
4149 foreach f $sources {
4150 if {[file extension $f] != ".vhd" && [file extension $f] != ".vhdl"} {
4151 Msg Info "File $f is not a VHDL file, copying it in workfolder..."
4152 file copy -force $f $workdir
4154 set file_path [Relative $repo_path $f]
4155 puts "ghdl -i --work=$libname --workdir=$workdir -fsynopsys --ieee=standard $options $file_path"
4156 GHDL "-i --work=$libname --workdir=$workdir -fsynopsys --ieee=standard $options $file_path"
4163 proc LaunchGHDL { project_name repo_path simset_name simset_dict {ext_path ""}} {
4167 set sim_props [
DictGet $simset_dict "properties"]
4168 set options [
DictGet $sim_props "options"]
4169 set runopts [
DictGet $sim_props "run_options"]
4171 dict for {prop_name prop_val} $sim_props {
4172 set prop_name [string toupper $prop_name]
4173 if { $prop_name == "TOP"} {
4174 set top_sim $prop_val
4177 set workdir $repo_path/Projects/$project_name/ghdl
4180 puts "ghdl -m --work=$simset_name -fsynopsys --ieee=standard $options $top_sim"
4181 GHDL "-m --work=$simset_name -fsynopsys --ieee=standard $options $top_sim"
4182 puts "ghdl -r --work=$simset_name -fsynopsys --ieee=standard $options $top_sim $runopts"
4183 GHDL "-r --work=$simset_name -fsynopsys --ieee=standard $options $top_sim $runopts"
4195 proc LaunchImplementation {reset do_create run_folder project_name {repo_path .} {njobs 4} {do_bitstream 0}} {
4196 Msg Info "Starting implementation flow..."
4198 if { $reset == 1 && $do_create == 0} {
4199 Msg Info "Resetting run before launching implementation..."
4204 source $repo_path/Hog/Tcl/integrated/pre-implementation.tcl
4207 if {$do_bitstream == 1} {
4208 launch_runs impl_1 -to_step [
BinaryStepName [get_property PART [current_project]]] $njobs -dir $run_folder
4210 launch_runs impl_1 -jobs $njobs -dir $run_folder
4215 Msg Info "running post-implementation"
4216 source $repo_path/Hog/Tcl/integrated/post-implementation.tcl
4217 if {$do_bitstream == 1} {
4218 Msg Info "running pre-bitstream"
4219 source $repo_path/Hog/Tcl/integrated/pre-bitstream.tcl
4220 Msg Info "running post-bitstream"
4221 source $repo_path/Hog/Tcl/integrated/post-bitstream.tcl
4225 set prog [get_property PROGRESS [get_runs impl_1]]
4226 set status [get_property STATUS [get_runs impl_1]]
4227 Msg Info "Run: impl_1 progress: $prog, status : $status"
4231 set status_file [open "$run_folder/timing.txt" "w"]
4232 puts $status_file "## $project_name Timing summary"
4234 set f [open [
lindex [glob "$run_folder/impl_1/*.twr" 0]]]
4236 while {[
gets $f line] >= 0} {
4237 if { [
string match "Timing summary:" $line] } {
4238 while {[
gets $f line] >= 0} {
4239 if { [
string match "Timing errors:*" $line] } {
4240 set errs [regexp -inline -- {[0-9]+} $line]
4242 if { [
string match "*Footnotes*" $line] } {
4245 puts $status_file "$line"
4254 Msg Info "Time requirements are met"
4255 file rename -force "$run_folder/timing.txt" "$run_folder/timing_ok.txt"
4258 Msg CriticalWarning "Time requirements are NOT met"
4259 file rename -force "$run_folder/timing.txt" "$run_folder/timing_error.txt"
4265 set wns [get_property STATS.WNS [get_runs [current_run]]]
4266 set tns [get_property STATS.TNS [get_runs [current_run]]]
4267 set whs [get_property STATS.WHS [get_runs [current_run]]]
4268 set ths [get_property STATS.THS [get_runs [current_run]]]
4269 set tpws [get_property STATS.TPWS [get_runs [current_run]]]
4271 if {$wns >= 0 && $whs >= 0 && $tpws >= 0} {
4272 Msg Info "Time requirements are met"
4273 set status_file [open "$run_folder/timing_ok.txt" "w"]
4276 Msg CriticalWarning "Time requirements are NOT met"
4277 set status_file [open "$run_folder/timing_error.txt" "w"]
4281 Msg Status "*** Timing summary ***"
4282 Msg Status "WNS: $wns"
4283 Msg Status "TNS: $tns"
4284 Msg Status "WHS: $whs"
4285 Msg Status "THS: $ths"
4286 Msg Status "TPWS: $tpws"
4292 puts $status_file "## $project_name Timing summary"
4294 m add row "| **Parameter** | \"**value (ns)**\" |"
4295 m add row "| --- | --- |"
4296 m add row "| WNS: | $wns |"
4297 m add row "| TNS: | $tns |"
4298 m add row "| WHS: | $whs |"
4299 m add row "| THS: | $ths |"
4300 m add row "| TPWS: | $tpws |"
4302 puts $status_file [m format 2string]
4303 puts $status_file "\n"
4304 if {$timing_ok == 1} {
4305 puts $status_file " Time requirements are met."
4307 puts $status_file "Time requirements are **NOT** met."
4309 puts $status_file "\n\n"
4313 if {$prog ne "100%"} {
4314 Msg Error "Implementation error"
4319 lassign [
GetRepoVersions [
file normalize ./Top/$project_name] $repo_path] sha
4321 Msg Info "Git describe set to $describe"
4323 set dst_dir [
file normalize "$repo_path/bin/$project_name\-$describe"]
4328 if {[
file exists $run_folder/versions.txt]} {
4329 file copy -force $run_folder/versions.txt $dst_dir
4331 Msg Warning "No versions file found in $run_folder/versions.txt"
4334 set timing_files [ glob -nocomplain "$run_folder/timing_*.txt"]
4335 set timing_file [
file normalize [
lindex $timing_files 0]]
4337 if {[
file exists $timing_file]} {
4338 file copy -force $timing_file $dst_dir/
4340 Msg Warning "No timing file found, not a problem if running locally"
4344 if {[
IsVersal [get_property part [current_project]]]} {
4345 if {[get_property segmented_configuration [current_project]] == 1} {
4346 Msg Info "Versal Segmented configuration detected: exporting XSA file..."
4347 set xsa_name "$dst_dir/[
file tail $project_name]\-$describe.xsa"
4348 write_hw_platform -fixed -force -file $xsa_name
4353 set revision [get_current_revision]
4355 if {[
catch {execute_module -tool fit} result]} {
4356 Msg Error "Result: $result\n"
4357 Msg Error "Place & Route failed. See the report file.\n"
4359 Msg Info "\nINFO: Place & Route was successful for revision $revision.\n"
4362 if {[
catch {execute_module -tool sta -args "--do_report_timing"} result]} {
4363 Msg Error "Result: $result\n"
4364 Msg Error "Time Quest failed. See the report file.\n"
4366 Msg Info "Time Quest was successfully run for revision $revision.\n"
4369 set panel "Timing Analyzer||Timing Analyzer Summary"
4370 set device [ get_report_panel_data -name $panel -col 1 -row_name "Device Name"]
4371 set timing_model [ get_report_panel_data -name $panel -col 1 -row_name "Timing Models"]
4372 set delay_model [ get_report_panel_data -name $panel -col 1 -row_name "Delay Model"]
4374 Msg Info "*******************************************************************"
4375 Msg Info "Device: $device"
4376 Msg Info "Timing Models: $timing_model"
4377 Msg Info "Delay Model: $delay_model"
4380 Msg Info "*******************************************************************"
4383 Msg Info "Starting implementation flow..."
4384 if {[
catch {run_tool -name {PLACEROUTE}}] } {
4385 Msg Error "PLACEROUTE FAILED!"
4387 Msg Info "PLACEROUTE PASSED."
4391 Msg Info "Run VERIFYTIMING ..."
4392 if {[
catch {run_tool -name {VERIFYTIMING} -script {Hog/Tcl/integrated/libero_timing.tcl}}] } {
4393 Msg CriticalWarning "VERIFYTIMING FAILED!"
4395 Msg Info "VERIFYTIMING PASSED \n"
4401 lassign [
GetRepoVersions [
file normalize ./Top/$project_name] $repo_path] sha
4403 Msg Info "Git describe set to $describe"
4405 set dst_dir [
file normalize "$repo_path/bin/$project_name\-$describe"]
4406 file mkdir $dst_dir/reports
4409 if {[
file exists $run_folder/versions.txt]} {
4410 file copy -force $run_folder/versions.txt $dst_dir
4412 Msg Warning "No versions file found in $run_folder/versions.txt"
4415 set timing_file_path [
file normalize "$repo_path/Projects/timing_libero.txt"]
4416 if {[
file exists $timing_file_path]} {
4417 file copy -force $timing_file_path $dst_dir/reports/Timing.txt
4418 set timing_file [open $timing_file_path "r"]
4419 set status_file [open "$dst_dir/timing.txt" "w"]
4420 puts $status_file "## $project_name Timing summary\n\n"
4421 puts $status_file "| | |"
4422 puts $status_file "| --- | --- |"
4423 while {[
gets $timing_file line] >= 0} {
4424 if { [
string match "SUMMARY" $line] } {
4425 while {[
gets $timing_file line] >= 0} {
4426 if { [
string match "END SUMMARY" $line] } {
4429 if {[
string first ":" $line] == -1} {
4432 set out_string "| [
string map {: | } $line] |"
4433 puts $status_file "$out_string"
4438 Msg Warning "No timing file found, not a problem if running locally"
4443 set force_rst "-forceOne"
4445 prj_run Map $force_rst
4446 prj_run PAR $force_rst
4459 proc LaunchSimulation {project_name lib_path simsets {repo_path .}} {
4462 set project [
file tail $project_name]
4463 set main_sim_folder [
file normalize "$repo_path/Projects/$project_name/$project.sim/"]
4465 if {$simsets != ""} {
4466 dict for {simset sim_dict} $simsets {
4467 lappend simsets_todo $simset
4469 Msg Info "Will run only the following simulation's sets (if they exist): $simsets_todo"
4474 set sim_dic [dict create]
4476 Msg Info "Retrieving list of simulation sets..."
4477 foreach s [get_filesets] {
4479 set use_simpass_str 0
4482 set type [get_property FILESET_TYPE $s]
4483 if {$type eq "SimulationSrcs"} {
4484 if {$simsets_todo != "" && $s ni $simsets_todo} {
4485 Msg Info "Skipping $s as it was not specified with the -simset option..."
4488 set sim_dict [
DictGet $simsets $s]
4489 set simulator [
DictGet $sim_dict "simulator"]
4490 set_property "target_simulator" $simulator [current_project]
4491 set hog_sim_props [
DictGet $sim_dict "hog"]
4492 dict for {prop_name prop_val} $hog_sim_props {
4493 # If HOG_SIMPASS_STR is set, use the HOG_SIMPASS_STR string to search for in logs, after simulation is done
4494 if { [string toupper $prop_name] == "HOG_SIMPASS_STR" && $prop_val != "" } {
4495 Msg Info "Setting simulation pass string as '$prop_val'"
4496 set use_simpass_str 1
4497 set simpass_str $prop_val
4499 if { [string toupper $prop_name] == "HOG_SILENT_SIM" && $prop_val == 1 } {
4500 set quiet_sim " -quiet"
4506 Msg Info "Creating simulation scripts for $s..."
4507 if { [
file exists $repo_path/Top/$project_name/pre-simulation.tcl] } {
4508 Msg Info "Running $repo_path/Top/$project_name/pre-simulation.tcl"
4509 source $repo_path/Top/$project_name/pre-simulation.tcl
4511 if { [
file exists $repo_path/Top/$project_name/pre-$s-simulation.tcl] } {
4512 Msg Info "Running $repo_path/Top/$project_name/pre-$s-simulation.tcl"
4513 source Running $repo_path/Top/$project_name/pre-$s-simulation.tcl
4515 current_fileset -simset $s
4516 set sim_dir $main_sim_folder/$s/behav
4517 set sim_output_logfile $sim_dir/xsim/simulate.log
4518 if { ([
string tolower $simulator] eq "xsim") } {
4519 set sim_name "xsim:$s"
4521 set simulation_command "launch_simulation $quiet_sim -simset [get_filesets $s]"
4522 if { [
catch $simulation_command log] } {
4525 Msg CriticalWarning "Simulation failed for $s, error info: $::errorInfo"
4526 lappend failed $sim_name
4531 if {$use_simpass_str == 1} {
4534 set file_desc [open $sim_output_logfile r]
4535 set log [read $file_desc]
4538 Msg Info "Searching for simulation pass string: '$simpass_str'"
4539 if {[
string first $simpass_str $log] == -1} {
4540 Msg CriticalWarning "Simulation failed for $s, error info: '$simpass_str' NOT found!"
4541 lappend failed $sim_name
4544 lappend success $sim_name
4548 lappend success $sim_name
4552 Msg Info "Simulation library path is set to $lib_path."
4554 if {!([
file exists $lib_path])} {
4555 Msg Warning "Could not find simulation library path: $lib_path, $simulator simulation will not work."
4559 if {$simlib_ok == 1} {
4560 set_property "compxlib.${simulator}_compiled_library_dir" [
file normalize $lib_path] [current_project]
4561 launch_simulation -scripts_only -simset [get_filesets $s]
4562 set top_name [get_property TOP $s]
4563 set sim_script [
file normalize $sim_dir/$simulator/]
4564 Msg Info "Adding simulation script location $sim_script for $s..."
4565 lappend sim_scripts $sim_script
4566 dict append sim_dic $sim_script $s
4568 Msg Error "Cannot run $simulator simulations without a valid library path"
4576 if {[
info exists sim_scripts]} {
4578 Msg Info "Generating IP simulation targets, if any..."
4580 foreach ip [get_ips] {
4581 generate_target simulation -quiet $ip
4586 Msg Info "====== Starting simulations runs ======"
4589 foreach s $sim_scripts {
4591 set cmd ./compile.sh
4592 Msg Info " ************* Compiling: $s ************* "
4594 set sim_name "comp:[dict get $sim_dic $s]"
4596 Msg CriticalWarning "Compilation failed for $s, error info: $::errorInfo"
4597 lappend failed $sim_name
4599 lappend success $sim_name
4601 Msg Info "###################### Compilation log starts ######################"
4602 Msg Info "\n\n$log\n\n"
4603 Msg Info "###################### Compilation log ends ######################"
4606 if { [
file exists "./elaborate.sh"] } {
4607 set cmd ./elaborate.sh
4608 Msg Info " ************* Elaborating: $s ************* "
4610 set sim_name "elab:[dict get $sim_dic $s]"
4612 Msg CriticalWarning "Elaboration failed for $s, error info: $::errorInfo"
4613 lappend failed $sim_name
4615 lappend success $sim_name
4617 Msg Info "###################### Elaboration log starts ######################"
4618 Msg Info "\n\n$log\n\n"
4619 Msg Info "###################### Elaboration log ends ######################"
4621 set cmd ./simulate.sh
4622 Msg Info " ************* Simulating: $s ************* "
4627 if {$use_simpass_str == 1} {
4628 if {[
string first $simpass_str $log] == -1} {
4632 Msg Debug "Simulation pass string not set, relying on simulator exit code."
4637 set sim_name "sim:[dict get $sim_dic $s]"
4639 Msg CriticalWarning "Simulation failed for $s, error info: $::errorInfo"
4640 lappend failed $sim_name
4642 lappend success $sim_name
4644 Msg Info "###################### Simulation log starts ######################"
4645 Msg Info "\n\n$log\n\n"
4646 Msg Info "###################### Simulation log ends ######################"
4652 if {[
llength $success] > 0} {
4653 set successes [
join $success "\n"]
4654 Msg Info "The following simulation sets were successful:\n\n$successes\n\n"
4657 if {[
llength $failed] > 0} {
4658 set failures [
join $failed "\n"]
4659 Msg Error "The following simulation sets have failed:\n\n$failures\n\n"
4661 }
elseif {[
llength $success] > 0} {
4662 Msg Info "All the [
llength $success] compilations, elaborations and simulations were successful."
4665 Msg Info "Simulation done."
4667 Msg Warning "Simulation is not yet supported for [
GetIDEName]."
4680 proc LaunchSynthesis {reset do_create run_folder project_name {repo_path .} {ext_path ""} {njobs 4}} {
4682 if {$reset == 1 && $do_create == 0} {
4683 Msg Info "Resetting run before launching synthesis..."
4687 source $repo_path/Hog/Tcl/integrated/pre-synthesis.tcl
4689 launch_runs synth_1 -jobs $njobs -dir $run_folder
4691 set prog [get_property PROGRESS [get_runs synth_1]]
4692 set status [get_property STATUS [get_runs synth_1]]
4693 Msg Info "Run: synth_1 progress: $prog, status : $status"
4700 lassign [
GetRepoVersions [
file normalize ./Top/$project_name] $repo_path $ext_path] sha
4702 Msg Info "Git describe set to $describe"
4705 set xci_file [get_property IP_FILE $ip]
4707 set xci_path [
file dirname $xci_file]
4708 set xci_ip_name [
file rootname [
file tail $xci_file]]
4709 foreach rptfile [glob -nocomplain -directory $xci_path *.rpt] {
4710 file copy $rptfile $repo_path/bin/$project_name-$describe/reports
4734 if {$prog ne "100%"} {
4735 Msg Error "Synthesis error, status is: $status"
4739 set project [
file tail [
file rootname $project_name]]
4741 Msg Info "Number of jobs set to $njobs."
4742 set_global_assignment -name NUM_PARALLEL_PROCESSORS $njobs
4746 lassign [
GetRepoVersions [
file normalize $repo_path/Top/$project_name] $repo_path] sha
4749 set revision [get_current_revision]
4752 set tool_and_command [
split [get_global_assignment -name PRE_FLOW_SCRIPT_FILE] ":"]
4753 set tool [
lindex $tool_and_command 0]
4754 set pre_flow_script [
lindex $tool_and_command 1]
4755 set cmd "$tool -t $pre_flow_script quartus_map $project $revision"
4761 Msg Warning "Can not execute command $cmd"
4762 Msg Warning "LOG: $log"
4764 Msg Info "Pre flow script executed!"
4768 if { ![is_project_open] } {
4769 Msg Info "Re-opening project file $project_name..."
4770 project_open $project -current_revision
4774 if {[
catch {execute_module -tool ipg -args "--clean"} result]} {
4775 Msg Error "Result: $result\n"
4776 Msg Error "IP Generation failed. See the report file.\n"
4778 Msg Info "IP Generation was successful for revision $revision.\n"
4782 if {[
catch {execute_module -tool map -args "--parallel"} result]} {
4783 Msg Error "Result: $result\n"
4784 Msg Error "Analysis & Synthesis failed. See the report file.\n"
4786 Msg Info "Analysis & Synthesis was successful for revision $revision.\n"
4790 defvar_set -name RWNETLIST_32_64_MIXED_FLOW -value 0
4792 Msg Info "Run SYNTHESIS..."
4793 if {[
catch {run_tool -name {SYNTHESIZE}}] } {
4794 Msg Error "SYNTHESIZE FAILED!"
4796 Msg Info "SYNTHESIZE PASSED!"
4802 set force_rst "-forceOne"
4804 prj_run Synthesis $force_rst
4805 if {[prj_syn] == "synplify"} {
4806 prj_run Translate $force_rst
4809 Msg Error "Impossible condition. You need to run this in an IDE."
4820 proc ListProjects {{repo_path .} {print 1} {ret_conf 0}} {
4821 set top_path [
file normalize $repo_path/Top]
4822 set confs [
findFiles [
file normalize $top_path] hog.conf]
4824 set confs [lsort $confs]
4828 set p [
Relative $top_path [
file dirname $c]]
4831 if { $description eq "test"} {
4832 set description " - Test project"
4833 }
elseif { $description ne ""} {
4834 set description " - $description"
4837 if {$print == 1 || $description ne " - Test project"} {
4839 set g [
file dirname $p]
4850 if {$ret_conf == 0} {
4865 proc Logo { {repo_path .} } {
4867 if {![
info exists ::env(HOG_LOGO_PRINTED)] || $::env(HOG_LOGO_PRINTED) eq "0"} {
4868 if {[
info exists ::env(HOG_COLOR)] && ([
string match "ENABLED" $::env(HOG_COLOR)] || [
string is integer -strict $::env(HOG_COLOR)] && $::env(HOG_COLOR) > 0 )} {
4869 set logo_file "$repo_path/Hog/images/hog_logo_color.txt"
4871 set logo_file "$repo_path/Hog/images/hog_logo.txt"
4875 set ver [
Git {describe --always}]
4879 if {[
file exists $logo_file]} {
4880 set f [open $logo_file "r"]
4883 set lines [
split $data "\n"]
4885 if {[regexp {(Version:)[ ]+} $l -> prefix]} {
4886 set string_len [
string length $l]
4888 set version_string "* Version: $ver"
4889 set version_len [
string length $version_string]
4890 append version_string [
string repeat " " [
expr {$string_len - $version_len - 1}]] "*"
4891 set l $version_string}
4895 Msg CriticalWarning "Logo file: $logo_file not found"
4909 proc Md5Sum {file_name} {
4910 if {!([
file exists $file_name])} {
4911 Msg Warning "Could not find $file_name."
4914 if {[
catch {
package require md5 2.0.7} result]} {
4915 Msg Warning "Tcl package md5 version 2.0.7 not found ($result), will use command line..."
4916 set hash [
lindex [
Execute md5sum $file_name] 0]
4918 set file_hash [
string tolower [md5::md5 -hex -file $file_name]]
4932 proc MergeDict {dict0 dict1 {remove_duplicates 1}} {
4933 set outdict [dict merge $dict1 $dict0]
4934 foreach key [dict keys $dict1] {
4935 if {[dict exists $dict0 $key]} {
4936 set temp_list [dict get $dict1 $key]
4937 foreach item $temp_list {
4939 if {[
IsInList $item [
DictGet $outdict $key]] == 0 || $remove_duplicates == 0} {
4941 dict lappend outdict $key $item
4953 proc MoveElementToEnd {inputList element} {
4954 set index [lsearch $inputList $element]
4956 set inputList [
lreplace $inputList $index $index]
4957 lappend inputList $element
4967 proc Msg {level msg {title ""}} {
4968 set level [
string tolower $level]
4969 if {$title == ""} {
set title [
lindex [
info level [
expr {[info level]-1}]] 0]}
4970 if {$level == 0 || $level == "status" || $level == "extra_info"} {
4973 }
elseif {$level == 1 || $level == "info"} {
4976 }
elseif {$level == 2 || $level == "warning"} {
4977 set vlevel {WARNING}
4979 }
elseif {$level == 3 || [
string first "critical" $level] !=-1} {
4980 set vlevel {CRITICAL WARNING}
4981 set qlevel critical_warning
4982 }
elseif {$level == 4 || $level == "error"} {
4985 }
elseif {$level == 5 || $level == "debug"} {
4986 if {([
info exists ::DEBUG_MODE] && $::DEBUG_MODE == 1) || ([
info exists ::env(HOG_DEBUG_MODE)] && $::env(HOG_DEBUG_MODE) == 1)} {
4988 set qlevel extra_info
4989 set msg "DEBUG: \[Hog:$title\] $msg"
4994 puts "Hog Error: level $level not defined"
5001 set status [
catch {send_msg_id Hog:$title-0 $vlevel $msg}]
5007 post_message -type $qlevel "Hog:$title $msg"
5008 if { $qlevel == "error"} {
5013 if {$vlevel != "STATUS"} {
5014 puts "$vlevel: \[Hog:$title\] $msg"
5019 if {$qlevel == "error"} {
5031 proc MsgAndLog {msg {severity "CriticalWarning"} {outFile ""}} {
5033 if {$outFile != ""} {
5034 set directory [
file dir $outFile]
5035 if {![
file exists $directory]} {
5036 Msg Info "Creating $directory..."
5037 file mkdir $directory
5040 set oF [open "$outFile" a+]
5050 proc OpenProject {project_file repo_path} {
5052 open_project $project_file
5054 set project_folder [
file dirname $project_file]
5055 set project [
file tail [
file rootname $project_file]]
5056 if {[
file exists $project_folder]} {
5058 if { ![is_project_open] } {
5059 Msg Info "Opening existing project file $project_file..."
5060 project_open $project -current_revision
5063 Msg Error "Project directory not found for $project_file."
5067 Msg Info "Opening existing project file $project_file..."
5069 open_project -file $project_file -do_backup_on_convert 1 -backup_file {./Projects/$project_file.zip}
5071 Msg Info "Opening existing project file $project_file..."
5072 prj_project open $project_file
5074 Msg Error "This IDE is currently not supported by Hog. Exiting!"
5081 return $tcl_platform(platform)
5091 proc ParseJSON {JSON_FILE JSON_KEY} {
5092 set result [
catch {
package require Tcl 8.4} TclFound]
5093 if {"$result" != "0"} {
5094 Msg CriticalWarning "Cannot find Tcl package version equal or higher than 8.4.\n $TclFound\n Exiting"
5098 set result [
catch {
package require json} JsonFound]
5099 if {"$result" != "0"} {
5100 Msg CriticalWarning "Cannot find JSON package equal or higher than 1.0.\n $JsonFound\n Exiting"
5103 set JsonDict [json::json2dict $JSON_FILE]
5104 set result [
catch {dict get $JsonDict $JSON_KEY} RETURNVALUE]
5105 if {"$result" != "0"} {
5106 Msg CriticalWarning "Cannot find $JSON_KEY in $JSON_FILE\n Exiting"
5118 proc PrintFileTree { {data} {repo_path} {indentation ""} } {
5121 foreach line $data {
5122 if {![regexp {^[\t\s]*$} $line] & ![regexp {^[\t\s]*\#} $line] } {
5123 lappend print_list "$line"
5128 foreach p $print_list {
5130 if {$i == [
llength $print_list]} {
5135 set file_name [
lindex [
split $p] 0]
5136 if {[
file exists [
file normalize [
lindex [glob -nocomplain $repo_path/$file_name] 0]]] } {
5139 set exists " !!!!! NOT FOUND !!!!!"
5142 Msg Status "$indentation$pad$p$exists"
5143 set last_printed $file_name
5146 return $last_printed
5154 proc ProjectExists {project {repo_path .}} {
5155 set index [lsearch -exact [
ListProjects $repo_path 0] $project]
5171 proc ReadConf {file_name} {
5173 if { [
catch {
package require inifile 0.2.3} ERROR] } {
5174 Msg Error "Could not find inifile package version 0.2.3 or higher.\n
5175 To use ghdl, libero or diamond with Hog, you need to install the tcllib package\n
5176 You can install it with 'sudo apt install tcllib' on Debian/Ubuntu or 'sudo dnf install tcllib' on Fedora/RedHat/CentOs."
5180 ::ini::commentchar "#"
5181 set f [::ini::open $file_name]
5182 set properties [dict create]
5183 foreach sec [::ini::sections $f] {
5185 if {$new_sec == "files"} {
5188 set key_pairs [::ini::get $f $sec]
5190 regsub -all {\{\"} $key_pairs "\{" key_pairs
5191 regsub -all {\"\}} $key_pairs "\}" key_pairs
5193 dict set properties $new_sec [dict create {*}$key_pairs]
5206 proc ReadExtraFileList { extra_file_name } {
5207 set extra_file_dict [dict create]
5208 if {[
file exists $extra_file_name]} {
5209 set file [open $extra_file_name "r"]
5210 set file_data [read $file]
5213 set data [
split $file_data "\n"]
5214 foreach line $data {
5215 if {![regexp {^ *$} $line] & ![regexp {^ *\#} $line] } {
5216 set ip_and_md5 [regexp -all -inline {\S+} $line]
5217 dict lappend extra_file_dict "[
lindex $ip_and_md5 0]" "[
lindex $ip_and_md5 1]"
5221 return $extra_file_dict
5238 proc ReadListFile {args} {
5242 if { [
catch {
package require cmdline} ERROR] } {
5243 puts "$ERROR\n If you are running this script on tclsh, you can fix this by installing 'tcllib'"
5249 {lib.arg "" "The name of the library files will be added to, if not given will be extracted from the file name."}
5250 {fileset.arg "" "The name of the library, from the main list file"}
5251 {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."}
5252 {print_log "If set, will use PrintFileTree for the VIEW directive"}
5253 {indent.arg "" "Used to indent files with the VIEW directive"}
5255 set usage "USAGE: ReadListFile \[options\] <list file> <path>"
5256 if {[
catch {
array set options [
cmdline::getoptions args $parameters $usage]}] || [
llength $args] != 2 } {
5260 set list_file [
lindex $args 0]
5261 set path [
lindex $args 1]
5262 set sha_mode $options(sha_mode)
5263 set lib $options(lib)
5264 set fileset $options(fileset)
5265 set print_log $options(print_log)
5266 set indent $options(indent)
5268 if { $sha_mode == 1} {
5269 set sha_mode_opt "-sha_mode"
5274 if { $print_log == 1 } {
5275 set print_log_opt "-print_log"
5277 set print_log_opt ""
5282 set lib [
file rootname [
file tail $list_file]]
5284 set fp [open $list_file r]
5285 set file_data [read $fp]
5287 set list_file_ext [
file extension $list_file]
5288 switch $list_file_ext {
5290 if {$fileset eq ""} {
5296 set fileset "constrs_1"
5299 set fileset "sources_1"
5303 set libraries [dict create]
5304 set filesets [dict create]
5305 set properties [dict create]
5307 set data [
split $file_data "\n"]
5309 set n [
llength $data]
5311 if {$print_log == 1} {
5312 if {$indent eq ""} {
5313 set list_file_rel [
file tail $list_file]
5314 Msg Status "\n$list_file_rel"
5318 Msg Debug "$n lines read from $list_file."
5321 foreach line $data {
5323 if {![regexp {^[\t\s]*$} $line] & ![regexp {^[\t\s]*\#} $line] } {
5324 set file_and_prop [regexp -all -inline {\S+} $line]
5325 set srcfile [
lindex $file_and_prop 0]
5326 set srcfile "$path/$srcfile"
5328 set srcfiles [glob -nocomplain $srcfile]
5331 if {$srcfiles != $srcfile && ! [
string equal $srcfiles ""]} {
5332 Msg Debug "Wildcard source expanded from $srcfile to $srcfiles"
5334 if {![
file exists $srcfile]} {
5335 if {$print_log == 0} {
5336 Msg CriticalWarning "File: $srcfile (from list file: $list_file) does not exist."
5342 foreach vhdlfile $srcfiles {
5343 if {[
file exists $vhdlfile]} {
5344 set vhdlfile [
file normalize $vhdlfile]
5345 set extension [
file extension $vhdlfile]
5347 set prop [
lrange $file_and_prop 1 end]
5350 set library [
lindex [regexp -inline {\ylib\s*=\s*(.+?)\y.*} $prop] 1]
5351 if { $library == "" } {
5355 if { $extension == $list_file_ext } {
5358 set ref_path [
lindex [regexp -inline {\ypath\s*=\s*(\S+).*} $prop] 1]
5359 if { $ref_path eq "" } {
5362 set ref_path [
file normalize $path/$ref_path]
5364 Msg Debug "List file $vhdlfile found in list file, recursively opening it using path \"$ref_path\"..."
5365 if {$print_log == 1} {
5366 if {[
file normalize $last_printed] ne [
file normalize $vhdlfile]} {
5367 Msg Status "$indent Inside [
file tail $vhdlfile]:"
5371 lassign [
ReadListFile {*}"-indent \" $indent\" -lib $library -fileset $fileset $sha_mode_opt $print_log_opt $vhdlfile $ref_path"] l p fs
5373 set properties [
MergeDict $p $properties]
5375 }
elseif {[lsearch {.src .sim .con ReadExtraFileList} $extension] >= 0 } {
5377 Msg Error "$vhdlfile cannot be included into $list_file, $extension files must be included into $extension files."
5380 regsub -all " *= *" $prop "=" prop
5384 if { [
string first "lib=" $p] == -1} {
5386 set pos [
string first "=" $p]
5390 set prop_name [
string range $p 0 [
expr {$pos - 1}]]
5393 dict lappend properties $vhdlfile $p
5394 Msg Debug "Adding property $p to $vhdlfile..."
5395 }
elseif { $list_file_ext != ".ipb" } {
5396 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]\]"
5400 if { [lsearch {.xci .ip .bd .xcix} $extension] >= 0} {
5402 set lib_name "ips.src"
5403 }
elseif { [
IsInList $extension {.vhd .vhdl}] || $list_file_ext == ".sim"} {
5405 if { ![
IsInList $extension {.vhd .vhdl}]} {
5406 set lib_name "others.sim"
5408 set lib_name "$library$list_file_ext"
5410 }
elseif { $list_file_ext == ".con" } {
5411 set lib_name "sources.con"
5412 }
elseif { $list_file_ext == ".ipb" } {
5413 set lib_name "xml.ipb"
5416 set lib_name "others.src"
5419 Msg Debug "Appending $vhdlfile to $lib_name list..."
5420 dict lappend libraries $lib_name $vhdlfile
5421 if { $sha_mode != 0 && [
file type $vhdlfile] eq "link"} {
5424 dict lappend libraries $lib_name $real_file
5425 Msg Debug "File $vhdlfile is a soft link, also adding the real file: $real_file"
5430 if {[dict exists $filesets $fileset] == 0} {
5432 Msg Debug "Adding $fileset to the fileset dictionary..."
5433 Msg Debug "Adding library $lib_name to fileset $fileset..."
5434 dict set filesets $fileset $lib_name
5438 Msg Debug "Adding library $lib_name to fileset $fileset..."
5439 dict lappend filesets $fileset $lib_name
5445 Msg CriticalWarning "File $vhdlfile not found."
5451 if {$sha_mode != 0} {
5453 if {$list_file_ext eq ".ipb"} {
5454 set sha_lib "xml.ipb"
5456 set sha_lib $lib$list_file_ext
5458 dict lappend libraries $sha_lib [
file normalize $list_file]
5459 if {[
file type $list_file] eq "link"} {
5462 dict lappend libraries $lib$list_file_ext $real_file
5463 Msg Debug "List file $list_file is a soft link, also adding the real file: $real_file"
5466 return [list $libraries $properties $filesets]
5474 proc Relative {base dst} {
5475 if {![
string equal [
file pathtype $base] [
file pathtype $dst]]} {
5476 Msg CriticalWarning "Unable to compute relation for paths of different path types: [
file pathtype $base] vs. [
file pathtype $dst], ($base vs. $dst)"
5480 set base [
file normalize [
file join [
pwd] $base]]
5481 set dst [
file normalize [
file join [
pwd] $dst]]
5484 set base [
file split $base]
5485 set dst [
file split $dst]
5487 while {[
string equal [
lindex $dst 0] [
lindex $base 0]]} {
5488 set dst [
lrange $dst 1 end]
5489 set base [
lrange $base 1 end]
5490 if {![
llength $dst]} {break}
5493 set dstlen [
llength $dst]
5494 set baselen [
llength $base]
5496 if {($dstlen == 0) && ($baselen == 0)} {
5499 while {$baselen > 0} {
5500 set dst [
linsert $dst 0 ..]
5503 set dst [
eval [
linsert $dst 0 file join]]
5514 proc RelativeLocal {pathName filePath} {
5515 if {[
string first [
file normalize $pathName] [
file normalize $filePath]] != -1} {
5516 return [
Relative $pathName $filePath]
5527 proc RemoveDuplicates {mydict} {
5528 set new_dict [dict create]
5529 foreach key [dict keys $mydict] {
5530 set values [
DictGet $mydict $key]
5531 foreach value $values {
5532 set idxs [
lreverse [
lreplace [lsearch -exact -all $values $value] 0 0]]
5534 set values [
lreplace $values $idx $idx]
5537 dict set new_dict $key $values
5548 proc ResetRepoFiles {reset_file} {
5549 if {[
file exists $reset_file]} {
5550 Msg Info "Found $reset_file, opening it..."
5551 set fp [open $reset_file r]
5552 set wild_cards [lsearch -all -inline -not -regexp [
split [read $fp] "\n"] "^ *$"]
5554 Msg Info "Found the following files/wild cards to restore if modified: $wild_cards..."
5555 foreach w $wild_cards {
5557 if {[
llength $mod_files] > 0} {
5558 Msg Info "Found modified $w files: $mod_files, will restore them..."
5561 Msg Info "No modified $w files found."
5572 proc RestoreModifiedFiles {{repo_path "."} {pattern "."}} {
5575 set ret [
Git checkout $pattern]
5586 proc SearchHogProjects {dir} {
5587 set projects_list {}
5588 if {[
file exists $dir]} {
5589 if {[
file isdirectory $dir]} {
5590 foreach proj_dir [glob -nocomplain -types d $dir/*] {
5591 if {![regexp {^.*Top/+(.*)$} $proj_dir dummy proj_name]} {
5592 Msg Warning "Could not parse Top directory $dir"
5595 if { [
file exists "$proj_dir/hog.conf"] } {
5596 lappend projects_list $proj_name
5599 lappend projects_list $p
5605 Msg Error "Input $dir is not a directory!"
5608 Msg Error "Directory $dir doesn't exist!"
5610 return $projects_list
5619 proc SetGenericsSimulation {repo_path proj_dir target} {
5620 set top_dir "$repo_path/Top/$proj_dir"
5621 set simsets [get_filesets]
5622 if { $simsets != "" } {
5623 foreach simset $simsets {
5625 if {[get_property FILESET_TYPE $simset] != "SimulationSrcs" } {
5629 set merged_generics_dict [dict create]
5633 set simset_generics [
DictGet $simset_dict "generics"]
5634 set merged_generics_dict [
MergeDict $merged_generics_dict $simset_generics 0]
5636 set_property generic $generic_str [get_filesets $simset]
5637 Msg Debug "Setting generics $generic_str for simulator $target\
5638 and simulation file-set $simset..."
5650 proc SetTopProperty {top_module fileset} {
5651 Msg Info "Setting TOP property to $top_module module"
5654 set_property "top" $top_module [get_filesets $fileset]
5657 set_global_assignment -name TOP_LEVEL_ENTITY $top_module
5659 set_root -module $top_module
5661 prj_impl option top $top_module
5666 proc VIVADO_PATH_PROPERTIES {} {
5667 return {"\.*\.TCL\.PRE$" "^.*\.TCL\.POST$" "^RQS_FILES$" "^INCREMENTAL\_CHECKPOINT$" "NOC\_SOLUTION\_FILE"}
5677 proc WriteConf {file_name config {comment ""}} {
5678 if { [
catch {
package require inifile 0.2.3} ERROR] } {
5679 puts "$ERROR\n If you are running this script on tclsh, you can fix this by installing 'tcllib'"
5683 ::ini::commentchar "#"
5684 set f [::ini::open $file_name w]
5686 foreach sec [dict keys $config] {
5687 set section [dict get $config $sec]
5688 dict for {p v} $section {
5689 if {[string trim $v] == ""} {
5690 Msg Warning "Property $p has empty value. Skipping..."
5693 ::ini::set $f $sec $p $v
5698 if {![
string equal "$comment" ""]} {
5699 ::ini::comment $f [
lindex [::ini::sections $f] 0] "" $comment
5700 set hog_header "Generated by Hog on [
clock format [
clock seconds] -format "%Y-%m-%d %H:%M:%S"]"
5701 ::ini::comment $f [
lindex [::ini::sections $f] 0] "" $hog_header
5717 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 ""}} {
5718 Msg Info "Passing parameters/generics to project's top module..."
5721 set generic_string [
concat \
5733 if {$xml_hash != "" && $xml_ver != ""} {
5734 lappend generic_string \
5739 foreach l $libs v $vers h $hashes {
5742 lappend generic_string "$ver" "$hash"
5745 foreach e $ext_names h $ext_hashes {
5747 lappend generic_string "$hash"
5750 foreach repo $user_ip_repos v $user_ip_vers h $user_ip_hashes {
5751 set repo_name [
file tail $repo]
5752 set ver "[
string toupper $repo_name]_VER=[
FormatGeneric $v]"
5753 set hash "[
string toupper $repo_name]_SHA=[
FormatGeneric $h]"
5754 lappend generic_string "$ver" "$hash"
5757 if {$flavour != -1} {
5758 lappend generic_string "FLAVOUR=$flavour"
5764 set generic_string "$prj_generics $generic_string"
5770 if {$mode == "create" || [
IsISE]} {
5774 if {[
file exists $top_file]} {
5777 Msg Debug "Found top level generics $generics in $top_file"
5779 set filtered_generic_string ""
5781 foreach generic_to_set [
split [
string trim $generic_string]] {
5782 set key [
lindex [
split $generic_to_set "="] 0]
5783 if {[dict exists $generics $key]} {
5784 Msg Debug "Hog generic $key found in $top_name"
5785 lappend filtered_generic_string "$generic_to_set"
5787 Msg Warning "Generic $key is passed by Hog but is NOT present in $top_name."
5793 set generic_string $filtered_generic_string
5798 set_property generic $generic_string [current_fileset]
5799 Msg Info "Setting parameters/generics..."
5800 Msg Debug "Detailed parameters/generics: $generic_string"
5805 set simulator [get_property target_simulator [current_project]]
5806 if {$mode == "create"} {
5813 Msg Info "Setting Synplify parameters/generics one by one..."
5814 foreach generic $generic_string {
5815 Msg Debug "Setting Synplify generic: $generic"
5816 set_option -hdl_param -set "$generic"
5819 Msg Info "Setting Diamond parameters/generics one by one..."
5820 prj_impl option -impl Implementation0 HDL_PARAM "$generic_string"
5830 proc WriteGenericsToBdIPs {mode repo_path proj generic_string} {
5831 Msg Debug "Parameters/generics passed to WriteGenericsToIP: $generic_string"
5833 set bd_ip_generics false
5835 if {[dict exists $properties "hog"]} {
5836 set propDict [dict get $properties "hog"]
5837 if {[dict exists $propDict "PASS_GENERICS_TO_BD_IPS"]} {
5838 set bd_ip_generics [dict get $propDict "PASS_GENERICS_TO_BD_IPS"]
5842 if {[
string compare [
string tolower $bd_ip_generics] "false"]==0} {
5846 if {$mode == "synth"} {
5847 Msg Info "Attempting to apply generics pre-synthesis..."
5848 set PARENT_PRJ [get_property "PARENT.PROJECT_PATH" [current_project]]
5849 set workaround [open "$repo_path/Projects/$proj/.hog/presynth_workaround.tcl" "w"]
5850 puts $workaround "source \[lindex \$argv 0\];"
5851 puts $workaround "open_project \[lindex \$argv 1\];"
5852 puts $workaround "WriteGenericsToBdIPs \[lindex \$argv 2\] \[lindex \$argv 3\] \[lindex \$argv 4\] \[lindex \$argv 5\];"
5853 puts $workaround "close_project"
5856 exec vivado -mode batch -source $repo_path/Projects/$proj/.hog/presynth_workaround.tcl \
5857 -tclargs $repo_path/Hog/Tcl/hog.tcl $PARENT_PRJ \
5858 "childprocess" $repo_path $proj $generic_string
5860 Msg Error "Encountered an error while attempting workaround: $errMsg"
5862 file delete $repo_path/Projects/$proj/.hog/presynth_workaround.tcl
5864 Msg Info "Done applying generics pre-synthesis."
5868 Msg Info "Looking for IPs to add generics to..."
5869 set ips_generic_string ""
5870 foreach generic_to_set [
split [
string trim $generic_string]] {
5871 set key [
lindex [
split $generic_to_set "="] 0]
5872 set value [
lindex [
split $generic_to_set "="] 1]
5873 append ips_generic_string "CONFIG.$key $value "
5877 if {[
string compare [
string tolower $bd_ip_generics] "true"]==0} {
5880 set ip_regex $bd_ip_generics
5883 set ip_list [get_ips -regex $ip_regex]
5884 Msg Debug "IPs found with regex \{$ip_regex\}: $ip_list"
5886 set regen_targets {}
5888 foreach {ip} $ip_list {
5889 set WARN_ABOUT_IP false
5890 set ip_props [list_property [get_ips $ip]]
5893 if {[lsearch -exact $ip_props "IS_BD_CONTEXT"] == -1} {
5897 if {[get_property "IS_BD_CONTEXT" [get_ips $ip]] eq "1"} {
5898 foreach {ip_prop} $ip_props {
5899 if {[dict exists $ips_generic_string $ip_prop]} {
5900 if {$WARN_ABOUT_IP == false} {
5901 lappend regen_targets [get_property SCOPE [get_ips $ip]]
5902 Msg Warning "The ip \{$ip\} contains generics that are set by Hog.\
5903 If this is IP is apart of a block design, the .bd file may contain stale, unused, values.\
5904 Hog will always apply the most up-to-date values to the IP during synthesis,\
5905 however these values may or may not be reflected in the .bd file."
5906 set WARN_ABOUT_IP true
5911 set xci_path [get_property IP_FILE [get_ips $ip]]
5913 if {[
string equal $generic_format "ERROR"]} {
5914 Msg Warning "Could not find format for generic $ip_prop in IP $ip. Skipping..."
5918 set value_to_set [dict get $ips_generic_string $ip_prop]
5919 switch -exact $generic_format {
5921 if {[
string match "32'h*" $value_to_set]} {
5922 scan [
string map {"32'h" ""} $value_to_set] "%x" value_to_set
5926 set value_to_set [
expr {$value_to_set ? "true" : "false"}]
5929 if {[
string match "32'h*" $value_to_set]} {
5930 binary scan [
binary format H* [
string map {"32'h" ""} $value_to_set]] d value_to_set
5934 if {[
string match "32'h*" $value_to_set]} {
5935 set value_to_set [
string map {"32'h" "0x"} $value_to_set]
5939 set value_to_set [
format "%s" $value_to_set]
5942 Msg Warning "Unknown generic format $generic_format for IP $ip. Will attempt to pass as string..."
5947 Msg Info "The IP \{$ip\} contains: $ip_prop ($generic_format), setting it to $value_to_set."
5948 if {[
catch {set_property -name $ip_prop -value $value_to_set -objects [ get_ips $ip]} prop_error]} {
5949 Msg CriticalWarning "Failed to set property $ip_prop to $value_to_set for IP \{$ip\}: $prop_error"
5956 foreach {regen_target} [lsort -unique $regen_targets] {
5957 Msg Info "Regenerating target: $regen_target"
5958 if {[
catch {generate_target -force all [get_files $regen_target]} prop_error]} {
5959 Msg CriticalWarning "Failed to regen targets: $prop_error"
5968 proc GetGenericFormatFromXciXML {generic_name xml_file} {
5970 if {![
file exists $xml_file]} {
5971 Msg Error "Could not find XML file: $xml_file"
5975 set fp [open $xml_file r]
5976 set xci_data [read $fp]
5979 set paramType "string"
5980 set modelparam_regex [
format {^.*\y%s\y.*$} [
string map {"CONFIG." "MODELPARAM_VALUE."} $generic_name]]
5981 set format_regex {format="([^"]+)"}
5983 set line [
lindex [regexp -inline -line $modelparam_regex $xci_data] 0]
5984 Msg Debug "line: $line"
5986 if {[regexp $format_regex $line match format_value]} {
5987 Msg Debug "Extracted: $format_value format from xml"
5988 set paramType $format_value
5990 Msg Debug "No format found, using string"
5999 proc GetGenericFormatFromXci {generic_name xci_file} {
6001 if {! [
file exists $xci_file]} {
6002 Msg Error "Could not find XCI file: $xci_file"
6006 set fp [open $xci_file r]
6007 set xci_data [read $fp]
6010 set paramType "string"
6011 if {[
string first "xilinx.com:schema:json_instance:1.0" $xci_data] == -1} {
6012 Msg Debug "XCI format is not JSON, trying XML..."
6013 set xml_file "[
file rootname $xci_file].xml"
6018 set generic_name [
string map {"CONFIG." ""} $generic_name]
6019 set ip_inst [
ParseJSON $xci_data "ip_inst"]
6020 set parameters [dict get $ip_inst parameters]
6021 set component_parameters [dict get $parameters component_parameters]
6022 if {[dict exists $component_parameters $generic_name]} {
6023 set generic_info [dict get $component_parameters $generic_name]
6024 if {[dict exists [
lindex $generic_info 0] format]} {
6025 set paramType [dict get [
lindex $generic_info 0] format]
6026 Msg Debug "Extracted: $paramType format from xci"
6029 Msg Debug "No format found, using string"
6042 proc WriteGitLabCIYAML {proj_name {ci_conf ""}} {
6043 if { [
catch {
package require yaml 0.3.3} YAMLPACKAGE]} {
6044 Msg CriticalWarning "Cannot find package YAML.\n Error message: $YAMLPACKAGE. If you are running on tclsh, you can fix this by installing package \"tcllib\""
6049 if {$ci_conf != ""} {
6051 foreach sec [dict keys $ci_confs] {
6052 if {[
string first : $sec] == -1} {
6053 lappend job_list $sec
6057 set job_list {"generate_project" "simulate_project"}
6061 set out_yaml [huddle create]
6062 foreach job $job_list {
6064 set huddle_tags [huddle list]
6066 set sec_dict [dict create]
6068 if {$ci_confs != ""} {
6069 foreach var [dict keys [dict get $ci_confs $job]] {
6070 if {$var == "tags"} {
6071 set tag_section "tags"
6072 set tags [dict get [dict get $ci_confs $job] $var]
6073 set tags [
split $tags ","]
6075 set tag_list [huddle list $tag]
6076 set huddle_tags [huddle combine $huddle_tags $tag_list]
6079 dict set sec_dict $var [dict get [dict get $ci_confs $job] $var]
6085 set huddle_variables [huddle create "PROJECT_NAME" $proj_name "extends" ".vars"]
6086 if {[dict exists $ci_confs "$job:variables"]} {
6087 set var_dict [dict get $ci_confs $job:variables]
6088 foreach var [dict keys $var_dict] {
6090 set value [dict get $var_dict "$var"]
6091 set var_inner [huddle create "$var" "$value"]
6092 set huddle_variables [huddle combine $huddle_variables $var_inner]
6097 set middle [huddle create "extends" ".$job" "variables" $huddle_variables]
6098 foreach sec [dict keys $sec_dict] {
6099 set value [dict get $sec_dict $sec]
6100 set var_inner [huddle create "$sec" "$value"]
6101 set middle [huddle combine $middle $var_inner]
6103 if {$tag_section != ""} {
6104 set middle2 [huddle create "$tag_section" $huddle_tags]
6105 set middle [huddle combine $middle $middle2]
6108 set outer [huddle create "$job:$proj_name" $middle]
6109 set out_yaml [huddle combine $out_yaml $outer]
6112 return [
string trimleft [ yaml::huddle2yaml $out_yaml] "-"]
6122 proc WriteListFiles {libs props list_path repo_path {ext_path ""} } {
6124 foreach lib [dict keys $libs] {
6125 if {[
llength [
DictGet $libs $lib]] > 0} {
6126 set list_file_name $list_path$lib
6127 set list_file [open $list_file_name w]
6128 Msg Info "Writing $list_file_name..."
6129 puts $list_file "#Generated by Hog on [
clock format [
clock seconds] -format "%Y-%m-%d %H:%M:%S"]"
6130 foreach file [
DictGet $libs $lib] {
6132 set prop [
DictGet $props $file]
6136 puts $list_file "$file_path $prop"
6139 set ext_list_file [open "[
file rootname $list_file].ext" a]
6140 puts $ext_list_file "$file_path $prop"
6141 close $ext_list_file
6144 Msg Warning "The path of file $file is not relative to your repository. Please check!"
6160 proc WriteSimListFile {simset libs props simsets list_path repo_path {force 0}} {
6163 set list_file_name $list_path/${simset}.sim
6164 if {$force == 0 && [
file exists $list_file_name]} {
6165 Msg Info "List file $list_file_name already exists, skipping..."
6169 set list_file [open $list_file_name a+]
6172 puts $list_file "\[files\]"
6173 Msg Info "Writing $list_file_name..."
6174 foreach lib [
DictGet $simsets $simset] {
6175 foreach file [
DictGet $libs $lib] {
6177 set prop [
DictGet $props $file]
6181 set lib_name [
file rootname $lib]
6182 if {$lib_name != $simset && [
file extension $file] == ".vhd" && [
file extension $file] == ""} {
6183 lappend prop "lib=$lib_name"
6185 puts $list_file "$file_path $prop"
6188 Msg Warning "The path of file $file is not relative to your repository. Please check!"
6201 proc WriteToFile {File msg} {
6202 set f [open $File a+]
6213 proc WriteUtilizationSummary {input output project_name run} {
6214 set f [open $input "r"]
6215 set o [open $output "a"]
6216 puts $o "## $project_name $run Utilization report\n\n"
6217 struct::matrix util_m
6218 util_m add columns 14
6221 util_m add row "| **Site Type** | **Used** | **Fixed** | **Prohibited** | **Available** | **Util%** |"
6222 util_m add row "| --- | --- | --- | --- | --- | --- |"
6224 util_m add row "| **Site Type** | **Used** | **Fixed** | **Available** | **Util%** |"
6225 util_m add row "| --- | --- | --- | --- | --- |"
6235 while {[
gets $f line] >= 0} {
6236 if { ( [
string first "| CLB LUTs" $line] >= 0 || [
string first "| Slice LUTs" $line] >= 0 ) && $luts == 0 } {
6237 util_m add row $line
6240 if { ( [
string first "| CLB Registers" $line] >= 0 || [
string first "| Slice Registers" $line] >= 0 ) && $regs == 0} {
6241 util_m add row $line
6244 if { [
string first "| Block RAM Tile" $line] >= 0 && $bram == 0 } {
6245 util_m add row $line
6248 if { [
string first "URAM " $line] >= 0 && $uram == 0} {
6249 util_m add row $line
6252 if { [
string first "DSPs" $line] >= 0 && $dsps == 0 } {
6253 util_m add row $line
6256 if { [
string first "Bonded IOB" $line] >= 0 && $ios == 0 } {
6257 util_m add row $line
6264 puts $o [util_m format 2string]
6271 Msg Error "Found Git version older than 2.7.2. Hog will not work as expected, exiting now."