Add C support for Atari 2600 (VCS)

This commit is contained in:
Florent Flament 2017-01-08 19:12:55 +01:00
parent 1fc2dfb64f
commit c1aac0de0e
13 changed files with 456 additions and 0 deletions

22
cfg/atari2600.cfg Normal file
View File

@ -0,0 +1,22 @@
# Atari VCS 2600 linker configuration file for cc65
#
# Florent Flament (contact@florentflament.com), 2017
SYMBOLS {
__STACKSIZE__: type = weak, value = $0010; # 16 Bytes system stack
}
MEMORY {
RAM: file = "", start = $0080, size = $0080 - __STACKSIZE__, define = yes;
ROM: file = %O, start = $F000, size = $1000, fill = yes, fillval = $FF;
}
SEGMENTS {
ZEROPAGE: load = RAM, type = zp;
STARTUP: load = ROM, type = ro;
CODE: load = ROM, type = ro;
RODATA: load = ROM, type = ro, optional = yes;
DATA: load = ROM, run = RAM, type = rw, optional = yes, define = yes;
BSS: load = RAM, type = bss, optional = yes;
VECTORS: load = ROM, type = ro, start = $FFFA;
}

26
include/_riot.h Normal file
View File

@ -0,0 +1,26 @@
/*****************************************************************************/
/* */
/* Atari VCS 2600 RIOT registers addresses */
/* */
/* Source: DASM - vcs.h */
/* */
/* Florent Flament (contact@florentflament.com), 2017 */
/* */
/*****************************************************************************/
/* RIOT registers */
struct __riot {
unsigned char swcha;
unsigned char swacnt;
unsigned char swchb;
unsigned char swbcnt;
unsigned char intim;
unsigned char timint;
unsigned char unused[14];
unsigned char tim1t;
unsigned char tim8t;
unsigned char tim64t;
unsigned char t1024t;
};

100
include/_tia.h Normal file
View File

@ -0,0 +1,100 @@
/*****************************************************************************/
/* */
/* Atari VCS 2600 TIA registers addresses */
/* */
/* Source: DASM - vcs.h */
/* */
/* Florent Flament (contact@florentflament.com), 2017 */
/* */
/*****************************************************************************/
/* TIA write / read registers */
struct __tia {
union {
unsigned char vsync;
unsigned char cxm0p;
};
union {
unsigned char vblank;
unsigned char cxm1p;
};
union {
unsigned char wsync;
unsigned char cxp0fb;
};
union {
unsigned char rsync;
unsigned char cxp1fb;
};
union {
unsigned char nusiz0;
unsigned char cxm0fb;
};
union {
unsigned char nusiz1;
unsigned char cxm1fb;
};
union {
unsigned char colup0;
unsigned char cxblpf;
};
union {
unsigned char colup1;
unsigned char cxppmm;
};
union {
unsigned char colupf;
unsigned char inpt0;
};
union {
unsigned char colubk;
unsigned char inpt1;
};
union {
unsigned char ctrlpf;
unsigned char inpt2;
};
union {
unsigned char refp0;
unsigned char inpt3;
};
union {
unsigned char refp1;
unsigned char inpt4;
};
union {
unsigned char pf0;
unsigned char inpt5;
};
unsigned char pf1;
unsigned char pf2;
unsigned char resp0;
unsigned char resp1;
unsigned char resm0;
unsigned char resm1;
unsigned char resbl;
unsigned char audc0;
unsigned char audc1;
unsigned char audf0;
unsigned char audf1;
unsigned char audv0;
unsigned char audv1;
unsigned char grp0;
unsigned char grp1;
unsigned char enam0;
unsigned char enam1;
unsigned char enabl;
unsigned char hmp0;
unsigned char hmp1;
unsigned char hmm0;
unsigned char hmm1;
unsigned char hmbl;
unsigned char vdelp0;
unsigned char vdelp1;
unsigned char vdelbl;
unsigned char resmp0;
unsigned char resmp1;
unsigned char hmove;
unsigned char hmclr;
unsigned char cxclr;
};

