Skip to main content

Native Cast boundary

Use simaai/kernels/ops/cast.h for the same tensor contract as A65 Cast and simaai/kernels/ev74/cast.h for the EV host codec. Link SimaKernels::cast. These targets build without MetaWare, ConfigManager, JSON parsing, GStreamer or private Core headers.

Shared semantics​

See Cast for the authoritative dtype, shape, stride, alignment and bit-conversion contract. Both ports independently accept contiguous or admitted strided views. Scalar rank zero lowers privately to one device element; empty tensors never submit numerical work. Explicit outputs remain required. Gaps and excess capacity are not output elements and remain untouched.

The host checker proves metadata; Runtime proves actual allocation ownership, permissions, mappings, coherence and lifetime. Device addresses are not CPU pointers. Representation/resource restrictions are EV admission errors, not new image-axis rules in the common contract.

Preparation and submission​

  1. Prepare using canonical ops::cast::check_inference().
  2. Apply ev74::cast::check_inference() for device representation limits.
  3. Resolve retained device regions or DMA-BUF bindings through Runtime.
  4. Encode an Invocation from the plan and actual regions, or use encode_relocatable() with zero address slots for a driver-patched submission.
  5. Submit through a transport that has verified the native entry capability.
  6. Retain tensor and descriptor storage until real device retirement; finish coherency before signaling public completion.

Runtime performs these steps automatically. Its submit() is asynchronous and its synchronous convenience method only submits and waits. Do not make callers remember a separate optional validation call.

Native device contract​

The native symbol simaai_kernels_ev74_cast_v1 consumes an aligned, fixed-width 208-byte version-1 little-endian descriptor. The codec encodes fields explicitly; it never serializes a C++ object or casts public dtype enumerators into wire tags. EV bus addresses use 64-bit wire fields in a 32-bit address domain. With resolved regions the codec validates addresses before submission. With DMA-BUFs, Runtime validates retained bindings and supplies driver relocations for offsets 24 and 32; the driver resolves addresses and the native entry validates the patched descriptor before computation. Zero-slot descriptors are never directly executable. Descriptor upload/storage belongs to Runtime, not the kernel.

Platform firmware must register the native entry and advertise the exact capability. Missing capability fails closed; never send this payload to an unmatched entry or silently select A65.

The entry uses the existing EV conversion kernels: dense DMA/SIMD, common contiguous-suffix DMA, then scattered scalar addressing. Singleton strides are normalized before dispatch. Device checks reject malformed descriptors before numerical dispatch; they supplement rather than replace host preflight.

DMA chunking​

Dense spans and admitted contiguous suffixes use two local slots to overlap input DMA, SIMD conversion and output DMA:

ConversionMaximum input chunkMaximum output chunk
BF16 → FP328 KiB16 KiB
FP32 → BF1616 KiB8 KiB

Both directions use two 24 KiB slots: 48 KiB of local storage per worker. Final chunks can be shorter. Input completion precedes conversion, and an output transfer must finish before its slot is reused; all outstanding outputs retire before return. Scattered scalar addressing is unchanged.

The chunk sizes bound both ports, rather than giving each conversion the same input byte count. This reduces sensitivity to tensor address phases without adding tensor staging, physical-address requirements or host work per chunk. It does not guarantee identical latency for every address, shape or platform. The bit-conversion, rounding, tail and padding contracts are unchanged.

Build and verification​

The ordinary host/A65 builds compile the host codec and ev74_cast_contract, which links the real native entry to a mock dispatcher. That verifies encoding, validation and dispatch controls, not EV SIMD results or DMA safety.

The private sima_cast device target includes the actual native entry. Use the approved private build environment. A compiled library is not complete platform firmware; registration, transport integration and real-device correctness and latency are separate acceptance stages. Do not describe missing stages as passed or replace installed firmware merely to run a host contract test.

The private device/test/native project builds one correctness executable and one latency executable by default. They share an independent fixture/oracle: 300 generated correctness cases plus a 30-case latency corpus. Latency records 100 samples after 10 warmups and reports device-entry-to-return cycles; nSIM cycle results are not DevKit wall-clock latency or asynchronous host submit-to-completion time. Correctness is checked outside the timed region. Tail percentiles remain diagnostic, and no baseline or numerical qualification is implied by compiling these test sources. Run correctness before latency on an otherwise idle target.

The Runtime Linux CVU adapter now exercises this entry end to end with the same shared request and real DMA-BUF storage. Its platform registration uses a distinct capability-probed native route. Real-device acceptance covers 300 generated cases and 66 Runtime submit-to-retirement latency cases, including 32 retained-buffer cases that vary input and output DMA phases independently. This is a different timing boundary from the private device-entry cycle tests above; those test executables have been compiled, but their compilation is not a simulator run. No mathematical behavior changed when adding driver-relocatable encoding.

C++ call​

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/cast.h>
#include <simaai/kernels/ops/cast.h>

namespace k = simaai::kernels;
namespace op = k::ops::cast;
namespace ev = k::ev74::cast;
const std::array inputs{k::TensorSpec{{2, 3}, k::DType::Float32}};
const std::array outputs{k::TensorSpec{{2, 3}, k::DType::BFloat16}};
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/cast/tests/correctness.cpp) and device fixture (EV74/cast/tests/runtime_e2e.cpp) for binding and execution coverage.

Compatible physical spans and bounded matrix publication​

The checked device entry can reorder private axes when both ports have a compatible physical order. Public logical shapes, strides and wire fields do not change. Short contiguous rows are gathered into bounded panels before selecting SIMD; they do not force one conversion per scalar.

For a source/output matrix permutation, the panel preserves the exact BF16 bit conversion. Short columns and suitable non-multiple-of-sixteen columns gather staged rows into contiguous local output vectors. Packed BF16 pairs can instead separate UInt32 halves without a gather, preserving exact bit widening. Output-column owners are balanced independently of a sixteen-column SIMD group; each owner's panel stays within the original bounded slot. Complete output-column interiors use DMA; scalar-width prefixes and tails use exact write-only stores. Output columns and outer strides must prove independent 16-byte granule ownership for multiple workers. Legal scalar-aligned phases without that proof compare the serial matrix against the existing granule-owned gather route once before computation. With multiple launched workers, a serial output column must contain at least ceil(4096 / workers) elements: its useful contiguous output work must match a fair share of the existing bounded panel before replacing parallel owners. With one worker, a column shorter than 4096 elements retains matrix execution only if it fits one matrix row panel, avoiding extra separately waited column publications. Longer columns retain SIMD matrix conversion and aligned middle DMA even when they need several publications. Short scalar-aligned columns that fit one panel therefore remain supported by the matrix, not a blanket scalar transpose rollback. Parallel, independently owned matrix columns are unchanged. Packed two-channel widening retains the generic parallel granule owner when using the matrix would reduce useful workers. Nonrepresentable input pitches retain the existing gather/scatter fallback. No output hole is initialized or read by this route.

cast_cvu_e2e --shared-family-only measures short and bulk matrix families, including scalar-aligned output phases, ragged columns and SDK pitch boundaries. It uses the ordinary device fixture and independent bit/guard oracle; the default suite includes the same cases.