#
# GRTC lost-COMPARE reproduction for nRF54L15 DK.
#
# Standalone Zephyr/NCS application. Build against the same NCS install that
# exhibits the problem:
#
#   west -z "$ZEPHYR_BASE" build -b nrf54l15dk/nrf54l15/cpuapp -d build
#
# See README.md.
#

cmake_minimum_required(VERSION 3.20.0)

find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
project(grtc_bug_reproduction)

# ---------------------------------------------------------------------------
# Patched-driver detection.
#
# The defect is in nrfx, so that is where a fix belongs and where NCS carries
# it: modules/hal/nordic/nrfx/drivers/src/nrfx_grtc.c. A patched nrfx suppresses
# BOTH phases -- phase A calls nrfx_grtc_syscounter_cc_abs_set() directly, phase
# B reaches it through the Zephyr system clock -- so a patched tree yields a
# clean run that reads like a pass rather than a reproduction. Warn loudly.
# ---------------------------------------------------------------------------
if(DEFINED ZEPHYR_HAL_NORDIC_MODULE_DIR)
    set(_hal_nordic_dir "${ZEPHYR_HAL_NORDIC_MODULE_DIR}")
else()
    # Pre-3.x layouts, or a tree assembled without west module metadata.
    set(_hal_nordic_dir "$ENV{ZEPHYR_BASE}/../modules/hal/nordic")
endif()
set(_nrfx_driver "${_hal_nordic_dir}/nrfx/drivers/src/nrfx_grtc.c")

if(EXISTS "${_nrfx_driver}")
    # The stock racy sequence in nrfx_grtc_syscounter_cc_abs_set() is
    # cc_set -> event_check -> "if (val > now)" -> event_clear, and that
    # comparison against a pre-sampled `now` occurs nowhere else in the file.
    # Any fix rewrites it away, so its absence is the reliable signal; a fix
    # authored for this defect also names it in a comment.
    file(STRINGS "${_nrfx_driver}" _nrfx_stock_race REGEX "if \\(val > now\\)")
    file(STRINGS "${_nrfx_driver}" _nrfx_named_fix  REGEX "lost-COMPARE")
    if(_nrfx_named_fix OR NOT _nrfx_stock_race)
        message(WARNING
            "The nrfx GRTC driver at ${_nrfx_driver} no longer contains the racy "
            "write-then-clear sequence, i.e. it carries a fix for this defect. "
            "NEITHER phase will reproduce anything: phase A will report zero lost "
            "events in its race pass, and phase B will never stall. To reproduce, "
            "restore the stock driver first:\n"
            "    git -C ${_hal_nordic_dir} checkout -- nrfx/drivers/src/nrfx_grtc.c\n"
            "The NCS tree is shared by every application in the workspace, so put "
            "the fix back afterwards.")
    endif()
else()
    message(WARNING
        "Could not find the nrfx GRTC driver at ${_nrfx_driver}; skipping the "
        "patched-driver check. If nrfx carries a fix for this defect, neither "
        "phase will reproduce.")
endif()

# Phase B is additionally suppressed by a Zephyr-side workaround: the local
# variant of it detects CCEN == 0 && EVENTS_COMPARE == 0 right after the nrfx
# call and re-raises the event. Phase A calls nrfx directly and is unaffected.
if(DEFINED ENV{ZEPHYR_BASE})
    set(_grtc_driver "$ENV{ZEPHYR_BASE}/drivers/timer/nrf_grtc_timer.c")
    if(EXISTS "${_grtc_driver}")
        # Recognisable either by a comment naming the defect, or by the event
        # register being forced through nrf_grtc_event_address_get(), which the
        # stock driver never calls.
        file(STRINGS "${_grtc_driver}" _grtc_patched
             REGEX "lost-COMPARE|nrf_grtc_event_address_get")
        if(_grtc_patched)
            message(WARNING
                "The Zephyr GRTC driver in $ENV{ZEPHYR_BASE} appears to carry a local "
                "lost-COMPARE workaround. Phase A still reproduces the nrfx race (given "
                "a stock nrfx), but phase B (system tick stall) will NOT trigger. Revert "
                "the driver first:\n"
                "    git -C $ENV{ZEPHYR_BASE} checkout -- drivers/timer/nrf_grtc_timer.c\n"
                "If another application in this workspace applies that patch from its own "
                "CMake hook, do not configure it against this ZEPHYR_BASE afterwards, or "
                "the revert will be silently undone.")
        endif()
    endif()
endif()

target_sources(app PRIVATE src/main.c src/grtc_regs.c)
target_sources_ifdef(CONFIG_GRTC_REPRO_ISOLATED   app PRIVATE src/test_isolated.c)
target_sources_ifdef(CONFIG_GRTC_REPRO_TICK_STALL app PRIVATE src/test_tick_stall.c)
