|
- ; 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_<REGION>=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 ; every check starts failed
- sta fail_mask
- 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 #<CHECK_ZP
- jsr pass
- @zp_done:
- jsr mmu_bank0
-
- ; ---------------------------------- KERNAL calls from both states
- ldy #$00
- @say0: lda bank0_msg,y
- beq @said0
- sty print_y
- jsr kcall_inline
- .word CHROUT
- ldy print_y
- iny
- bne @say0
- @said0: jsr common_say_bank1 ; same from the bank-1 state
- lda zp_probe
- cmp #ZP_SENTINEL
- bne @kc_done
- jsr state_is_bank0
- bne @kc_done
- lda kc1_ok
- cmp #$01
- bne @kc_done
- lda #<CHECK_KCALL
- jsr pass
- @kc_done:
-
- ; ------------------------------------------- bank-1 table window
- lda tables_first ; bank-0 bytes at the same addresses
- sta b0_first
- lda tables_last
- sta b0_last
- lda #<tables_first
- sta mmu_ptr
- lda #>tables_first
- sta mmu_ptr+1
- ldy #$00
- lda #$5A
- jsr mmu_poke1
- lda #<tables_last
- sta mmu_ptr
- 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
- 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 #<CHECK_BANK1
- jsr pass
- @b1_done:
-
- ; ----------------------------------------- shared common regions
- lda #$3C
- sta diskbuf
- lda #$C3
- sta scratch
- jsr common_shared_test
- lda shared_ok
- cmp #$01
- bne @sh_done
- lda MB_DATA+7 ; written from the bank-1 state
- cmp #$7E
- bne @sh_done
- lda #<CHECK_COMMON
- jsr pass
- @sh_done:
- lda #$00
- sta MB_DATA+7
-
- ; -------------------------------------- NMI under bank 1 + ZP
- jsr common_nmi_test
- lda MB_DATA+0
- beq @nmi_done ; the NMI never arrived
- lda MB_DATA+1
- cmp #CR_RAM1_KERNAL
- bne @nmi_done
- lda MB_DATA+2
- cmp #<__COMPILER_ZP_PAGE__
- bne @nmi_done
- lda MB_DATA+3
- cmp #ZP_SENTINEL
- bne @nmi_done
- lda nmi_sp
- cmp entry_sp_inner
- bne @nmi_done
- lda #<CHECK_NMI
- jsr pass
- @nmi_done:
-
- ; ------------------------------------------------- full restore
- jsr mmu_shutdown
- tsx
- cpx entry_sp
- bne @rs_done
- lda MMU_CR
- cmp entry_state+0
- bne @rs_done
- ldx #4
- @rs: lda MMU_RCR,x
- cmp entry_state+1,x
- bne @rs_done
- dex
- bpl @rs
- lda NMINV
- cmp entry_state+6
- bne @rs_done
- lda NMINV+1
- cmp entry_state+7
- bne @rs_done
- lda #<CHECK_RESTORE
- jsr pass
- @rs_done:
-
- ; ------------------------------------------------ report
- lda fail_mask
- sta MB_CODE
- lda fail_mask+1
- sta MB_CODE+1
- lda #<skel_done
- sta MB_ADDR
- 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
|