; E01-S05: capacity-checking skeleton for cfg/compiler.cfg. ; ; Links the production src/compiler/mmu.s with the frozen memory map and ; proves, in x128, every region and rule the compiler will depend on. Results ; go to the fixed test mailbox (src/common/mailbox.inc): ; MB_STATUS $A5 pass / $FA fail ; MB_CODE 16-bit mask of FAILED checks (CHECK_*), 0 on pass ; MB_DATA+0 NMIs counted by mmu_nmi_guard ; MB_DATA+1 CR seen right after the NMI (expect $4E) ; MB_DATA+2 P0L seen right after the NMI (expect the private page) ; MB_DATA+3 private zero-page sentinel after the NMI (expect $C5) ; ; Assemble with -D OVERFLOW_=1 to prove ld65 rejects an overflow of ; ZP, COMMON, MAIN, SWSTACK, or TABLES. .setcpu "6502" .include "../../src/common/c128.inc" .include "../../src/common/mailbox.inc" .import mmu_init, mmu_bank0, mmu_bank1, mmu_system, mmu_shutdown .import mmu_peek1, mmu_poke1, kcall_inline, mmu_nmi_count .importzp mmu_ptr .import __COMPILER_ZP_PAGE__ CHECK_ZP = $0001 ; private zero page isolated from system ZP CHECK_KCALL = $0002 ; KERNAL calls from both states keep ZP/MMU CHECK_BANK1 = $0004 ; first/last table bytes are bank-1 only CHECK_NMI = $0008 ; NMI under bank 1 + private ZP is harmless CHECK_COMMON = $0010 ; COMMON/DISKBUF/SCRATCH/MAILBOX shared CHECK_RESTORE = $0020 ; exact system state after mmu_shutdown CHECK_ALL = $003F ZP_SENTINEL = $C5 .segment "LOADADDR" .word $1C01 .segment "EXEHDR" .word basic_end .word 10 .byte $9E .byte "7181" ; SYS $1C0D .byte $00 basic_end: .word $0000 .segment "ZEROPAGE" zp_probe: .res 1 .ifdef OVERFLOW_ZP .res $FE .endif .segment "MAILBOX" mailbox: .res MB_SIZE .assert mailbox = MB_BASE, error, "MAILBOX segment must sit at MB_BASE" .segment "DISKBUF" diskbuf: .res $100 .segment "SCRATCH" scratch: .res 1 .segment "SWSTACK" swstack_first: .res 1 .res $0800 - 2 swstack_last: .res 1 .ifdef OVERFLOW_SWSTACK .res 1 .endif .segment "TABLES" tables_first: .res 1 .res $5500 - 2 tables_last: .res 1 .ifdef OVERFLOW_TABLES .res 1 .endif ; --------------------------------------------------------------- STARTUP .segment "STARTUP" .export skel_entry skel_entry: php sei tsx stx entry_sp ldx #MB_SIZE - 1 ; mailbox: initialized and running lda #$00 @clr: sta MB_BASE,x dex bpl @clr lda #MB_MAGIC0_VALUE sta MB_MAGIC0 lda #MB_MAGIC1_VALUE sta MB_MAGIC1 lda #MB_PROD_PLATFORM sta MB_PRODUCER lda #MB_ST_RUNNING sta MB_STATUS lda #CHECK_ALL sta fail_mask+1 lda MMU_CR ; system state for CHECK_RESTORE sta entry_state+0 ldx #4 @save: lda MMU_RCR,x sta entry_state+1,x dex bpl @save lda NMINV sta entry_state+6 lda NMINV+1 sta entry_state+7 lda zp_probe ; system ZP byte at the probe's offset sta sys_zp_before jsr mmu_init jsr mmu_bank0 ; ------------------------------------------- private zero page lda #ZP_SENTINEL sta zp_probe ; logical ZP -> physical $1Axx jsr mmu_system lda zp_probe ; system ZP again cmp sys_zp_before bne @zp_done lda __COMPILER_ZP_PAGE__ * 256 + zp_probe cmp #ZP_SENTINEL bne @zp_done lda #tables_first sta mmu_ptr+1 ldy #$00 lda #$5A jsr mmu_poke1 lda #tables_last sta mmu_ptr+1 lda #$A5 jsr mmu_poke1 jsr mmu_peek1 cmp #$A5 bne @b1_done lda #tables_first sta mmu_ptr+1 jsr mmu_peek1 cmp #$5A bne @b1_done lda tables_first cmp b0_first bne @b1_done lda tables_last cmp b0_last bne @b1_done jsr state_is_bank0 bne @b1_done lda #skel_done sta MB_ADDR+1 ldy #ok_msg - messages lda fail_mask ora fail_mask+1 bne @fail lda #MB_ST_PASS bne @report @fail: ldy #fail_msg - messages lda #MB_ST_FAIL @report: sta MB_STATUS skel_done: plp @print: lda messages,y beq @end sty print_y jsr CHROUT ldy print_y iny bne @print @end: rts .segment "CODE" ; Clear a passed check (A = low-byte mask; all checks fit in the low byte). pass: eor #$FF and fail_mask sta fail_mask rts ; Z=1 when the MMU shows the exact bank-0 compiler state. state_is_bank0: lda MMU_CR cmp #CR_RAM0_KERNAL bne @no lda MMU_P0L cmp #<__COMPILER_ZP_PAGE__ @no: rts .ifdef OVERFLOW_MAIN .res $9BF3 .endif .segment "RODATA" bank0_msg: .byte "KCALL FROM BANK 0", $0D, $00 messages: ok_msg: .byte "NOVA128 MAP SKELETON OK", $0D, $00 fail_msg: .byte "NOVA128 MAP SKELETON FAIL", $0D, $00 .segment "BSS" entry_sp: .res 1 entry_state: .res 8 ; CR, RCR, P0L, P0H, P1L, P1H, NMINV sys_zp_before: .res 1 fail_mask: .res 2 b0_first: .res 1 b0_last: .res 1 print_y: .res 1 ; ---------------------------------------------------------------- COMMON ; These routines run with bank 1 mapped, so they must be in common RAM. .segment "COMMON" common_say_bank1: lda #$00 sta kc1_ok jsr mmu_bank1 ldy #$00 @say: lda bank1_msg,y beq @said sty say_y jsr kcall_inline .word CHROUT ldy say_y iny bne @say @said: lda MMU_CR ; still bank 1 after the KERNAL calls? cmp #CR_RAM1_KERNAL bne @out lda MMU_P0L cmp #<__COMPILER_ZP_PAGE__ bne @out inc kc1_ok @out: jmp mmu_bank0 common_shared_test: lda #$00 sta shared_ok jsr mmu_bank1 lda diskbuf cmp #$3C bne @out lda scratch cmp #$C3 bne @out lda #$7E sta MB_DATA+7 inc shared_ok @out: jmp mmu_bank0 common_nmi_test: tsx stx entry_sp_inner jsr mmu_bank1 lda #$7F ; disable all CIA #2 sources, clear flags sta CIA2_ICR bit CIA2_ICR lda #$40 sta CIA2_TALO lda #$00 sta CIA2_TAHI lda mmu_nmi_count sta nmi_before lda #CIA_ICR_SET | CIA_ICR_TA sta CIA2_ICR lda #CIA_CRA_START | CIA_CRA_ONESHOT | CIA_CRA_LOAD sta CIA2_CRA ldx #$00 ; wait up to ~65K iterations ldy #$00 @wait: lda mmu_nmi_count cmp nmi_before bne @hit dex bne @wait dey bne @wait @hit: lda MMU_CR ; state right after the NMI returned sta MB_DATA+1 lda MMU_P0L sta MB_DATA+2 lda zp_probe sta MB_DATA+3 tsx ; same depth as at routine entry? stx nmi_sp lda #$7F sta CIA2_ICR lda #$00 sta CIA2_CRA bit CIA2_ICR lda mmu_nmi_count sec sbc nmi_before sta MB_DATA+0 jmp mmu_bank0 bank1_msg: .byte "KCALL FROM BANK 1", $0D, $00 kc1_ok: .byte $00 say_y: .byte $00 shared_ok: .byte $00 nmi_before: .byte $00 nmi_sp: .byte $00 entry_sp_inner: .byte $00 .ifdef OVERFLOW_COMMON .res $0600 .endif