/***************************************************************************
Atari 400/800
GTIA graphics television interface adapter
Juergen Buchmueller, June 1998
***************************************************************************/
#include "driver.h"
#include "cpu/m6502/m6502.h"
#include "includes/atari.h"
#include "video/gtia.h"
gtia_struct gtia;
#define P0 0x01
#define P1 0x02
#define P2 0x04
#define P3 0x08
#define M0 0x10
#define M1 0x20
#define M2 0x40
#define M3 0x80
#define CHECK_GRACTL 0
#define VERBOSE 0
static void gtia_reset(running_machine *machine);
static void gtia_state(void);
static void gtia_state_postload(void);
/**********************************************
* split a color into hue and luminance values
**********************************************/
#define SPLIT_HUE_LUM(data,hue,lum) \
hue = (data & HUE); lum = (data & LUM)
/**********************************************
* set both color clocks equal for one color
**********************************************/
#define SETCOL_B(o,d) \
antic.color_lookup[o] = (Machine->remapped_colortable[d] << 8) | Machine->remapped_colortable[d]
/**********************************************
* set left color clock for one color
**********************************************/
#define SETCOL_L(o,d) \
*((UINT8*)&antic.color_lookup[o] + 0) = Machine->remapped_colortable[d]
/**********************************************
* set right color clock for one color
**********************************************/
#define SETCOL_R(o,d) \
*((UINT8*)&antic.color_lookup[o] + 1) = Machine->remapped_colortable[d]
/*************************************
*
* Initialization/Reset
*
*************************************/
void gtia_init(const gtia_interface *intf)
{
memset(>ia, 0, sizeof(gtia));
gtia.intf = *intf;
add_reset_callback(Machine, gtia_reset);
/* state saves */
gtia_state();
}
static void gtia_state(void)
{
state_save_register_global(gtia.r.m0pf);
state_save_register_global(gtia.r.m1pf);
state_save_register_global(gtia.r.m2pf);
state_save_register_global(gtia.r.m3pf);
state_save_register_global(gtia.r.p0pf);
state_save_register_global(gtia.r.p1pf);
state_save_register_global(gtia.r.p2pf);
state_save_register_global(gtia.r.p3pf);
state_save_register_global(gtia.r.m0pl);
state_save_register_global(gtia.r.m1pl);
state_save_register_global(gtia.r.m2pl);
state_save_register_global(gtia.r.m3pl);
state_save_register_global(gtia.r.p0pl);
state_save_register_global(gtia.r.p1pl);
state_save_register_global(gtia.r.p2pl);
state_save_register_global(gtia.r.p3pl);
state_save_register_global_array(gtia.r.but);
state_save_register_global(gtia.r.pal);
state_save_register_global(gtia.r.gtia15);
state_save_register_global(gtia.r.gtia16);
state_save_register_global(gtia.r.gtia17);
state_save_register_global(gtia.r.gtia18);
state_save_register_global(gtia.r.gtia19);
state_save_register_global(gtia.r.gtia1a);
state_save_register_global(gtia.r.gtia1b);
state_save_register_global(gtia.r.gtia1c);
state_save_register_global(gtia.r.gtia1d);
state_save_register_global(gtia.r.gtia1e);
state_save_register_global(gtia.r.cons);
state_save_register_global(gtia.w.hposp0);
state_save_register_global(gtia.w.hposp1);
state_save_register_global(gtia.w.hposp2);
state_save_register_global(gtia.w.hposp3);
state_save_register_global(gtia.w.hposm0);
state_save_register_global(gtia.w.hposm1);
state_save_register_global(gtia.w.hposm2);
state_save_register_global(gtia.w.hposm3);
state_save_register_global(gtia.w.sizep0);
state_save_register_global(gtia.w.sizep1);
state_save_register_global(gtia.w.sizep2);
state_save_register_global(gtia.w.sizep3);
state_save_register_global(gtia.w.sizem);
state_save_register_global_array(gtia.w.grafp0);
state_save_register_global_array(gtia.w.grafp1);
state_save_register_global_array(gtia.w.grafp2);
state_save_register_global_array(gtia.w.grafp3);
state_save_register_global_array(gtia.w.grafm);
state_save_register_global(gtia.w.colpm0);
state_save_register_global(gtia.w.colpm1);
state_save_register_global(gtia.w.colpm2);
state_save_register_global(gtia.w.colpm3);
state_save_register_global(gtia.w.colpf0);
state_save_register_global(gtia.w.colpf1);
state_save_register_global(gtia.w.colpf2);
state_save_register_global(gtia.w.colpf3);
state_save_register_global(gtia.w.colbk);
state_save_register_global(gtia.w.prior);
state_save_register_global(gtia.w.vdelay);
state_save_register_global(gtia.w.gractl);
state_save_register_global(gtia.w.hitclr);
state_save_register_global(gtia.w.cons);
state_save_register_func_postload(gtia_state_postload);
}
static int is_ntsc(void)
{
return ATTOSECONDS_TO_HZ(Machine->screen[0].refresh) > 55;
}
static void gtia_reset(running_machine *machine)
{
int i;
/* reset the GTIA read/write/helper registers */
for (i = 0; i < 32; i++)
atari_gtia_w(i,0);
memset(>ia.r, 0, sizeof(gtia.r));
if (is_ntsc())
gtia.r.pal = 0xff;
else
gtia.r.pal = 0xf1;
gtia.r.gtia15 = 0xff;
gtia.r.gtia16 = 0xff;
gtia.r.gtia17 = 0xff;
gtia.r.gtia18 = 0xff;
gtia.r.gtia19 = 0xff;
gtia.r.gtia1a = 0xff;
gtia.r.gtia1b = 0xff;
gtia.r.gtia1c = 0xff;
gtia.r.gtia1d = 0xff;
gtia.r.gtia1e = 0xff;
gtia.r.cons = 0x07; /* console keys */
SETCOL_B(ILL,0x3e); /* bright red */
SETCOL_B(EOR,0xff); /* yellow */
}
/**************************************************************
*
* Read GTIA hardware registers
*
**************************************************************/
READ8_HANDLER( atari_gtia_r )
{
switch (offset & 31)
{
case 0: return gtia.r.m0pf;
case 1: return gtia.r.m1pf;
case 2: return gtia.r.m2pf;
case 3: return gtia.r.m3pf;
case 4: return gtia.r.p0pf;
case 5: return gtia.r.p1pf;
case 6: return gtia.r.p2pf;
case 7: return gtia.r.p3pf;
case 8: return gtia.r.m0pl;
case 9: return gtia.r.m1pl;
case 10: return gtia.r.m2pl;
case 11: return gtia.r.m3pl;
case 12: return gtia.r.p0pl;
case 13: return gtia.r.p1pl;
case 14: return gtia.r.p2pl;
case 15: return gtia.r.p3pl;
case 16: return gtia.r.but[0];
case 17: return gtia.r.but[1];
case 18: return gtia.r.but[2];
case 19: return gtia.r.but[3];
case 20: return gtia.r.pal;
case 21: return gtia.r.gtia15;
case 22: return gtia.r.gtia16;
case 23: return gtia.r.gtia17;
case 24: return gtia.r.gtia18;
case 25: return gtia.r.gtia19;
case 26: return gtia.r.gtia1a;
case 27: return gtia.r.gtia1b;
case 28: return gtia.r.gtia1c;
case 29: return gtia.r.gtia1d;
case 30: return gtia.r.gtia1e;
case 31:
gtia.r.cons = gtia.intf.console_read ? (gtia.intf.console_read() & 0x0F) : 0x00;
return gtia.r.cons;
}
return 0xff;
}
static void recalc_p0(void)
{
if (
#if CHECK_GRACTL
(gtia.w.gractl & GTIA_PLAYER) == 0 ||
#endif
gtia.w.grafp0[gtia.h.vdelay_p0] == 0 || gtia.w.hposp0 >= 224 )
{
gtia.h.grafp0 = 0;
gtia.h.usedp &= ~0x10;
}
else
{
gtia.h.grafp0 = gtia.w.grafp0[gtia.h.vdelay_p0];
gtia.h.usedp |= 0x10;
}
}
static void recalc_p1(void)
{
if (
#if CHECK_GRACTL
(gtia.w.gractl & GTIA_PLAYER) == 0 ||
#endif
gtia.w.grafp1[gtia.h.vdelay_p1] == 0 || gtia.w.hposp1 >= 224 )
{
gtia.h.grafp1 = 0;
gtia.h.usedp &= ~0x20;
}
else
{
gtia.h.grafp1 = gtia.w.grafp1[gtia.h.vdelay_p1];
gtia.h.usedp |= 0x20;
}
}
static void recalc_p2(void)
{
if (
#if CHECK_GRACTL
(gtia.w.gractl & GTIA_PLAYER) == 0 ||
#endif
gtia.w.grafp2[gtia.h.vdelay_p2] == 0 || gtia.w.hposp2 >= 224 )
{
gtia.h.grafp2 = 0;
gtia.h.usedp &= ~0x40;
}
else
{
gtia.h.grafp2 = gtia.w.grafp2[gtia.h.vdelay_p2];
gtia.h.usedp |= 0x40;
}
}
static void recalc_p3(void)
{
if (
#if CHECK_GRACTL
(gtia.w.gractl & GTIA_PLAYER) == 0 ||
#endif
gtia.w.grafp3[gtia.h.vdelay_p3] == 0 || gtia.w.hposp3 >= 224 )
{
gtia.h.grafp3 = 0;
gtia.h.usedp &= ~0x80;
}
else
{
gtia.h.grafp3 = gtia.w.grafp3[gtia.h.vdelay_p3];
gtia.h.usedp |= 0x80;
}
}
static void recalc_m0(void)
{
if (
#if CHECK_GRACTL
(gtia.w.gractl & GTIA_MISSILE) == 0 ||
#endif
(gtia.w.grafm[gtia.h.vdelay_m0] & 0x03) == 0 || gtia.w.hposm0 >= 224 )
{
gtia.h.grafm0 = 0;
gtia.h.usedm0 = 0;
}
else
{
gtia.h.grafm0 = (gtia.w.grafm[gtia.h.vdelay_m0] << 6) & 0xc0;
gtia.h.usedm0 = (gtia.w.prior & 0x10) ? 0x08 : 0x10;
}
}
static void recalc_m1(void)
{
if (
#if CHECK_GRACTL
(gtia.w.gractl & GTIA_MISSILE) == 0 ||
#endif
(gtia.w.grafm[gtia.h.vdelay_m1] & 0x0c) == 0 || gtia.w.hposm1 >= 224 )
{
gtia.h.grafm1 = 0;
gtia.h.usedm1 = 0;
}
else
{
gtia.h.grafm1 = (gtia.w.grafm[gtia.h.vdelay_m1] << 4) & 0xc0;
gtia.h.usedm1 = (gtia.w.prior & 0x10) ? 0x08 : 0x20;
}
}
static void recalc_m2(void)
{
if (
#if CHECK_GRACTL
(gtia.w.gractl & GTIA_MISSILE) == 0 ||
#endif
(gtia.w.grafm[gtia.h.vdelay_m2] & 0x30) == 0 || gtia.w.hposm2 >= 224 )
{
gtia.h.grafm2 = 0;
gtia.h.usedm2 = 0;
}
else
{
gtia.h.grafm2 = (gtia.w.grafm[gtia.h.vdelay_m2] << 2) & 0xc0;
gtia.h.usedm2 = (gtia.w.prior & 0x10) ? 0x08 : 0x40;
}
}
static void recalc_m3(void)
{
if (
#if CHECK_GRACTL
(gtia.w.gractl & GTIA_MISSILE) == 0 ||
#endif
(gtia.w.grafm[gtia.h.vdelay_m3] & 0xc0) == 0 || gtia.w.hposm3 >= 224)
{
gtia.h.grafm3 = 0;
gtia.h.usedm3 = 0;
}
else
{
gtia.h.grafm3 = (gtia.w.grafm[gtia.h.vdelay_m3] << 0) & 0xc0;
gtia.h.usedm3 = (gtia.w.prior & 0x10) ? 0x08 : 0x80;
}
}
WRITE8_HANDLER( atari_gtia_w )
{
/* used for mixing hue/lum of different colors */
static UINT8 lumpm0=0,lumpm1=0,lumpm2=0,lumpm3=0,lumpm4=0;
static UINT8 lumpf1=0,lumpf2=0,lumbk= 0;
static UINT8 huepm0=0,huepm1=0,huepm2=0,huepm3=0,huepm4=0;
static UINT8 huepf1=0,huepf2=0,huebk= 0;
switch (offset & 31)
{
case 0:
gtia.w.hposp0 = data;
recalc_p0();
break;
case 1:
gtia.w.hposp1 = data;
recalc_p1();
break;
case 2:
gtia.w.hposp2 = data;
recalc_p2();
break;
case 3:
gtia.w.hposp3 = data;
recalc_p3();
break;
case 4:
gtia.w.hposm0 = data;
recalc_m0();
break;
case 5:
gtia.w.hposm1 = data;
recalc_m1();
break;
case 6:
gtia.w.hposm2 = data;
recalc_m2();
break;
case 7:
gtia.w.hposm3 = data;
recalc_m3();
break;
case 8:
data &= 3;
gtia.w.sizep0 = data;
recalc_p0();
break;
case 9:
data &= 3;
gtia.w.sizep1 = data;
recalc_p1();
break;
case 10:
data &= 3;
gtia.w.sizep2 = data;
recalc_p2();
break;
case 11:
data &= 3;
gtia.w.sizep3 = data;
recalc_p3();
break;
case 12:
data &= 3;
gtia.w.sizem = data;
recalc_m0();
recalc_m1();
recalc_m2();
recalc_m3();
break;
case 13:
gtia.w.grafp0[0] = data;
recalc_p0();
break;
case 14:
gtia.w.grafp1[0] = data;
recalc_p1();
break;
case 15:
gtia.w.grafp2[0] = data;
recalc_p2();
break;
case 16:
gtia.w.grafp3[0] = data;
recalc_p3();
break;
case 17:
gtia.w.grafm[0] = data;
recalc_m0();
recalc_m1();
recalc_m2();
recalc_m3();
break;
case 18: /* color for player/missile #0 */
if (data == gtia.w.colpm0)
break;
gtia.w.colpm0 = data;
if (VERBOSE)
logerror("atari colpm0 $%02x\n", data);
SETCOL_B(PL0,data); /* set player 0 color */
SETCOL_B(MI0,data); /* set missile 0 color */
SETCOL_B(GT2,data); /* set GTIA mode 2 color 0 */
SETCOL_B(P000,data); /* set player 0 both pixels 0 */
SETCOL_L(P001,data); /* set player 0 left pixel 0 */
SETCOL_R(P010,data); /* set player 0 right pixel 0 */
SPLIT_HUE_LUM(data,huepm0,lumpm0);
data = huepm0 | lumpf1;
SETCOL_R(P001,data); /* set player 0 right pixel 1 */
SETCOL_L(P010,data); /* set player 0 left pixel 1 */
SETCOL_B(P011,data); /* set player 0 both pixels 1 */
break;
case 19: /* color for player/missile #1 */
if (data == gtia.w.colpm1)
break;
gtia.w.colpm1 = data;
if (VERBOSE)
logerror("atari colpm1 $%02x\n", data);
SETCOL_B(PL1,data); /* set player color 1 */
SETCOL_B(MI1,data); /* set missile color 1 */
SETCOL_B(GT2+1,data); /* set GTIA mode 2 color 1 */
SETCOL_B(P100,data); /* set player 1 both pixels 0 */
SETCOL_L(P101,data); /* set player 1 left pixel 0 */
SETCOL_R(P110,data); /* set player 1 right pixel 0 */
SPLIT_HUE_LUM(data,huepm1,lumpm1);
data = huepm1 | lumpf1;
SETCOL_R(P101,data); /* set player 1 right pixel 1 */
SETCOL_L(P110,data); /* set player 1 left pixel 1 */
SETCOL_B(P111,data); /* set player 1 both pixels 1 */
break;
case 20: /* color for player/missile #2 */
if (data == gtia.w.colpm2)
break;
gtia.w.colpm2 = data;
if (VERBOSE)
logerror("atari colpm2 $%02x\n", data);
SETCOL_B(PL2,data); /* set player 2 color */
SETCOL_B(MI2,data); /* set missile 2 color */
SETCOL_B(GT2+2,data); /* set GTIA mode 2 color 2 */
SETCOL_B(P200,data); /* set player 2 both pixels 0 */
SETCOL_L(P201,data); /* set player 2 left pixel 0 */
SETCOL_R(P210,data); /* set player 2 right pixel 0 */
SPLIT_HUE_LUM(data,huepm2,lumpm2);
data = huepm2 | lumpf1;
SETCOL_R(P201,data); /* set player 2 right pixel 1 */
SETCOL_L(P210,data); /* set player 2 left pixel 1 */
SETCOL_B(P211,data); /* set player 2 both pixels 1 */
break;
case 21: /* color for player/missile #3 */
if (data == gtia.w.colpm3)
break;
gtia.w.colpm3 = data;
if (VERBOSE)
logerror("atari colpm3 $%02x\n", data);
SETCOL_B(PL3,data); /* set player 3 color */
SETCOL_B(MI3,data); /* set missile 3 color */
SETCOL_B(GT2+3,data); /* set GTIA mode 2 color 3 */
SETCOL_B(P300,data); /* set player 3 both pixels 0 */
SETCOL_L(P301,data); /* set player 3 left pixel 0 */
SETCOL_R(P310,data); /* set player 3 right pixel 0 */
SPLIT_HUE_LUM(data,huepm3,lumpm3);
data = huepm3 | lumpf1;
SETCOL_R(P301,data); /* set player 3 right pixel 1 */
SETCOL_L(P310,data); /* set player 3 left pixel 1 */
SETCOL_B(P311,data); /* set player 3 both pixels 1 */
break;
case 22: /* playfield color #0 */
if (data == gtia.w.colpf0)
break;
gtia.w.colpf0 = data;
if (VERBOSE)
logerror("atari colpf0 $%02x\n", data);
SETCOL_B(PF0,data); /* set playfield 0 color */
SETCOL_B(GT2+4,data); /* set GTIA mode 2 color 4 */
break;
case 23: /* playfield color #1 */
if (data == gtia.w.colpf1)
break;
gtia.w.colpf1 = data;
if (VERBOSE)
logerror("atari colpf1 $%02x\n", data);
SETCOL_B(PF1,data); /* set playfield 1 color */
SETCOL_B(GT2+5,data); /* set GTIA mode 2 color 5 */
SPLIT_HUE_LUM(data,huepf1,lumpf1);
data = huepf2 | lumpf1;
SETCOL_R(T01,data); /* set text mode right pixel 1 */
SETCOL_L(T10,data); /* set text mode left pixel 1 */
SETCOL_B(T11,data); /* set text mode both pixels 1 */
data = huebk | lumpf1;
SETCOL_R(G01,data); /* set graphics mode right pixel 1 */
SETCOL_L(G10,data); /* set graphics mode left pixel 1 */
SETCOL_B(G11,data); /* set graphics mode both pixels 1 */
data = huepm0 | lumpf1;
SETCOL_R(P001,data); /* set player 0 right pixel 1 */
SETCOL_L(P010,data); /* set player 0 left pixel 1 */
SETCOL_B(P011,data); /* set player 0 both pixels 1 */
data = huepm1 | lumpf1;
SETCOL_R(P101,data); /* set player 1 right pixel 1 */
SETCOL_L(P110,data); /* set player 1 left pixel 1 */
SETCOL_B(P111,data); /* set player 1 both pixels 1 */
data = huepm2 | lumpf1;
SETCOL_R(P201,data); /* set player 2 right pixel 1 */
SETCOL_L(P210,data); /* set player 2 left pixel 1 */
SETCOL_B(P211,data); /* set player 2 both pixels 1 */
data = huepm3 | lumpf1;
SETCOL_R(P301,data); /* set player 3 right pixel 1 */
SETCOL_L(P310,data); /* set player 3 left pixel 1 */
SETCOL_B(P311,data); /* set player 3 both pixels 1 */
data = huepm4 | lumpf1;
SETCOL_R(P401,data); /* set missiles right pixel 1 */
SETCOL_L(P410,data); /* set missiles left pixel 1 */
SETCOL_B(P411,data); /* set missiles both pixels 1 */
break;
case 24: /* playfield color #2 */
if (data == gtia.w.colpf2)
break;
gtia.w.colpf2 = data;
if (VERBOSE)
logerror("atari colpf2 $%02x\n", data);
SETCOL_B(PF2,data); /* set playfield color 2 */
SETCOL_B(GT2+6,data); /* set GTIA mode 2 color 6 */
SETCOL_B(T00,data); /* set text mode both pixels 0 */
SETCOL_L(T01,data); /* set text mode left pixel 0 */
SETCOL_R(T10,data); /* set text mode right pixel 0 */
SPLIT_HUE_LUM(data,huepf2,lumpf2);
data = huepf2 | lumpf1;
SETCOL_R(T01,data); /* set text mode right pixel 1 */
SETCOL_L(T10,data); /* set text mode left pixel 1 */
SETCOL_B(T11,data); /* set text mode both pixels 1 */
break;
case 25: /* playfield color #3 */
if (data == gtia.w.colpf3)
break;
gtia.w.colpf3 = data;
if (VERBOSE)
logerror("atari colpf3 $%02x\n", data);
SETCOL_B(PF3,data); /* set playfield color 3 */
SETCOL_B(GT2+7,data); /* set GTIA mode 2 color 7 */
SETCOL_B(P400,data); /* set p/m xor mode both pixels 0 */
SETCOL_L(P401,data); /* set p/m xor mode left pixel 0 */
SETCOL_R(P410,data); /* set p/m xor mode right pixel 0 */
SPLIT_HUE_LUM(data,huepm4,lumpm4);
data = huepm4 | lumpf1;
SETCOL_R(P401,data); /* set p/m xor mode right pixel 1 */
SETCOL_L(P410,data); /* set p/m xor mode left pixel 1 */
SETCOL_B(P411,data); /* set p/m xor mode both pixels 1 */
break;
case 26: /* playfield background */
if (data == gtia.w.colbk)
break;
gtia.w.colbk = data;
if (VERBOSE)
logerror("atari colbk $%02x\n", data);
SETCOL_B(PBK,data); /* set background color */
SETCOL_B(GT2+8,data); /* set GTIA mode 2 color 8 */
SETCOL_B(GT2+9,data); /* set GTIA mode 2 color 9 */
SETCOL_B(GT2+10,data); /* set GTIA mode 2 color 10 */
SETCOL_B(GT2+11,data); /* set GTIA mode 2 color 11 */
SETCOL_B(GT2+12,data); /* set GTIA mode 2 color 12 */
SETCOL_B(GT2+13,data); /* set GTIA mode 2 color 13 */
SETCOL_B(GT2+14,data); /* set GTIA mode 2 color 14 */
SETCOL_B(GT2+15,data); /* set GTIA mode 2 color 15 */
SETCOL_B(G00,data); /* set 2 color graphics both pixels 0 */
SETCOL_L(G01,data); /* set 2 color graphics left pixel 0 */
SETCOL_R(G10,data); /* set 2 color graphics right pixel 0 */
SPLIT_HUE_LUM(data,huebk,lumbk);
data = huebk | lumpf1;
SETCOL_R(G01,data); /* set 2 color graphics right pixel 1 */
SETCOL_L(G10,data); /* set 2 color graphics left pixel 1 */
SETCOL_B(G11,data); /* set 2 color graphics both pixels 1 */
SETCOL_B(GT1+ 0,(data&HUE)+(0x00&LUM)); /* set GTIA mode 1 HUE + LUM 0..15 */
SETCOL_B(GT1+ 1,(data&HUE)+(0x11&LUM));
SETCOL_B(GT1+ 2,(data&HUE)+(0x22&LUM));
SETCOL_B(GT1+ 3,(data&HUE)+(0x33&LUM));
SETCOL_B(GT1+ 4,(data&HUE)+(0x44&LUM));
SETCOL_B(GT1+ 5,(data&HUE)+(0x55&LUM));
SETCOL_B(GT1+ 6,(data&HUE)+(0x66&LUM));
SETCOL_B(GT1+ 7,(data&HUE)+(0x77&LUM));
SETCOL_B(GT1+ 8,(data&HUE)+(0x88&LUM));
SETCOL_B(GT1+ 9,(data&HUE)+(0x99&LUM));
SETCOL_B(GT1+10,(data&HUE)+(0xaa&LUM));
SETCOL_B(GT1+11,(data&HUE)+(0xbb&LUM));
SETCOL_B(GT1+12,(data&HUE)+(0xcc&LUM));
SETCOL_B(GT1+13,(data&HUE)+(0xdd&LUM));
SETCOL_B(GT1+14,(data&HUE)+(0xee&LUM));
SETCOL_B(GT1+15,(data&HUE)+(0xff&LUM));
SETCOL_B(GT3+ 0,(data&LUM)+(0x00&HUE)); /* set GTIA mode 3 LUM + HUE 0..15 */
SETCOL_B(GT3+ 1,(data&LUM)+(0x11&HUE));
SETCOL_B(GT3+ 2,(data&LUM)+(0x22&HUE));
SETCOL_B(GT3+ 3,(data&LUM)+(0x33&HUE));
SETCOL_B(GT3+ 4,(data&LUM)+(0x44&HUE));
SETCOL_B(GT3+ 5,(data&LUM)+(0x55&HUE));
SETCOL_B(GT3+ 6,(data&LUM)+(0x66&HUE));
SETCOL_B(GT3+ 7,(data&LUM)+(0x77&HUE));
SETCOL_B(GT3+ 8,(data&LUM)+(0x88&HUE));
SETCOL_B(GT3+ 9,(data&LUM)+(0x99&HUE));
SETCOL_B(GT3+10,(data&LUM)+(0xaa&HUE));
SETCOL_B(GT3+11,(data&LUM)+(0xbb&HUE));
SETCOL_B(GT3+12,(data&LUM)+(0xcc&HUE));
SETCOL_B(GT3+13,(data&LUM)+(0xdd&HUE));
SETCOL_B(GT3+14,(data&LUM)+(0xee&HUE));
SETCOL_B(GT3+15,(data&LUM)+(0xff&HUE));
break;
case 27:
gtia.w.prior = data;
recalc_m0();
recalc_m1();
recalc_m2();
recalc_m3();
break;
case 28: /* delay until vertical retrace */
gtia.w.vdelay = data;
gtia.h.vdelay_m0 = (data >> 0) & 1;
gtia.h.vdelay_m1 = (data >> 1) & 1;
gtia.h.vdelay_m2 = (data >> 2) & 1;
gtia.h.vdelay_m3 = (data >> 3) & 1;
gtia.h.vdelay_p0 = (data >> 4) & 1;
gtia.h.vdelay_p1 = (data >> 5) & 1;
gtia.h.vdelay_p2 = (data >> 6) & 1;
gtia.h.vdelay_p3 = (data >> 7) & 1;
break;
case 29:
gtia.w.gractl = data;
recalc_p0();
recalc_p1();
recalc_p2();
recalc_p3();
recalc_m0();
recalc_m1();
recalc_m2();
recalc_m3();
break;
case 30: /* clear collisions */
gtia.r.m0pf = gtia.r.m1pf = gtia.r.m2pf = gtia.r.m3pf =
gtia.r.p0pf = gtia.r.p1pf = gtia.r.p2pf = gtia.r.p3pf =
gtia.r.m0pl = gtia.r.m1pl = gtia.r.m2pl = gtia.r.m3pl =
gtia.r.p0pl = gtia.r.p1pl = gtia.r.p2pl = gtia.r.p3pl = 0;
gtia.w.hitclr = data;
break;
case 31: /* write console (speaker) */
if (data == gtia.w.cons)
break;
gtia.w.cons = data;
if (gtia.intf.console_write)
gtia.intf.console_write(gtia.w.cons);
break;
}
}
static void gtia_state_postload(void)
{
recalc_p0();
recalc_p1();
recalc_p2();
recalc_p3();
recalc_m0();
recalc_m1();
recalc_m2();
recalc_m3();
}
static const UINT8 pf_collision[256] = {
0,1,2,0,4,0,0,0,8,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
};
static const int pf_prioindex[256] = {
/* PBK PF0 PF1 PF2 PF3 */
/* */ 0x000,0x100,0x100,0x000,0x200,0x000,0x000,0x000,0x200,0x000,0x000,0x000,0x000,0x000,0x000,0x000,
/* */ 0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,
/* */ 0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,
/* */ 0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,
/* T00 */ 0x400,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,
/* T01 */ 0x500,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,
/* T10 */ 0x600,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,
/* T11 */ 0x700,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,
/* G00 */ 0x400,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,
/* G01 */ 0x500,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,
/* G10 */ 0x600,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,
/* G11 */ 0x700,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,
/* GT1 */ 0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,
/* GT2 */ 0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,
/* GT3 */ 0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,
/* */ 0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000
};
#define RENDER_PLAYER(player,color) \
static void render_##player##_w1(UINT8 *dst) \
{ \
if( gtia.h.graf##player & 0x80 ) \
dst[0] |= color; \
if( gtia.h.graf##player & 0x40 ) \
dst[1] |= color; \
if( gtia.h.graf##player & 0x20 ) \
dst[2] |= color; \
if( gtia.h.graf##player & 0x10 ) \
dst[3] |= color; \
if( gtia.h.graf##player & 0x08 ) \
dst[4] |= color; \
if( gtia.h.graf##player & 0x04 ) \
dst[5] |= color; \
if( gtia.h.graf##player & 0x02 ) \
dst[6] |= color; \
if( gtia.h.graf##player & 0x01 ) \
dst[7] |= color; \
} \
static void render_##player##_w2(UINT8 *dst) \
{ \
if( gtia.h.graf##player & 0x80 ) \
{ \
dst[ 0] |= color; \
dst[ 1] |= color; \
} \
if( gtia.h.graf##player & 0x40 ) \
{ \
dst[ 2] |= color; \
dst[ 3] |= color; \
} \
if( gtia.h.graf##player & 0x20 ) \
{ \
dst[ 4] |= color; \
dst[ 5] |= color; \
} \
if( gtia.h.graf##player & 0x10 ) \
{ \
dst[ 6] |= color; \
dst[ 7] |= color; \
} \
if( gtia.h.graf##player & 0x08 ) \
{ \
dst[ 8] |= color; \
dst[ 9] |= color; \
} \
if( gtia.h.graf##player & 0x04 ) \
{ \
dst[10] |= color; \
dst[11] |= color; \
} \
if( gtia.h.graf##player & 0x02 ) \
{ \
dst[12] |= color; \
dst[13] |= color; \
} \
if( gtia.h.graf##player & 0x01 ) \
{ \
dst[14] |= color; \
dst[15] |= color; \
} \
} \
static void render_##player##_w4(UINT8 *dst) \
{ \
if( gtia.h.graf##player & 0x80 ) \
{ \
dst[ 0] |= color; \
dst[ 1] |= color; \
dst[ 2] |= color; \
dst[ 3] |= color; \
} \
if( gtia.h.graf##player & 0x40 ) \
{ \
dst[ 4] |= color; \
dst[ 5] |= color; \
dst[ 6] |= color; \
dst[ 7] |= color; \
} \
if( gtia.h.graf##player & 0x20 ) \
{ \
dst[ 8] |= color; \
dst[ 9] |= color; \
dst[10] |= color; \
dst[11] |= color; \
} \
if( gtia.h.graf##player & 0x10 ) \
{ \
dst[12] |= color; \
dst[13] |= color; \
dst[14] |= color; \
dst[15] |= color; \
} \
if( gtia.h.graf##player & 0x08 ) \
{ \
dst[16] |= color; \
dst[17] |= color; \
dst[18] |= color; \
dst[19] |= color; \
} \
if( gtia.h.graf##player & 0x04 ) \
{ \
dst[20] |= color; \
dst[21] |= color; \
dst[22] |= color; \
dst[23] |= color; \
} \
if( gtia.h.graf##player & 0x02 ) \
{ \
dst[24] |= color; \
dst[25] |= color; \
dst[26] |= color; \
dst[27] |= color; \
} \
if( gtia.h.graf##player & 0x01 ) \
{ \
dst[28] |= color; \
dst[29] |= color; \
dst[30] |= color; \
dst[31] |= color; \
} \
} \
static void (*render_##player[4])(UINT8 *dst)={ \
render_##player##_w1, \
render_##player##_w2, \
render_##player##_w2, \
render_##player##_w4 \
}
#define RENDER_MISSILE(missile,color) \
static void render_##missile##_w1(UINT8 *dst) \
{ \
if( gtia.h.graf##missile & 0x80 ) \
dst[0] |= color; \
if( gtia.h.graf##missile & 0x40 ) \
dst[1] |= color; \
} \
static void render_##missile##_w2(UINT8 *dst) \
{ \
if( gtia.h.graf##missile & 0x80 ) \
{ \
dst[ 0] |= color; \
dst[ 1] |= color; \
} \
if( gtia.h.graf##missile & 0x40 ) \
{ \
dst[ 2] |= color; \
dst[ 3] |= color; \
} \
} \
static void render_##missile##_w4(UINT8 *dst) \
{ \
if( gtia.h.graf##missile & 0x80 ) \
{ \
dst[ 0] |= color; \
dst[ 1] |= color; \
dst[ 2] |= color; \
dst[ 3] |= color; \
} \
if( gtia.h.graf##missile & 0x40 ) \
{ \
dst[ 4] |= color; \
dst[ 5] |= color; \
dst[ 6] |= color; \
dst[ 7] |= color; \
} \
} \
static void (*render_##missile[4])(UINT8 *dst) = { \
render_##missile##_w1, \
render_##missile##_w2, \
render_##missile##_w2, \
render_##missile##_w4 \
}
RENDER_PLAYER(p0,P0);
RENDER_PLAYER(p1,P1);
RENDER_PLAYER(p2,P2);
RENDER_PLAYER(p3,P3);
RENDER_MISSILE(m0,M0);
RENDER_MISSILE(m1,M1);
RENDER_MISSILE(m2,M2);
RENDER_MISSILE(m3,M3);
void gtia_render(VIDEO *video)
{
int x;
UINT8 *prio = antic.prio_table[gtia.w.prior & 0x3f];
UINT8 *src, *dst;
if( antic.scanline < VBL_END || antic.scanline >= 256 )
return;
if( gtia.h.grafp0 )
(*render_p0[gtia.w.sizep0])(&antic.pmbits[gtia.w.hposp0]);
if( gtia.h.grafp1 )
(*render_p1[gtia.w.sizep1])(&antic.pmbits[gtia.w.hposp1]);
if( gtia.h.grafp2 )
(*render_p2[gtia.w.sizep2])(&antic.pmbits[gtia.w.hposp2]);
if( gtia.h.grafp3 )
(*render_p3[gtia.w.sizep3])(&antic.pmbits[gtia.w.hposp3]);
if( gtia.h.grafm0 )
(*render_m0[gtia.w.sizem])(&antic.pmbits[gtia.w.hposm0]);
if( gtia.h.grafm1 )
(*render_m1[gtia.w.sizem])(&antic.pmbits[gtia.w.hposm1]);
if( gtia.h.grafm2 )
(*render_m2[gtia.w.sizem])(&antic.pmbits[gtia.w.hposm2]);
if( gtia.h.grafm3 )
(*render_m3[gtia.w.sizem])(&antic.pmbits[gtia.w.hposm3]);
src = antic.pmbits + PMOFFSET;
dst = antic.cclock + PMOFFSET - antic.hscrol_old;
for( x = 0; x < HWIDTH*4; x++, src++, dst++ )
{
UINT8 pm, pc, pf;
if( !*src )
continue;
/* get the player/missile combination bits and reset the buffer */
pm = *src;
*src = 0;
/* get the current playfield color */
pc = *dst;
pf = pf_collision[pc];
if (pm&P0) { gtia.r.p0pf |= pf; gtia.r.p0pl |= pm&( P1|P2|P3); }
if (pm&P1) { gtia.r.p1pf |= pf; gtia.r.p1pl |= pm&(P0| P2|P3); }
if (pm&P2) { gtia.r.p2pf |= pf; gtia.r.p2pl |= pm&(P0|P1| P3); }
if (pm&P3) { gtia.r.p3pf |= pf; gtia.r.p3pl |= pm&(P0|P1|P2 ); }
if (pm&M0) { gtia.r.m0pf |= pf; gtia.r.m0pl |= pm&(P0|P1|P2|P3); }
if (pm&M1) { gtia.r.m1pf |= pf; gtia.r.m1pl |= pm&(P0|P1|P2|P3); }
if (pm&M2) { gtia.r.m2pf |= pf; gtia.r.m2pl |= pm&(P0|P1|P2|P3); }
if (pm&M3) { gtia.r.m3pf |= pf; gtia.r.m3pl |= pm&(P0|P1|P2|P3); }
/* color with higher priority? change playfield */
pc = prio[pf_prioindex[pc] | pm];
if (pc) *dst = pc;
}
/* copy player/missile graphics in case of vdelay */
gtia.w.grafp0[1] = gtia.w.grafp0[0];
gtia.w.grafp1[1] = gtia.w.grafp1[0];
gtia.w.grafp2[1] = gtia.w.grafp2[0];
gtia.w.grafp3[1] = gtia.w.grafp3[0];
gtia.w.grafm[1] = gtia.w.grafm[0];
}
/************* ANTIC mode 0F : GTIA mode 1 ********************
* graphics mode 8x1:16 (32/40/48 byte per line)
***************************************************************/
#define GTIA1(s) COPY4(dst, antic.pf_gtia1[video->data[s]])
void gtia_mode_1_32(VIDEO *video)
{
PREPARE_GFXG1(32);
REP32(GTIA1);
POST_GFX(32);
}
void gtia_mode_1_40(VIDEO *video)
{
PREPARE_GFXG1(40);
REP40(GTIA1);
POST_GFX(40);
}
void gtia_mode_1_48(VIDEO *video)
{
PREPARE_GFXG1(48);
REP48(GTIA1);
POST_GFX(48);
}
/************* ANTIC mode 0F : GTIA mode 2 ********************
* graphics mode 8x1:16 (32/40/48 byte per line)
***************************************************************/
#define GTIA2(s) COPY4(dst, antic.pf_gtia2[video->data[s]])
void gtia_mode_2_32(VIDEO *video)
{
PREPARE_GFXG2(32);
REP32(GTIA2);
POST_GFX(32);
}
void gtia_mode_2_40(VIDEO *video)
{
PREPARE_GFXG2(40);
REP40(GTIA2);
POST_GFX(40);
}
void gtia_mode_2_48(VIDEO *video)
{
PREPARE_GFXG2(48);
REP48(GTIA2);
POST_GFX(48);
}
/************* ANTIC mode 0F : GTIA mode 3 ********************
* graphics mode 8x1:16 (32/40/48 byte per line)
***************************************************************/
#define GTIA3(s) COPY4(dst, antic.pf_gtia3[video->data[s]])
void gtia_mode_3_32(VIDEO *video)
{
PREPARE_GFXG3(32);
REP32(GTIA3);
POST_GFX(32);
}
void gtia_mode_3_40(VIDEO *video)
{
PREPARE_GFXG3(40);
REP40(GTIA3);
POST_GFX(40);
}
void gtia_mode_3_48(VIDEO *video)
{
PREPARE_GFXG3(48);
REP48(GTIA3);
POST_GFX(48);
}