; E04-S03: scalar emitter and arithmetic fixture in x128. ; ; The fixture drives codegen.s directly (parser integration is E04-S04), ; executes the emitted shapes, copies the golden bytes to golden_copy, then ; tests the arithmetic helpers. It runs in the compiler/BASIC mapping; all ; variables and the code buffer are below $A000. ; ; Mailbox data: ; +0 byte assignment (5A) ; +1 comparison bit mask (EQ..GE, expected 0E with 5,7) ; +2/+3 word add ($2221) ; +4/+5 integer sub ($ECBB) ; +6 multiply result low ($2EE0 -> E0) ; +7 arithmetic fault (1 = divide by zero) ; Failure bits: 1 emitter/assignment, 2 add/sub, 4 comparisons, ; 8 short-circuit, 16 multiply, 32 unsigned divide, 64 signed divide, ; 128 divide-by-zero. .setcpu "6502" .include "../../src/common/c128.inc" .include "../../src/common/mailbox.inc" .include "../../src/common/codegen.inc" .include "../../src/common/arithmetic.inc" .import cg_init, cg_len, cg_err, cg_code, cg_here, cg_patch_here .import cg_lda_imm, cg_ldx_imm, cg_ora_imm .import cg_lda_abs, cg_ldx_abs, cg_sta_abs, cg_stx_abs .import cg_adc_abs, cg_sbc_abs, cg_cmp_abs, cg_jsr_abs .import cg_clc, cg_sec, cg_rts, cg_branch_fwd .import ar_mul_u16, ar_div_u16, ar_div_i16, ar_a, ar_b, ar_rem, ar_fault ; Fixed bank-0 scratch variables (SCRATCH is unused by this fixture). V_SRC = $1B00 V_DST = $1B01 V_WIDE = $1B02 V_ADD_A = $1B04 V_ADD_B = $1B06 V_ADD_R = $1B08 V_SUB_A = $1B0A V_SUB_B = $1B0C V_SUB_R = $1B0E V_BYTE_A = $1B10 V_BYTE_B = $1B11 V_CMP = $1B12 V_FLAG = $1B13 V_EVAL = $1B14 V_MUL_A = $1B16 V_MUL_B = $1B18 V_MUL_R = $1B1A V_DIV_A = $1B1C V_DIV_B = $1B1E V_DIV_R = $1B20 V_SDIV_A = $1B22 V_SDIV_B = $1B24 V_SDIV_R = $1B26 .macro EMIT_LDA addr lda #<(addr) ldx #>(addr) jsr cg_lda_abs .endmacro .macro EMIT_LDX addr lda #<(addr) ldx #>(addr) jsr cg_ldx_abs .endmacro .macro EMIT_STA addr lda #<(addr) ldx #>(addr) jsr cg_sta_abs .endmacro .macro EMIT_STX addr lda #<(addr) ldx #>(addr) jsr cg_stx_abs .endmacro .macro EMIT_ADC addr lda #<(addr) ldx #>(addr) jsr cg_adc_abs .endmacro .macro EMIT_SBC addr lda #<(addr) ldx #>(addr) jsr cg_sbc_abs .endmacro .macro EMIT_CMP addr lda #<(addr) ldx #>(addr) jsr cg_cmp_abs .endmacro .macro EMIT_JSR addr lda #<(addr) ldx #>(addr) jsr cg_jsr_abs .endmacro .macro EMIT_LDA_IMM value lda #value jsr cg_lda_imm .endmacro .macro EMIT_ORA_IMM value lda #value jsr cg_ora_imm .endmacro .macro EMIT_BIT value EMIT_LDA V_CMP EMIT_ORA_IMM value EMIT_STA V_CMP .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 "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 MB_CODE sta MB_CODE+1 jsr init_vars jsr cg_init ; ---------------------------------------------------- golden shape 1: byte assignment EMIT_LDA V_SRC EMIT_STA V_DST jsr cg_rts lda cg_len sta s2 ; ---------------------------------------------------- shape 2: byte -> word widening EMIT_LDA V_SRC EMIT_STA V_WIDE EMIT_LDA_IMM $00 EMIT_STA V_WIDE+1 jsr cg_rts lda cg_len sta s3 ; ---------------------------------------------------- shape 3: word addition EMIT_LDA V_ADD_A jsr cg_clc EMIT_ADC V_ADD_B EMIT_STA V_ADD_R EMIT_LDA V_ADD_A+1 EMIT_ADC V_ADD_B+1 EMIT_STA V_ADD_R+1 jsr cg_rts lda cg_len sta s4 ; ---------------------------------------------------- shape 4: integer subtraction EMIT_LDA V_SUB_A jsr cg_sec EMIT_SBC V_SUB_B EMIT_STA V_SUB_R EMIT_LDA V_SUB_A+1 EMIT_SBC V_SUB_B+1 EMIT_STA V_SUB_R+1 jsr cg_rts lda cg_len sta s5 ; ---------------------------------------------------- shape 5: six comparisons EMIT_LDA_IMM $00 EMIT_STA V_CMP ; EQ bit 1 EMIT_LDA V_BYTE_A EMIT_CMP V_BYTE_B lda #$D0 ; BNE skip jsr cg_branch_fwd sta fix_eq EMIT_BIT $01 lda fix_eq jsr cg_patch_here ; NE bit 2 EMIT_LDA V_BYTE_A EMIT_CMP V_BYTE_B lda #$F0 ; BEQ skip jsr cg_branch_fwd sta fix_ne EMIT_BIT $02 lda fix_ne jsr cg_patch_here ; LT bit 4 EMIT_LDA V_BYTE_A EMIT_CMP V_BYTE_B lda #$B0 ; BCS skip jsr cg_branch_fwd sta fix_lt EMIT_BIT $04 lda fix_lt jsr cg_patch_here ; LE bit 8: equal or below goes to set, above skips EMIT_LDA V_BYTE_A EMIT_CMP V_BYTE_B lda #$F0 ; BEQ set jsr cg_branch_fwd sta fix_le1 lda #$90 ; BCC set jsr cg_branch_fwd sta fix_le2 lda #$B0 ; BCS skip jsr cg_branch_fwd sta fix_le3 lda fix_le1 jsr cg_patch_here lda fix_le2 jsr cg_patch_here EMIT_BIT $08 lda fix_le3 jsr cg_patch_here ; GT bit 16: equal or below skips EMIT_LDA V_BYTE_A EMIT_CMP V_BYTE_B lda #$F0 ; BEQ skip jsr cg_branch_fwd sta fix_gt1 lda #$90 ; BCC skip jsr cg_branch_fwd sta fix_gt2 EMIT_BIT $10 lda fix_gt1 jsr cg_patch_here lda fix_gt2 jsr cg_patch_here ; GE bit 32 EMIT_LDA V_BYTE_A EMIT_CMP V_BYTE_B lda #$90 ; BCC skip jsr cg_branch_fwd sta fix_ge EMIT_BIT $20 lda fix_ge jsr cg_patch_here jsr cg_rts lda cg_len sta s6 ; ---------------------------------------------------- shape 6: short-circuit AND EMIT_LDA_IMM $00 EMIT_STA V_EVAL EMIT_LDA V_BYTE_A lda #$F0 ; BEQ false jsr cg_branch_fwd sta fix_and1 EMIT_LDA_IMM $01 EMIT_STA V_EVAL EMIT_LDA V_BYTE_B lda #$F0 ; BEQ false jsr cg_branch_fwd sta fix_and2 EMIT_LDA_IMM $01 EMIT_STA V_FLAG jsr cg_rts lda fix_and1 jsr cg_patch_here lda fix_and2 jsr cg_patch_here EMIT_LDA_IMM $00 EMIT_STA V_FLAG jsr cg_rts lda cg_len sta s7 ; ---------------------------------------------------- shape 7: short-circuit OR EMIT_LDA_IMM $00 EMIT_STA V_EVAL EMIT_LDA V_BYTE_A lda #$D0 ; BNE true jsr cg_branch_fwd sta fix_or1 EMIT_LDA_IMM $01 EMIT_STA V_EVAL EMIT_LDA V_BYTE_B lda #$D0 ; BNE true jsr cg_branch_fwd sta fix_or2 EMIT_LDA_IMM $00 EMIT_STA V_FLAG jsr cg_rts lda fix_or1 jsr cg_patch_here lda fix_or2 jsr cg_patch_here EMIT_LDA_IMM $01 EMIT_STA V_FLAG jsr cg_rts lda cg_len sta golden_len jsr copy_golden lda cg_err beq @golden_ok lda #$01 jsr fail jmp @finish @golden_ok: ; ---------------------------------------------------- run golden shapes lda #$00 jsr run_code lda V_DST cmp #$5A beq @s2 lda #$01 jsr fail @s2: lda s2 jsr run_code lda V_WIDE cmp #$5A bne @s2_bad lda V_WIDE+1 bne @s2_bad jmp @s3 @s2_bad: lda #$01 jsr fail @s3: lda s3 jsr run_code lda V_ADD_R cmp #$21 bne @s3_bad lda V_ADD_R+1 cmp #$22 bne @s3_bad jmp @s4 @s3_bad: lda #$02 jsr fail @s4: lda s4 jsr run_code lda V_SUB_R cmp #$BB bne @s4_bad lda V_SUB_R+1 cmp #$EC bne @s4_bad jmp @s5 @s4_bad: lda #$02 jsr fail @s5: lda s5 jsr run_code lda V_CMP cmp #$0E beq @s6 lda #$04 jsr fail @s6: lda #$00 sta V_BYTE_A lda #$01 sta V_BYTE_B lda s6 jsr run_code lda V_FLAG bne @s6_bad lda V_EVAL bne @s6_bad jmp @s7 @s6_bad: lda #$08 jsr fail @s7: lda #$01 sta V_BYTE_A lda #$00 sta V_BYTE_B lda s7 jsr run_code lda V_FLAG cmp #$01 bne @s7_bad lda V_EVAL bne @s7_bad jmp @arith @s7_bad: lda #$08 jsr fail ; ---------------------------------------------------- arithmetic helpers @arith: jsr cg_init EMIT_LDA V_MUL_A EMIT_STA ar_a EMIT_LDA V_MUL_A+1 EMIT_STA ar_a+1 EMIT_LDA V_MUL_B EMIT_STA ar_b EMIT_LDA V_MUL_B+1 EMIT_STA ar_b+1 EMIT_JSR ar_mul_u16 EMIT_STA V_MUL_R EMIT_STX V_MUL_R+1 jsr cg_rts lda cg_err beq @mul_run lda #$10 jsr fail jmp @div @mul_run: lda #$00 jsr run_code lda V_MUL_R cmp #$E0 bne @mul_bad lda V_MUL_R+1 cmp #$2E bne @mul_bad jmp @div @mul_bad: lda #$10 jsr fail @div: jsr cg_init EMIT_LDA V_DIV_A EMIT_STA ar_a EMIT_LDA V_DIV_A+1 EMIT_STA ar_a+1 EMIT_LDA V_DIV_B EMIT_STA ar_b EMIT_LDA V_DIV_B+1 EMIT_STA ar_b+1 EMIT_JSR ar_div_u16 EMIT_STA V_DIV_R EMIT_STX V_DIV_R+1 jsr cg_rts lda cg_err beq @div_run lda #$20 jsr fail jmp @sdiv @div_run: lda #$00 jsr run_code bcs @div_bad lda V_DIV_R cmp #$8E bne @div_bad lda V_DIV_R+1 bne @div_bad lda ar_rem cmp #$06 bne @div_bad lda ar_rem+1 bne @div_bad jmp @sdiv @div_bad: lda #$20 jsr fail @sdiv: jsr cg_init EMIT_LDA V_SDIV_A EMIT_STA ar_a EMIT_LDA V_SDIV_A+1 EMIT_STA ar_a+1 EMIT_LDA V_SDIV_B EMIT_STA ar_b EMIT_LDA V_SDIV_B+1 EMIT_STA ar_b+1 EMIT_JSR ar_div_i16 EMIT_STA V_SDIV_R EMIT_STX V_SDIV_R+1 jsr cg_rts lda cg_err beq @sdiv_run lda #$40 jsr fail jmp @divzero @sdiv_run: lda #$00 jsr run_code bcs @sdiv_bad lda V_SDIV_R cmp #$F2 bne @sdiv_bad lda V_SDIV_R+1 cmp #$FF bne @sdiv_bad jmp @divzero @sdiv_bad: lda #$40 jsr fail @divzero: lda #$00 sta V_DIV_B sta V_DIV_B+1 jsr cg_init EMIT_LDA V_DIV_A EMIT_STA ar_a EMIT_LDA V_DIV_A+1 EMIT_STA ar_a+1 EMIT_LDA V_DIV_B EMIT_STA ar_b EMIT_LDA V_DIV_B+1 EMIT_STA ar_b+1 EMIT_JSR ar_div_u16 EMIT_STA V_DIV_R EMIT_STX V_DIV_R+1 jsr cg_rts lda cg_err beq @dz_run lda #$80 jsr fail jmp @finish @dz_run: lda #$00 jsr run_code bcc @dz_bad lda ar_fault cmp #AR_FAULT_DIV0 bne @dz_bad lda V_DIV_R ora V_DIV_R+1 bne @dz_bad jmp @finish @dz_bad: lda #$80 jsr fail ; ---------------------------------------------------- report @finish: lda V_DST sta MB_DATA+0 lda V_CMP sta MB_DATA+1 lda V_ADD_R sta MB_DATA+2 lda V_ADD_R+1 sta MB_DATA+3 lda V_SUB_R sta MB_DATA+4 lda V_SUB_R+1 sta MB_DATA+5 lda V_MUL_R sta MB_DATA+6 lda ar_fault sta MB_DATA+7 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 ; A = code-buffer offset. Patch a JSR operand and run the snippet. run_code: clc adc #cg_code adc #0 sta @target+2 @target: jsr $FFFF rts copy_golden: ldx #$00 @copy: cpx golden_len beq @done lda cg_code,x sta golden_copy,x inx bne @copy @done: rts init_vars: lda #$5A sta V_SRC sta V_DST lda #$00 sta V_WIDE sta V_WIDE+1 sta V_CMP sta V_FLAG sta V_EVAL sta ar_fault lda #$34 sta V_ADD_A lda #$12 sta V_ADD_A+1 lda #$ED sta V_ADD_B lda #$0F sta V_ADD_B+1 lda #$00 sta V_ADD_R sta V_ADD_R+1 lda #$00 sta V_SUB_A lda #$10 sta V_SUB_A+1 lda #$45 sta V_SUB_B lda #$23 sta V_SUB_B+1 lda #$00 sta V_SUB_R sta V_SUB_R+1 lda #$05 sta V_BYTE_A lda #$07 sta V_BYTE_B lda #$2C sta V_MUL_A lda #$01 sta V_MUL_A+1 lda #$28 sta V_MUL_B lda #$00 sta V_MUL_B+1 lda #$00 sta V_MUL_R sta V_MUL_R+1 lda #$E8 sta V_DIV_A lda #$03 sta V_DIV_A+1 lda #$07 sta V_DIV_B lda #$00 sta V_DIV_B+1 lda #$00 sta V_DIV_R sta V_DIV_R+1 lda #$9C sta V_SDIV_A lda #$FF sta V_SDIV_A+1 lda #$07 sta V_SDIV_B lda #$00 sta V_SDIV_B+1 lda #$00 sta V_SDIV_R sta V_SDIV_R+1 rts .segment "CODE" fail: ora fail_mask sta fail_mask rts .segment "RODATA" message: .byte "NOVA128 SCALAR TEST DONE", $0D, $00 .segment "BSS" fail_mask: .res 1 print_y: .res 1 s2: .res 1 s3: .res 1 s4: .res 1 s5: .res 1 s6: .res 1 s7: .res 1 fix_eq: .res 1 fix_ne: .res 1 fix_lt: .res 1 fix_le1: .res 1 fix_le2: .res 1 fix_le3: .res 1 fix_gt1: .res 1 fix_gt2: .res 1 fix_ge: .res 1 fix_and1: .res 1 fix_and2: .res 1 fix_or1: .res 1 fix_or2: .res 1 .export golden_len .export golden_copy golden_len: .res 1 golden_copy: .res 256