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 {$valueNumBits != "" && $valueHexFlag != "" && $valueHex != ""} {
1800 set prj_generics "$prj_generics $theKey=$valueHexFull"
1801 } elseif {$valueIntFull != "" && $ValueInt != ""} {
1802 set prj_generics "$prj_generics $theKey=$ValueInt"
1803 } elseif {$valueStrFull != "" && $ValueStr != ""} {
1804 set prj_generics "$prj_generics $theKey=\"$ValueStr\""
1806 set prj_generics "$prj_generics $theKey=\"$theValue\""
1808 } elseif {[lsearch -exact [GetSimulators] [string tolower $target]] >= 0} {
1809 if {$valueNumBits != "" && $valueHexFlag != "" && $valueHex != ""} {
1811 scan $valueNumBits %d numBits
1813 scan $valueHex %x numHex
1814 binary scan [binary format "I" $numHex] "B*" binval
1815 set numBits [expr {$numBits - 1}]
1816 set numBin [string range $binval end-$numBits end]
1817 set prj_generics "$prj_generics $theKey=\"$numBin\""
1818 } elseif {$valueIntFull != "" && $ValueInt != ""} {
1819 set prj_generics "$prj_generics $theKey=$ValueInt"
1820 } elseif {$valueStrFull != "" && $ValueStr != ""} {
1821 set prj_generics "$prj_generics {$theKey=\"$ValueStr\"}"
1823 set prj_generics "$prj_generics {$theKey=\"$theValue\"}"
1826 Msg Warning "Target : $target not implemented"
1829 return $prj_generics
1837 proc GetConfFiles {proj_dir} {
1838 Msg Debug "GetConfFiles called with proj_dir=$proj_dir"
1839 if {![
file isdirectory $proj_dir]} {
1840 Msg Error "$proj_dir is supposed to be the top project directory"
1843 set conf_file [
file normalize $proj_dir/hog.conf]
1844 set sim_file [
file normalize $proj_dir/sim.conf]
1845 set pre_tcl [
file normalize $proj_dir/pre-creation.tcl]
1846 set post_tcl [
file normalize $proj_dir/post-creation.tcl]
1848 return [list $conf_file $sim_file $pre_tcl $post_tcl]
1857 proc GetCustomCommands {parameters {directory .}} {
1858 set commands_dict [dict create]
1859 set commands_files [glob -nocomplain $directory/*.tcl]
1861 if {[
llength $commands_files] == 0} {
1865 foreach file $commands_files {
1870 if {$custom_cmd eq ""} {
1875 set custom_cmd_name [dict get $custom_cmd NAME]
1877 Msg Debug "Loaded custom command '$custom_cmd_name' from $file"
1880 if {[dict exists $commands_dict $custom_cmd_name]} {
1881 Msg Error "Custom command '$custom_cmd_name' in $file already defined as: \[dict get $commands_dict $custom_cmd_name\]. Skipping."
1887 set custom_cmd_name [
string toupper $custom_cmd_name]
1888 dict set commands_dict $custom_cmd_name $custom_cmd
1891 return $commands_dict
1894 proc SanitizeCustomCommand {cmdDict file parameters} {
1897 foreach k [dict keys $cmdDict] {
1898 set K [
string toupper $k]
1899 dict set normalized $K [dict get $cmdDict $k]
1902 set cmdDict $normalized
1903 if {![dict exists $cmdDict NAME]} {
1904 Msg Error "Custom command in $file missing required key NAME. Skipping."
1907 if {![dict exists $cmdDict SCRIPT]} {
1908 Msg Error "Custom command '$[dict get $cmdDict NAME]' in $file missing SCRIPT. Skipping."
1913 set allowed {NAME DESCRIPTION OPTIONS CUSTOM_OPTIONS SCRIPT IDE NO_EXIT}
1914 foreach k [dict keys $cmdDict] {
1915 if {[lsearch -exact $allowed $k] < 0} {
1916 Msg Warning "Custom command '[dict get $cmdDict NAME]' in $file: unknown key '$k'. Allowed: $allowed. Skipping."
1921 set name [
string trim [dict get $cmdDict NAME]]
1923 Msg Error "Custom command in $file has empty NAME. Skipping."
1927 if {![regexp {^[a-zA-Z][a-zA-Z0-9_]+$} $name]} {
1928 Msg Error "Custom command NAME '$name' (file $file) contains invalid characters."
1932 if {![dict exists $cmdDict DESCRIPTION]} {
1933 dict set cmdDict DESCRIPTION "No description provided."
1937 set hog_parameters {}
1938 foreach p $parameters {
1939 lappend hog_parameters [
lindex $p 0]
1944 if {[dict exists $cmdDict OPTIONS]} {
1945 set raw_opts [dict get $cmdDict OPTIONS]
1946 if {![
llength $raw_opts]} {
1950 foreach item $raw_opts {
1952 foreach p $parameters {
1953 set hog_parameter [
lindex $p 0]
1954 if { $item eq $hog_parameter } {
1955 lappend hog_options $p
1961 Msg Warning "Custom command '$name' in $file: option '$item' not found in Hog parameters. Skipping."
1964 dict set cmdDict OPTIONS $hog_options
1966 dict set cmdDict CUSTOM_OPTIONS {}
1973 if {[dict exists $cmdDict CUSTOM_OPTIONS]} {
1974 set raw_opts [dict get $cmdDict CUSTOM_OPTIONS]
1975 if {![
llength $raw_opts]} {
1978 foreach item $raw_opts {
1980 if {[
llength $item] != 2 && [
llength $item] != 3} {
1981 Msg Error "Bad custom option: \[$item\]. Custom command '$name' in $file: \
1982 each CUSTOM_OPTIONS entry must be {option \"help\"} for flags \
1983 and {option \"default_value\" \"help\"} for options with arguments. Skipping command."
1987 if {[
llength $item] == 2} {
1988 lassign $item opt help
1991 lassign $item opt def help
1994 if { [
IsInList $opt $hog_parameters] == 1 } {
1995 Msg Warning "Custom command '$name' in $file: option '$opt' already defined in Hog parameters. Skipping."
2001 if {![regexp {^[a-zA-Z][a-zA-Z0-9_]*(\.arg)?$} $opt]} {
2002 Msg Error "Custom command '$name' in $file: invalid option name '$opt'."
2007 Msg Warning "Custom command '$name' option '$opt' has empty help text."
2011 dict set cmdDict CUSTOM_OPTIONS {}
2015 if {[dict exists $cmdDict NO_EXIT]} {
2016 set no_exit [dict get $cmdDict NO_EXIT]
2017 set no_exit [
string tolower [
string trim $no_exit]]
2019 if {$no_exit eq "1" || $no_exit eq "true"} {
2025 dict set cmdDict NO_EXIT $no_exit
2027 dict set cmdDict NO_EXIT 0
2033 proc LoadCustomCommandFile {file parameters} {
2035 set dir [
file dirname $file]
2037 unset -nocomplain ::hog_command
2038 set rc [
catch {source $file} err]
2041 Msg Error "Error sourcing custom command file $file: $err"
2044 if {![
info exists ::hog_command]} {
2045 Msg Warning "File $file did not define ::hog_command. Skipping."
2048 set cmdDict $::hog_command
2050 if {[
catch {dict size $cmdDict}]} {
2051 Msg Error "In $file ::hog_command is not a valid dict. Skipping."
2061 proc GetDateAndTime {commit} {
2062 set clock_seconds [
clock seconds]
2065 set date [
Git "log -1 --format=%cd --date=format:%d%m%Y $commit"]
2066 set timee [
Git "log -1 --format=%cd --date=format:00%H%M%S $commit"]
2068 Msg Warning "Found Git version older than 2.9.3. Using current date and time instead of commit time."
2069 set date [
clock format $clock_seconds -format {%d%m%Y}]
2070 set timee [
clock format $clock_seconds -format {00%H%M%S}]
2072 return [list $date $timee]
2084 proc GetFile {file fileset} {
2087 set Files [get_files -all $file -of_object [get_filesets $fileset]]
2088 set f [
lindex $Files 0]
2096 puts "***DEBUG Hog:GetFile $file"
2105 proc GetFileGenerics {filename {entity ""}} {
2107 if {[
string equal $file_type "VERILOG_FILE"] || [
string equal $file_type "SYSTEMVERILOG_FILE"]} {
2109 }
elseif {[
string equal $file_type "VHDL_FILE"]} {
2112 Msg CriticalWarning "Could not determine extension of top level file."
2121 proc GetGenericsFromConf {proj_dir} {
2122 set generics_dict [dict create]
2123 set top_dir "Top/$proj_dir"
2124 set conf_file "$top_dir/hog.conf"
2126 Msg Debug "GetGenericsFromConf called with proj_dir=$proj_dir, top_dir=$top_dir"
2128 if {[
file exists $conf_file]} {
2130 if {[dict exists $properties generics]} {
2131 set generics_dict [dict get $properties generics]
2134 Msg Warning "File $conf_file not found."
2136 return $generics_dict
2149 proc GetSimSets {project_name repo_path {simsets ""} {ghdl 0} {no_conf 0}} {
2150 set simsets_dict [dict create]
2151 set list_dir "$repo_path/Top/$project_name/list"
2153 if {$simsets != ""} {
2154 foreach s $simsets {
2155 set list_file "$list_dir/$s.sim"
2156 if {[
file exists $list_file]} {
2157 lappend list_files $list_file
2158 }
elseif {$s != "sim_1"} {
2159 Msg CriticalWarning "Simulation set list file $list_file not found."
2164 set list_files [glob -nocomplain -directory $list_dir "*.sim"]
2168 set proj_dir [
file normalize $repo_path/Top/$project_name]
2169 set sim_file [
file normalize $proj_dir/sim.conf]
2171 foreach list_file $list_files {
2172 set file_name [
file tail $list_file]
2173 set simset_name [
file rootname $file_name]
2174 set fp [open $list_file r]
2175 set file_data [read $fp]
2177 set data [
split $file_data "\n"]
2179 set firstline [
lindex $data 0]
2181 if {[regexp {^ *\# *Simulator} $firstline]} {
2182 set simulator_prop [regexp -all -inline {\S+} $firstline]
2183 set simulator [
string tolower [
lindex $simulator_prop end]]
2185 Msg Warning "Simulator not set in $simset_name.sim. \
2186 The first line of $simset_name.sim should be #Simulator <SIMULATOR_NAME>,\
2187 where <SIMULATOR_NAME> can be xsim, questa, modelsim, ghdl, riviera, activehdl,\
2188 ies, or vcs, e.g. #Simulator questa.\
2189 Setting simulator by default to xsim."
2190 set simulator "xsim"
2192 if {$simulator eq "skip_simulation"} {
2193 Msg Info "Skipping simulation for $simset_name"
2196 if {($ghdl == 1 && $simulator != "ghdl") || ($ghdl == 0 && $simulator == "ghdl")} {
2200 set SIM_PROPERTIES ""
2201 if {[
file exists $sim_file] && $no_conf == 0} {
2202 set SIM_PROPERTIES [
ReadConf $sim_file]
2205 set global_sim_props [dict create]
2206 dict set global_sim_props "properties" [
DictGet $SIM_PROPERTIES "sim"]
2207 dict set global_sim_props "generics" [
DictGet $SIM_PROPERTIES "generics"]
2208 dict set global_sim_props "hog" [
DictGet $SIM_PROPERTIES "hog"]
2211 set sim_dict [dict create]
2212 dict set sim_dict "simulator" $simulator
2213 if {[dict exists $SIM_PROPERTIES $simset_name]} {
2214 dict set sim_dict "properties" [
DictGet $SIM_PROPERTIES $simset_name]
2215 dict set sim_dict "generics" [
DictGet $SIM_PROPERTIES "$simset_name:generics"]
2216 dict set sim_dict "hog" [
DictGet $SIM_PROPERTIES "$simset_name:hog"]
2217 }
elseif {$no_conf == 0} {
2219 set conf_dict [
ReadConf $list_file]
2220 set sim_dict [
MergeDict $sim_dict $conf_dict 0]
2222 set sim_dict [
MergeDict $sim_dict $global_sim_props 0]
2223 dict set simsets_dict $simset_name $sim_dict
2225 return $simsets_dict
2233 proc GetSimsetGenericsFromConf {proj_dir} {
2234 set simsets_generics_dict [dict create]
2235 set top_dir "Top/$proj_dir"
2236 set conf_file "$top_dir/sim.conf"
2239 if {[
file exists $conf_file]} {
2242 set simsets_generics_dict [dict filter $properties key *:generics]
2244 Msg Warning "File $conf_file not found."
2246 return $simsets_generics_dict
2257 proc GetGroupName {proj_dir repo_dir} {
2258 if {[regexp {^(.*)/(Top|Projects)/+(.*?)/*$} $proj_dir dummy possible_repo_dir proj_or_top dir]} {
2260 if {[
file normalize $repo_dir] eq [
file normalize $possible_repo_dir]} {
2261 set group [
file dir $dir]
2262 if {$group == "."} {
2267 Msg Warning "Project directory $proj_dir seems to be in $possible_repo_dir which is not a the main Git repository $repo_dir."
2270 Msg Warning "Could not parse project directory $proj_dir"
2283 proc GetHogDescribe {sha {repo_path .}} {
2286 set new_sha "[
string toupper [
GetSHA]]"
2289 set new_sha [
string toupper $sha]
2309 proc GetHogFiles {args} {
2312 if {[
catch {
package require cmdline} ERROR]} {
2313 puts "$ERROR\n If you are running this script on tclsh, you can fix this by installing 'tcllib'"
2320 {list_files.arg "" "The file wildcard, if not specified all Hog list files will be looked for."}
2321 {sha_mode "Forwarded to ReadListFile, see there for info."}
2322 {ext_path.arg "" "Path for the external libraries forwarded to ReadListFile."}
2323 {print_log "Forwarded to ReadListFile, see there for info."}
2325 set usage "USAGE: GetHogFiles \[options\] <list path> <repository path>"
2326 if {[
catch {
array set options [
cmdline::getoptions args $parameters $usage]}] || [
llength $args] != 2} {
2330 set list_path [
lindex $args 0]
2331 set repo_path [
lindex $args 1]
2333 set list_files $options(list_files)
2334 set sha_mode $options(sha_mode)
2335 set ext_path $options(ext_path)
2336 set print_log $options(print_log)
2338 if {$sha_mode == 1} {
2339 set sha_mode_opt "-sha_mode"
2344 if {$print_log == 1} {
2345 set print_log_opt "-print_log"
2347 set print_log_opt ""
2351 if {$list_files == ""} {
2352 set list_files {.src,.con,.sim,.ext}
2354 set libraries [dict create]
2355 set properties [dict create]
2356 set list_files [glob -nocomplain -directory $list_path "*{$list_files}"]
2357 set filesets [dict create]
2359 foreach f $list_files {
2360 set ext [
file extension $f]
2361 if {$ext == ".ext"} {
2362 lassign [
ReadListFile {*}"$sha_mode_opt $print_log_opt $f $ext_path"] l p fs
2364 lassign [
ReadListFile {*}"$sha_mode_opt $print_log_opt $f $repo_path"] l p fs
2367 set properties [
MergeDict $p $properties]
2368 Msg Debug "list file $f, filesets: $fs"
2370 Msg Debug "Merged filesets $filesets"
2372 return [list $libraries $properties $filesets]
2379 proc GetIDECommand {proj_conf {custom_ver ""}} {
2380 if {$custom_ver ne ""} {
2381 set ide_name_and_ver [
string tolower "$custom_ver"]
2382 }
elseif {[
file exists $proj_conf]} {
2383 set ide_name_and_ver [
string tolower [
GetIDEFromConf $proj_conf]]
2385 Msg Error "Configuration file $proj_conf not found."
2388 set ide_name [
lindex [regexp -all -inline {\S+} $ide_name_and_ver] 0]
2390 if {$ide_name eq "vivado" || $ide_name eq "vivado_vitis_classic"} {
2391 set command "vivado"
2393 set before_tcl_script " -nojournal -nolog -mode batch -notrace -source "
2394 set after_tcl_script " -tclargs "
2396 }
elseif {$ide_name eq "planahead"} {
2397 set command "planAhead"
2399 set before_tcl_script " -nojournal -nolog -mode batch -notrace -source "
2400 set after_tcl_script " -tclargs "
2402 }
elseif {$ide_name eq "quartus"} {
2403 set command "quartus_sh"
2405 set before_tcl_script " -t "
2406 set after_tcl_script " "
2408 }
elseif {$ide_name eq "libero"} {
2411 set command "libero"
2412 set before_tcl_script "SCRIPT:"
2413 set after_tcl_script " SCRIPT_ARGS:\""
2415 }
elseif {$ide_name eq "diamond"} {
2416 set command "diamondc"
2417 set before_tcl_script " "
2418 set after_tcl_script " "
2420 }
elseif {$ide_name eq "vitis_classic"} {
2423 set before_tcl_script ""
2424 set after_tcl_script " "
2426 }
elseif {$ide_name eq "ghdl"} {
2428 set before_tcl_script " "
2429 set after_tcl_script " "
2432 Msg Error "IDE: $ide_name not known."
2435 return [list $command $before_tcl_script $after_tcl_script $end_marker]
2441 proc GetIDEFromConf {conf_file} {
2442 set f [open $conf_file "r"]
2445 if {[regexp -all {^\# *(\w*) *(vitis_classic)? *(\d+\.\d+(?:\.\d+)?(?:\.\d+)?)?(_.*)? *$} $line dummy ide vitisflag version patch]} {
2446 if {[
info exists vitisflag] && $vitisflag != ""} {
2447 set ide "${ide}_${vitisflag}"
2450 if {[
info exists version] && $version != ""} {
2456 set ret [list $ide $ver]
2458 Msg CriticalWarning "The first line of hog.conf should be \#<IDE name> <version>, \
2459 where <IDE name>. is quartus, vivado, planahead, libero, diamond or ghdl, \
2460 and <version> the tool version, e.g. \#vivado 2020.2. Will assume vivado."
2461 set ret [list "vivado" "0.0.0"]
2468 proc GetIDEName {} {
2470 return "ISE/PlanAhead"
2488 proc GetIDEVersion {} {
2491 regexp {\d+\.\d+(\.\d+)?} [version -short] ver
2496 regexp {[\.0-9]+} $quartus(version) ver
2499 set ver [get_libero_version]
2501 regexp {\d+\.\d+(\.\d+)?} [sys_install version] ver
2503 regexp {\d+\.\d+(\.\d+)?} [version] ver
2515 proc GetLinkedFile {link_file} {
2516 if {[
file type $link_file] eq "link"} {
2517 if {[
OS] == "windows"} {
2519 lassign [
ExecuteRet realpath $link_file] ret msg
2520 lassign [
ExecuteRet cygpath -m $msg] ret2 msg2
2521 if {$ret == 0 && $ret2 == 0} {
2523 Msg Debug "Found link file $link_file on Windows, the linked file is: $real_file"
2525 Msg CriticalWarning "[
file normalize $link_file] is a soft link. \
2526 Soft link are not supported on Windows and readlink.exe or cygpath.exe did not work: readlink=$ret: $msg, cygpath=$ret2: $msg2."
2527 set real_file $link_file
2531 set linked_file [
file link $link_file]
2532 set real_file [
file normalize [
file dirname $link_file]/$linked_file]
2535 if {![
file exists $real_file]} {
2536 Msg Warning "$link_file is a broken link, because the linked file: $real_file does not exist."
2539 Msg Warning "$link file is not a soft link"
2540 set real_file $link_file
2553 proc GetMaxThreads {proj_dir} {
2555 if {[
file exists $proj_dir/hog.conf]} {
2557 if {[dict exists $properties parameters]} {
2558 set propDict [dict get $properties parameters]
2559 if {[dict exists $propDict MAX_THREADS]} {
2560 set maxThreads [dict get $propDict MAX_THREADS]
2564 Msg Warning "File $proj_dir/hog.conf not found. Max threads will be set to default value 1"
2577 proc GetModifiedFiles {{repo_path "."} {pattern "."}} {
2580 set ret [
Git "ls-files --modified $pattern"]
2589 proc GetOptions {argv parameters} {
2592 set param_list [list]
2593 set option_list [list]
2595 foreach p $parameters {
2596 lappend param_list [
lindex $p 0]
2600 while {$index < [
llength $argv]} {
2601 set arg [
lindex $argv $index]
2602 if {[
string first - $arg] == 0} {
2603 set option [
string trimleft $arg "-"]
2605 lappend option_list $arg
2606 if {[lsearch -regex $param_list "$option\[.arg]?"] >= 0 } {
2607 if {[lsearch -regex $param_list "$option\[.arg]"] >= 0 } {
2608 lappend option_list [
lindex $argv $index]
2613 lappend arg_list $arg
2617 Msg Debug "Argv: $argv"
2618 Msg Debug "Options: $option_list"
2619 Msg Debug "Arguments: $arg_list"
2620 return [list $option_list $arg_list]
2638 proc GetProjectFiles {{project_file ""}} {
2639 set libraries [dict create]
2640 set simlibraries [dict create]
2641 set constraints [dict create]
2642 set properties [dict create]
2643 set consets [dict create]
2644 set srcsets [dict create]
2645 set simsets [dict create]
2648 set all_filesets [get_filesets]
2649 set simulator [get_property target_simulator [current_project]]
2650 set top [get_property "top" [current_fileset]]
2652 dict lappend properties $topfile "top=$top"
2654 foreach fs $all_filesets {
2655 if {$fs == "utils_1"} {
2660 set all_files [get_files -quiet -of_objects [get_filesets $fs]]
2661 set fs_type [get_property FILESET_TYPE [get_filesets $fs]]
2663 if {$fs_type == "BlockSrcs"} {
2665 set dict_fs "sources_1"
2669 foreach f $all_files {
2676 if {[
lindex [get_property IS_GENERATED [
GetFile $f $fs]] 0] != 0} {
2681 if {[get_property FILE_TYPE [
GetFile $f $fs]] == "Configuration Files"} {
2687 if {[get_property CORE_CONTAINER [
GetFile $f $fs]] != ""} {
2688 if {[
file extension $f] == ".xcix"} {
2689 set f [get_property CORE_CONTAINER [
GetFile $f $fs]]
2697 if {[get_property SCOPED_TO_REF [
GetFile $f $fs]] != ""} {
2698 dict lappend properties $f "scoped_to_ref=[get_property SCOPED_TO_REF [
GetFile $f $fs]]"
2703 if {[get_property SCOPED_TO_CELLS [
GetFile $f $fs]] != ""} {
2704 dict lappend properties $f "scoped_to_cells=[get_property SCOPED_TO_CELLS [
GetFile $f $fs]]"
2708 if {[
IsInList "PARENT_COMPOSITE_FILE" [list_property [
GetFile $f $fs]]]} {
2713 if {[
file tail $f] == "nocattrs.dat"} {
2718 if {[
file extension $f] != ".coe"} {
2719 set f [
file normalize $f]
2722 set type [get_property FILE_TYPE [
GetFile $f $fs]]
2724 set lib [get_property -quiet LIBRARY [
GetFile $f $fs]]
2727 Msg Debug "File $f Extension [
file extension $f] Type [
lindex $type 0]"
2729 if {[
string equal [
lindex $type 0] "VHDL"] && [
llength $type] == 1} {
2731 }
elseif {[
string equal [
lindex $type 0] "Block"] && [
string equal [
lindex $type 1] "Designs"]} {
2734 }
elseif {[
string equal $type "SystemVerilog"] && [
file extension $f] != ".sv"} {
2735 set prop "SystemVerilog"
2736 }
elseif {[
string equal [
lindex $type 0] "XDC"] && [
file extension $f] != ".xdc"} {
2738 }
elseif {[
string equal $type "Verilog Header"] && [
file extension $f] != ".vh" && [
file extension $f] != ".svh"} {
2739 set prop "verilog_header"
2740 }
elseif {[
string equal $type "Verilog Template"] && [
file extension $f] == ".v" && [
file extension $f] != ".sv"} {
2741 set prop "verilog_template"
2743 set type [
lindex $type 0]
2747 if {![
string equal $prop ""]} {
2748 dict lappend properties $f $prop
2751 if {[
string equal $fs_type "SimulationSrcs"]} {
2753 if {[
string equal $type "VHDL"]} {
2754 set library "${lib}.sim"
2756 set library "others.sim"
2760 dict lappend simsets $dict_fs $library
2763 dict lappend simlibraries $library $f
2764 }
elseif {[
string equal $type "VHDL"]} {
2767 dict lappend srcsets $dict_fs "${lib}.src"
2769 dict lappend libraries "${lib}.src" $f
2770 }
elseif {[
string first "IP" $type] != -1} {
2773 dict lappend srcsets $dict_fs "ips.src"
2775 dict lappend libraries "ips.src" $f
2776 Msg Debug "Appending $f to ips.src"
2777 }
elseif {[
string equal $fs_type "Constrs"]} {
2780 dict lappend consets $dict_fs "sources.con"
2782 dict lappend constraints "sources.con" $f
2786 dict lappend srcsets $dict_fs "others.src"
2788 dict lappend libraries "others.src" $f
2789 Msg Debug "Appending $f to others.src"
2792 if {[
lindex [get_property -quiet used_in_synthesis [
GetFile $f $fs]] 0] == 0} {
2793 dict lappend properties $f "nosynth"
2795 if {[
lindex [get_property -quiet used_in_implementation [
GetFile $f $fs]] 0] == 0} {
2796 dict lappend properties $f "noimpl"
2798 if {[
lindex [get_property -quiet used_in_simulation [
GetFile $f $fs]] 0] == 0} {
2799 dict lappend properties $f "nosim"
2801 if {[
lindex [get_property -quiet IS_MANAGED [
GetFile $f $fs]] 0] == 0 && [
file extension $f] != ".xcix"} {
2802 dict lappend properties $f "locked"
2808 dict lappend properties "Simulator" [get_property target_simulator [current_project]]
2811 set file [open $project_file r]
2812 set in_file_manager 0
2814 while {[
gets $file line] >= 0} {
2816 if {[regexp {^KEY ActiveRoot \"([^\"]+)\"} $line -> value]} {
2817 set top [
string range $value 0 [
expr {[string first "::" $value] - 1}]]
2821 if {[regexp {^LIST FileManager} $line]} {
2822 set in_file_manager 1
2827 if {$in_file_manager && [regexp {^ENDLIST} $line]} {
2832 if {$in_file_manager && [regexp {^VALUE \"([^\"]+)} $line -> value]} {
2835 lassign [
split $value ,] file_path file_type
2838 set library "others"
2839 while {[
gets $file line] >= 0} {
2840 if {$line == "ENDFILE"} {
2843 regexp {^LIBRARY=\"([^\"]+)} $line -> library
2844 regexp {^PARENT=\"([^\"]+)} $line -> parent_file
2846 Msg Debug "Found file ${file_path} in project.."
2847 if {$parent_file == ""} {
2848 if {$file_type == "hdl"} {
2850 if {[
IsInList "${library}.src" [
DictGet $srcsets "sources_1"]] == 0} {
2851 dict lappend srcsets "sources_1" "${library}.src"
2853 dict lappend libraries "${library}.src" $file_path
2857 if {[
GetModuleName $file_path] == [
string tolower $top] && $top != ""} {
2858 Msg Debug "Found top module $top in $file_path"
2859 dict lappend properties $file_path "top=$top"
2861 }
elseif {$file_type == "tb_hdl"} {
2863 dict lappend simsets "sim_1" "${library}.sim"
2865 dict lappend simlibraries "${library}.sim" $file_path
2866 }
elseif {$file_type == "io_pdc" || $file_type == "sdc"} {
2868 dict lappend consets "constrs_1" "sources.con"
2870 dict lappend constraints "sources.con" $file_path
2877 set fileData [read [open $project_file]]
2879 set project_path [
file dirname $project_file]
2882 regsub {<\?xml.*\?>} $fileData "" fileData
2885 regexp {<Implementation.*?>(.*)</Implementation>} $fileData -> implementationContent
2889 set sourceRegex {<Source name="([^"]*?)" type="([^"]*?)" type_short="([^"]*?)".*?>(.*?)</Source>}
2891 set optionsRegex {<Options(.*?)\/>}
2892 regexp $optionsRegex $implementationContent -> prj_options
2893 foreach option $prj_options {
2894 if {[regexp {^top=\"([^\"]+)\"} $option match result]} {
2899 while {[regexp $sourceRegex $implementationContent match name type type_short optionsContent]} {
2900 Msg Debug "Found file ${name} in project..."
2901 set file_path [
file normalize $project_path/$name]
2903 set optionsRegex {<Options(.*?)\/>}
2904 regexp $optionsRegex $optionsContent -> options
2905 set library "others"
2907 foreach option $options {
2908 if {[
string first "System Verilog" $option]} {
2911 if {[regexp {^lib=\"([^\"]+)\"} $option match1 result]} {
2916 if {[regexp {syn_sim="([^"]*?)"} $match match_sim simonly]} {
2921 if {$type_short == "VHDL" || $type_short == "Verilog" || $type_short == "IPX"} {
2922 if {$ext == ".src"} {
2923 if {[
IsInList "${library}${ext}" [
DictGet $srcsets "sources_1"]] == 0} {
2924 dict lappend srcsets "sources_1" "${library}${ext}"
2926 dict lappend libraries "${library}${ext}" $file_path
2927 }
elseif {$ext == ".sim"} {
2929 dict lappend simsets "sim_1" "${library}.sim"
2931 dict lappend simlibraries "${library}.sim" $file_path
2937 Msg Debug "Found top module $top in $file_path"
2938 dict lappend properties $file_path "top=$top"
2940 }
elseif {$type_short == "SDC"} {
2942 dict lappend consets "constrs_1" "sources.con"
2944 dict lappend constraints "sources.con" $file_path
2948 regsub -- $match $implementationContent "" implementationContent
2951 return [list $libraries $properties $simlibraries $constraints $srcsets $simsets $consets]
2958 proc GetProjectFlavour {proj_name} {
2960 set flavour [
string map {. ""} [
file extension $proj_name]]
2961 if {$flavour != ""} {
2962 if {[
string is integer $flavour]} {
2963 Msg Info "Project $proj_name has flavour = $flavour, the generic variable FLAVOUR will be set to $flavour"
2965 Msg Warning "Project name has a unexpected non numeric extension, flavour will be set to -1"
2982 proc GetProjectVersion {proj_dir repo_path {ext_path ""} {sim 0}} {
2983 if {![
file exists $proj_dir]} {
2984 Msg CriticalWarning "$proj_dir not found"
2994 Msg Warning "Repository is not clean"
3002 Msg Debug "Project version $v_proj, latest tag $v_last"
3004 Msg Info "The specified project was modified since official version."
3011 Msg Info "The specified project was modified in the latest official version $ret"
3012 }
elseif {$comp == -1} {
3013 Msg Info "The specified project was modified in a past official version $ret"
3029 proc GetRepoVersions {proj_dir repo_path {ext_path ""} {sim 0}} {
3030 if {[
catch {
package require cmdline} ERROR]} {
3031 puts "$ERROR\n If you are running this script on tclsh, you can fix this by installing 'tcllib'"
3046 lappend SHAs [
GetSHA {Hog}]
3050 if {[
Git {status --untracked-files=no --porcelain}] eq ""} {
3051 Msg Info "Hog submodule [
pwd] clean."
3052 lassign [
GetVer ./] hog_ver hog_hash
3054 Msg CriticalWarning "Hog submodule [
pwd] not clean, commit hash will be set to 0."
3055 set hog_hash "0000000"
3056 set hog_ver "00000000"
3061 if {[
Git {status --untracked-files=no --porcelain}] eq ""} {
3062 Msg Info "Git working directory [
pwd] clean."
3065 Msg CriticalWarning "Git working directory [
pwd] not clean, commit hash, and version will be set to 0."
3070 lassign [
GetVer [
join $conf_files]] top_ver top_hash
3071 lappend SHAs $top_hash
3072 lappend versions $top_ver
3079 lassign [
GetHogFiles -list_files "*.src" -sha_mode "./list/" $repo_path] src_files dummy
3080 dict for {f files} $src_files {
3081 # library names have a .src extension in values returned by GetHogFiles
3082 set name [file rootname [file tail $f]]
3083 if {[file ext $f] == ".oth"} {
3086 lassign [GetVer $files] ver hash
3087 # Msg Info "Found source list file $f, version: $ver commit SHA: $hash"
3089 lappend versions $ver
3091 lappend hashes $hash
3098 lassign [
GetHogFiles -list_files "*.con" -sha_mode "./list/" $repo_path] cons_files dummy
3099 dict for {f files} $cons_files {
3100 #library names have a .con extension in values returned by GetHogFiles
3101 set name [file rootname [file tail $f]]
3102 lassign [GetVer $files] ver hash
3103 #Msg Info "Found constraint list file $f, version: $ver commit SHA: $hash"
3105 Msg CriticalWarning "Constraints file $f not found in Git."
3107 lappend cons_hashes $hash
3109 lappend versions $ver
3116 lassign [
GetHogFiles -list_files "*.sim" -sha_mode "./list/" $repo_path] sim_files dummy
3117 dict for {f files} $sim_files {
3118 #library names have a .sim extension in values returned by GetHogFiles
3119 set name [file rootname [file tail $f]]
3120 lassign [GetVer $files] ver hash
3121 #Msg Info "Found simulation list file $f, version: $ver commit SHA: $hash"
3122 lappend sim_hashes $hash
3124 lappend versions $ver
3130 if {"{}" eq $cons_hashes} {
3132 Msg CriticalWarning "No hashes found for constraints files (not in git)"
3135 set cons_hash [
string tolower [
Git "log --format=%h -1 $cons_hashes"]]
3142 set ext_files [glob -nocomplain "./list/*.ext"]
3145 foreach f $ext_files {
3146 set name [
file rootname [
file tail $f]]
3149 lappend ext_names $name
3150 lappend ext_hashes $hash
3153 lappend versions $ext_ver
3156 set file_data [read $fp]
3158 set data [
split $file_data "\n"]
3160 foreach line $data {
3161 if {![regexp {^ *$} $line] & ![regexp {^ *\#} $line]} {
3163 set file_and_prop [regexp -all -inline {\S+} $line]
3164 set hdlfile [
lindex $file_and_prop 0]
3165 set hdlfile $ext_path/$hdlfile
3166 if {[
file exists $hdlfile]} {
3167 set hash [
lindex $file_and_prop 1]
3168 set current_hash [
Md5Sum $hdlfile]
3169 if {[
string first $hash $current_hash] == -1} {
3170 Msg CriticalWarning "File $hdlfile has a wrong hash. Current checksum: $current_hash, expected: $hash"
3178 if {[
llength [glob -nocomplain ./list/*.ipb]] > 0} {
3180 lassign [
GetHogFiles -list_files "*.ipb" -sha_mode "./list/" $repo_path] xml_files dummy
3181 lassign [
GetVer [dict get $xml_files "xml.ipb"]] xml_ver xml_hash
3182 lappend SHAs $xml_hash
3183 lappend versions $xml_ver
3187 Msg Info "This project does not use IPbus XMLs"
3192 set user_ip_repos ""
3193 set user_ip_repo_hashes ""
3194 set user_ip_repo_vers ""
3196 if {[
file exists [
lindex $conf_files 0]]} {
3197 set PROPERTIES [
ReadConf [
lindex $conf_files 0]]
3198 if {[dict exists $PROPERTIES main]} {
3199 set main [dict get $PROPERTIES main]
3200 dict for {p v} $main {
3201 if {[string tolower $p] == "ip_repo_paths"} {
3203 if {[file isdirectory "$repo_path/$repo"]} {
3204 set repo_file_list [glob -nocomplain "$repo_path/$repo/*"]
3205 if {[llength $repo_file_list] == 0} {
3206 Msg Warning "IP_REPO_PATHS property set to $repo in hog.conf but directory is empty."
3208 lappend user_ip_repos "$repo_path/$repo"
3217 foreach repo $user_ip_repos {
3218 if {[
file isdirectory $repo]} {
3219 set repo_file_list [glob -nocomplain "$repo/*"]
3220 if {[
llength $repo_file_list] != 0} {
3221 lassign [
GetVer $repo] ver sha
3222 lappend user_ip_repo_hashes $sha
3223 lappend user_ip_repo_vers $ver
3224 lappend versions $ver
3226 Msg Warning "IP_REPO_PATHS property set to $repo in hog.conf but directory is empty."
3229 Msg Warning "IP_REPO_PATHS property set to $repo in hog.conf but directory does not exist."
3238 while {$found == 0} {
3239 set global_commit [
Git "log --format=%h -1 --abbrev=7 $SHAs"]
3244 if {$common_child == 0} {
3245 Msg CriticalWarning "The commit $sha is not an ancestor of the global commit $global_commit, which is OK. \
3246 But $sha and $global_commit do not have any common child, which is NOT OK. \
3247 This is probably do to a REBASE that is forbidden in Hog methodology as it changes git history. \
3248 Hog cannot guarantee the accuracy of the SHAs. \
3249 A way to fix this is to make a commit that touches all the projects in the repositories (e.g. change the Hog version), \
3250 but please do not rebase in the official branches in the future."
3252 Msg Info "The commit $sha is not an ancestor of the global commit $global_commit, adding the first common child $common_child instead..."
3253 lappend SHAs $common_child
3263 set global_commit "0000000"
3264 set global_version "00000000"
3269 set top_hash [
format %+07s $top_hash]
3270 set cons_hash [
format %+07s $cons_hash]
3271 return [list $global_commit $global_version \
3272 $hog_hash $hog_ver $top_hash $top_ver \
3273 $libs $hashes $vers $cons_ver $cons_hash \
3274 $ext_names $ext_hashes $xml_hash $xml_ver \
3275 $user_ip_repos $user_ip_repo_hashes $user_ip_repo_vers]
3284 proc GetSHA {{path ""}} {
3286 lassign [
GitRet {log --format=%h --abbrev=7 -1}] status result
3288 return [
string tolower $result]
3290 Msg Error "Something went wrong while finding the latest SHA. Does the repository have a commit?"
3296 set repo_path [
lindex [
Git {rev-parse --show-toplevel}] 0]
3300 set file_in_module 0
3301 if {[
file exists $repo_path/.gitmodules]} {
3302 lassign [
GitRet "config --file $repo_path/.gitmodules --get-regexp path"] status result
3304 set submodules [
split $result "\n"]
3307 Msg Warning "Something went wrong while trying to find submodules: $result"
3310 foreach mod $submodules {
3311 set module [
lindex $mod 1]
3312 if {[
string first "$repo_path/$module" $f] == 0} {
3314 set file_in_module 1
3315 lappend paths "$repo_path/$module"
3320 if {$file_in_module == 0} {
3326 lassign [
GitRet {log --format=%h --abbrev=7 -1} $paths] status result
3328 return [
string tolower $result]
3330 Msg Error "Something went wrong while finding the latest SHA. Does the repository have a commit?"
3333 return [
string tolower $result]
3337 proc GetSimulators {} {
3338 set SIMULATORS [list "modelsim" "questa" "riviera" "activehdl" "ies" "vcs"]
3343 proc GetTopFile {} {
3345 set compile_order_prop [get_property source_mgmt_mode [current_project]]
3346 if {$compile_order_prop ne "All"} {
3347 Msg CriticalWarning "Compile order is not set to automatic, setting it now..."
3348 set_property source_mgmt_mode All [current_project]
3349 update_compile_order -fileset sources_1
3351 return [
lindex [get_files -quiet -compile_order sources -used_in synthesis -filter {FILE_TYPE =~ "VHDL*" || FILE_TYPE =~ "*Verilog*" }] end]
3352 }
elseif {[
IsISE]} {
3353 debug::design_graph_mgr -create [current_fileset]
3354 debug::design_graph -add_fileset [current_fileset]
3355 debug::design_graph -update_all
3356 return [
lindex [debug::design_graph -get_compile_order] end]
3358 Msg Error "GetTopFile not yet implemented for this IDE"
3363 proc GetTopModule {} {
3365 return [get_property top [current_fileset]]
3367 Msg Error "GetTopModule not yet implemented for this IDE"
3377 proc GetVer {path {force_develop 0}} {
3381 Msg CriticalWarning "Empty SHA found for ${path}. Commit to Git to resolve this warning."
3384 set p [
lindex $path 0]
3385 if {[
file isdirectory $p]} {
3388 cd [
file dirname $p]
3390 set repo_path [
Git {rev-parse --show-toplevel}]
3393 return [list [
GetVerFromSHA $SHA $repo_path $force_develop] $SHA]
3404 proc GetVerFromSHA {SHA repo_path {force_develop 0}} {
3406 Msg CriticalWarning "Empty SHA found"
3409 lassign [
GitRet "tag --sort=creatordate --contain $SHA -l v*.*.* -l b*v*.*.*"] status result
3412 if {[regexp {^ *$} $result]} {
3414 lassign [
GitRet "log --oneline --pretty=\"%d\""] status2 tag_list
3417 set pattern {tag: v\d+\.\d+\.\d+}
3418 set real_tag_list {}
3419 foreach x $tag_list {
3420 set x_untrimmed [regexp -all -inline $pattern $x]
3421 regsub "tag: " $x_untrimmed "" x_trimmed
3422 set tt [
lindex $x_trimmed 0]
3423 if {![
string equal $tt ""]} {
3424 lappend real_tag_list $tt
3428 Msg Debug "Cleaned up list: $real_tag_list."
3430 set sorted_tags [lsort -decreasing -command CompareVersions $real_tag_list]
3432 Msg Debug "Sorted Tag list: $sorted_tags"
3434 set tag [
lindex $sorted_tags 0]
3437 set pattern {v\d+\.\d+\.\d+}
3438 if {![regexp $pattern $tag]} {
3439 Msg CriticalWarning "No Hog version tags found in this repository."
3444 set repo_conf $repo_path/Top/repo.conf
3448 set hotfix_prefix "hotfix/"
3449 set minor_prefix "minor_version/"
3450 set major_prefix "major_version/"
3452 set enable_develop_branch $force_develop
3454 set branch_name [
Git {rev-parse --abbrev-ref HEAD}]
3456 if {[
file exists $repo_conf]} {
3457 set PROPERTIES [
ReadConf $repo_conf]
3459 if {[dict exists $PROPERTIES main]} {
3460 set mainDict [dict get $PROPERTIES main]
3463 if {[dict exists $mainDict ENABLE_DEVELOP_BRANCH]} {
3464 set enable_develop_branch [dict get $mainDict ENABLE_DEVELOP_BRANCH]
3470 if {[dict exists $PROPERTIES prefixes]} {
3471 set prefixDict [dict get $PROPERTIES prefixes]
3473 if {[dict exists $prefixDict HOTFIX]} {
3474 set hotfix_prefix [dict get $prefixDict HOTFIX]
3476 if {[dict exists $prefixDict MINOR_VERSION]} {
3477 set minor_prefix [dict get $prefixDict MINOR_VERSION]
3479 if {[dict exists $prefixDict MAJOR_VERSION]} {
3480 set major_prefix [dict get $prefixDict MAJOR_VERSION]
3486 if {$enable_develop_branch == 1} {
3487 if {[
string match "$hotfix_prefix*" $branch_name]} {
3492 if {[
string match "$major_prefix*" $branch_name]} {
3494 set version_level major
3495 }
elseif {[
string match "$minor_prefix*" $branch_name] || ($enable_develop_branch == 1 && $is_hotfix == 0)} {
3497 set version_level minor
3500 set version_level patch
3504 Msg CriticalWarning "Tag $tag does not contain a Hog compatible version in this repository."
3507 }
elseif {$mr == 0} {
3508 switch $version_level {
3523 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."
3529 set vers [
split $result "\n"]
3530 set ver [
lindex $vers 0]
3532 if {[regexp {^v.*$} $v]} {
3540 Msg CriticalWarning "Error while trying to find tag for $SHA"
3548 set M [
format %02X $M]
3549 set m [
format %02X $m]
3550 set c [
format %04X $c]
3551 }
elseif {$M > -1} {
3553 set M [
format %02X $M]
3554 set m [
format %02X $m]
3555 set c [
format %04X $c]
3557 Msg Warning "Tag does not contain a properly formatted version: $ver"
3558 set M [
format %02X 0]
3559 set m [
format %02X 0]
3560 set c [
format %04X 0]
3573 proc Git {command {files ""}} {
3574 lassign [
GitRet $command $files] ret result
3576 Msg Error "Code $ret returned by git running: $command -- $files"
3587 proc GetModuleName {filename} {
3589 if {![
file exists $filename]} {
3590 Msg CriticalWarning "Error: File $filename does not exist."
3595 set fileId [open $filename r]
3598 set file_content [read $fileId]
3604 if {[
file extension $filename] == ".vhd" || [
file extension $filename] == ".vhdl"} {
3606 set file_content [
string tolower $file_content]
3608 set pattern {(?m)^\s*entity\s+(\S+)\s+is}
3609 }
elseif {[
file extension $filename] == ".v" || [
file extension $filename] == ".sv"} {
3611 set pattern {\n\s*module\s*(\w+)(\s*|\(|\n)}
3613 Msg Debug "File is neither VHDL nor Verilog... Returning empty string..."
3618 if {[regexp $pattern $file_content match module_name]} {
3621 Msg Debug "No module was found in $filename. Returning an empty string..."
3629 proc GetVerilogGenerics {file} {
3630 set fp [open $file r]
3636 foreach line [
split $data "\n"] {
3637 regsub "^\\s*\/\/.*" $line "" line
3638 regsub "(.*)\/\/.*" $line {\1} line
3639 if {![
string equal $line ""]} {
3640 append lines $line " "
3645 regsub -all {/\*.*\*/} $lines "" lines
3648 set punctuation [list]
3649 foreach char [list "(" ")" ";" "," " " "!" "<=" ":=" "=" "\[" "\]"] {
3650 lappend punctuation $char "\000$char\000"
3654 set tokens [
split [
string map $punctuation $lines] \000]
3656 set parameters [dict create]
3665 foreach token $tokens {
3666 set token [
string trim $token]
3667 if {![
string equal "" $token]} {
3668 if {[
string equal [
string tolower $token] "parameter"]} {
3669 set state $PARAM_NAME
3670 }
elseif {[
string equal $token ")"] || [
string equal $token ";"]} {
3672 }
elseif {$state == $PARAM_WIDTH} {
3673 if {[
string equal $token "\]"]} {
3674 set state $PARAM_NAME
3676 }
elseif {$state == $PARAM_VALUE} {
3677 if {[
string equal $token ","]} {
3678 set state $PARAM_NAME
3679 }
elseif {[
string equal $token ";"]} {
3684 }
elseif {$state == $PARAM_NAME} {
3685 if {[
string equal $token "="]} {
3686 set state $PARAM_VALUE
3687 }
elseif {[
string equal $token "\["]} {
3688 set state $PARAM_WIDTH
3689 }
elseif {[
string equal $token ","]} {
3690 set state $PARAM_NAME
3691 }
elseif {[
string equal $token ";"]} {
3693 }
elseif {[
string equal $token ")"]} {
3696 dict set parameters $token "integer"
3709 proc GetVhdlGenerics {file {entity ""}} {
3710 set fp [open $file r]
3716 foreach line [
split $data "\n"] {
3717 regsub "^\\s*--.*" $line "" line
3718 regsub "(.*)--.*" $line {\1} line
3719 if {![
string equal $line ""]} {
3720 append lines $line " "
3725 set generic_block ""
3726 set generics [dict create]
3728 if {1 == [
string equal $entity ""]} {
3729 regexp {(?i).*entity\s+([^\s]+)\s+is} $lines _ entity
3732 set generics_regexp "(?i).*entity\\s+$entity\\s+is\\s+generic\\s*\\((.*)\\)\\s*;\\s*port.*end.*$entity"
3734 if {[regexp $generics_regexp $lines _ generic_block]} {
3736 foreach line [
split $generic_block ";"] {
3738 regexp {(.*):\s*([A-Za-z0-9_]+).*} $line _ generic type
3741 set splits [
split $generic ","]
3742 foreach split $splits {
3743 dict set generics [
string trim $split] [
string trim $type]
3751 proc GHDL {command logfile} {
3752 set ret [
catch {
exec -ignorestderr ghdl {*}$command >>& $logfile} result options]
3757 return [list $ret $result]
3769 proc GitRet {command {files ""}} {
3772 set ret [
catch {
exec -ignorestderr git {*}$command} result]
3774 set ret [
catch {
exec -ignorestderr git {*}$command -- {*}$files} result]
3776 return [list $ret $result]
3784 proc GitVersion {target_version} {
3785 set ver [
split $target_version "."]
3786 set v [
Git --version]
3788 set current_ver [
split [
lindex $v 2] "."]
3789 set target [
expr {[lindex $ver 0] * 100000 + [lindex $ver 1] * 100 + [lindex $ver 2]}]
3790 set current [
expr {[lindex $current_ver 0] * 100000 + [lindex $current_ver 1] * 100 + [lindex $current_ver 2]}]
3791 return [
expr {$target <= $current}]
3805 proc HandleIP {what_to_do xci_file ip_path repo_path {gen_dir "."} {force 0}} {
3806 if {!($what_to_do eq "push") && !($what_to_do eq "pull")} {
3807 Msg Error "You must specify push or pull as first argument."
3810 if {[
catch {
package require tar} TARPACKAGE]} {
3811 Msg CriticalWarning "Cannot find package tar. You can fix this by installing package \"tcllib\""
3820 if {[
string first "/eos/" $ip_path] == 0} {
3828 lassign [
eos "ls $ip_path"] ret result
3830 Msg CriticalWarning "Could not run ls for for EOS path: $ip_path (error: $result). \
3831 Either the drectory does not exist or there are (temporary) problem with EOS."
3835 Msg Info "IP remote directory path, on EOS, is set to: $ip_path"
3841 if {!([
file exists $xci_file])} {
3842 Msg CriticalWarning "Could not find $xci_file."
3848 set xci_path [
file dirname $xci_file]
3849 set xci_name [
file tail $xci_file]
3850 set xci_ip_name [
file rootname [
file tail $xci_file]]
3851 set xci_dir_name [
file tail $xci_path]
3852 set gen_path $gen_dir
3854 set hash [
Md5Sum $xci_file]
3855 set file_name $xci_name\_$hash
3857 Msg Info "Preparing to $what_to_do IP: $xci_name..."
3859 if {$what_to_do eq "push"} {
3863 lassign [
eos "ls $ip_path/$file_name.tar"] ret result
3868 Msg Info "IP already in the EOS repository, will not copy..."
3870 Msg Info "IP already in the EOS repository, will forcefully replace..."
3876 if {[
file exists "$ip_path/$file_name.tar"]} {
3878 Msg Info "IP already in the local repository, will not copy..."
3880 Msg Info "IP already in the local repository, will forcefully replace..."
3889 if {$will_copy == 1} {
3891 Msg Info "Looking for generated files in $gen_path..."
3892 set ip_gen_files [glob -nocomplain $gen_path/*]
3896 if {[
llength $ip_gen_files] > 0} {
3897 Msg Info "Found some IP synthesised files matching $xci_ip_name"
3898 if {$will_remove == 1} {
3899 Msg Info "Removing old synthesised directory $ip_path/$file_name.tar..."
3901 eos "rm -rf $ip_path/$file_name.tar" 5
3903 file delete -force "$ip_path/$file_name.tar"
3907 Msg Info "Creating local archive with IP generated files..."
3909 foreach f $ip_gen_files {
3910 if {$first_file == 0} {
3911 ::tar::create $file_name.tar "[
Relative [
file normalize $repo_path] $f]"
3914 ::tar::add $file_name.tar "[
Relative [
file normalize $repo_path] $f]"
3918 Msg Info "Copying IP generated files for $xci_name..."
3920 lassign [
ExecuteRet xrdcp -f -s $file_name.tar $::env(EOS_MGM_URL)//$ip_path/] ret msg
3922 Msg CriticalWarning "Something went wrong when copying the IP files to EOS. Error message: $msg"
3925 Copy "$file_name.tar" "$ip_path/"
3927 Msg Info "Removing local archive"
3928 file delete $file_name.tar
3930 Msg Warning "Could not find synthesized files matching $gen_path/$file_name*"
3933 }
elseif {$what_to_do eq "pull"} {
3935 lassign [
eos "ls $ip_path/$file_name.tar"] ret result
3937 Msg Info "Nothing for $xci_name was found in the EOS repository, cannot pull."
3941 set remote_tar "$::env(EOS_MGM_URL)//$ip_path/$file_name.tar"
3942 Msg Info "IP $xci_name found in the repository $remote_tar, copying it locally to $repo_path..."
3944 lassign [
ExecuteRet xrdcp -f -r -s $remote_tar $repo_path] ret msg
3946 Msg CriticalWarning "Something went wrong when copying the IP files to EOS. Error message: $msg"
3950 if {[
file exists "$ip_path/$file_name.tar"]} {
3951 Msg Info "IP $xci_name found in local repository $ip_path/$file_name.tar, copying it locally to $repo_path..."
3952 Copy $ip_path/$file_name.tar $repo_path
3954 Msg Info "Nothing for $xci_name was found in the local IP repository, cannot pull."
3960 if {[
file exists $file_name.tar]} {
3961 remove_files $xci_file
3962 Msg Info "Extracting IP files from archive to $repo_path..."
3963 ::tar::untar $file_name.tar -dir $repo_path -noperms
3964 Msg Info "Removing local archive"
3965 file delete $file_name.tar
3966 add_files -norecurse -fileset sources_1 $xci_file
3979 proc HexVersionToString {version} {
3980 scan [
string range $version 0 1] %x M
3981 scan [
string range $version 2 3] %x m
3982 scan [
string range $version 4 7] %x c
3987 proc ImportTclLib {} {
3989 if {[
info exists env(HOG_TCLLIB_PATH)]} {
3990 lappend auto_path $env(HOG_TCLLIB_PATH)
3993 puts "ERROR: To run Hog with Microsemi Libero SoC or Lattice Diamond, you need to define the HOG_TCLLIB_PATH variable."
4008 proc InitLauncher {script tcl_path parameters commands argv {custom_commands ""}} {
4009 set repo_path [
file normalize "$tcl_path/../.."]
4011 set bin_path [
file normalize "$tcl_path/../../bin"]
4012 set top_path [
file normalize "$tcl_path/../../Top"]
4014 set cmd_lines [
split $commands "\n"]
4016 set command_options [dict create]
4017 set directive_descriptions [dict create]
4018 set directive_names [dict create]
4019 set common_directive_names [dict create]
4020 set custom_command ""
4021 set custom_command_options ""
4023 foreach l $cmd_lines {
4025 if {[regexp {\\(.*) \{\#} $l minc d]} {
4026 lappend directives_with_projects $d
4030 if {[regexp {\\(.*) \{} $l minc regular_expression]} {
4031 lappend directive_regex $regular_expression
4035 if {[regexp {\#\s*NAME(\*)?:\s*(.*)\s*} $l minc star name]} {
4036 dict set directive_names $name $regular_expression
4038 dict set common_directive_names $name $regular_expression
4041 set directive_names [
DictSort $directive_names]
4042 set common_directive_names [
DictSort $common_directive_names]
4045 if {[regexp {\#\s*DESCRIPTION:\s*(.*)\s*} $l minc x]} {
4046 dict set directive_descriptions $regular_expression $x
4050 if {[regexp {\#\s*OPTIONS:\s*(.*)\s*} $l minc x]} {
4051 dict set command_options $regular_expression [
split [regsub -all {[ \t\n]+} $x {}] ","]
4055 set short_usage "usage: ./Hog/Do \[OPTIONS\] <directive> \[project\]\n\nMost common directives (case insensitive):"
4057 dict for {key value} $common_directive_names {
4058 set short_usage "$short_usage\n - $key: [dict get $directive_descriptions $value]"
4061 if {[
string length $custom_commands] > 0} {
4062 Msg Debug "Found custom commands to add to short short_usage."
4063 set short_usage "$short_usage\n\nCustom commands:"
4064 dict for {key command} $custom_commands {
4065 Msg Debug "Adding $key : [dict get $command DESCRIPTION]"
4066 set short_usage "$short_usage\n - $key: [dict get $command DESCRIPTION]"
4072 set short_usage "$short_usage\n\n\
4073 To see all the available directives, run:\n./Hog/Do HELP\n\n\
4074 To list available options for the chosen directive run:\n\
4075 ./Hog/Do <directive> HELP\n
4078 set usage "usage: ./Hog/Do \[OPTIONS\] <directive> \[project\]\n\nDirectives (case insensitive):"
4080 dict for {key value} $directive_names {
4081 set usage "$usage\n - $key: [dict get $directive_descriptions $value]"
4085 if {[
string length $custom_commands] > 0} {
4086 Msg Debug "Found custom commands to add to short usage."
4087 set usage "$usage\n\nCustom commands:"
4088 dict for {key command} $custom_commands {
4089 Msg Debug "Adding $key : [dict get $command DESCRIPTION]"
4090 set usage "$usage\n - $key: [dict get $command DESCRIPTION]"
4095 set usage "$usage\n\nTo list available options for the chosen directive run:\n./Hog/Do <directive> HELP"
4104 Msg Debug "HogEnv.conf found"
4112 if {[
catch {
package require cmdline} ERROR]} {
4113 Msg Debug "The cmdline Tcl package was not found, sourcing it from Hog..."
4114 source $tcl_path/utils/cmdline.tcl
4117 set argv [regsub -all {(?i) HELP\y} $argv " -help"]
4122 set custom_parameters [list]
4123 dict for {key command} $custom_commands {
4124 set custom_parameters [concat $custom_parameters [dict get $command CUSTOM_OPTIONS]]
4127 lassign [
GetOptions $argv [
concat $custom_parameters $parameters]] option_list arg_list
4129 if {[
IsInList "-all" $option_list]} {
4138 set directive [
string toupper [
lindex $arg_list 0]]
4141 set argument_is_no_project 1
4143 set NO_DIRECTIVE_FOUND 0
4144 switch -regexp -- $directive "$commands"
4145 if {$NO_DIRECTIVE_FOUND == 1} {
4146 if {[
string length $custom_commands] > 0 && [dict exists $custom_commands $directive]} {
4147 set custom_command $directive
4148 set custom_command_hog_parameters [dict get $custom_commands $directive OPTIONS]
4149 set custom_command_options [dict get $custom_commands $directive CUSTOM_OPTIONS]
4150 set custom_command_options [
concat $custom_command_hog_parameters $custom_command_options]
4152 Msg Status "ERROR: Unknown directive $directive.\n\n"
4158 if {[
IsInList $directive $directives_with_projects 1]} {
4159 set argument_is_no_project 0
4163 if {$directive != ""} {
4164 if {[
IsInList $directive $directives_with_projects 1]} {
4165 puts "usage: ./Hog/Do \[OPTIONS\] $directive <project>\n"
4166 }
elseif {[regexp "^COMPSIM(LIB)?$" $directive]} {
4167 puts "usage: ./Hog/Do \[OPTIONS\] $directive <simulator>\n"
4169 puts "usage: ./Hog/Do \[OPTIONS\] $directive \n"
4172 dict for {dir desc} $directive_descriptions {
4173 if {[regexp $dir $directive]} {
4181 if {$custom_command ne ""} {
4182 if {[
llength $custom_command_options] > 0} {
4183 puts "Available options:"
4185 foreach custom_option $custom_command_options {
4186 set n [
llength $custom_option]
4188 lassign $custom_option opt help
4191 }
elseif {$n == 3} {
4192 lassign $custom_option opt def help
4193 puts " -$opt <argument>"
4195 puts " $help (default: $def)"
4200 Msg Warning "Custom option spec has invalid arity (expected 2 or 3): $custom_option"
4205 dict for {dir opts} $command_options {
4206 if {[regexp $dir $directive]} {
4207 puts "Available options:"
4209 foreach par $parameters {
4210 if {$opt == [lindex $par 0]} {
4211 if {[regexp {\.arg$} $opt]} {
4212 set opt_name [regsub {\.arg$} $opt ""]
4213 puts " -$opt_name <argument>"
4217 puts " [lindex $par [llength $par]-1]"
4231 if {$custom_command ne ""} {
4232 set parameters [
concat $parameters $custom_command_options]
4235 if {[
catch {
array set options [
cmdline::getoptions option_list $parameters $usage]} err]} {
4236 Msg Status "\nERROR: Syntax error, probably unknown option.\n\n USAGE: $err"
4240 if {[
llength $arg_list] <= $min_n_of_args || [
llength $arg_list] > $max_n_of_args} {
4241 Msg Status "\nERROR: Wrong number of arguments: [
llength $argv]"
4246 set project [
lindex $arg_list 1]
4248 if {$argument_is_no_project == 0} {
4250 regsub "^(\./)?Top/" $project "" project
4252 regsub "/? *\$" $project "" project
4258 Msg Debug "Option list:"
4259 foreach {key value} [
array get options] {
4260 Msg Debug "$key => $value"
4267 if {$proj_conf != 0} {
4270 lassign [
GetIDECommand $proj_conf] cmd before_tcl_script after_tcl_script end_marker
4271 Msg Info "Project $project uses $cmd IDE"
4274 set command "$cmd $before_tcl_script$script$after_tcl_script$argv$end_marker"
4276 if {$custom_command ne ""} {
4277 if { [dict exists $custom_commands $directive IDE] } {
4278 lassign [
GetIDECommand "" [dict get $custom_commands $directive IDE]] cmd before_tcl_script after_tcl_script end_marker
4279 Msg Info "Custom command: $custom_command uses $cmd IDE"
4280 set command "$cmd $before_tcl_script$script$after_tcl_script$argv$end_marker"
4282 set command "custom_tcl"
4284 }
elseif {$argument_is_no_project == 1} {
4286 Msg Debug "$project will be used as first argument"
4287 }
elseif {$project != ""} {
4290 }
elseif {$min_n_of_args < 0} {
4303 set project_group [
file dirname $project]
4304 set project_name $project
4305 set project [
file tail $project]
4306 Msg Debug "InitLauncher: project_group=$project_group, project_name=$project_name, project=$project"
4308 return [list $directive $project $project_name $project_group $repo_path $old_path $bin_path $top_path $usage $short_usage $command $cmd [
array get options]]
4315 proc IsCommitAncestor {ancestor commit} {
4316 lassign [
GitRet "merge-base --is-ancestor $ancestor $commit"] status result
4325 return [
expr {[info commands sys_install] != ""}]
4330 return [
expr {[info commands get_libero_version] != ""}]
4339 proc IsInList {element list {regex 0} {nocase 0}} {
4343 if {[regexp -nocase $x $element]} {
4347 if {[regexp $x $element]} {
4351 }
elseif {$regex == 0} {
4353 if {[
string tolower $x] eq [
string tolower $element]} {
4357 if {$x eq $element} {
4370 return [
expr {[string first PlanAhead [version]] == 0}]
4378 if {[
catch {
package require ::quartus::flow} result]} {
4391 proc IsRelativePath {path} {
4392 if {[
string index $path 0] == "/" || [
string index $path 0] == "~"} {
4400 proc IsSynplify {} {
4401 return [
expr {[info commands program_version] != ""}]
4406 return [
expr {![IsQuartus] && ![IsXilinx] && ![IsVitisClassic] && ![IsLibero] && ![IsSynplify] && ![IsDiamond]}]
4414 proc IsVersal {part} {
4415 if {[get_property ARCHITECTURE [get_parts $part]] eq "versal"} {
4425 return [
expr {[string first Vivado [version]] == 0}]
4433 if {[
info commands version] != ""} {
4434 set current_version [version]
4435 if {[
string first PlanAhead $current_version] == 0 || [
string first Vivado $current_version] == 0} {
4437 }
elseif {[
string first xsct $current_version] == 0} {
4440 Msg Warning "This IDE has the version command but it is not PlanAhead or Vivado: $current_version"
4449 proc IsVitisClassic {} {
4450 return [
expr {[info commands platform] != ""}]
4458 proc IsZynq {part} {
4459 if {[regexp {^(xc7z|xczu).*} $part]} {
4466 proc ImportGHDL {project_name repo_path simset_name simset_dict {ext_path ""}} {
4467 set list_path "$repo_path/Top/$project_name/list"
4468 lassign [
GetHogFiles -list_files {.src,.ext,.sim} -ext_path $ext_path $list_path $repo_path] src_files properties filesets
4473 set properties [
DictGet $simset_dict "properties"]
4474 set options [
DictGet $properties "options"]
4477 set workdir Projects/$project_name/ghdl
4478 file delete -force $workdir
4480 set import_log "$workdir/ghdl-import-${simset_name}.log"
4481 dict for {lib sources} $src_files {
4482 set libname [file rootname $lib]
4483 foreach f $sources {
4484 if {[file extension $f] != ".vhd" && [file extension $f] != ".vhdl"} {
4485 Msg Info "File $f is not a VHDL file, copying it in workfolder..."
4486 file copy -force $f $workdir
4488 set file_path [Relative $repo_path $f]
4489 set import_log_file [open $import_log "a"]
4490 puts "ghdl -i --work=$libname --workdir=$workdir -fsynopsys --ieee=standard $options $file_path"
4491 puts $import_log_file "ghdl -i --work=$libname --workdir=$workdir -fsynopsys --ieee=standard $options $file_path"
4492 close $import_log_file
4493 lassign [GHDL "-i --work=$libname --workdir=$workdir -fsynopsys --ieee=standard $options $file_path" $import_log] ret result
4495 Msg CriticalWarning "GHDL import failed for file $f: $result"
4504 proc LaunchGHDL {project_name repo_path simset_name simset_dict {ext_path ""}} {
4507 set sim_props [
DictGet $simset_dict "properties"]
4508 set options [
DictGet $sim_props "options"]
4509 set runopts [
DictGet $sim_props "run_options"]
4511 dict for {prop_name prop_val} $sim_props {
4512 set prop_name [string toupper $prop_name]
4513 if {$prop_name == "TOP"} {
4514 set top_sim $prop_val
4517 set workdir $repo_path/Projects/$project_name/ghdl
4518 set make_log "$workdir/ghdl-make-${simset_name}.log"
4519 set run_log "$workdir/ghdl-run-${simset_name}.log"
4522 set make_log_file [open $make_log "w"]
4524 puts "ghdl -m --work=$simset_name -fsynopsys --ieee=standard $options $top_sim"
4525 puts $make_log_file "ghdl -m --work=$simset_name -fsynopsys --ieee=standard $options $top_sim"
4526 close $make_log_file
4528 lassign [
GHDL "-m --work=$simset_name -fsynopsys --ieee=standard $options $top_sim" $make_log] ret result
4531 Msg Error "GHDL make failed for $top_sim: $result"
4535 set run_log_file [open $run_log "w"]
4536 puts "ghdl -r --work=$simset_name -fsynopsys --ieee=standard $options $top_sim $runopts"
4537 puts $run_log_file "ghdl -r --work=$simset_name -fsynopsys --ieee=standard $options $top_sim $runopts"
4540 lassign [
GHDL "-r --work=$simset_name -fsynopsys --ieee=standard $options $top_sim $runopts" $run_log] ret result
4544 Msg Error "GHDL run failed for $top_sim: $result"
4559 proc LaunchImplementation {reset do_create run_folder project_name {repo_path .} {njobs 4} {do_bitstream 0}} {
4560 Msg Info "Starting implementation flow..."
4562 if {$reset == 1 && $do_create == 0} {
4563 Msg Info "Resetting run before launching implementation..."
4568 source $repo_path/Hog/Tcl/integrated/pre-implementation.tcl
4571 if {$do_bitstream == 1} {
4572 launch_runs impl_1 -to_step [
BinaryStepName [get_property PART [current_project]]] -jobs $njobs -dir $run_folder
4574 launch_runs impl_1 -jobs $njobs -dir $run_folder
4579 Msg Info "running post-implementation"
4580 source $repo_path/Hog/Tcl/integrated/post-implementation.tcl
4581 if {$do_bitstream == 1} {
4582 Msg Info "running pre-bitstream"
4583 source $repo_path/Hog/Tcl/integrated/pre-bitstream.tcl
4584 Msg Info "running post-bitstream"
4585 source $repo_path/Hog/Tcl/integrated/post-bitstream.tcl
4589 set prog [get_property PROGRESS [get_runs impl_1]]
4590 set status [get_property STATUS [get_runs impl_1]]
4591 Msg Info "Run: impl_1 progress: $prog, status : $status"
4595 set status_file [open "$run_folder/timing.txt" "w"]
4596 puts $status_file "## $project_name Timing summary"
4598 set f [open [
lindex [glob "$run_folder/impl_1/*.twr" 0]]]
4600 while {[
gets $f line] >= 0} {
4601 if {[
string match "Timing summary:" $line]} {
4602 while {[
gets $f line] >= 0} {
4603 if {[
string match "Timing errors:*" $line]} {
4604 set errs [regexp -inline -- {[0-9]+} $line]
4606 if {[
string match "*Footnotes*" $line]} {
4609 puts $status_file "$line"
4618 Msg Info "Time requirements are met"
4619 file rename -force "$run_folder/timing.txt" "$run_folder/timing_ok.txt"
4622 Msg CriticalWarning "Time requirements are NOT met"
4623 file rename -force "$run_folder/timing.txt" "$run_folder/timing_error.txt"
4629 set wns [get_property STATS.WNS [get_runs [current_run]]]
4630 set tns [get_property STATS.TNS [get_runs [current_run]]]
4631 set whs [get_property STATS.WHS [get_runs [current_run]]]
4632 set ths [get_property STATS.THS [get_runs [current_run]]]
4633 set tpws [get_property STATS.TPWS [get_runs [current_run]]]
4635 if {$wns >= 0 && $whs >= 0 && $tpws >= 0} {
4636 Msg Info "Time requirements are met"
4637 set status_file [open "$run_folder/timing_ok.txt" "w"]
4640 Msg CriticalWarning "Time requirements are NOT met"
4641 set status_file [open "$run_folder/timing_error.txt" "w"]
4645 Msg Status "*** Timing summary ***"
4646 Msg Status "WNS: $wns"
4647 Msg Status "TNS: $tns"
4648 Msg Status "WHS: $whs"
4649 Msg Status "THS: $ths"
4650 Msg Status "TPWS: $tpws"
4656 puts $status_file "## $project_name Timing summary"
4658 m add row "| **Parameter** | \"**value (ns)**\" |"
4659 m add row "| --- | --- |"
4660 m add row "| WNS: | $wns |"
4661 m add row "| TNS: | $tns |"
4662 m add row "| WHS: | $whs |"
4663 m add row "| THS: | $ths |"
4664 m add row "| TPWS: | $tpws |"
4666 puts $status_file [m format 2string]
4667 puts $status_file "\n"
4668 if {$timing_ok == 1} {
4669 puts $status_file " Time requirements are met."
4671 puts $status_file "Time requirements are **NOT** met."
4673 puts $status_file "\n\n"
4677 if {$prog ne "100%"} {
4678 Msg Error "Implementation error"
4683 lassign [
GetRepoVersions [
file normalize ./Top/$project_name] $repo_path] sha
4685 Msg Info "Git describe set to $describe"
4687 set dst_dir [
file normalize "$repo_path/bin/$project_name\-$describe"]
4692 if {[
file exists $run_folder/versions.txt]} {
4693 file copy -force $run_folder/versions.txt $dst_dir
4695 Msg Warning "No versions file found in $run_folder/versions.txt"
4698 set timing_files [glob -nocomplain "$run_folder/timing_*.txt"]
4699 set timing_file [
file normalize [
lindex $timing_files 0]]
4701 if {[
file exists $timing_file]} {
4702 file copy -force $timing_file $dst_dir/
4704 Msg Warning "No timing file found, not a problem if running locally"
4708 if {[
IsVersal [get_property part [current_project]]]} {
4709 if {[get_property segmented_configuration [current_project]] == 1} {
4710 Msg Info "Versal Segmented configuration detected: exporting XSA file..."
4711 set xsa_name "$dst_dir/[
file tail $project_name]\-$describe.xsa"
4712 write_hw_platform -fixed -force -file $xsa_name
4716 set revision [get_current_revision]
4718 if {[
catch {execute_module -tool fit} result]} {
4719 Msg Error "Result: $result\n"
4720 Msg Error "Place & Route failed. See the report file.\n"
4722 Msg Info "\nINFO: Place & Route was successful for revision $revision.\n"
4725 if {[
catch {execute_module -tool sta -args "--do_report_timing"} result]} {
4726 Msg Error "Result: $result\n"
4727 Msg Error "Time Quest failed. See the report file.\n"
4729 Msg Info "Time Quest was successfully run for revision $revision.\n"
4732 set panel "Timing Analyzer||Timing Analyzer Summary"
4733 set device [get_report_panel_data -name $panel -col 1 -row_name "Device Name"]
4734 set timing_model [get_report_panel_data -name $panel -col 1 -row_name "Timing Models"]
4735 set delay_model [get_report_panel_data -name $panel -col 1 -row_name "Delay Model"]
4737 Msg Info "*******************************************************************"
4738 Msg Info "Device: $device"
4739 Msg Info "Timing Models: $timing_model"
4740 Msg Info "Delay Model: $delay_model"
4743 Msg Info "*******************************************************************"
4746 Msg Info "Starting implementation flow..."
4747 if {[
catch {run_tool -name {PLACEROUTE}}]} {
4748 Msg Error "PLACEROUTE FAILED!"
4750 Msg Info "PLACEROUTE PASSED."
4754 Msg Info "Run VERIFYTIMING ..."
4755 if {[
catch {run_tool -name {VERIFYTIMING} -script {Hog/Tcl/integrated/libero_timing.tcl}}]} {
4756 Msg CriticalWarning "VERIFYTIMING FAILED!"
4758 Msg Info "VERIFYTIMING PASSED \n"
4764 lassign [
GetRepoVersions [
file normalize ./Top/$project_name] $repo_path] sha
4766 Msg Info "Git describe set to $describe"
4768 set dst_dir [
file normalize "$repo_path/bin/$project_name\-$describe"]
4769 file mkdir $dst_dir/reports
4772 if {[
file exists $run_folder/versions.txt]} {
4773 file copy -force $run_folder/versions.txt $dst_dir
4775 Msg Warning "No versions file found in $run_folder/versions.txt"
4778 set timing_file_path [
file normalize "$repo_path/Projects/timing_libero.txt"]
4779 if {[
file exists $timing_file_path]} {
4780 file copy -force $timing_file_path $dst_dir/reports/Timing.txt
4781 set timing_file [open $timing_file_path "r"]
4782 set status_file [open "$dst_dir/timing.txt" "w"]
4783 puts $status_file "## $project_name Timing summary\n\n"
4784 puts $status_file "| | |"
4785 puts $status_file "| --- | --- |"
4786 while {[
gets $timing_file line] >= 0} {
4787 if {[
string match "SUMMARY" $line]} {
4788 while {[
gets $timing_file line] >= 0} {
4789 if {[
string match "END SUMMARY" $line]} {
4792 if {[
string first ":" $line] == -1} {
4795 set out_string "| [
string map {: | } $line] |"
4796 puts $status_file "$out_string"
4801 Msg Warning "No timing file found, not a problem if running locally"
4806 set force_rst "-forceOne"
4808 prj_run Map $force_rst
4809 prj_run PAR $force_rst
4821 proc GenerateBitstreamOnly {project_name {repo_path .}} {
4823 lassign [
GetRepoVersions [
file normalize ./Top/$project_name] $repo_path] sha
4825 set dst_dir [
file normalize "$repo_path/bin/$project_name\-$describe"]
4827 cd Projects/$project_name/$project_name.runs/impl_1
4828 Msg Info "Running pre-bitstream..."
4829 source $repo_path/Hog/Tcl/integrated/pre-bitstream.tcl
4831 Msg Info "Writing bitstream for $project_name..."
4833 write_bitstream -force $dst_dir/$project_name-$describe.bit
4835 Msg Info "Running post-bitstream..."
4836 source $repo_path/Hog/Tcl/integrated/post-bitstream.tcl
4845 proc LaunchSimulation {project_name lib_path simsets {repo_path .} {scripts_only 0} {compile_only 0}} {
4848 set project [
file tail $project_name]
4849 set main_sim_folder [
file normalize "$repo_path/Projects/$project_name/$project.sim/"]
4851 if {$simsets != ""} {
4852 dict for {simset sim_dict} $simsets {
4853 lappend simsets_todo $simset
4855 Msg Info "Will run only the following simulation's sets (if they exist): $simsets_todo"
4858 if {$scripts_only == 1} {
4859 Msg Info "Only generating simulation scripts, not running simulations..."
4862 if {$compile_only == 1} {
4863 Msg Info "Only compiling simulation libraries, not running simulations..."
4868 set sim_dic [dict create]
4870 Msg Info "Retrieving list of simulation sets..."
4871 foreach s [get_filesets] {
4873 set use_simpass_str 0
4876 set type [get_property FILESET_TYPE $s]
4877 if {$type eq "SimulationSrcs"} {
4878 if {$simsets_todo != "" && $s ni $simsets_todo} {
4879 Msg Info "Skipping $s as it was not specified with the -simset option..."
4882 set sim_dict [
DictGet $simsets $s]
4883 set simulator [
DictGet $sim_dict "simulator"]
4884 set_property "target_simulator" $simulator [current_project]
4885 set hog_sim_props [
DictGet $sim_dict "hog"]
4886 dict for {prop_name prop_val} $hog_sim_props {
4887 # If HOG_SIMPASS_STR is set, use the HOG_SIMPASS_STR string to search for in logs, after simulation is done
4888 if {[string toupper $prop_name] == "HOG_SIMPASS_STR" && $prop_val != ""} {
4889 Msg Info "Setting simulation pass string as '$prop_val'"
4890 set use_simpass_str 1
4891 set simpass_str $prop_val
4893 if {[string toupper $prop_name] == "HOG_SILENT_SIM" && $prop_val == 1} {
4894 set quiet_sim " -quiet"
4900 Msg Info "Creating simulation scripts for $s..."
4901 if {[
file exists $repo_path/Top/$project_name/pre-simulation.tcl]} {
4902 Msg Info "Running $repo_path/Top/$project_name/pre-simulation.tcl"
4903 source $repo_path/Top/$project_name/pre-simulation.tcl
4905 if {[
file exists $repo_path/Top/$project_name/pre-$s-simulation.tcl]} {
4906 Msg Info "Running $repo_path/Top/$project_name/pre-$s-simulation.tcl"
4907 source Running $repo_path/Top/$project_name/pre-$s-simulation.tcl
4909 current_fileset -simset $s
4910 set sim_dir $main_sim_folder/$s/behav
4911 set sim_output_logfile $sim_dir/xsim/simulate.log
4912 if {([
string tolower $simulator] eq "xsim")} {
4913 set sim_name "xsim:$s"
4915 set simulation_command "launch_simulation $quiet_sim -simset [get_filesets $s]"
4916 if {[
catch $simulation_command log]} {
4919 Msg CriticalWarning "Simulation failed for $s, error info: $::errorInfo"
4920 lappend failed $sim_name
4925 if {$use_simpass_str == 1} {
4928 set file_desc [open $sim_output_logfile r]
4929 set log [read $file_desc]
4932 Msg Info "Searching for simulation pass string: '$simpass_str'"
4933 if {[
string first $simpass_str $log] == -1} {
4934 Msg CriticalWarning "Simulation failed for $s, error info: '$simpass_str' NOT found!"
4935 lappend failed $sim_name
4938 lappend success $sim_name
4942 lappend success $sim_name
4946 Msg Info "Simulation library path is set to $lib_path."
4948 if {!([
file exists $lib_path])} {
4949 Msg Warning "Could not find simulation library path: $lib_path, $simulator simulation will not work."
4953 if {$simlib_ok == 1} {
4954 set_property "compxlib.${simulator}_compiled_library_dir" [
file normalize $lib_path] [current_project]
4955 launch_simulation -scripts_only -simset [get_filesets $s]
4956 set top_name [get_property TOP $s]
4957 set sim_script [
file normalize $sim_dir/$simulator/]
4958 Msg Info "Adding simulation script location $sim_script for $s..."
4959 lappend sim_scripts $sim_script
4960 dict append sim_dic $sim_script $s
4962 Msg Error "Cannot run $simulator simulations without a valid library path"
4969 if {[
info exists sim_scripts] && $scripts_only == 0} {
4971 Msg Info "Generating IP simulation targets, if any..."
4973 foreach ip [get_ips] {
4974 generate_target simulation -quiet $ip
4979 Msg Info "====== Starting simulations runs ======"
4982 foreach s $sim_scripts {
4984 set cmd ./compile.sh
4985 Msg Info " ************* Compiling: $s ************* "
4987 set sim_name "comp:[dict get $sim_dic $s]"
4989 Msg CriticalWarning "Compilation failed for $s, error info: $::errorInfo"
4990 lappend failed $sim_name
4992 lappend success $sim_name
4994 Msg Info "###################### Compilation log starts ######################"
4995 Msg Info "\n\n$log\n\n"
4996 Msg Info "###################### Compilation log ends ######################"
4998 if {$compile_only == 1} {
5001 if {[
file exists "./elaborate.sh"] } {
5002 set cmd ./elaborate.sh
5003 Msg Info " ************* Elaborating: $s ************* "
5005 set sim_name "elab:[dict get $sim_dic $s]"
5007 Msg CriticalWarning "Elaboration failed for $s, error info: $::errorInfo"
5008 lappend failed $sim_name
5010 lappend success $sim_name
5012 Msg Info "###################### Elaboration log starts ######################"
5013 Msg Info "\n\n$log\n\n"
5014 Msg Info "###################### Elaboration log ends ######################"
5016 set cmd ./simulate.sh
5017 Msg Info " ************* Simulating: $s ************* "
5022 if {$use_simpass_str == 1} {
5023 if {[
string first $simpass_str $log] == -1} {
5027 Msg Debug "Simulation pass string not set, relying on simulator exit code."
5031 set sim_name "sim:[dict get $sim_dic $s]"
5033 Msg CriticalWarning "Simulation failed for $s, error info: $::errorInfo"
5034 lappend failed $sim_name
5036 lappend success $sim_name
5038 Msg Info "###################### Simulation log starts ######################"
5039 Msg Info "\n\n$log\n\n"
5040 Msg Info "###################### Simulation log ends ######################"
5045 if {[
llength $success] > 0} {
5046 set successes [
join $success "\n"]
5047 Msg Info "The following simulation sets were successful:\n\n$successes\n\n"
5050 if {[
llength $failed] > 0} {
5051 set failures [
join $failed "\n"]
5052 Msg Error "The following simulation sets have failed:\n\n$failures\n\n"
5054 }
elseif {[
llength $success] > 0} {
5055 Msg Info "All the [
llength $success] compilations, elaborations and simulations were successful."
5058 Msg Info "Simulation done."
5060 Msg Warning "Simulation is not yet supported for [
GetIDEName]."
5071 proc LaunchRTLAnalysis {} {
5073 Msg Info "Starting RTL Analysis..."
5074 synth_design -rtl -name rtl_1
5087 proc LaunchSynthesis {reset do_create run_folder project_name {repo_path .} {ext_path ""} {njobs 4}} {
5089 if {$reset == 1 && $do_create == 0} {
5090 Msg Info "Resetting run before launching synthesis..."
5094 source $repo_path/Hog/Tcl/integrated/pre-synthesis.tcl
5096 launch_runs synth_1 -jobs $njobs -dir $run_folder
5098 set prog [get_property PROGRESS [get_runs synth_1]]
5099 set status [get_property STATUS [get_runs synth_1]]
5100 Msg Info "Run: synth_1 progress: $prog, status : $status"
5107 lassign [
GetRepoVersions [
file normalize ./Top/$project_name] $repo_path $ext_path] sha
5109 Msg Info "Git describe set to $describe"
5112 set xci_file [get_property IP_FILE $ip]
5114 set xci_path [
file dirname $xci_file]
5115 set xci_ip_name [
file rootname [
file tail $xci_file]]
5116 foreach rptfile [glob -nocomplain -directory $xci_path *.rpt] {
5117 file copy $rptfile $repo_path/bin/$project_name-$describe/reports
5121 if {$prog ne "100%"} {
5122 Msg Error "Synthesis error, status is: $status"
5126 set project [
file tail [
file rootname $project_name]]
5128 Msg Info "Number of jobs set to $njobs."
5129 set_global_assignment -name NUM_PARALLEL_PROCESSORS $njobs
5133 lassign [
GetRepoVersions [
file normalize $repo_path/Top/$project_name] $repo_path] sha
5136 set revision [get_current_revision]
5139 set tool_and_command [
split [get_global_assignment -name PRE_FLOW_SCRIPT_FILE] ":"]
5140 set tool [
lindex $tool_and_command 0]
5141 set pre_flow_script [
lindex $tool_and_command 1]
5142 set cmd "$tool -t $pre_flow_script quartus_map $project $revision"
5148 Msg Warning "Can not execute command $cmd"
5149 Msg Warning "LOG: $log"
5151 Msg Info "Pre flow script executed!"
5155 if {![is_project_open]} {
5156 Msg Info "Re-opening project file $project_name..."
5157 project_open $project -current_revision
5161 if {[
catch {execute_module -tool ipg -args "--clean"} result]} {
5162 Msg Error "Result: $result\n"
5163 Msg Error "IP Generation failed. See the report file.\n"
5165 Msg Info "IP Generation was successful for revision $revision.\n"
5169 if {[
catch {execute_module -tool map -args "--parallel"} result]} {
5170 Msg Error "Result: $result\n"
5171 Msg Error "Analysis & Synthesis failed. See the report file.\n"
5173 Msg Info "Analysis & Synthesis was successful for revision $revision.\n"
5177 defvar_set -name RWNETLIST_32_64_MIXED_FLOW -value 0
5179 Msg Info "Run SYNTHESIS..."
5180 if {[
catch {run_tool -name {SYNTHESIZE}}]} {
5181 Msg Error "SYNTHESIZE FAILED!"
5183 Msg Info "SYNTHESIZE PASSED!"
5189 set force_rst "-forceOne"
5191 prj_run Synthesis $force_rst
5192 if {[prj_syn] == "synplify"} {
5193 prj_run Translate $force_rst
5196 Msg Error "Impossible condition. You need to run this in an IDE."
5207 proc LaunchVitisBuild {project_name {repo_path .} {stage "presynth"}} {
5208 set proj_name $project_name
5209 set bin_dir [
file normalize "$repo_path/bin"]
5213 if {[
catch {
set ws_apps [app list -dict]}]} {
set ws_apps ""}
5214 lassign [
GetRepoVersions [
file normalize $repo_path/Top/$proj_name] $repo_path] commit version hog_hash hog_ver top_hash top_ver \
5215 libs hashes vers cons_ver cons_hash ext_names ext_hashes xml_hash xml_ver user_ip_repos user_ip_hashes user_ip_vers
5217 if {$commit == 0 } {
set commit $this_commit}
5221 foreach app_name [dict keys $ws_apps] {
5222 app config -name $app_name -set build-config Release
5225 WriteGenerics "vitisbuild" $repo_path $proj_name $date $timee $commit $version $top_hash $top_ver $hog_hash $hog_ver $cons_ver $cons_hash $libs \
5226 $vers $hashes $ext_names $ext_hashes $user_ip_repos $user_ip_vers $user_ip_hashes $flavour $xml_ver $xml_hash
5227 foreach app_name [dict keys $ws_apps] { app build -name $app_name}
5229 if {$stage == "presynth"} {
5230 Msg Info "Done building apps for $project_name..."
5234 Msg Info "Evaluating Git sha for $project_name..."
5235 lassign [
GetRepoVersions [
file normalize ./Top/$project_name] $repo_path] sha
5238 Msg Info "Hog describe set to: $describe"
5239 set dst_dir [
file normalize "$bin_dir/$proj_name\-$describe"]
5240 if {![
file exists $dst_dir]} {
5241 Msg Info "Creating $dst_dir..."
5245 foreach app_name [dict keys $ws_apps] {
5246 set main_file "$repo_path/Projects/$project_name/vitis_classic/$app_name/Release/$app_name.elf"
5247 set dst_main [
file normalize "$dst_dir/[
file tail $proj_name]\-$app_name\-$describe.elf"]
5249 if {![
file exists $main_file]} {
5250 Msg Error "No Vitis .elf file found. Perhaps there was an issue building it?"
5254 Msg Info "Copying main binary file $main_file into $dst_main..."
5255 file copy -force $main_file $dst_main
5264 proc GetProcFromProps {repo_path props platform} {
5265 if {[dict exists $props "platform:$platform" "BIF"]} {
5266 set bif_file [dict get $props "platform:$platform" "BIF"]
5268 set bif_file "$repo_path/$bif_file"
5272 Msg CriticalWarning "BIF file not found in platform ($platform) properties, skipping bootable image (.bin) generation"
5282 proc GetBifFromProps {repo_path props platform} {
5283 if {[dict exists $props "platform:$platform" "BIF"]} {
5284 set bif_file [dict get $props "platform:$platform" "BIF"]
5286 set bif_file "$repo_path/$bif_file"
5290 Msg CriticalWarning "BIF file not found in platform ($platform) properties, skipping bootable image (.bin) generation"
5299 proc GetPartFromProps {props} {
5300 if {[dict exists $props "main" "PART"]} {
5301 return [
string tolower [dict get $props "main" "PART"]]
5303 Msg Error "Part number not found in properties"
5312 proc GetArchFromPart {part} {
5314 if {[
string match "xczu*" $part]} {
5316 }
elseif {[
string match "xc7z*" $part]} {
5318 }
elseif {[
string match "xck26*" $part]} {
5321 Msg CriticalWarning "Unknown part number: $part"
5330 proc GetAppsFromProps {props {list_names 0}} {
5331 set prop_apps [dict filter $props key {app:*}]
5332 set apps [dict create]
5333 set app_names [list]
5335 dict for {app_key app_value} $prop_apps {
5336 if {[regexp {^app:(.+)$} $app_key -> app_name]} {
5337 set app_name [string trim [string tolower $app_name]]
5338 # Convert only the keys of the inner dictionary to lowercase
5339 set app_value_lower [dict create]
5340 dict for {key value} $app_value {
5341 dict set app_value_lower [string tolower $key] $value
5343 dict set apps $app_name $app_value_lower
5344 lappend app_names $app_name
5347 if {$list_names eq 1} {
5358 proc GetPlatformsFromProps {props {list_names 0} {lower_case 0}} {
5359 set platforms [dict create]
5360 set platform_names [list]
5361 set prop_platforms [dict filter $props key {platform:*}]
5363 dict for {platform_key platform_value} $prop_platforms {
5364 if {[regexp {^platform:(.+)$} $platform_key -> platform_name]} {
5365 if {$lower_case == 1} {
5366 set platform_name [string trim [string tolower $platform_name]]
5368 set platform_name [string trim $platform_name]
5370 dict set platforms $platform_name $platform_value
5371 lappend platform_names $platform_name
5374 if {$list_names eq 1} {
5375 return $platform_names
5390 proc GenerateBootArtifacts {properties repo_path proj_dir bin_dir proj_name describe bitfile mmi_file} {
5391 set elf_list [glob -nocomplain "$bin_dir/*.elf"]
5395 if {[
llength $elf_list] == 0} {
5396 Msg Warning "No ELF files found in $bin_dir, skipping generation of boot artifacts"
5400 if {![
file exists $bitfile]} {
5401 Msg Warning "Bitfile $bitfile does not exist, skipping generation of boot artifacts"
5405 Msg Info "Generating boot artifacts for $proj_name..."
5406 Msg Info "Found apps: $apps"
5407 Msg Info "Found platforms: $platforms"
5411 foreach elf_file $elf_list {
5412 set elf_name [
file rootname [
file tail $elf_file]]
5413 Msg Info "Found elf name: $elf_name"
5414 Msg Info "Removing $describe from elf"
5417 if {[regexp "^(.+)-(.+)-$describe\$" $elf_name -> project_name elf_app]} {
5418 set elf_app [
string trim [
string tolower $elf_app]]
5419 Msg Info "Found elf_app: $elf_app"
5421 Msg Error "Could not extract app name from elf file: $elf_name"
5424 Msg Info "Removed project name ($project_name) and $describe from elf"
5426 set app_conf [dict get $apps $elf_app]
5427 set plat [dict get $app_conf "platform"]
5428 set app_proc [dict get $app_conf "proc"]
5431 if {[regexp -nocase {microblaze|risc} $app_proc]} {
5432 Msg Info "Detected soft processor ($app_proc) for $elf_app, updating bitstream memory with ELF file..."
5435 if {[dict size $proc_map] == 0} {
5436 Msg Error "Failed to read map from $proc_map_file"
5439 Msg Info "Found processor map: $proc_map"
5441 set proc_cell [
lindex [
split [dict get $proc_map $app_proc] ":"] 1]
5442 Msg Info "Updating memory at processor cell: $proc_cell"
5444 set update_mem_cmd "updatemem -force -meminfo $mmi_file -data $elf_file -bit $bitfile -proc $proc_cell -out $bitfile"
5445 set ret [
catch {
exec -ignorestderr {*}$update_mem_cmd >@ stdout} result]
5447 Msg Error "Error updating memory for $elf_app: $result"
5449 Msg Info "Done updating memory for $elf_app"
5452 Msg Info "Detected hard processor ($app_proc) for $elf_app. Make sure the .elf file is defined in the platform ($plat)\
5453 .bif file to be included in the bootable binary image (.bin) generation."
5459 foreach plat $platforms {
5461 if {$bif_file != ""} {
5462 Msg Info "Generating bootable binary image (.bin) for $plat"
5464 Msg Info "Architecture: $arch"
5465 Msg Info "BIF file: $bif_file"
5466 set bootgen_cmd "bootgen -arch $arch -image $bif_file -o i $bin_dir/$proj_name-$plat-$describe.bin -w on"
5467 set ret [
catch {
exec -ignorestderr {*}$bootgen_cmd >@ stdout} result]
5469 Msg Error "Error generating bootable binary image (.bin) for $elf_app: $result"
5471 Msg Info "Done generating bootable binary image (.bin) for $plat"
5480 proc ReadProcMap {proc_map_file} {
5481 set proc_map [dict create]
5482 if {[
file exists $proc_map_file]} {
5483 set f [open $proc_map_file "r"]
5484 while {[
gets $f line] >= 0} {
5485 Msg Debug "Line: $line"
5486 if {[regexp {^(\S+)\s+(.+)$} $line -> key value]} {
5487 Msg Debug "Found key: $key, value: $value in proc map file"
5488 dict set proc_map $key $value
5502 proc ListProjects {{repo_path .} {print 1} {ret_conf 0}} {
5503 set top_path [
file normalize $repo_path/Top]
5504 set confs [
findFiles [
file normalize $top_path] hog.conf]
5506 set confs [lsort $confs]
5510 set p [
Relative $top_path [
file dirname $c]]
5513 if {$description eq "test"} {
5514 set description " - Test project"
5515 }
elseif {$description ne ""} {
5516 set description " - $description"
5519 if {$print == 1 || $description ne " - Test project"} {
5521 set g [
file dirname $p]
5532 if {$ret_conf == 0} {
5544 proc Md5Sum {file_name} {
5545 if {!([
file exists $file_name])} {
5546 Msg Warning "Could not find $file_name."
5549 if {[
catch {
package require md5 2.0.7} result]} {
5550 Msg Warning "Tcl package md5 version 2.0.7 not found ($result), will use command line..."
5551 set hash [
lindex [
Execute md5sum $file_name] 0]
5553 set file_hash [
string tolower [md5::md5 -hex -file $file_name]]
5567 proc MergeDict {dict0 dict1 {remove_duplicates 1}} {
5568 set outdict [dict merge $dict1 $dict0]
5569 foreach key [dict keys $dict1] {
5570 if {[dict exists $dict0 $key]} {
5571 set temp_list [dict get $dict1 $key]
5572 foreach item $temp_list {
5574 if {[
IsInList $item [
DictGet $outdict $key]] == 0 || $remove_duplicates == 0} {
5576 dict lappend outdict $key $item
5588 proc MoveElementToEnd {inputList element} {
5589 set index [lsearch $inputList $element]
5591 set inputList [
lreplace $inputList $index $index]
5592 lappend inputList $element
5601 proc OpenProject {project_file repo_path} {
5603 open_project $project_file
5605 set project_folder [
file dirname $project_file]
5606 set project [
file tail [
file rootname $project_file]]
5607 if {[
file exists $project_folder]} {
5609 if {![is_project_open]} {
5610 Msg Info "Opening existing project file $project_file..."
5611 project_open $project -current_revision
5614 Msg Error "Project directory not found for $project_file."
5618 Msg Info "Opening existing project file $project_file..."
5620 open_project -file $project_file -do_backup_on_convert 1 -backup_file {./Projects/$project_file.zip}
5622 Msg Info "Opening existing project file $project_file..."
5623 prj_project open $project_file
5625 Msg Error "This IDE is currently not supported by Hog. Exiting!"
5632 return $tcl_platform(platform)
5642 proc ParseJSON {JSON_FILE JSON_KEY} {
5643 set result [
catch {
package require Tcl 8.4} TclFound]
5644 if {"$result" != "0"} {
5645 Msg CriticalWarning "Cannot find Tcl package version equal or higher than 8.4.\n $TclFound\n Exiting"
5649 set result [
catch {
package require json} JsonFound]
5650 if {"$result" != "0"} {
5651 Msg CriticalWarning "Cannot find JSON package equal or higher than 1.0.\n $JsonFound\n Exiting"
5654 set JsonDict [json::json2dict $JSON_FILE]
5655 set result [
catch {dict get $JsonDict $JSON_KEY} RETURNVALUE]
5656 if {"$result" != "0"} {
5657 Msg CriticalWarning "Cannot find $JSON_KEY in $JSON_FILE\n Exiting"
5670 proc ProjectExists {project {repo_path .}} {
5671 set index [lsearch -exact [
ListProjects $repo_path 0] $project]
5677 Msg Error "Project $project not found in repository $repo_path"
5688 proc ReadConf {file_name} {
5689 if {[
catch {
package require inifile 0.2.3} ERROR]} {
5690 Msg Error "Could not find inifile package version 0.2.3 or higher.\n
5691 To use ghdl, libero or diamond with Hog, you need to install the tcllib package\n
5692 You can install it with 'sudo apt install tcllib' on Debian/Ubuntu or 'sudo dnf install tcllib' on Fedora/RedHat/CentOs."
5696 ::ini::commentchar "#"
5697 set f [::ini::open $file_name]
5698 set properties [dict create]
5699 foreach sec [::ini::sections $f] {
5701 if {$new_sec == "files"} {
5704 set key_pairs [::ini::get $f $sec]
5706 regsub -all {\{\"} $key_pairs "\{" key_pairs
5707 regsub -all {\"\}} $key_pairs "\}" key_pairs
5709 dict set properties $new_sec [dict create {*}$key_pairs]
5722 proc ReadExtraFileList {extra_file_name} {
5723 set extra_file_dict [dict create]
5724 if {[
file exists $extra_file_name]} {
5725 set file [open $extra_file_name "r"]
5726 set file_data [read $file]
5729 set data [
split $file_data "\n"]
5730 foreach line $data {
5731 if {![regexp {^ *$} $line] & ![regexp {^ *\#} $line]} {
5732 set ip_and_md5 [regexp -all -inline {\S+} $line]
5733 dict lappend extra_file_dict "[
lindex $ip_and_md5 0]" "[
lindex $ip_and_md5 1]"
5737 return $extra_file_dict
5757 proc ReadListFile {args} {
5760 if {[
catch {
package require cmdline} ERROR]} {
5761 puts "$ERROR\n If you are running this script on tclsh, you can fix this by installing 'tcllib'"
5767 {lib.arg "" "The name of the library files will be added to, if not given will be extracted from the file name."}
5768 {fileset.arg "" "The name of the library, from the main list file"}
5769 {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."}
5770 {print_log "If set, will use PrintFileTree for the VIEW directive"}
5771 {indent.arg "" "Used to indent files with the VIEW directive"}
5774 set usage "USAGE: ReadListFile \[options\] <list file> <path>"
5775 if {[
catch {
array set options [
cmdline::getoptions args $parameters $usage]}] || [
llength $args] != 2} {
5781 set list_file [
lindex $args 0]
5782 set path [
lindex $args 1]
5783 set sha_mode $options(sha_mode)
5784 set lib $options(lib)
5785 set fileset $options(fileset)
5786 set print_log $options(print_log)
5787 set indent $options(indent)
5789 if {$sha_mode == 1} {
5790 set sha_mode_opt "-sha_mode"
5795 if {$print_log == 1} {
5796 set print_log_opt "-print_log"
5798 set print_log_opt ""
5803 set lib [
file rootname [
file tail $list_file]]
5805 set fp [open $list_file r]
5806 set file_data [read $fp]
5808 set list_file_ext [
file extension $list_file]
5809 switch $list_file_ext {
5811 if {$fileset eq ""} {
5817 set fileset "constrs_1"
5820 set fileset "sources_1"
5824 set libraries [dict create]
5825 set filesets [dict create]
5826 set properties [dict create]
5828 set data [
split $file_data "\n"]
5830 set n [
llength $data]
5832 if {$print_log == 1} {
5833 if {$indent eq ""} {
5834 set list_file_rel [
file tail $list_file]
5835 Msg Status "\n$list_file_rel"
5839 Msg Debug "$n lines read from $list_file."
5842 foreach line $data {
5844 if {![regexp {^[\t\s]*$} $line] & ![regexp {^[\t\s]*\#} $line]} {
5845 set file_and_prop [regexp -all -inline {\S+} $line]
5846 set srcfile [
lindex $file_and_prop 0]
5847 set srcfile "$path/$srcfile"
5849 set srcfiles [glob -nocomplain $srcfile]
5852 if {$srcfiles != $srcfile && ![
string equal $srcfiles ""]} {
5853 Msg Debug "Wildcard source expanded from $srcfile to $srcfiles"
5855 if {![
file exists $srcfile]} {
5856 if {$print_log == 0} {
5857 Msg CriticalWarning "File: $srcfile (from list file: $list_file) does not exist."
5863 foreach vhdlfile $srcfiles {
5864 if {[
file exists $vhdlfile]} {
5865 set vhdlfile [
file normalize $vhdlfile]
5866 set extension [
file extension $vhdlfile]
5868 set prop [
lrange $file_and_prop 1 end]
5871 set library [
lindex [regexp -inline {\ylib\s*=\s*(.+?)\y.*} $prop] 1]
5872 if {$library == ""} {
5876 if {$extension == $list_file_ext} {
5879 set ref_path [
lindex [regexp -inline {\ypath\s*=\s*(\S+).*} $prop] 1]
5880 if {$ref_path eq ""} {
5883 set ref_path [
file normalize $path/$ref_path]
5885 Msg Debug "List file $vhdlfile found in list file, recursively opening it using path \"$ref_path\"..."
5886 if {$print_log == 1} {
5887 if {[
file normalize $last_printed] ne [
file normalize $vhdlfile]} {
5888 Msg Status "$indent Inside [
file tail $vhdlfile]:"
5892 lassign [
ReadListFile {*}"-indent \" $indent\" -lib $library -fileset $fileset $sha_mode_opt $print_log_opt $vhdlfile $ref_path"] l p fs
5894 set properties [
MergeDict $p $properties]
5896 }
elseif {[lsearch {.src .sim .con ReadExtraFileList} $extension] >= 0} {
5898 Msg Error "$vhdlfile cannot be included into $list_file, $extension files must be included into $extension files."
5901 regsub -all " *= *" $prop "=" prop
5905 if {[
string first "lib=" $p] == -1} {
5907 set pos [
string first "=" $p]
5911 set prop_name [
string range $p 0 [
expr {$pos - 1}]]
5914 dict lappend properties $vhdlfile $p
5915 Msg Debug "Adding property $p to $vhdlfile..."
5916 }
elseif {$list_file_ext != ".ipb"} {
5917 Msg Warning "Setting Property $p is not supported for file $vhdlfile or it is already its default. \
5922 if {[lsearch {.xci .ip .bd .xcix} $extension] >= 0} {
5924 set lib_name "ips.src"
5925 }
elseif {[
IsInList $extension {.vhd .vhdl}] || $list_file_ext == ".sim"} {
5927 if {![
IsInList $extension {.vhd .vhdl}]} {
5928 set lib_name "others.sim"
5930 set lib_name "$library$list_file_ext"
5932 }
elseif {$list_file_ext == ".con"} {
5933 set lib_name "sources.con"
5934 }
elseif {$list_file_ext == ".ipb"} {
5935 set lib_name "xml.ipb"
5936 }
elseif { [
IsInList $list_file_ext {.src}] && [
IsInList $extension {.c .cpp .h .hpp}] } {
5938 set lib_name "$library$list_file_ext"
5941 set lib_name "others.src"
5944 Msg Debug "Appending $vhdlfile to $lib_name list..."
5945 dict lappend libraries $lib_name $vhdlfile
5946 if {$sha_mode != 0 && [
file type $vhdlfile] eq "link"} {
5949 dict lappend libraries $lib_name $real_file
5950 Msg Debug "File $vhdlfile is a soft link, also adding the real file: $real_file"
5955 if {[dict exists $filesets $fileset] == 0} {
5957 Msg Debug "Adding $fileset to the fileset dictionary..."
5958 Msg Debug "Adding library $lib_name to fileset $fileset..."
5959 dict set filesets $fileset $lib_name
5963 Msg Debug "Adding library $lib_name to fileset $fileset..."
5964 dict lappend filesets $fileset $lib_name
5970 Msg CriticalWarning "File $vhdlfile not found."
5976 if {$sha_mode != 0} {
5978 if {$list_file_ext eq ".ipb"} {
5979 set sha_lib "xml.ipb"
5981 set sha_lib $lib$list_file_ext
5983 dict lappend libraries $sha_lib [
file normalize $list_file]
5984 if {[
file type $list_file] eq "link"} {
5987 dict lappend libraries $lib$list_file_ext $real_file
5988 Msg Debug "List file $list_file is a soft link, also adding the real file: $real_file"
5991 return [list $libraries $properties $filesets]
5999 proc Relative {base dst} {
6000 if {![
string equal [
file pathtype $base] [
file pathtype $dst]]} {
6001 Msg CriticalWarning "Unable to compute relation for paths of different path types: [
file pathtype $base] vs. [
file pathtype $dst], ($base vs. $dst)"
6005 set base [
file normalize [
file join [
pwd] $base]]
6006 set dst [
file normalize [
file join [
pwd] $dst]]
6009 set base [
file split $base]
6010 set dst [
file split $dst]
6012 while {[
string equal [
lindex $dst 0] [
lindex $base 0]]} {
6013 set dst [
lrange $dst 1 end]
6014 set base [
lrange $base 1 end]
6015 if {![
llength $dst]} {break}
6018 set dstlen [
llength $dst]
6019 set baselen [
llength $base]
6021 if {($dstlen == 0) && ($baselen == 0)} {
6024 while {$baselen > 0} {
6025 set dst [
linsert $dst 0 ..]
6028 set dst [
eval [
linsert $dst 0 file join]]
6039 proc RelativeLocal {pathName filePath} {
6040 if {[
string first [
file normalize $pathName] [
file normalize $filePath]] != -1} {
6041 return [
Relative $pathName $filePath]
6052 proc RemoveDuplicates {mydict} {
6053 set new_dict [dict create]
6054 foreach key [dict keys $mydict] {
6055 set values [
DictGet $mydict $key]
6056 foreach value $values {
6057 set idxs [
lreverse [
lreplace [lsearch -exact -all $values $value] 0 0]]
6059 set values [
lreplace $values $idx $idx]
6062 dict set new_dict $key $values
6073 proc ResetRepoFiles {reset_file} {
6074 if {[
file exists $reset_file]} {
6075 Msg Info "Found $reset_file, opening it..."
6076 set fp [open $reset_file r]
6077 set wild_cards [lsearch -all -inline -not -regexp [
split [read $fp] "\n"] "^ *$"]
6079 Msg Info "Found the following files/wild cards to restore if modified: $wild_cards..."
6080 foreach w $wild_cards {
6082 if {[
llength $mod_files] > 0} {
6083 Msg Info "Found modified $w files: $mod_files, will restore them..."
6086 Msg Info "No modified $w files found."
6097 proc RestoreModifiedFiles {{repo_path "."} {pattern "."}} {
6100 set ret [
Git checkout $pattern]
6111 proc SearchHogProjects {dir} {
6112 set projects_list {}
6113 if {[
file exists $dir]} {
6114 if {[
file isdirectory $dir]} {
6115 foreach proj_dir [glob -nocomplain -types d $dir/*] {
6116 if {![regexp {^.*Top/+(.*)$} $proj_dir dummy proj_name]} {
6117 Msg Warning "Could not parse Top directory $dir"
6120 if {[
file exists "$proj_dir/hog.conf"]} {
6121 lappend projects_list $proj_name
6124 lappend projects_list $p
6129 Msg Error "Input $dir is not a directory!"
6132 Msg Error "Directory $dir doesn't exist!"
6134 return $projects_list
6143 proc SetGenericsSimulation {repo_path proj_dir target} {
6144 set top_dir "$repo_path/Top/$proj_dir"
6145 set simsets [get_filesets]
6146 if {$simsets != ""} {
6147 foreach simset $simsets {
6149 if {[get_property FILESET_TYPE $simset] != "SimulationSrcs"} {
6153 set merged_generics_dict [dict create]
6157 set simset_generics [
DictGet $simset_dict "generics"]
6158 set merged_generics_dict [
MergeDict $merged_generics_dict $simset_generics 0]
6160 set_property generic $generic_str [get_filesets $simset]
6161 Msg Debug "Setting generics $generic_str for simulator $target\
6162 and simulation file-set $simset..."
6174 proc SetTopProperty {top_module fileset} {
6175 Msg Info "Setting TOP property to $top_module module"
6178 set_property "top" $top_module [get_filesets $fileset]
6181 set_global_assignment -name TOP_LEVEL_ENTITY $top_module
6183 set_root -module $top_module
6185 prj_impl option top $top_module
6190 proc VIVADO_PATH_PROPERTIES {} {
6191 return {"\.*\.TCL\.PRE$" "^.*\.TCL\.POST$" "^RQS_FILES$" "^INCREMENTAL\_CHECKPOINT$" "NOC\_SOLUTION\_FILE"}
6195 proc VITIS_PATH_PROPERTIES {} {
6196 return {"^HW$" "^XPFM$" "^LINKER-SCRIPT$" "^LIBRARIES$" "^LIBRARY-SEARCH-PATH$"}
6206 proc WriteConf {file_name config {comment ""}} {
6207 if {[
catch {
package require inifile 0.2.3} ERROR]} {
6208 puts "$ERROR\n If you are running this script on tclsh, you can fix this by installing 'tcllib'"
6212 ::ini::commentchar "#"
6213 set f [::ini::open $file_name w]
6215 foreach sec [dict keys $config] {
6216 set section [dict get $config $sec]
6217 dict for {p v} $section {
6218 if {[string trim $v] == ""} {
6219 Msg Warning "Property $p has empty value. Skipping..."
6222 ::ini::set $f $sec $p $v
6227 if {![
string equal "$comment" ""]} {
6228 ::ini::comment $f [
lindex [::ini::sections $f] 0] "" $comment
6229 set hog_header "Generated by Hog on [
clock format [
clock seconds] -format "%Y-%m-%d %H:%M:%S"]"
6230 ::ini::comment $f [
lindex [::ini::sections $f] 0] "" $hog_header
6245 proc WriteGenerics {mode repo_path design date timee\
6246 commit version top_hash top_ver hog_hash hog_ver \
6247 cons_ver cons_hash libs vers hashes ext_names ext_hashes \
6248 user_ip_repos user_ip_vers user_ip_hashes flavour {xml_ver ""} {xml_hash ""}} {
6249 Msg Info "Passing parameters/generics to project's top module..."
6252 set generic_string [
concat \
6264 if {$xml_hash != "" && $xml_ver != ""} {
6265 lappend generic_string \
6270 foreach l $libs v $vers h $hashes {
6273 lappend generic_string "$ver" "$hash"
6276 foreach e $ext_names h $ext_hashes {
6278 lappend generic_string "$hash"
6281 foreach repo $user_ip_repos v $user_ip_vers h $user_ip_hashes {
6282 set repo_name [
file tail $repo]
6283 set ver "[
string toupper $repo_name]_VER=[
FormatGeneric $v]"
6284 set hash "[
string toupper $repo_name]_SHA=[
FormatGeneric $h]"
6285 lappend generic_string "$ver" "$hash"
6288 if {$flavour != -1} {
6289 lappend generic_string "FLAVOUR=$flavour"
6295 set generic_string "$prj_generics $generic_string"
6301 if {$mode == "create" || [
IsISE]} {
6304 if {[
file exists $top_file]} {
6307 Msg Debug "Found top level generics $generics in $top_file"
6309 set filtered_generic_string ""
6311 foreach generic_to_set [
split [
string trim $generic_string]] {
6312 set key [
lindex [
split $generic_to_set "="] 0]
6313 if {[dict exists $generics $key]} {
6314 Msg Debug "Hog generic $key found in $top_name"
6315 lappend filtered_generic_string "$generic_to_set"
6317 Msg Warning "Generic $key is passed by Hog but is NOT present in $top_name."
6323 set generic_string $filtered_generic_string
6328 set_property generic $generic_string [current_fileset]
6329 Msg Info "Setting parameters/generics..."
6330 Msg Debug "Detailed parameters/generics: $generic_string"
6335 set simulator [get_property target_simulator [current_project]]
6336 if {$mode == "create"} {
6343 Msg Info "Setting Synplify parameters/generics one by one..."
6344 foreach generic $generic_string {
6345 Msg Debug "Setting Synplify generic: $generic"
6346 set_option -hdl_param -set "$generic"
6349 Msg Info "Setting Diamond parameters/generics one by one..."
6350 prj_impl option -impl Implementation0 HDL_PARAM "$generic_string"
6352 if {[
catch {
set ws_apps [app list -dict]}]} {
set ws_apps ""}
6354 foreach app_name [dict keys $ws_apps] {
6355 set defined_symbols [app config -name $app_name -get define-compiler-symbols]
6356 foreach generic_to_set [
split [
string trim $generic_string]] {
6357 set key [
lindex [
split $generic_to_set "="] 0]
6358 set value [
lindex [
split $generic_to_set "="] 1]
6359 if {[
string match "32'h*" $value]} {
6360 set value [
string map {"32'h" "0x"} $value]
6363 foreach symbol [
split $defined_symbols ";"] {
6364 if {[
string match "$key=*" $symbol]} {
6365 Msg Debug "Generic $key found in $app_name, removing it..."
6366 app config -name $app_name -remove define-compiler-symbols "$symbol"
6370 Msg Info "Setting Vitis parameters/generics for app $app_name: $key=$value"
6371 app config -name $app_name define-compiler-symbols "$key=$value"
6383 proc WriteGenericsToBdIPs {mode repo_path proj generic_string} {
6384 Msg Debug "Parameters/generics passed to WriteGenericsToIP: $generic_string"
6386 set bd_ip_generics false
6388 if {[dict exists $properties "hog"]} {
6389 set propDict [dict get $properties "hog"]
6390 if {[dict exists $propDict "PASS_GENERICS_TO_BD_IPS"]} {
6391 set bd_ip_generics [dict get $propDict "PASS_GENERICS_TO_BD_IPS"]
6395 if {[
string compare [
string tolower $bd_ip_generics] "false"] == 0} {
6399 if {$mode == "synth"} {
6400 Msg Info "Attempting to apply generics pre-synthesis..."
6401 set PARENT_PRJ [get_property "PARENT.PROJECT_PATH" [current_project]]
6402 set workaround [open "$repo_path/Projects/$proj/.hog/presynth_workaround.tcl" "w"]
6403 puts $workaround "source \[lindex \$argv 0\];"
6404 puts $workaround "open_project \[lindex \$argv 1\];"
6405 puts $workaround "WriteGenericsToBdIPs \[lindex \$argv 2\] \[lindex \$argv 3\] \[lindex \$argv 4\] \[lindex \$argv 5\];"
6406 puts $workaround "close_project"
6410 exec vivado -mode batch -source $repo_path/Projects/$proj/.hog/presynth_workaround.tcl \
6411 -tclargs $repo_path/Hog/Tcl/hog.tcl $PARENT_PRJ \
6412 "childprocess" $repo_path $proj $generic_string
6415 Msg Error "Encountered an error while attempting workaround: $errMsg"
6417 file delete $repo_path/Projects/$proj/.hog/presynth_workaround.tcl
6419 Msg Info "Done applying generics pre-synthesis."
6423 Msg Info "Looking for IPs to add generics to..."
6424 set ips_generic_string ""
6425 foreach generic_to_set [
split [
string trim $generic_string]] {
6426 set key [
lindex [
split $generic_to_set "="] 0]
6427 set value [
lindex [
split $generic_to_set "="] 1]
6428 append ips_generic_string "CONFIG.$key $value "
6432 if {[
string compare [
string tolower $bd_ip_generics] "true"] == 0} {
6435 set ip_regex $bd_ip_generics
6438 set ip_list [get_ips -regex $ip_regex]
6439 Msg Debug "IPs found with regex \{$ip_regex\}: $ip_list"
6441 set regen_targets {}
6443 foreach {ip} $ip_list {
6444 set WARN_ABOUT_IP false
6445 set ip_props [list_property [get_ips $ip]]
6448 if {[lsearch -exact $ip_props "IS_BD_CONTEXT"] == -1} {
6452 if {[get_property "IS_BD_CONTEXT" [get_ips $ip]] eq "1"} {
6453 foreach {ip_prop} $ip_props {
6454 if {[dict exists $ips_generic_string $ip_prop]} {
6455 if {$WARN_ABOUT_IP == false} {
6456 lappend regen_targets [get_property SCOPE [get_ips $ip]]
6457 Msg Warning "The ip \{$ip\} contains generics that are set by Hog.\
6458 If this is IP is apart of a block design, the .bd file may contain stale, unused, values.\
6459 Hog will always apply the most up-to-date values to the IP during synthesis,\
6460 however these values may or may not be reflected in the .bd file."
6461 set WARN_ABOUT_IP true
6466 set xci_path [get_property IP_FILE [get_ips $ip]]
6468 if {[
string equal $generic_format "ERROR"]} {
6469 Msg Warning "Could not find format for generic $ip_prop in IP $ip. Skipping..."
6473 set value_to_set [dict get $ips_generic_string $ip_prop]
6474 switch -exact $generic_format {
6476 if {[
string match "32'h*" $value_to_set]} {
6477 scan [
string map {"32'h" ""} $value_to_set] "%x" value_to_set
6481 set value_to_set [
expr {$value_to_set ? "true" : "false"}]
6484 if {[
string match "32'h*" $value_to_set]} {
6485 binary scan [
binary format H* [
string map {"32'h" ""} $value_to_set]] d value_to_set
6489 if {[
string match "32'h*" $value_to_set]} {
6490 set value_to_set [
string map {"32'h" "0x"} $value_to_set]
6494 set value_to_set [
format "%s" $value_to_set]
6497 Msg Warning "Unknown generic format $generic_format for IP $ip. Will attempt to pass as string..."
6502 Msg Info "The IP \{$ip\} contains: $ip_prop ($generic_format), setting it to $value_to_set."
6503 if {[
catch {set_property -name $ip_prop -value $value_to_set -objects [get_ips $ip]} prop_error]} {
6504 Msg CriticalWarning "Failed to set property $ip_prop to $value_to_set for IP \{$ip\}: $prop_error"
6511 foreach {regen_target} [lsort -unique $regen_targets] {
6512 Msg Info "Regenerating target: $regen_target"
6513 if {[
catch {generate_target -force all [get_files $regen_target]} prop_error]} {
6514 Msg CriticalWarning "Failed to regen targets: $prop_error"
6522 proc GetGenericFormatFromXciXML {generic_name xml_file} {
6523 if {![
file exists $xml_file]} {
6524 Msg Error "Could not find XML file: $xml_file"
6528 set fp [open $xml_file r]
6529 set xci_data [read $fp]
6532 set paramType "string"
6533 set modelparam_regex [
format {^.*\y%s\y.*$} [
string map {"CONFIG." "MODELPARAM_VALUE."} $generic_name]]
6534 set format_regex {format="([^"]+)"}
6536 set line [
lindex [regexp -inline -line $modelparam_regex $xci_data] 0]
6537 Msg Debug "line: $line"
6539 if {[regexp $format_regex $line match format_value]} {
6540 Msg Debug "Extracted: $format_value format from xml"
6541 set paramType $format_value
6543 Msg Debug "No format found, using string"
6552 proc GetGenericFormatFromXci {generic_name xci_file} {
6553 if {![
file exists $xci_file]} {
6554 Msg Error "Could not find XCI file: $xci_file"
6558 set fp [open $xci_file r]
6559 set xci_data [read $fp]
6562 set paramType "string"
6563 if {[
string first "xilinx.com:schema:json_instance:1.0" $xci_data] == -1} {
6564 Msg Debug "XCI format is not JSON, trying XML..."
6565 set xml_file "[
file rootname $xci_file].xml"
6569 set generic_name [
string map {"CONFIG." ""} $generic_name]
6570 set ip_inst [
ParseJSON $xci_data "ip_inst"]
6571 set parameters [dict get $ip_inst parameters]
6572 set component_parameters [dict get $parameters component_parameters]
6573 if {[dict exists $component_parameters $generic_name]} {
6574 set generic_info [dict get $component_parameters $generic_name]
6575 if {[dict exists [
lindex $generic_info 0] format]} {
6576 set paramType [dict get [
lindex $generic_info 0] format]
6577 Msg Debug "Extracted: $paramType format from xci"
6580 Msg Debug "No format found, using string"
6593 proc WriteGitLabCIYAML {proj_name {ci_conf ""}} {
6594 if {[
catch {
package require yaml 0.3.3} YAMLPACKAGE]} {
6595 Msg CriticalWarning "Cannot find package YAML.\n Error message: $YAMLPACKAGE. \
6596 If you are running on tclsh, you can fix this by installing package \"tcllib\""
6601 if {$ci_conf != ""} {
6603 foreach sec [dict keys $ci_confs] {
6604 if {[
string first : $sec] == -1} {
6605 lappend job_list $sec
6609 set job_list {"generate_project" "simulate_project"}
6613 set out_yaml [huddle create]
6614 foreach job $job_list {
6616 set huddle_tags [huddle list]
6618 set sec_dict [dict create]
6620 if {$ci_confs != ""} {
6621 foreach var [dict keys [dict get $ci_confs $job]] {
6622 if {$var == "tags"} {
6623 set tag_section "tags"
6624 set tags [dict get [dict get $ci_confs $job] $var]
6625 set tags [
split $tags ","]
6627 set tag_list [huddle list $tag]
6628 set huddle_tags [huddle combine $huddle_tags $tag_list]
6631 dict set sec_dict $var [dict get [dict get $ci_confs $job] $var]
6637 set huddle_variables [huddle create "PROJECT_NAME" $proj_name "extends" ".vars"]
6638 if {[dict exists $ci_confs "$job:variables"]} {
6639 set var_dict [dict get $ci_confs $job:variables]
6640 foreach var [dict keys $var_dict] {
6642 set value [dict get $var_dict "$var"]
6643 set var_inner [huddle create "$var" "$value"]
6644 set huddle_variables [huddle combine $huddle_variables $var_inner]
6649 set middle [huddle create "extends" ".$job" "variables" $huddle_variables]
6650 foreach sec [dict keys $sec_dict] {
6651 set value [dict get $sec_dict $sec]
6652 set var_inner [huddle create "$sec" "$value"]
6653 set middle [huddle combine $middle $var_inner]
6655 if {$tag_section != ""} {
6656 set middle2 [huddle create "$tag_section" $huddle_tags]
6657 set middle [huddle combine $middle $middle2]
6660 set outer [huddle create "$job:$proj_name" $middle]
6661 set out_yaml [huddle combine $out_yaml $outer]
6664 return [
string trimleft [yaml::huddle2yaml $out_yaml] "-"]
6674 proc WriteListFiles {libs props list_path repo_path {ext_path ""}} {
6676 foreach lib [dict keys $libs] {
6677 if {[
llength [
DictGet $libs $lib]] > 0} {
6678 set list_file_name $list_path$lib
6679 set list_file [open $list_file_name w]
6680 Msg Info "Writing $list_file_name..."
6681 puts $list_file "#Generated by Hog on [
clock format [
clock seconds] -format "%Y-%m-%d %H:%M:%S"]"
6682 foreach file [
DictGet $libs $lib] {
6684 set prop [
DictGet $props $file]
6688 puts $list_file "$file_path $prop"
6691 set ext_list_file [open "[
file rootname $list_file].ext" a]
6692 puts $ext_list_file "$file_path $prop"
6693 close $ext_list_file
6696 Msg Warning "The path of file $file is not relative to your repository. Please check!"
6712 proc WriteSimListFile {simset libs props simsets list_path repo_path {force 0}} {
6714 set list_file_name $list_path/${simset}.sim
6715 if {$force == 0 && [
file exists $list_file_name]} {
6716 Msg Info "List file $list_file_name already exists, skipping..."
6720 set list_file [open $list_file_name a+]
6723 puts $list_file "\[files\]"
6724 Msg Info "Writing $list_file_name..."
6725 foreach lib [
DictGet $simsets $simset] {
6726 foreach file [
DictGet $libs $lib] {
6728 set prop [
DictGet $props $file]
6732 set lib_name [
file rootname $lib]
6733 if {$lib_name != $simset && [
file extension $file] == ".vhd" && [
file extension $file] == ""} {
6734 lappend prop "lib=$lib_name"
6736 puts $list_file "$file_path $prop"
6739 Msg Warning "The path of file $file is not relative to your repository. Please check!"
6751 proc WriteToFile {File msg} {
6752 set f [open $File a+]
6763 proc WriteUtilizationSummary {input output project_name run} {
6764 set f [open $input "r"]
6765 set o [open $output "a"]
6766 puts $o "## $project_name $run Utilization report\n\n"
6767 struct::matrix util_m
6768 util_m add columns 14
6771 util_m add row "| **Site Type** | **Used** | **Fixed** | **Prohibited** | **Available** | **Util%** |"
6772 util_m add row "| --- | --- | --- | --- | --- | --- |"
6774 util_m add row "| **Site Type** | **Used** | **Fixed** | **Available** | **Util%** |"
6775 util_m add row "| --- | --- | --- | --- | --- |"
6785 while {[
gets $f line] >= 0} {
6786 if {([
string first "| CLB LUTs" $line] >= 0 || [
string first "| Slice LUTs" $line] >= 0) && $luts == 0} {
6787 util_m add row $line
6790 if {([
string first "| CLB Registers" $line] >= 0 || [
string first "| Slice Registers" $line] >= 0) && $regs == 0} {
6791 util_m add row $line
6794 if {[
string first "| Block RAM Tile" $line] >= 0 && $bram == 0} {
6795 util_m add row $line
6798 if {[
string first "URAM " $line] >= 0 && $uram == 0} {
6799 util_m add row $line
6802 if {[
string first "DSPs" $line] >= 0 && $dsps == 0} {
6803 util_m add row $line
6806 if {[
string first "Bonded IOB" $line] >= 0 && $ios == 0} {
6807 util_m add row $line
6814 puts $o [util_m format 2string]
6820 Msg Error "Found Git version older than 2.7.2. Hog will not work as expected, exiting now."