; E05-S01: free-list heap fixture in x128. ; ; Runs under CR=$0E with the heap at $4000-$4FFF (16 pages). All code and BSS ; stay below $4000. The fixture checks the allocator and records one flag per ; phase in MB_DATA; the final exhaustion check invokes the stable R005 fault ; path, so the mailbox intentionally ends FAIL with code 5. ; ; Expected screen: ; NOVA128 HEAP TEST ; HEAP OK ; RUNTIME FAULT R005 .setcpu "6502" .include "../../src/common/c128.inc" .include "../../src/common/mailbox.inc" .include "../../src/common/print.inc" .include "../../src/common/faults.inc" .include "../../src/common/heap.inc" .import pr_char, pr_cr, pr_text .import flt_report .import heap_init, heap_alloc, heap_free .import heap_base, heap_end, heap_free_head, heap_free_total, heap_error HEAP_TEST_BASE = $4000 HEAP_TEST_END = $5000 HEAP_TEST_PAGES = 16 HEAP_TEST_SIZE = $1000 .macro TEXT src, len lda #src ldy #len jsr pr_text .endmacro .macro PHASE number lda #number sta MB_CODE lda #$00 sta MB_CODE+1 .endmacro .macro FAIL_CS bcc :+ jmp @fail : .endmacro .macro FAIL_CC bcs :+ jmp @fail : .endmacro .macro FAIL_NE beq :+ jmp @fail : .endmacro .macro FAIL_EQ bne :+ jmp @fail : .endmacro .segment "LOADADDR" .word $1C01 .segment "EXEHDR" .word basic_end .word 10 .byte $9E .byte "7181" .byte $00 basic_end: .word $0000 .segment "MAILBOX" .res MB_SIZE .segment "ZEROPAGE" tptr: .res 2 .segment "STARTUP" .export test_entry, test_end test_entry: php sei ldx #MB_SIZE - 1 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_PROGRAM sta MB_PRODUCER lda #MB_ST_RUNNING sta MB_STATUS lda MMU_CR sta saved_cr lda #CR_RAM0_KERNAL sta MMU_CR lda #PR_CLEAR jsr pr_char TEXT title, 17 jsr pr_cr ; ------------------------------------------------------------- init PHASE 1 lda #$00 ldx #>HEAP_TEST_BASE ldy #HEAP_TEST_PAGES jsr heap_init FAIL_CS lda heap_free_total cmp #$00 FAIL_NE lda heap_free_total+1 cmp #$10 FAIL_NE lda heap_free_head cmp #$00 FAIL_NE lda heap_free_head+1 cmp #$40 FAIL_NE lda HEAP_TEST_BASE cmp #$00 FAIL_NE lda HEAP_TEST_BASE+1 cmp #$10 FAIL_NE lda HEAP_TEST_BASE+2 ora HEAP_TEST_BASE+3 FAIL_NE lda #$01 sta MB_DATA+0 ; ------------------------------------------- one allocation and free PHASE 2 lda #32 ldx #0 jsr heap_alloc FAIL_CS cmp #$04 FAIL_NE cpx #$40 FAIL_NE lda heap_free_total cmp #$DC FAIL_NE lda heap_free_total+1 cmp #$0F FAIL_NE lda HEAP_TEST_BASE cmp #$24 FAIL_NE lda HEAP_TEST_BASE+1 cmp #$80 FAIL_NE lda HEAP_TEST_BASE+2 cmp #$5A FAIL_NE lda HEAP_TEST_BASE+3 cmp #$A5 FAIL_NE ldy #0 @zero: lda HEAP_TEST_BASE+4,y FAIL_NE iny cpy #32 bne @zero lda #$A5 ldy #0 @fill: sta HEAP_TEST_BASE+4,y iny cpy #32 bne @fill lda #$04 ldx #$40 jsr heap_free FAIL_CS lda heap_free_total cmp #$00 FAIL_NE lda heap_free_total+1 cmp #$10 FAIL_NE lda HEAP_TEST_BASE cmp #$00 FAIL_NE lda HEAP_TEST_BASE+1 cmp #$10 FAIL_NE lda HEAP_TEST_BASE+2 ora HEAP_TEST_BASE+3 FAIL_NE lda #$01 sta MB_DATA+1 ; ------------------------------------------ split and coalesce twice PHASE 3 lda #16 ldx #0 jsr heap_alloc FAIL_CS cmp #$04 FAIL_NE cpx #$40 FAIL_NE lda heap_free_total cmp #$EC FAIL_NE lda heap_free_total+1 cmp #$0F FAIL_NE lda HEAP_TEST_BASE cmp #$14 FAIL_NE lda HEAP_TEST_BASE+1 cmp #$80 FAIL_NE lda HEAP_TEST_BASE+$14 cmp #$EC FAIL_NE lda HEAP_TEST_BASE+$15 cmp #$0F FAIL_NE lda #16 ldx #0 jsr heap_alloc FAIL_CS cmp #$18 FAIL_NE cpx #$40 FAIL_NE lda heap_free_total cmp #$D8 FAIL_NE lda heap_free_total+1 cmp #$0F FAIL_NE lda HEAP_TEST_BASE+$28 cmp #$D8 FAIL_NE lda HEAP_TEST_BASE+$29 cmp #$0F FAIL_NE lda #$04 ldx #$40 jsr heap_free FAIL_CS lda #$18 ldx #$40 jsr heap_free FAIL_CS lda heap_free_total cmp #$00 FAIL_NE lda heap_free_total+1 cmp #$10 FAIL_NE lda HEAP_TEST_BASE cmp #$00 FAIL_NE lda HEAP_TEST_BASE+1 cmp #$10 FAIL_NE lda HEAP_TEST_BASE+2 ora HEAP_TEST_BASE+3 FAIL_NE lda #$01 sta MB_DATA+2 ; ---------------------------------------------------- stress pass PHASE 4 lda #0 sta stress_i @alloc: lda #64 ldx #0 jsr heap_alloc FAIL_CS sta tptr stx tptr+1 ldx stress_i lda tptr sta ptrs,x lda tptr+1 sta ptrs+1,x ldy #0 lda tptr sta (tptr),y ldy #63 lda #$A5 sta (tptr),y lda stress_i clc adc #2 sta stress_i cmp #32 bne @alloc lda #0 sta stress_i @verify: ldx stress_i lda ptrs,x sta tptr lda ptrs+1,x sta tptr+1 ldy #0 lda (tptr),y cmp tptr FAIL_NE ldy #63 lda (tptr),y cmp #$A5 FAIL_NE lda stress_i clc adc #2 sta stress_i cmp #32 bne @verify lda #0 sta stress_i @free_even: ldx stress_i lda ptrs,x sta tptr lda ptrs+1,x sta tptr+1 lda tptr ldx tptr+1 jsr heap_free FAIL_CS lda stress_i clc adc #4 sta stress_i cmp #32 bne @free_even lda #30 sta stress_i @free_odd: ldx stress_i lda ptrs,x sta tptr lda ptrs+1,x sta tptr+1 lda tptr ldx tptr+1 jsr heap_free FAIL_CS lda stress_i sec sbc #4 sta stress_i bcs @free_odd lda heap_free_total cmp #$00 FAIL_NE lda heap_free_total+1 cmp #$10 FAIL_NE lda HEAP_TEST_BASE cmp #$00 FAIL_NE lda HEAP_TEST_BASE+1 cmp #$10 FAIL_NE lda #$01 sta MB_DATA+3 ; --------------------------------------------------- double free PHASE 5 lda #16 ldx #0 jsr heap_alloc FAIL_CS lda #$04 ldx #$40 jsr heap_free FAIL_CS lda #$04 ldx #$40 jsr heap_free FAIL_CC lda heap_error cmp #HEAP_ERR_DOUBLE FAIL_NE lda heap_free_total cmp #$00 FAIL_NE lda heap_free_total+1 cmp #$10 FAIL_NE lda #$01 sta MB_DATA+4 ; ------------------------------------------------ corrupt header PHASE 6 lda #16 ldx #0 jsr heap_alloc FAIL_CS lda #$00 sta HEAP_TEST_BASE+2 sta HEAP_TEST_BASE+3 lda #$04 ldx #$40 jsr heap_free FAIL_CC lda heap_error cmp #HEAP_ERR_CORRUPT FAIL_NE lda heap_free_total cmp #$EC FAIL_NE lda heap_free_total+1 cmp #$0F FAIL_NE lda #$5A sta HEAP_TEST_BASE+2 lda #$A5 sta HEAP_TEST_BASE+3 lda #$04 ldx #$40 jsr heap_free FAIL_CS lda heap_free_total cmp #$00 FAIL_NE lda heap_free_total+1 cmp #$10 FAIL_NE lda #$01 sta MB_DATA+5 ; ---------------------------------------- exhaustion and integrity PHASE 7 lda #0 sta stress_i @ex_alloc: lda #128 ldx #0 jsr heap_alloc FAIL_CS sta tptr stx tptr+1 ldx stress_i lda tptr sta ptrs,x lda tptr+1 sta ptrs+1,x ldy #0 lda #$C3 sta (tptr),y ldy #127 lda #$A5 sta (tptr),y lda stress_i clc adc #2 sta stress_i cmp #6 bne @ex_alloc lda heap_free_total cmp #$74 FAIL_NE lda heap_free_total+1 cmp #$0E FAIL_NE lda #$00 ldx #$10 jsr heap_alloc FAIL_CC lda heap_error cmp #HEAP_ERR_OOM FAIL_NE lda heap_free_total cmp #$74 FAIL_NE lda heap_free_total+1 cmp #$0E FAIL_NE lda #0 sta stress_i @ex_verify: ldx stress_i lda ptrs,x sta tptr lda ptrs+1,x sta tptr+1 ldy #0 lda (tptr),y cmp #$C3 FAIL_NE ldy #127 lda (tptr),y cmp #$A5 FAIL_NE lda stress_i clc adc #2 sta stress_i cmp #6 bne @ex_verify lda #0 sta stress_i @ex_free: ldx stress_i lda ptrs,x sta tptr lda ptrs+1,x sta tptr+1 lda tptr ldx tptr+1 jsr heap_free FAIL_CS lda stress_i clc adc #2 sta stress_i cmp #6 bne @ex_free lda heap_free_total cmp #$00 FAIL_NE lda heap_free_total+1 cmp #$10 FAIL_NE lda HEAP_TEST_BASE cmp #$00 FAIL_NE lda HEAP_TEST_BASE+1 cmp #$10 FAIL_NE lda #$01 sta MB_DATA+6 lda #$01 sta MB_DATA+7 TEXT heap_ok, 7 jsr pr_cr lda #FLT_HEAP ldx #$00 ldy #$40 jsr flt_report jmp @done @fail: lda #MB_ST_FAIL sta MB_STATUS @done: lda saved_cr sta MMU_CR plp rts .segment "RODATA" title: .byte "NOVA128 HEAP TEST" heap_ok: .byte "HEAP OK" .segment "BSS" saved_cr: .res 1 stress_i: .res 1 ptrs: .res 32 test_end: