Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
10bce7a
target/linx: execute v0.57 TCMP packed predicates
jiale-wangOwO Jul 24, 2026
6d74c1f
target/linx: fail closed on unsupported TEPL selectors
jiale-wangOwO Jul 24, 2026
b15119a
target/linx: honor signed narrow TEPL lanes
jiale-wangOwO Jul 24, 2026
3bd6c2a
target/linx: execute FP16 and BF16 TEPL arithmetic
jiale-wangOwO Jul 24, 2026
e6d6d79
target/linx: persist v0.57 tile shape metadata
jiale-wangOwO Jul 24, 2026
0741aeb
target/linx: execute v0.57 TNEG
jiale-wangOwO Jul 24, 2026
942a193
target/linx: execute v0.57 TREM and TREMS
jiale-wangOwO Jul 24, 2026
f855d45
target/linx: execute v0.57 TCMPS
jiale-wangOwO Jul 24, 2026
344bb8a
target/linx: execute v0.57 TSEL and TSELS
jiale-wangOwO Jul 24, 2026
61c2997
target/linx: execute v0.57 product and arg reductions
jiale-wangOwO Jul 24, 2026
d97abd7
target/linx: execute v0.57 row and column expand variants
jiale-wangOwO Jul 24, 2026
d85773b
target/linx: execute v0.57 TFILLPAD
jiale-wangOwO Jul 24, 2026
3467c22
target/linx: execute v0.57 partial binary operations
jiale-wangOwO Jul 24, 2026
ac80a14
target/linx: execute v0.57 reshape concat and gatherb
jiale-wangOwO Jul 24, 2026
17e76ea
target/linx: execute v0.57 TCI and TTRI
jiale-wangOwO Jul 24, 2026
b5bab91
target/linx: execute v0.57 TEXTRACT
jiale-wangOwO Jul 24, 2026
dce81e4
target/linx: execute v0.57 TDEQUANT
jiale-wangOwO Jul 24, 2026
ba5db86
target/linx: execute v0.57 TGEMV variants
jiale-wangOwO Jul 24, 2026
6f326ae
docs: record v0.57 PTO Tile execution status
jiale-wangOwO Jul 24, 2026
f8ef1e6
target/linx: execute TMATMUL bias tile profile
jiale-wangOwO Jul 25, 2026
4200c69
docs: record TMATMUL bias tile support
jiale-wangOwO Jul 25, 2026
a8e9be2
target/linx: execute Tile interleave profiles
jiale-wangOwO Jul 25, 2026
c26fe50
docs: record Tile interleave support
jiale-wangOwO Jul 25, 2026
698ea0a
target/linx: execute partial arg selection
jiale-wangOwO Jul 25, 2026
7481343
docs: record partial arg selection support
jiale-wangOwO Jul 25, 2026
455789f
docs: update consolidated Tile AVS paths
jiale-wangOwO Jul 25, 2026
e202f43
docs: identify PTO Tile target as v0.2
jiale-wangOwO Jul 25, 2026
b8f2910
docs: record PTO v0.1 to v0.2 baseline
jiale-wangOwO Jul 26, 2026
983afe0
target/linx: reject unsupported TEPL dtype profiles
jiale-wangOwO Jul 27, 2026
ce26997
Prevent TCVT from publishing misencoded narrow floats
Jul 27, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions docs/linxisa/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ This QEMU tree contains:
- A LinxISA CPU target (`target/linx/`)
- A minimal LinxISA `virt` machine (`hw/linx/virt.c`)

The current executable PTO Tile subset and its fail-closed boundaries are
recorded in [`pto-tile-support.md`](pto-tile-support.md).

## Quick start (smoke test)

Build/run a tiny freestanding `_start` that prints via the `virt` UART and powers
Expand Down
193 changes: 193 additions & 0 deletions docs/linxisa/pto-tile-support.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
# PTO Tile support on LinxISA v0.57

This document records the executable PTO Tile subset in the Linx QEMU target.
PTO ISA v0.1 is the previous semantic baseline and PTO ISA v0.2 is the current
adaptation target. Operations unchanged by v0.2 retain their v0.1 behavior.
The current target's encoded operation identities are carried by the
111-operation LinxISA v0.57 PTO map: 97 TEPL operations, 6 TMA operations, and
8 CUBE operations. These counts describe the complete v0.2 target set, not the
number of operations newly introduced in v0.2.

