Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,9 +108,9 @@ The `scripts/ckpt/` package provides the compilation, benchmarking, and device i
```bash
# Compilation pipelines (INPUT can be a benchmark name or path to .c file)
# --csv PATH writes a one-row CSV of compile-time stats only (no device/runtime columns).
ckpt compile milp INPUT --cap CAP [--link] [--estimator-mode assembly|ir] [--save-temps] [--halt-mode bor|lpm4|swbor] [--cpu-freq 1|8|16] [--device-debug] [--accumulate-keys FILE] [--csv CSV] ...
ckpt compile rockclimb INPUT --cap CAP [--link] [--no-precomputed-energy] [--save-temps] [--halt-mode bor|lpm4|swbor] [--cpu-freq 1|8|16] [--device-debug] [--accumulate-keys FILE] [--csv CSV] ...
ckpt compile schematic INPUT --cap CAP [--link] [--trace-file FILE] [--trace-only] [--save-temps] [--halt-mode bor|lpm4|swbor] [--cpu-freq 1|8|16] [--device-debug] [--accumulate-keys FILE] [--csv CSV] ...
ckpt compile milp INPUT --cap CAP [--link] [--estimator-mode assembly|ir] [--save-temps] [--halt-mode bor|swbor|wait] [--cpu-freq 1|8|16] [--device-debug] [--accumulate-keys FILE] [--csv CSV] ...
ckpt compile rockclimb INPUT --cap CAP [--link] [--no-precomputed-energy] [--save-temps] [--halt-mode bor|swbor|wait] [--cpu-freq 1|8|16] [--device-debug] [--accumulate-keys FILE] [--csv CSV] ...
ckpt compile schematic INPUT --cap CAP [--link] [--trace-file FILE] [--trace-only] [--save-temps] [--halt-mode bor|swbor|wait] [--cpu-freq 1|8|16] [--device-debug] [--accumulate-keys FILE] [--csv CSV] ...
ckpt compile uninstrumented INPUT [--link] [--save-temps] [--cpu-freq 1|8|16] [--device-debug] [--csv CSV] ...
# Explicit config paths also accepted: -e ENERGY_CONFIG -m/-c/-s ALGO_CONFIG

Expand Down
73 changes: 62 additions & 11 deletions passes/runtime/boot_common.inc
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,50 @@
* Requires F_CPU to be defined via -D at assembly time.
*/

#if !defined(HALT_BOR) && !defined(HALT_LPM4) && !defined(HALT_SWBOR)
#error "Define one of HALT_BOR, HALT_LPM4, or HALT_SWBOR"
#if !defined(HALT_BOR) && !defined(HALT_SWBOR) && !defined(HALT_WAIT)
#error "Define one of HALT_BOR, HALT_SWBOR, or HALT_WAIT"
#endif

#if (defined(HALT_BOR) + defined(HALT_LPM4) + defined(HALT_SWBOR)) > 1
#if (defined(HALT_BOR) + defined(HALT_SWBOR) + defined(HALT_WAIT)) > 1
#error "Define only one halt mode"
#endif

#ifdef HALT_WAIT
.extern wait_until_vcc_full
#endif

#ifdef DEVICE_DEBUG
.extern __nvm_done
#endif

/*
* park_if_done — Freeze completed runs (DEVICE_DEBUG only).
*
* Invoked at the very top of each boot entry, before the recovery
* check. Once __nvm_done is set, any later boot parks in LPM4 without
* touching NVM, so results and counters stay exactly as the completed
* run wrote them — resets from mspdebug readback attach, FET replug,
* or power cycles cannot re-execute the program. Only reflashing
* (which zeroes __nvm_done) starts a new run.
*
* debug_init() has the same guard for fresh boots, but recovery boots
* bypass main, so the check must also live here.
*/
.macro park_if_done
#ifdef DEVICE_DEBUG
cmp.w #1, &__nvm_done
jne 8f
/* WDT is still running this early after reset — stop it so it
cannot reset us out of the park. */
mov.w #0x5A80, &0x015C
9:
bis.w #0xF0, SR
nop
jmp 9b
8:
#endif
.endm

/*
* hw_init — Disable WDT, unlock GPIO, configure FRAM wait states + DCO.
*
Expand Down Expand Up @@ -105,7 +141,8 @@
* save_pc_sp_and_halt — Save return address + caller SP to NVM, then halt.
*
* Expects __nvm_pc and __nvm_sp to be .extern'd by the caller.
* Halt mode selected by HALT_BOR / HALT_LPM4 / HALT_SWBOR defines.
* Halt mode selected by HALT_BOR / HALT_SWBOR / HALT_WAIT.
* HALT_WAIT does not halt: it waits for a full capacitor and continues.
*/
.macro save_pc_sp_and_halt
/* Save return address as recovery PC.
Expand All @@ -129,14 +166,28 @@
br #_start
/* Unreachable — jump is unconditional */

#else /* HALT_LPM4 */
/* Enter LPM4 deep sleep (CPUOFF+OSCOFF+SCG0+SCG1 = bits 4-7 of SR).
System powers off. On energy harvest, reset vector fires. */
bis.w #0xF0, SR
nop
/* If woken by interrupt (not full reboot), fall through to ret */
#elif defined(HALT_WAIT)
/* Real intermittent power: the checkpoint above is complete, so wait
until the capacitor is full and continue into the next region
without rebooting. A power failure during the wait recovers to
this boundary. RockClimb inserts this call post-regalloc, where
caller-saved registers and SR flags may be live — preserve them
around the C call. */
push SR
push R11
push R12
push R13
push R14
push R15
call #wait_until_vcc_full
pop R15
pop R14
pop R13
pop R12
pop R11
pop SR

#endif /* BOR vs SWBOR vs LPM4 */
#endif /* BOR vs SWBOR vs WAIT */
.endm

/*
Expand Down
29 changes: 23 additions & 6 deletions passes/runtime/milp_boot.S
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@
.type _milp_boot, @function

_milp_boot:
park_if_done

/* Check if this is a recovery boot: nvm_pc != 0 */
mov.w &__nvm_pc, R14
tst.w R14
Expand All @@ -44,9 +46,19 @@ _do_recovery:
hw_init
poison_bor_sram

#ifdef HALT_WAIT
/* Real power failure: the board woke as soon as VCC crossed the
brownout level. Wait for a full capacitor before resuming.
__nvm_pc stays set so a death during this wait re-enters
recovery on the next boot. SP is the CRT-initialized stack;
the call clobbers R11-R15, so reload the saved PC after. */
call #wait_until_vcc_full
mov.w &__nvm_pc, R14
#else
/* R14 holds saved PC. Clear recovery marker first to prevent
infinite recovery loops on next reboot. */
mov.w #0, &__nvm_pc
#endif

/* Restore SP */
mov.w &__nvm_sp, SP
Expand All @@ -72,6 +84,13 @@ _normal_boot:
hw_init
zero_nvm_state

#ifdef HALT_WAIT
/* Fresh boot: wait for a full capacitor before the program starts.
Nothing persistent has been written yet, so a death during this
wait is simply another clean fresh boot. */
call #wait_until_vcc_full
#endif

/* Fall through to next CRT section (do NOT use ret here) */

.size _milp_boot, .-_milp_boot
Expand All @@ -81,15 +100,13 @@ _normal_boot:
* __region_boundary — Save PC + SP and halt at region boundaries
*
* Called at the start of each energy region (except the entry block).
* Saves the return address (= region body start) and SP to NVM,
* then enters deep sleep (LPM4) or triggers BOR. The system powers off.
* On next power-on, the reset vector fires, CRT runs, and boot
* recovery (above) resumes from saved state.
* Saves the return address (= region body start) and SP to NVM, then
* triggers BOR (or simulates one, or waits for a full capacitor —
* per halt mode). After a reboot, the reset vector fires, CRT runs,
* and boot recovery (above) resumes from saved state.
*
* Unlike RockClimb/SCHEMATIC, no register bulk-save is needed here.
* MILP handles all live state at IR level.
*
* If woken from LPM4 by an interrupt (not a full reboot), just returns.
*/
.section .text
.global __region_boundary
Expand Down
31 changes: 24 additions & 7 deletions passes/runtime/rockclimb_boot.S
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@
.type _rockclimb_boot, @function

_rockclimb_boot:
park_if_done

/* Check if this is a recovery boot: nvm_pc != 0 */
mov.w &__nvm_pc, R14
tst.w R14
Expand All @@ -40,9 +42,19 @@ _do_recovery:
hw_init
poison_bor_sram

#ifdef HALT_WAIT
/* Real power failure: the board woke as soon as VCC crossed the
brownout level. Wait for a full capacitor before resuming.
__nvm_pc stays set so a death during this wait re-enters
recovery on the next boot. SP is the CRT-initialized stack;
the call clobbers R11-R15, so reload the saved PC after. */
call #wait_until_vcc_full
mov.w &__nvm_pc, R14
#else
/* R14 holds saved PC. Clear recovery marker first to prevent
infinite recovery loops on next reboot. */
mov.w #0, &__nvm_pc
#endif

/* Restore SP */
mov.w &__nvm_sp, SP
Expand Down Expand Up @@ -89,6 +101,13 @@ _normal_boot:
hw_init
zero_nvm_state

#ifdef HALT_WAIT
/* Fresh boot: wait for a full capacitor before the program starts.
Nothing persistent has been written yet, so a death during this
wait is simply another clean fresh boot. */
call #wait_until_vcc_full
#endif

/* Fall through to next CRT section (do NOT use ret here) */

.size _rockclimb_boot, .-_rockclimb_boot
Expand All @@ -98,23 +117,21 @@ _normal_boot:
* __region_boundary — Save state and halt at region boundaries
*
* Called at the start of each energy region (except the entry block).
* Saves the return address (= region body start) and SP to NVM,
* then enters deep sleep (LPM4). The system powers off.
* On next power-on, the reset vector fires, CRT runs, and boot
* recovery (above) resumes from saved state.
* Saves the return address (= region body start) and SP to NVM, then
* triggers BOR (or simulates one, or waits for a full capacitor —
* per halt mode). After a reboot, the reset vector fires, CRT runs,
* and boot recovery (above) resumes from saved state.
*
* RockClimb's machine pass inserts per-register saves distributed
* at definition points — no bulk-save needed here.
*
* If woken from LPM4 by an interrupt (not a full reboot), just returns.
*/
.section .text
.global __region_boundary
.type __region_boundary, @function

__region_boundary:
#ifdef DEVICE_DEBUG
/* Preserve SR in case LPM4 wakes without a reset. */
/* Preserve SR flags for the wait-mode continue path. */
push SR
add_u32_to_nvm_counter cnt_boundary, 1
pop SR
Expand Down
3 changes: 2 additions & 1 deletion passes/runtime/rockclimb_runtime.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,8 @@ extern uint32_t cnt_boundary NVM_SECTION;
* depends on the compile-time mode:
* - swbor (HALT_SWBOR, default): jumps to _start without destroying state
* - bor (HALT_BOR): triggers reset and destroys modeled volatile state
* - lpm4 (HALT_LPM4): enters LPM4 deep sleep (real deployment)
* - wait (HALT_WAIT): waits until the capacitor is full, then continues
* (real intermittent power)
*
* On reboot, boot.S recovers from saved NVM state.
*
Expand Down
23 changes: 21 additions & 2 deletions passes/runtime/schematic_boot.S
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@
.type _schematic_boot, @function

_schematic_boot:
park_if_done

/* Check if this is a recovery boot: nvm_pc != 0 */
mov.w &__nvm_pc, R14
tst.w R14
Expand All @@ -44,9 +46,19 @@ _do_recovery:
hw_init
poison_bor_sram

#ifdef HALT_WAIT
/* Real power failure: the board woke as soon as VCC crossed the
brownout level. Wait for a full capacitor before resuming.
__nvm_pc stays set so a death during this wait re-enters
recovery on the next boot. SP is the CRT-initialized stack;
the call clobbers R11-R15, so reload the saved PC after. */
call #wait_until_vcc_full
mov.w &__nvm_pc, R14
#else
/* R14 holds saved PC. Clear recovery marker first to prevent
infinite recovery loops on next reboot. */
mov.w #0, &__nvm_pc
#endif

/* Restore SP */
mov.w &__nvm_sp, SP
Expand Down Expand Up @@ -93,6 +105,13 @@ _normal_boot:
hw_init
zero_nvm_state

#ifdef HALT_WAIT
/* Fresh boot: wait for a full capacitor before the program starts.
Nothing persistent has been written yet, so a death during this
wait is simply another clean fresh boot. */
call #wait_until_vcc_full
#endif

/* Fall through to next CRT section (do NOT use ret here) */

.size _schematic_boot, .-_schematic_boot
Expand All @@ -109,8 +128,8 @@ _normal_boot:
* Sequence:
* 1. Save R4-R15 to __nvm_regs (12 MOV instructions)
* 2. Save return address (PC) and caller SP to NVM
* 3. If halt mode: enter LPM4 or trigger BOR
* 4. Return (if woken by interrupt or halt disabled)
* 3. Trigger BOR, simulate one, or wait for a full capacitor
* (per halt mode) — the wait mode returns and continues
*/
.section .text
.global __region_boundary
Expand Down
6 changes: 3 additions & 3 deletions passes/runtime/schematic_runtime.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,11 +59,11 @@ extern uint32_t cnt_restore_mem NVM_SECTION;
* ============================================================================ */

/**
* Region boundary: bulk-save registers, save state, and halt (deep sleep).
* Region boundary: bulk-save registers, save state, and halt.
*
* Saves R4-R15 to NVM, then saves return address (region body start) and SP,
* then enters LPM4. System powers off. On reboot, boot.S recovers from
* saved state.
* then triggers BOR, simulates one, or waits for a full capacitor (per halt
* mode). On reboot, boot.S recovers from saved state.
*
* Provided by schematic_boot.S (assembly).
*/
Expand Down
Loading
Loading