Algorithms (forward, backprop/SGD, init, move_weights, diagnostics) now live
once in MLPCore<Storage> (nisps/ml/mlp.hpp). Storage models:
- FixedStorage (storage.hpp): template-sized std::array, zero heap. The
classic MLP<NIn,H1,H2,H3,NOut,...> is an alias preserving kInput/kHidden*/
kOutput/kNumLayers/weight_count() constexpr — firmware + bindings + modes
compile unchanged.
- DynamicStorage (dynamic_storage.hpp): runtime dims, ONE arena allocation
at construction, nothing per-call. #error under NISPS_TARGET_EMBEDDED
(new macro in core/perf.hpp); sole lint-cpp.sh heap-allowlist entry, plus
a lint check that fails if the #error guard disappears.
Verification:
- new ctest test_mlp_storage_parity: fixed↔dynamic BIT-identical across
init/draw/inference/train(FIFO)/move_weights(pin mask)/eval_loss/
layer_stats/set_weights/infer_batch/reset; invalid+moved-from inert
- golden ML vectors (pre-refactor constants) pass → bit-stable refactor
- native↔WASM parity PASS, max delta unchanged (2.4e-7)
- chokepoint B compile: PAFSynth .text 122324→122692 (+0.30%, ±1% budget);
RAM +416B (eval scratch)
- fix: firmware-common.sh used bare 'python' (absent here) → ${PYTHON:-python3}
Part of one-core-engine-refactor P2. nisps_ml_create ABI untouched (P2.2 is
an operator stop-point).
43 lines
1.7 KiB
C++
43 lines
1.7 KiB
C++
// nisps/core/perf.hpp — RP2040/RP2350 memory section + inlining attributes.
|
|
//
|
|
// On firmware builds the macros expand to GCC/Pico-specific section attributes
|
|
// so hot code/data lives in SRAM instead of XIP flash. On every other build
|
|
// (host tests, Emscripten/WASM) they are inert — the discipline of marking
|
|
// audio-critical declarations is preserved syntactically without affecting
|
|
// codegen.
|
|
//
|
|
// See architecture.md §3.4.
|
|
|
|
#pragma once
|
|
|
|
// NISPS_TARGET_EMBEDDED marks builds for the RP2350 hardware target. Code
|
|
// that is allowed heap allocation at construction time on host/WASM targets
|
|
// (e.g. nisps/ml/dynamic_storage.hpp) is compile-time excluded when this is
|
|
// defined — the zero-heap firmware contract is enforced structurally, not
|
|
// just by lint.
|
|
#if defined(ARDUINO_ARCH_RP2040) || defined(ARDUINO_ARCH_RP2350)
|
|
#define NISPS_TARGET_EMBEDDED 1
|
|
#endif
|
|
|
|
#if defined(ARDUINO_ARCH_RP2040) || defined(ARDUINO_ARCH_RP2350)
|
|
// Pico SDK provides __not_in_flash and __not_in_flash_func.
|
|
// __not_in_flash takes a section name string; __not_in_flash_func wraps the
|
|
// declaration directly.
|
|
#define NISPS_AUDIO_MEM __not_in_flash("audio")
|
|
#define NISPS_AUDIO_FUNC __not_in_flash_func
|
|
#define NISPS_APP_SRAM __not_in_flash("app")
|
|
#define NISPS_FORCE_INLINE __attribute__((always_inline)) inline
|
|
#define NISPS_HOT __attribute__((hot))
|
|
#define NISPS_NOINLINE __attribute__((noinline))
|
|
#else
|
|
#define NISPS_AUDIO_MEM
|
|
#define NISPS_AUDIO_FUNC(decl) decl
|
|
#define NISPS_APP_SRAM
|
|
#define NISPS_FORCE_INLINE inline
|
|
#define NISPS_HOT
|
|
#if defined(__GNUC__) || defined(__clang__)
|
|
#define NISPS_NOINLINE __attribute__((noinline))
|
|
#else
|
|
#define NISPS_NOINLINE
|
|
#endif
|
|
#endif
|