Support has three distinct levels:

1. L1: the LinxISA v0.57 selector or function has a unique decode identity.
2. L2: QEMU executes an operation that changes architectural Tile, ACC, or
memory state.
3. L3: a LinxISA AVS case executes the operation and checks exact values or
side effects.

A shared `BSTART.TEPL` decode does not imply support for every TEPL selector or
dtype profile. QEMU validates the selector/dtype tuple when binding `B.IOT`,
before source pinning, output reservation, or destination backing-store
clearing. Unsupported tuples raise an illegal-instruction exception without
changing the Tile queue or destination Tile.

## Summary

| Family | PTO ISA v0.2 target operations | Explicit execution paths | Fail-closed |
| --- | ---: | ---: | ---: |
| TMA | 6 | 6 | 0 |
| CUBE | 8 | 5 | 3 |
| TEPL | 97 | 86 | 11 |
| Total | 111 | 97 | 14 |

The `97/111` count means that at least one defined QEMU profile has an
execution path. It is not a claim that every dtype, shape, layout, rounding
mode, exception, or target-specific profile is complete.

## TMA

The six workbook operations have execution paths:

```text
TLOAD TSTORE TMOV TPREFETCH MGATHER MSCATTER
```

`TPREFETCH` follows the v0.57 destination-free contract: it performs TLOAD-like
address and shape validation without allocating or publishing a Tile output.
QEMU also implements supplemental masked and CAS gather/scatter functions that
are not included in the six-operation workbook count.

## CUBE

The following operations have execution paths:

| Operation | Function | Current QEMU profile |
| --- | ---: | --- |
| `TMATMUL` | 0 | S32 matrix multiply into the internal ACC |
| `TMATMUL_BIAS` | 1 | S32 matrix multiply plus one-row, per-column S32 bias |
| `TMATMUL_ACC` | 2 | Accumulate using the matching live source pair |
| `TGEMV` | 16 | Uses the M/N/K path with `N=1` |
| `TGEMV_ACC` | 18 | Accumulates into the existing TGEMV ACC |

Function 8 `ACCCVT` exports the internal ACC to a normal Tile. It is required
by the execution pipeline but is not one of the eight workbook operations.

`TMATMUL_BIAS` freezes exactly three sources in A, B, Bias order across one or
more `B.IOT` descriptors. The Bias Tile must be a one-row S32 Tile and is
broadcast by column. The current implementation intentionally rejects other
dtypes rather than treating the word-backed compatibility path as packed S8 or
floating-point CUBE execution.

These CUBE operations remain fail-closed:

- `TGEMV_BIAS`: the latest PTO definition uses `M=1`, while the existing QEMU
TGEMV compatibility profile uses `N=1`; the direction contract must be
reconciled before adding bias.
- `TMATMUL_MX` and `TGEMV_MX`: scale Tile roles, FP8/FP4 unpacking, and the
target MX reconstruction profile are not implemented. QEMU does not ignore
scale operands and report a normal matmul as MX support.

The current CUBE backing layout is a bounded, contiguous 8x8 CPU profile. It
must not be treated as complete fractal-layout or mixed-precision coverage.

## TEPL

The executable whitelist contains these 86 operations:

```text
TADD TSUB TMUL TDIV TMAX TMIN TAND TOR TXOR TSHL TSHR
TRELU TCVT TEXP TLOG TSQRT TRSQRT TRECIP TABS TNOT TNEG TREM
TADDS TSUBS TMULS TDIVS TMAXS TMINS TANDS TORS TXORS TSHLS TSHRS TREMS
TCMP TCMPS TSEL TSELS
TROWSUM TROWMAX TROWMIN TROWPROD TROWARGMAX TROWARGMIN
TCOLSUM TCOLMAX TCOLMIN TCOLPROD TCOLARGMAX TCOLARGMIN
TROWEXPAND TCOLEXPAND TEXPANDS
TROWEXPANDADD TROWEXPANDSUB TROWEXPANDMUL TROWEXPANDDIV
TROWEXPANDMAX TROWEXPANDMIN TROWEXPANDEXPDIF
TCOLEXPANDADD TCOLEXPANDSUB TCOLEXPANDMUL TCOLEXPANDDIV
TCOLEXPANDMAX TCOLEXPANDMIN TCOLEXPANDEXPDIF
TRESHAPE TTRANS TGATHER TSCATTER
TCI TTRI TFILLPAD TDEQUANT TEXTRACT TCONCAT TGATHERB
TDEINTERLEAVE TINTERLEAVE
TPARTADD TPARTMUL TPARTMAX TPARTMIN TPARTARGMAX TPARTARGMIN
```

