1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2024-11-26 12:49:21 +00:00

Added Atari 2600 target platform and a minimal sample program. It is functional, but still needs some work.

This commit is contained in:
jespergravgaard 2020-05-16 22:13:47 +02:00
parent 9693ea125a
commit 26718942e9
9 changed files with 1385 additions and 2 deletions

View File

@ -32,7 +32,7 @@ import java.util.stream.Collectors;
descriptionHeading = "%nDescription:%n%n",
parameterListHeading = "%nParameters:%n",
optionListHeading = "%nOptions:%n",
version = "KickC 0.8.1 BETA"
version = "KickC 0.8.2 BETA"
)
public class KickC implements Callable<Integer> {

View File

@ -0,0 +1,10 @@
// Atari 2600 VCS 4K ROM
.file [name="%O.prg", type="bin", segments="Code, Vectors"]
.segmentdef Code [start=$f800,min=$f800,max=$fff9]
.segmentdef Data [start=$80,max=$ff, virtual]
.segmentdef Vectors [start=$fffa,max=$ffff]
.segment Vectors
.word %E // NMI
.word %E // RESET
.word %E // IRQ
.segment Code

View File

@ -0,0 +1,8 @@
{
"link": "atari2600.ld",
"cpu": "MOS6502X",
"emulator": "stella",
"defines": {
"__ATARI2600__": 1
}
}

View File

@ -44,12 +44,16 @@ public class TestPrograms {
public TestPrograms() {
}
@Test
public void testAtari2600Min() throws IOException, URISyntaxException {
compileAndCompare("atari2600-min.c");
}
@Test
public void testVic20Raster() throws IOException, URISyntaxException {
compileAndCompare("vic20-raster.c");
}
@Test
public void testVic20Simple() throws IOException, URISyntaxException {
compileAndCompare("vic20-simple.c");

View File

@ -0,0 +1,51 @@
// Minimal Atari 2600 VCS Program
#pragma target(atari2600)
char * const VSYNC = 0x00;
char * const VBLANK = 0x01;
char * const WSYNC = 0x02;
char * const BACKGROUND_COLOR = 0x09;
char __mem col=0;
void main() {
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.
*WSYNC = 2; // Wait for SYNC (halts CPU until end of scanline)
*VSYNC = 2; // Accumulator D1=1, turns on Vertical Sync signal
*WSYNC = 2; // Wait for Sync - halts CPU until end of 1st scanline of VSYNC
*WSYNC = 2; // wait until end of 2nd scanline of VSYNC
*WSYNC = 0; // wait until end of 3rd scanline of VSYNC
*VSYNC = 0; // Accumulator 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++) {
*WSYNC = 0; // Wait for SYNC (halts CPU until end of scanline)
}
// 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.
*VBLANK = 0; // D1=1, turns off Vertical Blank signal (image output on)
char c = col++;
for(char i=0;i<192;i++) {
*WSYNC = 0; // Wait for SYNC (halts CPU until end of scanline)
*BACKGROUND_COLOR = c++; // Set background color
}
// Overscan - game logic
// Since we don't have any yet, just delay
*WSYNC = 0; // Wait for SYNC (halts CPU until end of scanline)
*VBLANK = 2; // // D1=1 turns image output off
*BACKGROUND_COLOR = 0;
for(char i=0;i<07;i++) {
*WSYNC = 0; // Wait for SYNC (halts CPU until end of scanline)
}
}
}

View File

@ -0,0 +1,113 @@
// Minimal Atari 2600 VCS Program
// Atari 2600 VCS 4K ROM
.file [name="atari2600-min.prg", type="bin", segments="Code, Vectors"]
.segmentdef Code [start=$f800,min=$f800,max=$fff9]
.segmentdef Data [start=$80,max=$ff, virtual]
.segmentdef Vectors [start=$fffa,max=$ffff]
.segment Vectors
.word main // NMI
.word main // RESET
.word main // IRQ
.segment Code
.label VSYNC = 0
.label VBLANK = 1
.label WSYNC = 2
.label BACKGROUND_COLOR = 9
.segment Code
main: {
lda #0
sta col
__b2:
// *WSYNC = 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 WSYNC
// *VSYNC = 2
// Wait for SYNC (halts CPU until end of scanline)
sta VSYNC
// *WSYNC = 2
// Accumulator D1=1, turns on Vertical Sync signal
sta WSYNC
// Wait for Sync - halts CPU until end of 1st scanline of VSYNC
sta WSYNC
// *WSYNC = 0
// wait until end of 2nd scanline of VSYNC
lda #0
sta WSYNC
// *VSYNC = 0
// wait until end of 3rd scanline of VSYNC
sta VSYNC
tax
// Vertical Blank - game logic
// Since we don't have any yet, just delay
__b3:
// for(char i=0;i<37;i++)
cpx #$25
bcc __b4
// *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.
lda #0
sta VBLANK
// c = col++
// D1=1, turns off Vertical Blank signal (image output on)
ldx col
inc col
tay
__b6:
// for(char i=0;i<192;i++)
cpy #$c0
bcc __b7
// *WSYNC = 0
// Overscan - game logic
// Since we don't have any yet, just delay
lda #0
sta WSYNC
// *VBLANK = 2
// Wait for SYNC (halts CPU until end of scanline)
lda #2
sta VBLANK
// *BACKGROUND_COLOR = 0
// // D1=1 turns image output off
lda #0
sta BACKGROUND_COLOR
tax
__b9:
// for(char i=0;i<07;i++)
cpx #7
bcc __b10
jmp __b2
__b10:
// *WSYNC = 0
lda #0
sta WSYNC
// for(char i=0;i<07;i++)
inx
jmp __b9
__b7:
// *WSYNC = 0
lda #0
sta WSYNC
// *BACKGROUND_COLOR = c++
// Wait for SYNC (halts CPU until end of scanline)
stx BACKGROUND_COLOR
// *BACKGROUND_COLOR = c++;
inx
// for(char i=0;i<192;i++)
iny
jmp __b6
__b4:
// *WSYNC = 0
lda #0
sta WSYNC
// for(char i=0;i<37;i++)
inx
jmp __b3
}
.segment Data
col: .byte 0

View File

@ -0,0 +1,62 @@
@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
[4] phi()
to:main::@1
main::@1: scope:[main] from main main::@9
[5] (byte) col#12 ← phi( main/(byte) 0 main::@9/(byte) col#1 )
to:main::@2
main::@2: scope:[main] from main::@1
[6] *((const nomodify byte*) WSYNC) ← (byte) 2
[7] *((const nomodify byte*) VSYNC) ← (byte) 2
[8] *((const nomodify byte*) WSYNC) ← (byte) 2
[9] *((const nomodify byte*) WSYNC) ← (byte) 2
[10] *((const nomodify byte*) WSYNC) ← (byte) 0
[11] *((const nomodify byte*) VSYNC) ← (byte) 0
to:main::@3
main::@3: scope:[main] from main::@2 main::@4
[12] (byte) main::i#2 ← phi( main::@2/(byte) 0 main::@4/(byte) main::i#1 )
[13] if((byte) main::i#2<(byte) $25) goto main::@4
to:main::@5
main::@5: scope:[main] from main::@3
[14] *((const nomodify byte*) VBLANK) ← (byte) 0
[15] (byte) main::c#0 ← (byte) col#12
[16] (byte) col#1 ← ++ (byte) col#12
to:main::@6
main::@6: scope:[main] from main::@5 main::@7
[17] (byte) main::c#2 ← phi( main::@5/(byte) main::c#0 main::@7/(byte) main::c#1 )
[17] (byte) main::i1#2 ← phi( main::@5/(byte) 0 main::@7/(byte) main::i1#1 )
[18] if((byte) main::i1#2<(byte) $c0) goto main::@7
to:main::@8
main::@8: scope:[main] from main::@6
[19] *((const nomodify byte*) WSYNC) ← (byte) 0
[20] *((const nomodify byte*) VBLANK) ← (byte) 2
[21] *((const nomodify byte*) BACKGROUND_COLOR) ← (byte) 0
to:main::@9
main::@9: scope:[main] from main::@10 main::@8
[22] (byte) main::i2#2 ← phi( main::@10/(byte) main::i2#1 main::@8/(byte) 0 )
[23] if((byte) main::i2#2<(byte) 7) goto main::@10
to:main::@1
main::@10: scope:[main] from main::@9
[24] *((const nomodify byte*) WSYNC) ← (byte) 0
[25] (byte) main::i2#1 ← ++ (byte) main::i2#2
to:main::@9
main::@7: scope:[main] from main::@6
[26] *((const nomodify byte*) WSYNC) ← (byte) 0
[27] *((const nomodify byte*) BACKGROUND_COLOR) ← (byte) main::c#2
[28] (byte) main::c#1 ← ++ (byte) main::c#2
[29] (byte) main::i1#1 ← ++ (byte) main::i1#2
to:main::@6
main::@4: scope:[main] from main::@3
[30] *((const nomodify byte*) WSYNC) ← (byte) 0
[31] (byte) main::i#1 ← ++ (byte) main::i#2
to:main::@3

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,40 @@
(label) @1
(label) @begin
(label) @end
(const nomodify byte*) BACKGROUND_COLOR = (byte*) 9
(const nomodify byte*) VBLANK = (byte*) 1
(const nomodify byte*) VSYNC = (byte*) 0
(const nomodify byte*) WSYNC = (byte*) 2
(byte) col
(byte) col#1 col mem[1] 78.71428571428571
(byte) col#12 col mem[1] 92.53846153846155
(void()) main()
(label) main::@1
(label) main::@10
(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::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::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
mem[1] [ col#12 col#1 ]
reg byte x [ main::i#2 main::i#1 ]
reg byte y [ main::i1#2 main::i1#1 ]
reg byte x [ main::c#2 main::c#0 main::c#1 ]
reg byte x [ main::i2#2 main::i2#1 ]