1366 lines
45 KiB
JSON
1366 lines
45 KiB
JSON
{
|
||
"$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": "E01–E09: 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": [
|
||
"E01–E08 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 E01–E09 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 E01–E09 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 E01–E09."
|
||
},
|
||
"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 E01–E09 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 E03–E05.",
|
||
"content_tex": "Zapisz mcause, mepc, isr_sp i source state."
|
||
},
|
||
{
|
||
"id": "handoff",
|
||
"title": "Zbadaj E06–E08.",
|
||
"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"
|
||
]
|
||
}
|