Skip to content

Hardware

A hardware target in Stream is a system of heterogeneous dataflow cores. You describe it with YAML in two layers:

  1. An accelerator file - names the system, lists its cores, and defines how the cores are connected.
  2. One core file per core type - describes a single core's compute array, memory hierarchy, and role.

Accelerator files live in stream/inputs/examples/hardware/; the core files they reference live in stream/inputs/examples/hardware/cores/. Several cores in an accelerator may point at the same core file (e.g. four identical compute cores).

The format is validated by stream/parser/accelerator_validator.py and built by stream/parser/accelerator_factory.py - those files are the authoritative schema if anything below is ambiguous.


Accelerator file

name: tpu_like_quad_core

cores:
  0: ./cores/tpu_like.yaml   # compute A
  1: ./cores/tpu_like.yaml   # compute B
  2: ./cores/tpu_like.yaml   # compute C
  3: ./cores/tpu_like.yaml   # compute D
  4: ./cores/pooling.yaml    # pooling engine
  5: ./cores/simd.yaml       # SIMD / vector unit
  6: ./cores/offchip.yaml    # DRAM controller

core_coordinates:
  0: [0, 0]
  1: [1, 0]
  2: [1, 1]
  3: [0, 1]
  4: [2, 0]
  5: [2, 1]
  6: [1, 2]

offchip_core_id: 6      # core that fronts external memory
unit_energy_cost: 0     # default per-transfer energy for the links below

core_connectivity:
  # 2-D mesh among the four compute cores
  - type: link
    cores: [0, 1]
    bandwidth: 32
  - type: link
    cores: [1, 2]
    bandwidth: 32
  # … more links …

  # shared bus to off-chip memory (all cores ↔ DRAM)
  - type: bus
    cores: [0, 1, 2, 3, 4, 5, 6]
    bandwidth: 128
Field Required Meaning
name yes A label for the system.
cores yes Map of integer core id → core file. Paths may be relative (./cores/foo.yaml); a bare filename is resolved against <accelerator_dir>/cores/ then <accelerator_dir>/.
offchip_core_id yes The id of the core that fronts external memory (DRAM). Must appear in cores. No computation is ever placed here.
kernel_library no Path, relative to this file, to the kernel library the target's AIE kernels are described by.
bandwidth no Map of core id to the measured bandwidth every transfer through that core shares, in bits per cycle: ceiling for reads and writes together, contiguous one way, and strided.read / strided.write per contiguous span in bytes. The allocation then runs no transfer through the core faster than its access pattern allows, and bounds every step by the time the core spends on one iteration's transfers.
reconfiguration no What reconfiguring the array between the designs of one dispatch costs, read by the cores' namespace constraints; for aie2, cycles_per_column per design and reset_cycles once.
core_connectivity yes List of links and buses connecting the cores (see below).
unit_energy_cost no Default energy per transferred word for every connection, unless overridden per-connection. Defaults to 0.
core_coordinates no Map of core id → [col, row]. Used for placement-aware models; required for the AIE namespace, optional otherwise.
core_memory_sharing no Groups of core ids that share L1 memory, e.g. ["0, 1", "2, 3"].

Each entry in core_connectivity is one connection:

Field Required Meaning
type no link (point-to-point between exactly two cores) or bus (shared medium between two or more cores). Defaults to link.
cores yes The connected core ids. Exactly two for a link; two or more for a bus.
bandwidth yes Peak bandwidth of the connection (bits per cycle), > 0.
unit_energy_cost no Per-word energy for this connection; inherits the accelerator-level default if omitted.

Connections are how the MILP allocator routes tensors between cores. A typical accelerator has fast point-to-point links on-chip and one wider bus to the off-chip core.


Core file

