From d714c6ab4c5f1abc07c82b367b4b9eb05e96e4f1 Mon Sep 17 00:00:00 2001 From: jespergravgaard Date: Thu, 21 May 2020 21:34:34 +0200 Subject: [PATCH] Added Atari 2600 Sprite test. --- src/main/kc/include/atari-tia.h | 26 +- src/main/kc/include/atari2600.h | 1 + .../dk/camelot64/kickc/test/TestPrograms.java | 5 + .../kc/examples/atari2600/atari2600-demo.c | 53 +- .../kc/examples/atari2600/atari2600-sprites.c | 157 ++ src/test/kc/inline-asm-ma-var.c | 2 +- .../ref/examples/atari2600/atari2600-demo.asm | 80 +- .../ref/examples/atari2600/atari2600-demo.cfg | 61 +- .../ref/examples/atari2600/atari2600-demo.log | 815 ++++--- .../ref/examples/atari2600/atari2600-demo.sym | 28 +- .../examples/atari2600/atari2600-sprites.asm | 211 ++ .../examples/atari2600/atari2600-sprites.cfg | 85 + .../examples/atari2600/atari2600-sprites.log | 2031 +++++++++++++++++ .../examples/atari2600/atari2600-sprites.sym | 131 ++ 14 files changed, 3224 insertions(+), 462 deletions(-) create mode 100644 src/test/kc/examples/atari2600/atari2600-sprites.c create mode 100644 src/test/ref/examples/atari2600/atari2600-sprites.asm create mode 100644 src/test/ref/examples/atari2600/atari2600-sprites.cfg create mode 100644 src/test/ref/examples/atari2600/atari2600-sprites.log create mode 100644 src/test/ref/examples/atari2600/atari2600-sprites.sym diff --git a/src/main/kc/include/atari-tia.h b/src/main/kc/include/atari-tia.h index 90d8ec1b0..1e2e86209 100644 --- a/src/main/kc/include/atari-tia.h +++ b/src/main/kc/include/atari-tia.h @@ -1,6 +1,19 @@ // Atari Television Interface Adaptor (TIA) // https://en.wikipedia.org/wiki/Television_Interface_Adaptor // http://www.qotile.net/minidig/docs/stella.pdf +// Based on https://github.com/munsie/dasm/blob/master/machines/atari2600/vcs.h + +// The number of CPU cycles per scanline +const char CYCLES_PER_SCANLINE = 76; + +// The TIA WSYNC register (for access from inline ASM) +char* const TIA_WSYNC = 0x02; +// The TIA RESP0 register (for access from inline ASM) +char* const TIA_RESP0 = 0x10; +// The TIA RESP1 register (for access from inline ASM) +char* const TIA_RESP1 = 0x11; +// The TIA HMP0 register (for access from inline ASM) +char* const TIA_HMP0 = 0x20; struct ATARI_TIA_WRITE { // $00 0000 00x0 Vertical Sync Set-Clear @@ -61,9 +74,9 @@ struct ATARI_TIA_WRITE { char GRP0; // $1C xxxx xxxx Graphics Register Player 1 char GRP1; - // $1D 0000 00x0 Graphics Enable Missle 0 + // $1D 0000 00x0 Graphics Enable Missile 0 char ENAM0; - // $1E 0000 00x0 Graphics Enable Missle 1 + // $1E 0000 00x0 Graphics Enable Missile 1 char ENAM1; // $1F 0000 00x0 Graphics Enable Ball char ENABL; @@ -71,9 +84,9 @@ struct ATARI_TIA_WRITE { char HMP0; // $21 xxxx 0000 Horizontal Motion Player 1 char HMP1; - // $22 xxxx 0000 Horizontal Motion Missle 0 + // $22 xxxx 0000 Horizontal Motion Missile 0 char HMM0; - // $23 xxxx 0000 Horizontal Motion Missle 1 + // $23 xxxx 0000 Horizontal Motion Missile 1 char HMM1; // $24 xxxx 0000 Horizontal Motion Ball char HMBL; @@ -83,9 +96,9 @@ struct ATARI_TIA_WRITE { char VDELP1; // $27 0000 000x Vertical Delay Ball char VDELBL; - // $28 0000 00x0 Reset Missle 0 to Player 0 + // $28 0000 00x0 Reset Missile 0 to Player 0 char RESMP0; - // $29 0000 00x0 Reset Missle 1 to Player 1 + // $29 0000 00x0 Reset Missile 1 to Player 1 char RESMP1; // $2A ---- ---- Apply Horizontal Motion char HMOVE; @@ -126,3 +139,4 @@ struct ATARI_TIA_READ { // $0D x000 0000 Read Input (Trigger) 1 char INPT5; }; + diff --git a/src/main/kc/include/atari2600.h b/src/main/kc/include/atari2600.h index d9c501d7c..1572befc2 100644 --- a/src/main/kc/include/atari2600.h +++ b/src/main/kc/include/atari2600.h @@ -12,3 +12,4 @@ struct ATARI_TIA_READ * const TIA_READ = 0x00; // Atari RIOT registers struct MOS6532_RIOT * const RIOT = 0x280; + diff --git a/src/test/java/dk/camelot64/kickc/test/TestPrograms.java b/src/test/java/dk/camelot64/kickc/test/TestPrograms.java index 20fbcc2d0..dc0bf716a 100644 --- a/src/test/java/dk/camelot64/kickc/test/TestPrograms.java +++ b/src/test/java/dk/camelot64/kickc/test/TestPrograms.java @@ -44,6 +44,11 @@ public class TestPrograms { public TestPrograms() { } + @Test + public void testAtari2600Sprites() throws IOException, URISyntaxException { + compileAndCompare("examples/atari2600/atari2600-sprites.c"); + } + @Test public void testAtari2600Demo() throws IOException, URISyntaxException { compileAndCompare("examples/atari2600/atari2600-demo.c"); diff --git a/src/test/kc/examples/atari2600/atari2600-demo.c b/src/test/kc/examples/atari2600/atari2600-demo.c index 1eaee4251..181854cff 100644 --- a/src/test/kc/examples/atari2600/atari2600-demo.c +++ b/src/test/kc/examples/atari2600/atari2600-demo.c @@ -1,4 +1,4 @@ -// Demonstration Atari 2600 VCS Program +// Minimal Atari 2600 VCS Program // Source: https://atariage.com/forums/blogs/entry/11109-step-1-generate-a-stable-display/ #pragma target(atari2600) #include @@ -7,49 +7,66 @@ #pragma data_seg(Vars) char __mem idx=0; -// Data +// Data #pragma data_seg(Data) -const char align(0x100) SINTABLE[0x100] = kickasm {{ +const char SINTABLE[0x100] = kickasm {{ .fill $100, round(127.5+127.5*sin(2*PI*i/256)) }}; void main() { + + TIA->PF0 = 0b10100000; + TIA->PF1 = 0b01010101; + TIA->PF2 = 0b10101010; + TIA->COLUPF = 0x55; + while(1) { // Vertical Sync // here we generate the signal that tells the TV to move the beam to the top of // the screen so we can start the next frame of video. // The Sync Signal must be on for 3 scanlines. - TIA->VSYNC = 2; // Accumulator D1=1, turns on Vertical Sync signal + TIA->VSYNC = 2; // D1=1, turns on Vertical Sync signal + RIOT->TIM64T = (41*76)/64; // Set timer to wait 41 lines TIA->WSYNC = 0; // Wait for Sync - halts CPU until end of 1st scanline of VSYNC TIA->WSYNC = 0; // wait until end of 2nd scanline of VSYNC TIA->WSYNC = 0; // wait until end of 3rd scanline of VSYNC - TIA->VSYNC = 0; // Accumulator D1=0, turns off Vertical Sync signal + TIA->VSYNC = 0; // D1=0, turns off Vertical Sync signal // Vertical Blank - game logic - // Since we don't have any yet, just delay - for(char i=0;i<37;i++) { - TIA->WSYNC = 0; // Wait for SYNC (halts CPU until end of scanline) - } + // Since we have a timer running this may take variable time + + + // Wait for the timer to run out + while(RIOT->INTIM) TIA->WSYNC = 0; // Screen - display logic - // Update the registers in TIA (the video chip) in order to generate what the player sees. + // Update the registers in TIA (the video chip) in order to generate what the player sees. // For now we're just going to output 192 colored scanlines lines so we have something to see. TIA->VBLANK = 0; // D1=1, turns off Vertical Blank signal (image output on) char c = SINTABLE[idx++]; for(char i=0;i<192;i++) { TIA->WSYNC = 0; // Wait for SYNC (halts CPU until end of scanline) - TIA->COLUBK = c++; // Set background color + TIA->COLUBK = c; // Set background color + TIA->PF0 = c; + TIA->PF1 = c; + TIA->PF2 = c; + TIA->HMOVE = c; + c++; } - // Overscan - game logic - // Since we don't have any yet, just delay + // Start OverScan TIA->WSYNC = 0; // Wait for SYNC (halts CPU until end of scanline) - TIA->VBLANK = 2; // // D1=1 turns image output off - TIA->COLUBK = 0; - for(char i=0;i<30;i++) { - TIA->WSYNC = 0; // Wait for SYNC (halts CPU until end of scanline) - } + TIA->VBLANK = 2; // D1=1 turns image output off + TIA->COLUBK = 0; // Set background color to black + RIOT->TIM64T = (27*76)/64; // Set timer to wait 27 lines + + // Vertical Blank - game logic + // Since we have a timer running this may take variable time + + // Wait for the timer to run out + while(RIOT->INTIM) TIA->WSYNC = 0; + } } diff --git a/src/test/kc/examples/atari2600/atari2600-sprites.c b/src/test/kc/examples/atari2600/atari2600-sprites.c new file mode 100644 index 000000000..bf7a7af2d --- /dev/null +++ b/src/test/kc/examples/atari2600/atari2600-sprites.c @@ -0,0 +1,157 @@ +// Minimal Atari 2600 VCS Program using Sprites +// Source: https://atariage.com/forums/blogs/entry/11109-step-1-generate-a-stable-display/ +#pragma target(atari2600) +#include +#pragma var_model(mem) + +// Data +#pragma data_seg(Data) +const char SINTABLE_160[0x100] = kickasm {{ + .fill $100, 5+round(74.5+74.5*sin(2*PI*i/256)) +}}; + +char SPRITE_C[] = { + 0, + 0b00011000, + 0b00011000, + 0b00011000, + 0b00011000, + 0b00111100, + 0b00111100, + 0b00111100, + 0b00111100, + 0b01100110, + 0b01100110, + 0b01100110, + 0b01100110, + 0b11000000, + 0b11000000, + 0b11000000, + 0b11000000, + 0b11000000, + 0b11000000, + 0b11000000, + 0b11000000, + 0b01100110, + 0b01100110, + 0b01100110, + 0b01100110, + 0b00111100, + 0b00111100, + 0b00111100, + 0b00111100, + 0b00011000, + 0b00011000, + 0b00011000, + 0b00011000, + 0 +}; + + +// Variables +#pragma data_seg(Vars) +// Counts frames +char idx; +char idx2 = 57; +// Player 0 X position +__ma char p0_xpos; +// Player 0 Y position +char p0_ypos; + +void main() { + + asm { cld } + // Player 0 + // - Color + TIA->COLUP0 = 0xf0; + // - Graphics + TIA->GRP0 = 0xaf; + + // Player 1 + // - Color + //TIA->COLUP1 = 0xf0; + // - Graphics + //TIA->GRP1 = 0xf5; + + while(1) { + + // Vertical Sync + // here we generate the signal that tells the TV to move the beam to the top of + // the screen so we can start the next frame of video. + // The Sync Signal must be on for 3 scanlines. + TIA->VSYNC = 2; // D1=1, turns on Vertical Sync signal + RIOT->TIM64T = (41*CYCLES_PER_SCANLINE)/64; // Set timer to wait 41 lines + TIA->WSYNC = 0; // Wait for Sync - halts CPU until end of 1st scanline of VSYNC + TIA->WSYNC = 0; // wait until end of 2nd scanline of VSYNC + TIA->WSYNC = 0; // wait until end of 3rd scanline of VSYNC + TIA->VSYNC = 0; // D1=0, turns off Vertical Sync signal + + // Vertical Blank - game logic + // Since we have a timer running this may take variable time + + // Vertical Sprite Position Player 0 - inline ASM to achieve cycle exact code + asm { + lda p0_xpos + sta TIA_WSYNC + sec + !: sbc #$f + bcs !- + eor #7 + asl + asl + asl + asl + sta TIA_HMP0 + sta TIA_RESP0 + } + p0_xpos = SINTABLE_160[idx++]; + p0_ypos = SINTABLE_160[idx2++]; + + // Execute horisontal movement + + TIA->WSYNC = 0; + TIA->HMOVE = 0; + + // Wait for the timer to run out + while(RIOT->INTIM) TIA->WSYNC = 0; + + // Screen - display logic + // Update the registers in TIA (the video chip) in order to generate what the player sees. + // For now we're just going to output 192 colored scanlines lines so we have something to see. + TIA->VBLANK = 0; // D1=1, turns off Vertical Blank signal (image output on) + TIA->COLUBK = 0x0; // Set background color to black + + // index into p0 (0 when not active) + char p0_idx = 0; + + for(char i=1;i<192;i++) { + // Wait for SYNC (halts CPU until end of scanline) + TIA->WSYNC = 0; + TIA->COLUBK = i; + if(p0_idx) { + // Player 0 is active - show it + char gfx = SPRITE_C[p0_idx]; + TIA->GRP0 = gfx; + if(gfx==0) + p0_idx = 0; + else + p0_idx++; + } else if(p0_ypos==i) + // Player 0 becomes active + p0_idx = 1; + } + + // Start OverScan + TIA->WSYNC = 0; // Wait for SYNC (halts CPU until end of scanline) + TIA->VBLANK = 2; // D1=1 turns image output off + TIA->COLUBK = 0; // Set background color to black + RIOT->TIM64T = (27*CYCLES_PER_SCANLINE)/64; // Set timer to wait 27 lines + + // Vertical Blank - game logic + // Since we have a timer running this may take variable time + + // Wait for the timer to run out + while(RIOT->INTIM) TIA->WSYNC = 0; + + } +} diff --git a/src/test/kc/inline-asm-ma-var.c b/src/test/kc/inline-asm-ma-var.c index 6cfa8d3a5..e6fe0ad31 100644 --- a/src/test/kc/inline-asm-ma-var.c +++ b/src/test/kc/inline-asm-ma-var.c @@ -13,5 +13,5 @@ void main() { eor value sta SCREEN } - } + } } diff --git a/src/test/ref/examples/atari2600/atari2600-demo.asm b/src/test/ref/examples/atari2600/atari2600-demo.asm index 015b7dab4..b611d0b8b 100644 --- a/src/test/ref/examples/atari2600/atari2600-demo.asm +++ b/src/test/ref/examples/atari2600/atari2600-demo.asm @@ -1,4 +1,4 @@ -// Demonstration Atari 2600 VCS Program +// Minimal Atari 2600 VCS Program // Source: https://atariage.com/forums/blogs/entry/11109-step-1-generate-a-stable-display/ // Atari 2600 VCS 2K ROM .file [name="atari2600-demo.a26", type="bin", segments="Code, Data, Vectors"] @@ -12,13 +12,34 @@ .word main // IRQ .segment Code + .const OFFSET_STRUCT_ATARI_TIA_WRITE_PF0 = $d + .const OFFSET_STRUCT_ATARI_TIA_WRITE_PF1 = $e + .const OFFSET_STRUCT_ATARI_TIA_WRITE_PF2 = $f + .const OFFSET_STRUCT_ATARI_TIA_WRITE_COLUPF = 8 + .const OFFSET_STRUCT_MOS6532_RIOT_TIM64T = $16 .const OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC = 2 + .const OFFSET_STRUCT_MOS6532_RIOT_INTIM = 4 .const OFFSET_STRUCT_ATARI_TIA_WRITE_VBLANK = 1 .const OFFSET_STRUCT_ATARI_TIA_WRITE_COLUBK = 9 + .const OFFSET_STRUCT_ATARI_TIA_WRITE_HMOVE = $2a // Atari TIA write registers .label TIA = 0 + // Atari RIOT registers + .label RIOT = $280 .segment Code main: { + // TIA->PF0 = 0b10100000 + lda #$a0 + sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_PF0 + // TIA->PF1 = 0b01010101 + lda #$55 + sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_PF1 + // TIA->PF2 = 0b10101010 + lda #$aa + sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_PF2 + // TIA->COLUPF = 0x55 + lda #$55 + sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_COLUPF lda #0 sta idx __b2: @@ -29,8 +50,12 @@ main: { // The Sync Signal must be on for 3 scanlines. lda #2 sta TIA + // RIOT->TIM64T = (41*76)/64 + // D1=1, turns on Vertical Sync signal + lda #$29*$4c/$40 + sta RIOT+OFFSET_STRUCT_MOS6532_RIOT_TIM64T // TIA->WSYNC = 0 - // Accumulator D1=1, turns on Vertical Sync signal + // Set timer to wait 41 lines lda #0 sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC // Wait for Sync - halts CPU until end of 1st scanline of VSYNC @@ -40,18 +65,16 @@ main: { // TIA->VSYNC = 0 // wait until end of 3rd scanline of VSYNC sta TIA - tax - // Vertical Blank - game logic - // Since we don't have any yet, just delay + // Wait for the timer to run out __b3: - // for(char i=0;i<37;i++) - cpx #$25 - bcc __b4 + // while(RIOT->INTIM) + lda #0 + cmp RIOT+OFFSET_STRUCT_MOS6532_RIOT_INTIM + bne __b4 // TIA->VBLANK = 0 // Screen - display logic - // Update the registers in TIA (the video chip) in order to generate what the player sees. + // Update the registers in TIA (the video chip) in order to generate what the player sees. // For now we're just going to output 192 colored scanlines lines so we have something to see. - lda #0 sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_VBLANK // c = SINTABLE[idx++] // D1=1, turns off Vertical Blank signal (image output on) @@ -64,8 +87,7 @@ main: { cpy #$c0 bcc __b7 // TIA->WSYNC = 0 - // Overscan - game logic - // Since we don't have any yet, just delay + // Start OverScan lda #0 sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC // TIA->VBLANK = 2 @@ -73,30 +95,41 @@ main: { lda #2 sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_VBLANK // TIA->COLUBK = 0 - // // D1=1 turns image output off + // D1=1 turns image output off lda #0 sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_COLUBK - tax + // RIOT->TIM64T = (27*76)/64 + // Set background color to black + lda #$1b*$4c/$40 + sta RIOT+OFFSET_STRUCT_MOS6532_RIOT_TIM64T + // Wait for the timer to run out __b9: - // for(char i=0;i<30;i++) - cpx #$1e - bcc __b10 + // while(RIOT->INTIM) + lda #0 + cmp RIOT+OFFSET_STRUCT_MOS6532_RIOT_INTIM + bne __b10 jmp __b2 __b10: // TIA->WSYNC = 0 lda #0 sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC - // for(char i=0;i<30;i++) - inx jmp __b9 __b7: - // TIA->WSYNC = 0 lda #0 sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC - // TIA->COLUBK = c++ + // TIA->COLUBK = c // Wait for SYNC (halts CPU until end of scanline) stx TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_COLUBK - // TIA->COLUBK = c++; + // TIA->PF0 = c + // Set background color + stx TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_PF0 + // TIA->PF1 = c + stx TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_PF1 + // TIA->PF2 = c + stx TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_PF2 + // TIA->HMOVE = c + stx TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_HMOVE + // c++; inx // for(char i=0;i<192;i++) iny @@ -105,12 +138,9 @@ main: { // TIA->WSYNC = 0 lda #0 sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC - // for(char i=0;i<37;i++) - inx jmp __b3 } .segment Data - .align $100 SINTABLE: .fill $100, round(127.5+127.5*sin(2*PI*i/256)) diff --git a/src/test/ref/examples/atari2600/atari2600-demo.cfg b/src/test/ref/examples/atari2600/atari2600-demo.cfg index b9395c569..57e83adbd 100644 --- a/src/test/ref/examples/atari2600/atari2600-demo.cfg +++ b/src/test/ref/examples/atari2600/atari2600-demo.cfg @@ -10,52 +10,57 @@ (void()) main() main: scope:[main] from @1 - [4] phi() + [4] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_PF0) ← (byte) $a0 + [5] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_PF1) ← (byte) $55 + [6] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_PF2) ← (byte) $aa + [7] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_COLUPF) ← (byte) $55 to:main::@1 main::@1: scope:[main] from main main::@9 - [5] (byte) idx#12 ← phi( main/(byte) 0 main::@9/(byte) idx#1 ) + [8] (byte) idx#12 ← phi( main/(byte) 0 main::@9/(byte) idx#1 ) to:main::@2 main::@2: scope:[main] from main::@1 - [6] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA) ← (byte) 2 - [7] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 - [8] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 - [9] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 - [10] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA) ← (byte) 0 + [9] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA) ← (byte) 2 + [10] *((byte*)(const nomodify struct MOS6532_RIOT*) RIOT+(const byte) OFFSET_STRUCT_MOS6532_RIOT_TIM64T) ← (byte)(number) $29*(number) $4c/(number) $40 + [11] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 + [12] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 + [13] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 + [14] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA) ← (byte) 0 to:main::@3 main::@3: scope:[main] from main::@2 main::@4 - [11] (byte) main::i#2 ← phi( main::@2/(byte) 0 main::@4/(byte) main::i#1 ) - [12] if((byte) main::i#2<(byte) $25) goto main::@4 + [15] if((byte) 0!=*((byte*)(const nomodify struct MOS6532_RIOT*) RIOT+(const byte) OFFSET_STRUCT_MOS6532_RIOT_INTIM)) goto main::@4 to:main::@5 main::@5: scope:[main] from main::@3 - [13] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_VBLANK) ← (byte) 0 - [14] (byte) main::c#0 ← *((const to_nomodify byte*) SINTABLE + (byte) idx#12) - [15] (byte) idx#1 ← ++ (byte) idx#12 + [16] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_VBLANK) ← (byte) 0 + [17] (byte) main::c#0 ← *((const to_nomodify byte*) SINTABLE + (byte) idx#12) + [18] (byte) idx#1 ← ++ (byte) idx#12 to:main::@6 main::@6: scope:[main] from main::@5 main::@7 - [16] (byte) main::c#2 ← phi( main::@5/(byte) main::c#0 main::@7/(byte) main::c#1 ) - [16] (byte) main::i1#2 ← phi( main::@5/(byte) 0 main::@7/(byte) main::i1#1 ) - [17] if((byte) main::i1#2<(byte) $c0) goto main::@7 + [19] (byte) main::c#2 ← phi( main::@5/(byte) main::c#0 main::@7/(byte) main::c#1 ) + [19] (byte) main::i#2 ← phi( main::@5/(byte) 0 main::@7/(byte) main::i#1 ) + [20] if((byte) main::i#2<(byte) $c0) goto main::@7 to:main::@8 main::@8: scope:[main] from main::@6 - [18] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 - [19] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_VBLANK) ← (byte) 2 - [20] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_COLUBK) ← (byte) 0 + [21] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 + [22] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_VBLANK) ← (byte) 2 + [23] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_COLUBK) ← (byte) 0 + [24] *((byte*)(const nomodify struct MOS6532_RIOT*) RIOT+(const byte) OFFSET_STRUCT_MOS6532_RIOT_TIM64T) ← (byte)(number) $1b*(number) $4c/(number) $40 to:main::@9 main::@9: scope:[main] from main::@10 main::@8 - [21] (byte) main::i2#2 ← phi( main::@10/(byte) main::i2#1 main::@8/(byte) 0 ) - [22] if((byte) main::i2#2<(byte) $1e) goto main::@10 + [25] if((byte) 0!=*((byte*)(const nomodify struct MOS6532_RIOT*) RIOT+(const byte) OFFSET_STRUCT_MOS6532_RIOT_INTIM)) goto main::@10 to:main::@1 main::@10: scope:[main] from main::@9 - [23] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 - [24] (byte) main::i2#1 ← ++ (byte) main::i2#2 + [26] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 to:main::@9 main::@7: scope:[main] from main::@6 - [25] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 - [26] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_COLUBK) ← (byte) main::c#2 - [27] (byte) main::c#1 ← ++ (byte) main::c#2 - [28] (byte) main::i1#1 ← ++ (byte) main::i1#2 + [27] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 + [28] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_COLUBK) ← (byte) main::c#2 + [29] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_PF0) ← (byte) main::c#2 + [30] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_PF1) ← (byte) main::c#2 + [31] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_PF2) ← (byte) main::c#2 + [32] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_HMOVE) ← (byte) main::c#2 + [33] (byte) main::c#1 ← ++ (byte) main::c#2 + [34] (byte) main::i#1 ← ++ (byte) main::i#2 to:main::@6 main::@4: scope:[main] from main::@3 - [29] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 - [30] (byte) main::i#1 ← ++ (byte) main::i#2 + [35] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 to:main::@3 diff --git a/src/test/ref/examples/atari2600/atari2600-demo.log b/src/test/ref/examples/atari2600/atari2600-demo.log index 7119a6db9..84ec031d5 100644 --- a/src/test/ref/examples/atari2600/atari2600-demo.log +++ b/src/test/ref/examples/atari2600/atari2600-demo.log @@ -10,74 +10,76 @@ CONTROL FLOW GRAPH SSA (void()) main() main: scope:[main] from @1 (byte) idx#10 ← phi( @1/(byte) idx#9 ) + *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_PF0) ← (number) $a0 + *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_PF1) ← (number) $55 + *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_PF2) ← (number) $aa + *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_COLUPF) ← (number) $55 to:main::@1 main::@1: scope:[main] from main main::@9 (byte) idx#8 ← phi( main/(byte) idx#10 main::@9/(byte) idx#11 ) - (bool~) main::$3 ← (number) 0 != (number) 1 - if((bool~) main::$3) goto main::@2 + (bool~) main::$1 ← (number) 0 != (number) 1 + if((bool~) main::$1) goto main::@2 to:main::@return main::@2: scope:[main] from main::@1 (byte) idx#12 ← phi( main::@1/(byte) idx#8 ) *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_VSYNC) ← (number) 2 + *((byte*)(const nomodify struct MOS6532_RIOT*) RIOT+(const byte) OFFSET_STRUCT_MOS6532_RIOT_TIM64T) ← (number) $29*(number) $4c/(number) $40 *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (number) 0 *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (number) 0 *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (number) 0 *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_VSYNC) ← (number) 0 - (byte) main::i#0 ← (byte) 0 to:main::@3 main::@3: scope:[main] from main::@2 main::@4 (byte) idx#7 ← phi( main::@2/(byte) idx#12 main::@4/(byte) idx#13 ) - (byte) main::i#2 ← phi( main::@2/(byte) main::i#0 main::@4/(byte) main::i#1 ) - (bool~) main::$0 ← (byte) main::i#2 < (number) $25 - if((bool~) main::$0) goto main::@4 + (bool~) main::$2 ← (number) 0 != *((byte*)(const nomodify struct MOS6532_RIOT*) RIOT+(const byte) OFFSET_STRUCT_MOS6532_RIOT_INTIM) + if((bool~) main::$2) goto main::@4 to:main::@5 main::@4: scope:[main] from main::@3 (byte) idx#13 ← phi( main::@3/(byte) idx#7 ) - (byte) main::i#3 ← phi( main::@3/(byte) main::i#2 ) *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (number) 0 - (byte) main::i#1 ← ++ (byte) main::i#3 to:main::@3 main::@5: scope:[main] from main::@3 (byte) idx#4 ← phi( main::@3/(byte) idx#7 ) *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_VBLANK) ← (number) 0 (byte) main::c#0 ← *((const to_nomodify byte*) SINTABLE + (byte) idx#4) (byte) idx#1 ← ++ (byte) idx#4 - (byte) main::i1#0 ← (byte) 0 + (byte) main::i#0 ← (byte) 0 to:main::@6 main::@6: scope:[main] from main::@5 main::@7 (byte) idx#16 ← phi( main::@5/(byte) idx#1 main::@7/(byte) idx#17 ) (byte) main::c#3 ← phi( main::@5/(byte) main::c#0 main::@7/(byte) main::c#1 ) - (byte) main::i1#2 ← phi( main::@5/(byte) main::i1#0 main::@7/(byte) main::i1#1 ) - (bool~) main::$1 ← (byte) main::i1#2 < (number) $c0 - if((bool~) main::$1) goto main::@7 + (byte) main::i#2 ← phi( main::@5/(byte) main::i#0 main::@7/(byte) main::i#1 ) + (bool~) main::$0 ← (byte) main::i#2 < (number) $c0 + if((bool~) main::$0) goto main::@7 to:main::@8 main::@7: scope:[main] from main::@6 (byte) idx#17 ← phi( main::@6/(byte) idx#16 ) - (byte) main::i1#3 ← phi( main::@6/(byte) main::i1#2 ) + (byte) main::i#3 ← phi( main::@6/(byte) main::i#2 ) (byte) main::c#2 ← phi( main::@6/(byte) main::c#3 ) *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (number) 0 *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_COLUBK) ← (byte) main::c#2 + *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_PF0) ← (byte) main::c#2 + *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_PF1) ← (byte) main::c#2 + *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_PF2) ← (byte) main::c#2 + *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_HMOVE) ← (byte) main::c#2 (byte) main::c#1 ← ++ (byte) main::c#2 - (byte) main::i1#1 ← ++ (byte) main::i1#3 + (byte) main::i#1 ← ++ (byte) main::i#3 to:main::@6 main::@8: scope:[main] from main::@6 (byte) idx#15 ← phi( main::@6/(byte) idx#16 ) *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (number) 0 *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_VBLANK) ← (number) 2 *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_COLUBK) ← (number) 0 - (byte) main::i2#0 ← (byte) 0 + *((byte*)(const nomodify struct MOS6532_RIOT*) RIOT+(const byte) OFFSET_STRUCT_MOS6532_RIOT_TIM64T) ← (number) $1b*(number) $4c/(number) $40 to:main::@9 main::@9: scope:[main] from main::@10 main::@8 (byte) idx#11 ← phi( main::@10/(byte) idx#14 main::@8/(byte) idx#15 ) - (byte) main::i2#2 ← phi( main::@10/(byte) main::i2#1 main::@8/(byte) main::i2#0 ) - (bool~) main::$2 ← (byte) main::i2#2 < (number) $1e - if((bool~) main::$2) goto main::@10 + (bool~) main::$3 ← (number) 0 != *((byte*)(const nomodify struct MOS6532_RIOT*) RIOT+(const byte) OFFSET_STRUCT_MOS6532_RIOT_INTIM) + if((bool~) main::$3) goto main::@10 to:main::@1 main::@10: scope:[main] from main::@9 (byte) idx#14 ← phi( main::@9/(byte) idx#11 ) - (byte) main::i2#3 ← phi( main::@9/(byte) main::i2#2 ) *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (number) 0 - (byte) main::i2#1 ← ++ (byte) main::i2#3 to:main::@9 main::@return: scope:[main] from main::@1 (byte) idx#5 ← phi( main::@1/(byte) idx#8 ) @@ -169,9 +171,17 @@ SYMBOL TABLE SSA (byte) MOS6532_RIOT::TIM8T (const byte*) MOS6532_RIOT::UNUSED[(number) $f] = { fill( $f, 0) } (const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_COLUBK = (byte) 9 +(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_COLUPF = (byte) 8 +(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_HMOVE = (byte) $2a +(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_PF0 = (byte) $d +(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_PF1 = (byte) $e +(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_PF2 = (byte) $f (const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_VBLANK = (byte) 1 (const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_VSYNC = (byte) 0 (const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC = (byte) 2 +(const byte) OFFSET_STRUCT_MOS6532_RIOT_INTIM = (byte) 4 +(const byte) OFFSET_STRUCT_MOS6532_RIOT_TIM64T = (byte) $16 +(const nomodify struct MOS6532_RIOT*) RIOT = (struct MOS6532_RIOT*)(number) $280 (const to_nomodify byte*) SINTABLE[(number) $100] = kickasm {{ .fill $100, round(127.5+127.5*sin(2*PI*i/256)) }} (const nomodify struct ATARI_TIA_WRITE*) TIA = (struct ATARI_TIA_WRITE*)(number) 0 @@ -220,34 +230,35 @@ SYMBOL TABLE SSA (byte) main::i#1 (byte) main::i#2 (byte) main::i#3 -(byte) main::i1 -(byte) main::i1#0 -(byte) main::i1#1 -(byte) main::i1#2 -(byte) main::i1#3 -(byte) main::i2 -(byte) main::i2#0 -(byte) main::i2#1 -(byte) main::i2#2 -(byte) main::i2#3 +Adding number conversion cast (unumber) $a0 in *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_PF0) ← (number) $a0 +Adding number conversion cast (unumber) $55 in *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_PF1) ← (number) $55 +Adding number conversion cast (unumber) $aa in *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_PF2) ← (number) $aa +Adding number conversion cast (unumber) $55 in *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_COLUPF) ← (number) $55 Adding number conversion cast (unumber) 2 in *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_VSYNC) ← (number) 2 +Adding number conversion cast (unumber) $29*$4c/$40 in *((byte*)(const nomodify struct MOS6532_RIOT*) RIOT+(const byte) OFFSET_STRUCT_MOS6532_RIOT_TIM64T) ← (number) $29*(number) $4c/(number) $40 Adding number conversion cast (unumber) 0 in *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (number) 0 Adding number conversion cast (unumber) 0 in *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (number) 0 Adding number conversion cast (unumber) 0 in *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (number) 0 Adding number conversion cast (unumber) 0 in *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_VSYNC) ← (number) 0 -Adding number conversion cast (unumber) $25 in (bool~) main::$0 ← (byte) main::i#2 < (number) $25 +Adding number conversion cast (unumber) 0 in (bool~) main::$2 ← (number) 0 != *((byte*)(const nomodify struct MOS6532_RIOT*) RIOT+(const byte) OFFSET_STRUCT_MOS6532_RIOT_INTIM) Adding number conversion cast (unumber) 0 in *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (number) 0 Adding number conversion cast (unumber) 0 in *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_VBLANK) ← (number) 0 -Adding number conversion cast (unumber) $c0 in (bool~) main::$1 ← (byte) main::i1#2 < (number) $c0 +Adding number conversion cast (unumber) $c0 in (bool~) main::$0 ← (byte) main::i#2 < (number) $c0 Adding number conversion cast (unumber) 0 in *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (number) 0 Adding number conversion cast (unumber) 0 in *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (number) 0 Adding number conversion cast (unumber) 2 in *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_VBLANK) ← (number) 2 Adding number conversion cast (unumber) 0 in *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_COLUBK) ← (number) 0 -Adding number conversion cast (unumber) $1e in (bool~) main::$2 ← (byte) main::i2#2 < (number) $1e +Adding number conversion cast (unumber) $1b*$4c/$40 in *((byte*)(const nomodify struct MOS6532_RIOT*) RIOT+(const byte) OFFSET_STRUCT_MOS6532_RIOT_TIM64T) ← (number) $1b*(number) $4c/(number) $40 +Adding number conversion cast (unumber) 0 in (bool~) main::$3 ← (number) 0 != *((byte*)(const nomodify struct MOS6532_RIOT*) RIOT+(const byte) OFFSET_STRUCT_MOS6532_RIOT_INTIM) Adding number conversion cast (unumber) 0 in *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (number) 0 Successful SSA optimization PassNAddNumberTypeConversions +Inlining cast *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_PF0) ← (unumber)(number) $a0 +Inlining cast *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_PF1) ← (unumber)(number) $55 +Inlining cast *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_PF2) ← (unumber)(number) $aa +Inlining cast *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_COLUPF) ← (unumber)(number) $55 Inlining cast *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_VSYNC) ← (unumber)(number) 2 +Inlining cast *((byte*)(const nomodify struct MOS6532_RIOT*) RIOT+(const byte) OFFSET_STRUCT_MOS6532_RIOT_TIM64T) ← (unumber)(number) $29*(number) $4c/(number) $40 Inlining cast *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (unumber)(number) 0 Inlining cast *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (unumber)(number) 0 Inlining cast *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (unumber)(number) 0 @@ -258,15 +269,21 @@ Inlining cast *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) Inlining cast *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (unumber)(number) 0 Inlining cast *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_VBLANK) ← (unumber)(number) 2 Inlining cast *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_COLUBK) ← (unumber)(number) 0 +Inlining cast *((byte*)(const nomodify struct MOS6532_RIOT*) RIOT+(const byte) OFFSET_STRUCT_MOS6532_RIOT_TIM64T) ← (unumber)(number) $1b*(number) $4c/(number) $40 Inlining cast *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (unumber)(number) 0 Successful SSA optimization Pass2InlineCast Simplifying constant pointer cast (struct ATARI_TIA_WRITE*) 0 +Simplifying constant pointer cast (struct MOS6532_RIOT*) 640 +Simplifying constant integer cast $a0 +Simplifying constant integer cast $55 +Simplifying constant integer cast $aa +Simplifying constant integer cast $55 Simplifying constant integer cast 2 Simplifying constant integer cast 0 Simplifying constant integer cast 0 Simplifying constant integer cast 0 Simplifying constant integer cast 0 -Simplifying constant integer cast $25 +Simplifying constant integer cast 0 Simplifying constant integer cast 0 Simplifying constant integer cast 0 Simplifying constant integer cast $c0 @@ -274,15 +291,19 @@ Simplifying constant integer cast 0 Simplifying constant integer cast 0 Simplifying constant integer cast 2 Simplifying constant integer cast 0 -Simplifying constant integer cast $1e +Simplifying constant integer cast 0 Simplifying constant integer cast 0 Successful SSA optimization PassNCastSimplification +Finalized unsigned number type (byte) $a0 +Finalized unsigned number type (byte) $55 +Finalized unsigned number type (byte) $aa +Finalized unsigned number type (byte) $55 Finalized unsigned number type (byte) 2 Finalized unsigned number type (byte) 0 Finalized unsigned number type (byte) 0 Finalized unsigned number type (byte) 0 Finalized unsigned number type (byte) 0 -Finalized unsigned number type (byte) $25 +Finalized unsigned number type (byte) 0 Finalized unsigned number type (byte) 0 Finalized unsigned number type (byte) 0 Finalized unsigned number type (byte) $c0 @@ -290,16 +311,14 @@ Finalized unsigned number type (byte) 0 Finalized unsigned number type (byte) 0 Finalized unsigned number type (byte) 2 Finalized unsigned number type (byte) 0 -Finalized unsigned number type (byte) $1e +Finalized unsigned number type (byte) 0 Finalized unsigned number type (byte) 0 Successful SSA optimization PassNFinalizeNumberTypeConversions Alias idx#12 = idx#8 idx#5 idx#2 -Alias main::i#2 = main::i#3 Alias idx#13 = idx#7 idx#4 Alias main::c#2 = main::c#3 -Alias main::i1#2 = main::i1#3 +Alias main::i#2 = main::i#3 Alias idx#15 = idx#17 idx#16 -Alias main::i2#2 = main::i2#3 Alias idx#11 = idx#14 Alias idx#0 = idx#9 Alias idx#3 = idx#6 @@ -310,32 +329,29 @@ Identical Phi Values (byte) idx#15 (byte) idx#1 Identical Phi Values (byte) idx#11 (byte) idx#15 Identical Phi Values (byte) idx#3 (byte) idx#12 Successful SSA optimization Pass2IdenticalPhiElimination -Simple Condition (bool~) main::$3 [4] if((number) 0!=(number) 1) goto main::@2 -Simple Condition (bool~) main::$0 [13] if((byte) main::i#2<(byte) $25) goto main::@4 -Simple Condition (bool~) main::$1 [22] if((byte) main::i1#2<(byte) $c0) goto main::@7 -Simple Condition (bool~) main::$2 [33] if((byte) main::i2#2<(byte) $1e) goto main::@10 +Simple Condition (bool~) main::$1 [8] if((number) 0!=(number) 1) goto main::@2 +Simple Condition (bool~) main::$2 [17] if((byte) 0!=*((byte*)(const nomodify struct MOS6532_RIOT*) RIOT+(const byte) OFFSET_STRUCT_MOS6532_RIOT_INTIM)) goto main::@4 +Simple Condition (bool~) main::$0 [25] if((byte) main::i#2<(byte) $c0) goto main::@7 +Simple Condition (bool~) main::$3 [40] if((byte) 0!=*((byte*)(const nomodify struct MOS6532_RIOT*) RIOT+(const byte) OFFSET_STRUCT_MOS6532_RIOT_INTIM)) goto main::@10 Successful SSA optimization Pass2ConditionalJumpSimplification +Constant right-side identified [10] *((byte*)(const nomodify struct MOS6532_RIOT*) RIOT+(const byte) OFFSET_STRUCT_MOS6532_RIOT_TIM64T) ← (unumber)(number) $29*(number) $4c/(number) $40 +Constant right-side identified [37] *((byte*)(const nomodify struct MOS6532_RIOT*) RIOT+(const byte) OFFSET_STRUCT_MOS6532_RIOT_TIM64T) ← (unumber)(number) $1b*(number) $4c/(number) $40 +Successful SSA optimization Pass2ConstantRValueConsolidation Constant (const byte) idx#0 = 0 Constant (const byte) main::i#0 = 0 -Constant (const byte) main::i1#0 = 0 -Constant (const byte) main::i2#0 = 0 Successful SSA optimization Pass2ConstantIdentification -if() condition always true - replacing block destination [4] if((number) 0!=(number) 1) goto main::@2 +if() condition always true - replacing block destination [8] if((number) 0!=(number) 1) goto main::@2 Successful SSA optimization Pass2ConstantIfs -Simplifying expression containing zero (byte*)TIA in [5] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_VSYNC) ← (byte) 2 -Simplifying expression containing zero (byte*)TIA in [9] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_VSYNC) ← (byte) 0 +Simplifying expression containing zero (byte*)TIA in [9] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_VSYNC) ← (byte) 2 +Simplifying expression containing zero (byte*)TIA in [14] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_VSYNC) ← (byte) 0 Successful SSA optimization PassNSimplifyExpressionWithZero Eliminating unused constant (const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_VSYNC Successful SSA optimization PassNEliminateUnusedVars Removing unused block main::@return Successful SSA optimization Pass2EliminateUnusedBlocks Inlining constant with var siblings (const byte) main::i#0 -Inlining constant with var siblings (const byte) main::i1#0 -Inlining constant with var siblings (const byte) main::i2#0 Inlining constant with var siblings (const byte) idx#0 Constant inlined main::i#0 = (byte) 0 -Constant inlined main::i1#0 = (byte) 0 -Constant inlined main::i2#0 = (byte) 0 Constant inlined idx#0 = (byte) 0 Successful SSA optimization Pass2ConstantInlining Added new block during phi lifting main::@11(between main::@9 and main::@1) @@ -343,24 +359,20 @@ 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 5 initial phi equivalence classes -Coalesced [17] main::c#4 ← main::c#0 -Coalesced [25] idx#18 ← idx#1 -Coalesced [28] main::i2#4 ← main::i2#1 -Coalesced [33] main::i1#4 ← main::i1#1 -Coalesced [34] main::c#5 ← main::c#1 -Coalesced [37] main::i#4 ← main::i#1 -Coalesced down to 5 phi equivalence classes +Created 3 initial phi equivalence classes +Coalesced [20] main::c#4 ← main::c#0 +Coalesced [28] idx#18 ← idx#1 +Coalesced [38] main::i#4 ← main::i#1 +Coalesced [39] main::c#5 ← main::c#1 +Coalesced down to 3 phi equivalence classes Culled Empty Block (label) @2 Culled Empty Block (label) main::@11 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 @@ -375,54 +387,59 @@ FINAL CONTROL FLOW GRAPH (void()) main() main: scope:[main] from @1 - [4] phi() + [4] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_PF0) ← (byte) $a0 + [5] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_PF1) ← (byte) $55 + [6] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_PF2) ← (byte) $aa + [7] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_COLUPF) ← (byte) $55 to:main::@1 main::@1: scope:[main] from main main::@9 - [5] (byte) idx#12 ← phi( main/(byte) 0 main::@9/(byte) idx#1 ) + [8] (byte) idx#12 ← phi( main/(byte) 0 main::@9/(byte) idx#1 ) to:main::@2 main::@2: scope:[main] from main::@1 - [6] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA) ← (byte) 2 - [7] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 - [8] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 - [9] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 - [10] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA) ← (byte) 0 + [9] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA) ← (byte) 2 + [10] *((byte*)(const nomodify struct MOS6532_RIOT*) RIOT+(const byte) OFFSET_STRUCT_MOS6532_RIOT_TIM64T) ← (byte)(number) $29*(number) $4c/(number) $40 + [11] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 + [12] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 + [13] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 + [14] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA) ← (byte) 0 to:main::@3 main::@3: scope:[main] from main::@2 main::@4 - [11] (byte) main::i#2 ← phi( main::@2/(byte) 0 main::@4/(byte) main::i#1 ) - [12] if((byte) main::i#2<(byte) $25) goto main::@4 + [15] if((byte) 0!=*((byte*)(const nomodify struct MOS6532_RIOT*) RIOT+(const byte) OFFSET_STRUCT_MOS6532_RIOT_INTIM)) goto main::@4 to:main::@5 main::@5: scope:[main] from main::@3 - [13] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_VBLANK) ← (byte) 0 - [14] (byte) main::c#0 ← *((const to_nomodify byte*) SINTABLE + (byte) idx#12) - [15] (byte) idx#1 ← ++ (byte) idx#12 + [16] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_VBLANK) ← (byte) 0 + [17] (byte) main::c#0 ← *((const to_nomodify byte*) SINTABLE + (byte) idx#12) + [18] (byte) idx#1 ← ++ (byte) idx#12 to:main::@6 main::@6: scope:[main] from main::@5 main::@7 - [16] (byte) main::c#2 ← phi( main::@5/(byte) main::c#0 main::@7/(byte) main::c#1 ) - [16] (byte) main::i1#2 ← phi( main::@5/(byte) 0 main::@7/(byte) main::i1#1 ) - [17] if((byte) main::i1#2<(byte) $c0) goto main::@7 + [19] (byte) main::c#2 ← phi( main::@5/(byte) main::c#0 main::@7/(byte) main::c#1 ) + [19] (byte) main::i#2 ← phi( main::@5/(byte) 0 main::@7/(byte) main::i#1 ) + [20] if((byte) main::i#2<(byte) $c0) goto main::@7 to:main::@8 main::@8: scope:[main] from main::@6 - [18] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 - [19] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_VBLANK) ← (byte) 2 - [20] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_COLUBK) ← (byte) 0 + [21] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 + [22] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_VBLANK) ← (byte) 2 + [23] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_COLUBK) ← (byte) 0 + [24] *((byte*)(const nomodify struct MOS6532_RIOT*) RIOT+(const byte) OFFSET_STRUCT_MOS6532_RIOT_TIM64T) ← (byte)(number) $1b*(number) $4c/(number) $40 to:main::@9 main::@9: scope:[main] from main::@10 main::@8 - [21] (byte) main::i2#2 ← phi( main::@10/(byte) main::i2#1 main::@8/(byte) 0 ) - [22] if((byte) main::i2#2<(byte) $1e) goto main::@10 + [25] if((byte) 0!=*((byte*)(const nomodify struct MOS6532_RIOT*) RIOT+(const byte) OFFSET_STRUCT_MOS6532_RIOT_INTIM)) goto main::@10 to:main::@1 main::@10: scope:[main] from main::@9 - [23] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 - [24] (byte) main::i2#1 ← ++ (byte) main::i2#2 + [26] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 to:main::@9 main::@7: scope:[main] from main::@6 - [25] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 - [26] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_COLUBK) ← (byte) main::c#2 - [27] (byte) main::c#1 ← ++ (byte) main::c#2 - [28] (byte) main::i1#1 ← ++ (byte) main::i1#2 + [27] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 + [28] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_COLUBK) ← (byte) main::c#2 + [29] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_PF0) ← (byte) main::c#2 + [30] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_PF1) ← (byte) main::c#2 + [31] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_PF2) ← (byte) main::c#2 + [32] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_HMOVE) ← (byte) main::c#2 + [33] (byte) main::c#1 ← ++ (byte) main::c#2 + [34] (byte) main::i#1 ← ++ (byte) main::i#2 to:main::@6 main::@4: scope:[main] from main::@3 - [29] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 - [30] (byte) main::i#1 ← ++ (byte) main::i#2 + [35] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 to:main::@3 @@ -496,45 +513,33 @@ VARIABLE REGISTER WEIGHTS (byte) MOS6532_RIOT::TIM64T (byte) MOS6532_RIOT::TIM8T (byte) idx -(byte) idx#1 78.71428571428571 -(byte) idx#12 100.25000000000001 +(byte) idx#1 64.82352941176471 +(byte) idx#12 109.36363636363637 (void()) main() (byte) main::c (byte) main::c#0 101.0 (byte) main::c#1 1001.0 -(byte) main::c#2 776.0 +(byte) main::c#2 888.5 (byte) main::i (byte) main::i#1 2002.0 -(byte) main::i#2 1001.0 -(byte) main::i1 -(byte) main::i1#1 2002.0 -(byte) main::i1#2 600.5999999999999 -(byte) main::i2 -(byte) main::i2#1 2002.0 -(byte) main::i2#2 1001.0 +(byte) main::i#2 333.6666666666667 Initial phi equivalence classes [ idx#12 idx#1 ] [ main::i#2 main::i#1 ] -[ main::i1#2 main::i1#1 ] [ main::c#2 main::c#0 main::c#1 ] -[ main::i2#2 main::i2#1 ] Complete equivalence classes [ idx#12 idx#1 ] [ main::i#2 main::i#1 ] -[ main::i1#2 main::i1#1 ] [ main::c#2 main::c#0 main::c#1 ] -[ main::i2#2 main::i2#1 ] Allocated mem[1] [ idx#12 idx#1 ] Allocated zp[1]:2 [ main::i#2 main::i#1 ] -Allocated zp[1]:3 [ main::i1#2 main::i1#1 ] -Allocated zp[1]:4 [ main::c#2 main::c#0 main::c#1 ] -Allocated zp[1]:5 [ main::i2#2 main::i2#1 ] +Allocated zp[1]:3 [ main::c#2 main::c#0 main::c#1 ] INITIAL ASM Target platform is atari2600 / MOS6502X // File Comments -// Demonstration Atari 2600 VCS Program +// Minimal Atari 2600 VCS Program // Source: https://atariage.com/forums/blogs/entry/11109-step-1-generate-a-stable-display/ // Upstart // Atari 2600 VCS 2K ROM @@ -550,11 +555,20 @@ Target platform is atari2600 / MOS6502X .segment Code // Global Constants & labels + .const OFFSET_STRUCT_ATARI_TIA_WRITE_PF0 = $d + .const OFFSET_STRUCT_ATARI_TIA_WRITE_PF1 = $e + .const OFFSET_STRUCT_ATARI_TIA_WRITE_PF2 = $f + .const OFFSET_STRUCT_ATARI_TIA_WRITE_COLUPF = 8 + .const OFFSET_STRUCT_MOS6532_RIOT_TIM64T = $16 .const OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC = 2 + .const OFFSET_STRUCT_MOS6532_RIOT_INTIM = 4 .const OFFSET_STRUCT_ATARI_TIA_WRITE_VBLANK = 1 .const OFFSET_STRUCT_ATARI_TIA_WRITE_COLUBK = 9 + .const OFFSET_STRUCT_ATARI_TIA_WRITE_HMOVE = $2a // Atari TIA write registers .label TIA = 0 + // Atari RIOT registers + .label RIOT = $280 // @begin __bbegin: // [1] phi from @begin to @1 [phi:@begin->@1] @@ -563,8 +577,6 @@ __b1_from___bbegin: // @1 __b1: // [2] call main - // [4] phi from @1 to main [phi:@1->main] -main_from___b1: jsr main // [3] phi from @1 to @end [phi:@1->@end] __bend_from___b1: @@ -574,13 +586,23 @@ __bend: .segment Code // main main: { + .label c = 3 .label i = 2 - .label c = 4 - .label i1 = 3 - .label i2 = 5 - // [5] phi from main to main::@1 [phi:main->main::@1] + // [4] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_PF0) ← (byte) $a0 -- _deref_pbuc1=vbuc2 + lda #$a0 + sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_PF0 + // [5] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_PF1) ← (byte) $55 -- _deref_pbuc1=vbuc2 + lda #$55 + sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_PF1 + // [6] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_PF2) ← (byte) $aa -- _deref_pbuc1=vbuc2 + lda #$aa + sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_PF2 + // [7] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_COLUPF) ← (byte) $55 -- _deref_pbuc1=vbuc2 + lda #$55 + sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_COLUPF + // [8] phi from main to main::@1 [phi:main->main::@1] __b1_from_main: - // [5] phi (byte) idx#12 = (byte) 0 [phi:main->main::@1#0] -- vbum1=vbuc1 + // [8] phi (byte) idx#12 = (byte) 0 [phi:main->main::@1#0] -- vbum1=vbuc1 lda #0 sta idx jmp __b1 @@ -589,148 +611,147 @@ main: { jmp __b2 // main::@2 __b2: - // [6] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA) ← (byte) 2 -- _deref_pbuc1=vbuc2 + // [9] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA) ← (byte) 2 -- _deref_pbuc1=vbuc2 // Vertical Sync // here we generate the signal that tells the TV to move the beam to the top of // the screen so we can start the next frame of video. // The Sync Signal must be on for 3 scanlines. lda #2 sta TIA - // [7] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 -- _deref_pbuc1=vbuc2 - // Accumulator D1=1, turns on Vertical Sync signal + // [10] *((byte*)(const nomodify struct MOS6532_RIOT*) RIOT+(const byte) OFFSET_STRUCT_MOS6532_RIOT_TIM64T) ← (byte)(number) $29*(number) $4c/(number) $40 -- _deref_pbuc1=vbuc2 + // D1=1, turns on Vertical Sync signal + lda #$29*$4c/$40 + sta RIOT+OFFSET_STRUCT_MOS6532_RIOT_TIM64T + // [11] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 -- _deref_pbuc1=vbuc2 + // Set timer to wait 41 lines lda #0 sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC - // [8] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 -- _deref_pbuc1=vbuc2 + // [12] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 -- _deref_pbuc1=vbuc2 // Wait for Sync - halts CPU until end of 1st scanline of VSYNC lda #0 sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC - // [9] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 -- _deref_pbuc1=vbuc2 + // [13] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 -- _deref_pbuc1=vbuc2 // wait until end of 2nd scanline of VSYNC lda #0 sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC - // [10] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA) ← (byte) 0 -- _deref_pbuc1=vbuc2 + // [14] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA) ← (byte) 0 -- _deref_pbuc1=vbuc2 // wait until end of 3rd scanline of VSYNC lda #0 sta TIA - // [11] phi from main::@2 to main::@3 [phi:main::@2->main::@3] - __b3_from___b2: - // [11] phi (byte) main::i#2 = (byte) 0 [phi:main::@2->main::@3#0] -- vbuz1=vbuc1 - lda #0 - sta.z i jmp __b3 - // Vertical Blank - game logic - // Since we don't have any yet, just delay + // Wait for the timer to run out // main::@3 __b3: - // [12] if((byte) main::i#2<(byte) $25) goto main::@4 -- vbuz1_lt_vbuc1_then_la1 - lda.z i - cmp #$25 - bcc __b4 + // [15] if((byte) 0!=*((byte*)(const nomodify struct MOS6532_RIOT*) RIOT+(const byte) OFFSET_STRUCT_MOS6532_RIOT_INTIM)) goto main::@4 -- vbuc1_neq__deref_pbuc2_then_la1 + lda #0 + cmp RIOT+OFFSET_STRUCT_MOS6532_RIOT_INTIM + bne __b4 jmp __b5 // main::@5 __b5: - // [13] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_VBLANK) ← (byte) 0 -- _deref_pbuc1=vbuc2 + // [16] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_VBLANK) ← (byte) 0 -- _deref_pbuc1=vbuc2 // Screen - display logic - // Update the registers in TIA (the video chip) in order to generate what the player sees. + // Update the registers in TIA (the video chip) in order to generate what the player sees. // For now we're just going to output 192 colored scanlines lines so we have something to see. lda #0 sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_VBLANK - // [14] (byte) main::c#0 ← *((const to_nomodify byte*) SINTABLE + (byte) idx#12) -- vbuz1=pbuc1_derefidx_vbum2 + // [17] (byte) main::c#0 ← *((const to_nomodify byte*) SINTABLE + (byte) idx#12) -- vbuz1=pbuc1_derefidx_vbum2 // D1=1, turns off Vertical Blank signal (image output on) ldy idx lda SINTABLE,y sta.z c - // [15] (byte) idx#1 ← ++ (byte) idx#12 -- vbum1=_inc_vbum1 + // [18] (byte) idx#1 ← ++ (byte) idx#12 -- vbum1=_inc_vbum1 inc idx - // [16] phi from main::@5 to main::@6 [phi:main::@5->main::@6] + // [19] phi from main::@5 to main::@6 [phi:main::@5->main::@6] __b6_from___b5: - // [16] phi (byte) main::c#2 = (byte) main::c#0 [phi:main::@5->main::@6#0] -- register_copy - // [16] phi (byte) main::i1#2 = (byte) 0 [phi:main::@5->main::@6#1] -- vbuz1=vbuc1 + // [19] phi (byte) main::c#2 = (byte) main::c#0 [phi:main::@5->main::@6#0] -- register_copy + // [19] phi (byte) main::i#2 = (byte) 0 [phi:main::@5->main::@6#1] -- vbuz1=vbuc1 lda #0 - sta.z i1 + sta.z i jmp __b6 // main::@6 __b6: - // [17] if((byte) main::i1#2<(byte) $c0) goto main::@7 -- vbuz1_lt_vbuc1_then_la1 - lda.z i1 + // [20] if((byte) main::i#2<(byte) $c0) goto main::@7 -- vbuz1_lt_vbuc1_then_la1 + lda.z i cmp #$c0 bcc __b7 jmp __b8 // main::@8 __b8: - // [18] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 -- _deref_pbuc1=vbuc2 - // Overscan - game logic - // Since we don't have any yet, just delay + // [21] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 -- _deref_pbuc1=vbuc2 + // Start OverScan lda #0 sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC - // [19] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_VBLANK) ← (byte) 2 -- _deref_pbuc1=vbuc2 + // [22] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_VBLANK) ← (byte) 2 -- _deref_pbuc1=vbuc2 // Wait for SYNC (halts CPU until end of scanline) lda #2 sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_VBLANK - // [20] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_COLUBK) ← (byte) 0 -- _deref_pbuc1=vbuc2 - // // D1=1 turns image output off + // [23] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_COLUBK) ← (byte) 0 -- _deref_pbuc1=vbuc2 + // D1=1 turns image output off lda #0 sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_COLUBK - // [21] phi from main::@8 to main::@9 [phi:main::@8->main::@9] - __b9_from___b8: - // [21] phi (byte) main::i2#2 = (byte) 0 [phi:main::@8->main::@9#0] -- vbuz1=vbuc1 - lda #0 - sta.z i2 + // [24] *((byte*)(const nomodify struct MOS6532_RIOT*) RIOT+(const byte) OFFSET_STRUCT_MOS6532_RIOT_TIM64T) ← (byte)(number) $1b*(number) $4c/(number) $40 -- _deref_pbuc1=vbuc2 + // Set background color to black + lda #$1b*$4c/$40 + sta RIOT+OFFSET_STRUCT_MOS6532_RIOT_TIM64T jmp __b9 + // Wait for the timer to run out // main::@9 __b9: - // [22] if((byte) main::i2#2<(byte) $1e) goto main::@10 -- vbuz1_lt_vbuc1_then_la1 - lda.z i2 - cmp #$1e - bcc __b10 - // [5] phi from main::@9 to main::@1 [phi:main::@9->main::@1] + // [25] if((byte) 0!=*((byte*)(const nomodify struct MOS6532_RIOT*) RIOT+(const byte) OFFSET_STRUCT_MOS6532_RIOT_INTIM)) goto main::@10 -- vbuc1_neq__deref_pbuc2_then_la1 + lda #0 + cmp RIOT+OFFSET_STRUCT_MOS6532_RIOT_INTIM + bne __b10 + // [8] phi from main::@9 to main::@1 [phi:main::@9->main::@1] __b1_from___b9: - // [5] phi (byte) idx#12 = (byte) idx#1 [phi:main::@9->main::@1#0] -- register_copy + // [8] phi (byte) idx#12 = (byte) idx#1 [phi:main::@9->main::@1#0] -- register_copy jmp __b1 // main::@10 __b10: - // [23] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 -- _deref_pbuc1=vbuc2 + // [26] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 -- _deref_pbuc1=vbuc2 lda #0 sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC - // [24] (byte) main::i2#1 ← ++ (byte) main::i2#2 -- vbuz1=_inc_vbuz1 - inc.z i2 - // [21] phi from main::@10 to main::@9 [phi:main::@10->main::@9] - __b9_from___b10: - // [21] phi (byte) main::i2#2 = (byte) main::i2#1 [phi:main::@10->main::@9#0] -- register_copy jmp __b9 // main::@7 __b7: - // [25] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 -- _deref_pbuc1=vbuc2 + // [27] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 -- _deref_pbuc1=vbuc2 lda #0 sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC - // [26] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_COLUBK) ← (byte) main::c#2 -- _deref_pbuc1=vbuz1 + // [28] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_COLUBK) ← (byte) main::c#2 -- _deref_pbuc1=vbuz1 // Wait for SYNC (halts CPU until end of scanline) lda.z c sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_COLUBK - // [27] (byte) main::c#1 ← ++ (byte) main::c#2 -- vbuz1=_inc_vbuz1 + // [29] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_PF0) ← (byte) main::c#2 -- _deref_pbuc1=vbuz1 + // Set background color + lda.z c + sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_PF0 + // [30] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_PF1) ← (byte) main::c#2 -- _deref_pbuc1=vbuz1 + lda.z c + sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_PF1 + // [31] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_PF2) ← (byte) main::c#2 -- _deref_pbuc1=vbuz1 + lda.z c + sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_PF2 + // [32] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_HMOVE) ← (byte) main::c#2 -- _deref_pbuc1=vbuz1 + lda.z c + sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_HMOVE + // [33] (byte) main::c#1 ← ++ (byte) main::c#2 -- vbuz1=_inc_vbuz1 inc.z c - // [28] (byte) main::i1#1 ← ++ (byte) main::i1#2 -- vbuz1=_inc_vbuz1 - inc.z i1 - // [16] phi from main::@7 to main::@6 [phi:main::@7->main::@6] + // [34] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuz1=_inc_vbuz1 + inc.z i + // [19] phi from main::@7 to main::@6 [phi:main::@7->main::@6] __b6_from___b7: - // [16] phi (byte) main::c#2 = (byte) main::c#1 [phi:main::@7->main::@6#0] -- register_copy - // [16] phi (byte) main::i1#2 = (byte) main::i1#1 [phi:main::@7->main::@6#1] -- register_copy + // [19] phi (byte) main::c#2 = (byte) main::c#1 [phi:main::@7->main::@6#0] -- register_copy + // [19] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@7->main::@6#1] -- register_copy jmp __b6 // main::@4 __b4: - // [29] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 -- _deref_pbuc1=vbuc2 + // [35] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 -- _deref_pbuc1=vbuc2 lda #0 sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC - // [30] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuz1=_inc_vbuz1 - inc.z i - // [11] phi from main::@4 to main::@3 [phi:main::@4->main::@3] - __b3_from___b4: - // [11] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@4->main::@3#0] -- register_copy jmp __b3 } // File Data .segment Data - .align $100 SINTABLE: .fill $100, round(127.5+127.5*sin(2*PI*i/256)) @@ -738,59 +759,71 @@ SINTABLE: idx: .byte 0 REGISTER UPLIFT POTENTIAL REGISTERS -Statement [6] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA) ← (byte) 2 [ idx#12 ] ( main:2 [ idx#12 ] { } ) always clobbers reg byte a +Statement [4] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_PF0) ← (byte) $a0 [ ] ( main:2 [ ] { } ) always clobbers reg byte a +Statement [5] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_PF1) ← (byte) $55 [ ] ( main:2 [ ] { } ) always clobbers reg byte a +Statement [6] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_PF2) ← (byte) $aa [ ] ( main:2 [ ] { } ) always clobbers reg byte a +Statement [7] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_COLUPF) ← (byte) $55 [ ] ( main:2 [ ] { } ) always clobbers reg byte a +Statement [9] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA) ← (byte) 2 [ idx#12 ] ( main:2 [ idx#12 ] { } ) always clobbers reg byte a Removing always clobbered register reg byte a as potential for mem[1] [ idx#12 idx#1 ] -Statement [7] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 [ idx#12 ] ( main:2 [ idx#12 ] { } ) always clobbers reg byte a -Statement [8] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 [ idx#12 ] ( main:2 [ idx#12 ] { } ) always clobbers reg byte a -Statement [9] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 [ idx#12 ] ( main:2 [ idx#12 ] { } ) always clobbers reg byte a -Statement [10] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA) ← (byte) 0 [ idx#12 ] ( main:2 [ idx#12 ] { } ) always clobbers reg byte a -Statement [13] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_VBLANK) ← (byte) 0 [ idx#12 ] ( main:2 [ idx#12 ] { } ) always clobbers reg byte a -Statement [18] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 [ idx#1 ] ( main:2 [ idx#1 ] { } ) always clobbers reg byte a -Statement [19] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_VBLANK) ← (byte) 2 [ idx#1 ] ( main:2 [ idx#1 ] { } ) always clobbers reg byte a -Statement [20] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_COLUBK) ← (byte) 0 [ idx#1 ] ( main:2 [ idx#1 ] { } ) always clobbers reg byte a -Statement [23] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 [ idx#1 main::i2#2 ] ( main:2 [ idx#1 main::i2#2 ] { } ) always clobbers reg byte a -Removing always clobbered register reg byte a as potential for zp[1]:5 [ main::i2#2 main::i2#1 ] -Statement [25] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 [ idx#1 main::i1#2 main::c#2 ] ( main:2 [ idx#1 main::i1#2 main::c#2 ] { } ) always clobbers reg byte a -Removing always clobbered register reg byte a as potential for zp[1]:3 [ main::i1#2 main::i1#1 ] -Removing always clobbered register reg byte a as potential for zp[1]:4 [ main::c#2 main::c#0 main::c#1 ] -Statement [29] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 [ idx#12 main::i#2 ] ( main:2 [ idx#12 main::i#2 ] { } ) always clobbers reg byte a +Statement [10] *((byte*)(const nomodify struct MOS6532_RIOT*) RIOT+(const byte) OFFSET_STRUCT_MOS6532_RIOT_TIM64T) ← (byte)(number) $29*(number) $4c/(number) $40 [ idx#12 ] ( main:2 [ idx#12 ] { } ) always clobbers reg byte a +Statement [11] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 [ idx#12 ] ( main:2 [ idx#12 ] { } ) always clobbers reg byte a +Statement [12] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 [ idx#12 ] ( main:2 [ idx#12 ] { } ) always clobbers reg byte a +Statement [13] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 [ idx#12 ] ( main:2 [ idx#12 ] { } ) always clobbers reg byte a +Statement [14] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA) ← (byte) 0 [ idx#12 ] ( main:2 [ idx#12 ] { } ) always clobbers reg byte a +Statement [15] if((byte) 0!=*((byte*)(const nomodify struct MOS6532_RIOT*) RIOT+(const byte) OFFSET_STRUCT_MOS6532_RIOT_INTIM)) goto main::@4 [ idx#12 ] ( main:2 [ idx#12 ] { } ) always clobbers reg byte a +Statement [16] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_VBLANK) ← (byte) 0 [ idx#12 ] ( main:2 [ idx#12 ] { } ) always clobbers reg byte a +Statement [21] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 [ idx#1 ] ( main:2 [ idx#1 ] { } ) always clobbers reg byte a +Statement [22] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_VBLANK) ← (byte) 2 [ idx#1 ] ( main:2 [ idx#1 ] { } ) always clobbers reg byte a +Statement [23] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_COLUBK) ← (byte) 0 [ idx#1 ] ( main:2 [ idx#1 ] { } ) always clobbers reg byte a +Statement [24] *((byte*)(const nomodify struct MOS6532_RIOT*) RIOT+(const byte) OFFSET_STRUCT_MOS6532_RIOT_TIM64T) ← (byte)(number) $1b*(number) $4c/(number) $40 [ idx#1 ] ( main:2 [ idx#1 ] { } ) always clobbers reg byte a +Statement [25] if((byte) 0!=*((byte*)(const nomodify struct MOS6532_RIOT*) RIOT+(const byte) OFFSET_STRUCT_MOS6532_RIOT_INTIM)) goto main::@10 [ idx#1 ] ( main:2 [ idx#1 ] { } ) always clobbers reg byte a +Statement [26] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 [ idx#1 ] ( main:2 [ idx#1 ] { } ) always clobbers reg byte a +Statement [27] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 [ idx#1 main::i#2 main::c#2 ] ( main:2 [ idx#1 main::i#2 main::c#2 ] { } ) always clobbers reg byte a Removing always clobbered register reg byte a as potential for zp[1]:2 [ main::i#2 main::i#1 ] -Statement [6] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA) ← (byte) 2 [ idx#12 ] ( main:2 [ idx#12 ] { } ) always clobbers reg byte a -Statement [7] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 [ idx#12 ] ( main:2 [ idx#12 ] { } ) always clobbers reg byte a -Statement [8] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 [ idx#12 ] ( main:2 [ idx#12 ] { } ) always clobbers reg byte a -Statement [9] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 [ idx#12 ] ( main:2 [ idx#12 ] { } ) always clobbers reg byte a -Statement [10] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA) ← (byte) 0 [ idx#12 ] ( main:2 [ idx#12 ] { } ) always clobbers reg byte a -Statement [13] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_VBLANK) ← (byte) 0 [ idx#12 ] ( main:2 [ idx#12 ] { } ) always clobbers reg byte a -Statement [18] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 [ idx#1 ] ( main:2 [ idx#1 ] { } ) always clobbers reg byte a -Statement [19] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_VBLANK) ← (byte) 2 [ idx#1 ] ( main:2 [ idx#1 ] { } ) always clobbers reg byte a -Statement [20] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_COLUBK) ← (byte) 0 [ idx#1 ] ( main:2 [ idx#1 ] { } ) always clobbers reg byte a -Statement [23] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 [ idx#1 main::i2#2 ] ( main:2 [ idx#1 main::i2#2 ] { } ) always clobbers reg byte a -Statement [25] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 [ idx#1 main::i1#2 main::c#2 ] ( main:2 [ idx#1 main::i1#2 main::c#2 ] { } ) always clobbers reg byte a -Statement [29] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 [ idx#12 main::i#2 ] ( main:2 [ idx#12 main::i#2 ] { } ) always clobbers reg byte a +Removing always clobbered register reg byte a as potential for zp[1]:3 [ main::c#2 main::c#0 main::c#1 ] +Statement [35] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 [ idx#12 ] ( main:2 [ idx#12 ] { } ) always clobbers reg byte a +Statement [4] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_PF0) ← (byte) $a0 [ ] ( main:2 [ ] { } ) always clobbers reg byte a +Statement [5] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_PF1) ← (byte) $55 [ ] ( main:2 [ ] { } ) always clobbers reg byte a +Statement [6] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_PF2) ← (byte) $aa [ ] ( main:2 [ ] { } ) always clobbers reg byte a +Statement [7] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_COLUPF) ← (byte) $55 [ ] ( main:2 [ ] { } ) always clobbers reg byte a +Statement [9] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA) ← (byte) 2 [ idx#12 ] ( main:2 [ idx#12 ] { } ) always clobbers reg byte a +Statement [10] *((byte*)(const nomodify struct MOS6532_RIOT*) RIOT+(const byte) OFFSET_STRUCT_MOS6532_RIOT_TIM64T) ← (byte)(number) $29*(number) $4c/(number) $40 [ idx#12 ] ( main:2 [ idx#12 ] { } ) always clobbers reg byte a +Statement [11] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 [ idx#12 ] ( main:2 [ idx#12 ] { } ) always clobbers reg byte a +Statement [12] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 [ idx#12 ] ( main:2 [ idx#12 ] { } ) always clobbers reg byte a +Statement [13] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 [ idx#12 ] ( main:2 [ idx#12 ] { } ) always clobbers reg byte a +Statement [14] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA) ← (byte) 0 [ idx#12 ] ( main:2 [ idx#12 ] { } ) always clobbers reg byte a +Statement [15] if((byte) 0!=*((byte*)(const nomodify struct MOS6532_RIOT*) RIOT+(const byte) OFFSET_STRUCT_MOS6532_RIOT_INTIM)) goto main::@4 [ idx#12 ] ( main:2 [ idx#12 ] { } ) always clobbers reg byte a +Statement [16] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_VBLANK) ← (byte) 0 [ idx#12 ] ( main:2 [ idx#12 ] { } ) always clobbers reg byte a +Statement [21] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 [ idx#1 ] ( main:2 [ idx#1 ] { } ) always clobbers reg byte a +Statement [22] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_VBLANK) ← (byte) 2 [ idx#1 ] ( main:2 [ idx#1 ] { } ) always clobbers reg byte a +Statement [23] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_COLUBK) ← (byte) 0 [ idx#1 ] ( main:2 [ idx#1 ] { } ) always clobbers reg byte a +Statement [24] *((byte*)(const nomodify struct MOS6532_RIOT*) RIOT+(const byte) OFFSET_STRUCT_MOS6532_RIOT_TIM64T) ← (byte)(number) $1b*(number) $4c/(number) $40 [ idx#1 ] ( main:2 [ idx#1 ] { } ) always clobbers reg byte a +Statement [25] if((byte) 0!=*((byte*)(const nomodify struct MOS6532_RIOT*) RIOT+(const byte) OFFSET_STRUCT_MOS6532_RIOT_INTIM)) goto main::@10 [ idx#1 ] ( main:2 [ idx#1 ] { } ) always clobbers reg byte a +Statement [26] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 [ idx#1 ] ( main:2 [ idx#1 ] { } ) always clobbers reg byte a +Statement [27] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 [ idx#1 main::i#2 main::c#2 ] ( main:2 [ idx#1 main::i#2 main::c#2 ] { } ) always clobbers reg byte a +Statement [35] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 [ idx#12 ] ( main:2 [ idx#12 ] { } ) always clobbers reg byte a Potential registers mem[1] [ idx#12 idx#1 ] : mem[1] , reg byte x , reg byte y , Potential registers zp[1]:2 [ main::i#2 main::i#1 ] : zp[1]:2 , reg byte x , reg byte y , -Potential registers zp[1]:3 [ main::i1#2 main::i1#1 ] : zp[1]:3 , reg byte x , reg byte y , -Potential registers zp[1]:4 [ main::c#2 main::c#0 main::c#1 ] : zp[1]:4 , reg byte x , reg byte y , -Potential registers zp[1]:5 [ main::i2#2 main::i2#1 ] : zp[1]:5 , reg byte x , reg byte y , +Potential registers zp[1]:3 [ main::c#2 main::c#0 main::c#1 ] : zp[1]:3 , reg byte x , reg byte y , REGISTER UPLIFT SCOPES -Uplift Scope [main] 3,003: zp[1]:2 [ main::i#2 main::i#1 ] 3,003: zp[1]:5 [ main::i2#2 main::i2#1 ] 2,602.6: zp[1]:3 [ main::i1#2 main::i1#1 ] 1,878: zp[1]:4 [ main::c#2 main::c#0 main::c#1 ] -Uplift Scope [] 178.96: mem[1] [ idx#12 idx#1 ] +Uplift Scope [main] 2,335.67: zp[1]:2 [ main::i#2 main::i#1 ] 1,990.5: zp[1]:3 [ main::c#2 main::c#0 main::c#1 ] +Uplift Scope [] 174.19: mem[1] [ idx#12 idx#1 ] Uplift Scope [ATARI_TIA_WRITE] Uplift Scope [ATARI_TIA_READ] Uplift Scope [MOS6532_RIOT] -Uplifting [main] best 8197 combination reg byte x [ main::i#2 main::i#1 ] reg byte x [ main::i2#2 main::i2#1 ] reg byte y [ main::i1#2 main::i1#1 ] reg byte x [ main::c#2 main::c#0 main::c#1 ] -Uplifting [] best 8197 combination mem[1] [ idx#12 idx#1 ] -Uplifting [ATARI_TIA_WRITE] best 8197 combination -Uplifting [ATARI_TIA_READ] best 8197 combination -Uplifting [MOS6532_RIOT] best 8197 combination +Uplifting [main] best 9401 combination reg byte y [ main::i#2 main::i#1 ] reg byte x [ main::c#2 main::c#0 main::c#1 ] +Uplifting [] best 9401 combination mem[1] [ idx#12 idx#1 ] +Uplifting [ATARI_TIA_WRITE] best 9401 combination +Uplifting [ATARI_TIA_READ] best 9401 combination +Uplifting [MOS6532_RIOT] best 9401 combination Attempting to uplift remaining variables inmem[1] [ idx#12 idx#1 ] -Uplifting [] best 8197 combination mem[1] [ idx#12 idx#1 ] +Uplifting [] best 9401 combination mem[1] [ idx#12 idx#1 ] ASSEMBLER BEFORE OPTIMIZATION // File Comments -// Demonstration Atari 2600 VCS Program +// Minimal Atari 2600 VCS Program // Source: https://atariage.com/forums/blogs/entry/11109-step-1-generate-a-stable-display/ // Upstart // Atari 2600 VCS 2K ROM @@ -806,11 +839,20 @@ ASSEMBLER BEFORE OPTIMIZATION .segment Code // Global Constants & labels + .const OFFSET_STRUCT_ATARI_TIA_WRITE_PF0 = $d + .const OFFSET_STRUCT_ATARI_TIA_WRITE_PF1 = $e + .const OFFSET_STRUCT_ATARI_TIA_WRITE_PF2 = $f + .const OFFSET_STRUCT_ATARI_TIA_WRITE_COLUPF = 8 + .const OFFSET_STRUCT_MOS6532_RIOT_TIM64T = $16 .const OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC = 2 + .const OFFSET_STRUCT_MOS6532_RIOT_INTIM = 4 .const OFFSET_STRUCT_ATARI_TIA_WRITE_VBLANK = 1 .const OFFSET_STRUCT_ATARI_TIA_WRITE_COLUBK = 9 + .const OFFSET_STRUCT_ATARI_TIA_WRITE_HMOVE = $2a // Atari TIA write registers .label TIA = 0 + // Atari RIOT registers + .label RIOT = $280 // @begin __bbegin: // [1] phi from @begin to @1 [phi:@begin->@1] @@ -819,8 +861,6 @@ __b1_from___bbegin: // @1 __b1: // [2] call main - // [4] phi from @1 to main [phi:@1->main] -main_from___b1: jsr main // [3] phi from @1 to @end [phi:@1->@end] __bend_from___b1: @@ -830,9 +870,21 @@ __bend: .segment Code // main main: { - // [5] phi from main to main::@1 [phi:main->main::@1] + // [4] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_PF0) ← (byte) $a0 -- _deref_pbuc1=vbuc2 + lda #$a0 + sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_PF0 + // [5] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_PF1) ← (byte) $55 -- _deref_pbuc1=vbuc2 + lda #$55 + sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_PF1 + // [6] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_PF2) ← (byte) $aa -- _deref_pbuc1=vbuc2 + lda #$aa + sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_PF2 + // [7] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_COLUPF) ← (byte) $55 -- _deref_pbuc1=vbuc2 + lda #$55 + sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_COLUPF + // [8] phi from main to main::@1 [phi:main->main::@1] __b1_from_main: - // [5] phi (byte) idx#12 = (byte) 0 [phi:main->main::@1#0] -- vbum1=vbuc1 + // [8] phi (byte) idx#12 = (byte) 0 [phi:main->main::@1#0] -- vbum1=vbuc1 lda #0 sta idx jmp __b1 @@ -841,140 +893,139 @@ main: { jmp __b2 // main::@2 __b2: - // [6] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA) ← (byte) 2 -- _deref_pbuc1=vbuc2 + // [9] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA) ← (byte) 2 -- _deref_pbuc1=vbuc2 // Vertical Sync // here we generate the signal that tells the TV to move the beam to the top of // the screen so we can start the next frame of video. // The Sync Signal must be on for 3 scanlines. lda #2 sta TIA - // [7] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 -- _deref_pbuc1=vbuc2 - // Accumulator D1=1, turns on Vertical Sync signal + // [10] *((byte*)(const nomodify struct MOS6532_RIOT*) RIOT+(const byte) OFFSET_STRUCT_MOS6532_RIOT_TIM64T) ← (byte)(number) $29*(number) $4c/(number) $40 -- _deref_pbuc1=vbuc2 + // D1=1, turns on Vertical Sync signal + lda #$29*$4c/$40 + sta RIOT+OFFSET_STRUCT_MOS6532_RIOT_TIM64T + // [11] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 -- _deref_pbuc1=vbuc2 + // Set timer to wait 41 lines lda #0 sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC - // [8] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 -- _deref_pbuc1=vbuc2 + // [12] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 -- _deref_pbuc1=vbuc2 // Wait for Sync - halts CPU until end of 1st scanline of VSYNC lda #0 sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC - // [9] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 -- _deref_pbuc1=vbuc2 + // [13] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 -- _deref_pbuc1=vbuc2 // wait until end of 2nd scanline of VSYNC lda #0 sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC - // [10] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA) ← (byte) 0 -- _deref_pbuc1=vbuc2 + // [14] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA) ← (byte) 0 -- _deref_pbuc1=vbuc2 // wait until end of 3rd scanline of VSYNC lda #0 sta TIA - // [11] phi from main::@2 to main::@3 [phi:main::@2->main::@3] - __b3_from___b2: - // [11] phi (byte) main::i#2 = (byte) 0 [phi:main::@2->main::@3#0] -- vbuxx=vbuc1 - ldx #0 jmp __b3 - // Vertical Blank - game logic - // Since we don't have any yet, just delay + // Wait for the timer to run out // main::@3 __b3: - // [12] if((byte) main::i#2<(byte) $25) goto main::@4 -- vbuxx_lt_vbuc1_then_la1 - cpx #$25 - bcc __b4 + // [15] if((byte) 0!=*((byte*)(const nomodify struct MOS6532_RIOT*) RIOT+(const byte) OFFSET_STRUCT_MOS6532_RIOT_INTIM)) goto main::@4 -- vbuc1_neq__deref_pbuc2_then_la1 + lda #0 + cmp RIOT+OFFSET_STRUCT_MOS6532_RIOT_INTIM + bne __b4 jmp __b5 // main::@5 __b5: - // [13] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_VBLANK) ← (byte) 0 -- _deref_pbuc1=vbuc2 + // [16] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_VBLANK) ← (byte) 0 -- _deref_pbuc1=vbuc2 // Screen - display logic - // Update the registers in TIA (the video chip) in order to generate what the player sees. + // Update the registers in TIA (the video chip) in order to generate what the player sees. // For now we're just going to output 192 colored scanlines lines so we have something to see. lda #0 sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_VBLANK - // [14] (byte) main::c#0 ← *((const to_nomodify byte*) SINTABLE + (byte) idx#12) -- vbuxx=pbuc1_derefidx_vbum1 + // [17] (byte) main::c#0 ← *((const to_nomodify byte*) SINTABLE + (byte) idx#12) -- vbuxx=pbuc1_derefidx_vbum1 // D1=1, turns off Vertical Blank signal (image output on) ldy idx ldx SINTABLE,y - // [15] (byte) idx#1 ← ++ (byte) idx#12 -- vbum1=_inc_vbum1 + // [18] (byte) idx#1 ← ++ (byte) idx#12 -- vbum1=_inc_vbum1 inc idx - // [16] phi from main::@5 to main::@6 [phi:main::@5->main::@6] + // [19] phi from main::@5 to main::@6 [phi:main::@5->main::@6] __b6_from___b5: - // [16] phi (byte) main::c#2 = (byte) main::c#0 [phi:main::@5->main::@6#0] -- register_copy - // [16] phi (byte) main::i1#2 = (byte) 0 [phi:main::@5->main::@6#1] -- vbuyy=vbuc1 + // [19] phi (byte) main::c#2 = (byte) main::c#0 [phi:main::@5->main::@6#0] -- register_copy + // [19] phi (byte) main::i#2 = (byte) 0 [phi:main::@5->main::@6#1] -- vbuyy=vbuc1 ldy #0 jmp __b6 // main::@6 __b6: - // [17] if((byte) main::i1#2<(byte) $c0) goto main::@7 -- vbuyy_lt_vbuc1_then_la1 + // [20] if((byte) main::i#2<(byte) $c0) goto main::@7 -- vbuyy_lt_vbuc1_then_la1 cpy #$c0 bcc __b7 jmp __b8 // main::@8 __b8: - // [18] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 -- _deref_pbuc1=vbuc2 - // Overscan - game logic - // Since we don't have any yet, just delay + // [21] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 -- _deref_pbuc1=vbuc2 + // Start OverScan lda #0 sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC - // [19] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_VBLANK) ← (byte) 2 -- _deref_pbuc1=vbuc2 + // [22] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_VBLANK) ← (byte) 2 -- _deref_pbuc1=vbuc2 // Wait for SYNC (halts CPU until end of scanline) lda #2 sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_VBLANK - // [20] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_COLUBK) ← (byte) 0 -- _deref_pbuc1=vbuc2 - // // D1=1 turns image output off + // [23] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_COLUBK) ← (byte) 0 -- _deref_pbuc1=vbuc2 + // D1=1 turns image output off lda #0 sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_COLUBK - // [21] phi from main::@8 to main::@9 [phi:main::@8->main::@9] - __b9_from___b8: - // [21] phi (byte) main::i2#2 = (byte) 0 [phi:main::@8->main::@9#0] -- vbuxx=vbuc1 - ldx #0 + // [24] *((byte*)(const nomodify struct MOS6532_RIOT*) RIOT+(const byte) OFFSET_STRUCT_MOS6532_RIOT_TIM64T) ← (byte)(number) $1b*(number) $4c/(number) $40 -- _deref_pbuc1=vbuc2 + // Set background color to black + lda #$1b*$4c/$40 + sta RIOT+OFFSET_STRUCT_MOS6532_RIOT_TIM64T jmp __b9 + // Wait for the timer to run out // main::@9 __b9: - // [22] if((byte) main::i2#2<(byte) $1e) goto main::@10 -- vbuxx_lt_vbuc1_then_la1 - cpx #$1e - bcc __b10 - // [5] phi from main::@9 to main::@1 [phi:main::@9->main::@1] + // [25] if((byte) 0!=*((byte*)(const nomodify struct MOS6532_RIOT*) RIOT+(const byte) OFFSET_STRUCT_MOS6532_RIOT_INTIM)) goto main::@10 -- vbuc1_neq__deref_pbuc2_then_la1 + lda #0 + cmp RIOT+OFFSET_STRUCT_MOS6532_RIOT_INTIM + bne __b10 + // [8] phi from main::@9 to main::@1 [phi:main::@9->main::@1] __b1_from___b9: - // [5] phi (byte) idx#12 = (byte) idx#1 [phi:main::@9->main::@1#0] -- register_copy + // [8] phi (byte) idx#12 = (byte) idx#1 [phi:main::@9->main::@1#0] -- register_copy jmp __b1 // main::@10 __b10: - // [23] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 -- _deref_pbuc1=vbuc2 + // [26] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 -- _deref_pbuc1=vbuc2 lda #0 sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC - // [24] (byte) main::i2#1 ← ++ (byte) main::i2#2 -- vbuxx=_inc_vbuxx - inx - // [21] phi from main::@10 to main::@9 [phi:main::@10->main::@9] - __b9_from___b10: - // [21] phi (byte) main::i2#2 = (byte) main::i2#1 [phi:main::@10->main::@9#0] -- register_copy jmp __b9 // main::@7 __b7: - // [25] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 -- _deref_pbuc1=vbuc2 + // [27] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 -- _deref_pbuc1=vbuc2 lda #0 sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC - // [26] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_COLUBK) ← (byte) main::c#2 -- _deref_pbuc1=vbuxx + // [28] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_COLUBK) ← (byte) main::c#2 -- _deref_pbuc1=vbuxx // Wait for SYNC (halts CPU until end of scanline) stx TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_COLUBK - // [27] (byte) main::c#1 ← ++ (byte) main::c#2 -- vbuxx=_inc_vbuxx + // [29] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_PF0) ← (byte) main::c#2 -- _deref_pbuc1=vbuxx + // Set background color + stx TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_PF0 + // [30] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_PF1) ← (byte) main::c#2 -- _deref_pbuc1=vbuxx + stx TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_PF1 + // [31] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_PF2) ← (byte) main::c#2 -- _deref_pbuc1=vbuxx + stx TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_PF2 + // [32] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_HMOVE) ← (byte) main::c#2 -- _deref_pbuc1=vbuxx + stx TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_HMOVE + // [33] (byte) main::c#1 ← ++ (byte) main::c#2 -- vbuxx=_inc_vbuxx inx - // [28] (byte) main::i1#1 ← ++ (byte) main::i1#2 -- vbuyy=_inc_vbuyy + // [34] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuyy=_inc_vbuyy iny - // [16] phi from main::@7 to main::@6 [phi:main::@7->main::@6] + // [19] phi from main::@7 to main::@6 [phi:main::@7->main::@6] __b6_from___b7: - // [16] phi (byte) main::c#2 = (byte) main::c#1 [phi:main::@7->main::@6#0] -- register_copy - // [16] phi (byte) main::i1#2 = (byte) main::i1#1 [phi:main::@7->main::@6#1] -- register_copy + // [19] phi (byte) main::c#2 = (byte) main::c#1 [phi:main::@7->main::@6#0] -- register_copy + // [19] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@7->main::@6#1] -- register_copy jmp __b6 // main::@4 __b4: - // [29] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 -- _deref_pbuc1=vbuc2 + // [35] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 -- _deref_pbuc1=vbuc2 lda #0 sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC - // [30] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuxx=_inc_vbuxx - inx - // [11] phi from main::@4 to main::@3 [phi:main::@4->main::@3] - __b3_from___b4: - // [11] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@4->main::@3#0] -- register_copy jmp __b3 } // File Data .segment Data - .align $100 SINTABLE: .fill $100, round(127.5+127.5*sin(2*PI*i/256)) @@ -999,28 +1050,23 @@ Succesful ASM optimization Pass5UnnecesaryLoadElimination 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: Succesful ASM optimization Pass5RedundantLabelElimination Removing instruction __bbegin: Removing instruction __bend: Removing instruction __b1_from_main: -Removing instruction __b3_from___b2: Removing instruction __b5: Removing instruction __b6_from___b5: Removing instruction __b8: -Removing instruction __b9_from___b8: Removing instruction __b1_from___b9: -Removing instruction __b9_from___b10: Removing instruction __b6_from___b7: -Removing instruction __b3_from___b4: Succesful ASM optimization Pass5UnusedLabelElimination Removing instruction jsr main Succesful ASM optimization Pass5SkipBegin -Replacing instruction ldx #0 with TAX +Removing instruction lda #0 Replacing instruction ldy #0 with TAY -Replacing instruction ldx #0 with TAX +Succesful ASM optimization Pass5UnnecesaryLoadElimination FINAL SYMBOL TABLE (label) @1 @@ -1096,14 +1142,22 @@ FINAL SYMBOL TABLE (byte) MOS6532_RIOT::TIM8T (const byte*) MOS6532_RIOT::UNUSED[(number) $f] = { fill( $f, 0) } (const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_COLUBK = (byte) 9 +(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_COLUPF = (byte) 8 +(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_HMOVE = (byte) $2a +(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_PF0 = (byte) $d +(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_PF1 = (byte) $e +(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_PF2 = (byte) $f (const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_VBLANK = (byte) 1 (const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC = (byte) 2 +(const byte) OFFSET_STRUCT_MOS6532_RIOT_INTIM = (byte) 4 +(const byte) OFFSET_STRUCT_MOS6532_RIOT_TIM64T = (byte) $16 +(const nomodify struct MOS6532_RIOT*) RIOT = (struct MOS6532_RIOT*) 640 (const to_nomodify byte*) SINTABLE[(number) $100] = kickasm {{ .fill $100, round(127.5+127.5*sin(2*PI*i/256)) }} (const nomodify struct ATARI_TIA_WRITE*) TIA = (struct ATARI_TIA_WRITE*) 0 (byte) idx -(byte) idx#1 idx mem[1] 78.71428571428571 -(byte) idx#12 idx mem[1] 100.25000000000001 +(byte) idx#1 idx mem[1] 64.82352941176471 +(byte) idx#12 idx mem[1] 109.36363636363637 (void()) main() (label) main::@1 (label) main::@10 @@ -1118,29 +1172,21 @@ FINAL SYMBOL TABLE (byte) main::c (byte) main::c#0 reg byte x 101.0 (byte) main::c#1 reg byte x 1001.0 -(byte) main::c#2 reg byte x 776.0 +(byte) main::c#2 reg byte x 888.5 (byte) main::i -(byte) main::i#1 reg byte x 2002.0 -(byte) main::i#2 reg byte x 1001.0 -(byte) main::i1 -(byte) main::i1#1 reg byte y 2002.0 -(byte) main::i1#2 reg byte y 600.5999999999999 -(byte) main::i2 -(byte) main::i2#1 reg byte x 2002.0 -(byte) main::i2#2 reg byte x 1001.0 +(byte) main::i#1 reg byte y 2002.0 +(byte) main::i#2 reg byte y 333.6666666666667 mem[1] [ idx#12 idx#1 ] -reg byte x [ main::i#2 main::i#1 ] -reg byte y [ main::i1#2 main::i1#1 ] +reg byte y [ main::i#2 main::i#1 ] reg byte x [ main::c#2 main::c#0 main::c#1 ] -reg byte x [ main::i2#2 main::i2#1 ] FINAL ASSEMBLER -Score: 6565 +Score: 8289 // File Comments -// Demonstration Atari 2600 VCS Program +// Minimal Atari 2600 VCS Program // Source: https://atariage.com/forums/blogs/entry/11109-step-1-generate-a-stable-display/ // Upstart // Atari 2600 VCS 2K ROM @@ -1156,164 +1202,193 @@ Score: 6565 .segment Code // Global Constants & labels + .const OFFSET_STRUCT_ATARI_TIA_WRITE_PF0 = $d + .const OFFSET_STRUCT_ATARI_TIA_WRITE_PF1 = $e + .const OFFSET_STRUCT_ATARI_TIA_WRITE_PF2 = $f + .const OFFSET_STRUCT_ATARI_TIA_WRITE_COLUPF = 8 + .const OFFSET_STRUCT_MOS6532_RIOT_TIM64T = $16 .const OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC = 2 + .const OFFSET_STRUCT_MOS6532_RIOT_INTIM = 4 .const OFFSET_STRUCT_ATARI_TIA_WRITE_VBLANK = 1 .const OFFSET_STRUCT_ATARI_TIA_WRITE_COLUBK = 9 + .const OFFSET_STRUCT_ATARI_TIA_WRITE_HMOVE = $2a // Atari TIA write registers .label TIA = 0 + // Atari RIOT registers + .label RIOT = $280 // @begin // [1] phi from @begin to @1 [phi:@begin->@1] // @1 // [2] call main - // [4] phi from @1 to main [phi:@1->main] // [3] phi from @1 to @end [phi:@1->@end] // @end .segment Code // main main: { - // [5] phi from main to main::@1 [phi:main->main::@1] - // [5] phi (byte) idx#12 = (byte) 0 [phi:main->main::@1#0] -- vbum1=vbuc1 + // TIA->PF0 = 0b10100000 + // [4] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_PF0) ← (byte) $a0 -- _deref_pbuc1=vbuc2 + lda #$a0 + sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_PF0 + // TIA->PF1 = 0b01010101 + // [5] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_PF1) ← (byte) $55 -- _deref_pbuc1=vbuc2 + lda #$55 + sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_PF1 + // TIA->PF2 = 0b10101010 + // [6] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_PF2) ← (byte) $aa -- _deref_pbuc1=vbuc2 + lda #$aa + sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_PF2 + // TIA->COLUPF = 0x55 + // [7] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_COLUPF) ← (byte) $55 -- _deref_pbuc1=vbuc2 + lda #$55 + sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_COLUPF + // [8] phi from main to main::@1 [phi:main->main::@1] + // [8] phi (byte) idx#12 = (byte) 0 [phi:main->main::@1#0] -- vbum1=vbuc1 lda #0 sta idx // main::@1 // main::@2 __b2: // TIA->VSYNC = 2 - // [6] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA) ← (byte) 2 -- _deref_pbuc1=vbuc2 + // [9] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA) ← (byte) 2 -- _deref_pbuc1=vbuc2 // Vertical Sync // here we generate the signal that tells the TV to move the beam to the top of // the screen so we can start the next frame of video. // The Sync Signal must be on for 3 scanlines. lda #2 sta TIA + // RIOT->TIM64T = (41*76)/64 + // [10] *((byte*)(const nomodify struct MOS6532_RIOT*) RIOT+(const byte) OFFSET_STRUCT_MOS6532_RIOT_TIM64T) ← (byte)(number) $29*(number) $4c/(number) $40 -- _deref_pbuc1=vbuc2 + // D1=1, turns on Vertical Sync signal + lda #$29*$4c/$40 + sta RIOT+OFFSET_STRUCT_MOS6532_RIOT_TIM64T // TIA->WSYNC = 0 - // [7] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 -- _deref_pbuc1=vbuc2 - // Accumulator D1=1, turns on Vertical Sync signal + // [11] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 -- _deref_pbuc1=vbuc2 + // Set timer to wait 41 lines lda #0 sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC - // [8] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 -- _deref_pbuc1=vbuc2 + // [12] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 -- _deref_pbuc1=vbuc2 // Wait for Sync - halts CPU until end of 1st scanline of VSYNC sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC - // [9] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 -- _deref_pbuc1=vbuc2 + // [13] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 -- _deref_pbuc1=vbuc2 // wait until end of 2nd scanline of VSYNC sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC // TIA->VSYNC = 0 - // [10] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA) ← (byte) 0 -- _deref_pbuc1=vbuc2 + // [14] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA) ← (byte) 0 -- _deref_pbuc1=vbuc2 // wait until end of 3rd scanline of VSYNC sta TIA - // [11] phi from main::@2 to main::@3 [phi:main::@2->main::@3] - // [11] phi (byte) main::i#2 = (byte) 0 [phi:main::@2->main::@3#0] -- vbuxx=vbuc1 - tax - // Vertical Blank - game logic - // Since we don't have any yet, just delay + // Wait for the timer to run out // main::@3 __b3: - // for(char i=0;i<37;i++) - // [12] if((byte) main::i#2<(byte) $25) goto main::@4 -- vbuxx_lt_vbuc1_then_la1 - cpx #$25 - bcc __b4 + // while(RIOT->INTIM) + // [15] if((byte) 0!=*((byte*)(const nomodify struct MOS6532_RIOT*) RIOT+(const byte) OFFSET_STRUCT_MOS6532_RIOT_INTIM)) goto main::@4 -- vbuc1_neq__deref_pbuc2_then_la1 + lda #0 + cmp RIOT+OFFSET_STRUCT_MOS6532_RIOT_INTIM + bne __b4 // main::@5 // TIA->VBLANK = 0 - // [13] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_VBLANK) ← (byte) 0 -- _deref_pbuc1=vbuc2 + // [16] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_VBLANK) ← (byte) 0 -- _deref_pbuc1=vbuc2 // Screen - display logic - // Update the registers in TIA (the video chip) in order to generate what the player sees. + // Update the registers in TIA (the video chip) in order to generate what the player sees. // For now we're just going to output 192 colored scanlines lines so we have something to see. - lda #0 sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_VBLANK // c = SINTABLE[idx++] - // [14] (byte) main::c#0 ← *((const to_nomodify byte*) SINTABLE + (byte) idx#12) -- vbuxx=pbuc1_derefidx_vbum1 + // [17] (byte) main::c#0 ← *((const to_nomodify byte*) SINTABLE + (byte) idx#12) -- vbuxx=pbuc1_derefidx_vbum1 // D1=1, turns off Vertical Blank signal (image output on) ldy idx ldx SINTABLE,y - // [15] (byte) idx#1 ← ++ (byte) idx#12 -- vbum1=_inc_vbum1 + // [18] (byte) idx#1 ← ++ (byte) idx#12 -- vbum1=_inc_vbum1 inc idx - // [16] phi from main::@5 to main::@6 [phi:main::@5->main::@6] - // [16] phi (byte) main::c#2 = (byte) main::c#0 [phi:main::@5->main::@6#0] -- register_copy - // [16] phi (byte) main::i1#2 = (byte) 0 [phi:main::@5->main::@6#1] -- vbuyy=vbuc1 + // [19] phi from main::@5 to main::@6 [phi:main::@5->main::@6] + // [19] phi (byte) main::c#2 = (byte) main::c#0 [phi:main::@5->main::@6#0] -- register_copy + // [19] phi (byte) main::i#2 = (byte) 0 [phi:main::@5->main::@6#1] -- vbuyy=vbuc1 tay // main::@6 __b6: // for(char i=0;i<192;i++) - // [17] if((byte) main::i1#2<(byte) $c0) goto main::@7 -- vbuyy_lt_vbuc1_then_la1 + // [20] if((byte) main::i#2<(byte) $c0) goto main::@7 -- vbuyy_lt_vbuc1_then_la1 cpy #$c0 bcc __b7 // main::@8 // TIA->WSYNC = 0 - // [18] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 -- _deref_pbuc1=vbuc2 - // Overscan - game logic - // Since we don't have any yet, just delay + // [21] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 -- _deref_pbuc1=vbuc2 + // Start OverScan lda #0 sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC // TIA->VBLANK = 2 - // [19] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_VBLANK) ← (byte) 2 -- _deref_pbuc1=vbuc2 + // [22] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_VBLANK) ← (byte) 2 -- _deref_pbuc1=vbuc2 // Wait for SYNC (halts CPU until end of scanline) lda #2 sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_VBLANK // TIA->COLUBK = 0 - // [20] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_COLUBK) ← (byte) 0 -- _deref_pbuc1=vbuc2 - // // D1=1 turns image output off + // [23] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_COLUBK) ← (byte) 0 -- _deref_pbuc1=vbuc2 + // D1=1 turns image output off lda #0 sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_COLUBK - // [21] phi from main::@8 to main::@9 [phi:main::@8->main::@9] - // [21] phi (byte) main::i2#2 = (byte) 0 [phi:main::@8->main::@9#0] -- vbuxx=vbuc1 - tax + // RIOT->TIM64T = (27*76)/64 + // [24] *((byte*)(const nomodify struct MOS6532_RIOT*) RIOT+(const byte) OFFSET_STRUCT_MOS6532_RIOT_TIM64T) ← (byte)(number) $1b*(number) $4c/(number) $40 -- _deref_pbuc1=vbuc2 + // Set background color to black + lda #$1b*$4c/$40 + sta RIOT+OFFSET_STRUCT_MOS6532_RIOT_TIM64T + // Wait for the timer to run out // main::@9 __b9: - // for(char i=0;i<30;i++) - // [22] if((byte) main::i2#2<(byte) $1e) goto main::@10 -- vbuxx_lt_vbuc1_then_la1 - cpx #$1e - bcc __b10 - // [5] phi from main::@9 to main::@1 [phi:main::@9->main::@1] - // [5] phi (byte) idx#12 = (byte) idx#1 [phi:main::@9->main::@1#0] -- register_copy + // while(RIOT->INTIM) + // [25] if((byte) 0!=*((byte*)(const nomodify struct MOS6532_RIOT*) RIOT+(const byte) OFFSET_STRUCT_MOS6532_RIOT_INTIM)) goto main::@10 -- vbuc1_neq__deref_pbuc2_then_la1 + lda #0 + cmp RIOT+OFFSET_STRUCT_MOS6532_RIOT_INTIM + bne __b10 + // [8] phi from main::@9 to main::@1 [phi:main::@9->main::@1] + // [8] phi (byte) idx#12 = (byte) idx#1 [phi:main::@9->main::@1#0] -- register_copy jmp __b2 // main::@10 __b10: // TIA->WSYNC = 0 - // [23] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 -- _deref_pbuc1=vbuc2 + // [26] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 -- _deref_pbuc1=vbuc2 lda #0 sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC - // for(char i=0;i<30;i++) - // [24] (byte) main::i2#1 ← ++ (byte) main::i2#2 -- vbuxx=_inc_vbuxx - inx - // [21] phi from main::@10 to main::@9 [phi:main::@10->main::@9] - // [21] phi (byte) main::i2#2 = (byte) main::i2#1 [phi:main::@10->main::@9#0] -- register_copy jmp __b9 // main::@7 __b7: - // TIA->WSYNC = 0 - // [25] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 -- _deref_pbuc1=vbuc2 + // [27] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 -- _deref_pbuc1=vbuc2 lda #0 sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC - // TIA->COLUBK = c++ - // [26] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_COLUBK) ← (byte) main::c#2 -- _deref_pbuc1=vbuxx + // TIA->COLUBK = c + // [28] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_COLUBK) ← (byte) main::c#2 -- _deref_pbuc1=vbuxx // Wait for SYNC (halts CPU until end of scanline) stx TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_COLUBK - // TIA->COLUBK = c++; - // [27] (byte) main::c#1 ← ++ (byte) main::c#2 -- vbuxx=_inc_vbuxx + // TIA->PF0 = c + // [29] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_PF0) ← (byte) main::c#2 -- _deref_pbuc1=vbuxx + // Set background color + stx TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_PF0 + // TIA->PF1 = c + // [30] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_PF1) ← (byte) main::c#2 -- _deref_pbuc1=vbuxx + stx TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_PF1 + // TIA->PF2 = c + // [31] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_PF2) ← (byte) main::c#2 -- _deref_pbuc1=vbuxx + stx TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_PF2 + // TIA->HMOVE = c + // [32] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_HMOVE) ← (byte) main::c#2 -- _deref_pbuc1=vbuxx + stx TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_HMOVE + // c++; + // [33] (byte) main::c#1 ← ++ (byte) main::c#2 -- vbuxx=_inc_vbuxx inx // for(char i=0;i<192;i++) - // [28] (byte) main::i1#1 ← ++ (byte) main::i1#2 -- vbuyy=_inc_vbuyy + // [34] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuyy=_inc_vbuyy iny - // [16] phi from main::@7 to main::@6 [phi:main::@7->main::@6] - // [16] phi (byte) main::c#2 = (byte) main::c#1 [phi:main::@7->main::@6#0] -- register_copy - // [16] phi (byte) main::i1#2 = (byte) main::i1#1 [phi:main::@7->main::@6#1] -- register_copy + // [19] phi from main::@7 to main::@6 [phi:main::@7->main::@6] + // [19] phi (byte) main::c#2 = (byte) main::c#1 [phi:main::@7->main::@6#0] -- register_copy + // [19] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@7->main::@6#1] -- register_copy jmp __b6 // main::@4 __b4: // TIA->WSYNC = 0 - // [29] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 -- _deref_pbuc1=vbuc2 + // [35] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 -- _deref_pbuc1=vbuc2 lda #0 sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC - // for(char i=0;i<37;i++) - // [30] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuxx=_inc_vbuxx - inx - // [11] phi from main::@4 to main::@3 [phi:main::@4->main::@3] - // [11] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@4->main::@3#0] -- register_copy jmp __b3 } // File Data .segment Data - .align $100 SINTABLE: .fill $100, round(127.5+127.5*sin(2*PI*i/256)) diff --git a/src/test/ref/examples/atari2600/atari2600-demo.sym b/src/test/ref/examples/atari2600/atari2600-demo.sym index 7a9b23ed1..1097bdef9 100644 --- a/src/test/ref/examples/atari2600/atari2600-demo.sym +++ b/src/test/ref/examples/atari2600/atari2600-demo.sym @@ -71,14 +71,22 @@ (byte) MOS6532_RIOT::TIM8T (const byte*) MOS6532_RIOT::UNUSED[(number) $f] = { fill( $f, 0) } (const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_COLUBK = (byte) 9 +(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_COLUPF = (byte) 8 +(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_HMOVE = (byte) $2a +(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_PF0 = (byte) $d +(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_PF1 = (byte) $e +(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_PF2 = (byte) $f (const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_VBLANK = (byte) 1 (const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC = (byte) 2 +(const byte) OFFSET_STRUCT_MOS6532_RIOT_INTIM = (byte) 4 +(const byte) OFFSET_STRUCT_MOS6532_RIOT_TIM64T = (byte) $16 +(const nomodify struct MOS6532_RIOT*) RIOT = (struct MOS6532_RIOT*) 640 (const to_nomodify byte*) SINTABLE[(number) $100] = kickasm {{ .fill $100, round(127.5+127.5*sin(2*PI*i/256)) }} (const nomodify struct ATARI_TIA_WRITE*) TIA = (struct ATARI_TIA_WRITE*) 0 (byte) idx -(byte) idx#1 idx mem[1] 78.71428571428571 -(byte) idx#12 idx mem[1] 100.25000000000001 +(byte) idx#1 idx mem[1] 64.82352941176471 +(byte) idx#12 idx mem[1] 109.36363636363637 (void()) main() (label) main::@1 (label) main::@10 @@ -93,19 +101,11 @@ (byte) main::c (byte) main::c#0 reg byte x 101.0 (byte) main::c#1 reg byte x 1001.0 -(byte) main::c#2 reg byte x 776.0 +(byte) main::c#2 reg byte x 888.5 (byte) main::i -(byte) main::i#1 reg byte x 2002.0 -(byte) main::i#2 reg byte x 1001.0 -(byte) main::i1 -(byte) main::i1#1 reg byte y 2002.0 -(byte) main::i1#2 reg byte y 600.5999999999999 -(byte) main::i2 -(byte) main::i2#1 reg byte x 2002.0 -(byte) main::i2#2 reg byte x 1001.0 +(byte) main::i#1 reg byte y 2002.0 +(byte) main::i#2 reg byte y 333.6666666666667 mem[1] [ idx#12 idx#1 ] -reg byte x [ main::i#2 main::i#1 ] -reg byte y [ main::i1#2 main::i1#1 ] +reg byte y [ main::i#2 main::i#1 ] reg byte x [ main::c#2 main::c#0 main::c#1 ] -reg byte x [ main::i2#2 main::i2#1 ] diff --git a/src/test/ref/examples/atari2600/atari2600-sprites.asm b/src/test/ref/examples/atari2600/atari2600-sprites.asm new file mode 100644 index 000000000..88c7062f8 --- /dev/null +++ b/src/test/ref/examples/atari2600/atari2600-sprites.asm @@ -0,0 +1,211 @@ +// Minimal Atari 2600 VCS Program using Sprites +// Source: https://atariage.com/forums/blogs/entry/11109-step-1-generate-a-stable-display/ + // Atari 2600 VCS 2K ROM +.file [name="atari2600-sprites.a26", type="bin", segments="Code, Data, Vectors"] +.segmentdef Code [start=$f800,min=$f800,max=$fff9] +.segmentdef Data [startAfter="Code",max=$fff9] +.segmentdef Vectors [start=$fffa,max=$ffff] +.segmentdef Vars [start=$80,max=$ff, virtual] +.segment Vectors +.word main // NMI +.word main // RESET +.word main // IRQ +.segment Code + + // The number of CPU cycles per scanline + .const CYCLES_PER_SCANLINE = $4c + .const OFFSET_STRUCT_ATARI_TIA_WRITE_COLUP0 = 6 + .const OFFSET_STRUCT_ATARI_TIA_WRITE_GRP0 = $1b + .const OFFSET_STRUCT_MOS6532_RIOT_TIM64T = $16 + .const OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC = 2 + .const OFFSET_STRUCT_ATARI_TIA_WRITE_HMOVE = $2a + .const OFFSET_STRUCT_MOS6532_RIOT_INTIM = 4 + .const OFFSET_STRUCT_ATARI_TIA_WRITE_VBLANK = 1 + .const OFFSET_STRUCT_ATARI_TIA_WRITE_COLUBK = 9 + // The TIA WSYNC register (for access from inline ASM) + .label TIA_WSYNC = 2 + // The TIA RESP0 register (for access from inline ASM) + .label TIA_RESP0 = $10 + // The TIA HMP0 register (for access from inline ASM) + .label TIA_HMP0 = $20 + // Atari TIA write registers + .label TIA = 0 + // Atari RIOT registers + .label RIOT = $280 +.segment Code +main: { + // asm + cld + // TIA->COLUP0 = 0xf0 + // Player 0 + // - Color + lda #$f0 + sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_COLUP0 + // TIA->GRP0 = 0xaf + // - Graphics + lda #$af + sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_GRP0 + lda #$39 + sta idx2 + lda #0 + sta idx + // Player 1 + // - Color + //TIA->COLUP1 = 0xf0; + // - Graphics + //TIA->GRP1 = 0xf5; + __b2: + // TIA->VSYNC = 2 + // Vertical Sync + // here we generate the signal that tells the TV to move the beam to the top of + // the screen so we can start the next frame of video. + // The Sync Signal must be on for 3 scanlines. + lda #2 + sta TIA + // RIOT->TIM64T = (41*CYCLES_PER_SCANLINE)/64 + // D1=1, turns on Vertical Sync signal + lda #$29*CYCLES_PER_SCANLINE/$40 + sta RIOT+OFFSET_STRUCT_MOS6532_RIOT_TIM64T + // TIA->WSYNC = 0 + // Set timer to wait 41 lines + lda #0 + sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC + // Wait for Sync - halts CPU until end of 1st scanline of VSYNC + sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC + // wait until end of 2nd scanline of VSYNC + sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC + // TIA->VSYNC = 0 + // wait until end of 3rd scanline of VSYNC + sta TIA + // asm + // Vertical Sprite Position Player 0 - inline ASM to achieve cycle exact code + lda p0_xpos + sta TIA_WSYNC + sec + !: + sbc #$f + bcs !- + eor #7 + asl + asl + asl + asl + sta TIA_HMP0 + sta TIA_RESP0 + // p0_xpos = SINTABLE_160[idx++] + ldy idx + lda SINTABLE_160,y + sta p0_xpos + // p0_xpos = SINTABLE_160[idx++]; + inc idx + // p0_ypos = SINTABLE_160[idx2++] + ldy idx2 + lda SINTABLE_160,y + sta p0_ypos + // p0_ypos = SINTABLE_160[idx2++]; + inc idx2 + // TIA->WSYNC = 0 + // Execute horisontal movement + lda #0 + sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC + // TIA->HMOVE = 0 + sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_HMOVE + // Wait for the timer to run out + __b3: + // while(RIOT->INTIM) + lda #0 + cmp RIOT+OFFSET_STRUCT_MOS6532_RIOT_INTIM + bne __b4 + // TIA->VBLANK = 0 + // Screen - display logic + // Update the registers in TIA (the video chip) in order to generate what the player sees. + // For now we're just going to output 192 colored scanlines lines so we have something to see. + sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_VBLANK + // TIA->COLUBK = 0x0 + // D1=1, turns off Vertical Blank signal (image output on) + sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_COLUBK + tay + ldx #1 + __b6: + // for(char i=1;i<192;i++) + cpx #$c0 + bcc __b7 + // TIA->WSYNC = 0 + // Start OverScan + lda #0 + sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC + // TIA->VBLANK = 2 + // Wait for SYNC (halts CPU until end of scanline) + lda #2 + sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_VBLANK + // TIA->COLUBK = 0 + // D1=1 turns image output off + lda #0 + sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_COLUBK + // RIOT->TIM64T = (27*CYCLES_PER_SCANLINE)/64 + // Set background color to black + lda #$1b*CYCLES_PER_SCANLINE/$40 + sta RIOT+OFFSET_STRUCT_MOS6532_RIOT_TIM64T + // Wait for the timer to run out + __b13: + // while(RIOT->INTIM) + lda #0 + cmp RIOT+OFFSET_STRUCT_MOS6532_RIOT_INTIM + bne __b14 + jmp __b2 + __b14: + // TIA->WSYNC = 0 + lda #0 + sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC + jmp __b13 + __b7: + // Wait for SYNC (halts CPU until end of scanline) + lda #0 + sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC + // TIA->COLUBK = i + stx TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_COLUBK + // if(p0_idx) + cpy #0 + bne __b9 + // if(p0_ypos==i) + cpx p0_ypos + bne __b10 + ldy #1 + jmp __b10 + __b1: + ldy #0 + __b10: + // for(char i=1;i<192;i++) + inx + jmp __b6 + __b9: + // gfx = SPRITE_C[p0_idx] + // Player 0 is active - show it + lda SPRITE_C,y + // TIA->GRP0 = gfx + sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_GRP0 + // if(gfx==0) + cmp #0 + beq __b1 + // p0_idx++; + iny + jmp __b10 + __b4: + // TIA->WSYNC = 0 + lda #0 + sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC + jmp __b3 +} +.segment Data +SINTABLE_160: +.fill $100, 5+round(74.5+74.5*sin(2*PI*i/256)) + + SPRITE_C: .byte 0, $18, $18, $18, $18, $3c, $3c, $3c, $3c, $66, $66, $66, $66, $c0, $c0, $c0, $c0, $c0, $c0, $c0, $c0, $66, $66, $66, $66, $3c, $3c, $3c, $3c, $18, $18, $18, $18, 0 +.segment Vars + // Player 0 X position + p0_xpos: .byte 0 + // Counts frames + idx: .byte 0 + // Player 0 Y position + p0_ypos: .byte 0 + idx2: .byte 0 diff --git a/src/test/ref/examples/atari2600/atari2600-sprites.cfg b/src/test/ref/examples/atari2600/atari2600-sprites.cfg new file mode 100644 index 000000000..b5213d2a4 --- /dev/null +++ b/src/test/ref/examples/atari2600/atari2600-sprites.cfg @@ -0,0 +1,85 @@ +@begin: scope:[] from + [0] phi() + to:@1 +@1: scope:[] from @begin + [1] phi() + [2] call main + to:@end +@end: scope:[] from @1 + [3] phi() + +(void()) main() +main: scope:[main] from @1 + asm { cld } + [5] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_COLUP0) ← (byte) $f0 + [6] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_GRP0) ← (byte) $af + to:main::@1 +main::@1: scope:[main] from main main::@13 + [7] (byte) idx2#2 ← phi( main/(byte) $39 main::@13/(byte) idx2#1 ) + [7] (byte) idx#2 ← phi( main/(byte) 0 main::@13/(byte) idx#1 ) + to:main::@2 +main::@2: scope:[main] from main::@1 + [8] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA) ← (byte) 2 + [9] *((byte*)(const nomodify struct MOS6532_RIOT*) RIOT+(const byte) OFFSET_STRUCT_MOS6532_RIOT_TIM64T) ← (byte) $29*(const nomodify byte) CYCLES_PER_SCANLINE/(byte) $40 + [10] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 + [11] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 + [12] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 + [13] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA) ← (byte) 0 + asm { ldap0_xpos staTIA_WSYNC sec !: sbc#$f bcs!- eor#7 asl asl asl asl staTIA_HMP0 staTIA_RESP0 } + [15] (byte) p0_xpos ← *((const to_nomodify byte*) SINTABLE_160 + (byte) idx#2) + [16] (byte) idx#1 ← ++ (byte) idx#2 + [17] (byte) p0_ypos#1 ← *((const to_nomodify byte*) SINTABLE_160 + (byte) idx2#2) + [18] (byte) idx2#1 ← ++ (byte) idx2#2 + [19] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 + [20] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_HMOVE) ← (byte) 0 + to:main::@3 +main::@3: scope:[main] from main::@2 main::@4 + [21] if((byte) 0!=*((byte*)(const nomodify struct MOS6532_RIOT*) RIOT+(const byte) OFFSET_STRUCT_MOS6532_RIOT_INTIM)) goto main::@4 + to:main::@5 +main::@5: scope:[main] from main::@3 + [22] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_VBLANK) ← (byte) 0 + [23] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_COLUBK) ← (byte) 0 + to:main::@6 +main::@6: scope:[main] from main::@10 main::@5 + [24] (byte) main::p0_idx#4 ← phi( main::@10/(byte) main::p0_idx#8 main::@5/(byte) 0 ) + [24] (byte) main::i#2 ← phi( main::@10/(byte) main::i#1 main::@5/(byte) 1 ) + [25] if((byte) main::i#2<(byte) $c0) goto main::@7 + to:main::@8 +main::@8: scope:[main] from main::@6 + [26] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 + [27] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_VBLANK) ← (byte) 2 + [28] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_COLUBK) ← (byte) 0 + [29] *((byte*)(const nomodify struct MOS6532_RIOT*) RIOT+(const byte) OFFSET_STRUCT_MOS6532_RIOT_TIM64T) ← (byte) $1b*(const nomodify byte) CYCLES_PER_SCANLINE/(byte) $40 + to:main::@13 +main::@13: scope:[main] from main::@14 main::@8 + [30] if((byte) 0!=*((byte*)(const nomodify struct MOS6532_RIOT*) RIOT+(const byte) OFFSET_STRUCT_MOS6532_RIOT_INTIM)) goto main::@14 + to:main::@1 +main::@14: scope:[main] from main::@13 + [31] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 + to:main::@13 +main::@7: scope:[main] from main::@6 + [32] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 + [33] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_COLUBK) ← (byte) main::i#2 + [34] if((byte) 0!=(byte) main::p0_idx#4) goto main::@9 + to:main::@11 +main::@11: scope:[main] from main::@7 + [35] if((byte) p0_ypos#1!=(byte) main::i#2) goto main::@15 + to:main::@10 +main::@15: scope:[main] from main::@11 + [36] phi() + to:main::@10 +main::@10: scope:[main] from main::@11 main::@12 main::@15 main::@9 + [37] (byte) main::p0_idx#8 ← phi( main::@9/(byte) 0 main::@15/(byte) main::p0_idx#4 main::@11/(byte) 1 main::@12/(byte) main::p0_idx#3 ) + [38] (byte) main::i#1 ← ++ (byte) main::i#2 + to:main::@6 +main::@9: scope:[main] from main::@7 + [39] (byte) main::gfx#0 ← *((const byte*) SPRITE_C + (byte) main::p0_idx#4) + [40] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_GRP0) ← (byte) main::gfx#0 + [41] if((byte) main::gfx#0==(byte) 0) goto main::@10 + to:main::@12 +main::@12: scope:[main] from main::@9 + [42] (byte) main::p0_idx#3 ← ++ (byte) main::p0_idx#4 + to:main::@10 +main::@4: scope:[main] from main::@3 + [43] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 + to:main::@3 diff --git a/src/test/ref/examples/atari2600/atari2600-sprites.log b/src/test/ref/examples/atari2600/atari2600-sprites.log new file mode 100644 index 000000000..57b24b608 --- /dev/null +++ b/src/test/ref/examples/atari2600/atari2600-sprites.log @@ -0,0 +1,2031 @@ +Fixing struct type size struct MOS6532_RIOT to 24 +Fixing struct type SIZE_OF struct MOS6532_RIOT to 24 +Fixing struct type SIZE_OF struct MOS6532_RIOT to 24 + +CONTROL FLOW GRAPH SSA +@begin: scope:[] from + (byte) idx#0 ← (byte) 0 + (byte) idx2#0 ← (byte) $39 + (byte) p0_ypos#0 ← (byte) 0 + to:@1 + +(void()) main() +main: scope:[main] from @1 + (byte) p0_ypos#10 ← phi( @1/(byte) p0_ypos#9 ) + (byte) idx2#9 ← phi( @1/(byte) idx2#8 ) + (byte) idx#9 ← phi( @1/(byte) idx#8 ) + asm { cld } + *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_COLUP0) ← (number) $f0 + *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_GRP0) ← (number) $af + to:main::@1 +main::@1: scope:[main] from main main::@15 + (byte) p0_ypos#8 ← phi( main/(byte) p0_ypos#10 main::@15/(byte) p0_ypos#11 ) + (byte) idx2#7 ← phi( main/(byte) idx2#9 main::@15/(byte) idx2#10 ) + (byte) idx#7 ← phi( main/(byte) idx#9 main::@15/(byte) idx#10 ) + (bool~) main::$4 ← (number) 0 != (number) 1 + if((bool~) main::$4) goto main::@2 + to:main::@return +main::@2: scope:[main] from main::@1 + (byte) idx2#4 ← phi( main::@1/(byte) idx2#7 ) + (byte) idx#4 ← phi( main::@1/(byte) idx#7 ) + *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_VSYNC) ← (number) 2 + *((byte*)(const nomodify struct MOS6532_RIOT*) RIOT+(const byte) OFFSET_STRUCT_MOS6532_RIOT_TIM64T) ← (number) $29*(const nomodify byte) CYCLES_PER_SCANLINE/(number) $40 + *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (number) 0 + *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (number) 0 + *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (number) 0 + *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_VSYNC) ← (number) 0 + asm { ldap0_xpos staTIA_WSYNC sec !: sbc#$f bcs!- eor#7 asl asl asl asl staTIA_HMP0 staTIA_RESP0 } + (byte) p0_xpos ← *((const to_nomodify byte*) SINTABLE_160 + (byte) idx#4) + (byte) idx#1 ← ++ (byte) idx#4 + (byte) p0_ypos#1 ← *((const to_nomodify byte*) SINTABLE_160 + (byte) idx2#4) + (byte) idx2#1 ← ++ (byte) idx2#4 + *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (number) 0 + *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_HMOVE) ← (number) 0 + to:main::@3 +main::@3: scope:[main] from main::@2 main::@4 + (byte) idx2#16 ← phi( main::@2/(byte) idx2#1 main::@4/(byte) idx2#21 ) + (byte) idx#16 ← phi( main::@2/(byte) idx#1 main::@4/(byte) idx#21 ) + (byte) p0_ypos#17 ← phi( main::@2/(byte) p0_ypos#1 main::@4/(byte) p0_ypos#21 ) + (bool~) main::$5 ← (number) 0 != *((byte*)(const nomodify struct MOS6532_RIOT*) RIOT+(const byte) OFFSET_STRUCT_MOS6532_RIOT_INTIM) + if((bool~) main::$5) goto main::@4 + to:main::@5 +main::@4: scope:[main] from main::@3 + (byte) idx2#21 ← phi( main::@3/(byte) idx2#16 ) + (byte) idx#21 ← phi( main::@3/(byte) idx#16 ) + (byte) p0_ypos#21 ← phi( main::@3/(byte) p0_ypos#17 ) + *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (number) 0 + to:main::@3 +main::@5: scope:[main] from main::@3 + (byte) idx2#15 ← phi( main::@3/(byte) idx2#16 ) + (byte) idx#15 ← phi( main::@3/(byte) idx#16 ) + (byte) p0_ypos#14 ← phi( main::@3/(byte) p0_ypos#17 ) + *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_VBLANK) ← (number) 0 + *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_COLUBK) ← (number) 0 + (byte) main::p0_idx#0 ← (byte) 0 + (byte) main::i#0 ← (byte) 1 + to:main::@6 +main::@6: scope:[main] from main::@10 main::@5 + (byte) idx2#13 ← phi( main::@10/(byte) idx2#14 main::@5/(byte) idx2#15 ) + (byte) idx#13 ← phi( main::@10/(byte) idx#14 main::@5/(byte) idx#15 ) + (byte) p0_ypos#12 ← phi( main::@10/(byte) p0_ypos#13 main::@5/(byte) p0_ypos#14 ) + (byte) main::p0_idx#7 ← phi( main::@10/(byte) main::p0_idx#8 main::@5/(byte) main::p0_idx#0 ) + (byte) main::i#2 ← phi( main::@10/(byte) main::i#1 main::@5/(byte) main::i#0 ) + (bool~) main::$0 ← (byte) main::i#2 < (number) $c0 + if((bool~) main::$0) goto main::@7 + to:main::@8 +main::@7: scope:[main] from main::@6 + (byte) idx2#22 ← phi( main::@6/(byte) idx2#13 ) + (byte) idx#22 ← phi( main::@6/(byte) idx#13 ) + (byte) p0_ypos#7 ← phi( main::@6/(byte) p0_ypos#12 ) + (byte) main::p0_idx#4 ← phi( main::@6/(byte) main::p0_idx#7 ) + (byte) main::i#3 ← phi( main::@6/(byte) main::i#2 ) + *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (number) 0 + *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_COLUBK) ← (byte) main::i#3 + (bool~) main::$6 ← (number) 0 != (byte) main::p0_idx#4 + if((bool~) main::$6) goto main::@9 + to:main::@12 +main::@8: scope:[main] from main::@6 + (byte) p0_ypos#16 ← phi( main::@6/(byte) p0_ypos#12 ) + (byte) idx2#12 ← phi( main::@6/(byte) idx2#13 ) + (byte) idx#12 ← phi( main::@6/(byte) idx#13 ) + *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (number) 0 + *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_VBLANK) ← (number) 2 + *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_COLUBK) ← (number) 0 + *((byte*)(const nomodify struct MOS6532_RIOT*) RIOT+(const byte) OFFSET_STRUCT_MOS6532_RIOT_TIM64T) ← (number) $1b*(const nomodify byte) CYCLES_PER_SCANLINE/(number) $40 + to:main::@15 +main::@9: scope:[main] from main::@7 + (byte) idx2#23 ← phi( main::@7/(byte) idx2#22 ) + (byte) idx#23 ← phi( main::@7/(byte) idx#22 ) + (byte) p0_ypos#22 ← phi( main::@7/(byte) p0_ypos#7 ) + (byte) main::i#9 ← phi( main::@7/(byte) main::i#3 ) + (byte) main::p0_idx#5 ← phi( main::@7/(byte) main::p0_idx#4 ) + (byte) main::gfx#0 ← *((const byte*) SPRITE_C + (byte) main::p0_idx#5) + *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_GRP0) ← (byte) main::gfx#0 + (bool~) main::$3 ← (byte) main::gfx#0 == (number) 0 + if((bool~) main::$3) goto main::@11 + to:main::@14 +main::@12: scope:[main] from main::@7 + (byte) idx2#18 ← phi( main::@7/(byte) idx2#22 ) + (byte) idx#18 ← phi( main::@7/(byte) idx#22 ) + (byte) main::p0_idx#9 ← phi( main::@7/(byte) main::p0_idx#4 ) + (byte) main::i#4 ← phi( main::@7/(byte) main::i#3 ) + (byte) p0_ypos#4 ← phi( main::@7/(byte) p0_ypos#7 ) + (bool~) main::$1 ← (byte) p0_ypos#4 == (byte) main::i#4 + (bool~) main::$2 ← ! (bool~) main::$1 + if((bool~) main::$2) goto main::@10 + to:main::@13 +main::@13: scope:[main] from main::@12 + (byte) idx2#19 ← phi( main::@12/(byte) idx2#18 ) + (byte) idx#19 ← phi( main::@12/(byte) idx#18 ) + (byte) p0_ypos#19 ← phi( main::@12/(byte) p0_ypos#4 ) + (byte) main::i#7 ← phi( main::@12/(byte) main::i#4 ) + (byte) main::p0_idx#1 ← (number) 1 + to:main::@10 +main::@10: scope:[main] from main::@11 main::@12 main::@13 main::@14 + (byte) idx2#14 ← phi( main::@11/(byte) idx2#17 main::@12/(byte) idx2#18 main::@13/(byte) idx2#19 main::@14/(byte) idx2#20 ) + (byte) idx#14 ← phi( main::@11/(byte) idx#17 main::@12/(byte) idx#18 main::@13/(byte) idx#19 main::@14/(byte) idx#20 ) + (byte) p0_ypos#13 ← phi( main::@11/(byte) p0_ypos#18 main::@12/(byte) p0_ypos#4 main::@13/(byte) p0_ypos#19 main::@14/(byte) p0_ypos#20 ) + (byte) main::p0_idx#8 ← phi( main::@11/(byte) main::p0_idx#2 main::@12/(byte) main::p0_idx#9 main::@13/(byte) main::p0_idx#1 main::@14/(byte) main::p0_idx#3 ) + (byte) main::i#5 ← phi( main::@11/(byte) main::i#6 main::@12/(byte) main::i#4 main::@13/(byte) main::i#7 main::@14/(byte) main::i#8 ) + (byte) main::i#1 ← ++ (byte) main::i#5 + to:main::@6 +main::@11: scope:[main] from main::@9 + (byte) idx2#17 ← phi( main::@9/(byte) idx2#23 ) + (byte) idx#17 ← phi( main::@9/(byte) idx#23 ) + (byte) p0_ypos#18 ← phi( main::@9/(byte) p0_ypos#22 ) + (byte) main::i#6 ← phi( main::@9/(byte) main::i#9 ) + (byte) main::p0_idx#2 ← (number) 0 + to:main::@10 +main::@14: scope:[main] from main::@9 + (byte) idx2#20 ← phi( main::@9/(byte) idx2#23 ) + (byte) idx#20 ← phi( main::@9/(byte) idx#23 ) + (byte) p0_ypos#20 ← phi( main::@9/(byte) p0_ypos#22 ) + (byte) main::i#8 ← phi( main::@9/(byte) main::i#9 ) + (byte) main::p0_idx#6 ← phi( main::@9/(byte) main::p0_idx#5 ) + (byte) main::p0_idx#3 ← ++ (byte) main::p0_idx#6 + to:main::@10 +main::@15: scope:[main] from main::@16 main::@8 + (byte) p0_ypos#11 ← phi( main::@16/(byte) p0_ypos#15 main::@8/(byte) p0_ypos#16 ) + (byte) idx2#10 ← phi( main::@16/(byte) idx2#11 main::@8/(byte) idx2#12 ) + (byte) idx#10 ← phi( main::@16/(byte) idx#11 main::@8/(byte) idx#12 ) + (bool~) main::$7 ← (number) 0 != *((byte*)(const nomodify struct MOS6532_RIOT*) RIOT+(const byte) OFFSET_STRUCT_MOS6532_RIOT_INTIM) + if((bool~) main::$7) goto main::@16 + to:main::@1 +main::@16: scope:[main] from main::@15 + (byte) p0_ypos#15 ← phi( main::@15/(byte) p0_ypos#11 ) + (byte) idx2#11 ← phi( main::@15/(byte) idx2#10 ) + (byte) idx#11 ← phi( main::@15/(byte) idx#10 ) + *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (number) 0 + to:main::@15 +main::@return: scope:[main] from main::@1 + (byte) idx2#5 ← phi( main::@1/(byte) idx2#7 ) + (byte) p0_ypos#5 ← phi( main::@1/(byte) p0_ypos#8 ) + (byte) idx#5 ← phi( main::@1/(byte) idx#7 ) + (byte) idx#2 ← (byte) idx#5 + (byte) p0_ypos#2 ← (byte) p0_ypos#5 + (byte) idx2#2 ← (byte) idx2#5 + return + to:@return +@1: scope:[] from @begin + (byte) idx2#8 ← phi( @begin/(byte) idx2#0 ) + (byte) p0_ypos#9 ← phi( @begin/(byte) p0_ypos#0 ) + (byte) idx#8 ← phi( @begin/(byte) idx#0 ) + call main + to:@2 +@2: scope:[] from @1 + (byte) idx2#6 ← phi( @1/(byte) idx2#2 ) + (byte) p0_ypos#6 ← phi( @1/(byte) p0_ypos#2 ) + (byte) idx#6 ← phi( @1/(byte) idx#2 ) + (byte) idx#3 ← (byte) idx#6 + (byte) p0_ypos#3 ← (byte) p0_ypos#6 + (byte) idx2#3 ← (byte) idx2#6 + to:@end +@end: scope:[] from @2 + +SYMBOL TABLE SSA +(label) @1 +(label) @2 +(label) @begin +(label) @end +(byte) ATARI_TIA_READ::CXBLPF +(byte) ATARI_TIA_READ::CXM0FB +(byte) ATARI_TIA_READ::CXM0P +(byte) ATARI_TIA_READ::CXM1FB +(byte) ATARI_TIA_READ::CXM1P +(byte) ATARI_TIA_READ::CXP0FB +(byte) ATARI_TIA_READ::CXP1FB +(byte) ATARI_TIA_READ::CXPPMM +(byte) ATARI_TIA_READ::INPT0 +(byte) ATARI_TIA_READ::INPT1 +(byte) ATARI_TIA_READ::INPT2 +(byte) ATARI_TIA_READ::INPT3 +(byte) ATARI_TIA_READ::INPT4 +(byte) ATARI_TIA_READ::INPT5 +(byte) ATARI_TIA_WRITE::AUDC0 +(byte) ATARI_TIA_WRITE::AUDC1 +(byte) ATARI_TIA_WRITE::AUDF0 +(byte) ATARI_TIA_WRITE::AUDF1 +(byte) ATARI_TIA_WRITE::AUDV0 +(byte) ATARI_TIA_WRITE::AUDV1 +(byte) ATARI_TIA_WRITE::COLUBK +(byte) ATARI_TIA_WRITE::COLUP0 +(byte) ATARI_TIA_WRITE::COLUP1 +(byte) ATARI_TIA_WRITE::COLUPF +(byte) ATARI_TIA_WRITE::CTRLPF +(byte) ATARI_TIA_WRITE::CXCLR +(byte) ATARI_TIA_WRITE::ENABL +(byte) ATARI_TIA_WRITE::ENAM0 +(byte) ATARI_TIA_WRITE::ENAM1 +(byte) ATARI_TIA_WRITE::GRP0 +(byte) ATARI_TIA_WRITE::GRP1 +(byte) ATARI_TIA_WRITE::HMBL +(byte) ATARI_TIA_WRITE::HMCLR +(byte) ATARI_TIA_WRITE::HMM0 +(byte) ATARI_TIA_WRITE::HMM1 +(byte) ATARI_TIA_WRITE::HMOVE +(byte) ATARI_TIA_WRITE::HMP0 +(byte) ATARI_TIA_WRITE::HMP1 +(byte) ATARI_TIA_WRITE::NUSIZ0 +(byte) ATARI_TIA_WRITE::NUSIZ1 +(byte) ATARI_TIA_WRITE::PF0 +(byte) ATARI_TIA_WRITE::PF1 +(byte) ATARI_TIA_WRITE::PF2 +(byte) ATARI_TIA_WRITE::REFP0 +(byte) ATARI_TIA_WRITE::REFP1 +(byte) ATARI_TIA_WRITE::RESBL +(byte) ATARI_TIA_WRITE::RESM0 +(byte) ATARI_TIA_WRITE::RESM1 +(byte) ATARI_TIA_WRITE::RESMP0 +(byte) ATARI_TIA_WRITE::RESMP1 +(byte) ATARI_TIA_WRITE::RESP0 +(byte) ATARI_TIA_WRITE::RESP1 +(byte) ATARI_TIA_WRITE::RSYNC +(byte) ATARI_TIA_WRITE::VBLANK +(byte) ATARI_TIA_WRITE::VDELBL +(byte) ATARI_TIA_WRITE::VDELP0 +(byte) ATARI_TIA_WRITE::VDELP1 +(byte) ATARI_TIA_WRITE::VSYNC +(byte) ATARI_TIA_WRITE::WSYNC +(const nomodify byte) CYCLES_PER_SCANLINE = (byte) $4c +(byte) MOS6532_RIOT::INTIM +(byte) MOS6532_RIOT::SWACNT +(byte) MOS6532_RIOT::SWBCNT +(byte) MOS6532_RIOT::SWCHA +(byte) MOS6532_RIOT::SWCHB +(byte) MOS6532_RIOT::T1024T +(byte) MOS6532_RIOT::TIM1T +(byte) MOS6532_RIOT::TIM64T +(byte) MOS6532_RIOT::TIM8T +(const byte*) MOS6532_RIOT::UNUSED[(number) $f] = { fill( $f, 0) } +(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_COLUBK = (byte) 9 +(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_COLUP0 = (byte) 6 +(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_GRP0 = (byte) $1b +(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_HMOVE = (byte) $2a +(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_VBLANK = (byte) 1 +(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_VSYNC = (byte) 0 +(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC = (byte) 2 +(const byte) OFFSET_STRUCT_MOS6532_RIOT_INTIM = (byte) 4 +(const byte) OFFSET_STRUCT_MOS6532_RIOT_TIM64T = (byte) $16 +(const nomodify struct MOS6532_RIOT*) RIOT = (struct MOS6532_RIOT*)(number) $280 +(const to_nomodify byte*) SINTABLE_160[(number) $100] = kickasm {{ .fill $100, 5+round(74.5+74.5*sin(2*PI*i/256)) + }} +(const byte*) SPRITE_C[] = { (byte) 0, (byte) $18, (byte) $18, (byte) $18, (byte) $18, (byte) $3c, (byte) $3c, (byte) $3c, (byte) $3c, (byte) $66, (byte) $66, (byte) $66, (byte) $66, (byte) $c0, (byte) $c0, (byte) $c0, (byte) $c0, (byte) $c0, (byte) $c0, (byte) $c0, (byte) $c0, (byte) $66, (byte) $66, (byte) $66, (byte) $66, (byte) $3c, (byte) $3c, (byte) $3c, (byte) $3c, (byte) $18, (byte) $18, (byte) $18, (byte) $18, (byte) 0 } +(const nomodify struct ATARI_TIA_WRITE*) TIA = (struct ATARI_TIA_WRITE*)(number) 0 +(const nomodify byte*) TIA_HMP0 = (byte*)(number) $20 +(const nomodify byte*) TIA_RESP0 = (byte*)(number) $10 +(const nomodify byte*) TIA_WSYNC = (byte*)(number) 2 +(byte) idx +(byte) idx#0 +(byte) idx#1 +(byte) idx#10 +(byte) idx#11 +(byte) idx#12 +(byte) idx#13 +(byte) idx#14 +(byte) idx#15 +(byte) idx#16 +(byte) idx#17 +(byte) idx#18 +(byte) idx#19 +(byte) idx#2 +(byte) idx#20 +(byte) idx#21 +(byte) idx#22 +(byte) idx#23 +(byte) idx#3 +(byte) idx#4 +(byte) idx#5 +(byte) idx#6 +(byte) idx#7 +(byte) idx#8 +(byte) idx#9 +(byte) idx2 +(byte) idx2#0 +(byte) idx2#1 +(byte) idx2#10 +(byte) idx2#11 +(byte) idx2#12 +(byte) idx2#13 +(byte) idx2#14 +(byte) idx2#15 +(byte) idx2#16 +(byte) idx2#17 +(byte) idx2#18 +(byte) idx2#19 +(byte) idx2#2 +(byte) idx2#20 +(byte) idx2#21 +(byte) idx2#22 +(byte) idx2#23 +(byte) idx2#3 +(byte) idx2#4 +(byte) idx2#5 +(byte) idx2#6 +(byte) idx2#7 +(byte) idx2#8 +(byte) idx2#9 +(void()) main() +(bool~) main::$0 +(bool~) main::$1 +(bool~) main::$2 +(bool~) main::$3 +(bool~) main::$4 +(bool~) main::$5 +(bool~) main::$6 +(bool~) main::$7 +(label) main::@1 +(label) main::@10 +(label) main::@11 +(label) main::@12 +(label) main::@13 +(label) main::@14 +(label) main::@15 +(label) main::@16 +(label) main::@2 +(label) main::@3 +(label) main::@4 +(label) main::@5 +(label) main::@6 +(label) main::@7 +(label) main::@8 +(label) main::@9 +(label) main::@return +(byte) main::gfx +(byte) main::gfx#0 +(byte) main::i +(byte) main::i#0 +(byte) main::i#1 +(byte) main::i#2 +(byte) main::i#3 +(byte) main::i#4 +(byte) main::i#5 +(byte) main::i#6 +(byte) main::i#7 +(byte) main::i#8 +(byte) main::i#9 +(byte) main::p0_idx +(byte) main::p0_idx#0 +(byte) main::p0_idx#1 +(byte) main::p0_idx#2 +(byte) main::p0_idx#3 +(byte) main::p0_idx#4 +(byte) main::p0_idx#5 +(byte) main::p0_idx#6 +(byte) main::p0_idx#7 +(byte) main::p0_idx#8 +(byte) main::p0_idx#9 +(byte) p0_xpos loadstore = (byte) 0 +(byte) p0_ypos +(byte) p0_ypos#0 +(byte) p0_ypos#1 +(byte) p0_ypos#10 +(byte) p0_ypos#11 +(byte) p0_ypos#12 +(byte) p0_ypos#13 +(byte) p0_ypos#14 +(byte) p0_ypos#15 +(byte) p0_ypos#16 +(byte) p0_ypos#17 +(byte) p0_ypos#18 +(byte) p0_ypos#19 +(byte) p0_ypos#2 +(byte) p0_ypos#20 +(byte) p0_ypos#21 +(byte) p0_ypos#22 +(byte) p0_ypos#3 +(byte) p0_ypos#4 +(byte) p0_ypos#5 +(byte) p0_ypos#6 +(byte) p0_ypos#7 +(byte) p0_ypos#8 +(byte) p0_ypos#9 + +Adding number conversion cast (unumber) $f0 in *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_COLUP0) ← (number) $f0 +Adding number conversion cast (unumber) $af in *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_GRP0) ← (number) $af +Adding number conversion cast (unumber) 2 in *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_VSYNC) ← (number) 2 +Adding number conversion cast (unumber) $29*CYCLES_PER_SCANLINE/$40 in *((byte*)(const nomodify struct MOS6532_RIOT*) RIOT+(const byte) OFFSET_STRUCT_MOS6532_RIOT_TIM64T) ← (number) $29*(const nomodify byte) CYCLES_PER_SCANLINE/(number) $40 +Adding number conversion cast (unumber) $29 in *((byte*)(const nomodify struct MOS6532_RIOT*) RIOT+(const byte) OFFSET_STRUCT_MOS6532_RIOT_TIM64T) ← ((unumber)) (number) $29*(const nomodify byte) CYCLES_PER_SCANLINE/(number) $40 +Adding number conversion cast (unumber) 0 in *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (number) 0 +Adding number conversion cast (unumber) 0 in *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (number) 0 +Adding number conversion cast (unumber) 0 in *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (number) 0 +Adding number conversion cast (unumber) 0 in *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_VSYNC) ← (number) 0 +Adding number conversion cast (unumber) 0 in *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (number) 0 +Adding number conversion cast (unumber) 0 in *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_HMOVE) ← (number) 0 +Adding number conversion cast (unumber) 0 in (bool~) main::$5 ← (number) 0 != *((byte*)(const nomodify struct MOS6532_RIOT*) RIOT+(const byte) OFFSET_STRUCT_MOS6532_RIOT_INTIM) +Adding number conversion cast (unumber) 0 in *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (number) 0 +Adding number conversion cast (unumber) 0 in *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_VBLANK) ← (number) 0 +Adding number conversion cast (unumber) 0 in *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_COLUBK) ← (number) 0 +Adding number conversion cast (unumber) $c0 in (bool~) main::$0 ← (byte) main::i#2 < (number) $c0 +Adding number conversion cast (unumber) 0 in *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (number) 0 +Adding number conversion cast (unumber) 0 in (bool~) main::$6 ← (number) 0 != (byte) main::p0_idx#4 +Adding number conversion cast (unumber) 0 in *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (number) 0 +Adding number conversion cast (unumber) 2 in *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_VBLANK) ← (number) 2 +Adding number conversion cast (unumber) 0 in *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_COLUBK) ← (number) 0 +Adding number conversion cast (unumber) $1b*CYCLES_PER_SCANLINE/$40 in *((byte*)(const nomodify struct MOS6532_RIOT*) RIOT+(const byte) OFFSET_STRUCT_MOS6532_RIOT_TIM64T) ← (number) $1b*(const nomodify byte) CYCLES_PER_SCANLINE/(number) $40 +Adding number conversion cast (unumber) $1b in *((byte*)(const nomodify struct MOS6532_RIOT*) RIOT+(const byte) OFFSET_STRUCT_MOS6532_RIOT_TIM64T) ← ((unumber)) (number) $1b*(const nomodify byte) CYCLES_PER_SCANLINE/(number) $40 +Adding number conversion cast (unumber) 0 in (bool~) main::$3 ← (byte) main::gfx#0 == (number) 0 +Adding number conversion cast (unumber) 1 in (byte) main::p0_idx#1 ← (number) 1 +Adding number conversion cast (unumber) 0 in (byte) main::p0_idx#2 ← (number) 0 +Adding number conversion cast (unumber) 0 in (bool~) main::$7 ← (number) 0 != *((byte*)(const nomodify struct MOS6532_RIOT*) RIOT+(const byte) OFFSET_STRUCT_MOS6532_RIOT_INTIM) +Adding number conversion cast (unumber) 0 in *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (number) 0 +Successful SSA optimization PassNAddNumberTypeConversions +Adding number conversion cast (unumber) $40 in *((byte*)(const nomodify struct MOS6532_RIOT*) RIOT+(const byte) OFFSET_STRUCT_MOS6532_RIOT_TIM64T) ← ((unumber)) (unumber)(number) $29*(const nomodify byte) CYCLES_PER_SCANLINE/(number) $40 +Adding number conversion cast (unumber) $40 in *((byte*)(const nomodify struct MOS6532_RIOT*) RIOT+(const byte) OFFSET_STRUCT_MOS6532_RIOT_TIM64T) ← ((unumber)) (unumber)(number) $1b*(const nomodify byte) CYCLES_PER_SCANLINE/(number) $40 +Successful SSA optimization PassNAddNumberTypeConversions +Inlining cast *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_COLUP0) ← (unumber)(number) $f0 +Inlining cast *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_GRP0) ← (unumber)(number) $af +Inlining cast *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_VSYNC) ← (unumber)(number) 2 +Inlining cast *((byte*)(const nomodify struct MOS6532_RIOT*) RIOT+(const byte) OFFSET_STRUCT_MOS6532_RIOT_TIM64T) ← (unumber)(unumber)(number) $29*(const nomodify byte) CYCLES_PER_SCANLINE/(unumber)(number) $40 +Inlining cast *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (unumber)(number) 0 +Inlining cast *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (unumber)(number) 0 +Inlining cast *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (unumber)(number) 0 +Inlining cast *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_VSYNC) ← (unumber)(number) 0 +Inlining cast *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (unumber)(number) 0 +Inlining cast *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_HMOVE) ← (unumber)(number) 0 +Inlining cast *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (unumber)(number) 0 +Inlining cast *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_VBLANK) ← (unumber)(number) 0 +Inlining cast *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_COLUBK) ← (unumber)(number) 0 +Inlining cast *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (unumber)(number) 0 +Inlining cast *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (unumber)(number) 0 +Inlining cast *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_VBLANK) ← (unumber)(number) 2 +Inlining cast *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_COLUBK) ← (unumber)(number) 0 +Inlining cast *((byte*)(const nomodify struct MOS6532_RIOT*) RIOT+(const byte) OFFSET_STRUCT_MOS6532_RIOT_TIM64T) ← (unumber)(unumber)(number) $1b*(const nomodify byte) CYCLES_PER_SCANLINE/(unumber)(number) $40 +Inlining cast (byte) main::p0_idx#1 ← (unumber)(number) 1 +Inlining cast (byte) main::p0_idx#2 ← (unumber)(number) 0 +Inlining cast *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (unumber)(number) 0 +Successful SSA optimization Pass2InlineCast +Simplifying constant pointer cast (byte*) 2 +Simplifying constant pointer cast (byte*) 16 +Simplifying constant pointer cast (byte*) 32 +Simplifying constant pointer cast (struct ATARI_TIA_WRITE*) 0 +Simplifying constant pointer cast (struct MOS6532_RIOT*) 640 +Simplifying constant integer cast $f0 +Simplifying constant integer cast $af +Simplifying constant integer cast 2 +Simplifying constant integer cast (unumber)(number) $29*(const nomodify byte) CYCLES_PER_SCANLINE/(unumber)(number) $40 +Simplifying constant integer cast $29 +Simplifying constant integer cast $40 +Simplifying constant integer cast 0 +Simplifying constant integer cast 0 +Simplifying constant integer cast 0 +Simplifying constant integer cast 0 +Simplifying constant integer cast 0 +Simplifying constant integer cast 0 +Simplifying constant integer cast 0 +Simplifying constant integer cast 0 +Simplifying constant integer cast 0 +Simplifying constant integer cast 0 +Simplifying constant integer cast $c0 +Simplifying constant integer cast 0 +Simplifying constant integer cast 0 +Simplifying constant integer cast 0 +Simplifying constant integer cast 2 +Simplifying constant integer cast 0 +Simplifying constant integer cast (unumber)(number) $1b*(const nomodify byte) CYCLES_PER_SCANLINE/(unumber)(number) $40 +Simplifying constant integer cast $1b +Simplifying constant integer cast $40 +Simplifying constant integer cast 0 +Simplifying constant integer cast 1 +Simplifying constant integer cast 0 +Simplifying constant integer cast 0 +Simplifying constant integer cast 0 +Successful SSA optimization PassNCastSimplification +Finalized unsigned number type (byte) $f0 +Finalized unsigned number type (byte) $af +Finalized unsigned number type (byte) 2 +Finalized unsigned number type (byte) $29 +Finalized unsigned number type (byte) $40 +Finalized unsigned number type (byte) 0 +Finalized unsigned number type (byte) 0 +Finalized unsigned number type (byte) 0 +Finalized unsigned number type (byte) 0 +Finalized unsigned number type (byte) 0 +Finalized unsigned number type (byte) 0 +Finalized unsigned number type (byte) 0 +Finalized unsigned number type (byte) 0 +Finalized unsigned number type (byte) 0 +Finalized unsigned number type (byte) 0 +Finalized unsigned number type (byte) $c0 +Finalized unsigned number type (byte) 0 +Finalized unsigned number type (byte) 0 +Finalized unsigned number type (byte) 0 +Finalized unsigned number type (byte) 2 +Finalized unsigned number type (byte) 0 +Finalized unsigned number type (byte) $1b +Finalized unsigned number type (byte) $40 +Finalized unsigned number type (byte) 0 +Finalized unsigned number type (byte) 1 +Finalized unsigned number type (byte) 0 +Finalized unsigned number type (byte) 0 +Finalized unsigned number type (byte) 0 +Successful SSA optimization PassNFinalizeNumberTypeConversions +Inversing boolean not [54] (bool~) main::$2 ← (byte) p0_ypos#4 != (byte) main::i#4 from [53] (bool~) main::$1 ← (byte) p0_ypos#4 == (byte) main::i#4 +Successful SSA optimization Pass2UnaryNotSimplification +Alias idx#2 = idx#4 idx#7 idx#5 +Alias idx2#2 = idx2#4 idx2#7 idx2#5 +Alias p0_ypos#14 = p0_ypos#21 p0_ypos#17 +Alias idx#15 = idx#21 idx#16 +Alias idx2#15 = idx2#21 idx2#16 +Alias main::i#2 = main::i#3 main::i#9 main::i#4 main::i#7 main::i#6 main::i#8 +Alias main::p0_idx#4 = main::p0_idx#7 main::p0_idx#5 main::p0_idx#9 main::p0_idx#6 +Alias p0_ypos#12 = p0_ypos#7 p0_ypos#16 p0_ypos#22 p0_ypos#4 p0_ypos#19 p0_ypos#18 p0_ypos#20 +Alias idx#12 = idx#22 idx#13 idx#23 idx#18 idx#19 idx#17 idx#20 +Alias idx2#12 = idx2#22 idx2#13 idx2#23 idx2#18 idx2#19 idx2#17 idx2#20 +Alias idx#10 = idx#11 +Alias idx2#10 = idx2#11 +Alias p0_ypos#11 = p0_ypos#15 +Alias p0_ypos#2 = p0_ypos#5 p0_ypos#8 +Alias idx#0 = idx#8 +Alias p0_ypos#0 = p0_ypos#9 +Alias idx2#0 = idx2#8 +Alias idx#3 = idx#6 +Alias p0_ypos#3 = p0_ypos#6 +Alias idx2#3 = idx2#6 +Successful SSA optimization Pass2AliasElimination +Alias main::i#2 = main::i#5 +Alias p0_ypos#12 = p0_ypos#13 +Alias idx#12 = idx#14 +Alias idx2#12 = idx2#14 +Successful SSA optimization Pass2AliasElimination +Identical Phi Values (byte) idx#9 (byte) idx#0 +Identical Phi Values (byte) idx2#9 (byte) idx2#0 +Identical Phi Values (byte) p0_ypos#10 (byte) p0_ypos#0 +Identical Phi Values (byte) p0_ypos#14 (byte) p0_ypos#1 +Identical Phi Values (byte) idx#15 (byte) idx#1 +Identical Phi Values (byte) idx2#15 (byte) idx2#1 +Identical Phi Values (byte) p0_ypos#12 (byte) p0_ypos#14 +Identical Phi Values (byte) idx#12 (byte) idx#15 +Identical Phi Values (byte) idx2#12 (byte) idx2#15 +Identical Phi Values (byte) idx#10 (byte) idx#12 +Identical Phi Values (byte) idx2#10 (byte) idx2#12 +Identical Phi Values (byte) p0_ypos#11 (byte) p0_ypos#12 +Identical Phi Values (byte) idx#3 (byte) idx#2 +Identical Phi Values (byte) p0_ypos#3 (byte) p0_ypos#2 +Identical Phi Values (byte) idx2#3 (byte) idx2#2 +Successful SSA optimization Pass2IdenticalPhiElimination +Simple Condition (bool~) main::$4 [9] if((number) 0!=(number) 1) goto main::@2 +Simple Condition (bool~) main::$5 [25] if((byte) 0!=*((byte*)(const nomodify struct MOS6532_RIOT*) RIOT+(const byte) OFFSET_STRUCT_MOS6532_RIOT_INTIM)) goto main::@4 +Simple Condition (bool~) main::$0 [33] if((byte) main::i#2<(byte) $c0) goto main::@7 +Simple Condition (bool~) main::$6 [37] if((byte) 0!=(byte) main::p0_idx#4) goto main::@9 +Simple Condition (bool~) main::$3 [45] if((byte) main::gfx#0==(byte) 0) goto main::@11 +Simple Condition (bool~) main::$2 [47] if((byte) p0_ypos#1!=(byte) main::i#2) goto main::@10 +Simple Condition (bool~) main::$7 [55] if((byte) 0!=*((byte*)(const nomodify struct MOS6532_RIOT*) RIOT+(const byte) OFFSET_STRUCT_MOS6532_RIOT_INTIM)) goto main::@16 +Successful SSA optimization Pass2ConditionalJumpSimplification +Constant (const byte) idx#0 = 0 +Constant (const byte) idx2#0 = $39 +Constant (const byte) p0_ypos#0 = 0 +Constant (const byte) main::p0_idx#0 = 0 +Constant (const byte) main::i#0 = 1 +Constant (const byte) main::p0_idx#1 = 1 +Constant (const byte) main::p0_idx#2 = 0 +Successful SSA optimization Pass2ConstantIdentification +if() condition always true - replacing block destination [9] if((number) 0!=(number) 1) goto main::@2 +Successful SSA optimization Pass2ConstantIfs +Simplifying expression containing zero (byte*)TIA in [10] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_VSYNC) ← (byte) 2 +Simplifying expression containing zero (byte*)TIA in [15] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_VSYNC) ← (byte) 0 +Successful SSA optimization PassNSimplifyExpressionWithZero +Eliminating unused variable - keeping the phi block (byte) p0_ypos#2 +Eliminating unused constant (const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_VSYNC +Successful SSA optimization PassNEliminateUnusedVars +Eliminating unused constant (const byte) p0_ypos#0 +Successful SSA optimization PassNEliminateUnusedVars +Removing unused block main::@return +Successful SSA optimization Pass2EliminateUnusedBlocks +Inlining constant with var siblings (const byte) main::p0_idx#0 +Inlining constant with var siblings (const byte) main::i#0 +Inlining constant with var siblings (const byte) main::p0_idx#1 +Inlining constant with var siblings (const byte) main::p0_idx#2 +Inlining constant with var siblings (const byte) idx#0 +Inlining constant with var siblings (const byte) idx2#0 +Constant inlined idx2#0 = (byte) $39 +Constant inlined main::p0_idx#0 = (byte) 0 +Constant inlined main::i#0 = (byte) 1 +Constant inlined main::p0_idx#1 = (byte) 1 +Constant inlined main::p0_idx#2 = (byte) 0 +Constant inlined idx#0 = (byte) 0 +Successful SSA optimization Pass2ConstantInlining +Added new block during phi lifting main::@17(between main::@15 and main::@1) +Added new block during phi lifting main::@18(between main::@12 and main::@10) +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::@13 +Adding NOP phi() at start of main::@11 +CALL GRAPH +Calls in [] to main:2 + +Created 5 initial phi equivalence classes +Coalesced [32] idx#24 ← idx#1 +Coalesced [33] idx2#24 ← idx2#1 +Coalesced [42] main::i#10 ← main::i#1 +Coalesced [43] main::p0_idx#10 ← main::p0_idx#8 +Coalesced (already) [44] main::p0_idx#11 ← main::p0_idx#4 +Coalesced [49] main::p0_idx#12 ← main::p0_idx#3 +Coalesced down to 4 phi equivalence classes +Culled Empty Block (label) @2 +Culled Empty Block (label) main::@17 +Culled Empty Block (label) main::@13 +Culled Empty Block (label) main::@11 +Renumbering block main::@12 to main::@11 +Renumbering block main::@14 to main::@12 +Renumbering block main::@15 to main::@13 +Renumbering block main::@16 to main::@14 +Renumbering block main::@18 to main::@15 +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::@15 + +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() + +(void()) main() +main: scope:[main] from @1 + asm { cld } + [5] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_COLUP0) ← (byte) $f0 + [6] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_GRP0) ← (byte) $af + to:main::@1 +main::@1: scope:[main] from main main::@13 + [7] (byte) idx2#2 ← phi( main/(byte) $39 main::@13/(byte) idx2#1 ) + [7] (byte) idx#2 ← phi( main/(byte) 0 main::@13/(byte) idx#1 ) + to:main::@2 +main::@2: scope:[main] from main::@1 + [8] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA) ← (byte) 2 + [9] *((byte*)(const nomodify struct MOS6532_RIOT*) RIOT+(const byte) OFFSET_STRUCT_MOS6532_RIOT_TIM64T) ← (byte) $29*(const nomodify byte) CYCLES_PER_SCANLINE/(byte) $40 + [10] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 + [11] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 + [12] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 + [13] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA) ← (byte) 0 + asm { ldap0_xpos staTIA_WSYNC sec !: sbc#$f bcs!- eor#7 asl asl asl asl staTIA_HMP0 staTIA_RESP0 } + [15] (byte) p0_xpos ← *((const to_nomodify byte*) SINTABLE_160 + (byte) idx#2) + [16] (byte) idx#1 ← ++ (byte) idx#2 + [17] (byte) p0_ypos#1 ← *((const to_nomodify byte*) SINTABLE_160 + (byte) idx2#2) + [18] (byte) idx2#1 ← ++ (byte) idx2#2 + [19] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 + [20] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_HMOVE) ← (byte) 0 + to:main::@3 +main::@3: scope:[main] from main::@2 main::@4 + [21] if((byte) 0!=*((byte*)(const nomodify struct MOS6532_RIOT*) RIOT+(const byte) OFFSET_STRUCT_MOS6532_RIOT_INTIM)) goto main::@4 + to:main::@5 +main::@5: scope:[main] from main::@3 + [22] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_VBLANK) ← (byte) 0 + [23] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_COLUBK) ← (byte) 0 + to:main::@6 +main::@6: scope:[main] from main::@10 main::@5 + [24] (byte) main::p0_idx#4 ← phi( main::@10/(byte) main::p0_idx#8 main::@5/(byte) 0 ) + [24] (byte) main::i#2 ← phi( main::@10/(byte) main::i#1 main::@5/(byte) 1 ) + [25] if((byte) main::i#2<(byte) $c0) goto main::@7 + to:main::@8 +main::@8: scope:[main] from main::@6 + [26] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 + [27] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_VBLANK) ← (byte) 2 + [28] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_COLUBK) ← (byte) 0 + [29] *((byte*)(const nomodify struct MOS6532_RIOT*) RIOT+(const byte) OFFSET_STRUCT_MOS6532_RIOT_TIM64T) ← (byte) $1b*(const nomodify byte) CYCLES_PER_SCANLINE/(byte) $40 + to:main::@13 +main::@13: scope:[main] from main::@14 main::@8 + [30] if((byte) 0!=*((byte*)(const nomodify struct MOS6532_RIOT*) RIOT+(const byte) OFFSET_STRUCT_MOS6532_RIOT_INTIM)) goto main::@14 + to:main::@1 +main::@14: scope:[main] from main::@13 + [31] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 + to:main::@13 +main::@7: scope:[main] from main::@6 + [32] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 + [33] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_COLUBK) ← (byte) main::i#2 + [34] if((byte) 0!=(byte) main::p0_idx#4) goto main::@9 + to:main::@11 +main::@11: scope:[main] from main::@7 + [35] if((byte) p0_ypos#1!=(byte) main::i#2) goto main::@15 + to:main::@10 +main::@15: scope:[main] from main::@11 + [36] phi() + to:main::@10 +main::@10: scope:[main] from main::@11 main::@12 main::@15 main::@9 + [37] (byte) main::p0_idx#8 ← phi( main::@9/(byte) 0 main::@15/(byte) main::p0_idx#4 main::@11/(byte) 1 main::@12/(byte) main::p0_idx#3 ) + [38] (byte) main::i#1 ← ++ (byte) main::i#2 + to:main::@6 +main::@9: scope:[main] from main::@7 + [39] (byte) main::gfx#0 ← *((const byte*) SPRITE_C + (byte) main::p0_idx#4) + [40] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_GRP0) ← (byte) main::gfx#0 + [41] if((byte) main::gfx#0==(byte) 0) goto main::@10 + to:main::@12 +main::@12: scope:[main] from main::@9 + [42] (byte) main::p0_idx#3 ← ++ (byte) main::p0_idx#4 + to:main::@10 +main::@4: scope:[main] from main::@3 + [43] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 + to:main::@3 + + +VARIABLE REGISTER WEIGHTS +(byte) ATARI_TIA_READ::CXBLPF +(byte) ATARI_TIA_READ::CXM0FB +(byte) ATARI_TIA_READ::CXM0P +(byte) ATARI_TIA_READ::CXM1FB +(byte) ATARI_TIA_READ::CXM1P +(byte) ATARI_TIA_READ::CXP0FB +(byte) ATARI_TIA_READ::CXP1FB +(byte) ATARI_TIA_READ::CXPPMM +(byte) ATARI_TIA_READ::INPT0 +(byte) ATARI_TIA_READ::INPT1 +(byte) ATARI_TIA_READ::INPT2 +(byte) ATARI_TIA_READ::INPT3 +(byte) ATARI_TIA_READ::INPT4 +(byte) ATARI_TIA_READ::INPT5 +(byte) ATARI_TIA_WRITE::AUDC0 +(byte) ATARI_TIA_WRITE::AUDC1 +(byte) ATARI_TIA_WRITE::AUDF0 +(byte) ATARI_TIA_WRITE::AUDF1 +(byte) ATARI_TIA_WRITE::AUDV0 +(byte) ATARI_TIA_WRITE::AUDV1 +(byte) ATARI_TIA_WRITE::COLUBK +(byte) ATARI_TIA_WRITE::COLUP0 +(byte) ATARI_TIA_WRITE::COLUP1 +(byte) ATARI_TIA_WRITE::COLUPF +(byte) ATARI_TIA_WRITE::CTRLPF +(byte) ATARI_TIA_WRITE::CXCLR +(byte) ATARI_TIA_WRITE::ENABL +(byte) ATARI_TIA_WRITE::ENAM0 +(byte) ATARI_TIA_WRITE::ENAM1 +(byte) ATARI_TIA_WRITE::GRP0 +(byte) ATARI_TIA_WRITE::GRP1 +(byte) ATARI_TIA_WRITE::HMBL +(byte) ATARI_TIA_WRITE::HMCLR +(byte) ATARI_TIA_WRITE::HMM0 +(byte) ATARI_TIA_WRITE::HMM1 +(byte) ATARI_TIA_WRITE::HMOVE +(byte) ATARI_TIA_WRITE::HMP0 +(byte) ATARI_TIA_WRITE::HMP1 +(byte) ATARI_TIA_WRITE::NUSIZ0 +(byte) ATARI_TIA_WRITE::NUSIZ1 +(byte) ATARI_TIA_WRITE::PF0 +(byte) ATARI_TIA_WRITE::PF1 +(byte) ATARI_TIA_WRITE::PF2 +(byte) ATARI_TIA_WRITE::REFP0 +(byte) ATARI_TIA_WRITE::REFP1 +(byte) ATARI_TIA_WRITE::RESBL +(byte) ATARI_TIA_WRITE::RESM0 +(byte) ATARI_TIA_WRITE::RESM1 +(byte) ATARI_TIA_WRITE::RESMP0 +(byte) ATARI_TIA_WRITE::RESMP1 +(byte) ATARI_TIA_WRITE::RESP0 +(byte) ATARI_TIA_WRITE::RESP1 +(byte) ATARI_TIA_WRITE::RSYNC +(byte) ATARI_TIA_WRITE::VBLANK +(byte) ATARI_TIA_WRITE::VDELBL +(byte) ATARI_TIA_WRITE::VDELP0 +(byte) ATARI_TIA_WRITE::VDELP1 +(byte) ATARI_TIA_WRITE::VSYNC +(byte) ATARI_TIA_WRITE::WSYNC +(byte) MOS6532_RIOT::INTIM +(byte) MOS6532_RIOT::SWACNT +(byte) MOS6532_RIOT::SWBCNT +(byte) MOS6532_RIOT::SWCHA +(byte) MOS6532_RIOT::SWCHB +(byte) MOS6532_RIOT::T1024T +(byte) MOS6532_RIOT::TIM1T +(byte) MOS6532_RIOT::TIM64T +(byte) MOS6532_RIOT::TIM8T +(byte) idx +(byte) idx#1 39.357142857142854 +(byte) idx#2 133.66666666666669 +(byte) idx2 +(byte) idx2#1 42.38461538461539 +(byte) idx2#2 109.36363636363637 +(void()) main() +(byte) main::gfx +(byte) main::gfx#0 1501.5 +(byte) main::i +(byte) main::i#1 2002.0 +(byte) main::i#2 417.08333333333337 +(byte) main::p0_idx +(byte) main::p0_idx#3 2002.0 +(byte) main::p0_idx#4 500.5 +(byte) main::p0_idx#8 1501.5 +(byte) p0_xpos loadstore 2.4634146341463414 = (byte) 0 +(byte) p0_ypos +(byte) p0_ypos#1 52.476190476190474 + +Initial phi equivalence classes +[ idx#2 idx#1 ] +[ idx2#2 idx2#1 ] +[ main::i#2 main::i#1 ] +[ main::p0_idx#4 main::p0_idx#8 main::p0_idx#3 ] +Added variable p0_xpos to live range equivalence class [ p0_xpos ] +Added variable p0_ypos#1 to live range equivalence class [ p0_ypos#1 ] +Added variable main::gfx#0 to live range equivalence class [ main::gfx#0 ] +Complete equivalence classes +[ idx#2 idx#1 ] +[ idx2#2 idx2#1 ] +[ main::i#2 main::i#1 ] +[ main::p0_idx#4 main::p0_idx#8 main::p0_idx#3 ] +[ p0_xpos ] +[ p0_ypos#1 ] +[ main::gfx#0 ] +Allocated mem[1] [ idx#2 idx#1 ] +Allocated mem[1] [ idx2#2 idx2#1 ] +Allocated mem[1] [ main::i#2 main::i#1 ] +Allocated mem[1] [ main::p0_idx#4 main::p0_idx#8 main::p0_idx#3 ] +Allocated mem[1] [ p0_xpos ] +Allocated mem[1] [ p0_ypos#1 ] +Allocated mem[1] [ main::gfx#0 ] + +INITIAL ASM +Target platform is atari2600 / MOS6502X + // File Comments +// Minimal Atari 2600 VCS Program using Sprites +// Source: https://atariage.com/forums/blogs/entry/11109-step-1-generate-a-stable-display/ + // Upstart + // Atari 2600 VCS 2K ROM +.file [name="atari2600-sprites.a26", type="bin", segments="Code, Data, Vectors"] +.segmentdef Code [start=$f800,min=$f800,max=$fff9] +.segmentdef Data [startAfter="Code",max=$fff9] +.segmentdef Vectors [start=$fffa,max=$ffff] +.segmentdef Vars [start=$80,max=$ff, virtual] +.segment Vectors +.word main // NMI +.word main // RESET +.word main // IRQ +.segment Code + + // Global Constants & labels + // The number of CPU cycles per scanline + .const CYCLES_PER_SCANLINE = $4c + .const OFFSET_STRUCT_ATARI_TIA_WRITE_COLUP0 = 6 + .const OFFSET_STRUCT_ATARI_TIA_WRITE_GRP0 = $1b + .const OFFSET_STRUCT_MOS6532_RIOT_TIM64T = $16 + .const OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC = 2 + .const OFFSET_STRUCT_ATARI_TIA_WRITE_HMOVE = $2a + .const OFFSET_STRUCT_MOS6532_RIOT_INTIM = 4 + .const OFFSET_STRUCT_ATARI_TIA_WRITE_VBLANK = 1 + .const OFFSET_STRUCT_ATARI_TIA_WRITE_COLUBK = 9 + // The TIA WSYNC register (for access from inline ASM) + .label TIA_WSYNC = 2 + // The TIA RESP0 register (for access from inline ASM) + .label TIA_RESP0 = $10 + // The TIA HMP0 register (for access from inline ASM) + .label TIA_HMP0 = $20 + // Atari TIA write registers + .label TIA = 0 + // Atari RIOT registers + .label RIOT = $280 + // @begin +__bbegin: + // [1] phi from @begin to @1 [phi:@begin->@1] +__b1_from___bbegin: + jmp __b1 + // @1 +__b1: + // [2] call main + jsr main + // [3] phi from @1 to @end [phi:@1->@end] +__bend_from___b1: + jmp __bend + // @end +__bend: +.segment Code + // main +main: { + // asm { cld } + cld + // [5] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_COLUP0) ← (byte) $f0 -- _deref_pbuc1=vbuc2 + // Player 0 + // - Color + lda #$f0 + sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_COLUP0 + // [6] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_GRP0) ← (byte) $af -- _deref_pbuc1=vbuc2 + // - Graphics + lda #$af + sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_GRP0 + // [7] phi from main to main::@1 [phi:main->main::@1] + __b1_from_main: + // [7] phi (byte) idx2#2 = (byte) $39 [phi:main->main::@1#0] -- vbum1=vbuc1 + lda #$39 + sta idx2 + // [7] phi (byte) idx#2 = (byte) 0 [phi:main->main::@1#1] -- vbum1=vbuc1 + lda #0 + sta idx + jmp __b1 + // Player 1 + // - Color + //TIA->COLUP1 = 0xf0; + // - Graphics + //TIA->GRP1 = 0xf5; + // main::@1 + __b1: + jmp __b2 + // main::@2 + __b2: + // [8] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA) ← (byte) 2 -- _deref_pbuc1=vbuc2 + // Vertical Sync + // here we generate the signal that tells the TV to move the beam to the top of + // the screen so we can start the next frame of video. + // The Sync Signal must be on for 3 scanlines. + lda #2 + sta TIA + // [9] *((byte*)(const nomodify struct MOS6532_RIOT*) RIOT+(const byte) OFFSET_STRUCT_MOS6532_RIOT_TIM64T) ← (byte) $29*(const nomodify byte) CYCLES_PER_SCANLINE/(byte) $40 -- _deref_pbuc1=vbuc2 + // D1=1, turns on Vertical Sync signal + lda #$29*CYCLES_PER_SCANLINE/$40 + sta RIOT+OFFSET_STRUCT_MOS6532_RIOT_TIM64T + // [10] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 -- _deref_pbuc1=vbuc2 + // Set timer to wait 41 lines + lda #0 + sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC + // [11] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 -- _deref_pbuc1=vbuc2 + // Wait for Sync - halts CPU until end of 1st scanline of VSYNC + lda #0 + sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC + // [12] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 -- _deref_pbuc1=vbuc2 + // wait until end of 2nd scanline of VSYNC + lda #0 + sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC + // [13] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA) ← (byte) 0 -- _deref_pbuc1=vbuc2 + // wait until end of 3rd scanline of VSYNC + lda #0 + sta TIA + // asm { ldap0_xpos staTIA_WSYNC sec !: sbc#$f bcs!- eor#7 asl asl asl asl staTIA_HMP0 staTIA_RESP0 } + // Vertical Sprite Position Player 0 - inline ASM to achieve cycle exact code + lda p0_xpos + sta TIA_WSYNC + sec + !: + sbc #$f + bcs !- + eor #7 + asl + asl + asl + asl + sta TIA_HMP0 + sta TIA_RESP0 + // [15] (byte) p0_xpos ← *((const to_nomodify byte*) SINTABLE_160 + (byte) idx#2) -- vbum1=pbuc1_derefidx_vbum2 + ldy idx + lda SINTABLE_160,y + sta p0_xpos + // [16] (byte) idx#1 ← ++ (byte) idx#2 -- vbum1=_inc_vbum1 + inc idx + // [17] (byte) p0_ypos#1 ← *((const to_nomodify byte*) SINTABLE_160 + (byte) idx2#2) -- vbum1=pbuc1_derefidx_vbum2 + ldy idx2 + lda SINTABLE_160,y + sta p0_ypos + // [18] (byte) idx2#1 ← ++ (byte) idx2#2 -- vbum1=_inc_vbum1 + inc idx2 + // [19] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 -- _deref_pbuc1=vbuc2 + // Execute horisontal movement + lda #0 + sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC + // [20] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_HMOVE) ← (byte) 0 -- _deref_pbuc1=vbuc2 + lda #0 + sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_HMOVE + jmp __b3 + // Wait for the timer to run out + // main::@3 + __b3: + // [21] if((byte) 0!=*((byte*)(const nomodify struct MOS6532_RIOT*) RIOT+(const byte) OFFSET_STRUCT_MOS6532_RIOT_INTIM)) goto main::@4 -- vbuc1_neq__deref_pbuc2_then_la1 + lda #0 + cmp RIOT+OFFSET_STRUCT_MOS6532_RIOT_INTIM + bne __b4 + jmp __b5 + // main::@5 + __b5: + // [22] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_VBLANK) ← (byte) 0 -- _deref_pbuc1=vbuc2 + // Screen - display logic + // Update the registers in TIA (the video chip) in order to generate what the player sees. + // For now we're just going to output 192 colored scanlines lines so we have something to see. + lda #0 + sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_VBLANK + // [23] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_COLUBK) ← (byte) 0 -- _deref_pbuc1=vbuc2 + // D1=1, turns off Vertical Blank signal (image output on) + lda #0 + sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_COLUBK + // [24] phi from main::@5 to main::@6 [phi:main::@5->main::@6] + __b6_from___b5: + // [24] phi (byte) main::p0_idx#4 = (byte) 0 [phi:main::@5->main::@6#0] -- vbum1=vbuc1 + lda #0 + sta p0_idx + // [24] phi (byte) main::i#2 = (byte) 1 [phi:main::@5->main::@6#1] -- vbum1=vbuc1 + lda #1 + sta i + jmp __b6 + // main::@6 + __b6: + // [25] if((byte) main::i#2<(byte) $c0) goto main::@7 -- vbum1_lt_vbuc1_then_la1 + lda i + cmp #$c0 + bcc __b7 + jmp __b8 + // main::@8 + __b8: + // [26] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 -- _deref_pbuc1=vbuc2 + // Start OverScan + lda #0 + sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC + // [27] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_VBLANK) ← (byte) 2 -- _deref_pbuc1=vbuc2 + // Wait for SYNC (halts CPU until end of scanline) + lda #2 + sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_VBLANK + // [28] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_COLUBK) ← (byte) 0 -- _deref_pbuc1=vbuc2 + // D1=1 turns image output off + lda #0 + sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_COLUBK + // [29] *((byte*)(const nomodify struct MOS6532_RIOT*) RIOT+(const byte) OFFSET_STRUCT_MOS6532_RIOT_TIM64T) ← (byte) $1b*(const nomodify byte) CYCLES_PER_SCANLINE/(byte) $40 -- _deref_pbuc1=vbuc2 + // Set background color to black + lda #$1b*CYCLES_PER_SCANLINE/$40 + sta RIOT+OFFSET_STRUCT_MOS6532_RIOT_TIM64T + jmp __b13 + // Wait for the timer to run out + // main::@13 + __b13: + // [30] if((byte) 0!=*((byte*)(const nomodify struct MOS6532_RIOT*) RIOT+(const byte) OFFSET_STRUCT_MOS6532_RIOT_INTIM)) goto main::@14 -- vbuc1_neq__deref_pbuc2_then_la1 + lda #0 + cmp RIOT+OFFSET_STRUCT_MOS6532_RIOT_INTIM + bne __b14 + // [7] phi from main::@13 to main::@1 [phi:main::@13->main::@1] + __b1_from___b13: + // [7] phi (byte) idx2#2 = (byte) idx2#1 [phi:main::@13->main::@1#0] -- register_copy + // [7] phi (byte) idx#2 = (byte) idx#1 [phi:main::@13->main::@1#1] -- register_copy + jmp __b1 + // main::@14 + __b14: + // [31] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 -- _deref_pbuc1=vbuc2 + lda #0 + sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC + jmp __b13 + // main::@7 + __b7: + // [32] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 -- _deref_pbuc1=vbuc2 + // Wait for SYNC (halts CPU until end of scanline) + lda #0 + sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC + // [33] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_COLUBK) ← (byte) main::i#2 -- _deref_pbuc1=vbum1 + lda i + sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_COLUBK + // [34] if((byte) 0!=(byte) main::p0_idx#4) goto main::@9 -- vbuc1_neq_vbum1_then_la1 + lda #0 + cmp p0_idx + bne __b9 + jmp __b11 + // main::@11 + __b11: + // [35] if((byte) p0_ypos#1!=(byte) main::i#2) goto main::@15 -- vbum1_neq_vbum2_then_la1 + lda p0_ypos + cmp i + bne __b15_from___b11 + // [37] phi from main::@11 to main::@10 [phi:main::@11->main::@10] + __b10_from___b11: + // [37] phi (byte) main::p0_idx#8 = (byte) 1 [phi:main::@11->main::@10#0] -- vbum1=vbuc1 + lda #1 + sta p0_idx + jmp __b10 + // [36] phi from main::@11 to main::@15 [phi:main::@11->main::@15] + __b15_from___b11: + jmp __b15 + // main::@15 + __b15: + // [37] phi from main::@12 main::@15 to main::@10 [phi:main::@12/main::@15->main::@10] + __b10_from___b12: + __b10_from___b15: + // [37] phi (byte) main::p0_idx#8 = (byte) main::p0_idx#3 [phi:main::@12/main::@15->main::@10#0] -- register_copy + jmp __b10 + // [37] phi from main::@9 to main::@10 [phi:main::@9->main::@10] + __b10_from___b9: + // [37] phi (byte) main::p0_idx#8 = (byte) 0 [phi:main::@9->main::@10#0] -- vbum1=vbuc1 + lda #0 + sta p0_idx + jmp __b10 + // main::@10 + __b10: + // [38] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbum1=_inc_vbum1 + inc i + // [24] phi from main::@10 to main::@6 [phi:main::@10->main::@6] + __b6_from___b10: + // [24] phi (byte) main::p0_idx#4 = (byte) main::p0_idx#8 [phi:main::@10->main::@6#0] -- register_copy + // [24] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@10->main::@6#1] -- register_copy + jmp __b6 + // main::@9 + __b9: + // [39] (byte) main::gfx#0 ← *((const byte*) SPRITE_C + (byte) main::p0_idx#4) -- vbum1=pbuc1_derefidx_vbum2 + // Player 0 is active - show it + ldy p0_idx + lda SPRITE_C,y + sta gfx + // [40] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_GRP0) ← (byte) main::gfx#0 -- _deref_pbuc1=vbum1 + lda gfx + sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_GRP0 + // [41] if((byte) main::gfx#0==(byte) 0) goto main::@10 -- vbum1_eq_0_then_la1 + lda gfx + cmp #0 + beq __b10_from___b9 + jmp __b12 + // main::@12 + __b12: + // [42] (byte) main::p0_idx#3 ← ++ (byte) main::p0_idx#4 -- vbum1=_inc_vbum1 + inc p0_idx + jmp __b10_from___b12 + // main::@4 + __b4: + // [43] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 -- _deref_pbuc1=vbuc2 + lda #0 + sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC + jmp __b3 + .segment Vars + gfx: .byte 0 + i: .byte 0 + // index into p0 (0 when not active) + // Player 0 becomes active + p0_idx: .byte 0 +} + // File Data +.segment Data +SINTABLE_160: +.fill $100, 5+round(74.5+74.5*sin(2*PI*i/256)) + + SPRITE_C: .byte 0, $18, $18, $18, $18, $3c, $3c, $3c, $3c, $66, $66, $66, $66, $c0, $c0, $c0, $c0, $c0, $c0, $c0, $c0, $66, $66, $66, $66, $3c, $3c, $3c, $3c, $18, $18, $18, $18, 0 +.segment Vars + // Player 0 X position + p0_xpos: .byte 0 + // Counts frames + idx: .byte 0 + // Player 0 Y position + p0_ypos: .byte 0 + idx2: .byte 0 + +REGISTER UPLIFT POTENTIAL REGISTERS +Statement [5] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_COLUP0) ← (byte) $f0 [ p0_xpos ] ( main:2 [ p0_xpos ] { } ) always clobbers reg byte a +Statement [6] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_GRP0) ← (byte) $af [ p0_xpos ] ( main:2 [ p0_xpos ] { } ) always clobbers reg byte a +Statement [8] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA) ← (byte) 2 [ idx#2 idx2#2 p0_xpos ] ( main:2 [ idx#2 idx2#2 p0_xpos ] { } ) always clobbers reg byte a +Removing always clobbered register reg byte a as potential for mem[1] [ idx#2 idx#1 ] +Removing always clobbered register reg byte a as potential for mem[1] [ idx2#2 idx2#1 ] +Statement [9] *((byte*)(const nomodify struct MOS6532_RIOT*) RIOT+(const byte) OFFSET_STRUCT_MOS6532_RIOT_TIM64T) ← (byte) $29*(const nomodify byte) CYCLES_PER_SCANLINE/(byte) $40 [ idx#2 idx2#2 p0_xpos ] ( main:2 [ idx#2 idx2#2 p0_xpos ] { } ) always clobbers reg byte a +Statement [10] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 [ idx#2 idx2#2 p0_xpos ] ( main:2 [ idx#2 idx2#2 p0_xpos ] { } ) always clobbers reg byte a +Statement [11] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 [ idx#2 idx2#2 p0_xpos ] ( main:2 [ idx#2 idx2#2 p0_xpos ] { } ) always clobbers reg byte a +Statement [12] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 [ idx#2 idx2#2 p0_xpos ] ( main:2 [ idx#2 idx2#2 p0_xpos ] { } ) always clobbers reg byte a +Statement [13] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA) ← (byte) 0 [ idx#2 idx2#2 p0_xpos ] ( main:2 [ idx#2 idx2#2 p0_xpos ] { } ) always clobbers reg byte a +Statement asm { ldap0_xpos staTIA_WSYNC sec !: sbc#$f bcs!- eor#7 asl asl asl asl staTIA_HMP0 staTIA_RESP0 } always clobbers reg byte a +Statement [15] (byte) p0_xpos ← *((const to_nomodify byte*) SINTABLE_160 + (byte) idx#2) [ idx#2 idx2#2 p0_xpos ] ( main:2 [ idx#2 idx2#2 p0_xpos ] { } ) always clobbers reg byte a +Statement [19] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 [ idx#1 idx2#1 p0_xpos p0_ypos#1 ] ( main:2 [ idx#1 idx2#1 p0_xpos p0_ypos#1 ] { } ) always clobbers reg byte a +Removing always clobbered register reg byte a as potential for mem[1] [ p0_ypos#1 ] +Statement [20] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_HMOVE) ← (byte) 0 [ idx#1 idx2#1 p0_xpos p0_ypos#1 ] ( main:2 [ idx#1 idx2#1 p0_xpos p0_ypos#1 ] { } ) always clobbers reg byte a +Statement [21] if((byte) 0!=*((byte*)(const nomodify struct MOS6532_RIOT*) RIOT+(const byte) OFFSET_STRUCT_MOS6532_RIOT_INTIM)) goto main::@4 [ idx#1 idx2#1 p0_xpos p0_ypos#1 ] ( main:2 [ idx#1 idx2#1 p0_xpos p0_ypos#1 ] { } ) always clobbers reg byte a +Statement [22] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_VBLANK) ← (byte) 0 [ idx#1 idx2#1 p0_xpos p0_ypos#1 ] ( main:2 [ idx#1 idx2#1 p0_xpos p0_ypos#1 ] { } ) always clobbers reg byte a +Statement [23] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_COLUBK) ← (byte) 0 [ idx#1 idx2#1 p0_xpos p0_ypos#1 ] ( main:2 [ idx#1 idx2#1 p0_xpos p0_ypos#1 ] { } ) always clobbers reg byte a +Statement [26] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 [ idx#1 idx2#1 p0_xpos ] ( main:2 [ idx#1 idx2#1 p0_xpos ] { } ) always clobbers reg byte a +Statement [27] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_VBLANK) ← (byte) 2 [ idx#1 idx2#1 p0_xpos ] ( main:2 [ idx#1 idx2#1 p0_xpos ] { } ) always clobbers reg byte a +Statement [28] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_COLUBK) ← (byte) 0 [ idx#1 idx2#1 p0_xpos ] ( main:2 [ idx#1 idx2#1 p0_xpos ] { } ) always clobbers reg byte a +Statement [29] *((byte*)(const nomodify struct MOS6532_RIOT*) RIOT+(const byte) OFFSET_STRUCT_MOS6532_RIOT_TIM64T) ← (byte) $1b*(const nomodify byte) CYCLES_PER_SCANLINE/(byte) $40 [ idx#1 idx2#1 p0_xpos ] ( main:2 [ idx#1 idx2#1 p0_xpos ] { } ) always clobbers reg byte a +Statement [30] if((byte) 0!=*((byte*)(const nomodify struct MOS6532_RIOT*) RIOT+(const byte) OFFSET_STRUCT_MOS6532_RIOT_INTIM)) goto main::@14 [ idx#1 idx2#1 p0_xpos ] ( main:2 [ idx#1 idx2#1 p0_xpos ] { } ) always clobbers reg byte a +Statement [31] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 [ idx#1 idx2#1 p0_xpos ] ( main:2 [ idx#1 idx2#1 p0_xpos ] { } ) always clobbers reg byte a +Statement [32] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 [ idx#1 idx2#1 p0_xpos p0_ypos#1 main::i#2 main::p0_idx#4 ] ( main:2 [ idx#1 idx2#1 p0_xpos p0_ypos#1 main::i#2 main::p0_idx#4 ] { } ) always clobbers reg byte a +Removing always clobbered register reg byte a as potential for mem[1] [ main::i#2 main::i#1 ] +Removing always clobbered register reg byte a as potential for mem[1] [ main::p0_idx#4 main::p0_idx#8 main::p0_idx#3 ] +Statement [43] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 [ idx#1 idx2#1 p0_xpos p0_ypos#1 ] ( main:2 [ idx#1 idx2#1 p0_xpos p0_ypos#1 ] { } ) always clobbers reg byte a +Statement [5] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_COLUP0) ← (byte) $f0 [ p0_xpos ] ( main:2 [ p0_xpos ] { } ) always clobbers reg byte a +Statement [6] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_GRP0) ← (byte) $af [ p0_xpos ] ( main:2 [ p0_xpos ] { } ) always clobbers reg byte a +Statement [8] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA) ← (byte) 2 [ idx#2 idx2#2 p0_xpos ] ( main:2 [ idx#2 idx2#2 p0_xpos ] { } ) always clobbers reg byte a +Statement [9] *((byte*)(const nomodify struct MOS6532_RIOT*) RIOT+(const byte) OFFSET_STRUCT_MOS6532_RIOT_TIM64T) ← (byte) $29*(const nomodify byte) CYCLES_PER_SCANLINE/(byte) $40 [ idx#2 idx2#2 p0_xpos ] ( main:2 [ idx#2 idx2#2 p0_xpos ] { } ) always clobbers reg byte a +Statement [10] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 [ idx#2 idx2#2 p0_xpos ] ( main:2 [ idx#2 idx2#2 p0_xpos ] { } ) always clobbers reg byte a +Statement [11] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 [ idx#2 idx2#2 p0_xpos ] ( main:2 [ idx#2 idx2#2 p0_xpos ] { } ) always clobbers reg byte a +Statement [12] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 [ idx#2 idx2#2 p0_xpos ] ( main:2 [ idx#2 idx2#2 p0_xpos ] { } ) always clobbers reg byte a +Statement [13] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA) ← (byte) 0 [ idx#2 idx2#2 p0_xpos ] ( main:2 [ idx#2 idx2#2 p0_xpos ] { } ) always clobbers reg byte a +Statement asm { ldap0_xpos staTIA_WSYNC sec !: sbc#$f bcs!- eor#7 asl asl asl asl staTIA_HMP0 staTIA_RESP0 } always clobbers reg byte a +Statement [15] (byte) p0_xpos ← *((const to_nomodify byte*) SINTABLE_160 + (byte) idx#2) [ idx#2 idx2#2 p0_xpos ] ( main:2 [ idx#2 idx2#2 p0_xpos ] { } ) always clobbers reg byte a +Statement [19] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 [ idx#1 idx2#1 p0_xpos p0_ypos#1 ] ( main:2 [ idx#1 idx2#1 p0_xpos p0_ypos#1 ] { } ) always clobbers reg byte a +Statement [20] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_HMOVE) ← (byte) 0 [ idx#1 idx2#1 p0_xpos p0_ypos#1 ] ( main:2 [ idx#1 idx2#1 p0_xpos p0_ypos#1 ] { } ) always clobbers reg byte a +Statement [21] if((byte) 0!=*((byte*)(const nomodify struct MOS6532_RIOT*) RIOT+(const byte) OFFSET_STRUCT_MOS6532_RIOT_INTIM)) goto main::@4 [ idx#1 idx2#1 p0_xpos p0_ypos#1 ] ( main:2 [ idx#1 idx2#1 p0_xpos p0_ypos#1 ] { } ) always clobbers reg byte a +Statement [22] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_VBLANK) ← (byte) 0 [ idx#1 idx2#1 p0_xpos p0_ypos#1 ] ( main:2 [ idx#1 idx2#1 p0_xpos p0_ypos#1 ] { } ) always clobbers reg byte a +Statement [23] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_COLUBK) ← (byte) 0 [ idx#1 idx2#1 p0_xpos p0_ypos#1 ] ( main:2 [ idx#1 idx2#1 p0_xpos p0_ypos#1 ] { } ) always clobbers reg byte a +Statement [26] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 [ idx#1 idx2#1 p0_xpos ] ( main:2 [ idx#1 idx2#1 p0_xpos ] { } ) always clobbers reg byte a +Statement [27] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_VBLANK) ← (byte) 2 [ idx#1 idx2#1 p0_xpos ] ( main:2 [ idx#1 idx2#1 p0_xpos ] { } ) always clobbers reg byte a +Statement [28] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_COLUBK) ← (byte) 0 [ idx#1 idx2#1 p0_xpos ] ( main:2 [ idx#1 idx2#1 p0_xpos ] { } ) always clobbers reg byte a +Statement [29] *((byte*)(const nomodify struct MOS6532_RIOT*) RIOT+(const byte) OFFSET_STRUCT_MOS6532_RIOT_TIM64T) ← (byte) $1b*(const nomodify byte) CYCLES_PER_SCANLINE/(byte) $40 [ idx#1 idx2#1 p0_xpos ] ( main:2 [ idx#1 idx2#1 p0_xpos ] { } ) always clobbers reg byte a +Statement [30] if((byte) 0!=*((byte*)(const nomodify struct MOS6532_RIOT*) RIOT+(const byte) OFFSET_STRUCT_MOS6532_RIOT_INTIM)) goto main::@14 [ idx#1 idx2#1 p0_xpos ] ( main:2 [ idx#1 idx2#1 p0_xpos ] { } ) always clobbers reg byte a +Statement [31] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 [ idx#1 idx2#1 p0_xpos ] ( main:2 [ idx#1 idx2#1 p0_xpos ] { } ) always clobbers reg byte a +Statement [32] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 [ idx#1 idx2#1 p0_xpos p0_ypos#1 main::i#2 main::p0_idx#4 ] ( main:2 [ idx#1 idx2#1 p0_xpos p0_ypos#1 main::i#2 main::p0_idx#4 ] { } ) always clobbers reg byte a +Statement [43] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 [ idx#1 idx2#1 p0_xpos p0_ypos#1 ] ( main:2 [ idx#1 idx2#1 p0_xpos p0_ypos#1 ] { } ) always clobbers reg byte a +Potential registers mem[1] [ idx#2 idx#1 ] : mem[1] , reg byte x , reg byte y , +Potential registers mem[1] [ idx2#2 idx2#1 ] : mem[1] , reg byte x , reg byte y , +Potential registers mem[1] [ main::i#2 main::i#1 ] : mem[1] , reg byte x , reg byte y , +Potential registers mem[1] [ main::p0_idx#4 main::p0_idx#8 main::p0_idx#3 ] : mem[1] , reg byte x , reg byte y , +Potential registers mem[1] [ p0_xpos ] : mem[1] , +Potential registers mem[1] [ p0_ypos#1 ] : mem[1] , reg byte x , reg byte y , +Potential registers mem[1] [ main::gfx#0 ] : mem[1] , reg byte a , reg byte x , reg byte y , + +REGISTER UPLIFT SCOPES +Uplift Scope [main] 4,004: mem[1] [ main::p0_idx#4 main::p0_idx#8 main::p0_idx#3 ] 2,419.08: mem[1] [ main::i#2 main::i#1 ] 1,501.5: mem[1] [ main::gfx#0 ] +Uplift Scope [] 173.02: mem[1] [ idx#2 idx#1 ] 151.75: mem[1] [ idx2#2 idx2#1 ] 52.48: mem[1] [ p0_ypos#1 ] 2.46: mem[1] [ p0_xpos ] +Uplift Scope [ATARI_TIA_WRITE] +Uplift Scope [ATARI_TIA_READ] +Uplift Scope [MOS6532_RIOT] + +Uplifting [main] best 13681 combination reg byte y [ main::p0_idx#4 main::p0_idx#8 main::p0_idx#3 ] reg byte x [ main::i#2 main::i#1 ] reg byte a [ main::gfx#0 ] +Uplifting [] best 13681 combination mem[1] [ idx#2 idx#1 ] mem[1] [ idx2#2 idx2#1 ] mem[1] [ p0_ypos#1 ] mem[1] [ p0_xpos ] +Uplifting [ATARI_TIA_WRITE] best 13681 combination +Uplifting [ATARI_TIA_READ] best 13681 combination +Uplifting [MOS6532_RIOT] best 13681 combination +Attempting to uplift remaining variables inmem[1] [ idx#2 idx#1 ] +Uplifting [] best 13681 combination mem[1] [ idx#2 idx#1 ] +Attempting to uplift remaining variables inmem[1] [ idx2#2 idx2#1 ] +Uplifting [] best 13681 combination mem[1] [ idx2#2 idx2#1 ] +Attempting to uplift remaining variables inmem[1] [ p0_ypos#1 ] +Uplifting [] best 13681 combination mem[1] [ p0_ypos#1 ] +Attempting to uplift remaining variables inmem[1] [ p0_xpos ] +Uplifting [] best 13681 combination mem[1] [ p0_xpos ] + +ASSEMBLER BEFORE OPTIMIZATION + // File Comments +// Minimal Atari 2600 VCS Program using Sprites +// Source: https://atariage.com/forums/blogs/entry/11109-step-1-generate-a-stable-display/ + // Upstart + // Atari 2600 VCS 2K ROM +.file [name="atari2600-sprites.a26", type="bin", segments="Code, Data, Vectors"] +.segmentdef Code [start=$f800,min=$f800,max=$fff9] +.segmentdef Data [startAfter="Code",max=$fff9] +.segmentdef Vectors [start=$fffa,max=$ffff] +.segmentdef Vars [start=$80,max=$ff, virtual] +.segment Vectors +.word main // NMI +.word main // RESET +.word main // IRQ +.segment Code + + // Global Constants & labels + // The number of CPU cycles per scanline + .const CYCLES_PER_SCANLINE = $4c + .const OFFSET_STRUCT_ATARI_TIA_WRITE_COLUP0 = 6 + .const OFFSET_STRUCT_ATARI_TIA_WRITE_GRP0 = $1b + .const OFFSET_STRUCT_MOS6532_RIOT_TIM64T = $16 + .const OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC = 2 + .const OFFSET_STRUCT_ATARI_TIA_WRITE_HMOVE = $2a + .const OFFSET_STRUCT_MOS6532_RIOT_INTIM = 4 + .const OFFSET_STRUCT_ATARI_TIA_WRITE_VBLANK = 1 + .const OFFSET_STRUCT_ATARI_TIA_WRITE_COLUBK = 9 + // The TIA WSYNC register (for access from inline ASM) + .label TIA_WSYNC = 2 + // The TIA RESP0 register (for access from inline ASM) + .label TIA_RESP0 = $10 + // The TIA HMP0 register (for access from inline ASM) + .label TIA_HMP0 = $20 + // Atari TIA write registers + .label TIA = 0 + // Atari RIOT registers + .label RIOT = $280 + // @begin +__bbegin: + // [1] phi from @begin to @1 [phi:@begin->@1] +__b1_from___bbegin: + jmp __b1 + // @1 +__b1: + // [2] call main + jsr main + // [3] phi from @1 to @end [phi:@1->@end] +__bend_from___b1: + jmp __bend + // @end +__bend: +.segment Code + // main +main: { + // asm { cld } + cld + // [5] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_COLUP0) ← (byte) $f0 -- _deref_pbuc1=vbuc2 + // Player 0 + // - Color + lda #$f0 + sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_COLUP0 + // [6] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_GRP0) ← (byte) $af -- _deref_pbuc1=vbuc2 + // - Graphics + lda #$af + sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_GRP0 + // [7] phi from main to main::@1 [phi:main->main::@1] + __b1_from_main: + // [7] phi (byte) idx2#2 = (byte) $39 [phi:main->main::@1#0] -- vbum1=vbuc1 + lda #$39 + sta idx2 + // [7] phi (byte) idx#2 = (byte) 0 [phi:main->main::@1#1] -- vbum1=vbuc1 + lda #0 + sta idx + jmp __b1 + // Player 1 + // - Color + //TIA->COLUP1 = 0xf0; + // - Graphics + //TIA->GRP1 = 0xf5; + // main::@1 + __b1: + jmp __b2 + // main::@2 + __b2: + // [8] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA) ← (byte) 2 -- _deref_pbuc1=vbuc2 + // Vertical Sync + // here we generate the signal that tells the TV to move the beam to the top of + // the screen so we can start the next frame of video. + // The Sync Signal must be on for 3 scanlines. + lda #2 + sta TIA + // [9] *((byte*)(const nomodify struct MOS6532_RIOT*) RIOT+(const byte) OFFSET_STRUCT_MOS6532_RIOT_TIM64T) ← (byte) $29*(const nomodify byte) CYCLES_PER_SCANLINE/(byte) $40 -- _deref_pbuc1=vbuc2 + // D1=1, turns on Vertical Sync signal + lda #$29*CYCLES_PER_SCANLINE/$40 + sta RIOT+OFFSET_STRUCT_MOS6532_RIOT_TIM64T + // [10] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 -- _deref_pbuc1=vbuc2 + // Set timer to wait 41 lines + lda #0 + sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC + // [11] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 -- _deref_pbuc1=vbuc2 + // Wait for Sync - halts CPU until end of 1st scanline of VSYNC + lda #0 + sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC + // [12] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 -- _deref_pbuc1=vbuc2 + // wait until end of 2nd scanline of VSYNC + lda #0 + sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC + // [13] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA) ← (byte) 0 -- _deref_pbuc1=vbuc2 + // wait until end of 3rd scanline of VSYNC + lda #0 + sta TIA + // asm { ldap0_xpos staTIA_WSYNC sec !: sbc#$f bcs!- eor#7 asl asl asl asl staTIA_HMP0 staTIA_RESP0 } + // Vertical Sprite Position Player 0 - inline ASM to achieve cycle exact code + lda p0_xpos + sta TIA_WSYNC + sec + !: + sbc #$f + bcs !- + eor #7 + asl + asl + asl + asl + sta TIA_HMP0 + sta TIA_RESP0 + // [15] (byte) p0_xpos ← *((const to_nomodify byte*) SINTABLE_160 + (byte) idx#2) -- vbum1=pbuc1_derefidx_vbum2 + ldy idx + lda SINTABLE_160,y + sta p0_xpos + // [16] (byte) idx#1 ← ++ (byte) idx#2 -- vbum1=_inc_vbum1 + inc idx + // [17] (byte) p0_ypos#1 ← *((const to_nomodify byte*) SINTABLE_160 + (byte) idx2#2) -- vbum1=pbuc1_derefidx_vbum2 + ldy idx2 + lda SINTABLE_160,y + sta p0_ypos + // [18] (byte) idx2#1 ← ++ (byte) idx2#2 -- vbum1=_inc_vbum1 + inc idx2 + // [19] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 -- _deref_pbuc1=vbuc2 + // Execute horisontal movement + lda #0 + sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC + // [20] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_HMOVE) ← (byte) 0 -- _deref_pbuc1=vbuc2 + lda #0 + sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_HMOVE + jmp __b3 + // Wait for the timer to run out + // main::@3 + __b3: + // [21] if((byte) 0!=*((byte*)(const nomodify struct MOS6532_RIOT*) RIOT+(const byte) OFFSET_STRUCT_MOS6532_RIOT_INTIM)) goto main::@4 -- vbuc1_neq__deref_pbuc2_then_la1 + lda #0 + cmp RIOT+OFFSET_STRUCT_MOS6532_RIOT_INTIM + bne __b4 + jmp __b5 + // main::@5 + __b5: + // [22] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_VBLANK) ← (byte) 0 -- _deref_pbuc1=vbuc2 + // Screen - display logic + // Update the registers in TIA (the video chip) in order to generate what the player sees. + // For now we're just going to output 192 colored scanlines lines so we have something to see. + lda #0 + sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_VBLANK + // [23] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_COLUBK) ← (byte) 0 -- _deref_pbuc1=vbuc2 + // D1=1, turns off Vertical Blank signal (image output on) + lda #0 + sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_COLUBK + // [24] phi from main::@5 to main::@6 [phi:main::@5->main::@6] + __b6_from___b5: + // [24] phi (byte) main::p0_idx#4 = (byte) 0 [phi:main::@5->main::@6#0] -- vbuyy=vbuc1 + ldy #0 + // [24] phi (byte) main::i#2 = (byte) 1 [phi:main::@5->main::@6#1] -- vbuxx=vbuc1 + ldx #1 + jmp __b6 + // main::@6 + __b6: + // [25] if((byte) main::i#2<(byte) $c0) goto main::@7 -- vbuxx_lt_vbuc1_then_la1 + cpx #$c0 + bcc __b7 + jmp __b8 + // main::@8 + __b8: + // [26] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 -- _deref_pbuc1=vbuc2 + // Start OverScan + lda #0 + sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC + // [27] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_VBLANK) ← (byte) 2 -- _deref_pbuc1=vbuc2 + // Wait for SYNC (halts CPU until end of scanline) + lda #2 + sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_VBLANK + // [28] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_COLUBK) ← (byte) 0 -- _deref_pbuc1=vbuc2 + // D1=1 turns image output off + lda #0 + sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_COLUBK + // [29] *((byte*)(const nomodify struct MOS6532_RIOT*) RIOT+(const byte) OFFSET_STRUCT_MOS6532_RIOT_TIM64T) ← (byte) $1b*(const nomodify byte) CYCLES_PER_SCANLINE/(byte) $40 -- _deref_pbuc1=vbuc2 + // Set background color to black + lda #$1b*CYCLES_PER_SCANLINE/$40 + sta RIOT+OFFSET_STRUCT_MOS6532_RIOT_TIM64T + jmp __b13 + // Wait for the timer to run out + // main::@13 + __b13: + // [30] if((byte) 0!=*((byte*)(const nomodify struct MOS6532_RIOT*) RIOT+(const byte) OFFSET_STRUCT_MOS6532_RIOT_INTIM)) goto main::@14 -- vbuc1_neq__deref_pbuc2_then_la1 + lda #0 + cmp RIOT+OFFSET_STRUCT_MOS6532_RIOT_INTIM + bne __b14 + // [7] phi from main::@13 to main::@1 [phi:main::@13->main::@1] + __b1_from___b13: + // [7] phi (byte) idx2#2 = (byte) idx2#1 [phi:main::@13->main::@1#0] -- register_copy + // [7] phi (byte) idx#2 = (byte) idx#1 [phi:main::@13->main::@1#1] -- register_copy + jmp __b1 + // main::@14 + __b14: + // [31] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 -- _deref_pbuc1=vbuc2 + lda #0 + sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC + jmp __b13 + // main::@7 + __b7: + // [32] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 -- _deref_pbuc1=vbuc2 + // Wait for SYNC (halts CPU until end of scanline) + lda #0 + sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC + // [33] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_COLUBK) ← (byte) main::i#2 -- _deref_pbuc1=vbuxx + stx TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_COLUBK + // [34] if((byte) 0!=(byte) main::p0_idx#4) goto main::@9 -- vbuc1_neq_vbuyy_then_la1 + cpy #0 + bne __b9 + jmp __b11 + // main::@11 + __b11: + // [35] if((byte) p0_ypos#1!=(byte) main::i#2) goto main::@15 -- vbum1_neq_vbuxx_then_la1 + cpx p0_ypos + bne __b15_from___b11 + // [37] phi from main::@11 to main::@10 [phi:main::@11->main::@10] + __b10_from___b11: + // [37] phi (byte) main::p0_idx#8 = (byte) 1 [phi:main::@11->main::@10#0] -- vbuyy=vbuc1 + ldy #1 + jmp __b10 + // [36] phi from main::@11 to main::@15 [phi:main::@11->main::@15] + __b15_from___b11: + jmp __b15 + // main::@15 + __b15: + // [37] phi from main::@12 main::@15 to main::@10 [phi:main::@12/main::@15->main::@10] + __b10_from___b12: + __b10_from___b15: + // [37] phi (byte) main::p0_idx#8 = (byte) main::p0_idx#3 [phi:main::@12/main::@15->main::@10#0] -- register_copy + jmp __b10 + // [37] phi from main::@9 to main::@10 [phi:main::@9->main::@10] + __b10_from___b9: + // [37] phi (byte) main::p0_idx#8 = (byte) 0 [phi:main::@9->main::@10#0] -- vbuyy=vbuc1 + ldy #0 + jmp __b10 + // main::@10 + __b10: + // [38] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuxx=_inc_vbuxx + inx + // [24] phi from main::@10 to main::@6 [phi:main::@10->main::@6] + __b6_from___b10: + // [24] phi (byte) main::p0_idx#4 = (byte) main::p0_idx#8 [phi:main::@10->main::@6#0] -- register_copy + // [24] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@10->main::@6#1] -- register_copy + jmp __b6 + // main::@9 + __b9: + // [39] (byte) main::gfx#0 ← *((const byte*) SPRITE_C + (byte) main::p0_idx#4) -- vbuaa=pbuc1_derefidx_vbuyy + // Player 0 is active - show it + lda SPRITE_C,y + // [40] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_GRP0) ← (byte) main::gfx#0 -- _deref_pbuc1=vbuaa + sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_GRP0 + // [41] if((byte) main::gfx#0==(byte) 0) goto main::@10 -- vbuaa_eq_0_then_la1 + cmp #0 + beq __b10_from___b9 + jmp __b12 + // main::@12 + __b12: + // [42] (byte) main::p0_idx#3 ← ++ (byte) main::p0_idx#4 -- vbuyy=_inc_vbuyy + iny + jmp __b10_from___b12 + // main::@4 + __b4: + // [43] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 -- _deref_pbuc1=vbuc2 + lda #0 + sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC + jmp __b3 +} + // File Data +.segment Data +SINTABLE_160: +.fill $100, 5+round(74.5+74.5*sin(2*PI*i/256)) + + SPRITE_C: .byte 0, $18, $18, $18, $18, $3c, $3c, $3c, $3c, $66, $66, $66, $66, $c0, $c0, $c0, $c0, $c0, $c0, $c0, $c0, $66, $66, $66, $66, $3c, $3c, $3c, $3c, $18, $18, $18, $18, 0 +.segment Vars + // Player 0 X position + p0_xpos: .byte 0 + // Counts frames + idx: .byte 0 + // Player 0 Y position + p0_ypos: .byte 0 + idx2: .byte 0 + +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 __b5 +Removing instruction jmp __b6 +Removing instruction jmp __b8 +Removing instruction jmp __b13 +Removing instruction jmp __b11 +Removing instruction jmp __b15 +Removing instruction jmp __b10 +Removing instruction jmp __b12 +Succesful ASM optimization Pass5NextJumpElimination +Removing instruction lda #0 +Removing instruction lda #0 +Removing instruction lda #0 +Removing instruction lda #0 +Removing instruction lda #0 +Succesful ASM optimization Pass5UnnecesaryLoadElimination +Replacing label __b1 with __b2 +Replacing label __b15_from___b11 with __b15 +Replacing label __b10_from___b12 with __b15 +Removing instruction __b1_from___bbegin: +Removing instruction __b1: +Removing instruction __bend_from___b1: +Removing instruction __b1: +Removing instruction __b15_from___b11: +Removing instruction __b10_from___b12: +Removing instruction __b10_from___b15: +Succesful ASM optimization Pass5RedundantLabelElimination +Removing instruction __bbegin: +Removing instruction __bend: +Removing instruction __b1_from_main: +Removing instruction __b5: +Removing instruction __b6_from___b5: +Removing instruction __b8: +Removing instruction __b1_from___b13: +Removing instruction __b11: +Removing instruction __b10_from___b11: +Removing instruction __b6_from___b10: +Removing instruction __b12: +Succesful ASM optimization Pass5UnusedLabelElimination +Removing instruction jsr main +Succesful ASM optimization Pass5SkipBegin +Skipping double jump to __b10 in bne __b15 +Skipping double jump to __b10 in jmp __b15 +Succesful ASM optimization Pass5DoubleJumpElimination +Relabelling long label __b10_from___b9 to __b1 +Succesful ASM optimization Pass5RelabelLongLabels +Removing instruction lda #0 +Replacing instruction ldy #0 with TAY +Succesful ASM optimization Pass5UnnecesaryLoadElimination +Removing instruction __b15: +Succesful ASM optimization Pass5UnusedLabelElimination +Removing unreachable instruction jmp __b10 +Succesful ASM optimization Pass5UnreachableCodeElimination + +FINAL SYMBOL TABLE +(label) @1 +(label) @begin +(label) @end +(byte) ATARI_TIA_READ::CXBLPF +(byte) ATARI_TIA_READ::CXM0FB +(byte) ATARI_TIA_READ::CXM0P +(byte) ATARI_TIA_READ::CXM1FB +(byte) ATARI_TIA_READ::CXM1P +(byte) ATARI_TIA_READ::CXP0FB +(byte) ATARI_TIA_READ::CXP1FB +(byte) ATARI_TIA_READ::CXPPMM +(byte) ATARI_TIA_READ::INPT0 +(byte) ATARI_TIA_READ::INPT1 +(byte) ATARI_TIA_READ::INPT2 +(byte) ATARI_TIA_READ::INPT3 +(byte) ATARI_TIA_READ::INPT4 +(byte) ATARI_TIA_READ::INPT5 +(byte) ATARI_TIA_WRITE::AUDC0 +(byte) ATARI_TIA_WRITE::AUDC1 +(byte) ATARI_TIA_WRITE::AUDF0 +(byte) ATARI_TIA_WRITE::AUDF1 +(byte) ATARI_TIA_WRITE::AUDV0 +(byte) ATARI_TIA_WRITE::AUDV1 +(byte) ATARI_TIA_WRITE::COLUBK +(byte) ATARI_TIA_WRITE::COLUP0 +(byte) ATARI_TIA_WRITE::COLUP1 +(byte) ATARI_TIA_WRITE::COLUPF +(byte) ATARI_TIA_WRITE::CTRLPF +(byte) ATARI_TIA_WRITE::CXCLR +(byte) ATARI_TIA_WRITE::ENABL +(byte) ATARI_TIA_WRITE::ENAM0 +(byte) ATARI_TIA_WRITE::ENAM1 +(byte) ATARI_TIA_WRITE::GRP0 +(byte) ATARI_TIA_WRITE::GRP1 +(byte) ATARI_TIA_WRITE::HMBL +(byte) ATARI_TIA_WRITE::HMCLR +(byte) ATARI_TIA_WRITE::HMM0 +(byte) ATARI_TIA_WRITE::HMM1 +(byte) ATARI_TIA_WRITE::HMOVE +(byte) ATARI_TIA_WRITE::HMP0 +(byte) ATARI_TIA_WRITE::HMP1 +(byte) ATARI_TIA_WRITE::NUSIZ0 +(byte) ATARI_TIA_WRITE::NUSIZ1 +(byte) ATARI_TIA_WRITE::PF0 +(byte) ATARI_TIA_WRITE::PF1 +(byte) ATARI_TIA_WRITE::PF2 +(byte) ATARI_TIA_WRITE::REFP0 +(byte) ATARI_TIA_WRITE::REFP1 +(byte) ATARI_TIA_WRITE::RESBL +(byte) ATARI_TIA_WRITE::RESM0 +(byte) ATARI_TIA_WRITE::RESM1 +(byte) ATARI_TIA_WRITE::RESMP0 +(byte) ATARI_TIA_WRITE::RESMP1 +(byte) ATARI_TIA_WRITE::RESP0 +(byte) ATARI_TIA_WRITE::RESP1 +(byte) ATARI_TIA_WRITE::RSYNC +(byte) ATARI_TIA_WRITE::VBLANK +(byte) ATARI_TIA_WRITE::VDELBL +(byte) ATARI_TIA_WRITE::VDELP0 +(byte) ATARI_TIA_WRITE::VDELP1 +(byte) ATARI_TIA_WRITE::VSYNC +(byte) ATARI_TIA_WRITE::WSYNC +(const nomodify byte) CYCLES_PER_SCANLINE = (byte) $4c +(byte) MOS6532_RIOT::INTIM +(byte) MOS6532_RIOT::SWACNT +(byte) MOS6532_RIOT::SWBCNT +(byte) MOS6532_RIOT::SWCHA +(byte) MOS6532_RIOT::SWCHB +(byte) MOS6532_RIOT::T1024T +(byte) MOS6532_RIOT::TIM1T +(byte) MOS6532_RIOT::TIM64T +(byte) MOS6532_RIOT::TIM8T +(const byte*) MOS6532_RIOT::UNUSED[(number) $f] = { fill( $f, 0) } +(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_COLUBK = (byte) 9 +(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_COLUP0 = (byte) 6 +(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_GRP0 = (byte) $1b +(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_HMOVE = (byte) $2a +(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_VBLANK = (byte) 1 +(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC = (byte) 2 +(const byte) OFFSET_STRUCT_MOS6532_RIOT_INTIM = (byte) 4 +(const byte) OFFSET_STRUCT_MOS6532_RIOT_TIM64T = (byte) $16 +(const nomodify struct MOS6532_RIOT*) RIOT = (struct MOS6532_RIOT*) 640 +(const to_nomodify byte*) SINTABLE_160[(number) $100] = kickasm {{ .fill $100, 5+round(74.5+74.5*sin(2*PI*i/256)) + }} +(const byte*) SPRITE_C[] = { (byte) 0, (byte) $18, (byte) $18, (byte) $18, (byte) $18, (byte) $3c, (byte) $3c, (byte) $3c, (byte) $3c, (byte) $66, (byte) $66, (byte) $66, (byte) $66, (byte) $c0, (byte) $c0, (byte) $c0, (byte) $c0, (byte) $c0, (byte) $c0, (byte) $c0, (byte) $c0, (byte) $66, (byte) $66, (byte) $66, (byte) $66, (byte) $3c, (byte) $3c, (byte) $3c, (byte) $3c, (byte) $18, (byte) $18, (byte) $18, (byte) $18, (byte) 0 } +(const nomodify struct ATARI_TIA_WRITE*) TIA = (struct ATARI_TIA_WRITE*) 0 +(const nomodify byte*) TIA_HMP0 = (byte*) 32 +(const nomodify byte*) TIA_RESP0 = (byte*) 16 +(const nomodify byte*) TIA_WSYNC = (byte*) 2 +(byte) idx +(byte) idx#1 idx mem[1] 39.357142857142854 +(byte) idx#2 idx mem[1] 133.66666666666669 +(byte) idx2 +(byte) idx2#1 idx2 mem[1] 42.38461538461539 +(byte) idx2#2 idx2 mem[1] 109.36363636363637 +(void()) main() +(label) main::@1 +(label) main::@10 +(label) main::@11 +(label) main::@12 +(label) main::@13 +(label) main::@14 +(label) main::@15 +(label) main::@2 +(label) main::@3 +(label) main::@4 +(label) main::@5 +(label) main::@6 +(label) main::@7 +(label) main::@8 +(label) main::@9 +(byte) main::gfx +(byte) main::gfx#0 reg byte a 1501.5 +(byte) main::i +(byte) main::i#1 reg byte x 2002.0 +(byte) main::i#2 reg byte x 417.08333333333337 +(byte) main::p0_idx +(byte) main::p0_idx#3 reg byte y 2002.0 +(byte) main::p0_idx#4 reg byte y 500.5 +(byte) main::p0_idx#8 reg byte y 1501.5 +(byte) p0_xpos loadstore mem[1] 2.4634146341463414 = (byte) 0 +(byte) p0_ypos +(byte) p0_ypos#1 p0_ypos mem[1] 52.476190476190474 + +mem[1] [ idx#2 idx#1 ] +mem[1] [ idx2#2 idx2#1 ] +reg byte x [ main::i#2 main::i#1 ] +reg byte y [ main::p0_idx#4 main::p0_idx#8 main::p0_idx#3 ] +mem[1] [ p0_xpos ] +mem[1] [ p0_ypos#1 ] +reg byte a [ main::gfx#0 ] + + +FINAL ASSEMBLER +Score: 11029 + + // File Comments +// Minimal Atari 2600 VCS Program using Sprites +// Source: https://atariage.com/forums/blogs/entry/11109-step-1-generate-a-stable-display/ + // Upstart + // Atari 2600 VCS 2K ROM +.file [name="atari2600-sprites.a26", type="bin", segments="Code, Data, Vectors"] +.segmentdef Code [start=$f800,min=$f800,max=$fff9] +.segmentdef Data [startAfter="Code",max=$fff9] +.segmentdef Vectors [start=$fffa,max=$ffff] +.segmentdef Vars [start=$80,max=$ff, virtual] +.segment Vectors +.word main // NMI +.word main // RESET +.word main // IRQ +.segment Code + + // Global Constants & labels + // The number of CPU cycles per scanline + .const CYCLES_PER_SCANLINE = $4c + .const OFFSET_STRUCT_ATARI_TIA_WRITE_COLUP0 = 6 + .const OFFSET_STRUCT_ATARI_TIA_WRITE_GRP0 = $1b + .const OFFSET_STRUCT_MOS6532_RIOT_TIM64T = $16 + .const OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC = 2 + .const OFFSET_STRUCT_ATARI_TIA_WRITE_HMOVE = $2a + .const OFFSET_STRUCT_MOS6532_RIOT_INTIM = 4 + .const OFFSET_STRUCT_ATARI_TIA_WRITE_VBLANK = 1 + .const OFFSET_STRUCT_ATARI_TIA_WRITE_COLUBK = 9 + // The TIA WSYNC register (for access from inline ASM) + .label TIA_WSYNC = 2 + // The TIA RESP0 register (for access from inline ASM) + .label TIA_RESP0 = $10 + // The TIA HMP0 register (for access from inline ASM) + .label TIA_HMP0 = $20 + // Atari TIA write registers + .label TIA = 0 + // Atari RIOT registers + .label RIOT = $280 + // @begin + // [1] phi from @begin to @1 [phi:@begin->@1] + // @1 + // [2] call main + // [3] phi from @1 to @end [phi:@1->@end] + // @end +.segment Code + // main +main: { + // asm + // asm { cld } + cld + // TIA->COLUP0 = 0xf0 + // [5] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_COLUP0) ← (byte) $f0 -- _deref_pbuc1=vbuc2 + // Player 0 + // - Color + lda #$f0 + sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_COLUP0 + // TIA->GRP0 = 0xaf + // [6] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_GRP0) ← (byte) $af -- _deref_pbuc1=vbuc2 + // - Graphics + lda #$af + sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_GRP0 + // [7] phi from main to main::@1 [phi:main->main::@1] + // [7] phi (byte) idx2#2 = (byte) $39 [phi:main->main::@1#0] -- vbum1=vbuc1 + lda #$39 + sta idx2 + // [7] phi (byte) idx#2 = (byte) 0 [phi:main->main::@1#1] -- vbum1=vbuc1 + lda #0 + sta idx + // Player 1 + // - Color + //TIA->COLUP1 = 0xf0; + // - Graphics + //TIA->GRP1 = 0xf5; + // main::@1 + // main::@2 + __b2: + // TIA->VSYNC = 2 + // [8] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA) ← (byte) 2 -- _deref_pbuc1=vbuc2 + // Vertical Sync + // here we generate the signal that tells the TV to move the beam to the top of + // the screen so we can start the next frame of video. + // The Sync Signal must be on for 3 scanlines. + lda #2 + sta TIA + // RIOT->TIM64T = (41*CYCLES_PER_SCANLINE)/64 + // [9] *((byte*)(const nomodify struct MOS6532_RIOT*) RIOT+(const byte) OFFSET_STRUCT_MOS6532_RIOT_TIM64T) ← (byte) $29*(const nomodify byte) CYCLES_PER_SCANLINE/(byte) $40 -- _deref_pbuc1=vbuc2 + // D1=1, turns on Vertical Sync signal + lda #$29*CYCLES_PER_SCANLINE/$40 + sta RIOT+OFFSET_STRUCT_MOS6532_RIOT_TIM64T + // TIA->WSYNC = 0 + // [10] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 -- _deref_pbuc1=vbuc2 + // Set timer to wait 41 lines + lda #0 + sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC + // [11] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 -- _deref_pbuc1=vbuc2 + // Wait for Sync - halts CPU until end of 1st scanline of VSYNC + sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC + // [12] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 -- _deref_pbuc1=vbuc2 + // wait until end of 2nd scanline of VSYNC + sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC + // TIA->VSYNC = 0 + // [13] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA) ← (byte) 0 -- _deref_pbuc1=vbuc2 + // wait until end of 3rd scanline of VSYNC + sta TIA + // asm + // asm { ldap0_xpos staTIA_WSYNC sec !: sbc#$f bcs!- eor#7 asl asl asl asl staTIA_HMP0 staTIA_RESP0 } + // Vertical Sprite Position Player 0 - inline ASM to achieve cycle exact code + lda p0_xpos + sta TIA_WSYNC + sec + !: + sbc #$f + bcs !- + eor #7 + asl + asl + asl + asl + sta TIA_HMP0 + sta TIA_RESP0 + // p0_xpos = SINTABLE_160[idx++] + // [15] (byte) p0_xpos ← *((const to_nomodify byte*) SINTABLE_160 + (byte) idx#2) -- vbum1=pbuc1_derefidx_vbum2 + ldy idx + lda SINTABLE_160,y + sta p0_xpos + // p0_xpos = SINTABLE_160[idx++]; + // [16] (byte) idx#1 ← ++ (byte) idx#2 -- vbum1=_inc_vbum1 + inc idx + // p0_ypos = SINTABLE_160[idx2++] + // [17] (byte) p0_ypos#1 ← *((const to_nomodify byte*) SINTABLE_160 + (byte) idx2#2) -- vbum1=pbuc1_derefidx_vbum2 + ldy idx2 + lda SINTABLE_160,y + sta p0_ypos + // p0_ypos = SINTABLE_160[idx2++]; + // [18] (byte) idx2#1 ← ++ (byte) idx2#2 -- vbum1=_inc_vbum1 + inc idx2 + // TIA->WSYNC = 0 + // [19] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 -- _deref_pbuc1=vbuc2 + // Execute horisontal movement + lda #0 + sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC + // TIA->HMOVE = 0 + // [20] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_HMOVE) ← (byte) 0 -- _deref_pbuc1=vbuc2 + sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_HMOVE + // Wait for the timer to run out + // main::@3 + __b3: + // while(RIOT->INTIM) + // [21] if((byte) 0!=*((byte*)(const nomodify struct MOS6532_RIOT*) RIOT+(const byte) OFFSET_STRUCT_MOS6532_RIOT_INTIM)) goto main::@4 -- vbuc1_neq__deref_pbuc2_then_la1 + lda #0 + cmp RIOT+OFFSET_STRUCT_MOS6532_RIOT_INTIM + bne __b4 + // main::@5 + // TIA->VBLANK = 0 + // [22] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_VBLANK) ← (byte) 0 -- _deref_pbuc1=vbuc2 + // Screen - display logic + // Update the registers in TIA (the video chip) in order to generate what the player sees. + // For now we're just going to output 192 colored scanlines lines so we have something to see. + sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_VBLANK + // TIA->COLUBK = 0x0 + // [23] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_COLUBK) ← (byte) 0 -- _deref_pbuc1=vbuc2 + // D1=1, turns off Vertical Blank signal (image output on) + sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_COLUBK + // [24] phi from main::@5 to main::@6 [phi:main::@5->main::@6] + // [24] phi (byte) main::p0_idx#4 = (byte) 0 [phi:main::@5->main::@6#0] -- vbuyy=vbuc1 + tay + // [24] phi (byte) main::i#2 = (byte) 1 [phi:main::@5->main::@6#1] -- vbuxx=vbuc1 + ldx #1 + // main::@6 + __b6: + // for(char i=1;i<192;i++) + // [25] if((byte) main::i#2<(byte) $c0) goto main::@7 -- vbuxx_lt_vbuc1_then_la1 + cpx #$c0 + bcc __b7 + // main::@8 + // TIA->WSYNC = 0 + // [26] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 -- _deref_pbuc1=vbuc2 + // Start OverScan + lda #0 + sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC + // TIA->VBLANK = 2 + // [27] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_VBLANK) ← (byte) 2 -- _deref_pbuc1=vbuc2 + // Wait for SYNC (halts CPU until end of scanline) + lda #2 + sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_VBLANK + // TIA->COLUBK = 0 + // [28] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_COLUBK) ← (byte) 0 -- _deref_pbuc1=vbuc2 + // D1=1 turns image output off + lda #0 + sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_COLUBK + // RIOT->TIM64T = (27*CYCLES_PER_SCANLINE)/64 + // [29] *((byte*)(const nomodify struct MOS6532_RIOT*) RIOT+(const byte) OFFSET_STRUCT_MOS6532_RIOT_TIM64T) ← (byte) $1b*(const nomodify byte) CYCLES_PER_SCANLINE/(byte) $40 -- _deref_pbuc1=vbuc2 + // Set background color to black + lda #$1b*CYCLES_PER_SCANLINE/$40 + sta RIOT+OFFSET_STRUCT_MOS6532_RIOT_TIM64T + // Wait for the timer to run out + // main::@13 + __b13: + // while(RIOT->INTIM) + // [30] if((byte) 0!=*((byte*)(const nomodify struct MOS6532_RIOT*) RIOT+(const byte) OFFSET_STRUCT_MOS6532_RIOT_INTIM)) goto main::@14 -- vbuc1_neq__deref_pbuc2_then_la1 + lda #0 + cmp RIOT+OFFSET_STRUCT_MOS6532_RIOT_INTIM + bne __b14 + // [7] phi from main::@13 to main::@1 [phi:main::@13->main::@1] + // [7] phi (byte) idx2#2 = (byte) idx2#1 [phi:main::@13->main::@1#0] -- register_copy + // [7] phi (byte) idx#2 = (byte) idx#1 [phi:main::@13->main::@1#1] -- register_copy + jmp __b2 + // main::@14 + __b14: + // TIA->WSYNC = 0 + // [31] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 -- _deref_pbuc1=vbuc2 + lda #0 + sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC + jmp __b13 + // main::@7 + __b7: + // [32] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 -- _deref_pbuc1=vbuc2 + // Wait for SYNC (halts CPU until end of scanline) + lda #0 + sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC + // TIA->COLUBK = i + // [33] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_COLUBK) ← (byte) main::i#2 -- _deref_pbuc1=vbuxx + stx TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_COLUBK + // if(p0_idx) + // [34] if((byte) 0!=(byte) main::p0_idx#4) goto main::@9 -- vbuc1_neq_vbuyy_then_la1 + cpy #0 + bne __b9 + // main::@11 + // if(p0_ypos==i) + // [35] if((byte) p0_ypos#1!=(byte) main::i#2) goto main::@15 -- vbum1_neq_vbuxx_then_la1 + cpx p0_ypos + bne __b10 + // [37] phi from main::@11 to main::@10 [phi:main::@11->main::@10] + // [37] phi (byte) main::p0_idx#8 = (byte) 1 [phi:main::@11->main::@10#0] -- vbuyy=vbuc1 + ldy #1 + jmp __b10 + // [36] phi from main::@11 to main::@15 [phi:main::@11->main::@15] + // main::@15 + // [37] phi from main::@12 main::@15 to main::@10 [phi:main::@12/main::@15->main::@10] + // [37] phi (byte) main::p0_idx#8 = (byte) main::p0_idx#3 [phi:main::@12/main::@15->main::@10#0] -- register_copy + // [37] phi from main::@9 to main::@10 [phi:main::@9->main::@10] + __b1: + // [37] phi (byte) main::p0_idx#8 = (byte) 0 [phi:main::@9->main::@10#0] -- vbuyy=vbuc1 + ldy #0 + // main::@10 + __b10: + // for(char i=1;i<192;i++) + // [38] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuxx=_inc_vbuxx + inx + // [24] phi from main::@10 to main::@6 [phi:main::@10->main::@6] + // [24] phi (byte) main::p0_idx#4 = (byte) main::p0_idx#8 [phi:main::@10->main::@6#0] -- register_copy + // [24] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@10->main::@6#1] -- register_copy + jmp __b6 + // main::@9 + __b9: + // gfx = SPRITE_C[p0_idx] + // [39] (byte) main::gfx#0 ← *((const byte*) SPRITE_C + (byte) main::p0_idx#4) -- vbuaa=pbuc1_derefidx_vbuyy + // Player 0 is active - show it + lda SPRITE_C,y + // TIA->GRP0 = gfx + // [40] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_GRP0) ← (byte) main::gfx#0 -- _deref_pbuc1=vbuaa + sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_GRP0 + // if(gfx==0) + // [41] if((byte) main::gfx#0==(byte) 0) goto main::@10 -- vbuaa_eq_0_then_la1 + cmp #0 + beq __b1 + // main::@12 + // p0_idx++; + // [42] (byte) main::p0_idx#3 ← ++ (byte) main::p0_idx#4 -- vbuyy=_inc_vbuyy + iny + jmp __b10 + // main::@4 + __b4: + // TIA->WSYNC = 0 + // [43] *((byte*)(const nomodify struct ATARI_TIA_WRITE*) TIA+(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC) ← (byte) 0 -- _deref_pbuc1=vbuc2 + lda #0 + sta TIA+OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC + jmp __b3 +} + // File Data +.segment Data +SINTABLE_160: +.fill $100, 5+round(74.5+74.5*sin(2*PI*i/256)) + + SPRITE_C: .byte 0, $18, $18, $18, $18, $3c, $3c, $3c, $3c, $66, $66, $66, $66, $c0, $c0, $c0, $c0, $c0, $c0, $c0, $c0, $66, $66, $66, $66, $3c, $3c, $3c, $3c, $18, $18, $18, $18, 0 +.segment Vars + // Player 0 X position + p0_xpos: .byte 0 + // Counts frames + idx: .byte 0 + // Player 0 Y position + p0_ypos: .byte 0 + idx2: .byte 0 + diff --git a/src/test/ref/examples/atari2600/atari2600-sprites.sym b/src/test/ref/examples/atari2600/atari2600-sprites.sym new file mode 100644 index 000000000..c029ef976 --- /dev/null +++ b/src/test/ref/examples/atari2600/atari2600-sprites.sym @@ -0,0 +1,131 @@ +(label) @1 +(label) @begin +(label) @end +(byte) ATARI_TIA_READ::CXBLPF +(byte) ATARI_TIA_READ::CXM0FB +(byte) ATARI_TIA_READ::CXM0P +(byte) ATARI_TIA_READ::CXM1FB +(byte) ATARI_TIA_READ::CXM1P +(byte) ATARI_TIA_READ::CXP0FB +(byte) ATARI_TIA_READ::CXP1FB +(byte) ATARI_TIA_READ::CXPPMM +(byte) ATARI_TIA_READ::INPT0 +(byte) ATARI_TIA_READ::INPT1 +(byte) ATARI_TIA_READ::INPT2 +(byte) ATARI_TIA_READ::INPT3 +(byte) ATARI_TIA_READ::INPT4 +(byte) ATARI_TIA_READ::INPT5 +(byte) ATARI_TIA_WRITE::AUDC0 +(byte) ATARI_TIA_WRITE::AUDC1 +(byte) ATARI_TIA_WRITE::AUDF0 +(byte) ATARI_TIA_WRITE::AUDF1 +(byte) ATARI_TIA_WRITE::AUDV0 +(byte) ATARI_TIA_WRITE::AUDV1 +(byte) ATARI_TIA_WRITE::COLUBK +(byte) ATARI_TIA_WRITE::COLUP0 +(byte) ATARI_TIA_WRITE::COLUP1 +(byte) ATARI_TIA_WRITE::COLUPF +(byte) ATARI_TIA_WRITE::CTRLPF +(byte) ATARI_TIA_WRITE::CXCLR +(byte) ATARI_TIA_WRITE::ENABL +(byte) ATARI_TIA_WRITE::ENAM0 +(byte) ATARI_TIA_WRITE::ENAM1 +(byte) ATARI_TIA_WRITE::GRP0 +(byte) ATARI_TIA_WRITE::GRP1 +(byte) ATARI_TIA_WRITE::HMBL +(byte) ATARI_TIA_WRITE::HMCLR +(byte) ATARI_TIA_WRITE::HMM0 +(byte) ATARI_TIA_WRITE::HMM1 +(byte) ATARI_TIA_WRITE::HMOVE +(byte) ATARI_TIA_WRITE::HMP0 +(byte) ATARI_TIA_WRITE::HMP1 +(byte) ATARI_TIA_WRITE::NUSIZ0 +(byte) ATARI_TIA_WRITE::NUSIZ1 +(byte) ATARI_TIA_WRITE::PF0 +(byte) ATARI_TIA_WRITE::PF1 +(byte) ATARI_TIA_WRITE::PF2 +(byte) ATARI_TIA_WRITE::REFP0 +(byte) ATARI_TIA_WRITE::REFP1 +(byte) ATARI_TIA_WRITE::RESBL +(byte) ATARI_TIA_WRITE::RESM0 +(byte) ATARI_TIA_WRITE::RESM1 +(byte) ATARI_TIA_WRITE::RESMP0 +(byte) ATARI_TIA_WRITE::RESMP1 +(byte) ATARI_TIA_WRITE::RESP0 +(byte) ATARI_TIA_WRITE::RESP1 +(byte) ATARI_TIA_WRITE::RSYNC +(byte) ATARI_TIA_WRITE::VBLANK +(byte) ATARI_TIA_WRITE::VDELBL +(byte) ATARI_TIA_WRITE::VDELP0 +(byte) ATARI_TIA_WRITE::VDELP1 +(byte) ATARI_TIA_WRITE::VSYNC +(byte) ATARI_TIA_WRITE::WSYNC +(const nomodify byte) CYCLES_PER_SCANLINE = (byte) $4c +(byte) MOS6532_RIOT::INTIM +(byte) MOS6532_RIOT::SWACNT +(byte) MOS6532_RIOT::SWBCNT +(byte) MOS6532_RIOT::SWCHA +(byte) MOS6532_RIOT::SWCHB +(byte) MOS6532_RIOT::T1024T +(byte) MOS6532_RIOT::TIM1T +(byte) MOS6532_RIOT::TIM64T +(byte) MOS6532_RIOT::TIM8T +(const byte*) MOS6532_RIOT::UNUSED[(number) $f] = { fill( $f, 0) } +(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_COLUBK = (byte) 9 +(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_COLUP0 = (byte) 6 +(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_GRP0 = (byte) $1b +(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_HMOVE = (byte) $2a +(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_VBLANK = (byte) 1 +(const byte) OFFSET_STRUCT_ATARI_TIA_WRITE_WSYNC = (byte) 2 +(const byte) OFFSET_STRUCT_MOS6532_RIOT_INTIM = (byte) 4 +(const byte) OFFSET_STRUCT_MOS6532_RIOT_TIM64T = (byte) $16 +(const nomodify struct MOS6532_RIOT*) RIOT = (struct MOS6532_RIOT*) 640 +(const to_nomodify byte*) SINTABLE_160[(number) $100] = kickasm {{ .fill $100, 5+round(74.5+74.5*sin(2*PI*i/256)) + }} +(const byte*) SPRITE_C[] = { (byte) 0, (byte) $18, (byte) $18, (byte) $18, (byte) $18, (byte) $3c, (byte) $3c, (byte) $3c, (byte) $3c, (byte) $66, (byte) $66, (byte) $66, (byte) $66, (byte) $c0, (byte) $c0, (byte) $c0, (byte) $c0, (byte) $c0, (byte) $c0, (byte) $c0, (byte) $c0, (byte) $66, (byte) $66, (byte) $66, (byte) $66, (byte) $3c, (byte) $3c, (byte) $3c, (byte) $3c, (byte) $18, (byte) $18, (byte) $18, (byte) $18, (byte) 0 } +(const nomodify struct ATARI_TIA_WRITE*) TIA = (struct ATARI_TIA_WRITE*) 0 +(const nomodify byte*) TIA_HMP0 = (byte*) 32 +(const nomodify byte*) TIA_RESP0 = (byte*) 16 +(const nomodify byte*) TIA_WSYNC = (byte*) 2 +(byte) idx +(byte) idx#1 idx mem[1] 39.357142857142854 +(byte) idx#2 idx mem[1] 133.66666666666669 +(byte) idx2 +(byte) idx2#1 idx2 mem[1] 42.38461538461539 +(byte) idx2#2 idx2 mem[1] 109.36363636363637 +(void()) main() +(label) main::@1 +(label) main::@10 +(label) main::@11 +(label) main::@12 +(label) main::@13 +(label) main::@14 +(label) main::@15 +(label) main::@2 +(label) main::@3 +(label) main::@4 +(label) main::@5 +(label) main::@6 +(label) main::@7 +(label) main::@8 +(label) main::@9 +(byte) main::gfx +(byte) main::gfx#0 reg byte a 1501.5 +(byte) main::i +(byte) main::i#1 reg byte x 2002.0 +(byte) main::i#2 reg byte x 417.08333333333337 +(byte) main::p0_idx +(byte) main::p0_idx#3 reg byte y 2002.0 +(byte) main::p0_idx#4 reg byte y 500.5 +(byte) main::p0_idx#8 reg byte y 1501.5 +(byte) p0_xpos loadstore mem[1] 2.4634146341463414 = (byte) 0 +(byte) p0_ypos +(byte) p0_ypos#1 p0_ypos mem[1] 52.476190476190474 + +mem[1] [ idx#2 idx#1 ] +mem[1] [ idx2#2 idx2#1 ] +reg byte x [ main::i#2 main::i#1 ] +reg byte y [ main::p0_idx#4 main::p0_idx#8 main::p0_idx#3 ] +mem[1] [ p0_xpos ] +mem[1] [ p0_ypos#1 ] +reg byte a [ main::gfx#0 ]