From c4f14cb7b889dedd8ffd4569e40fe15f9ef7e7da Mon Sep 17 00:00:00 2001 From: user Date: Sun, 19 Jul 2026 18:31:44 +0200 Subject: [PATCH] publish C07 pointers and arrays card --- README.md | 15 + json/card_source.json | 1264 +++++++++++++++++ ...1-4abec2d9-79e9-0dca-9040-c60669f51ff8.pdf | Bin 0 -> 2939863 bytes 3 files changed, 1279 insertions(+) create mode 100644 README.md create mode 100644 json/card_source.json create mode 100644 pdf/mpabi-inf-c-07-pointers-arrays-v00.01-4abec2d9-79e9-0dca-9040-c60669f51ff8.pdf diff --git a/README.md b/README.md new file mode 100644 index 0000000..7a5f033 --- /dev/null +++ b/README.md @@ -0,0 +1,15 @@ +# C07 — Pointers and Arrays + +Published source data and printable output for the C-series card covering +pointers, arrays, address arithmetic, and the K&R 5.4 linear allocator. + +- Series: `C · Freestanding RV32I and K&R` +- Card: `C07/13` +- Version: `v00.01` +- Resource UUID: `98dbe323-c624-53d6-9fe2-4ee688c44b38` +- [Interactive card](https://dce7fb9d-7b2f-5d49-96a2-3a30d3070b84.mpabi.pl/98dbe323-c624-53d6-9fe2-4ee688c44b38) + +The canonical teaching content is stored in `json/card_source.json`. The `pdf/` +directory contains the printable A4 rendering produced by `edu-tools/card-layouts`. +The interactive React renderer is deployed independently and resolves the stable +resource UUID above. diff --git a/json/card_source.json b/json/card_source.json new file mode 100644 index 0000000..734b7b4 --- /dev/null +++ b/json/card_source.json @@ -0,0 +1,1264 @@ +{ + "$schema": "https://zsl-gitea.mpabi.pl/edu-tools/card-layouts/raw/branch/main/schemas/card-source.schema.json", + "schema": "esc-card-source.v1", + "card": { + "id": "mpabi-inf-c-07-pointers-arrays", + "series": "c", + "series_title": "C · Freestanding RV32I and K&R", + "number": "07", + "count": "13", + "slug": "pointers-arrays", + "title": "Wskaźniki i tablice", + "topic": "Od K&R 5.1--5.4 do struktur i FreeRTOS heap_4", + "project": "Alokator pamięci", + "subject": "Informatyka", + "level": "PP@2024.06.28 · Inf. · ZP · Kl. 1 · Poz. 1", + "revision_date": "2026-07-19T00:00:00+02:00", + "status": "Gotowa", + "version": "v00.01", + "uuid": "4abec2d9-79e9-0dca-9040-c60669f51ff8", + "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, + "debug_checkpoints": { + "schema": "stem-debug-checkpoints.v1", + "semantics": "deterministic-replay", + "recorded_grid_pattern": "debug-snapshots/{snapshot_ref}.json", + "artifact": { + "source": "src/tasks/task04_address_arithmetic_alloc.c", + "source_git_blob": "a8aa25b3e6b68af6dbfd640937b6660b2ed5c5af", + "elf": ".stem/instances/hazard3-sim-inf-pointers-t4/build/hazard3/task04_address_arithmetic_alloc/prog.elf", + "hazard3_image": ".stem/instances/hazard3-sim-inf-pointers-t4/build/hazard3/task04_address_arithmetic_alloc/prog.bin", + "hazard3_image_sha256": "59e042815059da76a8c5e85c1317abaae9decf5e9ea77ef54e6da4175f71a307" + }, + "targets": { + "hazard3-sim": { + "adapter": "hazard3-reset-load-replay.v1", + "baseline": "restart-backend", + "clean_ram": true + }, + "rp2350": { + "adapter": "rp2350-sram-reset-load-replay.v1", + "baseline": "reset-load-elf-sram", + "requires_probe_lease": true, + "persistent_flash": false + } + }, + "items": { + "task04.reset.call": {"stop": {"symbol": "main", "offset": 16}, "verify": {"expressions": []}}, + "task04.reset.address": {"stop": {"symbol": "allocator_reset", "offset": 28}, "verify": {"expressions": []}}, + "task04.reset.store": {"stop": {"symbol": "allocator_reset", "offset": 32}, "verify": {"expressions": [{"expr": "allocp - allocbuf", "equals": 0}]}}, + "task04.reset.return": {"stop": {"symbol": "main", "offset": 24}, "verify": {"expressions": [{"expr": "allocp - allocbuf", "equals": 0}]}}, + "task04.alloc5.enter": {"stop": {"symbol": "main", "offset": 28}, "verify": {"expressions": [{"expr": "$a0", "equals": 5}, {"expr": "allocp - allocbuf", "equals": 0}]}}, + "task04.alloc5.cursor": {"stop": {"symbol": "alloc_local", "offset": 40, "condition": "$a0 == 5"}, "verify": {"expressions": [{"expr": "$a0", "equals": 5}, {"expr": "allocp - allocbuf", "equals": 0}]}}, + "task04.alloc5.buffer-address": {"stop": {"symbol": "alloc_local", "offset": 56, "condition": "$a0 == 5"}, "verify": {"expressions": [{"expr": "allocp - allocbuf", "equals": 0}]}}, + "task04.alloc5.used": {"stop": {"symbol": "alloc_local", "offset": 64, "condition": "$a0 == 5"}, "verify": {"expressions": [{"expr": "$a0", "equals": 5}, {"expr": "allocp - allocbuf", "equals": 0}]}}, + "task04.alloc5.commit": {"stop": {"symbol": "alloc_local", "offset": 156, "condition": "$a0 == 5"}, "verify": {"expressions": [{"expr": "$a0", "equals": 5}, {"expr": "allocp - allocbuf", "equals": 5}]}}, + "task04.alloc5.return": {"stop": {"symbol": "main", "offset": 40}, "verify": {"expressions": [{"expr": "allocp - allocbuf", "equals": 5}, {"expr": "first - allocbuf", "equals": 0}]}}, + "task04.alloc7.enter": {"stop": {"symbol": "main", "offset": 44}, "verify": {"expressions": [{"expr": "$a0", "equals": 7}, {"expr": "allocp - allocbuf", "equals": 5}]}}, + "task04.alloc7.cursor": {"stop": {"symbol": "alloc_local", "offset": 40, "condition": "$a0 == 7"}, "verify": {"expressions": [{"expr": "$a0", "equals": 7}, {"expr": "allocp - allocbuf", "equals": 5}]}}, + "task04.alloc7.used": {"stop": {"symbol": "alloc_local", "offset": 64, "condition": "$a0 == 7"}, "verify": {"expressions": [{"expr": "$a0", "equals": 7}, {"expr": "allocp - allocbuf", "equals": 5}]}}, + "task04.alloc7.commit": {"stop": {"symbol": "alloc_local", "offset": 156, "condition": "$a0 == 7"}, "verify": {"expressions": [{"expr": "$a0", "equals": 7}, {"expr": "allocp - allocbuf", "equals": 12}]}}, + "task04.alloc7.return": {"stop": {"symbol": "main", "offset": 56}, "verify": {"expressions": [{"expr": "allocp - allocbuf", "equals": 12}, {"expr": "first - allocbuf", "equals": 0}, {"expr": "second - allocbuf", "equals": 5}]}} + } + }, + "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": "Wskaźniki i tablice", + "url": "https://dce7fb9d-7b2f-5d49-96a2-3a30d3070b84.mpabi.pl/98dbe323-c624-53d6-9fe2-4ee688c44b38", + "repository_url": "https://zsl-gitea.mpabi.pl/edu-c/lab-rv32i-c-pointers-arrays", + "url_host_uuid": "dce7fb9d-7b2f-5d49-96a2-3a30d3070b84", + "url_domain": "mpabi.pl", + "doc_uuid": "98dbe323-c624-53d6-9fe2-4ee688c44b38", + "revision": "v00.01", + "issued_on": "2026-07-19T00:00:00+02:00", + "series": "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 + }, + "reference_registries": [ + { + "uuid": "03403a8a-e20d-5b17-9004-26d9fe6c3003", + "source": "../../../tools/debugging-strategies/json/reference_registry.json" + } + ], + "debug_strategies": { + "run.runtime": { + "id": "run.runtime", + "kind": "run", + "action": "replay", + "prerequisites": [ + "Hazard3/GDB online", + "symbole ELF Task04" + ], + "layout": [ + "source", + "assembly", + "registers", + "stack", + "allocbuf" + ], + "commands": [ + "info registers a0 a4 a5 sp s0 pc", + "print allocp - allocbuf", + "x/16bx allocbuf" + ], + "expected_observations": [ + "allocp przechodzi przez offsety 0, 5 i 12", + "allocbuf i allocp należą do .bss, a sp do bieżącej ramki stosu" + ], + "assertions": [ + "wybrany checkpoint odtwarza deterministyczny stan alokatora", + "PC i linia źródła odpowiadają wybranej strzałce UML" + ], + "evidence_fields": [ + "snapshot_ref", + "source_ref", + "PC", + "registers", + "allocp offset", + "ELF hash", + "timestamp" + ] + } + }, + "front_page_break": true, + "front_page_scope": { + "title": "Cel karty", + "content_tex": "Uczeń implementuje i weryfikuje liniowy alokator z areną \\texttt{allocbuf} i kursorem \\texttt{allocp}; przewiduje offsety, odczytuje je w pamięci oraz dowodzi, że \\texttt{allocp} nie jest wskaźnikiem stosu \\texttt{sp}.", + "scope_title": "Zakres karty", + "scope_table": { + "headers": ["K&R", "Numer tasku", "Najważniejsza idea", "Priorytet", "Status", "Version"], + "rows": [ + {"chapter": "5.1", "task": "Task01", "idea_tex": "adres, \\texttt{\\&}, \\texttt{*}", "priority": "obowiązkowe", "status": "not-started", "version": "v00.01"}, + {"chapter": "5.2", "task": "Task02", "idea_tex": "wskaźnik jako argument funkcji", "priority": "obowiązkowe", "status": "not-started", "version": "v00.01"}, + {"chapter": "5.3", "task": "Task03", "idea_tex": "relacja tablicy i wskaźnika", "priority": "obowiązkowe", "status": "not-started", "version": "v00.01"}, + {"chapter": "5.4", "task": "Task04", "idea_tex": "arytmetyka adresów, alokator", "priority": "obowiązkowe", "status": "in-progress", "version": "v00.01", "key": true}, + {"chapter": "5.5", "task": "Task05", "idea_tex": "napisy jako \\texttt{char *}, NUL", "priority": "ważne", "status": "not-started", "version": "v00.01"}, + {"chapter": "5.6", "task": "Task06", "idea_tex": "tablica wskaźników", "priority": "ważne", "status": "not-started", "version": "v00.01"}, + {"chapter": "5.7", "task": "Task07", "idea_tex": "tablice wielowymiarowe", "priority": "ważne", "status": "not-started", "version": "v00.01"}, + {"chapter": "5.8", "task": "Task08", "idea_tex": "inicjalizacja tablic wskaźników", "priority": "wspierające", "status": "not-started", "version": "v00.01"}, + {"chapter": "5.9", "task": "Task09", "idea_tex": "\\texttt{int a[R][C]} kontra \\texttt{int *a[]}", "priority": "bardzo ważne", "status": "not-started", "version": "v00.01"}, + {"chapter": "5.10", "task": "Task10", "idea_tex": "\\texttt{argv} i argumenty programu", "priority": "wspierające", "status": "not-started", "version": "v00.01"}, + {"chapter": "5.11", "task": "Task11", "idea_tex": "wskaźniki do funkcji", "priority": "ważne przed callbackami", "status": "not-started", "version": "v00.01"}, + {"chapter": "5.12", "task": "Task12", "idea_tex": "czytanie złożonych deklaracji", "priority": "uzupełniające", "status": "not-started", "version": "v00.01"} + ] + } + }, + "side_margin_tree_layout": { + "columns": [ + { + "id": "zawodowe", + "label": "TECH", + "side": "left", + "tree": "WE -> EK -> KW", + "description": "Umiejętności techniczne: C, RISC-V, debugowanie i pamięć." + }, + { + "id": "ogolne", + "label": "OG", + "side": "right", + "tree": "WE -> EN -> KW", + "description": "Umiejętności ogólne: przewidywanie, pomiar i wnioskowanie." + } + ] + }, + "learning_effects": { + "PTR.EN01": { + "bloom_level": "Analiza", + "label": "Przewidywanie", + "text": "Uczeń przewiduje wartości, adresy i offsety przed uruchomieniem programu, a następnie porównuje je z pomiarem.", + "assessment_criteria": ["PTR.KW01", "PTR.KW02"] + }, + "PTR.EN02": { + "bloom_level": "Ewaluacja", + "label": "Dowód", + "text": "Uczeń zapisuje odtwarzalny dowód i odróżnia wynik od jego interpretacji.", + "assessment_criteria": ["PTR.KW04"] + }, + "PTR.EK01": { + "bloom_level": "Zastosowanie", + "label": "Wskaźniki i tablice", + "text": "Uczeń stosuje adresowanie, dereferencję, argumenty wskaźnikowe i arytmetykę wskaźników w granicach tablicy.", + "assessment_criteria": ["PTR.KW01"] + }, + "PTR.EK02": { + "bloom_level": "Analiza", + "label": "Debugowanie RV32", + "text": "Uczeń odnajduje argumenty, zmienne lokalne, ramkę stosu, rejestry i bajty pamięci w debuggerze Hazard3.", + "assessment_criteria": ["PTR.KW03", "PTR.KW04"] + }, + "PTR.EK03": { + "bloom_level": "Analiza", + "label": "Alokator", + "text": "Uczeń śledzi inwarianty liniowego alokatora i wskazuje elementy potrzebne do przejścia do struktur oraz heap_4.", + "assessment_criteria": ["PTR.KW02", "PTR.KW03"] + } + }, + "assessment_criteria": { + "PTR.KW01": { + "text": "Task01--Task03 kończą się kodem 0, przewidywania są zapisane, a wartości i offsety zgadzają się z pomiarem.", + "learning_effects": ["PTR.EN01", "PTR.EK01"] + }, + "PTR.KW02": { + "text": "Task04 daje offsety 0, 5, 12 i 5; odrzuca brak miejsca i żądanie zera; suma znaków wynosi 372.", + "learning_effects": ["PTR.EN01", "PTR.EK03"] + }, + "PTR.KW03": { + "text": "Uczeń pokazuje allocbuf w pamięci, odróżnia allocp od sp oraz potwierdza wyrównanie sp do 16 bajtów.", + "learning_effects": ["PTR.EK02", "PTR.EK03"] + }, + "PTR.KW04": { + "text": "Dowód zawiera wynik AMD64, Hazard3 i -- dla Task04 na zajęciach -- RP2350, wraz z komendą, bramką i obserwacją debuggera.", + "learning_effects": ["PTR.EN02", "PTR.EK02"] + } + }, + "educational_requirements": { + "PTR.WE01": { + "text": "Poprawne rozumowanie o adresach, wartościach i przesunięciach wskaźników.", + "label": "Semantyka wskaźników", + "learning_effects": ["PTR.EN01", "PTR.EK01"], + "learning_tree": { + "schema": "we-learning-tree.v1", + "policy": "Najpierw przewidywanie, potem pomiar, na końcu wniosek.", + "ogolne": [ + { + "effect_ref": "PTR.EN01", + "display": "EN PTR 01", + "source": "LOCAL", + "official": "PTR", + "local": "01", + "kind": "EN", + "text": "Przewidywanie i porównanie wyniku.", + "tree_id": "PTR.WE01.OG.EN01", + "kw": [ + { + "criterion_ref": "PTR.KW01", + "display": "KW PTR 01", + "source": "LOCAL", + "kind": "KW", + "official": "PTR", + "local": "01", + "text": "Task01--Task03: zgodne wartości i offsety." + } + ] + } + ], + "zawodowe": [ + { + "effect_ref": "PTR.EK01", + "display": "EK PTR 01", + "source": "LOCAL", + "official": "PTR", + "local": "01", + "kind": "EK", + "text": "Wskaźniki, tablice i argumenty funkcji.", + "tree_id": "PTR.WE01.TECH.EK01", + "kw": [ + { + "criterion_ref": "PTR.KW01", + "display": "KW PTR 01", + "source": "LOCAL", + "kind": "KW", + "official": "PTR", + "local": "01", + "text": "Task01--Task03: zgodne wartości i offsety." + } + ] + } + ] + } + }, + "PTR.WE02": { + "text": "Odtwarzalna obserwacja wykonania programu na RV32 i RP2350.", + "label": "Pomiar debuggera", + "learning_effects": ["PTR.EN02", "PTR.EK02"], + "learning_tree": { + "schema": "we-learning-tree.v1", + "policy": "Każdy wniosek wskazuje komendę i obserwowany stan.", + "ogolne": [ + { + "effect_ref": "PTR.EN02", + "display": "EN PTR 02", + "source": "LOCAL", + "official": "PTR", + "local": "02", + "kind": "EN", + "text": "Dokumentowanie dowodu pomiarowego.", + "tree_id": "PTR.WE02.OG.EN02", + "kw": [ + { + "criterion_ref": "PTR.KW04", + "display": "KW PTR 04", + "source": "LOCAL", + "kind": "KW", + "official": "PTR", + "local": "04", + "text": "Dowód z platform, bramek i debuggera." + } + ] + } + ], + "zawodowe": [ + { + "effect_ref": "PTR.EK02", + "display": "EK PTR 02", + "source": "LOCAL", + "official": "PTR", + "local": "02", + "kind": "EK", + "text": "Rejestry, stos, ASM i pamięć RV32.", + "tree_id": "PTR.WE02.TECH.EK02", + "kw": [ + { + "criterion_ref": "PTR.KW03", + "display": "KW PTR 03", + "source": "LOCAL", + "kind": "KW", + "official": "PTR", + "local": "03", + "text": "allocbuf, allocp, sp i wyrównanie stosu." + }, + { + "criterion_ref": "PTR.KW04", + "display": "KW PTR 04", + "source": "LOCAL", + "kind": "KW", + "official": "PTR", + "local": "04", + "text": "Dowód z platform, bramek i debuggera." + } + ] + } + ] + } + }, + "PTR.WE03": { + "text": "Wyjaśnienie działania alokatora liniowego i jego ograniczeń przed strukturami i heap_4.", + "label": "Od K&R 5.4 do heap_4", + "learning_effects": ["PTR.EN01", "PTR.EK03"], + "learning_tree": { + "schema": "we-learning-tree.v1", + "policy": "Stan kursora i granice areny są sprawdzane po każdej operacji.", + "ogolne": [ + { + "effect_ref": "PTR.EN01", + "display": "EN PTR 03", + "source": "LOCAL", + "official": "PTR", + "local": "03", + "kind": "EN", + "text": "Przewidywanie osi zmian alokatora.", + "tree_id": "PTR.WE03.OG.EN01", + "kw": [ + { + "criterion_ref": "PTR.KW02", + "display": "KW PTR 02", + "source": "LOCAL", + "kind": "KW", + "official": "PTR", + "local": "02", + "text": "Offsety i przypadki brzegowe Task04." + } + ] + } + ], + "zawodowe": [ + { + "effect_ref": "PTR.EK03", + "display": "EK PTR 03", + "source": "LOCAL", + "official": "PTR", + "local": "03", + "kind": "EK", + "text": "Inwarianty alokatora i przejście do heap_4.", + "tree_id": "PTR.WE03.TECH.EK03", + "kw": [ + { + "criterion_ref": "PTR.KW02", + "display": "KW PTR 02", + "source": "LOCAL", + "kind": "KW", + "official": "PTR", + "local": "02", + "text": "Offsety i przypadki brzegowe Task04." + }, + { + "criterion_ref": "PTR.KW03", + "display": "KW PTR 03", + "source": "LOCAL", + "kind": "KW", + "official": "PTR", + "local": "03", + "text": "allocbuf, allocp, sp i wyrównanie stosu." + } + ] + } + ] + } + } + }, + "sections": [ + { + "title": "K&R 5.4 -- Task04: Linear Memory Allocator", + "order": 10, + "content_kind": "prose", + "content_tex": "\\textbf{Jak działa alokator liniowy}\n\n\\begin{itemize}[leftmargin=*]\n\\item \\textbf{Model pamięci:}\n \\begin{itemize}[label=--]\n \\item \\texttt{allocbuf[ALLOCSIZE]} jest statyczną areną 64 B.\n \\item \\texttt{allocp} wskazuje pierwszy wolny bajt; offset to \\texttt{allocp - allocbuf}.\n \\end{itemize}\n\\item \\textbf{Operacje:}\n \\begin{itemize}[label=--]\n \\item \\texttt{allocator\\_reset()} ustawia \\texttt{allocp = allocbuf}.\n \\item \\texttt{alloc\\_local(n)} zwraca bieżący kursor i przesuwa go o \\texttt{n}, jeżeli żądanie jest dodatnie i mieści się w arenie.\n \\end{itemize}\n\\item \\textbf{Stan po sekwencji reset → alloc(5) → alloc(7):}\n \\begin{itemize}[label=--]\n \\item \\texttt{first = allocbuf + 0},\n \\item \\texttt{second = allocbuf + 5},\n \\item \\texttt{allocp = allocbuf + 12}.\n \\end{itemize}\n\\item \\textbf{Ograniczenie:} pojedynczych bloków nie zwalniamy; pamięć odzyskuje \\texttt{allocator\\_reset()} dla całej areny. Dowolne \\texttt{free} pojawi się później przy strukturach i \\texttt{heap\\_4}.\n\\end{itemize}", + "asset_page_mode": "one-per-page", + "render_step_map": false, + "assets": [ + { + "path": "assets/task04-allocator-arena-model.png", + "caption": "SCHEMAT — arena allocbuf ma 64 B; po przydziałach 5 B i 7 B kursor allocp wskazuje offset 12. Odczytaj granice obu obszarów i pierwszy wolny bajt.", + "label": "fig:task04-arena-model", + "alt": "Schemat areny allocbuf 64 B z przydziałami 5 B i 7 B oraz kursorem allocp na offsecie 12.", + "kind": "diagram", + "width": 0.72 + }, + { + "path": "assets/task04-memory-flow.png", + "html_path": "assets/task04-memory-flow.svg", + "source_path": "assets/task04-memory-flow.puml", + "caption": "UML — sekwencja allocator_reset() → alloc_local(5) → alloc_local(7), ramki aktywacji main()/alloc_local(n) oraz statyczne obiekty allocbuf/allocp.", + "label": "fig:task04-memory-flow", + "alt": "Diagram sekwencji UML Task04: main wywołuje allocator_reset(), a następnie dwukrotnie funkcję alloc_local(), która odczytuje allocbuf i aktualizuje allocp.", + "kind": "diagram", + "width": 1.0, + "page_grid": { + "columns": 1, + "rows": 1, + "page_width": 938, + "page_height": 1184, + "overview": true + }, + "interactive": { + "kind": "uml-sequence", + "storage_key": "task04-memory-flow", + "title": "Alokator liniowy — sekwencja wywołań", + "task": { + "id": "task04", + "label": "Task04 · Linear Memory Allocator" + }, + "block": { + "id": "allocator-flow", + "label": "Sekwencja wykonania", + "description": "Diagram przedstawia kolejno allocator_reset(), alloc_local(5) i alloc_local(7). Wybór numerowanej strzałki synchronizuje Nvim view z odpowiadającym jej stanem wykonania." + }, + "snapshot_context": { + "target": "hazard3-sim · RV32I", + "captured_at": "2026-07-16T14:24:29+02:00", + "captured_with": "gdb-multiarch + Hazard3 tb_gdb; świeży przebieg, zatrzymania po zatwierdzeniu instrukcji", + "elf": "/workspace/.stem/instances/hazard3-sim-inf-pointers-t4/build/hazard3/task04_address_arithmetic_alloc/prog.elf", + "stack_top": "0x80100000" + }, + "terminal_view": { + "path": "assets/task04-first-allocation-annotated.png", + "title": "Termdebug — cztery połączone dowody", + "alt": "Adnotowany widok Termdebug: wywołanie alloc_local w C, li i jal w listingu, argument pięć w rejestrze a0 oraz bajty allocbuf.", + "caption": "Numery 1–4 łączą linię C, instrukcje RV32, ABI i pamięć. Dokładny stan wybranego kroku jest odtwarzany w Nvim view." + }, + "phases": [ + { + "id": "reset", + "label": "RESET", + "description": "Ustanowienie inwariantu allocp = allocbuf i offsetu 0.", + "svg_label": "RESET", + "steps": [ + { + "id": "reset-call", + "number": 1, + "label": "allocator_reset()", + "svg_label": "01", + "progress_id": "UML04-S01", + "description": "main ma już własną ramkę i stoi przed wywołaniem resetu; allocp jest jeszcze zerem z inicjalizacji .bss.", + "code_ref": "src/tasks/task04_address_arithmetic_alloc.c:62", + "snapshot_ref": "task04.reset.call", + "view": { + "connection_ref": "task04.debug.auto", + "layout": "termdebug.source-asm-dashboard-memory", + "reveal": {"anchor_ref": "src.task04.main.reset-call", "align": "center"}, + "annotations": [ + {"id": "ann.reset.call", "anchor_ref": "src.task04.main.reset-call", "label": "1 · reset", "tone": "danger", "shape": "outline", "anchor": {"kind": "screen-text", "text": "allocator_reset();", "padding_cells": 1}} + ] + }, + "snapshot": { + "pc": "0x8000124c", + "code": { + "source": "allocator_reset();", + "source_ref": "task04_address_arithmetic_alloc.c:62", + "assembly": "0x8000124c auipc ra,0x0\n0x80001250 jalr ra,-284(ra) # allocator_reset", + "note": "PC wskazuje pierwszą instrukcję pary wywołującej; skok wykona się dopiero w następnym kroku procesora." + }, + "registers": [{"name": "sp", "value": "0x800fffd0"}, {"name": "s0/fp", "value": "0x800ffff0"}, {"name": "ra", "value": "0x80001030"}, {"name": "a0", "value": "0x800014b0", "note": "wartość zastana; allocator_reset nie ma argumentów"}, {"name": "a4", "value": "0x00000000"}, {"name": "a5", "value": "0x00000000"}], + "frame": {"name": "main", "sp": "0x800fffd0", "fp": "0x800ffff0", "size_bytes": 32, "fields": [{"name": "first", "address": "0x800fffdc", "value": "raw 0x00000000", "state": "uninitialised"}, {"name": "second", "address": "0x800fffd8", "value": "raw 0x00000000", "state": "uninitialised"}, {"name": "out_of_memory", "address": "0x800fffd4", "value": "raw 0x00000000", "state": "uninitialised"}, {"name": "zero_request", "address": "0x800fffd0", "value": "raw 0x00000000", "state": "uninitialised"}]}, + "memory": {"items": [{"name": "allocbuf", "address": "0x80001450", "value": "char[64]"}, {"name": "allocp", "address": "0x80001490", "value": "0x00000000", "note": "jeszcze nie jest poprawnym kursorem"}], "arena": {"base": "0x80001450", "size_bytes": 64, "cursor": "0x00000000", "offset": null, "bytes": "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00"}}, + "description": "To stan wywołującego. Ramka main zajmuje 32 B; cztery sloty lokalne istnieją fizycznie, ale ich wartości C nie zostały jeszcze ustalone." + } + }, + { + "id": "reset-read-buffer-address", + "number": 2, + "label": "odczytaj adres &allocbuf[0]", + "svg_label": "02", + "progress_id": "UML04-S02", + "description": "Po prologu allocator_reset rejestr a4 zawiera świeżo wyliczony adres początku areny.", + "code_ref": "src/tasks/task04_address_arithmetic_alloc.c:20", + "snapshot_ref": "task04.reset.address", + "view": { + "connection_ref": "task04.debug.auto", + "layout": "termdebug.source-asm-dashboard-memory", + "reveal": {"anchor_ref": "src.task04.reset.assign", "align": "center"}, + "annotations": [ + {"id": "ann.reset.address", "anchor_ref": "src.task04.reset.assign", "label": "adres areny", "tone": "danger", "shape": "outline", "anchor": {"kind": "screen-text", "text": "allocp = allocbuf;", "padding_cells": 1}} + ] + }, + "snapshot": { + "pc": "0x8000114c", + "code": { + "source": "allocp = allocbuf;", + "source_ref": "task04_address_arithmetic_alloc.c:20", + "assembly": "0x80001144 lui a4,0x80001\n0x80001148 addi a4,a4,1104 # allocbuf\n0x8000114c sw a4,1168(a5) # allocp", + "note": "Adres początku areny jest już w a4; instrukcja sw wskazywana przez PC nie została jeszcze zatwierdzona." + }, + "registers": [{"name": "sp", "value": "0x800fffc0"}, {"name": "s0/fp", "value": "0x800fffd0"}, {"name": "ra", "value": "0x80001254"}, {"name": "a0", "value": "0x800014b0", "note": "reset nie używa a0"}, {"name": "a4", "value": "0x80001450", "note": "&allocbuf[0]"}, {"name": "a5", "value": "0x80001000", "note": "baza adresowania symbolu allocp"}], + "frame": {"name": "allocator_reset", "sp": "0x800fffc0", "fp": "0x800fffd0", "size_bytes": 16, "fields": [{"name": "saved s0", "address": "0x800fffc8", "value": "0x800ffff0", "state": "saved"}, {"name": "saved ra", "address": "0x800fffcc", "value": "0x80001254", "state": "saved"}]}, + "memory": {"items": [{"name": "allocbuf", "address": "0x80001450", "value": "char[64]"}, {"name": "allocp", "address": "0x80001490", "value": "0x00000000"}], "arena": {"base": "0x80001450", "size_bytes": 64, "cursor": "0x00000000", "offset": null, "bytes": "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00"}}, + "description": "Adres 0x80001450 został wyliczony w a4, ale zapis do zmiennej allocp jeszcze się nie wykonał." + } + }, + { + "id": "reset-buffer-address-result", + "number": 3, + "label": "początek areny", + "svg_label": "03", + "progress_id": "UML04-S03", + "description": "Ta przerywana strzałka interpretuje ten sam stabilny stan: wynikiem odczytu adresu jest 0x80001450 w a4.", + "code_ref": "src/tasks/task04_address_arithmetic_alloc.c:20", + "snapshot_ref": "task04.reset.address", + "view": { + "connection_ref": "task04.debug.auto", + "layout": "termdebug.source-asm-dashboard-memory", + "reveal": {"anchor_ref": "src.task04.reset.assign", "align": "center"}, + "annotations": [ + {"id": "ann.reset.a4", "anchor_ref": "reg.a4", "label": "a4 = &allocbuf[0]", "tone": "danger", "shape": "outline", "anchor": {"kind": "screen-text", "text": "a4 0x80001450", "padding_cells": 1}} + ] + }, + "snapshot": { + "pc": "0x8000114c", + "code": { + "source": "allocp = allocbuf;", + "source_ref": "task04_address_arithmetic_alloc.c:20", + "assembly": "a4 = 0x80001450 # &allocbuf[0]\npc = 0x8000114c # przed sw do allocp", + "note": "Strzałka zwrotna UML interpretuje wartość a4; nie odpowiada osobnej instrukcji." + }, + "registers": [{"name": "sp", "value": "0x800fffc0"}, {"name": "s0/fp", "value": "0x800fffd0"}, {"name": "ra", "value": "0x80001254"}, {"name": "a0", "value": "0x800014b0"}, {"name": "a4", "value": "0x80001450", "note": "początek areny"}, {"name": "a5", "value": "0x80001000"}], + "frame": {"name": "allocator_reset", "sp": "0x800fffc0", "fp": "0x800fffd0", "size_bytes": 16, "fields": [{"name": "saved s0", "address": "0x800fffc8", "value": "0x800ffff0", "state": "saved"}, {"name": "saved ra", "address": "0x800fffcc", "value": "0x80001254", "state": "saved"}]}, + "memory": {"items": [{"name": "allocbuf", "address": "0x80001450", "value": "char[64]"}, {"name": "allocp", "address": "0x80001490", "value": "0x00000000"}], "arena": {"base": "0x80001450", "size_bytes": 64, "cursor": "0x00000000", "offset": null, "bytes": "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00"}}, + "description": "Krok 03 nie wykonuje dodatkowej instrukcji; pokazuje wartość adresu zwróconą logicznie przez uczestnika allocbuf." + } + }, + { + "id": "reset-store-cursor", + "number": 4, + "label": "zapisz allocp = &allocbuf[0]", + "svg_label": "04", + "progress_id": "UML04-S04", + "description": "Instrukcja sw zakończyła zapis do symbolu allocp; od tej chwili kursor ma poprawny offset 0.", + "code_ref": "src/tasks/task04_address_arithmetic_alloc.c:20", + "snapshot_ref": "task04.reset.store", + "view": { + "connection_ref": "task04.debug.auto", + "layout": "termdebug.source-asm-dashboard-memory", + "reveal": {"anchor_ref": "src.task04.reset.assign", "align": "center"}, + "annotations": [ + {"id": "ann.reset.store", "anchor_ref": "asm.task04.reset.store-allocp", "label": "allocp ← allocbuf", "tone": "danger", "shape": "outline", "anchor": {"kind": "screen-text", "text": "a4,1168(a5)", "padding_cells": 1}} + ] + }, + "snapshot": { + "pc": "0x80001150", + "code": { + "source": "allocp = allocbuf;", + "source_ref": "task04_address_arithmetic_alloc.c:20", + "assembly": "0x8000114c sw a4,1168(a5) # allocp\n0x80001150 addi zero,zero,0 # PC po zapisie", + "note": "PC przesunął się za sw, więc pamięć pod symbolem allocp zawiera już 0x80001450." + }, + "registers": [{"name": "sp", "value": "0x800fffc0"}, {"name": "s0/fp", "value": "0x800fffd0"}, {"name": "ra", "value": "0x80001254"}, {"name": "a0", "value": "0x800014b0"}, {"name": "a4", "value": "0x80001450"}, {"name": "a5", "value": "0x80001000"}], + "frame": {"name": "allocator_reset", "sp": "0x800fffc0", "fp": "0x800fffd0", "size_bytes": 16, "fields": [{"name": "saved s0", "address": "0x800fffc8", "value": "0x800ffff0", "state": "saved"}, {"name": "saved ra", "address": "0x800fffcc", "value": "0x80001254", "state": "saved"}]}, + "memory": {"items": [{"name": "allocbuf", "address": "0x80001450", "value": "char[64]"}, {"name": "allocp", "address": "0x80001490", "value": "0x80001450"}], "arena": {"base": "0x80001450", "size_bytes": 64, "cursor": "0x80001450", "offset": 0, "bytes": "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00"}}, + "description": "Pomiar pamięci pod 0x80001490 daje 0x80001450, więc allocp - allocbuf = 0." + } + }, + { + "id": "reset-return", + "number": 5, + "label": "return void", + "svg_label": "05", + "progress_id": "UML04-S05", + "description": "Ramka allocator_reset zniknęła, sp wrócił do ramki main, a statyczny allocp zachował offset 0.", + "code_ref": "src/tasks/task04_address_arithmetic_alloc.c:21", + "snapshot_ref": "task04.reset.return", + "view": { + "connection_ref": "task04.debug.auto", + "layout": "termdebug.source-asm-dashboard-memory", + "reveal": {"anchor_ref": "src.task04.main.alloc5-call", "align": "center"}, + "annotations": [ + {"id": "ann.reset.return", "anchor_ref": "asm.task04.main.alloc5-arg", "label": "powrót do main", "tone": "danger", "shape": "outline", "anchor": {"kind": "screen-text", "text": "a0,5", "padding_cells": 1}} + ] + }, + "snapshot": { + "pc": "0x80001254", + "code": { + "source": "}", + "source_ref": "task04_address_arithmetic_alloc.c:21", + "assembly": "0x80001154 lw ra,12(sp)\n0x80001158 lw s0,8(sp)\n0x8000115c addi sp,sp,16\n0x80001160 ret\n0x80001254 li a0,5", + "note": "Po ret aktywna jest ponownie ramka main; następna instrukcja przygotuje argument pierwszego przydziału." + }, + "registers": [{"name": "sp", "value": "0x800fffd0"}, {"name": "s0/fp", "value": "0x800ffff0"}, {"name": "ra", "value": "0x80001254"}, {"name": "a0", "value": "0x800014b0", "note": "void: a0 nie jest wynikiem resetu"}, {"name": "a4", "value": "0x80001450"}, {"name": "a5", "value": "0x80001000"}], + "frame": {"name": "main", "sp": "0x800fffd0", "fp": "0x800ffff0", "size_bytes": 32, "fields": [{"name": "first", "address": "0x800fffdc", "value": "raw 0x00000000", "state": "uninitialised"}, {"name": "second", "address": "0x800fffd8", "value": "raw 0x00000000", "state": "uninitialised"}, {"name": "out_of_memory", "address": "0x800fffd4", "value": "raw 0x00000000", "state": "uninitialised"}, {"name": "zero_request", "address": "0x800fffd0", "value": "raw 0x00000000", "state": "uninitialised"}]}, + "memory": {"items": [{"name": "allocbuf", "address": "0x80001450", "value": "char[64]"}, {"name": "allocp", "address": "0x80001490", "value": "0x80001450"}], "arena": {"base": "0x80001450", "size_bytes": 64, "cursor": "0x80001450", "offset": 0, "bytes": "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00"}}, + "description": "Powrót usuwa tylko ramkę aktywacji. allocbuf i allocp w .bss pozostają dostępne przez cały czas działania programu." + } + } + ] + }, + { + "id": "alloc-5", + "label": "ALLOC(5)", + "description": "Pierwsza ramka alloc_local: n=5, used=0, result=allocbuf i końcowy offset 5.", + "svg_label": "ALLOC(5)", + "steps": [ + { + "id": "alloc5-call", + "number": 6, + "label": "first = alloc_local(5)", + "svg_label": "06", + "progress_id": "UML04-S06", + "description": "Po instrukcji li argument 5 jest widoczny w a0, a PC stoi przed jalr; ramka main nadal zawiera cztery lokalne wskaźniki.", + "code_ref": "src/tasks/task04_address_arithmetic_alloc.c:64", + "snapshot_ref": "task04.alloc5.enter", + "view": { + "connection_ref": "task04.debug.auto", + "layout": "termdebug.source-asm-dashboard-memory", + "reveal": {"anchor_ref": "src.task04.main.alloc5-call", "align": "center"}, + "annotations": [ + {"id": "ann.alloc5.source", "anchor_ref": "src.task04.main.alloc5-call", "label": "1 · wywołanie", "tone": "danger", "shape": "outline", "anchor": {"kind": "screen-text", "text": "first = alloc_local(5);", "padding_cells": 1}}, + {"id": "ann.alloc5.asm", "anchor_ref": "asm.task04.main.alloc5-arg", "label": "2 · li / jal", "tone": "danger", "shape": "outline", "anchor": {"kind": "screen-text", "text": "main+24 li a0,5", "padding_cells": 1}}, + {"id": "ann.alloc5.a0", "anchor_ref": "reg.a0", "label": "3 · a0 = 5", "tone": "danger", "shape": "outline", "anchor": {"kind": "screen-text", "text": "a0 0x00000005", "padding_cells": 1}}, + {"id": "ann.alloc5.arena", "anchor_ref": "memory.allocbuf", "label": "4 · arena", "tone": "danger", "shape": "outline", "anchor": {"kind": "screen-text", "text": "allocbuf[0]", "padding_cells": 1}} + ] + }, + "snapshot": { + "pc": "0x80001258", + "code": { + "source": "first = alloc_local(5);", + "source_ref": "task04_address_arithmetic_alloc.c:64", + "assembly": "0x80001254 li a0,5\n0x80001258 auipc ra,0x0 # PC\n0x8000125c jalr ra,-244(ra) # alloc_local", + "note": "To stan tuż przed wywołaniem: li ustawiło a0=5, ale prolog alloc_local jeszcze się nie wykonał." + }, + "registers": [{"name": "sp", "value": "0x800fffd0"}, {"name": "s0/fp", "value": "0x800ffff0"}, {"name": "ra", "value": "0x80001254"}, {"name": "a0", "value": "0x00000005", "note": "pierwszy argument RV32 ABI"}, {"name": "a4", "value": "0x80001450"}, {"name": "a5", "value": "0x80001000"}], + "frame": {"name": "main", "sp": "0x800fffd0", "fp": "0x800ffff0", "size_bytes": 32, "fields": [{"name": "zero_request", "address": "0x800fffd0", "value": "raw 0x00000000", "state": "uninitialised"}, {"name": "out_of_memory", "address": "0x800fffd4", "value": "raw 0x00000000", "state": "uninitialised"}, {"name": "second", "address": "0x800fffd8", "value": "raw 0x00000000", "state": "uninitialised"}, {"name": "first", "address": "0x800fffdc", "value": "raw 0x00000000", "state": "uninitialised"}]}, + "memory": {"items": [{"name": "allocbuf", "address": "0x80001450", "value": "char[64]"}, {"name": "allocp", "address": "0x80001490", "value": "0x80001450"}], "arena": {"base": "0x80001450", "size_bytes": 64, "cursor": "0x80001450", "offset": 0, "bytes": "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00"}}, + "description": "Przed jalr aktywna jest wyłącznie ramka main: sp=0x800fffd0, a0=5 i allocp nadal wskazuje allocbuf+0." + } + }, + { + "id": "alloc5-read-cursor", + "number": 7, + "label": "odczytaj bieżący kursor", + "svg_label": "07", + "progress_id": "UML04-S07", + "description": "Stabilny stan po odczycie pokazuje a5=0x80001450, zgodne z wartością zapisaną pod symbolem allocp.", + "code_ref": "src/tasks/task04_address_arithmetic_alloc.c:28", + "snapshot_ref": "task04.alloc5.cursor", + "view": { + "connection_ref": "task04.debug.auto", + "layout": "termdebug.source-asm-dashboard-memory", + "reveal": {"anchor_ref": "src.task04.alloc.null-check", "align": "center"}, + "annotations": [ + {"id": "ann.alloc5.cursor-read", "anchor_ref": "asm.task04.alloc.load-allocp", "label": "allocp", "tone": "danger", "shape": "outline", "anchor": {"kind": "screen-text", "text": "a5,1168(a5)", "padding_cells": 1}} + ] + }, + "snapshot": { + "pc": "0x8000118c", + "code": { + "source": "if (allocp == NULL) {\n return NULL;\n}", + "source_ref": "task04_address_arithmetic_alloc.c:28-30", + "assembly": "0x80001178 lui a5,0x80001\n0x8000117c lw a5,1168(a5) # allocp\n0x80001180 bne a5,zero,0x8000118c\n0x8000118c lui a5,0x80001", + "note": "Użyto stabilnego stanu po gałęzi: a5 zawiera architektonicznie zatwierdzony odczyt allocp." + }, + "registers": [{"name": "sp", "value": "0x800fffa0"}, {"name": "s0/fp", "value": "0x800fffd0"}, {"name": "ra", "value": "0x80001260"}, {"name": "a0", "value": "0x00000005"}, {"name": "a4", "value": "0x80001450"}, {"name": "a5", "value": "0x80001450", "note": "odczytana wartość allocp"}], + "frame": {"name": "alloc_local", "sp": "0x800fffa0", "fp": "0x800fffd0", "size_bytes": 48, "fields": [{"name": "n", "address": "0x800fffac", "value": "5", "state": "initialised"}, {"name": "used", "address": "0x800fffbc", "value": "raw 0x00000000", "state": "uninitialised"}, {"name": "result", "address": "0x800fffb8", "value": "raw 0x00000000", "state": "uninitialised"}]}, + "memory": {"items": [{"name": "allocbuf", "address": "0x80001450", "value": "char[64]"}, {"name": "allocp", "address": "0x80001490", "value": "0x80001450"}], "arena": {"base": "0x80001450", "size_bytes": 64, "cursor": "0x80001450", "offset": 0, "bytes": "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00"}}, + "description": "Hazard3 tb_gdb pokazuje wartość ładowania dopiero w stabilnym stanie po gałęzi; dlatego snapshot jest przypięty do PC 0x8000118c, a nie do chwilowego stanu potoku na 0x80001180." + } + }, + { + "id": "alloc5-cursor-result", + "number": 8, + "label": "&allocbuf[0]", + "svg_label": "08", + "progress_id": "UML04-S08", + "description": "Wynik logicznego odczytu kursora to początek areny; a5 i pamięć allocp zawierają ten sam adres.", + "code_ref": "src/tasks/task04_address_arithmetic_alloc.c:33", + "snapshot_ref": "task04.alloc5.cursor", + "view": { + "connection_ref": "task04.debug.auto", + "layout": "termdebug.source-asm-dashboard-memory", + "reveal": {"anchor_ref": "src.task04.alloc.used", "align": "center"}, + "annotations": [ + {"id": "ann.alloc5.cursor-value", "anchor_ref": "reg.a5", "label": "&allocbuf[0]", "tone": "danger", "shape": "outline", "anchor": {"kind": "screen-text", "text": "a5 0x80001450", "padding_cells": 1}} + ] + }, + "snapshot": { + "pc": "0x8000118c", + "code": { + "source": "used = allocp - allocbuf;", + "source_ref": "task04_address_arithmetic_alloc.c:33", + "assembly": "a5 = 0x80001450 # wartość allocp\npc = 0x8000118c # stabilny stan po lw/bne", + "note": "Strzałka zwrotna UML nazywa wartość odczytaną w kroku 07; nie wykonuje dodatkowej instrukcji." + }, + "registers": [{"name": "sp", "value": "0x800fffa0"}, {"name": "s0/fp", "value": "0x800fffd0"}, {"name": "ra", "value": "0x80001260"}, {"name": "a0", "value": "0x00000005"}, {"name": "a4", "value": "0x80001450"}, {"name": "a5", "value": "0x80001450"}], + "frame": {"name": "alloc_local", "sp": "0x800fffa0", "fp": "0x800fffd0", "size_bytes": 48, "fields": [{"name": "n", "address": "0x800fffac", "value": "5", "state": "initialised"}, {"name": "used", "address": "0x800fffbc", "value": "raw 0x00000000", "state": "uninitialised"}, {"name": "result", "address": "0x800fffb8", "value": "raw 0x00000000", "state": "uninitialised"}]}, + "memory": {"items": [{"name": "allocbuf", "address": "0x80001450", "value": "char[64]"}, {"name": "allocp", "address": "0x80001490", "value": "0x80001450"}], "arena": {"base": "0x80001450", "size_bytes": 64, "cursor": "0x80001450", "offset": 0, "bytes": "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00"}}, + "description": "Strzałka zwrotna nie dodaje instrukcji; wiąże wartość a5=0x80001450 z pojęciem pierwszego wolnego bajtu." + } + }, + { + "id": "alloc5-read-buffer-address", + "number": 9, + "label": "odczytaj adres początku areny", + "svg_label": "09", + "progress_id": "UML04-S09", + "description": "Po zbudowaniu adresu allocbuf oba rejestry robocze a4 i a5 mają 0x80001450.", + "code_ref": "src/tasks/task04_address_arithmetic_alloc.c:33", + "snapshot_ref": "task04.alloc5.buffer-address", + "view": { + "connection_ref": "task04.debug.auto", + "layout": "termdebug.source-asm-dashboard-memory", + "reveal": {"anchor_ref": "src.task04.alloc.used", "align": "center"}, + "annotations": [ + {"id": "ann.alloc5.buffer-address", "anchor_ref": "asm.task04.alloc.address-allocbuf", "label": "&allocbuf[0]", "tone": "danger", "shape": "outline", "anchor": {"kind": "screen-text", "text": "a5,a5,1104", "padding_cells": 1}} + ] + }, + "snapshot": { + "pc": "0x8000119c", + "code": { + "source": "used = allocp - allocbuf;", + "source_ref": "task04_address_arithmetic_alloc.c:33", + "assembly": "0x8000118c lui a5,0x80001\n0x80001190 lw a4,1168(a5) # allocp\n0x80001194 lui a5,0x80001\n0x80001198 addi a5,a5,1104 # allocbuf\n0x8000119c sub a5,a4,a5", + "note": "Tuż przed sub oba operandy mają adres 0x80001450." + }, + "registers": [{"name": "sp", "value": "0x800fffa0"}, {"name": "s0/fp", "value": "0x800fffd0"}, {"name": "ra", "value": "0x80001260"}, {"name": "a0", "value": "0x00000005"}, {"name": "a4", "value": "0x80001450", "note": "allocp"}, {"name": "a5", "value": "0x80001450", "note": "allocbuf"}], + "frame": {"name": "alloc_local", "sp": "0x800fffa0", "fp": "0x800fffd0", "size_bytes": 48, "fields": [{"name": "n", "address": "0x800fffac", "value": "5", "state": "initialised"}, {"name": "used", "address": "0x800fffbc", "value": "raw 0x00000000", "state": "uninitialised"}, {"name": "result", "address": "0x800fffb8", "value": "raw 0x00000000", "state": "uninitialised"}]}, + "memory": {"items": [{"name": "allocbuf", "address": "0x80001450", "value": "char[64]"}, {"name": "allocp", "address": "0x80001490", "value": "0x80001450"}], "arena": {"base": "0x80001450", "size_bytes": 64, "cursor": "0x80001450", "offset": 0, "bytes": "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00"}}, + "description": "Następna instrukcja odejmie a5 od a4. Równe adresy przewidują wynik used=0." + } + }, + { + "id": "alloc5-buffer-address-result", + "number": 10, + "label": "&allocbuf[0]", + "svg_label": "10", + "progress_id": "UML04-S10", + "description": "Początek areny używany w odejmowaniu adresów ma adres 0x80001450.", + "code_ref": "src/tasks/task04_address_arithmetic_alloc.c:33", + "snapshot_ref": "task04.alloc5.buffer-address", + "view": { + "connection_ref": "task04.debug.auto", + "layout": "termdebug.source-asm-dashboard-memory", + "reveal": {"anchor_ref": "src.task04.alloc.used", "align": "center"}, + "annotations": [ + {"id": "ann.alloc5.buffer-result", "anchor_ref": "reg.a5", "label": "początek areny", "tone": "danger", "shape": "outline", "anchor": {"kind": "screen-text", "text": "a5 0x80001450", "padding_cells": 1}} + ] + }, + "snapshot": { + "pc": "0x8000119c", + "code": { + "source": "used = allocp - allocbuf;", + "source_ref": "task04_address_arithmetic_alloc.c:33", + "assembly": "a4 = 0x80001450 # allocp\na5 = 0x80001450 # &allocbuf[0]\npc = 0x8000119c # przed sub", + "note": "Strzałka zwrotna UML eksponuje drugi operand odejmowania i dzieli stan z krokiem 09." + }, + "registers": [{"name": "sp", "value": "0x800fffa0"}, {"name": "s0/fp", "value": "0x800fffd0"}, {"name": "ra", "value": "0x80001260"}, {"name": "a0", "value": "0x00000005"}, {"name": "a4", "value": "0x80001450"}, {"name": "a5", "value": "0x80001450"}], + "frame": {"name": "alloc_local", "sp": "0x800fffa0", "fp": "0x800fffd0", "size_bytes": 48, "fields": [{"name": "n", "address": "0x800fffac", "value": "5", "state": "initialised"}, {"name": "used", "address": "0x800fffbc", "value": "raw 0x00000000", "state": "uninitialised"}, {"name": "result", "address": "0x800fffb8", "value": "raw 0x00000000", "state": "uninitialised"}]}, + "memory": {"items": [{"name": "allocbuf", "address": "0x80001450", "value": "char[64]"}, {"name": "allocp", "address": "0x80001490", "value": "0x80001450"}], "arena": {"base": "0x80001450", "size_bytes": 64, "cursor": "0x80001450", "offset": 0, "bytes": "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00"}}, + "description": "Krok 10 jest odpowiedzią logiczną allocbuf i dzieli snapshot z krokiem 09." + } + }, + { + "id": "alloc5-used", + "number": 11, + "label": "used = allocp - allocbuf = 0", + "svg_label": "11", + "progress_id": "UML04-S11", + "description": "Odejmowanie adresów dało 0, a wynik został zapisany do pola used w ramce.", + "code_ref": "src/tasks/task04_address_arithmetic_alloc.c:33", + "snapshot_ref": "task04.alloc5.used", + "view": { + "connection_ref": "task04.debug.auto", + "layout": "termdebug.source-asm-dashboard-memory", + "reveal": {"anchor_ref": "src.task04.alloc.used", "align": "center"}, + "annotations": [ + {"id": "ann.alloc5.used", "anchor_ref": "src.task04.alloc.used", "label": "used = 0", "tone": "danger", "shape": "outline", "anchor": {"kind": "screen-text", "text": "used = allocp - allocbuf;", "padding_cells": 1}} + ] + }, + "snapshot": { + "pc": "0x800011a4", + "code": { + "source": "used = allocp - allocbuf;", + "source_ref": "task04_address_arithmetic_alloc.c:33", + "assembly": "0x8000119c sub a5,a4,a5\n0x800011a0 sw a5,-20(s0) # used\n0x800011a4 lw a5,-36(s0) # n", + "note": "PC znajduje się za zapisem, dlatego slot used i a5 z wyniku odejmowania potwierdzają offset 0." + }, + "registers": [{"name": "sp", "value": "0x800fffa0"}, {"name": "s0/fp", "value": "0x800fffd0"}, {"name": "ra", "value": "0x80001260"}, {"name": "a0", "value": "0x00000005"}, {"name": "a4", "value": "0x80001450"}, {"name": "a5", "value": "0x00000000", "note": "wynik odejmowania"}], + "frame": {"name": "alloc_local", "sp": "0x800fffa0", "fp": "0x800fffd0", "size_bytes": 48, "fields": [{"name": "n", "address": "0x800fffac", "value": "5", "state": "initialised"}, {"name": "used", "address": "0x800fffbc", "value": "0", "state": "initialised"}, {"name": "result", "address": "0x800fffb8", "value": "raw 0x00000000", "state": "uninitialised"}]}, + "memory": {"items": [{"name": "allocbuf", "address": "0x80001450", "value": "char[64]"}, {"name": "allocp", "address": "0x80001490", "value": "0x80001450"}], "arena": {"base": "0x80001450", "size_bytes": 64, "cursor": "0x80001450", "offset": 0, "bytes": "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00"}}, + "description": "Pole used pod 0x800fffbc zawiera już 0. Pole result nadal nie ma wartości języka C." + } + }, + { + "id": "alloc5-commit", + "number": 12, + "label": "result = allocp; allocp += 5", + "svg_label": "12", + "progress_id": "UML04-S12", + "description": "result zachował stary kursor 0x80001450, a zapis do allocp przesunął kursor na 0x80001455.", + "code_ref": "src/tasks/task04_address_arithmetic_alloc.c:39-40", + "snapshot_ref": "task04.alloc5.commit", + "view": { + "connection_ref": "task04.debug.auto", + "layout": "termdebug.source-asm-dashboard-memory", + "reveal": {"anchor_ref": "src.task04.alloc.commit", "align": "center"}, + "annotations": [ + {"id": "ann.alloc5.commit", "anchor_ref": "src.task04.alloc.commit", "label": "offset 0 → 5", "tone": "danger", "shape": "outline", "anchor": {"kind": "screen-text", "text": "allocp += n;", "padding_cells": 1}} + ] + }, + "snapshot": { + "pc": "0x80001200", + "code": { + "source": "result = allocp;\nallocp += n;", + "source_ref": "task04_address_arithmetic_alloc.c:39-40", + "assembly": "0x800011e4 sw a5,-24(s0) # result\n0x800011ec lw a4,1168(a5) # allocp\n0x800011f0 lw a5,-36(s0) # n\n0x800011f4 add a4,a4,a5\n0x800011fc sw a4,1168(a5) # allocp\n0x80001200 lw a5,-24(s0) # result", + "note": "Stary kursor trafia do result, natomiast suma allocp+n zostaje zapisana jako nowy kursor." + }, + "registers": [{"name": "sp", "value": "0x800fffa0"}, {"name": "s0/fp", "value": "0x800fffd0"}, {"name": "ra", "value": "0x80001260"}, {"name": "a0", "value": "0x00000005"}, {"name": "a4", "value": "0x80001455", "note": "nowy kursor"}, {"name": "a5", "value": "0x80001000"}], + "frame": {"name": "alloc_local", "sp": "0x800fffa0", "fp": "0x800fffd0", "size_bytes": 48, "fields": [{"name": "n", "address": "0x800fffac", "value": "5", "state": "initialised"}, {"name": "used", "address": "0x800fffbc", "value": "0", "state": "initialised"}, {"name": "result", "address": "0x800fffb8", "value": "0x80001450", "state": "initialised"}]}, + "memory": {"items": [{"name": "allocbuf", "address": "0x80001450", "value": "char[64]"}, {"name": "allocp", "address": "0x80001490", "value": "0x80001455"}], "arena": {"base": "0x80001450", "size_bytes": 64, "cursor": "0x80001455", "offset": 5, "bytes": "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00"}}, + "description": "Przydział rezerwuje pięć bajtów bez zapisywania ich treści. Dlatego offset zmienia się na 5, lecz podgląd areny nadal zawiera zera." + } + }, + { + "id": "alloc5-return", + "number": 13, + "label": "return first = &allocbuf[0]", + "svg_label": "13", + "progress_id": "UML04-S13", + "description": "Po powrocie a0 i lokalne first mają 0x80001450; ramka alloc_local zniknęła, a allocp pozostał na offsecie 5.", + "code_ref": "src/tasks/task04_address_arithmetic_alloc.c:41", + "snapshot_ref": "task04.alloc5.return", + "view": { + "connection_ref": "task04.debug.auto", + "layout": "termdebug.source-asm-dashboard-memory", + "reveal": {"anchor_ref": "src.task04.main.alloc5-call", "align": "center"}, + "annotations": [ + {"id": "ann.alloc5.return", "anchor_ref": "src.task04.main.alloc5-call", "label": "first = &allocbuf[0]", "tone": "danger", "shape": "outline", "anchor": {"kind": "screen-text", "text": "first = alloc_local(5);", "padding_cells": 1}} + ] + }, + "snapshot": { + "pc": "0x80001264", + "code": { + "source": "return result;\n/* main: */ first = alloc_local(5);", + "source_ref": "task04_address_arithmetic_alloc.c:41,64", + "assembly": "0x80001200 lw a5,-24(s0) # result\n0x80001204 mv a0,a5\n0x80001214 ret\n0x80001260 sw a0,-20(s0) # first\n0x80001264 li a0,7", + "note": "Wartość wróciła w a0 i została zapisana do lokalnej first w ramce main." + }, + "registers": [{"name": "sp", "value": "0x800fffd0"}, {"name": "s0/fp", "value": "0x800ffff0"}, {"name": "ra", "value": "0x80001260"}, {"name": "a0", "value": "0x80001450", "note": "wartość zwrotna"}, {"name": "a4", "value": "0x80001455"}, {"name": "a5", "value": "0x80001450"}], + "frame": {"name": "main", "sp": "0x800fffd0", "fp": "0x800ffff0", "size_bytes": 32, "fields": [{"name": "first", "address": "0x800fffdc", "value": "0x80001450", "state": "initialised"}, {"name": "second", "address": "0x800fffd8", "value": "raw 0x00000000", "state": "uninitialised"}, {"name": "out_of_memory", "address": "0x800fffd4", "value": "raw 0x00000000", "state": "uninitialised"}, {"name": "zero_request", "address": "0x800fffd0", "value": "raw 0x00000000", "state": "uninitialised"}]}, + "memory": {"items": [{"name": "allocbuf", "address": "0x80001450", "value": "char[64]"}, {"name": "allocp", "address": "0x80001490", "value": "0x80001455"}], "arena": {"base": "0x80001450", "size_bytes": 64, "cursor": "0x80001455", "offset": 5, "bytes": "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00"}}, + "description": "first jest pierwszą zainicjalizowaną lokalną main. second oraz dwa późniejsze wyniki nadal są nieustalone." + } + } + ] + }, + { + "id": "alloc-7", + "label": "ALLOC(7)", + "description": "Druga ramka alloc_local: n=7, used=5, result=allocbuf+5 i końcowy offset 12.", + "svg_label": "ALLOC(7)", + "steps": [ + { + "id": "alloc7-call", + "number": 14, + "label": "second = alloc_local(7)", + "svg_label": "14", + "progress_id": "UML04-S14", + "description": "Po instrukcji li argument 7 jest widoczny w a0, first jest już zapisany w ramce main, a PC stoi przed drugim jalr.", + "code_ref": "src/tasks/task04_address_arithmetic_alloc.c:65", + "snapshot_ref": "task04.alloc7.enter", + "view": { + "connection_ref": "task04.debug.auto", + "layout": "termdebug.source-asm-dashboard-memory", + "reveal": {"anchor_ref": "src.task04.main.alloc7-call", "align": "center"}, + "annotations": [ + {"id": "ann.alloc7.source", "anchor_ref": "src.task04.main.alloc7-call", "label": "alloc(7)", "tone": "danger", "shape": "outline", "anchor": {"kind": "screen-text", "text": "second = alloc_local(7);", "padding_cells": 1}}, + {"id": "ann.alloc7.a0", "anchor_ref": "reg.a0", "label": "a0 = 7", "tone": "danger", "shape": "outline", "anchor": {"kind": "screen-text", "text": "a0 0x00000007", "padding_cells": 1}} + ] + }, + "snapshot": { + "pc": "0x80001268", + "code": { + "source": "second = alloc_local(7);", + "source_ref": "task04_address_arithmetic_alloc.c:65", + "assembly": "0x80001264 li a0,7\n0x80001268 auipc ra,0x0 # PC\n0x8000126c jalr ra,-260(ra) # alloc_local", + "note": "To stan przed drugim wywołaniem: pierwsze zwróciło allocbuf+0 i przesunęło kursor do offsetu 5." + }, + "registers": [{"name": "sp", "value": "0x800fffd0"}, {"name": "s0/fp", "value": "0x800ffff0"}, {"name": "ra", "value": "0x80001260"}, {"name": "a0", "value": "0x00000007"}, {"name": "a4", "value": "0x80001455"}, {"name": "a5", "value": "0x80001450"}], + "frame": {"name": "main", "sp": "0x800fffd0", "fp": "0x800ffff0", "size_bytes": 32, "fields": [{"name": "zero_request", "address": "0x800fffd0", "value": "raw 0x00000000", "state": "uninitialised"}, {"name": "out_of_memory", "address": "0x800fffd4", "value": "raw 0x00000000", "state": "uninitialised"}, {"name": "second", "address": "0x800fffd8", "value": "raw 0x00000000", "state": "uninitialised"}, {"name": "first", "address": "0x800fffdc", "value": "0x80001450", "state": "initialised"}]}, + "memory": {"items": [{"name": "allocbuf", "address": "0x80001450", "value": "char[64]"}, {"name": "allocp", "address": "0x80001490", "value": "0x80001455"}], "arena": {"base": "0x80001450", "size_bytes": 64, "cursor": "0x80001455", "offset": 5, "bytes": "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00"}}, + "description": "Ramka main pokazuje już first=0x80001450, lecz second pozostaje niezainicjalizowany aż do powrotu drugiego alloc_local." + } + }, + { + "id": "alloc7-read-cursor", + "number": 15, + "label": "odczytaj bieżący kursor", + "svg_label": "15", + "progress_id": "UML04-S15", + "description": "Stabilny odczyt allocp daje 0x80001455, czyli pięć bajtów za początkiem areny.", + "code_ref": "src/tasks/task04_address_arithmetic_alloc.c:28", + "snapshot_ref": "task04.alloc7.cursor", + "view": { + "connection_ref": "task04.debug.auto", + "layout": "termdebug.source-asm-dashboard-memory", + "reveal": {"anchor_ref": "src.task04.alloc.null-check", "align": "center"}, + "annotations": [ + {"id": "ann.alloc7.cursor-read", "anchor_ref": "asm.task04.alloc.load-allocp", "label": "allocbuf + 5", "tone": "danger", "shape": "outline", "anchor": {"kind": "screen-text", "text": "a5,1168(a5)", "padding_cells": 1}} + ] + }, + "snapshot": { + "pc": "0x8000118c", + "code": { + "source": "if (allocp == NULL) {\n return NULL;\n}", + "source_ref": "task04_address_arithmetic_alloc.c:28-30", + "assembly": "0x80001178 lui a5,0x80001\n0x8000117c lw a5,1168(a5) # allocp\n0x80001180 bne a5,zero,0x8000118c\n0x8000118c lui a5,0x80001", + "note": "Stabilny stan po gałęzi zawiera bieżący kursor 0x80001455, czyli allocbuf+5." + }, + "registers": [{"name": "sp", "value": "0x800fffa0"}, {"name": "s0/fp", "value": "0x800fffd0"}, {"name": "ra", "value": "0x80001270"}, {"name": "a0", "value": "0x00000007"}, {"name": "a4", "value": "0x80001455"}, {"name": "a5", "value": "0x80001455", "note": "odczytana wartość allocp"}], + "frame": {"name": "alloc_local", "sp": "0x800fffa0", "fp": "0x800fffd0", "size_bytes": 48, "fields": [{"name": "n", "address": "0x800fffac", "value": "7", "state": "initialised"}, {"name": "used", "address": "0x800fffbc", "value": "raw 0x00000000", "state": "uninitialised"}, {"name": "result", "address": "0x800fffb8", "value": "raw 0x80001450", "state": "uninitialised"}]}, + "memory": {"items": [{"name": "allocbuf", "address": "0x80001450", "value": "char[64]"}, {"name": "allocp", "address": "0x80001490", "value": "0x80001455"}], "arena": {"base": "0x80001450", "size_bytes": 64, "cursor": "0x80001455", "offset": 5, "bytes": "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00"}}, + "description": "a5 i pamięć pod symbolem allocp są zgodne. Snapshot używa stabilnego PC 0x8000118c z tego samego powodu co krok 07." + } + }, + { + "id": "alloc7-cursor-result", + "number": 16, + "label": "&allocbuf[5]", + "svg_label": "16", + "progress_id": "UML04-S16", + "description": "Wynik odczytu kursora to adres 0x80001455, czyli allocbuf + 5.", + "code_ref": "src/tasks/task04_address_arithmetic_alloc.c:33", + "snapshot_ref": "task04.alloc7.cursor", + "view": { + "connection_ref": "task04.debug.auto", + "layout": "termdebug.source-asm-dashboard-memory", + "reveal": {"anchor_ref": "src.task04.alloc.used", "align": "center"}, + "annotations": [ + {"id": "ann.alloc7.cursor-value", "anchor_ref": "reg.a5", "label": "&allocbuf[5]", "tone": "danger", "shape": "outline", "anchor": {"kind": "screen-text", "text": "a5 0x80001455", "padding_cells": 1}} + ] + }, + "snapshot": { + "pc": "0x8000118c", + "code": { + "source": "used = allocp - allocbuf;", + "source_ref": "task04_address_arithmetic_alloc.c:33", + "assembly": "a5 = 0x80001455 # wartość allocp\npc = 0x8000118c # stabilny stan po lw/bne", + "note": "Strzałka zwrotna UML interpretuje kursor jako &allocbuf[5] i nie dodaje instrukcji." + }, + "registers": [{"name": "sp", "value": "0x800fffa0"}, {"name": "s0/fp", "value": "0x800fffd0"}, {"name": "ra", "value": "0x80001270"}, {"name": "a0", "value": "0x00000007"}, {"name": "a4", "value": "0x80001455"}, {"name": "a5", "value": "0x80001455"}], + "frame": {"name": "alloc_local", "sp": "0x800fffa0", "fp": "0x800fffd0", "size_bytes": 48, "fields": [{"name": "n", "address": "0x800fffac", "value": "7", "state": "initialised"}, {"name": "used", "address": "0x800fffbc", "value": "raw 0x00000000", "state": "uninitialised"}, {"name": "result", "address": "0x800fffb8", "value": "raw 0x80001450", "state": "uninitialised"}]}, + "memory": {"items": [{"name": "allocbuf", "address": "0x80001450", "value": "char[64]"}, {"name": "allocp", "address": "0x80001490", "value": "0x80001455"}], "arena": {"base": "0x80001450", "size_bytes": 64, "cursor": "0x80001455", "offset": 5, "bytes": "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00"}}, + "description": "Krok 16 interpretuje adres: 0x80001455 - 0x80001450 = 5." + } + }, + { + "id": "alloc7-used", + "number": 17, + "label": "used = allocp - allocbuf = 5", + "svg_label": "17", + "progress_id": "UML04-S17", + "description": "Po odejmowaniu a5=5 i slot used=5 dowodzą, że pierwszy przydział zajął pięć bajtów.", + "code_ref": "src/tasks/task04_address_arithmetic_alloc.c:33", + "snapshot_ref": "task04.alloc7.used", + "view": { + "connection_ref": "task04.debug.auto", + "layout": "termdebug.source-asm-dashboard-memory", + "reveal": {"anchor_ref": "src.task04.alloc.used", "align": "center"}, + "annotations": [ + {"id": "ann.alloc7.used", "anchor_ref": "src.task04.alloc.used", "label": "used = 5", "tone": "danger", "shape": "outline", "anchor": {"kind": "screen-text", "text": "used = allocp - allocbuf;", "padding_cells": 1}} + ] + }, + "snapshot": { + "pc": "0x800011a4", + "code": { + "source": "used = allocp - allocbuf;", + "source_ref": "task04_address_arithmetic_alloc.c:33", + "assembly": "0x80001190 lw a4,1168(a5) # allocp\n0x80001198 addi a5,a5,1104 # allocbuf\n0x8000119c sub a5,a4,a5\n0x800011a0 sw a5,-20(s0) # used\n0x800011a4 lw a5,-36(s0) # n", + "note": "Różnica adresów 0x80001455−0x80001450 daje pięć bajtów i trafia do pola used." + }, + "registers": [{"name": "sp", "value": "0x800fffa0"}, {"name": "s0/fp", "value": "0x800fffd0"}, {"name": "ra", "value": "0x80001270"}, {"name": "a0", "value": "0x00000007"}, {"name": "a4", "value": "0x80001455"}, {"name": "a5", "value": "0x00000005"}], + "frame": {"name": "alloc_local", "sp": "0x800fffa0", "fp": "0x800fffd0", "size_bytes": 48, "fields": [{"name": "n", "address": "0x800fffac", "value": "7", "state": "initialised"}, {"name": "used", "address": "0x800fffbc", "value": "5", "state": "initialised"}, {"name": "result", "address": "0x800fffb8", "value": "raw 0x80001450", "state": "uninitialised"}]}, + "memory": {"items": [{"name": "allocbuf", "address": "0x80001450", "value": "char[64]"}, {"name": "allocp", "address": "0x80001490", "value": "0x80001455"}], "arena": {"base": "0x80001450", "size_bytes": 64, "cursor": "0x80001455", "offset": 5, "bytes": "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00"}}, + "description": "used jest już zainicjalizowane. result wciąż pokazuje jedynie surową pozostałość w slocie i pozostaje oznaczone znakiem zapytania." + } + }, + { + "id": "alloc7-commit", + "number": 18, + "label": "result = allocp; allocp += 7", + "svg_label": "18", + "progress_id": "UML04-S18", + "description": "result przyjmuje 0x80001455, a allocp przesuwa się o siedem bajtów do 0x8000145c, czyli offsetu 12.", + "code_ref": "src/tasks/task04_address_arithmetic_alloc.c:39-40", + "snapshot_ref": "task04.alloc7.commit", + "view": { + "connection_ref": "task04.debug.auto", + "layout": "termdebug.source-asm-dashboard-memory", + "reveal": {"anchor_ref": "src.task04.alloc.commit", "align": "center"}, + "annotations": [ + {"id": "ann.alloc7.commit", "anchor_ref": "src.task04.alloc.commit", "label": "offset 5 → 12", "tone": "danger", "shape": "outline", "anchor": {"kind": "screen-text", "text": "allocp += n;", "padding_cells": 1}} + ] + }, + "snapshot": { + "pc": "0x80001200", + "code": { + "source": "result = allocp;\nallocp += n;", + "source_ref": "task04_address_arithmetic_alloc.c:39-40", + "assembly": "0x800011e4 sw a5,-24(s0) # result\n0x800011ec lw a4,1168(a5) # allocp\n0x800011f0 lw a5,-36(s0) # n\n0x800011f4 add a4,a4,a5\n0x800011fc sw a4,1168(a5) # allocp\n0x80001200 lw a5,-24(s0) # result", + "note": "Stary kursor 0x80001455 staje się result, a zapis 0x8000145c ustala końcowy offset 12." + }, + "registers": [{"name": "sp", "value": "0x800fffa0"}, {"name": "s0/fp", "value": "0x800fffd0"}, {"name": "ra", "value": "0x80001270"}, {"name": "a0", "value": "0x00000007"}, {"name": "a4", "value": "0x8000145c", "note": "nowy kursor"}, {"name": "a5", "value": "0x80001000"}], + "frame": {"name": "alloc_local", "sp": "0x800fffa0", "fp": "0x800fffd0", "size_bytes": 48, "fields": [{"name": "n", "address": "0x800fffac", "value": "7", "state": "initialised"}, {"name": "used", "address": "0x800fffbc", "value": "5", "state": "initialised"}, {"name": "result", "address": "0x800fffb8", "value": "0x80001455", "state": "initialised"}]}, + "memory": {"items": [{"name": "allocbuf", "address": "0x80001450", "value": "char[64]"}, {"name": "allocp", "address": "0x80001490", "value": "0x8000145c"}], "arena": {"base": "0x80001450", "size_bytes": 64, "cursor": "0x8000145c", "offset": 12, "bytes": "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00"}}, + "description": "Stan pamięci potwierdza 5 + 7 = 12. Arena nadal zawiera zera, ponieważ sam alokator przesuwa kursor, ale nie inicjalizuje danych użytkownika." + } + }, + { + "id": "alloc7-return", + "number": 19, + "label": "return second = &allocbuf[5]", + "svg_label": "19", + "progress_id": "UML04-S19", + "description": "Po powrocie second=0x80001455, first=0x80001450, a statyczny allocp pozostaje na 0x8000145c.", + "code_ref": "src/tasks/task04_address_arithmetic_alloc.c:41", + "snapshot_ref": "task04.alloc7.return", + "view": { + "connection_ref": "task04.debug.auto", + "layout": "termdebug.source-asm-dashboard-memory", + "reveal": {"anchor_ref": "src.task04.main.alloc7-call", "align": "center"}, + "annotations": [ + {"id": "ann.alloc7.return", "anchor_ref": "src.task04.main.alloc7-call", "label": "second = &allocbuf[5]", "tone": "danger", "shape": "outline", "anchor": {"kind": "screen-text", "text": "second = alloc_local(7);", "padding_cells": 1}} + ] + }, + "snapshot": { + "pc": "0x80001274", + "code": { + "source": "return result;\n/* main: */ second = alloc_local(7);", + "source_ref": "task04_address_arithmetic_alloc.c:41,65", + "assembly": "0x80001200 lw a5,-24(s0) # result\n0x80001204 mv a0,a5\n0x80001214 ret\n0x80001270 sw a0,-24(s0) # second\n0x80001274 li a0,64", + "note": "Wartość 0x80001455 wróciła w a0 i została zapisana do second; kolejna instrukcja rozpoczyna już test braku pamięci." + }, + "registers": [{"name": "sp", "value": "0x800fffd0"}, {"name": "s0/fp", "value": "0x800ffff0"}, {"name": "ra", "value": "0x80001270"}, {"name": "a0", "value": "0x80001455", "note": "wartość zwrotna"}, {"name": "a4", "value": "0x8000145c"}, {"name": "a5", "value": "0x80001455"}], + "frame": {"name": "main", "sp": "0x800fffd0", "fp": "0x800ffff0", "size_bytes": 32, "fields": [{"name": "first", "address": "0x800fffdc", "value": "0x80001450", "state": "initialised"}, {"name": "second", "address": "0x800fffd8", "value": "0x80001455", "state": "initialised"}, {"name": "out_of_memory", "address": "0x800fffd4", "value": "raw 0x00000000", "state": "uninitialised"}, {"name": "zero_request", "address": "0x800fffd0", "value": "raw 0x00000000", "state": "uninitialised"}]}, + "memory": {"items": [{"name": "allocbuf", "address": "0x80001450", "value": "char[64]"}, {"name": "allocp", "address": "0x80001490", "value": "0x8000145c"}], "arena": {"base": "0x80001450", "size_bytes": 64, "cursor": "0x8000145c", "offset": 12, "bytes": "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00"}}, + "description": "Ramka alloc_local zniknęła. Ramka main zawiera oba wyniki, a stan alokatora w .bss zachowuje offset 12." + } + } + ] + } + ] + } + }, + { + "path": "assets/task04-first-allocation-annotated.png", + "caption": "KOD + DEBUG — zatrzymanie przed pierwszym przydziałem: (1) wywołanie w C, (2) li/jal w RISC-V, (3) argument n=5 w a0, (4) allocbuf przed zapisem. Połącz te cztery miejsca z komunikatem alloc(5) na UML.", + "label": "fig:task04-first-allocation", + "alt": "Termdebug Task04: GDB Dashboard po lewej, kod C i listing RISC-V po prawej oraz pusty allocbuf", + "kind": "screenshot", + "width": 1.0 + } + ] + } + ], + "tasks": { + "task01": { + "prompt_tex": "\\textbf{Adres, \\texttt{\\&} i dereferencja.} Przewidź i zmierz wartości \\texttt{x}, \\texttt{y}, \\texttt{z[0]}, \\texttt{z[1]} oraz relację \\texttt{iq == \\&z[0]}. Oczekiwane: \\texttt{x=0 y=1 z0=7 z1=12 same=1}.", + "criterion": "Wartości są zgodne, iq wskazuje z[0], a g_task01_pass ma wartość 1.", + "educational_requirement_refs": ["PTR.WE01", "PTR.WE02"], + "learning_effect_refs": ["PTR.EN01", "PTR.EK01", "PTR.EK02"], + "assessment_criterion_ref": "PTR.KW01" + }, + "task02": { + "prompt_tex": "\\textbf{Wskaźnik jako argument funkcji.} Prześledź \\texttt{swap\\_int} i \\texttt{parse\\_int}; porównaj ramkę funkcji z ramką \\texttt{main} oraz początkowe argumenty w \\texttt{a0/a1}. Oczekiwane: \\texttt{a=19 b=7 parsed=-42 status=1}.", + "criterion": "Zmiana obiektów wywołującego i przesunięcie wskaźnika wejściowego są wyjaśnione; g_task02_pass = 1.", + "educational_requirement_refs": ["PTR.WE01", "PTR.WE02"], + "learning_effect_refs": ["PTR.EN01", "PTR.EK01", "PTR.EK02"], + "assessment_criterion_ref": "PTR.KW01" + }, + "task03": { + "prompt_tex": "\\textbf{Tablica i arytmetyka wskaźnika.} Wykaż równoważność \\texttt{a[i]}, \\texttt{*(a+i)} i \\texttt{pa[i]}; zmierz różnicę adresów w elementach i bajtach. Oczekiwane: \\texttt{first=3 p2=8 i2=8 sum=42 len=5}.", + "criterion": "Wyniki i skala indeksu są wyjaśnione; g_task03_pass = 1.", + "educational_requirement_refs": ["PTR.WE01", "PTR.WE02"], + "learning_effect_refs": ["PTR.EN01", "PTR.EK01", "PTR.EK02"], + "assessment_criterion_ref": "PTR.KW01" + }, + "task04": { + "title": "K&R 5.4 -- Linear Memory Allocator", + "uuid": "98dbe323-c624-53d6-9fe2-4ee688c44b38", + "prompt_tex": "\\textbf{K\\&R 5.4 -- czysty alokator liniowy typu bump.} Zrealizuj wyłącznie reset całej areny oraz przydział przesuwający jeden kursor. Przewidź sekwencję reset $\\rightarrow$ alloc(5) $\\rightarrow$ alloc(7), a następnie potwierdź ją w kodzie, ABI RV32 i pamięci.", + "criterion": "Potwierdzono first=allocbuf+0, second=allocbuf+5 i allocp=allocbuf+12, bajty A B x y, sumę 372, odmowę braku pamięci i żądania zerowego oraz różnicę między allocp i sp.", + "conclusion_tex": "Ten alokator nie obsługuje pojedynczego \\texttt{free}; pamięć odzyskuje się przez reset całej areny. Dowolne zwalnianie bloków pojawi się później przy strukturach i \\texttt{heap\\_4}.", + "flow": [ + { + "kind": "block", + "id": "schema", + "title": "SCHEMAT — przewidź stan areny", + "content_tex": "Arena \\texttt{allocbuf} ma 64 bajty, a \\texttt{allocp} wskazuje pierwszy wolny bajt. Stan opisuje offset \\texttt{allocp - allocbuf}; bezwzględny adres nie jest częścią wyniku.", + "steps": [ + { + "id": "predict-state", + "title": "Zaznacz na Rys. 1 granice przydziałów i zapisz trzy offsety.", + "content_tex": "Obserwowalny wniosek przed uruchomieniem: reset daje 0, \\texttt{alloc(5)} daje 5, a \\texttt{alloc(7)} daje 12." + }, + { + "id": "predict-results", + "title": "Przypisz wyniki do początku każdego przydzielonego obszaru.", + "content_tex": "Oczekiwany stan: \\texttt{first = allocbuf + 0}, \\texttt{second = allocbuf + 5}, \\texttt{allocp = allocbuf + 12}." + } + ] + }, + { + "kind": "block", + "id": "uml", + "title": "UML — połącz wywołania z czasem życia danych", + "content_tex": "Rys. 2 rozdziela statyczne \\texttt{allocbuf/allocp} od logicznych ramek \\texttt{main()} i \\texttt{alloc\\_local(n)}. Paski aktywacji pokazują czas wykonywania funkcji, nie osobny obszar alokatora.", + "steps": [ + { + "id": "classify-storage", + "title": "Wybierz blok model i rozdziel .bss, ramkę main() oraz ramkę alloc_local(n).", + "content_tex": "Wniosek: \\texttt{allocbuf/allocp} istnieją przez cały program; \\texttt{first}, \\texttt{second}, \\texttt{out\\_of\\_memory}, \\texttt{zero\\_request} oraz \\texttt{n}, \\texttt{used}, \\texttt{result} mają automatyczny czas życia. Przy \\texttt{-O0} debugger wiąże ramkę z \\texttt{sp/s0}, ale kompilator może przechować wartość w rejestrze." + }, + { + "id": "follow-states", + "title": "Przejdź przez pięć stanów UML i dla każdego zapisz jeden sprawdzalny wniosek.", + "content_tex": "Użyj zakładek: model/notacja, reset, alloc(5), alloc(7), kod/debug. Nie opisuj każdej strzałki osobno; zakończ stan konkretną wartością, offsetem albo czasem życia." + } + ] + }, + { + "kind": "block", + "id": "code-debug", + "title": "KOD + DEBUG — sprawdź przewidywanie", + "content_tex": "Implementacja ma dwie operacje: \\texttt{allocator\\_reset()} oraz \\texttt{alloc\\_local(n)}. Przydział zachowuje stary kursor jako wynik, sprawdza granicę areny i przesuwa kursor o \\texttt{n} bajtów.", + "steps": [ + { + "id": "implement-bump", + "title": "Uzupełnij reset i dodatni przydział mieszczący się w arenie.", + "content_tex": "Wniosek z kodu: wynik jest starym \\texttt{allocp}, a nowy \\texttt{allocp} wskazuje pierwszy wolny bajt; żądanie zerowe i brak miejsca zwracają \\texttt{NULL} bez zmiany offsetu 12." + }, + { + "id": "run-native", + "title": "Uruchom stemctl test native-amd64 inf pointers 4 i porównaj z przewidywaniem.", + "content_tex": "Dowód kończy się wynikiem \\texttt{first=0 second=5 allocp=12 sum=372 oom=1 zero=1 pass=1}." + }, + { + "id": "inspect-hazard3", + "title": "Na Rys. 3 i w Hazard3 połącz C, li/jal, a0, sp/s0 oraz allocbuf.", + "content_tex": "Sprawdź \\texttt{a0=5}, ramkę bieżącej funkcji przy \\texttt{sp/s0}, \\texttt{first-allocbuf}, \\texttt{second-allocbuf}, \\texttt{allocp-allocbuf} i \\texttt{x/16bx allocbuf}. Wniosek: \\texttt{allocp} opisuje arenę w .bss, a \\texttt{sp} ramkę stosu." + }, + { + "id": "measure-rp2350", + "title": "Na zajęciach powtórz ten sam pomiar na RP2350.", + "content_tex": "Przez \\texttt{stemctl probe list} wybierz urządzenie. Wniosek ma zachować offsety i znaczenie zmiennych mimo innych bezwzględnych adresów." + } + ] + } + ], + "educational_requirement_refs": ["PTR.WE02", "PTR.WE03"], + "learning_effect_refs": ["PTR.EN01", "PTR.EN02", "PTR.EK02", "PTR.EK03"], + "assessment_criterion_ref": "PTR.KW02" + }, + "task05": { + "prompt_tex": "\\textbf{K\\&R 5.5 -- wskaźniki znakowe.} Przejdź po buforze do kończącego bajtu NUL i zwizualizuj bajty bufora.", + "criterion": "Granica napisu i ruch wskaźnika są poprawnie wskazane.", + "educational_requirement_refs": ["PTR.WE01", "PTR.WE02"], + "learning_effect_refs": ["PTR.EN01", "PTR.EK01", "PTR.EK02"], + "assessment_criterion_ref": "PTR.KW01" + }, + "task06": { + "prompt_tex": "\\textbf{K\\&R 5.6 -- tablica wskaźników.} Posortuj przez zamianę adresów bez kopiowania treści napisów.", + "criterion": "Uczeń odróżnia tablicę wskaźników od danych, na które wskazuje.", + "educational_requirement_refs": ["PTR.WE01", "PTR.WE02"], + "learning_effect_refs": ["PTR.EN01", "PTR.EK01", "PTR.EK02"], + "assessment_criterion_ref": "PTR.KW01" + }, + "task07": { + "prompt_tex": "\\textbf{K\\&R 5.7 -- tablica wielowymiarowa.} Zmierz układ kolejnych wierszy w pamięci.", + "criterion": "Uczeń wyjaśnia ciągłość elementów i krok wskaźnika do wiersza.", + "educational_requirement_refs": ["PTR.WE01"], + "learning_effect_refs": ["PTR.EN01", "PTR.EK01"], + "assessment_criterion_ref": "PTR.KW01" + }, + "task08": { + "prompt_tex": "\\textbf{K\\&R 5.8 -- inicjalizacja tablicy wskaźników.} Porównaj rozmieszczenie tablicy adresów i wskazywanych danych.", + "criterion": "Dwa odrębne obszary pamięci są poprawnie rozpoznane.", + "educational_requirement_refs": ["PTR.WE01", "PTR.WE02"], + "learning_effect_refs": ["PTR.EN01", "PTR.EK01", "PTR.EK02"], + "assessment_criterion_ref": "PTR.KW01" + }, + "task09": { + "prompt_tex": "\\textbf{K\\&R 5.9 -- tablica 2D kontra tablica wskaźników.} Porównaj typ, rozmiar i sposób adresowania.", + "criterion": "Uczeń nie utożsamia obu reprezentacji i potrafi wskazać koszt dostępu.", + "educational_requirement_refs": ["PTR.WE01", "PTR.WE02"], + "learning_effect_refs": ["PTR.EN01", "PTR.EK01", "PTR.EK02"], + "assessment_criterion_ref": "PTR.KW01" + }, + "task10": { + "prompt_tex": "\\textbf{K\\&R 5.10 -- argumenty programu.} Przejdź wskaźnikiem po \\texttt{argv} na AMD64.", + "criterion": "Uczeń wyjaśnia zakończenie tablicy argumentów i rozdział wskaźników od napisów.", + "educational_requirement_refs": ["PTR.WE01"], + "learning_effect_refs": ["PTR.EN01", "PTR.EK01"], + "assessment_criterion_ref": "PTR.KW01" + }, + "task11": { + "prompt_tex": "\\textbf{K\\&R 5.11 -- wskaźnik do funkcji.} Porównaj adres funkcji z pośrednią instrukcją wywołania i przygotuj pojęcie strategii/polityki.", + "criterion": "Adres funkcji i wywołanie pośrednie są odnalezione w źródle, rejestrze i listingu.", + "educational_requirement_refs": ["PTR.WE01", "PTR.WE02"], + "learning_effect_refs": ["PTR.EN01", "PTR.EK01", "PTR.EK02"], + "assessment_criterion_ref": "PTR.KW04" + }, + "task12": { + "prompt_tex": "\\textbf{K\\&R 5.12 -- złożone deklaracje.} Rozłóż deklarację od identyfikatora na operatory wskaźnika, tablicy i funkcji.", + "criterion": "Deklaracja jest czytana w poprawnej kolejności i powiązana z typem.", + "educational_requirement_refs": ["PTR.WE01"], + "learning_effect_refs": ["PTR.EN01", "PTR.EK01"], + "assessment_criterion_ref": "PTR.KW01" + } + }, + "tasks_order": ["task01", "task02", "task03", "task04", "task05", "task06", "task07", "task08", "task09", "task10", "task11", "task12"] +} diff --git a/pdf/mpabi-inf-c-07-pointers-arrays-v00.01-4abec2d9-79e9-0dca-9040-c60669f51ff8.pdf b/pdf/mpabi-inf-c-07-pointers-arrays-v00.01-4abec2d9-79e9-0dca-9040-c60669f51ff8.pdf new file mode 100644 index 0000000000000000000000000000000000000000..dfe504d355e914babd6863168b61e243874450de GIT binary patch literal 2939863 zcmce-byQnj_bv*-1C$g^fkJSXpv40Pin}`$cXvyH7I%lD#jQ|^7bp#03KVyT;!cqQ zH+_HKz2n?*?ily{^L~s)*36Q<*PQd2Pu9-LWKffq<$!Vu0vX08duM@s5N?Qzg*{MI z6v(CJ=V}Gv(o?mtw|eafdhKFq1r!$tdU(29nL7b}=O+k$s4@Ro1)yNvqn-e*oGt&;gOvU*T@ZQU z|BebT{w)=R{%a~g|2pSiaRc|84~SJM6^! zH~jvUnBf0kmH5w=Mv#x6`+xQ{|NmQ>&+m;r7Psrek1yG-SU-Qqp+Vsi_o$_O=e_x& zK0*3UOXjRM*@%TLm_>1j^>ij5m0PTxI76!$p_!IBNl0+j8?$@#EV1ZpE=OPd?qM(_ zkN66jPx7gBD7qoX%PNb%BKLW|#52>;w&2@Qf1!Z;&5$NI<1j9c?I-b!P;rL<4BMFM zT>}g`{Urt1d+j)Yr;N@AS=7pEF8YGOwho<8P6vOCU&Gb*3#7rDM!N`)v~X$vP3IZrejdu=>C<3&JVs&7(S5FwSy8OnM* zCdh{!|dcGSQZdK87FR>v25R*dS>YzrAmz!3QSl}KC@JG`A;HPhyU4&9>FO|nef zjJ~Fhl*czT5C(36?iyS`@iRJ%m>tBgf>!QE4vYH)n|y&Q%|ruI!%+1-{#z-Bv-`WSZolSvm^DhJdlhW)-s0Ti2yw1}BOk%T)q zsV`K0U;ZGnt;4V�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

~#j8#HR91AAPT`%0f(P-9`OxT8`RgkY^qVrNtTz zO{yUtr<;ddEk z_~-VJi{j?SS%msa;FU#4NwezvellOp8k_s&_3?$236Vzv(v_v1|NTHh;Qu5YQr^kj z#tO)#YiId4*Iht}2goI7WoKjS2@&GuM&{Dnd3vZ>xxaLAa&>XGa`uG00CK%_addIl zbTxmC%)yto^0s?zrSVGY|H+pZ6hdwbky-ZtlPmxKN|i^B{+lwdX729fAu9Sm*YSYx z{uR8OoIU=z{r|@uxzyaPEbU%}v)NhzXL`0$$$TbTt%9z|2W zRj~E`PR!=`OK^yip~H0coJZ&HJ!Zk3_TS&L`5km_s=cg_U%xfy?n6O=08qdv=;+*i z52$_M#^%P-Wq0&Jtj}fsx-_;waYN0zXZO>w0f1}8aLm4OHv!M34J?Tm!qybBySXgdx90MvHLnLDUpb(*vaE3Mp(B@rfQ#!&^cEz0BQ|q#BD;b7>yUeU_rv_iEO|+fkhJ!+F%Ub`~Xz z&?L#r^t)c-j*}1>i0-9I%*dxgZgsz^;q z`4sJKrN-nYm{{YR{EO3{FMH4-wBTZw#A)I?`M9O)tnwYcL6kl!Tl4oOg;%|LUoGR_ z4hSs)M)XtKJ>PL3TC5*bB;c18_7&hTOKucndjz-RQ?LsN+HKiVy-#)xz>IPtFJ