Explorar el Código

Add class descriptor addresses to Nova128 MAP records.

main
Daniel Covington hace 4 días
padre
commit
e2aed7a932
Se han modificado 7 ficheros con 62 adiciones y 23 borrados
  1. +5
    -3
      newLang/docs/architecture.md
  2. +2
    -0
      newLang/docs/decisions.md
  3. +6
    -5
      newLang/docs/memory-map.md
  4. +4
    -2
      newLang/scripts/verify-class-test.ps1
  5. +1
    -1
      newLang/src/common/formats.inc
  6. +34
    -10
      newLang/src/compiler/output.s
  7. +10
    -2
      newLang/tests/runtime/class-test.s

+ 5
- 3
newLang/docs/architecture.md Ver fichero

@@ -687,15 +687,17 @@ with no fields and no destructor, and a class with an optional destructor and
one interface-directory entry. one interface-directory entry.


`output.s` accepts class records through `out_class` and appends deterministic `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 ```text
CLASS name size destroy interface-count interface-directory
CLASS name address size destroy interface-count interface-directory
METHOD name address METHOD name address
``` ```


All numeric fields are four hex digits except the interface count, which is 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 caller's order. The class test reads the emitted MAP back and compares it with
the descriptor's actual destructor and directory addresses. the descriptor's actual destructor and directory addresses.




+ 2
- 0
newLang/docs/decisions.md Ver fichero

@@ -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. | | 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. | | 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 ## Deferred


- Native C128/80-column Vim port - Native C128/80-column Vim port


+ 6
- 5
newLang/docs/memory-map.md Ver fichero

