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
66 changes: 65 additions & 1 deletion passes/runtime/boot_common.inc
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@
.extern __nvm_done
#endif

.extern __nvm_in_region
.extern __nvm_violation

/*
* park_if_done — Freeze completed runs (DEVICE_DEBUG only).
*
Expand Down Expand Up @@ -49,6 +52,58 @@
#endif
.endm

/*
* check_region_violation — Detect a reset that arrived mid-region.
*
* __nvm_in_region is 1 from the moment execution (re)enters a region
* until the next boundary's checkpoint is committed. Every region is
* sized so the capacitor can always finish it, so no reset should ever
* arrive while the flag is set. If one does, the energy estimate was
* wrong: record it in __nvm_violation (read by the host) and park
* blinking LED1 (P1.0). The flag is deliberately left set, so every
* subsequent reset re-enters this park and the NVM evidence survives
* until the next reflash (which zeroes .nvm).
*
* Invoked after park_if_done, before the recovery check.
*/
.macro check_region_violation
tst.w &__nvm_in_region
jz 6f
hw_init
mov.w #1, &__nvm_violation
bis.b #0x01, &0x0204 /* P1DIR |= BIT0 (LED1) */
5:
xor.b #0x01, &0x0202 /* P1OUT ^= BIT0 */
#if F_CPU == 16000000
mov.w #13, R15
#elif F_CPU == 8000000
mov.w #7, R15
#else
mov.w #1, R15
#endif
4:
mov.w #0xFFFF, R14 /* ~200k cycles per outer iteration */
3:
dec.w R14
jnz 3b
dec.w R15
jnz 4b
jmp 5b
6:
.endm

/*
* mark_in_region — Flag that execution is (re)entering a region.
*
* Placed immediately before control returns to instrumented code:
* at the end of recovery, at the end of a fresh boot, and after the
* wait-mode boundary continues. Cleared by save_pc_sp_and_halt once
* the next boundary's checkpoint is committed.
*/
.macro mark_in_region
mov.w #1, &__nvm_in_region
.endm

/*
* hw_init — Disable WDT, unlock GPIO, configure FRAM wait states + DCO.
*
Expand Down Expand Up @@ -153,6 +208,11 @@
mov.w SP, &__nvm_sp
add.w #2, &__nvm_sp

/* Checkpoint is committed: the region completed within its energy
budget. A reset from here until mark_in_region is a legitimate
at-boundary death. */
mov.w #0, &__nvm_in_region

#if defined(HALT_BOR)
/* Software BOR: PMMCTL0 = PMMPW (0xA500) | PMMSWBOR (0x0004).
CPU resets immediately, FRAM survives. */
Expand Down Expand Up @@ -187,13 +247,17 @@
pop R11
pop SR

/* Full capacitor: continuing into the next region without a reboot. */
mark_in_region

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

/*
* zero_nvm_state — Clear __nvm_pc and __nvm_sp for fresh boot.
* zero_nvm_state — Clear __nvm_pc, __nvm_sp, __nvm_in_region for fresh boot.
*/
.macro zero_nvm_state
mov.w #0, &__nvm_pc
mov.w #0, &__nvm_sp
mov.w #0, &__nvm_in_region
.endm
6 changes: 6 additions & 0 deletions passes/runtime/milp_boot.S
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@

_milp_boot:
park_if_done
check_region_violation

/* Check if this is a recovery boot: nvm_pc != 0 */
mov.w &__nvm_pc, R14
Expand Down Expand Up @@ -72,6 +73,8 @@ _do_recovery:
at IR level. After regalloc, these become physical register
saves/restores automatically. */

mark_in_region

/* Jump to saved PC (pops from stack).
After ret: PC = saved PC, SP = __nvm_sp (push -2, ret +2 cancel). */
ret
Expand All @@ -91,6 +94,9 @@ _normal_boot:
call #wait_until_vcc_full
#endif

/* Entering the first region (CRT init + entry code count toward it). */
mark_in_region

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

.size _milp_boot, .-_milp_boot
Expand Down
13 changes: 13 additions & 0 deletions passes/runtime/milp_runtime.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,25 @@ __attribute__((section(".nvm"))) uint16_t __nvm_pc = 0;
/* Saved stack pointer */
__attribute__((section(".nvm"))) uint16_t __nvm_sp = 0;

/* 1 while a region is executing; cleared once a boundary's checkpoint
is committed. Boot code treats a reset with this flag set as an
energy-budget violation (see check_region_violation in boot_common.inc). */
__attribute__((section(".nvm"))) volatile uint16_t __nvm_in_region = 0;

/* Set by boot code when a reset arrived mid-region. Read by the host
after every run; only reflashing clears it. */
__attribute__((section(".nvm"))) volatile uint16_t __nvm_violation = 0;

/* __region_boundary is provided by milp_boot.S */

/* Halt CPU after benchmark completes.
Prevents post-main restarts from producing spurious GPIO edges
that inflate Saleae timing measurements. */
#include <msp430.h>
void bench_halt(void) {
/* Run complete — a later reset (e.g. mspdebug attach) is not a
mid-region death. */
__nvm_in_region = 0;
__bis_SR_register(LPM4_bits);
}

Expand All @@ -60,6 +72,7 @@ __attribute__((section(".nvm"))) volatile uint16_t __nvm_result = 0;
__attribute__((section(".nvm"))) volatile uint16_t __nvm_done = 0;

void debug_exit(int result) {
__nvm_in_region = 0;
debug_exit_begin(result);
uart_puts(" __region_boundary: ");
uart_put_u32(cnt_boundary);
Expand Down
6 changes: 6 additions & 0 deletions passes/runtime/rockclimb_boot.S
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@

_rockclimb_boot:
park_if_done
check_region_violation

/* Check if this is a recovery boot: nvm_pc != 0 */
mov.w &__nvm_pc, R14
Expand Down Expand Up @@ -89,6 +90,8 @@ _do_recovery:
counter update is omitted. */
#endif

mark_in_region

/* Jump to saved PC (pops from stack).
After ret: PC = saved PC, SP = __nvm_sp (push -2, ret +2 cancel). */
ret
Expand All @@ -108,6 +111,9 @@ _normal_boot:
call #wait_until_vcc_full
#endif

/* Entering the first region (CRT init + entry code count toward it). */
mark_in_region

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

.size _rockclimb_boot, .-_rockclimb_boot
Expand Down
13 changes: 13 additions & 0 deletions passes/runtime/rockclimb_runtime.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,22 @@ __attribute__((section(".nvm"))) uint16_t __nvm_pc = 0;
/* Saved stack pointer */
__attribute__((section(".nvm"))) uint16_t __nvm_sp = 0;

/* 1 while a region is executing; cleared once a boundary's checkpoint
is committed. Boot code treats a reset with this flag set as an
energy-budget violation (see check_region_violation in boot_common.inc). */
__attribute__((section(".nvm"))) volatile uint16_t __nvm_in_region = 0;

/* Set by boot code when a reset arrived mid-region. Read by the host
after every run; only reflashing clears it. */
__attribute__((section(".nvm"))) volatile uint16_t __nvm_violation = 0;

/* __region_boundary is provided by rockclimb_boot.S */

#include <msp430.h>
void bench_halt(void) {
/* Run complete — a later reset (e.g. mspdebug attach) is not a
mid-region death. */
__nvm_in_region = 0;
__bis_SR_register(LPM4_bits);
}

Expand All @@ -54,6 +66,7 @@ __attribute__((section(".nvm"))) volatile uint16_t __nvm_result = 0;
__attribute__((section(".nvm"))) volatile uint16_t __nvm_done = 0;

void debug_exit(int result) {
__nvm_in_region = 0;
debug_exit_begin(result);
uart_puts(" __region_boundary: ");
uart_put_u32(cnt_boundary);
Expand Down
6 changes: 6 additions & 0 deletions passes/runtime/schematic_boot.S
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@

_schematic_boot:
park_if_done
check_region_violation

/* Check if this is a recovery boot: nvm_pc != 0 */
mov.w &__nvm_pc, R14
Expand Down Expand Up @@ -93,6 +94,8 @@ _do_recovery:
pop SR
#endif

mark_in_region

/* Jump to saved PC (pops from stack).
After ret: PC = saved PC, SP = __nvm_sp (push -2, ret +2 cancel). */
ret
Expand All @@ -112,6 +115,9 @@ _normal_boot:
call #wait_until_vcc_full
#endif

/* Entering the first region (CRT init + entry code count toward it). */
mark_in_region

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

.size _schematic_boot, .-_schematic_boot
Expand Down
13 changes: 13 additions & 0 deletions passes/runtime/schematic_runtime.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,22 @@ __attribute__((section(".nvm"))) uint16_t __nvm_pc = 0;
/* Saved stack pointer */
__attribute__((section(".nvm"))) uint16_t __nvm_sp = 0;

/* 1 while a region is executing; cleared once a boundary's checkpoint
is committed. Boot code treats a reset with this flag set as an
energy-budget violation (see check_region_violation in boot_common.inc). */
__attribute__((section(".nvm"))) volatile uint16_t __nvm_in_region = 0;

/* Set by boot code when a reset arrived mid-region. Read by the host
after every run; only reflashing clears it. */
__attribute__((section(".nvm"))) volatile uint16_t __nvm_violation = 0;

/* __region_boundary is provided by schematic_boot.S */

#include <msp430.h>
void bench_halt(void) {
/* Run complete — a later reset (e.g. mspdebug attach) is not a
mid-region death. */
__nvm_in_region = 0;
__bis_SR_register(LPM4_bits);
}

Expand All @@ -60,6 +72,7 @@ __attribute__((section(".nvm"))) volatile uint16_t __nvm_result = 0;
__attribute__((section(".nvm"))) volatile uint16_t __nvm_done = 0;

void debug_exit(int result) {
__nvm_in_region = 0;
debug_exit_begin(result);
uart_puts(" __region_boundary: ");
uart_put_u32(cnt_boundary);
Expand Down
1 change: 1 addition & 0 deletions scripts/ckpt/bench/milp.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@
NVM_SYMBOLS: list[str] = [
"__nvm_done",
"__nvm_result",
"__nvm_violation",
"cnt_boundary",
"cnt_store_mem",
"cnt_restore_mem",
Expand Down
1 change: 1 addition & 0 deletions scripts/ckpt/bench/rockclimb.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
NVM_SYMBOLS: list[str] = [
"__nvm_done",
"__nvm_result",
"__nvm_violation",
"cnt_boundary",
]

Expand Down
34 changes: 27 additions & 7 deletions scripts/ckpt/bench/runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
from saleae.automation import Manager

from ..env import ProjectEnv
from ..errors import CkptError, CompilationError, DeviceError
from ..errors import CkptError, CompilationError, DeviceError, RegionViolationError
from ..output_parser import (
NvmCounters,
PassStatistics,
Expand Down Expand Up @@ -334,30 +334,48 @@ def run_benchmark_matrix(
# ----- Saleae timing + NVM read (only with a device) -----
nvm: NvmCounters | None = None
execution_time_us: float | None = None
region_violation = False
if output_dir is not None and saleae_manager is not None:
elf = output_dir / f"{bench_name}.elf"
if elf.is_file():
try:
from ..device.flash import read_nvm
from ..device.flash import (
check_region_violation,
raise_if_region_violation,
read_nvm,
)

try:
execution_time_us = measure_execution_time(
elf,
saleae_manager,
capture_timeout_seconds,
)
except DeviceError as exc:
logger.error(" DEVICE ERROR: %s", exc)

# Check the violation flag even when the capture
# failed: a mid-region reset parks the device
# blinking, so the stop pulse never fires and the
# capture times out.
try:
time.sleep(POST_CAPTURE_SETTLE_SECONDS)
if device_debug and nvm_symbols:
time.sleep(POST_CAPTURE_SETTLE_SECONDS)
nvm_dict = read_nvm(
tc,
elf,
FLASH_TIMEOUT,
nvm_symbols,
)
raise_if_region_violation(nvm_dict, elf)
nvm_text = "\n".join(
f"{k}={v}" for k, v in nvm_dict.items()
)
nvm = parse_nvm_output(nvm_text)
else:
check_region_violation(tc, elf, FLASH_TIMEOUT)
except RegionViolationError as exc:
logger.error(" REGION ENERGY VIOLATION: %s", exc)
region_violation = True
except DeviceError as exc:
logger.error(" DEVICE ERROR: %s", exc)

Expand Down Expand Up @@ -426,12 +444,14 @@ def run_benchmark_matrix(
if execution_time_us is not None:
row_fields["execution_time_us"] = str(round(execution_time_us, 2))

if had_compilation_error and row_status == "ok":
row_status = "link_failed"
if region_violation:
row_status = "region_violation"
row = BenchmarkRow(
benchmark=row_name,
capacitor=cap.label,
status="link_failed"
if had_compilation_error and row_status == "ok"
else row_status,
status=row_status,
fields=row_fields,
)
write_csv_row(writer, row, csv_header)
Expand Down
1 change: 1 addition & 0 deletions scripts/ckpt/bench/schematic.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@
NVM_SYMBOLS: list[str] = [
"__nvm_done",
"__nvm_result",
"__nvm_violation",
"cnt_boundary",
"cnt_save_reg",
"cnt_restore_reg",
Expand Down
Loading
Loading