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]} {
87 if {[
catch {
set ws_apps [app list -dict]}]} {
set ws_apps ""}
88 dict for {app_name app_config} $ws_apps {
89 set app_lib [string tolower "app_$app_name\.src"]
90 if {![IsInList $app_lib $libs_in_fileset 0 1]} {
91 Msg Warning "App '$app_name' exists in workspace but no corresponding sourcefile '$app_lib' found. \
92 Make sure you have a list file with the correct naming convention: \[app_<app_name>\.src\]"
98 foreach lib $libs_in_fileset {
99 Msg Debug "lib: $lib \n"
100 set lib_files [
DictGet $libraries $lib]
101 Msg Debug "Files in $lib: $lib_files"
102 set rootlib [
file rootname [
file tail $lib]]
103 set ext [
file extension $lib]
104 Msg Debug "lib: $lib ext: $ext fileset: $fileset"
108 if {[
string match "app_*" [
string tolower $lib]]} {
111 Msg Debug "Adding $lib to $fileset"
112 add_files -norecurse -fileset $fileset $lib_files
114 foreach f $lib_files {
115 set file_obj [get_files -of_objects [get_filesets $fileset] [list "*$f"]]
117 if {[
file extension $f] == ".vhd" || [
file extension $f] == ".vhdl"} {
118 set_property -name "library" -value $rootlib -objects $file_obj
122 set props [
DictGet $properties $f]
123 if {[
file extension $f] == ".vhd" || [
file extension $f] == ".vhdl"} {
125 if {[lsearch -inline -regexp $props "93"] < 0} {
128 if {[lsearch -inline -regexp $props "2008"] >= 0} {
129 set vhdl_year "VHDL 2008"
130 }
elseif {[lsearch -inline -regexp $props "2019"] >= 0} {
132 set vhdl_year "VHDL 2019"
134 Msg CriticalWarning "VHDL 2019 is not supported\
135 in Vivado version older than 2023.2.\
136 Using VHDL 2008, but this might not work."
137 set vhdl_year "VHDL 2008"
141 set vhdl_year "VHDL 2008"
143 Msg Debug "File type for $f is $vhdl_year"
144 set_property -name "file_type" -value $vhdl_year -objects $file_obj
147 Msg Debug "Filetype is VHDL 93 for $f"
152 if {[lsearch -inline -regexp $props "SystemVerilog"] > 0} {
155 set_property -name "file_type" -value "SystemVerilog" -objects $file_obj
156 Msg Debug "Filetype is SystemVerilog for $f"
158 Msg Warning "Xilinx PlanAhead/ISE does not support SystemVerilog.\
159 Property not set for $f"
164 set top [
lindex [regexp -inline {\ytop\s*=\s*(.+?)\y.*} $props] 1]
166 Msg Info "Setting $top as top module for file set $fileset..."
167 set globalSettings::synth_top_module $top
172 if {[lsearch -inline -regexp $props "verilog_header"] >= 0} {
173 Msg Debug "Setting verilog header type for $f..."
174 set_property file_type {Verilog Header} [get_files $f]
175 }
elseif {[lsearch -inline -regexp $props "verilog_template"] >= 0} {
177 Msg Debug "Setting verilog template type for $f..."
178 set_property file_type {Verilog Template} [get_files $f]
179 }
elseif {[lsearch -inline -regexp $props "verilog"] >= 0} {
181 Msg Debug "Setting verilog type for $f..."
182 set_property file_type {Verilog} [get_files $f]
186 if {[lsearch -inline -regexp $props "nosynth"] >= 0} {
187 Msg Debug "Setting not used in synthesis for $f..."
188 set_property -name "used_in_synthesis" -value "false" -objects $file_obj
192 if {[lsearch -inline -regexp $props "noimpl"] >= 0} {
193 Msg Debug "Setting not used in implementation for $f..."
194 set_property -name "used_in_implementation" -value "false" -objects $file_obj
198 if {[lsearch -inline -regexp $props "nosim"] >= 0} {
199 Msg Debug "Setting not used in simulation for $f..."
200 set_property -name "used_in_simulation" -value "false" -objects $file_obj
205 set top_sim [
lindex [regexp -inline {\ytopsim\s*=\s*(.+?)\y.*} $props] 1]
206 if {$top_sim != ""} {
207 Msg Warning "Setting the simulation top module with the topsim property is deprecated.\
208 Please set this property in the \[properties\] section of your .sim list file,
209 or in the \[$fileset\] section of your sim.conf,\
210 by adding the following line.\ntop=$top_sim"
214 set sim_runtime [
lindex [regexp -inline {\yruntime\s*=\s*(.+?)\y.*} $props] 1]
215 if {$sim_runtime != ""} {
216 Msg Warning "Setting the simulation runtime using the runtime= property is deprecated.\
217 Please set this property in the \[properties\] section of your .sim list file,\
218 or in the \[$fileset\] section of your sim.conf,\
219 by adding the following line.\n<simulator_name>.simulate.runtime=$sim_runtime"
223 if {[lsearch -inline -regexp $props "wavefile"] >= 0} {
224 Msg Warning "Setting a wave do file using the wavefile property is deprecated.\
225 Set this property in the sim.conf file under the \[$fileset\] section,\
226 or in the \[properties\] section of the .sim list file,\
227 by adding the following line .\n<simulator_name>.simulate.custom_wave_do=[
file tail $f]"
231 if {[lsearch -inline -regexp $props "dofile"] >= 0} {
232 Msg Warning "Setting a wave do file using the dofile property is deprecated.\
233 Set this property in the sim.conf file under the \[$fileset\] section,\
234 or in the \[properties\] section of the .sim list file,\
235 by adding the following line .\n<simulator_name>.simulate.custom_do=[
file tail $f]"
239 if {[lsearch -inline -regexp $props "locked"] >= 0 && $ext == ".ip"} {
240 Msg Info "Locking IP $f..."
241 set_property IS_MANAGED 0 [get_files $f]
245 if {[
file extension $f] == ".bd"} {
246 Msg Info "Generating Target for [
file tail $f],\
247 please remember to commit the (possible) changed file."
248 generate_target all [get_files $f]
253 if {[
file extension $f] == ".tcl" && $ext != ".con"} {
254 if {[lsearch -inline -regexp $props "source"] >= 0} {
255 Msg Info "Sourcing Tcl script $f,\
256 and setting it not used in synthesis, implementation and simulation..."
258 set_property -name "used_in_synthesis" -value "false" -objects $file_obj
259 set_property -name "used_in_implementation" -value "false" -objects $file_obj
260 set_property -name "used_in_simulation" -value "false" -objects $file_obj
265 set ref [
lindex [regexp -inline {\yscoped_to_ref\s*=\s*(.+?)\y.*} $props] 1]
266 set cell [
lindex [regexp -inline {\yscoped_to_cells\s*=\s*(.+?)\y.*} $props] 1]
267 if {([
file extension $f] == ".tcl" || [
file extension $f] == ".xdc") && $ext == ".con"} {
269 set_property SCOPED_TO_REF $ref $file_obj
272 set_property SCOPED_TO_CELLS $cell $file_obj
276 Msg Info "[
llength $lib_files] file/s added to library $rootlib..."
279 if {$ext == ".sim"} {
280 Msg Warning "Simulation files not supported in Quartus Prime mode... Skipping $lib"
282 if {![is_project_open]} {
283 Msg Error "Project is closed"
285 foreach cur_file $lib_files {
289 set props [
DictGet $properties $cur_file]
292 set top [
lindex [regexp -inline {\ytop\s*=\s*(.+?)\y.*} $props] 1]
294 Msg Info "Setting $top as top module for file set $fileset..."
295 set globalSettings::synth_top_module $top
298 if {[
string first "VHDL" $file_type] != -1} {
299 if {[
string first "1987" $props] != -1} {
300 set hdl_version "VHDL_1987"
301 }
elseif {[
string first "1993" $props] != -1} {
302 set hdl_version "VHDL_1993"
303 }
elseif {[
string first "2008" $props] != -1} {
304 set hdl_version "VHDL_2008"
306 set hdl_version "default"
308 if {$hdl_version == "default"} {
309 set_global_assignment -name $file_type $cur_file -library $rootlib
311 set_global_assignment -name $file_type $cur_file -hdl_version $hdl_version -library $rootlib
313 }
elseif {[
string first "SYSTEMVERILOG" $file_type] != -1} {
315 if {[
string first "2005" $props] != -1} {
316 set hdl_version "systemverilog_2005"
317 }
elseif {[
string first "2009" $props] != -1} {
318 set hdl_version "systemverilog_2009"
320 set hdl_version "default"
322 if {$hdl_version == "default"} {
323 set_global_assignment -name $file_type $cur_file
325 set_global_assignment -name $file_type $cur_file -hdl_version $hdl_version
327 }
elseif {[
string first "VERILOG" $file_type] != -1} {
329 if {[
string first "1995" $props] != -1} {
330 set hdl_version "verilog_1995"
331 }
elseif {[
string first "2001" $props] != -1} {
332 set hdl_version "verilog_2001"
334 set hdl_version "default"
336 if {$hdl_version == "default"} {
337 set_global_assignment -name $file_type $cur_file
339 set_global_assignment -name $file_type $cur_file -hdl_version $hdl_version
341 }
elseif {[
string first "SOURCE" $file_type] != -1 || [
string first "COMMAND_MACRO" $file_type] != -1} {
342 set_global_assignment -name $file_type $cur_file
343 if {$ext == ".con"} {
345 }
elseif {$ext == ".src"} {
347 if {[
string first "qsys" $props] != -1} {
350 regsub -all {\{||qsys||\}} $props $emptyString props
352 set qsysPath [
file dirname $cur_file]
353 set qsysName "[
file rootname [
file tail $cur_file]].qsys"
354 set qsysFile "$qsysPath/$qsysName"
355 set qsysLogFile "$qsysPath/[
file rootname [
file tail $cur_file]].qsys-script.log"
358 if {![
info exists ::env(QSYS_ROOTDIR)]} {
359 if {[
info exists ::env(QUARTUS_ROOTDIR)]} {
360 set qsys_rootdir "$::env(QUARTUS_ROOTDIR)/sopc_builder/bin"
361 Msg Warning "The QSYS_ROOTDIR environment variable is not set! I will use $qsys_rootdir"
363 Msg CriticalWarning "The QUARTUS_ROOTDIR environment variable is not set! Assuming all quartus executables are contained in your PATH!"
366 set qsys_rootdir $::env(QSYS_ROOTDIR)
369 set cmd "$qsys_rootdir/qsys-script"
370 set cmd_options " --script=$cur_file"
371 if {![
catch {"exec $cmd -version"}] || [
lindex $::errorCode 0] eq "NONE"} {
372 Msg Info "Executing: $cmd $cmd_options"
373 Msg Info "Saving logfile in: $qsysLogFile"
374 if {[
catch {
eval exec -ignorestderr "$cmd $cmd_options >>& $qsysLogFile"} ret opt]} {
375 set makeRet [
lindex [dict get $opt -errorcode] end]
376 Msg CriticalWarning "$cmd returned with $makeRet"
379 Msg Error " Could not execute command $cmd"
383 if {[
file exists $qsysName] != 0} {
384 file rename -force $qsysName $qsysFile
386 set qsysMd5Sum [
Md5Sum $qsysFile]
388 set fileDir [
file normalize "./hogTmp"]
389 set fileName "$fileDir/.hogQsys.md5"
390 if {![
file exists $fileDir]} {
393 set hogQsysFile [open $fileName "a"]
394 set fileEntry "$qsysFile\t$qsysMd5Sum"
395 puts $hogQsysFile $fileEntry
398 Msg ERROR "Error while moving the generated qsys file to final location: $qsysName not found!"
400 if {[
file exists $qsysFile] != 0} {
401 if {[
string first "noadd" $props] == -1} {
403 set_global_assignment -name $qsysFileType $qsysFile
405 regsub -all {noadd} $props $emptyString props
407 if {[
string first "nogenerate" $props] == -1} {
411 Msg ERROR "Error while generating ip variations from qsys: $qsysFile not found!"
415 }
elseif {[
string first "QSYS" $file_type] != -1} {
417 regsub -all {\{||\}} $props $emptyString props
418 if {[
string first "noadd" $props] == -1} {
419 set_global_assignment -name $file_type $cur_file
421 regsub -all {noadd} $props $emptyString props
425 if {[
string first "nogenerate" $props] == -1} {
429 set_global_assignment -name $file_type $cur_file -library $rootlib
434 if {$ext == ".con"} {
435 set vld_exts {.sdc .pin .dcf .gcf .pdc .ndc .fdc .crt .vcd }
436 foreach con_file $lib_files {
438 set con_ext [
file extension $con_file]
439 if {[
IsInList [
file extension $con_file] $vld_exts]} {
440 set option [
string map {. -} $con_ext]
441 set option [
string map {fdc net_fdc} $option]
442 set option [
string map {pdc io_pdc} $option]
443 create_links -convert_EDN_to_HDL 0 -library {work} $option $con_file
445 set props [
DictGet $properties $con_file]
447 if {$con_ext == ".sdc"} {
448 if {[lsearch $props "notiming"] >= 0} {
449 Msg Info "Excluding $con_file from timing verification..."
451 Msg Info "Adding $con_file to time verification"
452 append timing_conf_command " -file $con_file"
456 if {[lsearch $props "nosynth"] >= 0} {
457 Msg Info "Excluding $con_file from synthesis..."
459 Msg Info "Adding $con_file to synthesis"
460 append synth_conf_command " -file $con_file"
465 if {$con_ext == ".pdc" || $con_ext == ".sdc"} {
466 if {[lsearch $props "noplace"] >= 0} {
467 Msg Info "Excluding $con_file from place and route..."
469 Msg Info "Adding $con_file to place and route"
470 append place_conf_command " -file $con_file"
475 Msg CriticalWarning "Constraint file $con_file does not have a valid extension. Allowed extensions are: \n $vld_exts"
478 }
elseif {$ext == ".src"} {
479 foreach f $lib_files {
480 Msg Debug "Adding source $f to library $rootlib..."
481 create_links -library $rootlib -hdl_source $f
483 }
elseif {$ext == ".sim"} {
484 Msg Debug "Adding stimulus file $f to library..."
485 create_links -library $rootlib -stimulus $f
487 build_design_hierarchy
488 foreach cur_file $lib_files {
492 set props [
DictGet $properties $cur_file]
495 set top [
lindex [regexp -inline {\ytop\s*=\s*(.+?)\y.*} $props] 1]
497 Msg Info "Setting $top as top module for file set $rootlib..."
498 set globalSettings::synth_top_module "${top}::$rootlib"
503 if {$ext == ".src" || $ext == ".con" || $ext == ".ext"} {
504 foreach f $lib_files {
505 Msg Debug "Diamond: adding source file $f to library $rootlib..."
506 prj_src add -work $rootlib $f
507 set props [
DictGet $properties $f]
509 set top [
lindex [regexp -inline {\ytop\s*=\s*(.+?)\y.*} $props] 1]
511 Msg Info "Setting $top as top module for the project..."
512 set globalSettings::synth_top_module $top
516 if {[lsearch -inline -regexp $props "enable"] >= 0} {
517 Msg Debug "Setting $f as active Logic Preference file"
521 }
elseif {$ext == ".sim"} {
522 foreach f $lib_files {
523 Msg Debug "Diamond Adding simulation file $f to library $rootlib..."
524 prj_src add -work $rootlib -simulate_only $f
532 if {[
catch {
set ws_apps [app list -dict]}]} {
set ws_apps ""}
534 foreach app_name [dict keys $ws_apps] {
535 foreach f $lib_files {
536 if {[
string tolower $rootlib] != [
string tolower "app_$app_name"]} {
540 Msg Info "Adding source file $f from lib: $lib to vitis app \[$app_name\]..."
541 set proj_f_path [regsub "^$globalSettings::repo_path" $f ""]
542 set proj_f_path [regsub "[
file tail $f]$" $proj_f_path ""]
543 Msg Debug "Project_f_path is $proj_f_path"
545 importsources -name $app_name -soft-link -path $f -target $proj_f_path
555 if {[
DictGet $filesets "sim_1"] == ""} {
556 delete_fileset -quiet [get_filesets -quiet "sim_1"]
562 if {$synth_conf == 1} {
563 Msg Info $synth_conf_command
564 eval $synth_conf_command
566 if {$timing_conf == 1} {
567 Msg Info $timing_conf_command
568 eval $timing_conf_command
570 if {$place_conf == 1} {
571 Msg Info $place_conf_command
572 eval $place_conf_command
578 proc ALLOWED_PROPS {} {
579 return [dict create ".vhd" [list "93" "nosynth" "noimpl" "nosim" "1987" "1993" "2008" "2019"] \
580 ".vhdl" [list "93" "nosynth" "noimpl" "nosim" "1987" "1993" "2008" "2019"] \
581 ".bd" [list "nosim"] \
582 ".v" [list "SystemVerilog" "verilog_header" "nosynth" "noimpl" "nosim" "1995" "2001"] \
583 ".sv" [list "verilog" "verilog_header" "nosynth" "noimpl" "nosim" "2005" "2009"] \
584 ".do" [list "nosim"] \
585 ".udo" [list "nosim"] \
586 ".xci" [list "nosynth" "noimpl" "nosim" "locked"] \
587 ".xdc" [list "nosynth" "noimpl" "scoped_to_ref" "scoped_to_cells"] \
588 ".tcl" [list "nosynth" "noimpl" "nosim" "source" "qsys" "noadd"\
589 "--block-symbol-file" "--clear-output-directory" "--example-design"\
590 "--export-qsys-script" "--family" "--greybox" "--ipxact"\
591 "--jvm-max-heap-size" "--parallel" "--part" "--search-path"\
592 "--simulation" "--synthesis" "--testbench" "--testbench-simulation"\
593 "--upgrade-ip-cores" "--upgrade-variation-file"
595 ".qsys" [list "nogenerate" "noadd" "--block-symbol-file" "--clear-output-directory" "--example-design"\
596 "--export-qsys-script" "--family" "--greybox" "--ipxact" "--jvm-max-heap-size" "--parallel"\
597 "--part" "--search-path" "--simulation" "--synthesis" "--testbench" "--testbench-simulation"\
598 "--upgrade-ip-cores" "--upgrade-variation-file"
600 ".sdc" [list "notiming" "nosynth" "noplace"] \
601 ".elf" [list "scoped_to_ref" "scoped_to_cells" "nosim" "noimpl"] \
602 ".pdc" [list "nosynth" "noplace"] \
603 ".lpf" [list "enable"]]
614 proc BinaryStepName {part} {
616 return "WRITE_DEVICE_IMAGE"
620 return "WRITE_BITSTREAM"
629 proc CheckSyntax {project_name repo_path {project_file ""}} {
631 set syntax [check_syntax -return_string]
632 if {[
string first "CRITICAL" $syntax] != -1} {
637 lassign [
GetHogFiles -list_files "*.src" "$repo_path/Top/$project_name/list/" $repo_path] src_files dummy
638 dict for {lib files} $src_files {
640 set file_extension [file extension $f]
641 if {$file_extension == ".vhd" || $file_extension == ".vhdl" || $file_extension == ".v" || $file_extension == ".sv"} {
642 if {[catch {execute_module -tool map -args "--analyze_file=$f"} result]} {
643 Msg Error "\nResult: $result\n"
644 Msg Error "Check syntax failed.\n"
647 Msg Info "Check syntax was successful for $f.\n"
649 Msg Warning "Found syntax error in file $f:\n $result\n"
656 lassign [
GetProjectFiles $project_file] prjLibraries prjProperties prjSimLibraries prjConstraints prjSrcSets prjSimSets prjConSets
657 dict for {lib sources} $prjLibraries {
658 if {[file extension $lib] == ".src"} {
660 Msg Info "Checking Syntax of $f"
666 Msg Info "The Checking Syntax is not supported by this IDE. Skipping..."
671 proc CloseProject {} {
693 proc CompareVersions {ver1 ver2} {
702 if {[regexp {v(\d+)\.(\d+)\.(\d+)} $ver1 - x y z]} {
703 set ver1 [list $x $y $z]
705 if {[regexp {v(\d+)\.(\d+)\.(\d+)} $ver2 - x y z]} {
706 set ver2 [list $x $y $z]
710 set v1 [
join $ver1 ""]
712 set v2 [
join $ver2 ""]
715 if {[
string is integer $v1] && [
string is integer $v2]} {
716 set ver1 [
expr {[scan [lindex $ver1 0] %d] * 1000000 + [scan [lindex $ver1 1] %d] * 1000 + [scan [lindex $ver1 2] %d]}]
717 set ver2 [
expr {[scan [lindex $ver2 0] %d] * 1000000 + [scan [lindex $ver2 1] %d] * 1000 + [scan [lindex $ver2 2] %d]}]
721 }
elseif {$ver1 == $ver2} {
727 Msg Warning "Version is not numeric: $ver1, $ver2"
737 proc CheckExtraFiles {libraries constraints simlibraries} {
740 lassign [
GetProjectFiles] prjLibraries prjProperties prjSimLibraries prjConstraints
741 set prj_dir [get_property DIRECTORY [current_project]]
742 file mkdir "$prj_dir/.hog"
743 set extra_file_name "$prj_dir/.hog/extra.files"
744 set new_extra_file [open $extra_file_name "w"]
746 dict for {prjLib prjFiles} $prjLibraries {
747 foreach prjFile $prjFiles {
748 if {[file extension $prjFile] == ".xcix"} {
749 Msg Warning "IP $prjFile is packed in a .xcix core container. \
750 This files are not suitable for version control systems. We recommend to use .xci files instead."
753 if {[file extension $prjFile] == ".xci" && [get_property CORE_CONTAINER [get_files $prjFile]] != ""} {
754 Msg Info "$prjFile is a virtual IP file in a core container. Ignoring it..."
758 if {[IsInList $prjFile [DictGet $libraries $prjLib]] == 0} {
759 if {[file extension $prjFile] == ".bd"} {
760 # Generating BD products to save md5sum of already modified BD
761 Msg Info "Generating targets of $prjFile..."
762 generate_target all [get_files $prjFile]
764 puts $new_extra_file "$prjFile [Md5Sum $prjFile]"
765 Msg Info "$prjFile (lib: $prjLib) has been generated by an external script. Adding to $extra_file_name..."
769 close $new_extra_file
770 set extra_sim_file "$prj_dir/.hog/extrasim.files"
771 set new_extra_file [open $extra_sim_file "w"]
773 dict for {prjSimLib prjSimFiles} $prjSimLibraries {
774 foreach prjSimFile $prjSimFiles {
775 if {[IsInList $prjSimFile [DictGet $simlibraries $prjSimLib]] == 0} {
776 puts $new_extra_file "$prjSimFile [Md5Sum $prjSimFile]"
777 Msg Info "$prjSimFile (lib: $prjSimLib) has been generated by an external script. Adding to $extra_sim_file..."
781 close $new_extra_file
782 set extra_con_file "$prj_dir/.hog/extracon.files"
783 set new_extra_file [open $extra_con_file "w"]
785 dict for {prjConLib prjConFiles} $prjConstraints {
786 foreach prjConFile $prjConFiles {
787 if {[IsInList $prjConFile [DictGet $constraints $prjConLib]] == 0} {
788 puts $new_extra_file "$prjConFile [Md5Sum $prjConFile]"
789 Msg Info "$prjConFile has been generated by an external script. Adding to $extra_con_file..."
793 close $new_extra_file
800 proc CheckLatestHogRelease {{repo_path .}} {
803 set current_ver [
Git {describe --always}]
804 Msg Debug "Current version: $current_ver"
805 set current_sha [
Git "log $current_ver -1 --format=format:%H"]
806 Msg Debug "Current SHA: $current_sha"
809 if {[
OS] == "windows"} {
810 Msg Info "On windows we cannot set a timeout on 'git fetch', hopefully nothing will go wrong..."
813 Msg Info "Checking for latest Hog release, can take up to 5 seconds..."
816 set master_ver [
Git "describe origin/master"]
817 Msg Debug "Master version: $master_ver"
818 set master_sha [
Git "log $master_ver -1 --format=format:%H"]
819 Msg Debug "Master SHA: $master_sha"
820 set merge_base [
Git "merge-base $current_sha $master_sha"]
821 Msg Debug "merge base: $merge_base"
824 if {$merge_base != $master_sha} {
826 Msg Info "Version $master_ver has been released (https://gitlab.com/hog-cern/Hog/-/releases/$master_ver)"
827 Msg Status "You should consider updating Hog submodule with the following instructions:"
829 Msg Status "cd Hog && git checkout master && git pull"
831 Msg Status "Also update the ref: in your .gitlab-ci.yml to $master_ver"
835 Msg Info "Latest official version is $master_ver, nothing to do."
847 proc CheckYmlRef {repo_path allow_failure} {
848 if {$allow_failure} {
849 set MSG_TYPE CriticalWarning
854 if {[
catch {
package require yaml 0.3.3} YAMLPACKAGE]} {
855 Msg CriticalWarning "Cannot find package YAML, skipping consistency check of \"ref\" in gilab-ci.yaml file.\n Error message: $YAMLPACKAGE
856 You can fix this by installing package \"tcllib\""
864 if {[
file exists .gitlab-ci.yml]} {
868 if {[
file exists .gitlab-ci.yml]} {
869 set fp [open ".gitlab-ci.yml" r]
870 set file_data [read $fp]
873 Msg $MSG_TYPE "Cannot open file .gitlab-ci.yml"
877 set file_data "\n$file_data\n\n"
879 if {[
catch {::yaml::yaml2dict -stream $file_data} yamlDict]} {
880 Msg $MSG_TYPE "Parsing $repo_path/.gitlab-ci.yml failed. To fix this, check that yaml syntax is respected, remember not to use tabs."
884 dict for {dictKey dictValue} $yamlDict {
885 #looking for Hog include in .gitlab-ci.yml
886 if {"$dictKey" == "include" && (
887 [lsearch [split $dictValue " {}"] "/hog.yml"] != "-1" ||
888 [lsearch [split $dictValue " {}"] "/hog-dynamic.yml"] != "-1"
890 set YML_REF [lindex [split $dictValue " {}"] [expr {[lsearch -dictionary [split $dictValue " {}"] "ref"] + 1}]]
891 set YML_NAME [lindex [split $dictValue " {}"] [expr {[lsearch -dictionary [split $dictValue " {}"] "file"] + 1}]]
895 if {$YML_REF == ""} {
896 Msg Warning "Hog version not specified in the .gitlab-ci.yml. Assuming that master branch is used."
898 set YML_REF_F [
Git {name-rev --tags --name-only origin/master}]
901 set YML_REF_F [regsub -all "'" $YML_REF ""]
904 if {$YML_NAME == ""} {
905 Msg $MSG_TYPE "Hog included yml file not specified, assuming hog.yml"
906 set YML_NAME_F hog.yml
908 set YML_NAME_F [regsub -all "^/" $YML_NAME ""]
911 lappend YML_FILES $YML_NAME_F
917 if {[
catch {::yaml::yaml2dict -file $YML_NAME_F} yamlDict]} {
918 Msg $MSG_TYPE "Parsing $YML_NAME_F failed."
922 dict for {dictKey dictValue} $yamlDict {
923 #looking for included files
924 if {"$dictKey" == "include"} {
925 foreach v $dictValue {
926 lappend YML_FILES [lindex [split $v " "] [expr {[lsearch -dictionary [split $v " "] "local"] + 1}]]
932 Msg Info "Found the following yml files: $YML_FILES"
934 set HOGYML_SHA [
GetSHA $YML_FILES]
935 lassign [
GitRet "log --format=%h -1 --abbrev=7 $YML_REF_F" $YML_FILES] ret EXPECTEDYML_SHA
937 lassign [
GitRet "log --format=%h -1 --abbrev=7 origin/$YML_REF_F" $YML_FILES] ret EXPECTEDYML_SHA
939 Msg $MSG_TYPE "Error in project .gitlab-ci.yml. ref: $YML_REF not found"
940 set EXPECTEDYML_SHA ""
943 if {!($EXPECTEDYML_SHA eq "")} {
944 if {$HOGYML_SHA == $EXPECTEDYML_SHA} {
945 Msg Info "Hog included file $YML_FILES matches with $YML_REF in .gitlab-ci.yml."
947 Msg $MSG_TYPE "HOG $YML_FILES SHA mismatch.
948 From Hog submodule: $HOGYML_SHA
949 From ref in .gitlab-ci.yml: $EXPECTEDYML_SHA
950 You can fix this in 2 ways: by changing the ref in your repository or by changing the Hog submodule commit"
953 Msg $MSG_TYPE "One or more of the following files could not be found $YML_FILES in Hog at $YML_REF"
956 Msg Info ".gitlab-ci.yml not found in $repo_path. Skipping this step"
977 proc CompareLibDicts {proj_libs list_libs proj_sets list_sets proj_props list_props {severity "CriticalWarning"} {outFile ""} {extraFiles ""}} {
978 set extra_files $extraFiles
980 set out_prjlibs $proj_libs
981 set out_prjprops $proj_props
983 dict for {prjSet prjLibraries} $proj_sets {
984 # Check if sets is also in list files
985 if {[IsInList $prjSet $list_sets]} {
986 set listLibraries [DictGet $list_sets $prjSet]
987 # Loop over libraries in fileset
988 foreach prjLib $prjLibraries {
989 set prjFiles [DictGet $proj_libs $prjLib]
990 # Check if library exists in list files
991 if {[IsInList $prjLib $listLibraries]} {
992 # Loop over files in library
993 set listFiles [DictGet $list_libs $prjLib]
994 foreach prjFile $prjFiles {
995 set idx [lsearch -exact $listFiles $prjFile]
996 set listFiles [lreplace $listFiles $idx $idx]
998 # File is in project but not in list libraries, check if it was generated at creation time...
999 if {[dict exists $extra_files $prjFile]} {
1000 # File was generated at creation time, checking the md5sum
1001 # Removing the file from the prjFiles list
1002 set idx2 [lsearch -exact $prjFiles $prjFile]
1003 set prjFiles [lreplace $prjFiles $idx2 $idx2]
1004 set new_md5sum [Md5Sum $prjFile]
1005 set old_md5sum [DictGet $extra_files $prjFile]
1006 if {$new_md5sum != $old_md5sum} {
1007 # tclint-disable-next-line line-length
1008 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
1011 set extra_files [dict remove $extra_files $prjFile]
1013 # File is neither in list files nor in extra_files
1014 MsgAndLog "$prjFile was found in project but not in list files or .hog/extra.files" $severity $outFile
1018 # File is both in list files and project, checking properties...
1019 set prjProps [DictGet $proj_props $prjFile]
1020 set listProps [DictGet $list_props $prjFile]
1021 # Check if it is a potential sourced file
1022 if {[IsInList "nosynth" $prjProps] && [IsInList "noimpl" $prjProps] && [IsInList "nosim" $prjProps]} {
1023 # Check if it is sourced
1024 set idx_source [lsearch -exact $listProps "source"]
1025 if {$idx_source >= 0} {
1026 # It is sourced, let's replace the individual properties with source
1027 set idx [lsearch -exact $prjProps "noimpl"]
1028 set prjProps [lreplace $prjProps $idx $idx]
1029 set idx [lsearch -exact $prjProps "nosynth"]
1030 set prjProps [lreplace $prjProps $idx $idx]
1031 set idx [lsearch -exact $prjProps "nosim"]
1032 set prjProps [lreplace $prjProps $idx $idx]
1033 lappend prjProps "source"
1037 foreach prjProp $prjProps {
1038 set idx [lsearch -exact $listProps $prjProp]
1039 set listProps [lreplace $listProps $idx $idx]
1041 MsgAndLog "Property $prjProp of $prjFile was set in project but not in list files" $severity $outFile
1046 foreach listProp $listProps {
1047 if {[string first $listProp "topsim="] == -1 && [string first $listProp "enable"] == -1} {
1048 MsgAndLog "Property $listProp of $prjFile was found in list files but not set in project." $severity $outFile
1053 # Update project prjProps
1054 dict set out_prjprops $prjFile $prjProps
1057 # Loop over remaining files in list libraries
1058 foreach listFile $listFiles {
1059 MsgAndLog "$listFile was found in list files but not in project." $severity $outFile
1063 # Check extra files again...
1064 foreach prjFile $prjFiles {
1065 if {[dict exists $extra_files $prjFile]} {
1066 # File was generated at creation time, checking the md5sum
1067 # Removing the file from the prjFiles list
1068 set idx2 [lsearch -exact $prjFiles $prjFile]
1069 set prjFiles [lreplace $prjFiles $idx2 $idx2]
1070 set new_md5sum [Md5Sum $prjFile]
1071 set old_md5sum [DictGet $extra_files $prjFile]
1072 if {$new_md5sum != $old_md5sum} {
1073 # tclint-disable-next-line line-length
1074 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
1077 set extra_files [dict remove $extra_files $prjFile]
1079 # File is neither in list files nor in extra_files
1080 MsgAndLog "$prjFile was found in project but not in list files or .hog/extra.files" $severity $outFile
1085 # Update prjLibraries
1086 dict set out_prjlibs $prjLib $prjFiles
1089 MsgAndLog "Fileset $prjSet found in project but not in list files" $severity $outFile
1094 return [list $n_diffs $extra_files $out_prjlibs $out_prjprops]
1104 proc CompareVHDL {file1 file2} {
1105 set a [open $file1 r]
1106 set b [open $file2 r]
1108 while {[
gets $a line] != -1} {
1109 set line [regsub {^[\t\s]*(.*)?\s*} $line "\\1"]
1110 if {![regexp {^$} $line] & ![regexp {^--} $line]} {
1116 while {[
gets $b line] != -1} {
1117 set line [regsub {^[\t\s]*(.*)?\s*} $line "\\1"]
1118 if {![regexp {^$} $line] & ![regexp {^--} $line]} {
1127 foreach x $f1 y $f2 {
1129 lappend diff "> $x\n< $y\n\n"
1142 proc Copy {i_dirs o_dir} {
1143 foreach i_dir $i_dirs {
1144 if {[
file isdirectory $i_dir] && [
file isdirectory $o_dir]} {
1145 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]])} {
1146 file delete -force $o_dir/[
file tail $i_dir]
1150 file copy -force $i_dir $o_dir
1165 proc CopyIPbusXMLs {proj_dir path dst {xml_version "0.0.0"} {xml_sha "00000000"} {use_ipbus_sw 0} {generate 0}} {
1166 if {$use_ipbus_sw == 1} {
1167 lassign [
ExecuteRet python3 -c "from __future__ import print_function; from sys import path;print(':'.join(path\[1:\]))"] ret msg
1169 set ::env(PYTHONPATH) $msg
1170 lassign [
ExecuteRet gen_ipbus_addr_decode -h] ret msg
1177 Msg CriticalWarning "Problem while trying to run python: $msg"
1180 set dst [
file normalize $dst]
1182 if {$can_generate == 0} {
1183 if {$generate == 1} {
1184 Msg Error "Cannot generate IPbus address files, IPbus executable gen_ipbus_addr_decode not found or not working: $msg"
1187 Msg Warning "IPbus executable gen_ipbus_addr_decode not found or not working, will not verify IPbus address tables."
1194 set ipb_files [glob -nocomplain $proj_dir/list/*.ipb]
1195 set n_ipb_files [
llength $ipb_files]
1196 if {$n_ipb_files == 0} {
1197 Msg CriticalWarning "No files with .ipb extension found in $proj_dir/list."
1200 set libraries [dict create]
1201 set vhdl_dict [dict create]
1203 foreach ipb_file $ipb_files {
1209 set xmlfiles [dict get $libraries "xml.ipb"]
1211 set xml_list_error 0
1212 foreach xmlfile $xmlfiles {
1213 if {[
file isdirectory $xmlfile]} {
1214 Msg CriticalWarning "Directory $xmlfile listed in xml list file $list_file. Directories are not supported!"
1215 set xml_list_error 1
1218 if {[
file exists $xmlfile]} {
1219 if {[dict exists $vhdl_dict $xmlfile]} {
1220 set vhdl_file [
file normalize $path/[dict get $vhdl_dict $xmlfile]]
1224 lappend vhdls $vhdl_file
1225 set xmlfile [
file normalize $xmlfile]
1226 Msg Info "Copying $xmlfile to $dst and replacing place holders..."
1227 set in [open $xmlfile r]
1228 set out [open $dst/[
file tail $xmlfile] w]
1230 while {[
gets $in line] != -1} {
1231 set new_line [regsub {(.*)__VERSION__(.*)} $line "\\1$xml_version\\2"]
1232 set new_line2 [regsub {(.*)__GIT_SHA__(.*)} $new_line "\\1$xml_sha\\2"]
1233 puts $out $new_line2
1237 lappend xmls [
file tail $xmlfile]
1239 Msg Warning "XML file $xmlfile not found"
1242 if {${xml_list_error}} {
1243 Msg Error "Invalid files added to $list_file!"
1246 set cnt [
llength $xmls]
1247 Msg Info "$cnt xml file/s copied"
1250 if {$can_generate == 1} {
1253 file mkdir "address_decode"
1255 foreach x $xmls v $vhdls {
1257 set x [
file normalize ../$x]
1258 if {[
file exists $x]} {
1259 lassign [
ExecuteRet gen_ipbus_addr_decode --no-timestamp $x 2>&1] status log
1261 set generated_vhdl ./ipbus_decode_[
file rootname [
file tail $x]].vhd
1262 if {$generate == 1} {
1263 Msg Info "Copying generated VHDL file $generated_vhdl into $v (replacing if necessary)"
1264 file copy -force -- $generated_vhdl $v
1266 if {[
file exists $v]} {
1268 set n [
llength $diff]
1270 Msg CriticalWarning "$v does not correspond to its XML $x, [
expr {$n / 3}] line/s differ:"
1271 Msg Status [
join $diff "\n"]
1272 set diff_file [open ../diff_[
file rootname [
file tail $x]].txt w]
1273 puts $diff_file $diff
1276 Msg Info "[
file tail $x] and $v match."
1279 Msg Warning "VHDL address map file $v not found."
1283 Msg Warning "Address map generation failed for [
file tail $x]: $log"
1286 Msg Warning "Copied XML file $x not found."
1289 Msg Info "Skipped verification of [
file tail $x] as no VHDL file was specified."
1293 file delete -force address_decode
1305 proc DescriptionFromConf {conf_file} {
1306 set f [open $conf_file "r"]
1307 set lines [
split [read $f] "\n"]
1309 set second_line [
lindex $lines 1]
1312 if {![regexp {\#+ *(.+)} $second_line - description]} {
1316 if {[regexp -all {test|Test|TEST} $description]} {
1317 set description "test"
1330 proc DictGet {dictName keyName {default ""}} {
1331 if {[dict exists $dictName $keyName]} {
1332 return [dict get $dictName $keyName]
1343 proc DictSort {dict args} {
1345 foreach key [lsort {*}$args [dict keys $dict]] {
1346 dict set res $key [dict get $dict $key]
1356 proc DoxygenVersion {target_version} {
1357 set ver [
split $target_version "."]
1358 set v [
Execute doxygen --version]
1359 Msg Info "Found Doxygen version: $v"
1360 set current_ver [
split $v ". "]
1361 set target [
expr {[lindex $ver 0] * 100000 + [lindex $ver 1] * 100 + [lindex $ver 2]}]
1362 set current [
expr {[lindex $current_ver 0] * 100000 + [lindex $current_ver 1] * 100 + [lindex $current_ver 2]}]
1364 return [
expr {$target <= $current}]
1375 proc eos {command {attempt 1}} {
1377 if {![
info exists env(EOS_MGM_URL)]} {
1378 Msg Warning "Environment variable EOS_MGM_URL not set, setting it to default value root://eosuser.cern.ch"
1379 set ::env(EOS_MGM_URL) "root://eosuser.cern.ch"
1382 Msg Warning "The value of attempt should be 1 or more, not $attempt, setting it to 1 as default"
1385 for {
set i 0} {$i < $attempt} {
incr i} {
1386 set ret [
catch {
exec -ignorestderr eos {*}$command} result]
1391 set wait [
expr {1 + int(rand() * 29)}]
1392 Msg Warning "Command $command failed ($i/$attempt): $result, trying again in $wait seconds..."
1393 after [
expr {$wait * 1000}]
1397 return [list $ret $result]
1407 proc Execute {args} {
1411 Msg Error "Command [
join $args] returned error code: $ret"
1425 proc ExecuteRet {args} {
1427 if {[
llength $args] == 0} {
1428 Msg CriticalWarning "No argument given"
1432 set ret [
catch {
exec -ignorestderr {*}$args} result]
1435 return [list $ret $result]
1442 proc ExtractFilesSection {file_data} {
1443 set in_files_section 0
1446 foreach line $file_data {
1447 if {[regexp {^ *\[ *files *\]} $line]} {
1448 set in_files_section 1
1451 if {$in_files_section} {
1452 if {[regexp {^ *\[.*\]} $line]} {
1455 lappend result $line
1460 if {!$in_files_section} {
1474 proc ExtractVersionFromTag {tag} {
1475 if {[regexp {^(?:b(\d+))?v(\d+)\.(\d+).(\d+)(?:-\d+)?$} $tag -> mr M m p]} {
1480 Msg Warning "Repository tag $tag is not in a Hog-compatible format."
1486 return [list $M $m $p $mr]
1496 proc FileCommitted {File} {
1498 set currentDir [
pwd]
1499 cd [
file dirname [
file normalize $File]]
1500 set GitLog [
Git ls-files [
file tail $File]]
1501 if {$GitLog == ""} {
1502 Msg CriticalWarning "File [
file normalize $File] is not in the git repository. Please add it with:\n git add [
file normalize $File]\n"
1513 proc FindCommonGitChild {SHA1 SHA2} {
1515 set commits [
Git {log --oneline --merges}]
1518 foreach line [
split $commits "\n"] {
1519 set commit [
lindex [
split $line] 0]
1523 set ancestor $commit
1536 proc findFiles {basedir pattern} {
1539 set basedir [
string trimright [
file join [
file normalize $basedir] { }]]
1545 foreach fileName [glob -nocomplain -type {f r} -path $basedir $pattern] {
1546 lappend fileList $fileName
1550 foreach dirName [glob -nocomplain -type {d r} -path $basedir *] {
1553 set subDirList [
findFiles $dirName $pattern]
1554 if {[
llength $subDirList] > 0} {
1555 foreach subDirFile $subDirList {
1556 lappend fileList $subDirFile
1567 proc FindFileType {file_name} {
1568 set extension [
file extension $file_name]
1571 set file_extension "USE_SIGNALTAP_FILE"
1574 set file_extension "VHDL_FILE"
1577 set file_extension "VHDL_FILE"
1580 set file_extension "VERILOG_FILE"
1583 set file_extension "SYSTEMVERILOG_FILE"
1586 set file_extension "SDC_FILE"
1589 set file_extension "PDC_FILE"
1592 set file_extension "NDC_FILE"
1595 set file_extension "FDC_FILE"
1598 set file_extension "SOURCE_FILE"
1601 set file_extension "IP_FILE"
1604 set file_extension "QSYS_FILE"
1607 set file_extension "QIP_FILE"
1610 set file_extension "SIP_FILE"
1613 set file_extension "BSF_FILE"
1616 set file_extension "BDF_FILE"
1619 set file_extension "COMMAND_MACRO_FILE"
1622 set file_extension "VQM_FILE"
1625 set file_extension "ERROR"
1626 Msg Error "Unknown file extension $extension"
1629 return $file_extension
1636 proc FindNewestVersion {versions} {
1637 set new_ver 00000000
1638 foreach ver $versions {
1640 if {[
expr 0x$ver > 0x$new_ver]} {
1652 proc FindVhdlVersion {file_name} {
1653 set extension [
file extension $file_name]
1656 set vhdl_version "-hdl_version VHDL_2008"
1659 set vhdl_version "-hdl_version VHDL_2008"
1666 return $vhdl_version
1673 proc FormatGeneric {generic} {
1674 if {[
string is integer "0x$generic"]} {
1675 return [
format "32'h%08X" "0x$generic"]
1678 return [
format "32'h%08X" 0]
1688 proc GenerateBitstream {{run_folder ""} {repo_path .} {njobs 1}} {
1689 Msg Info "Starting write bitstream flow..."
1691 set revision [get_current_revision]
1692 if {[
catch {execute_module -tool asm} result]} {
1693 Msg Error "Result: $result\n"
1694 Msg Error "Generate bitstream failed. See the report file.\n"
1696 Msg Info "Generate bitstream was successful for revision $revision.\n"
1699 Msg Info "Run GENERATEPROGRAMMINGDATA ..."
1700 if {[
catch {run_tool -name {GENERATEPROGRAMMINGDATA}}]} {
1701 Msg Error "GENERATEPROGRAMMINGDATA FAILED!"
1703 Msg Info "GENERATEPROGRAMMINGDATA PASSED."
1705 Msg Info "Sourcing Hog/Tcl/integrated/post-bitstream.tcl"
1706 source $repo_path/Hog/Tcl/integrated/post-bitstream.tcl
1708 prj_run Export -impl Implementation0 -task Bitgen
1718 proc GenerateQsysSystem {qsysFile commandOpts} {
1719 if {[
file exists $qsysFile] != 0} {
1720 set qsysPath [
file dirname $qsysFile]
1721 set qsysName [
file rootname [
file tail $qsysFile]]
1722 set qsysIPDir "$qsysPath/$qsysName"
1723 set qsysLogFile "$qsysPath/$qsysName.qsys-generate.log"
1726 if {![
info exists ::env(QSYS_ROOTDIR)]} {
1727 if {[
info exists ::env(QUARTUS_ROOTDIR)]} {
1728 set qsys_rootdir "$::env(QUARTUS_ROOTDIR)/sopc_builder/bin"
1729 Msg Warning "The QSYS_ROOTDIR environment variable is not set! I will use $qsys_rootdir"
1731 Msg CriticalWarning "The QUARTUS_ROOTDIR environment variable is not set! Assuming all quartus executables are contained in your PATH!"
1734 set qsys_rootdir $::env(QSYS_ROOTDIR)
1737 set cmd "$qsys_rootdir/qsys-generate"
1738 set cmd_options "$qsysFile --output-directory=$qsysIPDir $commandOpts"
1739 if {![
catch {"exec $cmd -version"}] || [
lindex $::errorCode 0] eq "NONE"} {
1740 Msg Info "Executing: $cmd $cmd_options"
1741 Msg Info "Saving logfile in: $qsysLogFile"
1742 if {[
catch {
eval exec -ignorestderr "$cmd $cmd_options >>& $qsysLogFile"} ret opt]} {
1743 set makeRet [
lindex [dict get $opt -errorcode] end]
1744 Msg CriticalWarning "$cmd returned with $makeRet"
1747 Msg Error " Could not execute command $cmd"
1751 set qsysIPFileList [
concat \
1752 [glob -nocomplain -directory $qsysIPDir -types f *.ip *.qip] \
1753 [glob -nocomplain -directory "$qsysIPDir/synthesis" -types f *.ip *.qip *.vhd *.vhdl]
1755 foreach qsysIPFile $qsysIPFileList {
1756 if {[
file exists $qsysIPFile] != 0} {
1758 set_global_assignment -name $qsysIPFileType $qsysIPFile
1760 set IpMd5Sum [
Md5Sum $qsysIPFile]
1762 set fileDir [
file normalize "./hogTmp"]
1763 set fileName "$fileDir/.hogQsys.md5"
1764 if {![
file exists $fileDir]} {
1767 set hogQsysFile [open $fileName "a"]
1768 set fileEntry "$qsysIPFile\t$IpMd5Sum"
1769 puts $hogQsysFile $fileEntry
1774 Msg ERROR "Error while generating ip variations from qsys: $qsysFile not found!"
1784 proc GenericToSimulatorString {prop_dict target} {
1786 dict for {theKey theValue} $prop_dict {
1795 regexp {([0-9]*)('h)([0-9a-fA-F]*)} $theValue valueHexFull valueNumBits valueHexFlag valueHex
1796 regexp {^([0-9]*)$} $theValue valueIntFull ValueInt
1797 regexp {(?!^\d+$)^.+$} $theValue valueStrFull ValueStr
1798 if {[string tolower $target] == "vivado" || [string tolower $target] == "xsim"} {
1799 if {[string tolower $theValue] == "true" || [string tolower $theValue] == "false"} {
1800 set prj_generics "$prj_generics $theKey=$theValue"
1801 } elseif {$valueNumBits != "" && $valueHexFlag != "" && $valueHex != ""} {
1802 set prj_generics "$prj_generics $theKey=$valueHexFull"
1803 } elseif {$valueIntFull != "" && $ValueInt != ""} {
1804 set prj_generics "$prj_generics $theKey=$ValueInt"
1805 } elseif {$valueStrFull != "" && $ValueStr != ""} {
1806 set prj_generics "$prj_generics $theKey=\"$ValueStr\""
1808 set prj_generics "$prj_generics $theKey=\"$theValue\""
1810 } elseif {[lsearch -exact [GetSimulators] [string tolower $target]] >= 0} {
1811 if {$valueNumBits != "" && $valueHexFlag != "" && $valueHex != ""} {
1813 scan $valueNumBits %d numBits
1815 scan $valueHex %x numHex
1816 binary scan [binary format "I" $numHex] "B*" binval
1817 set numBits [expr {$numBits - 1}]
1818 set numBin [string range $binval end-$numBits end]
1819 set prj_generics "$prj_generics $theKey=\"$numBin\""
1820 } elseif {$valueIntFull != "" && $ValueInt != ""} {
1821 set prj_generics "$prj_generics $theKey=$ValueInt"
1822 } elseif {$valueStrFull != "" && $ValueStr != ""} {
1823 set prj_generics "$prj_generics {$theKey=\"$ValueStr\"}"
1825 set prj_generics "$prj_generics {$theKey=\"$theValue\"}"
1828 Msg Warning "Target : $target not implemented"
1831 return $prj_generics
1839 proc GetConfFiles {proj_dir} {
1840 Msg Debug "GetConfFiles called with proj_dir=$proj_dir"
1841 if {![
file isdirectory $proj_dir]} {
1842 Msg Error "$proj_dir is supposed to be the top project directory"
1845 set conf_file [
file normalize $proj_dir/hog.conf]
1846 set sim_file [
file normalize $proj_dir/sim.conf]
1847 set pre_tcl [
file normalize $proj_dir/pre-creation.tcl]
1848 set post_tcl [
file normalize $proj_dir/post-creation.tcl]
1850 return [list $conf_file $sim_file $pre_tcl $post_tcl]
1859 proc GetCustomCommands {parameters {directory .}} {
1860 set commands_dict [dict create]
1861 set commands_files [glob -nocomplain $directory/*.tcl]
1863 if {[
llength $commands_files] == 0} {
1867 foreach file $commands_files {
1872 if {$custom_cmd eq ""} {
1877 set custom_cmd_name [dict get $custom_cmd NAME]
1879 Msg Debug "Loaded custom command '$custom_cmd_name' from $file"
1882 if {[dict exists $commands_dict $custom_cmd_name]} {
1883 Msg Error "Custom command '$custom_cmd_name' in $file already defined as: \[dict get $commands_dict $custom_cmd_name\]. Skipping."
1889 set custom_cmd_name [
string toupper $custom_cmd_name]
1890 dict set commands_dict $custom_cmd_name $custom_cmd
1893 return $commands_dict
1896 proc SanitizeCustomCommand {cmdDict file parameters} {
1899 foreach k [dict keys $cmdDict] {
1900 set K [
string toupper $k]
1901 dict set normalized $K [dict get $cmdDict $k]
1904 set cmdDict $normalized
1905 if {![dict exists $cmdDict NAME]} {
1906 Msg Error "Custom command in $file missing required key NAME. Skipping."
1909 if {![dict exists $cmdDict SCRIPT]} {
1910 Msg Error "Custom command '$[dict get $cmdDict NAME]' in $file missing SCRIPT. Skipping."
1915 set allowed {NAME DESCRIPTION OPTIONS CUSTOM_OPTIONS SCRIPT IDE NO_EXIT}
1916 foreach k [dict keys $cmdDict] {
1917 if {[lsearch -exact $allowed $k] < 0} {
1918 Msg Warning "Custom command '[dict get $cmdDict NAME]' in $file: unknown key '$k'. Allowed: $allowed. Skipping."
1923 set name [
string trim [dict get $cmdDict NAME]]
1925 Msg Error "Custom command in $file has empty NAME. Skipping."
1929 if {![regexp {^[a-zA-Z][a-zA-Z0-9_]+$} $name]} {
1930 Msg Error "Custom command NAME '$name' (file $file) contains invalid characters."
1934 if {![dict exists $cmdDict DESCRIPTION]} {
1935 dict set cmdDict DESCRIPTION "No description provided."
1939 set hog_parameters {}
1940 foreach p $parameters {
1941 lappend hog_parameters [
lindex $p 0]
1946 if {[dict exists $cmdDict OPTIONS]} {
1947 set raw_opts [dict get $cmdDict OPTIONS]
1948 if {![
llength $raw_opts]} {
1952 foreach item $raw_opts {
1954 foreach p $parameters {
1955 set hog_parameter [
lindex $p 0]
1956 if { $item eq $hog_parameter } {
1957 lappend hog_options $p
1963 Msg Warning "Custom command '$name' in $file: option '$item' not found in Hog parameters. Skipping."
1966 dict set cmdDict OPTIONS $hog_options
1968 dict set cmdDict CUSTOM_OPTIONS {}
1975 if {[dict exists $cmdDict CUSTOM_OPTIONS]} {
1976 set raw_opts [dict get $cmdDict CUSTOM_OPTIONS]
1977 if {![
llength $raw_opts]} {
1980 foreach item $raw_opts {
1982 if {[
llength $item] != 2 && [
llength $item] != 3} {
1983 Msg Error "Bad custom option: \[$item\]. Custom command '$name' in $file: \
1984 each CUSTOM_OPTIONS entry must be {option \"help\"} for flags \
1985 and {option \"default_value\" \"help\"} for options with arguments. Skipping command."
1989 if {[
llength $item] == 2} {
1990 lassign $item opt help
1993 lassign $item opt def help
1996 if { [
IsInList $opt $hog_parameters] == 1 } {
1997 Msg Warning "Custom command '$name' in $file: option '$opt' already defined in Hog parameters. Skipping."
2003 if {![regexp {^[a-zA-Z][a-zA-Z0-9_]*(\.arg)?$} $opt]} {
2004 Msg Error "Custom command '$name' in $file: invalid option name '$opt'."
2009 Msg Warning "Custom command '$name' option '$opt' has empty help text."
2013 dict set cmdDict CUSTOM_OPTIONS {}
2017 if {[dict exists $cmdDict NO_EXIT]} {
2018 set no_exit [dict get $cmdDict NO_EXIT]
2019 set no_exit [
string tolower [
string trim $no_exit]]
2021 if {$no_exit eq "1" || $no_exit eq "true"} {
2027 dict set cmdDict NO_EXIT $no_exit
2029 dict set cmdDict NO_EXIT 0
2035 proc LoadCustomCommandFile {file parameters} {
2037 set dir [
file dirname $file]
2039 unset -nocomplain ::hog_command
2040 set rc [
catch {source $file} err]
2043 Msg Error "Error sourcing custom command file $file: $err"
2046 if {![
info exists ::hog_command]} {
2047 Msg Warning "File $file did not define ::hog_command. Skipping."
2050 set cmdDict $::hog_command
2052 if {[
catch {dict size $cmdDict}]} {
2053 Msg Error "In $file ::hog_command is not a valid dict. Skipping."
2063 proc GetDateAndTime {commit} {
2064 set clock_seconds [
clock seconds]
2067 set date [
Git "log -1 --format=%cd --date=format:%d%m%Y $commit"]
2068 set timee [
Git "log -1 --format=%cd --date=format:00%H%M%S $commit"]
2070 Msg Warning "Found Git version older than 2.9.3. Using current date and time instead of commit time."
2071 set date [
clock format $clock_seconds -format {%d%m%Y}]
2072 set timee [
clock format $clock_seconds -format {00%H%M%S}]
2074 return [list $date $timee]
2086 proc GetFile {file fileset} {
2089 set Files [get_files -all $file -of_object [get_filesets $fileset]]
2090 set f [
lindex $Files 0]
2098 puts "***DEBUG Hog:GetFile $file"
2107 proc GetFileGenerics {filename {entity ""}} {
2109 if {[
string equal $file_type "VERILOG_FILE"] || [
string equal $file_type "SYSTEMVERILOG_FILE"]} {
2111 }
elseif {[
string equal $file_type "VHDL_FILE"]} {
2114 Msg CriticalWarning "Could not determine extension of top level file."
2123 proc GetGenericsFromConf {proj_dir} {
2124 set generics_dict [dict create]
2125 set top_dir "Top/$proj_dir"
2126 set conf_file "$top_dir/hog.conf"
2128 Msg Debug "GetGenericsFromConf called with proj_dir=$proj_dir, top_dir=$top_dir"
2130 if {[
file exists $conf_file]} {
2132 if {[dict exists $properties generics]} {
2133 set generics_dict [dict get $properties generics]
2136 Msg Warning "File $conf_file not found."
2138 return $generics_dict
2151 proc GetSimSets {project_name repo_path {simsets ""} {ghdl 0} {no_conf 0}} {
2152 set simsets_dict [dict create]
2153 set list_dir "$repo_path/Top/$project_name/list"
2155 if {$simsets != ""} {
2156 foreach s $simsets {
2157 set list_file "$list_dir/$s.sim"
2158 if {[
file exists $list_file]} {
2159 lappend list_files $list_file
2160 }
elseif {$s != "sim_1"} {
2161 Msg CriticalWarning "Simulation set list file $list_file not found."
2166 set list_files [glob -nocomplain -directory $list_dir "*.sim"]
2170 set proj_dir [
file normalize $repo_path/Top/$project_name]
2171 set sim_file [
file normalize $proj_dir/sim.conf]
2173 foreach list_file $list_files {
2174 set file_name [
file tail $list_file]
2175 set simset_name [
file rootname $file_name]
2176 set fp [open $list_file r]
2177 set file_data [read $fp]
2179 set data [
split $file_data "\n"]
2181 set firstline [
lindex $data 0]
2183 if {[regexp {^ *\# *Simulator} $firstline]} {
2184 set simulator_prop [regexp -all -inline {\S+} $firstline]
2185 set simulator [
string tolower [
lindex $simulator_prop end]]
2187 Msg Warning "Simulator not set in $simset_name.sim. \
2188 The first line of $simset_name.sim should be #Simulator <SIMULATOR_NAME>,\
2189 where <SIMULATOR_NAME> can be xsim, questa, modelsim, ghdl, riviera, activehdl,\
2190 ies, or vcs, e.g. #Simulator questa.\
2191 Setting simulator by default to xsim."
2192 set simulator "xsim"
2194 if {$simulator eq "skip_simulation"} {
2195 Msg Info "Skipping simulation for $simset_name"
2198 if {($ghdl == 1 && $simulator != "ghdl") || ($ghdl == 0 && $simulator == "ghdl")} {
2202 set SIM_PROPERTIES ""
2203 if {[
file exists $sim_file] && $no_conf == 0} {
2204 set SIM_PROPERTIES [
ReadConf $sim_file]
2207 set global_sim_props [dict create]
2208 dict set global_sim_props "properties" [
DictGet $SIM_PROPERTIES "sim"]
2209 dict set global_sim_props "generics" [
DictGet $SIM_PROPERTIES "generics"]
2210 dict set global_sim_props "hog" [
DictGet $SIM_PROPERTIES "hog"]
2213 set sim_dict [dict create]
2214 dict set sim_dict "simulator" $simulator
2215 if {[dict exists $SIM_PROPERTIES $simset_name]} {
2216 dict set sim_dict "properties" [
DictGet $SIM_PROPERTIES $simset_name]
2217 dict set sim_dict "generics" [
DictGet $SIM_PROPERTIES "$simset_name:generics"]
2218 dict set sim_dict "hog" [
DictGet $SIM_PROPERTIES "$simset_name:hog"]
2219 }
elseif {$no_conf == 0} {
2221 set conf_dict [
ReadConf $list_file]
2222 set sim_dict [
MergeDict $sim_dict $conf_dict 0]
2224 set sim_dict [
MergeDict $sim_dict $global_sim_props 0]
2225 dict set simsets_dict $simset_name $sim_dict
2227 return $simsets_dict
2235 proc GetSimsetGenericsFromConf {proj_dir} {
2236 set simsets_generics_dict [dict create]
2237 set top_dir "Top/$proj_dir"
2238 set conf_file "$top_dir/sim.conf"
2241 if {[
file exists $conf_file]} {
2244 set simsets_generics_dict [dict filter $properties key *:generics]
2246 Msg Warning "File $conf_file not found."
2248 return $simsets_generics_dict
2259 proc GetGroupName {proj_dir repo_dir} {
2260 if {[regexp {^(.*)/(Top|Projects)/+(.*?)/*$} $proj_dir dummy possible_repo_dir proj_or_top dir]} {
2262 if {[
file normalize $repo_dir] eq [
file normalize $possible_repo_dir]} {
2263 set group [
file dir $dir]
2264 if {$group == "."} {
2269 Msg Warning "Project directory $proj_dir seems to be in $possible_repo_dir which is not a the main Git repository $repo_dir."
2272 Msg Warning "Could not parse project directory $proj_dir"
2285 proc GetHogDescribe {sha {repo_path .}} {
2288 set new_sha "[
string toupper [
GetSHA]]"
2291 set new_sha [
string toupper $sha]
2311 proc GetHogFiles {args} {
2314 if {[
catch {
package require cmdline} ERROR]} {
2315 puts "$ERROR\n If you are running this script on tclsh, you can fix this by installing 'tcllib'"
2322 {list_files.arg "" "The file wildcard, if not specified all Hog list files will be looked for."}
2323 {sha_mode "Forwarded to ReadListFile, see there for info."}
2324 {ext_path.arg "" "Path for the external libraries forwarded to ReadListFile."}
2325 {print_log "Forwarded to ReadListFile, see there for info."}
2327 set usage "USAGE: GetHogFiles \[options\] <list path> <repository path>"
2328 if {[
catch {
array set options [
cmdline::getoptions args $parameters $usage]}] || [
llength $args] != 2} {
2332 set list_path [
lindex $args 0]
2333 set repo_path [
lindex $args 1]
2335 set list_files $options(list_files)
2336 set sha_mode $options(sha_mode)
2337 set ext_path $options(ext_path)
2338 set print_log $options(print_log)
2340 if {$sha_mode == 1} {
2341 set sha_mode_opt "-sha_mode"
2346 if {$print_log == 1} {
2347 set print_log_opt "-print_log"
2349 set print_log_opt ""
2353 if {$list_files == ""} {
2354 set list_files {.src,.con,.sim,.ext}
2356 set libraries [dict create]
2357 set properties [dict create]
2358 set list_files [glob -nocomplain -directory $list_path "*{$list_files}"]
2359 set filesets [dict create]
2361 foreach f $list_files {
2362 set ext [
file extension $f]
2363 if {$ext == ".ext"} {
2364 lassign [
ReadListFile {*}"$sha_mode_opt $print_log_opt $f $ext_path"] l p fs
2366 lassign [
ReadListFile {*}"$sha_mode_opt $print_log_opt $f $repo_path"] l p fs
2369 set properties [
MergeDict $p $properties]
2370 Msg Debug "list file $f, filesets: $fs"
2372 Msg Debug "Merged filesets $filesets"
2374 return [list $libraries $properties $filesets]
2381 proc GetIDECommand {proj_conf {custom_ver ""}} {
2382 if {$custom_ver ne ""} {
2383 set ide_name_and_ver [
string tolower "$custom_ver"]
2384 }
elseif {[
file exists $proj_conf]} {
2385 set ide_name_and_ver [
string tolower [
GetIDEFromConf $proj_conf]]
2387 Msg Error "Configuration file $proj_conf not found."
2390 set ide_name [
lindex [regexp -all -inline {\S+} $ide_name_and_ver] 0]
2392 if {$ide_name eq "vivado" || $ide_name eq "vivado_vitis_classic"} {
2393 set command "vivado"
2395 set before_tcl_script " -nojournal -nolog -mode batch -notrace -source "
2396 set after_tcl_script " -tclargs "
2398 }
elseif {$ide_name eq "planahead"} {
2399 set command "planAhead"
2401 set before_tcl_script " -nojournal -nolog -mode batch -notrace -source "
2402 set after_tcl_script " -tclargs "
2404 }
elseif {$ide_name eq "quartus"} {
2405 set command "quartus_sh"
2407 set before_tcl_script " -t "
2408 set after_tcl_script " "
2410 }
elseif {$ide_name eq "libero"} {
2413 set command "libero"
2414 set before_tcl_script "SCRIPT:"
2415 set after_tcl_script " SCRIPT_ARGS:\""
2417 }
elseif {$ide_name eq "diamond"} {
2418 set command "diamondc"
2419 set before_tcl_script " "
2420 set after_tcl_script " "
2422 }
elseif {$ide_name eq "vitis_classic"} {
2425 set before_tcl_script ""
2426 set after_tcl_script " "
2428 }
elseif {$ide_name eq "ghdl"} {
2430 set before_tcl_script " "
2431 set after_tcl_script " "
2434 Msg Error "IDE: $ide_name not known."
2437 return [list $command $before_tcl_script $after_tcl_script $end_marker]
2443 proc GetIDEFromConf {conf_file} {
2444 set f [open $conf_file "r"]
2447 if {[regexp -all {^\# *(\w*) *(vitis_classic)? *(\d+\.\d+(?:\.\d+)?(?:\.\d+)?)?(_.*)? *$} $line dummy ide vitisflag version patch]} {
2448 if {[
info exists vitisflag] && $vitisflag != ""} {
2449 set ide "${ide}_${vitisflag}"
2452 if {[
info exists version] && $version != ""} {
2458 set ret [list $ide $ver]
2460 Msg CriticalWarning "The first line of hog.conf should be \#<IDE name> <version>, \
2461 where <IDE name>. is quartus, vivado, planahead, libero, diamond or ghdl, \
2462 and <version> the tool version, e.g. \#vivado 2020.2. Will assume vivado."
2463 set ret [list "vivado" "0.0.0"]
2470 proc GetIDEName {} {
2472 return "ISE/PlanAhead"
2490 proc GetIDEVersion {} {
2493 regexp {\d+\.\d+(\.\d+)?} [version -short] ver
2498 regexp {[\.0-9]+} $quartus(version) ver
2501 set ver [get_libero_version]
2503 regexp {\d+\.\d+(\.\d+)?} [sys_install version] ver
2505 regexp {\d+\.\d+(\.\d+)?} [version] ver
2517 proc GetLinkedFile {link_file} {
2518 if {[
file type $link_file] eq "link"} {
2519 if {[
OS] == "windows"} {
2521 lassign [
ExecuteRet realpath $link_file] ret msg
2522 lassign [
ExecuteRet cygpath -m $msg] ret2 msg2
2523 if {$ret == 0 && $ret2 == 0} {
2525 Msg Debug "Found link file $link_file on Windows, the linked file is: $real_file"
2527 Msg CriticalWarning "[
file normalize $link_file] is a soft link. \
2528 Soft link are not supported on Windows and readlink.exe or cygpath.exe did not work: readlink=$ret: $msg, cygpath=$ret2: $msg2."
2529 set real_file $link_file
2533 set linked_file [
file link $link_file]
2534 set real_file [
file normalize [
file dirname $link_file]/$linked_file]
2537 if {![
file exists $real_file]} {
2538 Msg Warning "$link_file is a broken link, because the linked file: $real_file does not exist."
2541 Msg Warning "$link file is not a soft link"
2542 set real_file $link_file
2555 proc GetMaxThreads {proj_dir} {
2557 if {[
file exists $proj_dir/hog.conf]} {
2559 if {[dict exists $properties parameters]} {
2560 set propDict [dict get $properties parameters]
2561 if {[dict exists $propDict MAX_THREADS]} {
2562 set maxThreads [dict get $propDict MAX_THREADS]
2566 Msg Warning "File $proj_dir/hog.conf not found. Max threads will be set to default value 1"
2579 proc GetModifiedFiles {{repo_path "."} {pattern "."}} {
2582 set ret [
Git "ls-files --modified $pattern"]
2591 proc GetOptions {argv parameters} {
2594 set param_list [list]
2595 set option_list [list]
2597 foreach p $parameters {
2598 lappend param_list [
lindex $p 0]
2602 while {$index < [
llength $argv]} {
2603 set arg [
lindex $argv $index]
2604 if {[
string first - $arg] == 0} {
2605 set option [
string trimleft $arg "-"]
2607 lappend option_list $arg
2608 if {[lsearch -regex $param_list "$option\[.arg]?"] >= 0 } {
2609 if {[lsearch -regex $param_list "$option\[.arg]"] >= 0 } {
2610 lappend option_list [
lindex $argv $index]
2615 lappend arg_list $arg
2619 Msg Debug "Argv: $argv"
2620 Msg Debug "Options: $option_list"
2621 Msg Debug "Arguments: $arg_list"
2622 return [list $option_list $arg_list]
2640 proc GetProjectFiles {{project_file ""}} {
2641 set libraries [dict create]
2642 set simlibraries [dict create]
2643 set constraints [dict create]
2644 set properties [dict create]
2645 set consets [dict create]
2646 set srcsets [dict create]
2647 set simsets [dict create]
2650 set all_filesets [get_filesets]
2651 set simulator [get_property target_simulator [current_project]]
2652 set top [get_property "top" [current_fileset]]
2654 dict lappend properties $topfile "top=$top"
2656 foreach fs $all_filesets {
2657 if {$fs == "utils_1"} {
2662 set all_files [get_files -quiet -of_objects [get_filesets $fs]]
2663 set fs_type [get_property FILESET_TYPE [get_filesets $fs]]
2665 if {$fs_type == "BlockSrcs"} {
2667 set dict_fs "sources_1"
2671 foreach f $all_files {
2678 if {[
lindex [get_property IS_GENERATED [
GetFile $f $fs]] 0] != 0} {
2683 if {[get_property FILE_TYPE [
GetFile $f $fs]] == "Configuration Files"} {
2689 if {[get_property CORE_CONTAINER [
GetFile $f $fs]] != ""} {
2690 if {[
file extension $f] == ".xcix"} {
2691 set f [get_property CORE_CONTAINER [
GetFile $f $fs]]
2699 if {[get_property SCOPED_TO_REF [
GetFile $f $fs]] != ""} {
2700 dict lappend properties $f "scoped_to_ref=[get_property SCOPED_TO_REF [
GetFile $f $fs]]"
2705 if {[get_property SCOPED_TO_CELLS [
GetFile $f $fs]] != ""} {
2706 dict lappend properties $f "scoped_to_cells=[get_property SCOPED_TO_CELLS [
GetFile $f $fs]]"
2710 if {[
IsInList "PARENT_COMPOSITE_FILE" [list_property [
GetFile $f $fs]]]} {
2715 if {[
file tail $f] == "nocattrs.dat"} {
2720 if {[
file extension $f] != ".coe"} {
2721 set f [
file normalize $f]
2724 set type [get_property FILE_TYPE [
GetFile $f $fs]]
2726 set lib [get_property -quiet LIBRARY [
GetFile $f $fs]]
2729 Msg Debug "File $f Extension [
file extension $f] Type [
lindex $type 0]"
2731 if {[
string equal [
lindex $type 0] "VHDL"] && [
llength $type] == 1} {
2733 }
elseif {[
string equal [
lindex $type 0] "Block"] && [
string equal [
lindex $type 1] "Designs"]} {
2736 }
elseif {[
string equal $type "SystemVerilog"] && [
file extension $f] != ".sv"} {
2737 set prop "SystemVerilog"
2738 }
elseif {[
string equal [
lindex $type 0] "XDC"] && [
file extension $f] != ".xdc"} {
2740 }
elseif {[
string equal $type "Verilog Header"] && [
file extension $f] != ".vh" && [
file extension $f] != ".svh"} {
2741 set prop "verilog_header"
2742 }
elseif {[
string equal $type "Verilog Template"] && [
file extension $f] == ".v" && [
file extension $f] != ".sv"} {
2743 set prop "verilog_template"
2745 set type [
lindex $type 0]
2749 if {![
string equal $prop ""]} {
2750 dict lappend properties $f $prop
2753 if {[
string equal $fs_type "SimulationSrcs"]} {
2755 if {[
string equal $type "VHDL"]} {
2756 set library "${lib}.sim"
2758 set library "others.sim"
2762 dict lappend simsets $dict_fs $library
2765 dict lappend simlibraries $library $f
2766 }
elseif {[
string equal $type "VHDL"]} {
2769 dict lappend srcsets $dict_fs "${lib}.src"
2771 dict lappend libraries "${lib}.src" $f
2772 }
elseif {[
string first "IP" $type] != -1} {
2775 dict lappend srcsets $dict_fs "ips.src"
2777 dict lappend libraries "ips.src" $f
2778 Msg Debug "Appending $f to ips.src"
2779 }
elseif {[
string equal $fs_type "Constrs"]} {
2782 dict lappend consets $dict_fs "sources.con"
2784 dict lappend constraints "sources.con" $f
2788 dict lappend srcsets $dict_fs "others.src"
2790 dict lappend libraries "others.src" $f
2791 Msg Debug "Appending $f to others.src"
2794 if {[
lindex [get_property -quiet used_in_synthesis [
GetFile $f $fs]] 0] == 0} {
2795 dict lappend properties $f "nosynth"
2797 if {[
lindex [get_property -quiet used_in_implementation [
GetFile $f $fs]] 0] == 0} {
2798 dict lappend properties $f "noimpl"
2800 if {[
lindex [get_property -quiet used_in_simulation [
GetFile $f $fs]] 0] == 0} {
2801 dict lappend properties $f "nosim"
2803 if {[
lindex [get_property -quiet IS_MANAGED [
GetFile $f $fs]] 0] == 0 && [
file extension $f] != ".xcix"} {
2804 dict lappend properties $f "locked"
2810 dict lappend properties "Simulator" [get_property target_simulator [current_project]]
2813 set file [open $project_file r]
2814 set in_file_manager 0
2816 while {[
gets $file line] >= 0} {
2818 if {[regexp {^KEY ActiveRoot \"([^\"]+)\"} $line -> value]} {
2819 set top [
string range $value 0 [
expr {[string first "::" $value] - 1}]]
2823 if {[regexp {^LIST FileManager} $line]} {
2824 set in_file_manager 1
2829 if {$in_file_manager && [regexp {^ENDLIST} $line]} {
2834 if {$in_file_manager && [regexp {^VALUE \"([^\"]+)} $line -> value]} {
2837 lassign [
split $value ,] file_path file_type
2840 set library "others"
2841 while {[
gets $file line] >= 0} {
2842 if {$line == "ENDFILE"} {
2845 regexp {^LIBRARY=\"([^\"]+)} $line -> library
2846 regexp {^PARENT=\"([^\"]+)} $line -> parent_file
2848 Msg Debug "Found file ${file_path} in project.."
2849 if {$parent_file == ""} {
2850 if {$file_type == "hdl"} {
2852 if {[
IsInList "${library}.src" [
DictGet $srcsets "sources_1"]] == 0} {
2853 dict lappend srcsets "sources_1" "${library}.src"
2855 dict lappend libraries "${library}.src" $file_path
2859 if {[
GetModuleName $file_path] == [
string tolower $top] && $top != ""} {
2860 Msg Debug "Found top module $top in $file_path"
2861 dict lappend properties $file_path "top=$top"
2863 }
elseif {$file_type == "tb_hdl"} {
2865 dict lappend simsets "sim_1" "${library}.sim"
2867 dict lappend simlibraries "${library}.sim" $file_path
2868 }
elseif {$file_type == "io_pdc" || $file_type == "sdc"} {
2870 dict lappend consets "constrs_1" "sources.con"
2872 dict lappend constraints "sources.con" $file_path
2879 set fileData [read [open $project_file]]
2881 set project_path [
file dirname $project_file]
2884 regsub {<\?xml.*\?>} $fileData "" fileData
2887 regexp {<Implementation.*?>(.*)</Implementation>} $fileData -> implementationContent
2891 set sourceRegex {<Source name="([^"]*?)" type="([^"]*?)" type_short="([^"]*?)".*?>(.*?)</Source>}
2893 set optionsRegex {<Options(.*?)\/>}
2894 regexp $optionsRegex $implementationContent -> prj_options
2895 foreach option $prj_options {
2896 if {[regexp {^top=\"([^\"]+)\"} $option match result]} {
2901 while {[regexp $sourceRegex $implementationContent match name type type_short optionsContent]} {
2902 Msg Debug "Found file ${name} in project..."
2903 set file_path [
file normalize $project_path/$name]
2905 set optionsRegex {<Options(.*?)\/>}
2906 regexp $optionsRegex $optionsContent -> options
2907 set library "others"
2909 foreach option $options {
2910 if {[
string first "System Verilog" $option]} {
2913 if {[regexp {^lib=\"([^\"]+)\"} $option match1 result]} {
2918 if {[regexp {syn_sim="([^"]*?)"} $match match_sim simonly]} {
2923 if {$type_short == "VHDL" || $type_short == "Verilog" || $type_short == "IPX"} {
2924 if {$ext == ".src"} {
2925 if {[
IsInList "${library}${ext}" [
DictGet $srcsets "sources_1"]] == 0} {
2926 dict lappend srcsets "sources_1" "${library}${ext}"
2928 dict lappend libraries "${library}${ext}" $file_path
2929 }
elseif {$ext == ".sim"} {
2931 dict lappend simsets "sim_1" "${library}.sim"
2933 dict lappend simlibraries "${library}.sim" $file_path
2939 Msg Debug "Found top module $top in $file_path"
2940 dict lappend properties $file_path "top=$top"
2942 }
elseif {$type_short == "SDC"} {
2944 dict lappend consets "constrs_1" "sources.con"
2946 dict lappend constraints "sources.con" $file_path
2950 regsub -- $match $implementationContent "" implementationContent
2953 return [list $libraries $properties $simlibraries $constraints $srcsets $simsets $consets]
2960 proc GetProjectFlavour {proj_name} {
2962 set flavour [
string map {. ""} [
file extension $proj_name]]
2963 if {$flavour != ""} {
2964 if {[
string is integer $flavour]} {
2965 Msg Info "Project $proj_name has flavour = $flavour, the generic variable FLAVOUR will be set to $flavour"
2967 Msg Warning "Project name has a unexpected non numeric extension, flavour will be set to -1"
2984 proc GetProjectVersion {proj_dir repo_path {ext_path ""} {sim 0}} {
2985 if {![
file exists $proj_dir]} {
2986 Msg CriticalWarning "$proj_dir not found"
2996 Msg Warning "Repository is not clean"
3004 Msg Debug "Project version $v_proj, latest tag $v_last"
3006 Msg Info "The specified project was modified since official version."
3013 Msg Info "The specified project was modified in the latest official version $ret"
3014 }
elseif {$comp == -1} {
3015 Msg Info "The specified project was modified in a past official version $ret"
3031 proc GetRepoVersions {proj_dir repo_path {ext_path ""} {sim 0}} {
3032 if {[
catch {
package require cmdline} ERROR]} {
3033 puts "$ERROR\n If you are running this script on tclsh, you can fix this by installing 'tcllib'"
3048 lappend SHAs [
GetSHA {Hog}]
3052 if {[
Git {status --untracked-files=no --porcelain}] eq ""} {
3053 Msg Info "Hog submodule [
pwd] clean."
3054 lassign [
GetVer ./] hog_ver hog_hash
3056 Msg CriticalWarning "Hog submodule [
pwd] not clean, commit hash will be set to 0."
3057 set hog_hash "0000000"
3058 set hog_ver "00000000"
3063 if {[
Git {status --untracked-files=no --porcelain}] eq ""} {
3064 Msg Info "Git working directory [
pwd] clean."
3067 Msg CriticalWarning "Git working directory [
pwd] not clean, commit hash, and version will be set to 0."
3072 lassign [
GetVer [
join $conf_files]] top_ver top_hash
3073 lappend SHAs $top_hash
3074 lappend versions $top_ver
3081 lassign [
GetHogFiles -list_files "*.src" -sha_mode "./list/" $repo_path] src_files dummy
3082 dict for {f files} $src_files {
3083 # library names have a .src extension in values returned by GetHogFiles
3084 set name [file rootname [file tail $f]]
3085 if {[file ext $f] == ".oth"} {
3088 lassign [GetVer $files] ver hash
3089 # Msg Info "Found source list file $f, version: $ver commit SHA: $hash"
3091 lappend versions $ver
3093 lappend hashes $hash
3100 lassign [
GetHogFiles -list_files "*.con" -sha_mode "./list/" $repo_path] cons_files dummy
3101 dict for {f files} $cons_files {
3102 #library names have a .con extension in values returned by GetHogFiles
3103 set name [file rootname [file tail $f]]
3104 lassign [GetVer $files] ver hash
3105 #Msg Info "Found constraint list file $f, version: $ver commit SHA: $hash"
3107 Msg CriticalWarning "Constraints file $f not found in Git."
3109 lappend cons_hashes $hash
3111 lappend versions $ver
3118 lassign [
GetHogFiles -list_files "*.sim" -sha_mode "./list/" $repo_path] sim_files dummy
3119 dict for {f files} $sim_files {
3120 #library names have a .sim extension in values returned by GetHogFiles
3121 set name [file rootname [file tail $f]]
3122 lassign [GetVer $files] ver hash
3123 #Msg Info "Found simulation list file $f, version: $ver commit SHA: $hash"
3124 lappend sim_hashes $hash
3126 lappend versions $ver
3132 if {"{}" eq $cons_hashes} {
3134 Msg CriticalWarning "No hashes found for constraints files (not in git)"
3137 set cons_hash [
string tolower [
Git "log --format=%h -1 $cons_hashes"]]
3144 set ext_files [glob -nocomplain "./list/*.ext"]
3147 foreach f $ext_files {
3148 set name [
file rootname [
file tail $f]]
3151 lappend ext_names $name
3152 lappend ext_hashes $hash
3155 lappend versions $ext_ver
3158 set file_data [read $fp]
3160 set data [
split $file_data "\n"]
3162 foreach line $data {
3163 if {![regexp {^ *$} $line] & ![regexp {^ *\#} $line]} {
3165 set file_and_prop [regexp -all -inline {\S+} $line]
3166 set hdlfile [
lindex $file_and_prop 0]
3167 set hdlfile $ext_path/$hdlfile
3168 if {[
file exists $hdlfile]} {
3169 set hash [
lindex $file_and_prop 1]
3170 set current_hash [
Md5Sum $hdlfile]
3171 if {[
string first $hash $current_hash] == -1} {
3172 Msg CriticalWarning "File $hdlfile has a wrong hash. Current checksum: $current_hash, expected: $hash"
3180 if {[
llength [glob -nocomplain ./list/*.ipb]] > 0} {
3182 lassign [
GetHogFiles -list_files "*.ipb" -sha_mode "./list/" $repo_path] xml_files dummy
3183 lassign [
GetVer [dict get $xml_files "xml.ipb"]] xml_ver xml_hash
3184 lappend SHAs $xml_hash
3185 lappend versions $xml_ver
3189 Msg Info "This project does not use IPbus XMLs"
3194 set user_ip_repos ""
3195 set user_ip_repo_hashes ""
3196 set user_ip_repo_vers ""
3198 if {[
file exists [
lindex $conf_files 0]]} {
3199 set PROPERTIES [
ReadConf [
lindex $conf_files 0]]
3200 if {[dict exists $PROPERTIES main]} {
3201 set main [dict get $PROPERTIES main]
3202 dict for {p v} $main {
3203 if {[string tolower $p] == "ip_repo_paths"} {
3205 if {[file isdirectory "$repo_path/$repo"]} {
3206 set repo_file_list [glob -nocomplain "$repo_path/$repo/*"]
3207 if {[llength $repo_file_list] == 0} {
3208 Msg Warning "IP_REPO_PATHS property set to $repo in hog.conf but directory is empty."
3210 lappend user_ip_repos "$repo_path/$repo"
3219 foreach repo $user_ip_repos {
3220 if {[
file isdirectory $repo]} {
3221 set repo_file_list [glob -nocomplain "$repo/*"]
3222 if {[
llength $repo_file_list] != 0} {
3223 lassign [
GetVer $repo] ver sha
3224 lappend user_ip_repo_hashes $sha
3225 lappend user_ip_repo_vers $ver
3226 lappend versions $ver
3228 Msg Warning "IP_REPO_PATHS property set to $repo in hog.conf but directory is empty."
3231 Msg Warning "IP_REPO_PATHS property set to $repo in hog.conf but directory does not exist."
3240 while {$found == 0} {
3241 set global_commit [
Git "log --format=%h -1 --abbrev=7 $SHAs"]
3246 if {$common_child == 0} {
3247 Msg CriticalWarning "The commit $sha is not an ancestor of the global commit $global_commit, which is OK. \
3248 But $sha and $global_commit do not have any common child, which is NOT OK. \
3249 This is probably do to a REBASE that is forbidden in Hog methodology as it changes git history. \
3250 Hog cannot guarantee the accuracy of the SHAs. \
3251 A way to fix this is to make a commit that touches all the projects in the repositories (e.g. change the Hog version), \
3252 but please do not rebase in the official branches in the future."
3254 Msg Info "The commit $sha is not an ancestor of the global commit $global_commit, adding the first common child $common_child instead..."
3255 lappend SHAs $common_child
3265 set global_commit "0000000"
3266 set global_version "00000000"
3271 set top_hash [
format %+07s $top_hash]
3272 set cons_hash [
format %+07s $cons_hash]
3273 return [list $global_commit $global_version \
3274 $hog_hash $hog_ver $top_hash $top_ver \
3275 $libs $hashes $vers $cons_ver $cons_hash \
3276 $ext_names $ext_hashes $xml_hash $xml_ver \
3277 $user_ip_repos $user_ip_repo_hashes $user_ip_repo_vers]
3286 proc GetSHA {{path ""}} {
3288 lassign [
GitRet {log --format=%h --abbrev=7 -1}] status result
3290 return [
string tolower $result]
3292 Msg Error "Something went wrong while finding the latest SHA. Does the repository have a commit?"
3298 set repo_path [
lindex [
Git {rev-parse --show-toplevel}] 0]
3302 set file_in_module 0
3303 if {[
file exists $repo_path/.gitmodules]} {
3304 lassign [
GitRet "config --file $repo_path/.gitmodules --get-regexp path"] status result
3306 set submodules [
split $result "\n"]
3309 Msg Warning "Something went wrong while trying to find submodules: $result"
3312 foreach mod $submodules {
3313 set module [
lindex $mod 1]
3314 if {[
string first "$repo_path/$module" $f] == 0} {
3316 set file_in_module 1
3317 lappend paths "$repo_path/$module"
3322 if {$file_in_module == 0} {
3328 lassign [
GitRet {log --format=%h --abbrev=7 -1} $paths] status result
3330 return [
string tolower $result]
3332 Msg Error "Something went wrong while finding the latest SHA. Does the repository have a commit?"
3335 return [
string tolower $result]
3339 proc GetSimulators {} {
3340 set SIMULATORS [list "modelsim" "questa" "riviera" "activehdl" "ies" "vcs"]
3345 proc GetTopFile {} {
3347 set compile_order_prop [get_property source_mgmt_mode [current_project]]
3348 if {$compile_order_prop ne "All"} {
3349 Msg CriticalWarning "Compile order is not set to automatic, setting it now..."
3350 set_property source_mgmt_mode All [current_project]
3351 update_compile_order -fileset sources_1
3353 return [
lindex [get_files -quiet -compile_order sources -used_in synthesis -filter {FILE_TYPE =~ "VHDL*" || FILE_TYPE =~ "*Verilog*" }] end]
3354 }
elseif {[
IsISE]} {
3355 debug::design_graph_mgr -create [current_fileset]
3356 debug::design_graph -add_fileset [current_fileset]
3357 debug::design_graph -update_all
3358 return [
lindex [debug::design_graph -get_compile_order] end]
3360 Msg Error "GetTopFile not yet implemented for this IDE"
3365 proc GetTopModule {} {
3367 return [get_property top [current_fileset]]
3369 Msg Error "GetTopModule not yet implemented for this IDE"
3379 proc GetVer {path {force_develop 0}} {
3383 Msg CriticalWarning "Empty SHA found for ${path}. Commit to Git to resolve this warning."
3386 set p [
lindex $path 0]
3387 if {[
file isdirectory $p]} {
3390 cd [
file dirname $p]
3392 set repo_path [
Git {rev-parse --show-toplevel}]
3395 return [list [
GetVerFromSHA $SHA $repo_path $force_develop] $SHA]
3406 proc GetVerFromSHA {SHA repo_path {force_develop 0}} {
3408 Msg CriticalWarning "Empty SHA found"
3411 lassign [
GitRet "tag --sort=creatordate --contain $SHA -l v*.*.* -l b*v*.*.*"] status result
3414 if {[regexp {^ *$} $result]} {
3416 lassign [
GitRet "log --oneline --pretty=\"%d\""] status2 tag_list
3419 set pattern {tag: v\d+\.\d+\.\d+}
3420 set real_tag_list {}
3421 foreach x $tag_list {
3422 set x_untrimmed [regexp -all -inline $pattern $x]
3423 regsub "tag: " $x_untrimmed "" x_trimmed
3424 set tt [
lindex $x_trimmed 0]
3425 if {![
string equal $tt ""]} {
3426 lappend real_tag_list $tt
3430 Msg Debug "Cleaned up list: $real_tag_list."
3432 set sorted_tags [lsort -decreasing -command CompareVersions $real_tag_list]
3434 Msg Debug "Sorted Tag list: $sorted_tags"
3436 set tag [
lindex $sorted_tags 0]
3439 set pattern {v\d+\.\d+\.\d+}
3440 if {![regexp $pattern $tag]} {
3441 Msg CriticalWarning "No Hog version tags found in this repository."
3446 set repo_conf $repo_path/Top/repo.conf
3450 set hotfix_prefix "hotfix/"
3451 set minor_prefix "minor_version/"
3452 set major_prefix "major_version/"
3454 set enable_develop_branch $force_develop
3456 set branch_name [
Git {rev-parse --abbrev-ref HEAD}]
3458 if {[
file exists $repo_conf]} {
3459 set PROPERTIES [
ReadConf $repo_conf]
3461 if {[dict exists $PROPERTIES main]} {
3462 set mainDict [dict get $PROPERTIES main]
3465 if {[dict exists $mainDict ENABLE_DEVELOP_BRANCH]} {
3466 set enable_develop_branch [dict get $mainDict ENABLE_DEVELOP_BRANCH]
3472 if {[dict exists $PROPERTIES prefixes]} {
3473 set prefixDict [dict get $PROPERTIES prefixes]
3475 if {[dict exists $prefixDict HOTFIX]} {
3476 set hotfix_prefix [dict get $prefixDict HOTFIX]
3478 if {[dict exists $prefixDict MINOR_VERSION]} {
3479 set minor_prefix [dict get $prefixDict MINOR_VERSION]
3481 if {[dict exists $prefixDict MAJOR_VERSION]} {
3482 set major_prefix [dict get $prefixDict MAJOR_VERSION]
3488 if {$enable_develop_branch == 1} {
3489 if {[
string match "$hotfix_prefix*" $branch_name]} {
3494 if {[
string match "$major_prefix*" $branch_name]} {
3496 set version_level major
3497 }
elseif {[
string match "$minor_prefix*" $branch_name] || ($enable_develop_branch == 1 && $is_hotfix == 0)} {
3499 set version_level minor
3502 set version_level patch
3506 Msg CriticalWarning "Tag $tag does not contain a Hog compatible version in this repository."
3509 }
elseif {$mr == 0} {
3510 switch $version_level {
3525 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."
3531 set vers [
split $result "\n"]
3532 set ver [
lindex $vers 0]
3534 if {[regexp {^v.*$} $v]} {
3542 Msg CriticalWarning "Error while trying to find tag for $SHA"
3550 set M [
format %02X $M]
3551 set m [
format %02X $m]
3552 set c [
format %04X $c]
3553 }
elseif {$M > -1} {
3555 set M [
format %02X $M]
3556 set m [
format %02X $m]
3557 set c [
format %04X $c]
3559 Msg Warning "Tag does not contain a properly formatted version: $ver"
3560 set M [
format %02X 0]
3561 set m [
format %02X 0]
3562 set c [
format %04X 0]
3575 proc Git {command {files ""}} {
3576 lassign [
GitRet $command $files] ret result
3578 Msg Error "Code $ret returned by git running: $command -- $files"
3589 proc GetModuleName {filename} {
3591 if {![
file exists $filename]} {
3592 Msg CriticalWarning "Error: File $filename does not exist."
3597 set fileId [open $filename r]
3600 set file_content [read $fileId]
3606 if {[
file extension $filename] == ".vhd" || [
file extension $filename] == ".vhdl"} {
3608 set file_content [
string tolower $file_content]
3610 set pattern {(?m)^\s*entity\s+(\S+)\s+is}
3611 }
elseif {[
file extension $filename] == ".v" || [
file extension $filename] == ".sv"} {
3613 set pattern {\n\s*module\s*(\w+)(\s*|\(|\n)}
3615 Msg Debug "File is neither VHDL nor Verilog... Returning empty string..."
3620 if {[regexp $pattern $file_content match module_name]} {
3623 Msg Debug "No module was found in $filename. Returning an empty string..."
3631 proc GetVerilogGenerics {file} {
3632 set fp [open $file r]
3638 foreach line [
split $data "\n"] {
3639 regsub "^\\s*\/\/.*" $line "" line
3640 regsub "(.*)\/\/.*" $line {\1} line
3641 if {![
string equal $line ""]} {
3642 append lines $line " "
3647 regsub -all {/\*.*\*/} $lines "" lines
3650 set punctuation [list]
3651 foreach char [list "(" ")" ";" "," " " "!" "<=" ":=" "=" "\[" "\]"] {
3652 lappend punctuation $char "\000$char\000"
3656 set tokens [
split [
string map $punctuation $lines] \000]
3658 set parameters [dict create]
3667 foreach token $tokens {
3668 set token [
string trim $token]
3669 if {![
string equal "" $token]} {
3670 if {[
string equal [
string tolower $token] "parameter"]} {
3671 set state $PARAM_NAME
3672 }
elseif {[
string equal $token ")"] || [
string equal $token ";"]} {
3674 }
elseif {$state == $PARAM_WIDTH} {
3675 if {[
string equal $token "\]"]} {
3676 set state $PARAM_NAME
3678 }
elseif {$state == $PARAM_VALUE} {
3679 if {[
string equal $token ","]} {
3680 set state $PARAM_NAME
3681 }
elseif {[
string equal $token ";"]} {
3686 }
elseif {$state == $PARAM_NAME} {
3687 if {[
string equal $token "="]} {
3688 set state $PARAM_VALUE
3689 }
elseif {[
string equal $token "\["]} {
3690 set state $PARAM_WIDTH
3691 }
elseif {[
string equal $token ","]} {
3692 set state $PARAM_NAME
3693 }
elseif {[
string equal $token ";"]} {
3695 }
elseif {[
string equal $token ")"]} {
3698 dict set parameters $token "integer"
3711 proc GetVhdlGenerics {file {entity ""}} {
3712 set fp [open $file r]
3718 foreach line [
split $data "\n"] {
3719 regsub "^\\s*--.*" $line "" line
3720 regsub "(.*)--.*" $line {\1} line
3721 if {![
string equal $line ""]} {
3722 append lines $line " "
3727 set generic_block ""
3728 set generics [dict create]
3730 if {1 == [
string equal $entity ""]} {
3731 regexp {(?i).*entity\s+([^\s]+)\s+is} $lines _ entity
3734 set generics_regexp "(?i).*entity\\s+$entity\\s+is\\s+generic\\s*\\((.*)\\)\\s*;\\s*port.*end.*$entity"
3736 if {[regexp $generics_regexp $lines _ generic_block]} {
3738 foreach line [
split $generic_block ";"] {
3740 regexp {(.*):\s*([A-Za-z0-9_]+).*} $line _ generic type
3743 set splits [
split $generic ","]
3744 foreach split $splits {
3745 dict set generics [
string trim $split] [
string trim $type]
3753 proc GHDL {command logfile} {
3754 set ret [
catch {
exec -ignorestderr ghdl {*}$command >>& $logfile} result options]
3759 return [list $ret $result]
3771 proc GitRet {command {files ""}} {
3774 set ret [
catch {
exec -ignorestderr git {*}$command} result]
3776 set ret [
catch {
exec -ignorestderr git {*}$command -- {*}$files} result]
3778 return [list $ret $result]
3786 proc GitVersion {target_version} {
3787 set ver [
split $target_version "."]
3788 set v [
Git --version]
3790 set current_ver [
split [
lindex $v 2] "."]
3791 set target [
expr {[lindex $ver 0] * 100000 + [lindex $ver 1] * 100 + [lindex $ver 2]}]
3792 set current [
expr {[lindex $current_ver 0] * 100000 + [lindex $current_ver 1] * 100 + [lindex $current_ver 2]}]
3793 return [
expr {$target <= $current}]
3807 proc HandleIP {what_to_do xci_file ip_path repo_path {gen_dir "."} {force 0}} {
3808 if {!($what_to_do eq "push") && !($what_to_do eq "pull")} {
3809 Msg Error "You must specify push or pull as first argument."
3812 if {[
catch {
package require tar} TARPACKAGE]} {
3813 Msg CriticalWarning "Cannot find package tar. You can fix this by installing package \"tcllib\""
3822 if {[
string first "/eos/" $ip_path] == 0} {
3830 lassign [
eos "ls $ip_path"] ret result
3832 Msg CriticalWarning "Could not run ls for for EOS path: $ip_path (error: $result). \
3833 Either the drectory does not exist or there are (temporary) problem with EOS."
3837 Msg Info "IP remote directory path, on EOS, is set to: $ip_path"
3843 if {!([
file exists $xci_file])} {
3844 Msg CriticalWarning "Could not find $xci_file."
3850 set xci_path [
file dirname $xci_file]
3851 set xci_name [
file tail $xci_file]
3852 set xci_ip_name [
file rootname [
file tail $xci_file]]
3853 set xci_dir_name [
file tail $xci_path]
3854 set gen_path $gen_dir
3856 set hash [
Md5Sum $xci_file]
3857 set file_name $xci_name\_$hash
3859 Msg Info "Preparing to $what_to_do IP: $xci_name..."
3861 if {$what_to_do eq "push"} {
3865 lassign [
eos "ls $ip_path/$file_name.tar"] ret result
3870 Msg Info "IP already in the EOS repository, will not copy..."
3872 Msg Info "IP already in the EOS repository, will forcefully replace..."
3878 if {[
file exists "$ip_path/$file_name.tar"]} {
3880 Msg Info "IP already in the local repository, will not copy..."
3882 Msg Info "IP already in the local repository, will forcefully replace..."
3891 if {$will_copy == 1} {
3893 Msg Info "Looking for generated files in $gen_path..."
3894 set ip_gen_files [glob -nocomplain $gen_path/*]
3898 if {[
llength $ip_gen_files] > 0} {
3899 Msg Info "Found some IP synthesised files matching $xci_ip_name"
3900 if {$will_remove == 1} {
3901 Msg Info "Removing old synthesised directory $ip_path/$file_name.tar..."
3903 eos "rm -rf $ip_path/$file_name.tar" 5
3905 file delete -force "$ip_path/$file_name.tar"
3909 Msg Info "Creating local archive with IP generated files..."
3911 foreach f $ip_gen_files {
3912 if {$first_file == 0} {
3913 ::tar::create $file_name.tar "[
Relative [
file normalize $repo_path] $f]"
3916 ::tar::add $file_name.tar "[
Relative [
file normalize $repo_path] $f]"
3920 Msg Info "Copying IP generated files for $xci_name..."
3922 lassign [
ExecuteRet xrdcp -f -s $file_name.tar $::env(EOS_MGM_URL)//$ip_path/] ret msg
3924 Msg CriticalWarning "Something went wrong when copying the IP files to EOS. Error message: $msg"
3927 Copy "$file_name.tar" "$ip_path/"
3929 Msg Info "Removing local archive"
3930 file delete $file_name.tar
3932 Msg Warning "Could not find synthesized files matching $gen_path/$file_name*"
3935 }
elseif {$what_to_do eq "pull"} {
3937 lassign [
eos "ls $ip_path/$file_name.tar"] ret result
3939 Msg Info "Nothing for $xci_name was found in the EOS repository, cannot pull."
3943 set remote_tar "$::env(EOS_MGM_URL)//$ip_path/$file_name.tar"
3944 Msg Info "IP $xci_name found in the repository $remote_tar, copying it locally to $repo_path..."
3946 lassign [
ExecuteRet xrdcp -f -r -s $remote_tar $repo_path] ret msg
3948 Msg CriticalWarning "Something went wrong when copying the IP files to EOS. Error message: $msg"
3952 if {[
file exists "$ip_path/$file_name.tar"]} {
3953 Msg Info "IP $xci_name found in local repository $ip_path/$file_name.tar, copying it locally to $repo_path..."
3954 Copy $ip_path/$file_name.tar $repo_path
3956 Msg Info "Nothing for $xci_name was found in the local IP repository, cannot pull."
3962 if {[
file exists $file_name.tar]} {
3963 remove_files $xci_file
3964 Msg Info "Extracting IP files from archive to $repo_path..."
3965 ::tar::untar $file_name.tar -dir $repo_path -noperms
3966 Msg Info "Removing local archive"
3967 file delete $file_name.tar
3968 add_files -norecurse -fileset sources_1 $xci_file
3981 proc HexVersionToString {version} {
3982 scan [
string range $version 0 1] %x M
3983 scan [
string range $version 2 3] %x m
3984 scan [
string range $version 4 7] %x c
3989 proc ImportTclLib {} {
3991 if {[
info exists env(HOG_TCLLIB_PATH)]} {
3992 lappend auto_path $env(HOG_TCLLIB_PATH)
3995 puts "ERROR: To run Hog with Microsemi Libero SoC or Lattice Diamond, you need to define the HOG_TCLLIB_PATH variable."
4010 proc InitLauncher {script tcl_path parameters commands argv {custom_commands ""}} {
4011 set repo_path [
file normalize "$tcl_path/../.."]
4013 set bin_path [
file normalize "$tcl_path/../../bin"]
4014 set top_path [
file normalize "$tcl_path/../../Top"]
4016 set cmd_lines [
split $commands "\n"]
4018 set command_options [dict create]
4019 set directive_descriptions [dict create]
4020 set directive_names [dict create]
4021 set common_directive_names [dict create]
4022 set custom_command ""
4023 set custom_command_options ""
4025 foreach l $cmd_lines {
4027 if {[regexp {\\(.*) \{\#} $l minc d]} {
4028 lappend directives_with_projects $d
4032 if {[regexp {\\(.*) \{} $l minc regular_expression]} {
4033 lappend directive_regex $regular_expression
4037 if {[regexp {\#\s*NAME(\*)?:\s*(.*)\s*} $l minc star name]} {
4038 dict set directive_names $name $regular_expression
4040 dict set common_directive_names $name $regular_expression
4043 set directive_names [
DictSort $directive_names]
4044 set common_directive_names [
DictSort $common_directive_names]
4047 if {[regexp {\#\s*DESCRIPTION:\s*(.*)\s*} $l minc x]} {
4048 dict set directive_descriptions $regular_expression $x
4052 if {[regexp {\#\s*OPTIONS:\s*(.*)\s*} $l minc x]} {
4053 dict set command_options $regular_expression [
split [regsub -all {[ \t\n]+} $x {}] ","]
4057 set short_usage "usage: ./Hog/Do \[OPTIONS\] <directive> \[project\]\n\nMost common directives (case insensitive):"
4059 dict for {key value} $common_directive_names {
4060 set short_usage "$short_usage\n - $key: [dict get $directive_descriptions $value]"
4063 if {[
string length $custom_commands] > 0} {
4064 Msg Debug "Found custom commands to add to short short_usage."
4065 set short_usage "$short_usage\n\nCustom commands:"
4066 dict for {key command} $custom_commands {
4067 Msg Debug "Adding $key : [dict get $command DESCRIPTION]"
4068 set short_usage "$short_usage\n - $key: [dict get $command DESCRIPTION]"
4074 set short_usage "$short_usage\n\n\
4075 To see all the available directives, run:\n./Hog/Do HELP\n\n\
4076 To list available options for the chosen directive run:\n\
4077 ./Hog/Do <directive> HELP\n
4080 set usage "usage: ./Hog/Do \[OPTIONS\] <directive> \[project\]\n\nDirectives (case insensitive):"
4082 dict for {key value} $directive_names {
4083 set usage "$usage\n - $key: [dict get $directive_descriptions $value]"
4087 if {[
string length $custom_commands] > 0} {
4088 Msg Debug "Found custom commands to add to short usage."
4089 set usage "$usage\n\nCustom commands:"
4090 dict for {key command} $custom_commands {
4091 Msg Debug "Adding $key : [dict get $command DESCRIPTION]"
4092 set usage "$usage\n - $key: [dict get $command DESCRIPTION]"
4097 set usage "$usage\n\nTo list available options for the chosen directive run:\n./Hog/Do <directive> HELP"
4106 Msg Debug "HogEnv.conf found"
4114 if {[
catch {
package require cmdline} ERROR]} {
4115 Msg Debug "The cmdline Tcl package was not found, sourcing it from Hog..."
4116 source $tcl_path/utils/cmdline.tcl
4119 set argv [regsub -all {(?i) HELP\y} $argv " -help"]
4124 set custom_parameters [list]
4125 dict for {key command} $custom_commands {
4126 set custom_parameters [concat $custom_parameters [dict get $command CUSTOM_OPTIONS]]
4129 lassign [
GetOptions $argv [
concat $custom_parameters $parameters]] option_list arg_list
4131 if {[
IsInList "-all" $option_list]} {
4140 set directive [
string toupper [
lindex $arg_list 0]]
4143 set argument_is_no_project 1
4145 set NO_DIRECTIVE_FOUND 0
4146 switch -regexp -- $directive "$commands"
4147 if {$NO_DIRECTIVE_FOUND == 1} {
4148 if {[
string length $custom_commands] > 0 && [dict exists $custom_commands $directive]} {
4149 set custom_command $directive
4150 set custom_command_hog_parameters [dict get $custom_commands $directive OPTIONS]
4151 set custom_command_options [dict get $custom_commands $directive CUSTOM_OPTIONS]
4152 set custom_command_options [
concat $custom_command_hog_parameters $custom_command_options]
4154 Msg Status "ERROR: Unknown directive $directive.\n\n"
4160 if {[
IsInList $directive $directives_with_projects 1]} {
4161 set argument_is_no_project 0
4165 if {$directive != ""} {
4166 if {[
IsInList $directive $directives_with_projects 1]} {
4167 puts "usage: ./Hog/Do \[OPTIONS\] $directive <project>\n"
4168 }
elseif {[regexp "^COMPSIM(LIB)?$" $directive]} {
4169 puts "usage: ./Hog/Do \[OPTIONS\] $directive <simulator>\n"
4171 puts "usage: ./Hog/Do \[OPTIONS\] $directive \n"
4174 dict for {dir desc} $directive_descriptions {
4175 if {[regexp $dir $directive]} {
4183 if {$custom_command ne ""} {
4184 if {[
llength $custom_command_options] > 0} {
4185 puts "Available options:"
4187 foreach custom_option $custom_command_options {
4188 set n [
llength $custom_option]
4190 lassign $custom_option opt help
4193 }
elseif {$n == 3} {
4194 lassign $custom_option opt def help
4195 puts " -$opt <argument>"
4197 puts " $help (default: $def)"
4202 Msg Warning "Custom option spec has invalid arity (expected 2 or 3): $custom_option"
4207 dict for {dir opts} $command_options {
4208 if {[regexp $dir $directive]} {
4209 puts "Available options:"
4211 foreach par $parameters {
4212 if {$opt == [lindex $par 0]} {
4213 if {[regexp {\.arg$} $opt]} {
4214 set opt_name [regsub {\.arg$} $opt ""]
4215 puts " -$opt_name <argument>"
4219 puts " [lindex $par [llength $par]-1]"
4233 if {$custom_command ne ""} {
4234 set parameters [
concat $parameters $custom_command_options]
4237 if {[
catch {
array set options [
cmdline::getoptions option_list $parameters $usage]} err]} {
4238 Msg Status "\nERROR: Syntax error, probably unknown option.\n\n USAGE: $err"
4242 if {[
llength $arg_list] <= $min_n_of_args || [
llength $arg_list] > $max_n_of_args} {
4243 Msg Status "\nERROR: Wrong number of arguments: [
llength $argv]"
4248 set project [
lindex $arg_list 1]
4250 if {$argument_is_no_project == 0} {
4252 regsub "^(\./)?Top/" $project "" project
4254 regsub "/? *\$" $project "" project
4260 Msg Debug "Option list:"
4261 foreach {key value} [
array get options] {
4262 Msg Debug "$key => $value"
4269 if {$proj_conf != 0} {
4272 lassign [
GetIDECommand $proj_conf] cmd before_tcl_script after_tcl_script end_marker
4273 Msg Info "Project $project uses $cmd IDE"
4276 set command "$cmd $before_tcl_script$script$after_tcl_script$argv$end_marker"
4278 if {$custom_command ne ""} {
4279 if { [dict exists $custom_commands $directive IDE] } {
4280 lassign [
GetIDECommand "" [dict get $custom_commands $directive IDE]] cmd before_tcl_script after_tcl_script end_marker
4281 Msg Info "Custom command: $custom_command uses $cmd IDE"
4282 set command "$cmd $before_tcl_script$script$after_tcl_script$argv$end_marker"
4284 set command "custom_tcl"
4286 }
elseif {$argument_is_no_project == 1} {
4288 Msg Debug "$project will be used as first argument"
4289 }
elseif {$project != ""} {
4292 }
elseif {$min_n_of_args < 0} {
4305 set project_group [
file dirname $project]
4306 set project_name $project
4307 set project [
file tail $project]
4308 Msg Debug "InitLauncher: project_group=$project_group, project_name=$project_name, project=$project"
4310 return [list $directive $project $project_name $project_group $repo_path $old_path $bin_path $top_path $usage $short_usage $command $cmd [
array get options]]
4317 proc IsCommitAncestor {ancestor commit} {
4318 lassign [
GitRet "merge-base --is-ancestor $ancestor $commit"] status result
4327 return [
expr {[info commands sys_install] != ""}]
4332 return [
expr {[info commands get_libero_version] != ""}]
4341 proc IsInList {element list {regex 0} {nocase 0}} {
4345 if {[regexp -nocase $x $element]} {
4349 if {[regexp $x $element]} {
4353 }
elseif {$regex == 0} {
4355 if {[
string tolower $x] eq [
string tolower $element]} {
4359 if {$x eq $element} {
4372 return [
expr {[string first PlanAhead [version]] == 0}]
4380 if {[
catch {
package require ::quartus::flow} result]} {
4393 proc IsRelativePath {path} {
4394 if {[
string index $path 0] == "/" || [
string index $path 0] == "~"} {
4402 proc IsSynplify {} {
4403 return [
expr {[info commands program_version] != ""}]
4408 return [
expr {![IsQuartus] && ![IsXilinx] && ![IsVitisClassic] && ![IsLibero] && ![IsSynplify] && ![IsDiamond]}]
4416 proc IsVerilog {file} {
4417 if {[
file extension $file] == ".v" || [
file extension $file] == ".sv"} {
4429 proc IsVersal {part} {
4430 if {[get_property ARCHITECTURE [get_parts $part]] eq "versal"} {
4440 return [
expr {[string first Vivado [version]] == 0}]
4448 if {[
info commands version] != ""} {
4449 set current_version [version]
4450 if {[
string first PlanAhead $current_version] == 0 || [
string first Vivado $current_version] == 0} {
4452 }
elseif {[
string first xsct $current_version] == 0} {
4455 Msg Warning "This IDE has the version command but it is not PlanAhead or Vivado: $current_version"
4464 proc IsVitisClassic {} {
4465 return [
expr {[info commands platform] != ""}]
4473 proc IsZynq {part} {
4474 if {[regexp {^(xc7z|xczu).*} $part]} {
4481 proc ImportGHDL {project_name repo_path simset_name simset_dict {ext_path ""}} {
4482 set list_path "$repo_path/Top/$project_name/list"
4483 lassign [
GetHogFiles -list_files {.src,.ext,.sim} -ext_path $ext_path $list_path $repo_path] src_files properties filesets
4488 set properties [
DictGet $simset_dict "properties"]
4489 set options [
DictGet $properties "options"]
4492 set workdir Projects/$project_name/ghdl
4493 file delete -force $workdir
4495 set import_log "$workdir/ghdl-import-${simset_name}.log"
4496 dict for {lib sources} $src_files {
4497 set libname [file rootname $lib]
4498 foreach f $sources {
4499 if {[file extension $f] != ".vhd" && [file extension $f] != ".vhdl"} {
4500 Msg Info "File $f is not a VHDL file, copying it in workfolder..."
4501 file copy -force $f $workdir
4503 set file_path [Relative $repo_path $f]
4504 set import_log_file [open $import_log "a"]
4505 puts "ghdl -i --work=$libname --workdir=$workdir -fsynopsys --ieee=standard $options $file_path"
4506 puts $import_log_file "ghdl -i --work=$libname --workdir=$workdir -fsynopsys --ieee=standard $options $file_path"
4507 close $import_log_file
4508 lassign [GHDL "-i --work=$libname --workdir=$workdir -fsynopsys --ieee=standard $options $file_path" $import_log] ret result
4510 Msg CriticalWarning "GHDL import failed for file $f: $result"
4519 proc LaunchGHDL {project_name repo_path simset_name simset_dict {ext_path ""}} {
4522 set sim_props [
DictGet $simset_dict "properties"]
4523 set options [
DictGet $sim_props "options"]
4524 set runopts [
DictGet $sim_props "run_options"]
4526 dict for {prop_name prop_val} $sim_props {
4527 set prop_name [string toupper $prop_name]
4528 if {$prop_name == "TOP"} {
4529 set top_sim $prop_val
4532 set workdir $repo_path/Projects/$project_name/ghdl
4533 set make_log "$workdir/ghdl-make-${simset_name}.log"
4534 set run_log "$workdir/ghdl-run-${simset_name}.log"
4537 set make_log_file [open $make_log "w"]
4539 puts "ghdl -m --work=$simset_name -fsynopsys --ieee=standard $options $top_sim"
4540 puts $make_log_file "ghdl -m --work=$simset_name -fsynopsys --ieee=standard $options $top_sim"
4541 close $make_log_file
4543 lassign [
GHDL "-m --work=$simset_name -fsynopsys --ieee=standard $options $top_sim" $make_log] ret result
4546 Msg Error "GHDL make failed for $top_sim: $result"
4550 set run_log_file [open $run_log "w"]
4551 puts "ghdl -r --work=$simset_name -fsynopsys --ieee=standard $options $top_sim $runopts"
4552 puts $run_log_file "ghdl -r --work=$simset_name -fsynopsys --ieee=standard $options $top_sim $runopts"
4555 lassign [
GHDL "-r --work=$simset_name -fsynopsys --ieee=standard $options $top_sim $runopts" $run_log] ret result
4559 Msg Error "GHDL run failed for $top_sim: $result"
4574 proc LaunchImplementation {reset do_create run_folder project_name {repo_path .} {njobs 4} {do_bitstream 0}} {
4575 Msg Info "Starting implementation flow..."
4577 if {$reset == 1 && $do_create == 0} {
4578 Msg Info "Resetting run before launching implementation..."
4583 source $repo_path/Hog/Tcl/integrated/pre-implementation.tcl
4586 if {$do_bitstream == 1} {
4587 launch_runs impl_1 -to_step [
BinaryStepName [get_property PART [current_project]]] -jobs $njobs -dir $run_folder
4589 launch_runs impl_1 -jobs $njobs -dir $run_folder
4594 Msg Info "running post-implementation"
4595 source $repo_path/Hog/Tcl/integrated/post-implementation.tcl
4596 if {$do_bitstream == 1} {
4597 Msg Info "running pre-bitstream"
4598 source $repo_path/Hog/Tcl/integrated/pre-bitstream.tcl
4599 Msg Info "running post-bitstream"
4600 source $repo_path/Hog/Tcl/integrated/post-bitstream.tcl
4604 set prog [get_property PROGRESS [get_runs impl_1]]
4605 set status [get_property STATUS [get_runs impl_1]]
4606 Msg Info "Run: impl_1 progress: $prog, status : $status"
4610 set status_file [open "$run_folder/timing.txt" "w"]
4611 puts $status_file "## $project_name Timing summary"
4613 set f [open [
lindex [glob "$run_folder/impl_1/*.twr" 0]]]
4615 while {[
gets $f line] >= 0} {
4616 if {[
string match "Timing summary:" $line]} {
4617 while {[
gets $f line] >= 0} {
4618 if {[
string match "Timing errors:*" $line]} {
4619 set errs [regexp -inline -- {[0-9]+} $line]
4621 if {[
string match "*Footnotes*" $line]} {
4624 puts $status_file "$line"
4633 Msg Info "Time requirements are met"
4634 file rename -force "$run_folder/timing.txt" "$run_folder/timing_ok.txt"
4637 Msg CriticalWarning "Time requirements are NOT met"
4638 file rename -force "$run_folder/timing.txt" "$run_folder/timing_error.txt"
4644 set wns [get_property STATS.WNS [get_runs [current_run]]]
4645 set tns [get_property STATS.TNS [get_runs [current_run]]]
4646 set whs [get_property STATS.WHS [get_runs [current_run]]]
4647 set ths [get_property STATS.THS [get_runs [current_run]]]
4648 set tpws [get_property STATS.TPWS [get_runs [current_run]]]
4650 if {$wns >= 0 && $whs >= 0 && $tpws >= 0} {
4651 Msg Info "Time requirements are met"
4652 set status_file [open "$run_folder/timing_ok.txt" "w"]
4655 Msg CriticalWarning "Time requirements are NOT met"
4656 set status_file [open "$run_folder/timing_error.txt" "w"]
4660 Msg Status "*** Timing summary ***"
4661 Msg Status "WNS: $wns"
4662 Msg Status "TNS: $tns"
4663 Msg Status "WHS: $whs"
4664 Msg Status "THS: $ths"
4665 Msg Status "TPWS: $tpws"
4671 puts $status_file "## $project_name Timing summary"
4673 m add row "| **Parameter** | \"**value (ns)**\" |"
4674 m add row "| --- | --- |"
4675 m add row "| WNS: | $wns |"
4676 m add row "| TNS: | $tns |"
4677 m add row "| WHS: | $whs |"
4678 m add row "| THS: | $ths |"
4679 m add row "| TPWS: | $tpws |"
4681 puts $status_file [m format 2string]
4682 puts $status_file "\n"
4683 if {$timing_ok == 1} {
4684 puts $status_file " Time requirements are met."
4686 puts $status_file "Time requirements are **NOT** met."
4688 puts $status_file "\n\n"
4692 if {$prog ne "100%"} {
4693 Msg Error "Implementation error"
4698 lassign [
GetRepoVersions [
file normalize ./Top/$project_name] $repo_path] sha
4700 Msg Info "Git describe set to $describe"
4702 set dst_dir [
file normalize "$repo_path/bin/$project_name\-$describe"]
4707 if {[
file exists $run_folder/versions.txt]} {
4708 file copy -force $run_folder/versions.txt $dst_dir
4710 Msg Warning "No versions file found in $run_folder/versions.txt"
4713 set timing_files [glob -nocomplain "$run_folder/timing_*.txt"]
4714 set timing_file [
file normalize [
lindex $timing_files 0]]
4716 if {[
file exists $timing_file]} {
4717 file copy -force $timing_file $dst_dir/
4719 Msg Warning "No timing file found, not a problem if running locally"
4723 if {[
IsVersal [get_property part [current_project]]]} {
4724 if {[get_property segmented_configuration [current_project]] == 1} {
4725 Msg Info "Versal Segmented configuration detected: exporting XSA file..."
4726 set xsa_name "$dst_dir/[
file tail $project_name]\-$describe.xsa"
4727 write_hw_platform -fixed -force -file $xsa_name
4731 set revision [get_current_revision]
4733 if {[
catch {execute_module -tool fit} result]} {
4734 Msg Error "Result: $result\n"
4735 Msg Error "Place & Route failed. See the report file.\n"
4737 Msg Info "\nINFO: Place & Route was successful for revision $revision.\n"
4740 if {[
catch {execute_module -tool sta -args "--do_report_timing"} result]} {
4741 Msg Error "Result: $result\n"
4742 Msg Error "Time Quest failed. See the report file.\n"
4744 Msg Info "Time Quest was successfully run for revision $revision.\n"
4747 set panel "Timing Analyzer||Timing Analyzer Summary"
4748 set device [get_report_panel_data -name $panel -col 1 -row_name "Device Name"]
4749 set timing_model [get_report_panel_data -name $panel -col 1 -row_name "Timing Models"]
4750 set delay_model [get_report_panel_data -name $panel -col 1 -row_name "Delay Model"]
4752 Msg Info "*******************************************************************"
4753 Msg Info "Device: $device"
4754 Msg Info "Timing Models: $timing_model"
4755 Msg Info "Delay Model: $delay_model"
4758 Msg Info "*******************************************************************"
4761 Msg Info "Starting implementation flow..."
4762 if {[
catch {run_tool -name {PLACEROUTE}}]} {
4763 Msg Error "PLACEROUTE FAILED!"
4765 Msg Info "PLACEROUTE PASSED."
4769 Msg Info "Run VERIFYTIMING ..."
4770 if {[
catch {run_tool -name {VERIFYTIMING} -script {Hog/Tcl/integrated/libero_timing.tcl}}]} {
4771 Msg CriticalWarning "VERIFYTIMING FAILED!"
4773 Msg Info "VERIFYTIMING PASSED \n"
4779 lassign [
GetRepoVersions [
file normalize ./Top/$project_name] $repo_path] sha
4781 Msg Info "Git describe set to $describe"
4783 set dst_dir [
file normalize "$repo_path/bin/$project_name\-$describe"]
4784 file mkdir $dst_dir/reports
4787 if {[
file exists $run_folder/versions.txt]} {
4788 file copy -force $run_folder/versions.txt $dst_dir
4790 Msg Warning "No versions file found in $run_folder/versions.txt"
4793 set timing_file_path [
file normalize "$repo_path/Projects/timing_libero.txt"]
4794 if {[
file exists $timing_file_path]} {
4795 file copy -force $timing_file_path $dst_dir/reports/Timing.txt
4796 set timing_file [open $timing_file_path "r"]
4797 set status_file [open "$dst_dir/timing.txt" "w"]
4798 puts $status_file "## $project_name Timing summary\n\n"
4799 puts $status_file "| | |"
4800 puts $status_file "| --- | --- |"
4801 while {[
gets $timing_file line] >= 0} {
4802 if {[
string match "SUMMARY" $line]} {
4803 while {[
gets $timing_file line] >= 0} {
4804 if {[
string match "END SUMMARY" $line]} {
4807 if {[
string first ":" $line] == -1} {
4810 set out_string "| [
string map {: | } $line] |"
4811 puts $status_file "$out_string"
4816 Msg Warning "No timing file found, not a problem if running locally"
4821 set force_rst "-forceOne"
4823 prj_run Map $force_rst
4824 prj_run PAR $force_rst
4836 proc GenerateBitstreamOnly {project_name {repo_path .}} {
4838 lassign [
GetRepoVersions [
file normalize ./Top/$project_name] $repo_path] sha
4840 set dst_dir [
file normalize "$repo_path/bin/$project_name\-$describe"]
4842 cd Projects/$project_name/$project_name.runs/impl_1
4843 Msg Info "Running pre-bitstream..."
4844 source $repo_path/Hog/Tcl/integrated/pre-bitstream.tcl
4846 Msg Info "Writing bitstream for $project_name..."
4848 write_bitstream -force $dst_dir/$project_name-$describe.bit
4850 Msg Info "Running post-bitstream..."
4851 source $repo_path/Hog/Tcl/integrated/post-bitstream.tcl
4860 proc LaunchSimulation {project_name lib_path simsets {repo_path .} {scripts_only 0} {compile_only 0}} {
4863 set project [
file tail $project_name]
4864 set main_sim_folder [
file normalize "$repo_path/Projects/$project_name/$project.sim/"]
4866 if {$simsets != ""} {
4867 dict for {simset sim_dict} $simsets {
4868 lappend simsets_todo $simset
4870 Msg Info "Will run only the following simulation's sets (if they exist): $simsets_todo"
4873 if {$scripts_only == 1} {
4874 Msg Info "Only generating simulation scripts, not running simulations..."
4877 if {$compile_only == 1} {
4878 Msg Info "Only compiling simulation libraries, not running simulations..."
4883 set sim_dic [dict create]
4885 Msg Info "Retrieving list of simulation sets..."
4886 foreach s [get_filesets] {
4888 set use_simpass_str 0
4891 set type [get_property FILESET_TYPE $s]
4892 if {$type eq "SimulationSrcs"} {
4893 if {$simsets_todo != "" && $s ni $simsets_todo} {
4894 Msg Info "Skipping $s as it was not specified with the -simset option..."
4897 set sim_dict [
DictGet $simsets $s]
4898 set simulator [
DictGet $sim_dict "simulator"]
4899 set_property "target_simulator" $simulator [current_project]
4900 set hog_sim_props [
DictGet $sim_dict "hog"]
4901 dict for {prop_name prop_val} $hog_sim_props {
4902 # If HOG_SIMPASS_STR is set, use the HOG_SIMPASS_STR string to search for in logs, after simulation is done
4903 if {[string toupper $prop_name] == "HOG_SIMPASS_STR" && $prop_val != ""} {
4904 Msg Info "Setting simulation pass string as '$prop_val'"
4905 set use_simpass_str 1
4906 set simpass_str $prop_val
4908 if {[string toupper $prop_name] == "HOG_SILENT_SIM" && $prop_val == 1} {
4909 set quiet_sim " -quiet"
4915 Msg Info "Creating simulation scripts for $s..."
4916 if {[
file exists $repo_path/Top/$project_name/pre-simulation.tcl]} {
4917 Msg Info "Running $repo_path/Top/$project_name/pre-simulation.tcl"
4918 source $repo_path/Top/$project_name/pre-simulation.tcl
4920 if {[
file exists $repo_path/Top/$project_name/pre-$s-simulation.tcl]} {
4921 Msg Info "Running $repo_path/Top/$project_name/pre-$s-simulation.tcl"
4922 source Running $repo_path/Top/$project_name/pre-$s-simulation.tcl
4924 current_fileset -simset $s
4925 set sim_dir $main_sim_folder/$s/behav
4926 set sim_output_logfile $sim_dir/xsim/simulate.log
4927 if {([
string tolower $simulator] eq "xsim")} {
4928 set sim_name "xsim:$s"
4930 set simulation_command "launch_simulation $quiet_sim -simset [get_filesets $s]"
4931 if {[
catch $simulation_command log]} {
4934 Msg CriticalWarning "Simulation failed for $s, error info: $::errorInfo"
4935 lappend failed $sim_name
4940 if {$use_simpass_str == 1} {
4943 set file_desc [open $sim_output_logfile r]
4944 set log [read $file_desc]
4947 Msg Info "Searching for simulation pass string: '$simpass_str'"
4948 if {[
string first $simpass_str $log] == -1} {
4949 Msg CriticalWarning "Simulation failed for $s, error info: '$simpass_str' NOT found!"
4950 lappend failed $sim_name
4953 lappend success $sim_name
4957 lappend success $sim_name
4961 Msg Info "Simulation library path is set to $lib_path."
4963 if {!([
file exists $lib_path])} {
4964 Msg Warning "Could not find simulation library path: $lib_path, $simulator simulation will not work."
4968 if {$simlib_ok == 1} {
4969 set_property "compxlib.${simulator}_compiled_library_dir" [
file normalize $lib_path] [current_project]
4970 launch_simulation -scripts_only -simset [get_filesets $s]
4971 set top_name [get_property TOP $s]
4972 set sim_script [
file normalize $sim_dir/$simulator/]
4973 Msg Info "Adding simulation script location $sim_script for $s..."
4974 lappend sim_scripts $sim_script
4975 dict append sim_dic $sim_script $s
4977 Msg Error "Cannot run $simulator simulations without a valid library path"
4984 if {[
info exists sim_scripts] && $scripts_only == 0} {
4986 Msg Info "Generating IP simulation targets, if any..."
4988 foreach ip [get_ips] {
4989 generate_target simulation -quiet $ip
4994 Msg Info "====== Starting simulations runs ======"
4997 foreach s $sim_scripts {
4999 set cmd ./compile.sh
5000 Msg Info " ************* Compiling: $s ************* "
5002 set sim_name "comp:[dict get $sim_dic $s]"
5004 Msg CriticalWarning "Compilation failed for $s, error info: $::errorInfo"
5005 lappend failed $sim_name
5007 lappend success $sim_name
5009 Msg Info "###################### Compilation log starts ######################"
5010 Msg Info "\n\n$log\n\n"
5011 Msg Info "###################### Compilation log ends ######################"
5013 if {$compile_only == 1} {
5016 if {[
file exists "./elaborate.sh"] } {
5017 set cmd ./elaborate.sh
5018 Msg Info " ************* Elaborating: $s ************* "
5020 set sim_name "elab:[dict get $sim_dic $s]"
5022 Msg CriticalWarning "Elaboration failed for $s, error info: $::errorInfo"
5023 lappend failed $sim_name
5025 lappend success $sim_name
5027 Msg Info "###################### Elaboration log starts ######################"
5028 Msg Info "\n\n$log\n\n"
5029 Msg Info "###################### Elaboration log ends ######################"
5031 set cmd ./simulate.sh
5032 Msg Info " ************* Simulating: $s ************* "
5037 if {$use_simpass_str == 1} {
5038 if {[
string first $simpass_str $log] == -1} {
5042 Msg Debug "Simulation pass string not set, relying on simulator exit code."
5046 set sim_name "sim:[dict get $sim_dic $s]"
5048 Msg CriticalWarning "Simulation failed for $s, error info: $::errorInfo"
5049 lappend failed $sim_name
5051 lappend success $sim_name
5053 Msg Info "###################### Simulation log starts ######################"
5054 Msg Info "\n\n$log\n\n"
5055 Msg Info "###################### Simulation log ends ######################"
5060 if {[
llength $success] > 0} {
5061 set successes [
join $success "\n"]
5062 Msg Info "The following simulation sets were successful:\n\n$successes\n\n"
5065 if {[
llength $failed] > 0} {
5066 set failures [
join $failed "\n"]
5067 Msg Error "The following simulation sets have failed:\n\n$failures\n\n"
5069 }
elseif {[
llength $success] > 0} {
5070 Msg Info "All the [
llength $success] compilations, elaborations and simulations were successful."
5073 Msg Info "Simulation done."
5075 Msg Warning "Simulation is not yet supported for [
GetIDEName]."
5086 proc LaunchRTLAnalysis {} {
5088 Msg Info "Starting RTL Analysis..."
5089 synth_design -rtl -name rtl_1
5102 proc LaunchSynthesis {reset do_create run_folder project_name {repo_path .} {ext_path ""} {njobs 4}} {
5104 if {$reset == 1 && $do_create == 0} {
5105 Msg Info "Resetting run before launching synthesis..."
5109 source $repo_path/Hog/Tcl/integrated/pre-synthesis.tcl
5111 launch_runs synth_1 -jobs $njobs -dir $run_folder
5113 set prog [get_property PROGRESS [get_runs synth_1]]
5114 set status [get_property STATUS [get_runs synth_1]]
5115 Msg Info "Run: synth_1 progress: $prog, status : $status"
5122 lassign [
GetRepoVersions [
file normalize ./Top/$project_name] $repo_path $ext_path] sha
5124 Msg Info "Git describe set to $describe"
5127 set xci_file [get_property IP_FILE $ip]
5129 set xci_path [
file dirname $xci_file]
5130 set xci_ip_name [
file rootname [
file tail $xci_file]]
5131 foreach rptfile [glob -nocomplain -directory $xci_path *.rpt] {
5132 file copy $rptfile $repo_path/bin/$project_name-$describe/reports
5136 if {$prog ne "100%"} {
5137 Msg Error "Synthesis error, status is: $status"
5141 set project [
file tail [
file rootname $project_name]]
5143 Msg Info "Number of jobs set to $njobs."
5144 set_global_assignment -name NUM_PARALLEL_PROCESSORS $njobs
5148 lassign [
GetRepoVersions [
file normalize $repo_path/Top/$project_name] $repo_path] sha
5151 set revision [get_current_revision]
5154 set tool_and_command [
split [get_global_assignment -name PRE_FLOW_SCRIPT_FILE] ":"]
5155 set tool [
lindex $tool_and_command 0]
5156 set pre_flow_script [
lindex $tool_and_command 1]
5157 set cmd "$tool -t $pre_flow_script quartus_map $project $revision"
5163 Msg Warning "Can not execute command $cmd"
5164 Msg Warning "LOG: $log"
5166 Msg Info "Pre flow script executed!"
5170 if {![is_project_open]} {
5171 Msg Info "Re-opening project file $project_name..."
5172 project_open $project -current_revision
5176 if {[
catch {execute_module -tool ipg -args "--clean"} result]} {
5177 Msg Error "Result: $result\n"
5178 Msg Error "IP Generation failed. See the report file.\n"
5180 Msg Info "IP Generation was successful for revision $revision.\n"
5184 if {[
catch {execute_module -tool map -args "--parallel"} result]} {
5185 Msg Error "Result: $result\n"
5186 Msg Error "Analysis & Synthesis failed. See the report file.\n"
5188 Msg Info "Analysis & Synthesis was successful for revision $revision.\n"
5192 defvar_set -name RWNETLIST_32_64_MIXED_FLOW -value 0
5194 Msg Info "Run SYNTHESIS..."
5195 if {[
catch {run_tool -name {SYNTHESIZE}}]} {
5196 Msg Error "SYNTHESIZE FAILED!"
5198 Msg Info "SYNTHESIZE PASSED!"
5204 set force_rst "-forceOne"
5206 prj_run Synthesis $force_rst
5207 if {[prj_syn] == "synplify"} {
5208 prj_run Translate $force_rst
5211 Msg Error "Impossible condition. You need to run this in an IDE."
5222 proc LaunchVitisBuild {project_name {repo_path .} {stage "presynth"}} {
5223 set proj_name $project_name
5224 set bin_dir [
file normalize "$repo_path/bin"]
5228 if {[
catch {
set ws_apps [app list -dict]}]} {
set ws_apps ""}
5229 lassign [
GetRepoVersions [
file normalize $repo_path/Top/$proj_name] $repo_path] commit version hog_hash hog_ver top_hash top_ver \
5230 libs hashes vers cons_ver cons_hash ext_names ext_hashes xml_hash xml_ver user_ip_repos user_ip_hashes user_ip_vers
5232 if {$commit == 0 } {
set commit $this_commit}
5236 foreach app_name [dict keys $ws_apps] {
5237 app config -name $app_name -set build-config Release
5240 WriteGenerics "vitisbuild" $repo_path $proj_name $date $timee $commit $version $top_hash $top_ver $hog_hash $hog_ver $cons_ver $cons_hash $libs \
5241 $vers $hashes $ext_names $ext_hashes $user_ip_repos $user_ip_vers $user_ip_hashes $flavour $xml_ver $xml_hash
5242 foreach app_name [dict keys $ws_apps] { app build -name $app_name}
5244 if {$stage == "presynth"} {
5245 Msg Info "Done building apps for $project_name..."
5249 Msg Info "Evaluating Git sha for $project_name..."
5250 lassign [
GetRepoVersions [
file normalize ./Top/$project_name] $repo_path] sha
5253 Msg Info "Hog describe set to: $describe"
5254 set dst_dir [
file normalize "$bin_dir/$proj_name\-$describe"]
5255 if {![
file exists $dst_dir]} {
5256 Msg Info "Creating $dst_dir..."
5260 foreach app_name [dict keys $ws_apps] {
5261 set main_file "$repo_path/Projects/$project_name/vitis_classic/$app_name/Release/$app_name.elf"
5262 set dst_main [
file normalize "$dst_dir/[
file tail $proj_name]\-$app_name\-$describe.elf"]
5264 if {![
file exists $main_file]} {
5265 Msg Error "No Vitis .elf file found. Perhaps there was an issue building it?"
5269 Msg Info "Copying main binary file $main_file into $dst_main..."
5270 file copy -force $main_file $dst_main
5279 proc GetProcFromProps {repo_path props platform} {
5280 if {[dict exists $props "platform:$platform" "BIF"]} {
5281 set bif_file [dict get $props "platform:$platform" "BIF"]
5283 set bif_file "$repo_path/$bif_file"
5287 Msg CriticalWarning "BIF file not found in platform ($platform) properties, skipping bootable image (.bin) generation"
5297 proc GetBifFromProps {repo_path props platform} {
5298 if {[dict exists $props "platform:$platform" "BIF"]} {
5299 set bif_file [dict get $props "platform:$platform" "BIF"]
5301 set bif_file "$repo_path/$bif_file"
5305 Msg CriticalWarning "BIF file not found in platform ($platform) properties, skipping bootable image (.bin) generation"
5314 proc GetPartFromProps {props} {
5315 if {[dict exists $props "main" "PART"]} {
5316 return [
string tolower [dict get $props "main" "PART"]]
5318 Msg Error "Part number not found in properties"
5327 proc GetArchFromPart {part} {
5329 if {[
string match "xczu*" $part]} {
5331 }
elseif {[
string match "xc7z*" $part]} {
5333 }
elseif {[
string match "xck26*" $part]} {
5336 Msg CriticalWarning "Unknown part number: $part"
5345 proc GetAppsFromProps {props {list_names 0}} {
5346 set prop_apps [dict filter $props key {app:*}]
5347 set apps [dict create]
5348 set app_names [list]
5350 dict for {app_key app_value} $prop_apps {
5351 if {[regexp {^app:(.+)$} $app_key -> app_name]} {
5352 set app_name [string trim [string tolower $app_name]]
5353 # Convert only the keys of the inner dictionary to lowercase
5354 set app_value_lower [dict create]
5355 dict for {key value} $app_value {
5356 dict set app_value_lower [string tolower $key] $value
5358 dict set apps $app_name $app_value_lower
5359 lappend app_names $app_name
5362 if {$list_names eq 1} {
5373 proc GetPlatformsFromProps {props {list_names 0} {lower_case 0}} {
5374 set platforms [dict create]
5375 set platform_names [list]
5376 set prop_platforms [dict filter $props key {platform:*}]
5378 dict for {platform_key platform_value} $prop_platforms {
5379 if {[regexp {^platform:(.+)$} $platform_key -> platform_name]} {
5380 if {$lower_case == 1} {
5381 set platform_name [string trim [string tolower $platform_name]]
5383 set platform_name [string trim $platform_name]
5385 dict set platforms $platform_name $platform_value
5386 lappend platform_names $platform_name
5389 if {$list_names eq 1} {
5390 return $platform_names
5405 proc GenerateBootArtifacts {properties repo_path proj_dir bin_dir proj_name describe bitfile mmi_file} {
5406 set elf_list [glob -nocomplain "$bin_dir/*.elf"]
5410 if {[
llength $elf_list] == 0} {
5411 Msg Warning "No ELF files found in $bin_dir, skipping generation of boot artifacts"
5415 if {![
file exists $bitfile]} {
5416 Msg Warning "Bitfile $bitfile does not exist, skipping generation of boot artifacts"
5420 Msg Info "Generating boot artifacts for $proj_name..."
5421 Msg Info "Found apps: $apps"
5422 Msg Info "Found platforms: $platforms"
5426 foreach elf_file $elf_list {
5427 set elf_name [
file rootname [
file tail $elf_file]]
5428 Msg Info "Found elf name: $elf_name"
5429 Msg Info "Removing $describe from elf"
5432 if {[regexp "^(.+)-(.+)-$describe\$" $elf_name -> project_name elf_app]} {
5433 set elf_app [
string trim [
string tolower $elf_app]]
5434 Msg Info "Found elf_app: $elf_app"
5436 Msg Error "Could not extract app name from elf file: $elf_name"
5439 Msg Info "Removed project name ($project_name) and $describe from elf"
5441 set app_conf [dict get $apps $elf_app]
5442 set plat [dict get $app_conf "platform"]
5443 set app_proc [dict get $app_conf "proc"]
5446 if {[regexp -nocase {microblaze|risc} $app_proc]} {
5447 Msg Info "Detected soft processor ($app_proc) for $elf_app, updating bitstream memory with ELF file..."
5450 if {[dict size $proc_map] == 0} {
5451 Msg Error "Failed to read map from $proc_map_file"
5454 Msg Info "Found processor map: $proc_map"
5456 set proc_cell [
lindex [
split [dict get $proc_map $app_proc] ":"] 1]
5457 Msg Info "Updating memory at processor cell: $proc_cell"
5459 set update_mem_cmd "updatemem -force -meminfo $mmi_file -data $elf_file -bit $bitfile -proc $proc_cell -out $bitfile"
5460 set ret [
catch {
exec -ignorestderr {*}$update_mem_cmd >@ stdout} result]
5462 Msg Error "Error updating memory for $elf_app: $result"
5464 Msg Info "Done updating memory for $elf_app"
5467 Msg Info "Detected hard processor ($app_proc) for $elf_app. Make sure the .elf file is defined in the platform ($plat)\
5468 .bif file to be included in the bootable binary image (.bin) generation."
5474 foreach plat $platforms {
5476 if {$bif_file != ""} {
5477 Msg Info "Generating bootable binary image (.bin) for $plat"
5479 Msg Info "Architecture: $arch"
5480 Msg Info "BIF file: $bif_file"
5481 set bootgen_cmd "bootgen -arch $arch -image $bif_file -o i $bin_dir/$proj_name-$plat-$describe.bin -w on"
5482 set ret [
catch {
exec -ignorestderr {*}$bootgen_cmd >@ stdout} result]
5484 Msg Error "Error generating bootable binary image (.bin) for $elf_app: $result"
5486 Msg Info "Done generating bootable binary image (.bin) for $plat"
5495 proc ReadProcMap {proc_map_file} {
5496 set proc_map [dict create]
5497 if {[
file exists $proc_map_file]} {
5498 set f [open $proc_map_file "r"]
5499 while {[
gets $f line] >= 0} {
5500 Msg Debug "Line: $line"
5501 if {[regexp {^(\S+)\s+(.+)$} $line -> key value]} {
5502 Msg Debug "Found key: $key, value: $value in proc map file"
5503 dict set proc_map $key $value
5517 proc ListProjects {{repo_path .} {print 1} {ret_conf 0}} {
5518 set top_path [
file normalize $repo_path/Top]
5519 set confs [
findFiles [
file normalize $top_path] hog.conf]
5521 set confs [lsort $confs]
5525 set p [
Relative $top_path [
file dirname $c]]
5528 if {$description eq "test"} {
5529 set description " - Test project"
5530 }
elseif {$description ne ""} {
5531 set description " - $description"
5534 if {$print == 1 || $description ne " - Test project"} {
5536 set g [
file dirname $p]
5547 if {$ret_conf == 0} {
5559 proc Md5Sum {file_name} {
5560 if {!([
file exists $file_name])} {
5561 Msg Warning "Could not find $file_name."
5564 if {[
catch {
package require md5 2.0.7} result]} {
5565 Msg Warning "Tcl package md5 version 2.0.7 not found ($result), will use command line..."
5566 set hash [
lindex [
Execute md5sum $file_name] 0]
5568 set file_hash [
string tolower [md5::md5 -hex -file $file_name]]
5582 proc MergeDict {dict0 dict1 {remove_duplicates 1}} {
5583 set outdict [dict merge $dict1 $dict0]
5584 foreach key [dict keys $dict1] {
5585 if {[dict exists $dict0 $key]} {
5586 set temp_list [dict get $dict1 $key]
5587 foreach item $temp_list {
5589 if {[
IsInList $item [
DictGet $outdict $key]] == 0 || $remove_duplicates == 0} {
5591 dict lappend outdict $key $item
5603 proc MoveElementToEnd {inputList element} {
5604 set index [lsearch $inputList $element]
5606 set inputList [
lreplace $inputList $index $index]
5607 lappend inputList $element
5616 proc OpenProject {project_file repo_path} {
5618 open_project $project_file
5620 set project_folder [
file dirname $project_file]
5621 set project [
file tail [
file rootname $project_file]]
5622 if {[
file exists $project_folder]} {
5624 if {![is_project_open]} {
5625 Msg Info "Opening existing project file $project_file..."
5626 project_open $project -current_revision
5629 Msg Error "Project directory not found for $project_file."
5633 Msg Info "Opening existing project file $project_file..."
5635 open_project -file $project_file -do_backup_on_convert 1 -backup_file {./Projects/$project_file.zip}
5637 Msg Info "Opening existing project file $project_file..."
5638 prj_project open $project_file
5640 Msg Error "This IDE is currently not supported by Hog. Exiting!"
5647 return $tcl_platform(platform)
5657 proc ParseJSON {JSON_FILE JSON_KEY} {
5658 set result [
catch {
package require Tcl 8.4} TclFound]
5659 if {"$result" != "0"} {
5660 Msg CriticalWarning "Cannot find Tcl package version equal or higher than 8.4.\n $TclFound\n Exiting"
5664 set result [
catch {
package require json} JsonFound]
5665 if {"$result" != "0"} {
5666 Msg CriticalWarning "Cannot find JSON package equal or higher than 1.0.\n $JsonFound\n Exiting"
5669 set JsonDict [json::json2dict $JSON_FILE]
5670 set result [
catch {dict get $JsonDict $JSON_KEY} RETURNVALUE]
5671 if {"$result" != "0"} {
5672 Msg CriticalWarning "Cannot find $JSON_KEY in $JSON_FILE\n Exiting"
5685 proc ProjectExists {project {repo_path .}} {
5686 set index [lsearch -exact [
ListProjects $repo_path 0] $project]
5692 Msg Error "Project $project not found in repository $repo_path"
5703 proc ReadConf {file_name} {
5704 if {[
catch {
package require inifile 0.2.3} ERROR]} {
5705 Msg Error "Could not find inifile package version 0.2.3 or higher.\n
5706 To use ghdl, libero or diamond with Hog, you need to install the tcllib package\n
5707 You can install it with 'sudo apt install tcllib' on Debian/Ubuntu or 'sudo dnf install tcllib' on Fedora/RedHat/CentOs."
5711 ::ini::commentchar "#"
5712 set f [::ini::open $file_name]
5713 set properties [dict create]
5714 foreach sec [::ini::sections $f] {
5716 if {$new_sec == "files"} {
5719 set key_pairs [::ini::get $f $sec]
5721 regsub -all {\{\"} $key_pairs "\{" key_pairs
5722 regsub -all {\"\}} $key_pairs "\}" key_pairs
5724 dict set properties $new_sec [dict create {*}$key_pairs]
5737 proc ReadExtraFileList {extra_file_name} {
5738 set extra_file_dict [dict create]
5739 if {[
file exists $extra_file_name]} {
5740 set file [open $extra_file_name "r"]
5741 set file_data [read $file]
5744 set data [
split $file_data "\n"]
5745 foreach line $data {
5746 if {![regexp {^ *$} $line] & ![regexp {^ *\#} $line]} {
5747 set ip_and_md5 [regexp -all -inline {\S+} $line]
5748 dict lappend extra_file_dict "[
lindex $ip_and_md5 0]" "[
lindex $ip_and_md5 1]"
5752 return $extra_file_dict
5772 proc ReadListFile {args} {
5775 if {[
catch {
package require cmdline} ERROR]} {
5776 puts "$ERROR\n If you are running this script on tclsh, you can fix this by installing 'tcllib'"
5782 {lib.arg "" "The name of the library files will be added to, if not given will be extracted from the file name."}
5783 {fileset.arg "" "The name of the library, from the main list file"}
5784 {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."}
5785 {print_log "If set, will use PrintFileTree for the VIEW directive"}
5786 {indent.arg "" "Used to indent files with the VIEW directive"}
5789 set usage "USAGE: ReadListFile \[options\] <list file> <path>"
5790 if {[
catch {
array set options [
cmdline::getoptions args $parameters $usage]}] || [
llength $args] != 2} {
5796 set list_file [
lindex $args 0]
5797 set path [
lindex $args 1]
5798 set sha_mode $options(sha_mode)
5799 set lib $options(lib)
5800 set fileset $options(fileset)
5801 set print_log $options(print_log)
5802 set indent $options(indent)
5804 if {$sha_mode == 1} {
5805 set sha_mode_opt "-sha_mode"
5810 if {$print_log == 1} {
5811 set print_log_opt "-print_log"
5813 set print_log_opt ""
5818 set lib [
file rootname [
file tail $list_file]]
5820 set fp [open $list_file r]
5821 set file_data [read $fp]
5823 set list_file_ext [
file extension $list_file]
5824 switch $list_file_ext {
5826 if {$fileset eq ""} {
5832 set fileset "constrs_1"
5835 set fileset "sources_1"
5839 set libraries [dict create]
5840 set filesets [dict create]
5841 set properties [dict create]
5843 set data [
split $file_data "\n"]
5845 set n [
llength $data]
5847 if {$print_log == 1} {
5848 if {$indent eq ""} {
5849 set list_file_rel [
file tail $list_file]
5850 Msg Status "\n$list_file_rel"
5854 Msg Debug "$n lines read from $list_file."
5857 foreach line $data {
5859 if {![regexp {^[\t\s]*$} $line] & ![regexp {^[\t\s]*\#} $line]} {
5860 set file_and_prop [regexp -all -inline {\S+} $line]
5861 set srcfile [
lindex $file_and_prop 0]
5862 set srcfile "$path/$srcfile"
5864 set srcfiles [glob -nocomplain $srcfile]
5867 if {$srcfiles != $srcfile && ![
string equal $srcfiles ""]} {
5868 Msg Debug "Wildcard source expanded from $srcfile to $srcfiles"
5870 if {![
file exists $srcfile]} {
5871 if {$print_log == 0} {
5872 Msg CriticalWarning "File: $srcfile (from list file: $list_file) does not exist."
5878 foreach vhdlfile $srcfiles {
5879 if {[
file exists $vhdlfile]} {
5880 set vhdlfile [
file normalize $vhdlfile]
5881 set extension [
file extension $vhdlfile]
5883 set prop [
lrange $file_and_prop 1 end]
5886 set library [
lindex [regexp -inline {\ylib\s*=\s*(.+?)\y.*} $prop] 1]
5887 if {$library == ""} {
5891 if {$extension == $list_file_ext} {
5894 set ref_path [
lindex [regexp -inline {\ypath\s*=\s*(\S+).*} $prop] 1]
5895 if {$ref_path eq ""} {
5898 set ref_path [
file normalize $path/$ref_path]
5900 Msg Debug "List file $vhdlfile found in list file, recursively opening it using path \"$ref_path\"..."
5901 if {$print_log == 1} {
5902 if {[
file normalize $last_printed] ne [
file normalize $vhdlfile]} {
5903 Msg Status "$indent Inside [
file tail $vhdlfile]:"
5907 lassign [
ReadListFile {*}"-indent \" $indent\" -lib $library -fileset $fileset $sha_mode_opt $print_log_opt $vhdlfile $ref_path"] l p fs
5909 set properties [
MergeDict $p $properties]
5911 }
elseif {[lsearch {.src .sim .con ReadExtraFileList} $extension] >= 0} {
5913 Msg Error "$vhdlfile cannot be included into $list_file, $extension files must be included into $extension files."
5916 regsub -all " *= *" $prop "=" prop
5920 if {[
string first "lib=" $p] == -1} {
5922 set pos [
string first "=" $p]
5926 set prop_name [
string range $p 0 [
expr {$pos - 1}]]
5929 dict lappend properties $vhdlfile $p
5930 Msg Debug "Adding property $p to $vhdlfile..."
5931 }
elseif {$list_file_ext != ".ipb"} {
5932 Msg Warning "Setting Property $p is not supported for file $vhdlfile or it is already its default. \
5937 if {[lsearch {.xci .ip .bd .xcix} $extension] >= 0} {
5939 set lib_name "ips.src"
5940 }
elseif {[
IsInList $extension {.vhd .vhdl}] || $list_file_ext == ".sim"} {
5942 if {![
IsInList $extension {.vhd .vhdl}]} {
5943 set lib_name "others.sim"
5945 set lib_name "$library$list_file_ext"
5947 }
elseif {$list_file_ext == ".con"} {
5948 set lib_name "sources.con"
5949 }
elseif {$list_file_ext == ".ipb"} {
5950 set lib_name "xml.ipb"
5951 }
elseif { [
IsInList $list_file_ext {.src}] && [
IsInList $extension {.c .cpp .h .hpp}] } {
5953 set lib_name "$library$list_file_ext"
5956 set lib_name "others.src"
5959 Msg Debug "Appending $vhdlfile to $lib_name list..."
5960 dict lappend libraries $lib_name $vhdlfile
5961 if {$sha_mode != 0 && [
file type $vhdlfile] eq "link"} {
5964 dict lappend libraries $lib_name $real_file
5965 Msg Debug "File $vhdlfile is a soft link, also adding the real file: $real_file"
5970 if {[dict exists $filesets $fileset] == 0} {
5972 Msg Debug "Adding $fileset to the fileset dictionary..."
5973 Msg Debug "Adding library $lib_name to fileset $fileset..."
5974 dict set filesets $fileset $lib_name
5978 Msg Debug "Adding library $lib_name to fileset $fileset..."
5979 dict lappend filesets $fileset $lib_name
5985 Msg CriticalWarning "File $vhdlfile not found."
5991 if {$sha_mode != 0} {
5993 if {$list_file_ext eq ".ipb"} {
5994 set sha_lib "xml.ipb"
5996 set sha_lib $lib$list_file_ext
5998 dict lappend libraries $sha_lib [
file normalize $list_file]
5999 if {[
file type $list_file] eq "link"} {
6002 dict lappend libraries $lib$list_file_ext $real_file
6003 Msg Debug "List file $list_file is a soft link, also adding the real file: $real_file"
6006 return [list $libraries $properties $filesets]
6015 proc Relative {base dst {quiet 0}} {
6016 if {![
string equal [
file pathtype $base] [
file pathtype $dst]]} {
6018 Msg CriticalWarning "Unable to compute relation for paths of different path types: [
file pathtype $base] vs. [
file pathtype $dst], ($base vs. $dst)"
6023 set base [
file normalize [
file join [
pwd] $base]]
6024 set dst [
file normalize [
file join [
pwd] $dst]]
6027 set base [
file split $base]
6028 set dst [
file split $dst]
6030 while {[
string equal [
lindex $dst 0] [
lindex $base 0]]} {
6031 set dst [
lrange $dst 1 end]
6032 set base [
lrange $base 1 end]
6033 if {![
llength $dst]} {break}
6036 set dstlen [
llength $dst]
6037 set baselen [
llength $base]
6039 if {($dstlen == 0) && ($baselen == 0)} {
6042 while {$baselen > 0} {
6043 set dst [
linsert $dst 0 ..]
6046 set dst [
eval [
linsert $dst 0 file join]]
6057 proc RelativeLocal {pathName filePath} {
6058 if {[
string first [
file normalize $pathName] [
file normalize $filePath]] != -1} {
6059 return [
Relative $pathName $filePath]
6070 proc RemoveDuplicates {mydict} {
6071 set new_dict [dict create]
6072 foreach key [dict keys $mydict] {
6073 set values [
DictGet $mydict $key]
6074 foreach value $values {
6075 set idxs [
lreverse [
lreplace [lsearch -exact -all $values $value] 0 0]]
6077 set values [
lreplace $values $idx $idx]
6080 dict set new_dict $key $values
6091 proc ResetRepoFiles {reset_file} {
6092 if {[
file exists $reset_file]} {
6093 Msg Info "Found $reset_file, opening it..."
6094 set fp [open $reset_file r]
6095 set wild_cards [lsearch -all -inline -not -regexp [
split [read $fp] "\n"] "^ *$"]
6097 Msg Info "Found the following files/wild cards to restore if modified: $wild_cards..."
6098 foreach w $wild_cards {
6100 if {[
llength $mod_files] > 0} {
6101 Msg Info "Found modified $w files: $mod_files, will restore them..."
6104 Msg Info "No modified $w files found."
6115 proc RestoreModifiedFiles {{repo_path "."} {pattern "."}} {
6118 set ret [
Git checkout $pattern]
6129 proc SearchHogProjects {dir} {
6130 set projects_list {}
6131 if {[
file exists $dir]} {
6132 if {[
file isdirectory $dir]} {
6133 foreach proj_dir [glob -nocomplain -types d $dir/*] {
6134 if {![regexp {^.*Top/+(.*)$} $proj_dir dummy proj_name]} {
6135 Msg Warning "Could not parse Top directory $dir"
6138 if {[
file exists "$proj_dir/hog.conf"]} {
6139 lappend projects_list $proj_name
6142 lappend projects_list $p
6147 Msg Error "Input $dir is not a directory!"
6150 Msg Error "Directory $dir doesn't exist!"
6152 return $projects_list
6161 proc SetGenericsSimulation {repo_path proj_dir target} {
6162 set top_dir "$repo_path/Top/$proj_dir"
6163 set simsets [get_filesets]
6164 if {$simsets != ""} {
6165 foreach simset $simsets {
6167 if {[get_property FILESET_TYPE $simset] != "SimulationSrcs"} {
6171 set merged_generics_dict [dict create]
6175 set simset_generics [
DictGet $simset_dict "generics"]
6176 set merged_generics_dict [
MergeDict $merged_generics_dict $simset_generics 0]
6178 set_property generic $generic_str [get_filesets $simset]
6179 Msg Debug "Setting generics $generic_str for simulator $target\
6180 and simulation file-set $simset..."
6192 proc SetTopProperty {top_module fileset} {
6193 Msg Info "Setting TOP property to $top_module module"
6196 set_property "top" $top_module [get_filesets $fileset]
6199 set_global_assignment -name TOP_LEVEL_ENTITY $top_module
6201 set_root -module $top_module
6203 prj_impl option top $top_module
6208 proc VIVADO_PATH_PROPERTIES {} {
6209 return {"\.*\.TCL\.PRE$" "^.*\.TCL\.POST$" "^RQS_FILES$" "^INCREMENTAL\_CHECKPOINT$" "NOC\_SOLUTION\_FILE"}
6213 proc VITIS_PATH_PROPERTIES {} {
6214 return {"^HW$" "^XPFM$" "^LINKER-SCRIPT$" "^LIBRARIES$" "^LIBRARY-SEARCH-PATH$"}
6224 proc WriteConf {file_name config {comment ""}} {
6225 if {[
catch {
package require inifile 0.2.3} ERROR]} {
6226 puts "$ERROR\n If you are running this script on tclsh, you can fix this by installing 'tcllib'"
6230 ::ini::commentchar "#"
6231 set f [::ini::open $file_name w]
6233 foreach sec [dict keys $config] {
6234 set section [dict get $config $sec]
6235 dict for {p v} $section {
6236 if {[string trim $v] == ""} {
6237 Msg Warning "Property $p has empty value. Skipping..."
6240 ::ini::set $f $sec $p $v
6245 if {![
string equal "$comment" ""]} {
6246 ::ini::comment $f [
lindex [::ini::sections $f] 0] "" $comment
6247 set hog_header "Generated by Hog on [
clock format [
clock seconds] -format "%Y-%m-%d %H:%M:%S"]"
6248 ::ini::comment $f [
lindex [::ini::sections $f] 0] "" $hog_header
6263 proc WriteGenerics {mode repo_path design date timee\
6264 commit version top_hash top_ver hog_hash hog_ver \
6265 cons_ver cons_hash libs vers hashes ext_names ext_hashes \
6266 user_ip_repos user_ip_vers user_ip_hashes flavour {xml_ver ""} {xml_hash ""}} {
6267 Msg Info "Passing parameters/generics to project's top module..."
6270 set generic_string [
concat \
6282 if {$xml_hash != "" && $xml_ver != ""} {
6283 lappend generic_string \
6288 foreach l $libs v $vers h $hashes {
6291 lappend generic_string "$ver" "$hash"
6294 foreach e $ext_names h $ext_hashes {
6296 lappend generic_string "$hash"
6299 foreach repo $user_ip_repos v $user_ip_vers h $user_ip_hashes {
6300 set repo_name [
file tail $repo]
6301 set ver "[
string toupper $repo_name]_VER=[
FormatGeneric $v]"
6302 set hash "[
string toupper $repo_name]_SHA=[
FormatGeneric $h]"
6303 lappend generic_string "$ver" "$hash"
6306 if {$flavour != -1} {
6307 lappend generic_string "FLAVOUR=$flavour"
6313 set generic_string "$prj_generics $generic_string"
6319 if {$mode == "create" || [
IsISE]} {
6322 if {[
file exists $top_file]} {
6325 Msg Debug "Found top level generics $generics in $top_file"
6327 set filtered_generic_string ""
6329 foreach generic_to_set [
split [
string trim $generic_string]] {
6330 set key [
lindex [
split $generic_to_set "="] 0]
6331 if {[dict exists $generics $key]} {
6332 Msg Debug "Hog generic $key found in $top_name"
6333 lappend filtered_generic_string "$generic_to_set"
6335 Msg Warning "Generic $key is passed by Hog but is NOT present in $top_name."
6341 set generic_string $filtered_generic_string
6346 set_property generic $generic_string [current_fileset]
6347 Msg Info "Setting parameters/generics..."
6348 Msg Debug "Detailed parameters/generics: $generic_string"
6353 set simulator [get_property target_simulator [current_project]]
6354 if {$mode == "create"} {
6361 Msg Info "Setting Synplify parameters/generics one by one..."
6362 foreach generic $generic_string {
6363 Msg Debug "Setting Synplify generic: $generic"
6364 set_option -hdl_param -set "$generic"
6367 Msg Info "Setting Diamond parameters/generics one by one..."
6368 prj_impl option -impl Implementation0 HDL_PARAM "$generic_string"
6370 if {[
catch {
set ws_apps [app list -dict]}]} {
set ws_apps ""}
6372 foreach app_name [dict keys $ws_apps] {
6373 set defined_symbols [app config -name $app_name -get define-compiler-symbols]
6374 foreach generic_to_set [
split [
string trim $generic_string]] {
6375 set key [
lindex [
split $generic_to_set "="] 0]
6376 set value [
lindex [
split $generic_to_set "="] 1]
6377 if {[
string match "32'h*" $value]} {
6378 set value [
string map {"32'h" "0x"} $value]
6381 foreach symbol [
split $defined_symbols ";"] {
6382 if {[
string match "$key=*" $symbol]} {
6383 Msg Debug "Generic $key found in $app_name, removing it..."
6384 app config -name $app_name -remove define-compiler-symbols "$symbol"
6388 Msg Info "Setting Vitis parameters/generics for app $app_name: $key=$value"
6389 app config -name $app_name define-compiler-symbols "$key=$value"
6401 proc WriteGenericsToBdIPs {mode repo_path proj generic_string} {
6402 Msg Debug "Parameters/generics passed to WriteGenericsToIP: $generic_string"
6404 set bd_ip_generics false
6406 if {[dict exists $properties "hog"]} {
6407 set propDict [dict get $properties "hog"]
6408 if {[dict exists $propDict "PASS_GENERICS_TO_BD_IPS"]} {
6409 set bd_ip_generics [dict get $propDict "PASS_GENERICS_TO_BD_IPS"]
6413 if {[
string compare [
string tolower $bd_ip_generics] "false"] == 0} {
6417 if {$mode == "synth"} {
6418 Msg Info "Attempting to apply generics pre-synthesis..."
6419 set PARENT_PRJ [get_property "PARENT.PROJECT_PATH" [current_project]]
6420 set workaround [open "$repo_path/Projects/$proj/.hog/presynth_workaround.tcl" "w"]
6421 puts $workaround "source \[lindex \$argv 0\];"
6422 puts $workaround "open_project \[lindex \$argv 1\];"
6423 puts $workaround "WriteGenericsToBdIPs \[lindex \$argv 2\] \[lindex \$argv 3\] \[lindex \$argv 4\] \[lindex \$argv 5\];"
6424 puts $workaround "close_project"
6428 exec vivado -mode batch -source $repo_path/Projects/$proj/.hog/presynth_workaround.tcl \
6429 -tclargs $repo_path/Hog/Tcl/hog.tcl $PARENT_PRJ \
6430 "childprocess" $repo_path $proj $generic_string
6433 Msg Error "Encountered an error while attempting workaround: $errMsg"
6435 file delete $repo_path/Projects/$proj/.hog/presynth_workaround.tcl
6437 Msg Info "Done applying generics pre-synthesis."
6441 Msg Info "Looking for IPs to add generics to..."
6442 set ips_generic_string ""
6443 foreach generic_to_set [
split [
string trim $generic_string]] {
6444 set key [
lindex [
split $generic_to_set "="] 0]
6445 set value [
lindex [
split $generic_to_set "="] 1]
6446 append ips_generic_string "CONFIG.$key $value "
6450 if {[
string compare [
string tolower $bd_ip_generics] "true"] == 0} {
6453 set ip_regex $bd_ip_generics
6456 set ip_list [get_ips -regex $ip_regex]
6457 Msg Debug "IPs found with regex \{$ip_regex\}: $ip_list"
6459 set regen_targets {}
6461 foreach {ip} $ip_list {
6462 set WARN_ABOUT_IP false
6463 set ip_props [list_property [get_ips $ip]]
6466 if {[lsearch -exact $ip_props "IS_BD_CONTEXT"] == -1} {
6470 if {[get_property "IS_BD_CONTEXT" [get_ips $ip]] eq "1"} {
6471 foreach {ip_prop} $ip_props {
6472 if {[dict exists $ips_generic_string $ip_prop]} {
6473 if {$WARN_ABOUT_IP == false} {
6474 lappend regen_targets [get_property SCOPE [get_ips $ip]]
6475 Msg Warning "The ip \{$ip\} contains generics that are set by Hog.\
6476 If this is IP is apart of a block design, the .bd file may contain stale, unused, values.\
6477 Hog will always apply the most up-to-date values to the IP during synthesis,\
6478 however these values may or may not be reflected in the .bd file."
6479 set WARN_ABOUT_IP true
6484 set xci_path [get_property IP_FILE [get_ips $ip]]
6486 if {[
string equal $generic_format "ERROR"]} {
6487 Msg Warning "Could not find format for generic $ip_prop in IP $ip. Skipping..."
6491 set value_to_set [dict get $ips_generic_string $ip_prop]
6492 switch -exact $generic_format {
6494 if {[
string match "32'h*" $value_to_set]} {
6495 scan [
string map {"32'h" ""} $value_to_set] "%x" value_to_set
6499 set value_to_set [
expr {$value_to_set ? "true" : "false"}]
6502 if {[
string match "32'h*" $value_to_set]} {
6503 binary scan [
binary format H* [
string map {"32'h" ""} $value_to_set]] d value_to_set
6507 if {[
string match "32'h*" $value_to_set]} {
6508 set value_to_set [
string map {"32'h" "0x"} $value_to_set]
6512 set value_to_set [
format "%s" $value_to_set]
6515 Msg Warning "Unknown generic format $generic_format for IP $ip. Will attempt to pass as string..."
6520 Msg Info "The IP \{$ip\} contains: $ip_prop ($generic_format), setting it to $value_to_set."
6521 if {[
catch {set_property -name $ip_prop -value $value_to_set -objects [get_ips $ip]} prop_error]} {
6522 Msg CriticalWarning "Failed to set property $ip_prop to $value_to_set for IP \{$ip\}: $prop_error"
6529 foreach {regen_target} [lsort -unique $regen_targets] {
6530 Msg Info "Regenerating target: $regen_target"
6531 if {[
catch {generate_target -force all [get_files $regen_target]} prop_error]} {
6532 Msg CriticalWarning "Failed to regen targets: $prop_error"
6540 proc GetGenericFormatFromXciXML {generic_name xml_file} {
6541 if {![
file exists $xml_file]} {
6542 Msg Error "Could not find XML file: $xml_file"
6546 set fp [open $xml_file r]
6547 set xci_data [read $fp]
6550 set paramType "string"
6551 set modelparam_regex [
format {^.*\y%s\y.*$} [
string map {"CONFIG." "MODELPARAM_VALUE."} $generic_name]]
6552 set format_regex {format="([^"]+)"}
6554 set line [
lindex [regexp -inline -line $modelparam_regex $xci_data] 0]
6555 Msg Debug "line: $line"
6557 if {[regexp $format_regex $line match format_value]} {
6558 Msg Debug "Extracted: $format_value format from xml"
6559 set paramType $format_value
6561 Msg Debug "No format found, using string"
6570 proc GetGenericFormatFromXci {generic_name xci_file} {
6571 if {![
file exists $xci_file]} {
6572 Msg Error "Could not find XCI file: $xci_file"
6576 set fp [open $xci_file r]
6577 set xci_data [read $fp]
6580 set paramType "string"
6581 if {[
string first "xilinx.com:schema:json_instance:1.0" $xci_data] == -1} {
6582 Msg Debug "XCI format is not JSON, trying XML..."
6583 set xml_file "[
file rootname $xci_file].xml"
6587 set generic_name [
string map {"CONFIG." ""} $generic_name]
6588 set ip_inst [
ParseJSON $xci_data "ip_inst"]
6589 set parameters [dict get $ip_inst parameters]
6590 set component_parameters [dict get $parameters component_parameters]
6591 if {[dict exists $component_parameters $generic_name]} {
6592 set generic_info [dict get $component_parameters $generic_name]
6593 if {[dict exists [
lindex $generic_info 0] format]} {
6594 set paramType [dict get [
lindex $generic_info 0] format]
6595 Msg Debug "Extracted: $paramType format from xci"
6598 Msg Debug "No format found, using string"
6611 proc WriteGitLabCIYAML {proj_name {ci_conf ""}} {
6612 if {[
catch {
package require yaml 0.3.3} YAMLPACKAGE]} {
6613 Msg CriticalWarning "Cannot find package YAML.\n Error message: $YAMLPACKAGE. \
6614 If you are running on tclsh, you can fix this by installing package \"tcllib\""
6619 if {$ci_conf != ""} {
6621 foreach sec [dict keys $ci_confs] {
6622 if {[
string first : $sec] == -1} {
6623 lappend job_list $sec
6627 set job_list {"generate_project" "simulate_project"}
6631 set out_yaml [huddle create]
6632 foreach job $job_list {
6634 set huddle_tags [huddle list]
6636 set sec_dict [dict create]
6638 if {$ci_confs != ""} {
6639 foreach var [dict keys [dict get $ci_confs $job]] {
6640 if {$var == "tags"} {
6641 set tag_section "tags"
6642 set tags [dict get [dict get $ci_confs $job] $var]
6643 set tags [
split $tags ","]
6645 set tag_list [huddle list $tag]
6646 set huddle_tags [huddle combine $huddle_tags $tag_list]
6649 dict set sec_dict $var [dict get [dict get $ci_confs $job] $var]
6655 set huddle_variables [huddle create "PROJECT_NAME" $proj_name "extends" ".vars"]
6656 if {[dict exists $ci_confs "$job:variables"]} {
6657 set var_dict [dict get $ci_confs $job:variables]
6658 foreach var [dict keys $var_dict] {
6660 set value [dict get $var_dict "$var"]
6661 set var_inner [huddle create "$var" "$value"]
6662 set huddle_variables [huddle combine $huddle_variables $var_inner]
6667 set middle [huddle create "extends" ".$job" "variables" $huddle_variables]
6668 foreach sec [dict keys $sec_dict] {
6669 set value [dict get $sec_dict $sec]
6670 set var_inner [huddle create "$sec" "$value"]
6671 set middle [huddle combine $middle $var_inner]
6673 if {$tag_section != ""} {
6674 set middle2 [huddle create "$tag_section" $huddle_tags]
6675 set middle [huddle combine $middle $middle2]
6678 set outer [huddle create "$job:$proj_name" $middle]
6679 set out_yaml [huddle combine $out_yaml $outer]
6682 return [
string trimleft [yaml::huddle2yaml $out_yaml] "-"]
6692 proc WriteListFiles {libs props list_path repo_path {ext_path ""}} {
6694 foreach lib [dict keys $libs] {
6695 if {[
llength [
DictGet $libs $lib]] > 0} {
6696 set list_file_name $list_path$lib
6697 set list_file [open $list_file_name w]
6698 Msg Info "Writing $list_file_name..."
6699 puts $list_file "#Generated by Hog on [
clock format [
clock seconds] -format "%Y-%m-%d %H:%M:%S"]"
6700 foreach file [
DictGet $libs $lib] {
6702 set prop [
DictGet $props $file]
6706 puts $list_file "$file_path $prop"
6709 set ext_list_file [open "[
file rootname $list_file].ext" a]
6710 puts $ext_list_file "$file_path $prop"
6711 close $ext_list_file
6714 Msg Warning "The path of file $file is not relative to your repository. Please check!"
6730 proc WriteSimListFile {simset libs props simsets list_path repo_path {force 0}} {
6732 set list_file_name $list_path/${simset}.sim
6733 if {$force == 0 && [
file exists $list_file_name]} {
6734 Msg Info "List file $list_file_name already exists, skipping..."
6738 set list_file [open $list_file_name a+]
6741 puts $list_file "\[files\]"
6742 Msg Info "Writing $list_file_name..."
6743 foreach lib [
DictGet $simsets $simset] {
6744 foreach file [
DictGet $libs $lib] {
6746 set prop [
DictGet $props $file]
6750 set lib_name [
file rootname $lib]
6751 if {$lib_name != $simset && [
file extension $file] == ".vhd" && [
file extension $file] == ""} {
6752 lappend prop "lib=$lib_name"
6754 puts $list_file "$file_path $prop"
6757 Msg Warning "The path of file $file is not relative to your repository. Please check!"
6769 proc WriteToFile {File msg} {
6770 set f [open $File a+]
6781 proc WriteUtilizationSummary {input output project_name run} {
6782 set f [open $input "r"]
6783 set o [open $output "a"]
6784 puts $o "## $project_name $run Utilization report\n\n"
6785 struct::matrix util_m
6786 util_m add columns 14
6789 util_m add row "| **Site Type** | **Used** | **Fixed** | **Prohibited** | **Available** | **Util%** |"
6790 util_m add row "| --- | --- | --- | --- | --- | --- |"
6792 util_m add row "| **Site Type** | **Used** | **Fixed** | **Available** | **Util%** |"
6793 util_m add row "| --- | --- | --- | --- | --- |"
6803 while {[
gets $f line] >= 0} {
6804 if {([
string first "| CLB LUTs" $line] >= 0 || [
string first "| Slice LUTs" $line] >= 0) && $luts == 0} {
6805 util_m add row $line
6808 if {([
string first "| CLB Registers" $line] >= 0 || [
string first "| Slice Registers" $line] >= 0) && $regs == 0} {
6809 util_m add row $line
6812 if {[
string first "| Block RAM Tile" $line] >= 0 && $bram == 0} {
6813 util_m add row $line
6816 if {[
string first "URAM " $line] >= 0 && $uram == 0} {
6817 util_m add row $line
6820 if {[
string first "DSPs" $line] >= 0 && $dsps == 0} {
6821 util_m add row $line
6824 if {[
string first "Bonded IOB" $line] >= 0 && $ios == 0} {
6825 util_m add row $line
6832 puts $o [util_m format 2string]
6838 Msg Error "Found Git version older than 2.7.2. Hog will not work as expected, exiting now."