Every core declares a type of the form <namespace>.<kind>:

  • namespace - zigzag (a full dataflow core modelled with ZigZag's cost model) or aie2 (an AMD AIE tile).
  • kind - compute, memory, shim, or offchip.

A bare kind (e.g. type: compute) is accepted and defaults to the zigzag namespace.

ZigZag cores (compute / offchip)

A ZigZag core has a memory hierarchy and an operational (MAC) array:

name: tpu_like
type: zigzag.compute

memories:
  rf_2B:                       # a register file serving outputs
    size: 16                   # capacity in bits
    r_cost: 0.021              # read energy (pJ)
    w_cost: 0.021              # write energy (pJ)
    area: 0
    latency: 1
    operands: [O]              # which operands this memory holds
    ports:
      - name: r_port_1
        type: read             # read | write | read_write
        bandwidth_min: 16      # bits / cycle
        bandwidth_max: 16
        allocation:
          - O, tl              # (operand, port-direction tag)
      - name: w_port_1
        type: write
        bandwidth_min: 16
        bandwidth_max: 16
        allocation:
          - O, fh
    served_dimensions: [D2]    # array dimensions this memory feeds

  sram_2MB:
    size: 16777216
    r_cost: 416.16
    w_cost: 378.4
    latency: 1
    operands: [I1, I2, O]      # weights, activations, outputs
    ports:
      - name: r_port_1
        type: read
        bandwidth_min: 64
        bandwidth_max: 2048
        allocation: [I1, tl, I2, tl, O, tl, O, th]
      - name: w_port_1
        type: write
        bandwidth_min: 64
        bandwidth_max: 2048
        allocation: [I1, fh, I2, fh, O, fh, O, fl]
    served_dimensions: [D1, D2]

operational_array:
  unit_energy: 0.04            # pJ per MAC
  unit_area: 1
  dimensions: [D1, D2]         # spatial (unrolled) dimensions of the array
  sizes: [32, 32]              # 32 × 32 systolic array

Operands. Stream uses three algorithmic operands: I1 (weights / first input), I2 (activations / second input), and O (output). A memory's operands field lists which of these it stores.

Ports and allocation. Each memory exposes ports. An allocation entry pairs an operand with a port-direction tag - fh (write the high / final value), fl (write the low / partial value), tl (read low / from lower level), th (read high / to higher level). This is how Stream knows which port carries which data movement when it builds the cost model.

served_dimensions. The operational-array dimensions (D1, D2, …) that this memory feeds. An empty list means the memory is innermost (feeds a single MAC lane).

operational_array. The spatial compute fabric: dimensions names the unrolled axes, sizes gives their extent, and unit_energy / unit_area are the per-MAC cost.

The off-chip core

The off-chip / DRAM core is just a ZigZag core with type: zigzag.offchip, a single large DRAM memory holding all operands, and a zero-size operational array (it never computes):

name: offchip
type: zigzag.offchip
memories:
  dram:
    size: 10000000000
    r_cost: 1000
    w_cost: 1000
    latency: 1
    operands: [I1, I2, O]
    ports:
      - name: rw_port_1
        type: read_write
        bandwidth_min: 64
        bandwidth_max: 64
        allocation: [I1, fh, I1, tl, I2, fh, I2, tl, O, fh, O, tl, O, fl, O, th]
    served_dimensions: [D1, D2]
operational_array:
  unit_energy: 0
  unit_area: 0
  dimensions: [D1, D2]
  sizes: [0, 0]

Restricting a core to certain operators

A compute core can be limited to specific operator types with an operator_types list. For example a pooling engine accepts only pooling ops:

name: pooling
type: zigzag.compute
# … memories, operational_array …
operator_types: [MaxPool, AveragePool, GlobalAveragePool]

If operator_types is omitted, the core accepts any operator. The auto-mapper (see Mapping) uses this field to decide which nodes a core is eligible for - e.g. SiLU/Mul go to the SIMD core, pooling to the pooling core, and Conv/Gemm to the general compute cores.

AIE cores

AIE tiles use the aie2 namespace and a lighter schema describing tile-local memory and the object-FIFO depth, rather than a full ZigZag hierarchy. These are used by the AIE codegen entry points and live under stream/inputs/aie/hardware/.

name: aie_tile
type: aie2.compute
max_object_fifo_depth: 12
memory:
  capacity: 524288     # bits
  bandwidth_min: 512   # bits / cycle
  bandwidth_max: 512

Example systems

Eight non-AIE example accelerators ship under stream/inputs/examples/hardware/ and are exercised across both example workloads in the test matrix (see the Workload × Hardware matrix in the README):

eyeriss_like_single_core, eyeriss_like_dual_core, eyeriss_like_quad_core, tpu_like_quad_core, simba_small, simba (a 36-core chiplet mesh), fusemax, and meta_prototype_dual_core_simd_offchip.

AIE example systems (single_core, single column, full array, Strix variant) live under stream/inputs/aie/hardware/.