Important profile limits include:

- Common elementwise paths support 1-, 2-, and 4-byte elements. Implemented
FP16 and BF16 arithmetic and TCVT encoding use QEMU softfloat. TCVT checks
both the queued source dtype and destination dtype before source pinning or
output reservation.
- `TEXP`, `TLOG`, `TSQRT`, `TRSQRT`, and `TRECIP` currently have an FP32-only
QEMU profile. FP16 and BF16 forms are rejected rather than writing zero.
- FP8/FPL8 profiles are not implemented by the generic arithmetic path and
are rejected rather than being interpreted as integers of the same width.
- `TCMP` and `TCMPS` produce a row-packed U32 predicate mask. `TSEL` and
`TSELS` consume that mask.
- Reduction, expand, layout, and partial-operation paths implement the current
row-major CPU profile; they do not claim every target fractal layout.
- `TFILLPAD` supports the documented Zero/Max/Min subset for the supported
row-major Vec dtypes.
- `TRESHAPE` is an equal-byte-count bitwise reshape. `TCONCAT` supports the
basic two-source column concatenation form.
- `TEXTRACT` supports the plain same-dtype bounded-window form.
- `TDEQUANT` supports S8/S16 source data, per-row FP32 scale and offset Tiles,
and FP32 output using
`dst[r,c] = (src[r,c] - offset[r]) * scale[r]`.
- `TINTERLEAVE` and `TDEINTERLEAVE` support the canonical two-source,
two-output row-major form. Descriptor order is `dst1, dst0, src1, src0`;
all Tiles have the same dtype and valid shape, and valid columns are even.
The single-source `TDEINTERLEAVE` overload remains rejected because the
current header profile cannot independently encode its wider source shape.
- `TPARTARGMAX` and `TPARTARGMIN` support equal-shape FP32 value Tiles with
S32/U32 index Tiles. Both value and selected-index outputs are published;
ties select `src1` as specified. Mismatched-valid-region profiles remain
outside this implementation.
- VMState version 15 adds the Tile shape metadata required to restore this
execution model. A pre-v15 stream with nonempty Tile state is deliberately
rejected because its missing shapes cannot be reconstructed; pre-v15 empty
Tile state remains loadable.

The remaining 11 TEPL operations are intentionally fail-closed:

| Operations | Missing contract or implementation |
| --- | --- |
| `TAXPY`, `TINSERT` | Require reading and preserving an existing destination, while the current TEPL output is a fresh allocation |
| `TQUANT` | INT8/MXFP8/MXFP4 profiles have different metadata, output counts, and packing contracts |
| `TIMG2COL` | Convolution window, repeat, padding, and configuration state are not fully encoded by the current header path |
| `TSORT` | Sorted value/index compound or multi-output contract is not closed |
| `TMRGSORT` | Variable source list and block-length/executed-count profile are not closed |
| `THISTOGRAM` | Separate source type, destination type, and ByteId are not available in the canonical data-attribute decode |
| `TPUSH`, `TPOP`, `TALLOC`, `TFREE` | Pipe/control operations require a pipe-handle and side-effect ABI outside ordinary TEPL compute |

In particular, `TQUANT` selector `0x083` is decoded but rejected by the
executable-selector gate. The operation must remain rejected until the chosen
quantization profile uniquely defines the visible inputs, outputs, metadata,
and packed representation.

## Regression evidence

The executable regression lives in the LinxISA superproject rather than this
QEMU submodule:

```text
avs/qemu/tests/10_tile_tma.cpp
avs/qemu/tests/10_tile_cube.cpp
avs/qemu/tests/10_tile_cube_asm.S
avs/qemu/tests/10_tile_tepl.cpp
avs/qemu/tests/10_tile_tepl_asm.S
```

The focused gate is:

```bash
QEMU=/path/to/qemu-system-linx64 \
python3 avs/qemu/run_tests.py --suite tile --timeout 40
```

The Tile suite provides exact-value coverage for the implemented batches,
including packed comparisons and selections, signed narrow lanes, FP16/BF16
arithmetic, persistent rectangular shape metadata, reductions, expand
operations, fill padding, partial operations, reshape/concat/gather-by-byte,
sequence/triangular generation, extraction, dequantization, and TGEMV with
ACC accumulation. AVS ID `0x000A0026` checks exact `TMATMUL_BIAS` results and
the two-descriptor A/B/Bias operand order. AVS IDs `0x000A0029` and
`0x000A002A` check that FP16 `TEXP` and BF16 `TLOG` trap, then resume and store
the surviving input queue head; all 1024 lanes must match the original source,
which proves that the rejected output was not reserved or published.

The representative TEPL negative checks use the stable same-ACR trap-return
path inside the normal Tile suite. The separate cross-ACR standalone
expected-trap harness remains unsuitable as general negative L3 evidence
because that lane can re-enter its test entry.
48 changes: 46 additions & 2 deletions target/linx/cpu.c
Original file line number Diff line number Diff line change
Expand Up @@ -3995,6 +3995,12 @@ static bool linx_cpu_post_load(void *opaque, int version_id, Error **errp)
memset(env->tile_reg_bytes, 0, sizeof(env->tile_reg_bytes));
memset(env->tile_reg_elem_bytes, 0, sizeof(env->tile_reg_elem_bytes));
memset(env->tile_reg_dtype, 0, sizeof(env->tile_reg_dtype));
memset(env->tile_reg_valid_cols, 0,
sizeof(env->tile_reg_valid_cols));
memset(env->tile_reg_valid_rows, 0,
sizeof(env->tile_reg_valid_rows));
memset(env->tile_reg_cols, 0, sizeof(env->tile_reg_cols));
memset(env->tile_reg_rows, 0, sizeof(env->tile_reg_rows));
memset(env->tile_acc, 0, sizeof(env->tile_acc));
env->tile_acc_bytes = 0;
return true;
Expand Down Expand Up @@ -4033,6 +4039,26 @@ static bool linx_cpu_post_load(void *opaque, int version_id, Error **errp)
if (version_id < 14) {
memset(env->tile_reg_dtype, 0, sizeof(env->tile_reg_dtype));
}
if (version_id < 15) {
bool nonempty_tile = false;

for (unsigned tile = 0;
tile < LINX_TILE_HAND_COUNT * LINX_TILE_HAND_DEPTH; tile++) {
nonempty_tile |= env->tile_reg_bytes[tile] != 0;
}
if (nonempty_tile) {
error_setg(errp,
"linx: cannot migrate nonempty pre-v15 tile state "
"without shape metadata");
return false;
}
memset(env->tile_reg_valid_cols, 0,
sizeof(env->tile_reg_valid_cols));
memset(env->tile_reg_valid_rows, 0,
sizeof(env->tile_reg_valid_rows));
memset(env->tile_reg_cols, 0, sizeof(env->tile_reg_cols));
memset(env->tile_reg_rows, 0, sizeof(env->tile_reg_rows));
}

