Silicon Validation Guide
Silicon Validation with LightOS
LightOS was designed from the ground up to accelerate silicon validation workflows. Traditional RTOS platforms require millions of simulation cycles just to boot—LightOS boots in under 1000 cycles.
Why Boot Time Matters
In RTL simulation, every cycle counts. A typical validation regression runs thousands of test cases:
| RTOS | Boot Cycles | 10,000 Tests | Time @ 100kHz Sim |
|---|---|---|---|
| FreeRTOS | ~500,000 | 5 billion | 13.9 hours |
| Zephyr | ~1,000,000 | 10 billion | 27.8 hours |
| LightOS | ~800 | 8 million | 1.3 minutes |
Key Features for Validation
Near-Instant Boot
// Boot sequence completes in microseconds
void main() {
lightos::Kernel::init(); // ~5μs on real hardware
// Your validation test starts immediately
}
Simulation-Aware Tick System
LightOS detects when running in RTL simulation and adjusts its tick source:
// In RTL simulation: memory-mapped tick register
// On real silicon: hardware timer
auto ticks = lightos::Kernel::current_tick();
Minimal Memory Footprint
- ~2KB RAM minimum configuration (scheduler + 1 thread)
- ~11KB RAM typical configuration
- 32KB Flash including scheduler, mutex, semaphore, message queue
- Leave more memory for your test patterns
Deterministic Behavior
- O(1) scheduler operations
- Predictable interrupt latency
- No hidden allocations during runtime
Measured ISR-period jitter (Cortex-R52 @ 600 MHz, 100 Hz tick)
LightOS ships an in-tree TRACE32 capture harness that samples the timer
ISR-period delta via PMCCNTR_EL0 for 16,384 consecutive periods in a
single uninterrupted run (no debugger halts during capture). Numbers below
are the median over the full window.
| Path | Variant | Median | IQR | Peak-to-peak | P99.9 − median |
|---|---|---|---|---|---|
| FIQ-driven tick (m01) | default build | 6,000,002 cyc / 10 ms | 1 cyc | 21 cyc / 35 ns | +1 cyc |
| FIQ-driven tick (m01-FIQ-nohook) | benchmark build² | 6,000,002 cyc / 10 ms | 1 cyc | 3 cyc / 5 ns | +1 cyc |
| IRQ-driven tick (m01) | default build | 6,000,002 cyc / 10 ms | 1 cyc | 32 cyc / 53 ns¹ | +1 cyc |
| IRQ-driven tick (m01-IRQ-nohook) | benchmark, steady state²³ | 6,000,002 cyc / 10 ms | 1 cyc | 1 cyc / 1.7 ns | +1 cyc |
Coop ctx-switch (m02), Scheduler::yield() | n=1024 | — | — | 182.5 cyc / 304 ns / switch (median) | — |
Coop ctx-switch (m02), yield_to(target) | n=1024 | — | — | 85.5 cyc / 143 ns / switch (median, 2.33× vs ThreadX) | — |
Coop ctx-switch under 100 kHz IRQ load (m04), yield_to(target) | n=1024 (13 M IRQs serviced) | — | — | 90 cyc / 150 ns / switch (median, +5.3 % vs floor); P99 357 cyc, max 397 cyc — bounded by one IRQ-service window | — |
Coop ctx-switch under 1 kHz IRQ load (m04b cadence sweep), yield_to(target) | n=1024 (39,612 IRQs serviced) | — | — | 90 cyc / 150 ns / switch (median, P99 90, max 90); jitter 15 cyc / 25 ns — zero in-window collisions — collapses to m02 floor | — |
App-thread wake via sleep_until (m03) | default | 6,000,002 cyc | 4 cyc | 31 cyc / 52 ns | +5 cyc |
¹ raw window peak-to-peak; one operator-perturbed sample excluded.
² benchmark build sets -DLIGHTOS_FIQ_HOOK_DISABLED=ON and/or
-DLIGHTOS_IRQ_HOOK_DISABLED=ON, eliding the default weak-symbol
bring-up hooks from the ISR entry path.
³ steady state excludes the first 256 warmup samples (I-cache cold-fill)
and TRACE32-halt-correlated paired outliers; the underlying handler is
deterministic at 1-cycle resolution.
On the same silicon, same compiler, and same tick rate, LightOS now leads ThreadX 6.4 on every measured axis:
- FIQ ISR jitter: 3.3 × tighter than ThreadX 6.4 (3 vs 10 cyc p2p, benchmark build).
- IRQ ISR jitter at steady state: ~17 × tighter (1 vs ~17 cyc p2p).
- Cooperative ctx switch through the scheduler: 1.09 × faster (182.5 vs 199.5 cyc / switch).
- Explicit-target
yield_toprimitive: 2.33 × faster thantx_thread_relinquish()(85.5 vs 199.5 cyc / switch).- With interrupts on (m04, 100 kHz Timer3 IRQ):yield_to(target)median 90 cyc / 150 ns / switch (+5.3 % vs the interrupt-free floor) across 1024 round-trips while servicing 13 M IRQs; tail bounded at 397 cyc / switch — exactly one IRQ-service window. - Cadence-sensitivity sweep (m04b, same firmware at 1 kHz Timer3
cadence): distribution collapses to the m02 floor — median
90 cyc / 150 ns / switch, P99 90 cyc, max 90 cyc, jitter 15 cyc /
25 ns over 1024 round-trips with 39,612 IRQs serviced. Zero
in-window IRQ collisions — confirms the m04 second-mode
population is purely a function of arrival rate, not a structural
cost of running with interrupts unmasked.- Application-visible wake (
sleep_until): a comparabletx_thread_sleepwake adds roughly 1.9 µs of dispatch jitter on top of the bare ISR.
The full report, raw .bin captures, CSV exports, and reproduction
recipe live under lightos/measurements/ in the repository.
Continuous Fuzzing of Firmware Parsers
LightOS ships with a libFuzzer + ASan/UBSan harness set that exercises the attack surfaces most likely to hide memory-safety bugs on real silicon:
- Diagnostic/command protocol parser — byte-stream parser driven with dictionary-assisted fuzzing.
- Flash key-value store —
mount()andget()driven against a simulated flash device. - Crash-dump deserializer — on-flash crash-dump records parsed via a libFuzzer-fed read callback with erased-flash (0xFF) padding semantics.
Each harness runs with AddressSanitizer and UndefinedBehaviorSanitizer, keeps its seed corpus in git, and stores mutated inputs out-of-tree. Enable with:
cmake -S . -B build-fuzz -G Ninja \
-DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ \
-DLIGHTOS_FUZZ=ON
cmake --build build-fuzz --target lightos_fuzz_all
bash scripts/run_fuzz.sh fuzz_aecmd_protocol 60
The first campaign found and fixed two real memory-safety defects before any external release.
Validation-Specific APIs
Test Harness Integration
#include <lightos/validation/test_harness.hpp>
int main() {
lightos::Kernel::init();
// Report test status to simulation environment
lightos::validation::test_start("flash_write_test");
// Run your test
bool passed = run_flash_write_test();
// Signal completion (terminates simulation)
lightos::validation::test_end(passed ? 0 : 1);
return 0;
}
Memory-Mapped Register Access
#include <lightos/hw/register.hpp>
// Type-safe register access
auto status = hw::read32(FLASH_STATUS_REG);
hw::write32(FLASH_CMD_REG, FLASH_CMD_ERASE);
// Wait for completion with timeout
bool ok = hw::poll_until(FLASH_STATUS_REG, FLASH_BUSY_BIT, 0,
lightos::ms(100));
Semihosting Support
For simulation environments with semihosting:
#include <lightos/semihosting.hpp>
// Print to simulation console
lightos::semihosting::printf("Test iteration %d\n", i);
// Read test parameters from host
uint32_t seed = lightos::semihosting::read_param("RANDOM_SEED");
// Exit simulation with status
lightos::semihosting::exit(test_passed ? 0 : 1);
Supported Simulation Environments
| Environment | Status | Notes |
|---|---|---|
| QEMU (ARM) | ✅ Full | Cortex-R52, Cortex-A53 |
| QEMU (RISC-V) | ✅ Full | RV32/RV64, virt machine |
| VCS/Synopsys | ✅ Full | Via PLI/DPI interface |
| Xcelium/Cadence | ✅ Full | Via PLI/DPI interface |
| Verilator | ✅ Full | SystemC wrapper |
| FPGA Emulation | ✅ Full | ZCU102, Arty A7 |
Example: Flash Controller Validation
#include <lightos/kernel.hpp>
#include <lightos/validation/test_harness.hpp>
// Test flash write/read cycle
void test_flash_basic() {
constexpr uint32_t TEST_ADDR = 0x1000;
constexpr uint32_t TEST_DATA = 0xDEADBEEF;
// Erase sector
flash_erase_sector(TEST_ADDR);
LIGHTOS_ASSERT(flash_is_erased(TEST_ADDR));
// Program
flash_program(TEST_ADDR, &TEST_DATA, sizeof(TEST_DATA));
// Verify
uint32_t readback;
flash_read(TEST_ADDR, &readback, sizeof(readback));
LIGHTOS_ASSERT(readback == TEST_DATA);
}
int main() {
lightos::Kernel::init();
lightos::validation::test_start("flash_basic");
test_flash_basic();
lightos::validation::test_end(0); // Success
return 0;
}
Build Configuration for Validation
# CMakeLists.txt
set(LIGHTOS_VALIDATION_MODE ON) # Enable validation features
set(LIGHTOS_SEMIHOSTING ON) # Enable semihosting
set(LIGHTOS_MINIMAL_BOOT ON) # Fastest boot sequence
set(LIGHTOS_TICK_SOURCE "memory") # Use memory-mapped tick
QEMU Quick Start
# Build for Cortex-R52
cmake -B build-qemu -DLIGHTOS_TARGET=cortex-r52 \
-DLIGHTOS_VALIDATION_MODE=ON
cmake --build build-qemu --target val_flash_test
# Run in QEMU
qemu-system-arm -M mps3-an536 -cpu cortex-r52 \
-kernel build-qemu/val_flash_test.elf \
-nographic -semihosting
Next Steps
- Getting Started Guide - Build your first LightOS project
- API Reference - Complete API documentation
- Examples - More validation test examples
- Migration Guide - Porting from FreeRTOS or Zephyr