Пример #1
0
def test_instance_name_tile():
    core = DummyCore()
    circuit = core.circuit()
    assert str(
        circuit.instances
    ) == '[MuxWithDefaultWrapper_2_32_8_0_inst0 = MuxWithDefaultWrapper_2_32_8_0(), dummy_1 = ConfigRegister_32_8_32_0(name="dummy_1"), dummy_2 = ConfigRegister_32_8_32_1(name="dummy_2")]'  # noqa
    with tempfile.TemporaryDirectory() as tempdir:
        m.compile(f"{tempdir}/core", circuit)
        assert check_files_equal(f"{tempdir}/core.v",
                                 "tests/generator/gold/core_instance_name.v")
Пример #2
0
def test_instance_name_tile():
    core = DummyCore()
    circuit = core.circuit()
    print(str(circuit.instances))
    assert str(
        circuit.instances
    ) == '[config_reg_0 = ConfigRegister_32_8_32_0(name="config_reg_0"), dummy_1_inst0 = dummy_1(), config_reg_1 = ConfigRegister_32_8_32_1(name="config_reg_1"), dummy_2_inst0 = dummy_2(), MuxWrapper_2_32_inst0 = MuxWrapper_2_32()]'  # noqa
    with tempfile.TemporaryDirectory() as tempdir:
        m.compile(f"{tempdir}/core", circuit, output="coreir-verilog")
        assert check_files_equal(f"{tempdir}/core.v",
                                 "tests/generator/gold/core_instance_name.v")
Пример #3
0
def test_dump_pnr():
    num_tracks = 2
    addr_width = 8
    data_width = 32
    bit_widths = [1, 16]

    tile_id_width = 16

    chip_size = 2
    track_length = 1

    # creates all the cores here
    # we don't want duplicated cores when snapping into different interconnect
    # graphs
    cores = {}
    for x in range(chip_size):
        for y in range(chip_size):
            cores[(x, y)] = DummyCore()

    def create_core(xx: int, yy: int):
        return cores[(xx, yy)]

    in_conn = []
    out_conn = []
    for side in SwitchBoxSide:
        in_conn.append((side, SwitchBoxIO.SB_IN))
        out_conn.append((side, SwitchBoxIO.SB_OUT))

    pipeline_regs = []
    for track in range(num_tracks):
        for side in SwitchBoxSide:
            pipeline_regs.append((track, side))

    ics = {}
    for bit_width in bit_widths:
        ic = create_uniform_interconnect(chip_size,
                                         chip_size,
                                         bit_width,
                                         create_core, {
                                             f"data_in_{bit_width}b": in_conn,
                                             f"data_out_{bit_width}b": out_conn
                                         }, {track_length: num_tracks},
                                         SwitchBoxType.Disjoint,
                                         pipeline_reg=pipeline_regs)
        ics[bit_width] = ic

    interconnect = Interconnect(ics,
                                addr_width,
                                data_width,
                                tile_id_width,
                                lift_ports=True)

    design_name = "test"
    with tempfile.TemporaryDirectory() as tempdir:
        interconnect.dump_pnr(tempdir, design_name)

        assert os.path.isfile(os.path.join(tempdir, f"{design_name}.info"))
        assert os.path.isfile(os.path.join(tempdir, "1.graph"))
        assert os.path.isfile(os.path.join(tempdir, "16.graph"))
        assert os.path.isfile(os.path.join(tempdir, f"{design_name}.layout"))
Пример #4
0
def interconnect_route():
    chip_size = 2

    # creates all the cores here
    # we don't want duplicated cores when snapping into different interconnect
    # graphs
    cores = {}
    for x in range(0, chip_size + 2):
        for y in range(0, chip_size + 2):
            cores[(x, y)] = IO16bit()
    for x in range(1, 1 + chip_size):
        for y in range(1, 1 + chip_size):
            cores[(x, y)] = DummyCore()
    # corners
    for x, y in [(0, 0), (0, chip_size + 1), (chip_size + 1, 0),
                 (chip_size + 1, chip_size + 1)]:
        cores[(x, y)] = None

    interconnect = create_cgra(chip_size, True, cores_input=cores)

    netlist = {
        "e0": [("I0", "io2f_16"), ("r0", "reg")],
        "e1": [("r0", "reg"), ("D0", "data_in_16b")],
        "e2": [("D0", "data_out_16b"), ("I1", "f2io_16")]
    }
    bus = {"e0": 16, "e1": 16, "e2": 16}

    with tempfile.TemporaryDirectory() as tempdir:
        _, route = pnr(interconnect, (netlist, bus), cwd=tempdir)

    # two paths
    route_path = [route["e0"][0], route["e1"][0], route["e2"][0]]

    return interconnect, route_path
Пример #5
0
def create_dummy_cgra(chip_size, num_tracks, reg_mode, wiring, num_cfg=1):
    addr_width = 8
    data_width = 32
    bit_widths = [1, 16]
    tile_id_width = 16
    track_length = 1
    # creates all the cores here
    # we don't want duplicated cores when snapping into different interconnect
    # graphs
    cores = {}
    for x in range(chip_size):
        for y in range(chip_size):
            cores[(x, y)] = DummyCore()

    def create_core(xx: int, yy: int):
        return cores[(xx, yy)]

    in_conn = []
    out_conn = []
    for side in SwitchBoxSide:
        in_conn.append((side, SwitchBoxIO.SB_IN))
        out_conn.append((side, SwitchBoxIO.SB_OUT))
    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 = {}
    for bit_width in bit_widths:
        ic = create_uniform_interconnect(chip_size, chip_size, bit_width,
                                         create_core, {
                                             f"data_in_{bit_width}b": in_conn,
                                             f"data_out_{bit_width}b": out_conn
                                         }, {track_length: num_tracks},
                                         SwitchBoxType.Disjoint, pipeline_regs)
        ics[bit_width] = ic
    interconnect = Interconnect(ics,
                                addr_width,
                                data_width,
                                tile_id_width,
                                lift_ports=True)
    # finalize the design
    interconnect.finalize()
    # wiring
    if wiring == GlobalSignalWiring.Fanout:
        apply_global_fanout_wiring(interconnect, IOSide.None_)
    elif wiring == GlobalSignalWiring.Meso:
        apply_global_meso_wiring(interconnect, IOSide.None_)
    else:
        assert wiring == GlobalSignalWiring.ParallelMeso
        apply_global_parallel_meso_wiring(interconnect, IOSide.None_, num_cfg)

    return bit_widths, data_width, ics, interconnect
Пример #6
0
def test_empty_tile_util():
    chip_size = 4
    margin = 1
    sides = IOSide.North | IOSide.East | IOSide.South | IOSide.West
    bit_widths = [1, 16]
    cores = {}
    track_length = 1
    num_tracks = 2
    addr_width = 8
    data_width = 32
    tile_id_width = 16
    for x in range(chip_size + 2 * margin):
        for y in range(chip_size + 2 * margin):
            if 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):
                cores[(x, y)] = None
            else:
                cores[(x, y)] = DummyCore()

    def core_fn(x, y):
        return cores[(x, y)]

    in_conn = []
    out_conn = []
    for side in SwitchBoxSide:
        in_conn.append((side, SwitchBoxIO.SB_IN))
        out_conn.append((side, SwitchBoxIO.SB_OUT))

    ics = {}
    for bit_width in bit_widths:
        ic = create_uniform_interconnect(chip_size,
                                         chip_size,
                                         bit_width,
                                         core_fn, {
                                             f"data_in_{bit_width}b": in_conn,
                                             f"data_out_{bit_width}b": out_conn
                                         }, {track_length: num_tracks},
                                         SwitchBoxType.Disjoint,
                                         io_sides=sides)
        ics[bit_width] = ic
    interconnect = Interconnect(ics, addr_width, data_width, tile_id_width)
    interconnect.finalize()
    # wiring
    apply_global_meso_wiring(interconnect)

    circuit = interconnect.circuit()
    with tempfile.TemporaryDirectory() as tempdir:
        filename = os.path.join(tempdir, "interconnect")
        magma.compile(filename, circuit, output="coreir-verilog")
