Contributing to NumCore
Development environment
Required tools
# Rust toolchain
rustup target add thumbv7m-none-eabi
# QEMU for ARM
# Debian/Ubuntu:
apt install qemu-system-arm
# Arch Linux:
pacman -S qemu-system-arm
# macOS (Homebrew):
brew install qemu
# ARM cross-tools (for binary analysis)
# Debian/Ubuntu:
apt install binutils-arm-none-eabi gcc-arm-none-eabi
IDE setup
The workspace root .cargo/config.toml does not set a default build target
(because it breaks host-side test compilation in IDEs).
VS Code with rust-analyzer:
{
"rust-analyzer.cargo.target": "thumbv7m-none-eabi",
"rust-analyzer.checkOnSave.allTargets": false
}
JetBrains RustRover: Set default target to thumbv7m-none-eabi in
Settings → Languages & Frameworks → Rust → Cargo.
Code conventions
Style
- Format all code with
rustfmt(cargo fmtbefore every commit) snake_casefor functions/variables,CamelCasefor types,SCREAMING_SNAKE_CASEfor constants- Maximum line length: 100 characters
- No trailing whitespace
- Alphabetise module declarations, match arms, and import lists
No comments
Do not add comments unless the code cannot be made self-documenting. Prefer meaningful identifier names, small single-purpose functions, and clear type systems. The existing doc comments on modules, types, and public functions are exceptions.
Safety contract
- Only
hal-<mcu>/may perform MMIO viaunsafe-- allunsafefor hardware is inhal-<mcu>/src/mmio.rs numcore-<mcu>/src/boot.rsis the only exception (.bss/.datainit)runtime/,math/,ui/must contain zerounsafeblocks- Every
unsafeblock must have a// SAFETY:comment
Layer rules
| Layer | Location | May import | Must not import | Unsafe |
|---|---|---|---|---|
| Boot | numcore-<mcu>/src/boot.rs | core | hal-*, numcore::* | Yes |
| HAL | hal-<mcu>/src/* | core, numcore::hal, submodules | runtime, math, ui | Yes |
| Runtime | numcore/src/runtime/ | numcore::hal, math, ui | Concrete HAL crates | No |
| Math | numcore/src/math/ | core only | Any HAL, runtime/, ui/ | No |
| UI | numcore/src/ui/ | numcore::hal (Display), core | Any HAL, runtime/, math/ | No |
Math function contract
All math functions must:
- Accept and return
i64(Q31.32) orOption<i64>/Option<Complex> - Never panic -- all errors are domain errors returning
None - Use saturating arithmetic (
.saturating_add(),.saturating_sub()) for addition and subtraction - Use i128 intermediates for multiplication and division (never overflow in intermediate computation)
- Handle
Nonepropagation via?throughout
Testing
Host-side suite (255 tests)
# All tests
cargo test -p numcore_math --tests
# Single test
cargo test -p numcore_math --tests test_sin_standard_angles
# All tests with output
cargo test -p numcore_math --tests -- --nocapture
Adding new tests
When adding a math function, add tests to test-suite/tests/math.rs covering:
- Expected values for representative inputs (verify against Python Decimal)
- Domain errors (invalid inputs returning
None) - Overflow/underflow at Q31.32 boundaries
- Roundtrip consistency where applicable
- Edge cases (zero, negative, min/max values)
Test pattern:
#[test]
fn test_my_function_basic() {
let input = Q31.32_from_float(2.0);
let expected = Q31.32_from_float(4.0);
let result = my_function(input);
assert!(result.is_some());
assert_eq!(result.unwrap(), expected);
}
#[test]
fn test_my_function_domain_error() {
let input = Q31.32_from_float(-1.0);
let result = my_function(input);
assert!(result.is_none());
}
Do not use approx::assert_relative_eq or epsilon comparisons. Fixed-point
arithmetic is exact -- use assert_eq! directly.
Verifying against Python
SCALE = 2**32
def to_q3132(x: float) -> int:
return round(x * SCALE)
def from_q3132(x: int) -> float:
return x / SCALE
# Compute reference values
ref = to_q3132(math.sin(math.pi / 4))
print(f"Expected Q31.32: {ref}")
print(f"Expected float: {from_q3132(ref)}")
Firmware integration test
echo "my_function(42)" | cargo run -p numcore-lm3s811 --release --target thumbv7m-none-eabi
CI pipeline
GitHub Actions runs on every PR:
cargo test -p numcore_math --tests-- all 255 testscargo build -p numcore-lm3s811 --release --target thumbv7m-none-eabi-- firmware builds
Pull request process
- Create a feature branch from
main - Run
cargo test -p numcore_math --tests-- all pass - Run
make build-- firmware compiles - Run in QEMU -- existing functionality works
- Open a PR with clear description of what, why, and how tested
What to include in a PR
- HAL features: register constants and bit masks
- Math functions: test cases (expected values, domain errors, overflow edges)
- Parser changes: example expressions exercising new grammar
- UI changes: screenshot or ASCII-art of display output
Code review checklist
- No new
unsafeblocks outside HAL or boot -
// SAFETY:comment on everyunsafeblock - All math functions return
Optionfor error cases - No heap allocation or
extern crate alloc - Tests cover: expected values, domain errors, overflow
-
cargo fmthas been run -
cargo test -p numcore_math --testspasses - Firmware builds with
make build - Verified in QEMU (basic expression evaluation)