Esempio n. 1
0
def instantiate_indexor(prefix, width):
    """
    Instantiate an indexor for accessing memory with name `prefix`.
    Generates structure to initialize and update the indexor.

    The initializor starts sets the memories to their maximum value
    because we expect all indices to be incremented once before
    being used.

    Returns (cells, structure)
    """
    stdlib = py_ast.Stdlib()
    name = py_ast.CompVar(NAME_SCHEME["index name"].format(prefix=prefix))
    add_name = py_ast.CompVar(f"{prefix}_add")
    cells = [
        py_ast.Cell(name, stdlib.register(width)),
        py_ast.Cell(add_name, stdlib.op("add", width, signed=False)),
    ]

    init_name = py_ast.CompVar(NAME_SCHEME["index init"].format(prefix=prefix))
    init_group = py_ast.Group(
        init_name,
        connections=[
            py_ast.Connect(py_ast.ConstantPort(width, 2**width - 1),
                           py_ast.CompPort(name, "in")),
            py_ast.Connect(py_ast.ConstantPort(1, 1),
                           py_ast.CompPort(name, "write_en")),
            py_ast.Connect(py_ast.CompPort(name, "done"),
                           py_ast.HolePort(init_name, "done")),
        ],
    )

    upd_name = py_ast.CompVar(
        NAME_SCHEME["index update"].format(prefix=prefix))
    upd_group = py_ast.Group(
        upd_name,
        connections=[
            py_ast.Connect(py_ast.ConstantPort(width, 1),
                           py_ast.CompPort(add_name, "left")),
            py_ast.Connect(py_ast.CompPort(name, "out"),
                           py_ast.CompPort(add_name, "right")),
            py_ast.Connect(py_ast.CompPort(add_name, "out"),
                           py_ast.CompPort(name, "in")),
            py_ast.Connect(py_ast.ConstantPort(1, 1),
                           py_ast.CompPort(name, "write_en")),
            py_ast.Connect(py_ast.CompPort(name, "done"),
                           py_ast.HolePort(upd_name, "done")),
        ],
    )

    return (cells, [init_group, upd_group])
Esempio n. 2
0
def instantiate_pe(row, col, right_edge=False, down_edge=False):
    """
    Instantiate the PE and all the registers connected to it.
    """
    # Add all the required cells.
    stdlib = py_ast.Stdlib()
    cells = [
        py_ast.Cell(py_ast.CompVar(f"pe_{row}_{col}"),
                    py_ast.CompInst(PE_NAME, [])),
        py_ast.Cell(py_ast.CompVar(f"top_{row}_{col}"),
                    stdlib.register(BITWIDTH)),
        py_ast.Cell(py_ast.CompVar(f"left_{row}_{col}"),
                    stdlib.register(BITWIDTH)),
    ]
    return cells
Esempio n. 3
0
def instantiate_memory(top_or_left, idx, size):
    """
    Instantiates:
    - top memory
    - structure to move data from memory to read registers.

    Returns (cells, structure) tuple.
    """
    if top_or_left == "top":
        name = f"t{idx}"
        target_reg = f"top_0_{idx}"
    elif top_or_left == "left":
        name = f"l{idx}"
        target_reg = f"left_{idx}_0"
    else:
        raise f"Invalid top_or_left: {top_or_left}"

    var_name = py_ast.CompVar(f"{name}")
    idx_name = py_ast.CompVar(NAME_SCHEME["index name"].format(prefix=name))
    group_name = py_ast.CompVar(NAME_SCHEME["memory move"].format(prefix=name))
    target_reg = py_ast.CompVar(target_reg)
    structure = py_ast.Group(
        group_name,
        connections=[
            py_ast.Connect(py_ast.CompPort(idx_name, "out"),
                           py_ast.CompPort(var_name, "addr0")),
            py_ast.Connect(
                py_ast.CompPort(var_name, "read_data"),
                py_ast.CompPort(target_reg, "in"),
            ),
            py_ast.Connect(py_ast.ConstantPort(1, 1),
                           py_ast.CompPort(target_reg, "write_en")),
            py_ast.Connect(py_ast.CompPort(target_reg, "done"),
                           py_ast.HolePort(group_name, "done")),
        ],
    )

    idx_width = bits_needed(size)
    # Instantiate the indexor
    (idx_cells, idx_structure) = instantiate_indexor(name, idx_width)
    idx_structure.append(structure)
    # Instantiate the memory
    idx_cells.append(
        py_ast.Cell(
            var_name,
            py_ast.Stdlib().mem_d1(BITWIDTH, size, idx_width),
            is_external=True,
        ))
    return (idx_cells, idx_structure)
Esempio n. 4
0
def create_systolic_array(top_length,
                          top_depth,
                          left_length,
                          left_depth,
                          gen_metadata=False):
    """
    top_length: Number of PEs in each row.
    top_depth: Number of elements processed by each PE in a row.
    left_length: Number of PEs in each column.
    left_depth: Number of elements processed by each PE in a col.
    """

    assert top_depth == left_depth, (
        f"Cannot multiply matrices: "
        f"{top_length}x{top_depth} and {left_depth}x{left_length}")

    cells = []
    wires = []

    # Instantiate all the memories
    for r in range(top_length):
        (c, s) = instantiate_memory("top", r, top_depth)
        cells.extend(c)
        wires.extend(s)

    for c in range(left_length):
        (c, s) = instantiate_memory("left", c, left_depth)
        cells.extend(c)
        wires.extend(s)

    # Instantiate output memory
    total_size = left_length * top_length
    out_idx_size = bits_needed(total_size)
    cells.append(
        py_ast.Cell(
            OUT_MEM,
            py_ast.Stdlib().mem_d1(BITWIDTH, total_size, out_idx_size),
            is_external=True,
        ))

    # Instantiate all the PEs
    for row in range(left_length):
        for col in range(top_length):
            # Instantiate the PEs
            c = instantiate_pe(row, col, col == top_length - 1,
                               row == left_length - 1)
            cells.extend(c)

            # Instantiate the mover fabric
            s = instantiate_data_move(row, col, col == top_length - 1,
                                      row == left_length - 1)
            wires.extend(s)

            # Instantiate output movement structure
            s = instantiate_output_move(row, col, top_length, out_idx_size)
            wires.append(s)

    control, source_map = generate_control(top_length,
                                           top_depth,
                                           left_length,
                                           left_depth,
                                           gen_metadata=gen_metadata)

    main = py_ast.Component(
        name="main",
        inputs=[],
        outputs=[],
        structs=wires + cells,
        controls=control,
    )

    return (
        py_ast.Program(
            imports=[
                py_ast.Import("primitives/core.futil"),
                py_ast.Import("primitives/binary_operators.futil"),
            ],
            components=[main],
        ),
        source_map,
    )