Files

395 lines
43 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-02-first-task",
"series": "freertos-c",
"series_title": "FreeRTOS C",
"number": "02",
"count": "15",
"slug": "first-task-tcb-stack",
"title": "Pierwszy task, TCB i stos taska",
"topic": "TaskFunction_t, void* context, TaskHandle_t i time slicing",
"project": "Freestanding C nad FreeRTOS",
"subject": "Informatyka",
"level": "Rok 2 · L02 · RV32I/Hazard3",
"revision_date": "2026-07-18T00:00:00+02:00",
"status": "Gotowa",
"version": "v00.01",
"uuid": "9ad444ee-ff3c-42c3-a108-80ed9ddb914d",
"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": "Aplikacja C → FreeRTOS → Hazard3", "status": "enabled", "target_label": "fig:a1-context"},
{"id": "A2", "label": "STRUCTURE", "subtitle": "Konteksty, uchwyty, funkcje i domeny pamięci", "status": "enabled", "target_label": "fig:a2-structure"},
{"id": "A3", "label": "DISPATCH", "subtitle": "TaskFunction_t + void* → WorkerContext*", "status": "enabled", "target_label": "fig:a3-dispatch"},
{"id": "A4", "label": "APPLICATION", "subtitle": "Topologia aplikacji", "status": "unavailable", "reason": "Topologia i inwarianty surowego modułu C są już kompletne w A2 i A5; osobny A4 dublowałby treść."},
{"id": "A5", "label": "FLOW", "subtitle": "Deterministyczny przebieg E01E12", "status": "enabled", "target_label": "fig:a5-flow-a"},
{"id": "A6", "label": "STATE", "subtitle": "Stan diagnostyczny kontekstu a stan kernela", "status": "enabled", "target_label": "fig:a6-state"},
{"id": "A7", "label": "RUNTIME", "subtitle": "Context, handle, TCB, stos, rejestry i tick", "status": "enabled", "target_label": "fig:a7-runtime"},
{"id": "A8", "label": "PATTERNS", "subtitle": "Wzorce projektowe", "status": "unavailable", "reason": "Context object, opaque handle i callback ABI są opisane dokładnie w A2/A3; osobny diagram wzorców byłby dekoracyjny."}
],
"debug_strategies": {
"code.context": {
"id": "code.context", "kind": "code", "action": "open",
"prerequisites": ["repozytorium FC02", "zweryfikowany source blob"],
"layout": ["read-only source", "granica architektoniczna"],
"commands": ["rg -n 'xTaskCreate|vTaskStartScheduler|TaskFunction_t' include src"],
"expected_observations": ["aplikacja korzysta z publicznego C API", "kernel i port pozostają oddzielnymi warstwami"],
"assertions": ["brak zależności aplikacji od pxCurrentTCB", "target to RV32I/Hazard3"],
"evidence_fields": ["code_ref", "source_git_blob", "zaznaczona relacja UML"]
},
"code.structure": {
"id": "code.structure", "kind": "code", "action": "open",
"prerequisites": ["freestanding C11", "include/task01_first_task.h"],
"layout": ["source", "diagram danych", "mapa pamięci"],
"commands": ["make check-contracts", "riscv64-unknown-elf-nm build/contracts/context_contract.o"],
"expected_observations": ["WorkerContext nie ma ukrytego modelu obiektowego", "C akceptuje zły cast void* w fixture compile-only"],
"assertions": ["&handle, wartość handle i TCB są odrębnymi pojęciami", "kontekst ma static lifetime"],
"evidence_fields": ["source blob", "layout pól", "wynik check-contracts"]
},
"code.abi": {
"id": "code.abi", "kind": "code", "action": "open",
"prerequisites": ["zbudowany prog.elf"],
"layout": ["sygnatura C", "nm/readelf", "listing RV32I"],
"commands": ["make check-abi", "riscv64-unknown-elf-objdump -d build/task01_first_task/prog.elf"],
"expected_observations": ["TaskFunction_t ma sygnaturę void (*)(void*)", "brak manglingu i runtime C++"],
"assertions": ["sum_task_entry jest symbolem C", "jawny cast nie wykonuje kontroli typu"],
"evidence_fields": ["ELF hash", "symbol", "instrukcja wejścia"]
},
"run.create": {
"id": "run.create", "kind": "run", "action": "replay",
"prerequisites": ["Hazard3 online", "czysta RAM", "aktualny ELF"],
"layout": ["source", "argumenty ABI", "context", "heap_4"],
"commands": ["info registers a0 a1 a2 a3 a4 a5 sp", "print g_worker_a", "print &g_worker_a.handle"],
"expected_observations": ["xTaskCreate otrzymuje entry i &workerA", "handle otrzymuje opaque TCB pointer"],
"assertions": ["E03 zatrzymuje się na xTaskCreate+0", "E04 ma handle != NULL"],
"evidence_fields": ["event_id", "context address", "field address", "handle value", "timestamp"]
},
"run.dispatch": {
"id": "run.dispatch", "kind": "run", "action": "replay",
"prerequisites": ["scheduler uruchomiony", "workerA READY"],
"layout": ["sum_task_entry source", "assembly", "a0", "task stack"],
"commands": ["info registers a0 sp pc", "x/i $pc", "print &g_worker_a", "bt"],
"expected_observations": ["na sum_task_entry+0 a0 == &g_worker_a", "SP należy do osobnego stosu taska"],
"assertions": ["typed pointer zachowuje ten sam adres", "cast nie tworzy drugiego dispatchu"],
"evidence_fields": ["pvParameters", "WorkerContext*", "SP", "PC", "instruction"]
},
"run.scheduler": {
"id": "run.scheduler", "kind": "run", "action": "replay",
"prerequisites": ["dwa workery priority=2", "time slicing włączony"],
"layout": ["source loop", "tick", "A/B/A evidence", "PC"],
"commands": ["print g_aba_task", "print g_aba_tick", "print g_observed_worker_changes"],
"expected_observations": ["bufor zawiera podciąg A → B → A", "ticki są niemalejące"],
"assertions": ["worker changes >= 2", "E08 emituje worker A dopiero po wykryciu podciągu"],
"evidence_fields": ["triplet", "ticks", "change count", "timestamp"]
},
"run.state": {
"id": "run.state", "kind": "run", "action": "replay",
"prerequisites": ["kanoniczny checkpoint"],
"layout": ["WorkerContext", "public kernel state", "source"],
"commands": ["print g_worker_a.trace_state", "print g_worker_a.handle", "info registers sp pc"],
"expected_observations": ["trace_state nie jest eTaskState", "COMPLETED poprzedza self-delete"],
"assertions": ["static context przeżywa usunięcie taska", "E11 jest stopem przed vTaskDelete"],
"evidence_fields": ["trace state", "kernel state", "event_id", "PC"]
},
"run.runtime": {
"id": "run.runtime", "kind": "run", "action": "replay",
"prerequisites": ["Hazard3/GDB online", "symbole ELF"],
"layout": ["context", "handle/TCB", "stack", "registers", "listing"],
"commands": ["print &g_worker_a", "print &g_worker_a.handle", "print g_worker_a.created_handle", "print g_worker_a.tcb_address", "print g_worker_a.stack_low", "print g_worker_a.stack_high", "info registers a0 sp pc"],
"expected_observations": ["context, TCB i stack są trzema obszarami", "SP mieści się w stack range"],
"assertions": ["created_handle == tcb_address", "zapisane adresy po delete są forensic i nie są dereferencjonowane"],
"evidence_fields": ["context", "field address", "handle/TCB", "stack range", "SP", "PC"]
},
"run.pass": {
"id": "run.pass", "kind": "run", "action": "replay",
"prerequisites": ["oba workery zakończone", "supervisor uruchomiony"],
"layout": ["contexts", "trace", "assertions"],
"commands": ["print g_worker_a", "print g_worker_b", "print g_aba_task", "print g_task01_pass"],
"expected_observations": ["oba wyniki = 200010000", "oba workery wykonały 20000 iteracji"],
"assertions": ["PASS = 1", "elapsed ticks >= 2", "A/B/A zapisane"],
"evidence_fields": ["results", "iterations", "PASS", "ticks", "trace", "timestamp"]
}
},
"template": "templates/karta-klasyczna.json",
"title_block": {
"category": "KARTA PRACY · INFORMATYKA",
"prepared_by": "M. Pabiszczak",
"prepared_on": "2026-07-18T00:00:00+02:00",
"title": "Pierwszy task, TCB i stos taska",
"url": "https://dce7fb9d-7b2f-5d49-96a2-3a30d3070b84.mpabi.pl/a2538a1a-3c37-4c14-a6ea-db5aba8fd038",
"repository_url": "https://zsl-gitea.mpabi.pl/edu-freertos-c/lab-rv32i-freertos-c-first-task",
"url_host_uuid": "dce7fb9d-7b2f-5d49-96a2-3a30d3070b84",
"url_domain": "mpabi.pl",
"doc_uuid": "a2538a1a-3c37-4c14-a6ea-db5aba8fd038",
"revision": "v00.01",
"issued_on": "2026-07-18T00:00:00+02:00",
"series": "FREERTOS-C-02",
"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ń tworzy task przez surowe API C FreeRTOS, śledzi \\texttt{pvParameters} od \\texttt{xTaskCreate} do typowanego \\texttt{WorkerContext} i odróżnia kontekst aplikacji od TCB oraz stosu taska. Każdy punkt wykonania odtwarza deterministycznie w Hazard3/GDB.",
"scope_title": "Zakres karty",
"scope_content_tex": "Dwa workery o równym priorytecie liczą sumę \\texttt{1..20000}; niżej priorytetowy supervisor sprawdza wyniki, ticki, podciąg \\texttt{A->B->A}, TCB i zakresy stosów. Poza zakresem są C++, kolejki, mutexy, ISR, timery i peryferia.",
"scope_table": {
"headers": ["Lekcja", "Task", "Najważniejsza idea", "Priorytet", "Status", "Version"],
"rows": [{"chapter": "FC02", "task": "Task01", "idea_tex": "Raw C task, typed context, TCB i stack", "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 C i pamięci."}
]
},
"learning_effects": {
"FC02.EN01": {"bloom_level": "Analiza", "label": "Model C taska", "text": "Uczeń odróżnia kontekst aplikacji, opaque handle, TCB i osobny stos taska.", "assessment_criteria": ["FC02.KW01"]},
"FC02.EK01": {"bloom_level": "Zastosowanie", "label": "Replay callbacku i schedulera", "text": "Uczeń odtwarza E01E12 i wiąże kod C z rejestrami, pamięcią oraz tickiem.", "assessment_criteria": ["FC02.KW01"]}
},
"assessment_criteria": {
"FC02.KW01": {"text": "Program kończy się PASS; oba wyniki wynoszą 200010000; callback-entry ma a0=&workerA; ślad zawiera A-B-A; context, TCB i stack są rozdzielone.", "learning_effects": ["FC02.EN01", "FC02.EK01"]}
},
"educational_requirements": {
"FC02.WE01": {
"text": "Zaprojektowanie i zbadanie pierwszego taska FreeRTOS przez surowe API C.",
"label": "Raw C FreeRTOS task",
"learning_effects": ["FC02.EN01", "FC02.EK01"],
"learning_tree": {
"schema": "we-learning-tree.v1",
"policy": "Każda kotwica UML ma wskazywać kod lub zweryfikowany checkpoint.",
"ogolne": [{"effect_ref": "FC02.EN01", "display": "EN LOCAL C.01", "source": "LOCAL", "official": "C", "local": "01", "kind": "EN", "tree_id": "FC02.WE01.OG.LOCAL.C.01", "text": "Czyta jawny model danych C.", "kw": [{"criterion_ref": "FC02.KW01", "display": "KW LOCAL C.01", "source": "LOCAL", "kind": "KW", "official": "C", "local": "01", "text": "Rozróżnia adres pola, handle, TCB i stack."}]}],
"zawodowe": [{"effect_ref": "FC02.EK01", "display": "EK LOCAL RTOS.01", "source": "LOCAL", "official": "RTOS", "local": "01", "kind": "EK", "tree_id": "FC02.WE01.TECH.LOCAL.RTOS.01", "text": "Odtwarza task w Hazard3/GDB.", "kw": [{"criterion_ref": "FC02.KW01", "display": "KW LOCAL RTOS.01", "source": "LOCAL", "kind": "KW", "official": "RTOS", "local": "01", "text": "Łączy checkpoint z UML i stanem CPU."}]}]
}
}
},
"debug_checkpoints": {
"schema": "stem-debug-checkpoints.v1",
"semantics": "deterministic-replay",
"artifact": {
"source": "src/tasks/task01_first_task.c",
"source_git_blob": "af1a98f7e0c2faaa4f7f25c0f42dd7aba723fae6",
"elf": "build/task01_first_task/prog.elf",
"hazard3_image": "build/task01_first_task/prog.bin",
"hazard3_image_sha256": "9cc1295d111ba910077f64800905f9256d22dea97bfcfb40023444806a11ff1c"
},
"targets": {"hazard3-sim": {"adapter": "hazard3-reset-load-replay.v1", "baseline": "restart-backend", "clean_ram": true}},
"items": {
"task01.contexts": {"event_id": "E01", "stop": {"symbol": "task01_debug_checkpoint_committed", "offset": 0, "condition": "$a0 == 1 && $a1 == &g_worker_a"}, "verify": {"expressions": [{"expr": "g_last_checkpoint", "equals": 1}, {"expr": "g_worker_a.trace_state", "equals": 0}, {"expr": "g_worker_a.handle == 0", "equals": 1}]}},
"task01.create-request": {"event_id": "E02", "stop": {"symbol": "task01_debug_checkpoint_committed", "offset": 0, "condition": "$a0 == 2 && $a1 == &g_worker_a && g_last_checkpoint == 2"}, "verify": {"expressions": [{"expr": "g_worker_a.trace_state", "equals": 0}]}},
"task01.create-call": {"event_id": "E03", "stop": {"symbol": "xTaskCreate", "offset": 0, "condition": "$a0 == sum_task_entry && $a3 == &g_worker_a && $a5 == &g_worker_a.handle"}, "verify": {"expressions": [{"expr": "g_last_checkpoint", "equals": 3}, {"expr": "g_worker_a.trace_state", "equals": 1}]}},
"task01.ready": {"event_id": "E04", "stop": {"symbol": "task01_debug_checkpoint_committed", "offset": 0, "condition": "$a0 == 4 && $a1 == &g_worker_a"}, "verify": {"expressions": [{"expr": "g_worker_a.trace_state", "equals": 2}, {"expr": "g_worker_a.handle != 0", "equals": 1}, {"expr": "g_worker_a.created_handle == g_worker_a.handle", "equals": 1}]}},
"task01.scheduler": {"event_id": "E05", "stop": {"symbol": "task01_debug_checkpoint_committed", "offset": 0, "condition": "$a0 == 5 && $a1 == &g_worker_a"}, "verify": {"expressions": [{"expr": "g_worker_a.handle != 0", "equals": 1}, {"expr": "g_worker_b.handle != 0", "equals": 1}, {"expr": "g_supervisor.handle != 0", "equals": 1}]}},
"task01.entry": {"event_id": "E06", "stop": {"symbol": "sum_task_entry", "offset": 0, "condition": "$a0 == &g_worker_a"}, "verify": {"expressions": [{"expr": "g_worker_a.trace_state", "equals": 2}, {"expr": "g_worker_a.created_handle != 0", "equals": 1}]}},
"task01.work": {"event_id": "E07", "stop": {"symbol": "task01_debug_checkpoint_committed", "offset": 0, "condition": "$a0 == 7 && $a1 == &g_worker_a"}, "verify": {"expressions": [{"expr": "g_worker_a.trace_state", "equals": 3}, {"expr": "g_worker_a.tcb_address == g_worker_a.created_handle", "equals": 1}, {"expr": "g_worker_a.entry_sp >= g_worker_a.stack_low && g_worker_a.entry_sp <= g_worker_a.stack_high", "equals": 1}]}},
"task01.timeslice": {"event_id": "E08", "stop": {"symbol": "task01_debug_checkpoint_committed", "offset": 0, "condition": "$a0 == 8 && $a1 == &g_worker_a"}, "verify": {"expressions": [{"expr": "g_timeslice_checkpoint_seen", "equals": 1}, {"expr": "g_aba_task[0]", "equals": 0}, {"expr": "g_aba_task[1]", "equals": 1}, {"expr": "g_aba_task[2]", "equals": 0}, {"expr": "g_observed_worker_changes >= 2", "equals": 1}]}},
"task01.result": {"event_id": "E09", "stop": {"symbol": "task01_debug_checkpoint_committed", "offset": 0, "condition": "$a0 == 9 && $a1 == &g_worker_a"}, "verify": {"expressions": [{"expr": "g_worker_a.result", "equals": 200010000}, {"expr": "g_worker_a.iterations", "equals": 20000}]}},
"task01.completed": {"event_id": "E10", "stop": {"symbol": "task01_debug_checkpoint_committed", "offset": 0, "condition": "$a0 == 10 && $a1 == &g_worker_a"}, "verify": {"expressions": [{"expr": "g_worker_a.trace_state", "equals": 4}, {"expr": "g_worker_a.handle == 0", "equals": 1}, {"expr": "g_worker_a.created_handle != 0", "equals": 1}]}},
"task01.delete": {"event_id": "E11", "stop": {"symbol": "task01_debug_checkpoint_committed", "offset": 0, "condition": "$a0 == 11 && $a1 == &g_worker_a"}, "verify": {"expressions": [{"expr": "g_worker_a.trace_state", "equals": 4}, {"expr": "g_worker_a.result", "equals": 200010000}]}},
"task01.pass": {"event_id": "E12", "stop": {"symbol": "task01_debug_checkpoint_committed", "offset": 0, "condition": "$a0 == 12 && $a1 == &g_supervisor"}, "verify": {"expressions": [{"expr": "g_task01_pass", "equals": 1}, {"expr": "g_worker_a.result", "equals": 200010000}, {"expr": "g_worker_b.result", "equals": 200010000}, {"expr": "g_worker_a.iterations", "equals": 20000}, {"expr": "g_worker_b.iterations", "equals": 20000}, {"expr": "g_elapsed_ticks >= 2", "equals": 1}, {"expr": "g_observed_worker_changes >= 2", "equals": 1}, {"expr": "g_aba_seen", "equals": 1}]}}
}
},
"sections": [
{
"title": "A1 — Context", "order": 10, "content_kind": "prose", "asset_page_mode": "one-per-page",
"content_tex": "Granice odpowiedzialności: aplikacja C, publiczne API FreeRTOS, kernel/port i Hazard3.",
"assets": [{
"path": "assets/a1-context.png", "html_path": "assets/a1-context.svg", "source_path": "assets/a1-context.puml",
"caption": "A1 CONTEXT — od modułu aplikacji C do wykonania na Hazard3.", "label": "fig:a1-context", "alt": "Granice aplikacji C, FreeRTOS C API, kernela, portu i Hazard3.", "kind": "diagram", "width": 1.0,
"page_grid": {"columns": 1, "rows": 1, "page_width": 660, "page_height": 760, "overview": true, "step_tiles": {"application": 1, "api": 1, "runtime": 1}},
"interactive": {
"kind": "uml-class", "storage_key": "fc02-a1-context", "title": "A1 · granice systemu",
"task": {"id": "task01", "label": "Task01 · raw C task"},
"block": {"id": "a1-context", "label": "A1 CONTEXT", "description": "Kierunek odpowiedzialności bez udawania runtime."},
"phases": [{"id": "system-boundary", "label": "BOUNDARIES", "steps": [
{"id": "application", "number": 1, "label": "application module requests tasks", "mode": "CODE", "strategy_ref": "code.context", "svg_label": "01", "svg_target": "Application", "code_ref": "src/tasks/task01_first_task.c:308", "description": "main przygotowuje konteksty i żąda utworzenia tasków.", "evidence": "Moduł zna wyłącznie publiczne nagłówki FreeRTOS."},
{"id": "api", "number": 2, "label": "FreeRTOS C API owns scheduling", "mode": "CODE", "strategy_ref": "code.context", "svg_label": "02", "svg_target": "CAPI", "code_ref": "vendor/FreeRTOS-Kernel/include/task.h:1", "description": "TaskFunction_t i xTaskCreate definiują granicę C.", "evidence": "Aplikacja nie używa pxCurrentTCB."},
{"id": "runtime", "number": 3, "label": "kernel/port execute on Hazard3", "mode": "CODE", "strategy_ref": "code.context", "svg_label": "03", "svg_target": "Runtime", "code_ref": "include/FreeRTOSConfig.h:1", "description": "Scheduler, tick, heap_4 i port RV32I wykonują taski.", "evidence": "Konfiguracja włącza preemption, time slicing i dynamic allocation."}
]}]
}
}]
},
{
"title": "A2 — Structure", "order": 20, "content_kind": "prose", "asset_page_mode": "one-per-page", "page_orientation": "landscape",
"content_tex": "Jawny model danych C oraz rozdział static context, opaque handle, TCB i task stack.",
"assets": [{
"path": "assets/a2-structure.png", "html_path": "assets/a2-structure.svg", "source_path": "assets/a2-structure.puml",
"caption": "A2 STRUCTURE — konteksty, funkcje wejściowe, inwarianty i domeny pamięci.", "label": "fig:a2-structure", "alt": "Struktury WorkerContext i SupervisorContext oraz ich relacje z FreeRTOS.", "kind": "diagram", "width": 1.0,
"page_grid": {"columns": 1, "rows": 1, "page_width": 940, "page_height": 560, "overview": true, "step_tiles": {"worker-context": 1, "handle": 1, "contexts": 1, "entries": 1, "supervisor": 1, "invariants": 1}},
"interactive": {
"kind": "uml-class", "storage_key": "fc02-a2-structure", "title": "A2 · dane i funkcje C",
"task": {"id": "task01", "label": "Task01 · raw C task"},
"block": {"id": "a2-structure", "label": "A2 STRUCTURE", "description": "Statyczna struktura kompilacyjna i domeny pamięci."},
"phases": [{"id": "c-data-functions", "label": "C DATA / FUNCTIONS", "steps": [
{"id": "worker-context", "number": 1, "label": "WorkerContext is application state", "mode": "CODE", "strategy_ref": "code.structure", "svg_label": "01", "svg_target": "Worker", "code_ref": "include/task01_first_task.h:18", "description": "Jawne pola tworzą obserwowalny kontekst aplikacji.", "evidence": "Brak ukrytego this, vptr i konstruktora."},
{"id": "handle", "number": 2, "label": "TaskHandle_t is an opaque handle", "mode": "CODE", "strategy_ref": "code.structure", "svg_label": "02", "svg_target": "Worker", "code_ref": "include/task01_first_task.h:25", "description": "&handle, wartość handle i adres TCB nie są tym samym pojęciem.", "evidence": "created_handle przechowuje historyczną wartość przed self-delete."},
{"id": "contexts", "number": 3, "label": "two static worker contexts", "mode": "CODE", "strategy_ref": "code.structure", "svg_label": "03", "svg_target": "Contexts", "code_ref": "src/tasks/task01_first_task.c:28", "description": "Konteksty istnieją przez cały program.", "evidence": "&g_worker_a i &g_worker_b nie leżą w ucHeap."},
{"id": "entries", "number": 4, "label": "entry functions have TaskFunction_t shape", "mode": "CODE", "strategy_ref": "code.abi", "svg_label": "04", "svg_target": "Entries", "code_ref": "include/task01_first_task.h:44", "description": "Obie funkcje wejściowe przyjmują dokładnie void*.", "evidence": "check-abi znajduje niemanglowane symbole C."},
{"id": "supervisor", "number": 5, "label": "SupervisorContext observes both workers", "mode": "CODE", "strategy_ref": "code.structure", "svg_label": "05", "svg_target": "Supervisor", "code_ref": "include/task01_first_task.h:36", "description": "Supervisor posiada wskaźniki do obu statycznych kontekstów.", "evidence": "Nie przejmuje ich lifetime ani storage."},
{"id": "invariants", "number": 6, "label": "common sum/scheduling invariants", "mode": "CODE", "strategy_ref": "code.structure", "svg_label": "06", "svg_target": "Invariants", "code_ref": "config/paired-experiment.json:1", "description": "Maszynowy kontrakt pary zamraża wspólne parametry C/C++.", "evidence": "make check-pair sprawdza kernel, config, stosy i workload."}
]}]
}
}]
},
{
"title": "A3 — Dispatch", "order": 30, "content_kind": "prose", "asset_page_mode": "one-per-page", "page_orientation": "landscape",
"content_tex": "Jedna granica callbacku: function pointer i void* przechodzą do typowanego ciała C.",
"assets": [{
"path": "assets/a3-dispatch.png", "html_path": "assets/a3-dispatch.svg", "source_path": "assets/a3-dispatch.puml",
"caption": "A3 DISPATCH — od TaskFunction_t i xTaskCreate do WorkerContext*.", "label": "fig:a3-dispatch", "alt": "Przepływ callbacku C i odzyskanie typowanego kontekstu.", "kind": "diagram", "width": 1.0,
"page_grid": {"columns": 1, "rows": 1, "page_width": 940, "page_height": 560, "overview": true, "step_tiles": {"signature": 1, "create": 1, "entry-abi": 1, "typed-context": 1, "work": 1, "wrong-cast": 1}},
"interactive": {
"kind": "uml-class", "storage_key": "fc02-a3-dispatch", "title": "A3 · callback i context",
"task": {"id": "task01", "label": "Task01 · raw C task"},
"block": {"id": "a3-dispatch", "label": "A3 DISPATCH", "description": "C function pointer, ABI RV32 i jawne odzyskanie typu."},
"phases": [{"id": "callback-context", "label": "CALLBACK / CONTEXT", "steps": [
{"id": "signature", "number": 1, "label": "TaskFunction_t erases context type", "mode": "CODE", "strategy_ref": "code.abi", "svg_label": "01", "svg_target": "Callback", "code_ref": "vendor/FreeRTOS-Kernel/include/projdefs.h:1", "description": "Kernel widzi tylko void (*)(void*).", "evidence": "Sygnatura nie koduje WorkerContext."},
{"id": "create", "number": 2, "label": "xTaskCreate receives entry and context", "mode": "RUN", "event_id": "E03", "strategy_ref": "run.create", "svg_label": "02", "svg_target": "Create", "code_ref": "src/tasks/task01_first_task.c:285", "snapshot_ref": "task01.create-call", "description": "Na xTaskCreate+0 rejestry niosą entry, &workerA i &workerA.handle.", "evidence": "a0=sum_task_entry, a3=&g_worker_a, a5=&g_worker_a.handle."},
{"id": "entry-abi", "number": 3, "label": "pvParameters arrives in RV32 a0", "mode": "RUN", "event_id": "E06", "strategy_ref": "run.dispatch", "svg_label": "03", "svg_target": "Entry", "code_ref": "src/tasks/task01_first_task.c:143", "snapshot_ref": "task01.entry", "description": "Stop jest na sum_task_entry+0, zanim wywołanie checkpointu nadpisze a0.", "evidence": "a0 == &g_worker_a."},
{"id": "typed-context", "number": 4, "label": "typed pointer recovers WorkerContext", "mode": "RUN", "event_id": "E07", "strategy_ref": "run.dispatch", "svg_label": "04", "svg_target": "Cast", "code_ref": "src/tasks/task01_first_task.c:145", "snapshot_ref": "task01.work", "description": "Jawny cast dokumentuje zamiar, lecz nie sprawdza typu.", "evidence": "worker i pvParameters mają ten sam adres."},
{"id": "work", "number": 5, "label": "entry executes typed calculation", "mode": "RUN", "event_id": "E09", "strategy_ref": "run.dispatch", "svg_label": "05", "svg_target": "Work", "code_ref": "src/tasks/task01_first_task.c:179", "snapshot_ref": "task01.result", "description": "Obliczenie zapisuje wynik w polu kontekstu.", "evidence": "result=200010000, iterations=20000."},
{"id": "wrong-cast", "number": 6, "label": "wrong context cast is accepted by C", "mode": "CODE", "strategy_ref": "code.structure", "svg_label": "06", "svg_target": "Hazard", "code_ref": "tests/context_contract.c:10", "description": "Fixture kompiluje się, ale nigdy nie jest linkowany ani wykonywany.", "evidence": "C nie zapewnia runtime type check dla void*."}
]}]
}
}]
},
{
"title": "A5 — Flow", "order": 40, "content_kind": "prose", "asset_page_mode": "one-per-page", "page_orientation": "landscape",
"spread_group": "fc02-first-task-lifecycle", "spread_label": "FC02 · raw C task lifecycle", "spread_columns": 2,
"content_tex": "E01--E12: od statycznego kontekstu do self-delete i PASS supervisora.",
"assets": [
{
"path": "assets/a5-flow-a.png", "html_path": "assets/a5-flow-a.svg", "source_path": "assets/a5-flow-a.puml",
"caption": "A5 część 1/2 — context, create, handle i scheduler.", "label": "fig:a5-flow-a", "alt": "Pierwszy segment sekwencji raw C task.", "kind": "diagram", "width": 1.0,
"page_grid": {"columns": 1, "rows": 1, "page_width": 940, "page_height": 560, "overview": true, "step_tiles": {"contexts": 1, "create-request": 1, "create-call": 1, "ready": 1, "scheduler": 1}},
"interactive": {
"kind": "uml-sequence", "storage_key": "fc02-a5-flow-a", "title": "część 1/2 · context do READY",
"task": {"id": "task01", "label": "Task01 · raw C task"},
"block": {"id": "a5-flow", "label": "A5 FLOW", "description": "Jeden blok i wspólni uczestnicy obejmują E01E12."},
"phases": [{"id": "create-start", "label": "CREATE / START", "steps": [
{"id": "contexts", "number": 1, "label": "static contexts prepared", "mode": "RUN", "event_id": "E01", "strategy_ref": "run.create", "svg_label": "01", "code_ref": "src/tasks/task01_first_task.c:313", "snapshot_ref": "task01.contexts", "description": "workerA istnieje przed TCB.", "evidence": "PREPARED, handle=NULL, result=0."},
{"id": "create-request", "number": 2, "label": "first worker create request", "mode": "RUN", "event_id": "E02", "strategy_ref": "run.create", "svg_label": "02", "code_ref": "src/tasks/task01_first_task.c:277", "snapshot_ref": "task01.create-request", "description": "create_worker otrzymuje &workerA.", "evidence": "Jest to pierwsze żądanie uruchomienia."},
{"id": "create-call", "number": 3, "label": "xTaskCreate(entry, &workerA)", "mode": "RUN", "event_id": "E03", "strategy_ref": "run.create", "svg_label": "03", "code_ref": "src/tasks/task01_first_task.c:285", "snapshot_ref": "task01.create-call", "description": "ABI C przekazuje funkcję i kontekst osobno.", "evidence": "a0/a3/a5 wskazują entry/context/handle field."},
{"id": "ready", "number": 4, "label": "handle non-null; diagnostic READY", "mode": "RUN", "event_id": "E04", "strategy_ref": "run.create", "svg_label": "04", "code_ref": "src/tasks/task01_first_task.c:303", "snapshot_ref": "task01.ready", "description": "Historyczna wartość handle zostaje zachowana.", "evidence": "created_handle == handle != NULL."},
{"id": "scheduler", "number": 5, "label": "vTaskStartScheduler", "mode": "RUN", "event_id": "E05", "strategy_ref": "run.create", "svg_label": "05", "code_ref": "src/tasks/task01_first_task.c:333", "snapshot_ref": "task01.scheduler", "description": "Ostatni stop na startup stack.", "evidence": "A, B i supervisor mają utworzone handle."}
]}]
}
},
{
"path": "assets/a5-flow-b.png", "html_path": "assets/a5-flow-b.svg", "source_path": "assets/a5-flow-b.puml",
"caption": "A5 część 2/2 — callback, time slicing, wynik, delete i PASS.", "label": "fig:a5-flow-b", "alt": "Drugi segment sekwencji raw C task.", "kind": "diagram", "width": 1.0,
"page_grid": {"columns": 1, "rows": 1, "page_width": 940, "page_height": 560, "overview": true, "step_tiles": {"entry": 1, "work": 1, "timeslice": 1, "result": 1, "completed": 1, "delete": 1, "pass": 1}},
"interactive": {
"kind": "uml-sequence", "storage_key": "fc02-a5-flow-b", "title": "część 2/2 · RUNNING do PASS",
"task": {"id": "task01", "label": "Task01 · raw C task"},
"block": {"id": "a5-flow", "label": "A5 FLOW", "description": "Kontynuacja tego samego diagramu i kontekstów."},
"phases": [{"id": "dispatch-finish", "label": "DISPATCH / FINISH", "steps": [
{"id": "entry", "number": 6, "label": "sum_task_entry(&workerA)", "mode": "RUN", "event_id": "E06", "strategy_ref": "run.dispatch", "svg_label": "06", "code_ref": "src/tasks/task01_first_task.c:143", "snapshot_ref": "task01.entry", "description": "Callback entry zachowuje pierwszy argument w a0.", "evidence": "a0 == &g_worker_a na wejściu symbolu."},
{"id": "work", "number": 7, "label": "typed context; RUNNING", "mode": "RUN", "event_id": "E07", "strategy_ref": "run.dispatch", "svg_label": "07", "code_ref": "src/tasks/task01_first_task.c:157", "snapshot_ref": "task01.work", "description": "Kontekst jest typowany, a SP należy do stosu taska.", "evidence": "created_handle==tcb_address i stack_low<=sp<=stack_high."},
{"id": "timeslice", "number": 8, "label": "tick: A -> B -> A", "mode": "RUN", "event_id": "E08", "strategy_ref": "run.scheduler", "svg_label": "08", "code_ref": "src/tasks/task01_first_task.c:172", "snapshot_ref": "task01.timeslice", "description": "Checkpoint powstaje dopiero po wykryciu podciągu, niezależnie od pierwszego taska.", "evidence": "g_aba_task={0,1,0}; observed changes>=2."},
{"id": "result", "number": 9, "label": "result published", "mode": "RUN", "event_id": "E09", "strategy_ref": "run.dispatch", "svg_label": "09", "code_ref": "src/tasks/task01_first_task.c:179", "snapshot_ref": "task01.result", "description": "Wynik i liczba iteracji są zapisane w context.", "evidence": "200010000 i 20000."},
{"id": "completed", "number": 10, "label": "COMPLETED; public handle NULL", "mode": "RUN", "event_id": "E10", "strategy_ref": "run.state", "svg_label": "10", "code_ref": "src/tasks/task01_first_task.c:185", "snapshot_ref": "task01.completed", "description": "created_handle zachowuje forensic address, public handle zostaje wyczyszczony.", "evidence": "Static context nadal istnieje."},
{"id": "delete", "number": 11, "label": "vTaskDelete(NULL)", "mode": "RUN", "event_id": "E11", "strategy_ref": "run.state", "svg_label": "11", "code_ref": "src/tasks/task01_first_task.c:189", "snapshot_ref": "task01.delete", "description": "Stop jest przed niepowracającym self-delete.", "evidence": "Adresy TCB/stack po delete są tylko forensic."},
{"id": "pass", "number": 12, "label": "supervisor verifies PASS", "mode": "RUN", "event_id": "E12", "strategy_ref": "run.pass", "svg_label": "12", "code_ref": "src/tasks/task01_first_task.c:231", "snapshot_ref": "task01.pass", "description": "Supervisor sprawdza oba workery i wspólne inwarianty pary.", "evidence": "PASS=1, dwa wyniki, A/B/A, ticks i stack bounds."}
]}]
}
}
]
},
{
"title": "A6 — State", "order": 50, "content_kind": "prose", "asset_page_mode": "one-per-page",
"content_tex": "Statyczny lifetime context, diagnostyczny \\texttt{trace\\_state} i rzeczywiste stany taska kernela to trzy różne osie.",
"assets": [{
"path": "assets/a6-state.png", "html_path": "assets/a6-state.svg", "source_path": "assets/a6-state.puml",
"caption": "A6 STATE — korelacja stanu kontekstu z Ready, Running, time slice i Deleted.", "label": "fig:a6-state", "alt": "Oddzielne tory stanu diagnostycznego i stanu FreeRTOS.", "kind": "diagram", "width": 1.0,
"page_grid": {"columns": 1, "rows": 1, "page_width": 660, "page_height": 760, "overview": true, "step_tiles": {"lifetime": 1, "prepared": 1, "running": 1, "kernel-running": 1, "timeslice": 1, "deleted": 1}},
"interactive": {
"kind": "uml-state", "storage_key": "fc02-a6-state", "title": "A6 · dwa modele stanu",
"task": {"id": "task01", "label": "Task01 · raw C task"},
"block": {"id": "a6-state", "label": "A6 STATE", "description": "Nie utożsamiaj trace_state z eTaskState."},
"phases": [
{"id": "context-diagnostic", "label": "CONTEXT / DIAGNOSTIC", "steps": [
{"id": "lifetime", "number": 1, "label": "static WorkerContext lifetime", "mode": "CODE", "strategy_ref": "code.structure", "svg_label": "01", "svg_target": "ObjectLifetime", "code_ref": "src/tasks/task01_first_task.c:28", "description": "Context istnieje przed taskiem i po jego self-delete.", "evidence": "Adres static storage jest stały."},
{"id": "prepared", "number": 2, "label": "PREPARED -> STARTING -> READY", "mode": "RUN", "event_id": "E04", "strategy_ref": "run.state", "svg_label": "02", "svg_target": "Starting", "code_ref": "src/tasks/task01_first_task.c:279", "snapshot_ref": "task01.ready", "description": "Stan diagnostyczny opisuje aplikację.", "evidence": "READY współistnieje z handle != NULL."},
{"id": "running", "number": 3, "label": "RUNNING -> COMPLETED", "mode": "RUN", "event_id": "E10", "strategy_ref": "run.state", "svg_label": "03", "svg_target": "RunningWrapper", "code_ref": "src/tasks/task01_first_task.c:185", "snapshot_ref": "task01.completed", "description": "COMPLETED jest zapisane przed delete.", "evidence": "Static context nie znika."}
]},
{"id": "kernel", "label": "KERNEL", "steps": [
{"id": "kernel-running", "number": 4, "label": "Ready <-> Running", "mode": "RUN", "event_id": "E07", "strategy_ref": "run.state", "svg_label": "04", "svg_target": "RunningKernel", "code_ref": "src/tasks/task01_first_task.c:157", "snapshot_ref": "task01.work", "description": "CPU-bound worker nie przechodzi przez Blocked.", "evidence": "Scheduler wybiera równorzędne Ready taski."},
{"id": "timeslice", "number": 5, "label": "equal-priority time slicing", "mode": "RUN", "event_id": "E08", "strategy_ref": "run.scheduler", "svg_label": "05", "svg_target": "TimeSlice", "code_ref": "src/tasks/task01_first_task.c:172", "snapshot_ref": "task01.timeslice", "description": "Podciąg A/B/A dowodzi wznowienia kontekstu.", "evidence": "Ticki są niemalejące."},
{"id": "deleted", "number": 6, "label": "Deleted does not destroy static context", "mode": "RUN", "event_id": "E11", "strategy_ref": "run.state", "svg_label": "06", "svg_target": "DeletedKernel", "code_ref": "src/tasks/task01_first_task.c:189", "snapshot_ref": "task01.delete", "description": "E11 jest przed delete; karta nie dereferencjonuje forensic TCB później.", "evidence": "Context/result pozostają obserwowalne dla supervisora."}
]}
]
}
}]
},
{
"title": "A7 — Runtime", "order": 60, "content_kind": "prose", "asset_page_mode": "one-per-page", "page_orientation": "landscape",
"content_tex": "Dowód runtime wiąże source i ELF z adresem context, polem handle, TCB, stosem, SP, PC, tickiem i wynikiem.",
"assets": [{
"path": "assets/a7-runtime.png", "html_path": "assets/a7-runtime.svg", "source_path": "assets/a7-runtime.puml",
"caption": "A7 RUNTIME — context, handle/TCB, osobny stack, ABI i dowód końcowy.", "label": "fig:a7-runtime", "alt": "Mapa pamięci i dowodów runtime pierwszego taska C.", "kind": "diagram", "width": 1.0,
"page_grid": {"columns": 1, "rows": 1, "page_width": 940, "page_height": 560, "overview": true, "step_tiles": {"context": 1, "handle": 1, "tcb-stack": 1, "abi": 1, "schedule": 1, "evidence": 1}},
"interactive": {
"kind": "uml-object", "storage_key": "fc02-a7-runtime", "title": "A7 · mapa wykonania",
"task": {"id": "task01", "label": "Task01 · raw C task"},
"block": {"id": "a7-runtime", "label": "A7 RUNTIME", "description": "Minimalny zestaw pomiarów dobrany do pytania."},
"phases": [
{"id": "memory", "label": "MEMORY", "steps": [
{"id": "context", "number": 1, "label": "context address is not TCB", "mode": "RUN", "event_id": "E04", "strategy_ref": "run.runtime", "svg_label": "01", "svg_target": "Context", "code_ref": "src/tasks/task01_first_task.c:28", "snapshot_ref": "task01.ready", "description": "&g_worker_a ma static storage.", "evidence": "Adres nie leży w ucHeap."},
{"id": "handle", "number": 2, "label": "field address, handle value and TCB", "mode": "RUN", "event_id": "E07", "strategy_ref": "run.runtime", "svg_label": "02", "svg_target": "Handle", "code_ref": "include/task01_first_task.h:25", "snapshot_ref": "task01.work", "description": "&handle jest adresem pola, handle wartością opaque.", "evidence": "created_handle == tcb_address, ale &handle różni się od obu."},
{"id": "tcb-stack", "number": 3, "label": "TCB and stack are separate heap_4 blocks", "mode": "RUN", "event_id": "E07", "strategy_ref": "run.runtime", "svg_label": "03", "svg_target": "TCB", "code_ref": "src/tasks/task01_first_task.c:126", "snapshot_ref": "task01.work", "description": "TaskStatus_t dostarcza publiczną obserwację handle i stack bounds.", "evidence": "SP należy do zakresu stack, nie do context/TCB."}
]},
{"id": "cpu-scheduler", "label": "CPU / SCHEDULER", "steps": [
{"id": "abi", "number": 4, "label": "pvParameters in a0 at callback entry", "mode": "RUN", "event_id": "E06", "strategy_ref": "run.dispatch", "svg_label": "04", "svg_target": "ABI", "code_ref": "src/tasks/task01_first_task.c:143", "snapshot_ref": "task01.entry", "description": "Stop bezpośrednio na symbolu zachowuje ABI evidence.", "evidence": "a0 == &g_worker_a."},
{"id": "schedule", "number": 5, "label": "PC, tick and A/B/A trace", "mode": "RUN", "event_id": "E08", "strategy_ref": "run.scheduler", "svg_label": "05", "svg_target": "Schedule", "code_ref": "src/tasks/task01_first_task.c:172", "snapshot_ref": "task01.timeslice", "description": "Trace liczy obserwowane zmiany workera, nie wszystkie przełączenia kernela.", "evidence": "A/B/A, ticks i PC są powiązane z E08."},
{"id": "evidence", "number": 6, "label": "result, source and checkpoint identity", "mode": "RUN", "event_id": "E12", "strategy_ref": "run.pass", "svg_label": "06", "svg_target": "Evidence", "code_ref": "src/tasks/task01_first_task.c:231", "snapshot_ref": "task01.pass", "description": "Końcowy dowód wiąże wynik ze źródłem, ELF i timestampem.", "evidence": "snapshot_ref, event_id, source blob, image hash i PASS."}
]}
]
}
}]
},
{"title": "Task01 — Raw C task", "order": 70, "content_kind": "tasks", "task_refs": ["task01"]}
],
"tasks": {
"task01": {
"title": "Pierwszy task FreeRTOS — callback, context, TCB i stos",
"uuid": "a2538a1a-3c37-4c14-a6ea-db5aba8fd038",
"prompt_tex": "Przejdź po aktywnych perspektywach A1, A2, A3, A5, A6 i A7. Dla kroków RUN użyj Enter lub F2 i udowodnij w Hazard3/GDB przepływ \\texttt{xTaskCreate -> sum\\_task\\_entry -> WorkerContext -> vTaskDelete}.",
"criterion": "Program wypisuje PASS; oba wyniki wynoszą 200010000; E06 pokazuje a0=&workerA; trace zawiera A-B-A; context, TCB i stack są rozdzielone.",
"conclusion_tex": "Surowe API C przekazuje zachowanie i dane oddzielnie: \\texttt{TaskFunction\\_t} wybiera kod, a \\texttt{void*} niesie adres jawnego kontekstu. Scheduler, TCB i stos pozostają własnością FreeRTOS.",
"flow": [
{"kind": "block", "id": "c-model", "title": "A — model C i granica ABI", "content_tex": "Najpierw czytaj A1--A3 bez uruchamiania programu.", "steps": [
{"id": "read-context", "title": "Odczytaj WorkerContext.", "content_tex": "Rozróżnij static context, adres pola handle, wartość handle, TCB i stack."},
{"id": "prove-c-abi", "title": "Udowodnij callback ABI.", "content_tex": "Na E03 zbadaj argumenty \\texttt{xTaskCreate}, a na E06 rejestr \\texttt{a0} przed prologiem \\texttt{sum\\_task\\_entry}."}
]},
{"kind": "block", "id": "runtime-trace", "title": "B — sekwencja i scheduler", "content_tex": "Każdy RUN replay zaczyna się od czystej RAM.", "steps": [
{"id": "follow-context", "title": "Śledź jeden adres context.", "content_tex": "Porównaj \\texttt{\\&g\\_worker\\_a} w \\texttt{main}, \\texttt{xTaskCreate} i \\texttt{sum\\_task\\_entry}."},
{"id": "follow-stack", "title": "Śledź osobny stos.", "content_tex": "Potwierdź \\texttt{stack\\_low <= sp <= stack\\_high} i \\texttt{created\\_handle == tcb\\_address}."},
{"id": "follow-scheduler", "title": "Śledź A-B-A.", "content_tex": "Zapisz triplet workerów, ticki i liczbę obserwowanych zmian."}
]},
{"kind": "exercise", "id": "raw-c-debug-report", "title": "Ćwiczenie — timestampowany ślad taska C", "prompt_tex": "Wybierz E01, E03, E06, E08, E10 i E12. Dla każdego zapisz timestamp, PC, SP, adres context, wartość handle/TCB i stan. Wyjaśnij, których adresów po E11 nie wolno dereferencjonować.", "evidence_tex": "Timestampowane snapshoty Hazard3/GDB powiązane z kotwami UML oraz końcowy PASS.", "criterion": "Raport zachowuje tożsamość context, rozdziela TCB od stack i nie myli trace_state z eTaskState.", "based_on": ["c-model", "runtime-trace"]}
],
"educational_requirement_refs": ["FC02.WE01"],
"learning_effect_refs": ["FC02.EN01", "FC02.EK01"],
"assessment_criterion_ref": "FC02.KW01"
}
},
"tasks_order": ["task01"]
}