17 if {![
info exists tcl_path]} {
18 set tcl_path [
file normalize "[
file dirname [
info script]]"]
20 source "$tcl_path/utils/Logger.tcl"
24 set CI_STAGES {"generate_project" "simulate_project"}
25 set CI_PROPS {"-synth_only"}
34 proc AddFile {file fileset} {
36 add_files -norecurse -fileset $fileset $file
46 proc AddHogFiles {libraries properties filesets} {
47 Msg Info "Adding source files to project..."
48 Msg Debug "Filesets: $filesets"
49 Msg Debug "Libraries: $libraries"
50 Msg Debug "Properties: $properties"
53 set synth_conf_command "organize_tool_files -tool {SYNTHESIZE} -input_type {constraint}"
55 set timing_conf_command "organize_tool_files -tool {VERIFYTIMING} -input_type {constraint}"
57 set place_conf_command "organize_tool_files -tool {PLACEROUTE} -input_type {constraint}"
61 foreach fileset [dict keys $filesets] {
62 Msg Debug "Fileset: $fileset"
65 if {[
string equal [get_filesets -quiet $fileset] ""]} {
67 create_fileset -simset $fileset
70 current_fileset -simset [get_filesets $fileset]
71 set simulation [get_filesets $fileset]
73 set_property -name {$simulator.compile.vhdl_syntax} -value {2008} -objects $simulation
75 set_property SOURCE_SET sources_1 $simulation
79 set libs_in_fileset [
DictGet $filesets $fileset]
80 if {[
IsInList "ips.src" $libs_in_fileset]} {
85 foreach lib $libs_in_fileset {
86 Msg Debug "lib: $lib \n"
87 set lib_files [
DictGet $libraries $lib]
88 Msg Debug "Files in $lib: $lib_files"
89 set rootlib [
file rootname [
file tail $lib]]
90 set ext [
file extension $lib]
91 Msg Debug "lib: $lib ext: $ext fileset: $fileset"
94 Msg Debug "Adding $lib to $fileset"
95 add_files -norecurse -fileset $fileset $lib_files
97 foreach f $lib_files {
98 set file_obj [get_files -of_objects [get_filesets $fileset] [list "*$f"]]
100 if {[
file extension $f] == ".vhd" || [
file extension $f] == ".vhdl"} {
101 set_property -name "library" -value $rootlib -objects $file_obj
105 set props [
DictGet $properties $f]
106 if {[
file extension $f] == ".vhd" || [
file extension $f] == ".vhdl"} {
108 if {[lsearch -inline -regexp $props "93"] < 0} {
111 if {[lsearch -inline -regexp $props "2008"] >= 0} {
112 set vhdl_year "VHDL 2008"
113 }
elseif {[lsearch -inline -regexp $props "2019"] >= 0} {
115 set vhdl_year "VHDL 2019"
117 Msg CriticalWarning "VHDL 2019 is not supported\
118 in Vivado version older than 2023.2.\
119 Using VHDL 2008, but this might not work."
120 set vhdl_year "VHDL 2008"
124 set vhdl_year "VHDL 2008"
126 Msg Debug "File type for $f is $vhdl_year"
127 set_property -name "file_type" -value $vhdl_year -objects $file_obj
130 Msg Debug "Filetype is VHDL 93 for $f"
135 if {[lsearch -inline -regexp $props "SystemVerilog"] > 0} {
138 set_property -name "file_type" -value "SystemVerilog" -objects $file_obj
139 Msg Debug "Filetype is SystemVerilog for $f"
141 Msg Warning "Xilinx PlanAhead/ISE does not support SystemVerilog.\
142 Property not set for $f"
147 set top [
lindex [regexp -inline {\ytop\s*=\s*(.+?)\y.*} $props] 1]
149 Msg Info "Setting $top as top module for file set $fileset..."
150 set globalSettings::synth_top_module $top
155 if {[lsearch -inline -regexp $props "verilog_header"] >= 0} {
156 Msg Debug "Setting verilog header type for $f..."
157 set_property file_type {Verilog Header} [get_files $f]
158 }
elseif {[lsearch -inline -regexp $props "verilog_template"] >= 0} {
160 Msg Debug "Setting verilog template type for $f..."
161 set_property file_type {Verilog Template} [get_files $f]
162 }
elseif {[lsearch -inline -regexp $props "verilog"] >= 0} {
164 Msg Debug "Setting verilog type for $f..."
165 set_property file_type {Verilog} [get_files $f]
169 if {[lsearch -inline -regexp $props "nosynth"] >= 0} {
170 Msg Debug "Setting not used in synthesis for $f..."
171 set_property -name "used_in_synthesis" -value "false" -objects $file_obj
175 if {[lsearch -inline -regexp $props "noimpl"] >= 0} {
176 Msg Debug "Setting not used in implementation for $f..."
177 set_property -name "used_in_implementation" -value "false" -objects $file_obj
181 if {[lsearch -inline -regexp $props "nosim"] >= 0} {
182 Msg Debug "Setting not used in simulation for $f..."
183 set_property -name "used_in_simulation" -value "false" -objects $file_obj
188 set top_sim [
lindex [regexp -inline {\ytopsim\s*=\s*(.+?)\y.*} $props] 1]
189 if {$top_sim != ""} {
190 Msg Warning "Setting the simulation top module with the topsim property is deprecated.\
191 Please set this property in the \[properties\] section of your .sim list file,
192 or in the \[$fileset\] section of your sim.conf,\
193 by adding the following line.\ntop=$top_sim"
197 set sim_runtime [
lindex [regexp -inline {\yruntime\s*=\s*(.+?)\y.*} $props] 1]
198 if {$sim_runtime != ""} {
199 Msg Warning "Setting the simulation runtime using the runtime= property is deprecated.\
200 Please set this property in the \[properties\] section of your .sim list file,\
201 or in the \[$fileset\] section of your sim.conf,\
202 by adding the following line.\n<simulator_name>.simulate.runtime=$sim_runtime"
206 if {[lsearch -inline -regexp $props "wavefile"] >= 0} {
207 Msg Warning "Setting a wave do file using the wavefile property is deprecated.\
208 Set this property in the sim.conf file under the \[$fileset\] section,\
209 or in the \[properties\] section of the .sim list file,\
210 by adding the following line .\n<simulator_name>.simulate.custom_wave_do=[
file tail $f]"
214 if {[lsearch -inline -regexp $props "dofile"] >= 0} {
215 Msg Warning "Setting a wave do file using the dofile property is deprecated.\
216 Set this property in the sim.conf file under the \[$fileset\] section,\
217 or in the \[properties\] section of the .sim list file,\
218 by adding the following line .\n<simulator_name>.simulate.custom_do=[
file tail $f]"
222 if {[lsearch -inline -regexp $props "locked"] >= 0 && $ext == ".ip"} {
223 Msg Info "Locking IP $f..."
224 set_property IS_MANAGED 0 [get_files $f]
228 if {[
file extension $f] == ".bd"} {
229 Msg Info "Generating Target for [
file tail $f],\
230 please remember to commit the (possible) changed file."
231 generate_target all [get_files $f]
236 if {[
file extension $f] == ".tcl" && $ext != ".con"} {
237 if {[lsearch -inline -regexp $props "source"] >= 0} {
238 Msg Info "Sourcing Tcl script $f,\
239 and setting it not used in synthesis, implementation and simulation..."
241 set_property -name "used_in_synthesis" -value "false" -objects $file_obj
242 set_property -name "used_in_implementation" -value "false" -objects $file_obj
243 set_property -name "used_in_simulation" -value "false" -objects $file_obj
248 set ref [
lindex [regexp -inline {\yscoped_to_ref\s*=\s*(.+?)\y.*} $props] 1]
249 set cell [
lindex [regexp -inline {\yscoped_to_cells\s*=\s*(.+?)\y.*} $props] 1]
250 if {([
file extension $f] == ".tcl" || [
file extension $f] == ".xdc") && $ext == ".con"} {
252 set_property SCOPED_TO_REF $ref $file_obj
255 set_property SCOPED_TO_CELLS $cell $file_obj
259 Msg Info "[
llength $lib_files] file/s added to library $rootlib..."
262 if {$ext == ".sim"} {
263 Msg Warning "Simulation files not supported in Quartus Prime mode... Skipping $lib"
265 if {![is_project_open]} {
266 Msg Error "Project is closed"
268 foreach cur_file $lib_files {
272 set props [
DictGet $properties $cur_file]
275 set top [
lindex [regexp -inline {\ytop\s*=\s*(.+?)\y.*} $props] 1]
277 Msg Info "Setting $top as top module for file set $fileset..."
278 set globalSettings::synth_top_module $top
281 if {[
string first "VHDL" $file_type] != -1} {
282 if {[
string first "1987" $props] != -1} {
283 set hdl_version "VHDL_1987"
284 }
elseif {[
string first "1993" $props] != -1} {
285 set hdl_version "VHDL_1993"
286 }
elseif {[
string first "2008" $props] != -1} {
287 set hdl_version "VHDL_2008"
289 set hdl_version "default"
291 if {$hdl_version == "default"} {
292 set_global_assignment -name $file_type $cur_file -library $rootlib
294 set_global_assignment -name $file_type $cur_file -hdl_version $hdl_version -library $rootlib
296 }
elseif {[
string first "SYSTEMVERILOG" $file_type] != -1} {
298 if {[
string first "2005" $props] != -1} {
299 set hdl_version "systemverilog_2005"
300 }
elseif {[
string first "2009" $props] != -1} {
301 set hdl_version "systemverilog_2009"
303 set hdl_version "default"
305 if {$hdl_version == "default"} {
306 set_global_assignment -name $file_type $cur_file
308 set_global_assignment -name $file_type $cur_file -hdl_version $hdl_version
310 }
elseif {[
string first "VERILOG" $file_type] != -1} {
312 if {[
string first "1995" $props] != -1} {
313 set hdl_version "verilog_1995"
314 }
elseif {[
string first "2001" $props] != -1} {
315 set hdl_version "verilog_2001"
317 set hdl_version "default"
319 if {$hdl_version == "default"} {
320 set_global_assignment -name $file_type $cur_file
322 set_global_assignment -name $file_type $cur_file -hdl_version $hdl_version
324 }
elseif {[
string first "SOURCE" $file_type] != -1 || [
string first "COMMAND_MACRO" $file_type] != -1} {
325 set_global_assignment -name $file_type $cur_file
326 if {$ext == ".con"} {
328 }
elseif {$ext == ".src"} {
330 if {[
string first "qsys" $props] != -1} {
333 regsub -all {\{||qsys||\}} $props $emptyString props
335 set qsysPath [
file dirname $cur_file]
336 set qsysName "[
file rootname [
file tail $cur_file]].qsys"
337 set qsysFile "$qsysPath/$qsysName"
338 set qsysLogFile "$qsysPath/[
file rootname [
file tail $cur_file]].qsys-script.log"
341 if {![
info exists ::env(QSYS_ROOTDIR)]} {
342 if {[
info exists ::env(QUARTUS_ROOTDIR)]} {
343 set qsys_rootdir "$::env(QUARTUS_ROOTDIR)/sopc_builder/bin"
344 Msg Warning "The QSYS_ROOTDIR environment variable is not set! I will use $qsys_rootdir"
346 Msg CriticalWarning "The QUARTUS_ROOTDIR environment variable is not set! Assuming all quartus executables are contained in your PATH!"
349 set qsys_rootdir $::env(QSYS_ROOTDIR)
352 set cmd "$qsys_rootdir/qsys-script"
353 set cmd_options " --script=$cur_file"
354 if {![
catch {"exec $cmd -version"}] || [
lindex $::errorCode 0] eq "NONE"} {
355 Msg Info "Executing: $cmd $cmd_options"
356 Msg Info "Saving logfile in: $qsysLogFile"
357 if {[
catch {
eval exec -ignorestderr "$cmd $cmd_options >>& $qsysLogFile"} ret opt]} {
358 set makeRet [
lindex [dict get $opt -errorcode] end]
359 Msg CriticalWarning "$cmd returned with $makeRet"
362 Msg Error " Could not execute command $cmd"
366 if {[
file exists $qsysName] != 0} {
367 file rename -force $qsysName $qsysFile
369 set qsysMd5Sum [
Md5Sum $qsysFile]
371 set fileDir [
file normalize "./hogTmp"]
372 set fileName "$fileDir/.hogQsys.md5"
373 if {![
file exists $fileDir]} {
376 set hogQsysFile [open $fileName "a"]
377 set fileEntry "$qsysFile\t$qsysMd5Sum"
378 puts $hogQsysFile $fileEntry
381 Msg ERROR "Error while moving the generated qsys file to final location: $qsysName not found!"
383 if {[
file exists $qsysFile] != 0} {
384 if {[
string first "noadd" $props] == -1} {
386 set_global_assignment -name $qsysFileType $qsysFile
388 regsub -all {noadd} $props $emptyString props
390 if {[
string first "nogenerate" $props] == -1} {
394 Msg ERROR "Error while generating ip variations from qsys: $qsysFile not found!"
398 }
elseif {[
string first "QSYS" $file_type] != -1} {
400 regsub -all {\{||\}} $props $emptyString props
401 if {[
string first "noadd" $props] == -1} {
402 set_global_assignment -name $file_type $cur_file
404 regsub -all {noadd} $props $emptyString props
408 if {[
string first "nogenerate" $props] == -1} {
412 set_global_assignment -name $file_type $cur_file -library $rootlib
417 if {$ext == ".con"} {
418 set vld_exts {.sdc .pin .dcf .gcf .pdc .ndc .fdc .crt .vcd }
419 foreach con_file $lib_files {
421 set con_ext [
file extension $con_file]
422 if {[
IsInList [
file extension $con_file] $vld_exts]} {
423 set option [
string map {. -} $con_ext]
424 set option [
string map {fdc net_fdc} $option]
425 set option [
string map {pdc io_pdc} $option]
426 create_links -convert_EDN_to_HDL 0 -library {work} $option $con_file
428 set props [
DictGet $properties $con_file]
430 if {$con_ext == ".sdc"} {
431 if {[lsearch $props "notiming"] >= 0} {
432 Msg Info "Excluding $con_file from timing verification..."
434 Msg Info "Adding $con_file to time verification"
435 append timing_conf_command " -file $con_file"
439 if {[lsearch $props "nosynth"] >= 0} {
440 Msg Info "Excluding $con_file from synthesis..."
442 Msg Info "Adding $con_file to synthesis"
443 append synth_conf_command " -file $con_file"
448 if {$con_ext == ".pdc" || $con_ext == ".sdc"} {
449 if {[lsearch $props "noplace"] >= 0} {
450 Msg Info "Excluding $con_file from place and route..."
452 Msg Info "Adding $con_file to place and route"
453 append place_conf_command " -file $con_file"
458 Msg CriticalWarning "Constraint file $con_file does not have a valid extension. Allowed extensions are: \n $vld_exts"
461 }
elseif {$ext == ".src"} {
462 foreach f $lib_files {
463 Msg Debug "Adding source $f to library $rootlib..."
464 create_links -library $rootlib -hdl_source $f
466 }
elseif {$ext == ".sim"} {
467 Msg Debug "Adding stimulus file $f to library..."
468 create_links -library $rootlib -stimulus $f
470 build_design_hierarchy
471 foreach cur_file $lib_files {
475 set props [
DictGet $properties $cur_file]
478 set top [
lindex [regexp -inline {\ytop\s*=\s*(.+?)\y.*} $props] 1]
480 Msg Info "Setting $top as top module for file set $rootlib..."
481 set globalSettings::synth_top_module "${top}::$rootlib"
486 if {$ext == ".src" || $ext == ".con" || $ext == ".ext"} {
487 foreach f $lib_files {
488 Msg Debug "Diamond: adding source file $f to library $rootlib..."
489 prj_src add -work $rootlib $f
490 set props [
DictGet $properties $f]
492 set top [
lindex [regexp -inline {\ytop\s*=\s*(.+?)\y.*} $props] 1]
494 Msg Info "Setting $top as top module for the project..."
495 set globalSettings::synth_top_module $top
499 if {[lsearch -inline -regexp $props "enable"] >= 0} {
500 Msg Debug "Setting $f as active Logic Preference file"
504 }
elseif {$ext == ".sim"} {
505 foreach f $lib_files {
506 Msg Debug "Diamond Adding simulation file $f to library $rootlib..."
507 prj_src add -work $rootlib -simulate_only $f
517 if {[
DictGet $filesets "sim_1"] == ""} {
518 delete_fileset -quiet [get_filesets -quiet "sim_1"]
524 if {$synth_conf == 1} {
525 Msg Info $synth_conf_command
526 eval $synth_conf_command
528 if {$timing_conf == 1} {
529 Msg Info $timing_conf_command
530 eval $timing_conf_command
532 if {$place_conf == 1} {
533 Msg Info $place_conf_command
534 eval $place_conf_command
540 proc ALLOWED_PROPS {} {
541 return [dict create ".vhd" [list "93" "nosynth" "noimpl" "nosim" "1987" "1993" "2008" "2019"] \
542 ".vhdl" [list "93" "nosynth" "noimpl" "nosim" "1987" "1993" "2008" "2019"] \
543 ".bd" [list "nosim"] \
544 ".v" [list "SystemVerilog" "verilog_header" "nosynth" "noimpl" "nosim" "1995" "2001"] \
545 ".sv" [list "verilog" "verilog_header" "nosynth" "noimpl" "nosim" "2005" "2009"] \
546 ".do" [list "nosim"] \
547 ".udo" [list "nosim"] \
548 ".xci" [list "nosynth" "noimpl" "nosim" "locked"] \
549 ".xdc" [list "nosynth" "noimpl"] \
550 ".tcl" [list "nosynth" "noimpl" "nosim" "source" "qsys" "noadd"\
551 "--block-symbol-file" "--clear-output-directory" "--example-design"\
552 "--export-qsys-script" "--family" "--greybox" "--ipxact"\
553 "--jvm-max-heap-size" "--parallel" "--part" "--search-path"\
554 "--simulation" "--synthesis" "--testbench" "--testbench-simulation"\
555 "--upgrade-ip-cores" "--upgrade-variation-file"
557 ".qsys" [list "nogenerate" "noadd" "--block-symbol-file" "--clear-output-directory" "--example-design"\
558 "--export-qsys-script" "--family" "--greybox" "--ipxact" "--jvm-max-heap-size" "--parallel"\
559 "--part" "--search-path" "--simulation" "--synthesis" "--testbench" "--testbench-simulation"\
560 "--upgrade-ip-cores" "--upgrade-variation-file"
562 ".sdc" [list "notiming" "nosynth" "noplace"] \
563 ".elf" [list "scoped_to_ref" "scoped_to_cells" "nosim" "noimpl"] \
564 ".pdc" [list "nosynth" "noplace"] \
565 ".lpf" [list "enable"]]
576 proc BinaryStepName {part} {
578 return "WRITE_DEVICE_IMAGE"
582 return "WRITE_BITSTREAM"
591 proc CheckSyntax {project_name repo_path {project_file ""}} {
593 set syntax [check_syntax -return_string]
594 if {[
string first "CRITICAL" $syntax] != -1} {
599 lassign [
GetHogFiles -list_files "*.src" "$repo_path/Top/$project_name/list/" $repo_path] src_files dummy
600 dict for {lib files} $src_files {
602 set file_extension [file extension $f]
603 if {$file_extension == ".vhd" || $file_extension == ".vhdl" || $file_extension == ".v" || $file_extension == ".sv"} {
604 if {[catch {execute_module -tool map -args "--analyze_file=$f"} result]} {
605 Msg Error "\nResult: $result\n"
606 Msg Error "Check syntax failed.\n"
609 Msg Info "Check syntax was successful for $f.\n"
611 Msg Warning "Found syntax error in file $f:\n $result\n"
618 lassign [
GetProjectFiles $project_file] prjLibraries prjProperties prjSimLibraries prjConstraints prjSrcSets prjSimSets prjConSets
619 dict for {lib sources} $prjLibraries {
620 if {[file extension $lib] == ".src"} {
622 Msg Info "Checking Syntax of $f"
628 Msg Info "The Checking Syntax is not supported by this IDE. Skipping..."
633 proc CloseProject {} {
655 proc CompareVersions {ver1 ver2} {
664 if {[regexp {v(\d+)\.(\d+)\.(\d+)} $ver1 - x y z]} {
665 set ver1 [list $x $y $z]
667 if {[regexp {v(\d+)\.(\d+)\.(\d+)} $ver2 - x y z]} {
668 set ver2 [list $x $y $z]
672 set v1 [
join $ver1 ""]
674 set v2 [
join $ver2 ""]
677 if {[
string is integer $v1] && [
string is integer $v2]} {
678 set ver1 [
expr {[scan [lindex $ver1 0] %d] * 1000000 + [scan [lindex $ver1 1] %d] * 1000 + [scan [lindex $ver1 2] %d]}]
679 set ver2 [
expr {[scan [lindex $ver2 0] %d] * 1000000 + [scan [lindex $ver2 1] %d] * 1000 + [scan [lindex $ver2 2] %d]}]
683 }
elseif {$ver1 == $ver2} {
689 Msg Warning "Version is not numeric: $ver1, $ver2"
699 proc CheckExtraFiles {libraries constraints simlibraries} {
702 lassign [
GetProjectFiles] prjLibraries prjProperties prjSimLibraries prjConstraints
703 set prj_dir [get_property DIRECTORY [current_project]]
704 file mkdir "$prj_dir/.hog"
705 set extra_file_name "$prj_dir/.hog/extra.files"
706 set new_extra_file [open $extra_file_name "w"]
708 dict for {prjLib prjFiles} $prjLibraries {
709 foreach prjFile $prjFiles {
710 if {[file extension $prjFile] == ".xcix"} {
711 Msg Warning "IP $prjFile is packed in a .xcix core container. \
712 This files are not suitable for version control systems. We recommend to use .xci files instead."
715 if {[file extension $prjFile] == ".xci" && [get_property CORE_CONTAINER [get_files $prjFile]] != ""} {
716 Msg Info "$prjFile is a virtual IP file in a core container. Ignoring it..."
720 if {[IsInList $prjFile [DictGet $libraries $prjLib]] == 0} {
721 if {[file extension $prjFile] == ".bd"} {
722 # Generating BD products to save md5sum of already modified BD
723 Msg Info "Generating targets of $prjFile..."
724 generate_target all [get_files $prjFile]
726 puts $new_extra_file "$prjFile [Md5Sum $prjFile]"
727 Msg Info "$prjFile (lib: $prjLib) has been generated by an external script. Adding to $extra_file_name..."
731 close $new_extra_file
732 set extra_sim_file "$prj_dir/.hog/extrasim.files"
733 set new_extra_file [open $extra_sim_file "w"]
735 dict for {prjSimLib prjSimFiles} $prjSimLibraries {
736 foreach prjSimFile $prjSimFiles {
737 if {[IsInList $prjSimFile [DictGet $simlibraries $prjSimLib]] == 0} {
738 puts $new_extra_file "$prjSimFile [Md5Sum $prjSimFile]"
739 Msg Info "$prjSimFile (lib: $prjSimLib) has been generated by an external script. Adding to $extra_sim_file..."
743 close $new_extra_file
744 set extra_con_file "$prj_dir/.hog/extracon.files"
745 set new_extra_file [open $extra_con_file "w"]
747 dict for {prjConLib prjConFiles} $prjConstraints {
748 foreach prjConFile $prjConFiles {
749 if {[IsInList $prjConFile [DictGet $constraints $prjConLib]] == 0} {
750 puts $new_extra_file "$prjConFile [Md5Sum $prjConFile]"
751 Msg Info "$prjConFile has been generated by an external script. Adding to $extra_con_file..."
755 close $new_extra_file
762 proc CheckLatestHogRelease {{repo_path .}} {
765 set current_ver [
Git {describe --always}]
766 Msg Debug "Current version: $current_ver"
767 set current_sha [
Git "log $current_ver -1 --format=format:%H"]
768 Msg Debug "Current SHA: $current_sha"
771 if {[
OS] == "windows"} {
772 Msg Info "On windows we cannot set a timeout on 'git fetch', hopefully nothing will go wrong..."
775 Msg Info "Checking for latest Hog release, can take up to 5 seconds..."
778 set master_ver [
Git "describe origin/master"]
779 Msg Debug "Master version: $master_ver"
780 set master_sha [
Git "log $master_ver -1 --format=format:%H"]
781 Msg Debug "Master SHA: $master_sha"
782 set merge_base [
Git "merge-base $current_sha $master_sha"]
783 Msg Debug "merge base: $merge_base"
786 if {$merge_base != $master_sha} {
788 Msg Info "Version $master_ver has been released (https://gitlab.com/hog-cern/Hog/-/releases/$master_ver)"
789 Msg Status "You should consider updating Hog submodule with the following instructions:"
791 Msg Status "cd Hog && git checkout master && git pull"
793 Msg Status "Also update the ref: in your .gitlab-ci.yml to $master_ver"
797 Msg Info "Latest official version is $master_ver, nothing to do."
809 proc CheckYmlRef {repo_path allow_failure} {
810 if {$allow_failure} {
811 set MSG_TYPE CriticalWarning
816 if {[
catch {
package require yaml 0.3.3} YAMLPACKAGE]} {
817 Msg CriticalWarning "Cannot find package YAML, skipping consistency check of \"ref\" in gilab-ci.yaml file.\n Error message: $YAMLPACKAGE
818 You can fix this by installing package \"tcllib\""
826 if {[
file exists .gitlab-ci.yml]} {
830 if {[
file exists .gitlab-ci.yml]} {
831 set fp [open ".gitlab-ci.yml" r]
832 set file_data [read $fp]
835 Msg $MSG_TYPE "Cannot open file .gitlab-ci.yml"
839 set file_data "\n$file_data\n\n"
841 if {[
catch {::yaml::yaml2dict -stream $file_data} yamlDict]} {
842 Msg $MSG_TYPE "Parsing $repo_path/.gitlab-ci.yml failed. To fix this, check that yaml syntax is respected, remember not to use tabs."
846 dict for {dictKey dictValue} $yamlDict {
847 #looking for Hog include in .gitlab-ci.yml
848 if {"$dictKey" == "include" && (
849 [lsearch [split $dictValue " {}"] "/hog.yml"] != "-1" ||
850 [lsearch [split $dictValue " {}"] "/hog-dynamic.yml"] != "-1"
852 set YML_REF [lindex [split $dictValue " {}"] [expr {[lsearch -dictionary [split $dictValue " {}"] "ref"] + 1}]]
853 set YML_NAME [lindex [split $dictValue " {}"] [expr {[lsearch -dictionary [split $dictValue " {}"] "file"] + 1}]]
857 if {$YML_REF == ""} {
858 Msg Warning "Hog version not specified in the .gitlab-ci.yml. Assuming that master branch is used."
860 set YML_REF_F [
Git {name-rev --tags --name-only origin/master}]
863 set YML_REF_F [regsub -all "'" $YML_REF ""]
866 if {$YML_NAME == ""} {
867 Msg $MSG_TYPE "Hog included yml file not specified, assuming hog.yml"
868 set YML_NAME_F hog.yml
870 set YML_NAME_F [regsub -all "^/" $YML_NAME ""]
873 lappend YML_FILES $YML_NAME_F
879 if {[
catch {::yaml::yaml2dict -file $YML_NAME_F} yamlDict]} {
880 Msg $MSG_TYPE "Parsing $YML_NAME_F failed."
884 dict for {dictKey dictValue} $yamlDict {
885 #looking for included files
886 if {"$dictKey" == "include"} {
887 foreach v $dictValue {
888 lappend YML_FILES [lindex [split $v " "] [expr {[lsearch -dictionary [split $v " "] "local"] + 1}]]
894 Msg Info "Found the following yml files: $YML_FILES"
896 set HOGYML_SHA [
GetSHA $YML_FILES]
897 lassign [
GitRet "log --format=%h -1 --abbrev=7 $YML_REF_F" $YML_FILES] ret EXPECTEDYML_SHA
899 lassign [
GitRet "log --format=%h -1 --abbrev=7 origin/$YML_REF_F" $YML_FILES] ret EXPECTEDYML_SHA
901 Msg $MSG_TYPE "Error in project .gitlab-ci.yml. ref: $YML_REF not found"
902 set EXPECTEDYML_SHA ""
905 if {!($EXPECTEDYML_SHA eq "")} {
906 if {$HOGYML_SHA == $EXPECTEDYML_SHA} {
907 Msg Info "Hog included file $YML_FILES matches with $YML_REF in .gitlab-ci.yml."
909 Msg $MSG_TYPE "HOG $YML_FILES SHA mismatch.
910 From Hog submodule: $HOGYML_SHA
911 From ref in .gitlab-ci.yml: $EXPECTEDYML_SHA
912 You can fix this in 2 ways: by changing the ref in your repository or by changing the Hog submodule commit"
915 Msg $MSG_TYPE "One or more of the following files could not be found $YML_FILES in Hog at $YML_REF"
918 Msg Info ".gitlab-ci.yml not found in $repo_path. Skipping this step"
939 proc CompareLibDicts {proj_libs list_libs proj_sets list_sets proj_props list_props {severity "CriticalWarning"} {outFile ""} {extraFiles ""}} {
940 set extra_files $extraFiles
942 set out_prjlibs $proj_libs
943 set out_prjprops $proj_props
945 dict for {prjSet prjLibraries} $proj_sets {
946 # Check if sets is also in list files
947 if {[IsInList $prjSet $list_sets]} {
948 set listLibraries [DictGet $list_sets $prjSet]
949 # Loop over libraries in fileset
950 foreach prjLib $prjLibraries {
951 set prjFiles [DictGet $proj_libs $prjLib]
952 # Check if library exists in list files
953 if {[IsInList $prjLib $listLibraries]} {
954 # Loop over files in library
955 set listFiles [DictGet $list_libs $prjLib]
956 foreach prjFile $prjFiles {
957 set idx [lsearch -exact $listFiles $prjFile]
958 set listFiles [lreplace $listFiles $idx $idx]
960 # File is in project but not in list libraries, check if it was generated at creation time...
961 if {[dict exists $extra_files $prjFile]} {
962 # File was generated at creation time, checking the md5sum
963 # Removing the file from the prjFiles list
964 set idx2 [lsearch -exact $prjFiles $prjFile]
965 set prjFiles [lreplace $prjFiles $idx2 $idx2]
966 set new_md5sum [Md5Sum $prjFile]
967 set old_md5sum [DictGet $extra_files $prjFile]
968 if {$new_md5sum != $old_md5sum} {
969 # tclint-disable-next-line line-length
970 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
973 set extra_files [dict remove $extra_files $prjFile]
975 # File is neither in list files nor in extra_files
976 MsgAndLog "$prjFile was found in project but not in list files or .hog/extra.files" $severity $outFile
980 # File is both in list files and project, checking properties...
981 set prjProps [DictGet $proj_props $prjFile]
982 set listProps [DictGet $list_props $prjFile]
983 # Check if it is a potential sourced file
984 if {[IsInList "nosynth" $prjProps] && [IsInList "noimpl" $prjProps] && [IsInList "nosim" $prjProps]} {
985 # Check if it is sourced
986 set idx_source [lsearch -exact $listProps "source"]
987 if {$idx_source >= 0} {
988 # It is sourced, let's replace the individual properties with source
989 set idx [lsearch -exact $prjProps "noimpl"]
990 set prjProps [lreplace $prjProps $idx $idx]
991 set idx [lsearch -exact $prjProps "nosynth"]
992 set prjProps [lreplace $prjProps $idx $idx]
993 set idx [lsearch -exact $prjProps "nosim"]
994 set prjProps [lreplace $prjProps $idx $idx]
995 lappend prjProps "source"
999 foreach prjProp $prjProps {
1000 set idx [lsearch -exact $listProps $prjProp]
1001 set listProps [lreplace $listProps $idx $idx]
1003 MsgAndLog "Property $prjProp of $prjFile was set in project but not in list files" $severity $outFile
1008 foreach listProp $listProps {
1009 if {[string first $listProp "topsim="] == -1 && [string first $listProp "enable"] == -1} {
1010 MsgAndLog "Property $listProp of $prjFile was found in list files but not set in project." $severity $outFile
1015 # Update project prjProps
1016 dict set out_prjprops $prjFile $prjProps
1019 # Loop over remaining files in list libraries
1020 foreach listFile $listFiles {
1021 MsgAndLog "$listFile was found in list files but not in project." $severity $outFile
1025 # Check extra files again...
1026 foreach prjFile $prjFiles {
1027 if {[dict exists $extra_files $prjFile]} {
1028 # File was generated at creation time, checking the md5sum
1029 # Removing the file from the prjFiles list
1030 set idx2 [lsearch -exact $prjFiles $prjFile]
1031 set prjFiles [lreplace $prjFiles $idx2 $idx2]
1032 set new_md5sum [Md5Sum $prjFile]
1033 set old_md5sum [DictGet $extra_files $prjFile]
1034 if {$new_md5sum != $old_md5sum} {
1035 # tclint-disable-next-line line-length
1036 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
1039 set extra_files [dict remove $extra_files $prjFile]
1041 # File is neither in list files nor in extra_files
1042 MsgAndLog "$prjFile was found in project but not in list files or .hog/extra.files" $severity $outFile
1047 # Update prjLibraries
1048 dict set out_prjlibs $prjLib $prjFiles
1051 MsgAndLog "Fileset $prjSet found in project but not in list files" $severity $outFile
1056 return [list $n_diffs $extra_files $out_prjlibs $out_prjprops]
1066 proc CompareVHDL {file1 file2} {
1067 set a [open $file1 r]
1068 set b [open $file2 r]
1070 while {[
gets $a line] != -1} {
1071 set line [regsub {^[\t\s]*(.*)?\s*} $line "\\1"]
1072 if {![regexp {^$} $line] & ![regexp {^--} $line]} {
1078 while {[
gets $b line] != -1} {
1079 set line [regsub {^[\t\s]*(.*)?\s*} $line "\\1"]
1080 if {![regexp {^$} $line] & ![regexp {^--} $line]} {
1089 foreach x $f1 y $f2 {
1091 lappend diff "> $x\n< $y\n\n"
1104 proc Copy {i_dirs o_dir} {
1105 foreach i_dir $i_dirs {
1106 if {[
file isdirectory $i_dir] && [
file isdirectory $o_dir]} {
1107 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]])} {
1108 file delete -force $o_dir/[
file tail $i_dir]
1112 file copy -force $i_dir $o_dir
1127 proc CopyIPbusXMLs {proj_dir path dst {xml_version "0.0.0"} {xml_sha "00000000"} {use_ipbus_sw 0} {generate 0}} {
1128 if {$use_ipbus_sw == 1} {
1129 lassign [
ExecuteRet python3 -c "from __future__ import print_function; from sys import path;print(':'.join(path\[1:\]))"] ret msg
1131 set ::env(PYTHONPATH) $msg
1132 lassign [
ExecuteRet gen_ipbus_addr_decode -h] ret msg
1139 Msg CriticalWarning "Problem while trying to run python: $msg"
1142 set dst [
file normalize $dst]
1144 if {$can_generate == 0} {
1145 if {$generate == 1} {
1146 Msg Error "Cannot generate IPbus address files, IPbus executable gen_ipbus_addr_decode not found or not working: $msg"
1149 Msg Warning "IPbus executable gen_ipbus_addr_decode not found or not working, will not verify IPbus address tables."
1156 set ipb_files [glob -nocomplain $proj_dir/list/*.ipb]
1157 set n_ipb_files [
llength $ipb_files]
1158 if {$n_ipb_files == 0} {
1159 Msg CriticalWarning "No files with .ipb extension found in $proj_dir/list."
1162 set libraries [dict create]
1163 set vhdl_dict [dict create]
1165 foreach ipb_file $ipb_files {
1171 set xmlfiles [dict get $libraries "xml.ipb"]
1173 set xml_list_error 0
1174 foreach xmlfile $xmlfiles {
1175 if {[
file isdirectory $xmlfile]} {
1176 Msg CriticalWarning "Directory $xmlfile listed in xml list file $list_file. Directories are not supported!"
1177 set xml_list_error 1
1180 if {[
file exists $xmlfile]} {
1181 if {[dict exists $vhdl_dict $xmlfile]} {
1182 set vhdl_file [
file normalize $path/[dict get $vhdl_dict $xmlfile]]
1186 lappend vhdls $vhdl_file
1187 set xmlfile [
file normalize $xmlfile]
1188 Msg Info "Copying $xmlfile to $dst and replacing place holders..."
1189 set in [open $xmlfile r]
1190 set out [open $dst/[
file tail $xmlfile] w]
1192 while {[
gets $in line] != -1} {
1193 set new_line [regsub {(.*)__VERSION__(.*)} $line "\\1$xml_version\\2"]
1194 set new_line2 [regsub {(.*)__GIT_SHA__(.*)} $new_line "\\1$xml_sha\\2"]
1195 puts $out $new_line2
1199 lappend xmls [
file tail $xmlfile]
1201 Msg Warning "XML file $xmlfile not found"
1204 if {${xml_list_error}} {
1205 Msg Error "Invalid files added to $list_file!"
1208 set cnt [
llength $xmls]
1209 Msg Info "$cnt xml file/s copied"
1212 if {$can_generate == 1} {
1215 file mkdir "address_decode"
1217 foreach x $xmls v $vhdls {
1219 set x [
file normalize ../$x]
1220 if {[
file exists $x]} {
1221 lassign [
ExecuteRet gen_ipbus_addr_decode --no-timestamp $x 2>&1] status log
1223 set generated_vhdl ./ipbus_decode_[
file rootname [
file tail $x]].vhd
1224 if {$generate == 1} {
1225 Msg Info "Copying generated VHDL file $generated_vhdl into $v (replacing if necessary)"
1226 file copy -force -- $generated_vhdl $v
1228 if {[
file exists $v]} {
1230 set n [
llength $diff]
1232 Msg CriticalWarning "$v does not correspond to its XML $x, [
expr {$n / 3}] line/s differ:"
1233 Msg Status [
join $diff "\n"]
1234 set diff_file [open ../diff_[
file rootname [
file tail $x]].txt w]
1235 puts $diff_file $diff
1238 Msg Info "[
file tail $x] and $v match."
1241 Msg Warning "VHDL address map file $v not found."
1245 Msg Warning "Address map generation failed for [
file tail $x]: $log"
1248 Msg Warning "Copied XML file $x not found."
1251 Msg Info "Skipped verification of [
file tail $x] as no VHDL file was specified."
1255 file delete -force address_decode
1267 proc DescriptionFromConf {conf_file} {
1268 set f [open $conf_file "r"]
1269 set lines [
split [read $f] "\n"]
1271 set second_line [
lindex $lines 1]
1274 if {![regexp {\#+ *(.+)} $second_line - description]} {
1278 if {[regexp -all {test|Test|TEST} $description]} {
1279 set description "test"
1292 proc DictGet {dictName keyName {default ""}} {
1293 if {[dict exists $dictName $keyName]} {
1294 return [dict get $dictName $keyName]
1305 proc DictSort {dict args} {
1307 foreach key [lsort {*}$args [dict keys $dict]] {
1308 dict set res $key [dict get $dict $key]
1318 proc DoxygenVersion {target_version} {
1319 set ver [
split $target_version "."]
1320 set v [
Execute doxygen --version]
1321 Msg Info "Found Doxygen version: $v"
1322 set current_ver [
split $v ". "]
1323 set target [
expr {[lindex $ver 0] * 100000 + [lindex $ver 1] * 100 + [lindex $ver 2]}]
1324 set current [
expr {[lindex $current_ver 0] * 100000 + [lindex $current_ver 1] * 100 + [lindex $current_ver 2]}]
1326 return [
expr {$target <= $current}]
1337 proc eos {command {attempt 1}} {
1339 if {![
info exists env(EOS_MGM_URL)]} {
1340 Msg Warning "Environment variable EOS_MGM_URL not set, setting it to default value root://eosuser.cern.ch"
1341 set ::env(EOS_MGM_URL) "root://eosuser.cern.ch"
1344 Msg Warning "The value of attempt should be 1 or more, not $attempt, setting it to 1 as default"
1347 for {
set i 0} {$i < $attempt} {
incr i} {
1348 set ret [
catch {
exec -ignorestderr eos {*}$command} result]
1353 set wait [
expr {1 + int(rand() * 29)}]
1354 Msg Warning "Command $command failed ($i/$attempt): $result, trying again in $wait seconds..."
1355 after [
expr {$wait * 1000}]
1359 return [list $ret $result]
1369 proc Execute {args} {
1373 Msg Error "Command [
join $args] returned error code: $ret"
1387 proc ExecuteRet {args} {
1389 if {[
llength $args] == 0} {
1390 Msg CriticalWarning "No argument given"
1394 set ret [
catch {
exec -ignorestderr {*}$args} result]
1397 return [list $ret $result]
1404 proc ExtractFilesSection {file_data} {
1405 set in_files_section 0
1408 foreach line $file_data {
1409 if {[regexp {^ *\[ *files *\]} $line]} {
1410 set in_files_section 1
1413 if {$in_files_section} {
1414 if {[regexp {^ *\[.*\]} $line]} {
1417 lappend result $line
1422 if {!$in_files_section} {
1436 proc ExtractVersionFromTag {tag} {
1437 if {[regexp {^(?:b(\d+))?v(\d+)\.(\d+).(\d+)(?:-\d+)?$} $tag -> mr M m p]} {
1442 Msg Warning "Repository tag $tag is not in a Hog-compatible format."
1448 return [list $M $m $p $mr]
1458 proc FileCommitted {File} {
1460 set currentDir [
pwd]
1461 cd [
file dirname [
file normalize $File]]
1462 set GitLog [
Git ls-files [
file tail $File]]
1463 if {$GitLog == ""} {
1464 Msg CriticalWarning "File [
file normalize $File] is not in the git repository. Please add it with:\n git add [
file normalize $File]\n"
1475 proc FindCommonGitChild {SHA1 SHA2} {
1477 set commits [
Git {log --oneline --merges}]
1480 foreach line [
split $commits "\n"] {
1481 set commit [
lindex [
split $line] 0]
1485 set ancestor $commit
1498 proc findFiles {basedir pattern} {
1501 set basedir [
string trimright [
file join [
file normalize $basedir] { }]]
1507 foreach fileName [glob -nocomplain -type {f r} -path $basedir $pattern] {
1508 lappend fileList $fileName
1512 foreach dirName [glob -nocomplain -type {d r} -path $basedir *] {
1515 set subDirList [
findFiles $dirName $pattern]
1516 if {[
llength $subDirList] > 0} {
1517 foreach subDirFile $subDirList {
1518 lappend fileList $subDirFile
1529 proc FindFileType {file_name} {
1530 set extension [
file extension $file_name]
1533 set file_extension "USE_SIGNALTAP_FILE"
1536 set file_extension "VHDL_FILE"
1539 set file_extension "VHDL_FILE"
1542 set file_extension "VERILOG_FILE"
1545 set file_extension "SYSTEMVERILOG_FILE"
1548 set file_extension "SDC_FILE"
1551 set file_extension "PDC_FILE"
1554 set file_extension "NDC_FILE"
1557 set file_extension "FDC_FILE"
1560 set file_extension "SOURCE_FILE"
1563 set file_extension "IP_FILE"
1566 set file_extension "QSYS_FILE"
1569 set file_extension "QIP_FILE"
1572 set file_extension "SIP_FILE"
1575 set file_extension "BSF_FILE"
1578 set file_extension "BDF_FILE"
1581 set file_extension "COMMAND_MACRO_FILE"
1584 set file_extension "VQM_FILE"
1587 set file_extension "ERROR"
1588 Msg Error "Unknown file extension $extension"
1591 return $file_extension
1598 proc FindNewestVersion {versions} {
1599 set new_ver 00000000
1600 foreach ver $versions {
1602 if {[
expr 0x$ver > 0x$new_ver]} {
1614 proc FindVhdlVersion {file_name} {
1615 set extension [
file extension $file_name]
1618 set vhdl_version "-hdl_version VHDL_2008"
1621 set vhdl_version "-hdl_version VHDL_2008"
1628 return $vhdl_version
1635 proc FormatGeneric {generic} {
1636 if {[
string is integer "0x$generic"]} {
1637 return [
format "32'h%08X" "0x$generic"]
1640 return [
format "32'h%08X" 0]
1650 proc GenerateBitstream {{run_folder ""} {repo_path .} {njobs 1}} {
1651 Msg Info "Starting write bitstream flow..."
1653 set revision [get_current_revision]
1654 if {[
catch {execute_module -tool asm} result]} {
1655 Msg Error "Result: $result\n"
1656 Msg Error "Generate bitstream failed. See the report file.\n"
1658 Msg Info "Generate bitstream was successful for revision $revision.\n"
1661 Msg Info "Run GENERATEPROGRAMMINGDATA ..."
1662 if {[
catch {run_tool -name {GENERATEPROGRAMMINGDATA}}]} {
1663 Msg Error "GENERATEPROGRAMMINGDATA FAILED!"
1665 Msg Info "GENERATEPROGRAMMINGDATA PASSED."
1667 Msg Info "Sourcing Hog/Tcl/integrated/post-bitstream.tcl"
1668 source $repo_path/Hog/Tcl/integrated/post-bitstream.tcl
1670 prj_run Export -impl Implementation0 -task Bitgen
1680 proc GenerateQsysSystem {qsysFile commandOpts} {
1681 if {[
file exists $qsysFile] != 0} {
1682 set qsysPath [
file dirname $qsysFile]
1683 set qsysName [
file rootname [
file tail $qsysFile]]
1684 set qsysIPDir "$qsysPath/$qsysName"
1685 set qsysLogFile "$qsysPath/$qsysName.qsys-generate.log"
1688 if {![
info exists ::env(QSYS_ROOTDIR)]} {
1689 if {[
info exists ::env(QUARTUS_ROOTDIR)]} {
1690 set qsys_rootdir "$::env(QUARTUS_ROOTDIR)/sopc_builder/bin"
1691 Msg Warning "The QSYS_ROOTDIR environment variable is not set! I will use $qsys_rootdir"
1693 Msg CriticalWarning "The QUARTUS_ROOTDIR environment variable is not set! Assuming all quartus executables are contained in your PATH!"
1696 set qsys_rootdir $::env(QSYS_ROOTDIR)
1699 set cmd "$qsys_rootdir/qsys-generate"
1700 set cmd_options "$qsysFile --output-directory=$qsysIPDir $commandOpts"
1701 if {![
catch {"exec $cmd -version"}] || [
lindex $::errorCode 0] eq "NONE"} {
1702 Msg Info "Executing: $cmd $cmd_options"
1703 Msg Info "Saving logfile in: $qsysLogFile"
1704 if {[
catch {
eval exec -ignorestderr "$cmd $cmd_options >>& $qsysLogFile"} ret opt]} {
1705 set makeRet [
lindex [dict get $opt -errorcode] end]
1706 Msg CriticalWarning "$cmd returned with $makeRet"
1709 Msg Error " Could not execute command $cmd"
1713 set qsysIPFileList [
concat \
1714 [glob -nocomplain -directory $qsysIPDir -types f *.ip *.qip] \
1715 [glob -nocomplain -directory "$qsysIPDir/synthesis" -types f *.ip *.qip *.vhd *.vhdl]
1717 foreach qsysIPFile $qsysIPFileList {
1718 if {[
file exists $qsysIPFile] != 0} {
1720 set_global_assignment -name $qsysIPFileType $qsysIPFile
1722 set IpMd5Sum [
Md5Sum $qsysIPFile]
1724 set fileDir [
file normalize "./hogTmp"]
1725 set fileName "$fileDir/.hogQsys.md5"
1726 if {![
file exists $fileDir]} {
1729 set hogQsysFile [open $fileName "a"]
1730 set fileEntry "$qsysIPFile\t$IpMd5Sum"
1731 puts $hogQsysFile $fileEntry
1736 Msg ERROR "Error while generating ip variations from qsys: $qsysFile not found!"
1746 proc GenericToSimulatorString {prop_dict target} {
1748 dict for {theKey theValue} $prop_dict {
1757 regexp {([0-9]*)('h)([0-9a-fA-F]*)} $theValue valueHexFull valueNumBits valueHexFlag valueHex
1758 regexp {^([0-9]*)$} $theValue valueIntFull ValueInt
1759 regexp {(?!^\d+$)^.+$} $theValue valueStrFull ValueStr
1760 if {[string tolower $target] == "vivado" || [string tolower $target] == "xsim"} {
1761 if {$valueNumBits != "" && $valueHexFlag != "" && $valueHex != ""} {
1762 set prj_generics "$prj_generics $theKey=$valueHexFull"
1763 } elseif {$valueIntFull != "" && $ValueInt != ""} {
1764 set prj_generics "$prj_generics $theKey=$ValueInt"
1765 } elseif {$valueStrFull != "" && $ValueStr != ""} {
1766 set prj_generics "$prj_generics $theKey=\"$ValueStr\""
1768 set prj_generics "$prj_generics $theKey=\"$theValue\""
1770 } elseif {[lsearch -exact [GetSimulators] [string tolower $target]] >= 0} {
1771 if {$valueNumBits != "" && $valueHexFlag != "" && $valueHex != ""} {
1773 scan $valueNumBits %d numBits
1775 scan $valueHex %x numHex
1776 binary scan [binary format "I" $numHex] "B*" binval
1777 set numBits [expr {$numBits - 1}]
1778 set numBin [string range $binval end-$numBits end]
1779 set prj_generics "$prj_generics $theKey=\"$numBin\""
1780 } elseif {$valueIntFull != "" && $ValueInt != ""} {
1781 set prj_generics "$prj_generics $theKey=$ValueInt"
1782 } elseif {$valueStrFull != "" && $ValueStr != ""} {
1783 set prj_generics "$prj_generics {$theKey=\"$ValueStr\"}"
1785 set prj_generics "$prj_generics {$theKey=\"$theValue\"}"
1788 Msg Warning "Target : $target not implemented"
1791 return $prj_generics
1799 proc GetConfFiles {proj_dir} {
1800 if {![
file isdirectory $proj_dir]} {
1801 Msg Error "$proj_dir is supposed to be the top project directory"
1804 set conf_file [
file normalize $proj_dir/hog.conf]
1805 set sim_file [
file normalize $proj_dir/sim.conf]
1806 set pre_tcl [
file normalize $proj_dir/pre-creation.tcl]
1807 set post_tcl [
file normalize $proj_dir/post-creation.tcl]
1809 return [list $conf_file $sim_file $pre_tcl $post_tcl]
1818 proc GetCustomCommands {{directory .} {ret_commands 0}} {
1819 set commands_dict [dict create]
1820 set commands_files [glob -nocomplain $directory/*.tcl]
1821 set commands_string ""
1823 if {[
llength $commands_files] == 0} {
1827 if {$ret_commands == 0} {
1828 append commands_string "\nCustom Commands:\n"
1831 foreach file $commands_files {
1832 set base_name [
string toupper [
file rootname [
file tail $file]]]
1833 if {$ret_commands == 1} {
1834 append commands_string "
1836 Msg Info \"Running custom script: $file\"
1838 Msg Info \"Done running custom script...\"
1843 set f [open $file r]
1844 set first_line [
gets $f]
1846 if {[regexp -nocase "^#\s*$base_name:\s*(.*)" $first_line full_match script_des]} {
1847 append commands_string " - $base_name: $script_des\n"
1849 append commands_string " - $base_name: runs $file\n"
1853 return $commands_string
1859 proc GetDateAndTime {commit} {
1860 set clock_seconds [
clock seconds]
1863 set date [
Git "log -1 --format=%cd --date=format:%d%m%Y $commit"]
1864 set timee [
Git "log -1 --format=%cd --date=format:00%H%M%S $commit"]
1866 Msg Warning "Found Git version older than 2.9.3. Using current date and time instead of commit time."
1867 set date [
clock format $clock_seconds -format {%d%m%Y}]
1868 set timee [
clock format $clock_seconds -format {00%H%M%S}]
1870 return [list $date $timee]
1882 proc GetFile {file fileset} {
1885 set Files [get_files -all $file -of_object [get_filesets $fileset]]
1886 set f [
lindex $Files 0]
1894 puts "***DEBUG Hog:GetFile $file"
1903 proc GetFileGenerics {filename {entity ""}} {
1905 if {[
string equal $file_type "VERILOG_FILE"] || [
string equal $file_type "SYSTEMVERILOG_FILE"]} {
1907 }
elseif {[
string equal $file_type "VHDL_FILE"]} {
1910 Msg CriticalWarning "Could not determine extension of top level file."
1919 proc GetGenericsFromConf {proj_dir} {
1920 set generics_dict [dict create]
1921 set top_dir "Top/$proj_dir"
1922 set conf_file "$top_dir/hog.conf"
1925 if {[
file exists $conf_file]} {
1927 if {[dict exists $properties generics]} {
1928 set generics_dict [dict get $properties generics]
1931 Msg Warning "File $conf_file not found."
1933 return $generics_dict
1946 proc GetSimSets {project_name repo_path {simsets ""} {ghdl 0} {no_conf 0}} {
1947 set simsets_dict [dict create]
1948 set list_dir "$repo_path/Top/$project_name/list"
1950 if {$simsets != ""} {
1951 foreach s $simsets {
1952 set list_file "$list_dir/$s.sim"
1953 if {[
file exists $list_file]} {
1954 lappend list_files $list_file
1955 }
elseif {$s != "sim_1"} {
1956 Msg CriticalWarning "Simulation set list file $list_file not found."
1961 set list_files [glob -nocomplain -directory $list_dir "*.sim"]
1965 set proj_dir [
file normalize $repo_path/Top/$project_name]
1966 set sim_file [
file normalize $proj_dir/sim.conf]
1968 foreach list_file $list_files {
1969 set file_name [
file tail $list_file]
1970 set simset_name [
file rootname $file_name]
1971 set fp [open $list_file r]
1972 set file_data [read $fp]
1974 set data [
split $file_data "\n"]
1976 set firstline [
lindex $data 0]
1978 if {[regexp {^ *\# *Simulator} $firstline]} {
1979 set simulator_prop [regexp -all -inline {\S+} $firstline]
1980 set simulator [
string tolower [
lindex $simulator_prop end]]
1982 Msg Warning "Simulator not set in $simset_name.sim. \
1983 The first line of $simset_name.sim should be #Simulator <SIMULATOR_NAME>,\
1984 where <SIMULATOR_NAME> can be xsim, questa, modelsim, ghdl, riviera, activehdl,\
1985 ies, or vcs, e.g. #Simulator questa.\
1986 Setting simulator by default to xsim."
1987 set simulator "xsim"
1989 if {$simulator eq "skip_simulation"} {
1990 Msg Info "Skipping simulation for $simset_name"
1993 if {($ghdl == 1 && $simulator != "ghdl") || ($ghdl == 0 && $simulator == "ghdl")} {
1997 set SIM_PROPERTIES ""
1998 if {[
file exists $sim_file] && $no_conf == 0} {
1999 set SIM_PROPERTIES [
ReadConf $sim_file]
2002 set global_sim_props [dict create]
2003 dict set global_sim_props "properties" [
DictGet $SIM_PROPERTIES "sim"]
2004 dict set global_sim_props "generics" [
DictGet $SIM_PROPERTIES "generics"]
2005 dict set global_sim_props "hog" [
DictGet $SIM_PROPERTIES "hog"]
2008 set sim_dict [dict create]
2009 dict set sim_dict "simulator" $simulator
2010 if {[dict exists $SIM_PROPERTIES $simset_name]} {
2011 dict set sim_dict "properties" [
DictGet $SIM_PROPERTIES $simset_name]
2012 dict set sim_dict "generics" [
DictGet $SIM_PROPERTIES "$simset_name:generics"]
2013 dict set sim_dict "hog" [
DictGet $SIM_PROPERTIES "$simset_name:hog"]
2014 }
elseif {$no_conf == 0} {
2016 set conf_dict [
ReadConf $list_file]
2017 set sim_dict [
MergeDict $sim_dict $conf_dict 0]
2019 set sim_dict [
MergeDict $sim_dict $global_sim_props 0]
2020 dict set simsets_dict $simset_name $sim_dict
2022 return $simsets_dict
2030 proc GetSimsetGenericsFromConf {proj_dir} {
2031 set simsets_generics_dict [dict create]
2032 set top_dir "Top/$proj_dir"
2033 set conf_file "$top_dir/sim.conf"
2036 if {[
file exists $conf_file]} {
2039 set simsets_generics_dict [dict filter $properties key *:generics]
2041 Msg Warning "File $conf_file not found."
2043 return $simsets_generics_dict
2054 proc GetGroupName {proj_dir repo_dir} {
2055 if {[regexp {^(.*)/(Top|Projects)/+(.*?)/*$} $proj_dir dummy possible_repo_dir proj_or_top dir]} {
2057 if {[
file normalize $repo_dir] eq [
file normalize $possible_repo_dir]} {
2058 set group [
file dir $dir]
2059 if {$group == "."} {
2064 Msg Warning "Project directory $proj_dir seems to be in $possible_repo_dir which is not a the main Git repository $repo_dir."
2067 Msg Warning "Could not parse project directory $proj_dir"
2080 proc GetHogDescribe {sha {repo_path .}} {
2083 set new_sha "[
string toupper [
GetSHA]]"
2086 set new_sha [
string toupper $sha]
2106 proc GetHogFiles {args} {
2109 if {[
catch {
package require cmdline} ERROR]} {
2110 puts "$ERROR\n If you are running this script on tclsh, you can fix this by installing 'tcllib'"
2117 {list_files.arg "" "The file wildcard, if not specified all Hog list files will be looked for."}
2118 {sha_mode "Forwarded to ReadListFile, see there for info."}
2119 {ext_path.arg "" "Path for the external libraries forwarded to ReadListFile."}
2120 {print_log "Forwarded to ReadListFile, see there for info."}
2122 set usage "USAGE: GetHogFiles \[options\] <list path> <repository path>"
2123 if {[
catch {
array set options [
cmdline::getoptions args $parameters $usage]}] || [
llength $args] != 2} {
2127 set list_path [
lindex $args 0]
2128 set repo_path [
lindex $args 1]
2130 set list_files $options(list_files)
2131 set sha_mode $options(sha_mode)
2132 set ext_path $options(ext_path)
2133 set print_log $options(print_log)
2135 if {$sha_mode == 1} {
2136 set sha_mode_opt "-sha_mode"
2141 if {$print_log == 1} {
2142 set print_log_opt "-print_log"
2144 set print_log_opt ""
2148 if {$list_files == ""} {
2149 set list_files {.src,.con,.sim,.ext}
2151 set libraries [dict create]
2152 set properties [dict create]
2153 set list_files [glob -nocomplain -directory $list_path "*{$list_files}"]
2154 set filesets [dict create]
2156 foreach f $list_files {
2157 set ext [
file extension $f]
2158 if {$ext == ".ext"} {
2159 lassign [
ReadListFile {*}"$sha_mode_opt $print_log_opt $f $ext_path"] l p fs
2161 lassign [
ReadListFile {*}"$sha_mode_opt $print_log_opt $f $repo_path"] l p fs
2164 set properties [
MergeDict $p $properties]
2165 Msg Debug "list file $f, filesets: $fs"
2167 Msg Debug "Merged filesets $filesets"
2169 return [list $libraries $properties $filesets]
2175 proc GetIDECommand {proj_conf} {
2177 if {[
file exists $proj_conf]} {
2178 set ide_name_and_ver [
string tolower [
GetIDEFromConf $proj_conf]]
2179 set ide_name [
lindex [regexp -all -inline {\S+} $ide_name_and_ver] 0]
2181 if {$ide_name eq "vivado"} {
2182 set command "vivado"
2184 set before_tcl_script " -nojournal -nolog -mode batch -notrace -source "
2185 set after_tcl_script " -tclargs "
2187 }
elseif {$ide_name eq "planahead"} {
2188 set command "planAhead"
2190 set before_tcl_script " -nojournal -nolog -mode batch -notrace -source "
2191 set after_tcl_script " -tclargs "
2193 }
elseif {$ide_name eq "quartus"} {
2194 set command "quartus_sh"
2196 set before_tcl_script " -t "
2197 set after_tcl_script " "
2199 }
elseif {$ide_name eq "libero"} {
2202 set command "libero"
2203 set before_tcl_script "SCRIPT:"
2204 set after_tcl_script " SCRIPT_ARGS:\""
2206 }
elseif {$ide_name eq "diamond"} {
2207 set command "diamondc"
2208 set before_tcl_script " "
2209 set after_tcl_script " "
2211 }
elseif {$ide_name eq "ghdl"} {
2213 set before_tcl_script " "
2214 set after_tcl_script " "
2217 Msg Error "IDE: $ide_name not known."
2220 Msg Error "Configuration file $proj_conf not found."
2223 return [list $command $before_tcl_script $after_tcl_script $end_marker]
2229 proc GetIDEFromConf {conf_file} {
2230 set f [open $conf_file "r"]
2233 if {[regexp -all {^\# *(\w*) *(\d+\.\d+(?:\.\d+)?(?:\.\d+)?)?(_.*)? *$} $line dummy ide version patch]} {
2234 if {[
info exists version] && $version != ""} {
2240 set ret [list $ide $ver]
2242 Msg CriticalWarning "The first line of hog.conf should be \#<IDE name> <version>, \
2243 where <IDE name>. is quartus, vivado, planahead, libero, diamond or ghdl, \
2244 and <version> the tool version, e.g. \#vivado 2020.2. Will assume vivado."
2245 set ret [list "vivado" "0.0.0"]
2252 proc GetIDEName {} {
2254 return "ISE/PlanAhead"
2272 proc GetIDEVersion {} {
2275 regexp {\d+\.\d+(\.\d+)?} [version -short] ver
2280 regexp {[\.0-9]+} $quartus(version) ver
2283 set ver [get_libero_version]
2285 regexp {\d+\.\d+(\.\d+)?} [sys_install version] ver
2297 proc GetLinkedFile {link_file} {
2298 if {[
file type $link_file] eq "link"} {
2299 if {[
OS] == "windows"} {
2301 lassign [
ExecuteRet realpath $link_file] ret msg
2302 lassign [
ExecuteRet cygpath -m $msg] ret2 msg2
2303 if {$ret == 0 && $ret2 == 0} {
2305 Msg Debug "Found link file $link_file on Windows, the linked file is: $real_file"
2307 Msg CriticalWarning "[
file normalize $link_file] is a soft link. \
2308 Soft link are not supported on Windows and readlink.exe or cygpath.exe did not work: readlink=$ret: $msg, cygpath=$ret2: $msg2."
2309 set real_file $link_file
2313 set linked_file [
file link $link_file]
2314 set real_file [
file normalize [
file dirname $link_file]/$linked_file]
2317 if {![
file exists $real_file]} {
2318 Msg Warning "$link_file is a broken link, because the linked file: $real_file does not exist."
2321 Msg Warning "$link file is not a soft link"
2322 set real_file $link_file
2335 proc GetMaxThreads {proj_dir} {
2337 if {[
file exists $proj_dir/hog.conf]} {
2339 if {[dict exists $properties parameters]} {
2340 set propDict [dict get $properties parameters]
2341 if {[dict exists $propDict MAX_THREADS]} {
2342 set maxThreads [dict get $propDict MAX_THREADS]
2346 Msg Warning "File $proj_dir/hog.conf not found. Max threads will be set to default value 1"
2359 proc GetModifiedFiles {{repo_path "."} {pattern "."}} {
2362 set ret [
Git "ls-files --modified $pattern"]
2371 proc GetOptions {argv parameters} {
2374 set param_list [list]
2375 set option_list [list]
2377 foreach p $parameters {
2378 lappend param_list [
lindex $p 0]
2382 while {$index < [
llength $argv]} {
2383 set arg [
lindex $argv $index]
2384 if {[
string first - $arg] == 0} {
2385 set option [
string trimleft $arg "-"]
2387 lappend option_list $arg
2388 if {[lsearch $param_list ${option}*] >= 0 && [
string first ".arg" [lsearch -inline $param_list ${option}*]] >= 0} {
2389 lappend option_list [
lindex $argv $index]
2393 lappend arg_list $arg
2397 Msg Debug "Argv: $argv"
2398 Msg Debug "Options: $option_list"
2399 Msg Debug "Arguments: $arg_list"
2400 return [list $option_list $arg_list]
2418 proc GetProjectFiles {{project_file ""}} {
2419 set libraries [dict create]
2420 set simlibraries [dict create]
2421 set constraints [dict create]
2422 set properties [dict create]
2423 set consets [dict create]
2424 set srcsets [dict create]
2425 set simsets [dict create]
2428 set all_filesets [get_filesets]
2429 set simulator [get_property target_simulator [current_project]]
2430 set top [get_property "top" [current_fileset]]
2432 dict lappend properties $topfile "top=$top"
2434 foreach fs $all_filesets {
2435 if {$fs == "utils_1"} {
2440 set all_files [get_files -quiet -of_objects [get_filesets $fs]]
2441 set fs_type [get_property FILESET_TYPE [get_filesets $fs]]
2443 if {$fs_type == "BlockSrcs"} {
2445 set dict_fs "sources_1"
2449 foreach f $all_files {
2456 if {[
lindex [get_property IS_GENERATED [
GetFile $f $fs]] 0] != 0} {
2461 if {[get_property FILE_TYPE [
GetFile $f $fs]] == "Configuration Files"} {
2467 if {[get_property CORE_CONTAINER [
GetFile $f $fs]] != ""} {
2468 if {[
file extension $f] == ".xcix"} {
2469 set f [get_property CORE_CONTAINER [
GetFile $f $fs]]
2477 if {[get_property SCOPED_TO_REF [
GetFile $f $fs]] != ""} {
2478 dict lappend properties $f "scoped_to_ref=[get_property SCOPED_TO_REF [
GetFile $f $fs]]"
2483 if {[get_property SCOPED_TO_CELLS [
GetFile $f $fs]] != ""} {
2484 dict lappend properties $f "scoped_to_cells=[get_property SCOPED_TO_CELLS [
GetFile $f $fs]]"
2488 if {[
IsInList "PARENT_COMPOSITE_FILE" [list_property [
GetFile $f $fs]]]} {
2493 if {[
file tail $f] == "nocattrs.dat"} {
2498 if {[
file extension $f] != ".coe"} {
2499 set f [
file normalize $f]
2502 set type [get_property FILE_TYPE [
GetFile $f $fs]]
2504 set lib [get_property -quiet LIBRARY [
GetFile $f $fs]]
2507 Msg Debug "File $f Extension [
file extension $f] Type [
lindex $type 0]"
2509 if {[
string equal [
lindex $type 0] "VHDL"] && [
llength $type] == 1} {
2511 }
elseif {[
string equal [
lindex $type 0] "Block"] && [
string equal [
lindex $type 1] "Designs"]} {
2514 }
elseif {[
string equal $type "SystemVerilog"] && [
file extension $f] != ".sv"} {
2515 set prop "SystemVerilog"
2516 }
elseif {[
string equal [
lindex $type 0] "XDC"] && [
file extension $f] != ".xdc"} {
2518 }
elseif {[
string equal $type "Verilog Header"] && [
file extension $f] != ".vh" && [
file extension $f] != ".svh"} {
2519 set prop "verilog_header"
2520 }
elseif {[
string equal $type "Verilog Template"] && [
file extension $f] == ".v" && [
file extension $f] != ".sv"} {
2521 set prop "verilog_template"
2523 set type [
lindex $type 0]
2527 if {![
string equal $prop ""]} {
2528 dict lappend properties $f $prop
2531 if {[
string equal $fs_type "SimulationSrcs"]} {
2533 if {[
string equal $type "VHDL"]} {
2534 set library "${lib}.sim"
2536 set library "others.sim"
2540 dict lappend simsets $dict_fs $library
2543 dict lappend simlibraries $library $f
2544 }
elseif {[
string equal $type "VHDL"]} {
2547 dict lappend srcsets $dict_fs "${lib}.src"
2549 dict lappend libraries "${lib}.src" $f
2550 }
elseif {[
string first "IP" $type] != -1} {
2553 dict lappend srcsets $dict_fs "ips.src"
2555 dict lappend libraries "ips.src" $f
2556 Msg Debug "Appending $f to ips.src"
2557 }
elseif {[
string equal $fs_type "Constrs"]} {
2560 dict lappend consets $dict_fs "sources.con"
2562 dict lappend constraints "sources.con" $f
2566 dict lappend srcsets $dict_fs "others.src"
2568 dict lappend libraries "others.src" $f
2569 Msg Debug "Appending $f to others.src"
2572 if {[
lindex [get_property -quiet used_in_synthesis [
GetFile $f $fs]] 0] == 0} {
2573 dict lappend properties $f "nosynth"
2575 if {[
lindex [get_property -quiet used_in_implementation [
GetFile $f $fs]] 0] == 0} {
2576 dict lappend properties $f "noimpl"
2578 if {[
lindex [get_property -quiet used_in_simulation [
GetFile $f $fs]] 0] == 0} {
2579 dict lappend properties $f "nosim"
2581 if {[
lindex [get_property -quiet IS_MANAGED [
GetFile $f $fs]] 0] == 0 && [
file extension $f] != ".xcix"} {
2582 dict lappend properties $f "locked"
2588 dict lappend properties "Simulator" [get_property target_simulator [current_project]]
2591 set file [open $project_file r]
2592 set in_file_manager 0
2594 while {[
gets $file line] >= 0} {
2596 if {[regexp {^KEY ActiveRoot \"([^\"]+)\"} $line -> value]} {
2597 set top [
string range $value 0 [
expr {[string first "::" $value] - 1}]]
2601 if {[regexp {^LIST FileManager} $line]} {
2602 set in_file_manager 1
2607 if {$in_file_manager && [regexp {^ENDLIST} $line]} {
2612 if {$in_file_manager && [regexp {^VALUE \"([^\"]+)} $line -> value]} {
2615 lassign [
split $value ,] file_path file_type
2618 set library "others"
2619 while {[
gets $file line] >= 0} {
2620 if {$line == "ENDFILE"} {
2623 regexp {^LIBRARY=\"([^\"]+)} $line -> library
2624 regexp {^PARENT=\"([^\"]+)} $line -> parent_file
2626 Msg Debug "Found file ${file_path} in project.."
2627 if {$parent_file == ""} {
2628 if {$file_type == "hdl"} {
2630 if {[
IsInList "${library}.src" [
DictGet $srcsets "sources_1"]] == 0} {
2631 dict lappend srcsets "sources_1" "${library}.src"
2633 dict lappend libraries "${library}.src" $file_path
2637 if {[
GetModuleName $file_path] == [
string tolower $top] && $top != ""} {
2638 Msg Debug "Found top module $top in $file_path"
2639 dict lappend properties $file_path "top=$top"
2641 }
elseif {$file_type == "tb_hdl"} {
2643 dict lappend simsets "sim_1" "${library}.sim"
2645 dict lappend simlibraries "${library}.sim" $file_path
2646 }
elseif {$file_type == "io_pdc" || $file_type == "sdc"} {
2648 dict lappend consets "constrs_1" "sources.con"
2650 dict lappend constraints "sources.con" $file_path
2657 set fileData [read [open $project_file]]
2659 set project_path [
file dirname $project_file]
2662 regsub {<\?xml.*\?>} $fileData "" fileData
2665 regexp {<Implementation.*?>(.*)</Implementation>} $fileData -> implementationContent
2669 set sourceRegex {<Source name="([^"]*?)" type="([^"]*?)" type_short="([^"]*?)".*?>(.*?)</Source>}
2671 set optionsRegex {<Options(.*?)\/>}
2672 regexp $optionsRegex $implementationContent -> prj_options
2673 foreach option $prj_options {
2674 if {[regexp {^top=\"([^\"]+)\"} $option match result]} {
2679 while {[regexp $sourceRegex $implementationContent match name type type_short optionsContent]} {
2680 Msg Debug "Found file ${name} in project..."
2681 set file_path [
file normalize $project_path/$name]
2683 set optionsRegex {<Options(.*?)\/>}
2684 regexp $optionsRegex $optionsContent -> options
2685 set library "others"
2687 foreach option $options {
2688 if {[
string first "System Verilog" $option]} {
2691 if {[regexp {^lib=\"([^\"]+)\"} $option match1 result]} {
2696 if {[regexp {syn_sim="([^"]*?)"} $match match_sim simonly]} {
2701 if {$type_short == "VHDL" || $type_short == "Verilog" || $type_short == "IPX"} {
2702 if {$ext == ".src"} {
2703 if {[
IsInList "${library}${ext}" [
DictGet $srcsets "sources_1"]] == 0} {
2704 dict lappend srcsets "sources_1" "${library}${ext}"
2706 dict lappend libraries "${library}${ext}" $file_path
2707 }
elseif {$ext == ".sim"} {
2709 dict lappend simsets "sim_1" "${library}.sim"
2711 dict lappend simlibraries "${library}.sim" $file_path
2717 Msg Debug "Found top module $top in $file_path"
2718 dict lappend properties $file_path "top=$top"
2720 }
elseif {$type_short == "SDC"} {
2722 dict lappend consets "constrs_1" "sources.con"
2724 dict lappend constraints "sources.con" $file_path
2728 regsub -- $match $implementationContent "" implementationContent
2731 return [list $libraries $properties $simlibraries $constraints $srcsets $simsets $consets]
2738 proc GetProjectFlavour {proj_name} {
2740 set flavour [
string map {. ""} [
file extension $proj_name]]
2741 if {$flavour != ""} {
2742 if {[
string is integer $flavour]} {
2743 Msg Info "Project $proj_name has flavour = $flavour, the generic variable FLAVOUR will be set to $flavour"
2745 Msg Warning "Project name has a unexpected non numeric extension, flavour will be set to -1"
2762 proc GetProjectVersion {proj_dir repo_path {ext_path ""} {sim 0}} {
2763 if {![
file exists $proj_dir]} {
2764 Msg CriticalWarning "$proj_dir not found"
2774 Msg Warning "Repository is not clean"
2782 Msg Debug "Project version $v_proj, latest tag $v_last"
2784 Msg Info "The specified project was modified since official version."
2791 Msg Info "The specified project was modified in the latest official version $ret"
2792 }
elseif {$comp == -1} {
2793 Msg Info "The specified project was modified in a past official version $ret"
2809 proc GetRepoVersions {proj_dir repo_path {ext_path ""} {sim 0}} {
2810 if {[
catch {
package require cmdline} ERROR]} {
2811 puts "$ERROR\n If you are running this script on tclsh, you can fix this by installing 'tcllib'"
2826 lappend SHAs [
GetSHA {Hog}]
2830 if {[
Git {status --untracked-files=no --porcelain}] eq ""} {
2831 Msg Info "Hog submodule [
pwd] clean."
2832 lassign [
GetVer ./] hog_ver hog_hash
2834 Msg CriticalWarning "Hog submodule [
pwd] not clean, commit hash will be set to 0."
2835 set hog_hash "0000000"
2836 set hog_ver "00000000"
2841 if {[
Git {status --untracked-files=no --porcelain}] eq ""} {
2842 Msg Info "Git working directory [
pwd] clean."
2845 Msg CriticalWarning "Git working directory [
pwd] not clean, commit hash, and version will be set to 0."
2850 lassign [
GetVer [
join $conf_files]] top_ver top_hash
2851 lappend SHAs $top_hash
2852 lappend versions $top_ver
2859 lassign [
GetHogFiles -list_files "*.src" -sha_mode "./list/" $repo_path] src_files dummy
2860 dict for {f files} $src_files {
2861 # library names have a .src extension in values returned by GetHogFiles
2862 set name [file rootname [file tail $f]]
2863 if {[file ext $f] == ".oth"} {
2866 lassign [GetVer $files] ver hash
2867 # Msg Info "Found source list file $f, version: $ver commit SHA: $hash"
2869 lappend versions $ver
2871 lappend hashes $hash
2878 lassign [
GetHogFiles -list_files "*.con" -sha_mode "./list/" $repo_path] cons_files dummy
2879 dict for {f files} $cons_files {
2880 #library names have a .con extension in values returned by GetHogFiles
2881 set name [file rootname [file tail $f]]
2882 lassign [GetVer $files] ver hash
2883 #Msg Info "Found constraint list file $f, version: $ver commit SHA: $hash"
2885 Msg CriticalWarning "Constraints file $f not found in Git."
2887 lappend cons_hashes $hash
2889 lappend versions $ver
2896 lassign [
GetHogFiles -list_files "*.sim" -sha_mode "./list/" $repo_path] sim_files dummy
2897 dict for {f files} $sim_files {
2898 #library names have a .sim extension in values returned by GetHogFiles
2899 set name [file rootname [file tail $f]]
2900 lassign [GetVer $files] ver hash
2901 #Msg Info "Found simulation list file $f, version: $ver commit SHA: $hash"
2902 lappend sim_hashes $hash
2904 lappend versions $ver
2910 if {"{}" eq $cons_hashes} {
2912 Msg CriticalWarning "No hashes found for constraints files (not in git)"
2915 set cons_hash [
string tolower [
Git "log --format=%h -1 $cons_hashes"]]
2922 set ext_files [glob -nocomplain "./list/*.ext"]
2925 foreach f $ext_files {
2926 set name [
file rootname [
file tail $f]]
2929 lappend ext_names $name
2930 lappend ext_hashes $hash
2933 lappend versions $ext_ver
2936 set file_data [read $fp]
2938 set data [
split $file_data "\n"]
2940 foreach line $data {
2941 if {![regexp {^ *$} $line] & ![regexp {^ *\#} $line]} {
2943 set file_and_prop [regexp -all -inline {\S+} $line]
2944 set hdlfile [
lindex $file_and_prop 0]
2945 set hdlfile $ext_path/$hdlfile
2946 if {[
file exists $hdlfile]} {
2947 set hash [
lindex $file_and_prop 1]
2948 set current_hash [
Md5Sum $hdlfile]
2949 if {[
string first $hash $current_hash] == -1} {
2950 Msg CriticalWarning "File $hdlfile has a wrong hash. Current checksum: $current_hash, expected: $hash"
2958 if {[
llength [glob -nocomplain ./list/*.ipb]] > 0} {
2960 lassign [
GetHogFiles -list_files "*.ipb" -sha_mode "./list/" $repo_path] xml_files dummy
2961 lassign [
GetVer [dict get $xml_files "xml.ipb"]] xml_ver xml_hash
2962 lappend SHAs $xml_hash
2963 lappend versions $xml_ver
2967 Msg Info "This project does not use IPbus XMLs"
2972 set user_ip_repos ""
2973 set user_ip_repo_hashes ""
2974 set user_ip_repo_vers ""
2976 if {[
file exists [
lindex $conf_files 0]]} {
2977 set PROPERTIES [
ReadConf [
lindex $conf_files 0]]
2978 if {[dict exists $PROPERTIES main]} {
2979 set main [dict get $PROPERTIES main]
2980 dict for {p v} $main {
2981 if {[string tolower $p] == "ip_repo_paths"} {
2983 if {[file isdirectory "$repo_path/$repo"]} {
2984 set repo_file_list [glob -nocomplain "$repo_path/$repo/*"]
2985 if {[llength $repo_file_list] == 0} {
2986 Msg Warning "IP_REPO_PATHS property set to $repo in hog.conf but directory is empty."
2988 lappend user_ip_repos "$repo_path/$repo"
2997 foreach repo $user_ip_repos {
2998 if {[
file isdirectory $repo]} {
2999 set repo_file_list [glob -nocomplain "$repo/*"]
3000 if {[
llength $repo_file_list] != 0} {
3001 lassign [
GetVer $repo] ver sha
3002 lappend user_ip_repo_hashes $sha
3003 lappend user_ip_repo_vers $ver
3004 lappend versions $ver
3006 Msg Warning "IP_REPO_PATHS property set to $repo in hog.conf but directory is empty."
3009 Msg Warning "IP_REPO_PATHS property set to $repo in hog.conf but directory does not exist."
3018 while {$found == 0} {
3019 set global_commit [
Git "log --format=%h -1 --abbrev=7 $SHAs"]
3024 if {$common_child == 0} {
3025 Msg CriticalWarning "The commit $sha is not an ancestor of the global commit $global_commit, which is OK. \
3026 But $sha and $global_commit do not have any common child, which is NOT OK. \
3027 This is probably do to a REBASE that is forbidden in Hog methodology as it changes git history. \
3028 Hog cannot guarantee the accuracy of the SHAs. \
3029 A way to fix this is to make a commit that touches all the projects in the repositories (e.g. change the Hog version), \
3030 but please do not rebase in the official branches in the future."
3032 Msg Info "The commit $sha is not an ancestor of the global commit $global_commit, adding the first common child $common_child instead..."
3033 lappend SHAs $common_child
3043 set global_commit "0000000"
3044 set global_version "00000000"
3049 set top_hash [
format %+07s $top_hash]
3050 set cons_hash [
format %+07s $cons_hash]
3051 return [list $global_commit $global_version \
3052 $hog_hash $hog_ver $top_hash $top_ver \
3053 $libs $hashes $vers $cons_ver $cons_hash \
3054 $ext_names $ext_hashes $xml_hash $xml_ver \
3055 $user_ip_repos $user_ip_repo_hashes $user_ip_repo_vers]
3064 proc GetSHA {{path ""}} {
3066 lassign [
GitRet {log --format=%h --abbrev=7 -1}] status result
3068 return [
string tolower $result]
3070 Msg Error "Something went wrong while finding the latest SHA. Does the repository have a commit?"
3076 set repo_path [
lindex [
Git {rev-parse --show-toplevel}] 0]
3080 set file_in_module 0
3081 if {[
file exists $repo_path/.gitmodules]} {
3082 lassign [
GitRet "config --file $repo_path/.gitmodules --get-regexp path"] status result
3084 set submodules [
split $result "\n"]
3087 Msg Warning "Something went wrong while trying to find submodules: $result"
3090 foreach mod $submodules {
3091 set module [
lindex $mod 1]
3092 if {[
string first "$repo_path/$module" $f] == 0} {
3094 set file_in_module 1
3095 lappend paths "$repo_path/$module"
3100 if {$file_in_module == 0} {
3106 lassign [
GitRet {log --format=%h --abbrev=7 -1} $paths] status result
3108 return [
string tolower $result]
3110 Msg Error "Something went wrong while finding the latest SHA. Does the repository have a commit?"
3113 return [
string tolower $result]
3117 proc GetSimulators {} {
3118 set SIMULATORS [list "modelsim" "questa" "riviera" "activehdl" "ies" "vcs"]
3123 proc GetTopFile {} {
3125 set compile_order_prop [get_property source_mgmt_mode [current_project]]
3126 if {$compile_order_prop ne "All"} {
3127 Msg CriticalWarning "Compile order is not set to automatic, setting it now..."
3128 set_property source_mgmt_mode All [current_project]
3129 update_compile_order -fileset sources_1
3131 return [
lindex [get_files -quiet -compile_order sources -used_in synthesis -filter {FILE_TYPE =~ "VHDL*" || FILE_TYPE =~ "*Verilog*" }] end]
3132 }
elseif {[
IsISE]} {
3133 debug::design_graph_mgr -create [current_fileset]
3134 debug::design_graph -add_fileset [current_fileset]
3135 debug::design_graph -update_all
3136 return [
lindex [debug::design_graph -get_compile_order] end]
3138 Msg Error "GetTopFile not yet implemented for this IDE"
3143 proc GetTopModule {} {
3145 return [get_property top [current_fileset]]
3147 Msg Error "GetTopModule not yet implemented for this IDE"
3157 proc GetVer {path {force_develop 0}} {
3161 Msg CriticalWarning "Empty SHA found for ${path}. Commit to Git to resolve this warning."
3164 set p [
lindex $path 0]
3165 if {[
file isdirectory $p]} {
3168 cd [
file dirname $p]
3170 set repo_path [
Git {rev-parse --show-toplevel}]
3173 return [list [
GetVerFromSHA $SHA $repo_path $force_develop] $SHA]
3184 proc GetVerFromSHA {SHA repo_path {force_develop 0}} {
3186 Msg CriticalWarning "Empty SHA found"
3189 lassign [
GitRet "tag --sort=creatordate --contain $SHA -l v*.*.* -l b*v*.*.*"] status result
3192 if {[regexp {^ *$} $result]} {
3194 lassign [
GitRet "log --oneline --pretty=\"%d\""] status2 tag_list
3197 set pattern {tag: v\d+\.\d+\.\d+}
3198 set real_tag_list {}
3199 foreach x $tag_list {
3200 set x_untrimmed [regexp -all -inline $pattern $x]
3201 regsub "tag: " $x_untrimmed "" x_trimmed
3202 set tt [
lindex $x_trimmed 0]
3203 if {![
string equal $tt ""]} {
3204 lappend real_tag_list $tt
3208 Msg Debug "Cleaned up list: $real_tag_list."
3210 set sorted_tags [lsort -decreasing -command CompareVersions $real_tag_list]
3212 Msg Debug "Sorted Tag list: $sorted_tags"
3214 set tag [
lindex $sorted_tags 0]
3217 set pattern {v\d+\.\d+\.\d+}
3218 if {![regexp $pattern $tag]} {
3219 Msg CriticalWarning "No Hog version tags found in this repository."
3224 set repo_conf $repo_path/Top/repo.conf
3228 set hotfix_prefix "hotfix/"
3229 set minor_prefix "minor_version/"
3230 set major_prefix "major_version/"
3232 set enable_develop_branch $force_develop
3234 set branch_name [
Git {rev-parse --abbrev-ref HEAD}]
3236 if {[
file exists $repo_conf]} {
3237 set PROPERTIES [
ReadConf $repo_conf]
3239 if {[dict exists $PROPERTIES main]} {
3240 set mainDict [dict get $PROPERTIES main]
3243 if {[dict exists $mainDict ENABLE_DEVELOP_BRANCH]} {
3244 set enable_develop_branch [dict get $mainDict ENABLE_DEVELOP_BRANCH]
3250 if {[dict exists $PROPERTIES prefixes]} {
3251 set prefixDict [dict get $PROPERTIES prefixes]
3253 if {[dict exists $prefixDict HOTFIX]} {
3254 set hotfix_prefix [dict get $prefixDict HOTFIX]
3256 if {[dict exists $prefixDict MINOR_VERSION]} {
3257 set minor_prefix [dict get $prefixDict MINOR_VERSION]
3259 if {[dict exists $prefixDict MAJOR_VERSION]} {
3260 set major_prefix [dict get $prefixDict MAJOR_VERSION]
3266 if {$enable_develop_branch == 1} {
3267 if {[
string match "$hotfix_prefix*" $branch_name]} {
3272 if {[
string match "$major_prefix*" $branch_name]} {
3274 set version_level major
3275 }
elseif {[
string match "$minor_prefix*" $branch_name] || ($enable_develop_branch == 1 && $is_hotfix == 0)} {
3277 set version_level minor
3280 set version_level patch
3284 Msg CriticalWarning "Tag $tag does not contain a Hog compatible version in this repository."
3287 }
elseif {$mr == 0} {
3288 switch $version_level {
3303 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."
3309 set vers [
split $result "\n"]
3310 set ver [
lindex $vers 0]
3312 if {[regexp {^v.*$} $v]} {
3320 Msg CriticalWarning "Error while trying to find tag for $SHA"
3328 set M [
format %02X $M]
3329 set m [
format %02X $m]
3330 set c [
format %04X $c]
3331 }
elseif {$M > -1} {
3333 set M [
format %02X $M]
3334 set m [
format %02X $m]
3335 set c [
format %04X $c]
3337 Msg Warning "Tag does not contain a properly formatted version: $ver"
3338 set M [
format %02X 0]
3339 set m [
format %02X 0]
3340 set c [
format %04X 0]
3353 proc Git {command {files ""}} {
3354 lassign [
GitRet $command $files] ret result
3356 Msg Error "Code $ret returned by git running: $command -- $files"
3367 proc GetModuleName {filename} {
3369 if {![
file exists $filename]} {
3370 Msg CriticalWarning "Error: File $filename does not exist."
3375 set fileId [open $filename r]
3378 set file_content [read $fileId]
3384 if {[
file extension $filename] == ".vhd" || [
file extension $filename] == ".vhdl"} {
3386 set file_content [
string tolower $file_content]
3388 set pattern {(?m)^\s*entity\s+(\S+)\s+is}
3389 }
elseif {[
file extension $filename] == ".v" || [
file extension $filename] == ".sv"} {
3391 set pattern {\n\s*module\s*(\w+)(\s*|\(|\n)}
3393 Msg Debug "File is neither VHDL nor Verilog... Returning empty string..."
3398 if {[regexp $pattern $file_content match module_name]} {
3401 Msg Debug "No module was found in $filename. Returning an empty string..."
3409 proc GetVerilogGenerics {file} {
3410 set fp [open $file r]
3416 foreach line [
split $data "\n"] {
3417 regsub "^\\s*\/\/.*" $line "" line
3418 regsub "(.*)\/\/.*" $line {\1} line
3419 if {![
string equal $line ""]} {
3420 append lines $line " "
3425 regsub -all {/\*.*\*/} $lines "" lines
3428 set punctuation [list]
3429 foreach char [list "(" ")" ";" "," " " "!" "<=" ":=" "=" "\[" "\]"] {
3430 lappend punctuation $char "\000$char\000"
3434 set tokens [
split [
string map $punctuation $lines] \000]
3436 set parameters [dict create]
3445 foreach token $tokens {
3446 set token [
string trim $token]
3447 if {![
string equal "" $token]} {
3448 if {[
string equal [
string tolower $token] "parameter"]} {
3449 set state $PARAM_NAME
3450 }
elseif {[
string equal $token ")"] || [
string equal $token ";"]} {
3452 }
elseif {$state == $PARAM_WIDTH} {
3453 if {[
string equal $token "\]"]} {
3454 set state $PARAM_NAME
3456 }
elseif {$state == $PARAM_VALUE} {
3457 if {[
string equal $token ","]} {
3458 set state $PARAM_NAME
3459 }
elseif {[
string equal $token ";"]} {
3464 }
elseif {$state == $PARAM_NAME} {
3465 if {[
string equal $token "="]} {
3466 set state $PARAM_VALUE
3467 }
elseif {[
string equal $token "\["]} {
3468 set state $PARAM_WIDTH
3469 }
elseif {[
string equal $token ","]} {
3470 set state $PARAM_NAME
3471 }
elseif {[
string equal $token ";"]} {
3473 }
elseif {[
string equal $token ")"]} {
3476 dict set parameters $token "integer"
3489 proc GetVhdlGenerics {file {entity ""}} {
3490 set fp [open $file r]
3496 foreach line [
split $data "\n"] {
3497 regsub "^\\s*--.*" $line "" line
3498 regsub "(.*)--.*" $line {\1} line
3499 if {![
string equal $line ""]} {
3500 append lines $line " "
3505 set generic_block ""
3506 set generics [dict create]
3508 if {1 == [
string equal $entity ""]} {
3509 regexp {(?i).*entity\s+([^\s]+)\s+is} $lines _ entity
3512 set generics_regexp "(?i).*entity\\s+$entity\\s+is\\s+generic\\s*\\((.*)\\)\\s*;\\s*port.*end.*$entity"
3514 if {[regexp $generics_regexp $lines _ generic_block]} {
3516 foreach line [
split $generic_block ";"] {
3518 regexp {(.*):\s*([A-Za-z0-9_]+).*} $line _ generic type
3521 set splits [
split $generic ","]
3522 foreach split $splits {
3523 dict set generics [
string trim $split] [
string trim $type]
3531 proc GHDL {command logfile} {
3532 set ret [
catch {
exec -ignorestderr ghdl {*}$command >>& $logfile} result options]
3537 return [list $ret $result]
3549 proc GitRet {command {files ""}} {
3552 set ret [
catch {
exec -ignorestderr git {*}$command} result]
3554 set ret [
catch {
exec -ignorestderr git {*}$command -- {*}$files} result]
3556 return [list $ret $result]
3564 proc GitVersion {target_version} {
3565 set ver [
split $target_version "."]
3566 set v [
Git --version]
3568 set current_ver [
split [
lindex $v 2] "."]
3569 set target [
expr {[lindex $ver 0] * 100000 + [lindex $ver 1] * 100 + [lindex $ver 2]}]
3570 set current [
expr {[lindex $current_ver 0] * 100000 + [lindex $current_ver 1] * 100 + [lindex $current_ver 2]}]
3571 return [
expr {$target <= $current}]
3585 proc HandleIP {what_to_do xci_file ip_path repo_path {gen_dir "."} {force 0}} {
3586 if {!($what_to_do eq "push") && !($what_to_do eq "pull")} {
3587 Msg Error "You must specify push or pull as first argument."
3590 if {[
catch {
package require tar} TARPACKAGE]} {
3591 Msg CriticalWarning "Cannot find package tar. You can fix this by installing package \"tcllib\""
3600 if {[
string first "/eos/" $ip_path] == 0} {
3608 lassign [
eos "ls $ip_path"] ret result
3610 Msg CriticalWarning "Could not run ls for for EOS path: $ip_path (error: $result). \
3611 Either the drectory does not exist or there are (temporary) problem with EOS."
3615 Msg Info "IP remote directory path, on EOS, is set to: $ip_path"
3621 if {!([
file exists $xci_file])} {
3622 Msg CriticalWarning "Could not find $xci_file."
3628 set xci_path [
file dirname $xci_file]
3629 set xci_name [
file tail $xci_file]
3630 set xci_ip_name [
file rootname [
file tail $xci_file]]
3631 set xci_dir_name [
file tail $xci_path]
3632 set gen_path $gen_dir
3634 set hash [
Md5Sum $xci_file]
3635 set file_name $xci_name\_$hash
3637 Msg Info "Preparing to $what_to_do IP: $xci_name..."
3639 if {$what_to_do eq "push"} {
3643 lassign [
eos "ls $ip_path/$file_name.tar"] ret result
3648 Msg Info "IP already in the EOS repository, will not copy..."
3650 Msg Info "IP already in the EOS repository, will forcefully replace..."
3656 if {[
file exists "$ip_path/$file_name.tar"]} {
3658 Msg Info "IP already in the local repository, will not copy..."
3660 Msg Info "IP already in the local repository, will forcefully replace..."
3669 if {$will_copy == 1} {
3671 Msg Info "Looking for generated files in $gen_path..."
3672 set ip_gen_files [glob -nocomplain $gen_path/*]
3676 if {[
llength $ip_gen_files] > 0} {
3677 Msg Info "Found some IP synthesised files matching $xci_ip_name"
3678 if {$will_remove == 1} {
3679 Msg Info "Removing old synthesised directory $ip_path/$file_name.tar..."
3681 eos "rm -rf $ip_path/$file_name.tar" 5
3683 file delete -force "$ip_path/$file_name.tar"
3687 Msg Info "Creating local archive with IP generated files..."
3689 foreach f $ip_gen_files {
3690 if {$first_file == 0} {
3691 ::tar::create $file_name.tar "[
Relative [
file normalize $repo_path] $f]"
3694 ::tar::add $file_name.tar "[
Relative [
file normalize $repo_path] $f]"
3698 Msg Info "Copying IP generated files for $xci_name..."
3700 lassign [
ExecuteRet xrdcp -f -s $file_name.tar $::env(EOS_MGM_URL)//$ip_path/] ret msg
3702 Msg CriticalWarning "Something went wrong when copying the IP files to EOS. Error message: $msg"
3705 Copy "$file_name.tar" "$ip_path/"
3707 Msg Info "Removing local archive"
3708 file delete $file_name.tar
3710 Msg Warning "Could not find synthesized files matching $gen_path/$file_name*"
3713 }
elseif {$what_to_do eq "pull"} {
3715 lassign [
eos "ls $ip_path/$file_name.tar"] ret result
3717 Msg Info "Nothing for $xci_name was found in the EOS repository, cannot pull."
3721 set remote_tar "$::env(EOS_MGM_URL)//$ip_path/$file_name.tar"
3722 Msg Info "IP $xci_name found in the repository $remote_tar, copying it locally to $repo_path..."
3724 lassign [
ExecuteRet xrdcp -f -r -s $remote_tar $repo_path] ret msg
3726 Msg CriticalWarning "Something went wrong when copying the IP files to EOS. Error message: $msg"
3730 if {[
file exists "$ip_path/$file_name.tar"]} {
3731 Msg Info "IP $xci_name found in local repository $ip_path/$file_name.tar, copying it locally to $repo_path..."
3732 Copy $ip_path/$file_name.tar $repo_path
3734 Msg Info "Nothing for $xci_name was found in the local IP repository, cannot pull."
3740 if {[
file exists $file_name.tar]} {
3741 remove_files $xci_file
3742 Msg Info "Extracting IP files from archive to $repo_path..."
3743 ::tar::untar $file_name.tar -dir $repo_path -noperms
3744 Msg Info "Removing local archive"
3745 file delete $file_name.tar
3746 add_files -norecurse -fileset sources_1 $xci_file
3759 proc HexVersionToString {version} {
3760 scan [
string range $version 0 1] %x M
3761 scan [
string range $version 2 3] %x m
3762 scan [
string range $version 4 7] %x c
3767 proc ImportTclLib {} {
3769 if {[
info exists env(HOG_TCLLIB_PATH)]} {
3770 lappend auto_path $env(HOG_TCLLIB_PATH)
3773 puts "ERROR: To run Hog with Microsemi Libero SoC or Lattice Diamond, you need to define the HOG_TCLLIB_PATH variable."
3788 proc InitLauncher {script tcl_path parameters commands argv {custom_commands ""}} {
3789 set repo_path [
file normalize "$tcl_path/../.."]
3791 set bin_path [
file normalize "$tcl_path/../../bin"]
3792 set top_path [
file normalize "$tcl_path/../../Top"]
3794 set cmd_lines [
split $commands "\n"]
3796 set command_options [dict create]
3797 set directive_descriptions [dict create]
3798 set directive_names [dict create]
3799 set common_directive_names [dict create]
3801 foreach l $cmd_lines {
3803 if {[regexp {\\(.*) \{\#} $l minc d]} {
3804 lappend directives_with_projects $d
3808 if {[regexp {\\(.*) \{} $l minc regular_expression]} {
3809 lappend directive_regex $regular_expression
3813 if {[regexp {\#\s*NAME(\*)?:\s*(.*)\s*} $l minc star name]} {
3814 dict set directive_names $name $regular_expression
3816 dict set common_directive_names $name $regular_expression
3819 set directive_names [
DictSort $directive_names]
3820 set common_directive_names [
DictSort $common_directive_names]
3823 if {[regexp {\#\s*DESCRIPTION:\s*(.*)\s*} $l minc x]} {
3824 dict set directive_descriptions $regular_expression $x
3828 if {[regexp {\#\s*OPTIONS:\s*(.*)\s*} $l minc x]} {
3829 dict set command_options $regular_expression [
split [regsub -all {[ \t\n]+} $x {}] ","]
3833 set short_usage "usage: ./Hog/Do \[OPTIONS\] <directive> \[project\]\n\nMost common directives (case insensitive):"
3835 dict for {key value} $common_directive_names {
3836 set short_usage "$short_usage\n - $key: [dict get $directive_descriptions $value]"
3839 set short_usage "$short_usage\n\n\
3840 To see all the available directives, run:\n./Hog/Do HELP\n\n\
3841 To list available options for the chosen directive run:\n\
3842 ./Hog/Do <directive> HELP\n
3845 set usage "usage: ./Hog/Do \[OPTIONS\] <directive> \[project\]\n\nDirectives (case insensitive):"
3847 dict for {key value} $directive_names {
3848 set usage "$usage\n - $key: [dict get $directive_descriptions $value]"
3851 set usage "$usage\n$custom_commands"
3853 set usage "$usage\n\nTo list available options for the chosen directive run:\n./Hog/Do <directive> HELP"
3862 Msg Debug "HogEnv.conf found"
3870 if {[
catch {
package require cmdline} ERROR]} {
3871 Msg Debug "The cmdline Tcl package was not found, sourcing it from Hog..."
3872 source $tcl_path/utils/cmdline.tcl
3875 set argv [regsub -all {(?i) HELP\y} $argv " -help"]
3877 lassign [
GetOptions $argv $parameters] option_list arg_list
3879 if {[
IsInList "-all" $option_list]} {
3888 set directive [
string toupper [
lindex $arg_list 0]]
3891 set argument_is_no_project 0
3893 switch -regexp -- $directive "$commands"
3896 if {$directive != ""} {
3897 if {[
IsInList $directive $directives_with_projects 1]} {
3898 puts "usage: ./Hog/Do \[OPTIONS\] $directive <project>\n"
3899 }
elseif {[regexp "^COMPSIM(LIB)?$" $directive]} {
3900 puts "usage: ./Hog/Do \[OPTIONS\] $directive <simulator>\n"
3902 puts "usage: ./Hog/Do \[OPTIONS\] $directive \n"
3905 dict for {dir desc} $directive_descriptions {
3906 if {[regexp $dir $directive]} {
3912 dict for {dir opts} $command_options {
3913 if {[regexp $dir $directive]} {
3914 puts "Available options:"
3916 foreach par $parameters {
3917 if {$opt == [lindex $par 0]} {
3918 if {[regexp {\.arg$} $opt]} {
3919 set opt_name [regsub {\.arg$} $opt ""]
3920 puts " -$opt_name <argument>"
3924 puts " [lindex $par [llength $par]-1]"
3938 if {[
catch {
array set options [
cmdline::getoptions option_list $parameters $usage]} err]} {
3939 Msg Status "\nERROR: Syntax error, probably unknown option.\n\n USAGE: $err"
3943 if {[
llength $arg_list] <= $min_n_of_args || [
llength $arg_list] > $max_n_of_args} {
3944 Msg Status "\nERROR: Wrong number of arguments: [
llength $argv]"
3949 set project [
lindex $arg_list 1]
3951 if {$argument_is_no_project == 0} {
3953 regsub "^(\./)?Top/" $project "" project
3955 regsub "/? *\$" $project "" project
3961 Msg Debug "Option list:"
3962 foreach {key value} [
array get options] {
3963 Msg Debug "$key => $value"
3970 if {$proj_conf != 0} {
3973 lassign [
GetIDECommand $proj_conf] cmd before_tcl_script after_tcl_script end_marker
3974 Msg Info "Project $project uses $cmd IDE"
3977 set command "$cmd $before_tcl_script$script$after_tcl_script$argv$end_marker"
3979 if {$argument_is_no_project == 1} {
3981 Msg Debug "$project will be used as first argument"
3982 }
elseif {$project != ""} {
3985 }
elseif {$min_n_of_args < 0} {
3998 set project_group [
file dirname $project]
3999 set project [
file tail $project]
4000 if {$project_group != "."} {
4001 set project_name "$project_group/$project"
4003 set project_name "$project"
4006 return [list $directive $project $project_name $project_group $repo_path $old_path $bin_path $top_path $usage $short_usage $command $cmd [
array get options]]
4013 proc IsCommitAncestor {ancestor commit} {
4014 lassign [
GitRet "merge-base --is-ancestor $ancestor $commit"] status result
4023 return [
expr {[info commands sys_install] != ""}]
4028 return [
expr {[info commands get_libero_version] != ""}]
4036 proc IsInList {element list {regex 0}} {
4038 if {$regex == 1 && [regexp $x $element]} {
4040 }
elseif {$regex == 0 && $x eq $element} {
4051 return [
expr {[string first PlanAhead [version]] == 0}]
4059 if {[
catch {
package require ::quartus::flow} result]} {
4072 proc IsRelativePath {path} {
4073 if {[
string index $path 0] == "/" || [
string index $path 0] == "~"} {
4081 proc IsSynplify {} {
4082 return [
expr {[info commands program_version] != ""}]
4087 return [
expr {![IsQuartus] && ![IsXilinx] && ![IsLibero] && ![IsSynplify] && ![IsDiamond]}]
4095 proc IsVersal {part} {
4096 if {[get_property ARCHITECTURE [get_parts $part]] eq "versal"} {
4106 return [
expr {[string first Vivado [version]] == 0}]
4114 if {[
info commands version] != ""} {
4115 set current_version [version]
4116 if {[
string first PlanAhead $current_version] == 0 || [
string first Vivado $current_version] == 0} {
4119 Msg Warning "This IDE has the version command but it is not PlanAhead or Vivado: $current_version"
4132 proc IsZynq {part} {
4133 if {[regexp {^(xc7z|xczu).*} $part]} {
4140 proc ImportGHDL {project_name repo_path simset_name simset_dict {ext_path ""}} {
4141 set list_path "$repo_path/Top/$project_name/list"
4142 lassign [
GetHogFiles -list_files {.src,.ext,.sim} -ext_path $ext_path $list_path $repo_path] src_files properties filesets
4147 set properties [
DictGet $simset_dict "properties"]
4148 set options [
DictGet $properties "options"]
4151 set workdir Projects/$project_name/ghdl
4152 file delete -force $workdir
4154 set import_log "$workdir/ghdl-import-${simset_name}.log"
4155 dict for {lib sources} $src_files {
4156 set libname [file rootname $lib]
4157 foreach f $sources {
4158 if {[file extension $f] != ".vhd" && [file extension $f] != ".vhdl"} {
4159 Msg Info "File $f is not a VHDL file, copying it in workfolder..."
4160 file copy -force $f $workdir
4162 set file_path [Relative $repo_path $f]
4163 set import_log_file [open $import_log "a"]
4164 puts "ghdl -i --work=$libname --workdir=$workdir -fsynopsys --ieee=standard $options $file_path"
4165 puts $import_log_file "ghdl -i --work=$libname --workdir=$workdir -fsynopsys --ieee=standard $options $file_path"
4166 close $import_log_file
4167 lassign [GHDL "-i --work=$libname --workdir=$workdir -fsynopsys --ieee=standard $options $file_path" $import_log] ret result
4169 Msg CriticalWarning "GHDL import failed for file $f: $result"
4178 proc LaunchGHDL {project_name repo_path simset_name simset_dict {ext_path ""}} {
4181 set sim_props [
DictGet $simset_dict "properties"]
4182 set options [
DictGet $sim_props "options"]
4183 set runopts [
DictGet $sim_props "run_options"]
4185 dict for {prop_name prop_val} $sim_props {
4186 set prop_name [string toupper $prop_name]
4187 if {$prop_name == "TOP"} {
4188 set top_sim $prop_val
4191 set workdir $repo_path/Projects/$project_name/ghdl
4192 set make_log "$workdir/ghdl-make-${simset_name}.log"
4193 set run_log "$workdir/ghdl-run-${simset_name}.log"
4196 set make_log_file [open $make_log "w"]
4198 puts "ghdl -m --work=$simset_name -fsynopsys --ieee=standard $options $top_sim"
4199 puts $make_log_file "ghdl -m --work=$simset_name -fsynopsys --ieee=standard $options $top_sim"
4200 close $make_log_file
4202 lassign [
GHDL "-m --work=$simset_name -fsynopsys --ieee=standard $options $top_sim" $make_log] ret result
4205 Msg Error "GHDL make failed for $top_sim: $result"
4209 set run_log_file [open $run_log "w"]
4210 puts "ghdl -r --work=$simset_name -fsynopsys --ieee=standard $options $top_sim $runopts"
4211 puts $run_log_file "ghdl -r --work=$simset_name -fsynopsys --ieee=standard $options $top_sim $runopts"
4214 lassign [
GHDL "-r --work=$simset_name -fsynopsys --ieee=standard $options $top_sim $runopts" $run_log] ret result
4218 Msg Error "GHDL run failed for $top_sim: $result"
4233 proc LaunchImplementation {reset do_create run_folder project_name {repo_path .} {njobs 4} {do_bitstream 0}} {
4234 Msg Info "Starting implementation flow..."
4236 if {$reset == 1 && $do_create == 0} {
4237 Msg Info "Resetting run before launching implementation..."
4242 source $repo_path/Hog/Tcl/integrated/pre-implementation.tcl
4245 if {$do_bitstream == 1} {
4246 launch_runs impl_1 -to_step [
BinaryStepName [get_property PART [current_project]]] -jobs $njobs -dir $run_folder
4248 launch_runs impl_1 -jobs $njobs -dir $run_folder
4253 Msg Info "running post-implementation"
4254 source $repo_path/Hog/Tcl/integrated/post-implementation.tcl
4255 if {$do_bitstream == 1} {
4256 Msg Info "running pre-bitstream"
4257 source $repo_path/Hog/Tcl/integrated/pre-bitstream.tcl
4258 Msg Info "running post-bitstream"
4259 source $repo_path/Hog/Tcl/integrated/post-bitstream.tcl
4263 set prog [get_property PROGRESS [get_runs impl_1]]
4264 set status [get_property STATUS [get_runs impl_1]]
4265 Msg Info "Run: impl_1 progress: $prog, status : $status"
4269 set status_file [open "$run_folder/timing.txt" "w"]
4270 puts $status_file "## $project_name Timing summary"
4272 set f [open [
lindex [glob "$run_folder/impl_1/*.twr" 0]]]
4274 while {[
gets $f line] >= 0} {
4275 if {[
string match "Timing summary:" $line]} {
4276 while {[
gets $f line] >= 0} {
4277 if {[
string match "Timing errors:*" $line]} {
4278 set errs [regexp -inline -- {[0-9]+} $line]
4280 if {[
string match "*Footnotes*" $line]} {
4283 puts $status_file "$line"
4292 Msg Info "Time requirements are met"
4293 file rename -force "$run_folder/timing.txt" "$run_folder/timing_ok.txt"
4296 Msg CriticalWarning "Time requirements are NOT met"
4297 file rename -force "$run_folder/timing.txt" "$run_folder/timing_error.txt"
4303 set wns [get_property STATS.WNS [get_runs [current_run]]]
4304 set tns [get_property STATS.TNS [get_runs [current_run]]]
4305 set whs [get_property STATS.WHS [get_runs [current_run]]]
4306 set ths [get_property STATS.THS [get_runs [current_run]]]
4307 set tpws [get_property STATS.TPWS [get_runs [current_run]]]
4309 if {$wns >= 0 && $whs >= 0 && $tpws >= 0} {
4310 Msg Info "Time requirements are met"
4311 set status_file [open "$run_folder/timing_ok.txt" "w"]
4314 Msg CriticalWarning "Time requirements are NOT met"
4315 set status_file [open "$run_folder/timing_error.txt" "w"]
4319 Msg Status "*** Timing summary ***"
4320 Msg Status "WNS: $wns"
4321 Msg Status "TNS: $tns"
4322 Msg Status "WHS: $whs"
4323 Msg Status "THS: $ths"
4324 Msg Status "TPWS: $tpws"
4330 puts $status_file "## $project_name Timing summary"
4332 m add row "| **Parameter** | \"**value (ns)**\" |"
4333 m add row "| --- | --- |"
4334 m add row "| WNS: | $wns |"
4335 m add row "| TNS: | $tns |"
4336 m add row "| WHS: | $whs |"
4337 m add row "| THS: | $ths |"
4338 m add row "| TPWS: | $tpws |"
4340 puts $status_file [m format 2string]
4341 puts $status_file "\n"
4342 if {$timing_ok == 1} {
4343 puts $status_file " Time requirements are met."
4345 puts $status_file "Time requirements are **NOT** met."
4347 puts $status_file "\n\n"
4351 if {$prog ne "100%"} {
4352 Msg Error "Implementation error"
4357 lassign [
GetRepoVersions [
file normalize ./Top/$project_name] $repo_path] sha
4359 Msg Info "Git describe set to $describe"
4361 set dst_dir [
file normalize "$repo_path/bin/$project_name\-$describe"]
4366 if {[
file exists $run_folder/versions.txt]} {
4367 file copy -force $run_folder/versions.txt $dst_dir
4369 Msg Warning "No versions file found in $run_folder/versions.txt"
4372 set timing_files [glob -nocomplain "$run_folder/timing_*.txt"]
4373 set timing_file [
file normalize [
lindex $timing_files 0]]
4375 if {[
file exists $timing_file]} {
4376 file copy -force $timing_file $dst_dir/
4378 Msg Warning "No timing file found, not a problem if running locally"
4382 if {[
IsVersal [get_property part [current_project]]]} {
4383 if {[get_property segmented_configuration [current_project]] == 1} {
4384 Msg Info "Versal Segmented configuration detected: exporting XSA file..."
4385 set xsa_name "$dst_dir/[
file tail $project_name]\-$describe.xsa"
4386 write_hw_platform -fixed -force -file $xsa_name
4390 set revision [get_current_revision]
4392 if {[
catch {execute_module -tool fit} result]} {
4393 Msg Error "Result: $result\n"
4394 Msg Error "Place & Route failed. See the report file.\n"
4396 Msg Info "\nINFO: Place & Route was successful for revision $revision.\n"
4399 if {[
catch {execute_module -tool sta -args "--do_report_timing"} result]} {
4400 Msg Error "Result: $result\n"
4401 Msg Error "Time Quest failed. See the report file.\n"
4403 Msg Info "Time Quest was successfully run for revision $revision.\n"
4406 set panel "Timing Analyzer||Timing Analyzer Summary"
4407 set device [get_report_panel_data -name $panel -col 1 -row_name "Device Name"]
4408 set timing_model [get_report_panel_data -name $panel -col 1 -row_name "Timing Models"]
4409 set delay_model [get_report_panel_data -name $panel -col 1 -row_name "Delay Model"]
4411 Msg Info "*******************************************************************"
4412 Msg Info "Device: $device"
4413 Msg Info "Timing Models: $timing_model"
4414 Msg Info "Delay Model: $delay_model"
4417 Msg Info "*******************************************************************"
4420 Msg Info "Starting implementation flow..."
4421 if {[
catch {run_tool -name {PLACEROUTE}}]} {
4422 Msg Error "PLACEROUTE FAILED!"
4424 Msg Info "PLACEROUTE PASSED."
4428 Msg Info "Run VERIFYTIMING ..."
4429 if {[
catch {run_tool -name {VERIFYTIMING} -script {Hog/Tcl/integrated/libero_timing.tcl}}]} {
4430 Msg CriticalWarning "VERIFYTIMING FAILED!"
4432 Msg Info "VERIFYTIMING PASSED \n"
4438 lassign [
GetRepoVersions [
file normalize ./Top/$project_name] $repo_path] sha
4440 Msg Info "Git describe set to $describe"
4442 set dst_dir [
file normalize "$repo_path/bin/$project_name\-$describe"]
4443 file mkdir $dst_dir/reports
4446 if {[
file exists $run_folder/versions.txt]} {
4447 file copy -force $run_folder/versions.txt $dst_dir
4449 Msg Warning "No versions file found in $run_folder/versions.txt"
4452 set timing_file_path [
file normalize "$repo_path/Projects/timing_libero.txt"]
4453 if {[
file exists $timing_file_path]} {
4454 file copy -force $timing_file_path $dst_dir/reports/Timing.txt
4455 set timing_file [open $timing_file_path "r"]
4456 set status_file [open "$dst_dir/timing.txt" "w"]
4457 puts $status_file "## $project_name Timing summary\n\n"
4458 puts $status_file "| | |"
4459 puts $status_file "| --- | --- |"
4460 while {[
gets $timing_file line] >= 0} {
4461 if {[
string match "SUMMARY" $line]} {
4462 while {[
gets $timing_file line] >= 0} {
4463 if {[
string match "END SUMMARY" $line]} {
4466 if {[
string first ":" $line] == -1} {
4469 set out_string "| [
string map {: | } $line] |"
4470 puts $status_file "$out_string"
4475 Msg Warning "No timing file found, not a problem if running locally"
4480 set force_rst "-forceOne"
4482 prj_run Map $force_rst
4483 prj_run PAR $force_rst
4496 proc LaunchSimulation {project_name lib_path simsets {repo_path .}} {
4499 set project [
file tail $project_name]
4500 set main_sim_folder [
file normalize "$repo_path/Projects/$project_name/$project.sim/"]
4502 if {$simsets != ""} {
4503 dict for {simset sim_dict} $simsets {
4504 lappend simsets_todo $simset
4506 Msg Info "Will run only the following simulation's sets (if they exist): $simsets_todo"
4511 set sim_dic [dict create]
4513 Msg Info "Retrieving list of simulation sets..."
4514 foreach s [get_filesets] {
4516 set use_simpass_str 0
4519 set type [get_property FILESET_TYPE $s]
4520 if {$type eq "SimulationSrcs"} {
4521 if {$simsets_todo != "" && $s ni $simsets_todo} {
4522 Msg Info "Skipping $s as it was not specified with the -simset option..."
4525 set sim_dict [
DictGet $simsets $s]
4526 set simulator [
DictGet $sim_dict "simulator"]
4527 set_property "target_simulator" $simulator [current_project]
4528 set hog_sim_props [
DictGet $sim_dict "hog"]
4529 dict for {prop_name prop_val} $hog_sim_props {
4530 # If HOG_SIMPASS_STR is set, use the HOG_SIMPASS_STR string to search for in logs, after simulation is done
4531 if {[string toupper $prop_name] == "HOG_SIMPASS_STR" && $prop_val != ""} {
4532 Msg Info "Setting simulation pass string as '$prop_val'"
4533 set use_simpass_str 1
4534 set simpass_str $prop_val
4536 if {[string toupper $prop_name] == "HOG_SILENT_SIM" && $prop_val == 1} {
4537 set quiet_sim " -quiet"
4543 Msg Info "Creating simulation scripts for $s..."
4544 if {[
file exists $repo_path/Top/$project_name/pre-simulation.tcl]} {
4545 Msg Info "Running $repo_path/Top/$project_name/pre-simulation.tcl"
4546 source $repo_path/Top/$project_name/pre-simulation.tcl
4548 if {[
file exists $repo_path/Top/$project_name/pre-$s-simulation.tcl]} {
4549 Msg Info "Running $repo_path/Top/$project_name/pre-$s-simulation.tcl"
4550 source Running $repo_path/Top/$project_name/pre-$s-simulation.tcl
4552 current_fileset -simset $s
4553 set sim_dir $main_sim_folder/$s/behav
4554 set sim_output_logfile $sim_dir/xsim/simulate.log
4555 if {([
string tolower $simulator] eq "xsim")} {
4556 set sim_name "xsim:$s"
4558 set simulation_command "launch_simulation $quiet_sim -simset [get_filesets $s]"
4559 if {[
catch $simulation_command log]} {
4562 Msg CriticalWarning "Simulation failed for $s, error info: $::errorInfo"
4563 lappend failed $sim_name
4568 if {$use_simpass_str == 1} {
4571 set file_desc [open $sim_output_logfile r]
4572 set log [read $file_desc]
4575 Msg Info "Searching for simulation pass string: '$simpass_str'"
4576 if {[
string first $simpass_str $log] == -1} {
4577 Msg CriticalWarning "Simulation failed for $s, error info: '$simpass_str' NOT found!"
4578 lappend failed $sim_name
4581 lappend success $sim_name
4585 lappend success $sim_name
4589 Msg Info "Simulation library path is set to $lib_path."
4591 if {!([
file exists $lib_path])} {
4592 Msg Warning "Could not find simulation library path: $lib_path, $simulator simulation will not work."
4596 if {$simlib_ok == 1} {
4597 set_property "compxlib.${simulator}_compiled_library_dir" [
file normalize $lib_path] [current_project]
4598 launch_simulation -scripts_only -simset [get_filesets $s]
4599 set top_name [get_property TOP $s]
4600 set sim_script [
file normalize $sim_dir/$simulator/]
4601 Msg Info "Adding simulation script location $sim_script for $s..."
4602 lappend sim_scripts $sim_script
4603 dict append sim_dic $sim_script $s
4605 Msg Error "Cannot run $simulator simulations without a valid library path"
4612 if {[
info exists sim_scripts]} {
4614 Msg Info "Generating IP simulation targets, if any..."
4616 foreach ip [get_ips] {
4617 generate_target simulation -quiet $ip
4622 Msg Info "====== Starting simulations runs ======"
4625 foreach s $sim_scripts {
4627 set cmd ./compile.sh
4628 Msg Info " ************* Compiling: $s ************* "
4630 set sim_name "comp:[dict get $sim_dic $s]"
4632 Msg CriticalWarning "Compilation failed for $s, error info: $::errorInfo"
4633 lappend failed $sim_name
4635 lappend success $sim_name
4637 Msg Info "###################### Compilation log starts ######################"
4638 Msg Info "\n\n$log\n\n"
4639 Msg Info "###################### Compilation log ends ######################"
4642 if {[
file exists "./elaborate.sh"]} {
4643 set cmd ./elaborate.sh
4644 Msg Info " ************* Elaborating: $s ************* "
4646 set sim_name "elab:[dict get $sim_dic $s]"
4648 Msg CriticalWarning "Elaboration failed for $s, error info: $::errorInfo"
4649 lappend failed $sim_name
4651 lappend success $sim_name
4653 Msg Info "###################### Elaboration log starts ######################"
4654 Msg Info "\n\n$log\n\n"
4655 Msg Info "###################### Elaboration log ends ######################"
4657 set cmd ./simulate.sh
4658 Msg Info " ************* Simulating: $s ************* "
4663 if {$use_simpass_str == 1} {
4664 if {[
string first $simpass_str $log] == -1} {
4668 Msg Debug "Simulation pass string not set, relying on simulator exit code."
4672 set sim_name "sim:[dict get $sim_dic $s]"
4674 Msg CriticalWarning "Simulation failed for $s, error info: $::errorInfo"
4675 lappend failed $sim_name
4677 lappend success $sim_name
4679 Msg Info "###################### Simulation log starts ######################"
4680 Msg Info "\n\n$log\n\n"
4681 Msg Info "###################### Simulation log ends ######################"
4686 if {[
llength $success] > 0} {
4687 set successes [
join $success "\n"]
4688 Msg Info "The following simulation sets were successful:\n\n$successes\n\n"
4691 if {[
llength $failed] > 0} {
4692 set failures [
join $failed "\n"]
4693 Msg Error "The following simulation sets have failed:\n\n$failures\n\n"
4695 }
elseif {[
llength $success] > 0} {
4696 Msg Info "All the [
llength $success] compilations, elaborations and simulations were successful."
4699 Msg Info "Simulation done."
4701 Msg Warning "Simulation is not yet supported for [
GetIDEName]."
4714 proc LaunchSynthesis {reset do_create run_folder project_name {repo_path .} {ext_path ""} {njobs 4}} {
4716 if {$reset == 1 && $do_create == 0} {
4717 Msg Info "Resetting run before launching synthesis..."
4721 source $repo_path/Hog/Tcl/integrated/pre-synthesis.tcl
4723 launch_runs synth_1 -jobs $njobs -dir $run_folder
4725 set prog [get_property PROGRESS [get_runs synth_1]]
4726 set status [get_property STATUS [get_runs synth_1]]
4727 Msg Info "Run: synth_1 progress: $prog, status : $status"
4734 lassign [
GetRepoVersions [
file normalize ./Top/$project_name] $repo_path $ext_path] sha
4736 Msg Info "Git describe set to $describe"
4739 set xci_file [get_property IP_FILE $ip]
4741 set xci_path [
file dirname $xci_file]
4742 set xci_ip_name [
file rootname [
file tail $xci_file]]
4743 foreach rptfile [glob -nocomplain -directory $xci_path *.rpt] {
4744 file copy $rptfile $repo_path/bin/$project_name-$describe/reports
4748 if {$prog ne "100%"} {
4749 Msg Error "Synthesis error, status is: $status"
4753 set project [
file tail [
file rootname $project_name]]
4755 Msg Info "Number of jobs set to $njobs."
4756 set_global_assignment -name NUM_PARALLEL_PROCESSORS $njobs
4760 lassign [
GetRepoVersions [
file normalize $repo_path/Top/$project_name] $repo_path] sha
4763 set revision [get_current_revision]
4766 set tool_and_command [
split [get_global_assignment -name PRE_FLOW_SCRIPT_FILE] ":"]
4767 set tool [
lindex $tool_and_command 0]
4768 set pre_flow_script [
lindex $tool_and_command 1]
4769 set cmd "$tool -t $pre_flow_script quartus_map $project $revision"
4775 Msg Warning "Can not execute command $cmd"
4776 Msg Warning "LOG: $log"
4778 Msg Info "Pre flow script executed!"
4782 if {![is_project_open]} {
4783 Msg Info "Re-opening project file $project_name..."
4784 project_open $project -current_revision
4788 if {[
catch {execute_module -tool ipg -args "--clean"} result]} {
4789 Msg Error "Result: $result\n"
4790 Msg Error "IP Generation failed. See the report file.\n"
4792 Msg Info "IP Generation was successful for revision $revision.\n"
4796 if {[
catch {execute_module -tool map -args "--parallel"} result]} {
4797 Msg Error "Result: $result\n"
4798 Msg Error "Analysis & Synthesis failed. See the report file.\n"
4800 Msg Info "Analysis & Synthesis was successful for revision $revision.\n"
4804 defvar_set -name RWNETLIST_32_64_MIXED_FLOW -value 0
4806 Msg Info "Run SYNTHESIS..."
4807 if {[
catch {run_tool -name {SYNTHESIZE}}]} {
4808 Msg Error "SYNTHESIZE FAILED!"
4810 Msg Info "SYNTHESIZE PASSED!"
4816 set force_rst "-forceOne"
4818 prj_run Synthesis $force_rst
4819 if {[prj_syn] == "synplify"} {
4820 prj_run Translate $force_rst
4823 Msg Error "Impossible condition. You need to run this in an IDE."
4834 proc ListProjects {{repo_path .} {print 1} {ret_conf 0}} {
4835 set top_path [
file normalize $repo_path/Top]
4836 set confs [
findFiles [
file normalize $top_path] hog.conf]
4838 set confs [lsort $confs]
4842 set p [
Relative $top_path [
file dirname $c]]
4845 if {$description eq "test"} {
4846 set description " - Test project"
4847 }
elseif {$description ne ""} {
4848 set description " - $description"
4851 if {$print == 1 || $description ne " - Test project"} {
4853 set g [
file dirname $p]
4864 if {$ret_conf == 0} {
4876 proc Md5Sum {file_name} {
4877 if {!([
file exists $file_name])} {
4878 Msg Warning "Could not find $file_name."
4881 if {[
catch {
package require md5 2.0.7} result]} {
4882 Msg Warning "Tcl package md5 version 2.0.7 not found ($result), will use command line..."
4883 set hash [
lindex [
Execute md5sum $file_name] 0]
4885 set file_hash [
string tolower [md5::md5 -hex -file $file_name]]
4899 proc MergeDict {dict0 dict1 {remove_duplicates 1}} {
4900 set outdict [dict merge $dict1 $dict0]
4901 foreach key [dict keys $dict1] {
4902 if {[dict exists $dict0 $key]} {
4903 set temp_list [dict get $dict1 $key]
4904 foreach item $temp_list {
4906 if {[
IsInList $item [
DictGet $outdict $key]] == 0 || $remove_duplicates == 0} {
4908 dict lappend outdict $key $item
4920 proc MoveElementToEnd {inputList element} {
4921 set index [lsearch $inputList $element]
4923 set inputList [
lreplace $inputList $index $index]
4924 lappend inputList $element
4933 proc OpenProject {project_file repo_path} {
4935 open_project $project_file
4937 set project_folder [
file dirname $project_file]
4938 set project [
file tail [
file rootname $project_file]]
4939 if {[
file exists $project_folder]} {
4941 if {![is_project_open]} {
4942 Msg Info "Opening existing project file $project_file..."
4943 project_open $project -current_revision
4946 Msg Error "Project directory not found for $project_file."
4950 Msg Info "Opening existing project file $project_file..."
4952 open_project -file $project_file -do_backup_on_convert 1 -backup_file {./Projects/$project_file.zip}
4954 Msg Info "Opening existing project file $project_file..."
4955 prj_project open $project_file
4957 Msg Error "This IDE is currently not supported by Hog. Exiting!"
4964 return $tcl_platform(platform)
4974 proc ParseJSON {JSON_FILE JSON_KEY} {
4975 set result [
catch {
package require Tcl 8.4} TclFound]
4976 if {"$result" != "0"} {
4977 Msg CriticalWarning "Cannot find Tcl package version equal or higher than 8.4.\n $TclFound\n Exiting"
4981 set result [
catch {
package require json} JsonFound]
4982 if {"$result" != "0"} {
4983 Msg CriticalWarning "Cannot find JSON package equal or higher than 1.0.\n $JsonFound\n Exiting"
4986 set JsonDict [json::json2dict $JSON_FILE]
4987 set result [
catch {dict get $JsonDict $JSON_KEY} RETURNVALUE]
4988 if {"$result" != "0"} {
4989 Msg CriticalWarning "Cannot find $JSON_KEY in $JSON_FILE\n Exiting"
5002 proc ProjectExists {project {repo_path .}} {
5003 set index [lsearch -exact [
ListProjects $repo_path 0] $project]
5019 proc ReadConf {file_name} {
5020 if {[
catch {
package require inifile 0.2.3} ERROR]} {
5021 Msg Error "Could not find inifile package version 0.2.3 or higher.\n
5022 To use ghdl, libero or diamond with Hog, you need to install the tcllib package\n
5023 You can install it with 'sudo apt install tcllib' on Debian/Ubuntu or 'sudo dnf install tcllib' on Fedora/RedHat/CentOs."
5027 ::ini::commentchar "#"
5028 set f [::ini::open $file_name]
5029 set properties [dict create]
5030 foreach sec [::ini::sections $f] {
5032 if {$new_sec == "files"} {
5035 set key_pairs [::ini::get $f $sec]
5037 regsub -all {\{\"} $key_pairs "\{" key_pairs
5038 regsub -all {\"\}} $key_pairs "\}" key_pairs
5040 dict set properties $new_sec [dict create {*}$key_pairs]
5053 proc ReadExtraFileList {extra_file_name} {
5054 set extra_file_dict [dict create]
5055 if {[
file exists $extra_file_name]} {
5056 set file [open $extra_file_name "r"]
5057 set file_data [read $file]
5060 set data [
split $file_data "\n"]
5061 foreach line $data {
5062 if {![regexp {^ *$} $line] & ![regexp {^ *\#} $line]} {
5063 set ip_and_md5 [regexp -all -inline {\S+} $line]
5064 dict lappend extra_file_dict "[
lindex $ip_and_md5 0]" "[
lindex $ip_and_md5 1]"
5068 return $extra_file_dict
5088 proc ReadListFile {args} {
5091 if {[
catch {
package require cmdline} ERROR]} {
5092 puts "$ERROR\n If you are running this script on tclsh, you can fix this by installing 'tcllib'"
5098 {lib.arg "" "The name of the library files will be added to, if not given will be extracted from the file name."}
5099 {fileset.arg "" "The name of the library, from the main list file"}
5100 {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."}
5101 {print_log "If set, will use PrintFileTree for the VIEW directive"}
5102 {indent.arg "" "Used to indent files with the VIEW directive"}
5105 set usage "USAGE: ReadListFile \[options\] <list file> <path>"
5106 if {[
catch {
array set options [
cmdline::getoptions args $parameters $usage]}] || [
llength $args] != 2} {
5110 set list_file [
lindex $args 0]
5111 set path [
lindex $args 1]
5112 set sha_mode $options(sha_mode)
5113 set lib $options(lib)
5114 set fileset $options(fileset)
5115 set print_log $options(print_log)
5116 set indent $options(indent)
5118 if {$sha_mode == 1} {
5119 set sha_mode_opt "-sha_mode"
5124 if {$print_log == 1} {
5125 set print_log_opt "-print_log"
5127 set print_log_opt ""
5132 set lib [
file rootname [
file tail $list_file]]
5134 set fp [open $list_file r]
5135 set file_data [read $fp]
5137 set list_file_ext [
file extension $list_file]
5138 switch $list_file_ext {
5140 if {$fileset eq ""} {
5146 set fileset "constrs_1"
5149 set fileset "sources_1"
5153 set libraries [dict create]
5154 set filesets [dict create]
5155 set properties [dict create]
5157 set data [
split $file_data "\n"]
5159 set n [
llength $data]
5161 if {$print_log == 1} {
5162 if {$indent eq ""} {
5163 set list_file_rel [
file tail $list_file]
5164 Msg Status "\n$list_file_rel"
5168 Msg Debug "$n lines read from $list_file."
5171 foreach line $data {
5173 if {![regexp {^[\t\s]*$} $line] & ![regexp {^[\t\s]*\#} $line]} {
5174 set file_and_prop [regexp -all -inline {\S+} $line]
5175 set srcfile [
lindex $file_and_prop 0]
5176 set srcfile "$path/$srcfile"
5178 set srcfiles [glob -nocomplain $srcfile]
5181 if {$srcfiles != $srcfile && ![
string equal $srcfiles ""]} {
5182 Msg Debug "Wildcard source expanded from $srcfile to $srcfiles"
5184 if {![
file exists $srcfile]} {
5185 if {$print_log == 0} {
5186 Msg CriticalWarning "File: $srcfile (from list file: $list_file) does not exist."
5192 foreach vhdlfile $srcfiles {
5193 if {[
file exists $vhdlfile]} {
5194 set vhdlfile [
file normalize $vhdlfile]
5195 set extension [
file extension $vhdlfile]
5197 set prop [
lrange $file_and_prop 1 end]
5200 set library [
lindex [regexp -inline {\ylib\s*=\s*(.+?)\y.*} $prop] 1]
5201 if {$library == ""} {
5205 if {$extension == $list_file_ext} {
5208 set ref_path [
lindex [regexp -inline {\ypath\s*=\s*(\S+).*} $prop] 1]
5209 if {$ref_path eq ""} {
5212 set ref_path [
file normalize $path/$ref_path]
5214 Msg Debug "List file $vhdlfile found in list file, recursively opening it using path \"$ref_path\"..."
5215 if {$print_log == 1} {
5216 if {[
file normalize $last_printed] ne [
file normalize $vhdlfile]} {
5217 Msg Status "$indent Inside [
file tail $vhdlfile]:"
5221 lassign [
ReadListFile {*}"-indent \" $indent\" -lib $library -fileset $fileset $sha_mode_opt $print_log_opt $vhdlfile $ref_path"] l p fs
5223 set properties [
MergeDict $p $properties]
5225 }
elseif {[lsearch {.src .sim .con ReadExtraFileList} $extension] >= 0} {
5227 Msg Error "$vhdlfile cannot be included into $list_file, $extension files must be included into $extension files."
5230 regsub -all " *= *" $prop "=" prop
5234 if {[
string first "lib=" $p] == -1} {
5236 set pos [
string first "=" $p]
5240 set prop_name [
string range $p 0 [
expr {$pos - 1}]]
5243 dict lappend properties $vhdlfile $p
5244 Msg Debug "Adding property $p to $vhdlfile..."
5245 }
elseif {$list_file_ext != ".ipb"} {
5246 Msg Warning "Setting Property $p is not supported for file $vhdlfile or it is already its default. \
5251 if {[lsearch {.xci .ip .bd .xcix} $extension] >= 0} {
5253 set lib_name "ips.src"
5254 }
elseif {[
IsInList $extension {.vhd .vhdl}] || $list_file_ext == ".sim"} {
5256 if {![
IsInList $extension {.vhd .vhdl}]} {
5257 set lib_name "others.sim"
5259 set lib_name "$library$list_file_ext"
5261 }
elseif {$list_file_ext == ".con"} {
5262 set lib_name "sources.con"
5263 }
elseif {$list_file_ext == ".ipb"} {
5264 set lib_name "xml.ipb"
5267 set lib_name "others.src"
5270 Msg Debug "Appending $vhdlfile to $lib_name list..."
5271 dict lappend libraries $lib_name $vhdlfile
5272 if {$sha_mode != 0 && [
file type $vhdlfile] eq "link"} {
5275 dict lappend libraries $lib_name $real_file
5276 Msg Debug "File $vhdlfile is a soft link, also adding the real file: $real_file"
5281 if {[dict exists $filesets $fileset] == 0} {
5283 Msg Debug "Adding $fileset to the fileset dictionary..."
5284 Msg Debug "Adding library $lib_name to fileset $fileset..."
5285 dict set filesets $fileset $lib_name
5289 Msg Debug "Adding library $lib_name to fileset $fileset..."
5290 dict lappend filesets $fileset $lib_name
5296 Msg CriticalWarning "File $vhdlfile not found."
5302 if {$sha_mode != 0} {
5304 if {$list_file_ext eq ".ipb"} {
5305 set sha_lib "xml.ipb"
5307 set sha_lib $lib$list_file_ext
5309 dict lappend libraries $sha_lib [
file normalize $list_file]
5310 if {[
file type $list_file] eq "link"} {
5313 dict lappend libraries $lib$list_file_ext $real_file
5314 Msg Debug "List file $list_file is a soft link, also adding the real file: $real_file"
5317 return [list $libraries $properties $filesets]
5325 proc Relative {base dst} {
5326 if {![
string equal [
file pathtype $base] [
file pathtype $dst]]} {
5327 Msg CriticalWarning "Unable to compute relation for paths of different path types: [
file pathtype $base] vs. [
file pathtype $dst], ($base vs. $dst)"
5331 set base [
file normalize [
file join [
pwd] $base]]
5332 set dst [
file normalize [
file join [
pwd] $dst]]
5335 set base [
file split $base]
5336 set dst [
file split $dst]
5338 while {[
string equal [
lindex $dst 0] [
lindex $base 0]]} {
5339 set dst [
lrange $dst 1 end]
5340 set base [
lrange $base 1 end]
5341 if {![
llength $dst]} {break}
5344 set dstlen [
llength $dst]
5345 set baselen [
llength $base]
5347 if {($dstlen == 0) && ($baselen == 0)} {
5350 while {$baselen > 0} {
5351 set dst [
linsert $dst 0 ..]
5354 set dst [
eval [
linsert $dst 0 file join]]
5365 proc RelativeLocal {pathName filePath} {
5366 if {[
string first [
file normalize $pathName] [
file normalize $filePath]] != -1} {
5367 return [
Relative $pathName $filePath]
5378 proc RemoveDuplicates {mydict} {
5379 set new_dict [dict create]
5380 foreach key [dict keys $mydict] {
5381 set values [
DictGet $mydict $key]
5382 foreach value $values {
5383 set idxs [
lreverse [
lreplace [lsearch -exact -all $values $value] 0 0]]
5385 set values [
lreplace $values $idx $idx]
5388 dict set new_dict $key $values
5399 proc ResetRepoFiles {reset_file} {
5400 if {[
file exists $reset_file]} {
5401 Msg Info "Found $reset_file, opening it..."
5402 set fp [open $reset_file r]
5403 set wild_cards [lsearch -all -inline -not -regexp [
split [read $fp] "\n"] "^ *$"]
5405 Msg Info "Found the following files/wild cards to restore if modified: $wild_cards..."
5406 foreach w $wild_cards {
5408 if {[
llength $mod_files] > 0} {
5409 Msg Info "Found modified $w files: $mod_files, will restore them..."
5412 Msg Info "No modified $w files found."
5423 proc RestoreModifiedFiles {{repo_path "."} {pattern "."}} {
5426 set ret [
Git checkout $pattern]
5437 proc SearchHogProjects {dir} {
5438 set projects_list {}
5439 if {[
file exists $dir]} {
5440 if {[
file isdirectory $dir]} {
5441 foreach proj_dir [glob -nocomplain -types d $dir/*] {
5442 if {![regexp {^.*Top/+(.*)$} $proj_dir dummy proj_name]} {
5443 Msg Warning "Could not parse Top directory $dir"
5446 if {[
file exists "$proj_dir/hog.conf"]} {
5447 lappend projects_list $proj_name
5450 lappend projects_list $p
5455 Msg Error "Input $dir is not a directory!"
5458 Msg Error "Directory $dir doesn't exist!"
5460 return $projects_list
5469 proc SetGenericsSimulation {repo_path proj_dir target} {
5470 set top_dir "$repo_path/Top/$proj_dir"
5471 set simsets [get_filesets]
5472 if {$simsets != ""} {
5473 foreach simset $simsets {
5475 if {[get_property FILESET_TYPE $simset] != "SimulationSrcs"} {
5479 set merged_generics_dict [dict create]
5483 set simset_generics [
DictGet $simset_dict "generics"]
5484 set merged_generics_dict [
MergeDict $merged_generics_dict $simset_generics 0]
5486 set_property generic $generic_str [get_filesets $simset]
5487 Msg Debug "Setting generics $generic_str for simulator $target\
5488 and simulation file-set $simset..."
5500 proc SetTopProperty {top_module fileset} {
5501 Msg Info "Setting TOP property to $top_module module"
5504 set_property "top" $top_module [get_filesets $fileset]
5507 set_global_assignment -name TOP_LEVEL_ENTITY $top_module
5509 set_root -module $top_module
5511 prj_impl option top $top_module
5516 proc VIVADO_PATH_PROPERTIES {} {
5517 return {"\.*\.TCL\.PRE$" "^.*\.TCL\.POST$" "^RQS_FILES$" "^INCREMENTAL\_CHECKPOINT$" "NOC\_SOLUTION\_FILE"}
5527 proc WriteConf {file_name config {comment ""}} {
5528 if {[
catch {
package require inifile 0.2.3} ERROR]} {
5529 puts "$ERROR\n If you are running this script on tclsh, you can fix this by installing 'tcllib'"
5533 ::ini::commentchar "#"
5534 set f [::ini::open $file_name w]
5536 foreach sec [dict keys $config] {
5537 set section [dict get $config $sec]
5538 dict for {p v} $section {
5539 if {[string trim $v] == ""} {
5540 Msg Warning "Property $p has empty value. Skipping..."
5543 ::ini::set $f $sec $p $v
5548 if {![
string equal "$comment" ""]} {
5549 ::ini::comment $f [
lindex [::ini::sections $f] 0] "" $comment
5550 set hog_header "Generated by Hog on [
clock format [
clock seconds] -format "%Y-%m-%d %H:%M:%S"]"
5551 ::ini::comment $f [
lindex [::ini::sections $f] 0] "" $hog_header
5566 proc WriteGenerics {mode repo_path design date timee\
5567 commit version top_hash top_ver hog_hash hog_ver \
5568 cons_ver cons_hash libs vers hashes ext_names ext_hashes \
5569 user_ip_repos user_ip_vers user_ip_hashes flavour {xml_ver ""} {xml_hash ""}} {
5570 Msg Info "Passing parameters/generics to project's top module..."
5573 set generic_string [
concat \
5585 if {$xml_hash != "" && $xml_ver != ""} {
5586 lappend generic_string \
5591 foreach l $libs v $vers h $hashes {
5594 lappend generic_string "$ver" "$hash"
5597 foreach e $ext_names h $ext_hashes {
5599 lappend generic_string "$hash"
5602 foreach repo $user_ip_repos v $user_ip_vers h $user_ip_hashes {
5603 set repo_name [
file tail $repo]
5604 set ver "[
string toupper $repo_name]_VER=[
FormatGeneric $v]"
5605 set hash "[
string toupper $repo_name]_SHA=[
FormatGeneric $h]"
5606 lappend generic_string "$ver" "$hash"
5609 if {$flavour != -1} {
5610 lappend generic_string "FLAVOUR=$flavour"
5616 set generic_string "$prj_generics $generic_string"
5622 if {$mode == "create" || [
IsISE]} {
5625 if {[
file exists $top_file]} {
5628 Msg Debug "Found top level generics $generics in $top_file"
5630 set filtered_generic_string ""
5632 foreach generic_to_set [
split [
string trim $generic_string]] {
5633 set key [
lindex [
split $generic_to_set "="] 0]
5634 if {[dict exists $generics $key]} {
5635 Msg Debug "Hog generic $key found in $top_name"
5636 lappend filtered_generic_string "$generic_to_set"
5638 Msg Warning "Generic $key is passed by Hog but is NOT present in $top_name."
5644 set generic_string $filtered_generic_string
5649 set_property generic $generic_string [current_fileset]
5650 Msg Info "Setting parameters/generics..."
5651 Msg Debug "Detailed parameters/generics: $generic_string"
5656 set simulator [get_property target_simulator [current_project]]
5657 if {$mode == "create"} {
5664 Msg Info "Setting Synplify parameters/generics one by one..."
5665 foreach generic $generic_string {
5666 Msg Debug "Setting Synplify generic: $generic"
5667 set_option -hdl_param -set "$generic"
5670 Msg Info "Setting Diamond parameters/generics one by one..."
5671 prj_impl option -impl Implementation0 HDL_PARAM "$generic_string"
5681 proc WriteGenericsToBdIPs {mode repo_path proj generic_string} {
5682 Msg Debug "Parameters/generics passed to WriteGenericsToIP: $generic_string"
5684 set bd_ip_generics false
5686 if {[dict exists $properties "hog"]} {
5687 set propDict [dict get $properties "hog"]
5688 if {[dict exists $propDict "PASS_GENERICS_TO_BD_IPS"]} {
5689 set bd_ip_generics [dict get $propDict "PASS_GENERICS_TO_BD_IPS"]
5693 if {[
string compare [
string tolower $bd_ip_generics] "false"] == 0} {
5697 if {$mode == "synth"} {
5698 Msg Info "Attempting to apply generics pre-synthesis..."
5699 set PARENT_PRJ [get_property "PARENT.PROJECT_PATH" [current_project]]
5700 set workaround [open "$repo_path/Projects/$proj/.hog/presynth_workaround.tcl" "w"]
5701 puts $workaround "source \[lindex \$argv 0\];"
5702 puts $workaround "open_project \[lindex \$argv 1\];"
5703 puts $workaround "WriteGenericsToBdIPs \[lindex \$argv 2\] \[lindex \$argv 3\] \[lindex \$argv 4\] \[lindex \$argv 5\];"
5704 puts $workaround "close_project"
5708 exec vivado -mode batch -source $repo_path/Projects/$proj/.hog/presynth_workaround.tcl \
5709 -tclargs $repo_path/Hog/Tcl/hog.tcl $PARENT_PRJ \
5710 "childprocess" $repo_path $proj $generic_string
5713 Msg Error "Encountered an error while attempting workaround: $errMsg"
5715 file delete $repo_path/Projects/$proj/.hog/presynth_workaround.tcl
5717 Msg Info "Done applying generics pre-synthesis."
5721 Msg Info "Looking for IPs to add generics to..."
5722 set ips_generic_string ""
5723 foreach generic_to_set [
split [
string trim $generic_string]] {
5724 set key [
lindex [
split $generic_to_set "="] 0]
5725 set value [
lindex [
split $generic_to_set "="] 1]
5726 append ips_generic_string "CONFIG.$key $value "
5730 if {[
string compare [
string tolower $bd_ip_generics] "true"] == 0} {
5733 set ip_regex $bd_ip_generics
5736 set ip_list [get_ips -regex $ip_regex]
5737 Msg Debug "IPs found with regex \{$ip_regex\}: $ip_list"
5739 set regen_targets {}
5741 foreach {ip} $ip_list {
5742 set WARN_ABOUT_IP false
5743 set ip_props [list_property [get_ips $ip]]
5746 if {[lsearch -exact $ip_props "IS_BD_CONTEXT"] == -1} {
5750 if {[get_property "IS_BD_CONTEXT" [get_ips $ip]] eq "1"} {
5751 foreach {ip_prop} $ip_props {
5752 if {[dict exists $ips_generic_string $ip_prop]} {
5753 if {$WARN_ABOUT_IP == false} {
5754 lappend regen_targets [get_property SCOPE [get_ips $ip]]
5755 Msg Warning "The ip \{$ip\} contains generics that are set by Hog.\
5756 If this is IP is apart of a block design, the .bd file may contain stale, unused, values.\
5757 Hog will always apply the most up-to-date values to the IP during synthesis,\
5758 however these values may or may not be reflected in the .bd file."
5759 set WARN_ABOUT_IP true
5764 set xci_path [get_property IP_FILE [get_ips $ip]]
5766 if {[
string equal $generic_format "ERROR"]} {
5767 Msg Warning "Could not find format for generic $ip_prop in IP $ip. Skipping..."
5771 set value_to_set [dict get $ips_generic_string $ip_prop]
5772 switch -exact $generic_format {
5774 if {[
string match "32'h*" $value_to_set]} {
5775 scan [
string map {"32'h" ""} $value_to_set] "%x" value_to_set
5779 set value_to_set [
expr {$value_to_set ? "true" : "false"}]
5782 if {[
string match "32'h*" $value_to_set]} {
5783 binary scan [
binary format H* [
string map {"32'h" ""} $value_to_set]] d value_to_set
5787 if {[
string match "32'h*" $value_to_set]} {
5788 set value_to_set [
string map {"32'h" "0x"} $value_to_set]
5792 set value_to_set [
format "%s" $value_to_set]
5795 Msg Warning "Unknown generic format $generic_format for IP $ip. Will attempt to pass as string..."
5800 Msg Info "The IP \{$ip\} contains: $ip_prop ($generic_format), setting it to $value_to_set."
5801 if {[
catch {set_property -name $ip_prop -value $value_to_set -objects [get_ips $ip]} prop_error]} {
5802 Msg CriticalWarning "Failed to set property $ip_prop to $value_to_set for IP \{$ip\}: $prop_error"
5809 foreach {regen_target} [lsort -unique $regen_targets] {
5810 Msg Info "Regenerating target: $regen_target"
5811 if {[
catch {generate_target -force all [get_files $regen_target]} prop_error]} {
5812 Msg CriticalWarning "Failed to regen targets: $prop_error"
5820 proc GetGenericFormatFromXciXML {generic_name xml_file} {
5821 if {![
file exists $xml_file]} {
5822 Msg Error "Could not find XML file: $xml_file"
5826 set fp [open $xml_file r]
5827 set xci_data [read $fp]
5830 set paramType "string"
5831 set modelparam_regex [
format {^.*\y%s\y.*$} [
string map {"CONFIG." "MODELPARAM_VALUE."} $generic_name]]
5832 set format_regex {format="([^"]+)"}
5834 set line [
lindex [regexp -inline -line $modelparam_regex $xci_data] 0]
5835 Msg Debug "line: $line"
5837 if {[regexp $format_regex $line match format_value]} {
5838 Msg Debug "Extracted: $format_value format from xml"
5839 set paramType $format_value
5841 Msg Debug "No format found, using string"
5850 proc GetGenericFormatFromXci {generic_name xci_file} {
5851 if {![
file exists $xci_file]} {
5852 Msg Error "Could not find XCI file: $xci_file"
5856 set fp [open $xci_file r]
5857 set xci_data [read $fp]
5860 set paramType "string"
5861 if {[
string first "xilinx.com:schema:json_instance:1.0" $xci_data] == -1} {
5862 Msg Debug "XCI format is not JSON, trying XML..."
5863 set xml_file "[
file rootname $xci_file].xml"
5867 set generic_name [
string map {"CONFIG." ""} $generic_name]
5868 set ip_inst [
ParseJSON $xci_data "ip_inst"]
5869 set parameters [dict get $ip_inst parameters]
5870 set component_parameters [dict get $parameters component_parameters]
5871 if {[dict exists $component_parameters $generic_name]} {
5872 set generic_info [dict get $component_parameters $generic_name]
5873 if {[dict exists [
lindex $generic_info 0] format]} {
5874 set paramType [dict get [
lindex $generic_info 0] format]
5875 Msg Debug "Extracted: $paramType format from xci"
5878 Msg Debug "No format found, using string"
5891 proc WriteGitLabCIYAML {proj_name {ci_conf ""}} {
5892 if {[
catch {
package require yaml 0.3.3} YAMLPACKAGE]} {
5893 Msg CriticalWarning "Cannot find package YAML.\n Error message: $YAMLPACKAGE. \
5894 If you are running on tclsh, you can fix this by installing package \"tcllib\""
5899 if {$ci_conf != ""} {
5901 foreach sec [dict keys $ci_confs] {
5902 if {[
string first : $sec] == -1} {
5903 lappend job_list $sec
5907 set job_list {"generate_project" "simulate_project"}
5911 set out_yaml [huddle create]
5912 foreach job $job_list {
5914 set huddle_tags [huddle list]
5916 set sec_dict [dict create]
5918 if {$ci_confs != ""} {
5919 foreach var [dict keys [dict get $ci_confs $job]] {
5920 if {$var == "tags"} {
5921 set tag_section "tags"
5922 set tags [dict get [dict get $ci_confs $job] $var]
5923 set tags [
split $tags ","]
5925 set tag_list [huddle list $tag]
5926 set huddle_tags [huddle combine $huddle_tags $tag_list]
5929 dict set sec_dict $var [dict get [dict get $ci_confs $job] $var]
5935 set huddle_variables [huddle create "PROJECT_NAME" $proj_name "extends" ".vars"]
5936 if {[dict exists $ci_confs "$job:variables"]} {
5937 set var_dict [dict get $ci_confs $job:variables]
5938 foreach var [dict keys $var_dict] {
5940 set value [dict get $var_dict "$var"]
5941 set var_inner [huddle create "$var" "$value"]
5942 set huddle_variables [huddle combine $huddle_variables $var_inner]
5947 set middle [huddle create "extends" ".$job" "variables" $huddle_variables]
5948 foreach sec [dict keys $sec_dict] {
5949 set value [dict get $sec_dict $sec]
5950 set var_inner [huddle create "$sec" "$value"]
5951 set middle [huddle combine $middle $var_inner]
5953 if {$tag_section != ""} {
5954 set middle2 [huddle create "$tag_section" $huddle_tags]
5955 set middle [huddle combine $middle $middle2]
5958 set outer [huddle create "$job:$proj_name" $middle]
5959 set out_yaml [huddle combine $out_yaml $outer]
5962 return [
string trimleft [yaml::huddle2yaml $out_yaml] "-"]
5972 proc WriteListFiles {libs props list_path repo_path {ext_path ""}} {
5974 foreach lib [dict keys $libs] {
5975 if {[
llength [
DictGet $libs $lib]] > 0} {
5976 set list_file_name $list_path$lib
5977 set list_file [open $list_file_name w]
5978 Msg Info "Writing $list_file_name..."
5979 puts $list_file "#Generated by Hog on [
clock format [
clock seconds] -format "%Y-%m-%d %H:%M:%S"]"
5980 foreach file [
DictGet $libs $lib] {
5982 set prop [
DictGet $props $file]
5986 puts $list_file "$file_path $prop"
5989 set ext_list_file [open "[
file rootname $list_file].ext" a]
5990 puts $ext_list_file "$file_path $prop"
5991 close $ext_list_file
5994 Msg Warning "The path of file $file is not relative to your repository. Please check!"
6010 proc WriteSimListFile {simset libs props simsets list_path repo_path {force 0}} {
6012 set list_file_name $list_path/${simset}.sim
6013 if {$force == 0 && [
file exists $list_file_name]} {
6014 Msg Info "List file $list_file_name already exists, skipping..."
6018 set list_file [open $list_file_name a+]
6021 puts $list_file "\[files\]"
6022 Msg Info "Writing $list_file_name..."
6023 foreach lib [
DictGet $simsets $simset] {
6024 foreach file [
DictGet $libs $lib] {
6026 set prop [
DictGet $props $file]
6030 set lib_name [
file rootname $lib]
6031 if {$lib_name != $simset && [
file extension $file] == ".vhd" && [
file extension $file] == ""} {
6032 lappend prop "lib=$lib_name"
6034 puts $list_file "$file_path $prop"
6037 Msg Warning "The path of file $file is not relative to your repository. Please check!"
6049 proc WriteToFile {File msg} {
6050 set f [open $File a+]
6061 proc WriteUtilizationSummary {input output project_name run} {
6062 set f [open $input "r"]
6063 set o [open $output "a"]
6064 puts $o "## $project_name $run Utilization report\n\n"
6065 struct::matrix util_m
6066 util_m add columns 14
6069 util_m add row "| **Site Type** | **Used** | **Fixed** | **Prohibited** | **Available** | **Util%** |"
6070 util_m add row "| --- | --- | --- | --- | --- | --- |"
6072 util_m add row "| **Site Type** | **Used** | **Fixed** | **Available** | **Util%** |"
6073 util_m add row "| --- | --- | --- | --- | --- |"
6083 while {[
gets $f line] >= 0} {
6084 if {([
string first "| CLB LUTs" $line] >= 0 || [
string first "| Slice LUTs" $line] >= 0) && $luts == 0} {
6085 util_m add row $line
6088 if {([
string first "| CLB Registers" $line] >= 0 || [
string first "| Slice Registers" $line] >= 0) && $regs == 0} {
6089 util_m add row $line
6092 if {[
string first "| Block RAM Tile" $line] >= 0 && $bram == 0} {
6093 util_m add row $line
6096 if {[
string first "URAM " $line] >= 0 && $uram == 0} {
6097 util_m add row $line
6100 if {[
string first "DSPs" $line] >= 0 && $dsps == 0} {
6101 util_m add row $line
6104 if {[
string first "Bonded IOB" $line] >= 0 && $ios == 0} {
6105 util_m add row $line
6112 puts $o [util_m format 2string]
6118 Msg Error "Found Git version older than 2.7.2. Hog will not work as expected, exiting now."