{ "$schema": "../../../tools/card-layouts/schemas/card-source.schema.json", "schema": "esc-card-source.v1", "card": { "id": "mpabi-freertos-c-14-gpio-timer-deferred", "series": "freertos-c", "series_title": "FreeRTOS C", "number": "14", "count": "15", "slug": "gpio-timer-deferred", "title": "GPIO, hardware timer and deferred work", "topic": "mtime tick ISR, pended daemon callback and one bounded GPIO transition", "project": "Freestanding C nad FreeRTOS", "subject": "Informatyka", "level": "Rok 2 · L14 · RV32I/Hazard3", "revision_date": "2026-07-19T00:00:00+02:00", "status": "Gotowa", "version": "v00.01", "uuid": "7de92b94-df89-5c00-be47-d85523ad02ac", "author": "M. Pabiszczak", "year": "2026" }, "generated": { "tex": "doc/generated/main.tex", "html": "web/index.html", "html_css": "web/style.css", "html_tree_inspector": false, "react_app": true }, "render_dictionary": false, "viewpoints": [ { "id": "A1", "label": "CONTEXT", "subtitle": "hardware/ISR/daemon boundary", "status": "enabled", "target_label": "fig:a1-context" }, { "id": "A2", "label": "STRUCTURE", "subtitle": "event and register records", "status": "enabled", "target_label": "fig:a2-structure" }, { "id": "A3", "label": "DISPATCH", "subtitle": "pended callback binding", "status": "enabled", "target_label": "fig:a3-dispatch" }, { "id": "A4", "label": "APPLICATION", "subtitle": "single event topology", "status": "unavailable", "reason": "A1 already identifies every application participant and A5 provides the complete concrete topology in time." }, { "id": "A5", "label": "FLOW", "subtitle": "E01-E06 hardware replay", "status": "enabled", "target_label": "fig:a5-flow" }, { "id": "A6", "label": "STATE", "subtitle": "pending and applied states", "status": "enabled", "target_label": "fig:a6-state" }, { "id": "A7", "label": "RUNTIME", "subtitle": "mtime, stacks and ELF", "status": "enabled", "target_label": "fig:a7-runtime" }, { "id": "A8", "label": "PATTERNS", "subtitle": "deferred interrupt processing", "status": "unavailable", "reason": "Deferred interrupt processing is the mechanism proved in A3 and A6; a separate page would repeat the same decision." } ], "debug_strategies": { "code.contract": { "id": "code.contract", "kind": "code", "action": "open", "expected_observations": [ "ISR and callback are separate functions", "one GPIO owner" ], "assertions": [ "hook never blocks", "callback arguments outlive the ISR" ], "evidence_fields": [ "code_ref", "priority", "register", "API" ], "prerequisites": [ "FC06 and FC07 complete" ], "layout": [ "mtime port", "tick hook", "timer queue", "daemon callback", "GPIO" ], "commands": [ "rg -n 'TickHook|PendFunction|MTIME|gpio' include src Makefile" ] }, "run.timer": { "id": "run.timer", "kind": "run", "action": "replay", "expected_observations": [ "E03 at target tick", "pend returns pdPASS and wake true" ], "assertions": [ "mcause is MTI", "compare was reloaded", "one command accepted" ], "evidence_fields": [ "tick", "mtime", "mtimecmp", "mcause", "pend result", "ISR SP" ], "prerequisites": [ "clean Hazard3 RAM", "target tick armed" ], "layout": [ "mtime", "mtimecmp", "mcause", "timer command queue" ], "commands": [ "make sim", "print g_fc14", "print g_fc14_events" ] }, "run.daemon": { "id": "run.daemon", "kind": "run", "action": "replay", "expected_observations": [ "callback at same tick", "GPIO low-to-high once" ], "assertions": [ "daemon handle matches", "E04 precedes E05", "callback stack differs from ISR" ], "evidence_fields": [ "TaskHandle_t", "SP", "tick", "GPIO before/after", "transition count" ], "prerequisites": [ "E03 command queued", "daemon priority 3" ], "layout": [ "daemon handle", "callback arguments", "GPIO bank", "event order" ], "commands": [ "break fc14_checkpoint_committed if $a0 == 4", "print g_fc14" ] }, "code.identity": { "id": "code.identity", "kind": "code", "action": "open", "expected_observations": [ "all C boundaries are linked", "no C++ metadata" ], "assertions": [ "timer task implementation is present", "pended function API is present" ], "evidence_fields": [ "symbol", "source blob", "ELF SHA256", "image SHA256" ], "prerequisites": [ "built ELF" ], "layout": [ "trap", "tick", "timer daemon", "application symbols" ], "commands": [ "make check-abi", "riscv64-unknown-elf-nm build/task01_gpio_timer/prog.elf" ] }, "run.identity": { "id": "run.identity", "kind": "run", "action": "replay", "expected_observations": [ "one PASS", "digest bf66bc48 three times" ], "assertions": [ "six ordered events", "exactly one GPIO transition" ], "evidence_fields": [ "digest", "event count", "SP values", "artifact identity" ], "prerequisites": [ "built image" ], "layout": [ "six-event trace", "three clean processes" ], "commands": [ "make check-determinism" ] } }, "template": "templates/karta-klasyczna.json", "title_block": { "category": "KARTA PRACY · INFORMATYKA", "prepared_by": "M. Pabiszczak", "prepared_on": "2026-07-19T00:00:00+02:00", "title": "GPIO, hardware timer and deferred work", "url": "https://dce7fb9d-7b2f-5d49-96a2-3a30d3070b84.mpabi.pl/0cc561df-bf81-5bba-9df1-c872d5b42eb8", "repository_url": "https://zsl-gitea.mpabi.pl/edu-freertos-c/lab-rv32i-freertos-c-gpio-timer", "url_host_uuid": "dce7fb9d-7b2f-5d49-96a2-3a30d3070b84", "url_domain": "mpabi.pl", "doc_uuid": "0cc561df-bf81-5bba-9df1-c872d5b42eb8", "revision": "v00.01", "issued_on": "2026-07-19T00:00:00+02:00", "series": "FREERTOS-C-14", "document_type": "karta pracy", "tool": "card-layouts", "show_qr": true, "show_repository_qr": true, "height_cm": 2.6, "repeat_on_every_page": true, "replace_front_matter": true }, "front_page_scope": { "title": "Cel karty", "content_tex": "Uczeń odróżnia hardware timer interrupt od callbacku software timera: ISR tylko zatwierdza zdarzenie i odkłada pracę, a timer daemon wykonuje ograniczoną zmianę GPIO.", "scope_title": "Zakres karty", "scope_content_tex": "Stimulus uzbraja tick +3. Machine timer ISR zapisuje mtime, mtimecmp, mcause i stos, po czym wywołuje xTimerPendFunctionCallFromISR. Daemon priority 3 przełącza GPIO przed powrotem do przerwanego taska priority 2.", "scope_table": { "headers": [ "Lekcja", "Task", "Najważniejsza idea", "Priorytet", "Status", "Version" ], "rows": [ { "chapter": "FC14", "task": "Task01", "idea_tex": "mtime tick ISR, pended daemon callback and one bounded GPIO transition", "priority": "główny", "status": "ready", "version": "v00.01", "key": true } ] } }, "side_margin_tree_layout": { "columns": [ { "id": "zawodowe", "label": "TECH", "side": "left", "tree": "WE -> EK -> KW", "description": "Dowody runtime." }, { "id": "ogolne", "label": "OG", "side": "right", "tree": "WE -> EN -> KW", "description": "Model FreeRTOS C." } ] }, "learning_effects": { "FC14.EN01": { "bloom_level": "Analiza", "label": "Hardware timer versus deferred callback", "text": "Uczeń rozdziela machine timer ISR, tick hook, timer command queue, daemon task and GPIO owner.", "assessment_criteria": [ "FC14.KW01" ] }, "FC14.EK01": { "bloom_level": "Zastosowanie", "label": "One-event deferred-work replay", "text": "Uczeń odtwarza E01–E06 i dowodzi kolejności ISR → daemon → interrupted task.", "assessment_criteria": [ "FC14.KW01" ] } }, "assessment_criteria": { "FC14.KW01": { "text": "PASS; mcause=MTI; mtimecmp>mtime; one successful pend; daemon callback in target tick; one GPIO transition; three distinct stacks; deterministic digest.", "learning_effects": [ "FC14.EN01", "FC14.EK01" ] } }, "educational_requirements": { "FC14.WE01": { "text": "Projektowanie i badanie deferred interrupt processing dla timera sprzętowego i GPIO w FreeRTOS C.", "label": "mtime tick ISR, pended daemon callback and one bounded GPIO transition", "learning_effects": [ "FC14.EN01", "FC14.EK01" ], "learning_tree": { "schema": "we-learning-tree.v1", "policy": "Każda aktywna kotwica wskazuje kod lub checkpoint.", "ogolne": [ { "effect_ref": "FC14.EN01", "display": "EN LOCAL RTOS.14", "source": "LOCAL", "official": "RTOS", "local": "14", "kind": "EN", "tree_id": "FC14.WE01.OG.LOCAL.RTOS.14", "text": "Uczeń rozdziela machine timer ISR, tick hook, timer command queue, daemon task and GPIO owner.", "kw": [ { "criterion_ref": "FC14.KW01", "display": "KW LOCAL RTOS.14", "source": "LOCAL", "kind": "KW", "official": "RTOS", "local": "14", "text": "Łączy kod, diagram i zweryfikowany dowód." } ] } ], "zawodowe": [ { "effect_ref": "FC14.EK01", "display": "EK LOCAL RTOS.14", "source": "LOCAL", "official": "RTOS", "local": "14", "kind": "EK", "tree_id": "FC14.WE01.TECH.LOCAL.RTOS.14", "text": "Uczeń odtwarza E01–E06 i dowodzi kolejności ISR → daemon → interrupted task.", "kw": [ { "criterion_ref": "FC14.KW01", "display": "KW LOCAL RTOS.14", "source": "LOCAL", "kind": "KW", "official": "RTOS", "local": "14", "text": "Łączy kod, diagram i zweryfikowany dowód." } ] } ] } } }, "debug_checkpoints": { "schema": "stem-debug-checkpoints.v1", "semantics": "deterministic-replay", "artifact": { "source": "src/tasks/task01_gpio_timer.c", "source_git_blob": "ec2e552d61694b31bbe65af1ec361442980de23b", "elf": "build/task01_gpio_timer/prog.elf", "hazard3_elf_sha256": "dde14e1ccc2ad816883b45a7cd9a1b431f157c1509abe02b9f6559e53365d619", "hazard3_image": "build/task01_gpio_timer/prog.bin", "hazard3_image_sha256": "3ffeec5e5e362efdd714ef9d354b1e3592a183bda582c6fb21be63736fb7a92d" }, "targets": { "hazard3-sim": { "adapter": "hazard3-reset-load-replay.v1", "baseline": "restart-backend", "clean_ram": true } }, "items": { "task01.configured": { "event_id": "E01", "stop": { "symbol": "fc14_checkpoint_committed", "offset": 0, "condition": "$a0 == 1" }, "verify": { "expressions": [ { "expr": "g_fc14_event_count", "equals": 1 }, { "expr": "g_fc14.gpio.direction", "equals": 1 }, { "expr": "g_fc14_events[0].value", "equals": 3 } ] } }, "task01.armed": { "event_id": "E02", "stop": { "symbol": "fc14_checkpoint_committed", "offset": 0, "condition": "$a0 == 2" }, "verify": { "expressions": [ { "expr": "g_fc14.armed", "equals": 1 }, { "expr": "g_fc14.pended", "equals": 0 }, { "expr": "g_fc14.target_tick == g_fc14_events[1].value", "equals": 1 } ] } }, "task01.tick-isr": { "event_id": "E03", "stop": { "symbol": "fc14_checkpoint_committed", "offset": 0, "condition": "$a0 == 3" }, "verify": { "expressions": [ { "expr": "g_fc14.mcause", "equals": 2147483655 }, { "expr": "g_fc14.pend_result", "equals": 1 }, { "expr": "g_fc14.higher_priority_task_woken", "equals": 1 }, { "expr": "g_fc14.mtimecmp_after_reload > g_fc14.mtime_at_isr", "equals": 1 } ] } }, "task01.callback": { "event_id": "E04", "stop": { "symbol": "fc14_checkpoint_committed", "offset": 0, "condition": "$a0 == 4" }, "verify": { "expressions": [ { "expr": "g_fc14.callback_calls", "equals": 1 }, { "expr": "g_fc14.gpio.data", "equals": 1 }, { "expr": "g_fc14.gpio.transitions", "equals": 1 }, { "expr": "g_fc14.callback_saw_stimulus_after", "equals": 0 } ] } }, "task01.stimulus-resumed": { "event_id": "E05", "stop": { "symbol": "fc14_checkpoint_committed", "offset": 0, "condition": "$a0 == 5" }, "verify": { "expressions": [ { "expr": "g_fc14.applied_at_stimulus_resume", "equals": 1 }, { "expr": "g_fc14.stimulus_after", "equals": 1 } ] } }, "task01.pass": { "event_id": "E06", "stop": { "symbol": "fc14_checkpoint_committed", "offset": 0, "condition": "$a0 == 6" }, "verify": { "expressions": [ { "expr": "g_fc14_pass", "equals": 1 }, { "expr": "g_fc14_event_count", "equals": 6 }, { "expr": "g_fc14.pend_calls", "equals": 1 }, { "expr": "g_fc14.callback_calls", "equals": 1 } ] } } } }, "sections": [ { "title": "A1 — Hardware, ISR and daemon boundary", "order": 10, "content_kind": "prose", "asset_page_mode": "one-per-page", "page_orientation": "portrait", "content_tex": "The hardware interrupt only records and defers. GPIO changes later in task context; this is not a software-timer expiry callback.", "assets": [ { "path": "assets/a1-context.png", "html_path": "assets/a1-context.svg", "source_path": "assets/a1-context.puml", "caption": "A1 CONTEXT — mtime, tick ISR, pend queue, daemon and GPIO.", "label": "fig:a1-context", "alt": "A1 · hardware-to-deferred-work boundary", "kind": "diagram", "width": 1.0, "page_grid": { "columns": 1, "rows": 1, "page_width": 660, "page_height": 760, "overview": true, "step_tiles": { "mtime": 1, "port": 1, "hook": 1, "daemon": 1, "gpio": 1, "pass": 1 } }, "interactive": { "kind": "uml-class", "storage_key": "fc14-a1-context", "title": "A1 · hardware-to-deferred-work boundary", "task": { "id": "task01", "label": "Task01 · hardware timer to deferred GPIO" }, "block": { "id": "a1", "label": "A1 CONTEXT", "description": "The machine timer, kernel tick path, application hook, timer queue, daemon task and GPIO register bank have separate roles." }, "phases": [ { "id": "boundary", "label": "HARDWARE / ISR / DAEMON", "steps": [ { "id": "mtime", "number": 1, "label": "mtime and mtimecmp generate the kernel tick", "mode": "CODE", "strategy_ref": "code.contract", "svg_label": "01", "code_ref": "include/FreeRTOSConfig.h:4", "description": "mtime and mtimecmp generate the kernel tick", "evidence": "10 MHz clock, 1 kHz tick" }, { "id": "port", "number": 2, "label": "port reloads compare and increments tick", "mode": "CODE", "strategy_ref": "code.contract", "svg_label": "02", "code_ref": "vendor/FreeRTOS-Kernel/portable/GCC/RISC-V/portASM.S:368", "description": "port reloads compare and increments tick", "evidence": "machine timer trap" }, { "id": "hook", "number": 3, "label": "tick hook accepts exactly one target event", "mode": "CODE", "strategy_ref": "code.contract", "svg_label": "03", "code_ref": "src/tasks/task01_gpio_timer.c:97", "description": "tick hook accepts exactly one target event", "evidence": "minimal ISR path" }, { "id": "daemon", "number": 4, "label": "pended function runs on timer daemon", "mode": "CODE", "strategy_ref": "code.contract", "svg_label": "04", "code_ref": "src/tasks/task01_gpio_timer.c:127", "description": "pended function runs on timer daemon", "evidence": "task context" }, { "id": "gpio", "number": 5, "label": "daemon owns the GPIO transition", "mode": "CODE", "strategy_ref": "code.contract", "svg_label": "05", "code_ref": "include/task01_gpio_timer_model.h:32", "description": "daemon owns the GPIO transition", "evidence": "exactly one toggle" }, { "id": "pass", "number": 6, "label": "runtime proves every boundary", "mode": "RUN", "event_id": "E06", "strategy_ref": "run.identity", "svg_label": "06", "code_ref": "src/tasks/task01_gpio_timer.c:202", "snapshot_ref": "task01.pass", "description": "runtime proves every boundary", "evidence": "PASS and deterministic digest" } ] } ] } } ] }, { "title": "A2 — Event and register records", "order": 20, "content_kind": "prose", "asset_page_mode": "one-per-page", "page_orientation": "portrait", "content_tex": "The callback receives a pointer and a 32-bit event value through the timer command queue. It does not capture ISR stack storage.", "assets": [ { "path": "assets/a2-structure.png", "html_path": "assets/a2-structure.svg", "source_path": "assets/a2-structure.puml", "caption": "A2 STRUCTURE — experiment, command, GPIO and evidence records.", "label": "fig:a2-structure", "alt": "A2 · deferred event storage", "kind": "diagram", "width": 1.0, "page_grid": { "columns": 1, "rows": 1, "page_width": 660, "page_height": 760, "overview": true, "step_tiles": { "experiment": 1, "gpio-record": 1, "event-record": 1, "command": 1, "identity": 1 } }, "interactive": { "kind": "uml-class", "storage_key": "fc14-a2-structure", "title": "A2 · deferred event storage", "task": { "id": "task01", "label": "Task01 · hardware timer to deferred GPIO" }, "block": { "id": "a2", "label": "A2 STRUCTURE", "description": "One bounded experiment record connects hardware time, trap state, daemon identity, GPIO values and six commit-last events." }, "phases": [ { "id": "storage", "label": "RECORDS AND OWNERSHIP", "steps": [ { "id": "experiment", "number": 1, "label": "experiment stores timing and context proof", "mode": "CODE", "strategy_ref": "code.contract", "svg_label": "01", "code_ref": "include/task01_gpio_timer.h:20", "description": "experiment stores timing and context proof", "evidence": "ticks, mtime, SP and result" }, { "id": "gpio-record", "number": 2, "label": "volatile GPIO bank stores direction and data", "mode": "CODE", "strategy_ref": "code.contract", "svg_label": "02", "code_ref": "include/task01_gpio_timer_model.h:10", "description": "volatile GPIO bank stores direction and data", "evidence": "transition counter" }, { "id": "event-record", "number": 3, "label": "six evidence records commit last", "mode": "CODE", "strategy_ref": "code.contract", "svg_label": "03", "code_ref": "include/task01_gpio_timer_model.h:17", "description": "six evidence records commit last", "evidence": "sequence, actor and tick" }, { "id": "command", "number": 4, "label": "timer queue copies callback and arguments", "mode": "CODE", "strategy_ref": "code.contract", "svg_label": "04", "code_ref": "vendor/FreeRTOS-Kernel/timers.c:1233", "description": "timer queue copies callback and arguments", "evidence": "daemon command message" }, { "id": "identity", "number": 5, "label": "callback handle equals timer daemon handle", "mode": "RUN", "event_id": "E04", "strategy_ref": "run.daemon", "svg_label": "05", "code_ref": "src/tasks/task01_gpio_timer.c:135", "snapshot_ref": "task01.callback", "description": "callback handle equals timer daemon handle", "evidence": "same TaskHandle_t" } ] } ] } } ] }, { "title": "A3 — Pended-function dispatch", "order": 30, "content_kind": "prose", "asset_page_mode": "one-per-page", "page_orientation": "portrait", "content_tex": "The port restores the daemon task before the interrupted stimulus continues. The callback and ISR therefore have different stacks and API permissions.", "assets": [ { "path": "assets/a3-dispatch.png", "html_path": "assets/a3-dispatch.svg", "source_path": "assets/a3-dispatch.puml", "caption": "A3 DISPATCH — MTI, tick hook, timer queue and daemon restore.", "label": "fig:a3-dispatch", "alt": "A3 · timer-to-daemon dispatch", "kind": "diagram", "width": 1.0, "page_grid": { "columns": 1, "rows": 1, "page_width": 660, "page_height": 760, "overview": true, "step_tiles": { "trap": 1, "reload": 1, "pend": 1, "yield": 1, "callback": 1, "resume": 1 } }, "interactive": { "kind": "uml-class", "storage_key": "fc14-a3-dispatch", "title": "A3 · timer-to-daemon dispatch", "task": { "id": "task01", "label": "Task01 · hardware timer to deferred GPIO" }, "block": { "id": "a3", "label": "A3 DISPATCH", "description": "A real machine timer trap reaches the tick hook, which queues one function and requests a switch to the higher-priority timer daemon." }, "phases": [ { "id": "dispatch", "label": "MTI / PEND / RESTORE", "steps": [ { "id": "trap", "number": 1, "label": "machine timer enters full trap path", "mode": "CODE", "strategy_ref": "code.contract", "svg_label": "01", "code_ref": "vendor/FreeRTOS-Kernel/portable/GCC/RISC-V/portASM.S:368", "description": "machine timer enters full trap path", "evidence": "mcause timer interrupt" }, { "id": "reload", "number": 2, "label": "port reloads mtimecmp before hook", "mode": "CODE", "strategy_ref": "code.contract", "svg_label": "02", "code_ref": "vendor/FreeRTOS-Kernel/portable/GCC/RISC-V/portASM.S:377", "description": "port reloads mtimecmp before hook", "evidence": "next compare is in the future" }, { "id": "pend", "number": 3, "label": "hook records and pends one callback", "mode": "RUN", "event_id": "E03", "strategy_ref": "run.timer", "svg_label": "03", "code_ref": "src/tasks/task01_gpio_timer.c:109", "snapshot_ref": "task01.tick-isr", "description": "hook records and pends one callback", "evidence": "pdPASS and wake=true" }, { "id": "yield", "number": 4, "label": "FromISR result requests daemon restore", "mode": "CODE", "strategy_ref": "code.contract", "svg_label": "04", "code_ref": "src/tasks/task01_gpio_timer.c:117", "description": "FromISR result requests daemon restore", "evidence": "one port yield" }, { "id": "callback", "number": 5, "label": "daemon applies GPIO in the same tick", "mode": "RUN", "event_id": "E04", "strategy_ref": "run.daemon", "svg_label": "05", "code_ref": "src/tasks/task01_gpio_timer.c:135", "snapshot_ref": "task01.callback", "description": "daemon applies GPIO in the same tick", "evidence": "daemon stack and GPIO=1" }, { "id": "resume", "number": 6, "label": "stimulus resumes only after callback", "mode": "RUN", "event_id": "E05", "strategy_ref": "run.daemon", "svg_label": "06", "code_ref": "src/tasks/task01_gpio_timer.c:183", "snapshot_ref": "task01.stimulus-resumed", "description": "stimulus resumes only after callback", "evidence": "applied_at_resume=1" } ] } ] } } ] }, { "title": "A5 — One hardware event replay", "order": 50, "content_kind": "prose", "asset_page_mode": "one-per-page", "page_orientation": "portrait", "content_tex": "The decisive order is E03 ISR, E04 daemon, E05 interrupted stimulus. Exactly one accepted event produces exactly one GPIO transition.", "assets": [ { "path": "assets/a5-flow.png", "html_path": "assets/a5-flow.svg", "source_path": "assets/a5-flow.puml", "caption": "A5 FLOW — E01–E06 from configuration to PASS.", "label": "fig:a5-flow", "alt": "A5 · deferred GPIO replay", "kind": "diagram", "width": 1.0, "page_grid": { "columns": 1, "rows": 1, "page_width": 660, "page_height": 760, "overview": true, "step_tiles": { "config": 1, "arm": 1, "isr": 1, "apply": 1, "stimulus": 1, "verified": 1 } }, "interactive": { "kind": "uml-sequence", "storage_key": "fc14-a5-flow", "title": "A5 · deferred GPIO replay", "task": { "id": "task01", "label": "Task01 · hardware timer to deferred GPIO" }, "block": { "id": "a5", "label": "A5 FLOW", "description": "Six events show configuration, arming, timer ISR, daemon callback, interrupted-task resume and final verification." }, "phases": [ { "id": "flow", "label": "ARM / INTERRUPT / DEFER / APPLY", "steps": [ { "id": "config", "number": 1, "label": "configure daemon priority and GPIO output", "mode": "RUN", "event_id": "E01", "strategy_ref": "run.timer", "svg_label": "01", "code_ref": "src/tasks/task01_gpio_timer.c:260", "snapshot_ref": "task01.configured", "description": "configure daemon priority and GPIO output", "evidence": "daemon priority 3" }, { "id": "arm", "number": 2, "label": "stimulus arms target tick plus three", "mode": "RUN", "event_id": "E02", "strategy_ref": "run.timer", "svg_label": "02", "code_ref": "src/tasks/task01_gpio_timer.c:163", "snapshot_ref": "task01.armed", "description": "stimulus arms target tick plus three", "evidence": "armed=1" }, { "id": "isr", "number": 3, "label": "mtime compare fires at target", "mode": "RUN", "event_id": "E03", "strategy_ref": "run.timer", "svg_label": "03", "code_ref": "src/tasks/task01_gpio_timer.c:112", "snapshot_ref": "task01.tick-isr", "description": "mtime compare fires at target", "evidence": "mcause=MTI; pended once" }, { "id": "apply", "number": 4, "label": "daemon toggles GPIO low to high", "mode": "RUN", "event_id": "E04", "strategy_ref": "run.daemon", "svg_label": "04", "code_ref": "src/tasks/task01_gpio_timer.c:141", "snapshot_ref": "task01.callback", "description": "daemon toggles GPIO low to high", "evidence": "transition count 1" }, { "id": "stimulus", "number": 5, "label": "interrupted task resumes after apply", "mode": "RUN", "event_id": "E05", "strategy_ref": "run.daemon", "svg_label": "05", "code_ref": "src/tasks/task01_gpio_timer.c:183", "snapshot_ref": "task01.stimulus-resumed", "description": "interrupted task resumes after apply", "evidence": "applied already true" }, { "id": "verified", "number": 6, "label": "verifier commits complete proof", "mode": "RUN", "event_id": "E06", "strategy_ref": "run.identity", "svg_label": "06", "code_ref": "src/tasks/task01_gpio_timer.c:225", "snapshot_ref": "task01.pass", "description": "verifier commits complete proof", "evidence": "digest bf66bc48" } ] } ] } } ] }, { "title": "A6 — Pending and applied states", "order": 60, "content_kind": "prose", "asset_page_mode": "one-per-page", "page_orientation": "portrait", "content_tex": "Queue acceptance does not mean GPIO has changed. The callback commit is the first point where applied and the output register may be one.", "assets": [ { "path": "assets/a6-state.png", "html_path": "assets/a6-state.svg", "source_path": "assets/a6-state.puml", "caption": "A6 STATE — armed, pended, daemon-running, applied and verified.", "label": "fig:a6-state", "alt": "A6 · deferred-work state machine", "kind": "diagram", "width": 1.0, "page_grid": { "columns": 1, "rows": 1, "page_width": 660, "page_height": 760, "overview": true, "step_tiles": { "armed": 1, "queued": 1, "running": 1, "applied": 1, "retired": 1, "terminal": 1 } }, "interactive": { "kind": "uml-class", "storage_key": "fc14-a6-state", "title": "A6 · deferred-work state machine", "task": { "id": "task01", "label": "Task01 · hardware timer to deferred GPIO" }, "block": { "id": "a6", "label": "A6 STATE", "description": "The event moves through armed, accepted, queued, executing and applied states; hardware and software ownership change at explicit boundaries." }, "phases": [ { "id": "state", "label": "EVENT LIFETIME", "steps": [ { "id": "armed", "number": 1, "label": "armed until target tick", "mode": "RUN", "event_id": "E02", "strategy_ref": "run.timer", "svg_label": "01", "code_ref": "src/tasks/task01_gpio_timer.c:169", "snapshot_ref": "task01.armed", "description": "armed until target tick", "evidence": "pended=0" }, { "id": "queued", "number": 2, "label": "ISR queues one daemon command", "mode": "RUN", "event_id": "E03", "strategy_ref": "run.timer", "svg_label": "02", "code_ref": "src/tasks/task01_gpio_timer.c:117", "snapshot_ref": "task01.tick-isr", "description": "ISR queues one daemon command", "evidence": "pended=1" }, { "id": "running", "number": 3, "label": "daemon consumes callback and arguments", "mode": "RUN", "event_id": "E04", "strategy_ref": "run.daemon", "svg_label": "03", "code_ref": "src/tasks/task01_gpio_timer.c:128", "snapshot_ref": "task01.callback", "description": "daemon consumes callback and arguments", "evidence": "callback_calls=1" }, { "id": "applied", "number": 4, "label": "GPIO records one transition", "mode": "RUN", "event_id": "E04", "strategy_ref": "run.daemon", "svg_label": "04", "code_ref": "src/tasks/task01_gpio_timer.c:142", "snapshot_ref": "task01.callback", "description": "GPIO records one transition", "evidence": "data=1" }, { "id": "retired", "number": 5, "label": "stimulus observes completed work", "mode": "RUN", "event_id": "E05", "strategy_ref": "run.daemon", "svg_label": "05", "code_ref": "src/tasks/task01_gpio_timer.c:184", "snapshot_ref": "task01.stimulus-resumed", "description": "stimulus observes completed work", "evidence": "applied=1" }, { "id": "terminal", "number": 6, "label": "all counts remain exactly one", "mode": "RUN", "event_id": "E06", "strategy_ref": "run.identity", "svg_label": "06", "code_ref": "src/tasks/task01_gpio_timer.c:203", "snapshot_ref": "task01.pass", "description": "all counts remain exactly one", "evidence": "PASS" } ] } ] } } ] }, { "title": "A7 — Timer, stacks and artifact proof", "order": 70, "content_kind": "prose", "asset_page_mode": "one-per-page", "page_orientation": "portrait", "content_tex": "The final gate also requires C-only ABI symbols, the exact source and ELF hashes, and three identical simulator processes.", "assets": [ { "path": "assets/a7-runtime.png", "html_path": "assets/a7-runtime.svg", "source_path": "assets/a7-runtime.puml", "caption": "A7 RUNTIME — mtime, mtimecmp, cause, three stacks and identity.", "label": "fig:a7-runtime", "alt": "A7 · hardware and context proof", "kind": "diagram", "width": 1.0, "page_grid": { "columns": 1, "rows": 1, "page_width": 660, "page_height": 760, "overview": true, "step_tiles": { "registers": 1, "cause": 1, "same-tick": 1, "stacks": 1, "abi": 1, "determinism": 1 } }, "interactive": { "kind": "uml-class", "storage_key": "fc14-a7-runtime", "title": "A7 · hardware and context proof", "task": { "id": "task01", "label": "Task01 · hardware timer to deferred GPIO" }, "block": { "id": "a7", "label": "A7 RUNTIME", "description": "Runtime evidence distinguishes hardware time, RTOS tick, ISR stack, daemon stack and interrupted-task stack." }, "phases": [ { "id": "runtime", "label": "RUNTIME PROOF", "steps": [ { "id": "registers", "number": 1, "label": "mtimecmp is reloaded beyond current mtime", "mode": "RUN", "event_id": "E03", "strategy_ref": "run.timer", "svg_label": "01", "code_ref": "src/tasks/task01_gpio_timer.c:115", "snapshot_ref": "task01.tick-isr", "description": "mtimecmp is reloaded beyond current mtime", "evidence": "compare > counter" }, { "id": "cause", "number": 2, "label": "mcause identifies machine timer interrupt", "mode": "RUN", "event_id": "E03", "strategy_ref": "run.timer", "svg_label": "02", "code_ref": "src/tasks/task01_gpio_timer.c:113", "snapshot_ref": "task01.tick-isr", "description": "mcause identifies machine timer interrupt", "evidence": "0x80000007" }, { "id": "same-tick", "number": 3, "label": "ISR and callback share target tick", "mode": "RUN", "event_id": "E04", "strategy_ref": "run.daemon", "svg_label": "03", "code_ref": "src/tasks/task01_gpio_timer.c:137", "snapshot_ref": "task01.callback", "description": "ISR and callback share target tick", "evidence": "isr_tick=callback_tick" }, { "id": "stacks", "number": 4, "label": "ISR, daemon and stimulus SP differ", "mode": "RUN", "event_id": "E06", "strategy_ref": "run.identity", "svg_label": "04", "code_ref": "src/tasks/task01_gpio_timer.c:222", "snapshot_ref": "task01.pass", "description": "ISR, daemon and stimulus SP differ", "evidence": "three contexts" }, { "id": "abi", "number": 5, "label": "ELF exposes tick, pend and daemon symbols", "mode": "CODE", "strategy_ref": "code.identity", "svg_label": "05", "code_ref": "scripts/check_abi.sh:18", "description": "ELF exposes tick, pend and daemon symbols", "evidence": "no C++ runtime" }, { "id": "determinism", "number": 6, "label": "three processes agree on digest", "mode": "RUN", "event_id": "E06", "strategy_ref": "run.identity", "svg_label": "06", "code_ref": "scripts/check_determinism.sh:14", "snapshot_ref": "task01.pass", "description": "three processes agree on digest", "evidence": "bf66bc48" } ] } ] } } ] }, { "title": "Task01 — hardware timer to deferred GPIO", "order": 90, "content_kind": "tasks", "task_refs": [ "task01" ] } ], "tasks": { "task01": { "title": "Prove one machine-timer event from ISR to daemon GPIO work", "uuid": "0cc561df-bf81-5bba-9df1-c872d5b42eb8", "prompt_tex": "Odtwórz E01--E06. Udowodnij, że źródłem jest machine timer interrupt, ISR jedynie odkłada pracę, a GPIO zmienia dopiero callback timer daemon taska.", "criterion": "PASS; mcause=MTI; mtimecmp>mtime; one successful pend; daemon callback in target tick; one GPIO transition; three distinct stacks; deterministic digest.", "conclusion_tex": "Hardware timer określa moment przerwania; kolejka timer service określa moment wykonania odroczonej funkcji. Są to dwa konteksty, dwa stosy i dwa różne kontrakty API.", "flow": [ { "kind": "block", "id": "contract", "title": "A — kontrakt", "content_tex": "Rozdziel hardware, ISR, daemon i rejestr GPIO.", "steps": [ { "id": "contexts", "title": "Przypisz konteksty i API.", "content_tex": "Wskaż, co wolno zrobić w tick hooku, a co dopiero w callbacku." }, { "id": "predict", "title": "Przewidź kolejność.", "content_tex": "Zapisz oczekiwane E03, E04 i E05 dla daemon priority 3." } ] }, { "kind": "block", "id": "replay", "title": "B — replay", "content_tex": "Zbierz dowód hardware i task context.", "steps": [ { "id": "timer", "title": "Sprawdź E02--E03.", "content_tex": "Target tick, mtime, mtimecmp, mcause i pend result." }, { "id": "daemon", "title": "Sprawdź E04--E05.", "content_tex": "Daemon handle, callback SP, GPIO i kolejność restore." }, { "id": "pass", "title": "Sprawdź E06.", "content_tex": "Counts, trzy stosy, ABI i digest." } ] }, { "kind": "exercise", "id": "select-mechanism", "title": "Ćwiczenie — wybór mechanizmu", "prompt_tex": "Dla trzech prac wybierz notification, semaphore albo daemon deferral: inkrementacja licznika, zapis bloku flash i obudzenie konkretnego taska. Uzasadnij właściciela, latency i budżet.", "evidence_tex": "Tabela workload → mechanizm → odbiorca → dozwolone operacje → ryzyko blokowania.", "criterion": "Wybór wynika z wymaganej własności i kosztu; uczeń nie przeciąża timer daemon taska nieograniczoną pracą.", "based_on": [ "contract", "replay" ] } ], "educational_requirement_refs": [ "FC14.WE01" ], "learning_effect_refs": [ "FC14.EN01", "FC14.EK01" ], "assessment_criterion_ref": "FC14.KW01" } }, "tasks_order": [ "task01" ] }