stella/src/emucore/TIATables.cxx

727 lines
27 KiB
C++

//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id$
//============================================================================
#include <cassert>
#include "bspf.hxx"
#include "TIATables.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void TIATables::computeAllTables()
{
memset(DisabledMask, 0, 640);
buildCollisionMaskTable();
buildPxMaskTable();
buildMxMaskTable();
buildBLMaskTable();
buildPFMaskTable();
buildGRPReflectTable();
buildPxPosResetWhenTable();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void TIATables::buildCollisionMaskTable()
{
for(uInt8 i = 0; i < 64; ++i)
{
CollisionMask[i] = 0;
if((i & M0Bit) && (i & P1Bit)) // M0-P1
CollisionMask[i] |= Cx_M0P1;
if((i & M0Bit) && (i & P0Bit)) // M0-P0
CollisionMask[i] |= Cx_M0P0;
if((i & M1Bit) && (i & P0Bit)) // M1-P0
CollisionMask[i] |= Cx_M1P0;
if((i & M1Bit) && (i & P1Bit)) // M1-P1
CollisionMask[i] |= Cx_M1P1;
if((i & P0Bit) && (i & PFBit)) // P0-PF
CollisionMask[i] |= Cx_P0PF;
if((i & P0Bit) && (i & BLBit)) // P0-BL
CollisionMask[i] |= Cx_P0BL;
if((i & P1Bit) && (i & PFBit)) // P1-PF
CollisionMask[i] |= Cx_P1PF;
if((i & P1Bit) && (i & BLBit)) // P1-BL
CollisionMask[i] |= Cx_P1BL;
if((i & M0Bit) && (i & PFBit)) // M0-PF
CollisionMask[i] |= Cx_M0PF;
if((i & M0Bit) && (i & BLBit)) // M0-BL
CollisionMask[i] |= Cx_M0BL;
if((i & M1Bit) && (i & PFBit)) // M1-PF
CollisionMask[i] |= Cx_M1PF;
if((i & M1Bit) && (i & BLBit)) // M1-BL
CollisionMask[i] |= Cx_M1BL;
if((i & BLBit) && (i & PFBit)) // BL-PF
CollisionMask[i] |= Cx_BLPF;
if((i & P0Bit) && (i & P1Bit)) // P0-P1
CollisionMask[i] |= Cx_P0P1;
if((i & M0Bit) && (i & M1Bit)) // M0-M1
CollisionMask[i] |= Cx_M0M1;
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// [suppress mode:2][nusiz:8][pixel:320]
// suppress=1: suppress on
// suppress=0: suppress off
void TIATables::buildPxMaskTable()
{
Int32 x, suppress, nusiz;
// Set the player mask table to all zeros
for(nusiz = 0; nusiz < 8; ++nusiz)
for(x = 0; x < 160; ++x)
PxMask[0][nusiz][x] = PxMask[1][nusiz][x] = 0x00;
// Now, compute the player mask table
for(suppress = 0; suppress < 2; ++suppress)
{
for(nusiz = 0; nusiz < 8; ++nusiz)
{
for(x = 0; x < 160 + 72; ++x)
{
// nusiz:
// 0: one copy
// 1: two copies-close
// 2: two copies-med
// 3: three copies-close
// 4: two copies-wide
// 5: double size player
// 6: 3 copies medium
// 7: quad sized player
switch(nusiz)
{
case 0x00:
if((suppress == 0) && (x >= 0) && (x < 8))
PxMask[suppress][nusiz][x % 160] = 0x80 >> x;
break;
case 0x01:
if((suppress == 0) && (x >= 0) && (x < 8))
PxMask[suppress][nusiz][x % 160] = 0x80 >> x;
else if(((x - 16) >= 0) && ((x - 16) < 8))
PxMask[suppress][nusiz][x % 160] = 0x80 >> (x - 16);
break;
case 0x02:
if((suppress == 0) && (x >= 0) && (x < 8))
PxMask[suppress][nusiz][x % 160] = 0x80 >> x;
else if(((x - 32) >= 0) && ((x - 32) < 8))
PxMask[suppress][nusiz][x % 160] = 0x80 >> (x - 32);
break;
case 0x03:
if((suppress == 0) && (x >= 0) && (x < 8))
PxMask[suppress][nusiz][x % 160] = 0x80 >> x;
else if(((x - 16) >= 0) && ((x - 16) < 8))
PxMask[suppress][nusiz][x % 160] = 0x80 >> (x - 16);
else if(((x - 32) >= 0) && ((x - 32) < 8))
PxMask[suppress][nusiz][x % 160] = 0x80 >> (x - 32);
break;
case 0x04:
if((suppress == 0) && (x >= 0) && (x < 8))
PxMask[suppress][nusiz][x % 160] = 0x80 >> x;
else if(((x - 64) >= 0) && ((x - 64) < 8))
PxMask[suppress][nusiz][x % 160] = 0x80 >> (x - 64);
break;
case 0x05:
// For some reason in double size nusiz the player's output
// is delayed by one pixel thus we use > instead of >=
if((suppress == 0) && (x > 0) && (x <= 16))
PxMask[suppress][nusiz][x % 160] = 0x80 >> ((x - 1)/2);
break;
case 0x06:
if((suppress == 0) && (x >= 0) && (x < 8))
PxMask[suppress][nusiz][x % 160] = 0x80 >> x;
else if(((x - 32) >= 0) && ((x - 32) < 8))
PxMask[suppress][nusiz][x % 160] = 0x80 >> (x - 32);
else if(((x - 64) >= 0) && ((x - 64) < 8))
PxMask[suppress][nusiz][x % 160] = 0x80 >> (x - 64);
break;
case 0x07:
// For some reason in quad size nusiz the player's output
// is delayed by one pixel thus we use > instead of >=
if((suppress == 0) && (x > 0) && (x <= 32))
PxMask[suppress][nusiz][x % 160] = 0x80 >> ((x - 1)/4);
break;
}
}
// Copy data into wrap-around area
for(x = 0; x < 160; ++x)
PxMask[suppress][nusiz][x + 160] = PxMask[suppress][nusiz][x];
}
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// [number:8][size:5][pixel:320]
void TIATables::buildMxMaskTable()
{
Int32 x, size, number;
// Clear the missle table to start with
for(number = 0; number < 8; ++number)
for(size = 0; size < 5; ++size)
for(x = 0; x < 160; ++x)
MxMask[number][size][x] = false;
for(number = 0; number < 8; ++number)
{
for(size = 0; size < 5; ++size)
{
for(x = 0; x < 160 + 72; ++x)
{
// For the following, size index = 4 is almost exactly the same as
// index = 2; that is, 1 << 2, or 4 colour clocks wide
// To simulate the weirdness in the Cosmic Ark starfield effect,
// each group of 4 pixels has its 3rd pixel blanked
switch(number)
{
// Only one copy of the missle
case 0x00:
case 0x05:
case 0x07:
if(size != 4)
{
if((x >= 0) && (x < (1 << size)))
MxMask[number][size][x % 160] = true;
}
else
{
if((x >= 0) && (x < (1 << 2)))
MxMask[number][4][x % 160] = ((x - 2) % 4 == 0 ? false : true);
}
break;
// Two copies - close
case 0x01:
if(size != 4)
{
if((x >= 0) && (x < (1 << size)))
MxMask[number][size][x % 160] = true;
else if(((x - 16) >= 0) && ((x - 16) < (1 << size)))
MxMask[number][size][x % 160] = true;
}
else
{
if((x >= 0) && (x < (1 << 2)))
MxMask[number][4][x % 160] = ((x - 2) % 4 == 0 ? false : true);
else if(((x - 16) >= 0) && ((x - 16) < (1 << 2)))
MxMask[number][4][x % 160] = ((x - 2) % 4 == 0 ? false : true);
}
break;
// Two copies - medium
case 0x02:
if(size != 4)
{
if((x >= 0) && (x < (1 << size)))
MxMask[number][size][x % 160] = true;
else if(((x - 32) >= 0) && ((x - 32) < (1 << size)))
MxMask[number][size][x % 160] = true;
}
else
{
if((x >= 0) && (x < (1 << 2)))
MxMask[number][4][x % 160] = ((x - 2) % 4 == 0 ? false : true);
else if(((x - 32) >= 0) && ((x - 32) < (1 << 2)))
MxMask[number][4][x % 160] = ((x - 2) % 4 == 0 ? false : true);
}
break;
// Three copies - close
case 0x03:
if(size != 4)
{
if((x >= 0) && (x < (1 << size)))
MxMask[number][size][x % 160] = true;
else if(((x - 16) >= 0) && ((x - 16) < (1 << size)))
MxMask[number][size][x % 160] = true;
else if(((x - 32) >= 0) && ((x - 32) < (1 << size)))
MxMask[number][size][x % 160] = true;
}
else
{
if((x >= 0) && (x < (1 << 2)))
MxMask[number][4][x % 160] = ((x - 2) % 4 == 0 ? false : true);
else if(((x - 16) >= 0) && ((x - 16) < (1 << 2)))
MxMask[number][4][x % 160] = ((x - 2) % 4 == 0 ? false : true);
else if(((x - 32) >= 0) && ((x - 32) < (1 << 2)))
MxMask[number][4][x % 160] = ((x - 2) % 4 == 0 ? false : true);
}
break;
// Two copies - wide
case 0x04:
if(size != 4)
{
if((x >= 0) && (x < (1 << size)))
MxMask[number][size][x % 160] = true;
else if(((x - 64) >= 0) && ((x - 64) < (1 << size)))
MxMask[number][size][x % 160] = true;
}
else
{
if((x >= 0) && (x < (1 << 2)))
MxMask[number][4][x % 160] = ((x - 2) % 4 == 0 ? false : true);
else if(((x - 64) >= 0) && ((x - 64) < (1 << 2)))
MxMask[number][4][x % 160] = ((x - 2) % 4 == 0 ? false : true);
}
break;
// Three copies - medium
case 0x06:
if(size != 4)
{
if((x >= 0) && (x < (1 << size)))
MxMask[number][size][x % 160] = true;
else if(((x - 32) >= 0) && ((x - 32) < (1 << size)))
MxMask[number][size][x % 160] = true;
else if(((x - 64) >= 0) && ((x - 64) < (1 << size)))
MxMask[number][size][x % 160] = true;
}
else
{
if((x >= 0) && (x < (1 << 2)))
MxMask[number][4][x % 160] = ((x - 2) % 4 == 0 ? false : true);
else if(((x - 32) >= 0) && ((x - 32) < (1 << 2)))
MxMask[number][4][x % 160] = ((x - 2) % 4 == 0 ? false : true);
else if(((x - 64) >= 0) && ((x - 64) < (1 << 2)))
MxMask[number][4][x % 160] = ((x - 2) % 4 == 0 ? false : true);
}
break;
}
}
// Copy data into wrap-around area
for(x = 0; x < 160; ++x)
MxMask[number][size][x + 160] =
MxMask[number][size][x];
}
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// [size:4][pixel:320]
void TIATables::buildBLMaskTable()
{
for(Int32 size = 0; size < 4; ++size)
{
Int32 x;
// Set all of the masks to false to start with
for(x = 0; x < 160; ++x)
BLMask[size][x] = false;
// Set the necessary fields true
for(x = 0; x < 160 + 8; ++x)
if((x >= 0) && (x < (1 << size)))
BLMask[size][x % 160] = true;
// Copy fields into the wrap-around area of the mask
for(x = 0; x < 160; ++x)
BLMask[size][x + 160] = BLMask[size][x];
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// [reflect:2][pixel:160]
// reflect=1: reflection on
// reflect=0: reflection off
void TIATables::buildPFMaskTable()
{
Int32 x;
// Compute playfield mask table for non-reflected mode
for(x = 0; x < 160; ++x)
{
if(x < 16)
PFMask[0][x] = 0x00001 << (x >> 2);
else if(x < 48)
PFMask[0][x] = 0x00800 >> ((x - 16) >> 2);
else if(x < 80)
PFMask[0][x] = 0x01000 << ((x - 48) >> 2);
else if(x < 96)
PFMask[0][x] = 0x00001 << ((x - 80) >> 2);
else if(x < 128)
PFMask[0][x] = 0x00800 >> ((x - 96) >> 2);
else if(x < 160)
PFMask[0][x] = 0x01000 << ((x - 128) >> 2);
}
// Compute playfield mask table for reflected mode
for(x = 0; x < 160; ++x)
{
if(x < 16)
PFMask[1][x] = 0x00001 << (x >> 2);
else if(x < 48)
PFMask[1][x] = 0x00800 >> ((x - 16) >> 2);
else if(x < 80)
PFMask[1][x] = 0x01000 << ((x - 48) >> 2);
else if(x < 112)
PFMask[1][x] = 0x80000 >> ((x - 80) >> 2);
else if(x < 144)
PFMask[1][x] = 0x00010 << ((x - 112) >> 2);
else if(x < 160)
PFMask[1][x] = 0x00008 >> ((x - 144) >> 2);
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void TIATables::buildGRPReflectTable()
{
for(uInt16 i = 0; i < 256; ++i)
{
uInt8 r = 0;
for(uInt16 t = 1; t <= 128; t <<= 1)
r = (r << 1) | ((i & t) ? 0x01 : 0x00);
GRPReflect[i] = r;
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// [nusiz:8][old pixel:160][new pixel:160]
void TIATables::buildPxPosResetWhenTable()
{
uInt32 nusiz, oldx, newx;
// Loop through all player nusizs, all old player positions, and all new
// player positions and determine where the new position is located:
// 1 means the new position is within the display of an old copy of the
// player, -1 means the new position is within the delay portion of an
// old copy of the player, and 0 means it's neither of these two
for(nusiz = 0; nusiz < 8; ++nusiz)
{
for(oldx = 0; oldx < 160; ++oldx)
{
// Set everything to 0 for non-delay/non-display section
for(newx = 0; newx < 160; ++newx)
PxPosResetWhen[nusiz][oldx][newx] = 0;
// Now, we'll set the entries for non-delay/non-display section
for(newx = 0; newx < 160 + 72 + 5; ++newx)
{
// nusiz:
// 0: one copy
// 1: two copies-close
// 2: two copies-med
// 3: three copies-close
// 4: two copies-wide
// 5: double size player
// 6: 3 copies medium
// 7: quad sized player
switch(nusiz)
{
case 0x00:
if((newx >= oldx) && (newx < (oldx + 4)))
PxPosResetWhen[nusiz][oldx][newx % 160] = -1;
else if((newx >= oldx + 4) && (newx < (oldx + 4 + 8)))
PxPosResetWhen[nusiz][oldx][newx % 160] = 1;
break;
case 0x01:
if((newx >= oldx) && (newx < (oldx + 4)))
PxPosResetWhen[nusiz][oldx][newx % 160] = -1;
else if((newx >= (oldx + 16)) && (newx < (oldx + 16 + 4)))
PxPosResetWhen[nusiz][oldx][newx % 160] = -1;
else if((newx >= oldx + 4) && (newx < (oldx + 4 + 8)))
PxPosResetWhen[nusiz][oldx][newx % 160] = 1;
else if((newx >= oldx + 16 + 4) && (newx < (oldx + 16 + 4 + 8)))
PxPosResetWhen[nusiz][oldx][newx % 160] = 1;
break;
case 0x02:
if((newx >= oldx) && (newx < (oldx + 4)))
PxPosResetWhen[nusiz][oldx][newx % 160] = -1;
else if((newx >= (oldx + 32)) && (newx < (oldx + 32 + 4)))
PxPosResetWhen[nusiz][oldx][newx % 160] = -1;
else if((newx >= oldx + 4) && (newx < (oldx + 4 + 8)))
PxPosResetWhen[nusiz][oldx][newx % 160] = 1;
else if((newx >= oldx + 32 + 4) && (newx < (oldx + 32 + 4 + 8)))
PxPosResetWhen[nusiz][oldx][newx % 160] = 1;
break;
case 0x03:
if((newx >= oldx) && (newx < (oldx + 4)))
PxPosResetWhen[nusiz][oldx][newx % 160] = -1;
else if((newx >= (oldx + 16)) && (newx < (oldx + 16 + 4)))
PxPosResetWhen[nusiz][oldx][newx % 160] = -1;
else if((newx >= (oldx + 32)) && (newx < (oldx + 32 + 4)))
PxPosResetWhen[nusiz][oldx][newx % 160] = -1;
else if((newx >= oldx + 4) && (newx < (oldx + 4 + 8)))
PxPosResetWhen[nusiz][oldx][newx % 160] = 1;
else if((newx >= oldx + 16 + 4) && (newx < (oldx + 16 + 4 + 8)))
PxPosResetWhen[nusiz][oldx][newx % 160] = 1;
else if((newx >= oldx + 32 + 4) && (newx < (oldx + 32 + 4 + 8)))
PxPosResetWhen[nusiz][oldx][newx % 160] = 1;
break;
case 0x04:
if((newx >= oldx) && (newx < (oldx + 4)))
PxPosResetWhen[nusiz][oldx][newx % 160] = -1;
else if((newx >= (oldx + 64)) && (newx < (oldx + 64 + 4)))
PxPosResetWhen[nusiz][oldx][newx % 160] = -1;
else if((newx >= oldx + 4) && (newx < (oldx + 4 + 8)))
PxPosResetWhen[nusiz][oldx][newx % 160] = 1;
else if((newx >= oldx + 64 + 4) && (newx < (oldx + 64 + 4 + 8)))
PxPosResetWhen[nusiz][oldx][newx % 160] = 1;
break;
case 0x05:
if((newx >= oldx) && (newx < (oldx + 4)))
PxPosResetWhen[nusiz][oldx][newx % 160] = -1;
else if((newx >= oldx + 4) && (newx < (oldx + 4 + 16)))
PxPosResetWhen[nusiz][oldx][newx % 160] = 1;
break;
case 0x06:
if((newx >= oldx) && (newx < (oldx + 4)))
PxPosResetWhen[nusiz][oldx][newx % 160] = -1;
else if((newx >= (oldx + 32)) && (newx < (oldx + 32 + 4)))
PxPosResetWhen[nusiz][oldx][newx % 160] = -1;
else if((newx >= (oldx + 64)) && (newx < (oldx + 64 + 4)))
PxPosResetWhen[nusiz][oldx][newx % 160] = -1;
else if((newx >= oldx + 4) && (newx < (oldx + 4 + 8)))
PxPosResetWhen[nusiz][oldx][newx % 160] = 1;
else if((newx >= oldx + 32 + 4) && (newx < (oldx + 32 + 4 + 8)))
PxPosResetWhen[nusiz][oldx][newx % 160] = 1;
else if((newx >= oldx + 64 + 4) && (newx < (oldx + 64 + 4 + 8)))
PxPosResetWhen[nusiz][oldx][newx % 160] = 1;
break;
case 0x07:
if((newx >= oldx) && (newx < (oldx + 4)))
PxPosResetWhen[nusiz][oldx][newx % 160] = -1;
else if((newx >= oldx + 4) && (newx < (oldx + 4 + 32)))
PxPosResetWhen[nusiz][oldx][newx % 160] = 1;
break;
}
}
// Let's do a sanity check on table entries
uInt32 s1 = 0, s2 = 0;
for(newx = 0; newx < 160; ++newx)
{
if(PxPosResetWhen[nusiz][oldx][newx] == -1)
++s1;
if(PxPosResetWhen[nusiz][oldx][newx] == 1)
++s2;
}
assert((s1 % 4 == 0) && (s2 % 8 == 0));
}
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const Int16 TIATables::PokeDelay[64] = {
0, // VSYNC
1, // VBLANK (0) / 1
0, // WSYNC
0, // RSYNC
0, // NUSIZ0
0, // NUSIZ1
0, // COLUP0
0, // COLUP1
0, // COLUPF
0, // COLUBK
0, // CTRLPF
1, // REFP0
1, // REFP1
-1, // PF0 (4) / -1
-1, // PF1 (4) / -1
-1, // PF2 (4) / -1
0, // RESP0
0, // RESP1
8, // RESM0 (0) / 8
8, // RESM1 (0) / 8
0, // RESBL
0, // AUDC0 (-1) / 0
0, // AUDC1 (-1) / 0
0, // AUDF0 (-1) / 0
0, // AUDF1 (-1) / 0
0, // AUDV0 (-1) / 0
0, // AUDV1 (-1) / 0
1, // GRP0
1, // GRP1
1, // ENAM0
1, // ENAM1
1, // ENABL
0, // HMP0
0, // HMP1
0, // HMM0
0, // HMM1
0, // HMBL
0, // VDELP0
0, // VDELP1
0, // VDELBL
0, // RESMP0
0, // RESMP1
3, // HMOVE
0, // HMCLR
0, // CXCLR
// remaining values are undefined TIA write locations
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const bool TIATables::HMOVEBlankEnableCycles[76] = {
true, true, true, true, true, true, true, true, true, true, // 00
true, true, true, true, true, true, true, true, true, true, // 10
true, false, false, false, false, false, false, false, false, false, // 20
false, false, false, false, false, false, false, false, false, false, // 30
false, false, false, false, false, false, false, false, false, false, // 40
false, false, false, false, false, false, false, false, false, false, // 50
false, false, false, false, false, false, false, false, false, false, // 60
false, false, false, false, false, true // 70
};
#if 0
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const Int32 TIATables::CompleteMotion[76][16] = {
{ 0, -1, -2, -3, -4, -5, -6, -7, 8, 7, 6, 5, 4, 3, 2, 1}, // HBLANK
{ 0, -1, -2, -3, -4, -5, -6, -7, 8, 7, 6, 5, 4, 3, 2, 1}, // HBLANK
{ 0, -1, -2, -3, -4, -5, -6, -7, 8, 7, 6, 5, 4, 3, 2, 1}, // HBLANK
{ 0, -1, -2, -3, -4, -5, -6, -7, 8, 7, 6, 5, 4, 3, 2, 1}, // HBLANK
{ 0, -1, -2, -3, -4, -5, -6, -6, 8, 7, 6, 5, 4, 3, 2, 1}, // HBLANK
{ 0, -1, -2, -3, -4, -5, -5, -5, 8, 7, 6, 5, 4, 3, 2, 1}, // HBLANK
{ 0, -1, -2, -3, -4, -5, -5, -5, 8, 7, 6, 5, 4, 3, 2, 1}, // HBLANK
{ 0, -1, -2, -3, -4, -4, -4, -4, 8, 7, 6, 5, 4, 3, 2, 1}, // HBLANK
{ 0, -1, -2, -3, -3, -3, -3, -3, 8, 7, 6, 5, 4, 3, 2, 1}, // HBLANK
{ 0, -1, -2, -2, -2, -2, -2, -2, 8, 7, 6, 5, 4, 3, 2, 1}, // HBLANK
{ 0, -1, -2, -2, -2, -2, -2, -2, 8, 7, 6, 5, 4, 3, 2, 1}, // HBLANK
{ 0, -1, -1, -1, -1, -1, -1, -1, 8, 7, 6, 5, 4, 3, 2, 1}, // HBLANK
{ 0, 0, 0, 0, 0, 0, 0, 0, 8, 7, 6, 5, 4, 3, 2, 1}, // HBLANK
{ 1, 1, 1, 1, 1, 1, 1, 1, 8, 7, 6, 5, 4, 3, 2, 1}, // HBLANK
{ 1, 1, 1, 1, 1, 1, 1, 1, 8, 7, 6, 5, 4, 3, 2, 1}, // HBLANK
{ 2, 2, 2, 2, 2, 2, 2, 2, 8, 7, 6, 5, 4, 3, 2, 2}, // HBLANK
{ 3, 3, 3, 3, 3, 3, 3, 3, 8, 7, 6, 5, 4, 3, 3, 3}, // HBLANK
{ 4, 4, 4, 4, 4, 4, 4, 4, 8, 7, 6, 5, 4, 4, 4, 4}, // HBLANK
{ 4, 4, 4, 4, 4, 4, 4, 4, 8, 7, 6, 5, 4, 4, 4, 4}, // HBLANK
{ 5, 5, 5, 5, 5, 5, 5, 5, 8, 7, 6, 5, 5, 5, 5, 5}, // HBLANK
{ 6, 6, 6, 6, 6, 6, 6, 6, 8, 7, 6, 6, 6, 6, 6, 6}, // HBLANK
{ 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, 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, 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, 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, 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, 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, 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, -1, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, -1, -2, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, -1, -2, -3, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, -1, -2, -3, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, -1, -2, -3, -4, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, -1, -2, -3, -4, -5, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, -1, -2, -3, -4, -5, -6, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, -1, -2, -3, -4, -5, -6, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, -1, -2, -3, -4, -5, -6, -7, 0, 0, 0, 0, 0, 0, 0, 0},
{-1, -2, -3, -4, -5, -6, -7, -8, 0, 0, 0, 0, 0, 0, 0, 0},
{-2, -3, -4, -5, -6, -7, -8, -9, 0, 0, 0, 0, 0, 0, 0, -1},
{-2, -3, -4, -5, -6, -7, -8, -9, 0, 0, 0, 0, 0, 0, 0, -1},
{-3, -4, -5, -6, -7, -8, -9,-10, 0, 0, 0, 0, 0, 0, -1, -2},
{-4, -5, -6, -7, -8, -9,-10,-11, 0, 0, 0, 0, 0, -1, -2, -3},
{-5, -6, -7, -8, -9,-10,-11,-12, 0, 0, 0, 0, -1, -2, -3, -4},
{-5, -6, -7, -8, -9,-10,-11,-12, 0, 0, 0, 0, -1, -2, -3, -4},
{-6, -7, -8, -9,-10,-11,-12,-13, 0, 0, 0, -1, -2, -3, -4, -5},
{-7, -8, -9,-10,-11,-12,-13,-14, 0, 0, -1, -2, -3, -4, -5, -6},
{-8, -9,-10,-11,-12,-13,-14,-15, 0, -1, -2, -3, -4, -5, -6, -7},
{-8, -9,-10,-11,-12,-13,-14,-15, 0, -1, -2, -3, -4, -5, -6, -7},
{ 0, -1, -2, -3, -4, -5, -6, -7, 8, 7, 6, 5, 4, 3, 2, 1} // HBLANK
};
#endif
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt8 TIATables::PxMask[2][8][320];
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt8 TIATables::MxMask[8][5][320];
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt8 TIATables::BLMask[4][320];
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt32 TIATables::PFMask[2][160];
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt8 TIATables::GRPReflect[256];
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt16 TIATables::CollisionMask[64];
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt8 TIATables::DisabledMask[640];
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Int8 TIATables::PxPosResetWhen[8][160][160];