{ "$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"] }