if (env->tile_ior_count > LINX_TILE_MAX_IOR ||
env->vec_ri_count > LINX_VEC_RI_MAX ||
Expand All @@ -4058,10 +4084,20 @@ static bool linx_cpu_post_load(void *opaque, int version_id, Error **errp)
for (unsigned tile = 0;
tile < LINX_TILE_HAND_COUNT * LINX_TILE_HAND_DEPTH; tile++) {
const uint32_t bytes = env->tile_reg_bytes[tile];
const uint32_t elem_bytes = env->tile_reg_elem_bytes[tile];
const uint32_t valid_cols = env->tile_reg_valid_cols[tile];
const uint32_t valid_rows = env->tile_reg_valid_rows[tile];
const uint32_t cols = env->tile_reg_cols[tile];
const uint32_t rows = env->tile_reg_rows[tile];
const unsigned hand = tile / LINX_TILE_HAND_DEPTH;
const unsigned depth = tile % LINX_TILE_HAND_DEPTH;
if (bytes > LINX_TILE_MAX_BYTES || (bytes & 3u) != 0 ||
((env->tile_hand_live[hand] & (1u << depth)) != 0 && bytes == 0)) {
((env->tile_hand_live[hand] & (1u << depth)) != 0 && bytes == 0) ||
(bytes != 0 &&
(elem_bytes == 0 || valid_cols == 0 || valid_rows == 0 ||
cols == 0 || rows == 0 || valid_cols > cols ||
valid_rows > rows ||
(uint64_t)rows * cols * elem_bytes > bytes))) {
error_setg(errp, "linx: invalid migrated tile %u state", tile);
return false;
}
Expand Down Expand Up @@ -4184,7 +4220,7 @@ static bool linx_cpu_post_load(void *opaque, int version_id, Error **errp)

static const VMStateDescription vmstate_linx_cpu = {
.name = "linx_cpu",
.version_id = 14,
.version_id = 15,
.minimum_version_id = 11,
.pre_save = linx_cpu_pre_save,
.post_load_errp = linx_cpu_post_load,
Expand Down Expand Up @@ -4275,6 +4311,14 @@ static const VMStateDescription vmstate_linx_cpu = {
LINX_TILE_HAND_COUNT * LINX_TILE_HAND_DEPTH, 13),
VMSTATE_UINT8_ARRAY_V(env.tile_reg_dtype, LinxCPU,
LINX_TILE_HAND_COUNT * LINX_TILE_HAND_DEPTH, 14),
VMSTATE_UINT16_ARRAY_V(env.tile_reg_valid_cols, LinxCPU,
LINX_TILE_HAND_COUNT * LINX_TILE_HAND_DEPTH, 15),
VMSTATE_UINT16_ARRAY_V(env.tile_reg_valid_rows, LinxCPU,
LINX_TILE_HAND_COUNT * LINX_TILE_HAND_DEPTH, 15),
VMSTATE_UINT16_ARRAY_V(env.tile_reg_cols, LinxCPU,
LINX_TILE_HAND_COUNT * LINX_TILE_HAND_DEPTH, 15),
VMSTATE_UINT16_ARRAY_V(env.tile_reg_rows, LinxCPU,
LINX_TILE_HAND_COUNT * LINX_TILE_HAND_DEPTH, 15),
VMSTATE_UINT32_ARRAY_V(env.tile_acc, LinxCPU,
LINX_TILE_MAX_WORDS, 12),
VMSTATE_UINT32_V(env.tile_acc_bytes, LinxCPU, 12),
Expand Down
12 changes: 5 additions & 7 deletions target/linx/cpu.h
Original file line number Diff line number Diff line change
Expand Up @@ -394,13 +394,7 @@ typedef struct CPUArchState {
uint32_t ebarg_stack_depth;
uint64_t ebarg_stack[LINX_EBARG_STACK_DEPTH][LINX_SSR_EBARG_COUNT];

/*
* Tile block state (TAU bring-up).
*
* For now this models a minimal single-B.IOT descriptor per block. The
* implementation is intentionally small and is primarily used for PTO ISA
* bring-up (matmul demo).
*/
/* Tile block header state and frozen multi-B.IOT queue bindings. */
uint32_t tile_func;
uint32_t tile_dtype;
uint32_t tile_iot_valid;
Expand Down Expand Up @@ -451,6 +445,10 @@ typedef struct CPUArchState {
uint32_t tile_reg_bytes[32]; /* per-tile footprint in bytes */
uint8_t tile_reg_elem_bytes[32]; /* producer element width for sparse offsets */
uint8_t tile_reg_dtype[32]; /* canonical v0.57 producer DataType */
uint16_t tile_reg_valid_cols[32]; /* LB0 valid columns/elements */
uint16_t tile_reg_valid_rows[32]; /* LB1 valid rows */
uint16_t tile_reg_cols[32]; /* LB2 physical row stride in elements */
uint16_t tile_reg_rows[32]; /* physical rows derived from the footprint */

/* Accumulator backing store (separate scratch). */
uint32_t tile_acc[LINX_TILE_MAX_WORDS];
Expand Down
Loading