Files

1366 lines
45 KiB
JSON
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{
"$schema": "../../../tools/card-layouts/schemas/card-source.schema.json",
"schema": "esc-card-source.v1",
"card": {
"id": "mpabi-freertos-c-07-isr-semaphore",
"series": "freertos-c",
"series_title": "FreeRTOS C",
"number": "07",
"count": "15",
"slug": "isr-semaphore",
"title": "Przerwanie zewnętrzne i semaphore FromISR",
"topic": "Hazard3 MEI, xISRStack, xSemaphoreGiveFromISR i yield",
"project": "Freestanding C nad FreeRTOS",
"subject": "Informatyka",
"level": "Rok 2 · L07 · RV32I/Hazard3",
"revision_date": "2026-07-19T00:00:00+02:00",
"status": "Gotowa",
"version": "v00.01",
"uuid": "530724e2-6774-5b17-9912-b3f5c243c15d",
"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": "Testbench → Hazard3 → port → task",
"status": "enabled",
"target_label": "fig:a1-context"
},
{
"id": "A2",
"label": "STRUCTURE",
"subtitle": "Struktura",
"status": "unavailable",
"reason": "Obiekty runtime i ich relacje są pełniej pokazane w A7."
},
{
"id": "A3",
"label": "DISPATCH",
"subtitle": "Vector, trap, FromISR i context switch",
"status": "enabled",
"target_label": "fig:a3-dispatch"
},
{
"id": "A4",
"label": "APPLICATION",
"subtitle": "Eksperyment",
"status": "unavailable",
"reason": "Konkretny handoff jest kompletny w A5."
},
{
"id": "A5",
"label": "FLOW",
"subtitle": "E01E09: trigger do PASS",
"status": "enabled",
"target_label": "fig:a5-flow"
},
{
"id": "A6",
"label": "STATE",
"subtitle": "Semaphore empty/given/taken i task state",
"status": "enabled",
"target_label": "fig:a6-state"
},
{
"id": "A7",
"label": "RUNTIME",
"subtitle": "Waiter, stimulus i xISRStack",
"status": "enabled",
"target_label": "fig:a7-runtime"
},
{
"id": "A8",
"label": "PATTERNS",
"subtitle": "Wzorce",
"status": "unavailable",
"reason": "Deferred interrupt handoff jest tu mechanizmem wykonania A3/A5, nie osobnym wzorcem aplikacyjnym."
}
],
"debug_strategies": {
"code.irq-contract": {
"id": "code.irq-contract",
"kind": "code",
"action": "open",
"expected_observations": [
"external vector trafia do pełnego trap path",
"ISR API ma osobny suffix"
],
"assertions": [
"source clear poprzedza give",
"port ma 256-word ISR stack"
],
"evidence_fields": [
"code_ref",
"symbol",
"ABI"
],
"prerequisites": [
"źródło FC07"
],
"layout": [
"vector bridge",
"FreeRTOS trap",
"application ISR",
"config"
],
"commands": [
"rg -n 'isr_external_irq|application_interrupt|GiveFromISR|SET_IRQ' src include"
]
},
"run.trap": {
"id": "run.trap",
"kind": "run",
"action": "replay",
"expected_observations": [
"mcause=0x8000000b",
"ISR SP różny od task SP",
"source=0"
],
"assertions": [
"real MEI",
"full context saved"
],
"evidence_fields": [
"mcause",
"SP",
"PC",
"IRQ register",
"timestamp"
],
"prerequisites": [
"Hazard3 online",
"IRQ5 enabled",
"czysta RAM"
],
"layout": [
"mcause",
"mepc",
"xISRStack",
"source register"
],
"commands": [
"print/x g_fc07.mcause",
"print/x g_fc07.isr_sp",
"print g_fc07.irq_source_after_clear"
]
},
"run.handoff": {
"id": "run.handoff",
"kind": "run",
"action": "replay",
"expected_observations": [
"xHPW=pdTRUE",
"E07 poprzedza E08"
],
"assertions": [
"waiter value widzi stimulus_after=0",
"stimulus po resume widzi waiter_ran=1"
],
"evidence_fields": [
"state",
"actor",
"value",
"PC/SP"
],
"prerequisites": [
"waiter Blocked na binary semaphore"
],
"layout": [
"semaphore",
"xHPW",
"waiter/stimulus TCB",
"event order"
],
"commands": [
"print g_fc07.higher_priority_task_woken",
"print g_fc07_events"
]
},
"run.pass": {
"id": "run.pass",
"kind": "run",
"action": "replay",
"expected_observations": [
"PASS=1",
"nine sequential markers"
],
"assertions": [
"three distinct stack contexts",
"digest stable"
],
"evidence_fields": [
"PASS",
"digest",
"source blob",
"ELF hash",
"timestamp"
],
"prerequisites": [
"E01E08 committed"
],
"layout": [
"nine records",
"stack separation",
"digest"
],
"commands": [
"print g_fc07_pass",
"print g_fc07.digest"
]
}
},
"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": "Przerwanie zewnętrzne i semaphore FromISR",
"url": "https://dce7fb9d-7b2f-5d49-96a2-3a30d3070b84.mpabi.pl/a6da1075-8d1f-5615-b0e6-0fc33e59e1e3",
"repository_url": "https://zsl-gitea.mpabi.pl/edu-freertos-c/lab-rv32i-freertos-c-isr-semaphore",
"url_host_uuid": "dce7fb9d-7b2f-5d49-96a2-3a30d3070b84",
"url_domain": "mpabi.pl",
"doc_uuid": "a6da1075-8d1f-5615-b0e6-0fc33e59e1e3",
"revision": "v00.01",
"issued_on": "2026-07-19T00:00:00+02:00",
"series": "FREERTOS-C-07",
"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ń rozdziela task context od ISR context, używa API FromISR i dowodzi natychmiastowego przełączenia do wyższego taska.",
"scope_title": "Zakres karty",
"scope_content_tex": "Prawdziwe wejście IRQ5 testbencha wywołuje machine external interrupt. Port zapisuje pełny kontekst i przechodzi na xISRStack. ISR czyści źródło, daje binary semaphore i wywołuje portYIELD_FROM_ISR. Waiter priority 3 działa przed powrotem do stimulus priority 2.",
"scope_table": {
"headers": [
"Lekcja",
"Task",
"Najważniejsza idea",
"Priorytet",
"Status",
"Version"
],
"rows": [
{
"chapter": "FC07",
"task": "Task01",
"idea_tex": "Hazard3 MEI, xISRStack, xSemaphoreGiveFromISR i yield",
"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": {
"FC07.EN01": {
"bloom_level": "Analiza",
"label": "Model ISR handoff",
"text": "Uczeń rozdziela hardware source, trap port, xISRStack, FromISR API i task scheduling.",
"assessment_criteria": [
"FC07.KW01"
]
},
"FC07.EK01": {
"bloom_level": "Zastosowanie",
"label": "Replay realnego MEI",
"text": "Uczeń odtwarza E01E09 i wiąże mcause, source clear, xHPW, trzy SP oraz kolejność context restore.",
"assessment_criteria": [
"FC07.KW01"
]
}
},
"assessment_criteria": {
"FC07.KW01": {
"text": "PASS; mcause=MEI; source=0 przed give; xHPW=1; waiter E07 przed stimulus E08; trzy różne stosy; deterministyczny digest.",
"learning_effects": [
"FC07.EN01",
"FC07.EK01"
]
}
},
"educational_requirements": {
"FC07.WE01": {
"text": "Zaprojektowanie i zbadanie bezpiecznego handoff z prawdziwego przerwania do taska FreeRTOS.",
"label": "Hazard3 MEI, xISRStack, xSemaphoreGiveFromISR i yield",
"learning_effects": [
"FC07.EN01",
"FC07.EK01"
],
"learning_tree": {
"schema": "we-learning-tree.v1",
"policy": "Każda aktywna kotwica wskazuje kod lub checkpoint.",
"ogolne": [
{
"effect_ref": "FC07.EN01",
"display": "EN LOCAL RTOS.07",
"source": "LOCAL",
"official": "RTOS",
"local": "07",
"kind": "EN",
"tree_id": "FC07.WE01.OG.LOCAL.RTOS.07",
"text": "Uczeń rozdziela hardware source, trap port, xISRStack, FromISR API i task scheduling.",
"kw": [
{
"criterion_ref": "FC07.KW01",
"display": "KW LOCAL RTOS.07",
"source": "LOCAL",
"kind": "KW",
"official": "RTOS",
"local": "07",
"text": "Łączy kod, diagram i zweryfikowany dowód."
}
]
}
],
"zawodowe": [
{
"effect_ref": "FC07.EK01",
"display": "EK LOCAL RTOS.07",
"source": "LOCAL",
"official": "RTOS",
"local": "07",
"kind": "EK",
"tree_id": "FC07.WE01.TECH.LOCAL.RTOS.07",
"text": "Uczeń odtwarza E01E09 i wiąże mcause, source clear, xHPW, trzy SP oraz kolejność context restore.",
"kw": [
{
"criterion_ref": "FC07.KW01",
"display": "KW LOCAL RTOS.07",
"source": "LOCAL",
"kind": "KW",
"official": "RTOS",
"local": "07",
"text": "Łączy kod, diagram i zweryfikowany dowód."
}
]
}
]
}
}
},
"debug_checkpoints": {
"schema": "stem-debug-checkpoints.v1",
"semantics": "deterministic-replay",
"artifact": {
"source": "src/tasks/task01_isr_semaphore.c",
"source_git_blob": "be3f48ea00d0fa32f09c9124bad9e123105708d9",
"elf": "build/task01_isr_semaphore/prog.elf",
"hazard3_elf_sha256": "9dbe2d28af41000340e99e33d86890272544f807682e99eecc47f2b0f9e022e5",
"hazard3_image": "build/task01_isr_semaphore/prog.bin",
"hazard3_image_sha256": "ac9dca42435e9e3fc523a310d12f985212b95e3a70a9c89a61b646036d675754"
},
"targets": {
"hazard3-sim": {
"adapter": "hazard3-reset-load-replay.v1",
"baseline": "restart-backend",
"clean_ram": true
}
},
"items": {
"task01.config": {
"event_id": "E01",
"stop": {
"symbol": "fc07_checkpoint_committed",
"offset": 0,
"condition": "$a0 == 1"
},
"verify": {
"expressions": [
{
"expr": "g_fc07_event_count",
"equals": 1
},
{
"expr": "g_fc07.semaphore == 0",
"equals": 1
}
]
}
},
"task01.waiter-block": {
"event_id": "E02",
"stop": {
"symbol": "fc07_checkpoint_committed",
"offset": 0,
"condition": "$a0 == 2"
},
"verify": {
"expressions": [
{
"expr": "g_fc07.waiter_sp != 0",
"equals": 1
},
{
"expr": "g_fc07.waiter_ran",
"equals": 0
}
]
}
},
"task01.before-trigger": {
"event_id": "E03",
"stop": {
"symbol": "fc07_checkpoint_committed",
"offset": 0,
"condition": "$a0 == 3"
},
"verify": {
"expressions": [
{
"expr": "g_fc07.stimulus_sp != 0",
"equals": 1
},
{
"expr": "g_fc07.stimulus_after",
"equals": 0
}
]
}
},
"task01.isr-entry": {
"event_id": "E04",
"stop": {
"symbol": "fc07_checkpoint_committed",
"offset": 0,
"condition": "$a0 == 4"
},
"verify": {
"expressions": [
{
"expr": "g_fc07.mcause",
"equals": 2147483659
},
{
"expr": "g_fc07.isr_sp != g_fc07.stimulus_sp",
"equals": 1
}
]
}
},
"task01.source-clear": {
"event_id": "E05",
"stop": {
"symbol": "fc07_checkpoint_committed",
"offset": 0,
"condition": "$a0 == 5"
},
"verify": {
"expressions": [
{
"expr": "g_fc07.irq_source_after_clear",
"equals": 0
},
{
"expr": "g_fc07.waiter_ran",
"equals": 0
}
]
}
},
"task01.give-yield": {
"event_id": "E06",
"stop": {
"symbol": "fc07_checkpoint_committed",
"offset": 0,
"condition": "$a0 == 6"
},
"verify": {
"expressions": [
{
"expr": "g_fc07.higher_priority_task_woken",
"equals": 1
},
{
"expr": "g_fc07.stimulus_after",
"equals": 0
}
]
}
},
"task01.waiter-runs": {
"event_id": "E07",
"stop": {
"symbol": "fc07_checkpoint_committed",
"offset": 0,
"condition": "$a0 == 7"
},
"verify": {
"expressions": [
{
"expr": "g_fc07.waiter_ran",
"equals": 1
},
{
"expr": "g_fc07.stimulus_after",
"equals": 0
}
]
}
},
"task01.stimulus-resumes": {
"event_id": "E08",
"stop": {
"symbol": "fc07_checkpoint_committed",
"offset": 0,
"condition": "$a0 == 8"
},
"verify": {
"expressions": [
{
"expr": "g_fc07.waiter_ran",
"equals": 1
},
{
"expr": "g_fc07.stimulus_after",
"equals": 1
}
]
}
},
"task01.pass": {
"event_id": "E09",
"stop": {
"symbol": "fc07_checkpoint_committed",
"offset": 0,
"condition": "$a0 == 9"
},
"verify": {
"expressions": [
{
"expr": "g_fc07_pass",
"equals": 1
},
{
"expr": "g_fc07_event_count",
"equals": 9
},
{
"expr": "g_fc07_events[6].actor",
"equals": 2
}
]
}
}
}
},
"sections": [
{
"title": "A1 — Context",
"order": 10,
"content_kind": "prose",
"asset_page_mode": "one-per-page",
"page_orientation": "landscape",
"content_tex": "Źródło testbencha, kontroler Hazard3, port FreeRTOS, ISR aplikacji i waiter są osobnymi warstwami odpowiedzialności.",
"assets": [
{
"path": "assets/a1-context.png",
"html_path": "assets/a1-context.svg",
"source_path": "assets/a1-context.puml",
"caption": "A1 CONTEXT — IRQ5 do high-priority waitera.",
"label": "fig:a1-context",
"alt": "Warstwy realnego external IRQ.",
"kind": "diagram",
"width": 1.0,
"page_grid": {
"columns": 1,
"rows": 1,
"page_width": 940,
"page_height": 560,
"overview": true,
"step_tiles": {
"source": 1,
"hazard": 1,
"port": 1,
"isr": 1,
"waiter": 1
}
},
"interactive": {
"kind": "uml-class",
"storage_key": "fc07-a1-context",
"title": "A1 · granice interrupt path",
"task": {
"id": "task01",
"label": "Task01 · ISR semaphore"
},
"block": {
"id": "a1",
"label": "A1 CONTEXT",
"description": "Od fizycznej linii IRQ do odblokowanego taska."
},
"phases": [
{
"id": "context",
"label": "SOURCE / CPU / PORT / ISR / TASK",
"steps": [
{
"id": "source",
"number": 1,
"label": "testbench drives a real IRQ line",
"mode": "RUN",
"event_id": "E03",
"strategy_ref": "run.trap",
"svg_label": "01",
"code_ref": "src/tasks/task01_isr_semaphore.c:156",
"snapshot_ref": "task01.before-trigger",
"description": "MMIO store ustawia bit wejścia CPU.",
"evidence": "IRQ mask bit 5."
},
{
"id": "hazard",
"number": 2,
"label": "Hazard3 raises machine external interrupt",
"mode": "RUN",
"event_id": "E04",
"strategy_ref": "run.trap",
"svg_label": "02",
"code_ref": "src/tasks/task01_isr_semaphore.c:103",
"snapshot_ref": "task01.isr-entry",
"description": "To nie jest tick hook.",
"evidence": "mcause=MEI."
},
{
"id": "port",
"number": 3,
"label": "port saves full task context",
"mode": "CODE",
"strategy_ref": "code.irq-contract",
"svg_label": "03",
"code_ref": "src/common/hazard3_freertos_traps.S:24",
"description": "Vector skacze do official trap handler.",
"evidence": "xISRStack."
},
{
"id": "isr",
"number": 4,
"label": "application ISR clears and gives",
"mode": "RUN",
"event_id": "E06",
"strategy_ref": "run.handoff",
"svg_label": "04",
"code_ref": "src/tasks/task01_isr_semaphore.c:99",
"snapshot_ref": "task01.give-yield",
"description": "API FromISR ustawia xHPW.",
"evidence": "source=0, xHPW=1."
},
{
"id": "waiter",
"number": 5,
"label": "higher waiter consumes semaphore",
"mode": "RUN",
"event_id": "E07",
"strategy_ref": "run.handoff",
"svg_label": "05",
"code_ref": "src/tasks/task01_isr_semaphore.c:135",
"snapshot_ref": "task01.waiter-runs",
"description": "Context restore wybiera waiter TCB.",
"evidence": "stimulus_after=0."
}
]
}
]
}
}
]
},
{
"title": "A3 — Dispatch",
"order": 30,
"content_kind": "prose",
"asset_page_mode": "one-per-page",
"page_orientation": "landscape",
"content_tex": "Samo vTaskSwitchContext w zwykłym handlerze nie wystarcza. Port musi najpierw zapisać pełny kontekst przerwanego taska, przejść na ISR stack i dopiero potem odtworzyć kontekst wybranego taska.",
"assets": [
{
"path": "assets/a3-dispatch.png",
"html_path": "assets/a3-dispatch.svg",
"source_path": "assets/a3-dispatch.puml",
"caption": "A3 DISPATCH — vector, trap, FromISR i restore.",
"label": "fig:a3-dispatch",
"alt": "Dispatch external IRQ w porcie FreeRTOS.",
"kind": "diagram",
"width": 1.0,
"page_grid": {
"columns": 1,
"rows": 1,
"page_width": 940,
"page_height": 560,
"overview": true,
"step_tiles": {
"vector": 1,
"trap": 1,
"stack": 1,
"app": 1,
"give": 1,
"yield": 1,
"restore": 1
}
},
"interactive": {
"kind": "uml-class",
"storage_key": "fc07-a3-dispatch",
"title": "A3 · external interrupt dispatch",
"task": {
"id": "task01",
"label": "Task01 · ISR semaphore"
},
"block": {
"id": "a3",
"label": "A3 DISPATCH",
"description": "Pełny context save umożliwia yield z ISR."
},
"phases": [
{
"id": "dispatch",
"label": "VECTOR / SAVE / ISR / RESTORE",
"steps": [
{
"id": "vector",
"number": 1,
"label": "external vector enters port",
"mode": "CODE",
"strategy_ref": "code.irq-contract",
"svg_label": "01",
"code_ref": "src/common/hazard3_freertos_traps.S:24",
"description": "Strong symbol zastępuje weak handler testbencha.",
"evidence": "isr_external_irq."
},
{
"id": "trap",
"number": 2,
"label": "trap saves full context",
"mode": "RUN",
"event_id": "E04",
"strategy_ref": "run.trap",
"svg_label": "02",
"code_ref": "vendor/FreeRTOS-Kernel/portable/GCC/RISC-V/portASM.S:356",
"snapshot_ref": "task01.isr-entry",
"description": "Interrupted SP jest zapisany w TCB.",
"evidence": "mepc/mstatus/registers."
},
{
"id": "stack",
"number": 3,
"label": "handler runs on xISRStack",
"mode": "RUN",
"event_id": "E04",
"strategy_ref": "run.trap",
"svg_label": "03",
"code_ref": "src/tasks/task01_isr_semaphore.c:104",
"snapshot_ref": "task01.isr-entry",
"description": "ISR SP różni się od obu tasków.",
"evidence": "isr_sp."
},
{
"id": "app",
"number": 4,
"label": "application handler owns device protocol",
"mode": "RUN",
"event_id": "E05",
"strategy_ref": "run.trap",
"svg_label": "04",
"code_ref": "src/tasks/task01_isr_semaphore.c:107",
"snapshot_ref": "task01.source-clear",
"description": "Najpierw clear source.",
"evidence": "register=0."
},
{
"id": "give",
"number": 5,
"label": "FromISR unblocks waiter",
"mode": "RUN",
"event_id": "E06",
"strategy_ref": "run.handoff",
"svg_label": "05",
"code_ref": "src/tasks/task01_isr_semaphore.c:111",
"snapshot_ref": "task01.give-yield",
"description": "Binary semaphore staje się available.",
"evidence": "xHPW=1."
},
{
"id": "yield",
"number": 6,
"label": "yield selects waiter TCB",
"mode": "RUN",
"event_id": "E06",
"strategy_ref": "run.handoff",
"svg_label": "06",
"code_ref": "src/tasks/task01_isr_semaphore.c:118",
"snapshot_ref": "task01.give-yield",
"description": "Switch następuje przed mret.",
"evidence": "vTaskSwitchContext."
},
{
"id": "restore",
"number": 7,
"label": "port restores selected task",
"mode": "RUN",
"event_id": "E07",
"strategy_ref": "run.handoff",
"svg_label": "07",
"code_ref": "src/tasks/task01_isr_semaphore.c:135",
"snapshot_ref": "task01.waiter-runs",
"description": "CPU nie wraca od razu do stimulus.",
"evidence": "E07 before E08."
}
]
}
]
}
}
]
},
{
"title": "A5 — Flow",
"order": 40,
"content_kind": "prose",
"asset_page_mode": "one-per-page",
"page_orientation": "landscape",
"content_tex": "Sekwencja dowodzi source-clear-before-give oraz waiter-before-interrupted-task.",
"assets": [
{
"path": "assets/a5-flow.png",
"html_path": "assets/a5-flow.svg",
"source_path": "assets/a5-flow.puml",
"caption": "A5 FLOW — od Blocked przez ISR do natychmiastowego waitera.",
"label": "fig:a5-flow",
"alt": "Sekwencja ISR semaphore handoff.",
"kind": "diagram",
"width": 1.0,
"page_grid": {
"columns": 1,
"rows": 1,
"page_width": 940,
"page_height": 560,
"overview": true,
"step_tiles": {
"config": 1,
"wait": 1,
"trigger": 1,
"entry": 1,
"clear": 1,
"give": 1,
"waiter": 1,
"resume": 1,
"pass": 1
}
},
"interactive": {
"kind": "uml-sequence",
"storage_key": "fc07-a5-flow",
"title": "A5 · IRQ handoff replay",
"task": {
"id": "task01",
"label": "Task01 · ISR semaphore"
},
"block": {
"id": "a5",
"label": "A5 FLOW",
"description": "Jeden realny handoff E01E09."
},
"phases": [
{
"id": "flow",
"label": "TRIGGER / ISR / YIELD / PASS",
"steps": [
{
"id": "config",
"number": 1,
"label": "IRQ contract configured",
"mode": "RUN",
"event_id": "E01",
"strategy_ref": "run.trap",
"svg_label": "01",
"code_ref": "src/tasks/task01_isr_semaphore.c:238",
"snapshot_ref": "task01.config",
"description": "IRQ5 i priority są jawne.",
"evidence": "event count 1."
},
{
"id": "wait",
"number": 2,
"label": "waiter reaches empty take",
"mode": "RUN",
"event_id": "E02",
"strategy_ref": "run.handoff",
"svg_label": "02",
"code_ref": "src/tasks/task01_isr_semaphore.c:130",
"snapshot_ref": "task01.waiter-block",
"description": "Następnie przechodzi do Blocked.",
"evidence": "waiter_ran=0."
},
{
"id": "trigger",
"number": 3,
"label": "stimulus commits before trigger",
"mode": "RUN",
"event_id": "E03",
"strategy_ref": "run.trap",
"svg_label": "03",
"code_ref": "src/tasks/task01_isr_semaphore.c:155",
"snapshot_ref": "task01.before-trigger",
"description": "Kontrolowany punkt przed MMIO.",
"evidence": "stimulus_after=0."
},
{
"id": "entry",
"number": 4,
"label": "MEI enters xISRStack",
"mode": "RUN",
"event_id": "E04",
"strategy_ref": "run.trap",
"svg_label": "04",
"code_ref": "src/tasks/task01_isr_semaphore.c:103",
"snapshot_ref": "task01.isr-entry",
"description": "Prawdziwy async trap.",
"evidence": "mcause and SP."
},
{
"id": "clear",
"number": 5,
"label": "ISR clears hardware source",
"mode": "RUN",
"event_id": "E05",
"strategy_ref": "run.trap",
"svg_label": "05",
"code_ref": "src/tasks/task01_isr_semaphore.c:107",
"snapshot_ref": "task01.source-clear",
"description": "Zapobiega retrigger.",
"evidence": "source=0."
},
{
"id": "give",
"number": 6,
"label": "give requests a switch",
"mode": "RUN",
"event_id": "E06",
"strategy_ref": "run.handoff",
"svg_label": "06",
"code_ref": "src/tasks/task01_isr_semaphore.c:111",
"snapshot_ref": "task01.give-yield",
"description": "Wyższy task stał się Ready.",
"evidence": "xHPW=pdTRUE."
},
{
"id": "waiter",
"number": 7,
"label": "waiter runs before stimulus",
"mode": "RUN",
"event_id": "E07",
"strategy_ref": "run.handoff",
"svg_label": "07",
"code_ref": "src/tasks/task01_isr_semaphore.c:135",
"snapshot_ref": "task01.waiter-runs",
"description": "Natychmiastowy efekt yield.",
"evidence": "stimulus_after=0."
},
{
"id": "resume",
"number": 8,
"label": "interrupted stimulus resumes",
"mode": "RUN",
"event_id": "E08",
"strategy_ref": "run.handoff",
"svg_label": "08",
"code_ref": "src/tasks/task01_isr_semaphore.c:158",
"snapshot_ref": "task01.stimulus-resumes",
"description": "Dopiero po zakończeniu waitera.",
"evidence": "waiter_ran=1."
},
{
"id": "pass",
"number": 9,
"label": "verifier commits PASS",
"mode": "RUN",
"event_id": "E09",
"strategy_ref": "run.pass",
"svg_label": "09",
"code_ref": "src/tasks/task01_isr_semaphore.c:186",
"snapshot_ref": "task01.pass",
"description": "Sprawdza order, stacks i cause.",
"evidence": "PASS=1, digest."
}
]
}
]
}
}
]
},
{
"title": "A6 — State",
"order": 50,
"content_kind": "prose",
"asset_page_mode": "one-per-page",
"page_orientation": "portrait",
"content_tex": "GiveFromISR zmienia obiekt synchronizacyjny i stan waitera, lecz natychmiastowe wykonanie wymaga dodatkowego yield request.",
"assets": [
{
"path": "assets/a6-state.png",
"html_path": "assets/a6-state.svg",
"source_path": "assets/a6-state.puml",
"caption": "A6 STATE — empty, given, switch i taken.",
"label": "fig:a6-state",
"alt": "Maszyna stanu semaphore handoff.",
"kind": "diagram",
"width": 1.0,
"page_grid": {
"columns": 1,
"rows": 1,
"page_width": 660,
"page_height": 760,
"overview": true,
"step_tiles": {
"empty": 1,
"pending": 1,
"given": 1,
"switch": 1,
"taken": 1,
"resumed": 1
}
},
"interactive": {
"kind": "uml-class",
"storage_key": "fc07-a6-state",
"title": "A6 · ISR handoff state",
"task": {
"id": "task01",
"label": "Task01 · ISR semaphore"
},
"block": {
"id": "a6",
"label": "A6 STATE",
"description": "Semaphore state i scheduler decision."
},
"phases": [
{
"id": "state",
"label": "SEMAPHORE / TASK / SWITCH",
"steps": [
{
"id": "empty",
"number": 1,
"label": "empty semaphore blocks waiter",
"mode": "RUN",
"event_id": "E02",
"strategy_ref": "run.handoff",
"svg_label": "01",
"code_ref": "src/tasks/task01_isr_semaphore.c:131",
"snapshot_ref": "task01.waiter-block",
"description": "Waiter trafia na wait list.",
"evidence": "Blocked."
},
{
"id": "pending",
"number": 2,
"label": "IRQ interrupts stimulus",
"mode": "RUN",
"event_id": "E04",
"strategy_ref": "run.trap",
"svg_label": "02",
"code_ref": "src/tasks/task01_isr_semaphore.c:99",
"snapshot_ref": "task01.isr-entry",
"description": "Stimulus context jest zachowany.",
"evidence": "mepc and SP."
},
{
"id": "given",
"number": 3,
"label": "give makes waiter Ready",
"mode": "RUN",
"event_id": "E06",
"strategy_ref": "run.handoff",
"svg_label": "03",
"code_ref": "src/tasks/task01_isr_semaphore.c:111",
"snapshot_ref": "task01.give-yield",
"description": "Semaphore nie pozostaje full.",
"evidence": "xHPW=true."
},
{
"id": "switch",
"number": 4,
"label": "yield requests context switch",
"mode": "RUN",
"event_id": "E06",
"strategy_ref": "run.handoff",
"svg_label": "04",
"code_ref": "src/tasks/task01_isr_semaphore.c:118",
"snapshot_ref": "task01.give-yield",
"description": "pxCurrentTCB wybiera waitera.",
"evidence": "vTaskSwitchContext."
},
{
"id": "taken",
"number": 5,
"label": "waiter consumes token",
"mode": "RUN",
"event_id": "E07",
"strategy_ref": "run.handoff",
"svg_label": "05",
"code_ref": "src/tasks/task01_isr_semaphore.c:131",
"snapshot_ref": "task01.waiter-runs",
"description": "Take wraca pdPASS.",
"evidence": "waiter Running."
},
{
"id": "resumed",
"number": 6,
"label": "stimulus eventually resumes",
"mode": "RUN",
"event_id": "E08",
"strategy_ref": "run.handoff",
"svg_label": "06",
"code_ref": "src/tasks/task01_isr_semaphore.c:158",
"snapshot_ref": "task01.stimulus-resumes",
"description": "Oryginalny mepc nie ginie.",
"evidence": "E08 after E07."
}
]
}
]
}
}
]
},
{
"title": "A7 — Runtime",
"order": 60,
"content_kind": "prose",
"asset_page_mode": "one-per-page",
"page_orientation": "portrait",
"content_tex": "ISR stack nie należy do żadnego taska. Port zapisuje interrupted task stack, wykonuje ISR na xISRStack i odtwarza stack wybranego waitera.",
"assets": [
{
"path": "assets/a7-runtime.png",
"html_path": "assets/a7-runtime.svg",
"source_path": "assets/a7-runtime.puml",
"caption": "A7 RUNTIME — stimulus TCB, xISRStack i waiter TCB.",
"label": "fig:a7-runtime",
"alt": "Runtime trzech kontekstów stosu.",
"kind": "diagram",
"width": 1.0,
"page_grid": {
"columns": 1,
"rows": 1,
"page_width": 660,
"page_height": 760,
"overview": true,
"step_tiles": {
"waiter": 1,
"stimulus": 1,
"isr": 1,
"sem": 1,
"evidence": 1
}
},
"interactive": {
"kind": "uml-class",
"storage_key": "fc07-a7-runtime",
"title": "A7 · stack and context evidence",
"task": {
"id": "task01",
"label": "Task01 · ISR semaphore"
},
"block": {
"id": "a7",
"label": "A7 RUNTIME",
"description": "Trzy stosy i dwa TCB w jednym trap replay."
},
"phases": [
{
"id": "runtime",
"label": "TCB / ISR STACK / RESTORE",
"steps": [
{
"id": "waiter",
"number": 1,
"label": "waiter owns priority-3 stack",
"mode": "RUN",
"event_id": "E02",
"strategy_ref": "run.handoff",
"svg_label": "01",
"code_ref": "src/tasks/task01_isr_semaphore.c:129",
"snapshot_ref": "task01.waiter-block",
"description": "SP zapisany przed take.",
"evidence": "waiter_sp."
},
{
"id": "stimulus",
"number": 2,
"label": "stimulus owns interrupted stack",
"mode": "RUN",
"event_id": "E03",
"strategy_ref": "run.trap",
"svg_label": "02",
"code_ref": "src/tasks/task01_isr_semaphore.c:153",
"snapshot_ref": "task01.before-trigger",
"description": "Priority 2.",
"evidence": "stimulus_sp."
},
{
"id": "isr",
"number": 3,
"label": "trap switches to xISRStack",
"mode": "RUN",
"event_id": "E04",
"strategy_ref": "run.trap",
"svg_label": "03",
"code_ref": "src/tasks/task01_isr_semaphore.c:104",
"snapshot_ref": "task01.isr-entry",
"description": "ISR nie zużywa task stack.",
"evidence": "isr_sp distinct."
},
{
"id": "sem",
"number": 4,
"label": "semaphore links ISR and waiter",
"mode": "RUN",
"event_id": "E06",
"strategy_ref": "run.handoff",
"svg_label": "04",
"code_ref": "src/tasks/task01_isr_semaphore.c:111",
"snapshot_ref": "task01.give-yield",
"description": "Only FromISR API in ISR.",
"evidence": "xHPW."
},
{
"id": "evidence",
"number": 5,
"label": "event order proves selected return",
"mode": "RUN",
"event_id": "E09",
"strategy_ref": "run.pass",
"svg_label": "05",
"code_ref": "src/tasks/task01_isr_semaphore.c:195",
"snapshot_ref": "task01.pass",
"description": "E07 waiter, E08 stimulus.",
"evidence": "nine committed records."
}
]
}
]
}
}
]
},
{
"title": "Task01 — ISR semaphore",
"order": 90,
"content_kind": "tasks",
"task_refs": [
"task01"
]
}
],
"tasks": {
"task01": {
"title": "External IRQ → FromISR semaphore → high-priority task",
"uuid": "a6da1075-8d1f-5615-b0e6-0fc33e59e1e3",
"prompt_tex": "Przejdź po A1, A3, A5, A6 i A7. Odtwórz E01E09 i udowodnij source-clear-before-give oraz waiter-before-stimulus.",
"criterion": "PASS; mcause=MEI; source=0 przed give; xHPW=1; waiter E07 przed stimulus E08; trzy różne stosy; deterministyczny digest.",
"conclusion_tex": "ISR działa na osobnym stacku i używa FromISR API. xHigherPriorityTaskWoken jest informacją dla portu; dopiero portYIELD_FROM_ISR powoduje restore kontekstu wyższego taska przed powrotem do przerwanego kodu.",
"flow": [
{
"kind": "block",
"id": "contract",
"title": "A — kontrakt przerwania",
"content_tex": "Rozdziel source, vector, port, ISR i task.",
"steps": [
{
"id": "order",
"title": "Ustal kolejność ISR.",
"content_tex": "Najpierw clear, potem give, na końcu yield."
},
{
"id": "predict",
"title": "Przewidź context restore.",
"content_tex": "Wskaż, czy pierwszy wykona się waiter czy stimulus."
}
]
},
{
"kind": "block",
"id": "replay",
"title": "B — replay Hazard3",
"content_tex": "Każdy RUN zaczyna się od czystej RAM i wyłączonego źródła.",
"steps": [
{
"id": "trap",
"title": "Zbadaj E03E05.",
"content_tex": "Zapisz mcause, mepc, isr_sp i source state."
},
{
"id": "handoff",
"title": "Zbadaj E06E08.",
"content_tex": "Porównaj xHPW i kolejność tasków."
},
{
"id": "pass",
"title": "Zbadaj E09.",
"content_tex": "Sprawdź trzy stosy, markers i digest."
}
]
},
{
"kind": "exercise",
"id": "no-yield",
"title": "Ćwiczenie — brak yield request",
"prompt_tex": "W kontrolowanym wariancie pomiń portYIELD_FROM_ISR, zachowując GiveFromISR. Zmierz, kiedy waiter zacznie działać i wskaż następny legalny scheduling point.",
"evidence_tex": "Dwa timestampowane ślady E07/E08 z yield i bez yield oraz opis różnicy.",
"criterion": "Uczeń nie myli odblokowania taska z natychmiastowym wykonaniem i przywraca poprawny yield w wersji finalnej.",
"based_on": [
"contract",
"replay"
]
}
],
"educational_requirement_refs": [
"FC07.WE01"
],
"learning_effect_refs": [
"FC07.EN01",
"FC07.EK01"
],
"assessment_criterion_ref": "FC07.KW01"
}
},
"tasks_order": [
"task01"
]
}