@@ -721,11 +721,29 @@ def is_inst(module: ConfigT) -> bool:
721721 return top_level_mem or top_level_module
722722
723723
724- def get_base_and_size (name_to_block : IpBlocksT , inst : ConfigT ,
725- ifname : Optional [str ]) -> Tuple [int , int ]:
724+ def get_base_and_size (block : IpBlock ,
725+ inst : ConfigT ,
726+ ifname : Optional [str ]
727+ ) -> Tuple [Dict [str , int ], int ] | None :
728+ '''Return (base_addrs, size) to describe addresses inst uses on ifname.
729+
730+ It may be that this instance doesn't actually use the interface at all in
731+ the top-level (perhaps because its support for the interface is disabled by
732+ a parameter). If so, return None.
733+
734+ If the instance *does* use the interface, base_addrs is a map from address
735+ space ID to the base address of the block in that address space.
736+
737+ size is the size in bytes that the block uses on the interface named
738+ ifname.
739+ '''
740+
741+ # Check whether the top-level connects up this interface. If not, return
742+ # None.
743+ base_addrs = inst ['base_addrs' ].get (ifname )
744+ if base_addrs is None :
745+ return None
726746
727- block = name_to_block .get (inst ['type' ])
728- assert block , f"No module named { inst ['type' ]} (coming from instance { inst ['name' ]} )"
729747 # If inst is the instantiation of some block, find the register block
730748 # that corresponds to ifname
731749 if rb := block .reg_blocks .get (ifname ):
@@ -739,7 +757,7 @@ def get_base_and_size(name_to_block: IpBlocksT, inst: ConfigT,
739757 'default' if ifname is None else repr (ifname ),
740758 inst ['name' ], block .name ))
741759
742- base_addrs = deepcopy (inst [ ' base_addrs' ][ ifname ] )
760+ base_addrs = deepcopy (base_addrs )
743761
744762 for (asid , base_addr ) in base_addrs .items ():
745763 if isinstance (base_addr , str ):
@@ -981,19 +999,28 @@ def _init_device_regions(self, addr_space):
981999 for inst in self .top ['module' ]:
9821000 block = self ._name_to_block [inst ['type' ]]
9831001 for if_name in block .reg_blocks .keys ():
1002+ bases_size = get_base_and_size (block , inst , if_name )
1003+ if bases_size is None :
1004+ # Nothing to do for this interface: it is not used in this
1005+ # instance.
1006+ continue
1007+
1008+ bases , size = bases_size
1009+ base = bases .get (addr_space )
1010+ if base is None :
1011+ # Again, nothing to do for this interface: it does not
1012+ # define anything mapped into addr_space.
1013+ continue
1014+
9841015 full_if = (inst ['name' ], if_name )
9851016 full_if_name = Name .from_snake_case (full_if [0 ])
9861017 if if_name is not None :
9871018 full_if_name += Name .from_snake_case (if_name )
9881019
9891020 name = full_if_name
990- base , size = get_base_and_size (self ._name_to_block , inst ,
991- if_name )
992- if addr_space not in base :
993- continue
9941021
9951022 region = MemoryRegion (self ._top_name , name , addr_space ,
996- base [ addr_space ] , size )
1023+ base , size )
9971024 device_region [inst ['name' ]].update ({if_name : region })
9981025
9991026 self .device_regions [addr_space ] = device_region
@@ -1039,19 +1066,36 @@ def _init_device_memories(self, addr_space):
10391066 device_memories = defaultdict (dict )
10401067
10411068 for inst in self .top ['module' ]:
1042- if "memory" in inst :
1043- for if_name , val in inst ["memory" ].items ():
1044- base , size = get_base_and_size (self ._name_to_block , inst ,
1045- if_name )
1046- if addr_space not in base :
1047- continue
1048-
1049- full_if_name = Name .from_snake_case (inst ['name' ]) + \
1050- Name .from_snake_case (if_name )
1051- region = MemoryRegion (self ._top_name , full_if_name , addr_space ,
1052- base [addr_space ], size )
1053-
1054- device_memories [inst ['name' ]].update ({if_name : region })
1069+ block = self ._name_to_block .get (inst ['type' ])
1070+ if block is None :
1071+ raise RuntimeError (f"No block defined for instance "
1072+ f"type { inst ['type' ]} (with name "
1073+ f"{ inst ['name' ]} )" )
1074+
1075+ for if_name , val in inst .get ("memory" , {}).items ():
1076+ bases_size = get_base_and_size (block , inst , if_name )
1077+
1078+ # We expect bases_size not to be None. If it is None, then the
1079+ # instance defines the memory but doesn't give it a base
1080+ # address (which seems unlikely to be right).
1081+ if bases_size is None :
1082+ raise RuntimeError (f"The instance named { inst ['name' ]} "
1083+ f"defines a memory for interface "
1084+ f"{ if_name } , but doesn't give it a "
1085+ f"base address." )
1086+
1087+ bases , size = bases_size
1088+ base = bases .get (addr_space )
1089+
1090+ if base is None :
1091+ continue
1092+
1093+ full_if_name = Name .from_snake_case (inst ['name' ]) + \
1094+ Name .from_snake_case (if_name )
1095+ region = MemoryRegion (self ._top_name , full_if_name , addr_space ,
1096+ base , size )
1097+
1098+ device_memories [inst ['name' ]].update ({if_name : region })
10551099
10561100 self .device_memories [addr_space ] = device_memories
10571101
0 commit comments