diff --git a/newLang/docs/architecture.md b/newLang/docs/architecture.md index 5b96bd0..8c129fd 100644 --- a/newLang/docs/architecture.md +++ b/newLang/docs/architecture.md @@ -687,15 +687,17 @@ with no fields and no destructor, and a class with an optional destructor and one interface-directory entry. `output.s` accepts class records through `out_class` and appends deterministic -MAP lines after the section records: +MAP lines after the section records. `out_class_addr` supplies the descriptor +address: ```text -CLASS name size destroy interface-count interface-directory +CLASS name address size destroy interface-count interface-directory METHOD name address ``` All numeric fields are four hex digits except the interface count, which is -two. METHOD records follow all CLASS records in `out_method` call order. Empty classes and no destructor are written as `0000`; records keep the +two. METHOD records follow all CLASS records in `out_method` call order; both +record kinds use the final linked addresses. Empty classes and no destructor are written as `0000`; records keep the caller's order. The class test reads the emitted MAP back and compares it with the descriptor's actual destructor and directory addresses. diff --git a/newLang/docs/decisions.md b/newLang/docs/decisions.md index ef6cea7..f6c65ed 100644 --- a/newLang/docs/decisions.md +++ b/newLang/docs/decisions.md @@ -69,6 +69,8 @@ documented default. `Proposed` means a later change still needs approval. | D139 | E04-S07 begins the pass-3 address path. `flow.s` resolves absolute `JMP`/`JSR` operands against `fl_code_base`, which defaults to `cg_code`; `sizing.s` computes the final code base as `PRG_ENTRY_ADDR + bytes before CODE` and installs it with `em_set_base` before pass 2. `counter.n8` aliases two local bytes, loops `i = 1 to 5`, and sums into `total`; its fixture writes `COUNTER.PRG`/`COUNTB.PRG` with STUB, START, and CODE sections. The generated wrapper selects CR `$0E`, sets `FRAME_FP` to `$BF80`, calls the code base, reads `total`, restores CR, and reports PASS. | Proves final section addresses and generated-code relocation in a real x128 run while keeping existing in-place emitter fixtures unchanged. D140 completes the count-mode and MAP work for E04-S07. Implemented by `flow.s`, `emit.s`, `sizing.s`, `counter.n8`, the counter fixture, and its scripts. | | D140 | E04-S07 completes count-mode sizing and the MAP/diagnostic evidence. `em_count` selects the count pass; `em_end_func` records each routine length in `em_routine_sizes`; `sz_capture` snapshots code length, entry, routine sizes, and all 64 label offsets; the emitting pass runs with `diag_suppress`; `sz_verify` counts every difference and raises `RES_SIZE_MISMATCH` (E228) after the pass. The counter fixture requires `sz_mismatch = 0`, 175 code bytes, `CODE 1C4F`, deterministic PRGs, and `total = 15`. `output.s` adds `METHOD name address` records after `CLASS` records, proven by `METHOD DESTROY`/`METHOD STUB` in the class MAP. `tests/parser/unresolved.n8` proves one unknown method produces exactly one `SEM_UNKNOWN_NAME` (E61), and the output suite still proves E202 in the pass-3-adjacent writer path. | Closes the E04-S07 acceptance evidence without changing ordinary in-place fixtures: `parse_file` clears `em_count`, `diag_suppress`, and the base request, while `parse_file_sized` opts into the counted path. The code buffer remains 255 bytes and `em_entry` remains an offset; general program startup and frame sizing are separate work. Implemented by `parser.s`, `emit.s`, `emit.inc`, `sizing.s`, `diagnostics.s`, `diagcat.inc`, `output.s`, `formats.inc`, the counter/class/output/parser fixtures, and their scripts. | +| D141 | The MAP CLASS record carries the class descriptor's final address between the name and size: `CLASS name address size destroy interface-count interface-directory`. `out_class_addr` supplies it, `OUT_CLASS_RECORD_SIZE` grows from 10 to 12 bytes, and METHOD records remain `METHOD name address`. The class fixture exports `desc_empty`/`desc_box` and compares both descriptor addresses plus the two method addresses against the linker labels. | Makes class and method map records symmetric and directly verifiable, instead of requiring the caller to infer a descriptor address from the size/destructor fields. This is a visible MAP format change; existing SECTION, ENTRY, and method records keep their order. | + ## Deferred - Native C128/80-column Vim port diff --git a/newLang/docs/memory-map.md b/newLang/docs/memory-map.md index 023aa3a..07bc0e6 100644 --- a/newLang/docs/memory-map.md +++ b/newLang/docs/memory-map.md @@ -19,7 +19,7 @@ later stories. | BASIC 7 stub | 12 bytes, `10 SYS 7181` | | Entry | `$1C0D` | | Sections | ascending addresses, zero-filled gaps | -| MAP | `NOVA128 MAP 1`, `ENTRY hhhh`, `SECTION name start size`, `CLASS name size destroy count ifdir`, `METHOD name address` | +| MAP | `NOVA128 MAP 1`, `ENTRY hhhh`, `SECTION name start size`, `CLASS name address size destroy count ifdir`, `METHOD name address` | | Startup | clears mailbox, producer `$03`, status PASS, then `RTS` | The fixed startup is copied from `src/runtime/startup.s`; `output.s` refuses @@ -116,14 +116,15 @@ wired. | Destructor | `$0000` means none | | Interface directory | 4-byte entries: interface descriptor, method table | | Flags | reserved, must be 0; no parent-class slot | -| MAP | `CLASS name size destroy count ifdir` and `METHOD name address` after sections | +| MAP | `CLASS name address size destroy count ifdir` and `METHOD name address` after sections | The ABI is fixed in `src/common/class.inc`; D134 records the provisional decision. `src/runtime/objects.s` reads descriptors and objects without allocating. `output.s` writes class MAP records in `out_class` call order and method MAP -records in `out_method` call order; the E05-S02 fixture checks a -no-destructor/no-interface class, a destructor plus one interface entry, and -two method addresses. Interface dispatch remains E06 work. +records in `out_method` call order. The descriptor address comes from +`out_class_addr`; method addresses come from `out_method_addr`. The E05-S02 +fixture checks a no-destructor/no-interface class, a destructor plus one +interface entry, two method addresses, and both descriptor addresses. Interface dispatch remains E06 work. ## Construction and Deletion (E05-S03) diff --git a/newLang/scripts/verify-class-test.ps1 b/newLang/scripts/verify-class-test.ps1 index 1de2371..eec9084 100644 --- a/newLang/scripts/verify-class-test.ps1 +++ b/newLang/scripts/verify-class-test.ps1 @@ -52,6 +52,8 @@ function Read-DiskFile([string]$Name, [string]$Dest, [bool]$Seq) { $mapPath = Join-Path $out "CLASSTEST.MAP" Read-DiskFile "classtest.map" $mapPath $true $mapLines = ([IO.File]::ReadAllText($mapPath)).TrimEnd("`r", "`n") -split "`r`n|`r|`n" +$empty = Get-Nova128Label $labels "desc_empty" +$box = Get-Nova128Label $labels "desc_box" $destroy = Get-Nova128Label $labels "destroy_b" $stub = Get-Nova128Label $labels "method_stub" $ifdir = Get-Nova128Label $labels "iface_dir" @@ -60,8 +62,8 @@ $expectedMap = @( "ENTRY 1C0D", "SECTION STUB 1C01 000C", "SECTION START 1C0D 004A", - ("CLASS EMPTY 0007 0000 00 0000"), - ("CLASS BOX 0023 {0:X4} 01 {1:X4}" -f $destroy, $ifdir), + ("CLASS EMPTY {0:X4} 0007 0000 00 0000" -f $empty), + ("CLASS BOX {0:X4} 0023 {1:X4} 01 {2:X4}" -f $box, $destroy, $ifdir), ("METHOD DESTROY {0:X4}" -f $destroy), ("METHOD STUB {0:X4}" -f $stub)) if (($mapLines -join "`n") -ne ($expectedMap -join "`n")) { diff --git a/newLang/src/common/formats.inc b/newLang/src/common/formats.inc index 5f91fc9..ab9f958 100644 --- a/newLang/src/common/formats.inc +++ b/newLang/src/common/formats.inc @@ -16,7 +16,7 @@ OUT_MAX_SECTIONS = 8 OUT_SECTION_NAME_MAX = 12 OUT_RECORD_SIZE = 7 ; name ptr(2), name len(1), start(2), size(2) OUT_MAX_CLASSES = 8 -OUT_CLASS_RECORD_SIZE = 10 ; name ptr(2), len(1), size(2), destroy(2), count(1), dir(2) +OUT_CLASS_RECORD_SIZE = 12 ; name ptr(2), len(1), addr(2), size(2), destroy(2), count(1), dir(2) OUT_MAX_METHODS = 16 OUT_METHOD_RECORD_SIZE = 5 ; name ptr(2), len(1), address(2) diff --git a/newLang/src/compiler/output.s b/newLang/src/compiler/output.s index b221fc5..be4374d 100644 --- a/newLang/src/compiler/output.s +++ b/newLang/src/compiler/output.s @@ -7,7 +7,7 @@ ; NOVA128 MAP 1 ; ENTRY hhhh ; SECTION name start size -; CLASS name size destroy interface-count interface-directory +; CLASS name address size destroy interface-count interface-directory ; ; API (all calls in the bank-0 compiler state): ; out_begin A/X = source name (bank 0), Y = length. Sets out_load and @@ -21,7 +21,7 @@ ; out_end_section ; out_finish Writes the MAP, closes both files, and returns C=0 on success. ; out_class A/X = class name, Y = length. Adds a deterministic CLASS -; record from out_class_size/destroy/ifaces/ifdir. Class +; record from out_class_addr/size/destroy/ifaces/ifdir. Class ; records follow the SECTION lines in call order. ; out_abort Closes and scratches only files created by this run. ; @@ -39,7 +39,7 @@ .export out_begin, out_startup, out_section, out_end_section .export out_byte, out_bytes, out_finish, out_abort -.export out_class, out_method, out_method_addr +.export out_class, out_class_addr, out_method, out_method_addr .export out_class_size, out_class_destroy, out_class_ifaces, out_class_ifdir .export out_load, out_entry, out_start, out_err @@ -254,6 +254,8 @@ out_begin: sta out_count sta out_class_count sta out_method_count + sta out_class_addr + sta out_class_addr+1 sta out_in_section sta out_prg_created sta out_map_created @@ -596,6 +598,12 @@ out_class: lda out_tmp_len sta (out_rec_ptr),y iny + lda out_class_addr + sta (out_rec_ptr),y + iny + lda out_class_addr+1 + sta (out_rec_ptr),y + iny lda out_class_size sta (out_rec_ptr),y iny @@ -932,9 +940,9 @@ out_write_classes: lda (out_rec_ptr),y sta out_num+1 jsr out_hex4 - bcc @size_ok + bcc @addr_ok jmp @out -@size_ok: +@addr_ok: lda #' ' jsr out_char bcc @space2 @@ -947,9 +955,9 @@ out_write_classes: lda (out_rec_ptr),y sta out_num+1 jsr out_hex4 - bcc @destroy_ok + bcc @size_ok jmp @out -@destroy_ok: +@size_ok: lda #' ' jsr out_char bcc @space3 @@ -957,16 +965,31 @@ out_write_classes: @space3: ldy #7 lda (out_rec_ptr),y + sta out_num + iny + lda (out_rec_ptr),y + sta out_num+1 + jsr out_hex4 + bcc @destroy_ok + jmp @out +@destroy_ok: + lda #' ' + jsr out_char + bcc @space4 + jmp @out +@space4: + ldy #9 + lda (out_rec_ptr),y jsr out_hex_byte bcc @count_ok jmp @out @count_ok: lda #' ' jsr out_char - bcc @space4 + bcc @space5 jmp @out -@space4: - ldy #8 +@space5: + ldy #10 lda (out_rec_ptr),y sta out_num iny @@ -1172,6 +1195,7 @@ out_classes: .res OUT_MAX_CLASSES * OUT_CLASS_RECORD_SIZE out_methods: .res OUT_MAX_METHODS * OUT_METHOD_RECORD_SIZE out_method_count: .res 1 out_method_addr: .res 2 +out_class_addr: .res 2 out_class_size: .res 2 out_class_destroy: .res 2 out_class_ifaces: .res 1 diff --git a/newLang/tests/runtime/class-test.s b/newLang/tests/runtime/class-test.s index 8309a4f..b63a83b 100644 --- a/newLang/tests/runtime/class-test.s +++ b/newLang/tests/runtime/class-test.s @@ -15,12 +15,12 @@ .import mmu_init, mmu_bank0, mmu_shutdown .import out_begin, out_startup, out_finish, out_abort .import out_load, out_entry, out_err -.import out_class, out_class_size, out_class_destroy +.import out_class, out_class_addr, out_class_size, out_class_destroy .import out_method, out_method_addr .import out_class_ifaces, out_class_ifdir .import obj_class, obj_size, obj_destroy, obj_iface_dir -.export destroy_b, iface_dir, method_stub +.export desc_empty, desc_box, destroy_b, iface_dir, method_stub .segment "LOADADDR" .word $1C01 @@ -205,6 +205,10 @@ test_entry: jmp @p7_abort : + lda #desc_empty + sta out_class_addr+1 lda #7 ; EMPTY: size 7, no destructor/interface sta out_class_size lda #$00 @@ -220,6 +224,10 @@ test_entry: jsr out_class bcs @p7_abort + lda #desc_box + sta out_class_addr+1 lda #35 ; BOX: destructor and one interface sta out_class_size lda #$00