; E04-S02: software-frame ABI test in x128. ; ; The fixture runs with CR=$0E and IRQs masked so the frame stack at ; $B800-$BFFF is RAM. It restores the entry CR before returning to BASIC. ; Checks: ; +0/+1 recursive two-byte result (sum 1..50 = 1275 = $04FB) ; +2 one-byte return (5+7 = 12) ; +3 overflow error (FRAME_ERR_STACK) ; +4/+5 SP after the overflow unwinds ($C000) ; +6 frame_error after overflow (FRAME_ERR_STACK) ; +7 FP low after unwinding (0) ; Failure bits: 1 recursion, 2 one-byte return, 4 overflow, 8 stack state. .setcpu "6502" .include "../../src/common/c128.inc" .include "../../src/common/mailbox.inc" .include "../../src/common/frames.inc" .import frame_init, frame_enter, frame_leave, frame_discard .import frame_push_byte, frame_push_word, frame_error .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 "STARTUP" .export test_entry 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 #$00 sta fail_mask sta sum_lo sta sum_hi sta byte_sum sta ov_error sta MB_CODE sta MB_CODE+1 jsr frame_init lda MMU_CR sta saved_cr lda #CR_RAM0_KERNAL sta MMU_CR ; ------------------------------------------------ successful recursion jsr frame_init lda #<50 ldx #>50 jsr frame_push_word bcs @rec_push_fail jsr recurse bcs @rec_call_fail sta sum_lo stx sum_hi lda #2 ldx #0 jsr frame_discard lda sum_lo cmp #$FB bne @rec_bad lda sum_hi cmp #$04 bne @rec_bad lda FRAME_SP cmp #FRAME_STACK_TOP bne @rec_bad jmp @byte_return @rec_push_fail: lda #$01 jsr fail jmp @byte_return @rec_call_fail: lda #2 ldx #0 jsr frame_discard lda #$01 jsr fail jmp @byte_return @rec_bad: lda #$01 jsr fail ; --------------------------------------------------- one-byte return @byte_return: jsr frame_init lda #7 jsr frame_push_byte bcs @byte_fail lda #5 jsr frame_push_byte bcs @byte_fail jsr sum_bytes bcs @byte_fail sta byte_sum lda #2 ldx #0 jsr frame_discard lda byte_sum cmp #12 beq @overflow @byte_fail: lda #$02 jsr fail ; ------------------------------------------------------ stack overflow @overflow: jsr frame_init lda #<1000 ldx #>1000 jsr frame_push_word bcs @ov_push_fail jsr recurse bcc @ov_no_fault lda #2 ldx #0 jsr frame_discard lda frame_error sta ov_error cmp #FRAME_ERR_STACK beq @ov_check_sp lda #$04 jsr fail jmp @ov_check_sp @ov_push_fail: lda #$04 jsr fail jmp @finish @ov_no_fault: lda #2 ldx #0 jsr frame_discard lda #$04 jsr fail @ov_check_sp: lda FRAME_SP cmp #FRAME_STACK_TOP bne @ov_bad lda FRAME_FP ora FRAME_FP+1 beq @finish @ov_bad: lda #$08 jsr fail ; ---------------------------------------------- hardware-stack guard tsx stx saved_hw_sp ldx #$20 txs lda #0 ldx #0 jsr frame_enter ldx saved_hw_sp txs bcc @hw_bad lda frame_error cmp #FRAME_ERR_STACK beq @finish @hw_bad: lda #$10 jsr fail ; ---------------------------------------------------------- report @finish: lda sum_lo sta MB_DATA+0 lda sum_hi sta MB_DATA+1 lda byte_sum sta MB_DATA+2 lda ov_error sta MB_DATA+3 lda FRAME_SP sta MB_DATA+4 lda FRAME_SP+1 sta MB_DATA+5 lda frame_error sta MB_DATA+6 lda FRAME_FP sta MB_DATA+7 lda saved_cr sta MMU_CR lda fail_mask sta MB_CODE lda #$00 sta MB_CODE+1 lda #MB_ST_FAIL ldx fail_mask bne @status lda #MB_ST_PASS @status: sta MB_STATUS ldy #$00 @print: lda message,y beq @end sty print_y jsr CHROUT ldy print_y iny bne @print @end: plp rts .segment "CODE" fail: ora fail_mask sta fail_mask rts ; recurse(depth) -> depth + recurse(depth-1), zero at depth 0. ; Arguments: depth word at FP+2. Locals: depth word, result word. recurse: lda #24 ldx #0 jsr frame_enter bcc @entered jmp @entry_err @entered: ; local +0/+1 = depth, local +2/+3 = sentinel/result ldy #2 lda (FRAME_FP),y ldy #0 sta (FRAME_SP),y ldy #3 lda (FRAME_FP),y ldy #1 sta (FRAME_SP),y ldy #2 lda #$A5 sta (FRAME_SP),y iny lda #$5A sta (FRAME_SP),y ldy #0 lda (FRAME_SP),y sta depth iny lda (FRAME_SP),y sta depth+1 lda depth ora depth+1 beq @zero lda depth sec sbc #1 sta calc lda depth+1 sbc #0 sta calc+1 lda calc ldx calc+1 jsr frame_push_word bcs @push_err jsr recurse bcs @nested_err sta result stx result+1 lda #2 ldx #0 jsr frame_discard ldy #2 lda (FRAME_SP),y cmp #$A5 bne @corrupt iny lda (FRAME_SP),y cmp #$5A bne @corrupt ldy #0 lda (FRAME_SP),y clc adc result sta result ldy #1 lda (FRAME_SP),y adc result+1 sta result+1 ldy #2 lda result sta (FRAME_SP),y ldy #3 lda result+1 sta (FRAME_SP),y lda result ldx result+1 jmp @leave @zero: lda #0 ldx #0 @leave: sta ret_lo stx ret_hi jsr frame_leave lda ret_lo ldx ret_hi clc rts @entry_err: lda #FRAME_ERR_STACK sec rts @push_err: jsr frame_leave lda #FRAME_ERR_STACK sec rts @nested_err: lda #2 ldx #0 jsr frame_discard jsr frame_leave lda #FRAME_ERR_STACK sec rts @corrupt: lda #2 ldx #0 jsr frame_discard jsr frame_leave lda #FRAME_ERR_STATE sec rts ; sum_bytes(a,b) -> A = a+b. Two byte arguments at FP+2 and FP+3. sum_bytes: lda #0 ldx #0 jsr frame_enter bcs @out ldy #2 lda (FRAME_FP),y iny clc adc (FRAME_FP),y sta sum_result jsr frame_leave lda sum_result clc rts @out: sec rts .segment "RODATA" message: .byte "NOVA128 FRAME TEST DONE", $0D, $00 .segment "BSS" fail_mask: .res 1 print_y: .res 1 saved_cr: .res 1 saved_hw_sp: .res 1 sum_lo: .res 1 sum_hi: .res 1 byte_sum: .res 1 ov_error: .res 1 depth: .res 2 calc: .res 2 result: .res 2 ret_lo: .res 1 ret_hi: .res 1 sum_result: .res 1