You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
netkit maintains two public interfaces over one C++26 implementation — part of an embedded-first, multi-modal inference engine with interpreter and AOT-compiled deployment paths (PHILOSOPHY.md):
Interface
Header
Standard
Role
C++ API
include/*.hpp
C++26
Primary API — engine, CLI, C++ tests
C API
include/netkit.h
C23
FFI bridge for C callers / C-only MCUs
C source in this repository is limited to tests/test_c_api.c and examples/infer_c.c. The bridge is implemented in src/netkit_api.cpp (C++26).
Policy
Core runtime parity: arena, tensor, ops, MLP/CNN construction, .nk loading, high-level model run, regression, and CLI entry points must have documented C equivalents in netkit.h before the feature is considered complete.
Naming: C functions use the nk_ prefix and snake_case (nk_model_load, nk_ops_relu).
Errors: C functions return nk_status_t; details are available via nk_last_error().
Memory: C handles (nk_arena_t, nk_model_t, nk_mlp_t, nk_cnn_t) use fixed-size opaque storage for stack allocation — no heap in the handle itself.
Regression tests: embedded in .nk files (TCAS section). C callers use nk_run_model_tests() / nk_run_all_tests() (CPU / desktop builds only).
When adding a feature, update this file and both c-api.md and cpp-api.md.
Build targets / backends are shared via include/netkit_config.h (included by both netkit.h and C++ headers). Keep the Build configuration tables in c-api.md and cpp-api.md in sync when changing NETKIT_TARGET_*, arena, or CMSIS / ESP-NN / NMSIS-NN / XNNPACK defaults — BUILD_TARGETS.md, PLATFORMS.md. C and C++ callers use the same nk_* / engine APIs; backends (CmsisNn*, EspNn*, NmsisNn*, Xnnpack*) are compile-time only and need no C mirror.
Shared inference path (fully documented for both APIs)
runs C++ then C; test-full adds full Python ONNX parity
Both suites exercise the same 89 embedded .nk inference cases; nk_run_all_tests() delegates to run_all_tests() in src/test.cpp. The C suite additionally smoke-tests nk_run_model_tests() on composite and ONNX-import fixtures before the full regression pass.
Symbol map
Version / errors
C++
C
(constants in headers)
NK_VERSION_*, nk_version_string()
NkLoader::LoadStatus
nk_status_t via many-to-one map (below), nk_status_string()
LoadResult::message
nk_last_error()
NkLoader::LoadStatus → nk_status_t (in netkit_api.cpp):
nk_arena_init_heap / nk_arena_destroy_heap — CPU default; MPU via NETKIT_HEAP_ARENA=1; MCU forbidden (#error)
Arena::alloc
nk_arena_alloc (size + alignment)
Arena::reset
nk_arena_reset
Arena::capacity / offset (fields) / remaining()
nk_arena_capacity, nk_arena_used (maps to offset), nk_arena_remaining
Arena::kDefaultCapacity
NK_ARENA_DEFAULT_CAPACITY
Arena::attach_mapped_file / release_mapped_file
Transparent inside nk_*_load when NETKIT_USE_MMAP=1
Tensor (tensor.hpp)
C++
C
Tensor
nk_tensor_t
DataType (Float32…Int32)
nk_dtype_t (NK_DTYPE_FLOAT32…NK_DTYPE_INT32)
kMaxTensorRank
NK_MAX_TENSOR_RANK
sizeof(Tensor) == sizeof(nk_tensor_t) and matching offsetof for data / rank / shape / stride / num_elements / bytes are enforced in src/netkit_api.cpp (DataType is uint8_t; nk_dtype_t is a 4-byte enum with the same field padding).
TensorFactory (tensor_factory.hpp)
C++
C
Create2D
nk_tensor_create_2d
CreateND
nk_tensor_create_nd
View2D
nk_tensor_view_2d
View2DInt8
nk_tensor_view_2d_int8
View3DInt8
nk_tensor_view_3d_int8
View1DInt32
nk_tensor_view_1d_int32
Fill
nk_tensor_fill
Print
nk_tensor_print
PrintLabeled
nk_tensor_print_labeled
Tensor access (tensor_access.hpp)
C++
C
tensor_data_f32
nk_tensor_data_f32, nk_tensor_data_f32_const (nullptr if dtype ≠ float32)
tensor_data_i8
nk_tensor_data_i8, nk_tensor_data_i8_const (nullptr if dtype ≠ int8)
tensor_data_i32
nk_tensor_data_i32, nk_tensor_data_i32_const (nullptr if dtype ≠ int32)
NMSIS-NN int8 production (Nuclei N300 / RV32*); float32 reference (NMSIS-NN has no float API); same C nk_* load/run as Arm MCU
AOT deployment
Path
C++
C
Interpreter (embed .nk + loader)
netkit::aot::*::Model or *_aot_load + nk_model_load_memory
*_aot.h + nk_model_load_memory
Lowered (static Kernels:: chain)
netkit::aot::*::Model in *_aot.hpp
C header + C++ body: *_aot.h / *_aot_run_int8 wrap the lowered C++ Model (--language c); no pure-C lowered emitter
Lowered AOT keeps coef arrays in flash .rodata (no SRAM copy at load). NUCLEO int8 boards default to quant lowered; XIAO ESP32C3 int8 peer boards default to interpreter embed (TFLM-fair; see STATUS.md — lowered was a hair slower under ESP-NN and needs investigation).
Quantized manual construction + low-level runtime — C callers load .nk and use nk_model_run_int8 (or typed nk_mlp_* / nk_cnn_* forward after load); query with nk_*_is_quantized
Compile-time backends selected by NETKIT_TARGET + NETKIT_* flags; C callers share the same path via nk_model_run / nk_model_run_int8 — no C backend API