feat: publish FreeRTOS C FC02 card

This commit is contained in:
2026-07-19 16:36:02 +02:00
commit e3420748ee
208 changed files with 57240 additions and 0 deletions
+394
View File
@@ -0,0 +1,394 @@
{
"$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 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 xTaskCreate, a na E06 rejestr a0 przed prologiem 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 &g_worker_a w main, xTaskCreate i sum_task_entry."},
{"id": "follow-stack", "title": "Śledź osobny stos.", "content_tex": "Potwierdź stack_low <= sp <= stack_high i 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"]
}