# K15 — Explicit FromISR, UART and GPIO wrappers

K15 routes a real Hazard3 machine-external interrupt through the official
FreeRTOS RISC-V trap path. The C++ layer keeps task and ISR views explicit:
UartTaskView/GpioTaskView contain configuration and output operations, while
UartIsrView/GpioIsrView expose only bounded register reads and clears.

One IsrContext accumulates wake requests from two primitives:

    UART RX bytes: 0x41, 0x42
    static queue capacity: 1
    accepted: 0x41
    overflow policy: drop-newest -> 0x42 dropped
    GPIO edge: task notification
    higherPriorityTaskWoken: true
    yield_if_needed calls: exactly 1

The high-priority receiver consumes byte 0x41 and notification count 1, then
drives GPIO output high. It runs before the interrupted stimulus continues,
which proves the ISR-requested context switch.

## Build

    make check

The gate includes a host contract test, freestanding ABI/storage checks and a
real external-IRQ simulation on Hazard3.

## Debug

    riscv64-unknown-elf-gdb build/task01_isr_drivers/prog.elf
    b isr_drivers_debug_checkpoint
    p/x g_mcause
    p g_rx_queued
    p g_rx_dropped
    p/x g_receiver_byte
    p/x g_dropped_byte
    p g_higher_priority_task_woken
    p g_isr_yield_calls
    p g_stimulus_after_seen_by_receiver
    p g_receiver_done_at_stimulus_resume
    p g_isr_drivers_pass

## Scope boundary

ISR code cannot call a blocking task API. Parsing, debounce and GPIO policy
belong to a task. Backpressure is explicit: this exercise uses drop-newest and
counts the dropped byte. The handler creates one IsrContext and calls
yield_if_needed once, after all FromISR publications and peripheral clears.
