コード例 #1
0
ファイル: gen-systolic.py プロジェクト: pbonh/calyx
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 = ast.Stdlib()
    cells = [
        ast.Cell(ast.CompVar(f"pe_{row}_{col}"), ast.CompInst(PE_NAME, [])),
        ast.Cell(ast.CompVar(f"top_{row}_{col}"), stdlib.register(BITWIDTH)),
        ast.Cell(ast.CompVar(f"left_{row}_{col}"), stdlib.register(BITWIDTH)),
    ]
    return cells
コード例 #2
0
ファイル: gen-systolic.py プロジェクト: pbonh/calyx
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 = ast.CompVar(f"{name}")
    idx_name = ast.CompVar(NAME_SCHEME["index name"].format(prefix=name))
    group_name = ast.CompVar(NAME_SCHEME["memory move"].format(prefix=name))
    target_reg = ast.CompVar(target_reg)
    structure = ast.Group(
        group_name,
        connections=[
            ast.Connect(ast.CompPort(idx_name, "out"), ast.CompPort(var_name, "addr0")),
            ast.Connect(
                ast.CompPort(var_name, "read_data"), ast.CompPort(target_reg, "in")
            ),
            ast.Connect(ast.ConstantPort(1, 1), ast.CompPort(target_reg, "write_en")),
            ast.Connect(
                ast.CompPort(target_reg, "done"), 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(
        ast.Cell(
            var_name, ast.Stdlib().mem_d1(BITWIDTH, size, idx_width), is_external=True
        )
    )
    return (idx_cells, idx_structure)
コード例 #3
0
ファイル: gen-systolic.py プロジェクト: pbonh/calyx
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 = ast.Stdlib()
    name = ast.CompVar(NAME_SCHEME["index name"].format(prefix=prefix))
    add_name = ast.CompVar(f"{prefix}_add")
    cells = [
        ast.Cell(name, stdlib.register(width)),
        ast.Cell(add_name, stdlib.op("add", width, signed=False)),
    ]

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

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

    return (cells, [init_group, upd_group])
コード例 #4
0
ファイル: gen-systolic.py プロジェクト: pbonh/calyx
def instantiate_output_move(row, col, row_idx_bitwidth, col_idx_bitwidth):
    """
    Generates groups to move the final value from a PE into the output array.
    """
    group_name = ast.CompVar(NAME_SCHEME["out mem move"].format(pe=f"pe_{row}_{col}"))
    pe = ast.CompVar(f"pe_{row}_{col}")
    return ast.Group(
        group_name,
        connections=[
            ast.Connect(
                ast.ConstantPort(row_idx_bitwidth, row), ast.CompPort(OUT_MEM, "addr0")
            ),
            ast.Connect(
                ast.ConstantPort(col_idx_bitwidth, col), ast.CompPort(OUT_MEM, "addr1")
            ),
            ast.Connect(ast.CompPort(pe, "out"), ast.CompPort(OUT_MEM, "write_data")),
            ast.Connect(ast.ConstantPort(1, 1), ast.CompPort(OUT_MEM, "write_en")),
            ast.Connect(
                ast.CompPort(OUT_MEM, "done"), ast.HolePort(group_name, "done")
            ),
        ],
    )
コード例 #5
0
ファイル: gen-systolic.py プロジェクト: pbonh/calyx
def instantiate_data_move(row, col, right_edge, down_edge):
    """
    Generates groups for "data movers" which are groups that move data
    from the `write` register of the PE at (row, col) to the read register
    of the PEs at (row+1, col) and (row, col+1)
    """
    name = f"pe_{row}_{col}"
    structures = []

    if not right_edge:
        group_name = ast.CompVar(NAME_SCHEME["register move right"].format(pe=name))
        src_reg = ast.CompVar(f"left_{row}_{col}")
        dst_reg = ast.CompVar(f"left_{row}_{col + 1}")
        mover = ast.Group(
            group_name,
            connections=[
                ast.Connect(ast.CompPort(src_reg, "out"), ast.CompPort(dst_reg, "in")),
                ast.Connect(ast.ConstantPort(1, 1), ast.CompPort(dst_reg, "write_en")),
                ast.Connect(
                    ast.CompPort(dst_reg, "done"), ast.HolePort(group_name, "done")
                ),
            ],
        )
        structures.append(mover)

    if not down_edge:
        group_name = ast.CompVar(NAME_SCHEME["register move down"].format(pe=name))
        src_reg = ast.CompVar(f"top_{row}_{col}")
        dst_reg = ast.CompVar(f"top_{row + 1}_{col}")
        mover = ast.Group(
            group_name,
            connections=[
                ast.Connect(ast.CompPort(src_reg, "out"), ast.CompPort(dst_reg, "in")),
                ast.Connect(ast.ConstantPort(1, 1), ast.CompPort(dst_reg, "write_en")),
                ast.Connect(
                    ast.CompPort(dst_reg, "done"), ast.HolePort(group_name, "done")
                ),
            ],
        )
        structures.append(mover)

    return structures
コード例 #6
0
ファイル: gen-systolic.py プロジェクト: pbonh/calyx
def generate_control(top_length, top_depth, left_length, left_depth):
    """
    Logically, control performs the following actions:
    1. Initialize all the memory indexors at the start.
    2. For each time step in the schedule:
        a. Move the data required by PEs in this cycle.
        b. Update the memory indices if needed.
        c. Run the PEs that need to be active this cycle.
    """
    sch = schedule_to_timesteps(
        generate_schedule(top_length, top_depth, left_length, left_depth)
    )

    control = []

    # Initialize all memories.
    init_indices = [
        ast.Enable(NAME_SCHEME["index init"].format(prefix=f"t{idx}"))
        for idx in range(top_length)
    ]
    init_indices.extend(
        [
            ast.Enable(NAME_SCHEME["index init"].format(prefix=f"l{idx}"))
            for idx in range(left_length)
        ]
    )
    control.append(ast.ParComp(init_indices))

    # Increment memories for PE_00 before computing with it.
    upd_pe00_mem = []
    upd_pe00_mem.append(ast.Enable(NAME_SCHEME["index update"].format(prefix="t0")))
    upd_pe00_mem.append(ast.Enable(NAME_SCHEME["index update"].format(prefix="l0")))
    control.append(ast.ParComp(upd_pe00_mem))

    for (idx, elements) in enumerate(sch):
        # Move all the requisite data.
        move = [ast.Enable(row_data_mover_at(r, c)) for (r, c) in elements]
        move.extend([ast.Enable(col_data_mover_at(r, c)) for (r, c) in elements])
        control.append(ast.ParComp(move))

        # Update the indices if needed.
        more_control = []
        if idx < len(sch) - 1:
            next_elements = sch[idx + 1]
            upd_memory = [
                ast.Enable(upd)
                for (r, c) in next_elements
                if (r == 0 or c == 0)
                for upd in index_update_at(r, c)
            ]
            more_control.extend(upd_memory)

        # ast.Invoke the PEs and move the data to the next layer.
        for (r, c) in elements:
            more_control.append(
                ast.Invoke(
                    id=ast.CompVar(f"pe_{r}_{c}"),
                    in_connects=[
                        ("top", ast.CompPort(ast.CompVar(f"top_{r}_{c}"), "out")),
                        ("left", ast.CompPort(ast.CompVar(f"left_{r}_{c}"), "out")),
                    ],
                    out_connects=[],
                )
            )

        control.append(ast.ParComp(more_control))

    # Move all the results into output memory
    mover_groups = []
    for row in range(left_length):
        for col in range(top_length):
            mover_groups.append(
                ast.Enable(NAME_SCHEME["out mem move"].format(pe=f"pe_{row}_{col}"))
            )

    control.append(ast.SeqComp(mover_groups))
    return ast.SeqComp(stmts=control)
コード例 #7
0
ファイル: gen-systolic.py プロジェクト: pbonh/calyx
#!/usr/bin/env python3

import numpy as np
from futil import ast
from futil.utils import bits_needed

# Global constant for the current bitwidth.
BITWIDTH = 32
# Name of the ouput array
OUT_MEM = ast.CompVar("out_mem")
PE_NAME = "mac_pe"

# Eventually, PE_DEF will be included a separate `.futil` file.
PE_DEF = """
component mac_pe(top: 32, left: 32) -> (out: 32) {
  cells {
    // Storage
    acc = std_reg(32);
    mul_reg = std_reg(32);
    // Computation
    add = std_add(32);
    mul = std_mult_pipe(32);
  }
  wires {
    group do_mul<"static"=4> {
      mul.left = top;
      mul.right = left;
      mul.go = !mul.done ? 1'd1;
      mul_reg.in = mul.done ? mul.out;
      mul_reg.write_en = mul.done ? 1'd1;
      do_mul[done] = mul_reg.done;