26
include/atari2600.h Normal file
View File

@ -0,0 +1,26 @@
/*****************************************************************************/
/* */
/* Atari VCS 2600 TIA & RIOT registers addresses */
/* */
/* Source: DASM Version 1.05 - vcs.h */
/* */
/* Florent Flament (contact@florentflament.com), 2017 */
/* */
/*****************************************************************************/
#ifndef _ATARI2600_H
#define _ATARI2600_H
/* Check for errors */
#if !defined(__ATARI2600__)
# error This module may only be used when compiling for the Atari 2600!
#endif
#include <_tia.h>
#define TIA (*(struct __tia*)0x0000)
#include <_riot.h>
#define RIOT (*(struct __riot*)0x0280)
/* End of atari2600.h */
#endif /* #ifndef _ATARI2600_H */

View File

@ -19,6 +19,7 @@ TARGETS = apple2 \
apple2enh \
atari \
atarixl \
atari2600 \
atari5200 \
atmos \
$(CBMS) \

49
libsrc/atari2600/crt0.s Normal file
View File

@ -0,0 +1,49 @@
; Atari VCS 2600 startup code for cc65
;
; Florent Flament (contact@florentflament.com), 2017
.export _exit
.export __STARTUP__ : absolute = 1
.import __RAM_START__, __RAM_SIZE__
.import copydata
.import _main
.include "zeropage.inc"
.segment "STARTUP"
start:
; Clear decimal mode
cld
; Initialization Loop:
; * Clears Atari 2600 whole memory (128 bytes) including BSS segment
; * Clears TIA registers
; * Sets system stack pointer to $ff (i.e top of zero-page)
ldx #0
txa
clearLoop:
dex
txs
pha
bne clearLoop
; Initialize data
jsr copydata
; Initialize C stack pointer
lda #<(__RAM_START__ + __RAM_SIZE__)
ldx #>(__RAM_START__ + __RAM_SIZE__)
sta sp
stx sp+1
; Call main
jsr _main
_exit: jmp _exit
.segment "VECTORS"
.word start ; NMI
.word start ; Reset
.word start ; IRQ

162
libsrc/atari2600/ctype.s Normal file
View File

