def clk_physical(interconnect: Interconnect): for (x, y) in interconnect.tile_circuits: tile = interconnect.tile_circuits[(x, y)] tile_core = tile.core # We only want to do this on PE and memory tiles if isinstance(tile_core, IOCore) or tile_core is None: continue orig_in_port = tile.ports.clk orig_out_port = tile.ports.clk_out # Remove the pass through connection that already exists tile.remove_wire(orig_in_port, orig_out_port) # Create a new pass through clock input tile.add_port("clk_pass_through", magma.In(magma.Clock)) pass_through_input = tile.ports.clk_pass_through # Create new pass through output pass_through_output = pass_signal_through(tile, pass_through_input) # Connect new clk pass through input to old pass through output tile.wire(pass_through_input, orig_out_port) # For top row tiles, connect new clk input to global clock if y < 2: interconnect.wire(interconnect.ports.clk, pass_through_input) # For other tiles, connect new clk input to # pass through output of tile above. else: tile_above = interconnect.tile_circuits[(x, y-1)] interconnect.wire(tile_above.ports.clk_pass_through_out, pass_through_input)
def get_core_registers(interconnect: Interconnect): result = [] for x, y in interconnect.tile_circuits: tile = interconnect.tile_circuits[(x, y)] cores = [tile.core] + tile.additional_cores for core in cores: if core is None: continue if isinstance(core, PeakCore): # extract out PE's configuration # notice that peak core is a black box. we have no idea what # the registers' semantic meaning feat_addr = tile.features().index(core) regs = list(core.registers.keys()) regs.sort() for idx, reg_name in enumerate(regs): reg_addr = idx width = core.reg_width[reg_name] addr = interconnect.get_config_addr(reg_addr, feat_addr, x, y) result.append({ "name": reg_name, "addr": addr, "range": (1 << width) - 1, "lo": 0, "hi": width + 1 }) elif isinstance(core, LakeCoreBase): # memory has couple features base_feat_addr = tile.features().index(core) regs = list(core.registers.keys()) for reg_name in regs: reg_addr, lo, hi = core.get_reg_info(reg_name) width = core.registers[reg_name].width addr = interconnect.get_config_addr(reg_addr, base_feat_addr, x, y) result.append({ "name": reg_name, "addr": addr, "range": 1 << width, "lo": lo, "hi": hi }) # SRAM num_sram = core.num_sram_features if not hasattr(core, "mem_width"): continue repeat = core.mem_width // core.data_width for sram_index in range(num_sram): for reg_addr in range(256): addr = \ interconnect.get_config_addr( reg_addr, base_feat_addr + sram_index, x, y) result.append({ "name": f"SRAM_{sram_index}_{reg_addr}", "addr": addr, "range": (1 << 16) - 1, "repeat": repeat }) return result
def get_interconnect_regs(interconnect: Interconnect): """function to loop through every interconnect object and dump the entire configuration space """ result = [] for x, y in interconnect.tile_circuits: tile = interconnect.tile_circuits[(x, y)] # cb first for cb_name, cb in tile.cbs.items(): # get the index index = tile.features().index(cb) # reg space is always 0 for CB reg_addr = 0 # need to get range # notice that we may already replace the mux with aoi + const # so we need to get the height from the actual mux mux = cb.mux mux_range = mux.height config_addr = interconnect.get_config_addr(reg_addr, index, x, y) result.append({ "name": cb_name, "addr": config_addr, "range": mux_range }) for switchbox in tile.sbs.values(): index = tile.features().index(switchbox) # sort the reg names reg_names = list(switchbox.registers.keys()) reg_names.sort() for sb, sb_mux in switchbox.sb_muxs.values(): if sb_mux.height > 1: config_name = get_mux_sel_name(sb) assert config_name in reg_names reg_addr = reg_names.index(config_name) mux_range = sb_mux.height config_addr = interconnect.get_config_addr(reg_addr, index, x, y) result.append({ "name": str(sb), "addr": config_addr, "range": mux_range }) for node, reg_mux in switchbox.reg_muxs.values(): if reg_mux.height > 1: config_name = get_mux_sel_name(node) assert config_name in reg_names reg_addr = reg_names.index(config_name) mux_range = reg_mux.height config_addr = interconnect.get_config_addr(reg_addr, index, x, y) result.append({ "name": str(node), "addr": config_addr, "range": mux_range }) return result
def __prune_graph(self, ic: Interconnect) -> Tuple[Dict[int, InterconnectGraph], Set[Node]]: graphs = {} nodes = set() for bit_width in self.interconnect.get_bit_widths(): graphs[bit_width] = ic.get_graph(bit_width) # clear out every connection being made in the graph # this is fine since we have clone the graph for _, graph in graphs.items(): for coord in graph: tile = graph[coord] for sb in tile.switchbox.get_all_sbs(): sb.clear() for _, node in tile.switchbox.registers.items(): node.clear() for _, node in tile.switchbox.reg_muxs.items(): node.clear() for _, node in tile.ports.items(): node.clear() # also need to add pseudo connection between the port input and port # output # after this point we can't use the graph to route any more for route in self._routes: for i in range(len(route) - 1): from_node_ref = route[i] to_node_ref = route[i + 1] graph = ic.get_graph(from_node_ref.width) from_node = InterconnectGraph.locate_node(graph, from_node_ref) to_node = InterconnectGraph.locate_node(graph, to_node_ref) from_node.add_edge(to_node) nodes.add(from_node) nodes.add(to_node) # second pass to fake port connections so that we can determine the # evaluate order in the graph for route in self._routes: for node in route[1:]: # node is a sink node if not isinstance(node, PortNode): continue graph = ic.get_graph(node.width) sink_node = InterconnectGraph.locate_node(graph, node) for src_route in self._routes: graph_ = ic.get_graph(src_route[0].width) src_node = InterconnectGraph.locate_node(graph_, src_route[0]) if not isinstance(src_node, PortNode): continue if src_node.x == node.x and src_node.y == node.y: sink_node.add_edge(src_node, force_connect=True) return graphs, nodes
def get_core_registers(interconnect: Interconnect): result = [] for x, y in interconnect.tile_circuits: tile = interconnect.tile_circuits[(x, y)] core = tile.core if core is None: continue if isinstance(core, PeakCore): # extract out PE's configuration # notice that peak core is a black box. we have no idea what # the registers' semantic meaning feat_addr = tile.features().index(core) regs = list(core.registers.keys()) regs.sort() for idx, reg_name in enumerate(regs): reg_addr = idx width = core.reg_width[reg_name] addr = interconnect.get_config_addr(reg_addr, feat_addr, x, y) result.append({ "name": reg_name, "addr": addr, "range": 1 << width }) elif isinstance(core, MemCore): # memory has five features base_feat_addr = tile.features().index(core) regs = list(core.registers.keys()) regs.sort() for idx, reg_name in enumerate(regs): reg_addr = idx width = core.registers[reg_name].width addr = interconnect.get_config_addr(reg_addr, base_feat_addr, x, y) result.append({ "name": reg_name, "addr": addr, "range": 1 << width }) # SRAM for sram_index in range(4): for reg_addr in range(256): addr = \ interconnect.get_config_addr( reg_addr, base_feat_addr + sram_index, x, y) result.append({ "name": f"SRAM_{sram_index}_{reg_addr}", "addr": addr, "range": 1 << 16 }) return result
def pipeline_config_signals(interconnect: Interconnect, interval): # Right now in canal, the width of config_addr and config_data # are hard-coded to be the same. This should be changed. config_data_width = interconnect.config_data_width config_addr_width = config_data_width for (x, y) in interconnect.tile_circuits: tile = interconnect.tile_circuits[(x, y)] tile_core = tile.core # We only want to do this on PE and memory tiles if tile_core is None or "config" not in tile_core.ports or y == 0: continue else: if interval != 0 and y % interval == 0 and ( (x, y + 1) in interconnect.tile_circuits): tile_below = interconnect.tile_circuits[(x, y + 1)] pipe_stage = PipelineStage(config_addr_width, config_data_width) # remove existing config wire interconnect.remove_wire(tile.ports.config_out, tile_below.ports.config) # Now, wire config through the pipe stage interconnect.wire(tile.ports.config_out, pipe_stage.ports.config) interconnect.wire(pipe_stage.ports.config_out, tile_below.ports.config) # Wire up pipe stage clock input to output clock interconnect.wire(tile.ports.clk_out, pipe_stage.ports.clk)
def route_one_tile(interconnect: Interconnect, x: int, y: int, ports: List[str], seed: int = 0): import random r = random.Random(seed) result = {} mapping = {} interface_mapping = __get_interface_name(interconnect) tile = interconnect.tile_circuits[(x, y)] port_nodes = {} for tile_g in tile.tiles.values(): for p, node in tile_g.ports.items(): if p in ports: port_nodes[p] = node # check if we've found all port nodes for p in ports: if p not in port_nodes: raise ValueError(f"Unable to find port {p}") used_nodes = set() # sort the keys to be deterministic port_names = list(port_nodes.keys()) port_names.sort() input_ports = {} output_ports = {} for bit_width in interconnect.get_bit_widths(): input_ports[bit_width] = __get_input_ports(interconnect, bit_width) output_ports[bit_width] = __get_output_ports(interconnect, bit_width) # based on if it's input or output used_nodes = set() for port_name in port_names: node = port_nodes[port_name] bit_width = node.width if len(node) == 0: # it's an input # randomly choose an input src_index = r.randrange(len(input_ports[bit_width])) src_node = input_ports[bit_width][src_index] input_ports[bit_width].pop(src_index) path = __route(src_node, node, used_nodes) mapping[port_name] = interface_mapping[src_node] else: # it's on output # randomly choose an output dst_index = r.randrange(len(output_ports[bit_width])) dst_node = output_ports[bit_width][dst_index] output_ports[bit_width].pop(dst_index) path = __route(node, dst_node, used_nodes) mapping[port_name] = interface_mapping[dst_node] for n in path: used_nodes.add(n) result[f"e{len(result)}"] = [path] return result, mapping
def clk_physical(interconnect: Interconnect): for (x, y) in interconnect.tile_circuits: tile = interconnect.tile_circuits[(x, y)] tile_core = tile.core # We only want to do this on PE and memory tiles if tile_core is None or isinstance(tile_core, IOCoreBase): continue elif isinstance(tile_core, MemCore): if (x, y + 1) in interconnect.tile_circuits: tile_below = interconnect.tile_circuits[(x, y + 1)] if isinstance(tile_below.core, MemCore): interconnect.remove_wire(tile.ports.clk_out, tile_below.ports.clk) # Get the PE tile to the left of this mem tile tile_left = interconnect.tile_circuits[(x - 1, y)] # Connect the clk input of this mem tile to the right clk # output of the neighboring PE tile interconnect.wire(tile_left.ports.clk_pass_through_out_right, tile.ports.clk) else: orig_in_port = tile.ports.clk orig_out_port = tile.ports.clk_out # Remove the pass through connection that already exists tile.remove_wire(orig_in_port, orig_out_port) # Create a new pass through clock input tile.add_port("clk_pass_through", magma.In(magma.Bit)) pass_through_input = tile.ports.clk_pass_through pass_through_input_as_clk = tile.convert(pass_through_input, magma.clock) # Create 2 new clk pass through outputs (bottom and right) tile.add_port("clk_pass_through_out_bot", magma.Out(magma.Bit)) tile.add_port("clk_pass_through_out_right", magma.Out(magma.Clock)) tile.wire(tile.ports.clk_pass_through, tile.ports.clk_pass_through_out_bot) tile.wire(pass_through_input_as_clk, tile.ports.clk_pass_through_out_right) # Connect new clk pass through input to old pass through output tile.wire(pass_through_input_as_clk, orig_out_port) # For top row tiles, connect new clk input to global clock if y < 2: interconnect_clk_as_bit = interconnect.convert( interconnect.ports.clk, magma.bit) interconnect.wire(interconnect_clk_as_bit, pass_through_input) # For other tiles, connect new clk input to # pass through output of tile above. else: tile_above = interconnect.tile_circuits[(x, y - 1)] interconnect.wire(tile_above.ports.clk_pass_through_out_bot, pass_through_input)
def config_port_pass(interconnect: Interconnect): # x coordinate of garnet x_min = interconnect.x_min x_max = interconnect.x_max width = x_max - x_min + 1 # Add parallel configuration ports to interconnect # interconnect must have config port assert "config" in interconnect.ports interconnect.remove_port("config") config_data_width = interconnect.config_data_width # config_addr_width is same as config_data_width interconnect.add_port( "config", magma.In(magma.Array[ width, ConfigurationType(config_data_width, config_data_width)])) # looping through on a per-column bases for x_coor in range(x_min, x_min + width): column = interconnect.get_column(x_coor) # skip tiles with no config column = [entry for entry in column if "config" in entry.ports] # wire configuration ports to first tile in column interconnect.wire(interconnect.ports.config[x_coor], column[0].ports.config)
def stall_port_pass(interconnect: Interconnect): # x coordinate of garnet x_min = interconnect.x_min x_max = interconnect.x_max width = x_max - x_min + 1 # Add cgra stall assert "stall" in interconnect.ports stall_signal_width = interconnect.stall_signal_width # Currently stall signal is 1 bit assert stall_signal_width == 1 interconnect.remove_port("stall") interconnect.add_port( "stall", magma.In(magma.Bits[width * interconnect.stall_signal_width])) # looping through on a per-column bases for x_coor in range(x_min, x_min + width): column = interconnect.get_column(x_coor) # skip tiles with no stall column = [entry for entry in column if "stall" in entry.ports] # wire configuration ports to first tile in column interconnect.wire(interconnect.ports.stall[x_coor], column[0].ports.stall[0])
def tile_id_physical(interconnect: Interconnect): tile_id_width = interconnect.tile_id_width tie_hi_width = (tile_id_width // 2) + 1 if (tile_id_width % 2) == 0: tie_lo_width = tile_id_width // 2 else: tie_lo_width = (tile_id_width // 2) + 1 for (x, y) in interconnect.tile_circuits: tile = interconnect.tile_circuits[(x, y)] tile_core = tile.core if isinstance(tile_core, IOCoreValid) or tile_core is None: continue tile.add_ports(hi=magma.Out(magma.Bits[tie_hi_width]), lo=magma.Out(magma.Bits[tie_lo_width])) # wire all hi bits high tile.wire(tile.ports.hi, Const((2**tie_hi_width) - 1)) # wire all lo bits low tile.wire(tile.ports.lo, Const(0)) # Get the correct tile_id value x_bv = BitVector[tile_id_width / 2](x) y_bv = BitVector[tile_id_width / 2](y) tile_id_bv = BitVector.concat(y_bv, x_bv) # Disconnect existing constant from tile_id port tile_id_port = tile.ports.tile_id for wire in interconnect.wires: if tile_id_port in wire: interconnect.remove_wire(wire[0], wire[1]) break # Actually connect hi/lo outputs to tile_id at top level for i in range(tile_id_width): lo_index = i // 2 if (i % 2) == 0: hi_index = i // 2 else: hi_index = (i // 2) + 1 hi_port = tile.ports.hi[hi_index] lo_port = tile.ports.lo[lo_index] tie_port = hi_port if (tile_id_bv[i] == 1) else lo_port # Connect tile_id ports to hi/lo outputs instead of constant interconnect.wire(tile.ports.tile_id[i], tie_port)
def __get_ports(interconnect: Interconnect, bit_width, predicate): interface = interconnect.interface() result = [] for port_name in interface: port = interconnect.ports[port_name] port_type = port.base_type() node = interface[port_name] if node.width != bit_width: continue if predicate(port_type): result.append(node) return result
def parse_routing_result(raw_routing_result, interconnect: Interconnect): # in the original cyclone implementation we don't need this # since it just translate this IR into bsb format without verifying the # connectivity. here, however, we need to since we're producing bitstream result = {} for net_id, raw_routes in raw_routing_result.items(): result[net_id] = [] for raw_segment in raw_routes: segment = [] for node_str in raw_segment: node = interconnect.parse_node(node_str) segment.append(node) result[net_id].append(segment) return result
def chain_pass(interconnect: Interconnect): # pragma: nocover for (x, y) in interconnect.tile_circuits: tile = interconnect.tile_circuits[(x, y)] tile_core = tile.core if isinstance(tile_core, MemCore): # lift ports up lift_mem_ports(tile, tile_core) previous_tile = interconnect.tile_circuits[(x, y - 1)] if not isinstance(previous_tile.core, MemCore): interconnect.wire(Const(0), tile.ports.chain_valid_in) interconnect.wire(Const(0), tile.ports.chain_data_in) else: interconnect.wire(previous_tile.ports.chain_valid_out, tile.ports.chain_valid_in) interconnect.wire(previous_tile.ports.chain_data_out, tile.ports.chain_data_in)
def config_mem_tile(interconnect: Interconnect, full_cfg, new_config_data, x_place, y_place, mcore_cfg): for config_reg, val, feat in new_config_data: idx, value = mcore_cfg.get_config_data(config_reg, val) full_cfg.append((interconnect.get_config_addr(idx, feat, x_place, y_place), value))
def create_cgra(width: int, height: int, io_sides: IOSide, add_reg: bool = True, mem_ratio: Tuple[int, int] = (1, 4), reg_addr_width: int = 8, config_data_width: int = 32, tile_id_width: int = 16, num_tracks: int = 5, add_pd: bool = True, use_sram_stub: bool = True, hi_lo_tile_id: bool = True, pass_through_clk: bool = True, global_signal_wiring: GlobalSignalWiring = GlobalSignalWiring.Meso, standalone: bool = False, switchbox_type: SwitchBoxType = SwitchBoxType.Imran, port_conn_override: Dict[str, List[Tuple[SwitchBoxSide, SwitchBoxIO]]] = None): # currently only add 16bit io cores bit_widths = [1, 16] track_length = 1 # compute the actual size width, height = get_actual_size(width, height, io_sides) # these values are inclusive x_min, x_max, y_min, y_max = get_array_size(width, height, io_sides) # compute ratio tile_max = mem_ratio[-1] mem_tile_ratio = tile_max - mem_ratio[0] # creates all the cores here # we don't want duplicated cores when snapping into different interconnect # graphs cores = {} for x in range(width): for y in range(height): # empty corner if x in range(x_min) and y in range(y_min): core = None elif x in range(x_min) and y in range(y_max + 1, height): core = None elif x in range(x_max + 1, width) and y in range(y_min): core = None elif x in range(x_max + 1, width) and y in range(y_max + 1, height): core = None elif x in range(x_min) \ or x in range(x_max + 1, width) \ or y in range(y_min) \ or y in range(y_max + 1, height): core = IOCore() else: core = MemCore(use_sram_stub=use_sram_stub) if \ ((x - x_min) % tile_max >= mem_tile_ratio) else \ PeakCore(PE_fc) cores[(x, y)] = core def create_core(xx: int, yy: int): return cores[(xx, yy)] # Specify input and output port connections. inputs = set() outputs = set() for core in cores.values(): # Skip IO cores. if core is None or isinstance(core, IOCore): continue inputs |= {i.qualified_name() for i in core.inputs()} outputs |= {o.qualified_name() for o in core.outputs()} # This is slightly different from the original CGRA. Here we connect # input to every SB_IN and output to every SB_OUT. port_conns = {} in_conn = [(side, SwitchBoxIO.SB_IN) for side in SwitchBoxSide] out_conn = [(side, SwitchBoxIO.SB_OUT) for side in SwitchBoxSide] port_conns.update({input_: in_conn for input_ in inputs}) port_conns.update({output: out_conn for output in outputs}) if port_conn_override is not None: port_conns.update(port_conn_override) pipeline_regs = [] for track in range(num_tracks): for side in SwitchBoxSide: pipeline_regs.append((track, side)) # if reg mode is off, reset to empty if not add_reg: pipeline_regs = [] ics = {} track_list = list(range(num_tracks)) io_in = {"f2io_1": [0], "f2io_16": [0]} io_out = {"io2f_1": track_list, "io2f_16": track_list} for bit_width in bit_widths: if io_sides & IOSide.None_: io_conn = None else: io_conn = {"in": io_in, "out": io_out} ic = create_uniform_interconnect(width, height, bit_width, create_core, port_conns, {track_length: num_tracks}, switchbox_type, pipeline_regs, io_sides=io_sides, io_conn=io_conn) ics[bit_width] = ic interconnect = Interconnect(ics, reg_addr_width, config_data_width, tile_id_width, lift_ports=standalone, stall_signal_width=1) if hi_lo_tile_id: tile_id_physical(interconnect) if add_pd: add_power_domain(interconnect) interconnect.finalize() if global_signal_wiring == GlobalSignalWiring.Meso: apply_global_meso_wiring(interconnect, io_sides=io_sides) elif global_signal_wiring == GlobalSignalWiring.Fanout: apply_global_fanout_wiring(interconnect, io_sides=io_sides) elif global_signal_wiring == GlobalSignalWiring.ParallelMeso: apply_global_meso_wiring(interconnect, io_sides=io_sides) if add_pd: add_aon_read_config_data(interconnect) if pass_through_clk: clk_physical(interconnect) return interconnect
def config_mem_tile(interconnect: Interconnect, full_cfg, new_config_data, x_place, y_place, mcore_cfg): for config_reg, val, feat in new_config_data: full_cfg.append( (interconnect.get_config_addr(mcore_cfg.get_reg_index(config_reg), feat, x_place, y_place), val))
def create_cgra(chip_size: int, add_io: bool = False, cores_input=None): # currently only add 16bit io cores num_tracks = 2 reg_mode = True addr_width = 8 data_width = 32 bit_widths = [1, 16] tile_id_width = 16 track_length = 1 margin = 0 if not add_io else 1 chip_size += 2 * margin # recalculate the margin # creates all the cores here # we don't want duplicated cores when snapping into different interconnect # graphs if cores_input is None: cores_input = {} cores = {} for x in range(chip_size): for y in range(chip_size): if (x, y) in cores_input: # allow it to override cores[(x, y)] = cores_input[(x, y)] continue # empty corner if x in range(margin) and y in range(margin): core = None elif x in range(margin) and y in range(chip_size - margin, chip_size): core = None elif x in range(chip_size - margin, chip_size) and y in range(margin): core = None elif x in range(chip_size - margin, chip_size) and y in range(chip_size - margin, chip_size): core = None elif x in range(margin) \ or x in range(chip_size - margin, chip_size) \ or y in range(margin) \ or y in range(chip_size - margin, chip_size): if x == margin or y == margin: core = IO16bit() else: core = IO1bit() else: core = MemoryCore(1024) if ((x - margin) % 2 == 1) else \ PeCore() cores[(x, y)] = core def create_core(xx: int, yy: int): return cores[(xx, yy)] # specify input and output port connections inputs = ["data0", "data1", "bit0", "bit1", "bit2", "data_in", "addr_in", "flush", "ren_in", "wen_in", "data_in_16b", "wen", "ren", "addr"] outputs = ["out", "outb", "data_out", "data_out_16b"] # this is slightly different from the chip we tape out # here we connect input to every SB_IN and output to every SB_OUT port_conns = {} in_conn = [] out_conn = [] for side in SwitchBoxSide: in_conn.append((side, SwitchBoxIO.SB_IN)) out_conn.append((side, SwitchBoxIO.SB_OUT)) for input_port in inputs: port_conns[input_port] = in_conn for output_port in outputs: port_conns[output_port] = out_conn pipeline_regs = [] for track in range(num_tracks): for side in SwitchBoxSide: pipeline_regs.append((track, side)) # if reg mode is off, reset to empty if not reg_mode: pipeline_regs = [] ics = {} sides = IOSide.North | IOSide.East | IOSide.South | IOSide.West io_in = {"f2io_1": [1], "f2io_16": [0]} io_out = {"io2f_1": [1], "io2f_16": [0]} for bit_width in bit_widths: if add_io: io_conn = {"in": io_in, "out": io_out} else: io_conn = None ic = create_uniform_interconnect(chip_size, chip_size, bit_width, create_core, port_conns, {track_length: num_tracks}, SwitchBoxType.Disjoint, pipeline_regs, io_sides=sides, io_conn=io_conn) ics[bit_width] = ic interconnect = Interconnect(ics, addr_width, data_width, tile_id_width) return interconnect
def get_interconnect_regs(interconnect: Interconnect): """function to loop through every interconnect object and dump the entire configuration space """ result = [] for x, y in interconnect.tile_circuits: tile = interconnect.tile_circuits[(x, y)] # cb first for cb_name, cb in tile.cbs.items(): # get the index index = tile.features().index(cb) # need to get range # notice that we may already replace the mux with aoi + const # so we need to get the height from the actual mux mux = cb.mux mux_range = mux.height if mux_range <= 1: continue reg_addr, lo, hi = cb.get_reg_info(get_mux_sel_name(cb.node)) config_addr = interconnect.get_config_addr(reg_addr, index, x, y) result.append({ "name": cb_name, "addr": config_addr, "range": mux_range - 1, "lo": lo, "hi": hi, "reg_name": f"config_reg_{reg_addr}" }) for switchbox in tile.sbs.values(): index = tile.features().index(switchbox) for sb, sb_mux in switchbox.sb_muxs.values(): if sb_mux.height > 1: config_name = get_mux_sel_name(sb) reg_addr, lo, hi = switchbox.get_reg_info(config_name) mux_range = sb_mux.height config_addr = interconnect.get_config_addr(reg_addr, index, x, y) result.append({ "name": str(sb), "addr": config_addr, "range": mux_range - 1, "lo": lo, "hi": hi, "reg_name": f"config_reg_{reg_addr}" }) for node, reg_mux in switchbox.reg_muxs.values(): if reg_mux.height > 1: config_name = get_mux_sel_name(node) reg_addr, lo, hi = switchbox.get_reg_info(config_name) mux_range = reg_mux.height config_addr = interconnect.get_config_addr(reg_addr, index, x, y) result.append({ "name": str(node), "addr": config_addr, "range": mux_range - 1, "lo": lo, "hi": hi, "reg_name": f"config_reg_{reg_addr}" }) return result
def __get_interface_name(interconnect: Interconnect): result = {} interface = interconnect.interface() for port_name, port_node in interface.items(): result[port_node] = port_name return result