Fix HEARTBEAT-TICKS@: read heartbeat_ticks() (ISR hardware timer), not

vm->heartbeat.tick_count (FORTH-dispatch counter)

Captain Bob's law is unambiguous: the adaptive heartbeat is the one and
only clock, full stop. The first cut of this word read the wrong
counter under that name -- vm->heartbeat.tick_count is a colon-word-
dispatch counter gated at a fixed cadence (frozen during idle, blind to
per-dispatch CPU cost, see FABRIC-2.md Section Q). The real adaptive
heartbeat is heartbeat_ticks() in src/starkernel/heartbeat.c, driven
directly by the ISR-latched 100Hz hardware timer -- genuinely
time-based, confirmed advancing during idle wall-clock time on all
three architectures (amd64 4039->5510, aarch64 6126->7607, riscv64
2965->4466, each over ~15s idle). Kernel build only (__STARKERNEL__);
hosted build has no ISR timer and keeps the old fallback.

Three-arch QEMU acceptance: POST 1012/0/0 on each, word live-tested.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Robert Allan James
2026-08-21 09:33:17 -04:00
co-authored by Claude Sonnet 5
parent 3998ce6aaf
commit 4076a01c35
7 changed files with 43945 additions and 4 deletions
+1 -1
View File
@@ -1,5 +1,5 @@
# Capsule Block Manifest — Auto-generated
<!-- Generated by mkcapsule --manifest 2026-08-21T03:22:02Z -->
<!-- Generated by mkcapsule --manifest 2026-08-21T13:31:45Z -->
<!-- DO NOT EDIT — re-run mkcapsule --manifest to refresh. -->
<!-- Hand-written justifications and immutability notes live -->
<!-- in MANIFEST.md alongside this auto-generated index. -->
BIN
View File
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+13 -3
View File
@@ -47,6 +47,7 @@
#include "../../include/vm.h"
#ifdef __STARKERNEL__
#include "starkernel/vm/arena.h"
#include "starkernel/timer.h"
#endif
#include "include/vocabulary_words.h"
#include "../../include/version.h"
@@ -797,14 +798,23 @@ static void starforth_word_zuse_authenticate(VM *vm)
* @brief Read-only accessor for the canonical heartbeat tick counter
*
* Stack effect: ( -- n )
* Pushes vm->heartbeat.tick_count -- the one clock this project's timing
* measurements are supposed to read, not host wall-clock. Read-only: no
* corresponding store word exists or should exist.
* On the kernel build, pushes heartbeat_ticks() -- the ISR-driven hardware
* timer tick count (src/starkernel/heartbeat.c), the one real clock in this
* project. NOT vm->heartbeat.tick_count, which is a FORTH colon-word-dispatch
* counter gated at a fixed cadence -- frozen during idle time and blind to
* any cost that doesn't change control flow (see FABRIC-2.md Section Q).
* On the hosted build (no ISR timer), falls back to vm->heartbeat.tick_count
* since that's the only tick source available there.
* Read-only: no corresponding store word exists or should exist.
* @param vm Pointer to the VM instance
*/
static void starforth_word_heartbeat_ticks(VM* vm)
{
#ifdef __STARKERNEL__
vm_push(vm, (cell_t)heartbeat_ticks());
#else
vm_push(vm, (cell_t)vm->heartbeat.tick_count);
#endif
}
/**