// cxxChronoProbe.cpp - exercise the etl::chrono surface (Phase 5.3).
//
// Takes two steady_clock::now() readings around a busy loop, verifies
// that the second is >= the first (clock is monotonic), then prints
// the duration count via printf.  Also validates the chrono rep is
// `int32_t` (the etl_profile.h override) so that i64 libcalls don't
// creep into chrono::now() comparison paths.
//
// Marker layout (16-bit little-endian at $025xxx unless noted):
//   $025010 = 0xBEEF  main entered
//   $025012 = 1 if sizeof(steady_clock::duration::rep) == 4 (i32 rep)
//             0 otherwise
//   $025014 = 1 if t1 >= t0 (monotonic), 0 otherwise
//   $025016 = (uint16_t)(t1.time_since_epoch().count() & 0xFFFF)
//             low 16 bits of the second reading; used by smoke to
//             confirm a non-zero value (clock is actually ticking)
//   $025018 = (uint16_t)(elapsed_ms & 0xFFFF)
//             low 16 bits of (t1 - t0).count() in milliseconds; will
//             be small but ETL chrono::duration_cast<milliseconds>
//             returning the raw rep means even tiny elapsed values
//             write *something* here (proves the subtract path works)
//   $025000 = 0xC0DE  reached end-of-main (sentinel for runInGno --check)
#include <stdint.h>
#include <stdio.h>
#include "etl/chrono.h"

int main(void) {
    *(volatile uint16_t *)0x025010UL = 0xBEEF;

    // Compile-time contract: clock-rep is i32 (etl_profile.h override).
    // Any chrono lib that snuck i64 back in would FAIL HERE — caught
    // on the demo build, not silently bloating the .omf.
    static_assert(sizeof(etl::chrono::steady_clock::duration::rep) == 4,
                  "etl::chrono::steady_clock::rep must be i32 — check "
                  "ETL_CHRONO_STEADY_CLOCK_DURATION in etl_profile.h");
    static_assert(sizeof(etl::chrono::system_clock::duration::rep) == 4,
                  "etl::chrono::system_clock::rep must be i32");
    static_assert(sizeof(etl::chrono::high_resolution_clock::duration::rep) == 4,
                  "etl::chrono::high_resolution_clock::rep must be i32");
    *(volatile uint16_t *)0x025012UL = 1;

    // Two readings around a busy loop.  Loop is sized to take long
    // enough that one VBL tick (16.67 ms) reliably elapses, but short
    // enough that the demo completes well within the runInGno timeout.
    auto t0 = etl::chrono::steady_clock::now();

    // Busy-spin.  volatile keeps the optimizer from collapsing it.
    volatile uint16_t spin = 0;
    for (uint16_t i = 0; i < 20000; i++) {
        spin = (uint16_t)(spin + 1);
    }

    auto t1 = etl::chrono::steady_clock::now();

    // Monotonic check.  Use the raw count() so the comparison is on
    // i32 reps, not the time_point operator< (which works too — just
    // belt-and-braces).
    long c0 = t0.time_since_epoch().count();
    long c1 = t1.time_since_epoch().count();
    *(volatile uint16_t *)0x025014UL = (uint16_t)((c1 >= c0) ? 1 : 0);

    // Low 16 bits of the absolute reading.  If the VBL counter
    // wasn't ticking at all both readings would be 0 — make that
    // visible to the host.
    *(volatile uint16_t *)0x025016UL = (uint16_t)(c1 & 0xFFFFL);

    // Elapsed milliseconds.  steady_clock's rep is already
    // milliseconds (period = etl::milli), so the count delta IS
    // the elapsed ms; no duration_cast required.
    long elapsed_ms = c1 - c0;
    *(volatile uint16_t *)0x025018UL = (uint16_t)(elapsed_ms & 0xFFFFL);

    // Human-readable.  GNO redirects stdout to fd 1; printf %ld is
    // fully supported (Phase 1 audit closed the printf gaps).
    printf("steady_clock t0 = %ld ms\n", c0);
    printf("steady_clock t1 = %ld ms\n", c1);
    printf("elapsed         = %ld ms\n", elapsed_ms);

    *(volatile uint16_t *)0x025000UL = 0xC0DE;
    return 0;
}
