A5200DS/arm9/source/emu/gtia.c

712 lines
26 KiB
C

/*
* gtia.c - GTIA chip emulation
*
* Copyright (C) 1995-1998 David Firth
* Copyright (C) 1998-2005 Atari800 development team (see DOC/CREDITS)
*
* This file is part of the Atari800 emulator project which emulates
* the Atari 400, 800, 800XL, 130XE, and 5200 8-bit computers.
*
* Atari800 is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Atari800 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Atari800; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <nds.h>
#include "config.h"
#include "a5200utils.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "atari.h"
#include "antic.h"
#include "gtia.h"
#include "input.h"
#include "pokeysnd.h"
/* GTIA Registers ---------------------------------------------------------- */
UBYTE M0PL __attribute__((section(".dtcm")));
UBYTE M1PL __attribute__((section(".dtcm")));
UBYTE M2PL __attribute__((section(".dtcm")));
UBYTE M3PL __attribute__((section(".dtcm")));
UBYTE P0PL __attribute__((section(".dtcm")));
UBYTE P1PL __attribute__((section(".dtcm")));
UBYTE P2PL __attribute__((section(".dtcm")));
UBYTE P3PL __attribute__((section(".dtcm")));
UBYTE HPOSP0 __attribute__((section(".dtcm")));
UBYTE HPOSP1 __attribute__((section(".dtcm")));
UBYTE HPOSP2 __attribute__((section(".dtcm")));
UBYTE HPOSP3 __attribute__((section(".dtcm")));
UBYTE HPOSM0 __attribute__((section(".dtcm")));
UBYTE HPOSM1 __attribute__((section(".dtcm")));
UBYTE HPOSM2 __attribute__((section(".dtcm")));
UBYTE HPOSM3 __attribute__((section(".dtcm")));
UBYTE SIZEP0 __attribute__((section(".dtcm")));
UBYTE SIZEP1 __attribute__((section(".dtcm")));
UBYTE SIZEP2 __attribute__((section(".dtcm")));
UBYTE SIZEP3 __attribute__((section(".dtcm")));
UBYTE SIZEM __attribute__((section(".dtcm")));
UBYTE GRAFP0 __attribute__((section(".dtcm")));
UBYTE GRAFP1 __attribute__((section(".dtcm")));
UBYTE GRAFP2 __attribute__((section(".dtcm")));
UBYTE GRAFP3 __attribute__((section(".dtcm")));
UBYTE GRAFM __attribute__((section(".dtcm")));
UBYTE COLPM0 __attribute__((section(".dtcm")));
UBYTE COLPM1 __attribute__((section(".dtcm")));
UBYTE COLPM2 __attribute__((section(".dtcm")));
UBYTE COLPM3 __attribute__((section(".dtcm")));
UBYTE COLPF0 __attribute__((section(".dtcm")));
UBYTE COLPF1 __attribute__((section(".dtcm")));
UBYTE COLPF2 __attribute__((section(".dtcm")));
UBYTE COLPF3 __attribute__((section(".dtcm")));
UBYTE COLBK __attribute__((section(".dtcm")));
UBYTE PRIOR __attribute__((section(".dtcm")));
UBYTE VDELAY __attribute__((section(".dtcm")));
UBYTE GRACTL __attribute__((section(".dtcm")));
UBYTE POTENA __attribute__((section(".dtcm")));
/* Internal GTIA state ----------------------------------------------------- */
UBYTE consol_index __attribute__((section(".dtcm"))) = 0;
UBYTE consol_table[3] __attribute__((section(".dtcm")));
UBYTE consol_mask __attribute__((section(".dtcm")));
UBYTE TRIG[4] __attribute__((section(".dtcm")));
UBYTE TRIG_latch[4] __attribute__((section(".dtcm")));
void set_prior(UBYTE byte); /* in antic.c */
/* Player/Missile stuff ---------------------------------------------------- */
/* change to 0x00 to disable collisions */
#define collisions_mask_missile_playfield 0x0f
#define collisions_mask_player_playfield 0x0f
#define collisions_mask_missile_player 0x0f
#define collisions_mask_player_player 0x0f
#define P1PL_T P1PL
#define P2PL_T P2PL
#define P3PL_T P3PL
#define M0PL_T M0PL
#define M1PL_T M1PL
#define M2PL_T M2PL
#define M3PL_T M3PL
extern UBYTE player_dma_enabled;
extern UBYTE missile_dma_enabled;
extern UBYTE player_gra_enabled;
extern UBYTE missile_gra_enabled;
extern UBYTE player_flickering;
extern UBYTE missile_flickering;
static UBYTE *hposp_ptr[4] __attribute__((section(".dtcm")));
static UBYTE *hposm_ptr[4] __attribute__((section(".dtcm")));
static ULONG hposp_mask[4] __attribute__((section(".dtcm")));
static ULONG *grafp_ptr[4] __attribute__((section(".dtcm")));
static UBYTE global_sizem[4] __attribute__((section(".dtcm")));
static UBYTE PM_Width[4] __attribute__((section(".dtcm"))) = {1, 2, 1, 4};
ULONG *grafp_lookup = (ULONG*)0x068A0000; // Using 4K here for lookup table... ULONG[4][256]
/* Meaning of bits in pm_scanline:
bit 0 - Player 0
bit 1 - Player 1
bit 2 - Player 2
bit 3 - Player 3
bit 4 - Missile 0
bit 5 - Missile 1
bit 6 - Missile 2
bit 7 - Missile 3
*/
UBYTE pm_scanline[ATARI_WIDTH / 2 + 8] __attribute__((section(".dtcm"))); /* there's a byte for every *pair* of pixels */
UBYTE pm_dirty __attribute__((section(".dtcm"))) = TRUE;
#define C_PM0 0x01
#define C_PM1 0x02
#define C_PM01 0x03
#define C_PM2 0x04
#define C_PM3 0x05
#define C_PM23 0x06
#define C_PM023 0x07
#define C_PM123 0x08
#define C_PM0123 0x09
#define C_PM25 0x0a
#define C_PM35 0x0b
#define C_PM235 0x0c
#define C_COLLS 0x0d
#define C_BAK 0x00
#define C_HI2 0x20
#define C_HI3 0x30
#define C_PF0 0x40
#define C_PF1 0x50
#define C_PF2 0x60
#define C_PF3 0x70
extern UWORD cl_lookup[128];
#define PF0PM (*(UBYTE *) &cl_lookup[C_PF0 | C_COLLS])
#define PF1PM (*(UBYTE *) &cl_lookup[C_PF1 | C_COLLS])
#define PF2PM (*(UBYTE *) &cl_lookup[C_PF2 | C_COLLS])
#define PF3PM (*(UBYTE *) &cl_lookup[C_PF3 | C_COLLS])
/* Colours ----------------------------------------------------------------- */
extern UWORD hires_lookup_l[128];
extern ULONG lookup_gtia9[16];
extern ULONG lookup_gtia11[16];
void setup_gtia9_11(void) {
int i;
ULONG count9 = 0;
ULONG count11 = 0;
lookup_gtia11[0] = lookup_gtia9[0] & 0xf0f0f0f0;
for (i = 1; i < 16; i++) {
lookup_gtia9[i] = lookup_gtia9[0] | (count9 += 0x01010101);
lookup_gtia11[i] = lookup_gtia9[0] | (count11 += 0x10101010);
}
}
/* Initialization ---------------------------------------------------------- */
void GTIA_Initialise(void)
{
int i;
for (i = 0; i < 256; i++) {
int tmp = i + 0x100;
ULONG grafp1 = 0;
ULONG grafp2 = 0;
ULONG grafp4 = 0;
do {
grafp1 <<= 1;
grafp2 <<= 2;
grafp4 <<= 4;
if (tmp & 1) {
grafp1++;
grafp2 += 3;
grafp4 += 15;
}
tmp >>= 1;
} while (tmp != 1);
grafp_lookup[2*256+i] = grafp_lookup[0*256+i] = grafp1;
grafp_lookup[1*256+i] = grafp2;
grafp_lookup[3*256+i] = grafp4;
}
memset(cl_lookup, COLOUR_BLACK, sizeof(cl_lookup));
for (i = 0; i < 32; i++)
GTIA_PutByte((UWORD) i, 0);
POTENA=0;
}
#define update_partial_pmpl_colls()
/* Prepare PMG scanline ---------------------------------------------------- */
ITCM_CODE void new_pm_scanline(void)
{
/* Clear if necessary */
if (pm_dirty) {
memset(pm_scanline, 0, ATARI_WIDTH / 2);
pm_dirty = FALSE;
}
/* Draw Players */
#define DO_PLAYER(n) if (GRAFP##n) { \
ULONG grafp = grafp_ptr[n][GRAFP##n] & hposp_mask[n]; \
if (grafp) { \
UBYTE *ptr = hposp_ptr[n]; \
pm_dirty = TRUE; \
do { \
if (grafp & 1) \
P##n##PL_T |= *ptr |= 1 << n; \
ptr++; \
grafp >>= 1; \
} while (grafp); \
} \
}
/* optimized DO_PLAYER(0): pm_scanline is clear and P0PL is unused */
if (GRAFP0) {
ULONG grafp = grafp_ptr[0][GRAFP0] & hposp_mask[0];
if (grafp) {
UBYTE *ptr = hposp_ptr[0];
pm_dirty = TRUE;
do {
if (grafp & 1)
*ptr = 1;
ptr++;
grafp >>= 1;
} while (grafp);
}
}
DO_PLAYER(1)
DO_PLAYER(2)
DO_PLAYER(3)
/* Draw Missiles */
#define DO_MISSILE(n,p,m,r,l) if (GRAFM & m) { \
int j = global_sizem[n]; \
UBYTE *ptr = hposm_ptr[n]; \
if (GRAFM & r) { \
if (GRAFM & l) \
j <<= 1; \
} \
else \
ptr += j; \
if (ptr < pm_scanline + 2) { \
j += ptr - pm_scanline - 2; \
ptr = pm_scanline + 2; \
} \
else if (ptr + j > pm_scanline + ATARI_WIDTH / 2 - 2) \
j = pm_scanline + ATARI_WIDTH / 2 - 2 - ptr; \
if (j > 0) \
do \
M##n##PL_T |= *ptr++ |= p; \
while (--j); \
}
if (GRAFM) {
pm_dirty = TRUE;
DO_MISSILE(3, 0x80, 0xc0, 0x80, 0x40)
DO_MISSILE(2, 0x40, 0x30, 0x20, 0x10)
DO_MISSILE(1, 0x20, 0x0c, 0x08, 0x04)
DO_MISSILE(0, 0x10, 0x03, 0x02, 0x01)
}
}
/* GTIA registers ---------------------------------------------------------- */
void GTIA_Frame(void)
{
int consol = key_consol | 0x08;
consol_table[0] = consol;
consol_table[1] = consol_table[2] &= consol;
if (GRACTL & 4) {
TRIG_latch[0] &= TRIG[0];
TRIG_latch[1] &= TRIG[1];
TRIG_latch[2] &= TRIG[2];
TRIG_latch[3] &= TRIG[3];
}
}
UBYTE GTIA_GetByte(UWORD addr)
{
switch (addr & 0x1f) {
case _M0PF:
return (((PF0PM & 0x10) >> 4)
+ ((PF1PM & 0x10) >> 3)
+ ((PF2PM & 0x10) >> 2)
+ ((PF3PM & 0x10) >> 1)) & collisions_mask_missile_playfield;
case _M1PF:
return (((PF0PM & 0x20) >> 5)
+ ((PF1PM & 0x20) >> 4)
+ ((PF2PM & 0x20) >> 3)
+ ((PF3PM & 0x20) >> 2)) & collisions_mask_missile_playfield;
case _M2PF:
return (((PF0PM & 0x40) >> 6)
+ ((PF1PM & 0x40) >> 5)
+ ((PF2PM & 0x40) >> 4)
+ ((PF3PM & 0x40) >> 3)) & collisions_mask_missile_playfield;
case _M3PF:
return (((PF0PM & 0x80) >> 7)
+ ((PF1PM & 0x80) >> 6)
+ ((PF2PM & 0x80) >> 5)
+ ((PF3PM & 0x80) >> 4)) & collisions_mask_missile_playfield;
case _P0PF:
return ((PF0PM & 0x01)
+ ((PF1PM & 0x01) << 1)
+ ((PF2PM & 0x01) << 2)
+ ((PF3PM & 0x01) << 3)) & collisions_mask_player_playfield;
case _P1PF:
return (((PF0PM & 0x02) >> 1)
+ (PF1PM & 0x02)
+ ((PF2PM & 0x02) << 1)
+ ((PF3PM & 0x02) << 2)) & collisions_mask_player_playfield;
case _P2PF:
return (((PF0PM & 0x04) >> 2)
+ ((PF1PM & 0x04) >> 1)
+ (PF2PM & 0x04)
+ ((PF3PM & 0x04) << 1)) & collisions_mask_player_playfield;
case _P3PF:
return (((PF0PM & 0x08) >> 3)
+ ((PF1PM & 0x08) >> 2)
+ ((PF2PM & 0x08) >> 1)
+ (PF3PM & 0x08)) & collisions_mask_player_playfield;
case _M0PL:
update_partial_pmpl_colls();
return M0PL & collisions_mask_missile_player;
case _M1PL:
update_partial_pmpl_colls();
return M1PL & collisions_mask_missile_player;
case _M2PL:
update_partial_pmpl_colls();
return M2PL & collisions_mask_missile_player;
case _M3PL:
update_partial_pmpl_colls();
return M3PL & collisions_mask_missile_player;
case _P0PL:
update_partial_pmpl_colls();
return (((P1PL & 0x01) << 1) /* mask in player 1 */
+ ((P2PL & 0x01) << 2) /* mask in player 2 */
+ ((P3PL & 0x01) << 3)) /* mask in player 3 */
& collisions_mask_player_player;
case _P1PL:
update_partial_pmpl_colls();
return ((P1PL & 0x01) /* mask in player 0 */
+ ((P2PL & 0x02) << 1) /* mask in player 2 */
+ ((P3PL & 0x02) << 2)) /* mask in player 3 */
& collisions_mask_player_player;
case _P2PL:
update_partial_pmpl_colls();
return ((P2PL & 0x03) /* mask in player 0 and 1 */
+ ((P3PL & 0x04) << 1)) /* mask in player 3 */
& collisions_mask_player_player;
case _P3PL:
update_partial_pmpl_colls();
return (P3PL & 0x07) /* mask in player 0,1, and 2 */
& collisions_mask_player_player;
case _TRIG0:
return TRIG[0] & TRIG_latch[0];
case _TRIG1:
return TRIG[1] & TRIG_latch[1];
case _TRIG2:
return TRIG[2] & TRIG_latch[2];
case _TRIG3:
return TRIG[3] & TRIG_latch[3];
case _PAL:
return 0x0f; // Force NTSC
case _CONSOL:
{
UBYTE byte = consol_table[consol_index] & consol_mask;
if (consol_index > 0) {
consol_index--;
}
return byte;
}
default:
break;
}
return 0xf;
}
#define UPDATE_PM_CYCLE_EXACT {}
void GTIA_PutByte(UWORD addr, UBYTE byte)
{
UWORD cword;
UWORD cword2;
switch (addr & 0x1f)
{
case _CONSOL:
consol_mask = (~byte) & 0x0f;
POTENA = byte & 0x04;
break;
case _COLBK:
COLBK = byte &= 0xfe;
COLOUR_TO_WORD(cword,byte);
cl_lookup[C_BAK] = cword;
if (cword != (UWORD) (lookup_gtia9[0]) ) {
lookup_gtia9[0] = cword + (cword << 16);
if (PRIOR & 0x40)
setup_gtia9_11();
}
break;
case _COLPF0:
COLPF0 = byte &= 0xfe;
COLOUR_TO_WORD(cword,byte);
cl_lookup[C_PF0] = cword;
if ((PRIOR & 1) == 0) {
cl_lookup[C_PF0 | C_PM23] = cl_lookup[C_PF0 | C_PM3] = cl_lookup[C_PF0 | C_PM2] = cword;
if ((PRIOR & 3) == 0) {
if (PRIOR & 0xf) {
cl_lookup[C_PF0 | C_PM01] = cl_lookup[C_PF0 | C_PM1] = cl_lookup[C_PF0 | C_PM0] = cword;
if ((PRIOR & 0xf) == 0xc)
cl_lookup[C_PF0 | C_PM0123] = cl_lookup[C_PF0 | C_PM123] = cl_lookup[C_PF0 | C_PM023] = cword;
}
else
cl_lookup[C_PF0 | C_PM01] = (cl_lookup[C_PF0 | C_PM0] = cword | cl_lookup[C_PM0]) | (cl_lookup[C_PF0 | C_PM1] = cword | cl_lookup[C_PM1]);
}
if ((PRIOR & 0xf) >= 0xa)
cl_lookup[C_PF0 | C_PM25] = cword;
}
break;
case _COLPF1:
COLPF1 = byte &= 0xfe;
COLOUR_TO_WORD(cword,byte);
cl_lookup[C_PF1] = cword;
if ((PRIOR & 1) == 0) {
cl_lookup[C_PF1 | C_PM23] = cl_lookup[C_PF1 | C_PM3] = cl_lookup[C_PF1 | C_PM2] = cword;
if ((PRIOR & 3) == 0) {
if (PRIOR & 0xf) {
cl_lookup[C_PF1 | C_PM01] = cl_lookup[C_PF1 | C_PM1] = cl_lookup[C_PF1 | C_PM0] = cword;
if ((PRIOR & 0xf) == 0xc)
cl_lookup[C_PF1 | C_PM0123] = cl_lookup[C_PF1 | C_PM123] = cl_lookup[C_PF1 | C_PM023] = cword;
}
else
cl_lookup[C_PF1 | C_PM01] = (cl_lookup[C_PF1 | C_PM0] = cword | cl_lookup[C_PM0]) | (cl_lookup[C_PF1 | C_PM1] = cword | cl_lookup[C_PM1]);
}
}
((UBYTE *)hires_lookup_l)[0x80] = ((UBYTE *)hires_lookup_l)[0x41] = (UBYTE)
(hires_lookup_l[0x60] = cword & 0xf0f);
break;
case _COLPF2:
COLPF2 = byte &= 0xfe;
COLOUR_TO_WORD(cword,byte);
cl_lookup[C_PF2] = cword;
if (PRIOR & 4)
cl_lookup[C_PF2 | C_PM01] = cl_lookup[C_PF2 | C_PM1] = cl_lookup[C_PF2 | C_PM0] = cword;
if ((PRIOR & 9) == 0) {
if (PRIOR & 0xf)
cl_lookup[C_PF2 | C_PM23] = cl_lookup[C_PF2 | C_PM3] = cl_lookup[C_PF2 | C_PM2] = cword;
else
cl_lookup[C_PF2 | C_PM23] = (cl_lookup[C_PF2 | C_PM2] = cword | cl_lookup[C_PM2]) | (cl_lookup[C_PF2 | C_PM3] = cword | cl_lookup[C_PM3]);
}
break;
case _COLPF3:
COLPF3 = byte &= 0xfe;
COLOUR_TO_WORD(cword,byte);
cl_lookup[C_PF3] = cword;
if (PRIOR & 4)
cl_lookup[C_PF3 | C_PM01] = cl_lookup[C_PF3 | C_PM1] = cl_lookup[C_PF3 | C_PM0] = cword;
if ((PRIOR & 9) == 0) {
if (PRIOR & 0xf)
cl_lookup[C_PF3 | C_PM23] = cl_lookup[C_PF3 | C_PM3] = cl_lookup[C_PF3 | C_PM2] = cword;
else {
cl_lookup[C_PF3 | C_PM25] = cl_lookup[C_PF2 | C_PM25] = cl_lookup[C_PM25] = cl_lookup[C_PF3 | C_PM2] = cword | cl_lookup[C_PM2];
cl_lookup[C_PF3 | C_PM35] = cl_lookup[C_PF2 | C_PM35] = cl_lookup[C_PM35] = cl_lookup[C_PF3 | C_PM3] = cword | cl_lookup[C_PM3];
cl_lookup[C_PF3 | C_PM235] = cl_lookup[C_PF2 | C_PM235] = cl_lookup[C_PM235] = cl_lookup[C_PF3 | C_PM23] = cl_lookup[C_PF3 | C_PM2] | cl_lookup[C_PF3 | C_PM3];
cl_lookup[C_PF0 | C_PM235] = cl_lookup[C_PF0 | C_PM35] = cl_lookup[C_PF0 | C_PM25] =
cl_lookup[C_PF1 | C_PM235] = cl_lookup[C_PF1 | C_PM35] = cl_lookup[C_PF1 | C_PM25] = cword;
}
}
break;
case _COLPM0:
COLPM0 = byte &= 0xfe;
COLOUR_TO_WORD(cword,byte);
cl_lookup[C_PM023] = cl_lookup[C_PM0] = cword;
cl_lookup[C_PM0123] = cl_lookup[C_PM01] = cword2 = cword | cl_lookup[C_PM1];
if ((PRIOR & 4) == 0) {
cl_lookup[C_PF2 | C_PM0] = cl_lookup[C_PF3 | C_PM0] = cword;
cl_lookup[C_PF2 | C_PM01] = cl_lookup[C_PF3 | C_PM01] = cword2;
if ((PRIOR & 0xc) == 0) {
if (PRIOR & 3) {
cl_lookup[C_PF0 | C_PM0] = cl_lookup[C_PF1 | C_PM0] = cword;
cl_lookup[C_PF0 | C_PM01] = cl_lookup[C_PF1 | C_PM01] = cword2;
}
else {
cl_lookup[C_PF0 | C_PM0] = cword | cl_lookup[C_PF0];
cl_lookup[C_PF1 | C_PM0] = cword | cl_lookup[C_PF1];
cl_lookup[C_PF0 | C_PM01] = cword2 | cl_lookup[C_PF0];
cl_lookup[C_PF1 | C_PM01] = cword2 | cl_lookup[C_PF1];
}
}
}
break;
case _COLPM1:
COLPM1 = byte &= 0xfe;
COLOUR_TO_WORD(cword,byte);
cl_lookup[C_PM123] = cl_lookup[C_PM1] = cword;
cl_lookup[C_PM0123] = cl_lookup[C_PM01] = cword2 = cword | cl_lookup[C_PM0];
if ((PRIOR & 4) == 0) {
cl_lookup[C_PF2 | C_PM1] = cl_lookup[C_PF3 | C_PM1] = cword;
cl_lookup[C_PF2 | C_PM01] = cl_lookup[C_PF3 | C_PM01] = cword2;
if ((PRIOR & 0xc) == 0) {
if (PRIOR & 3) {
cl_lookup[C_PF0 | C_PM1] = cl_lookup[C_PF1 | C_PM1] = cword;
cl_lookup[C_PF0 | C_PM01] = cl_lookup[C_PF1 | C_PM01] = cword2;
}
else {
cl_lookup[C_PF0 | C_PM1] = cword | cl_lookup[C_PF0];
cl_lookup[C_PF1 | C_PM1] = cword | cl_lookup[C_PF1];
cl_lookup[C_PF0 | C_PM01] = cword2 | cl_lookup[C_PF0];
cl_lookup[C_PF1 | C_PM01] = cword2 | cl_lookup[C_PF1];
}
}
}
break;
case _COLPM2:
COLPM2 = byte &= 0xfe;
COLOUR_TO_WORD(cword,byte);
cl_lookup[C_PM2] = cword;
cl_lookup[C_PM23] = cword2 = cword | cl_lookup[C_PM3];
if (PRIOR & 1) {
cl_lookup[C_PF0 | C_PM2] = cl_lookup[C_PF1 | C_PM2] = cword;
cl_lookup[C_PF0 | C_PM23] = cl_lookup[C_PF1 | C_PM23] = cword2;
}
if ((PRIOR & 6) == 0) {
if (PRIOR & 9) {
cl_lookup[C_PF2 | C_PM2] = cl_lookup[C_PF3 | C_PM2] = cword;
cl_lookup[C_PF2 | C_PM23] = cl_lookup[C_PF3 | C_PM23] = cword2;
}
else {
cl_lookup[C_PF2 | C_PM2] = cword | cl_lookup[C_PF2];
cl_lookup[C_PF3 | C_PM25] = cl_lookup[C_PF2 | C_PM25] = cl_lookup[C_PM25] = cl_lookup[C_PF3 | C_PM2] = cword | cl_lookup[C_PF3];
cl_lookup[C_PF2 | C_PM23] = cword2 | cl_lookup[C_PF2];
cl_lookup[C_PF3 | C_PM235] = cl_lookup[C_PF2 | C_PM235] = cl_lookup[C_PM235] = cl_lookup[C_PF3 | C_PM23] = cword2 | cl_lookup[C_PF3];
}
}
break;
case _COLPM3:
COLPM3 = byte &= 0xfe;
COLOUR_TO_WORD(cword,byte);
cl_lookup[C_PM3] = cword;
cl_lookup[C_PM23] = cword2 = cword | cl_lookup[C_PM2];
if (PRIOR & 1) {
cl_lookup[C_PF0 | C_PM3] = cl_lookup[C_PF1 | C_PM3] = cword;
cl_lookup[C_PF0 | C_PM23] = cl_lookup[C_PF1 | C_PM23] = cword2;
}
if ((PRIOR & 6) == 0) {
if (PRIOR & 9) {
cl_lookup[C_PF2 | C_PM3] = cl_lookup[C_PF3 | C_PM3] = cword;
cl_lookup[C_PF2 | C_PM23] = cl_lookup[C_PF3 | C_PM23] = cword2;
}
else {
cl_lookup[C_PF2 | C_PM3] = cword | cl_lookup[C_PF2];
cl_lookup[C_PF3 | C_PM35] = cl_lookup[C_PF2 | C_PM35] = cl_lookup[C_PM35] = cl_lookup[C_PF3 | C_PM3] = cword | cl_lookup[C_PF3];
cl_lookup[C_PF2 | C_PM23] = cword2 | cl_lookup[C_PF2];
cl_lookup[C_PF3 | C_PM235] = cl_lookup[C_PF2 | C_PM235] = cl_lookup[C_PM235] = cl_lookup[C_PF3 | C_PM23] = cword2 | cl_lookup[C_PF3];
}
}
break;
case _GRAFM:
GRAFM = byte;
UPDATE_PM_CYCLE_EXACT
break;
#define CYCLE_EXACT_GRAFP(n)
#define DO_GRAFP(n) case _GRAFP##n:\
GRAFP##n = byte;\
CYCLE_EXACT_GRAFP(n);\
break;
DO_GRAFP(0)
DO_GRAFP(1)
DO_GRAFP(2)
DO_GRAFP(3)
case _HITCLR:
M0PL = M1PL = M2PL = M3PL = 0;
P0PL = P1PL = P2PL = P3PL = 0;
PF0PM = PF1PM = PF2PM = PF3PM = 0;
break;
/* TODO: cycle-exact missile HPOS, GRAF, SIZE */
/* this is only an approximation */
case _HPOSM0:
HPOSM0 = byte;
hposm_ptr[0] = pm_scanline + byte - 0x20;
UPDATE_PM_CYCLE_EXACT
break;
case _HPOSM1:
HPOSM1 = byte;
hposm_ptr[1] = pm_scanline + byte - 0x20;
UPDATE_PM_CYCLE_EXACT
break;
case _HPOSM2:
HPOSM2 = byte;
hposm_ptr[2] = pm_scanline + byte - 0x20;
UPDATE_PM_CYCLE_EXACT
break;
case _HPOSM3:
HPOSM3 = byte;
hposm_ptr[3] = pm_scanline + byte - 0x20;
UPDATE_PM_CYCLE_EXACT
break;
#define CYCLE_EXACT_HPOSP(n)
#define DO_HPOSP(n) case _HPOSP##n: \
hposp_ptr[n] = pm_scanline + byte - 0x20; \
if (byte >= 0x22) { \
if (byte > 0xbe) { \
if (byte >= 0xde) \
hposp_mask[n] = 0; \
else \
hposp_mask[n] = 0xffffffff >> (byte - 0xbe); \
} \
else \
hposp_mask[n] = 0xffffffff; \
} \
else if (byte > 2) \
hposp_mask[n] = 0xffffffff << (0x22 - byte); \
else \
hposp_mask[n] = 0; \
CYCLE_EXACT_HPOSP(n)\
HPOSP##n = byte; \
break;
DO_HPOSP(0)
DO_HPOSP(1)
DO_HPOSP(2)
DO_HPOSP(3)
/* TODO: cycle-exact size changes */
/* this is only an approximation */
case _SIZEM:
SIZEM = byte;
global_sizem[0] = PM_Width[byte & 0x03];
global_sizem[1] = PM_Width[(byte & 0x0c) >> 2];
global_sizem[2] = PM_Width[(byte & 0x30) >> 4];
global_sizem[3] = PM_Width[(byte & 0xc0) >> 6];
UPDATE_PM_CYCLE_EXACT
break;
case _SIZEP0:
SIZEP0 = byte;
grafp_ptr[0] = &grafp_lookup[(byte & 3)*256];
UPDATE_PM_CYCLE_EXACT
break;
case _SIZEP1:
SIZEP1 = byte;
grafp_ptr[1] = &grafp_lookup[(byte & 3)*256];
UPDATE_PM_CYCLE_EXACT
break;
case _SIZEP2:
SIZEP2 = byte;
grafp_ptr[2] = &grafp_lookup[(byte & 3)*256];
UPDATE_PM_CYCLE_EXACT
break;
case _SIZEP3:
SIZEP3 = byte;
grafp_ptr[3] = &grafp_lookup[(byte & 3)*256];
UPDATE_PM_CYCLE_EXACT
break;
case _PRIOR:
set_prior(byte);
PRIOR = byte;
if (byte & 0x40)
setup_gtia9_11();
break;
case _VDELAY:
VDELAY = byte;
break;
case _GRACTL:
GRACTL = byte;
missile_gra_enabled = (byte & 0x01);
player_gra_enabled = (byte & 0x02);
player_flickering = ((player_dma_enabled | player_gra_enabled) == 0x02);
missile_flickering = ((missile_dma_enabled | missile_gra_enabled) == 0x01);
if ((byte & 4) == 0)
TRIG_latch[0] = TRIG_latch[1] = TRIG_latch[2] = TRIG_latch[3] = 1;
break;
}
}