diff --git a/include/hucc/core-config.inc b/include/hucc/core-config.inc index 4841e0c..cf57592 100644 --- a/include/hucc/core-config.inc +++ b/include/hucc/core-config.inc @@ -120,15 +120,41 @@ SUPPORT_TED2 = 0 ; (0 or 1) .endif ; -; Support development for the SuperGrafx? +; Support development for the SuperGRAFX? ; -; This enables SuperGrafx support in certain library functions. +; This enables SuperGRAFX support in certain library functions. ; .ifndef SUPPORT_SGX SUPPORT_SGX = 0 ; (0 or 1) .endif +; +; Choose SuperGRAFX VPC initialization mode. +; +; SGX_PARALLAX=0 (useful when VDC #1 is a fullscreen HUD) +; +; FRONT +; SP1 = VDC #1 (pce) sprite pixels +; BG1 = VDC #1 (pce) background pixels +; SP2 = VDC #2 (sgx) sprite pixels +; BG2 = VDC #2 (sgx) background pixels +; BACK +; +; SGX_PARALLAX=1 +; +; FRONT +; SP1 = VDC #1 (pce) sprite pixels +; SP2 = VDC #2 (sgx) sprite pixels +; BG1 = VDC #1 (pce) background pixels +; BG2 = VDC #2 (sgx) background pixels +; BACK +; + + .ifndef SGX_PARALLAX +SGX_PARALLAX = 1 ; The most common default. + .endif + ; ; Support development for the ArcadeCard? ; diff --git a/include/hucc/hucc-codegen.asm b/include/hucc/hucc-codegen.asm index 955b3cf..fe877df 100644 --- a/include/hucc/hucc-codegen.asm +++ b/include/hucc/hucc-codegen.asm @@ -534,338 +534,1111 @@ __bra .macro .endm ; ************** -; boolean test, always followed by a __tst.wr or __not.wr -; this MUST set the Z flag for the susequent branches! +; always preceeded by a __tst.wr before peephole optimization -__cmp.wt .macro - jsr \1 +__bfalse .macro + bcc \1 .endm ; ************** -; boolean test, always followed by a __tst.wr or __not.wr -; this MUST set the Z flag for the susequent branches! +; always preceeded by a __tst.wr before peephole optimization -__cmp.ut .macro +__btrue .macro + bcs \1 + .endm + +; ************** +; boolean test, always followed by a __tst.wr or __not.wr before peephole optimization +; this MUST set the Z flag for the subsequent branches! + +__cmp.wt .macro jsr \1 .endm ; ************** ; optimized boolean test -; this MUST set the Z flag for the susequent branches! +; C is true (1) if Y:A == integer-value, else false (0) +; this MUST set the C flag for the subsequent branches! -__equ.wi .macro - eor.l #\1 +__equ_w.wi .macro + cmp.l #\1 bne !false+ cpy.h #\1 - beq !true+ -!false: lda #-1 -!true: inc a - cly + beq !+ +!false: clc +!: .endm ; ************** ; optimized boolean test -; this MUST set the Z flag for the susequent branches! +; C is true (1) if Y:A != integer-value, else false (0) +; this MUST set the C flag for the subsequent branches! -__neq.wi .macro +__neq_w.wi .macro + sec eor.l #\1 - bne !true+ - cpy.h #\1 - beq !false+ -!true: lda #1 -!false: cly + bne !+ + tya + eor.h #\1 + bne !+ + clc +!: + .endm + +; ************** +; optimized boolean test (signed word) +; C is true (1) if Y:A < integer-value, else false (0) +; this MUST set the C flag for the susequent branches! + +__slt_w.wi .macro + cmp.l #\1 ; Subtract integer from Y:A. + tya + sbc.h #\1 + bvc !+ + eor #$80 ; -ve if Y:A < integer (signed). +!: asl a + .endm + +; ************** +; optimized boolean test (signed word) +; C is true (1) if Y:A <= integer-value, else false (0) +; this MUST set the C flag for the susequent branches! + +__sle_w.wi .macro + clc ; Subtract integer+1 from Y:A. + sbc.l #\1 + tya + sbc.h #\1 + bvc !+ + eor #$80 ; -ve if Y:A <= integer (signed). +!: asl a + .endm + +; ************** +; optimized boolean test (signed word) +; C is true (1) if Y:A > integer-value, else false (0) +; this MUST set the C flag for the susequent branches! + +__sgt_w.wi .macro + clc ; Subtract integer+1 from Y:A. + sbc.l #\1 + tya + sbc.h #\1 + bvc !+ + eor #$80 ; +ve if Y:A > integer (signed). +!: eor #$80 + asl a + .endm + +; ************** +; optimized boolean test (signed word) +; C is true (1) if Y:A >= integer-value, else false (0) +; this MUST set the C flag for the susequent branches! + +__sge_w.wi .macro + cmp.l #\1 ; Subtract integer from Y:A. + tya + sbc.h #\1 + bvc !+ + eor #$80 ; +ve if Y:A >= integer (signed). +!: eor #$80 + asl a + .endm + +; ************** +; optimized boolean test (unsigned word) +; C is true (1) if Y:A < integer-value, else false (0) +; this MUST set the C flag for the susequent branches! + +__ult_w.wi .macro + cmp.l #\1 ; Subtract integer from Y:A. + tya + sbc.h #\1 ; CC if Y:A < integer. + ror a + eor #$80 + rol a + .endm + +; ************** +; optimized boolean test (unsigned word) +; C is true (1) if Y:A <= integer-value, else false (0) +; this MUST set the C flag for the susequent branches! + +__ule_w.wi .macro + clc ; Subtract integer+1 from Y:A. + sbc.l #\1 + tya + sbc.h #\1 ; CC if Y:A <= integer. + ror a + eor #$80 + rol a + .endm + +; ************** +; optimized boolean test (unsigned word) +; C is true (1) if Y:A > integer-value, else false (0) +; this MUST set the C flag for the susequent branches! + +__ugt_w.wi .macro + clc ; Subtract integer+1 from Y:A. + sbc.l #\1 + tya + sbc.h #\1 ; CS if Y:A > integer. + .endm + +; ************** +; optimized boolean test (unsigned word) +; C is true (1) if Y:A >= integer-value, else false (0) +; this MUST set the C flag for the susequent branches! + +__uge_w.wi .macro + cmp.l #\1 ; Subtract integer from Y:A. + tya + sbc.h #\1 ; CS if Y:A >= integer. + .endm + +; ************** +; optimized boolean test +; C is true (1) if A == integer-value, else false (0) +; this MUST set the C flag for the subsequent branches! + +__equ_b.uiq .macro + cmp #\1 + beq !+ + clc +!: + .endm + +; ************** +; optimized boolean test +; C is true (1) if A != integer-value, else false (0) +; this MUST set the C flag for the subsequent branches! + +__neq_b.uiq .macro + sec + eor #\1 + bne !+ + clc +!: + .endm + +; ************** +; optimized boolean test (signed byte) +; C is true (1) if A < integer-value, else false (0) +; this MUST set the C flag for the susequent branches! + +__slt_b.biq .macro + sec ; Subtract integer from A. + sbc #\1 + bvc !+ + eor #$80 ; -ve if A < integer (signed). +!: asl a + .endm + +; ************** +; optimized boolean test (signed byte) +; C is true (1) if A <= integer-value, else false (0) +; this MUST set the C flag for the susequent branches! + +__sle_b.biq .macro + clc ; Subtract integer+1 from A. + sbc #\1 + bvc !+ + eor #$80 ; -ve if A <= integer (signed). +!: asl a + .endm + +; ************** +; optimized boolean test (signed byte) +; C is true (1) if A > integer-value, else false (0) +; this MUST set the C flag for the susequent branches! + +__sgt_b.biq .macro + clc ; Subtract integer+1 from A. + sbc.l #\1 + bvc !+ + eor #$80 ; +ve if A > integer (signed). +!: eor #$80 + asl a + .endm + +; ************** +; optimized boolean test (signed byte) +; C is true (1) if A >= integer-value, else false (0) +; this MUST set the C flag for the susequent branches! + +__sge_b.biq .macro + sec ; Subtract integer from A. + sbc #\1 + bvc !+ + eor #$80 ; +ve if A >= integer (signed). +!: eor #$80 + asl a + .endm + +; ************** +; optimized boolean test (unsigned byte) +; C is true (1) if A < integer-value, else false (0) +; this MUST set the C flag for the susequent branches! + +__ult_b.uiq .macro + cmp #\1 ; Subtract integer from A. + ror a ; CC if A < integer. + eor #$80 + rol a + .endm + +; ************** +; optimized boolean test (unsigned byte) +; C is true (1) if A <= integer-value, else false (0) +; this MUST set the C flag for the susequent branches! + +__ule_b.uiq .macro + clc ; Subtract integer+1 from A. + sbc #\1 + ror a ; CC if A <= integer. + eor #$80 + rol a + .endm + +; ************** +; optimized boolean test (unsigned byte) +; C is true (1) if A > integer-value, else false (0) +; this MUST set the C flag for the susequent branches! + +__ugt_b.uiq .macro + clc ; Subtract integer+1 from A. + sbc #\1 ; CS if A > integer. + .endm + +; ************** +; optimized boolean test (unsigned byte) +; C is true (1) if A >= integer-value, else false (0) +; this MUST set the C flag for the susequent branches! + +__uge_b.uiq .macro + cmp #\1 ; Subtract integer from A. + ; CS if A >= integer. + .endm + +; ************** +; optimized boolean test +; C is true (1) if Y:A == memory-value, else false (0) +; this MUST set the C flag for the subsequent branches! + +__equ_w.wm .macro + cmp.l \1 + bne !false+ + cpy.h \1 + beq !+ +!false: clc +!: + .endm + +; ************** +; optimized boolean test +; C is true (1) if Y:A != memory-value, else false (0) +; this MUST set the C flag for the subsequent branches! + +__neq_w.wm .macro + sec + eor.l \1 + bne !+ + tya + eor.h \1 + bne !+ + clc +!: + .endm + +; ************** +; optimized boolean test (signed word) +; C is true (1) if Y:A < memory-value, else false (0) +; this MUST set the C flag for the susequent branches! + +__slt_w.wm .macro + cmp.l \1 ; Subtract memory from Y:A. + tya + sbc.h \1 + bvc !+ + eor #$80 ; -ve if Y:A < memory (signed). +!: asl a + .endm + +; ************** +; optimized boolean test (signed word) +; C is true (1) if Y:A <= memory-value, else false (0) +; this MUST set the C flag for the susequent branches! + +__sle_w.wm .macro + clc ; Subtract memory+1 from Y:A. + sbc.l \1 + tya + sbc.h \1 + bvc !+ + eor #$80 ; -ve if Y:A <= memory (signed). +!: asl a + .endm + +; ************** +; optimized boolean test (signed word) +; C is true (1) if Y:A > memory-value, else false (0) +; this MUST set the C flag for the susequent branches! + +__sgt_w.wm .macro + clc ; Subtract memory+1 from Y:A. + sbc.l \1 + tya + sbc.h \1 + bvc !+ + eor #$80 ; +ve if Y:A > memory (signed). +!: eor #$80 + asl a + .endm + +; ************** +; optimized boolean test (signed word) +; C is true (1) if Y:A >= memory-value, else false (0) +; this MUST set the C flag for the susequent branches! + +__sge_w.wm .macro + cmp.l \1 ; Subtract memory from Y:A. + tya + sbc.h \1 + bvc !+ + eor #$80 ; +ve if Y:A >= memory (signed). +!: eor #$80 + asl a + .endm + +; ************** +; optimized boolean test (unsigned word) +; C is true (1) if Y:A < memory-value, else false (0) +; this MUST set the C flag for the susequent branches! + +__ult_w.wm .macro + cmp.l \1 ; Subtract memory from Y:A. + tya + sbc.h \1 ; CC if Y:A < memory. + ror a + eor #$80 + rol a + .endm + +; ************** +; optimized boolean test (unsigned word) +; C is true (1) if Y:A <= memory-value, else false (0) +; this MUST set the C flag for the susequent branches! + +__ule_w.wm .macro + clc ; Subtract memory+1 from Y:A. + sbc.l \1 + tya + sbc.h \1 ; CC if Y:A <= memory. + ror a + eor #$80 + rol a + .endm + +; ************** +; optimized boolean test (unsigned word) +; C is true (1) if Y:A > memory-value, else false (0) +; this MUST set the C flag for the susequent branches! + +__ugt_w.wm .macro + clc ; Subtract memory+1 from Y:A. + sbc.l \1 + tya + sbc.h \1 ; CS if Y:A > memory. + .endm + +; ************** +; optimized boolean test (unsigned word) +; C is true (1) if Y:A >= memory-value, else false (0) +; this MUST set the C flag for the susequent branches! + +__uge_w.wm .macro + cmp.l \1 ; Subtract memory from Y:A. + tya + sbc.h \1 ; CS if Y:A >= memory. + .endm + +; ************** +; optimized boolean test +; C is true (1) if A == memory-value, else false (0) +; this MUST set the C flag for the subsequent branches! + +__equ_b.umq .macro + cmp \1 + beq !+ + clc +!: + .endm + +; ************** +; optimized boolean test +; C is true (1) if A != memory-value, else false (0) +; this MUST set the C flag for the subsequent branches! + +__neq_b.umq .macro + sec + eor \1 + bne !+ + clc +!: + .endm + +; ************** +; optimized boolean test (signed byte) +; C is true (1) if A < memory-value, else false (0) +; this MUST set the C flag for the susequent branches! + +__slt_b.bmq .macro + sec ; Subtract memory from A. + sbc \1 + bvc !+ + eor #$80 ; -ve if A < memory (signed). +!: asl a + .endm + +; ************** +; optimized boolean test (signed byte) +; C is true (1) if A <= memory-value, else false (0) +; this MUST set the C flag for the susequent branches! + +__sle_b.bmq .macro + clc ; Subtract memory+1 from A. + sbc \1 + bvc !+ + eor #$80 ; -ve if A <= memory (signed). +!: asl a + .endm + +; ************** +; optimized boolean test (signed byte) +; C is true (1) if A > memory-value, else false (0) +; this MUST set the C flag for the susequent branches! + +__sgt_b.bmq .macro + clc ; Subtract memory+1 from A. + sbc.l \1 + bvc !+ + eor #$80 ; +ve if A > memory (signed). +!: eor #$80 + asl a + .endm + +; ************** +; optimized boolean test (signed byte) +; C is true (1) if A >= memory-value, else false (0) +; this MUST set the C flag for the susequent branches! + +__sge_b.bmq .macro + sec ; Subtract memory from A. + sbc \1 + bvc !+ + eor #$80 ; +ve if A >= memory (signed). +!: eor #$80 + asl a + .endm + +; ************** +; optimized boolean test (unsigned byte) +; C is true (1) if A < memory-value, else false (0) +; this MUST set the C flag for the susequent branches! + +__ult_b.umq .macro + cmp \1 ; Subtract memory from A. + ror a ; CC if A < memory. + eor #$80 + rol a + .endm + +; ************** +; optimized boolean test (unsigned byte) +; C is true (1) if A <= memory-value, else false (0) +; this MUST set the C flag for the susequent branches! + +__ule_b.umq .macro + clc ; Subtract memory+1 from A. + sbc \1 + ror a ; CC if A <= memory. + eor #$80 + rol a + .endm + +; ************** +; optimized boolean test (unsigned byte) +; C is true (1) if A > memory-value, else false (0) +; this MUST set the C flag for the susequent branches! + +__ugt_b.umq .macro + clc ; Subtract memory+1 from A. + sbc \1 ; CS if A > memory. + .endm + +; ************** +; optimized boolean test (unsigned byte) +; C is true (1) if A >= memory-value, else false (0) +; this MUST set the C flag for the susequent branches! + +__uge_b.umq .macro + cmp \1 ; Subtract memory from A. + ; CS if A >= memory. + .endm + +; ************** +; optimized boolean test +; C is true (1) if Y:A == memory-value, else false (0) +; this MUST set the C flag for the subsequent branches! + +__equ_w.ws .macro + cmp.l <__stack + \1, x + bne !false+ + tya + cmp.h <__stack + \1, x + beq !+ +!false: clc +!: + .endm + +; ************** +; optimized boolean test +; C is true (1) if Y:A != memory-value, else false (0) +; this MUST set the C flag for the subsequent branches! + +__neq_w.ws .macro + sec + eor.l <__stack + \1, x + bne !+ + tya + eor.h <__stack + \1, x + bne !+ + clc +!: + .endm + +; ************** +; optimized boolean test (signed word) +; C is true (1) if Y:A < memory-value, else false (0) +; this MUST set the C flag for the susequent branches! + +__slt_w.ws .macro + cmp.l <__stack + \1, x; Subtract memory from Y:A. + tya + sbc.h <__stack + \1, x + bvc !+ + eor #$80 ; -ve if Y:A < memory (signed). +!: asl a + .endm + +; ************** +; optimized boolean test (signed word) +; C is true (1) if Y:A <= memory-value, else false (0) +; this MUST set the C flag for the susequent branches! + +__sle_w.ws .macro + clc ; Subtract memory+1 from Y:A. + sbc.l <__stack + \1, x + tya + sbc.h <__stack + \1, x + bvc !+ + eor #$80 ; -ve if Y:A <= memory (signed). +!: asl a + .endm + +; ************** +; optimized boolean test (signed word) +; C is true (1) if Y:A > memory-value, else false (0) +; this MUST set the C flag for the susequent branches! + +__sgt_w.ws .macro + clc ; Subtract memory+1 from Y:A. + sbc.l <__stack + \1, x + tya + sbc.h <__stack + \1, x + bvc !+ + eor #$80 ; +ve if Y:A > memory (signed). +!: eor #$80 + asl a + .endm + +; ************** +; optimized boolean test (signed word) +; C is true (1) if Y:A >= memory-value, else false (0) +; this MUST set the C flag for the susequent branches! + +__sge_w.ws .macro + cmp.l <__stack + \1, x; Subtract memory from Y:A. + tya + sbc.h <__stack + \1, x + bvc !+ + eor #$80 ; +ve if Y:A >= memory (signed). +!: eor #$80 + asl a + .endm + +; ************** +; optimized boolean test (unsigned word) +; C is true (1) if Y:A < memory-value, else false (0) +; this MUST set the C flag for the susequent branches! + +__ult_w.ws .macro + cmp.l <__stack + \1, x; Subtract memory from Y:A. + tya + sbc.h <__stack + \1, x; CC if Y:A < memory. + ror a + eor #$80 + rol a + .endm + +; ************** +; optimized boolean test (unsigned word) +; C is true (1) if Y:A <= memory-value, else false (0) +; this MUST set the C flag for the susequent branches! + +__ule_w.ws .macro + clc ; Subtract memory+1 from Y:A. + sbc.l <__stack + \1, x + tya + sbc.h <__stack + \1, x; CC if Y:A <= memory. + ror a + eor #$80 + rol a + .endm + +; ************** +; optimized boolean test (unsigned word) +; C is true (1) if Y:A > memory-value, else false (0) +; this MUST set the C flag for the susequent branches! + +__ugt_w.ws .macro + clc ; Subtract memory+1 from Y:A. + sbc.l <__stack + \1, x + tya + sbc.h <__stack + \1, x; CS if Y:A > memory. + .endm + +; ************** +; optimized boolean test (unsigned word) +; C is true (1) if Y:A >= memory-value, else false (0) +; this MUST set the C flag for the susequent branches! + +__uge_w.ws .macro + cmp.l <__stack + \1, x; Subtract memory from Y:A. + tya + sbc.h <__stack + \1, x; CS if Y:A >= memory. + .endm + +; ************** +; optimized boolean test +; C is true (1) if A == memory-value, else false (0) +; this MUST set the C flag for the subsequent branches! + +__equ_b.usq .macro + cmp <__stack + \1, x + beq !+ + clc +!: + .endm + +; ************** +; optimized boolean test +; C is true (1) if A != memory-value, else false (0) +; this MUST set the C flag for the subsequent branches! + +__neq_b.usq .macro + sec + eor <__stack + \1, x + bne !+ + clc +!: + .endm + +; ************** +; optimized boolean test (signed byte) +; C is true (1) if A < memory-value, else false (0) +; this MUST set the C flag for the susequent branches! + +__slt_b.bsq .macro + sec ; Subtract memory from A. + sbc <__stack + \1, x + bvc !+ + eor #$80 ; -ve if A < memory (signed). +!: asl a + .endm + +; ************** +; optimized boolean test (signed byte) +; C is true (1) if A <= memory-value, else false (0) +; this MUST set the C flag for the susequent branches! + +__sle_b.bsq .macro + clc ; Subtract memory+1 from A. + sbc <__stack + \1, x + bvc !+ + eor #$80 ; -ve if A <= memory (signed). +!: asl a + .endm + +; ************** +; optimized boolean test (signed byte) +; C is true (1) if A > memory-value, else false (0) +; this MUST set the C flag for the susequent branches! + +__sgt_b.bsq .macro + clc ; Subtract memory+1 from A. + sbc.l <__stack + \1, x + bvc !+ + eor #$80 ; +ve if A > memory (signed). +!: eor #$80 + asl a .endm ; ************** -; optimized boolean test -; this MUST set the Z flag for the susequent branches! +; optimized boolean test (signed byte) +; C is true (1) if A >= memory-value, else false (0) +; this MUST set the C flag for the susequent branches! -__equ.ui .macro - eor.l #\1 - beq !true+ -!false: lda #-1 -!true: inc a - cly +__sge_b.bsq .macro + sec ; Subtract memory from A. + sbc <__stack + \1, x + bvc !+ + eor #$80 ; +ve if A >= memory (signed). +!: eor #$80 + asl a .endm ; ************** -; optimized boolean test -; this MUST set the Z flag for the susequent branches! +; optimized boolean test (unsigned byte) +; C is true (1) if A < memory-value, else false (0) +; this MUST set the C flag for the susequent branches! -__neq.ui .macro - eor.l #\1 - beq !false+ - lda #1 -!false: cly +__ult_b.usq .macro + cmp <__stack + \1, x; Subtract memory from A. + ror a ; CC if A < memory. + eor #$80 + rol a .endm ; ************** -; boolean test, optimized into __not.wr if used before a __tst.wr -; this MUST set the Z flag for the susequent branches! +; optimized boolean test (unsigned byte) +; C is true (1) if A <= memory-value, else false (0) +; this MUST set the C flag for the susequent branches! -__not.wr .macro - sty __temp - ora __temp - beq !+ - lda #1 -!: eor #1 - cly +__ule_b.usq .macro + clc ; Subtract memory+1 from A. + sbc <__stack + \1, x + ror a ; CC if A <= memory. + eor #$80 + rol a .endm ; ************** -; boolean test, always output immediately before a __bfalse or __btrue -; this MUST set the Z flag for the susequent branches! +; optimized boolean test (unsigned byte) +; C is true (1) if A > memory-value, else false (0) +; this MUST set the C flag for the susequent branches! -__tst.wr .macro - sty __temp - ora __temp - beq !+ - lda #1 -!: cly +__ugt_b.usq .macro + clc ; Subtract memory+1 from A. + sbc <__stack + \1, x; CS if A > memory. .endm ; ************** -; always preceeded by a __tst.wr before peephole optimization +; optimized boolean test (unsigned byte) +; C is true (1) if A >= memory-value, else false (0) +; this MUST set the C flag for the susequent branches! -__bfalse .macro - beq \1 +__uge_b.usq .macro + cmp <__stack + \1, x; Subtract memory from A. + ; CS if A >= memory. .endm ; ************** -; always preceeded by a __tst.wr before peephole optimization +; boolean test, optimized into __not.wr if used before a __tst.wr +; C is true (1) if Y:A == 0, else false (0) +; this MUST set the C flag for the subsequent branches! -__btrue .macro - bne \1 +__not.wr .macro + sty __temp + ora __temp + sec + beq !+ + clc +!: .endm ; ************** ; optimized boolean test -; this MUST set the Z flag for the susequent branches! +; C is true (1) if memory-value == 0, else false (0) +; this MUST set the C flag for the subsequent branches! __not.wp .macro ldy #1 lda [\1], y ora [\1] + sec beq !+ - lda #-1 -!: inc a - cly + clc +!: .endm ; ************** ; optimized boolean test -; this MUST set the Z flag for the susequent branches! +; C is true (1) if memory-value == 0, else false (0) +; this MUST set the C flag for the subsequent branches! __not.wm .macro lda.l \1 ora.h \1 + sec beq !+ - lda #-1 -!: inc a - cly + clc +!: .endm ; ************** ; optimized boolean test -; this MUST set the Z flag for the susequent branches! +; C is true (1) if memory-value == 0, else false (0) +; this MUST set the C flag for the subsequent branches! __not.ws .macro ; __STACK lda.l <__stack + \1, x ora.h <__stack + \1, x + sec beq !+ - lda #-1 -!: inc a - cly + clc +!: .endm ; ************** ; optimized boolean test -; this MUST set the Z flag for the susequent branches! +; C is true (1) if memory-value == 0, else false (0) +; this MUST set the C flag for the subsequent branches! __not.war .macro asl a tay lda.l \1, y ora.h \1, y + sec beq !+ - lda #-1 -!: inc a - cly + clc +!: .endm ; ************** ; optimized boolean test -; this MUST set the Z flag for the susequent branches! +; C is true (1) if memory-value == 0, else false (0) +; this MUST set the C flag for the subsequent branches! __not.up .macro lda [\1] + sec beq !+ - lda #-1 -!: inc a - cly + clc +!: .endm ; ************** ; optimized boolean test -; this MUST set the Z flag for the susequent branches! +; C is true (1) if memory-value == 0, else false (0) +; this MUST set the C flag for the subsequent branches! __not.um .macro lda \1 + sec beq !+ - lda #-1 -!: inc a - cly + clc +!: .endm ; ************** ; optimized boolean test -; this MUST set the Z flag for the susequent branches! +; C is true (1) if memory-value == 0, else false (0) +; this MUST set the C flag for the subsequent branches! __not.us .macro ; __STACK lda.l <__stack + \1, x + sec beq !+ - lda #-1 -!: inc a - cly + clc +!: .endm ; ************** ; optimized boolean test -; this MUST set the Z flag for the susequent branches! +; C is true (1) if memory-value == 0, else false (0) +; this MUST set the C flag for the subsequent branches! __not.uar .macro tay lda \1, y + sec beq !+ - lda #-1 -!: inc a - cly + clc +!: .endm ; ************** ; optimized boolean test -; this MUST set the Z flag for the susequent branches! +; C is true (1) if memory-value == 0, else false (0) +; this MUST set the C flag for the subsequent branches! __not.uay .macro lda \1, y + sec beq !+ - lda #-1 -!: inc a - cly + clc +!: + .endm + +; ************** +; boolean test, always output immediately before a __bfalse or __btrue +; C is true (1) if Y:A != 0, else false (0) +; this MUST set the C flag for the subsequent branches! + +__tst.wr .macro + sty __temp + ora __temp + sec + bne !+ + clc +!: .endm ; ************** ; optimized boolean test -; this MUST set the Z flag for the susequent branches! +; C is true (1) if memory-value != 0, else false (0) +; this MUST set the C flag for the subsequent branches! __tst.wp .macro ldy #1 lda [\1], y ora [\1] - beq !+ - lda #1 -!: cly + sec + bne !+ + clc +!: .endm ; ************** ; optimized boolean test -; this MUST set the Z flag for the susequent branches! +; C is true (1) if memory-value != 0, else false (0) +; this MUST set the C flag for the subsequent branches! __tst.wm .macro lda.l \1 ora.h \1 - beq !+ - lda #1 -!: cly + sec + bne !+ + clc +!: .endm ; ************** ; optimized boolean test -; this MUST set the Z flag for the susequent branches! +; C is true (1) if memory-value != 0, else false (0) +; this MUST set the C flag for the subsequent branches! __tst.ws .macro ; __STACK lda.l <__stack + \1, x ora.h <__stack + \1, x - beq !+ - lda #1 -!: cly + sec + bne !+ + clc +!: .endm ; ************** ; optimized boolean test -; this MUST set the Z flag for the susequent branches! +; C is true (1) if memory-value != 0, else false (0) +; this MUST set the C flag for the subsequent branches! __tst.war .macro asl a tay lda.l \1, y ora.h \1, y - beq !+ - lda #1 -!: cly + sec + bne !+ + clc +!: .endm ; ************** ; optimized boolean test -; this MUST set the Z flag for the susequent branches! +; C is true (1) if memory-value != 0, else false (0) +; this MUST set the C flag for the subsequent branches! __tst.up .macro lda [\1] - beq !+ - lda #1 -!: cly + sec + bne !+ + clc +!: .endm ; ************** ; optimized boolean test -; this MUST set the Z flag for the susequent branches! +; C is true (1) if memory-value != 0, else false (0) +; this MUST set the C flag for the subsequent branches! __tst.um .macro lda \1 - beq !+ - lda #1 -!: cly + sec + bne !+ + clc +!: .endm ; ************** ; optimized boolean test -; this MUST set the Z flag for the susequent branches! +; C is true (1) if memory-value != 0, else false (0) +; this MUST set the C flag for the subsequent branches! __tst.us .macro ; __STACK lda.l <__stack + \1, x - beq !+ - lda #1 -!: cly + sec + bne !+ + clc +!: .endm ; ************** ; optimized boolean test -; this MUST set the Z flag for the susequent branches! +; C is true (1) if memory-value != 0, else false (0) +; this MUST set the C flag for the subsequent branches! __tst.uar .macro tay lda \1, y - beq !+ - lda #1 -!: cly + sec + bne !+ + clc +!: .endm ; ************** ; optimized boolean test -; this MUST set the Z flag for the susequent branches! +; C is true (1) if memory-value != 0, else false (0) +; this MUST set the C flag for the subsequent branches! __tst.uay .macro lda \1, y - beq !+ - lda #1 -!: cly + sec + bne !+ + clc +!: .endm ; ************** ; optimized boolean test -; this MUST set the Z flag for the susequent branches! +; C is true (1) if (Y:A & integer) == 0, else false (0) +; this MUST set the C flag for the subsequent branches! __nand.wi .macro + clc .if ((\1 & $FF00) == 0) and #\1 .else @@ -874,24 +1647,23 @@ __nand.wi .macro and.h #\1 .else and.l #\1 - bne !false+ + bne !+ tya and.h #\1 .endif .endif - .if (\1 != 1) - beq !+ -!false: lda #1 - .endif -!: eor #1 - cly + bne !+ + sec +!: .endm ; ************** ; optimized boolean test -; this MUST set the Z flag for the susequent branches! +; C is true (1) if (Y:A & integer) != 0, else false (0) +; this MUST set the C flag for the subsequent branches! __tand.wi .macro + sec .if ((\1 & $FF00) == 0) and #\1 .else @@ -900,16 +1672,24 @@ __tand.wi .macro and.h #\1 .else and.l #\1 - bne !true+ + bne !+ tya and.h #\1 .endif .endif - .if (\1 != 1) - beq !+ -!true: lda #1 - .endif -!: cly + bne !+ + clc +!: + .endm + +; ************** +; convert boolean test result C flag into a 16-bit Y:A integer + +__bool .macro + cla + rol a + cly + cmp #1 ; Only needed for unoptimized code. .endm @@ -2278,7 +3058,7 @@ __sub.wt .macro ; __STACK ; ************** __sub.wi .macro - .if ((\?1 == ARG_ABS) && (\1 >= 0) && (\1 < 256)) + .if ((\?1 == ARG_ABS) && ((\1) >= 0) && ((\1) < 256)) sec sbc.l #\1 bcs !+ @@ -2936,55 +3716,57 @@ __ldd_s_b .macro ; __STACK ; *************************************************************************** ; ************** -; Y:A is true if stacked-value == Y:A, else false +; C is true (1) if stacked-value == Y:A, else false (0) -eq_w: cmp.l <__stack, x +equ_w: cmp.l <__stack, x bne return_false - say + tya cmp.h <__stack, x - say bne return_false - bra return_true +; bra return_true + +; ************** +; boolean result, this MUST set the C flag for the subsequent branches! + +return_true: inx + inx + sec + rts ; ************** -; Y:A is true if stacked-value != Y:A, else false +; C is true (1) if stacked-value != Y:A, else false (0) -ne_w: cmp.l <__stack, x +neq_w: cmp.l <__stack, x bne return_true - say + tya cmp.h <__stack, x - say bne return_true - bra return_false +; bra return_false ; ************** -; Y:A is true if stacked-value < Y:A, else false +; boolean result, this MUST set the C flagy for the subsequent branches! -lt_sw: clc ; Subtract memory+1 from Y:A. - sbc.l <__stack, x - tya - sbc.h <__stack, x - bvc !+ - eor #$80 -!: bpl return_true ; +ve if Y:A > memory (signed). - bra return_false ; -ve if Y:A <= memory (signed). +return_false: inx + inx + clc + rts ; ************** -; Y:A is true if stacked-value >= Y:A, else false +; C is true (1) if stacked-value < Y:A, else false (0) -ge_sw: clc ; Subtract memory+1 from Y:A. +slt_w: clc ; Subtract memory+1 from Y:A. sbc.l <__stack, x tya sbc.h <__stack, x bvc !+ eor #$80 -!: bmi return_true ; -ve if Y:A <= memory (signed). - bra return_false ; +ve if Y:A > memory (signed). +!: bpl return_true ; +ve if Y:A > memory (signed). + bra return_false ; -ve if Y:A <= memory (signed). ; ************** -; Y:A is true if stacked-value <= Y:A, else false +; C is true (1) if stacked-value <= Y:A, else false (0) -le_sw: cmp.l <__stack, x ; Subtract memory from Y:A. +sle_w: cmp.l <__stack, x ; Subtract memory from Y:A. tya sbc.h <__stack, x bvc !+ @@ -2993,9 +3775,9 @@ le_sw: cmp.l <__stack, x ; Subtract memory from Y:A. bra return_false ; -ve if Y:A < memory (signed). ; ************** -; Y:A is true if stacked-value > Y:A, else false +; C is true (1) if stacked-value > Y:A, else false (0) -gt_sw: cmp.l <__stack, x ; Subtract memory from Y:A. +sgt_w: cmp.l <__stack, x ; Subtract memory from Y:A. tya sbc.h <__stack, x bvc !+ @@ -3004,151 +3786,53 @@ gt_sw: cmp.l <__stack, x ; Subtract memory from Y:A. bra return_false ; +ve if Y:A >= memory (signed). ; ************** -; Y:A is true if stacked-value < Y:A, else false +; C is true (1) if stacked-value >= Y:A, else false (0) -lt_uw: clc ; Subtract memory+1 from Y:A. +sge_w: clc ; Subtract memory+1 from Y:A. sbc.l <__stack, x tya sbc.h <__stack, x - bcs return_true ; CS if Y:A > memory. - bra return_false + bvc !+ + eor #$80 +!: bmi return_true ; -ve if Y:A <= memory (signed). + bra return_false ; +ve if Y:A > memory (signed). ; ************** -; Y:A is true if stacked-value >= Y:A, else false +; C is true (1) if stacked-value < Y:A, else false (0) -ge_uw: clc ; Subtract memory+1 from Y:A. +ult_w: clc ; Subtract memory+1 from Y:A. sbc.l <__stack, x tya sbc.h <__stack, x - bcc return_true ; CC if Y:A <= memory. + bcs return_true ; CS if Y:A > memory. bra return_false ; ************** -; Y:A is true if stacked-value <= Y:A, else false +; C is true (1) if stacked-value <= Y:A, else false (0) -le_uw: cmp.l <__stack, x ; Subtract memory from Y:A. +ule_w: cmp.l <__stack, x ; Subtract memory from Y:A. tya sbc.h <__stack, x bcs return_true ; CS if Y:A >= memory. bra return_false ; ************** -; Y:A is true if stacked-value > Y:A, else false +; C is true (1) if stacked-value > Y:A, else false (0) -gt_uw: cmp.l <__stack, x ; Subtract memory from Y:A. +ugt_w: cmp.l <__stack, x ; Subtract memory from Y:A. tya sbc.h <__stack, x bcc return_true ; CC if Y:A < memory. bra return_false ; ************** -; boolean result, this MUST set the Z flag for the susequent branches! - -return_true: inx - inx ; don't push Y:A, they are thrown away - cly - lda #1 ; Also set valid Z flag. - rts - -; ************** -; boolean result, this MUST set the Z flag for the susequent branches! - -return_false: inx - inx ; don't push Y:A, they are thrown away - cly - lda #0 ; Also set valid Z flag. - rts - - - -; *************************************************************************** -; *************************************************************************** -; subroutines for comparison tests with signed and unsigned bytes -; *************************************************************************** -; *************************************************************************** - -; ************** -; Y:A is true if stacked-value == Y:A, else false - -eq_b: cmp <__stack, x - bne return_false - bra return_true - -; ************** -; Y:A is true if stacked-value != Y:A, else false - -ne_b: cmp <__stack, x - bne return_true - bra return_false - -; ************** -; Y:A is true if stacked-value < Y:A, else false - -lt_sb: clc ; Subtract memory+1 from A. - sbc.l <__stack, x - bvc !+ - eor #$80 -!: bpl return_true ; +ve if A > memory (signed). - bra return_false ; -ve if A <= memory (signed). - -; ************** -; Y:A is true if stacked-value >= Y:A, else false - -ge_sb: clc ; Subtract memory+1 from A. - sbc.l <__stack, x - bvc !+ - eor #$80 -!: bmi return_true ; -ve if A <= memory (signed). - bra return_false ; +ve if A > memory (signed). - -; ************** -; Y:A is true if stacked-value <= Y:A, else false - -le_sb: sec ; Subtract memory from A. - sbc.l <__stack, x ; Cannot use a "cmp" as it - bvc !+ ; does not set the V flag! - eor #$80 -!: bpl return_true ; +ve if A >= memory (signed). - bra return_false ; -ve if A < memory (signed). - -; ************** -; Y:A is true if stacked-value > Y:A, else false - -gt_sb: sec ; Subtract memory from A. - sbc.l <__stack, x ; Cannot use a "cmp" as it - bvc !+ ; does not set the V flag! - eor #$80 -!: bmi return_true ; -ve if A < memory (signed). - bra return_false ; +ve if A >= memory (signed). - -; ************** -; Y:A is true if stacked-value < Y:A, else false - -lt_ub: clc ; Subtract memory+1 from A. - sbc.l <__stack, x - bcs return_true ; CS if A > memory. - bra return_false - -; ************** -; Y:A is true if stacked-value >= Y:A, else false +; C is true (1) if stacked-value >= Y:A, else false (0) -ge_ub: clc ; Subtract memory+1 from A. +uge_w: clc ; Subtract memory+1 from Y:A. sbc.l <__stack, x - bcc return_true ; CC if A <= memory. - bra return_false - -; ************** -; Y:A is true if stacked-value <= Y:A, else false - -le_ub: cmp.l <__stack, x ; Subtract memory from A. - bcs return_true ; CS if Y:A >= memory. - bra return_false - -; ************** -; Y:A is true if stacked-value > Y:A, else false - -gt_ub: cmp.l <__stack, x ; Subtract memory from A. - bcc return_true ; CC if A < memory. + tya + sbc.h <__stack, x + bcc return_true ; CC if Y:A <= memory. bra return_false diff --git a/include/hucc/hucc-config.inc b/include/hucc/hucc-config.inc index dab1f2b..1416637 100644 --- a/include/hucc/hucc-config.inc +++ b/include/hucc/hucc-config.inc @@ -100,9 +100,9 @@ SUPPORT_TED2 = 0 ; (0 or 1) .endif ; -; Support development for the SuperGrafx? +; Support development for the SuperGRAFX? ; -; This enables SuperGrafx support in certain library functions. +; This enables SuperGRAFX support in certain library functions. ; .ifndef SUPPORT_SGX @@ -113,6 +113,32 @@ SUPPORT_SGX = 0 ; (0 or 1) .endif .endif +; +; Choose SuperGRAFX VPC initialization mode. +; +; SGX_PARALLAX=0 (useful when VDC #1 is a fullscreen HUD) +; +; FRONT +; SP1 = VDC #1 (pce) sprite pixels +; BG1 = VDC #1 (pce) background pixels +; SP2 = VDC #2 (sgx) sprite pixels +; BG2 = VDC #2 (sgx) background pixels +; BACK +; +; SGX_PARALLAX=1 +; +; FRONT +; SP1 = VDC #1 (pce) sprite pixels +; SP2 = VDC #2 (sgx) sprite pixels +; BG1 = VDC #1 (pce) background pixels +; BG2 = VDC #2 (sgx) background pixels +; BACK +; + + .ifndef SGX_PARALLAX +SGX_PARALLAX = 1 ; The most common default. + .endif + ; ; Support development for the ArcadeCard? ; diff --git a/include/hucc/vdc.asm b/include/hucc/vdc.asm index 798d3af..24fbc1b 100644 --- a/include/hucc/vdc.asm +++ b/include/hucc/vdc.asm @@ -337,6 +337,11 @@ set_mode_vdc .proc ; ; HuC6202 VIDEO PRIORITY CONTROLLER (huge thanks to Charles MacDonald!) ; +; The VPC has no access to sprite priority data, it can only sort pixels +; based upon which VDC and whether they are "sprite" or "background". +; +; This can sometimes lead to unexpected results with low-priority sprites. +; ; VPC registers $0008 and $0009 make up four 4-bit values that define the ; enabled layers and priority setting for the four possible window areas. ; @@ -355,34 +360,28 @@ set_mode_vdc .proc ; Priority Setting 0b00xx: (useful when VDC #1 is a fullscreen HUD) ; ; FRONT -; SP1'= VDC #1 high priority sprites -; BG1 = VDC #1 background -; SP1 = VDC #1 low priority sprites -; SP2'= VDC #2 high priority sprites -; BG2 = VDC #2 background -; SP2 = VDC #2 low priority sprites +; SP1 = VDC #1 (pce) sprite pixels +; BG1 = VDC #1 (pce) background pixels +; SP2 = VDC #2 (sgx) sprite pixels +; BG2 = VDC #2 (sgx) background pixels ; BACK ; ; Priority Setting 0b01xx: (useful for parallax backgrounds) ; ; FRONT -; SP1'= VDC #1 high priority sprites -; SP2'= VDC #2 high priority sprites -; BG1 = VDC #1 background -; SP1 = VDC #1 low priority sprites -; BG2 = VDC #2 background -; SP2 = VDC #2 low priority sprites +; SP1 = VDC #1 (pce) sprite pixels +; SP2 = VDC #2 (sgx) sprite pixels +; BG1 = VDC #1 (pce) background pixels +; BG2 = VDC #2 (sgx) background pixels ; BACK ; ; Priority Setting 0b10xx: (only useful for special effects) ; ; FRONT -; BG1 = VDC #1 background (with holes for sprites) -; SP2'= VDC #2 high priority sprites -; BG2 = VDC #2 background -; SP2 = VDC #2 low priority sprites -; SP1'= VDC #1 high priority sprites -; SP1 = VDC #1 low priority sprites +; BG1 = VDC #1 (pce) background pixels (transparent where sprites) +; BG2 = VDC #2 (sgx) background pixels +; SP1 = VDC #1 (pce) sprite pixels +; SP2 = VDC #2 (sgx) sprite pixels ; BACK .if SUPPORT_SGX diff --git a/src/hucc/code.c b/src/hucc/code.c index cafd5ee..3415ae0 100644 --- a/src/hucc/code.c +++ b/src/hucc/code.c @@ -24,6 +24,20 @@ int segment; /* externs */ extern int arg_stack_flag; +/* convert comparison operation to a string */ +const char * compare2str [] = { + "equ", // CMP_EQU + "neq", // CMP_NEQ + "slt", // CMP_SLT + "sle", // CMP_SLE + "sgt", // CMP_SGT + "sge", // CMP_SGE + "ult", // CMP_ULT + "ule", // CMP_ULE + "ugt", // CMP_UGT + "uge" // CMP_UGE +}; + /* * print all assembler info before any code is generated * @@ -157,6 +171,17 @@ void out_ins_sym (int code, int type, intptr_t data, SYMBOL *sym) gen_ins(&tmp); } +void out_ins_cmp (int code, int type) +{ + INS tmp; + + memset(&tmp, 0, sizeof(INS)); + + tmp.ins_code = code; + tmp.cmp_type = type; + gen_ins(&tmp); +} + void gen_ins (INS *tmp) { if (optimize) @@ -498,6 +523,20 @@ void gen_code (INS *tmp) nl(); break; + case I_BFALSE: + ot("__bfalse\t"); + outlabel((int)data); + nl(); + nl(); + break; + + case I_BTRUE: + ot("__btrue\t\t"); + outlabel((int)data); + nl(); + nl(); + break; + case I_DEF: outstr((const char *)data); outstr(" .equ "); @@ -507,64 +546,63 @@ void gen_code (INS *tmp) case I_CMP_WT: ot("__cmp.wt\t"); - - switch (type) { - case T_SYMBOL: - outsymbol((SYMBOL *)data); - break; - case T_LIB: - outstr((const char *)data); - break; - } + outstr(compare2str[tmp->cmp_type]); + outstr("_w"); nl(); break; - case I_CMP_UT: - ot("__cmp.ut\t"); - - switch (type) { - case T_SYMBOL: - outsymbol((SYMBOL *)data); - break; - case T_LIB: - outstr((const char *)data); - break; - } + case X_CMP_WI: + ot("__"); + outstr(compare2str[tmp->cmp_type]); + outstr("_w.wi\t"); + out_type(type, data); nl(); break; - case X_EQU_WI: - ot("__equ.wi\t"); + case X_CMP_WM: + ot("__"); + outstr(compare2str[tmp->cmp_type]); + outstr("_w.wm\t"); out_type(type, data); nl(); break; - case X_NEQ_WI: - ot("__neq.wi\t"); - out_type(type, data); + case X_CMP_WS: + ot("__"); + outstr(compare2str[tmp->cmp_type]); + outstr("_w.ws\t"); + outdec((int)data); + outlocal(tmp->sym); nl(); break; - case I_TST_WR: - ol("__tst.wr"); + case X_CMP_UIQ: + ot("__"); + outstr(compare2str[tmp->cmp_type]); + outstr("_b.uiq\t"); + out_type(type, data); + nl(); break; - case I_NOT_WR: - ol("__not.wr"); + case X_CMP_UMQ: + ot("__"); + outstr(compare2str[tmp->cmp_type]); + outstr("_b.umq\t"); + out_type(type, data); + nl(); break; - case I_BFALSE: - ot("__bfalse\t"); - outlabel((int)data); - nl(); + case X_CMP_USQ: + ot("__"); + outstr(compare2str[tmp->cmp_type]); + outstr("_b.usq\t"); + outdec((int)data); + outlocal(tmp->sym); nl(); break; - case I_BTRUE: - ot("__btrue\t\t"); - outlabel((int)data); - nl(); - nl(); + case I_NOT_WR: + ol("__not.wr"); break; case X_NOT_WP: @@ -606,6 +644,7 @@ void gen_code (INS *tmp) case X_NOT_US: ot("__not.us\t"); outdec((int)data); + outlocal(tmp->sym); nl(); break; @@ -621,6 +660,10 @@ void gen_code (INS *tmp) nl(); break; + case I_TST_WR: + ol("__tst.wr"); + break; + case X_TST_WP: ot("__tst.wp\t"); out_addr(type, data); @@ -636,6 +679,7 @@ void gen_code (INS *tmp) case X_TST_WS: ot("__tst.ws\t"); outdec((int)data); + outlocal(tmp->sym); nl(); break; @@ -660,6 +704,7 @@ void gen_code (INS *tmp) case X_TST_US: ot("__tst.us\t"); outdec((int)data); + outlocal(tmp->sym); nl(); break; @@ -687,6 +732,10 @@ void gen_code (INS *tmp) nl(); break; + case I_BOOLEAN: + ol("__bool"); + break; + /* i-codes for loading the primary register */ case I_LD_WI: diff --git a/src/hucc/code.h b/src/hucc/code.h index c95fba2..5f62b6b 100644 --- a/src/hucc/code.h +++ b/src/hucc/code.h @@ -21,6 +21,7 @@ void defword (void); void out_ins (int code, int type, intptr_t data); void out_ins_ex (int code, int type, intptr_t data, int imm_type, intptr_t imm_data); void out_ins_sym (int code, int type, intptr_t data, SYMBOL *sym); +void out_ins_cmp (int code, int type); void gen_ins (INS *tmp); void gen_code (INS *tmp); diff --git a/src/hucc/defs.h b/src/hucc/defs.h index 69856df..ef2f186 100644 --- a/src/hucc/defs.h +++ b/src/hucc/defs.h @@ -64,16 +64,20 @@ enum ICODE { I_LABEL, I_ALIAS, I_BRA, - I_DEF, - I_CMP_WT, - I_CMP_UT, - X_EQU_WI, - X_NEQ_WI, - I_NOT_WR, - I_TST_WR, I_BFALSE, I_BTRUE, + I_DEF, + + I_CMP_WT, + X_CMP_WI, + X_CMP_WM, + X_CMP_WS, + + X_CMP_UIQ, + X_CMP_UMQ, + X_CMP_USQ, + I_NOT_WR, X_NOT_WP, X_NOT_WM, X_NOT_WS, @@ -83,6 +87,8 @@ enum ICODE { X_NOT_US, X_NOT_UAR, X_NOT_UAY, + + I_TST_WR, X_TST_WP, X_TST_WM, X_TST_WS, @@ -96,6 +102,8 @@ enum ICODE { X_NAND_WI, X_TAND_WI, + I_BOOLEAN, + /* i-codes for loading the primary register */ I_LD_WI, @@ -323,6 +331,22 @@ enum ICODE { X_LDD_S_B }; +/* + * boolean comparison operations + */ +enum ICOMPARE { + CMP_EQU, + CMP_NEQ, + CMP_SLT, + CMP_SLE, + CMP_SGT, + CMP_SGE, + CMP_ULT, + CMP_ULE, + CMP_UGT, + CMP_UGE +}; + /* * INTSIZE is the size of an integer in the target machine * BYTEOFF is the offset of an byte within an integer on the @@ -343,12 +367,11 @@ enum ICODE { #define T_PTR 4 #define T_STACK 5 #define T_STRING 6 -#define T_LIB 7 -#define T_SIZE 8 -#define T_BANK 9 -#define T_VRAM 10 -#define T_PAL 11 -#define T_LITERAL 12 +#define T_SIZE 7 +#define T_BANK 8 +#define T_VRAM 9 +#define T_PAL 10 +#define T_LITERAL 11 #define FOREVER for (;;) #define FALSE 0 @@ -537,6 +560,7 @@ struct macro { typedef struct { enum ICODE ins_code; + enum ICOMPARE cmp_type; int ins_type; intptr_t ins_data; int imm_type; diff --git a/src/hucc/expr.c b/src/hucc/expr.c index 36b4b38..957a885 100644 --- a/src/hucc/expr.c +++ b/src/hucc/expr.c @@ -86,16 +86,6 @@ static int is_ptrptr (LVALUE *lval) return (s && (s->ptr_order > 1 || (s->identity == ARRAY && s->ptr_order > 0))); } -static int is_byte (LVALUE *lval) -{ -#if 0 // Byte comparisons are broken, disable them for now. - if (lval->symbol && !lval->ptr_type && - (lval->symbol->sym_type == CCHAR || lval->symbol->sym_type == CUCHAR)) - return (1); -#endif - return (0); -} - static void gen_scale_right (LVALUE *lval, LVALUE *lval2) { if (dbltest(lval, lval2)) { @@ -398,13 +388,13 @@ int heir5 (LVALUE *lval, int comma) gpush(); if (heir6(lval2, comma)) rvalue(lval2); - geq(is_byte(lval) && is_byte(lval2)); + geq(); } else if (match("!=")) { gpush(); if (heir6(lval2, comma)) rvalue(lval2); - gne(is_byte(lval) && is_byte(lval2)); + gne(); } else return (0); @@ -443,10 +433,10 @@ int heir6 (LVALUE *lval, int comma) is_unsigned(lval) || is_unsigned(lval2) ) { - gule(is_byte(lval) && is_byte(lval2)); + gule(); continue; } - gle(is_byte(lval) && is_byte(lval2)); + gle(); } else if (match(">=")) { gpush(); @@ -456,10 +446,10 @@ int heir6 (LVALUE *lval, int comma) is_unsigned(lval) || is_unsigned(lval2) ) { - guge(is_byte(lval) && is_byte(lval2)); + guge(); continue; } - gge(is_byte(lval) && is_byte(lval2)); + gge(); } else if ((sstreq("<")) && !sstreq("<<")) { @@ -471,10 +461,10 @@ int heir6 (LVALUE *lval, int comma) is_unsigned(lval) || is_unsigned(lval2) ) { - gult(is_byte(lval) && is_byte(lval2)); + gult(); continue; } - glt(is_byte(lval) && is_byte(lval2)); + glt(); } else if ((sstreq(">")) && !sstreq(">>")) { @@ -486,10 +476,10 @@ int heir6 (LVALUE *lval, int comma) is_unsigned(lval) || is_unsigned(lval2) ) { - gugt(is_byte(lval) && is_byte(lval2)); + gugt(); continue; } - ggt(is_byte(lval) && is_byte(lval2)); + ggt(); } else return (0); diff --git a/src/hucc/gen.c b/src/hucc/gen.c index ebaa83a..184de91 100644 --- a/src/hucc/gen.c +++ b/src/hucc/gen.c @@ -233,6 +233,7 @@ void jump (int label) void testjump (int label, int ft) { out_ins(I_TST_WR, 0, 0); + out_ins(I_BOOLEAN, 0, 0); if (ft) out_ins(I_BTRUE, T_LABEL, label); else @@ -455,15 +456,17 @@ void gcom (void) void gbool (void) { out_ins(I_TST_WR, 0, 0); + out_ins(I_BOOLEAN, 0, 0); } /* - * logical complement of primary register + * boolean logical complement of primary register * */ void glneg (void) { out_ins(I_NOT_WR, 0, 0); + out_ins(I_BOOLEAN, 0, 0); } /* @@ -510,12 +513,11 @@ void gdec (LVALUE *lval) * equal * */ -void geq (int is_byte) + +void geq (void) { - if (is_byte) - out_ins(I_CMP_WT, T_LIB, (intptr_t)"eq_b"); - else - out_ins(I_CMP_WT, T_LIB, (intptr_t)"eq_w"); + out_ins_cmp(I_CMP_WT, CMP_EQU); + out_ins(I_BOOLEAN, 0, 0); stkp = stkp + INTSIZE; } @@ -523,12 +525,10 @@ void geq (int is_byte) * not equal * */ -void gne (int is_byte) +void gne (void) { - if (is_byte) - out_ins(I_CMP_WT, T_LIB, (intptr_t)"ne_b"); - else - out_ins(I_CMP_WT, T_LIB, (intptr_t)"ne_w"); + out_ins_cmp(I_CMP_WT, CMP_NEQ); + out_ins(I_BOOLEAN, 0, 0); stkp = stkp + INTSIZE; } @@ -536,12 +536,10 @@ void gne (int is_byte) * less than (signed) * */ -void glt (int is_byte) +void glt (void) { - if (is_byte) - out_ins(I_CMP_WT, T_LIB, (intptr_t)"lt_sb"); - else - out_ins(I_CMP_WT, T_LIB, (intptr_t)"lt_sw"); + out_ins_cmp(I_CMP_WT, CMP_SLT); + out_ins(I_BOOLEAN, 0, 0); stkp = stkp + INTSIZE; } @@ -549,12 +547,10 @@ void glt (int is_byte) * less than or equal (signed) * */ -void gle (int is_byte) +void gle (void) { - if (is_byte) - out_ins(I_CMP_WT, T_LIB, (intptr_t)"le_sb"); - else - out_ins(I_CMP_WT, T_LIB, (intptr_t)"le_sw"); + out_ins_cmp(I_CMP_WT, CMP_SLE); + out_ins(I_BOOLEAN, 0, 0); stkp = stkp + INTSIZE; } @@ -562,12 +558,10 @@ void gle (int is_byte) * greater than (signed) * */ -void ggt (int is_byte) +void ggt (void) { - if (is_byte) - out_ins(I_CMP_WT, T_LIB, (intptr_t)"gt_sb"); - else - out_ins(I_CMP_WT, T_LIB, (intptr_t)"gt_sw"); + out_ins_cmp(I_CMP_WT, CMP_SGT); + out_ins(I_BOOLEAN, 0, 0); stkp = stkp + INTSIZE; } @@ -575,12 +569,10 @@ void ggt (int is_byte) * greater than or equal (signed) * */ -void gge (int is_byte) +void gge (void) { - if (is_byte) - out_ins(I_CMP_WT, T_LIB, (intptr_t)"ge_sb"); - else - out_ins(I_CMP_WT, T_LIB, (intptr_t)"ge_sw"); + out_ins_cmp(I_CMP_WT, CMP_SGE); + out_ins(I_BOOLEAN, 0, 0); stkp = stkp + INTSIZE; } @@ -588,12 +580,10 @@ void gge (int is_byte) * less than (unsigned) * */ -void gult (int is_byte) +void gult (void) { - if (is_byte) - out_ins(I_CMP_WT, T_LIB, (intptr_t)"lt_ub"); - else - out_ins(I_CMP_WT, T_LIB, (intptr_t)"lt_uw"); + out_ins_cmp(I_CMP_WT, CMP_ULT); + out_ins(I_BOOLEAN, 0, 0); stkp = stkp + INTSIZE; } @@ -601,12 +591,10 @@ void gult (int is_byte) * less than or equal (unsigned) * */ -void gule (int is_byte) +void gule (void) { - if (is_byte) - out_ins(I_CMP_WT, T_LIB, (intptr_t)"le_ub"); - else - out_ins(I_CMP_WT, T_LIB, (intptr_t)"le_uw"); + out_ins_cmp(I_CMP_WT, CMP_ULE); + out_ins(I_BOOLEAN, 0, 0); stkp = stkp + INTSIZE; } @@ -614,12 +602,10 @@ void gule (int is_byte) * greater than (unsigned) * */ -void gugt (int is_byte) +void gugt (void) { - if (is_byte) - out_ins(I_CMP_WT, T_LIB, (intptr_t)"gt_ub"); - else - out_ins(I_CMP_WT, T_LIB, (intptr_t)"gt_uw"); + out_ins_cmp(I_CMP_WT, CMP_UGT); + out_ins(I_BOOLEAN, 0, 0); stkp = stkp + INTSIZE; } @@ -627,12 +613,10 @@ void gugt (int is_byte) * greater than or equal (unsigned) * */ -void guge (int is_byte) +void guge (void) { - if (is_byte) - out_ins(I_CMP_WT, T_LIB, (intptr_t)"ge_ub"); - else - out_ins(I_CMP_WT, T_LIB, (intptr_t)"ge_uw"); + out_ins_cmp(I_CMP_WT, CMP_UGE); + out_ins(I_BOOLEAN, 0, 0); stkp = stkp + INTSIZE; } diff --git a/src/hucc/gen.h b/src/hucc/gen.h index f487efb..ff2e195 100644 --- a/src/hucc/gen.h +++ b/src/hucc/gen.h @@ -39,16 +39,16 @@ void gbool (void); void glneg (void); void ginc (LVALUE *lval); void gdec (LVALUE *lval); -void geq (int is_byte); -void gne (int is_byte); -void glt (int is_byte); -void gle (int is_byte); -void ggt (int is_byte); -void gge (int is_byte); -void gult (int is_byte); -void gule (int is_byte); -void gugt (int is_byte); -void guge (int is_byte); +void geq (void); +void gne (void); +void glt (void); +void gle (void); +void ggt (void); +void gge (void); +void gult (void); +void gule (void); +void gugt (void); +void guge (void); void gcast (int type); void gsei (void); void gcli (void); diff --git a/src/hucc/io.c b/src/hucc/io.c index c50475e..d9707c0 100644 --- a/src/hucc/io.c +++ b/src/hucc/io.c @@ -466,7 +466,7 @@ void outsymbol (SYMBOL *ptr) outstr(ptr->name); } if (ptr->linked) { - outstr(" /* "); + outstr(" /* "); outstr(ptr->linked->name); outstr(" */"); } @@ -641,7 +641,8 @@ void outstr (const char *ptr) void outlocal (SYMBOL *ptr) { if (ptr) { - outstr(" ; "); + outstr(" /* "); outstr(ptr->name); + outstr(" */"); } } diff --git a/src/hucc/optimize.c b/src/hucc/optimize.c index ddef029..7bf634e 100644 --- a/src/hucc/optimize.c +++ b/src/hucc/optimize.c @@ -99,16 +99,20 @@ unsigned char icode_flags[] = { /* I_LABEL */ 0, /* I_ALIAS */ 0, /* I_BRA */ 0, - /* I_DEF */ 0, - /* I_CMP_WT */ 0, - /* I_CMP_UT */ 0, - /* X_EQU_WI */ 0, - /* X_NEQ_WI */ 0, - /* I_NOT_WR */ 0, - /* I_TST_WR */ 0, /* I_BFALSE */ 0, /* I_BTRUE */ 0, + /* I_DEF */ 0, + + /* I_CMP_WT */ 0, + /* X_CMP_WI */ 0, + /* X_CMP_WM */ 0, + /* X_CMP_WS */ IS_SPREL, + + /* X_CMP_UIQ */ IS_UBYTE, + /* X_CMP_UMQ */ IS_UBYTE, + /* X_CMP_USQ */ IS_SPREL + IS_UBYTE, + /* I_NOT_WR */ 0, /* X_NOT_WP */ 0, /* X_NOT_WM */ 0, /* X_NOT_WS */ IS_SPREL, @@ -118,6 +122,8 @@ unsigned char icode_flags[] = { /* X_NOT_US */ IS_SPREL, /* X_NOT_UAR */ 0, /* X_NOT_UAY */ 0, + + /* I_TST_WR */ 0, /* X_TST_WP */ 0, /* X_TST_WM */ 0, /* X_TST_WS */ IS_SPREL, @@ -131,6 +137,8 @@ unsigned char icode_flags[] = { /* X_NAND_WI */ 0, /* X_TAND_WI */ 0, + /* I_BOOLEAN */ 0, + // i-codes for loading the primary register /* I_LD_WI */ 0, @@ -358,6 +366,35 @@ unsigned char icode_flags[] = { /* X_LDD_S_B */ IS_SPREL }; +/* invert comparison operation */ +int compare2not [] = { + CMP_NEQ, // CMP_EQU + CMP_EQU, // CMP_NEQ + CMP_SGE, // CMP_SLT + CMP_SGT, // CMP_SLE + CMP_SLE, // CMP_SGT + CMP_SLT, // CMP_SGE + CMP_UGE, // CMP_ULT + CMP_UGT, // CMP_ULE + CMP_ULE, // CMP_UGT + CMP_ULT // CMP_UGE +}; + +/* optimize comparison between unsigned chars */ +/* C promotes an unsigned char to a signed int for comparison */ +int compare2uchar [] = { + CMP_EQU, // CMP_EQU + CMP_NEQ, // CMP_NEQ + CMP_ULT, // CMP_SLT + CMP_ULE, // CMP_SLE + CMP_UGT, // CMP_SGT + CMP_UGE, // CMP_SGE + CMP_ULT, // CMP_ULT + CMP_ULE, // CMP_ULE + CMP_UGT, // CMP_UGT + CMP_UGE // CMP_UGE +}; + /* defines */ #define Q_SIZE 16 @@ -1198,6 +1235,321 @@ void push_ins (INS *ins) } } + /* then optimize conditional tests, part 1 */ + if (q_nb >= 5) { + /* + * LLnn: --> LLnn: + * __bool __bfalse + * __tst.wr + * __bool + * __bfalse + * + * LLnn: --> LLnn: + * __bool __btrue + * __tst.wr + * __bool + * __btrue + * + * Remove redundant __tst.wr in compound conditionals + * that the compiler generates. + * + * Done before removing the 2nd __bool in a later rule + * so that the redundancy is easier to understand. + */ + if + ((p[0]->ins_code == I_BFALSE || + p[0]->ins_code == I_BTRUE) && + (p[1]->ins_code == I_BOOLEAN) && + (p[2]->ins_code == I_TST_WR) && + (p[3]->ins_code == I_BOOLEAN) && + (p[4]->ins_code == I_LABEL) + ) { + *p[3] = *p[0]; + nb = 3; + } + + /* + * LLnn: --> LLnn: + * __bool LLqq: + * __tst.wr __bool + * __bool + * LLqq: + * + * Remove redundant __tst.wr in compound conditionals + * that the compiler generates. + * + * Done before reordering the 2nd __bool in a later rule + * so that the redundancy is easier to understand. + */ + else if + ((p[0]->ins_code == I_BFALSE || + p[0]->ins_code == I_BTRUE || + p[0]->ins_code == I_LABEL) && + (p[1]->ins_code == I_BOOLEAN) && + (p[2]->ins_code == I_TST_WR) && + (p[3]->ins_code == I_BOOLEAN) && + (p[4]->ins_code == I_LABEL) + ) { + *p[3] = *p[0]; + *p[2] = *p[1]; + nb = 2; + } + + /* flush queue */ + if (nb) { + q_wr -= nb; + q_nb -= nb; + nb = 0; + + if (q_wr < 0) + q_wr += Q_SIZE; + + /* loop */ + goto lv1_loop; + } + } + + /* then optimize conditional tests, part 2 */ + if (q_nb >= 3) { + /* + * __tst.wr --> __not.wr + * __bool + * __not.wr + */ + if + ((p[0]->ins_code == I_NOT_WR) && + (p[1]->ins_code == I_BOOLEAN) && + (p[2]->ins_code == I_TST_WR) + ) { + p[2]->ins_code = I_NOT_WR; + nb = 2; + } + + /* + * __not.wr --> __tst.wr + * __bool + * __not.wr + */ + else if + ((p[0]->ins_code == I_NOT_WR) && + (p[1]->ins_code == I_BOOLEAN) && + (p[2]->ins_code == I_NOT_WR) + ) { + p[2]->ins_code = I_TST_WR; + nb = 2; + } + + /* + * __cmp.wt --> __cmp.wt + * __bool + * __tst.wr + * + * __cmp.wi --> __cmp.wi + * __bool + * __tst.wr + * + * __cmp.wm --> __cmp.wm + * __bool + * __tst.wr + * + * __cmp.ws --> __cmp.ws + * __bool + * __tst.wr + * + * __cmp.uiq --> __cmp.uiq + * __bool + * __tst.wr + * + * __cmp.umq --> __cmp.umq + * __bool + * __tst.wr + * + * __cmp.usq --> __cmp.usq + * __bool + * __tst.wr + * + * __not.wr --> __not.wr + * __bool + * __tst.wr + * + * __tst.wr --> __tst.wr + * __bool + * __tst.wr + */ + else if + ((p[0]->ins_code == I_TST_WR) && + (p[1]->ins_code == I_BOOLEAN) && + (p[2]->ins_code == I_CMP_WT || + p[2]->ins_code == X_CMP_WI || + p[2]->ins_code == X_CMP_WM || + p[2]->ins_code == X_CMP_WS || + p[2]->ins_code == X_CMP_UIQ || + p[2]->ins_code == X_CMP_UMQ || + p[2]->ins_code == X_CMP_USQ || + p[2]->ins_code == I_NOT_WR || + p[2]->ins_code == I_TST_WR) + ) { + nb = 2; + } + + /* + * __cmp.wi --> __cmp.wi + * __bool + * __not.wr + * + * __cmp.wm --> __cmp.wm + * __bool + * __not.wr + * + * __cmp.ws --> __cmp.ws + * __bool + * __not.wr + * + * __cmp.uiq --> __cmp.uiq + * __bool + * __not.wr + * + * __cmp.umq --> __cmp.umq + * __bool + * __not.wr + * + * __cmp.usq --> __cmp.usq + * __bool + * __not.wr + * + * N.B. This inverts the test condition of the __cmp.wi! + */ + else if + ((p[0]->ins_code == I_NOT_WR) && + (p[1]->ins_code == I_BOOLEAN) && + (p[2]->ins_code == X_CMP_WI || + p[2]->ins_code == X_CMP_WM || + p[2]->ins_code == X_CMP_WS || + p[2]->ins_code == X_CMP_UIQ || + p[2]->ins_code == X_CMP_UMQ || + p[2]->ins_code == X_CMP_USQ) + ) { + p[2]->cmp_type = compare2not[p[2]->cmp_type]; + nb = 2; + } + + /* flush queue */ + if (nb) { + q_wr -= nb; + q_nb -= nb; + nb = 0; + + if (q_wr < 0) + q_wr += Q_SIZE; + + /* loop */ + goto lv1_loop; + } + } + + /* then optimize conditional tests, part 3 */ + if (q_nb >= 2) { + /* + * __bool --> LLnn: + * LLnn: __bool + * + * Delay boolean conversion until the end of a list of labels. + * + * N.B. This optimization should be done before the X_TST_WM optimization! + */ + if + ((p[0]->ins_code == I_LABEL) && + (p[1]->ins_code == I_BOOLEAN) + ) { + *p[1] = *p[0]; + p[0]->ins_code = I_BOOLEAN; + p[0]->ins_type = 0; + p[0]->ins_data = 0; + /* no instructions removed, just loop */ + goto lv1_loop; + } + + /* + * __bool --> __bfalse + * __bfalse + * + * __bool --> __btrue + * __btrue + * + * __bool --> __bool + * __bool + * + * These remove redundant conversions of a flag into a boolean. + * + * N.B. This optimization should be done before the X_TST_WM optimization! + */ + else if + ((p[1]->ins_code == I_BOOLEAN) && + (p[0]->ins_code == I_BFALSE || + p[0]->ins_code == I_BTRUE || + p[0]->ins_code == I_BOOLEAN) + ) { + *p[1] = *p[0]; + nb = 1; + } + + /* + * __bra LLaa --> __bra LLaa + * __bra LLbb + */ + else if + ((p[0]->ins_code == I_BRA) && + (p[1]->ins_code == I_BRA) + ) { + nb = 1; + } + + /* + * LLaa: LLaa .alias LLbb + * __bra LLbb --> __bra LLbb + */ + else if + ((p[0]->ins_code == I_BRA) && + (p[1]->ins_code == I_LABEL) + ) { + int i = 1; + do { + if (p[i]->ins_data != p[0]->ins_data) { + p[i]->ins_code = I_ALIAS; + p[i]->imm_type = T_VALUE; + p[i]->imm_data = p[0]->ins_data; + } + } while (++i < q_nb && i < 10 && p[i]->ins_code == I_LABEL); + } + + /* + * __bra LLaa --> LLaa: + * LLaa: + */ + else if + ((p[0]->ins_code == I_LABEL) && + (p[1]->ins_code == I_BRA) && + (p[1]->ins_type == T_LABEL) && + (p[0]->ins_data == p[1]->ins_data) + ) { + *p[1] = *p[0]; + nb = 1; + } + + /* flush queue */ + if (nb) { + q_wr -= nb; + q_nb -= nb; + nb = 0; + + if (q_wr < 0) + q_wr += Q_SIZE; + + /* loop */ + goto lv1_loop; + } + } + /* 6-instruction patterns */ if (q_nb >= 6) { /* @@ -1375,6 +1727,35 @@ void push_ins (INS *ins) } #endif + /* + * is_ubyte() --> is_ubyte() + * __push.wr __cmp.umq type, symbol + * __ld.um symbol + * __cmp.wt type + * + * is_ubyte() --> is_ubyte() + * __push.wr __cmp.usq type, (n - 2) + * __ld.us n + * __cmp.wt type + */ + else if + ((p[0]->ins_code == I_CMP_WT) && + (p[1]->ins_code == I_LD_UM || + p[1]->ins_code == X_LD_US) && + (p[2]->ins_code == I_PUSH_WR) && + (is_ubyte(p[3])) + ) { + /* replace code */ + *p[2] = *p[1]; + switch (p[1]->ins_code) { + case I_LD_UM: p[2]->ins_code = X_CMP_UMQ; break; + case X_LD_US: p[2]->ins_code = X_CMP_USQ; p[2]->ins_data -= 2; break; + default: break; + } + p[2]->cmp_type = compare2uchar[p[0]->cmp_type]; + nb = 2; + } + /* flush queue */ if (nb) { q_wr -= nb; @@ -1556,58 +1937,61 @@ void push_ins (INS *ins) } /* - * __push.wr --> __equ.wi i - * __ld.wi i - * __cmp.wt eq_w - * - * __push.wr --> __neq.wi i - * __ld.wi i - * __cmp.wt ne_w - * * __push.wr --> __not.wr * __ld.wi 0 - * __cmp.wt eq_w + * __cmp.wt equ_w * * __push.wr --> __tst.wr * __ld.wi 0 - * __cmp.wt ne_w + * __cmp.wt neq_w + * + * Check for this before converting to X_CMP_WI! */ else if ((p[0]->ins_code == I_CMP_WT) && + (p[0]->cmp_type == CMP_EQU || + p[0]->cmp_type == CMP_NEQ) && (p[1]->ins_code == I_LD_WI) && - (p[2]->ins_code == I_PUSH_WR) && + (p[1]->ins_type == T_VALUE) && + (p[1]->ins_data == 0) && + (p[2]->ins_code == I_PUSH_WR) + ) { + /* replace code */ + p[2]->ins_code = (p[0]->cmp_type == CMP_EQU) ? I_NOT_WR : I_TST_WR; + p[2]->ins_type = 0; + p[2]->ins_data = 0; + nb = 2; + } - (p[1]->ins_type == T_VALUE || p[1]->ins_type == T_SYMBOL) && - (strcmp((char *)p[0]->ins_data, "eq_w") == 0 || - strcmp((char *)p[0]->ins_data, "eq_b") == 0 || - strcmp((char *)p[0]->ins_data, "ne_w") == 0 || - strcmp((char *)p[0]->ins_data, "ne_b") == 0) + /* + * __push.wr --> __cmp.wi type, i + * __ld.wi i + * __cmp.wt type + * + * __push.wr --> __cmp.wm type, symbol + * __ld.wm symbol + * __cmp.wt type + * + * __push.wr --> __cmp.ws type, (n - 2) + * __ld.ws n + * __cmp.wt type + */ + else if + ((p[0]->ins_code == I_CMP_WT) && + (p[1]->ins_code == I_LD_WI || + p[1]->ins_code == I_LD_WM || + p[1]->ins_code == X_LD_WS) && + (p[2]->ins_code == I_PUSH_WR) ) { /* replace code */ - if (p[1]->ins_data == 0) { - if (strcmp((char *)p[0]->ins_data, "eq_w") == 0) - p[2]->ins_code = I_NOT_WR; - else if (strcmp((char *)p[0]->ins_data, "eq_b") == 0) - p[2]->ins_code = I_NOT_WR; - else if (strcmp((char *)p[0]->ins_data, "ne_w") == 0) - p[2]->ins_code = I_TST_WR; - else if (strcmp((char *)p[0]->ins_data, "ne_b") == 0) - p[2]->ins_code = I_TST_WR; - p[2]->ins_type = 0; - p[2]->ins_data = 0; - } else { - if (strcmp((char *)p[0]->ins_data, "eq_w") == 0) - p[2]->ins_code = X_EQU_WI; - else if (strcmp((char *)p[0]->ins_data, "eq_b") == 0) - p[2]->ins_code = X_EQU_WI; - else if (strcmp((char *)p[0]->ins_data, "ne_w") == 0) - p[2]->ins_code = X_NEQ_WI; - else if (strcmp((char *)p[0]->ins_data, "ne_b") == 0) - p[2]->ins_code = X_NEQ_WI; - p[2]->ins_type = p[1]->ins_type; - p[2]->ins_data = p[1]->ins_data; + *p[2] = *p[1]; + switch (p[1]->ins_code) { + case I_LD_WI: p[2]->ins_code = X_CMP_WI; break; + case I_LD_WM: p[2]->ins_code = X_CMP_WM; break; + case X_LD_WS: p[2]->ins_code = X_CMP_WS; p[2]->ins_data -= 2; break; + default: break; } - + p[2]->cmp_type = p[0]->cmp_type; nb = 2; } @@ -1733,59 +2117,60 @@ void push_ins (INS *ins) /* * __ld.{w/b/u}p symbol --> __not.{w/u}p symbol * __tst.wr not(__tst.wr or __not.wr) - * not(__tst.wr or __not.wr) + * not(__bool or __tst.wr or __not.wr) * * __ld.{w/b/u}p symbol --> __tst.{w/u}p symbol * __not.wr not(__tst.wr or __not.wr) - * not(__tst.wr or __not.wr) + * not(__bool or __tst.wr or __not.wr) * * __ld.{w/b/u}m symbol --> __not.{w/u}m symbol * __tst.wr not(__tst.wr or __not.wr) - * not(__tst.wr or __not.wr) + * not(__bool or __tst.wr or __not.wr) * * __ld.{w/b/u}m symbol --> __tst.{w/u}m symbol * __not.wr not(__tst.wr or __not.wr) - * not(__tst.wr or __not.wr) + * not(__bool or __tst.wr or __not.wr) * * __ld.{w/b/u}s symbol --> __not.{w/u}s symbol * __tst.wr not(__tst.wr or __not.wr) - * not(__tst.wr or __not.wr) + * not(__bool or __tst.wr or __not.wr) * * __ld.{w/b/u}s symbol --> __tst.{w/u}s symbol * __not.wr not(__tst.wr or __not.wr) - * not(__tst.wr or __not.wr) + * not(__bool or __tst.wr or __not.wr) * * __ld.{w/b/u}ar symbol --> __not.{w/u}ar symbol * __tst.wr not(__tst.wr or __not.wr) - * not(__tst.wr or __not.wr) + * not(__bool or __tst.wr or __not.wr) * * __ld.{w/b/u}ar symbol --> __tst.{w/u}ar symbol * __not.wr not(__tst.wr or __not.wr) - * not(__tst.wr or __not.wr) + * not(__bool or __tst.wr or __not.wr) * * __ld.{b/u}ay symbol --> __not.uay symbol * __tst.wr not(__tst.wr or __not.wr) - * not(__tst.wr or __not.wr) + * not(__bool or __tst.wr or __not.wr) * * __ld.{b/u}ay symbol --> __tst.uay symbol * __not.wr not(__tst.wr or __not.wr) - * not(__tst.wr or __not.wr) + * not(__bool or __tst.wr or __not.wr) * * __and.{w/u}i n --> __tand.wi n * __tst.wr not(__tst.wr or __not.wr) - * not(__tst.wr or __not.wr) + * not(__bool or __tst.wr or __not.wr) * * __and.{w/u}i n --> __nand.wi n * __not.wr not(__tst.wr or __not.wr) - * not(__tst.wr or __not.wr) + * not(__bool or __tst.wr or __not.wr) * * N.B. This deliberately tests for the i-code after * the target I_TST_WR or I_NOT_WR in order to delay - * the match until after merging the dupliated tests + * the match until after merging the duplicate tests * that the code-generator often emits. */ else if - ((p[0]->ins_code != I_TST_WR) && + ((p[0]->ins_code != I_BOOLEAN) && + (p[0]->ins_code != I_TST_WR) && (p[0]->ins_code != I_NOT_WR) && (p[1]->ins_code == I_TST_WR || p[1]->ins_code == I_NOT_WR) && @@ -1925,49 +2310,6 @@ void push_ins (INS *ins) /* 2-instruction patterns */ if (q_nb >= 2) { - /* - * __bra LLaa --> __bra LLaa - * __bra LLbb - */ - if - ((p[0]->ins_code == I_BRA) && - (p[1]->ins_code == I_BRA) - ) { - nb = 1; - } - - /* - * LLaa: LLaa .alias LLbb - * __bra LLbb --> __bra LLbb - */ - if - ((p[0]->ins_code == I_BRA) && - (p[1]->ins_code == I_LABEL) - ) { - int i = 1; - do { - if (p[i]->ins_data != p[0]->ins_data) { - p[i]->ins_code = I_ALIAS; - p[i]->imm_type = T_VALUE; - p[i]->imm_data = p[0]->ins_data; - } - } while (++i < q_nb && i < 10 && p[i]->ins_code == I_LABEL); - } - - /* - * __bra LLaa --> LLaa: - * LLaa: - */ - else if - ((p[0]->ins_code == I_LABEL) && - (p[1]->ins_code == I_BRA) && - (p[1]->ins_type == T_LABEL) && - (p[0]->ins_data == p[1]->ins_data) - ) { - *p[1] = *p[0]; - nb = 1; - } - /* * __ld.{b/u}p __ptr --> __ld.{b/u}p __ptr * __switch.wr __switch.ur @@ -1981,7 +2323,7 @@ void push_ins (INS *ins) * __ld.{b/u}ar array --> __ld.{b/u}ar array * __switch.wr __switch.ur */ - else if + if ((p[0]->ins_code == I_SWITCH_WR) && (p[1]->ins_code == I_LD_BP || p[1]->ins_code == I_LD_UP || @@ -2021,57 +2363,6 @@ void push_ins (INS *ins) nb = 1; } - /* - * __tst.wr --> __not.wr - * __not.wr - */ - else if - ((p[0]->ins_code == I_NOT_WR) && - (p[1]->ins_code == I_TST_WR) - ) { - p[1]->ins_code = I_NOT_WR; - nb = 1; - } - - /* - * __not.wr --> __tst.wr - * __not.wr - */ - else if - ((p[0]->ins_code == I_NOT_WR) && - (p[1]->ins_code == I_NOT_WR) - ) { - p[1]->ins_code = I_TST_WR; - nb = 1; - } - - /* - * __cmp.wt --> __cmp.wt - * __tst.wr - * - * __not.wr --> __not.wr - * __tst.wr - * - * __tst.wr --> __tst.wr - * __tst.wr - * - * This removes redundant tests in compound conditionals ... - * - * LLnn: --> LLnn: - * __tst.wr - */ - else if - ((p[0]->ins_code == I_TST_WR) && - (p[1]->ins_code == I_CMP_WT || - p[1]->ins_code == X_EQU_WI || - p[1]->ins_code == X_NEQ_WI || - p[1]->ins_code == I_NOT_WR || - p[1]->ins_code == I_TST_WR || - p[1]->ins_code == I_LABEL) - ) { - nb = 1; - } - /* * __modsp i --> __modsp (i + j) * __modsp j @@ -2582,6 +2873,30 @@ void push_ins (INS *ins) goto lv1_loop; } + /* + * __ld.u{p/m/s/ar/ay} symbol --> __ld.u{p/m/s/ar/ay} symbol + * __cmp_w.wi j __cmp_b.uiq j + * + * __and.uiq i --> __and.uiq i + * __cmp_w.wi j __cmp_b.uiq j + * + * C promotes an unsigned char to a signed int so this + * must be done in the peephole, not the compiler. + */ + else if + ((p[0]->ins_code == X_CMP_WI) && + (p[0]->ins_type == T_VALUE) && + (p[0]->ins_data >= 0) && + (p[0]->ins_data <= 255) && + (is_ubyte(p[1])) + ) { + /* replace code */ + p[0]->ins_code = X_CMP_UIQ; + p[0]->cmp_type = compare2uchar[p[0]->cmp_type]; + /* no instructions removed, just loop */ + goto lv1_loop; + } + /* flush queue */ if (nb) { q_wr -= nb; @@ -2732,7 +3047,6 @@ void push_ins (INS *ins) case I_POP_WR: case I_CMP_WT: - case I_CMP_UT: case I_ST_WPT: case I_ST_UPT: case I_ADD_WT: