Native DetessCast boundary
Use simaai/kernels/ops/detesscast.h for shared admission and
simaai/kernels/ev74/detesscast.h for device encoding. Link
SimaKernels::detesscast.
These host targets require no MetaWare, ConfigManager, JSON or GStreamer.
Contract
The DetessCast contract applies to both backends:
MlaTiled BF16 input becomes contiguous or byte-strided BF16 or FP32 output with the same
explicit logical shape. Ranks one through six are supported; rank-zero scalars
are not. Empty tensors require no numerical device invocation.
Contiguous output means logical row-major storage, not necessarily channels
last. Every admitted D/H/W/C axis mapping remains meaningful. Unmapped axes
are independent outer dimensions. Compact and padded-to-16 input channel
storage are supported. Explicit Strided output supports scalar-aligned,
non-overlapping positive strides on non-unit axes, including pitches, steps and
physical axis permutations. Singleton strides may be zero. FP16 and quantized
inputs are unsupported.
Compiler channel-block input
The shared contract also admits MlaCBlocked input with trailing H/W/C at
ranks 3–6; see the physical addressing equation.
The native codec carries an explicit blocked-layout flag. The device validates
the trailing axes and padded-channel contract before dispatch. Existing firmware
that does not understand this flag rejects the packet; deploy matching firmware
and host artifacts together.
The worker gathers valid 16-channel fragments directly into bounded local panels, then reconstructs BF16 bits with the shared numerical core. No DDR intermediate or A65 tensor scan is required. Dense output uses disjoint task ownership; output DMA must retire before its slot is reused. Pixel-major-only bulk readers are not used for blocked payloads.
Parameters
Params is empty. Tensor dtype and layout determine conversion and geometry.
There is no scale, zero point, rounding selector or caller-controlled fast path.
Numerical behavior
For each physical input pixel, read the logical channel's low byte from the first plane and high byte from the second. The second plane starts after the tile's stored channel count, including padding:
uint16_t bits = uint16_t(low) | (uint16_t(high) << 8);
// BF16 output stores bits unchanged.
uint32_t fp32_bits = uint32_t(bits) << 16;
This is integer reconstruction, not floating-point conversion. Both outputs preserve signed zero, subnormals, infinities and NaN sign, payload and signaling status. No floating-point rounding or flush mode changes the answer. Subsequent arithmetic on signaling NaNs can still raise an exception.
Boundary tiles use their actual extents and their own stored channel count. Input channel padding and intertile alignment gaps are ignored, not checked for zero or copied into output. DetessCast cannot recover precision lost upstream.
C++ call
The A65 call constructs explicit
specifications and invokes checked execution. Shared preparation is
ops::detesscast::check_inference(request). A65 selects synchronous numerical
execution with a65::detesscast::prepare(metadata); Runtime selects its backend
while accepting the same typed request.
The EV host codec follows this lifecycle:
shared check_inference → EV representability check → encode_relocatable
→ retained DMA-BUF bindings and address relocation
→ asynchronous submission → confirmed retirement and coherency
bind() is available for transport integrations with resolved device regions.
CPU pointers are not EV addresses. Runtime's synchronous convenience operation
submits the same job and waits for its completion.
Place the includes and namespace aliases at file scope; the remaining statements
belong in a simaai::kernels::Status-returning caller function. It checks metadata and
encodes a relocatable descriptor, not EV74 computation. Runtime must map actual
buffers, bind addresses and retain inputs, outputs and any workspace until
confirmed device completion.
#include <array>
#include <simaai/kernels/ev74/detesscast.h>
#include <simaai/kernels/ops/detesscast.h>
namespace k = simaai::kernels;
namespace op = k::ops::detesscast;
namespace ev = k::ev74::detesscast;
k::MlaTiled tiled;
tiled.axes = {-1, -1, 0, 1}; // Shape [W,C], with an explicit channel axis.
tiled.tile_shape = {1, 1, 2, 3};
const std::array inputs{k::TensorSpec{{2, 3}, k::DType::BFloat16, tiled}};
const std::array outputs{k::TensorSpec{{2, 3}, k::DType::Float32}};
const op::Request request{inputs, outputs, op::Params{}};
auto checked = op::check_inference(request);
if (const auto *error = std::get_if<k::Error>(&checked)) return *error;
const auto &plan = std::get<op::Plan>(checked);
auto encoded = ev::encode_relocatable(plan);
if (const auto *error = std::get_if<k::Error>(&encoded)) return *error;
// Encoding leaves device addresses unbound; no device work has run.
return {};
See the host contract tests (EV74/detesscast/tests/correctness.cpp) and
device fixture (EV74/detesscast/tests/runtime_e2e.cpp) for binding and execution coverage.
Memory and lifecycle
Preparation derives the physical tiled input span and the full addressed output span, including holes. Input alignment is 16 bytes; output alignment is its scalar width, two or four bytes. Required input/output ranges must not overlap. Accessible extra capacity does not authorize writing beyond the required output range.
Runtime owns allocation, mappings, coherency, scheduling and recovery. The kernel receives borrowed storage, retained through confirmed completion. A timeout is not permission to release in-flight DMA buffers. There is no full untiled intermediate, CPU tensor prescan or per-tile A65 submission.
Native boundary
The dense version-1 descriptor is 168 bytes, with device address slots at offsets 24
and 32. Six-capacity dimensions, mapping, tile shape and padding policy describe
the input; output dtype determines scalar width. Dense output strides are
derived rather than supplied redundantly. A non-dense output sets STRIDED
and appends six little-endian 64-bit byte strides, producing a 216-byte packet.
Explicit row-major strides, ignoring singleton strides, use the
168-byte packet and dense implementation. Host and target compilers assert
every field offset, size and alignment. EV-visible ranges must fit its 32-bit
address aperture.
Platform firmware must explicitly compose and register
simaai_kernels_ev74_detesscast_v1; Runtime
must verify the matching capability before numerical submission. A successful
host build does not establish installed firmware support.
Strided output ownership
For byte-strided output, the addressed scalar offset is
offset = sum(coordinate[axis] * strides_bytes[axis])
span = scalar_bytes + sum((shape[axis] - 1) * strides_bytes[axis])
Admission sorts non-unit axes by stride and proves each new axis starts beyond
the complete previously addressed extent; it checks alignment, signed-64-bit
representability, overflow and capacity. The device repeats those checks before
dispatch and rejects nonzero unused stride slots. Bindings must cover the full
span, not just elements * scalar_bytes. Output holes remain untouched.
A private strided worker reuses the bounded tiled gather and bit-exact numerical conversion, then coalesces the largest contiguous logical suffix into output spans. Whole aligned 16-byte interiors use DMA; exact scalar-boundary bytes do not round into holes. Each write retires before another span or exact boundary can share its physical write granule. Arbitrary strided output uses one owner: logical non-overlap alone does not prove independent DMA granules. Input-slot prefetch still overlaps conversion; no full untiled DDR intermediate or A65 per-element processing is introduced. Dense workers use parallel ownership and a pipelined pair of slots.
The host/native suites include pitched, stepped, permuted and singleton views, panel transitions, both output dtypes, compiler-block input, guarded holes and immediate/deferred DMA. Old firmware rejects the new flag/length; deploy the matching package, transport capability table and firmware together. Compilation and host expression models are not real-device qualification.
Implementation notes
Output ownership determines scheduling; input tile boundaries do not determine independent output regions.
The general readers assign contiguous output intervals, not input tiles. Different channel tiles can contribute adjacent values to one dense pixel, so input-tile ownership alone would not establish independent output writes. The entry derives interval boundaries from the actual output address. Interior writes use 16-byte-aligned, whole-16-byte DMA ranges; unique boundary tasks use exact scalar-width stores. No output guard or neighboring view is included to round up a transfer.
Each general-reader task processes at most 4,096 logical elements. Two 8 KiB source slots hold separate gathered low/high planes; two output slots hold reconstructed values. A 4 KiB raw-fragment slot handles short or partial physical spans. Explicit staging for these readers is 52 KiB for FP32 and 36 KiB for BF16. Physical input tiles can be larger: only bounded fragments are read, never a whole oversized tile. Generated stack frames, nested calls and static local storage must also fit the configured VCCM; array sizes alone do not establish that bound.
The geometry uses at most sixteen full/boundary tile classes, independent of tensor size. Bulk input reads use DMA, including short fragments:
- Contiguous channel spans retain direct planar copies. A complete 4,096-element panel with adjacent 4,096-byte source planes uses one 8 KiB read into the matching local planes. Partial panels, padding gaps and separated planes retain separate reads; rank alone does not establish eligibility.
- Channels-last tensors can gather each channel tile across multiple pixels directly into the local logical planes. The local destination pitch is the full logical channel count; the source pitch is twice the tile's stored channel count. This also gathers narrow channel tails and RGB without requiring one tile to hold every channel.
- Partial pixels and short spans can stage a bounded physical interval, then select the required bytes locally. Padding may be read within the admitted physical storage, but never contributes to the numerical output.
- When H/W are the last logical axes and C is an earlier axis, complete rows can use a bounded rectangular gather. DMA packs low/high byte rectangles into the raw slot; local row copies place them at the logical W pitch. Each rectangle stays within one H tile and each transfer within one W tile. Partial rows retain the general path. This reduces descriptor submissions without changing output ownership or allocating a full untiled intermediate.
- Other innermost-axis runs use pitched gathers when representable. Pitches outside the DMA field range are split into exact row transfers, not narrowed or replaced with per-element DDR reads.
Full-channel W/C rows have a separate fused reader when C is the last logical axis, W immediately precedes it, the channel extent fits one tile, there are at least eight logical channels, and each stored pixel fits within 4 KiB. Two 4 KiB raw slots alternate: prefetch the next physical fragment while reconstructing the current fragment directly into its owned output panel. This avoids repacking canonical low/high planes and needs one contiguous input transfer rather than two pitched plane transfers for a fragment. Explicit staging is 40 KiB for FP32 or 24 KiB for BF16. Partial first/last pixels write only the task's logical output interval; reading a complete physical pixel does not expand output ownership.
For FP32 output with a 16-byte-aligned output address, full-channel C16/C32 raw-row inputs use a separate private full-pixel entry. Both Compact and PadTo16 qualify because these channel counts need no padding. The 4,096-element panels are divisible by both channel counts, so task boundaries and bounded input fragments contain whole pixels. Fixed SIMD loops reconstruct one or two sixteen-lane vectors directly from the low/high byte planes. Native admission selects this entry once; the general raw-row converter contains no C16/C32 specialization checks. Scalar-aligned but not 16-byte-aligned output retains the general converter, including exact partial-channel heads and tails. This changes neither DMA ownership nor BF16 bit-pattern preservation, including NaN payloads.
Raw-row conversion placement
The FP32 general raw-row worker uses a non-inlined conversion leaf with scalar metadata and pointer arguments. This keeps its vector state out of transfer scheduling. The BF16 raw-row converter is inlined into its dtype-specific worker: its shuffle-index state is prepared once per worker rather than rebuilt for each raw fragment. This trades retained vector state and spills for less repeated setup. Neither placement is a universal latency guarantee.
DMA scheduling, ownership and slot retirement remain in the worker. Conversion runs only after its input read completes. Both placements preserve integer byte-plane reconstruction, every BF16 payload and FP32 bit placement, without floating-point arithmetic or additional input/output transfers.
Channel-subtiled FP32 row bands
A separate private entry handles bounded canonical HWC tensors whose channels span three or four tiles. It is selected only when:
- Output is FP32 and its device address is 16-byte aligned.
- Rank is three through six; H, W and C are the last three logical axes. D is absent or immediately precedes H, with D tile extent one. Other axes are outer dimensions.
- Effective channel tile extent is 16 or 32, with three or four channel tiles.
- H and W have no partial spatial tiles, and tile width is a multiple of 16.
- One complete tile-width row fits both bounded raw and output slots.
The worker chooses the largest row band satisfying:
rows = min(tile_height,
4096 / (2 * tile_channels * tile_width),
4096 / (logical_channels * tile_width))
Each task owns these complete pixel rows across all channel tiles, rather than assigning separate output ownership to each input channel tile. A final band may contain fewer rows. A mixed-radix cursor advances W tile, H band, H tile, D and outer slice without decoding each pixel's coordinates.
Two 4 KiB raw slots alternate contiguous reads of each physical channel tile's row band. The worker reconstructs integer FP32 bits directly into their dense channel slices in one of two 16 KiB output slots. Stored padded channels can be read but are never written as logical output. Full sixteen-channel groups use SIMD reconstruction; channel tails use exact integer reconstruction. Dense pixel strides can make vector destinations unaligned even when the slot base is 64-byte aligned; SIMD alone does not establish a performance improvement.
The full-channel conversion advances source and destination pointers once per pixel instead of recomputing their offsets with multiplications. Explicit sixteen-channel SIMD reconstruction remains inside that scalar pixel traversal.
A one-logical-channel tail uses a separate private conversion leaf that works
across sixteen pixels at a time. Compact C1 storage contains aligned consecutive
BF16 halfwords; the leaf loads sixteen words, widens them and shifts left by16.
Pad16 C1 storage retains separate byte planes; the leaf gathers the low and high
bytes at offsets pixel * (2 * stored_channels) and reconstructs the same FP32
bits. A word scatter writes only the owned channel of each output pixel at
offsets pixel * logical_channels. The source interval contains every gathered
byte; no padded channel contributes a numerical value. A scalar residual
handles fewer than sixteen pixels without speculative vector reads or writes.
The leaf takes pointers and scalar metadata, not vector values across its call boundary. It allocates no additional staging buffers and does not submit DMA. Its index-vector setup is local to conversion; all event lifetime and output ownership rules remain in the worker. Other partial channel counts retain the existing exact scalar tail. This changes data access and instruction placement, not rounding, NaN payloads or the order of mathematical operations.
Each output row uses a chained, whole-16-byte 1D DMA. This avoids narrowing a full-image row pitch into a 16-bit 2D field. Output completion precedes slot reuse, and each raw read completes before conversion or reuse. Explicit staging is 40 KiB; generated frames and helper stack still require target inspection.
This path trades fewer input DMA calls and coordinate calculations for more output-row calls and potentially more padded input bytes. BF16 outputs, two-channel-tile shapes (including C33 with tile C32), partial spatial tiles, noncanonical axes, and scalar-aligned but not 16-byte-aligned output retain the existing readers. No public descriptor field or numerical behavior changes.
For rank-one input only, the unique global output head and tail can read exact volatile input bytes rather than submit a DMA for a few values. Each boundary contains at most seven elements. This exception never applies to an aligned interior panel, even when that panel is short.
Every local DMA destination lies within bounded worker-local staging. Source transfers must fit the admitted physical span; every output store stays within its worker-owned logical output interval. DMA submission overhead and read amplification remain performance considerations on bulk DMA paths.
Gather paths decode logical coordinates once per group and reuse them when walking channel or width tiles. No per-element logical-coordinate interpreter is needed for a regular run. The planar reader initializes coordinates once per panel and advances them with a mixed-radix cursor. Channel-only input uses direct channel-tile offsets instead of the general four-axis lookup.
For BF16, local SIMD joins sixteen low/high bytes into sixteen words. For FP32,
it widens the bytes directly to integer words and computes
(uint32_t(low) << 16) | (uint32_t(high) << 24). This avoids an intermediate
16-bit join/widen sequence while preserving exactly the same output bits.
The native entry selects one of eight internal implementations once: BF16 or FP32, each with a compact planar reader, general gather reader or fused raw-row reader, plus the FP32 full-pixel and channel-band specializations described above. Full-pixel selection takes precedence within eligible raw-row inputs. Otherwise, channel-only tensors and channels-last tensors whose complete channel extent fits one tile with at least eight channels use the planar reader; remaining layouts use the gather reader. Separate entry bodies keep unrelated layout logic and scratch out of the selected path. Internal specialization does not add a public parameter or another device submission. Source completion precedes unpacking; output completion precedes slot reuse. The entry drains all writes before reporting numerical completion.
Tests and qualification
Use independent byte-planar input construction and bit-defined output goldens. A CastTess/DetessCast round trip is supplemental because inverse layout errors can cancel. Include every BF16 word, both outputs, ranks and axis permutations, channel/spatial tails, poisoned padding, bounded giant tiles, scalar-aligned output offsets and dirty-buffer reuse.
Host codec and mocked dispatch tests do not execute EV instructions or DMA. Actual-source host tests include both immediate transfers and a deferred, dependency-aware DMA model. The latter checks missing waits, unfinished transfers and premature output-slot reuse; it does not model hardware masks or concurrent workers. DMA coverage checks exempt only the rank-one global boundary bytes described above; aligned interiors still require complete coverage. Include 4 KiB raw-capacity admission boundaries, 16-bit DMA pitch boundaries, and rank-six cursor carries across mapped and unmapped axes. Assert native routing for aligned C16/C32, neighboring channel counts, split channel tiles, rank-one input and nonadjacent W/C axes. Retain exhaustive BF16 bit-pattern tests for both specialized and partial-output fallback paths, with one through four modeled workers and deferred DMA. Real-device qualification requires correctness with one through four workers, uninstrumented submit-to-retirement measurements and the complete neighboring operation suites in the composed firmware. Measure process CPU separately; lower wall latency does not establish lower CPU cost or account for all IRQ work. Percentile tails are diagnostic under the documented median policy.
Channel-inner physical output traversal
After packet, capacity and nonoverlap validation, a channel-contiguous strided output may use a backend-private physical axis order. The input's mapped axes, outer strides and dense coordinates follow the same permutation. Source runs can follow W, H or D when the exact current tile pitch fits the DMA field; no run crosses its current tile extent. BF16 low/high planes remain separate bounded reads. Public logical output order, untouched holes and the established single-owner strided publication contract do not change. Channel-outer and CBlocked cases retain their existing routes rather than assuming a cheaper unproved gather.
H/C and D/C traversal can trade additional exact input-row commands for fewer scalar output writes. Host models report input/output DMA calls, payload bytes and output bytes left to typed stores; input-command count alone is not a latency criterion. Paired device qualification must decide the net benefit. Sparse BF16 row envelopes use exact low/high-plane DMA instead of rereading long row gaps; envelope staging is limited to twice its live two-plane payload.
detesscast_cvu_e2e --shared-family-only measures H/C and D/C output families
with both output dtypes, channel tails, C-first logical order, holes and phases.
The default fixture includes the same cases and checks every output scalar,
untouched hole and guard using its independent tiled oracle.