@ -0,0 +1,162 @@
;
; Ullrich von Bassewitz, 2003-10-10
;
; Character specification table.
;
.include "ctype.inc"
; The tables are readonly, put them into the rodata segment
.rodata
; The following 256 byte wide table specifies attributes for the isxxx type
; of functions. Doing it by a table means some overhead in space, but it
; has major advantages:
;
; * It is fast. If it weren't for the slow parameter passing of cc65, one
; could even define macros for the isxxx functions (this is usually
; done on other platforms).
;
; * It is highly portable. The only unportable part is the table itself,
; all real code goes into the common library.
;
; * We save some code in the isxxx functions.
__ctype:
.byte CT_CTRL ; 0/00 ___ctrl_@___
.byte CT_CTRL ; 1/01 ___ctrl_A___
.byte CT_CTRL ; 2/02 ___ctrl_B___
.byte CT_CTRL ; 3/03 ___ctrl_C___
.byte CT_CTRL ; 4/04 ___ctrl_D___
.byte CT_CTRL ; 5/05 ___ctrl_E___
.byte CT_CTRL ; 6/06 ___ctrl_F___
.byte CT_CTRL ; 7/07 ___ctrl_G___
.byte CT_CTRL ; 8/08 ___ctrl_H___
.byte CT_CTRL | CT_OTHER_WS | CT_SPACE_TAB
; 9/09 ___ctrl_I___
.byte CT_CTRL | CT_OTHER_WS ; 10/0a ___ctrl_J___
.byte CT_CTRL | CT_OTHER_WS ; 11/0b ___ctrl_K___
.byte CT_CTRL | CT_OTHER_WS ; 12/0c ___ctrl_L___
.byte CT_CTRL | CT_OTHER_WS ; 13/0d ___ctrl_M___
.byte CT_CTRL ; 14/0e ___ctrl_N___
.byte CT_CTRL ; 15/0f ___ctrl_O___
.byte CT_CTRL ; 16/10 ___ctrl_P___
.byte CT_CTRL ; 17/11 ___ctrl_Q___
.byte CT_CTRL ; 18/12 ___ctrl_R___
.byte CT_CTRL ; 19/13 ___ctrl_S___
.byte CT_CTRL ; 20/14 ___ctrl_T___
.byte CT_CTRL ; 21/15 ___ctrl_U___
.byte CT_CTRL ; 22/16 ___ctrl_V___
.byte CT_CTRL ; 23/17 ___ctrl_W___
.byte CT_CTRL ; 24/18 ___ctrl_X___
.byte CT_CTRL ; 25/19 ___ctrl_Y___
.byte CT_CTRL ; 26/1a ___ctrl_Z___
.byte CT_CTRL ; 27/1b ___ctrl_[___
.byte CT_CTRL ; 28/1c ___ctrl_\___
.byte CT_CTRL ; 29/1d ___ctrl_]___
.byte CT_CTRL ; 30/1e ___ctrl_^___
.byte CT_CTRL ; 31/1f ___ctrl_____
.byte CT_SPACE | CT_SPACE_TAB ; 32/20 ___SPACE___
.byte CT_NONE ; 33/21 _____!_____
.byte CT_NONE ; 34/22 _____"_____
.byte CT_NONE ; 35/23 _____#_____
.byte CT_NONE ; 36/24 _____$_____
.byte CT_NONE ; 37/25 _____%_____
.byte CT_NONE ; 38/26 _____&_____
.byte CT_NONE ; 39/27 _____'_____
.byte CT_NONE ; 40/28 _____(_____
.byte CT_NONE ; 41/29 _____)_____
.byte CT_NONE ; 42/2a _____*_____
.byte CT_NONE ; 43/2b _____+_____
.byte CT_NONE ; 44/2c _____,_____
.byte CT_NONE ; 45/2d _____-_____
.byte CT_NONE ; 46/2e _____._____
.byte CT_NONE ; 47/2f _____/_____
.byte CT_DIGIT | CT_XDIGIT ; 48/30 _____0_____
.byte CT_DIGIT | CT_XDIGIT ; 49/31 _____1_____
.byte CT_DIGIT | CT_XDIGIT ; 50/32 _____2_____
.byte CT_DIGIT | CT_XDIGIT ; 51/33 _____3_____
.byte CT_DIGIT | CT_XDIGIT ; 52/34 _____4_____
.byte CT_DIGIT | CT_XDIGIT ; 53/35 _____5_____
.byte CT_DIGIT | CT_XDIGIT ; 54/36 _____6_____
.byte CT_DIGIT | CT_XDIGIT ; 55/37 _____7_____
.byte CT_DIGIT | CT_XDIGIT ; 56/38 _____8_____
.byte CT_DIGIT | CT_XDIGIT ; 57/39 _____9_____
.byte CT_NONE ; 58/3a _____:_____
.byte CT_NONE ; 59/3b _____;_____
.byte CT_NONE ; 60/3c _____<_____
.byte CT_NONE ; 61/3d _____=_____
.byte CT_NONE ; 62/3e _____>_____
.byte CT_NONE ; 63/3f _____?_____
.byte CT_NONE ; 64/40 _____@_____
.byte CT_UPPER | CT_XDIGIT ; 65/41 _____A_____
.byte CT_UPPER | CT_XDIGIT ; 66/42 _____B_____
.byte CT_UPPER | CT_XDIGIT ; 67/43 _____C_____
.byte CT_UPPER | CT_XDIGIT ; 68/44 _____D_____
.byte CT_UPPER | CT_XDIGIT ; 69/45 _____E_____
.byte CT_UPPER | CT_XDIGIT ; 70/46 _____F_____
.byte CT_UPPER ; 71/47 _____G_____
.byte CT_UPPER ; 72/48 _____H_____
.byte CT_UPPER ; 73/49 _____I_____
.byte CT_UPPER ; 74/4a _____J_____
.byte CT_UPPER ; 75/4b _____K_____
.byte CT_UPPER ; 76/4c _____L_____
.byte CT_UPPER ; 77/4d _____M_____
.byte CT_UPPER ; 78/4e _____N_____
.byte CT_UPPER ; 79/4f _____O_____
.byte CT_UPPER ; 80/50 _____P_____
.byte CT_UPPER ; 81/51 _____Q_____
.byte CT_UPPER ; 82/52 _____R_____
.byte CT_UPPER ; 83/53 _____S_____
.byte CT_UPPER ; 84/54 _____T_____
.byte CT_UPPER ; 85/55 _____U_____
.byte CT_UPPER ; 86/56 _____V_____
.byte CT_UPPER ; 87/57 _____W_____
.byte CT_UPPER ; 88/58 _____X_____
.byte CT_UPPER ; 89/59 _____Y_____
.byte CT_UPPER ; 90/5a _____Z_____
.byte CT_NONE ; 91/5b _____[_____
.byte CT_NONE ; 92/5c _____\_____
.byte CT_NONE ; 93/5d _____]_____
.byte CT_NONE ; 94/5e _____^_____
.byte CT_NONE ; 95/5f _UNDERLINE_
.byte CT_NONE ; 96/60 ___grave___
.byte CT_LOWER | CT_XDIGIT ; 97/61 _____a_____
.byte CT_LOWER | CT_XDIGIT ; 98/62 _____b_____
.byte CT_LOWER | CT_XDIGIT ; 99/63 _____c_____
.byte CT_LOWER | CT_XDIGIT ; 100/64 _____d_____
.byte CT_LOWER | CT_XDIGIT ; 101/65 _____e_____
.byte CT_LOWER | CT_XDIGIT ; 102/66 _____f_____
.byte CT_LOWER ; 103/67 _____g_____
.byte CT_LOWER ; 104/68 _____h_____
.byte CT_LOWER ; 105/69 _____i_____
.byte CT_LOWER ; 106/6a _____j_____
.byte CT_LOWER ; 107/6b _____k_____
.byte CT_LOWER ; 108/6c _____l_____
.byte CT_LOWER ; 109/6d _____m_____
.byte CT_LOWER ; 110/6e _____n_____
.byte CT_LOWER ; 111/6f _____o_____
.byte CT_LOWER ; 112/70 _____p_____
.byte CT_LOWER ; 113/71 _____q_____
.byte CT_LOWER ; 114/72 _____r_____
.byte CT_LOWER ; 115/73 _____s_____
.byte CT_LOWER ; 116/74 _____t_____
.byte CT_LOWER ; 117/75 _____u_____
.byte CT_LOWER ; 118/76 _____v_____
.byte CT_LOWER ; 119/77 _____w_____
.byte CT_LOWER ; 120/78 _____x_____
.byte CT_LOWER ; 121/79 _____y_____
.byte CT_LOWER ; 122/7a _____z_____
.byte CT_NONE ; 123/7b _____{_____
.byte CT_NONE ; 124/7c _____|_____
.byte CT_NONE ; 125/7d _____}_____
.byte CT_NONE ; 126/7e _____~_____
.byte CT_OTHER_WS ; 127/7f ____DEL____
.res 128, CT_NONE ; 128-255

View File

@ -147,6 +147,9 @@ EXELIST_atari = \
EXELIST_atarixl = $(EXELIST_atari)
EXELIST_atari2600 = \
atari2600hello
# --------------------------------------------------------------------------
# Rules to make the binaries and the disk

56
samples/atari2600hello.c Normal file
View File

@ -0,0 +1,56 @@
/*****************************************************************************/
/* */
/* Atari VCS 2600 sample C program */
/* */
/* Florent Flament (contact@florentflament.com), 2017 */
/* */
/*****************************************************************************/
#include <atari2600.h>
// PAL Timings
// Roughly computed based on Stella Programmer's guide (Steve Wright)
// scanlines count per section.
#define VBLANK_TIM64 51 // 45 lines * 76 cycles/line / 64 cycles/tick
#define KERNAL_T1024 17 // 228 lines * 76 cycles/line / 1024 cycles/tick
#define OVERSCAN_TIM64 42 // 36 lines * 76 cycles/line / 64 cycles/tick
// Testing memory zones
const unsigned char rodata_v[] = "Hello!";
unsigned char data_v = 0x77;
unsigned char bss_v;
void main(void) {
unsigned char color = 0x79; // Stack variable
bss_v = 0x88; // Testing BSS variable
for/*ever*/(;;) {
// Vertical Sync signal
TIA.vsync = 0x02;
TIA.wsync = 0x00;
TIA.wsync = 0x00;
TIA.wsync = 0x00;
TIA.vsync = 0x00;
// Vertical Blank timer setting
RIOT.tim64t = VBLANK_TIM64;
// Doing frame computation during blank
TIA.colubk = color++; // Update color
// Wait for end of Vertical Blank
while (RIOT.timint == 0) {}
TIA.wsync = 0x00;
TIA.vblank = 0x00; // Turn on beam
// Display frame
RIOT.t1024t = KERNAL_T1024;
while (RIOT.timint == 0) {}
TIA.wsync = 0x00;
TIA.vblank = 0x02; // Turn off beam
// Overscan
RIOT.tim64t = OVERSCAN_TIM64;
while (RIOT.timint == 0) {}
}
}

