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
253 Msg Info "[
llength $lib_files] file/s added to library $rootlib..."
256 if {$ext == ".sim"} {
257 Msg Warning "Simulation files not supported in Quartus Prime mode... Skipping $lib"
259 if {![is_project_open]} {
260 Msg Error "Project is closed"
262 foreach cur_file $lib_files {
266 set props [
DictGet $properties $cur_file]
269 set top [
lindex [regexp -inline {\ytop\s*=\s*(.+?)\y.*} $props] 1]
271 Msg Info "Setting $top as top module for file set $fileset..."
272 set globalSettings::synth_top_module $top
275 if {[
string first "VHDL" $file_type] != -1} {
276 if {[
string first "1987" $props] != -1} {
277 set hdl_version "VHDL_1987"
278 }
elseif {[
string first "1993" $props] != -1} {
279 set hdl_version "VHDL_1993"
280 }
elseif {[
string first "2008" $props] != -1} {
281 set hdl_version "VHDL_2008"
283 set hdl_version "default"
285 if {$hdl_version == "default"} {
286 set_global_assignment -name $file_type $cur_file -library $rootlib
288 set_global_assignment -name $file_type $cur_file -hdl_version $hdl_version -library $rootlib
290 }
elseif {[
string first "SYSTEMVERILOG" $file_type] != -1} {
292 if {[
string first "2005" $props] != -1} {
293 set hdl_version "systemverilog_2005"
294 }
elseif {[
string first "2009" $props] != -1} {
295 set hdl_version "systemverilog_2009"
297 set hdl_version "default"
299 if {$hdl_version == "default"} {
300 set_global_assignment -name $file_type $cur_file
302 set_global_assignment -name $file_type $cur_file -hdl_version $hdl_version
304 }
elseif {[
string first "VERILOG" $file_type] != -1} {
306 if {[
string first "1995" $props] != -1} {
307 set hdl_version "verilog_1995"
308 }
elseif {[
string first "2001" $props] != -1} {
309 set hdl_version "verilog_2001"
311 set hdl_version "default"
313 if {$hdl_version == "default"} {
314 set_global_assignment -name $file_type $cur_file
316 set_global_assignment -name $file_type $cur_file -hdl_version $hdl_version
318 }
elseif {[
string first "SOURCE" $file_type] != -1 || [
string first "COMMAND_MACRO" $file_type] != -1} {
319 set_global_assignment -name $file_type $cur_file
320 if {$ext == ".con"} {
322 }
elseif {$ext == ".src"} {
324 if {[
string first "qsys" $props] != -1} {
327 regsub -all {\{||qsys||\}} $props $emptyString props
329 set qsysPath [
file dirname $cur_file]
330 set qsysName "[
file rootname [
file tail $cur_file]].qsys"
331 set qsysFile "$qsysPath/$qsysName"
332 set qsysLogFile "$qsysPath/[
file rootname [
file tail $cur_file]].qsys-script.log"
335 if {![
info exists ::env(QSYS_ROOTDIR)]} {
336 if {[
info exists ::env(QUARTUS_ROOTDIR)]} {
337 set qsys_rootdir "$::env(QUARTUS_ROOTDIR)/sopc_builder/bin"
338 Msg Warning "The QSYS_ROOTDIR environment variable is not set! I will use $qsys_rootdir"
340 Msg CriticalWarning "The QUARTUS_ROOTDIR environment variable is not set! Assuming all quartus executables are contained in your PATH!"
343 set qsys_rootdir $::env(QSYS_ROOTDIR)
346 set cmd "$qsys_rootdir/qsys-script"
347 set cmd_options " --script=$cur_file"
348 if {![
catch {"exec $cmd -version"}] || [
lindex $::errorCode 0] eq "NONE"} {
349 Msg Info "Executing: $cmd $cmd_options"
350 Msg Info "Saving logfile in: $qsysLogFile"
351 if {[
catch {
eval exec -ignorestderr "$cmd $cmd_options >>& $qsysLogFile"} ret opt]} {
352 set makeRet [
lindex [dict get $opt -errorcode] end]
353 Msg CriticalWarning "$cmd returned with $makeRet"
356 Msg Error " Could not execute command $cmd"
360 if {[
file exists $qsysName] != 0} {
361 file rename -force $qsysName $qsysFile
363 set qsysMd5Sum [
Md5Sum $qsysFile]
365 set fileDir [
file normalize "./hogTmp"]
366 set fileName "$fileDir/.hogQsys.md5"
367 if {![
file exists $fileDir]} {
370 set hogQsysFile [open $fileName "a"]
371 set fileEntry "$qsysFile\t$qsysMd5Sum"
372 puts $hogQsysFile $fileEntry
375 Msg ERROR "Error while moving the generated qsys file to final location: $qsysName not found!"
377 if {[
file exists $qsysFile] != 0} {
378 if {[
string first "noadd" $props] == -1} {
380 set_global_assignment -name $qsysFileType $qsysFile
382 regsub -all {noadd} $props $emptyString props
384 if {[
string first "nogenerate" $props] == -1} {
388 Msg ERROR "Error while generating ip variations from qsys: $qsysFile not found!"
392 }
elseif {[
string first "QSYS" $file_type] != -1} {
394 regsub -all {\{||\}} $props $emptyString props
395 if {[
string first "noadd" $props] == -1} {
396 set_global_assignment -name $file_type $cur_file
398 regsub -all {noadd} $props $emptyString props
402 if {[
string first "nogenerate" $props] == -1} {
406 set_global_assignment -name $file_type $cur_file -library $rootlib
411 if {$ext == ".con"} {
412 set vld_exts {.sdc .pin .dcf .gcf .pdc .ndc .fdc .crt .vcd }
413 foreach con_file $lib_files {
415 set con_ext [
file extension $con_file]
416 if {[
IsInList [
file extension $con_file] $vld_exts]} {
417 set option [
string map {. -} $con_ext]
418 set option [
string map {fdc net_fdc} $option]
419 set option [
string map {pdc io_pdc} $option]
420 create_links -convert_EDN_to_HDL 0 -library {work} $option $con_file
422 set props [
DictGet $properties $con_file]
424 if {$con_ext == ".sdc"} {
425 if {[lsearch $props "notiming"] >= 0} {
426 Msg Info "Excluding $con_file from timing verification..."
428 Msg Info "Adding $con_file to time verification"
429 append timing_conf_command " -file $con_file"
433 if {[lsearch $props "nosynth"] >= 0} {
434 Msg Info "Excluding $con_file from synthesis..."
436 Msg Info "Adding $con_file to synthesis"
437 append synth_conf_command " -file $con_file"
442 if {$con_ext == ".pdc" || $con_ext == ".sdc"} {
443 if {[lsearch $props "noplace"] >= 0} {
444 Msg Info "Excluding $con_file from place and route..."
446 Msg Info "Adding $con_file to place and route"
447 append place_conf_command " -file $con_file"
452 Msg CriticalWarning "Constraint file $con_file does not have a valid extension. Allowed extensions are: \n $vld_exts"
455 }
elseif {$ext == ".src"} {
456 foreach f $lib_files {
457 Msg Debug "Adding source $f to library $rootlib..."
458 create_links -library $rootlib -hdl_source $f
460 }
elseif {$ext == ".sim"} {
461 Msg Debug "Adding stimulus file $f to library..."
462 create_links -library $rootlib -stimulus $f
464 build_design_hierarchy
465 foreach cur_file $lib_files {
469 set props [
DictGet $properties $cur_file]
472 set top [
lindex [regexp -inline {\ytop\s*=\s*(.+?)\y.*} $props] 1]
474 Msg Info "Setting $top as top module for file set $rootlib..."
475 set globalSettings::synth_top_module "${top}::$rootlib"
480 if {$ext == ".src" || $ext == ".con" || $ext == ".ext"} {
481 foreach f $lib_files {
482 Msg Debug "Diamond: adding source file $f to library $rootlib..."
483 prj_src add -work $rootlib $f
484 set props [
DictGet $properties $f]
486 set top [
lindex [regexp -inline {\ytop\s*=\s*(.+?)\y.*} $props] 1]
488 Msg Info "Setting $top as top module for the project..."
489 set globalSettings::synth_top_module $top
493 if {[lsearch -inline -regexp $props "enable"] >= 0} {
494 Msg Debug "Setting $f as active Logic Preference file"
498 }
elseif {$ext == ".sim"} {
499 foreach f $lib_files {
500 Msg Debug "Diamond Adding simulation file $f to library $rootlib..."
501 prj_src add -work $rootlib -simulate_only $f
511 if {[
DictGet $filesets "sim_1"] == ""} {
512 delete_fileset -quiet [get_filesets -quiet "sim_1"]
518 if {$synth_conf == 1} {
519 Msg Info $synth_conf_command
520 eval $synth_conf_command
522 if {$timing_conf == 1} {
523 Msg Info $timing_conf_command
524 eval $timing_conf_command
526 if {$place_conf == 1} {
527 Msg Info $place_conf_command
528 eval $place_conf_command
534 proc ALLOWED_PROPS {} {
535 return [dict create ".vhd" [list "93" "nosynth" "noimpl" "nosim" "1987" "1993" "2008" "2019"] \
536 ".vhdl" [list "93" "nosynth" "noimpl" "nosim" "1987" "1993" "2008" "2019"] \
537 ".bd" [list "nosim"] \
538 ".v" [list "SystemVerilog" "verilog_header" "nosynth" "noimpl" "nosim" "1995" "2001"] \
539 ".sv" [list "verilog" "verilog_header" "nosynth" "noimpl" "nosim" "2005" "2009"] \
540 ".do" [list "nosim"] \
541 ".udo" [list "nosim"] \
542 ".xci" [list "nosynth" "noimpl" "nosim" "locked"] \
543 ".xdc" [list "nosynth" "noimpl"] \
544 ".tcl" [list "nosynth" "noimpl" "nosim" "source" "qsys" "noadd"\
545 "--block-symbol-file" "--clear-output-directory" "--example-design"\
546 "--export-qsys-script" "--family" "--greybox" "--ipxact"\
547 "--jvm-max-heap-size" "--parallel" "--part" "--search-path"\
548 "--simulation" "--synthesis" "--testbench" "--testbench-simulation"\
549 "--upgrade-ip-cores" "--upgrade-variation-file"
551 ".qsys" [list "nogenerate" "noadd" "--block-symbol-file" "--clear-output-directory" "--example-design"\
552 "--export-qsys-script" "--family" "--greybox" "--ipxact" "--jvm-max-heap-size" "--parallel"\
553 "--part" "--search-path" "--simulation" "--synthesis" "--testbench" "--testbench-simulation"\
554 "--upgrade-ip-cores" "--upgrade-variation-file"
556 ".sdc" [list "notiming" "nosynth" "noplace"] \
557 ".elf" [list "scoped_to_ref" "scoped_to_cells" "nosim" "noimpl"] \
558 ".pdc" [list "nosynth" "noplace"] \
559 ".lpf" [list "enable"]]
570 proc BinaryStepName {part} {
572 return "WRITE_DEVICE_IMAGE"
576 return "WRITE_BITSTREAM"
585 proc CheckSyntax {project_name repo_path {project_file ""}} {
587 set syntax [check_syntax -return_string]
588 if {[
string first "CRITICAL" $syntax] != -1} {
593 lassign [
GetHogFiles -list_files "*.src" "$repo_path/Top/$project_name/list/" $repo_path] src_files dummy
594 dict for {lib files} $src_files {
596 set file_extension [file extension $f]
597 if {$file_extension == ".vhd" || $file_extension == ".vhdl" || $file_extension == ".v" || $file_extension == ".sv"} {
598 if {[catch {execute_module -tool map -args "--analyze_file=$f"} result]} {
599 Msg Error "\nResult: $result\n"
600 Msg Error "Check syntax failed.\n"
603 Msg Info "Check syntax was successful for $f.\n"
605 Msg Warning "Found syntax error in file $f:\n $result\n"
612 lassign [
GetProjectFiles $project_file] prjLibraries prjProperties prjSimLibraries prjConstraints prjSrcSets prjSimSets prjConSets
613 dict for {lib sources} $prjLibraries {
614 if {[file extension $lib] == ".src"} {
616 Msg Info "Checking Syntax of $f"
622 Msg Info "The Checking Syntax is not supported by this IDE. Skipping..."
627 proc CloseProject {} {
649 proc CompareVersions {ver1 ver2} {
658 if {[regexp {v(\d+)\.(\d+)\.(\d+)} $ver1 - x y z]} {
659 set ver1 [list $x $y $z]
661 if {[regexp {v(\d+)\.(\d+)\.(\d+)} $ver2 - x y z]} {
662 set ver2 [list $x $y $z]
666 set v1 [
join $ver1 ""]
668 set v2 [
join $ver2 ""]
671 if {[
string is integer $v1] && [
string is integer $v2]} {
672 set ver1 [
expr {[scan [lindex $ver1 0] %d] * 1000000 + [scan [lindex $ver1 1] %d] * 1000 + [scan [lindex $ver1 2] %d]}]
673 set ver2 [
expr {[scan [lindex $ver2 0] %d] * 1000000 + [scan [lindex $ver2 1] %d] * 1000 + [scan [lindex $ver2 2] %d]}]
677 }
elseif {$ver1 == $ver2} {
683 Msg Warning "Version is not numeric: $ver1, $ver2"
693 proc CheckExtraFiles {libraries constraints simlibraries} {
696 lassign [
GetProjectFiles] prjLibraries prjProperties prjSimLibraries prjConstraints
697 set prj_dir [get_property DIRECTORY [current_project]]
698 file mkdir "$prj_dir/.hog"
699 set extra_file_name "$prj_dir/.hog/extra.files"
700 set new_extra_file [open $extra_file_name "w"]
702 dict for {prjLib prjFiles} $prjLibraries {
703 foreach prjFile $prjFiles {
704 if {[file extension $prjFile] == ".xcix"} {
705 Msg Warning "IP $prjFile is packed in a .xcix core container. \
706 This files are not suitable for version control systems. We recommend to use .xci files instead."
709 if {[file extension $prjFile] == ".xci" && [get_property CORE_CONTAINER [get_files $prjFile]] != ""} {
710 Msg Info "$prjFile is a virtual IP file in a core container. Ignoring it..."
714 if {[IsInList $prjFile [DictGet $libraries $prjLib]] == 0} {
715 if {[file extension $prjFile] == ".bd"} {
716 # Generating BD products to save md5sum of already modified BD
717 Msg Info "Generating targets of $prjFile..."
718 generate_target all [get_files $prjFile]
720 puts $new_extra_file "$prjFile [Md5Sum $prjFile]"
721 Msg Info "$prjFile (lib: $prjLib) has been generated by an external script. Adding to $extra_file_name..."
725 close $new_extra_file
726 set extra_sim_file "$prj_dir/.hog/extrasim.files"
727 set new_extra_file [open $extra_sim_file "w"]
729 dict for {prjSimLib prjSimFiles} $prjSimLibraries {
730 foreach prjSimFile $prjSimFiles {
731 if {[IsInList $prjSimFile [DictGet $simlibraries $prjSimLib]] == 0} {
732 puts $new_extra_file "$prjSimFile [Md5Sum $prjSimFile]"
733 Msg Info "$prjSimFile (lib: $prjSimLib) has been generated by an external script. Adding to $extra_sim_file..."
737 close $new_extra_file
738 set extra_con_file "$prj_dir/.hog/extracon.files"
739 set new_extra_file [open $extra_con_file "w"]
741 dict for {prjConLib prjConFiles} $prjConstraints {
742 foreach prjConFile $prjConFiles {
743 if {[IsInList $prjConFile [DictGet $constraints $prjConLib]] == 0} {
744 puts $new_extra_file "$prjConFile [Md5Sum $prjConFile]"
745 Msg Info "$prjConFile has been generated by an external script. Adding to $extra_con_file..."
749 close $new_extra_file
756 proc CheckLatestHogRelease {{repo_path .}} {
759 set current_ver [
Git {describe --always}]
760 Msg Debug "Current version: $current_ver"
761 set current_sha [
Git "log $current_ver -1 --format=format:%H"]
762 Msg Debug "Current SHA: $current_sha"
765 if {[
OS] == "windows"} {
766 Msg Info "On windows we cannot set a timeout on 'git fetch', hopefully nothing will go wrong..."
769 Msg Info "Checking for latest Hog release, can take up to 5 seconds..."
772 set master_ver [
Git "describe origin/master"]
773 Msg Debug "Master version: $master_ver"
774 set master_sha [
Git "log $master_ver -1 --format=format:%H"]
775 Msg Debug "Master SHA: $master_sha"
776 set merge_base [
Git "merge-base $current_sha $master_sha"]
777 Msg Debug "merge base: $merge_base"
780 if {$merge_base != $master_sha} {
782 Msg Info "Version $master_ver has been released (https://gitlab.com/hog-cern/Hog/-/releases/$master_ver)"
783 Msg Status "You should consider updating Hog submodule with the following instructions:"
785 Msg Status "cd Hog && git checkout master && git pull"
787 Msg Status "Also update the ref: in your .gitlab-ci.yml to $master_ver"
791 Msg Info "Latest official version is $master_ver, nothing to do."
803 proc CheckYmlRef {repo_path allow_failure} {
804 if {$allow_failure} {
805 set MSG_TYPE CriticalWarning
810 if {[
catch {
package require yaml 0.3.3} YAMLPACKAGE]} {
811 Msg CriticalWarning "Cannot find package YAML, skipping consistency check of \"ref\" in gilab-ci.yaml file.\n Error message: $YAMLPACKAGE
812 You can fix this by installing package \"tcllib\""
820 if {[
file exists .gitlab-ci.yml]} {
824 if {[
file exists .gitlab-ci.yml]} {
825 set fp [open ".gitlab-ci.yml" r]
826 set file_data [read $fp]
829 Msg $MSG_TYPE "Cannot open file .gitlab-ci.yml"
833 set file_data "\n$file_data\n\n"
835 if {[
catch {::yaml::yaml2dict -stream $file_data} yamlDict]} {
836 Msg $MSG_TYPE "Parsing $repo_path/.gitlab-ci.yml failed. To fix this, check that yaml syntax is respected, remember not to use tabs."
840 dict for {dictKey dictValue} $yamlDict {
841 #looking for Hog include in .gitlab-ci.yml
842 if {"$dictKey" == "include" && (
843 [lsearch [split $dictValue " {}"] "/hog.yml"] != "-1" ||
844 [lsearch [split $dictValue " {}"] "/hog-dynamic.yml"] != "-1"
846 set YML_REF [lindex [split $dictValue " {}"] [expr {[lsearch -dictionary [split $dictValue " {}"] "ref"] + 1}]]
847 set YML_NAME [lindex [split $dictValue " {}"] [expr {[lsearch -dictionary [split $dictValue " {}"] "file"] + 1}]]
851 if {$YML_REF == ""} {
852 Msg Warning "Hog version not specified in the .gitlab-ci.yml. Assuming that master branch is used."
854 set YML_REF_F [
Git {name-rev --tags --name-only origin/master}]
857 set YML_REF_F [regsub -all "'" $YML_REF ""]
860 if {$YML_NAME == ""} {
861 Msg $MSG_TYPE "Hog included yml file not specified, assuming hog.yml"
862 set YML_NAME_F hog.yml
864 set YML_NAME_F [regsub -all "^/" $YML_NAME ""]
867 lappend YML_FILES $YML_NAME_F
873 if {[
catch {::yaml::yaml2dict -file $YML_NAME_F} yamlDict]} {
874 Msg $MSG_TYPE "Parsing $YML_NAME_F failed."
878 dict for {dictKey dictValue} $yamlDict {
879 #looking for included files
880 if {"$dictKey" == "include"} {
881 foreach v $dictValue {
882 lappend YML_FILES [lindex [split $v " "] [expr {[lsearch -dictionary [split $v " "] "local"] + 1}]]
888 Msg Info "Found the following yml files: $YML_FILES"
890 set HOGYML_SHA [
GetSHA $YML_FILES]
891 lassign [
GitRet "log --format=%h -1 --abbrev=7 $YML_REF_F" $YML_FILES] ret EXPECTEDYML_SHA
893 lassign [
GitRet "log --format=%h -1 --abbrev=7 origin/$YML_REF_F" $YML_FILES] ret EXPECTEDYML_SHA
895 Msg $MSG_TYPE "Error in project .gitlab-ci.yml. ref: $YML_REF not found"
896 set EXPECTEDYML_SHA ""
899 if {!($EXPECTEDYML_SHA eq "")} {
900 if {$HOGYML_SHA == $EXPECTEDYML_SHA} {
901 Msg Info "Hog included file $YML_FILES matches with $YML_REF in .gitlab-ci.yml."
903 Msg $MSG_TYPE "HOG $YML_FILES SHA mismatch.
904 From Hog submodule: $HOGYML_SHA
905 From ref in .gitlab-ci.yml: $EXPECTEDYML_SHA
906 You can fix this in 2 ways: by changing the ref in your repository or by changing the Hog submodule commit"
909 Msg $MSG_TYPE "One or more of the following files could not be found $YML_FILES in Hog at $YML_REF"
912 Msg Info ".gitlab-ci.yml not found in $repo_path. Skipping this step"
933 proc CompareLibDicts {proj_libs list_libs proj_sets list_sets proj_props list_props {severity "CriticalWarning"} {outFile ""} {extraFiles ""}} {
934 set extra_files $extraFiles
936 set out_prjlibs $proj_libs
937 set out_prjprops $proj_props
939 dict for {prjSet prjLibraries} $proj_sets {
940 # Check if sets is also in list files
941 if {[IsInList $prjSet $list_sets]} {
942 set listLibraries [DictGet $list_sets $prjSet]
943 # Loop over libraries in fileset
944 foreach prjLib $prjLibraries {
945 set prjFiles [DictGet $proj_libs $prjLib]
946 # Check if library exists in list files
947 if {[IsInList $prjLib $listLibraries]} {
948 # Loop over files in library
949 set listFiles [DictGet $list_libs $prjLib]
950 foreach prjFile $prjFiles {
951 set idx [lsearch -exact $listFiles $prjFile]
952 set listFiles [lreplace $listFiles $idx $idx]
954 # File is in project but not in list libraries, check if it was generated at creation time...
955 if {[dict exists $extra_files $prjFile]} {
956 # File was generated at creation time, checking the md5sum
957 # Removing the file from the prjFiles list
958 set idx2 [lsearch -exact $prjFiles $prjFile]
959 set prjFiles [lreplace $prjFiles $idx2 $idx2]
960 set new_md5sum [Md5Sum $prjFile]
961 set old_md5sum [DictGet $extra_files $prjFile]
962 if {$new_md5sum != $old_md5sum} {
963 # tclint-disable-next-line line-length
964 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
967 set extra_files [dict remove $extra_files $prjFile]
969 # File is neither in list files nor in extra_files
970 MsgAndLog "$prjFile was found in project but not in list files or .hog/extra.files" $severity $outFile
974 # File is both in list files and project, checking properties...
975 set prjProps [DictGet $proj_props $prjFile]
976 set listProps [DictGet $list_props $prjFile]
977 # Check if it is a potential sourced file
978 if {[IsInList "nosynth" $prjProps] && [IsInList "noimpl" $prjProps] && [IsInList "nosim" $prjProps]} {
979 # Check if it is sourced
980 set idx_source [lsearch -exact $listProps "source"]
981 if {$idx_source >= 0} {
982 # It is sourced, let's replace the individual properties with source
983 set idx [lsearch -exact $prjProps "noimpl"]
984 set prjProps [lreplace $prjProps $idx $idx]
985 set idx [lsearch -exact $prjProps "nosynth"]
986 set prjProps [lreplace $prjProps $idx $idx]
987 set idx [lsearch -exact $prjProps "nosim"]
988 set prjProps [lreplace $prjProps $idx $idx]
989 lappend prjProps "source"
993 foreach prjProp $prjProps {
994 set idx [lsearch -exact $listProps $prjProp]
995 set listProps [lreplace $listProps $idx $idx]
997 MsgAndLog "Property $prjProp of $prjFile was set in project but not in list files" $severity $outFile
1002 foreach listProp $listProps {
1003 if {[string first $listProp "topsim="] == -1 && [string first $listProp "enable"] == -1} {
1004 MsgAndLog "Property $listProp of $prjFile was found in list files but not set in project." $severity $outFile
1009 # Update project prjProps
1010 dict set out_prjprops $prjFile $prjProps
1013 # Loop over remaining files in list libraries
1014 foreach listFile $listFiles {
1015 MsgAndLog "$listFile was found in list files but not in project." $severity $outFile
1019 # Check extra files again...
1020 foreach prjFile $prjFiles {
1021 if {[dict exists $extra_files $prjFile]} {
1022 # File was generated at creation time, checking the md5sum
1023 # Removing the file from the prjFiles list
1024 set idx2 [lsearch -exact $prjFiles $prjFile]
1025 set prjFiles [lreplace $prjFiles $idx2 $idx2]
1026 set new_md5sum [Md5Sum $prjFile]
1027 set old_md5sum [DictGet $extra_files $prjFile]
1028 if {$new_md5sum != $old_md5sum} {
1029 # tclint-disable-next-line line-length
1030 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
1033 set extra_files [dict remove $extra_files $prjFile]
1035 # File is neither in list files nor in extra_files
1036 MsgAndLog "$prjFile was found in project but not in list files or .hog/extra.files" $severity $outFile
1041 # Update prjLibraries
1042 dict set out_prjlibs $prjLib $prjFiles
1045 MsgAndLog "Fileset $prjSet found in project but not in list files" $severity $outFile
1050 return [list $n_diffs $extra_files $out_prjlibs $out_prjprops]
1060 proc CompareVHDL {file1 file2} {
1061 set a [open $file1 r]
1062 set b [open $file2 r]
1064 while {[
gets $a line] != -1} {
1065 set line [regsub {^[\t\s]*(.*)?\s*} $line "\\1"]
1066 if {![regexp {^$} $line] & ![regexp {^--} $line]} {
1072 while {[
gets $b line] != -1} {
1073 set line [regsub {^[\t\s]*(.*)?\s*} $line "\\1"]
1074 if {![regexp {^$} $line] & ![regexp {^--} $line]} {
1083 foreach x $f1 y $f2 {
1085 lappend diff "> $x\n< $y\n\n"
1098 proc Copy {i_dirs o_dir} {
1099 foreach i_dir $i_dirs {
1100 if {[
file isdirectory $i_dir] && [
file isdirectory $o_dir]} {
1101 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]])} {
1102 file delete -force $o_dir/[
file tail $i_dir]
1106 file copy -force $i_dir $o_dir
1121 proc CopyIPbusXMLs {proj_dir path dst {xml_version "0.0.0"} {xml_sha "00000000"} {use_ipbus_sw 0} {generate 0}} {
1122 if {$use_ipbus_sw == 1} {
1123 lassign [
ExecuteRet python3 -c "from __future__ import print_function; from sys import path;print(':'.join(path\[1:\]))"] ret msg
1125 set ::env(PYTHONPATH) $msg
1126 lassign [
ExecuteRet gen_ipbus_addr_decode -h] ret msg
1133 Msg CriticalWarning "Problem while trying to run python: $msg"
1136 set dst [
file normalize $dst]
1138 if {$can_generate == 0} {
1139 if {$generate == 1} {
1140 Msg Error "Cannot generate IPbus address files, IPbus executable gen_ipbus_addr_decode not found or not working: $msg"
1143 Msg Warning "IPbus executable gen_ipbus_addr_decode not found or not working, will not verify IPbus address tables."
1150 set ipb_files [glob -nocomplain $proj_dir/list/*.ipb]
1151 set n_ipb_files [
llength $ipb_files]
1152 if {$n_ipb_files == 0} {
1153 Msg CriticalWarning "No files with .ipb extension found in $proj_dir/list."
1156 set libraries [dict create]
1157 set vhdl_dict [dict create]
1159 foreach ipb_file $ipb_files {
1165 set xmlfiles [dict get $libraries "xml.ipb"]
1167 set xml_list_error 0
1168 foreach xmlfile $xmlfiles {
1169 if {[
file isdirectory $xmlfile]} {
1170 Msg CriticalWarning "Directory $xmlfile listed in xml list file $list_file. Directories are not supported!"
1171 set xml_list_error 1
1174 if {[
file exists $xmlfile]} {
1175 if {[dict exists $vhdl_dict $xmlfile]} {
1176 set vhdl_file [
file normalize $path/[dict get $vhdl_dict $xmlfile]]
1180 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"
1211 foreach x $xmls v $vhdls {
1213 set x [
file normalize ../$x]
1214 if {[
file exists $x]} {
1215 lassign [
ExecuteRet gen_ipbus_addr_decode --no-timestamp $x 2>&1] status log
1217 set generated_vhdl ./ipbus_decode_[
file rootname [
file tail $x]].vhd
1218 if {$generate == 1} {
1219 Msg Info "Copying generated VHDL file $generated_vhdl into $v (replacing if necessary)"
1220 file copy -force -- $generated_vhdl $v
1222 if {[
file exists $v]} {
1224 set n [
llength $diff]
1226 Msg CriticalWarning "$v does not correspond to its XML $x, [
expr {$n / 3}] line/s differ:"
1227 Msg Status [
join $diff "\n"]
1228 set diff_file [open ../diff_[
file rootname [
file tail $x]].txt w]
1229 puts $diff_file $diff
1232 Msg Info "[
file tail $x] and $v match."
1235 Msg Warning "VHDL address map file $v not found."
1239 Msg Warning "Address map generation failed for [
file tail $x]: $log"
1242 Msg Warning "Copied XML file $x not found."
1245 Msg Info "Skipped verification of [
file tail $x] as no VHDL file was specified."
1249 file delete -force address_decode
1261 proc DescriptionFromConf {conf_file} {
1262 set f [open $conf_file "r"]
1263 set lines [
split [read $f] "\n"]
1265 set second_line [
lindex $lines 1]
1268 if {![regexp {\#+ *(.+)} $second_line - description]} {
1272 if {[regexp -all {test|Test|TEST} $description]} {
1273 set description "test"
1286 proc DictGet {dictName keyName {default ""}} {
1287 if {[dict exists $dictName $keyName]} {
1288 return [dict get $dictName $keyName]
1299 proc DictSort {dict args} {
1301 foreach key [lsort {*}$args [dict keys $dict]] {
1302 dict set res $key [dict get $dict $key]
1312 proc DoxygenVersion {target_version} {
1313 set ver [
split $target_version "."]
1314 set v [
Execute doxygen --version]
1315 Msg Info "Found Doxygen version: $v"
1316 set current_ver [
split $v ". "]
1317 set target [
expr {[lindex $ver 0] * 100000 + [lindex $ver 1] * 100 + [lindex $ver 2]}]
1318 set current [
expr {[lindex $current_ver 0] * 100000 + [lindex $current_ver 1] * 100 + [lindex $current_ver 2]}]
1320 return [
expr {$target <= $current}]
1331 proc eos {command {attempt 1}} {
1333 if {![
info exists env(EOS_MGM_URL)]} {
1334 Msg Warning "Environment variable EOS_MGM_URL not set, setting it to default value root://eosuser.cern.ch"
1335 set ::env(EOS_MGM_URL) "root://eosuser.cern.ch"
1338 Msg Warning "The value of attempt should be 1 or more, not $attempt, setting it to 1 as default"
1341 for {
set i 0} {$i < $attempt} {
incr i} {
1342 set ret [
catch {
exec -ignorestderr eos {*}$command} result]
1347 set wait [
expr {1 + int(rand() * 29)}]
1348 Msg Warning "Command $command failed ($i/$attempt): $result, trying again in $wait seconds..."
1349 after [
expr {$wait * 1000}]
1353 return [list $ret $result]
1363 proc Execute {args} {
1367 Msg Error "Command [
join $args] returned error code: $ret"
1381 proc ExecuteRet {args} {
1383 if {[
llength $args] == 0} {
1384 Msg CriticalWarning "No argument given"
1388 set ret [
catch {
exec -ignorestderr {*}$args} result]
1391 return [list $ret $result]
1398 proc ExtractFilesSection {file_data} {
1399 set in_files_section 0
1402 foreach line $file_data {
1403 if {[regexp {^ *\[ *files *\]} $line]} {
1404 set in_files_section 1
1407 if {$in_files_section} {
1408 if {[regexp {^ *\[.*\]} $line]} {
1411 lappend result $line
1416 if {!$in_files_section} {
1430 proc ExtractVersionFromTag {tag} {
1431 if {[regexp {^(?:b(\d+))?v(\d+)\.(\d+).(\d+)(?:-\d+)?$} $tag -> mr M m p]} {
1436 Msg Warning "Repository tag $tag is not in a Hog-compatible format."
1442 return [list $M $m $p $mr]
1452 proc FileCommitted {File} {
1454 set currentDir [
pwd]
1455 cd [
file dirname [
file normalize $File]]
1456 set GitLog [
Git ls-files [
file tail $File]]
1457 if {$GitLog == ""} {
1458 Msg CriticalWarning "File [
file normalize $File] is not in the git repository. Please add it with:\n git add [
file normalize $File]\n"
1469 proc FindCommonGitChild {SHA1 SHA2} {
1471 set commits [
Git {log --oneline --merges}]
1474 foreach line [
split $commits "\n"] {
1475 set commit [
lindex [
split $line] 0]
1479 set ancestor $commit
1492 proc findFiles {basedir pattern} {
1495 set basedir [
string trimright [
file join [
file normalize $basedir] { }]]
1501 foreach fileName [glob -nocomplain -type {f r} -path $basedir $pattern] {
1502 lappend fileList $fileName
1506 foreach dirName [glob -nocomplain -type {d r} -path $basedir *] {
1509 set subDirList [
findFiles $dirName $pattern]
1510 if {[
llength $subDirList] > 0} {
1511 foreach subDirFile $subDirList {
1512 lappend fileList $subDirFile
1523 proc FindFileType {file_name} {
1524 set extension [
file extension $file_name]
1527 set file_extension "USE_SIGNALTAP_FILE"
1530 set file_extension "VHDL_FILE"
1533 set file_extension "VHDL_FILE"
1536 set file_extension "VERILOG_FILE"
1539 set file_extension "SYSTEMVERILOG_FILE"
1542 set file_extension "SDC_FILE"
1545 set file_extension "PDC_FILE"
1548 set file_extension "NDC_FILE"
1551 set file_extension "FDC_FILE"
1554 set file_extension "SOURCE_FILE"
1557 set file_extension "IP_FILE"
1560 set file_extension "QSYS_FILE"
1563 set file_extension "QIP_FILE"
1566 set file_extension "SIP_FILE"
1569 set file_extension "BSF_FILE"
1572 set file_extension "BDF_FILE"
1575 set file_extension "COMMAND_MACRO_FILE"
1578 set file_extension "VQM_FILE"
1581 set file_extension "ERROR"
1582 Msg Error "Unknown file extension $extension"
1585 return $file_extension
1592 proc FindNewestVersion {versions} {
1593 set new_ver 00000000
1594 foreach ver $versions {
1596 if {[
expr 0x$ver > 0x$new_ver]} {
1608 proc FindVhdlVersion {file_name} {
1609 set extension [
file extension $file_name]
1612 set vhdl_version "-hdl_version VHDL_2008"
1615 set vhdl_version "-hdl_version VHDL_2008"
1622 return $vhdl_version
1629 proc FormatGeneric {generic} {
1630 if {[
string is integer "0x$generic"]} {
1631 return [
format "32'h%08X" "0x$generic"]
1634 return [
format "32'h%08X" 0]
1644 proc GenerateBitstream {{run_folder ""} {repo_path .} {njobs 1}} {
1645 Msg Info "Starting write bitstream flow..."
1647 set revision [get_current_revision]
1648 if {[
catch {execute_module -tool asm} result]} {
1649 Msg Error "Result: $result\n"
1650 Msg Error "Generate bitstream failed. See the report file.\n"
1652 Msg Info "Generate bitstream was successful for revision $revision.\n"
1655 Msg Info "Run GENERATEPROGRAMMINGDATA ..."
1656 if {[
catch {run_tool -name {GENERATEPROGRAMMINGDATA}}]} {
1657 Msg Error "GENERATEPROGRAMMINGDATA FAILED!"
1659 Msg Info "GENERATEPROGRAMMINGDATA PASSED."
1661 Msg Info "Sourcing Hog/Tcl/integrated/post-bitstream.tcl"
1662 source $repo_path/Hog/Tcl/integrated/post-bitstream.tcl
1664 prj_run Export -impl Implementation0 -task Bitgen
1674 proc GenerateQsysSystem {qsysFile commandOpts} {
1675 if {[
file exists $qsysFile] != 0} {
1676 set qsysPath [
file dirname $qsysFile]
1677 set qsysName [
file rootname [
file tail $qsysFile]]
1678 set qsysIPDir "$qsysPath/$qsysName"
1679 set qsysLogFile "$qsysPath/$qsysName.qsys-generate.log"
1682 if {![
info exists ::env(QSYS_ROOTDIR)]} {
1683 if {[
info exists ::env(QUARTUS_ROOTDIR)]} {
1684 set qsys_rootdir "$::env(QUARTUS_ROOTDIR)/sopc_builder/bin"
1685 Msg Warning "The QSYS_ROOTDIR environment variable is not set! I will use $qsys_rootdir"
1687 Msg CriticalWarning "The QUARTUS_ROOTDIR environment variable is not set! Assuming all quartus executables are contained in your PATH!"
1690 set qsys_rootdir $::env(QSYS_ROOTDIR)
1693 set cmd "$qsys_rootdir/qsys-generate"
1694 set cmd_options "$qsysFile --output-directory=$qsysIPDir $commandOpts"
1695 if {![
catch {"exec $cmd -version"}] || [
lindex $::errorCode 0] eq "NONE"} {
1696 Msg Info "Executing: $cmd $cmd_options"
1697 Msg Info "Saving logfile in: $qsysLogFile"
1698 if {[
catch {
eval exec -ignorestderr "$cmd $cmd_options >>& $qsysLogFile"} ret opt]} {
1699 set makeRet [
lindex [dict get $opt -errorcode] end]
1700 Msg CriticalWarning "$cmd returned with $makeRet"
1703 Msg Error " Could not execute command $cmd"
1707 set qsysIPFileList [
concat \
1708 [glob -nocomplain -directory $qsysIPDir -types f *.ip *.qip] \
1709 [glob -nocomplain -directory "$qsysIPDir/synthesis" -types f *.ip *.qip *.vhd *.vhdl]
1711 foreach qsysIPFile $qsysIPFileList {
1712 if {[
file exists $qsysIPFile] != 0} {
1714 set_global_assignment -name $qsysIPFileType $qsysIPFile
1716 set IpMd5Sum [
Md5Sum $qsysIPFile]
1718 set fileDir [
file normalize "./hogTmp"]
1719 set fileName "$fileDir/.hogQsys.md5"
1720 if {![
file exists $fileDir]} {
1723 set hogQsysFile [open $fileName "a"]
1724 set fileEntry "$qsysIPFile\t$IpMd5Sum"
1725 puts $hogQsysFile $fileEntry
1730 Msg ERROR "Error while generating ip variations from qsys: $qsysFile not found!"
1740 proc GenericToSimulatorString {prop_dict target} {
1742 dict for {theKey theValue} $prop_dict {
1751 regexp {([0-9]*)('h)([0-9a-fA-F]*)} $theValue valueHexFull valueNumBits valueHexFlag valueHex
1752 regexp {^([0-9]*)$} $theValue valueIntFull ValueInt
1753 regexp {(?!^\d+$)^.+$} $theValue valueStrFull ValueStr
1754 if {[string tolower $target] == "vivado" || [string tolower $target] == "xsim"} {
1755 if {$valueNumBits != "" && $valueHexFlag != "" && $valueHex != ""} {
1756 set prj_generics "$prj_generics $theKey=$valueHexFull"
1757 } elseif {$valueIntFull != "" && $ValueInt != ""} {
1758 set prj_generics "$prj_generics $theKey=$ValueInt"
1759 } elseif {$valueStrFull != "" && $ValueStr != ""} {
1760 set prj_generics "$prj_generics $theKey=\"$ValueStr\""
1762 set prj_generics "$prj_generics $theKey=\"$theValue\""
1764 } elseif {[lsearch -exact [GetSimulators] [string tolower $target]] >= 0} {
1765 if {$valueNumBits != "" && $valueHexFlag != "" && $valueHex != ""} {
1767 scan $valueNumBits %d numBits
1769 scan $valueHex %x numHex
1770 binary scan [binary format "I" $numHex] "B*" binval
1771 set numBits [expr {$numBits - 1}]
1772 set numBin [string range $binval end-$numBits end]
1773 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\"}"
1779 set prj_generics "$prj_generics {$theKey=\"$theValue\"}"
1782 Msg Warning "Target : $target not implemented"
1785 return $prj_generics
1793 proc GetConfFiles {proj_dir} {
1794 if {![
file isdirectory $proj_dir]} {
1795 Msg Error "$proj_dir is supposed to be the top project directory"
1798 set conf_file [
file normalize $proj_dir/hog.conf]
1799 set sim_file [
file normalize $proj_dir/sim.conf]
1800 set pre_tcl [
file normalize $proj_dir/pre-creation.tcl]
1801 set post_tcl [
file normalize $proj_dir/post-creation.tcl]
1803 return [list $conf_file $sim_file $pre_tcl $post_tcl]
1812 proc GetCustomCommands {{directory .} {ret_commands 0}} {
1813 set commands_dict [dict create]
1814 set commands_files [glob -nocomplain $directory/*.tcl]
1815 set commands_string ""
1817 if {[
llength $commands_files] == 0} {
1821 if {$ret_commands == 0} {
1822 append commands_string "\nCustom Commands:\n"
1825 foreach file $commands_files {
1826 set base_name [
string toupper [
file rootname [
file tail $file]]]
1827 if {$ret_commands == 1} {
1828 append commands_string "
1830 Msg Info \"Running custom script: $file\"
1832 Msg Info \"Done running custom script...\"
1837 set f [open $file r]
1838 set first_line [
gets $f]
1840 if {[regexp -nocase "^#\s*$base_name:\s*(.*)" $first_line full_match script_des]} {
1841 append commands_string " - $base_name: $script_des\n"
1843 append commands_string " - $base_name: runs $file\n"
1847 return $commands_string
1853 proc GetDateAndTime {commit} {
1854 set clock_seconds [
clock seconds]
1857 set date [
Git "log -1 --format=%cd --date=format:%d%m%Y $commit"]
1858 set timee [
Git "log -1 --format=%cd --date=format:00%H%M%S $commit"]
1860 Msg Warning "Found Git version older than 2.9.3. Using current date and time instead of commit time."
1861 set date [
clock format $clock_seconds -format {%d%m%Y}]
1862 set timee [
clock format $clock_seconds -format {00%H%M%S}]
1864 return [list $date $timee]
1876 proc GetFile {file fileset} {
1879 set Files [get_files -all $file -of_object [get_filesets $fileset]]
1880 set f [
lindex $Files 0]
1888 puts "***DEBUG Hog:GetFile $file"
1897 proc GetFileGenerics {filename {entity ""}} {
1899 if {[
string equal $file_type "VERILOG_FILE"] || [
string equal $file_type "SYSTEMVERILOG_FILE"]} {
1901 }
elseif {[
string equal $file_type "VHDL_FILE"]} {
1904 Msg CriticalWarning "Could not determine extension of top level file."
1913 proc GetGenericsFromConf {proj_dir} {
1914 set generics_dict [dict create]
1915 set top_dir "Top/$proj_dir"
1916 set conf_file "$top_dir/hog.conf"
1919 if {[
file exists $conf_file]} {
1921 if {[dict exists $properties generics]} {
1922 set generics_dict [dict get $properties generics]
1925 Msg Warning "File $conf_file not found."
1927 return $generics_dict
1940 proc GetSimSets {project_name repo_path {simsets ""} {ghdl 0} {no_conf 0}} {
1941 set simsets_dict [dict create]
1942 set list_dir "$repo_path/Top/$project_name/list"
1944 if {$simsets != ""} {
1945 foreach s $simsets {
1946 set list_file "$list_dir/$s.sim"
1947 if {[
file exists $list_file]} {
1948 lappend list_files $list_file
1949 }
elseif {$s != "sim_1"} {
1950 Msg CriticalWarning "Simulation set list file $list_file not found."
1955 set list_files [glob -nocomplain -directory $list_dir "*.sim"]
1959 set proj_dir [
file normalize $repo_path/Top/$project_name]
1960 set sim_file [
file normalize $proj_dir/sim.conf]
1962 foreach list_file $list_files {
1963 set file_name [
file tail $list_file]
1964 set simset_name [
file rootname $file_name]
1965 set fp [open $list_file r]
1966 set file_data [read $fp]
1968 set data [
split $file_data "\n"]
1970 set firstline [
lindex $data 0]
1972 if {[regexp {^ *\# *Simulator} $firstline]} {
1973 set simulator_prop [regexp -all -inline {\S+} $firstline]
1974 set simulator [
string tolower [
lindex $simulator_prop end]]
1976 Msg Warning "Simulator not set in $simset_name.sim. \
1977 The first line of $simset_name.sim should be #Simulator <SIMULATOR_NAME>,\
1978 where <SIMULATOR_NAME> can be xsim, questa, modelsim, ghdl, riviera, activehdl,\
1979 ies, or vcs, e.g. #Simulator questa.\
1980 Setting simulator by default to xsim."
1981 set simulator "xsim"
1983 if {$simulator eq "skip_simulation"} {
1984 Msg Info "Skipping simulation for $simset_name"
1987 if {($ghdl == 1 && $simulator != "ghdl") || ($ghdl == 0 && $simulator == "ghdl")} {
1991 set SIM_PROPERTIES ""
1992 if {[
file exists $sim_file] && $no_conf == 0} {
1993 set SIM_PROPERTIES [
ReadConf $sim_file]
1996 set global_sim_props [dict create]
1997 dict set global_sim_props "properties" [
DictGet $SIM_PROPERTIES "sim"]
1998 dict set global_sim_props "generics" [
DictGet $SIM_PROPERTIES "generics"]
1999 dict set global_sim_props "hog" [
DictGet $SIM_PROPERTIES "hog"]
2002 set sim_dict [dict create]
2003 dict set sim_dict "simulator" $simulator
2004 if {[dict exists $SIM_PROPERTIES $simset_name]} {
2005 dict set sim_dict "properties" [
DictGet $SIM_PROPERTIES $simset_name]
2006 dict set sim_dict "generics" [
DictGet $SIM_PROPERTIES "$simset_name:generics"]
2007 dict set sim_dict "hog" [
DictGet $SIM_PROPERTIES "$simset_name:hog"]
2008 }
elseif {$no_conf == 0} {
2010 set conf_dict [
ReadConf $list_file]
2011 set sim_dict [
MergeDict $sim_dict $conf_dict 0]
2013 set sim_dict [
MergeDict $sim_dict $global_sim_props 0]
2014 dict set simsets_dict $simset_name $sim_dict
2016 return $simsets_dict
2024 proc GetSimsetGenericsFromConf {proj_dir} {
2025 set simsets_generics_dict [dict create]
2026 set top_dir "Top/$proj_dir"
2027 set conf_file "$top_dir/sim.conf"
2030 if {[
file exists $conf_file]} {
2033 set simsets_generics_dict [dict filter $properties key *:generics]
2035 Msg Warning "File $conf_file not found."
2037 return $simsets_generics_dict
2048 proc GetGroupName {proj_dir repo_dir} {
2049 if {[regexp {^(.*)/(Top|Projects)/+(.*?)/*$} $proj_dir dummy possible_repo_dir proj_or_top dir]} {
2051 if {[
file normalize $repo_dir] eq [
file normalize $possible_repo_dir]} {
2052 set group [
file dir $dir]
2053 if {$group == "."} {
2058 Msg Warning "Project directory $proj_dir seems to be in $possible_repo_dir which is not a the main Git repository $repo_dir."
2061 Msg Warning "Could not parse project directory $proj_dir"
2074 proc GetHogDescribe {sha {repo_path .}} {
2077 set new_sha "[
string toupper [
GetSHA]]"
2080 set new_sha [
string toupper $sha]
2100 proc GetHogFiles {args} {
2103 if {[
catch {
package require cmdline} ERROR]} {
2104 puts "$ERROR\n If you are running this script on tclsh, you can fix this by installing 'tcllib'"
2111 {list_files.arg "" "The file wildcard, if not specified all Hog list files will be looked for."}
2112 {sha_mode "Forwarded to ReadListFile, see there for info."}
2113 {ext_path.arg "" "Path for the external libraries forwarded to ReadListFile."}
2114 {print_log "Forwarded to ReadListFile, see there for info."}
2116 set usage "USAGE: GetHogFiles \[options\] <list path> <repository path>"
2117 if {[
catch {
array set options [
cmdline::getoptions args $parameters $usage]}] || [
llength $args] != 2} {
2121 set list_path [
lindex $args 0]
2122 set repo_path [
lindex $args 1]
2124 set list_files $options(list_files)
2125 set sha_mode $options(sha_mode)
2126 set ext_path $options(ext_path)
2127 set print_log $options(print_log)
2129 if {$sha_mode == 1} {
2130 set sha_mode_opt "-sha_mode"
2135 if {$print_log == 1} {
2136 set print_log_opt "-print_log"
2138 set print_log_opt ""
2142 if {$list_files == ""} {
2143 set list_files {.src,.con,.sim,.ext}
2145 set libraries [dict create]
2146 set properties [dict create]
2147 set list_files [glob -nocomplain -directory $list_path "*{$list_files}"]
2148 set filesets [dict create]
2150 foreach f $list_files {
2151 set ext [
file extension $f]
2152 if {$ext == ".ext"} {
2153 lassign [
ReadListFile {*}"$sha_mode_opt $print_log_opt $f $ext_path"] l p fs
2155 lassign [
ReadListFile {*}"$sha_mode_opt $print_log_opt $f $repo_path"] l p fs
2158 set properties [
MergeDict $p $properties]
2159 Msg Debug "list file $f, filesets: $fs"
2161 Msg Debug "Merged filesets $filesets"
2163 return [list $libraries $properties $filesets]
2169 proc GetIDECommand {proj_conf} {
2171 if {[
file exists $proj_conf]} {
2172 set ide_name_and_ver [
string tolower [
GetIDEFromConf $proj_conf]]
2173 set ide_name [
lindex [regexp -all -inline {\S+} $ide_name_and_ver] 0]
2175 if {$ide_name eq "vivado"} {
2176 set command "vivado"
2178 set before_tcl_script " -nojournal -nolog -mode batch -notrace -source "
2179 set after_tcl_script " -tclargs "
2181 }
elseif {$ide_name eq "planahead"} {
2182 set command "planAhead"
2184 set before_tcl_script " -nojournal -nolog -mode batch -notrace -source "
2185 set after_tcl_script " -tclargs "
2187 }
elseif {$ide_name eq "quartus"} {
2188 set command "quartus_sh"
2190 set before_tcl_script " -t "
2191 set after_tcl_script " "
2193 }
elseif {$ide_name eq "libero"} {
2196 set command "libero"
2197 set before_tcl_script "SCRIPT:"
2198 set after_tcl_script " SCRIPT_ARGS:\""
2200 }
elseif {$ide_name eq "diamond"} {
2201 set command "diamondc"
2202 set before_tcl_script " "
2203 set after_tcl_script " "
2205 }
elseif {$ide_name eq "ghdl"} {
2207 set before_tcl_script " "
2208 set after_tcl_script " "
2211 Msg Error "IDE: $ide_name not known."
2214 Msg Error "Configuration file $proj_conf not found."
2217 return [list $command $before_tcl_script $after_tcl_script $end_marker]
2223 proc GetIDEFromConf {conf_file} {
2224 set f [open $conf_file "r"]
2227 if {[regexp -all {^\# *(\w*) *(\d+\.\d+(?:\.\d+)?(?:\.\d+)?)?(_.*)? *$} $line dummy ide version patch]} {
2228 if {[
info exists version] && $version != ""} {
2234 set ret [list $ide $ver]
2236 Msg CriticalWarning "The first line of hog.conf should be \#<IDE name> <version>, \
2237 where <IDE name>. is quartus, vivado, planahead, libero, diamond or ghdl, \
2238 and <version> the tool version, e.g. \#vivado 2020.2. Will assume vivado."
2239 set ret [list "vivado" "0.0.0"]
2246 proc GetIDEName {} {
2248 return "ISE/PlanAhead"
2266 proc GetIDEVersion {} {
2269 regexp {\d+\.\d+(\.\d+)?} [version -short] ver
2274 regexp {[\.0-9]+} $quartus(version) ver
2277 set ver [get_libero_version]
2279 regexp {\d+\.\d+(\.\d+)?} [sys_install version] ver
2291 proc GetLinkedFile {link_file} {
2292 if {[
file type $link_file] eq "link"} {
2293 if {[
OS] == "windows"} {
2295 lassign [
ExecuteRet realpath $link_file] ret msg
2296 lassign [
ExecuteRet cygpath -m $msg] ret2 msg2
2297 if {$ret == 0 && $ret2 == 0} {
2299 Msg Debug "Found link file $link_file on Windows, the linked file is: $real_file"
2301 Msg CriticalWarning "[
file normalize $link_file] is a soft link. \
2302 Soft link are not supported on Windows and readlink.exe or cygpath.exe did not work: readlink=$ret: $msg, cygpath=$ret2: $msg2."
2303 set real_file $link_file
2307 set linked_file [
file link $link_file]
2308 set real_file [
file normalize [
file dirname $link_file]/$linked_file]
2311 if {![
file exists $real_file]} {
2312 Msg Warning "$link_file is a broken link, because the linked file: $real_file does not exist."
2315 Msg Warning "$link file is not a soft link"
2316 set real_file $link_file
2329 proc GetMaxThreads {proj_dir} {
2331 if {[
file exists $proj_dir/hog.conf]} {
2333 if {[dict exists $properties parameters]} {
2334 set propDict [dict get $properties parameters]
2335 if {[dict exists $propDict MAX_THREADS]} {
2336 set maxThreads [dict get $propDict MAX_THREADS]
2340 Msg Warning "File $proj_dir/hog.conf not found. Max threads will be set to default value 1"
2353 proc GetModifiedFiles {{repo_path "."} {pattern "."}} {
2356 set ret [
Git "ls-files --modified $pattern"]
2365 proc GetOptions {argv parameters} {
2368 set param_list [list]
2369 set option_list [list]
2371 foreach p $parameters {
2372 lappend param_list [
lindex $p 0]
2376 while {$index < [
llength $argv]} {
2377 set arg [
lindex $argv $index]
2378 if {[
string first - $arg] == 0} {
2379 set option [
string trimleft $arg "-"]
2381 lappend option_list $arg
2382 if {[lsearch $param_list ${option}*] >= 0 && [
string first ".arg" [lsearch -inline $param_list ${option}*]] >= 0} {
2383 lappend option_list [
lindex $argv $index]
2387 lappend arg_list $arg
2391 Msg Debug "Argv: $argv"
2392 Msg Debug "Options: $option_list"
2393 Msg Debug "Arguments: $arg_list"
2394 return [list $option_list $arg_list]
2412 proc GetProjectFiles {{project_file ""}} {
2413 set libraries [dict create]
2414 set simlibraries [dict create]
2415 set constraints [dict create]
2416 set properties [dict create]
2417 set consets [dict create]
2418 set srcsets [dict create]
2419 set simsets [dict create]
2422 set all_filesets [get_filesets]
2423 set simulator [get_property target_simulator [current_project]]
2424 set top [get_property "top" [current_fileset]]
2426 dict lappend properties $topfile "top=$top"
2428 foreach fs $all_filesets {
2429 if {$fs == "utils_1"} {
2434 set all_files [get_files -quiet -of_objects [get_filesets $fs]]
2435 set fs_type [get_property FILESET_TYPE [get_filesets $fs]]
2437 if {$fs_type == "BlockSrcs"} {
2439 set dict_fs "sources_1"
2443 foreach f $all_files {
2450 if {[
lindex [get_property IS_GENERATED [
GetFile $f $fs]] 0] != 0} {
2455 if {[get_property FILE_TYPE [
GetFile $f $fs]] == "Configuration Files"} {
2461 if {[get_property CORE_CONTAINER [
GetFile $f $fs]] != ""} {
2462 if {[
file extension $f] == ".xcix"} {
2463 set f [get_property CORE_CONTAINER [
GetFile $f $fs]]
2471 if {[get_property SCOPED_TO_REF [
GetFile $f $fs]] != ""} {
2472 dict lappend properties $f "scoped_to_ref=[get_property SCOPED_TO_REF [
GetFile $f $fs]]"
2477 if {[get_property SCOPED_TO_CELLS [
GetFile $f $fs]] != ""} {
2478 dict lappend properties $f "scoped_to_cells=[get_property SCOPED_TO_CELLS [
GetFile $f $fs]]"
2482 if {[
IsInList "PARENT_COMPOSITE_FILE" [list_property [
GetFile $f $fs]]]} {
2487 if {[
file tail $f] == "nocattrs.dat"} {
2492 if {[
file extension $f] != ".coe"} {
2493 set f [
file normalize $f]
2496 set type [get_property FILE_TYPE [
GetFile $f $fs]]
2498 set lib [get_property -quiet LIBRARY [
GetFile $f $fs]]
2501 Msg Debug "File $f Extension [
file extension $f] Type [
lindex $type 0]"
2503 if {[
string equal [
lindex $type 0] "VHDL"] && [
llength $type] == 1} {
2505 }
elseif {[
string equal [
lindex $type 0] "Block"] && [
string equal [
lindex $type 1] "Designs"]} {
2508 }
elseif {[
string equal $type "SystemVerilog"] && [
file extension $f] != ".sv"} {
2509 set prop "SystemVerilog"
2510 }
elseif {[
string equal [
lindex $type 0] "XDC"] && [
file extension $f] != ".xdc"} {
2512 }
elseif {[
string equal $type "Verilog Header"] && [
file extension $f] != ".vh" && [
file extension $f] != ".svh"} {
2513 set prop "verilog_header"
2514 }
elseif {[
string equal $type "Verilog Template"] && [
file extension $f] == ".v" && [
file extension $f] != ".sv"} {
2515 set prop "verilog_template"
2517 set type [
lindex $type 0]
2521 if {![
string equal $prop ""]} {
2522 dict lappend properties $f $prop
2525 if {[
string equal $fs_type "SimulationSrcs"]} {
2527 if {[
string equal $type "VHDL"]} {
2528 set library "${lib}.sim"
2530 set library "others.sim"
2534 dict lappend simsets $dict_fs $library
2537 dict lappend simlibraries $library $f
2538 }
elseif {[
string equal $type "VHDL"]} {
2541 dict lappend srcsets $dict_fs "${lib}.src"
2543 dict lappend libraries "${lib}.src" $f
2544 }
elseif {[
string first "IP" $type] != -1} {
2547 dict lappend srcsets $dict_fs "ips.src"
2549 dict lappend libraries "ips.src" $f
2550 Msg Debug "Appending $f to ips.src"
2551 }
elseif {[
string equal $fs_type "Constrs"]} {
2554 dict lappend consets $dict_fs "sources.con"
2556 dict lappend constraints "sources.con" $f
2560 dict lappend srcsets $dict_fs "others.src"
2562 dict lappend libraries "others.src" $f
2563 Msg Debug "Appending $f to others.src"
2566 if {[
lindex [get_property -quiet used_in_synthesis [
GetFile $f $fs]] 0] == 0} {
2567 dict lappend properties $f "nosynth"
2569 if {[
lindex [get_property -quiet used_in_implementation [
GetFile $f $fs]] 0] == 0} {
2570 dict lappend properties $f "noimpl"
2572 if {[
lindex [get_property -quiet used_in_simulation [
GetFile $f $fs]] 0] == 0} {
2573 dict lappend properties $f "nosim"
2575 if {[
lindex [get_property -quiet IS_MANAGED [
GetFile $f $fs]] 0] == 0 && [
file extension $f] != ".xcix"} {
2576 dict lappend properties $f "locked"
2582 dict lappend properties "Simulator" [get_property target_simulator [current_project]]
2585 set file [open $project_file r]
2586 set in_file_manager 0
2588 while {[
gets $file line] >= 0} {
2590 if {[regexp {^KEY ActiveRoot \"([^\"]+)\"} $line -> value]} {
2591 set top [
string range $value 0 [
expr {[string first "::" $value] - 1}]]
2595 if {[regexp {^LIST FileManager} $line]} {
2596 set in_file_manager 1
2601 if {$in_file_manager && [regexp {^ENDLIST} $line]} {
2606 if {$in_file_manager && [regexp {^VALUE \"([^\"]+)} $line -> value]} {
2609 lassign [
split $value ,] file_path file_type
2612 set library "others"
2613 while {[
gets $file line] >= 0} {
2614 if {$line == "ENDFILE"} {
2617 regexp {^LIBRARY=\"([^\"]+)} $line -> library
2618 regexp {^PARENT=\"([^\"]+)} $line -> parent_file
2620 Msg Debug "Found file ${file_path} in project.."
2621 if {$parent_file == ""} {
2622 if {$file_type == "hdl"} {
2624 if {[
IsInList "${library}.src" [
DictGet $srcsets "sources_1"]] == 0} {
2625 dict lappend srcsets "sources_1" "${library}.src"
2627 dict lappend libraries "${library}.src" $file_path
2631 if {[
GetModuleName $file_path] == [
string tolower $top] && $top != ""} {
2632 Msg Debug "Found top module $top in $file_path"
2633 dict lappend properties $file_path "top=$top"
2635 }
elseif {$file_type == "tb_hdl"} {
2637 dict lappend simsets "sim_1" "${library}.sim"
2639 dict lappend simlibraries "${library}.sim" $file_path
2640 }
elseif {$file_type == "io_pdc" || $file_type == "sdc"} {
2642 dict lappend consets "constrs_1" "sources.con"
2644 dict lappend constraints "sources.con" $file_path
2651 set fileData [read [open $project_file]]
2653 set project_path [
file dirname $project_file]
2656 regsub {<\?xml.*\?>} $fileData "" fileData
2659 regexp {<Implementation.*?>(.*)</Implementation>} $fileData -> implementationContent
2663 set sourceRegex {<Source name="([^"]*?)" type="([^"]*?)" type_short="([^"]*?)".*?>(.*?)</Source>}
2665 set optionsRegex {<Options(.*?)\/>}
2666 regexp $optionsRegex $implementationContent -> prj_options
2667 foreach option $prj_options {
2668 if {[regexp {^top=\"([^\"]+)\"} $option match result]} {
2673 while {[regexp $sourceRegex $implementationContent match name type type_short optionsContent]} {
2674 Msg Debug "Found file ${name} in project..."
2675 set file_path [
file normalize $project_path/$name]
2677 set optionsRegex {<Options(.*?)\/>}
2678 regexp $optionsRegex $optionsContent -> options
2679 set library "others"
2681 foreach option $options {
2682 if {[
string first "System Verilog" $option]} {
2685 if {[regexp {^lib=\"([^\"]+)\"} $option match1 result]} {
2690 if {[regexp {syn_sim="([^"]*?)"} $match match_sim simonly]} {
2695 if {$type_short == "VHDL" || $type_short == "Verilog" || $type_short == "IPX"} {
2696 if {$ext == ".src"} {
2697 if {[
IsInList "${library}${ext}" [
DictGet $srcsets "sources_1"]] == 0} {
2698 dict lappend srcsets "sources_1" "${library}${ext}"
2700 dict lappend libraries "${library}${ext}" $file_path
2701 }
elseif {$ext == ".sim"} {
2703 dict lappend simsets "sim_1" "${library}.sim"
2705 dict lappend simlibraries "${library}.sim" $file_path
2711 Msg Debug "Found top module $top in $file_path"
2712 dict lappend properties $file_path "top=$top"
2714 }
elseif {$type_short == "SDC"} {
2716 dict lappend consets "constrs_1" "sources.con"
2718 dict lappend constraints "sources.con" $file_path
2722 regsub -- $match $implementationContent "" implementationContent
2725 return [list $libraries $properties $simlibraries $constraints $srcsets $simsets $consets]
2732 proc GetProjectFlavour {proj_name} {
2734 set flavour [
string map {. ""} [
file extension $proj_name]]
2735 if {$flavour != ""} {
2736 if {[
string is integer $flavour]} {
2737 Msg Info "Project $proj_name has flavour = $flavour, the generic variable FLAVOUR will be set to $flavour"
2739 Msg Warning "Project name has a unexpected non numeric extension, flavour will be set to -1"
2756 proc GetProjectVersion {proj_dir repo_path {ext_path ""} {sim 0}} {
2757 if {![
file exists $proj_dir]} {
2758 Msg CriticalWarning "$proj_dir not found"
2768 Msg Warning "Repository is not clean"
2776 Msg Debug "Project version $v_proj, latest tag $v_last"
2778 Msg Info "The specified project was modified since official version."
2785 Msg Info "The specified project was modified in the latest official version $ret"
2786 }
elseif {$comp == -1} {
2787 Msg Info "The specified project was modified in a past official version $ret"
2803 proc GetRepoVersions {proj_dir repo_path {ext_path ""} {sim 0}} {
2804 if {[
catch {
package require cmdline} ERROR]} {
2805 puts "$ERROR\n If you are running this script on tclsh, you can fix this by installing 'tcllib'"
2820 lappend SHAs [
GetSHA {Hog}]
2824 if {[
Git {status --untracked-files=no --porcelain}] eq ""} {
2825 Msg Info "Hog submodule [
pwd] clean."
2826 lassign [
GetVer ./] hog_ver hog_hash
2828 Msg CriticalWarning "Hog submodule [
pwd] not clean, commit hash will be set to 0."
2829 set hog_hash "0000000"
2830 set hog_ver "00000000"
2835 if {[
Git {status --untracked-files=no --porcelain}] eq ""} {
2836 Msg Info "Git working directory [
pwd] clean."
2839 Msg CriticalWarning "Git working directory [
pwd] not clean, commit hash, and version will be set to 0."
2844 lassign [
GetVer [
join $conf_files]] top_ver top_hash
2845 lappend SHAs $top_hash
2846 lappend versions $top_ver
2853 lassign [
GetHogFiles -list_files "*.src" -sha_mode "./list/" $repo_path] src_files dummy
2854 dict for {f files} $src_files {
2855 # library names have a .src extension in values returned by GetHogFiles
2856 set name [file rootname [file tail $f]]
2857 if {[file ext $f] == ".oth"} {
2860 lassign [GetVer $files] ver hash
2861 # Msg Info "Found source list file $f, version: $ver commit SHA: $hash"
2863 lappend versions $ver
2865 lappend hashes $hash
2872 lassign [
GetHogFiles -list_files "*.con" -sha_mode "./list/" $repo_path] cons_files dummy
2873 dict for {f files} $cons_files {
2874 #library names have a .con extension in values returned by GetHogFiles
2875 set name [file rootname [file tail $f]]
2876 lassign [GetVer $files] ver hash
2877 #Msg Info "Found constraint list file $f, version: $ver commit SHA: $hash"
2879 Msg CriticalWarning "Constraints file $f not found in Git."
2881 lappend cons_hashes $hash
2883 lappend versions $ver
2890 lassign [
GetHogFiles -list_files "*.sim" -sha_mode "./list/" $repo_path] sim_files dummy
2891 dict for {f files} $sim_files {
2892 #library names have a .sim extension in values returned by GetHogFiles
2893 set name [file rootname [file tail $f]]
2894 lassign [GetVer $files] ver hash
2895 #Msg Info "Found simulation list file $f, version: $ver commit SHA: $hash"
2896 lappend sim_hashes $hash
2898 lappend versions $ver
2904 if {"{}" eq $cons_hashes} {
2906 Msg CriticalWarning "No hashes found for constraints files (not in git)"
2909 set cons_hash [
string tolower [
Git "log --format=%h -1 $cons_hashes"]]
2916 set ext_files [glob -nocomplain "./list/*.ext"]
2919 foreach f $ext_files {
2920 set name [
file rootname [
file tail $f]]
2923 lappend ext_names $name
2924 lappend ext_hashes $hash
2927 lappend versions $ext_ver
2930 set file_data [read $fp]
2932 set data [
split $file_data "\n"]
2934 foreach line $data {
2935 if {![regexp {^ *$} $line] & ![regexp {^ *\#} $line]} {
2937 set file_and_prop [regexp -all -inline {\S+} $line]
2938 set hdlfile [
lindex $file_and_prop 0]
2939 set hdlfile $ext_path/$hdlfile
2940 if {[
file exists $hdlfile]} {
2941 set hash [
lindex $file_and_prop 1]
2942 set current_hash [
Md5Sum $hdlfile]
2943 if {[
string first $hash $current_hash] == -1} {
2944 Msg CriticalWarning "File $hdlfile has a wrong hash. Current checksum: $current_hash, expected: $hash"
2952 if {[
llength [glob -nocomplain ./list/*.ipb]] > 0} {
2954 lassign [
GetHogFiles -list_files "*.ipb" -sha_mode "./list/" $repo_path] xml_files dummy
2955 lassign [
GetVer [dict get $xml_files "xml.ipb"]] xml_ver xml_hash
2956 lappend SHAs $xml_hash
2957 lappend versions $xml_ver
2961 Msg Info "This project does not use IPbus XMLs"
2966 set user_ip_repos ""
2967 set user_ip_repo_hashes ""
2968 set user_ip_repo_vers ""
2970 if {[
file exists [
lindex $conf_files 0]]} {
2971 set PROPERTIES [
ReadConf [
lindex $conf_files 0]]
2972 if {[dict exists $PROPERTIES main]} {
2973 set main [dict get $PROPERTIES main]
2974 dict for {p v} $main {
2975 if {[string tolower $p] == "ip_repo_paths"} {
2977 if {[file isdirectory "$repo_path/$repo"]} {
2978 set repo_file_list [glob -nocomplain "$repo_path/$repo/*"]
2979 if {[llength $repo_file_list] == 0} {
2980 Msg Warning "IP_REPO_PATHS property set to $repo in hog.conf but directory is empty."
2982 lappend user_ip_repos "$repo_path/$repo"
2991 foreach repo $user_ip_repos {
2992 if {[
file isdirectory $repo]} {
2993 set repo_file_list [glob -nocomplain "$repo/*"]
2994 if {[
llength $repo_file_list] != 0} {
2995 lassign [
GetVer $repo] ver sha
2996 lappend user_ip_repo_hashes $sha
2997 lappend user_ip_repo_vers $ver
2998 lappend versions $ver
3000 Msg Warning "IP_REPO_PATHS property set to $repo in hog.conf but directory is empty."
3003 Msg Warning "IP_REPO_PATHS property set to $repo in hog.conf but directory does not exist."
3012 while {$found == 0} {
3013 set global_commit [
Git "log --format=%h -1 --abbrev=7 $SHAs"]
3018 if {$common_child == 0} {
3019 Msg CriticalWarning "The commit $sha is not an ancestor of the global commit $global_commit, which is OK. \
3020 But $sha and $global_commit do not have any common child, which is NOT OK. \
3021 This is probably do to a REBASE that is forbidden in Hog methodology as it changes git history. \
3022 Hog cannot guarantee the accuracy of the SHAs. \
3023 A way to fix this is to make a commit that touches all the projects in the repositories (e.g. change the Hog version), \
3024 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 \
3046 $hog_hash $hog_ver $top_hash $top_ver \
3047 $libs $hashes $vers $cons_ver $cons_hash \
3048 $ext_names $ext_hashes $xml_hash $xml_ver \
3049 $user_ip_repos $user_ip_repo_hashes $user_ip_repo_vers]
3058 proc GetSHA {{path ""}} {
3060 lassign [
GitRet {log --format=%h --abbrev=7 -1}] status result
3062 return [
string tolower $result]
3064 Msg Error "Something went wrong while finding the latest SHA. Does the repository have a commit?"
3070 set repo_path [
lindex [
Git {rev-parse --show-toplevel}] 0]
3074 set file_in_module 0
3075 if {[
file exists $repo_path/.gitmodules]} {
3076 lassign [
GitRet "config --file $repo_path/.gitmodules --get-regexp path"] status result
3078 set submodules [
split $result "\n"]
3081 Msg Warning "Something went wrong while trying to find submodules: $result"
3084 foreach mod $submodules {
3085 set module [
lindex $mod 1]
3086 if {[
string first "$repo_path/$module" $f] == 0} {
3088 set file_in_module 1
3089 lappend paths "$repo_path/$module"
3094 if {$file_in_module == 0} {
3100 lassign [
GitRet {log --format=%h --abbrev=7 -1} $paths] status result
3102 return [
string tolower $result]
3104 Msg Error "Something went wrong while finding the latest SHA. Does the repository have a commit?"
3107 return [
string tolower $result]
3111 proc GetSimulators {} {
3112 set SIMULATORS [list "modelsim" "questa" "riviera" "activehdl" "ies" "vcs"]
3117 proc GetTopFile {} {
3119 set compile_order_prop [get_property source_mgmt_mode [current_project]]
3120 if {$compile_order_prop ne "All"} {
3121 Msg CriticalWarning "Compile order is not set to automatic, setting it now..."
3122 set_property source_mgmt_mode All [current_project]
3123 update_compile_order -fileset sources_1
3125 return [
lindex [get_files -quiet -compile_order sources -used_in synthesis -filter {FILE_TYPE =~ "VHDL*" || FILE_TYPE =~ "*Verilog*" }] end]
3126 }
elseif {[
IsISE]} {
3127 debug::design_graph_mgr -create [current_fileset]
3128 debug::design_graph -add_fileset [current_fileset]
3129 debug::design_graph -update_all
3130 return [
lindex [debug::design_graph -get_compile_order] end]
3132 Msg Error "GetTopFile not yet implemented for this IDE"
3137 proc GetTopModule {} {
3139 return [get_property top [current_fileset]]
3141 Msg Error "GetTopModule not yet implemented for this IDE"
3151 proc GetVer {path {force_develop 0}} {
3155 Msg CriticalWarning "Empty SHA found for ${path}. Commit to Git to resolve this warning."
3158 set p [
lindex $path 0]
3159 if {[
file isdirectory $p]} {
3162 cd [
file dirname $p]
3164 set repo_path [
Git {rev-parse --show-toplevel}]
3167 return [list [
GetVerFromSHA $SHA $repo_path $force_develop] $SHA]
3178 proc GetVerFromSHA {SHA repo_path {force_develop 0}} {
3180 Msg CriticalWarning "Empty SHA found"
3183 lassign [
GitRet "tag --sort=creatordate --contain $SHA -l v*.*.* -l b*v*.*.*"] status result
3186 if {[regexp {^ *$} $result]} {
3188 lassign [
GitRet "log --oneline --pretty=\"%d\""] status2 tag_list
3191 set pattern {tag: v\d+\.\d+\.\d+}
3192 set real_tag_list {}
3193 foreach x $tag_list {
3194 set x_untrimmed [regexp -all -inline $pattern $x]
3195 regsub "tag: " $x_untrimmed "" x_trimmed
3196 set tt [
lindex $x_trimmed 0]
3197 if {![
string equal $tt ""]} {
3198 lappend real_tag_list $tt
3202 Msg Debug "Cleaned up list: $real_tag_list."
3204 set sorted_tags [lsort -decreasing -command CompareVersions $real_tag_list]
3206 Msg Debug "Sorted Tag list: $sorted_tags"
3208 set tag [
lindex $sorted_tags 0]
3211 set pattern {v\d+\.\d+\.\d+}
3212 if {![regexp $pattern $tag]} {
3213 Msg CriticalWarning "No Hog version tags found in this repository."
3218 set repo_conf $repo_path/Top/repo.conf
3222 set hotfix_prefix "hotfix/"
3223 set minor_prefix "minor_version/"
3224 set major_prefix "major_version/"
3226 set enable_develop_branch $force_develop
3228 set branch_name [
Git {rev-parse --abbrev-ref HEAD}]
3230 if {[
file exists $repo_conf]} {
3231 set PROPERTIES [
ReadConf $repo_conf]
3233 if {[dict exists $PROPERTIES main]} {
3234 set mainDict [dict get $PROPERTIES main]
3237 if {[dict exists $mainDict ENABLE_DEVELOP_BRANCH]} {
3238 set enable_develop_branch [dict get $mainDict ENABLE_DEVELOP_BRANCH]
3244 if {[dict exists $PROPERTIES prefixes]} {
3245 set prefixDict [dict get $PROPERTIES prefixes]
3247 if {[dict exists $prefixDict HOTFIX]} {
3248 set hotfix_prefix [dict get $prefixDict HOTFIX]
3250 if {[dict exists $prefixDict MINOR_VERSION]} {
3251 set minor_prefix [dict get $prefixDict MINOR_VERSION]
3253 if {[dict exists $prefixDict MAJOR_VERSION]} {
3254 set major_prefix [dict get $prefixDict MAJOR_VERSION]
3260 if {$enable_develop_branch == 1} {
3261 if {[
string match "$hotfix_prefix*" $branch_name]} {
3266 if {[
string match "$major_prefix*" $branch_name]} {
3268 set version_level major
3269 }
elseif {[
string match "$minor_prefix*" $branch_name] || ($enable_develop_branch == 1 && $is_hotfix == 0)} {
3271 set version_level minor
3274 set version_level patch
3278 Msg CriticalWarning "Tag $tag does not contain a Hog compatible version in this repository."
3281 }
elseif {$mr == 0} {
3282 switch $version_level {
3297 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."
3303 set vers [
split $result "\n"]
3304 set ver [
lindex $vers 0]
3306 if {[regexp {^v.*$} $v]} {
3314 Msg CriticalWarning "Error while trying to find tag for $SHA"
3322 set M [
format %02X $M]
3323 set m [
format %02X $m]
3324 set c [
format %04X $c]
3325 }
elseif {$M > -1} {
3327 set M [
format %02X $M]
3328 set m [
format %02X $m]
3329 set c [
format %04X $c]
3331 Msg Warning "Tag does not contain a properly formatted version: $ver"
3332 set M [
format %02X 0]
3333 set m [
format %02X 0]
3334 set c [
format %04X 0]
3347 proc Git {command {files ""}} {
3348 lassign [
GitRet $command $files] ret result
3350 Msg Error "Code $ret returned by git running: $command -- $files"
3361 proc GetModuleName {filename} {
3363 if {![
file exists $filename]} {
3364 Msg CriticalWarning "Error: File $filename does not exist."
3369 set fileId [open $filename r]
3372 set file_content [read $fileId]
3378 if {[
file extension $filename] == ".vhd" || [
file extension $filename] == ".vhdl"} {
3380 set file_content [
string tolower $file_content]
3382 set pattern {(?m)^\s*entity\s+(\S+)\s+is}
3383 }
elseif {[
file extension $filename] == ".v" || [
file extension $filename] == ".sv"} {
3385 set pattern {\n\s*module\s*(\w+)(\s*|\(|\n)}
3387 Msg Debug "File is neither VHDL nor Verilog... Returning empty string..."
3392 if {[regexp $pattern $file_content match module_name]} {
3395 Msg Debug "No module was found in $filename. Returning an empty string..."
3403 proc GetVerilogGenerics {file} {
3404 set fp [open $file r]
3410 foreach line [
split $data "\n"] {
3411 regsub "^\\s*\/\/.*" $line "" line
3412 regsub "(.*)\/\/.*" $line {\1} line
3413 if {![
string equal $line ""]} {
3414 append lines $line " "
3419 regsub -all {/\*.*\*/} $lines "" lines
3422 set punctuation [list]
3423 foreach char [list "(" ")" ";" "," " " "!" "<=" ":=" "=" "\[" "\]"] {
3424 lappend punctuation $char "\000$char\000"
3428 set tokens [
split [
string map $punctuation $lines] \000]
3430 set parameters [dict create]
3439 foreach token $tokens {
3440 set token [
string trim $token]
3441 if {![
string equal "" $token]} {
3442 if {[
string equal [
string tolower $token] "parameter"]} {
3443 set state $PARAM_NAME
3444 }
elseif {[
string equal $token ")"] || [
string equal $token ";"]} {
3446 }
elseif {$state == $PARAM_WIDTH} {
3447 if {[
string equal $token "\]"]} {
3448 set state $PARAM_NAME
3450 }
elseif {$state == $PARAM_VALUE} {
3451 if {[
string equal $token ","]} {
3452 set state $PARAM_NAME
3453 }
elseif {[
string equal $token ";"]} {
3458 }
elseif {$state == $PARAM_NAME} {
3459 if {[
string equal $token "="]} {
3460 set state $PARAM_VALUE
3461 }
elseif {[
string equal $token "\["]} {
3462 set state $PARAM_WIDTH
3463 }
elseif {[
string equal $token ","]} {
3464 set state $PARAM_NAME
3465 }
elseif {[
string equal $token ";"]} {
3467 }
elseif {[
string equal $token ")"]} {
3470 dict set parameters $token "integer"
3483 proc GetVhdlGenerics {file {entity ""}} {
3484 set fp [open $file r]
3490 foreach line [
split $data "\n"] {
3491 regsub "^\\s*--.*" $line "" line
3492 regsub "(.*)--.*" $line {\1} line
3493 if {![
string equal $line ""]} {
3494 append lines $line " "
3499 set generic_block ""
3500 set generics [dict create]
3502 if {1 == [
string equal $entity ""]} {
3503 regexp {(?i).*entity\s+([^\s]+)\s+is} $lines _ entity
3506 set generics_regexp "(?i).*entity\\s+$entity\\s+is\\s+generic\\s*\\((.*)\\)\\s*;\\s*port.*end.*$entity"
3508 if {[regexp $generics_regexp $lines _ generic_block]} {
3510 foreach line [
split $generic_block ";"] {
3512 regexp {(.*):\s*([A-Za-z0-9_]+).*} $line _ generic type
3515 set splits [
split $generic ","]
3516 foreach split $splits {
3517 dict set generics [
string trim $split] [
string trim $type]
3525 proc GHDL {command logfile} {
3526 set ret [
catch {
exec -ignorestderr ghdl {*}$command >>& $logfile} result options]
3531 return [list $ret $result]
3543 proc GitRet {command {files ""}} {
3546 set ret [
catch {
exec -ignorestderr git {*}$command} result]
3548 set ret [
catch {
exec -ignorestderr git {*}$command -- {*}$files} result]
3550 return [list $ret $result]
3558 proc GitVersion {target_version} {
3559 set ver [
split $target_version "."]
3560 set v [
Git --version]
3562 set current_ver [
split [
lindex $v 2] "."]
3563 set target [
expr {[lindex $ver 0] * 100000 + [lindex $ver 1] * 100 + [lindex $ver 2]}]
3564 set current [
expr {[lindex $current_ver 0] * 100000 + [lindex $current_ver 1] * 100 + [lindex $current_ver 2]}]
3565 return [
expr {$target <= $current}]
3579 proc HandleIP {what_to_do xci_file ip_path repo_path {gen_dir "."} {force 0}} {
3580 if {!($what_to_do eq "push") && !($what_to_do eq "pull")} {
3581 Msg Error "You must specify push or pull as first argument."
3584 if {[
catch {
package require tar} TARPACKAGE]} {
3585 Msg CriticalWarning "Cannot find package tar. You can fix this by installing package \"tcllib\""
3594 if {[
string first "/eos/" $ip_path] == 0} {
3602 lassign [
eos "ls $ip_path"] ret result
3604 Msg CriticalWarning "Could not run ls for for EOS path: $ip_path (error: $result). \
3605 Either the drectory does not exist or there are (temporary) problem with EOS."
3609 Msg Info "IP remote directory path, on EOS, is set to: $ip_path"
3615 if {!([
file exists $xci_file])} {
3616 Msg CriticalWarning "Could not find $xci_file."
3622 set xci_path [
file dirname $xci_file]
3623 set xci_name [
file tail $xci_file]
3624 set xci_ip_name [
file rootname [
file tail $xci_file]]
3625 set xci_dir_name [
file tail $xci_path]
3626 set gen_path $gen_dir
3628 set hash [
Md5Sum $xci_file]
3629 set file_name $xci_name\_$hash
3631 Msg Info "Preparing to $what_to_do IP: $xci_name..."
3633 if {$what_to_do eq "push"} {
3637 lassign [
eos "ls $ip_path/$file_name.tar"] ret result
3642 Msg Info "IP already in the EOS repository, will not copy..."
3644 Msg Info "IP already in the EOS repository, will forcefully replace..."
3650 if {[
file exists "$ip_path/$file_name.tar"]} {
3652 Msg Info "IP already in the local repository, will not copy..."
3654 Msg Info "IP already in the local repository, will forcefully replace..."
3663 if {$will_copy == 1} {
3665 Msg Info "Looking for generated files in $gen_path..."
3666 set ip_gen_files [glob -nocomplain $gen_path/*]
3670 if {[
llength $ip_gen_files] > 0} {
3671 Msg Info "Found some IP synthesised files matching $xci_ip_name"
3672 if {$will_remove == 1} {
3673 Msg Info "Removing old synthesised directory $ip_path/$file_name.tar..."
3675 eos "rm -rf $ip_path/$file_name.tar" 5
3677 file delete -force "$ip_path/$file_name.tar"
3681 Msg Info "Creating local archive with IP generated files..."
3683 foreach f $ip_gen_files {
3684 if {$first_file == 0} {
3685 ::tar::create $file_name.tar "[
Relative [
file normalize $repo_path] $f]"
3688 ::tar::add $file_name.tar "[
Relative [
file normalize $repo_path] $f]"
3692 Msg Info "Copying IP generated files for $xci_name..."
3694 lassign [
ExecuteRet xrdcp -f -s $file_name.tar $::env(EOS_MGM_URL)//$ip_path/] ret msg
3696 Msg CriticalWarning "Something went wrong when copying the IP files to EOS. Error message: $msg"
3699 Copy "$file_name.tar" "$ip_path/"
3701 Msg Info "Removing local archive"
3702 file delete $file_name.tar
3704 Msg Warning "Could not find synthesized files matching $gen_path/$file_name*"
3707 }
elseif {$what_to_do eq "pull"} {
3709 lassign [
eos "ls $ip_path/$file_name.tar"] ret result
3711 Msg Info "Nothing for $xci_name was found in the EOS repository, cannot pull."
3715 set remote_tar "$::env(EOS_MGM_URL)//$ip_path/$file_name.tar"
3716 Msg Info "IP $xci_name found in the repository $remote_tar, copying it locally to $repo_path..."
3718 lassign [
ExecuteRet xrdcp -f -r -s $remote_tar $repo_path] ret msg
3720 Msg CriticalWarning "Something went wrong when copying the IP files to EOS. Error message: $msg"
3724 if {[
file exists "$ip_path/$file_name.tar"]} {
3725 Msg Info "IP $xci_name found in local repository $ip_path/$file_name.tar, copying it locally to $repo_path..."
3726 Copy $ip_path/$file_name.tar $repo_path
3728 Msg Info "Nothing for $xci_name was found in the local IP repository, cannot pull."
3734 if {[
file exists $file_name.tar]} {
3735 remove_files $xci_file
3736 Msg Info "Extracting IP files from archive to $repo_path..."
3737 ::tar::untar $file_name.tar -dir $repo_path -noperms
3738 Msg Info "Removing local archive"
3739 file delete $file_name.tar
3740 add_files -norecurse -fileset sources_1 $xci_file
3753 proc HexVersionToString {version} {
3754 scan [
string range $version 0 1] %x M
3755 scan [
string range $version 2 3] %x m
3756 scan [
string range $version 4 7] %x c
3761 proc ImportTclLib {} {
3763 if {[
info exists env(HOG_TCLLIB_PATH)]} {
3764 lappend auto_path $env(HOG_TCLLIB_PATH)
3767 puts "ERROR: To run Hog with Microsemi Libero SoC or Lattice Diamond, you need to define the HOG_TCLLIB_PATH variable."
3782 proc InitLauncher {script tcl_path parameters commands argv {custom_commands ""}} {
3783 set repo_path [
file normalize "$tcl_path/../.."]
3785 set bin_path [
file normalize "$tcl_path/../../bin"]
3786 set top_path [
file normalize "$tcl_path/../../Top"]
3788 set cmd_lines [
split $commands "\n"]
3790 set command_options [dict create]
3791 set directive_descriptions [dict create]
3792 set directive_names [dict create]
3793 set common_directive_names [dict create]
3795 foreach l $cmd_lines {
3797 if {[regexp {\\(.*) \{\#} $l minc d]} {
3798 lappend directives_with_projects $d
3802 if {[regexp {\\(.*) \{} $l minc regular_expression]} {
3803 lappend directive_regex $regular_expression
3807 if {[regexp {\#\s*NAME(\*)?:\s*(.*)\s*} $l minc star name]} {
3808 dict set directive_names $name $regular_expression
3810 dict set common_directive_names $name $regular_expression
3813 set directive_names [
DictSort $directive_names]
3814 set common_directive_names [
DictSort $common_directive_names]
3817 if {[regexp {\#\s*DESCRIPTION:\s*(.*)\s*} $l minc x]} {
3818 dict set directive_descriptions $regular_expression $x
3822 if {[regexp {\#\s*OPTIONS:\s*(.*)\s*} $l minc x]} {
3823 dict set command_options $regular_expression [
split [regsub -all {[ \t\n]+} $x {}] ","]
3827 set short_usage "usage: ./Hog/Do \[OPTIONS\] <directive> \[project\]\n\nMost common directives (case insensitive):"
3829 dict for {key value} $common_directive_names {
3830 set short_usage "$short_usage\n - $key: [dict get $directive_descriptions $value]"
3833 set short_usage "$short_usage\n\n\
3834 To see all the available directives, run:\n./Hog/Do HELP\n\n\
3835 To list available options for the chosen directive run:\n\
3836 ./Hog/Do <directive> HELP\n
3839 set usage "usage: ./Hog/Do \[OPTIONS\] <directive> \[project\]\n\nDirectives (case insensitive):"
3841 dict for {key value} $directive_names {
3842 set usage "$usage\n - $key: [dict get $directive_descriptions $value]"
3845 set usage "$usage\n$custom_commands"
3847 set usage "$usage\n\nTo list available options for the chosen directive run:\n./Hog/Do <directive> HELP"
3854 if {[
catch {
package require cmdline} ERROR]} {
3855 Msg Debug "The cmdline Tcl package was not found, sourcing it from Hog..."
3856 source $tcl_path/utils/cmdline.tcl
3859 set argv [regsub -all {(?i) HELP\y} $argv " -help"]
3861 lassign [
GetOptions $argv $parameters] option_list arg_list
3863 if {[
IsInList "-all" $option_list]} {
3872 set directive [
string toupper [
lindex $arg_list 0]]
3875 set argument_is_no_project 0
3877 switch -regexp -- $directive "$commands"
3880 if {$directive != ""} {
3881 if {[
IsInList $directive $directives_with_projects 1]} {
3882 puts "usage: ./Hog/Do \[OPTIONS\] $directive <project>\n"
3883 }
elseif {[regexp "^COMPSIM(LIB)?$" $directive]} {
3884 puts "usage: ./Hog/Do \[OPTIONS\] $directive <simulator>\n"
3886 puts "usage: ./Hog/Do \[OPTIONS\] $directive \n"
3889 dict for {dir desc} $directive_descriptions {
3890 if {[regexp $dir $directive]} {
3896 dict for {dir opts} $command_options {
3897 if {[regexp $dir $directive]} {
3898 puts "Available options:"
3900 foreach par $parameters {
3901 if {$opt == [lindex $par 0]} {
3902 if {[regexp {\.arg$} $opt]} {
3903 set opt_name [regsub {\.arg$} $opt ""]
3904 puts " -$opt_name <argument>"
3908 puts " [lindex $par [llength $par]-1]"
3922 if {[
catch {
array set options [
cmdline::getoptions option_list $parameters $usage]} err]} {
3923 Msg Status "\nERROR: Syntax error, probably unknown option.\n\n USAGE: $err"
3927 if {[
llength $arg_list] <= $min_n_of_args || [
llength $arg_list] > $max_n_of_args} {
3928 Msg Status "\nERROR: Wrong number of arguments: [
llength $argv]"
3933 set project [
lindex $arg_list 1]
3935 if {$argument_is_no_project == 0} {
3937 regsub "^(\./)?Top/" $project "" project
3939 regsub "/? *\$" $project "" project
3945 Msg Debug "Option list:"
3946 foreach {key value} [
array get options] {
3947 Msg Debug "$key => $value"
3954 if {$proj_conf != 0} {
3957 lassign [
GetIDECommand $proj_conf] cmd before_tcl_script after_tcl_script end_marker
3958 Msg Info "Project $project uses $cmd IDE"
3961 set command "$cmd $before_tcl_script$script$after_tcl_script$argv$end_marker"
3963 if {$argument_is_no_project == 1} {
3965 Msg Debug "$project will be used as first argument"
3966 }
elseif {$project != ""} {
3969 }
elseif {$min_n_of_args < 0} {
3982 set project_group [
file dirname $project]
3983 set project [
file tail $project]
3984 if {$project_group != "."} {
3985 set project_name "$project_group/$project"
3987 set project_name "$project"
3990 return [list $directive $project $project_name $project_group $repo_path $old_path $bin_path $top_path $usage $short_usage $command $cmd [
array get options]]
3997 proc IsCommitAncestor {ancestor commit} {
3998 lassign [
GitRet "merge-base --is-ancestor $ancestor $commit"] status result
4007 return [
expr {[info commands sys_install] != ""}]
4012 return [
expr {[info commands get_libero_version] != ""}]
4020 proc IsInList {element list {regex 0}} {
4022 if {$regex == 1 && [regexp $x $element]} {
4024 }
elseif {$regex == 0 && $x eq $element} {
4035 return [
expr {[string first PlanAhead [version]] == 0}]
4043 if {[
catch {
package require ::quartus::flow} result]} {
4056 proc IsRelativePath {path} {
4057 if {[
string index $path 0] == "/" || [
string index $path 0] == "~"} {
4065 proc IsSynplify {} {
4066 return [
expr {[info commands program_version] != ""}]
4071 return [
expr {![IsQuartus] && ![IsXilinx] && ![IsLibero] && ![IsSynplify] && ![IsDiamond]}]
4079 proc IsVersal {part} {
4080 if {[get_property ARCHITECTURE [get_parts $part]] eq "versal"} {
4090 return [
expr {[string first Vivado [version]] == 0}]
4098 if {[
info commands version] != ""} {
4099 set current_version [version]
4100 if {[
string first PlanAhead $current_version] == 0 || [
string first Vivado $current_version] == 0} {
4103 Msg Warning "This IDE has the version command but it is not PlanAhead or Vivado: $current_version"
4116 proc IsZynq {part} {
4117 if {[regexp {^(xc7z|xczu).*} $part]} {
4124 proc ImportGHDL {project_name repo_path simset_name simset_dict {ext_path ""}} {
4125 set list_path "$repo_path/Top/$project_name/list"
4126 lassign [
GetHogFiles -list_files {.src,.ext,.sim} -ext_path $ext_path $list_path $repo_path] src_files properties filesets
4131 set properties [
DictGet $simset_dict "properties"]
4132 set options [
DictGet $properties "options"]
4135 set workdir Projects/$project_name/ghdl
4136 file delete -force $workdir
4138 set import_log "$workdir/ghdl-import-${simset_name}.log"
4139 dict for {lib sources} $src_files {
4140 set libname [file rootname $lib]
4141 foreach f $sources {
4142 if {[file extension $f] != ".vhd" && [file extension $f] != ".vhdl"} {
4143 Msg Info "File $f is not a VHDL file, copying it in workfolder..."
4144 file copy -force $f $workdir
4146 set file_path [Relative $repo_path $f]
4147 set import_log_file [open $import_log "a"]
4148 puts "ghdl -i --work=$libname --workdir=$workdir -fsynopsys --ieee=standard $options $file_path"
4149 puts $import_log_file "ghdl -i --work=$libname --workdir=$workdir -fsynopsys --ieee=standard $options $file_path"
4150 close $import_log_file
4151 lassign [GHDL "-i --work=$libname --workdir=$workdir -fsynopsys --ieee=standard $options $file_path" $import_log] ret result
4153 Msg CriticalWarning "GHDL import failed for file $f: $result"
4162 proc LaunchGHDL {project_name repo_path simset_name simset_dict {ext_path ""}} {
4165 set sim_props [
DictGet $simset_dict "properties"]
4166 set options [
DictGet $sim_props "options"]
4167 set runopts [
DictGet $sim_props "run_options"]
4169 dict for {prop_name prop_val} $sim_props {
4170 set prop_name [string toupper $prop_name]
4171 if {$prop_name == "TOP"} {
4172 set top_sim $prop_val
4175 set workdir $repo_path/Projects/$project_name/ghdl
4176 set make_log "$workdir/ghdl-make-${simset_name}.log"
4177 set run_log "$workdir/ghdl-run-${simset_name}.log"
4180 set make_log_file [open $make_log "w"]
4182 puts "ghdl -m --work=$simset_name -fsynopsys --ieee=standard $options $top_sim"
4183 puts $make_log_file "ghdl -m --work=$simset_name -fsynopsys --ieee=standard $options $top_sim"
4184 close $make_log_file
4186 lassign [
GHDL "-m --work=$simset_name -fsynopsys --ieee=standard $options $top_sim" $make_log] ret result
4189 Msg Error "GHDL make failed for $top_sim: $result"
4193 set run_log_file [open $run_log "w"]
4194 puts "ghdl -r --work=$simset_name -fsynopsys --ieee=standard $options $top_sim $runopts"
4195 puts $run_log_file "ghdl -r --work=$simset_name -fsynopsys --ieee=standard $options $top_sim $runopts"
4198 lassign [
GHDL "-r --work=$simset_name -fsynopsys --ieee=standard $options $top_sim $runopts" $run_log] ret result
4202 Msg Error "GHDL run failed for $top_sim: $result"
4217 proc LaunchImplementation {reset do_create run_folder project_name {repo_path .} {njobs 4} {do_bitstream 0}} {
4218 Msg Info "Starting implementation flow..."
4220 if {$reset == 1 && $do_create == 0} {
4221 Msg Info "Resetting run before launching implementation..."
4226 source $repo_path/Hog/Tcl/integrated/pre-implementation.tcl
4229 if {$do_bitstream == 1} {
4230 launch_runs impl_1 -to_step [
BinaryStepName [get_property PART [current_project]]] -jobs $njobs -dir $run_folder
4232 launch_runs impl_1 -jobs $njobs -dir $run_folder
4237 Msg Info "running post-implementation"
4238 source $repo_path/Hog/Tcl/integrated/post-implementation.tcl
4239 if {$do_bitstream == 1} {
4240 Msg Info "running pre-bitstream"
4241 source $repo_path/Hog/Tcl/integrated/pre-bitstream.tcl
4242 Msg Info "running post-bitstream"
4243 source $repo_path/Hog/Tcl/integrated/post-bitstream.tcl
4247 set prog [get_property PROGRESS [get_runs impl_1]]
4248 set status [get_property STATUS [get_runs impl_1]]
4249 Msg Info "Run: impl_1 progress: $prog, status : $status"
4253 set status_file [open "$run_folder/timing.txt" "w"]
4254 puts $status_file "## $project_name Timing summary"
4256 set f [open [
lindex [glob "$run_folder/impl_1/*.twr" 0]]]
4258 while {[
gets $f line] >= 0} {
4259 if {[
string match "Timing summary:" $line]} {
4260 while {[
gets $f line] >= 0} {
4261 if {[
string match "Timing errors:*" $line]} {
4262 set errs [regexp -inline -- {[0-9]+} $line]
4264 if {[
string match "*Footnotes*" $line]} {
4267 puts $status_file "$line"
4276 Msg Info "Time requirements are met"
4277 file rename -force "$run_folder/timing.txt" "$run_folder/timing_ok.txt"
4280 Msg CriticalWarning "Time requirements are NOT met"
4281 file rename -force "$run_folder/timing.txt" "$run_folder/timing_error.txt"
4287 set wns [get_property STATS.WNS [get_runs [current_run]]]
4288 set tns [get_property STATS.TNS [get_runs [current_run]]]
4289 set whs [get_property STATS.WHS [get_runs [current_run]]]
4290 set ths [get_property STATS.THS [get_runs [current_run]]]
4291 set tpws [get_property STATS.TPWS [get_runs [current_run]]]
4293 if {$wns >= 0 && $whs >= 0 && $tpws >= 0} {
4294 Msg Info "Time requirements are met"
4295 set status_file [open "$run_folder/timing_ok.txt" "w"]
4298 Msg CriticalWarning "Time requirements are NOT met"
4299 set status_file [open "$run_folder/timing_error.txt" "w"]
4303 Msg Status "*** Timing summary ***"
4304 Msg Status "WNS: $wns"
4305 Msg Status "TNS: $tns"
4306 Msg Status "WHS: $whs"
4307 Msg Status "THS: $ths"
4308 Msg Status "TPWS: $tpws"
4314 puts $status_file "## $project_name Timing summary"
4316 m add row "| **Parameter** | \"**value (ns)**\" |"
4317 m add row "| --- | --- |"
4318 m add row "| WNS: | $wns |"
4319 m add row "| TNS: | $tns |"
4320 m add row "| WHS: | $whs |"
4321 m add row "| THS: | $ths |"
4322 m add row "| TPWS: | $tpws |"
4324 puts $status_file [m format 2string]
4325 puts $status_file "\n"
4326 if {$timing_ok == 1} {
4327 puts $status_file " Time requirements are met."
4329 puts $status_file "Time requirements are **NOT** met."
4331 puts $status_file "\n\n"
4335 if {$prog ne "100%"} {
4336 Msg Error "Implementation error"
4341 lassign [
GetRepoVersions [
file normalize ./Top/$project_name] $repo_path] sha
4343 Msg Info "Git describe set to $describe"
4345 set dst_dir [
file normalize "$repo_path/bin/$project_name\-$describe"]
4350 if {[
file exists $run_folder/versions.txt]} {
4351 file copy -force $run_folder/versions.txt $dst_dir
4353 Msg Warning "No versions file found in $run_folder/versions.txt"
4356 set timing_files [glob -nocomplain "$run_folder/timing_*.txt"]
4357 set timing_file [
file normalize [
lindex $timing_files 0]]
4359 if {[
file exists $timing_file]} {
4360 file copy -force $timing_file $dst_dir/
4362 Msg Warning "No timing file found, not a problem if running locally"
4366 if {[
IsVersal [get_property part [current_project]]]} {
4367 if {[get_property segmented_configuration [current_project]] == 1} {
4368 Msg Info "Versal Segmented configuration detected: exporting XSA file..."
4369 set xsa_name "$dst_dir/[
file tail $project_name]\-$describe.xsa"
4370 write_hw_platform -fixed -force -file $xsa_name
4374 set revision [get_current_revision]
4376 if {[
catch {execute_module -tool fit} result]} {
4377 Msg Error "Result: $result\n"
4378 Msg Error "Place & Route failed. See the report file.\n"
4380 Msg Info "\nINFO: Place & Route was successful for revision $revision.\n"
4383 if {[
catch {execute_module -tool sta -args "--do_report_timing"} result]} {
4384 Msg Error "Result: $result\n"
4385 Msg Error "Time Quest failed. See the report file.\n"
4387 Msg Info "Time Quest was successfully run for revision $revision.\n"
4390 set panel "Timing Analyzer||Timing Analyzer Summary"
4391 set device [get_report_panel_data -name $panel -col 1 -row_name "Device Name"]
4392 set timing_model [get_report_panel_data -name $panel -col 1 -row_name "Timing Models"]
4393 set delay_model [get_report_panel_data -name $panel -col 1 -row_name "Delay Model"]
4395 Msg Info "*******************************************************************"
4396 Msg Info "Device: $device"
4397 Msg Info "Timing Models: $timing_model"
4398 Msg Info "Delay Model: $delay_model"
4401 Msg Info "*******************************************************************"
4404 Msg Info "Starting implementation flow..."
4405 if {[
catch {run_tool -name {PLACEROUTE}}]} {
4406 Msg Error "PLACEROUTE FAILED!"
4408 Msg Info "PLACEROUTE PASSED."
4412 Msg Info "Run VERIFYTIMING ..."
4413 if {[
catch {run_tool -name {VERIFYTIMING} -script {Hog/Tcl/integrated/libero_timing.tcl}}]} {
4414 Msg CriticalWarning "VERIFYTIMING FAILED!"
4416 Msg Info "VERIFYTIMING PASSED \n"
4422 lassign [
GetRepoVersions [
file normalize ./Top/$project_name] $repo_path] sha
4424 Msg Info "Git describe set to $describe"
4426 set dst_dir [
file normalize "$repo_path/bin/$project_name\-$describe"]
4427 file mkdir $dst_dir/reports
4430 if {[
file exists $run_folder/versions.txt]} {
4431 file copy -force $run_folder/versions.txt $dst_dir
4433 Msg Warning "No versions file found in $run_folder/versions.txt"
4436 set timing_file_path [
file normalize "$repo_path/Projects/timing_libero.txt"]
4437 if {[
file exists $timing_file_path]} {
4438 file copy -force $timing_file_path $dst_dir/reports/Timing.txt
4439 set timing_file [open $timing_file_path "r"]
4440 set status_file [open "$dst_dir/timing.txt" "w"]
4441 puts $status_file "## $project_name Timing summary\n\n"
4442 puts $status_file "| | |"
4443 puts $status_file "| --- | --- |"
4444 while {[
gets $timing_file line] >= 0} {
4445 if {[
string match "SUMMARY" $line]} {
4446 while {[
gets $timing_file line] >= 0} {
4447 if {[
string match "END SUMMARY" $line]} {
4450 if {[
string first ":" $line] == -1} {
4453 set out_string "| [
string map {: | } $line] |"
4454 puts $status_file "$out_string"
4459 Msg Warning "No timing file found, not a problem if running locally"
4464 set force_rst "-forceOne"
4466 prj_run Map $force_rst
4467 prj_run PAR $force_rst
4480 proc LaunchSimulation {project_name lib_path simsets {repo_path .}} {
4483 set project [
file tail $project_name]
4484 set main_sim_folder [
file normalize "$repo_path/Projects/$project_name/$project.sim/"]
4486 if {$simsets != ""} {
4487 dict for {simset sim_dict} $simsets {
4488 lappend simsets_todo $simset
4490 Msg Info "Will run only the following simulation's sets (if they exist): $simsets_todo"
4495 set sim_dic [dict create]
4497 Msg Info "Retrieving list of simulation sets..."
4498 foreach s [get_filesets] {
4500 set use_simpass_str 0
4503 set type [get_property FILESET_TYPE $s]
4504 if {$type eq "SimulationSrcs"} {
4505 if {$simsets_todo != "" && $s ni $simsets_todo} {
4506 Msg Info "Skipping $s as it was not specified with the -simset option..."
4509 set sim_dict [
DictGet $simsets $s]
4510 set simulator [
DictGet $sim_dict "simulator"]
4511 set_property "target_simulator" $simulator [current_project]
4512 set hog_sim_props [
DictGet $sim_dict "hog"]
4513 dict for {prop_name prop_val} $hog_sim_props {
4514 # If HOG_SIMPASS_STR is set, use the HOG_SIMPASS_STR string to search for in logs, after simulation is done
4515 if {[string toupper $prop_name] == "HOG_SIMPASS_STR" && $prop_val != ""} {
4516 Msg Info "Setting simulation pass string as '$prop_val'"
4517 set use_simpass_str 1
4518 set simpass_str $prop_val
4520 if {[string toupper $prop_name] == "HOG_SILENT_SIM" && $prop_val == 1} {
4521 set quiet_sim " -quiet"
4527 Msg Info "Creating simulation scripts for $s..."
4528 if {[
file exists $repo_path/Top/$project_name/pre-simulation.tcl]} {
4529 Msg Info "Running $repo_path/Top/$project_name/pre-simulation.tcl"
4530 source $repo_path/Top/$project_name/pre-simulation.tcl
4532 if {[
file exists $repo_path/Top/$project_name/pre-$s-simulation.tcl]} {
4533 Msg Info "Running $repo_path/Top/$project_name/pre-$s-simulation.tcl"
4534 source Running $repo_path/Top/$project_name/pre-$s-simulation.tcl
4536 current_fileset -simset $s
4537 set sim_dir $main_sim_folder/$s/behav
4538 set sim_output_logfile $sim_dir/xsim/simulate.log
4539 if {([
string tolower $simulator] eq "xsim")} {
4540 set sim_name "xsim:$s"
4542 set simulation_command "launch_simulation $quiet_sim -simset [get_filesets $s]"
4543 if {[
catch $simulation_command log]} {
4546 Msg CriticalWarning "Simulation failed for $s, error info: $::errorInfo"
4547 lappend failed $sim_name
4552 if {$use_simpass_str == 1} {
4555 set file_desc [open $sim_output_logfile r]
4556 set log [read $file_desc]
4559 Msg Info "Searching for simulation pass string: '$simpass_str'"
4560 if {[
string first $simpass_str $log] == -1} {
4561 Msg CriticalWarning "Simulation failed for $s, error info: '$simpass_str' NOT found!"
4562 lappend failed $sim_name
4565 lappend success $sim_name
4569 lappend success $sim_name
4573 Msg Info "Simulation library path is set to $lib_path."
4575 if {!([
file exists $lib_path])} {
4576 Msg Warning "Could not find simulation library path: $lib_path, $simulator simulation will not work."
4580 if {$simlib_ok == 1} {
4581 set_property "compxlib.${simulator}_compiled_library_dir" [
file normalize $lib_path] [current_project]
4582 launch_simulation -scripts_only -simset [get_filesets $s]
4583 set top_name [get_property TOP $s]
4584 set sim_script [
file normalize $sim_dir/$simulator/]
4585 Msg Info "Adding simulation script location $sim_script for $s..."
4586 lappend sim_scripts $sim_script
4587 dict append sim_dic $sim_script $s
4589 Msg Error "Cannot run $simulator simulations without a valid library path"
4596 if {[
info exists sim_scripts]} {
4598 Msg Info "Generating IP simulation targets, if any..."
4600 foreach ip [get_ips] {
4601 generate_target simulation -quiet $ip
4606 Msg Info "====== Starting simulations runs ======"
4609 foreach s $sim_scripts {
4611 set cmd ./compile.sh
4612 Msg Info " ************* Compiling: $s ************* "
4614 set sim_name "comp:[dict get $sim_dic $s]"
4616 Msg CriticalWarning "Compilation failed for $s, error info: $::errorInfo"
4617 lappend failed $sim_name
4619 lappend success $sim_name
4621 Msg Info "###################### Compilation log starts ######################"
4622 Msg Info "\n\n$log\n\n"
4623 Msg Info "###################### Compilation log ends ######################"
4626 if {[
file exists "./elaborate.sh"]} {
4627 set cmd ./elaborate.sh
4628 Msg Info " ************* Elaborating: $s ************* "
4630 set sim_name "elab:[dict get $sim_dic $s]"
4632 Msg CriticalWarning "Elaboration failed for $s, error info: $::errorInfo"
4633 lappend failed $sim_name
4635 lappend success $sim_name
4637 Msg Info "###################### Elaboration log starts ######################"
4638 Msg Info "\n\n$log\n\n"
4639 Msg Info "###################### Elaboration log ends ######################"
4641 set cmd ./simulate.sh
4642 Msg Info " ************* Simulating: $s ************* "
4647 if {$use_simpass_str == 1} {
4648 if {[
string first $simpass_str $log] == -1} {
4652 Msg Debug "Simulation pass string not set, relying on simulator exit code."
4656 set sim_name "sim:[dict get $sim_dic $s]"
4658 Msg CriticalWarning "Simulation failed for $s, error info: $::errorInfo"
4659 lappend failed $sim_name
4661 lappend success $sim_name
4663 Msg Info "###################### Simulation log starts ######################"
4664 Msg Info "\n\n$log\n\n"
4665 Msg Info "###################### Simulation log ends ######################"
4670 if {[
llength $success] > 0} {
4671 set successes [
join $success "\n"]
4672 Msg Info "The following simulation sets were successful:\n\n$successes\n\n"
4675 if {[
llength $failed] > 0} {
4676 set failures [
join $failed "\n"]
4677 Msg Error "The following simulation sets have failed:\n\n$failures\n\n"
4679 }
elseif {[
llength $success] > 0} {
4680 Msg Info "All the [
llength $success] compilations, elaborations and simulations were successful."
4683 Msg Info "Simulation done."
4685 Msg Warning "Simulation is not yet supported for [
GetIDEName]."
4698 proc LaunchSynthesis {reset do_create run_folder project_name {repo_path .} {ext_path ""} {njobs 4}} {
4700 if {$reset == 1 && $do_create == 0} {
4701 Msg Info "Resetting run before launching synthesis..."
4705 source $repo_path/Hog/Tcl/integrated/pre-synthesis.tcl
4707 launch_runs synth_1 -jobs $njobs -dir $run_folder
4709 set prog [get_property PROGRESS [get_runs synth_1]]
4710 set status [get_property STATUS [get_runs synth_1]]
4711 Msg Info "Run: synth_1 progress: $prog, status : $status"
4718 lassign [
GetRepoVersions [
file normalize ./Top/$project_name] $repo_path $ext_path] sha
4720 Msg Info "Git describe set to $describe"
4723 set xci_file [get_property IP_FILE $ip]
4725 set xci_path [
file dirname $xci_file]
4726 set xci_ip_name [
file rootname [
file tail $xci_file]]
4727 foreach rptfile [glob -nocomplain -directory $xci_path *.rpt] {
4728 file copy $rptfile $repo_path/bin/$project_name-$describe/reports
4732 if {$prog ne "100%"} {
4733 Msg Error "Synthesis error, status is: $status"
4737 set project [
file tail [
file rootname $project_name]]
4739 Msg Info "Number of jobs set to $njobs."
4740 set_global_assignment -name NUM_PARALLEL_PROCESSORS $njobs
4744 lassign [
GetRepoVersions [
file normalize $repo_path/Top/$project_name] $repo_path] sha
4747 set revision [get_current_revision]
4750 set tool_and_command [
split [get_global_assignment -name PRE_FLOW_SCRIPT_FILE] ":"]
4751 set tool [
lindex $tool_and_command 0]
4752 set pre_flow_script [
lindex $tool_and_command 1]
4753 set cmd "$tool -t $pre_flow_script quartus_map $project $revision"
4759 Msg Warning "Can not execute command $cmd"
4760 Msg Warning "LOG: $log"
4762 Msg Info "Pre flow script executed!"
4766 if {![is_project_open]} {
4767 Msg Info "Re-opening project file $project_name..."
4768 project_open $project -current_revision
4772 if {[
catch {execute_module -tool ipg -args "--clean"} result]} {
4773 Msg Error "Result: $result\n"
4774 Msg Error "IP Generation failed. See the report file.\n"
4776 Msg Info "IP Generation was successful for revision $revision.\n"
4780 if {[
catch {execute_module -tool map -args "--parallel"} result]} {
4781 Msg Error "Result: $result\n"
4782 Msg Error "Analysis & Synthesis failed. See the report file.\n"
4784 Msg Info "Analysis & Synthesis was successful for revision $revision.\n"
4788 defvar_set -name RWNETLIST_32_64_MIXED_FLOW -value 0
4790 Msg Info "Run SYNTHESIS..."
4791 if {[
catch {run_tool -name {SYNTHESIZE}}]} {
4792 Msg Error "SYNTHESIZE FAILED!"
4794 Msg Info "SYNTHESIZE PASSED!"
4800 set force_rst "-forceOne"
4802 prj_run Synthesis $force_rst
4803 if {[prj_syn] == "synplify"} {
4804 prj_run Translate $force_rst
4807 Msg Error "Impossible condition. You need to run this in an IDE."
4818 proc ListProjects {{repo_path .} {print 1} {ret_conf 0}} {
4819 set top_path [
file normalize $repo_path/Top]
4820 set confs [
findFiles [
file normalize $top_path] hog.conf]
4822 set confs [lsort $confs]
4826 set p [
Relative $top_path [
file dirname $c]]
4829 if {$description eq "test"} {
4830 set description " - Test project"
4831 }
elseif {$description ne ""} {
4832 set description " - $description"
4835 if {$print == 1 || $description ne " - Test project"} {
4837 set g [
file dirname $p]
4848 if {$ret_conf == 0} {
4861 proc Logo {{repo_path .}} {
4863 if {![
info exists ::env(HOG_LOGO_PRINTED)] || $::env(HOG_LOGO_PRINTED) eq "0"} {
4865 [
info exists ::env(HOG_COLOR)] && ([
string match "ENABLED" $::env(HOG_COLOR)] || [
string is integer -strict $::env(HOG_COLOR)] && $::env(HOG_COLOR) > 0)
4867 set logo_file "$repo_path/Hog/images/hog_logo_color.txt"
4869 set logo_file "$repo_path/Hog/images/hog_logo.txt"
4873 set ver [
Git {describe --always}]
4877 if {[
file exists $logo_file]} {
4878 set f [open $logo_file "r"]
4881 set lines [
split $data "\n"]
4883 if {[regexp {(Version:)[ ]+} $l -> prefix]} {
4884 set string_len [
string length $l]
4886 set version_string "* Version: $ver"
4887 set version_len [
string length $version_string]
4888 append version_string [
string repeat " " [
expr {$string_len - $version_len - 1}]] "*"
4889 set l $version_string
4894 Msg CriticalWarning "Logo file: $logo_file not found"
4906 proc Md5Sum {file_name} {
4907 if {!([
file exists $file_name])} {
4908 Msg Warning "Could not find $file_name."
4911 if {[
catch {
package require md5 2.0.7} result]} {
4912 Msg Warning "Tcl package md5 version 2.0.7 not found ($result), will use command line..."
4913 set hash [
lindex [
Execute md5sum $file_name] 0]
4915 set file_hash [
string tolower [md5::md5 -hex -file $file_name]]
4929 proc MergeDict {dict0 dict1 {remove_duplicates 1}} {
4930 set outdict [dict merge $dict1 $dict0]
4931 foreach key [dict keys $dict1] {
4932 if {[dict exists $dict0 $key]} {
4933 set temp_list [dict get $dict1 $key]
4934 foreach item $temp_list {
4936 if {[
IsInList $item [
DictGet $outdict $key]] == 0 || $remove_duplicates == 0} {
4938 dict lappend outdict $key $item
4950 proc MoveElementToEnd {inputList element} {
4951 set index [lsearch $inputList $element]
4953 set inputList [
lreplace $inputList $index $index]
4954 lappend inputList $element
4964 proc Msg {level msg {title ""}} {
4965 set level [
string tolower $level]
4966 if {$title == ""} {
set title [
lindex [
info level [
expr {[info level] - 1}]] 0]}
4967 if {$level == 0 || $level == "status" || $level == "extra_info"} {
4970 }
elseif {$level == 1 || $level == "info"} {
4973 }
elseif {$level == 2 || $level == "warning"} {
4974 set vlevel {WARNING}
4976 }
elseif {$level == 3 || [
string first "critical" $level] != -1} {
4977 set vlevel {CRITICAL WARNING}
4978 set qlevel critical_warning
4979 }
elseif {$level == 4 || $level == "error"} {
4982 }
elseif {$level == 5 || $level == "debug"} {
4983 if {([
info exists ::DEBUG_MODE] && $::DEBUG_MODE == 1) || ([
info exists ::env(HOG_DEBUG_MODE)] && $::env(HOG_DEBUG_MODE) == 1)} {
4985 set qlevel extra_info
4986 set msg "DEBUG: \[Hog:$title\] $msg"
4991 puts "Hog Error: level $level not defined"
4998 set status [
catch {send_msg_id Hog:$title-0 $vlevel $msg}]
5004 post_message -type $qlevel "Hog:$title $msg"
5005 if {$qlevel == "error"} {
5010 if {$vlevel != "STATUS"} {
5011 puts "$vlevel: \[Hog:$title\] $msg"
5016 if {$qlevel == "error"} {
5028 proc MsgAndLog {msg {severity "CriticalWarning"} {outFile ""}} {
5030 if {$outFile != ""} {
5031 set directory [
file dir $outFile]
5032 if {![
file exists $directory]} {
5033 Msg Info "Creating $directory..."
5034 file mkdir $directory
5037 set oF [open "$outFile" a+]
5047 proc OpenProject {project_file repo_path} {
5049 open_project $project_file
5051 set project_folder [
file dirname $project_file]
5052 set project [
file tail [
file rootname $project_file]]
5053 if {[
file exists $project_folder]} {
5055 if {![is_project_open]} {
5056 Msg Info "Opening existing project file $project_file..."
5057 project_open $project -current_revision
5060 Msg Error "Project directory not found for $project_file."
5064 Msg Info "Opening existing project file $project_file..."
5066 open_project -file $project_file -do_backup_on_convert 1 -backup_file {./Projects/$project_file.zip}
5068 Msg Info "Opening existing project file $project_file..."
5069 prj_project open $project_file
5071 Msg Error "This IDE is currently not supported by Hog. Exiting!"
5078 return $tcl_platform(platform)
5088 proc ParseJSON {JSON_FILE JSON_KEY} {
5089 set result [
catch {
package require Tcl 8.4} TclFound]
5090 if {"$result" != "0"} {
5091 Msg CriticalWarning "Cannot find Tcl package version equal or higher than 8.4.\n $TclFound\n Exiting"
5095 set result [
catch {
package require json} JsonFound]
5096 if {"$result" != "0"} {
5097 Msg CriticalWarning "Cannot find JSON package equal or higher than 1.0.\n $JsonFound\n Exiting"
5100 set JsonDict [json::json2dict $JSON_FILE]
5101 set result [
catch {dict get $JsonDict $JSON_KEY} RETURNVALUE]
5102 if {"$result" != "0"} {
5103 Msg CriticalWarning "Cannot find $JSON_KEY in $JSON_FILE\n Exiting"
5115 proc PrintFileContent {filename} {
5117 set file [open $filename r]
5120 set content [read $file]
5136 proc PrintFileTree {{data} {repo_path} {indentation ""}} {
5139 foreach line $data {
5140 if {![regexp {^[\t\s]*$} $line] & ![regexp {^[\t\s]*\#} $line]} {
5141 lappend print_list "$line"
5146 foreach p $print_list {
5148 if {$i == [
llength $print_list]} {
5153 set file_name [
lindex [
split $p] 0]
5154 if {[
file exists [
file normalize [
lindex [glob -nocomplain $repo_path/$file_name] 0]]]} {
5157 set exists " !!!!! NOT FOUND !!!!!"
5160 Msg Status "$indentation$pad$p$exists"
5161 set last_printed $file_name
5164 return $last_printed
5172 proc ProjectExists {project {repo_path .}} {
5173 set index [lsearch -exact [
ListProjects $repo_path 0] $project]
5189 proc ReadConf {file_name} {
5190 if {[
catch {
package require inifile 0.2.3} ERROR]} {
5191 Msg Error "Could not find inifile package version 0.2.3 or higher.\n
5192 To use ghdl, libero or diamond with Hog, you need to install the tcllib package\n
5193 You can install it with 'sudo apt install tcllib' on Debian/Ubuntu or 'sudo dnf install tcllib' on Fedora/RedHat/CentOs."
5197 ::ini::commentchar "#"
5198 set f [::ini::open $file_name]
5199 set properties [dict create]
5200 foreach sec [::ini::sections $f] {
5202 if {$new_sec == "files"} {
5205 set key_pairs [::ini::get $f $sec]
5207 regsub -all {\{\"} $key_pairs "\{" key_pairs
5208 regsub -all {\"\}} $key_pairs "\}" key_pairs
5210 dict set properties $new_sec [dict create {*}$key_pairs]
5223 proc ReadExtraFileList {extra_file_name} {
5224 set extra_file_dict [dict create]
5225 if {[
file exists $extra_file_name]} {
5226 set file [open $extra_file_name "r"]
5227 set file_data [read $file]
5230 set data [
split $file_data "\n"]
5231 foreach line $data {
5232 if {![regexp {^ *$} $line] & ![regexp {^ *\#} $line]} {
5233 set ip_and_md5 [regexp -all -inline {\S+} $line]
5234 dict lappend extra_file_dict "[
lindex $ip_and_md5 0]" "[
lindex $ip_and_md5 1]"
5238 return $extra_file_dict
5258 proc ReadListFile {args} {
5261 if {[
catch {
package require cmdline} ERROR]} {
5262 puts "$ERROR\n If you are running this script on tclsh, you can fix this by installing 'tcllib'"
5268 {lib.arg "" "The name of the library files will be added to, if not given will be extracted from the file name."}
5269 {fileset.arg "" "The name of the library, from the main list file"}
5270 {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."}
5271 {print_log "If set, will use PrintFileTree for the VIEW directive"}
5272 {indent.arg "" "Used to indent files with the VIEW directive"}
5275 set usage "USAGE: ReadListFile \[options\] <list file> <path>"
5276 if {[
catch {
array set options [
cmdline::getoptions args $parameters $usage]}] || [
llength $args] != 2} {
5280 set list_file [
lindex $args 0]
5281 set path [
lindex $args 1]
5282 set sha_mode $options(sha_mode)
5283 set lib $options(lib)
5284 set fileset $options(fileset)
5285 set print_log $options(print_log)
5286 set indent $options(indent)
5288 if {$sha_mode == 1} {
5289 set sha_mode_opt "-sha_mode"
5294 if {$print_log == 1} {
5295 set print_log_opt "-print_log"
5297 set print_log_opt ""
5302 set lib [
file rootname [
file tail $list_file]]
5304 set fp [open $list_file r]
5305 set file_data [read $fp]
5307 set list_file_ext [
file extension $list_file]
5308 switch $list_file_ext {
5310 if {$fileset eq ""} {
5316 set fileset "constrs_1"
5319 set fileset "sources_1"
5323 set libraries [dict create]
5324 set filesets [dict create]
5325 set properties [dict create]
5327 set data [
split $file_data "\n"]
5329 set n [
llength $data]
5331 if {$print_log == 1} {
5332 if {$indent eq ""} {
5333 set list_file_rel [
file tail $list_file]
5334 Msg Status "\n$list_file_rel"
5338 Msg Debug "$n lines read from $list_file."
5341 foreach line $data {
5343 if {![regexp {^[\t\s]*$} $line] & ![regexp {^[\t\s]*\#} $line]} {
5344 set file_and_prop [regexp -all -inline {\S+} $line]
5345 set srcfile [
lindex $file_and_prop 0]
5346 set srcfile "$path/$srcfile"
5348 set srcfiles [glob -nocomplain $srcfile]
5351 if {$srcfiles != $srcfile && ![
string equal $srcfiles ""]} {
5352 Msg Debug "Wildcard source expanded from $srcfile to $srcfiles"
5354 if {![
file exists $srcfile]} {
5355 if {$print_log == 0} {
5356 Msg CriticalWarning "File: $srcfile (from list file: $list_file) does not exist."
5362 foreach vhdlfile $srcfiles {
5363 if {[
file exists $vhdlfile]} {
5364 set vhdlfile [
file normalize $vhdlfile]
5365 set extension [
file extension $vhdlfile]
5367 set prop [
lrange $file_and_prop 1 end]
5370 set library [
lindex [regexp -inline {\ylib\s*=\s*(.+?)\y.*} $prop] 1]
5371 if {$library == ""} {
5375 if {$extension == $list_file_ext} {
5378 set ref_path [
lindex [regexp -inline {\ypath\s*=\s*(\S+).*} $prop] 1]
5379 if {$ref_path eq ""} {
5382 set ref_path [
file normalize $path/$ref_path]
5384 Msg Debug "List file $vhdlfile found in list file, recursively opening it using path \"$ref_path\"..."
5385 if {$print_log == 1} {
5386 if {[
file normalize $last_printed] ne [
file normalize $vhdlfile]} {
5387 Msg Status "$indent Inside [
file tail $vhdlfile]:"
5391 lassign [
ReadListFile {*}"-indent \" $indent\" -lib $library -fileset $fileset $sha_mode_opt $print_log_opt $vhdlfile $ref_path"] l p fs
5393 set properties [
MergeDict $p $properties]
5395 }
elseif {[lsearch {.src .sim .con ReadExtraFileList} $extension] >= 0} {
5397 Msg Error "$vhdlfile cannot be included into $list_file, $extension files must be included into $extension files."
5400 regsub -all " *= *" $prop "=" prop
5404 if {[
string first "lib=" $p] == -1} {
5406 set pos [
string first "=" $p]
5410 set prop_name [
string range $p 0 [
expr {$pos - 1}]]
5413 dict lappend properties $vhdlfile $p
5414 Msg Debug "Adding property $p to $vhdlfile..."
5415 }
elseif {$list_file_ext != ".ipb"} {
5416 Msg Warning "Setting Property $p is not supported for file $vhdlfile or it is already its default. \
5421 if {[lsearch {.xci .ip .bd .xcix} $extension] >= 0} {
5423 set lib_name "ips.src"
5424 }
elseif {[
IsInList $extension {.vhd .vhdl}] || $list_file_ext == ".sim"} {
5426 if {![
IsInList $extension {.vhd .vhdl}]} {
5427 set lib_name "others.sim"
5429 set lib_name "$library$list_file_ext"
5431 }
elseif {$list_file_ext == ".con"} {
5432 set lib_name "sources.con"
5433 }
elseif {$list_file_ext == ".ipb"} {
5434 set lib_name "xml.ipb"
5437 set lib_name "others.src"
5440 Msg Debug "Appending $vhdlfile to $lib_name list..."
5441 dict lappend libraries $lib_name $vhdlfile
5442 if {$sha_mode != 0 && [
file type $vhdlfile] eq "link"} {
5445 dict lappend libraries $lib_name $real_file
5446 Msg Debug "File $vhdlfile is a soft link, also adding the real file: $real_file"
5451 if {[dict exists $filesets $fileset] == 0} {
5453 Msg Debug "Adding $fileset to the fileset dictionary..."
5454 Msg Debug "Adding library $lib_name to fileset $fileset..."
5455 dict set filesets $fileset $lib_name
5459 Msg Debug "Adding library $lib_name to fileset $fileset..."
5460 dict lappend filesets $fileset $lib_name
5466 Msg CriticalWarning "File $vhdlfile not found."
5472 if {$sha_mode != 0} {
5474 if {$list_file_ext eq ".ipb"} {
5475 set sha_lib "xml.ipb"
5477 set sha_lib $lib$list_file_ext
5479 dict lappend libraries $sha_lib [
file normalize $list_file]
5480 if {[
file type $list_file] eq "link"} {
5483 dict lappend libraries $lib$list_file_ext $real_file
5484 Msg Debug "List file $list_file is a soft link, also adding the real file: $real_file"
5487 return [list $libraries $properties $filesets]
5495 proc Relative {base dst} {
5496 if {![
string equal [
file pathtype $base] [
file pathtype $dst]]} {
5497 Msg CriticalWarning "Unable to compute relation for paths of different path types: [
file pathtype $base] vs. [
file pathtype $dst], ($base vs. $dst)"
5501 set base [
file normalize [
file join [
pwd] $base]]
5502 set dst [
file normalize [
file join [
pwd] $dst]]
5505 set base [
file split $base]
5506 set dst [
file split $dst]
5508 while {[
string equal [
lindex $dst 0] [
lindex $base 0]]} {
5509 set dst [
lrange $dst 1 end]
5510 set base [
lrange $base 1 end]
5511 if {![
llength $dst]} {break}
5514 set dstlen [
llength $dst]
5515 set baselen [
llength $base]
5517 if {($dstlen == 0) && ($baselen == 0)} {
5520 while {$baselen > 0} {
5521 set dst [
linsert $dst 0 ..]
5524 set dst [
eval [
linsert $dst 0 file join]]
5535 proc RelativeLocal {pathName filePath} {
5536 if {[
string first [
file normalize $pathName] [
file normalize $filePath]] != -1} {
5537 return [
Relative $pathName $filePath]
5548 proc RemoveDuplicates {mydict} {
5549 set new_dict [dict create]
5550 foreach key [dict keys $mydict] {
5551 set values [
DictGet $mydict $key]
5552 foreach value $values {
5553 set idxs [
lreverse [
lreplace [lsearch -exact -all $values $value] 0 0]]
5555 set values [
lreplace $values $idx $idx]
5558 dict set new_dict $key $values
5569 proc ResetRepoFiles {reset_file} {
5570 if {[
file exists $reset_file]} {
5571 Msg Info "Found $reset_file, opening it..."
5572 set fp [open $reset_file r]
5573 set wild_cards [lsearch -all -inline -not -regexp [
split [read $fp] "\n"] "^ *$"]
5575 Msg Info "Found the following files/wild cards to restore if modified: $wild_cards..."
5576 foreach w $wild_cards {
5578 if {[
llength $mod_files] > 0} {
5579 Msg Info "Found modified $w files: $mod_files, will restore them..."
5582 Msg Info "No modified $w files found."
5593 proc RestoreModifiedFiles {{repo_path "."} {pattern "."}} {
5596 set ret [
Git checkout $pattern]
5607 proc SearchHogProjects {dir} {
5608 set projects_list {}
5609 if {[
file exists $dir]} {
5610 if {[
file isdirectory $dir]} {
5611 foreach proj_dir [glob -nocomplain -types d $dir/*] {
5612 if {![regexp {^.*Top/+(.*)$} $proj_dir dummy proj_name]} {
5613 Msg Warning "Could not parse Top directory $dir"
5616 if {[
file exists "$proj_dir/hog.conf"]} {
5617 lappend projects_list $proj_name
5620 lappend projects_list $p
5625 Msg Error "Input $dir is not a directory!"
5628 Msg Error "Directory $dir doesn't exist!"
5630 return $projects_list
5639 proc SetGenericsSimulation {repo_path proj_dir target} {
5640 set top_dir "$repo_path/Top/$proj_dir"
5641 set simsets [get_filesets]
5642 if {$simsets != ""} {
5643 foreach simset $simsets {
5645 if {[get_property FILESET_TYPE $simset] != "SimulationSrcs"} {
5649 set merged_generics_dict [dict create]
5653 set simset_generics [
DictGet $simset_dict "generics"]
5654 set merged_generics_dict [
MergeDict $merged_generics_dict $simset_generics 0]
5656 set_property generic $generic_str [get_filesets $simset]
5657 Msg Debug "Setting generics $generic_str for simulator $target\
5658 and simulation file-set $simset..."
5670 proc SetTopProperty {top_module fileset} {
5671 Msg Info "Setting TOP property to $top_module module"
5674 set_property "top" $top_module [get_filesets $fileset]
5677 set_global_assignment -name TOP_LEVEL_ENTITY $top_module
5679 set_root -module $top_module
5681 prj_impl option top $top_module
5686 proc VIVADO_PATH_PROPERTIES {} {
5687 return {"\.*\.TCL\.PRE$" "^.*\.TCL\.POST$" "^RQS_FILES$" "^INCREMENTAL\_CHECKPOINT$" "NOC\_SOLUTION\_FILE"}
5697 proc WriteConf {file_name config {comment ""}} {
5698 if {[
catch {
package require inifile 0.2.3} ERROR]} {
5699 puts "$ERROR\n If you are running this script on tclsh, you can fix this by installing 'tcllib'"
5703 ::ini::commentchar "#"
5704 set f [::ini::open $file_name w]
5706 foreach sec [dict keys $config] {
5707 set section [dict get $config $sec]
5708 dict for {p v} $section {
5709 if {[string trim $v] == ""} {
5710 Msg Warning "Property $p has empty value. Skipping..."
5713 ::ini::set $f $sec $p $v
5718 if {![
string equal "$comment" ""]} {
5719 ::ini::comment $f [
lindex [::ini::sections $f] 0] "" $comment
5720 set hog_header "Generated by Hog on [
clock format [
clock seconds] -format "%Y-%m-%d %H:%M:%S"]"
5721 ::ini::comment $f [
lindex [::ini::sections $f] 0] "" $hog_header
5736 proc WriteGenerics {mode repo_path design date timee\
5737 commit version top_hash top_ver hog_hash hog_ver \
5738 cons_ver cons_hash libs vers hashes ext_names ext_hashes \
5739 user_ip_repos user_ip_vers user_ip_hashes flavour {xml_ver ""} {xml_hash ""}} {
5740 Msg Info "Passing parameters/generics to project's top module..."
5743 set generic_string [
concat \
5755 if {$xml_hash != "" && $xml_ver != ""} {
5756 lappend generic_string \
5761 foreach l $libs v $vers h $hashes {
5764 lappend generic_string "$ver" "$hash"
5767 foreach e $ext_names h $ext_hashes {
5769 lappend generic_string "$hash"
5772 foreach repo $user_ip_repos v $user_ip_vers h $user_ip_hashes {
5773 set repo_name [
file tail $repo]
5774 set ver "[
string toupper $repo_name]_VER=[
FormatGeneric $v]"
5775 set hash "[
string toupper $repo_name]_SHA=[
FormatGeneric $h]"
5776 lappend generic_string "$ver" "$hash"
5779 if {$flavour != -1} {
5780 lappend generic_string "FLAVOUR=$flavour"
5786 set generic_string "$prj_generics $generic_string"
5792 if {$mode == "create" || [
IsISE]} {
5795 if {[
file exists $top_file]} {
5798 Msg Debug "Found top level generics $generics in $top_file"
5800 set filtered_generic_string ""
5802 foreach generic_to_set [
split [
string trim $generic_string]] {
5803 set key [
lindex [
split $generic_to_set "="] 0]
5804 if {[dict exists $generics $key]} {
5805 Msg Debug "Hog generic $key found in $top_name"
5806 lappend filtered_generic_string "$generic_to_set"
5808 Msg Warning "Generic $key is passed by Hog but is NOT present in $top_name."
5814 set generic_string $filtered_generic_string
5819 set_property generic $generic_string [current_fileset]
5820 Msg Info "Setting parameters/generics..."
5821 Msg Debug "Detailed parameters/generics: $generic_string"
5826 set simulator [get_property target_simulator [current_project]]
5827 if {$mode == "create"} {
5834 Msg Info "Setting Synplify parameters/generics one by one..."
5835 foreach generic $generic_string {
5836 Msg Debug "Setting Synplify generic: $generic"
5837 set_option -hdl_param -set "$generic"
5840 Msg Info "Setting Diamond parameters/generics one by one..."
5841 prj_impl option -impl Implementation0 HDL_PARAM "$generic_string"
5851 proc WriteGenericsToBdIPs {mode repo_path proj generic_string} {
5852 Msg Debug "Parameters/generics passed to WriteGenericsToIP: $generic_string"
5854 set bd_ip_generics false
5856 if {[dict exists $properties "hog"]} {
5857 set propDict [dict get $properties "hog"]
5858 if {[dict exists $propDict "PASS_GENERICS_TO_BD_IPS"]} {
5859 set bd_ip_generics [dict get $propDict "PASS_GENERICS_TO_BD_IPS"]
5863 if {[
string compare [
string tolower $bd_ip_generics] "false"] == 0} {
5867 if {$mode == "synth"} {
5868 Msg Info "Attempting to apply generics pre-synthesis..."
5869 set PARENT_PRJ [get_property "PARENT.PROJECT_PATH" [current_project]]
5870 set workaround [open "$repo_path/Projects/$proj/.hog/presynth_workaround.tcl" "w"]
5871 puts $workaround "source \[lindex \$argv 0\];"
5872 puts $workaround "open_project \[lindex \$argv 1\];"
5873 puts $workaround "WriteGenericsToBdIPs \[lindex \$argv 2\] \[lindex \$argv 3\] \[lindex \$argv 4\] \[lindex \$argv 5\];"
5874 puts $workaround "close_project"
5878 exec vivado -mode batch -source $repo_path/Projects/$proj/.hog/presynth_workaround.tcl \
5879 -tclargs $repo_path/Hog/Tcl/hog.tcl $PARENT_PRJ \
5880 "childprocess" $repo_path $proj $generic_string
5883 Msg Error "Encountered an error while attempting workaround: $errMsg"
5885 file delete $repo_path/Projects/$proj/.hog/presynth_workaround.tcl
5887 Msg Info "Done applying generics pre-synthesis."
5891 Msg Info "Looking for IPs to add generics to..."
5892 set ips_generic_string ""
5893 foreach generic_to_set [
split [
string trim $generic_string]] {
5894 set key [
lindex [
split $generic_to_set "="] 0]
5895 set value [
lindex [
split $generic_to_set "="] 1]
5896 append ips_generic_string "CONFIG.$key $value "
5900 if {[
string compare [
string tolower $bd_ip_generics] "true"] == 0} {
5903 set ip_regex $bd_ip_generics
5906 set ip_list [get_ips -regex $ip_regex]
5907 Msg Debug "IPs found with regex \{$ip_regex\}: $ip_list"
5909 set regen_targets {}
5911 foreach {ip} $ip_list {
5912 set WARN_ABOUT_IP false
5913 set ip_props [list_property [get_ips $ip]]
5916 if {[lsearch -exact $ip_props "IS_BD_CONTEXT"] == -1} {
5920 if {[get_property "IS_BD_CONTEXT" [get_ips $ip]] eq "1"} {
5921 foreach {ip_prop} $ip_props {
5922 if {[dict exists $ips_generic_string $ip_prop]} {
5923 if {$WARN_ABOUT_IP == false} {
5924 lappend regen_targets [get_property SCOPE [get_ips $ip]]
5925 Msg Warning "The ip \{$ip\} contains generics that are set by Hog.\
5926 If this is IP is apart of a block design, the .bd file may contain stale, unused, values.\
5927 Hog will always apply the most up-to-date values to the IP during synthesis,\
5928 however these values may or may not be reflected in the .bd file."
5929 set WARN_ABOUT_IP true
5934 set xci_path [get_property IP_FILE [get_ips $ip]]
5936 if {[
string equal $generic_format "ERROR"]} {
5937 Msg Warning "Could not find format for generic $ip_prop in IP $ip. Skipping..."
5941 set value_to_set [dict get $ips_generic_string $ip_prop]
5942 switch -exact $generic_format {
5944 if {[
string match "32'h*" $value_to_set]} {
5945 scan [
string map {"32'h" ""} $value_to_set] "%x" value_to_set
5949 set value_to_set [
expr {$value_to_set ? "true" : "false"}]
5952 if {[
string match "32'h*" $value_to_set]} {
5953 binary scan [
binary format H* [
string map {"32'h" ""} $value_to_set]] d value_to_set
5957 if {[
string match "32'h*" $value_to_set]} {
5958 set value_to_set [
string map {"32'h" "0x"} $value_to_set]
5962 set value_to_set [
format "%s" $value_to_set]
5965 Msg Warning "Unknown generic format $generic_format for IP $ip. Will attempt to pass as string..."
5970 Msg Info "The IP \{$ip\} contains: $ip_prop ($generic_format), setting it to $value_to_set."
5971 if {[
catch {set_property -name $ip_prop -value $value_to_set -objects [get_ips $ip]} prop_error]} {
5972 Msg CriticalWarning "Failed to set property $ip_prop to $value_to_set for IP \{$ip\}: $prop_error"
5979 foreach {regen_target} [lsort -unique $regen_targets] {
5980 Msg Info "Regenerating target: $regen_target"
5981 if {[
catch {generate_target -force all [get_files $regen_target]} prop_error]} {
5982 Msg CriticalWarning "Failed to regen targets: $prop_error"
5990 proc GetGenericFormatFromXciXML {generic_name xml_file} {
5991 if {![
file exists $xml_file]} {
5992 Msg Error "Could not find XML file: $xml_file"
5996 set fp [open $xml_file r]
5997 set xci_data [read $fp]
6000 set paramType "string"
6001 set modelparam_regex [
format {^.*\y%s\y.*$} [
string map {"CONFIG." "MODELPARAM_VALUE."} $generic_name]]
6002 set format_regex {format="([^"]+)"}
6004 set line [
lindex [regexp -inline -line $modelparam_regex $xci_data] 0]
6005 Msg Debug "line: $line"
6007 if {[regexp $format_regex $line match format_value]} {
6008 Msg Debug "Extracted: $format_value format from xml"
6009 set paramType $format_value
6011 Msg Debug "No format found, using string"
6020 proc GetGenericFormatFromXci {generic_name xci_file} {
6021 if {![
file exists $xci_file]} {
6022 Msg Error "Could not find XCI file: $xci_file"
6026 set fp [open $xci_file r]
6027 set xci_data [read $fp]
6030 set paramType "string"
6031 if {[
string first "xilinx.com:schema:json_instance:1.0" $xci_data] == -1} {
6032 Msg Debug "XCI format is not JSON, trying XML..."
6033 set xml_file "[
file rootname $xci_file].xml"
6037 set generic_name [
string map {"CONFIG." ""} $generic_name]
6038 set ip_inst [
ParseJSON $xci_data "ip_inst"]
6039 set parameters [dict get $ip_inst parameters]
6040 set component_parameters [dict get $parameters component_parameters]
6041 if {[dict exists $component_parameters $generic_name]} {
6042 set generic_info [dict get $component_parameters $generic_name]
6043 if {[dict exists [
lindex $generic_info 0] format]} {
6044 set paramType [dict get [
lindex $generic_info 0] format]
6045 Msg Debug "Extracted: $paramType format from xci"
6048 Msg Debug "No format found, using string"
6061 proc WriteGitLabCIYAML {proj_name {ci_conf ""}} {
6062 if {[
catch {
package require yaml 0.3.3} YAMLPACKAGE]} {
6063 Msg CriticalWarning "Cannot find package YAML.\n Error message: $YAMLPACKAGE. \
6064 If you are running on tclsh, you can fix this by installing package \"tcllib\""
6069 if {$ci_conf != ""} {
6071 foreach sec [dict keys $ci_confs] {
6072 if {[
string first : $sec] == -1} {
6073 lappend job_list $sec
6077 set job_list {"generate_project" "simulate_project"}
6081 set out_yaml [huddle create]
6082 foreach job $job_list {
6084 set huddle_tags [huddle list]
6086 set sec_dict [dict create]
6088 if {$ci_confs != ""} {
6089 foreach var [dict keys [dict get $ci_confs $job]] {
6090 if {$var == "tags"} {
6091 set tag_section "tags"
6092 set tags [dict get [dict get $ci_confs $job] $var]
6093 set tags [
split $tags ","]
6095 set tag_list [huddle list $tag]
6096 set huddle_tags [huddle combine $huddle_tags $tag_list]
6099 dict set sec_dict $var [dict get [dict get $ci_confs $job] $var]
6105 set huddle_variables [huddle create "PROJECT_NAME" $proj_name "extends" ".vars"]
6106 if {[dict exists $ci_confs "$job:variables"]} {
6107 set var_dict [dict get $ci_confs $job:variables]
6108 foreach var [dict keys $var_dict] {
6110 set value [dict get $var_dict "$var"]
6111 set var_inner [huddle create "$var" "$value"]
6112 set huddle_variables [huddle combine $huddle_variables $var_inner]
6117 set middle [huddle create "extends" ".$job" "variables" $huddle_variables]
6118 foreach sec [dict keys $sec_dict] {
6119 set value [dict get $sec_dict $sec]
6120 set var_inner [huddle create "$sec" "$value"]
6121 set middle [huddle combine $middle $var_inner]
6123 if {$tag_section != ""} {
6124 set middle2 [huddle create "$tag_section" $huddle_tags]
6125 set middle [huddle combine $middle $middle2]
6128 set outer [huddle create "$job:$proj_name" $middle]
6129 set out_yaml [huddle combine $out_yaml $outer]
6132 return [
string trimleft [yaml::huddle2yaml $out_yaml] "-"]
6142 proc WriteListFiles {libs props list_path repo_path {ext_path ""}} {
6144 foreach lib [dict keys $libs] {
6145 if {[
llength [
DictGet $libs $lib]] > 0} {
6146 set list_file_name $list_path$lib
6147 set list_file [open $list_file_name w]
6148 Msg Info "Writing $list_file_name..."
6149 puts $list_file "#Generated by Hog on [
clock format [
clock seconds] -format "%Y-%m-%d %H:%M:%S"]"
6150 foreach file [
DictGet $libs $lib] {
6152 set prop [
DictGet $props $file]
6156 puts $list_file "$file_path $prop"
6159 set ext_list_file [open "[
file rootname $list_file].ext" a]
6160 puts $ext_list_file "$file_path $prop"
6161 close $ext_list_file
6164 Msg Warning "The path of file $file is not relative to your repository. Please check!"
6180 proc WriteSimListFile {simset libs props simsets list_path repo_path {force 0}} {
6182 set list_file_name $list_path/${simset}.sim
6183 if {$force == 0 && [
file exists $list_file_name]} {
6184 Msg Info "List file $list_file_name already exists, skipping..."
6188 set list_file [open $list_file_name a+]
6191 puts $list_file "\[files\]"
6192 Msg Info "Writing $list_file_name..."
6193 foreach lib [
DictGet $simsets $simset] {
6194 foreach file [
DictGet $libs $lib] {
6196 set prop [
DictGet $props $file]
6200 set lib_name [
file rootname $lib]
6201 if {$lib_name != $simset && [
file extension $file] == ".vhd" && [
file extension $file] == ""} {
6202 lappend prop "lib=$lib_name"
6204 puts $list_file "$file_path $prop"
6207 Msg Warning "The path of file $file is not relative to your repository. Please check!"
6219 proc WriteToFile {File msg} {
6220 set f [open $File a+]
6231 proc WriteUtilizationSummary {input output project_name run} {
6232 set f [open $input "r"]
6233 set o [open $output "a"]
6234 puts $o "## $project_name $run Utilization report\n\n"
6235 struct::matrix util_m
6236 util_m add columns 14
6239 util_m add row "| **Site Type** | **Used** | **Fixed** | **Prohibited** | **Available** | **Util%** |"
6240 util_m add row "| --- | --- | --- | --- | --- | --- |"
6242 util_m add row "| **Site Type** | **Used** | **Fixed** | **Available** | **Util%** |"
6243 util_m add row "| --- | --- | --- | --- | --- |"
6253 while {[
gets $f line] >= 0} {
6254 if {([
string first "| CLB LUTs" $line] >= 0 || [
string first "| Slice LUTs" $line] >= 0) && $luts == 0} {
6255 util_m add row $line
6258 if {([
string first "| CLB Registers" $line] >= 0 || [
string first "| Slice Registers" $line] >= 0) && $regs == 0} {
6259 util_m add row $line
6262 if {[
string first "| Block RAM Tile" $line] >= 0 && $bram == 0} {
6263 util_m add row $line
6266 if {[
string first "URAM " $line] >= 0 && $uram == 0} {
6267 util_m add row $line
6270 if {[
string first "DSPs" $line] >= 0 && $dsps == 0} {
6271 util_m add row $line
6274 if {[
string first "Bonded IOB" $line] >= 0 && $ios == 0} {
6275 util_m add row $line
6282 puts $o [util_m format 2string]
6289 Msg Error "Found Git version older than 2.7.2. Hog will not work as expected, exiting now."