Пример #7
0
def test_empty_switch_box():
    bit_width = 1
    core = CoreInterface(DummyCore())
    tile = Tile(0, 0, bit_width, SwitchBox(0, 0, 0, bit_width, []))
    tile.set_core(core)
    # because we need something to be connected to the core node
    # otherwise it's an illogical tile
    sb_node = SwitchBoxNode(0, 1, 0, bit_width, SwitchBoxSide.NORTH,
                            SwitchBoxIO.SB_IN)
    sb_node.add_edge(tile.ports["data_in_1b"])

    tile_circuit = TileCircuit({bit_width: tile}, 8, 32)
    tile_circuit.finalize()
    # also need to ground the 16 bit
    tile_circuit.wire(Const(0), tile_circuit.core.ports["data_in_16b"])
    circuit = tile_circuit.circuit()
    with tempfile.TemporaryDirectory() as tempdir:
        filename = os.path.join(tempdir, "tile")
        magma.compile(filename, circuit, output="coreir-verilog")
Пример #8
0
def test_1x1(double_buffer):
    ics = {}
    in_conn = []
    out_conn = []
    addr_width = 8
    data_width = 32
    for side in SwitchBoxSide:
        in_conn.append((side, SwitchBoxIO.SB_IN))
        out_conn.append((side, SwitchBoxIO.SB_OUT))

    core = DummyCore()

    for bit_width in {1, 16}:
        ic = create_uniform_interconnect(1, 1, bit_width,
                                         lambda _, __: core,
                                         {f"data_in_{bit_width}b": in_conn,
                                          f"data_out_{bit_width}b": out_conn},
                                         {1: 2},
                                         SwitchBoxType.Disjoint)
        ics[bit_width] = ic
    interconnect = Interconnect(ics, addr_width, data_width, 16,
                                lift_ports=True, double_buffer=double_buffer)
    interconnect.finalize()
    apply_global_fanout_wiring(interconnect)
    circuit = interconnect.circuit()
    with tempfile.TemporaryDirectory() as tempdir:
        filename = os.path.join(tempdir, "test1x1")
        magma.compile(filename, circuit, output="coreir-verilog")
    # test routing for 1x1
    compares = {}
    for seed in {0, 1}:
        routing_result, _ = route_one_tile(interconnect, 0, 0,
                                           ports=["data_in_16b",
                                                  "data_out_16b"],
                                           seed=seed)
        # routing result ordering is the same as ports
        assert len(routing_result) == 2
        bs = interconnect.get_route_bitstream(routing_result)
        assert len(bs) > 0
        compares[seed] = bs
    for i in range(2):
        assert compares[0][i] != compares[1][i]
Пример #9
0
def test_double_buffer():
    addr_width = 8
    data_width = 32
    bit_widths = [1, 16]
    num_tracks = 5
    tile_id_width = 16
    x = 0
    y = 0

    dummy_core = DummyCore()
    core = CoreInterface(dummy_core)

    tiles: Dict[int, Tile] = {}

    for bit_width in bit_widths:
        # we use disjoint switch here
        switchbox = DisjointSwitchBox(x, y, num_tracks, bit_width)
        tile = Tile(x, y, bit_width, switchbox)
        tiles[bit_width] = tile

    # set the core and core connection
    # here all the input ports are connect to SB_IN and all output ports are
    # connected to SB_OUT
    input_connections = []
    for track in range(num_tracks):
        for side in SwitchBoxSide:
            input_connections.append(
                SBConnectionType(side, track, SwitchBoxIO.SB_IN))
    output_connections = []
    for track in range(num_tracks):
        for side in SwitchBoxSide:
            output_connections.append(
                SBConnectionType(side, track, SwitchBoxIO.SB_OUT))

    for bit_width, tile in tiles.items():
        tile.set_core(core)
        input_port_name = f"data_in_{bit_width}b"
        output_port_name = f"data_out_{bit_width}b"

        tile.set_core_connection(input_port_name, input_connections)
        tile.set_core_connection(output_port_name, output_connections)

    tile_circuit = TileCircuit(tiles,
                               addr_width,
                               data_width,
                               tile_id_width=tile_id_width,
                               double_buffer=True)
    tile_circuit.finalize()
    circuit = tile_circuit.circuit()
    bit_width = 16
    # find corresponding sb
    sb_circuit: SB = None
    for _, sb in tile_circuit.sbs.items():
        if sb.switchbox.width == bit_width:
            sb_circuit = sb
            break
    assert sb_circuit is not None
    # find that connection box
    input_port_name = f"data_in_{bit_width}b"

    cb_circuit: CB = None
    for _, cb in tile_circuit.cbs.items():
        if cb.node.name == input_port_name:
            cb_circuit = cb
            break
    assert cb_circuit

    output_port_name = f"data_out_{bit_width}b"
    out_port_node = tile_circuit.tiles[bit_width].ports[output_port_name]
    in_port_node = tile_circuit.tiles[bit_width].ports[input_port_name]

    input_1 = sb_circuit.switchbox.get_sb(SwitchBoxSide.NORTH, 0,
                                          SwitchBoxIO.SB_IN)
    input_1_name = create_name(str(input_1))
    input_2 = sb_circuit.switchbox.get_sb(SwitchBoxSide.EAST, 1,
                                          SwitchBoxIO.SB_IN)
    input_2_name = create_name(str(input_2))
    output_sb = sb_circuit.switchbox.get_sb(SwitchBoxSide.SOUTH, 2,
                                            SwitchBoxIO.SB_OUT)
    output_name = create_name(str(output_sb))

    input_1_bitstream = tile_circuit.get_route_bitstream_config(
        input_1, in_port_node)
    input_2_bitstream = tile_circuit.get_route_bitstream_config(
        input_2, in_port_node)
    output_bitstream = tile_circuit.get_route_bitstream_config(
        out_port_node, output_sb)

    # notice that both of them will be configured using the double buffer scheme

    def get_config_data(config_data, reg_data):
        for reg_addr, feat_addr, config_value in reg_data:
            reg_addr = reg_addr << tile_circuit.feature_config_slice.start
            feat_addr = feat_addr << tile_circuit.tile_id_width
            addr = reg_addr | feat_addr
            addr = BitVector[data_width](addr) | BitVector[data_width](0)
            config_data.append((addr, config_value))

    input1_config_data = []
    input2_config_data = []
    get_config_data(input1_config_data, [input_1_bitstream, output_bitstream])
    get_config_data(input2_config_data, [input_2_bitstream, output_bitstream])
    input1_config_data = compress_config_data(input1_config_data)
    input2_config_data = compress_config_data(input2_config_data)

    tester = BasicTester(circuit, circuit.clk, circuit.reset)
    tester.poke(circuit.tile_id, 0)

    for addr, config_value in input1_config_data:
        tester.configure(addr, config_value)
        tester.config_read(addr)
        tester.eval()
        tester.expect(circuit.read_config_data, config_value)

    # configure the double buffer register
    tester.poke(circuit.config_db, 1)
    for addr, config_value in input2_config_data:
        tester.configure(addr, config_value)
        tester.config_read(addr)
        tester.eval()
        tester.expect(circuit.read_config_data, config_value)

    # the route should still be input 1
    port = circuit.interface.ports[input_1_name]
    tester.poke(port, 42)
    port = circuit.interface.ports[input_2_name]
    tester.poke(port, 43)
    tester.eval()
    tester.expect(circuit.interface.ports[output_name], 42)
    # now use the double buffer
    tester.poke(circuit.use_db, 1)
    tester.eval()
    tester.expect(circuit.interface.ports[output_name], 43)

    with tempfile.TemporaryDirectory() as tempdir:
        tester.compile_and_run(target="verilator",
                               magma_output="coreir-verilog",
                               directory=tempdir,
                               flags=["-Wno-fatal"])
Пример #10
0
def test_tile(num_tracks: int, add_additional_core: bool):
    import random
    random.seed(0)
    addr_width = 8
    data_width = 32
    bit_widths = [1, 16]

    tile_id_width = 16
    x = 0
    y = 0

    dummy_core = DummyCore()
    core = CoreInterface(dummy_core)

    if add_additional_core:
        c = AdditionalDummyCore()
        additional_core = CoreInterface(c)
    else:
        additional_core = None

    tiles: Dict[int, Tile] = {}

    for bit_width in bit_widths:
        # we use disjoint switch here
        switchbox = DisjointSwitchBox(x, y, num_tracks, bit_width)
        tile = Tile(x, y, bit_width, switchbox)
        tiles[bit_width] = tile

    # set the core and core connection
    # here all the input ports are connect to SB_IN and all output ports are
    # connected to SB_OUT
    input_connections = []
    for track in range(num_tracks):
        for side in SwitchBoxSide:
            input_connections.append(
                SBConnectionType(side, track, SwitchBoxIO.SB_IN))
    output_connections = []
    for track in range(num_tracks):
        for side in SwitchBoxSide:
            output_connections.append(
                SBConnectionType(side, track, SwitchBoxIO.SB_OUT))

    for bit_width, tile in tiles.items():
        tile.set_core(core)
        if add_additional_core:
            connection_type = CoreConnectionType.Core | CoreConnectionType.CB
            tile.add_additional_core(additional_core, connection_type)

        input_port_name = f"data_in_{bit_width}b"
        input_port_name_extra = f"data_in_{bit_width}b_extra"
        output_port_name = f"data_out_{bit_width}b"

        tile.set_core_connection(input_port_name, input_connections)
        tile.set_core_connection(output_port_name, output_connections)

        if add_additional_core:
            tile.set_core_connection(input_port_name_extra, input_connections)

    tile_circuit = TileCircuit(tiles,
                               addr_width,
                               data_width,
                               tile_id_width=tile_id_width)

    # finalize it
    tile_circuit.finalize()

    circuit = tile_circuit.circuit()

    # set up the configuration and test data
    # there are several things we are interested in the tile level and
    # need to test
    # 1. given an input to SB_IN, and configure it to CB, will the core
    # receive the data or not
    # 2. given an output signal from core, and configure it to SB, will the
    # SB_OUT receive the data or not
    # However, because we can only poke input ports, we cannot test #2 in the
    # current environment. As a result, we will combined these 2 together, that
    # is:
    # given an SB_IN signal, we configure the CB to the data_in, then configure
    # the SB_OUT to receive the signal
    raw_config_data = []
    config_data = []
    test_data = []
    tile_id = fault.random.random_bv(tile_id_width)

    for bit_width in bit_widths:
        # find corresponding sb
        sb_circuit: SB = None
        for _, sb in tile_circuit.sbs.items():
            if sb.switchbox.width == bit_width:
                sb_circuit = sb
                break
        assert sb_circuit is not None

        # input
        if add_additional_core:
            input_port_name = f"data_in_{bit_width}b_extra"
        else:
            input_port_name = f"data_in_{bit_width}b"
        in_port_node = tile_circuit.tiles[bit_width].ports[input_port_name]
        # find that connection box
        cb_circuit: CB = None
        for _, cb in tile_circuit.cbs.items():
            if cb.node.name == input_port_name:
                cb_circuit = cb
                break
        assert cb_circuit

        output_port_name = f"data_out_{bit_width}b"
        out_port_node = tile_circuit.tiles[bit_width].ports[output_port_name]

        all_sbs = sb_circuit.switchbox.get_all_sbs()
        for in_sb_node in all_sbs:
            if in_sb_node.io != SwitchBoxIO.SB_IN:
                continue

            for out_sb_node in all_sbs:
                if out_sb_node.io != SwitchBoxIO.SB_OUT:
                    continue
                # find the output node's index to that switch box node
                data0 = tile_circuit.get_route_bitstream_config(
                    in_sb_node, in_port_node)
                data1 = tile_circuit.get_route_bitstream_config(
                    out_port_node, out_sb_node)
                raw_config_data.append(data0)

                raw_config_data.append(data1)

                # configure the cb to route data from additional core to the
                # main core
                if add_additional_core:
                    input_port_name = f"data_in_{bit_width}b"
                    output_port_name = f"data_out_{bit_width}b_extra"
                    additional_in_port_node = \
                        tile_circuit.tiles[bit_width].ports[input_port_name]
                    additional_out_port_node = \
                        tile_circuit.tiles[bit_width].ports[output_port_name]
                    data2 = tile_circuit.get_route_bitstream_config(
                        additional_out_port_node, additional_in_port_node)
                    raw_config_data.append(data2)

                in_sb_name = create_name(str(in_sb_node))
                out_sb_name = create_name(str(out_sb_node))
                test_data.append(
                    (circuit.interface.ports[in_sb_name],
                     circuit.interface.ports[out_sb_name],
                     fault.random.random_bv(bit_width), in_sb_node))

    if add_additional_core:
        assert len(raw_config_data) / 3 == len(test_data)
    else:
        assert len(raw_config_data) / 2 == len(test_data)

    # process the raw config data and change it into the actual config addr
    for reg_addr, feat_addr, config_value in raw_config_data:
        reg_addr = reg_addr << tile_circuit.feature_config_slice.start
        feat_addr = feat_addr << tile_circuit.tile_id_width
        addr = reg_addr | feat_addr
        addr = BitVector[data_width](addr) | BitVector[data_width](tile_id)
        config_data.append((addr, config_value))

    # actual tests
    tester = BasicTester(circuit, circuit.clk, circuit.reset)
    tester.poke(circuit.tile_id, tile_id)

    stride = 3 if add_additional_core else 2
    for i in range(0, len(config_data), stride):
        tester.reset()
        c_data = config_data[i:i + stride]
        c_data = compress_config_data(c_data)
        for addr, config_value in c_data:
            tester.configure(addr, config_value)
            tester.configure(addr, config_value + 1, False)
            tester.config_read(addr)
            tester.eval()
            tester.expect(circuit.read_config_data, config_value)

        input_port, output_port, value, in_node = test_data[i // stride]

        tester.poke(input_port, value)
        tester.eval()
        # add additional error to check, i.e. sending random junk data to
        # all unrelated ports
        for bit_width in bit_widths:
            sb = tile_circuit.sbs[bit_width]
            sbs = sb.switchbox.get_all_sbs()
            for sb in sbs:
                if sb == in_node or sb.io == SwitchBoxIO.SB_OUT:
                    continue
                port_name = create_name(str(sb))
                port = circuit.interface.ports[port_name]
                tester.poke(port, fault.random.random_bv(bit_width))
                tester.eval()

        tester.expect(output_port, value)

    with tempfile.TemporaryDirectory() as tempdir:
        tester.compile_and_run(target="verilator",
                               magma_output="coreir-verilog",
                               directory=tempdir,
                               flags=["-Wno-fatal"])
Пример #11
0
 def dummy_col(_: int, __: int):
     return DummyCore()