29 source $tcl_path/utils/hdl_parser.tcl
31 proc PrintOrWrite {output_file msg} {
32 if {$output_file ne ""} {
33 puts $output_file $msg
39 proc _create_hier_meta {} {
40 set hier_meta [dict create]
41 dict set hier_meta all_modules {}
42 dict set hier_meta proj_files {}
43 dict set hier_meta parsed_files_cache {}
47 proc _compute_file_checksum {file_path} {
48 if {![
file exists $file_path]} {
52 if {[
catch {
package require md5 2.0.7} result]} {
54 if {[
catch {
exec md5sum $file_path} output]} {
57 return [
lindex $output 0]
59 return [
string tolower [md5::md5 -hex -file $file_path]]
64 proc is_known_library {hier_meta_ref lib_name} {
65 upvar 1 $hier_meta_ref hier_meta
66 return [dict exists $hier_meta libraries known_libs $lib_name]
69 proc is_ignored_module {module_key ignore_patterns} {
70 foreach pattern $ignore_patterns {
71 if {[
string match $pattern $module_key]} {
78 proc _create_proj_file_info {file_path library properties} {
79 set file_info [dict create]
80 dict set file_info file_path $file_path
81 dict set file_info library $library
82 dict set file_info properties $properties
83 dict set file_info ext [
file extension $file_path]
87 proc file_info_path {file_info} {
return [dict get $file_info file_path]}
88 proc file_info_library {file_info} {
return [dict get $file_info library]}
89 proc file_info_properties {file_info} {
return [dict get $file_info properties]}
90 proc file_info_ext {file_info} {
return [dict get $file_info ext]}
92 proc _store_module {hier_meta_ref mod_name mod_library mod_type file_path references_list props} {
93 upvar 1 $hier_meta_ref hier_meta
95 set key "${mod_library}.${mod_type}.${mod_name}"
97 dict set mod name $mod_name
98 dict set mod library $mod_library
99 dict set mod type $mod_type
100 dict set mod file_path $file_path
101 dict set mod references $references_list
102 dict set mod properties $props
103 dict set mod color "white"
105 dict set hier_meta all_modules $key $mod
108 proc _hier_parse_hdl {hier_meta_ref file_info} {
109 upvar 1 $hier_meta_ref hier_meta
112 if {[
string first "top_control" $file_info] != -1} {
117 if {[
string first "top_l0mdt" $file_info] != -1} {
123 if {![
file exists $f]} {
return}
127 set ext [
string tolower [
file extension $f]]
129 Msg Debug "Parsing $f"
130 set discovered_modules [list]
132 foreach node $hdl_constructs {
138 set node_type [dict get $node type]
139 set node_name [dict get $node name]
141 set references [list]
142 set sv_include_files [list]
143 foreach component [dict get $node components_declared] {
144 lappend references "unknown.component.[dict get $component name]"
147 foreach inst [dict get $node instantiations] {
148 if { [dict get $inst type] == "component_inst"} {
149 lappend references "unknown.component.[dict get $inst mod_name]"
150 }
elseif { [dict get $inst type] == "entity_inst"} {
151 set split_name [
split [dict get $inst mod_name] "."]
152 lappend references "[
lindex $split_name 0].component.[
lindex $split_name 1]"
153 }
elseif { [dict get $inst type] == "sv_import"} {
154 lappend references "unknown.sv_package.[dict get $inst mod_name]"
155 }
elseif { [dict get $inst type] == "sv_include"} {
156 lappend sv_include_files [dict get $inst mod_name]
157 }
elseif { [dict get $inst type] == "vhdl_pkg_inst"} {
158 set split_name [
split [dict get $inst mod_name] "."]
159 lappend references "[
lindex $split_name 0].vhdl_package.[
lindex $split_name 1]"
163 foreach lib [dict get $node libraries] {
164 foreach use [dict get $lib uses] {
165 set split_name [
split $use "."]
166 lappend references "[
lindex $split_name 0].vhdl_package.[
lindex $split_name 1]"
170 set references [lsort -unique $references]
171 dict set node references $references
172 dict set node sv_includes $sv_include_files
174 set mod_properties [dict create]
175 if {$ext eq ".v" || $ext eq ".vh" || $ext eq ".sv" || $ext eq ".svh" ||
176 [lsearch -exact $file_properties "SystemVerilog"] != -1} {
177 if {$ext eq ".sv" || $ext eq ".svh" ||
178 [lsearch -exact $file_properties "SystemVerilog"] != -1} {
179 dict set mod_properties filetype "SystemVerilog"
181 dict set mod_properties filetype "Verilog"
183 }
elseif {$ext eq ".vhd" || $ext eq ".vhdl"} {
184 set knownYears {93 2008 2019}
186 foreach y $knownYears {
187 if {[lsearch -exact $file_properties $y] != -1} {
192 dict set mod_properties filetype "VHDL$year"
195 dict set node properties $mod_properties
196 dict set node library $library
197 dict set node color "white"
199 if {$node_type == "vhdl_architecture"} {
200 set key "${library}.${node_type}.[dict get $node entity].${node_name}"
202 set key "${library}.${node_type}.${node_name}"
205 dict set hier_meta all_modules $key $node
206 lappend discovered_modules $key
208 return $discovered_modules
211 proc _xml_extract_blocks {xml_content tag} {
213 set open_tag "<$tag>"
214 set close_tag "</$tag>"
217 set start [
string first $open_tag $xml_content $cursor]
218 if {$start == -1} { break}
219 set content_start [
expr {$start + [string length $open_tag]}]
220 set end [
string first $close_tag $xml_content $content_start]
221 if {$end == -1} { break}
222 set block [
string range $xml_content $content_start [
expr {$end - 1}]]
223 lappend blocks [
string trim $block]
224 set cursor [
expr {$end + [string length $close_tag]}]
230 proc _parse_xci_xml {xml_content} {
233 set filesets_dict [dict create]
237 if {$fs_name eq ""} { continue}
242 if {$file_name ne ""} {
243 set file_dict [dict create name $file_name logicalName $logical_name]
244 lappend fs_files $file_dict
247 dict set filesets_dict $fs_name $fs_files
255 set view_files [list]
258 if {$fs_name ne "" && [dict exists $filesets_dict $fs_name]} {
259 set view_files [
concat $view_files [dict get $filesets_dict $fs_name]]
264 if {[
string match "xilinx_*behavioralsimulation" $view_name]} {
265 set view_type "behav"
266 }
elseif {[
string match "xilinx_*simulationwrapper" $view_name]} {
267 set view_type "wrapper"
270 if {$view_type ne "" && [
llength $view_files] > 0 && $model_name ne ""} {
271 set view_dict [dict create name $view_name type $view_type modelName $model_name files $view_files]
272 lappend view_list $view_dict
277 set wrapper_views [list]
278 set non_wrapper_views [list]
280 foreach view $view_list {
281 set view_type [dict get $view type]
282 if {$view_type eq "wrapper"} {
283 lappend wrapper_views $view
285 lappend non_wrapper_views $view
289 return [dict create wrappers $wrapper_views nonwrappers $non_wrapper_views]
292 proc _hier_parse_ip {hier_meta_ref file_info {include_gen_prods 0}} {
293 upvar 1 $hier_meta_ref hier_meta
296 if {![
file exists $f]} {
return}
299 set name [
file rootname [
file tail $f]]
300 set mod_properties [dict create]
301 dict set mod_properties filetype "XCI"
304 if {[
catch {open $f r} fid]} {
305 Msg Warning "Warning: Could not open XCI file: $f"
307 set content [read $fid]
310 if {[regexp {"OUTPUTDIR":\s*\[\s*\{\s*"value":\s*"([^"]+)"} $content -> dir_value]} {
311 set output_dir $dir_value
315 set xci_dir [
file dirname $f]
316 set resolved_output_dir [
file normalize [
file join $xci_dir $output_dir]]
321 if { $include_gen_prods == 1} {
322 set xml_path [
file join $xci_dir "${name}.xml"]
323 if {[
file exists $xml_path]} {
324 if {[
catch {open $xml_path r} xml_fid]} {
325 Msg Warning "Warning: Could not open XML file: $xml_path"
327 set xml_content [read $xml_fid]
331 set wrapper_views [dict get $view_data wrappers]
332 set non_wrapper_views [dict get $view_data nonwrappers]
339 foreach view $non_wrapper_views {
340 set view_name [dict get $view name]
341 set view_type [dict get $view type]
342 set model_name [dict get $view modelName]
343 set view_files [dict get $view files]
349 set unique_files [dict create]
350 foreach file_dict $view_files {
351 set file_name [dict get $file_dict name]
352 set logical_name [dict get $file_dict logicalName]
353 set file_base [
file rootname [
file tail $file_name]]
355 if {![dict exists $unique_files $file_base]} {
356 dict set unique_files $file_base [list]
358 dict lappend unique_files $file_base [dict create name $file_name logicalName $logical_name]
362 set view_file_refs [list]
363 dict for {base_name file_list} $unique_files {
364 set all_node_keys [list]
365 foreach file_dict $file_list {
366 set file_name [dict get $file_dict name]
367 set logical_name [dict get $file_dict logicalName]
368 lappend all_node_keys "${logical_name}.xci_gen_file.${file_name}"
371 foreach file_dict $file_list {
372 set file_name [dict get $file_dict name]
373 set logical_name [dict get $file_dict logicalName]
374 set full_file_path [file normalize [file join $resolved_output_dir $file_name]]
375 set file_node_key "${logical_name}.xci_gen_file.${file_name}"
377 set file_ext [string tolower [file extension $file_name]]
378 set filetype "Unknown"
379 if {$file_ext eq ".v"} {
380 set filetype "Verilog"
381 } elseif {$file_ext eq ".vhd" || $file_ext eq ".vhdl"} {
383 } elseif {$file_ext eq ".sv"} {
384 set filetype "SystemVerilog"
387 set file_props [dict create filetype $filetype logicalName $logical_name xciRole "generated"]
390 if {[llength $file_list] > 1} {
391 set other_keys [lsearch -all -inline -not -exact $all_node_keys $file_node_key]
392 dict set file_props duplicates $other_keys
395 _store_module hier_meta $file_name $logical_name "xci_gen_file" $full_file_path [list] $file_props
396 lappend view_file_refs $file_node_key
400 set view_node_key "${library}.${view_name}.${model_name}"
401 set view_props [dict create filetype "XCI_VIEW" xciRole "view" viewType $view_type]
402 _store_module hier_meta $model_name $library $view_name "" $view_file_refs $view_props
405 foreach wrapper $wrapper_views {
406 set wrapper_model_name [dict get $wrapper modelName]
407 set wrapper_name [dict get $wrapper name]
409 set wrapper_refs [list]
410 foreach view $non_wrapper_views {
411 set model_name [dict get $view modelName]
412 set view_name [dict get $view name]
413 set view_node_key "${library}.${view_name}.${model_name}"
414 lappend wrapper_refs $view_node_key
418 set wrapper_file [dict get [
lindex [dict get $wrapper files] 0] name]
419 set wrapper_file [
file normalize [
file join $resolved_output_dir $wrapper_file]]
420 set file_ext [
string tolower [
file extension $wrapper_file]]
422 set wrapper_node_key "${library}.xci_wrapper.${wrapper_model_name}"
423 set filetype "Unknown"
424 if {$file_ext eq ".v"} {
425 set filetype "Verilog"
426 }
elseif {$file_ext eq ".vhd" || $file_ext eq ".vhdl"} {
428 }
elseif {$file_ext eq ".sv"} {
429 set filetype "SystemVerilog"
431 set wrapper_props [dict create filetype $filetype xciRole "wrapper"]
432 _store_module hier_meta $wrapper_model_name $library "xci_wrapper" $wrapper_file $wrapper_refs $wrapper_props
434 lappend all_subs $wrapper_node_key
442 set all_subs [lsort -unique $all_subs]
444 _store_module hier_meta $name $library "xci" $f $all_subs $mod_properties
451 proc _hier_parse_file {hier_meta_ref file_info {include_gen_prods 0}} {
452 upvar 1 $hier_meta_ref hier_meta
455 if {$ext eq ".vhd" || $ext eq ".vhdl" || $ext eq ".v" || $ext eq ".sv" ||
456 $ext eq ".vh" || $ext eq ".svh"} {
458 }
elseif {$ext eq ".xci"} {
460 }
elseif {$ext eq ".bd"} {
469 proc _hier_submodule_append {hier_meta_ref parent_key sub_key} {
470 upvar 1 $hier_meta_ref hier_meta
472 if {[dict exists $hier_meta all_modules $parent_key]} {
473 set mod [dict get $hier_meta all_modules $parent_key]
474 dict lappend mod references $sub_key
475 dict set hier_meta all_modules $parent_key $mod
480 proc _reference_resolver {hier_meta_ref} {
481 upvar 1 $hier_meta_ref hier_meta
483 set package_bodies [ dict filter [dict get $hier_meta all_modules] script {k v} {expr {[dict get $v type] eq "vhdl_package_body"}}]
484 set architectures [ dict filter [dict get $hier_meta all_modules] script {k v} {expr {[dict get $v type] eq "vhdl_architecture"}}]
486 dict for {package_body body_info} $package_bodies {
487 set entity_key [split $package_body "."]
488 set entity_key "[lindex $entity_key 0].vhdl_package.[lindex $entity_key 2]"
489 if {[dict exists [dict get $hier_meta all_modules] $entity_key]} {
490 _hier_submodule_append hier_meta $entity_key $package_body
495 dict for {architecture arch_info} $architectures {
496 # if {[string first "top_l0mdt" $architecture] != -1} {
501 # if {[string first "top_control" $architecture] != -1} {
506 set entity_key [split $architecture "."]
507 set entity_key "[lindex $entity_key 0].vhdl_entity.[lindex $entity_key 2]"
508 if {[dict exists [dict get $hier_meta all_modules] $entity_key]} {
509 _hier_submodule_append hier_meta $entity_key $architecture
516 set resolution_list [list]
518 dict for {mod_key mod} [dict get $hier_meta all_modules] {
519 set references_data [dict get $mod references]
520 set new_references [list]
521 set mod_lib [dict get $mod library]
523 if { [string first "top_control" $mod_key] != -1 } {
527 foreach ref $references_data {
528 # puts "Processing ref: $ref in mod: $mod_key"
529 set parts [split $ref "."]
530 set library [lindex $parts 0]
531 set type [lindex $parts 1]
532 set name [lindex $parts 2]
536 set resolved_mod_name ""
538 if {$library == "unknown" && $type == "sv_package"} {
539 set pattern ".*\\.sv_package\\.$name\$"
540 set matches [dict filter [dict get $hier_meta all_modules] \
541 script {k v} {expr {[regexp $pattern $k]}}]
542 if {[dict size $matches] == 0} {
543 lappend new_references $ref
544 Msg Debug "No sv_package match found for $ref in $mod_key"
546 dict for {k v} $matches {
547 lappend new_references $k
548 Msg Debug "Mod: $mod_key resolved $ref to $k"
555 if { ($library != "unknown" && $library != "work" && $type != "component") || ($library == "unknown" && $type != "component") } {
556 # puts "Keeping reference as-is: $ref"
557 lappend new_references $ref
562 if { $library != "unknown"} {
569 set pattern "${ref_lib}\\.(vhdl_entity|verilog_module)\\.$name\$"
570 set matches [dict filter [dict get $hier_meta all_modules] script {k v} {expr {[regexp $pattern $k]}}]
571 if {[dict size $matches] == 0} {
572 set pattern ".*\\.(vhdl_entity|verilog_module)\\.$name\$"
573 set matches [dict filter [dict get $hier_meta all_modules] script {k v} {expr {[regexp $pattern $k]}}]
574 if {[dict size $matches] > 1} {
575 Msg Warning "Ambiguous component reference '$name' in '$mod_key': multiple libraries match, picking first found"
579 # Also resolve to XCI wrapper/IP types (e.g. Vivado-generated IPs instantiated as components)
580 if {[dict size $matches] == 0} {
581 set pattern ".*\\.(xci_wrapper|xci)\\.$name\$"
582 set matches [dict filter [dict get $hier_meta all_modules] script {k v} {expr {[regexp $pattern $k]}}]
585 if {[dict size $matches] == 0} {
586 lappend new_references $ref
587 Msg Debug "No match found for $ref in $mod_key"
589 dict for {k v} $matches {
590 lappend new_references $k
591 Msg Debug "Mod: $mod_key resolved $ref to $k"
597 dict set hier_meta all_modules $mod_key references $new_references
603 dict for {mod_key mod} [dict get $hier_meta all_modules] {
604 if {![dict exists $mod sv_includes]} { continue }
605 set sv_includes [dict get $mod sv_includes]
606 if {[llength $sv_includes] == 0} { continue }
608 set new_refs [dict get $mod references]
609 foreach include_file $sv_includes {
610 dict for {proj_file _} [dict get $hier_meta proj_files] {
611 if {[file tail $proj_file] ne $include_file} { continue }
612 dict for {k m} [dict get $hier_meta all_modules] {
613 if {[dict get $m file_path] eq $proj_file &&
614 [lsearch -exact $new_refs $k] == -1} {
617 Msg Debug "Mod: $mod_key include-depends on $k (via $include_file)"
622 dict set hier_meta all_modules $mod_key references $new_refs
625 return [dict create total $total_resolved resolutions $resolution_list]
628 proc dfs_sort {hier_meta_ref top_module} {
629 upvar 1 $hier_meta_ref hier_meta
632 proc _dfs_visit {hier_meta_ref node sorted_ref bad_nodes_ref} {
633 upvar 1 $hier_meta_ref hier_meta
634 upvar 1 $sorted_ref sorted
635 upvar 1 $bad_nodes_ref bad_nodes
637 if {![dict exists $hier_meta all_modules $node]} {
641 set mod [dict get $hier_meta all_modules $node]
642 set color [dict get $mod color]
644 if {$color eq "gray"} {
645 Msg Warning "Warning: Circular dependency detected at $node"
646 if {[lsearch -exact $bad_nodes $node] == -1} {
647 lappend bad_nodes $node
652 if {$color eq "black"} {
656 dict set mod color "gray"
657 dict set hier_meta all_modules $node $mod
660 set references [dict get $mod references]
661 foreach child $references {
665 set mod [dict get $hier_meta all_modules $node]
666 dict set mod color "black"
667 dict set hier_meta all_modules $node $mod
675 _dfs_visit hier_meta $top_module sorted bad_nodes
677 if {[
llength $bad_nodes] > 0} {
678 return [dict create success 0 sorted {} cycles 1 bad_nodes $bad_nodes]
681 return [dict create success 1 sorted $sorted cycles 0 bad_nodes {}]
685 proc _debug_string_hier_meta {hier_meta_ref {indent 0}} {
686 upvar 1 $hier_meta_ref hier_meta
688 set ind [
string repeat " " $indent]
689 set s "${ind}=== ALL MODULES ==="
690 dict for {key mod} [dict get $hier_meta all_modules] {
691 append s "\n${ind}$key:"
692 dict for {field value} $mod {
693 append s "\n${ind} $field: $value"
698 append s "\n${ind}=== PROJECT FILES ==="
699 dict for {file finfo} [dict get $hier_meta proj_files] {
700 append s "\n${ind}$file:"
701 dict for {field value} $finfo {
702 append s "\n${ind} $field: $value"
711 proc Hierarchy {listProperties listLibraries repo_path {output_path ""} \
712 {compile_order 0} {light ""} {top_module_override ""} {ignore_opt_list ""} {include_ieee 0} {include_gen_prods 0} {quiet 0}} {
717 set ignore_list [list]
719 if {$include_ieee == 0} {
720 lappend ignore_list "ieee.*.*"
721 lappend ignore_list "std.*.*"
724 foreach pat [
split $ignore_opt_list ","] {
725 set pat [
string trim $pat]
727 if {![regexp {^[\w*]+\.[\w*]+\.[\w*]+$} $pat]} {
728 Msg Warning "Warning: ignore pattern '$pat' does not match expected format <lib>.<type>.<name> (wildcards * allowed), ignoring"
730 lappend ignore_list $pat
735 if {$top_module_override ne ""} {
736 set top_module $top_module_override
737 Msg Warning "Using specified top module: $top_module"
740 dict for {lib files} $listLibraries {
741 set lib [file rootname $lib]
745 if {[dict exists $listProperties $f]} {
747 set fprops [dict get $listProperties $f]
748 if {$top_module eq ""} {
749 set top [lindex [regexp -inline {\ytop\s*=\s*(.+?)\y.*} $fprops] 1]
751 set ext [file extension $f]
752 if {$ext eq ".vhd" || $ext eq ".vhdl"} {
753 set top_module "${lib}.vhdl_entity.${top}"
754 } elseif { $ext eq ".v" || $ext eq ".sv"} {
755 set top_module "${lib}.verilog_module.${top}"
757 set top_module "${lib}.component.${top}"
764 dict set hier_meta proj_files $f [_create_proj_file_info $f $lib $props]
768 if {$top_module_override eq ""} {
769 Msg Info "Top module from properties: $top_module"
773 dict for {file file_info} [dict get $hier_meta proj_files] {
774 _hier_parse_file hier_meta $file_info $include_gen_prods
777 set parse_us [
lindex $t_parse 0]
778 set parse_ms [
expr {$parse_us / 1000.0}]
780 Msg Info "Completed initial parsing in $parse_ms ms"
782 set t_resolve [
time {
783 set resolve_result [_reference_resolver hier_meta]
785 set resolve_us [
lindex $t_resolve 0]
786 set resolve_ms [
expr {$resolve_us / 1000.0}]
788 set total [dict get $resolve_result total]
789 set resolutions [dict get $resolve_result resolutions]
790 Msg Info "Completed reference resolution: $total references resolved in $resolve_ms ms"
793 if {$output_path != ""} {
794 set output_file [open $repo_path/$output_path "w"]
801 set sorted_modules [
dfs_sort hier_meta $top_module]
802 set bad_nodes [dict get $sorted_modules bad_nodes]
806 if {$compile_order} {
807 set compile_order_dict [
print_compile_order hier_meta [dict get $sorted_modules sorted] $output_file $quiet]
808 if {$output_path != ""} {
811 return $compile_order_dict
813 set p [
print_hierarchy hier_meta $top_module $output_file $ignore_list $bad_nodes $light]
814 if {[
llength $p] != 0} {
PrintOrWrite $output_file "\n\n=====Packages in project:====="}
815 dict for {lib pkg_list} $p {
816 if {[llength $pkg_list] == 0} {
819 PrintOrWrite $output_file "Library: $lib"
820 foreach pkg_entry $pkg_list {
821 PrintOrWrite $output_file " Package: $pkg_entry"
826 if {$output_path != ""} {
831 proc print_compile_order {hier_meta_ref sorted_list {output_file ""} {quiet 0}} {
832 upvar 1 $hier_meta_ref hier_meta
842 set seen [dict create]
844 foreach mod_key $sorted_list {
845 set mod [dict get $hier_meta all_modules $mod_key]
846 set file_path [dict get $mod file_path]
847 set library [dict get $mod library]
848 set pair "${file_path}\t${library}"
850 if {$file_path eq "" || [dict exists $seen $pair]} {
853 dict set seen $pair 1
854 lappend result $file_path $library
857 dict for {file file_info} [dict get $hier_meta proj_files] {
858 set library [file_info_library $file_info]
859 set pair "${file}\t${library}"
860 if {[dict exists $seen $pair]} {
863 dict set seen $pair 1
864 lappend result $file $library
868 foreach {file lib} $result {
877 proc print_hierarchy {hier_meta_ref module {output_file ""} {ignore_list ""} \
878 {bad_nodes ""} {light 0} {indent 0} {stack_ref ""} {last_properties_ref ""} {is_last 1}} {
879 upvar 1 $hier_meta_ref hier_meta
887 if {$stack_ref eq ""} {
889 set last_properties [list]
891 upvar 1 $stack_ref stack
892 upvar 1 $last_properties_ref last_properties
896 if {![dict exists $hier_meta all_modules $module]} {
897 set parts [
split $module "."]
898 set lib [
lindex $parts 0]
899 set type [
lindex $parts 1]
900 set name [
lindex $parts 2]
905 set mod [dict get $hier_meta all_modules $module]
907 set name [dict get $mod name]
908 set type [dict get $mod type]
909 set lib [dict get $mod library]
910 set file_path [dict get $mod file_path]
915 if {$type eq "vhdl_entity" && $module_exists} {
916 set references [dict get $mod references]
918 foreach ref $references {
919 if {[
string match "${lib}.vhdl_architecture.${name}.*" $ref]} {
920 lappend arch_refs $ref
923 if {[
llength $arch_refs] == 1} {
924 set arch_key [
lindex $arch_refs 0]
925 if {[dict exists $hier_meta all_modules $arch_key]} {
926 set arch_mod [dict get $hier_meta all_modules $arch_key]
927 set arch_file_path [dict get $arch_mod file_path]
928 if {$arch_file_path eq $file_path} {
929 set p [
print_hierarchy hier_meta $arch_key $output_file $ignore_list $bad_nodes $light $indent stack last_properties $is_last]
930 set package_dict [
MergeDict $p $package_dict]
939 if {[lsearch -exact $stack $module] != -1} {
940 if {[lsearch -exact $bad_nodes $module] != -1} {
946 lappend stack $module
950 for {
set i 0} {$i < [
llength $last_properties]} {
incr i} {
951 if {[
lindex $last_properties $i]} {
952 append indent_str " "
954 append indent_str "│ "
971 set path_str " - ${file_path}"
974 if {$type == "vhdl_architecture"} {
975 set name "[dict get $mod entity].$name"
979 if {[
string first "vhdl_package" $type] == -1} {
980 if {!$module_exists} {
981 set msg "${indent_str}${connector}${lib}.${name} (${type})"
982 }
elseif {$is_circular} {
983 set msg "${indent_str}${connector}${lib}.${name} (${type})${path_str} \[WARNING: circular reference detected\]"
985 set msg "${indent_str}${connector}${lib}.${name} (${type})${path_str}"
988 if {[
DictGet $package_dict "$lib"] == ""} {
989 dict set package_dict "$lib" [list]
991 set package_list [
DictGet $package_dict "$lib"]
992 if {![
IsInList $package_list "${name} ${path_str}"] } {
993 lappend package_list "${name} ${path_str}"
994 dict set package_dict "$lib" $package_list
1001 if {$is_circular || !$module_exists} {
1002 return $package_dict
1005 set references [dict get $mod references]
1006 set all_subs [lsort -unique $references]
1009 set filtered_subs [list]
1010 foreach sub $all_subs {
1012 lappend filtered_subs $sub
1016 set num_subs [
llength $filtered_subs]
1018 foreach sub $filtered_subs {
1020 set is_last_child [
expr {$sub_idx == $num_subs}]
1022 lappend last_properties $is_last
1023 set p [
print_hierarchy hier_meta $sub $output_file $ignore_list $bad_nodes $light [
expr {$indent + 1}] stack last_properties $is_last_child]
1024 set package_dict [
MergeDict $p $package_dict]
1025 set last_properties [
lrange $last_properties 0 end-1]
1028 set stack [
lrange $stack 0 end-1]
1029 return $package_dict
1034 proc get_rtl_refs {node {name ""}} {
1035 set out [dict create]
1037 if {$name ne "" && ![
catch {dict get $node reference_info} refinfo]} {
1039 catch {
set rt [dict get $refinfo ref_type]}
1040 catch {
set rn [dict get $refinfo ref_name]}
1041 if {[
string equal $rt "hdl"] && $rn ne ""} {
1042 dict set out $name $rn
1046 if {![
catch {dict get $node components} comps]} {
1047 dict for {cname cnode} $comps {
1048 set childMap [get_rtl_refs $cnode $cname]
1049 set out [dict merge $out $childMap]
1053 dict for {k v} $node {
1054 if {$k eq "components" || $k eq "reference_info"} {continue}
1055 if {[catch {dict size $v}]} {continue}
1056 set childMap [get_rtl_refs $v $k]
1057 set out [dict merge $out $childMap]
1063 proc _hier_parse_bd {hier_meta_ref file_info} {
1064 upvar 1 $hier_meta_ref hier_meta
1068 if {![
file exists $f]} {
return}
1073 set name [
file rootname [
file tail $f]]
1074 set mod_properties [dict create]
1075 dict set mod_properties filetype "BD"
1077 set bd_file [open $f r]
1078 set bd_json [read $bd_file]
1080 set bd_design $bd_json
1082 set lines [
split $bd_design "\n"]
1083 set filtered_lines {}
1084 foreach line $lines {
1085 if {[
string first "\\" $line] == -1} {
1086 lappend filtered_lines $line
1089 set bd_design [
join $filtered_lines "\n"]
1091 regsub -all {":\s*\{} $bd_design " \{" bd_design
1092 regsub -all {:\s*("(?:[^"\\]|\\.)*")} $bd_design { {\1}} bd_design
1093 regsub -all {"} $bd_design {} bd_design
1094 regsub -all {,} $bd_design {} bd_design
1095 regsub -all {:\s* \{} $bd_design {\{} bd_design
1096 regsub -all {\[} $bd_design "\{" bd_design
1097 regsub -all {\]} $bd_design "\}" bd_design
1099 set bd_design [
string range $bd_design 1 end-1]
1101 if {[
catch {dict size $bd_design} err]} {
1102 Msg Warning "Warning: malformed bd_design in $f, skipping"
1106 set bd_design [
lindex $bd_design 1]
1108 set unknown_modules {}
1110 if {[lsearch -exact $unknown_modules $v] == -1} {
1111 lappend unknown_modules "unknown.component.$v"
1114 _store_module hier_meta $name $library component $f $unknown_modules $mod_properties