Skip to content

Verifying Your Deployment

Two tools confirm a deployment works before you run a full model: the firmware's own hardware test suite (test_dynmod.sh, checks firmware boot and the DLOAD/IPC path directly) and test_c7x_runtime (checks the c7x::Module C++ API on top of a working firmware).

Firmware Hardware Test Suite

# From the firmware/c7x directory:
test/test_dynmod.sh --deploy

# Or with options:
test/test_dynmod.sh --target root@am67a --module /path/to/lib0.out

The test script covers 6 milestones: 1. Firmware boots via remoteproc 2. Basic IPC (ping, status) 3. Dynamic module load via DLOAD 4. Inference execution (cg_main_dsp with trace verification) 5. Module unload 6. Load-infer-unload stability cycle (5 iterations)

test_c7x_runtime (C++ API)

test_c7x_runtime is a C++ test binary for the c7x::Module ARM inference API. It exercises libc7x_arm_runtime.so end-to-end on an AM67A/BeagleY-AI ARM board against a live C7x DSP firmware instance -- a good way to confirm your deployment actually works before running a full model.

This is the C++ counterpart to the Python integration tests in tests/ti-dsp-runtime/dsp-tests/test_c7x_vm_dsp.py. Both test the same underlying c7x_compute_client IPC path; this binary tests the C++ c7x::Module wrapper directly, without Python or TVM overhead.

Test cases

# Name What it checks
1 LOAD/CLOSE Module::Load() connects to the DSP and loads the ELF; Close() is idempotent (safe to call twice)
2 INFERENCE Run() returns a non-degenerate output tensor (ndim > 0, data_size > 0); prints shape and dtype
3 REFERENCE If --ref is supplied: max|out - ref| < atol; skipped otherwise
4 CREATE_INPUT CreateInput() pointer lies within [StagingBuffer(), StagingBuffer()+size) (pre-staged DDR); inference result matches standard-path result
5 REPEATED_INFER Three consecutive Run() calls with identical input produce bit-identical output

Test 1 is a prerequisite: if the module cannot be loaded, the remaining tests are skipped and the binary exits immediately.

Building

test_c7x_runtime is built automatically alongside libc7x_arm_runtime.so when the arm/ CMakeLists detects the source file:

cd src/runtime/ti_dsp/firmware/c7x/arm

# Cross-compile for ARM64 (default)
./build.sh --board j722s-evm

# Or natively on the AM67A board
./build.sh --board j722s-evm native

Outputs written to arm/build/:

libc7x_arm_runtime.so   — shared library (required at runtime)
c7x_compute             — CLI tool
test_c7x_runtime        — this test binary

Deploying to AM67A

cd src/runtime/ti_dsp/firmware/c7x/arm
./build.sh --board j722s-evm deploy

This SCPs all three binaries plus c7x_runtime.h to the board and runs ldconfig so the shared library is found by the dynamic linker:

am67a:/usr/local/bin/c7x_compute
am67a:/usr/local/bin/test_c7x_runtime
am67a:/usr/local/lib/libc7x_arm_runtime.so
am67a:/usr/local/include/c7x_runtime.h

The deploy hostname is a deterministic function of --board (beagley-ai -> beagley-ai, else am67a) -- add an SSH-config alias if your board is reachable under a different name.

Preparing test inputs

The test binary takes a raw flat binary input.bin (contiguous, row-major). Use Python/numpy on the development machine to generate it alongside a CPU reference output ref.bin:

import numpy as np

# Generate a random input matching your model's expected shape
inp = np.random.randn(1, 64).astype("float32")
inp.tofile("/tmp/input.bin")

# Run on CPU to get the reference output
import sys
sys.path.insert(0, "tests/ti-dsp-runtime/dsp-tests")
from test_c7x_vm_dsp import _cpu_reference_mlp
ref = _cpu_reference_mlp(inp)
ref.tofile("/tmp/ref.bin")

Or use the pytest fixture directly — test_c7x_vm_dsp.py::TestC7xCpp generates and transfers the files automatically.

Running on AM67A

SSH into the board and run:

# Minimal: load + infer + repeatability only (no reference check)
test_c7x_runtime /path/to/lib0.out /path/to/input.bin \
    --shape 1,64 --dtype float32

# With reference comparison (max |out - ref| < 1e-3)
test_c7x_runtime /path/to/lib0.out /path/to/input.bin \
    --shape 1,64 --dtype float32 \
    --ref /path/to/ref.bin --atol 1e-3

# Classification model example (ResNet-18 style, 1000 classes)
test_c7x_runtime resnet18.out input_1x3x224x224.bin \
    --shape 1,3,224,224 --dtype float32 \
    --ref cpu_output_1x1000.bin --atol 5e-3

CLI reference

test_c7x_runtime <lib0.out> <input.bin>
                 [--shape D0,D1,...] [--dtype TYPE]
                 [--ref ref.bin] [--atol TOL]

Required:
  lib0.out      TVM c_static DLOAD module (output of build_dsp_dynmod())
  input.bin     Raw binary input tensor, flat row-major, no header

Optional:
  --shape       Comma-separated dimensions matching the model input
                (default: 1,64)
  --dtype       Element type: float32 float16 int32 int8 uint8
                (default: float32)
  --ref         CPU reference output for numerical comparison
  --atol        Absolute tolerance for --ref comparison (default: 1e-3)

Exit code: 0 = all run tests passed; N = N failures

Expected output (all tests pass)

test_c7x_runtime: /tmp/mlp_lib0.out
  input: /tmp/input.bin  shape: 1,64  dtype: float32 (256 bytes)

--- Test 1: LOAD/CLOSE
  PASS  load_close

--- Test 2: INFERENCE
  Output: ndim=2  data_size=32  dtype=2.32
    shape[0]=1
    shape[1]=8
  PASS  inference

--- Test 3: REFERENCE COMPARISON
  max|out - ref| = 1.23e-07  (atol=1.00e-03)
  PASS  reference

--- Test 4: CREATE_INPUT
  PASS  create_input_range
  PASS  create_input_result

--- Test 5: REPEATED_INFER
  PASS  repeated_infer

Results: 5 passed, 0 failed

Prerequisites

Requirement Notes
AM67A (J722S) board Running Linux (Yocto/Ubuntu)
c7x_compute firmware Running on DSP; check with c7x_compute ping
libc7x_arm_runtime.so Installed via ./build.sh deploy
lib0.out TVM c_static module for C7x (DLOAD-compatible ELF)
aarch64-linux-gnu-g++ Cross-compiler, for building on dev PC