; E06-S01: interface value ABI fixture in x128. ; ; Runs under CR=$0E. It checks: ; - the four-byte value is little-endian: object low/high then table ; low/high; ; - null conversion writes four zero bytes and ignores the table pointer; ; - a non-null object with no table is IF_ERR_TABLE with a zero table half; ; - copying preserves all four bytes and never reads through a null pointer; ; - slot lookup reads table[slot*2] in declaration slot order; ; - the four-byte result area IF_RESULT carries all four bytes, and a failed ; store leaves the previous result intact; ; - four interface bytes pushed right-to-left arrive at FP+2..FP+5. ; ; MB_DATA flags 0..5 report the six phases. .setcpu "6502" .include "../../src/common/c128.inc" .include "../../src/common/mailbox.inc" .include "../../src/common/print.inc" .include "../../src/common/frames.inc" .include "../../src/common/interfaces.inc" .import pr_char, pr_cr, pr_text .import frame_init, frame_enter, frame_leave, frame_push_byte, frame_discard .import if_conv, if_copy, if_is_null, if_slot, if_ret_store, if_ret_load .import if_error .importzp if_obj, if_tab, if_dst, if_src .macro TEXT src, len lda #src ldy #len jsr pr_text .endmacro .macro PHASE n lda #n sta MB_CODE lda #$00 sta MB_CODE+1 .endmacro .macro POINT var lda #var sta tptr+1 .endmacro .macro SETDST var lda #var sta if_dst+1 .endmacro .macro SETSRC var lda #var sta if_src+1 .endmacro .macro EXPECT v0, v1, v2, v3 lda #v0 sta e0 lda #v1 sta e1 lda #v2 sta e2 lda #v3 sta e3 .endmacro .macro FAIL_CS bcc :+ jmp @fail : .endmacro .macro FAIL_CC bcs :+ jmp @fail : .endmacro .macro FAIL_NE beq :+ 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 #$00 sta MB_CODE sta MB_CODE+1 lda MMU_CR sta saved_cr lda #CR_RAM0_KERNAL sta MMU_CR lda #PR_CLEAR jsr pr_char TEXT title, 22 jsr pr_cr ; 1: little-endian layout of object and table pointers. PHASE 1 lda #$34 sta if_obj lda #$12 sta if_obj+1 lda #$78 sta if_tab lda #$56 sta if_tab+1 SETDST val_a jsr if_conv FAIL_CS lda if_error FAIL_NE POINT val_a EXPECT $34, $12, $78, $56 jsr cmp_val FAIL_CS lda #$01 sta MB_DATA+0 ; 2: canonical null and invalid conversion. PHASE 2 lda #$00 sta if_obj sta if_obj+1 lda #$78 sta if_tab lda #$56 sta if_tab+1 SETDST val_b jsr if_conv FAIL_CS lda if_error FAIL_NE POINT val_b EXPECT $00, $00, $00, $00 jsr cmp_val FAIL_CS lda #val_b jsr if_is_null FAIL_CC lda #val_a jsr if_is_null FAIL_CS lda #$34 sta if_obj lda #$12 sta if_obj+1 lda #$00 sta if_tab sta if_tab+1 SETDST val_c jsr if_conv FAIL_CC lda if_error cmp #IF_ERR_TABLE FAIL_NE POINT val_c EXPECT $34, $12, $00, $00 jsr cmp_val FAIL_CS lda #$00 ldx #$00 jsr if_is_null FAIL_CC lda #$01 sta MB_DATA+1 ; 3: copying preserves every byte and rejects a null source pointer. PHASE 3 SETSRC val_a SETDST val_d jsr if_copy FAIL_CS POINT val_d EXPECT $34, $12, $78, $56 jsr cmp_val FAIL_CS POINT val_a EXPECT $34, $12, $78, $56 jsr cmp_val FAIL_CS SETSRC val_b SETDST val_e jsr if_copy FAIL_CS POINT val_e EXPECT $00, $00, $00, $00 jsr cmp_val FAIL_CS lda #$00 sta if_src sta if_src+1 SETDST val_e jsr if_copy FAIL_CC lda if_error cmp #IF_ERR_NULL FAIL_NE POINT val_e EXPECT $00, $00, $00, $00 jsr cmp_val FAIL_CS lda #$01 sta MB_DATA+2 ; 4: slot order and the two refusal cases. PHASE 4 lda #$34 sta if_obj lda #$12 sta if_obj+1 lda #slot_tab sta if_tab+1 SETDST val_f jsr if_conv FAIL_CS lda #val_f ldy #0 jsr if_slot FAIL_CS cmp #$EF FAIL_NE cpx #$BE FAIL_NE lda #val_f ldy #1 jsr if_slot FAIL_CS cmp #$FE FAIL_NE cpx #$CA FAIL_NE lda #val_b ldy #0 jsr if_slot FAIL_CC lda if_error cmp #IF_ERR_NULL FAIL_NE lda #val_c ldy #0 jsr if_slot FAIL_CC lda if_error cmp #IF_ERR_TABLE FAIL_NE lda #$01 sta MB_DATA+3 ; 5: four-byte result area. PHASE 5 lda #val_a jsr if_ret_store FAIL_CS POINT IF_RESULT EXPECT $34, $12, $78, $56 jsr cmp_val FAIL_CS lda #val_g jsr if_ret_load FAIL_CS POINT val_g EXPECT $34, $12, $78, $56 jsr cmp_val FAIL_CS lda #val_b jsr if_ret_store FAIL_CS lda #val_h jsr if_ret_load FAIL_CS POINT val_h EXPECT $00, $00, $00, $00 jsr cmp_val FAIL_CS lda #val_a jsr if_ret_store FAIL_CS lda #$00 ldx #$00 jsr if_ret_store FAIL_CC lda if_error cmp #IF_ERR_NULL FAIL_NE POINT IF_RESULT EXPECT $34, $12, $78, $56 jsr cmp_val FAIL_CS lda #$01 sta MB_DATA+4 ; 6: an interface argument pushed right-to-left lands object-first. PHASE 6 jsr frame_init lda FRAME_SP sta saved_sp lda FRAME_SP+1 sta saved_sp+1 lda #$56 jsr frame_push_byte FAIL_CS lda #$78 jsr frame_push_byte FAIL_CS lda #$12 jsr frame_push_byte FAIL_CS lda #$34 jsr frame_push_byte FAIL_CS jsr take_iface FAIL_CS lda #IF_VALUE_SIZE ldx #$00 jsr frame_discard lda FRAME_SP cmp saved_sp FAIL_NE lda FRAME_SP+1 cmp saved_sp+1 FAIL_NE lda #$01 sta MB_DATA+5 TEXT iface_ok, 12 jsr pr_cr lda #MB_ST_PASS sta MB_STATUS lda #$00 sta MB_CODE sta MB_CODE+1 jmp @restore @fail: lda #MB_ST_FAIL sta MB_STATUS TEXT iface_fail, 14 jsr pr_cr @restore: lda saved_cr sta MMU_CR plp rts ; Reads the four argument bytes at FP+2..FP+5: object $1234, table $5678. take_iface: lda #$00 ldx #$00 jsr frame_enter bcs @bad ldy #2 lda (FRAME_FP),y cmp #$34 bne @bad iny lda (FRAME_FP),y cmp #$12 bne @bad iny lda (FRAME_FP),y cmp #$78 bne @bad iny lda (FRAME_FP),y cmp #$56 bne @bad jsr frame_leave clc rts @bad: sec rts ; C=1 when the four bytes at tptr differ from e0..e3. cmp_val: ldy #$00 lda (tptr),y cmp e0 bne @no iny lda (tptr),y cmp e1 bne @no iny lda (tptr),y cmp e2 bne @no iny lda (tptr),y cmp e3 bne @no clc rts @no: sec rts .segment "DATA" slot_tab: .word $BEEF .word $CAFE .assert * - slot_tab = 2 * IF_SLOT_SIZE, error, "slot table size" .segment "RODATA" title: .byte "NOVA128 INTERFACE ABI" iface_ok: .byte "INTERFACE OK" iface_fail: .byte "INTERFACE FAIL" .segment "BSS" saved_cr: .res 1 saved_sp: .res 2 e0: .res 1 e1: .res 1 e2: .res 1 e3: .res 1 val_a: .res IF_VALUE_SIZE val_b: .res IF_VALUE_SIZE val_c: .res IF_VALUE_SIZE val_d: .res IF_VALUE_SIZE val_e: .res IF_VALUE_SIZE val_f: .res IF_VALUE_SIZE val_g: .res IF_VALUE_SIZE val_h: .res IF_VALUE_SIZE test_end: