選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

5.7KB


story: E04-S01 owner: e04_output status: done started: 2026-11-09 depends-on: [E01-S05, E02-S04]

E04-S01 Claim

Intended change

Add the generated-program container and writer. src/compiler/output.s accepts a source base name, writes a PRG with a valid load-address header and ordered sections, records each section's start/size plus the entry point in a MAP file, and emits the fixed BASIC 7 stub and startup path from src/runtime/startup.s. The generated program initializes the test mailbox, reports pass, and returns cleanly to BASIC.

An existing NAME.PRG or NAME.MAP is refused with the new disk diagnostic E202 instead of being overwritten. Outputs created by the current run are scratched if emission fails or the caller aborts, so no partial final file is left behind.

File area

  • src/compiler/output.s (new), src/runtime/startup.s (new)
  • src/common/formats.inc (new), src/common/diagcat.inc, docs/diagnostics.md
  • tests/codegen/output-test.s
  • scripts/build-output-test.ps1, scripts/verify-output-test.ps1
  • docs/decisions.md, docs/architecture.md, docs/memory-map.md
  • planning/claims/E04-S01.md
  • generated files under build/

Acceptance evidence

  • Writes a valid load-address header and deterministic sections: the generated generate.prg is 133 bytes, starts with 01 1C, contains the verified 12-byte 10 SYS 7181 stub at $1C01, 74 startup bytes at $1C0D, zero padding through $1C7F, and DE AD BE EF at $1C80.
  • Emits a runnable startup path and clean termination: the extracted PRG autostarts in x128, writes producer $03, status $A5, code 0, empty data, and returns to BASIC.
  • Refuses/handles output-name collision according to the approved policy: the pre-existing collide.prg/collide.map fixtures cause OUT_ERR_EXISTS; both files remain byte-for-byte unchanged because nothing is opened before the check.
  • Removes or marks partial output after any failure: the order.prg section-order failure and the abort.prg partial-section run both call out_abort; neither PRG nor MAP exists afterwards.
  • MAP records section start, size, and entry point: generate.map is the exact CR-terminated sequence NOVA128 MAP 1, ENTRY 1C0D, SECTION STUB 1C01 000C, SECTION START 1C0D 004A, SECTION PAD 1C80 0004.

Coordination notes

  • E01-S05 and E02-S04 are done; no other claim overlapped this area.
  • D128 records the provisional container and refusal policy. E04-S02 still owns the higher generated-program map (banking, heap, software stack); this story's fixture keeps sections below $4000 where BASIC's mapping exposes RAM.
  • output.s returns OUT_ERR_EXISTS; E202 is in the stable catalog for the compiler shell (a later story) to report. No shell integration was invented here.
  • Production and abort paths use the existing diskio.s wrappers; no module except mmu.s touches the MMU.

Work log

  • Built the writer around a compact section-record table (name pointer, length, start, size), a load-address header, and a MAP written after the PRG closes.
  • First build failed because out_rec_ptr was in BSS; 6502 (ptr),y requires zero page. Moved it to ZEROPAGE.
  • Long branches in out_begin and out_write_map needed short-branch/jmp trampolines.
  • First x128 result was OUT_ERR_ORDER: the load-address header had advanced out_current to $1C03, so the $1C01 STUB section looked backward. The writer now rewinds to out_load after the header.
  • The next fixture exposed every PRG byte as 01: out_byte loaded the section flag into A before calling out_put. It now saves the byte first.
  • Collision fixtures originally used PETSCII uppercase names while the writer preserved the source's PETSCII lowercase names, so the writer legitimately did not see them. Fixtures and host reads now use the same lowercase names.
  • The abort fixture initially emitted a byte after out_startup had ended its section, producing OUT_ERR_STATE; it now opens an explicit X section and writes $AA before aborting.
  • A stale parser-test x128 held port 6530 and caused empty/dropped monitor replies. Verification identifies test-image processes and stops only those before running.

Completion

  • Tests run:
    • scripts/build-output-test.ps1
    • scripts/verify-output-test.ps1 -Port 6530 -RunPort 6531
    • scripts/build-diag-test.ps1 -UpdateDocs
    • scripts/verify-diag-test.ps1 -Port 6530
    • scripts/verify-parser-test.ps1 -Port 6530
    • git diff --check
  • Results: writer fixture PASS with results finish=0, collision=1, order=2, abort=0; PRG and MAP bytes match; generated PRG autostarts with producer 3 and PASS; collision fixtures unchanged; abort/order outputs absent. Diagnostics: catalog 71 entries, docs in sync, 19 screen rows and ERR files exact. Parser: all 41 fixtures pass, lowest expression SP $A7.
  • Files changed: src/compiler/output.s, src/runtime/startup.s, src/common/formats.inc, src/common/diagcat.inc, docs/diagnostics.md, tests/codegen/output-test.s, scripts/build-output-test.ps1, scripts/verify-output-test.ps1, docs/decisions.md, docs/architecture.md, docs/memory-map.md, this claim.
  • Remaining risks: an existing output must be erased before recompiling (refusal policy, D128); a power loss during direct PRG writing can leave a partial file because there is no atomic rename; at most 8 sections and 12-character section names; the MAP has no symbols/class/interface entries yet; the startup is only the mailbox/termination path and does not install a runtime mapping; sections above $3FFF are E04-S02 work; out_load is caller-controlled rather than validated against the fixed container.

Powered by TurnKey Linux.