示例#1
0
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
示例#3
0
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
示例#4
0
    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
示例#5
0
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)
示例#7
0
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
示例#8
0
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])
示例#11
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)
示例#12
0
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
示例#13
0
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
示例#14
0
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)
示例#15
0
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))
示例#16
0
文件: util.py 项目: zamyers/garnet
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
示例#17
0
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))
示例#18
0
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
示例#19
0
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
示例#20
0
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