From 6f4a1f055595f39a27f4de387b549397290dbe9c Mon Sep 17 00:00:00 2001 From: jespergravgaard Date: Sat, 6 Jul 2019 11:00:15 +0200 Subject: [PATCH] Tetris NPE has been fixed. --- .../dk/camelot64/kickc/test/TestPrograms.java | 2 +- src/test/ref/tetris-npe.asm | 22 + src/test/ref/tetris-npe.cfg | 27 + src/test/ref/tetris-npe.log | 537 ++++++++++++++++++ src/test/ref/tetris-npe.sym | 23 + 5 files changed, 610 insertions(+), 1 deletion(-) create mode 100644 src/test/ref/tetris-npe.asm create mode 100644 src/test/ref/tetris-npe.cfg create mode 100644 src/test/ref/tetris-npe.log create mode 100644 src/test/ref/tetris-npe.sym diff --git a/src/test/java/dk/camelot64/kickc/test/TestPrograms.java b/src/test/java/dk/camelot64/kickc/test/TestPrograms.java index ec5ea2b15..c4c7872e9 100644 --- a/src/test/java/dk/camelot64/kickc/test/TestPrograms.java +++ b/src/test/java/dk/camelot64/kickc/test/TestPrograms.java @@ -1218,12 +1218,12 @@ public class TestPrograms { compileAndCompare("const-if-problem"); } - /* @Test public void testTetrisNullPointer() throws IOException, URISyntaxException { compileAndCompare("tetris-npe"); } + /* @Test public void testUnrollCall() throws IOException, URISyntaxException { compileAndCompare("unroll-call"); diff --git a/src/test/ref/tetris-npe.asm b/src/test/ref/tetris-npe.asm new file mode 100644 index 000000000..fcfb511ed --- /dev/null +++ b/src/test/ref/tetris-npe.asm @@ -0,0 +1,22 @@ +// NullPointerException using current_movedown_rate in the main loop +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" + .label RASTER = $d012 + .label SCREEN = $400 + .const RATE = $32 +main: { + ldx #0 + ldy #RATE + b2: + lda #$ff + cmp RASTER + bne b2 + dey + cpy #0 + bne b2 + inx + stx SCREEN + ldy #RATE + jmp b2 +} diff --git a/src/test/ref/tetris-npe.cfg b/src/test/ref/tetris-npe.cfg new file mode 100644 index 000000000..571777991 --- /dev/null +++ b/src/test/ref/tetris-npe.cfg @@ -0,0 +1,27 @@ +@begin: scope:[] from + [0] phi() + to:@1 +@1: scope:[] from @begin + [1] phi() + [2] call main + to:@end +@end: scope:[] from @1 + [3] phi() +main: scope:[main] from @1 + [4] phi() + to:main::@1 +main::@1: scope:[main] from main main::@3 main::@4 + [5] (byte) ypos#2 ← phi( main/(byte) 0 main::@4/(byte) ypos#1 ) + [5] (byte) counter#3 ← phi( main/(const byte) RATE#0 main::@4/(const byte) RATE#0 main::@3/(byte) counter#1 ) + to:main::@2 +main::@2: scope:[main] from main::@1 main::@2 + [6] if(*((const byte*) RASTER#0)!=(byte) $ff) goto main::@2 + to:main::@3 +main::@3: scope:[main] from main::@2 + [7] (byte) counter#1 ← -- (byte) counter#3 + [8] if((byte) counter#1!=(byte) 0) goto main::@1 + to:main::@4 +main::@4: scope:[main] from main::@3 + [9] (byte) ypos#1 ← ++ (byte) ypos#2 + [10] *((const byte*) SCREEN#0) ← (byte) ypos#1 + to:main::@1 diff --git a/src/test/ref/tetris-npe.log b/src/test/ref/tetris-npe.log new file mode 100644 index 000000000..ad82604f2 --- /dev/null +++ b/src/test/ref/tetris-npe.log @@ -0,0 +1,537 @@ +Identified constant variable (byte*) RASTER +Identified constant variable (byte*) SCREEN +Identified constant variable (byte) RATE +Culled Empty Block (label) main::@2 +Culled Empty Block (label) main::@12 +Culled Empty Block (label) main::@3 +Culled Empty Block (label) main::@13 +Culled Empty Block (label) main::@5 +Culled Empty Block (label) main::@7 +Culled Empty Block (label) main::@8 +Culled Empty Block (label) main::@9 +Culled Empty Block (label) main::@11 +Culled Empty Block (label) main::@14 + +CONTROL FLOW GRAPH SSA +@begin: scope:[] from + (byte*) RASTER#0 ← ((byte*)) (number) $d012 + (byte*) SCREEN#0 ← ((byte*)) (number) $400 + (byte) ypos#0 ← (number) 0 + (byte) RATE#0 ← (number) $32 + (byte) counter#0 ← (byte) RATE#0 + to:@1 +main: scope:[main] from @1 + (byte) ypos#10 ← phi( @1/(byte) ypos#9 ) + (byte) counter#11 ← phi( @1/(byte) counter#10 ) + to:main::@1 +main::@1: scope:[main] from main main::@10 main::@6 + (byte) ypos#8 ← phi( main/(byte) ypos#10 main::@10/(byte) ypos#1 main::@6/(byte) ypos#7 ) + (byte) counter#9 ← phi( main/(byte) counter#11 main::@10/(byte) counter#2 main::@6/(byte) counter#1 ) + if(true) goto main::@4 + to:main::@return +main::@4: scope:[main] from main::@1 main::@4 + (byte) ypos#11 ← phi( main::@1/(byte) ypos#8 main::@4/(byte) ypos#11 ) + (byte) counter#8 ← phi( main::@1/(byte) counter#9 main::@4/(byte) counter#8 ) + (bool~) main::$0 ← *((byte*) RASTER#0) != (number) $ff + if((bool~) main::$0) goto main::@4 + to:main::@6 +main::@6: scope:[main] from main::@4 + (byte) ypos#7 ← phi( main::@4/(byte) ypos#11 ) + (byte) counter#5 ← phi( main::@4/(byte) counter#8 ) + (byte) counter#1 ← -- (byte) counter#5 + (bool~) main::$1 ← (byte) counter#1 == (number) 0 + (bool~) main::$2 ← ! (bool~) main::$1 + if((bool~) main::$2) goto main::@1 + to:main::@10 +main::@10: scope:[main] from main::@6 + (byte) ypos#4 ← phi( main::@6/(byte) ypos#7 ) + (byte) counter#2 ← (byte) RATE#0 + (byte) ypos#1 ← ++ (byte) ypos#4 + *((byte*) SCREEN#0) ← (byte) ypos#1 + to:main::@1 +main::@return: scope:[main] from main::@1 + (byte) ypos#5 ← phi( main::@1/(byte) ypos#8 ) + (byte) counter#6 ← phi( main::@1/(byte) counter#9 ) + (byte) counter#3 ← (byte) counter#6 + (byte) ypos#2 ← (byte) ypos#5 + return + to:@return +@1: scope:[] from @begin + (byte) ypos#9 ← phi( @begin/(byte) ypos#0 ) + (byte) counter#10 ← phi( @begin/(byte) counter#0 ) + call main + to:@2 +@2: scope:[] from @1 + (byte) ypos#6 ← phi( @1/(byte) ypos#2 ) + (byte) counter#7 ← phi( @1/(byte) counter#3 ) + (byte) counter#4 ← (byte) counter#7 + (byte) ypos#3 ← (byte) ypos#6 + to:@end +@end: scope:[] from @2 + +SYMBOL TABLE SSA +(label) @1 +(label) @2 +(label) @begin +(label) @end +(byte*) RASTER +(byte*) RASTER#0 +(byte) RATE +(byte) RATE#0 +(byte*) SCREEN +(byte*) SCREEN#0 +(byte) counter +(byte) counter#0 +(byte) counter#1 +(byte) counter#10 +(byte) counter#11 +(byte) counter#2 +(byte) counter#3 +(byte) counter#4 +(byte) counter#5 +(byte) counter#6 +(byte) counter#7 +(byte) counter#8 +(byte) counter#9 +(void()) main() +(bool~) main::$0 +(bool~) main::$1 +(bool~) main::$2 +(label) main::@1 +(label) main::@10 +(label) main::@4 +(label) main::@6 +(label) main::@return +(byte) ypos +(byte) ypos#0 +(byte) ypos#1 +(byte) ypos#10 +(byte) ypos#11 +(byte) ypos#2 +(byte) ypos#3 +(byte) ypos#4 +(byte) ypos#5 +(byte) ypos#6 +(byte) ypos#7 +(byte) ypos#8 +(byte) ypos#9 + +Adding number conversion cast (unumber) 0 in (byte) ypos#0 ← (number) 0 +Adding number conversion cast (unumber) $32 in (byte) RATE#0 ← (number) $32 +Adding number conversion cast (unumber) $ff in (bool~) main::$0 ← *((byte*) RASTER#0) != (number) $ff +Adding number conversion cast (unumber) 0 in (bool~) main::$1 ← (byte) counter#1 == (number) 0 +Successful SSA optimization PassNAddNumberTypeConversions +Inlining cast (byte*) RASTER#0 ← (byte*)(number) $d012 +Inlining cast (byte*) SCREEN#0 ← (byte*)(number) $400 +Inlining cast (byte) ypos#0 ← (unumber)(number) 0 +Inlining cast (byte) RATE#0 ← (unumber)(number) $32 +Successful SSA optimization Pass2InlineCast +Simplifying constant pointer cast (byte*) 53266 +Simplifying constant pointer cast (byte*) 1024 +Simplifying constant integer cast 0 +Simplifying constant integer cast $32 +Simplifying constant integer cast $ff +Simplifying constant integer cast 0 +Successful SSA optimization PassNCastSimplification +Finalized unsigned number type (byte) 0 +Finalized unsigned number type (byte) $32 +Finalized unsigned number type (byte) $ff +Finalized unsigned number type (byte) 0 +Successful SSA optimization PassNFinalizeNumberTypeConversions +Inversing boolean not [14] (bool~) main::$2 ← (byte) counter#1 != (byte) 0 from [13] (bool~) main::$1 ← (byte) counter#1 == (byte) 0 +Successful SSA optimization Pass2UnaryNotSimplification +Alias (byte) RATE#0 = (byte) counter#0 (byte) counter#10 +Alias (byte) counter#5 = (byte) counter#8 +Alias (byte) ypos#11 = (byte) ypos#7 (byte) ypos#4 +Alias (byte) counter#3 = (byte) counter#6 (byte) counter#9 +Alias (byte) ypos#2 = (byte) ypos#5 (byte) ypos#8 +Alias (byte) ypos#0 = (byte) ypos#9 +Alias (byte) counter#4 = (byte) counter#7 +Alias (byte) ypos#3 = (byte) ypos#6 +Successful SSA optimization Pass2AliasElimination +Self Phi Eliminated (byte) counter#5 +Self Phi Eliminated (byte) ypos#11 +Successful SSA optimization Pass2SelfPhiElimination +Identical Phi Values (byte) counter#11 (byte) RATE#0 +Identical Phi Values (byte) ypos#10 (byte) ypos#0 +Identical Phi Values (byte) counter#5 (byte) counter#3 +Identical Phi Values (byte) ypos#11 (byte) ypos#2 +Identical Phi Values (byte) counter#4 (byte) counter#3 +Identical Phi Values (byte) ypos#3 (byte) ypos#2 +Successful SSA optimization Pass2IdenticalPhiElimination +Simple Condition (bool~) main::$0 [10] if(*((byte*) RASTER#0)!=(byte) $ff) goto main::@4 +Simple Condition (bool~) main::$2 [15] if((byte) counter#1!=(byte) 0) goto main::@1 +Successful SSA optimization Pass2ConditionalJumpSimplification +Constant (const byte*) RASTER#0 = (byte*) 53266 +Constant (const byte*) SCREEN#0 = (byte*) 1024 +Constant (const byte) ypos#0 = 0 +Constant (const byte) RATE#0 = $32 +Successful SSA optimization Pass2ConstantIdentification +Constant (const byte) counter#2 = RATE#0 +Successful SSA optimization Pass2ConstantIdentification +if() condition always true - replacing block destination [7] if(true) goto main::@4 +Successful SSA optimization Pass2ConstantIfs +Removing unused block main::@return +Successful SSA optimization Pass2EliminateUnusedBlocks +Self Phi Eliminated (byte) ypos#2 +Successful SSA optimization Pass2SelfPhiElimination +Inlining constant with var siblings (const byte) ypos#0 +Inlining constant with var siblings (const byte) counter#2 +Constant inlined ypos#0 = (byte) 0 +Constant inlined counter#2 = (const byte) RATE#0 +Successful SSA optimization Pass2ConstantInlining +Added new block during phi lifting main::@15(between main::@6 and main::@1) +Adding NOP phi() at start of @begin +Adding NOP phi() at start of @1 +Adding NOP phi() at start of @2 +Adding NOP phi() at start of @end +Adding NOP phi() at start of main +CALL GRAPH +Calls in [] to main:2 + +Created 2 initial phi equivalence classes +Coalesced [12] ypos#12 ← ypos#1 +Coalesced [13] counter#12 ← counter#1 +Coalesced down to 2 phi equivalence classes +Culled Empty Block (label) @2 +Culled Empty Block (label) main::@15 +Renumbering block main::@4 to main::@2 +Renumbering block main::@6 to main::@3 +Renumbering block main::@10 to main::@4 +Adding NOP phi() at start of @begin +Adding NOP phi() at start of @1 +Adding NOP phi() at start of @end +Adding NOP phi() at start of main + +FINAL CONTROL FLOW GRAPH +@begin: scope:[] from + [0] phi() + to:@1 +@1: scope:[] from @begin + [1] phi() + [2] call main + to:@end +@end: scope:[] from @1 + [3] phi() +main: scope:[main] from @1 + [4] phi() + to:main::@1 +main::@1: scope:[main] from main main::@3 main::@4 + [5] (byte) ypos#2 ← phi( main/(byte) 0 main::@4/(byte) ypos#1 ) + [5] (byte) counter#3 ← phi( main/(const byte) RATE#0 main::@4/(const byte) RATE#0 main::@3/(byte) counter#1 ) + to:main::@2 +main::@2: scope:[main] from main::@1 main::@2 + [6] if(*((const byte*) RASTER#0)!=(byte) $ff) goto main::@2 + to:main::@3 +main::@3: scope:[main] from main::@2 + [7] (byte) counter#1 ← -- (byte) counter#3 + [8] if((byte) counter#1!=(byte) 0) goto main::@1 + to:main::@4 +main::@4: scope:[main] from main::@3 + [9] (byte) ypos#1 ← ++ (byte) ypos#2 + [10] *((const byte*) SCREEN#0) ← (byte) ypos#1 + to:main::@1 + + +VARIABLE REGISTER WEIGHTS +(byte*) RASTER +(byte) RATE +(byte*) SCREEN +(byte) counter +(byte) counter#1 151.5 +(byte) counter#3 101.0 +(void()) main() +(byte) ypos +(byte) ypos#1 16.5 +(byte) ypos#2 5.5 + +Initial phi equivalence classes +[ counter#3 counter#1 ] +[ ypos#2 ypos#1 ] +Complete equivalence classes +[ counter#3 counter#1 ] +[ ypos#2 ypos#1 ] +Allocated zp ZP_BYTE:2 [ counter#3 counter#1 ] +Allocated zp ZP_BYTE:3 [ ypos#2 ypos#1 ] + +INITIAL ASM +//SEG0 File Comments +// NullPointerException using current_movedown_rate in the main loop +//SEG1 Basic Upstart +.pc = $801 "Basic" +:BasicUpstart(bbegin) +.pc = $80d "Program" +//SEG2 Global Constants & labels + .label RASTER = $d012 + .label SCREEN = $400 + .const RATE = $32 + .label counter = 2 + .label ypos = 3 +//SEG3 @begin +bbegin: +//SEG4 [1] phi from @begin to @1 [phi:@begin->@1] +b1_from_bbegin: + jmp b1 +//SEG5 @1 +b1: +//SEG6 [2] call main +//SEG7 [4] phi from @1 to main [phi:@1->main] +main_from_b1: + jsr main +//SEG8 [3] phi from @1 to @end [phi:@1->@end] +bend_from_b1: + jmp bend +//SEG9 @end +bend: +//SEG10 main +main: { + //SEG11 [5] phi from main to main::@1 [phi:main->main::@1] + b1_from_main: + //SEG12 [5] phi (byte) ypos#2 = (byte) 0 [phi:main->main::@1#0] -- vbuz1=vbuc1 + lda #0 + sta ypos + //SEG13 [5] phi (byte) counter#3 = (const byte) RATE#0 [phi:main->main::@1#1] -- vbuz1=vbuc1 + lda #RATE + sta counter + jmp b1 + //SEG14 [5] phi from main::@3 to main::@1 [phi:main::@3->main::@1] + b1_from_b3: + //SEG15 [5] phi (byte) counter#3 = (byte) counter#1 [phi:main::@3->main::@1#0] -- register_copy + jmp b1 + //SEG16 main::@1 + b1: + jmp b2 + //SEG17 main::@2 + b2: + //SEG18 [6] if(*((const byte*) RASTER#0)!=(byte) $ff) goto main::@2 -- _deref_pbuc1_neq_vbuc2_then_la1 + lda #$ff + cmp RASTER + bne b2 + jmp b3 + //SEG19 main::@3 + b3: + //SEG20 [7] (byte) counter#1 ← -- (byte) counter#3 -- vbuz1=_dec_vbuz1 + dec counter + //SEG21 [8] if((byte) counter#1!=(byte) 0) goto main::@1 -- vbuz1_neq_0_then_la1 + lda counter + cmp #0 + bne b1_from_b3 + jmp b4 + //SEG22 main::@4 + b4: + //SEG23 [9] (byte) ypos#1 ← ++ (byte) ypos#2 -- vbuz1=_inc_vbuz1 + inc ypos + //SEG24 [10] *((const byte*) SCREEN#0) ← (byte) ypos#1 -- _deref_pbuc1=vbuz1 + lda ypos + sta SCREEN + //SEG25 [5] phi from main::@4 to main::@1 [phi:main::@4->main::@1] + b1_from_b4: + //SEG26 [5] phi (byte) ypos#2 = (byte) ypos#1 [phi:main::@4->main::@1#0] -- register_copy + //SEG27 [5] phi (byte) counter#3 = (const byte) RATE#0 [phi:main::@4->main::@1#1] -- vbuz1=vbuc1 + lda #RATE + sta counter + jmp b1 +} +//SEG28 File Data + +REGISTER UPLIFT POTENTIAL REGISTERS +Statement [6] if(*((const byte*) RASTER#0)!=(byte) $ff) goto main::@2 [ counter#3 ypos#2 ] ( main:2 [ counter#3 ypos#2 ] ) always clobbers reg byte a +Removing always clobbered register reg byte a as potential for zp ZP_BYTE:2 [ counter#3 counter#1 ] +Removing always clobbered register reg byte a as potential for zp ZP_BYTE:3 [ ypos#2 ypos#1 ] +Statement [6] if(*((const byte*) RASTER#0)!=(byte) $ff) goto main::@2 [ counter#3 ypos#2 ] ( main:2 [ counter#3 ypos#2 ] ) always clobbers reg byte a +Potential registers zp ZP_BYTE:2 [ counter#3 counter#1 ] : zp ZP_BYTE:2 , reg byte x , reg byte y , +Potential registers zp ZP_BYTE:3 [ ypos#2 ypos#1 ] : zp ZP_BYTE:3 , reg byte x , reg byte y , + +REGISTER UPLIFT SCOPES +Uplift Scope [] 252.5: zp ZP_BYTE:2 [ counter#3 counter#1 ] 22: zp ZP_BYTE:3 [ ypos#2 ypos#1 ] +Uplift Scope [main] + +Uplifting [] best 14052 combination reg byte y [ counter#3 counter#1 ] reg byte x [ ypos#2 ypos#1 ] +Uplifting [main] best 14052 combination + +ASSEMBLER BEFORE OPTIMIZATION +//SEG0 File Comments +// NullPointerException using current_movedown_rate in the main loop +//SEG1 Basic Upstart +.pc = $801 "Basic" +:BasicUpstart(bbegin) +.pc = $80d "Program" +//SEG2 Global Constants & labels + .label RASTER = $d012 + .label SCREEN = $400 + .const RATE = $32 +//SEG3 @begin +bbegin: +//SEG4 [1] phi from @begin to @1 [phi:@begin->@1] +b1_from_bbegin: + jmp b1 +//SEG5 @1 +b1: +//SEG6 [2] call main +//SEG7 [4] phi from @1 to main [phi:@1->main] +main_from_b1: + jsr main +//SEG8 [3] phi from @1 to @end [phi:@1->@end] +bend_from_b1: + jmp bend +//SEG9 @end +bend: +//SEG10 main +main: { + //SEG11 [5] phi from main to main::@1 [phi:main->main::@1] + b1_from_main: + //SEG12 [5] phi (byte) ypos#2 = (byte) 0 [phi:main->main::@1#0] -- vbuxx=vbuc1 + ldx #0 + //SEG13 [5] phi (byte) counter#3 = (const byte) RATE#0 [phi:main->main::@1#1] -- vbuyy=vbuc1 + ldy #RATE + jmp b1 + //SEG14 [5] phi from main::@3 to main::@1 [phi:main::@3->main::@1] + b1_from_b3: + //SEG15 [5] phi (byte) counter#3 = (byte) counter#1 [phi:main::@3->main::@1#0] -- register_copy + jmp b1 + //SEG16 main::@1 + b1: + jmp b2 + //SEG17 main::@2 + b2: + //SEG18 [6] if(*((const byte*) RASTER#0)!=(byte) $ff) goto main::@2 -- _deref_pbuc1_neq_vbuc2_then_la1 + lda #$ff + cmp RASTER + bne b2 + jmp b3 + //SEG19 main::@3 + b3: + //SEG20 [7] (byte) counter#1 ← -- (byte) counter#3 -- vbuyy=_dec_vbuyy + dey + //SEG21 [8] if((byte) counter#1!=(byte) 0) goto main::@1 -- vbuyy_neq_0_then_la1 + cpy #0 + bne b1_from_b3 + jmp b4 + //SEG22 main::@4 + b4: + //SEG23 [9] (byte) ypos#1 ← ++ (byte) ypos#2 -- vbuxx=_inc_vbuxx + inx + //SEG24 [10] *((const byte*) SCREEN#0) ← (byte) ypos#1 -- _deref_pbuc1=vbuxx + stx SCREEN + //SEG25 [5] phi from main::@4 to main::@1 [phi:main::@4->main::@1] + b1_from_b4: + //SEG26 [5] phi (byte) ypos#2 = (byte) ypos#1 [phi:main::@4->main::@1#0] -- register_copy + //SEG27 [5] phi (byte) counter#3 = (const byte) RATE#0 [phi:main::@4->main::@1#1] -- vbuyy=vbuc1 + ldy #RATE + jmp b1 +} +//SEG28 File Data + +ASSEMBLER OPTIMIZATIONS +Removing instruction jmp b1 +Removing instruction jmp bend +Removing instruction jmp b1 +Removing instruction jmp b2 +Removing instruction jmp b3 +Removing instruction jmp b4 +Succesful ASM optimization Pass5NextJumpElimination +Replacing label b1 with b2 +Replacing label b1_from_b3 with b2 +Replacing label b1 with b2 +Removing instruction b1_from_bbegin: +Removing instruction b1: +Removing instruction main_from_b1: +Removing instruction bend_from_b1: +Removing instruction b1_from_b3: +Removing instruction b1: +Succesful ASM optimization Pass5RedundantLabelElimination +Removing instruction bend: +Removing instruction b1_from_main: +Removing instruction b3: +Removing instruction b4: +Removing instruction b1_from_b4: +Succesful ASM optimization Pass5UnusedLabelElimination +Updating BasicUpstart to call main directly +Removing instruction jsr main +Succesful ASM optimization Pass5SkipBegin +Removing instruction jmp b2 +Succesful ASM optimization Pass5NextJumpElimination +Removing instruction bbegin: +Succesful ASM optimization Pass5UnusedLabelElimination + +FINAL SYMBOL TABLE +(label) @1 +(label) @begin +(label) @end +(byte*) RASTER +(const byte*) RASTER#0 RASTER = (byte*) 53266 +(byte) RATE +(const byte) RATE#0 RATE = (byte) $32 +(byte*) SCREEN +(const byte*) SCREEN#0 SCREEN = (byte*) 1024 +(byte) counter +(byte) counter#1 reg byte y 151.5 +(byte) counter#3 reg byte y 101.0 +(void()) main() +(label) main::@1 +(label) main::@2 +(label) main::@3 +(label) main::@4 +(byte) ypos +(byte) ypos#1 reg byte x 16.5 +(byte) ypos#2 reg byte x 5.5 + +reg byte y [ counter#3 counter#1 ] +reg byte x [ ypos#2 ypos#1 ] + + +FINAL ASSEMBLER +Score: 10110 + +//SEG0 File Comments +// NullPointerException using current_movedown_rate in the main loop +//SEG1 Basic Upstart +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" +//SEG2 Global Constants & labels + .label RASTER = $d012 + .label SCREEN = $400 + .const RATE = $32 +//SEG3 @begin +//SEG4 [1] phi from @begin to @1 [phi:@begin->@1] +//SEG5 @1 +//SEG6 [2] call main +//SEG7 [4] phi from @1 to main [phi:@1->main] +//SEG8 [3] phi from @1 to @end [phi:@1->@end] +//SEG9 @end +//SEG10 main +main: { + //SEG11 [5] phi from main to main::@1 [phi:main->main::@1] + //SEG12 [5] phi (byte) ypos#2 = (byte) 0 [phi:main->main::@1#0] -- vbuxx=vbuc1 + ldx #0 + //SEG13 [5] phi (byte) counter#3 = (const byte) RATE#0 [phi:main->main::@1#1] -- vbuyy=vbuc1 + ldy #RATE + //SEG14 [5] phi from main::@3 to main::@1 [phi:main::@3->main::@1] + //SEG15 [5] phi (byte) counter#3 = (byte) counter#1 [phi:main::@3->main::@1#0] -- register_copy + //SEG16 main::@1 + //SEG17 main::@2 + b2: + //SEG18 [6] if(*((const byte*) RASTER#0)!=(byte) $ff) goto main::@2 -- _deref_pbuc1_neq_vbuc2_then_la1 + lda #$ff + cmp RASTER + bne b2 + //SEG19 main::@3 + //SEG20 [7] (byte) counter#1 ← -- (byte) counter#3 -- vbuyy=_dec_vbuyy + dey + //SEG21 [8] if((byte) counter#1!=(byte) 0) goto main::@1 -- vbuyy_neq_0_then_la1 + cpy #0 + bne b2 + //SEG22 main::@4 + //SEG23 [9] (byte) ypos#1 ← ++ (byte) ypos#2 -- vbuxx=_inc_vbuxx + inx + //SEG24 [10] *((const byte*) SCREEN#0) ← (byte) ypos#1 -- _deref_pbuc1=vbuxx + stx SCREEN + //SEG25 [5] phi from main::@4 to main::@1 [phi:main::@4->main::@1] + //SEG26 [5] phi (byte) ypos#2 = (byte) ypos#1 [phi:main::@4->main::@1#0] -- register_copy + //SEG27 [5] phi (byte) counter#3 = (const byte) RATE#0 [phi:main::@4->main::@1#1] -- vbuyy=vbuc1 + ldy #RATE + jmp b2 +} +//SEG28 File Data + diff --git a/src/test/ref/tetris-npe.sym b/src/test/ref/tetris-npe.sym new file mode 100644 index 000000000..74bde72be --- /dev/null +++ b/src/test/ref/tetris-npe.sym @@ -0,0 +1,23 @@ +(label) @1 +(label) @begin +(label) @end +(byte*) RASTER +(const byte*) RASTER#0 RASTER = (byte*) 53266 +(byte) RATE +(const byte) RATE#0 RATE = (byte) $32 +(byte*) SCREEN +(const byte*) SCREEN#0 SCREEN = (byte*) 1024 +(byte) counter +(byte) counter#1 reg byte y 151.5 +(byte) counter#3 reg byte y 101.0 +(void()) main() +(label) main::@1 +(label) main::@2 +(label) main::@3 +(label) main::@4 +(byte) ypos +(byte) ypos#1 reg byte x 16.5 +(byte) ypos#2 reg byte x 5.5 + +reg byte y [ counter#3 counter#1 ] +reg byte x [ ypos#2 ypos#1 ]