mirror of
https://gitlab.com/camelot/kickc.git
synced 2026-04-26 21:18:18 +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:
@@ -32,7 +32,7 @@ import java.util.stream.Collectors;
|
|||||||
descriptionHeading = "%nDescription:%n%n",
|
descriptionHeading = "%nDescription:%n%n",
|
||||||
parameterListHeading = "%nParameters:%n",
|
parameterListHeading = "%nParameters:%n",
|
||||||
optionListHeading = "%nOptions:%n",
|
optionListHeading = "%nOptions:%n",
|
||||||
version = "KickC 0.8.1 BETA"
|
version = "KickC 0.8.2 BETA"
|
||||||
)
|
)
|
||||||
public class KickC implements Callable<Integer> {
|
public class KickC implements Callable<Integer> {
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"link": "atari2600.ld",
|
||||||
|
"cpu": "MOS6502X",
|
||||||
|
"emulator": "stella",
|
||||||
|
"defines": {
|
||||||
|
"__ATARI2600__": 1
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -44,12 +44,16 @@ public class TestPrograms {
|
|||||||
public TestPrograms() {
|
public TestPrograms() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAtari2600Min() throws IOException, URISyntaxException {
|
||||||
|
compileAndCompare("atari2600-min.c");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testVic20Raster() throws IOException, URISyntaxException {
|
public void testVic20Raster() throws IOException, URISyntaxException {
|
||||||
compileAndCompare("vic20-raster.c");
|
compileAndCompare("vic20-raster.c");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testVic20Simple() throws IOException, URISyntaxException {
|
public void testVic20Simple() throws IOException, URISyntaxException {
|
||||||
compileAndCompare("vic20-simple.c");
|
compileAndCompare("vic20-simple.c");
|
||||||
|
|||||||
@@ -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)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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
|
||||||
@@ -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
@@ -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 ]
|
||||||
Reference in New Issue
Block a user