@@ -19,7 +19,7 @@ later stories.
| BASIC 7 stub | 12 bytes, `10 SYS 7181` | | BASIC 7 stub | 12 bytes, `10 SYS 7181` |
| Entry | `$1C0D` | | Entry | `$1C0D` |
| Sections | ascending addresses, zero-filled gaps | | 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` | | Startup | clears mailbox, producer `$03`, status PASS, then `RTS` |


The fixed startup is copied from `src/runtime/startup.s`; `output.s` refuses The fixed startup is copied from `src/runtime/startup.s`; `output.s` refuses
@@ -116,14 +116,15 @@ wired.
| Destructor | `$0000` means none | | Destructor | `$0000` means none |
| Interface directory | 4-byte entries: interface descriptor, method table | | Interface directory | 4-byte entries: interface descriptor, method table |
| Flags | reserved, must be 0; no parent-class slot | | 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 The ABI is fixed in `src/common/class.inc`; D134 records the provisional
decision. `src/runtime/objects.s` reads descriptors and objects without 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 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) ## Construction and Deletion (E05-S03)




+ 4
- 2
newLang/scripts/verify-class-test.ps1 Ver fichero

@@ -52,6 +52,8 @@ function Read-DiskFile([string]$Name, [string]$Dest, [bool]$Seq) {
$mapPath = Join-Path $out "CLASSTEST.MAP" $mapPath = Join-Path $out "CLASSTEST.MAP"
Read-DiskFile "classtest.map" $mapPath $true Read-DiskFile "classtest.map" $mapPath $true
$mapLines = ([IO.File]::ReadAllText($mapPath)).TrimEnd("`r", "`n") -split "`r`n|`r|`n" $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" $destroy = Get-Nova128Label $labels "destroy_b"
$stub = Get-Nova128Label $labels "method_stub" $stub = Get-Nova128Label $labels "method_stub"
$ifdir = Get-Nova128Label $labels "iface_dir" $ifdir = Get-Nova128Label $labels "iface_dir"
@@ -60,8 +62,8 @@ $expectedMap = @(
"ENTRY 1C0D", "ENTRY 1C0D",
"SECTION STUB 1C01 000C", "SECTION STUB 1C01 000C",
"SECTION START 1C0D 004A", "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 DESTROY {0:X4}" -f $destroy),
("METHOD STUB {0:X4}" -f $stub)) ("METHOD STUB {0:X4}" -f $stub))
if (($mapLines -join "`n") -ne ($expectedMap -join "`n")) { if (($mapLines -join "`n") -ne ($expectedMap -join "`n")) {


+ 1
- 1
newLang/src/common/formats.inc Ver fichero

@@ -16,7 +16,7 @@ OUT_MAX_SECTIONS = 8
OUT_SECTION_NAME_MAX = 12 OUT_SECTION_NAME_MAX = 12
OUT_RECORD_SIZE = 7 ; name ptr(2), name len(1), start(2), size(2) OUT_RECORD_SIZE = 7 ; name ptr(2), name len(1), start(2), size(2)
OUT_MAX_CLASSES = 8 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_MAX_METHODS = 16
OUT_METHOD_RECORD_SIZE = 5 ; name ptr(2), len(1), address(2) OUT_METHOD_RECORD_SIZE = 5 ; name ptr(2), len(1), address(2)




+ 34
- 10
newLang/src/compiler/output.s Ver fichero

@@ -7,7 +7,7 @@
; NOVA128 MAP 1 ; NOVA128 MAP 1
; ENTRY hhhh ; ENTRY hhhh
; SECTION name start size ; 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): ; API (all calls in the bank-0 compiler state):
; out_begin A/X = source name (bank 0), Y = length. Sets out_load and ; out_begin A/X = source name (bank 0), Y = length. Sets out_load and
@@ -21,7 +21,7 @@
; out_end_section ; out_end_section
; out_finish Writes the MAP, closes both files, and returns C=0 on success. ; 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 ; 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. ; records follow the SECTION lines in call order.
; out_abort Closes and scratches only files created by this run. ; 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_begin, out_startup, out_section, out_end_section
.export out_byte, out_bytes, out_finish, out_abort .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_class_size, out_class_destroy, out_class_ifaces, out_class_ifdir
.export out_load, out_entry, out_start, out_err .export out_load, out_entry, out_start, out_err


@@ -254,6 +254,8 @@ out_begin:
sta out_count sta out_count
sta out_class_count sta out_class_count
sta out_method_count sta out_method_count
sta out_class_addr
sta out_class_addr+1
sta out_in_section sta out_in_section
sta out_prg_created sta out_prg_created
sta out_map_created sta out_map_created
@@ -596,6 +598,12 @@ out_class:
lda out_tmp_len lda out_tmp_len
sta (out_rec_ptr),y sta (out_rec_ptr),y
iny 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 lda out_class_size
sta (out_rec_ptr),y sta (out_rec_ptr),y
iny iny
@@ -932,9 +940,9 @@ out_write_classes:
lda (out_rec_ptr),y lda (out_rec_ptr),y
sta out_num+1 sta out_num+1
jsr out_hex4 jsr out_hex4
bcc @size_ok
bcc @addr_ok
jmp @out jmp @out
@size_ok:
@addr_ok:
lda #' ' lda #' '
jsr out_char jsr out_char
bcc @space2 bcc @space2
@@ -947,9 +955,9 @@ out_write_classes:
lda (out_rec_ptr),y lda (out_rec_ptr),y
sta out_num+1 sta out_num+1
jsr out_hex4 jsr out_hex4
bcc @destroy_ok
bcc @size_ok
jmp @out jmp @out
@destroy_ok:
@size_ok:
lda #' ' lda #' '
jsr out_char jsr out_char
bcc @space3 bcc @space3
@@ -957,16 +965,31 @@ out_write_classes:
@space3: @space3:
ldy #7 ldy #7
lda (out_rec_ptr),y 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 jsr out_hex_byte
bcc @count_ok bcc @count_ok
jmp @out jmp @out
@count_ok: @count_ok:
lda #' ' lda #' '
jsr out_char jsr out_char
bcc @space4
bcc @space5
jmp @out jmp @out
@space4:
ldy #8
@space5:
ldy #10
lda (out_rec_ptr),y lda (out_rec_ptr),y
sta out_num sta out_num
iny 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_methods: .res OUT_MAX_METHODS * OUT_METHOD_RECORD_SIZE
out_method_count: .res 1 out_method_count: .res 1
out_method_addr: .res 2 out_method_addr: .res 2
out_class_addr: .res 2
out_class_size: .res 2 out_class_size: .res 2
out_class_destroy: .res 2 out_class_destroy: .res 2
out_class_ifaces: .res 1 out_class_ifaces: .res 1


+ 10
- 2
newLang/tests/runtime/class-test.s Ver fichero

@@ -15,12 +15,12 @@
.import mmu_init, mmu_bank0, mmu_shutdown .import mmu_init, mmu_bank0, mmu_shutdown
.import out_begin, out_startup, out_finish, out_abort .import out_begin, out_startup, out_finish, out_abort
.import out_load, out_entry, out_err .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_method, out_method_addr
.import out_class_ifaces, out_class_ifdir .import out_class_ifaces, out_class_ifdir
.import obj_class, obj_size, obj_destroy, obj_iface_dir .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" .segment "LOADADDR"
.word $1C01 .word $1C01
@@ -205,6 +205,10 @@ test_entry:
jmp @p7_abort jmp @p7_abort
: :


lda #<desc_empty
sta out_class_addr
lda #>desc_empty
sta out_class_addr+1
lda #7 ; EMPTY: size 7, no destructor/interface lda #7 ; EMPTY: size 7, no destructor/interface
sta out_class_size sta out_class_size
lda #$00 lda #$00
@@ -220,6 +224,10 @@ test_entry:
jsr out_class jsr out_class
bcs @p7_abort bcs @p7_abort


lda #<desc_box
sta out_class_addr
lda #>desc_box
sta out_class_addr+1
lda #35 ; BOX: destructor and one interface lda #35 ; BOX: destructor and one interface
sta out_class_size sta out_class_size
lda #$00 lda #$00


Cargando…
Cancelar
Guardar

Powered by TurnKey Linux.