View File

@ -205,6 +205,10 @@ static void SetSys (const char* Sys)
AbEnd ("Cannot use `module' as a target for the assembler");
break;
case TGT_ATARI2600:
NewSymbol ("__ATARI2600__", 1);
break;
case TGT_ATARI5200:
NewSymbol ("__ATARI5200__", 1);
break;

View File

@ -161,6 +161,10 @@ static void SetSys (const char* Sys)
AbEnd ("Cannot use `module' as a target for the compiler");
break;
case TGT_ATARI2600:
DefineNumericMacro ("__ATARI2600__", 1);
break;
case TGT_ATARI5200:
DefineNumericMacro ("__ATARI5200__", 1);
break;

View File

@ -145,6 +145,7 @@ static const TargetEntry TargetMap[] = {
{ "apple2", TGT_APPLE2 },
{ "apple2enh", TGT_APPLE2ENH },
{ "atari", TGT_ATARI },
{ "atari2600", TGT_ATARI2600 },
{ "atari5200", TGT_ATARI5200 },
{ "atarixl", TGT_ATARIXL },
{ "atmos", TGT_ATMOS },
@ -181,6 +182,7 @@ static const TargetProperties PropertyTable[TGT_COUNT] = {
{ "none", CPU_6502, BINFMT_BINARY, CTNone },
{ "module", CPU_6502, BINFMT_O65, CTNone },
{ "atari", CPU_6502, BINFMT_BINARY, CTAtari },
{ "atari2600", CPU_6502, BINFMT_BINARY, CTNone },
{ "atari5200", CPU_6502, BINFMT_BINARY, CTAtari },
{ "atarixl", CPU_6502, BINFMT_BINARY, CTAtari },
{ "vic20", CPU_6502, BINFMT_BINARY, CTPET },

View File

@ -55,6 +55,7 @@ typedef enum {
TGT_NONE,
TGT_MODULE,
TGT_ATARI,
TGT_ATARI2600,
TGT_ATARI5200,
TGT_ATARIXL,
TGT_VIC20,