1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2025-01-17 00:30:07 +00:00

Added Atari 2600 Sprite test.

This commit is contained in:
jespergravgaard 2020-05-21 21:34:34 +02:00
parent c9965b2cc7
commit d714c6ab4c
14 changed files with 3224 additions and 462 deletions

View File

@ -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;
};

View File

@ -12,3 +12,4 @@ struct ATARI_TIA_READ * const TIA_READ = 0x00;
// Atari RIOT registers
struct MOS6532_RIOT * const RIOT = 0x280;

View File

@ -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");

View File

@ -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 <atari2600.h>
@ -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;
}
}

View File

@ -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 <atari2600.h>
#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;
}
}

View File

@ -13,5 +13,5 @@ void main() {
eor value
sta SCREEN
}
}
}
}

View File

@ -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))

View File

@ -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

File diff suppressed because it is too large Load Diff

View File

@ -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 ]

View File

@ -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

View File

@ -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

File diff suppressed because it is too large Load Diff

View File

@ -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 ]