// license:GPL-2.0+
// copyright-holders:Juergen Buchmueller
/******************************************************************************
Atari 400/800
ANTIC video controller
Juergen Buchmueller, June 1998
******************************************************************************/
#include "emu.h"
#include "antic.h"
#include "screen.h"
#ifdef MAME_DEBUG
#define VERBOSE 1
#else
#define VERBOSE 0
#endif
#define LOG(x) do { if (VERBOSE) logerror x; } while (0)
#define CYCLES_PER_LINE 114 /* total number of cpu cycles per scanline (incl. hblank) */
#define CYCLES_REFRESH 9 /* number of cycles lost for ANTICs RAM refresh using DMA */
#define CYCLES_HSTART 32 /* where does the ANTIC DMA fetch start */
#define CYCLES_DLI_NMI 7 /* number of cycles until the CPU recognizes a DLI */
#define CYCLES_HSYNC 104 /* where does the HSYNC position of a scanline start */
#define PMOFFSET 32 /* # of pixels to adjust p/m hpos */
#define VPAGE 0xf000 /* 4K page mask for video data src */
#define VOFFS 0x0fff /* 4K offset mask for video data src */
#define DPAGE 0xfc00 /* 1K page mask for display list */
#define DOFFS 0x03ff /* 1K offset mask for display list */
#define DLI_NMI 0x80 /* 10000000b bit mask for display list interrupt */
#define VBL_NMI 0x40 /* 01000000b bit mask for vertical blank interrupt */
#define ANTIC_DLI 0x80 /* 10000000b cmds with display list intr */
#define ANTIC_LMS 0x40 /* 01000000b cmds with load memory scan */
#define ANTIC_VSCR 0x20 /* 00100000b cmds with vertical scroll */
#define ANTIC_HSCR 0x10 /* 00010000b cmds with horizontal scroll */
#define ANTIC_MODE 0x0f /* 00001111b cmd mode mask */
#define DMA_ANTIC 0x20 /* 00100000b ANTIC DMA enable */
#define DMA_PM_DBLLINE 0x10 /* 00010000b double line player/missile */
#define DMA_PLAYER 0x08 /* 00001000b player DMA enable */
#define DMA_MISSILE 0x04 /* 00000100b missile DMA enable */
#define OFS_MIS_SINGLE 3*256 /* offset missiles single line DMA */
#define OFS_PL0_SINGLE 4*256 /* offset player 0 single line DMA */
#define OFS_PL1_SINGLE 5*256 /* offset player 1 single line DMA */
#define OFS_PL2_SINGLE 6*256 /* offset player 2 single line DMA */
#define OFS_PL3_SINGLE 7*256 /* offset player 3 single line DMA */
#define OFS_MIS_DOUBLE 3*128 /* offset missiles double line DMA */
#define OFS_PL0_DOUBLE 4*128 /* offset player 0 double line DMA */
#define OFS_PL1_DOUBLE 5*128 /* offset player 1 double line DMA */
#define OFS_PL2_DOUBLE 6*128 /* offset player 2 double line DMA */
#define OFS_PL3_DOUBLE 7*128 /* offset player 3 double line DMA */
#define PFD 0x00 /* 00000000b playfield default color */
#define PBK 0x00 /* 00000000b playfield background */
#define PF0 0x01 /* 00000001b playfield color #0 */
#define PF1 0x02 /* 00000010b playfield color #1 */
#define PF2 0x04 /* 00000100b playfield color #2 */
#define PF3 0x08 /* 00001000b playfield color #3 */
#define PL0 0x11 /* 00010001b player #0 */
#define PL1 0x12 /* 00010010b player #1 */
#define PL2 0x14 /* 00010100b player #2 */
#define PL3 0x18 /* 00011000b player #3 */
#define MI0 0x21 /* 00100001b missile #0 */
#define MI1 0x22 /* 00100010b missile #1 */
#define MI2 0x24 /* 00100100b missile #2 */
#define MI3 0x28 /* 00101000b missile #3 */
#define T00 0x40 /* 01000000b text mode pixels 00 */
#define P000 0x48 /* 01001000b player #0 pixels 00 */
#define P100 0x4a /* 01001010b player #1 pixels 00 */
#define P200 0x4c /* 01001100b player #2 pixels 00 */
#define P300 0x4e /* 01001110b player #3 pixels 00 */
#define P400 0x4f /* 01001111b missiles pixels 00 */
#define T01 0x50 /* 01010000b text mode pixels 01 */
#define P001 0x58 /* 01011000b player #0 pixels 01 */
#define P101 0x5a /* 01011010b player #1 pixels 01 */
#define P201 0x5c /* 01011100b player #2 pixels 01 */
#define P301 0x5e /* 01011110b player #3 pixels 01 */
#define P401 0x5f /* 01011111b missiles pixels 01 */
#define T10 0x60 /* 01100000b text mode pixels 10 */
#define P010 0x68 /* 01101000b player #0 pixels 10 */
#define P110 0x6a /* 01101010b player #1 pixels 10 */
#define P210 0x6c /* 01101100b player #2 pixels 10 */
#define P310 0x6e /* 01101110b player #3 pixels 10 */
#define P410 0x6f /* 01101111b missiles pixels 10 */
#define T11 0x70 /* 01110000b text mode pixels 11 */
#define P011 0x78 /* 01111000b player #0 pixels 11 */
#define P111 0x7a /* 01111010b player #1 pixels 11 */
#define P211 0x7c /* 01111100b player #2 pixels 11 */
#define P311 0x7e /* 01111110b player #3 pixels 11 */
#define P411 0x7f /* 01111111b missiles pixels 11 */
#define G00 0x80 /* 10000000b hires gfx pixels 00 */
#define G01 0x90 /* 10010000b hires gfx pixels 01 */
#define G10 0xa0 /* 10100000b hires gfx pixels 10 */
#define G11 0xb0 /* 10110000b hires gfx pixels 11 */
#define GT1 0xc0 /* 11000000b gtia mode 1 */
#define GT2 0xd0 /* 11010000b gtia mode 2 */
#define GT3 0xe0 /* 11100000b gtia mode 3 */
#define ILL 0xfe /* 11111110b illegal priority */
#define EOR 0xff /* 11111111b EOR mode color */
#define LUM 0x0f /* 00001111b luminance bits */
#define HUE 0xf0 /* 11110000b hue bits */
#define TRIGGER_VBLANK 64715
#define TRIGGER_STEAL 64716
#define TRIGGER_HSYNC 64717
/*****************************************************************************
* If your memcpy does not expand too well if you use it with constant
* size_t field, you might want to define these macros somehow different.
* NOTE: dst is not necessarily uint32_t aligned (because of horz scrolling)!
*****************************************************************************/
#define COPY4(dst,s1) *dst++ = s1
#define COPY8(dst,s1,s2) *dst++ = s1; *dst++ = s2
#define COPY16(dst,s1,s2,s3,s4) *dst++ = s1; *dst++ = s2; *dst++ = s3; *dst++ = s4
#define RDANTIC(space) space.read_byte(m_dpage+m_doffs)
#define RDVIDEO(space,o) space.read_byte(m_vpage+((m_voffs+(o))&VOFFS))
#define RDCHGEN(space,o) space.read_byte(m_chbase+(o))
#define RDPMGFXS(space,o) space.read_byte(m_pmbase_s+(o)+(m_scanline>>1))
#define RDPMGFXD(space,o) space.read_byte(m_pmbase_d+(o)+m_scanline)
#define PREPARE() \
uint32_t *dst = (uint32_t *)&m_cclock[PMOFFSET]
#define PREPARE_TXT2(space,width) \
uint32_t *dst = (uint32_t *)&m_cclock[PMOFFSET]; \
for (int i = 0; i < width; i++) \
{ \
uint16_t ch = RDVIDEO(space,i) << 3; \
if (ch & 0x400) \
{ \
ch = RDCHGEN(space,(ch & 0x3f8) + m_w.chbasl); \
ch = (ch ^ m_chxor) & m_chand; \
} \
else \
{ \
ch = RDCHGEN(space,ch + m_w.chbasl); \
} \
video->data[i] = ch; \
}
#define PREPARE_TXT3(space,width) \
uint32_t *dst = (uint32_t *)&m_cclock[PMOFFSET]; \
for (int i = 0; i < width; i++) \
{ \
uint16_t ch = RDVIDEO(space,i) << 3; \
if (ch & 0x400) \
{ \
ch &= 0x3f8; \
if ((ch & 0x300) == 0x300) \
{ \
if (m_w.chbasl < 2) /* first two lines empty */ \
ch = 0x00; \
else /* lines 2..7 are standard, 8&9 are 0&1 */ \
ch = RDCHGEN(space,ch + (m_w.chbasl & 7));\
} \
else \
{ \
if (m_w.chbasl > 7) /* last two lines empty */ \
ch = 0x00; \
else /* lines 0..7 are standard */ \
ch = RDCHGEN(space,ch + m_w.chbasl); \
} \
ch = (ch ^ m_chxor) & m_chand; \
} \
else \
{ \
if ((ch & 0x300) == 0x300) \
{ \
if (m_w.chbasl < 2) /* first two lines empty */ \
ch = 0x00; \
else /* lines 2..7 are standard, 8&9 are 0&1 */ \
ch = RDCHGEN(space,ch + (m_w.chbasl & 7));\
} \
else \
{ \
if (m_w.chbasl > 7) /* last two lines empty */ \
ch = 0x00; \
else /* lines 0..7 are standard */ \
ch = RDCHGEN(space,ch + m_w.chbasl); \
} \
} \
video->data[i] = ch; \
}
#define PREPARE_TXT45(space,width,shift) \
uint32_t *dst = (uint32_t *)&m_cclock[PMOFFSET]; \
for (int i = 0; i < width; i++) \
{ \
uint16_t ch = RDVIDEO(space,i) << 3; \
ch = ((ch>>2)&0x100)|RDCHGEN(space,(ch&0x3f8)+(m_w.chbasl>>shift)); \
video->data[i] = ch; \
}
#define PREPARE_TXT67(space,width,shift) \
uint32_t *dst = (uint32_t *)&m_cclock[PMOFFSET]; \
for (int i = 0; i < width; i++) \
{ \
uint16_t ch = RDVIDEO(space,i) << 3; \
ch = (ch&0x600)|(RDCHGEN(space,(ch&0x1f8)+(m_w.chbasl>>shift))<<1); \
video->data[i] = ch; \
}
#define PREPARE_GFX8(space,width) \
uint32_t *dst = (uint32_t *)&m_cclock[PMOFFSET]; \
for (int i = 0; i < width; i++) \
video->data[i] = RDVIDEO(space,i) << 2
#define PREPARE_GFX9BC(space,width) \
uint32_t *dst = (uint32_t *)&m_cclock[PMOFFSET]; \
for (int i = 0; i < width; i++) \
video->data[i] = RDVIDEO(space,i) << 1
#define PREPARE_GFXA(space,width) \
uint32_t *dst = (uint32_t *)&m_cclock[PMOFFSET]; \
for (int i = 0; i < width; i++) \
video->data[i] = RDVIDEO(space,i) << 1
#define PREPARE_GFXDE(space,width) \
uint32_t *dst = (uint32_t *)&m_cclock[PMOFFSET]; \
for (int i = 0; i < width; i++) \
video->data[i] = RDVIDEO(space,i)
#define PREPARE_GFXF(space,width) \
uint32_t *dst = (uint32_t *)&m_cclock[PMOFFSET]; \
for (int i = 0; i < width; i++) \
video->data[i] = RDVIDEO(space,i)
#define PREPARE_GFXG1(space,width) \
uint32_t *dst = (uint32_t *)&m_cclock[PMOFFSET]; \
for (int i = 0; i < width; i++) \
video->data[i] = RDVIDEO(space,i)
#define PREPARE_GFXG2(space,width) \
uint32_t *dst = (uint32_t *)&m_cclock[PMOFFSET]; \
for (int i = 0; i < width; i++) \
video->data[i] = RDVIDEO(space,i)
#define PREPARE_GFXG3(space,width) \
uint32_t *dst = (uint32_t *)&m_cclock[PMOFFSET]; \
for (int i = 0; i < width; i++) \
video->data[i] = RDVIDEO(space,i)
/******************************************************************
* common end of a single antic/gtia mode emulation function
******************************************************************/
#define POST() \
--m_modelines
#define POST_GFX(width) \
m_steal_cycles += width; \
if (--m_modelines == 0) \
m_voffs = (m_voffs + width) & VOFFS
#define POST_TXT(width) \
m_steal_cycles += width; \
if (--m_modelines == 0) \
m_voffs = (m_voffs + width) & VOFFS; \
else if (m_w.chactl & 4) \
m_w.chbasl--; \
else \
m_w.chbasl++
/* erase a number of color clocks to background color PBK */
#define ERASE(size) \
for (int i = 0; i < size; i++) \
{ \
*dst++ = (PBK << 24) | (PBK << 16) | (PBK << 8) | PBK; \
}
#define ZAP48() \
dst = (uint32_t *)&antic.cclock[PMOFFSET]; \
dst[ 0] = (PBK << 24) | (PBK << 16) | (PBK << 8) | PBK; \
dst[ 1] = (PBK << 24) | (PBK << 16) | (PBK << 8) | PBK; \
dst[ 2] = (PBK << 24) | (PBK << 16) | (PBK << 8) | PBK; \
dst[45] = (PBK << 24) | (PBK << 16) | (PBK << 8) | PBK; \
dst[46] = (PBK << 24) | (PBK << 16) | (PBK << 8) | PBK; \
dst[47] = (PBK << 24) | (PBK << 16) | (PBK << 8) | PBK
#define REP(FUNC, size) \
for (int i = 0; i < size; i++) \
{ \
FUNC(i); \
}
constexpr unsigned antic_device::TOTAL_LINES_60HZ;
constexpr unsigned antic_device::TOTAL_LINES_50HZ;
constexpr double antic_device::FRAME_RATE_50HZ;
constexpr double antic_device::FRAME_RATE_60HZ;
// devices
DEFINE_DEVICE_TYPE(ATARI_ANTIC, antic_device, "antic", "Atari ANTIC")
//-------------------------------------------------
// antic_device - constructor
//-------------------------------------------------
antic_device::antic_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
device_t(mconfig, ATARI_ANTIC, tag, owner, clock),
device_video_interface(mconfig, *this),
m_gtia(*this, finder_base::DUMMY_TAG),
m_maincpu(*this, ":maincpu"),
m_djoy_b(*this, ":djoy_b"),
m_artifacts(*this, ":artifacts"),
m_tv_artifacts(0),
m_render1(0),
m_render2(0),
m_render3(0),
m_cmd(0),
m_steal_cycles(0),
m_vscrol_old(0),
m_hscrol_old(0),
m_modelines(0),
m_chbase(0),
m_chand(0),
m_chxor(0),
m_scanline(0),
m_pfwidth(0),
m_dpage(0),
m_doffs(0),
m_vpage(0),
m_voffs(0),
m_pmbase_s(0),
m_pmbase_d(0)
{
}
//-------------------------------------------------
// device_start - device-specific startup
//-------------------------------------------------
void antic_device::device_start()
{
m_bitmap = std::make_unique<bitmap_ind16>(screen().width(), screen().height());
m_cclk_expand = make_unique_clear<uint32_t[]>(21 * 256);
m_pf_21 = &m_cclk_expand[ 0 * 256];
m_pf_x10b = &m_cclk_expand[ 1 * 256];
m_pf_3210b2 = &m_cclk_expand[ 3 * 256];
m_pf_210b4 = &m_cclk_expand[11 * 256];
m_pf_210b2 = &m_cclk_expand[15 * 256];
m_pf_1b = &m_cclk_expand[17 * 256];
m_pf_gtia1 = &m_cclk_expand[18 * 256];
m_pf_gtia2 = &m_cclk_expand[19 * 256];
m_pf_gtia3 = &m_cclk_expand[20 * 256];
m_used_colors = std::make_unique<uint8_t[]>(21 * 256);
memset(m_used_colors.get(), 0, 21 * 256 * sizeof(uint8_t));
m_uc_21 = &m_used_colors[ 0 * 256];
m_uc_x10b = &m_used_colors[ 1 * 256];
m_uc_3210b2 = &m_used_colors[ 3 * 256];
m_uc_210b4 = &m_used_colors[11 * 256];
m_uc_210b2 = &m_used_colors[15 * 256];
m_uc_1b = &m_used_colors[17 * 256];
m_uc_g1 = &m_used_colors[18 * 256];
m_uc_g2 = &m_used_colors[19 * 256];
m_uc_g3 = &m_used_colors[20 * 256];
LOG(("atari cclk_init\n"));
cclk_init();
for (auto & elem : m_prio_table)
elem = make_unique_clear<uint8_t[]>(8*256);
LOG(("atari prio_init\n"));
prio_init();
for (int i = 0; i < screen().height(); i++)
m_video[i] = auto_alloc_clear(machine(), <VIDEO>());
/* save states */
save_pointer(NAME((uint8_t *) &m_r), sizeof(m_r));
save_pointer(NAME((uint8_t *) &m_w), sizeof(m_w));
// TODO: save VIDEO items
save_item(NAME(m_tv_artifacts));
save_item(NAME(m_render1));
save_item(NAME(m_render2));
save_item(NAME(m_render3));
save_item(NAME(m_cmd));
save_item(NAME(m_steal_cycles));
save_item(NAME(m_vscrol_old));
save_item(NAME(m_hscrol_old));
save_item(NAME(m_modelines));
save_item(NAME(m_chbase));
save_item(NAME(m_chand));
save_item(NAME(m_chxor));
save_item(NAME(m_scanline));
save_item(NAME(m_pfwidth));
save_item(NAME(m_dpage));
save_item(NAME(m_doffs));
save_item(NAME(m_vpage));
save_item(NAME(m_voffs));
save_item(NAME(m_pmbase_s));
save_item(NAME(m_pmbase_d));
save_item(NAME(m_cclock));
save_item(NAME(m_pmbits));
save_pointer(NAME(m_cclk_expand), 21 * 256);
save_pointer(NAME(m_used_colors), 21 * 256);
}
//-------------------------------------------------
// device_reset - device-specific reset
//-------------------------------------------------
void antic_device::device_reset()
{
/* reset the ANTIC read / write registers */
memset(&m_r, 0, sizeof(m_r));
memset(&m_w, 0, sizeof(m_w));
m_r.antic00 = 0xff;
m_r.antic01 = 0xff;
m_r.antic02 = 0xff;
m_r.antic03 = 0xff;
m_r.antic04 = 0xff;
m_r.antic05 = 0xff;
m_r.antic06 = 0xff;
m_r.antic07 = 0xff;
m_r.antic08 = 0xff;
m_r.antic09 = 0xff;
m_r.antic0a = 0xff;
m_r.penh = 0x00;
m_r.penv = 0x00;
m_r.antic0e = 0xff;
m_r.nmist = 0x1f;
memset(m_cclock, 0, sizeof(m_cclock));
memset(m_pmbits, 0, sizeof(m_pmbits));
}
/*************************************************************************
* The priority tables tell which playfield, player or missile colors
* have precedence about the others, depending on the contents of the
* "prior" register. There are 64 possible priority selections.
* The table is here to make it easier to build the 'illegal' priority
* combinations that produce black or 'ILL' color.
*************************************************************************/
/*************************************************************************
* calculate player/missile priorities (GTIA prior at $D00D)
* prior color priorities in descending order
* ------------------------------------------------------------------
* bit 0 PL0 PL1 PL2 PL3 PF0 PF1 PF2 PF3/P4 BK
* all players in front of all playfield colors
* bit 1 PL0 PL1 PF0 PF1 PF2 PF3/P4 PL2 PL3 BK
* pl 0+1 in front of pf 0-3 in front of pl 2+3
* bit 2 PF0 PF1 PF2 PF3/P4 PL0 PL1 PL2 PL3 BK
* all playfield colors in front of all players
* bit 3 PF0 PF1 PL0 PL1 PL2 PL3 PF2 PF3/P4 BK
* pf 0+1 in front of all players in front of pf 2+3
* bit 4 missiles colors are PF3 (P4)
* missiles have the same priority as pf3
* bit 5 PL0+PL1 and PL2+PL3 bits xored
* 00: playfield, 01: PL0/2, 10: PL1/3 11: black (EOR)
* bit 7+6 CTIA mod (00) or GTIA mode 1 to 3 (01, 10, 11)
*************************************************************************/
/* player/missile #4 color is equal to playfield #3 */
#define PM4 PF3
/* bit masks for players and missiles */
#define P0 0x01
#define P1 0x02
#define P2 0x04
#define P3 0x08
#define M0 0x10
#define M1 0x20
#define M2 0x40
#define M3 0x80
/************************************************************************
* Contents of the following table:
*
* PL0 -PL3 are the player/missile colors 0 to 3
* P000-P011 are the 4 available color clocks for playfield color 0
* P100-P111 are the 4 available color clocks for playfield color 1
* P200-P211 are the 4 available color clocks for playfield color 2
* P300-P311 are the 4 available color clocks for playfield color 3
* ILL is some undefined color. On my 800XL it looked light yellow ;)
*
* Each line holds the 8 bitmasks and resulting colors for player and
* missile number 0 to 3 in their fixed priority order.
* The 8 lines per block are for the 8 available playfield colors.
* Yes, 8 colors because the text modes 2,3 and graphics mode F can
* be combined with players. The result is the players color with
* luminance of the modes foreground (ie. colpf1).
* Any combination of players/missiles (256) is checked for the highest
* priority player or missile and the resulting color is stored into
* m_prio_table. The second part (20-3F) contains the resulting
* color values for the EOR mode, which is derived from the *visible*
* player/missile colors calculated for the first part (00-1F).
* The priorities of combining priority bits (which games use!) are:
************************************************************************/
static const uint8_t _pm_colors[32][8*2*8] = {
{
M0, PL0,P0, PL0,M1, PL1,P1, PL1,M2, PL2,P2, PL2,M3, PL3,P3, PL3, // 00
M0, PL0,P0, PL0,M1, PL1,P1, PL1,M2, PL2,P2, PL2,M3, PL3,P3, PL3,
M0, PL0,P0, PL0,M1, PL1,P1, PL1,M2, PL2,P2, PL2,M3, PL3,P3, PL3,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
M0,P000,P0,P000,M1,P100,P1,P100,M2,P200,P2,P200,M3,P300,P3,P300,
M0,P001,P0,P001,M1,P101,P1,P101,M2,P201,P2,P201,M3,P301,P3,P301,
M0,P010,P0,P010,M1,P110,P1,P110,M2,P210,P2,P210,M3,P310,P3,P310,
M0,P011,P0,P011,M1,P111,P1,P111,M2,P211,P2,P211,M3,P311,P3,P311
},
{
M0, PL0,P0, PL0,M1, PL1,P1, PL1,M2, PL2,P2, PL2,M3, PL3,P3, PL3, // 01
M0, PL0,P0, PL0,M1, PL1,P1, PL1,M2, PL2,P2, PL2,M3, PL3,P3, PL3,
M0, PL0,P0, PL0,M1, PL1,P1, PL1,M2, PL2,P2, PL2,M3, PL3,P3, PL3,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
M0,P000,P0,P000,M1,P100,P1,P100,M2,P200,P2,P200,M3,P300,P3,P300,
M0,P001,P0,P001,M1,P101,P1,P101,M2,P201,P2,P201,M3,P301,P3,P301,
M0,P010,P0,P010,M1,P110,P1,P110,M2,P210,P2,P210,M3,P310,P3,P310,
M0,P011,P0,P011,M1,P111,P1,P111,M2,P211,P2,P211,M3,P311,P3,P311
},
{
M0, PL0,P0, PL0,M1, PL1,P1, PL1,M2, PL2,P2, PL2,M3, PL3,P3, PL3, // 02
M0, PL0,P0, PL0,M1, PL1,P1, PL1,M2, 0,P2, 0,M3, 0,P3, 0,
M0, PL0,P0, PL0,M1, PL1,P1, PL1,M2, 0,P2, 0,M3, 0,P3, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
M0,P000,P0,P000,M1,P100,P1,P100,M2,P200,P2,P200,M3,P300,P3,P300,
M0,P001,P0,P001,M1,P101,P1,P101,M2,P201,P2,P201,M3,P301,P3,P301,
M0,P010,P0,P010,M1,P110,P1,P110,M2,P210,P2,P210,M3,P310,P3,P310,
M0,P011,P0,P011,M1,P111,P1,P111,M2,P211,P2,P211,M3,P311,P3,P311
},
{
M0, PL0,P0, PL0,M1, PL1,P1, PL1,M2, PL2,P2, PL2,M3, PL3,P3, PL3, // 03
M0, PL0,P0, PL0,M1, PL1,P1, PL1,M2, PL2,P2, PL2,M3, PL3,P3, PL3,
M0, PL0,P0, PL0,M1, PL1,P1, PL1,M2, ILL,P2, ILL,M3, ILL,P3, ILL,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
M0,P000,P0,P000,M1,P100,P1,P100,M2,P200,P2,P200,M3,P300,P3,P300,
M0,P001,P0,P001,M1,P101,P1,P101,M2,P201,P2,P201,M3,P301,P3,P301,
M0,P010,P0,P010,M1,P110,P1,P110,M2,P210,P2,P210,M3,P310,P3,P310,
M0,P011,P0,P011,M1,P111,P1,P111,M2,P211,P2,P211,M3,P311,P3,P311
},
{
M0, PL0,P0, PL0,M1, PL1,P1, PL1,M2, PL2,P2, PL2,M3, PL3,P3, PL3, // 04
M0, 0,P0, 0,M1, 0,P1, 0,M2, 0,P2, 0,M3, 0,P3, 0,
M0, 0,P0, 0,M1, 0,P1, 0,M2, 0,P2, 0,M3, 0,P3, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
M0,P000,P0,P000,M1,P100,P1,P100,M2,P200,P2,P200,M3,P300,P3,P300,
M0,P001,P0,P001,M1,P101,P1,P101,M2,P201,P2,P201,M3,P301,P3,P301,
M0,P010,P0,P010,M1,P110,P1,P110,M2,P210,P2,P210,M3,P310,P3,P310,
M0,P011,P0,P011,M1,P111,P1,P111,M2,P211,P2,P211,M3,P311,P3,P311
},
{
M0, PL0,P0, PL0,M1, PL1,P1, PL1,M2, PL2,P2, PL2,M3, PL3,P3, PL3, // 05
M0, ILL,P0, ILL,M1, ILL,P1, ILL,M2, PL2,P2, PL2,M3, PL3,P3, PL3,
M0, 0,P0, 0,M1, 0,P1, 0,M2, ILL,P2, ILL,M3, ILL,P3, ILL,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
M0,P000,P0,P000,M1,P100,P1,P100,M2,P200,P2,P200,M3,P300,P3,P300,
M0,P001,P0,P001,M1,P101,P1,P101,M2,P201,P2,P201,M3,P301,P3,P301,
M0,P010,P0,P010,M1,P110,P1,P110,M2,P210,P2,P210,M3,P310,P3,P310,
M0,P011,P0,P011,M1,P111,P1,P111,M2,P211,P2,P211,M3,P311,P3,P311
},
{
M0, PL0,P0, PL0,M1, PL1,P1, PL1,M2, PL2,P2, PL2,M3, PL3,P3, PL3, // 06
M0, 0,P0, ILL,M1, 0,P1, ILL,M2, 0,P2, 0,M3, 0,P3, 0,
M0, 0,P0, 0,M1, 0,P1, 0,M2, 0,P2, 0,M3, 0,P3, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
M0,P000,P0,P000,M1,P100,P1,P100,M2,P200,P2,P200,M3,P300,P3,P300,
M0,P001,P0,P001,M1,P101,P1,P101,M2,P201,P2,P201,M3,P301,P3,P301,
M0,P010,P0,P010,M1,P110,P1,P110,M2,P210,P2,P210,M3,P310,P3,P310,
M0,P011,P0,P011,M1,P111,P1,P111,M2,P211,P2,P211,M3,P311,P3,P311
},
{
M0, PL0,P0, PL0,M1, PL1,P1, PL1,M2, PL2,P2, PL2,M3, PL3,P3, PL3, // 07
M0, ILL,P0, ILL,M1, ILL,P1, ILL,M2, PL2,P2, PL2,M3, PL3,P3, PL3,
M0, 0,P0, 0,M1, 0,P1, 0,M2, ILL,P2, ILL,M3, ILL,P3, ILL,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
M0,P000,P0,P000,M1,P100,P1,P100,M2,P200,P2,P200,M3,P300,P3,P300,
M0,P001,P0,P001,M1,P101,P1,P101,M2,P201,P2,P201,M3,P301,P3,P301,
M0,P010,P0,P010,M1,P110,P1,P110,M2,P210,P2,P210,M3,P310,P3,P310,
M0,P011,P0,P011,M1,P111,P1,P111,M2,P211,P2,P211,M3,P311,P3,P311
},
{
M0, PL0,P0, PL0,M1, PL1,P1, PL1,M2, PL2,P2, PL2,M3, PL3,P3, PL3, // 08
M0, 0,P0, 0,M1, 0,P1, 0,M2, 0,P2, 0,M3, 0,P3, 0,
M0, PL0,P0, PL0,M1, PL1,P1, PL1,M2, PL2,P2, PL2,M3, PL3,P3, PL3,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
M0,P000,P0,P000,M1,P100,P1,P100,M2,P200,P2,P200,M3,P300,P3,P300,
M0,P001,P0,P001,M1,P101,P1,P101,M2,P201,P2,P201,M3,P301,P3,P301,
M0,P010,P0,P010,M1,P110,P1,P110,M2,P210,P2,P210,M3,P310,P3,P310,
M0,P011,P0,P011,M1,P111,P1,P111,M2,P211,P2,P211,M3,P311,P3,P311
},
{
M0, PL0,P0, PL0,M1, PL1,P1, PL1,M2, PL2,P2, PL2,M3, PL3,P3, PL3, // 09
M0, ILL,P0, ILL,M1, ILL,P1, ILL,M2, PL2,P2, PL2,M3, PL3,P3, PL3,
M0, PL0,P0, PL0,M1, PL1,P1, PL1,M2, PL2,P2, PL2,M3, PL3,P3, PL3,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
M0,P000,P0,P000,M1,P100,P1,P100,M2,P200,P2,P200,M3,P300,P3,P300,
M0,P001,P0,P001,M1,P101,P1,P101,M2,P201,P2,P201,M3,P301,P3,P301,
M0,P010,P0,P010,M1,P110,P1,P110,M2,P210,P2,P210,M3,P310,P3,P310,
M0,P011,P0,P011,M1,P111,P1,P111,M2,P211,P2,P211,M3,P311,P3,P311
},
{
M0, PL0,P0, PL0,M1, PL1,P1, PL1,M2, PL2,P2, PL2,M3, PL3,P3, PL3, // 0A
M0, ILL,P0, ILL,M1, ILL,P1, ILL,M2, 0,P2, 0,M3, 0,P3, 0,
M0, PL0,P0, PL0,M1, PL1,P1, PL1,M2, ILL,P2, ILL,M3, ILL,P3, ILL,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
M0,P000,P0,P000,M1,P100,P1,P100,M2,P200,P2,P200,M3,P300,P3,P300,
M0,P001,P0,P001,M1,P101,P1,P101,M2,P201,P2,P201,M3,P301,P3,P301,
M0,P010,P0,P010,M1,P110,P1,P110,M2,P210,P2,P210,M3,P310,P3,P310,
M0,P011,P0,P011,M1,P111,P1,P111,M2,P211,P2,P211,M3,P311,P3,P311
},
{
M0, PL0,P0, PL0,M1, PL1,P1, PL1,M2, PL2,P2, PL2,M3, PL3,P3, PL3, // 0B
M0, ILL,P0, ILL,M1, ILL,P1, ILL,M2, PL2,P2, PL2,M3, PL3,P3, PL3,
M0, PL0,P0, PL0,M1, PL1,P1, PL1,M2, ILL,P2, ILL,M3, ILL,P3, ILL,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
M0,P000,P0,P000,M1,P100,P1,P100,M2,P200,P2,P200,M3,P300,P3,P300,
M0,P001,P0,P001,M1,P101,P1,P101,M2,P201,P2,P201,M3,P301,P3,P301,
M0,P010,P0,P010,M1,P110,P1,P110,M2,P210,P2,P210,M3,P310,P3,P310,
M0,P011,P0,P011,M1,P111,P1,P111,M2,P211,P2,P211,M3,P311,P3,P311
},
{
M0, PL0,P0, PL0,M1, PL1,P1, PL1,M2, PL2,P2, PL2,M3, PL3,P3, PL3, // 0C
M0, 0,P0, 0,M1, 0,P1, 0,M2, 0,P2, 0,M3, 0,P3, 0,
M0, 0,P0, 0,M1, 0,P1, 0,M2, ILL,P2, ILL,M3, ILL,P3, ILL,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
M0,P000,P0,P000,M1,P100,P1,P100,M2,P200,P2,P200,M3,P300,P3,P300,
M0,P001,P0,P001,M1,P101,P1,P101,M2,P201,P2,P201,M3,P301,P3,P301,
M0,P010,P0,P010,M1,P110,P1,P110,M2,P210,P2,P210,M3,P310,P3,P310,
M0,P011,P0,P011,M1,P111,P1,P111,M2,P211,P2,P211,M3,P311,P3,P311
},
{
M0, PL0,P0, PL0,M1, PL1,P1, PL1,M2, PL2,P2, PL2,M3, PL3,P3, PL3, // 0D
M0, 0,P0, 0,M1, 0,P1, 0,M2, PL2,P2, PL2,M3, PL3,P3, PL3,
M0, 0,P0, 0,M1, 0,P1, 0,M2, ILL,P2, ILL,M3, ILL,P3, ILL,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
M0,P000,P0,P000,M1,P100,P1,P100,M2,P200,P2,P200,M3,P300,P3,P300,
M0,P001,P0,P001,M1,P101,P1,P101,M2,P201,P2,P201,M3,P301,P3,P301,
M0,P010,P0,P010,M1,P110,P1,P110,M2,P210,P2,P210,M3,P310,P3,P310,
M0,P011,P0,P011,M1,P111,P1,P111,M2,P211,P2,P211,M3,P311,P3,P311
},
{
M0, PL0,P0, PL0,M1, PL1,P1, PL1,M2, PL2,P2, PL2,M3, PL3,P3, PL3, // 0E
M0, 0,P0, 0,M1, 0,P1, 0,M2, 0,P2, 0,M3, 0,P3, 0,
M0, 0,P0, 0,M1, 0,P1, 0,M2, ILL,P2, ILL,M3, ILL,P3, ILL,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
M0,P000,P0,P000,M1,P100,P1,P100,M2,P200,P2,P200,M3,P300,P3,P300,
M0,P001,P0,P001,M1,P101,P1,P101,M2,P201,P2,P201,M3,P301,P3,P301,
M0,P010,P0,P010,M1,P110,P1,P110,M2,P210,P2,P210,M3,P310,P3,P310,
M0,P011,P0,P011,M1,P111,P1,P111,M2,P211,P2,P211,M3,P311,P3,P311
},
{
M0, PL0,P0, PL0,M1, PL1,P1, PL1,M2, PL2,P2, PL2,M3, PL3,P3, PL3, // 0F
M0, 0,P0, 0,M1, 0,P1, 0,M2, PL2,P2, PL2,M3, PL3,P3, PL3,
M0, 0,P0, 0,M1, 0,P1, 0,M2, ILL,P2, ILL,M3, ILL,P3, ILL,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
M0,P000,P0,P000,M1,P100,P1,P100,M2,P200,P2,P200,M3,P300,P3,P300,
M0,P001,P0,P001,M1,P101,P1,P101,M2,P201,P2,P201,M3,P301,P3,P301,
M0,P010,P0,P010,M1,P110,P1,P110,M2,P210,P2,P210,M3,P310,P3,P310,
M0,P011,P0,P011,M1,P111,P1,P111,M2,P211,P2,P211,M3,P311,P3,P311
},
{
P0, PL0,P1, PL1,P2, PL2,P3, PL3,M0, PM4,M1, PM4,M2, PM4,M3, PM4, // 10
P0, PL0,P1, PL1,P2, PL2,P3, PL3,M0, PM4,M1, PM4,M2, PM4,M3, PM4,
P0, PL0,P1, PL1,P2, PL2,P3, PL3,M0, PM4,M1, PM4,M2, PM4,M3, PM4,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
P0,P000,P1,P100,P2,P200,P3,P300,M0,P400,M1,P400,M2,P400,M3,P400,
P0,P001,P1,P101,P2,P201,P3,P301,M0,P401,M1,P401,M2,P401,M3,P401,
P0,P010,P1,P110,P2,P210,P3,P310,M0,P410,M1,P410,M2,P410,M3,P410,
P0,P011,P1,P111,P2,P211,P3,P311,M0,P411,M1,P411,M2,P411,M3,P411
},
{
P0, PL0,P1, PL1,P2, PL2,P3, PL3,M0, PM4,M1, PM4,M2, PM4,M3, PM4, // 11
P0, PL0,P1, PL1,P2, PL2,P3, PL3,M0, PM4,M1, PM4,M2, PM4,M3, PM4,
P0, PL0,P1, PL1,P2, PL2,P3, PL3,M0, PM4,M1, PM4,M2, PM4,M3, PM4,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
P0,P000,P1,P100,P2,P200,P3,P300,M0,P400,M1,P400,M2,P400,M3,P400,
P0,P001,P1,P101,P2,P201,P3,P301,M0,P401,M1,P401,M2,P401,M3,P401,
P0,P010,P1,P110,P2,P210,P3,P310,M0,P410,M1,P410,M2,P410,M3,P410,
P0,P011,P1,P111,P2,P211,P3,P311,M0,P411,M1,P411,M2,P411,M3,P411
},
{
P0, PL0,P1, PL1,M0, PM4,M1, PM4,M2, PM4,M3, PM4,P2, PL2,P3, PL3, // 12
P0, PL0,P1, PL1,M0, PM4,M1, PM4,M2, PM4,M3, PM4,P2, 0,P3, 0,
P0, PL0,P1, PL1,M0, PM4,M1, PM4,M2, PM4,M3, PM4,P2, 0,P3, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
P0,P000,P1,P100,M0,P400,M1,P400,M2,P400,M3,P400,P2,P200,P3,P300,
P0,P001,P1,P101,M0,P401,M1,P401,M2,P401,M3,P401,P2,P201,P3,P301,
P0,P010,P1,P110,M0,P410,M1,P410,M2,P410,M3,P410,P2,P210,P3,P310,
P0,P011,P1,P111,M0,P411,M1,P411,M2,P411,M3,P411,P2,P211,P3,P311
},
{
P0, PL0,P1, PL1,M0, PM4,M1, PM4,M2, PM4,M3, PM4,P2, PL2,P3, PL3, // 13
P0, PL0,P1, PL1,M0, PM4,M1, PM4,M2, PM4,M3, PM4,P2, PL2,P3, PL3,
P0, PL0,P1, PL1,M0, PM4,M1, PM4,M2, PM4,M3, PM4,P2, ILL,P3, ILL,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
P0,P000,P1,P100,M0,P400,M1,P400,M2,P400,M3,P400,P2,P200,P3,P300,
P0,P001,P1,P101,M0,P401,M1,P401,M2,P401,M3,P401,P2,P201,P3,P301,
P0,P010,P1,P110,M0,P410,M1,P410,M2,P410,M3,P410,P2,P210,P3,P310,
P0,P011,P1,P111,M0,P411,M1,P411,M2,P411,M3,P411,P2,P211,P3,P311
},
{
M0, PM4,M1, PM4,M2, PM4,M3, PM4,P0, PL0,P1, PL1,P2, PL2,P3, PL3, // 14
M0, PM4,M1, PM4,M2, PM4,M3, PM4,P0, 0,P1, 0,P2, 0,P3, 0,
M0, PM4,M1, PM4,M2, PM4,M3, PM4,P0, 0,P1, 0,P2, 0,P3, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
M0,P400,M1,P400,M2,P400,M3,P400,P0,P000,P1,P100,P2,P200,P3,P300,
M0,P401,M1,P401,M2,P401,M3,P401,P0,P001,P1,P101,P2,P201,P3,P301,
M0,P410,M1,P410,M2,P410,M3,P410,P0,P010,P1,P110,P2,P210,P3,P310,
M0,P411,M1,P411,M2,P411,M3,P411,P0,P011,P1,P111,P2,P211,P3,P311
},
{
M0, PM4,M1, PM4,M2, PM4,M3, PM4,P2,P0, PL0,P1, PL1, PL2,P3, PL3, // 15
M0, PM4,M1, PM4,M2, PM4,M3, PM4,P2,P0, ILL,P1, ILL, PL2,P3, PL3,
M0, PM4,M1, PM4,M2, PM4,M3, PM4,P2,P0, 0,P1, 0, ILL,P3, ILL,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
M0,P000,M1,P100,M2,P200,M3,P300,P2,P0,P000,P1,P100,P200,P3,P300,
M0,P001,M1,P101,M2,P201,M3,P301,P2,P0,P001,P1,P101,P201,P3,P301,
M0,P010,M1,P110,M2,P210,M3,P310,P2,P0,P010,P1,P110,P210,P3,P310,
M0,P011,M1,P111,M2,P211,M3,P311,P2,P0,P011,P1,P111,P211,P3,P311
},
{
M0, PM4,M1, PM4,M2, PM4,M3, PM4,P0, PL0,P1, PL1,P2, PL2,P3, PL3, // 16
M0, PM4,M1, PM4,M2, PM4,M3, PM4,P0, ILL,P1, ILL,P2, 0,P3, 0,
M0, PM4,M1, PM4,M2, PM4,M3, PM4,P0, 0,P1, 0,P2, 0,P3, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
M0,P000,M1,P100,M2,P200,M3,P300,P0,P000,P1,P100,P2,P200,P3,P300,
M0,P001,M1,P101,M2,P201,M3,P301,P0,P001,P1,P101,P2,P201,P3,P301,
M0,P010,M1,P110,M2,P210,M3,P310,P0,P010,P1,P110,P2,P210,P3,P310,
M0,P011,M1,P111,M2,P211,M3,P311,P0,P011,P1,P111,P2,P211,P3,P311
},
{
M0, PM4,M1, PM4,M2, PM4,M3, PM4,P2,P0, PL0,P1, PL1, PL2,P3, PL3, // 17
M0, PM4,M1, PM4,M2, PM4,M3, PM4,P2,P0, ILL,P1, ILL, PL2,P3, PL3,
M0, PM4,M1, PM4,M2, PM4,M3, PM4,P2,P0, 0,P1, 0, ILL,P3, ILL,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
M0,P000,M1,P100,M2,P200,M3,P300,P2,P0,P000,P1,P100,P200,P3,P300,
M0,P001,M1,P101,M2,P201,M3,P301,P2,P0,P001,P1,P101,P201,P3,P301,
M0,P010,M1,P110,M2,P210,M3,P310,P2,P0,P010,P1,P110,P210,P3,P310,
M0,P011,M1,P111,M2,P211,M3,P311,P2,P0,P011,P1,P111,P211,P3,P311
},
{
P0, PL0,P1, PL1,P2, PL2,P3, PL3,M0, PM4,M1, PM4,M2, PM4,M3, PM4, // 18
P0, PL0,P1, PL1,P2, PL2,P3, PL3,M0, PM4,M1, PM4,M2, PM4,M3, PM4,
P0, PL0,P1, PL1,P2, PL2,P3, PL3,M0, PM4,M1, PM4,M2, PM4,M3, PM4,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
P0,P000,P1,P100,P2,P200,P3,P300,M0,P400,M1,P400,M2,P400,M3,P400,
P0,P001,P1,P101,P2,P201,P3,P301,M0,P401,M1,P401,M2,P401,M3,P401,
P0,P010,P1,P110,P2,P210,P3,P310,M0,P410,M1,P410,M2,P410,M3,P410,
P0,P011,P1,P111,P2,P211,P3,P311,M0,P411,M1,P411,M2,P411,M3,P411
},
{
P0, PL0,P1, PL1,P2, PL2,P3, PL3,M0, PM4,M1, PM4,M2, PM4,M3, PM4, // 19
P0, ILL,P1, ILL,P2, PL2,P3, PL3,M0, PM4,M1, PM4,M2, PM4,M3, PM4,
P0, PL0,P1, PL1,P2, PL2,P3, PL3,M0, PM4,M1, PM4,M2, PM4,M3, PM4,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
P0,P000,P1,P100,P2,P200,P3,P300,M0,P000,M1,P100,M2,P200,M3,P300,
P0,P001,P1,P101,P2,P201,P3,P301,M0,P001,M1,P101,M2,P201,M3,P301,
P0,P010,P1,P110,P2,P210,P3,P310,M0,P010,M1,P110,M2,P210,M3,P310,
P0,P011,P1,P111,P2,P211,P3,P311,M0,P011,M1,P111,M2,P211,M3,P311
},
{
P0, PL0,P1, PL1,P2, PL2,P3, PL3,M0, PM4,M1, PM4,M2, PM4,M3, PM4, // 1A
P0, ILL,P1, ILL,P2, 0,P3, 0,M0, PM4,M1, PM4,M2, PM4,M3, PM4,
P0, PL0,P1, PL1,P2, ILL,P3, ILL,M0, PM4,M1, PM4,M2, PM4,M3, PM4,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
P0,P000,P1,P100,P2,P200,P3,P300,M0,P400,M1,P400,M2,P400,M3,P400,
P0,P001,P1,P101,P2,P201,P3,P301,M0,P401,M1,P401,M2,P401,M3,P401,
P0,P010,P1,P110,P2,P210,P3,P310,M0,P410,M1,P410,M2,P410,M3,P410,
P0,P011,P1,P111,P2,P211,P3,P311,M0,P411,M1,P411,M2,P411,M3,P411
},
{
P0, PL0,P1, PL1,P2, PL2,P3, PL3,M0, PM4,M1, PM4,M2, PM4,M3, PM4, // 1B
P0, ILL,P1, ILL,P2, PL2,P3, PL3,M0, PM4,M1, PM4,M2, PM4,M3, PM4,
P0, PL0,P1, PL1,P2, ILL,P3, ILL,M0, PM4,M1, PM4,M2, PM4,M3, PM4,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
P0,P000,P1,P100,P2,P200,P3,P300,M0,P400,M1,P400,M2,P400,M3,P400,
P0,P001,P1,P101,P2,P201,P3,P301,M0,P401,M1,P401,M2,P401,M3,P401,
P0,P010,P1,P110,P2,P210,P3,P310,M0,P410,M1,P410,M2,P410,M3,P410,
P0,P011,P1,P111,P2,P211,P3,P311,M0,P411,M1,P411,M2,P411,M3,P411
},
{
P0, PL0,P1, PL1,P2, PL2,P3, PL3,M0, PM4,M1, PM4,M2, PM4,M3, PM4, // 1C
P0, 0,P1, 0,P2, 0,P3, 0,M0, PM4,M1, PM4,M2, PM4,M3, PM4,
P0, 0,P1, 0,P2, ILL,P3, ILL,M0, PM4,M1, PM4,M2, PM4,M3, PM4,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
P0,P000,P1,P100,P2,P200,P3,P300,M0,P400,M1,P400,M2,P400,M3,P400,
P0,P001,P1,P101,P2,P201,P3,P301,M0,P401,M1,P401,M2,P401,M3,P401,
P0,P010,P1,P110,P2,P210,P3,P310,M0,P410,M1,P410,M2,P410,M3,P410,
P0,P011,P1,P111,P2,P211,P3,P311,M0,P411,M1,P411,M2,P411,M3,P411
},
{
P0, PL0,P1, PL1,P2, PL2,P3, PL3,M0, PM4,M1, PM4,M2, PM4,M3, PM4, // 1D
P0, 0,P1, 0,P2, PL2,P3, PL3,M0, PM4,M1, PM4,M2, PM4,M3, PM4,
P0, 0,P1, 0,P2, ILL,P3, ILL,M0, PM4,M1, PM4,M2, PM4,M3, PM4,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
P0,P000,P1,P100,P2,P200,P3,P300,M0,P400,M1,P400,M2,P400,M3,P400,
P0,P001,P1,P101,P2,P201,P3,P301,M0,P401,M1,P401,M2,P401,M3,P401,
P0,P010,P1,P110,P2,P210,P3,P310,M0,P410,M1,P410,M2,P410,M3,P410,
P0,P011,P1,P111,P2,P211,P3,P311,M0,P411,M1,P411,M2,P411,M3,P411
},
{
P0, PL0,P1, PL1,P2, PL2,P3, PL3,M0, PM4,M1, PM4,M2, PM4,M3, PM4, // 1E
P0, 0,P1, 0,P2, 0,P3, 0,M0, PM4,M1, PM4,M2, PM4,M3, PM4,
P0, 0,P1, 0,P2, ILL,P3, ILL,M0, PM4,M1, PM4,M2, PM4,M3, PM4,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
P0,P000,P1,P100,P2,P200,P3,P300,M0,P400,M1,P400,M2,P400,M3,P400,
P0,P001,P1,P101,P2,P201,P3,P301,M0,P401,M1,P401,M2,P401,M3,P401,
P0,P010,P1,P110,P2,P210,P3,P310,M0,P410,M1,P410,M2,P410,M3,P410,
P0,P011,P1,P111,P2,P211,P3,P311,M0,P411,M1,P411,M2,P411,M3,P411
},
{
P0, PL0,P1, PL1,P2, PL2,P3, PL3,M0, PM4,M1, PM4,M2, PM4,M3, PM4, // 1F
P0, 0,P1, 0,P2, 0,P3, 0,M0, PM4,M1, PM4,M2, PM4,M3, PM4,
P0, 0,P1, 0,P2, ILL,P3, ILL,M0, PM4,M1, PM4,M2, PM4,M3, PM4,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
P0,P000,P1,P100,P2,P200,P3,P300,M0,P400,M1,P400,M2,P400,M3,P400,
P0,P001,P1,P101,P2,P201,P3,P301,M0,P401,M1,P401,M2,P401,M3,P401,
P0,P010,P1,P110,P2,P210,P3,P310,M0,P410,M1,P410,M2,P410,M3,P410,
P0,P011,P1,P111,P2,P211,P3,P311,M0,P411,M1,P411,M2,P411,M3,P411
}
};
/************************************************************************
* prio_init
* Initialize player/missile priority lookup tables
************************************************************************/
void antic_device::prio_init()
{
int i, j, pm, p, c;
const uint8_t * prio;
/* 32 priority bit combinations */
for( i = 0; i < 32; i++ )
{
/* 8 playfield colors */
for( j = 0; j < 8; j++ )
{
prio = &_pm_colors[i][j*16];
/* 256 player/missile combinations to build */
for( pm = 0; pm < 256; pm++ )
{
c = PFD; /* assume playfield color */
for( p = 0; (c == PFD) && (p < 16); p += 2 )
{
if (((prio[p] & pm) == prio[p]) && (prio[p+1]))
c = prio[p+1];
}
m_prio_table[i][(j << 8) + pm] = c;
if( (c==PL0 || c==P000 || c==P001 || c==P010 || c==P011) &&
(pm & (P0+P1))==(P0+P1))
c = EOR;
if( (c==PL2 || c==P200 || c==P201 || c==P210 || c==P211) &&
(pm & (P2+P3))==(P2+P3))
c = EOR;
m_prio_table[32 + i][(j << 8) + pm] = c;
}
}
}
}
/************************************************************************
* cclk_init
* Initialize "color clock" lookup tables
************************************************************************/
void antic_device::cclk_init()
{
static const uint8_t _pf_21[4] = {T00,T01,T10,T11};
static const uint8_t _pf_1b[4] = {G00,G01,G10,G11};
static const uint8_t _pf_210b[4] = {PBK,PF0,PF1,PF2};
static const uint8_t _pf_310b[4] = {PBK,PF0,PF1,PF3};
int i;
uint8_t * dst;
/* setup color translation for the ANTIC modes */
for( i = 0; i < 256; i++ )
{
/****** text mode (2,3) **********/
dst = (uint8_t *)&m_pf_21[0x000+i];
*dst++ = _pf_21[(i>>6)&3];
*dst++ = _pf_21[(i>>4)&3];
*dst++ = _pf_21[(i>>2)&3];
*dst++ = _pf_21[(i>>0)&3];
/****** 4 color text (4,5) with pf2, D, E **********/
dst = (uint8_t *)&m_pf_x10b[0x000+i];
*dst++ = _pf_210b[(i>>6)&3];
*dst++ = _pf_210b[(i>>4)&3];
*dst++ = _pf_210b[(i>>2)&3];
*dst++ = _pf_210b[(i>>0)&3];
dst = (uint8_t *)&m_pf_x10b[0x100+i];
*dst++ = _pf_310b[(i>>6)&3];
*dst++ = _pf_310b[(i>>4)&3];
*dst++ = _pf_310b[(i>>2)&3];
*dst++ = _pf_310b[(i>>0)&3];
/****** pf0 color text (6,7), 9, B, C **********/
dst = (uint8_t *)&m_pf_3210b2[0x000+i*2];
*dst++ = (i&0x80)?PF0:PBK;
*dst++ = (i&0x40)?PF0:PBK;
*dst++ = (i&0x20)?PF0:PBK;
*dst++ = (i&0x10)?PF0:PBK;
*dst++ = (i&0x08)?PF0:PBK;
*dst++ = (i&0x04)?PF0:PBK;
*dst++ = (i&0x02)?PF0:PBK;
*dst++ = (i&0x01)?PF0:PBK;
/****** pf1 color text (6,7), 9, B, C **********/
dst = (uint8_t *)&m_pf_3210b2[0x200+i*2];
*dst++ = (i&0x80)?PF1:PBK;
*dst++ = (i&0x40)?PF1:PBK;
*dst++ = (i&0x20)?PF1:PBK;
*dst++ = (i&0x10)?PF1:PBK;
*dst++ = (i&0x08)?PF1:PBK;
*dst++ = (i&0x04)?PF1:PBK;
*dst++ = (i&0x02)?PF1:PBK;
*dst++ = (i&0x01)?PF1:PBK;
/****** pf2 color text (6,7), 9, B, C **********/
dst = (uint8_t *)&m_pf_3210b2[0x400+i*2];
*dst++ = (i&0x80)?PF2:PBK;
*dst++ = (i&0x40)?PF2:PBK;
*dst++ = (i&0x20)?PF2:PBK;
*dst++ = (i&0x10)?PF2:PBK;
*dst++ = (i&0x08)?PF2:PBK;
*dst++ = (i&0x04)?PF2:PBK;
*dst++ = (i&0x02)?PF2:PBK;
*dst++ = (i&0x01)?PF2:PBK;
/****** pf3 color text (6,7), 9, B, C **********/
dst = (uint8_t *)&m_pf_3210b2[0x600+i*2];
*dst++ = (i&0x80)?PF3:PBK;
*dst++ = (i&0x40)?PF3:PBK;
*dst++ = (i&0x20)?PF3:PBK;
*dst++ = (i&0x10)?PF3:PBK;
*dst++ = (i&0x08)?PF3:PBK;
*dst++ = (i&0x04)?PF3:PBK;
*dst++ = (i&0x02)?PF3:PBK;
*dst++ = (i&0x01)?PF3:PBK;
/****** 4 color graphics 4 cclks (8) **********/
dst = (uint8_t *)&m_pf_210b4[i*4];
*dst++ = _pf_210b[(i>>6)&3];
*dst++ = _pf_210b[(i>>6)&3];
*dst++ = _pf_210b[(i>>6)&3];
*dst++ = _pf_210b[(i>>6)&3];
*dst++ = _pf_210b[(i>>4)&3];
*dst++ = _pf_210b[(i>>4)&3];
*dst++ = _pf_210b[(i>>4)&3];
*dst++ = _pf_210b[(i>>4)&3];
*dst++ = _pf_210b[(i>>2)&3];
*dst++ = _pf_210b[(i>>2)&3];
*dst++ = _pf_210b[(i>>2)&3];
*dst++ = _pf_210b[(i>>2)&3];
*dst++ = _pf_210b[(i>>0)&3];
*dst++ = _pf_210b[(i>>0)&3];
*dst++ = _pf_210b[(i>>0)&3];
*dst++ = _pf_210b[(i>>0)&3];
/****** 4 color graphics 2 cclks (A) **********/
dst = (uint8_t *)&m_pf_210b2[i*2];
*dst++ = _pf_210b[(i>>6)&3];
*dst++ = _pf_210b[(i>>6)&3];
*dst++ = _pf_210b[(i>>4)&3];
*dst++ = _pf_210b[(i>>4)&3];
*dst++ = _pf_210b[(i>>2)&3];
*dst++ = _pf_210b[(i>>2)&3];
*dst++ = _pf_210b[(i>>0)&3];
*dst++ = _pf_210b[(i>>0)&3];
/****** high resolution graphics (F) **********/
dst = (uint8_t *)&m_pf_1b[i];
*dst++ = _pf_1b[(i>>6)&3];
*dst++ = _pf_1b[(i>>4)&3];
*dst++ = _pf_1b[(i>>2)&3];
*dst++ = _pf_1b[(i>>0)&3];
/****** gtia mode 1 **********/
dst = (uint8_t *)&m_pf_gtia1[i];
*dst++ = GT1+((i>>4)&15);
*dst++ = GT1+((i>>4)&15);
*dst++ = GT1+(i&15);
*dst++ = GT1+(i&15);
/****** gtia mode 2 **********/
dst = (uint8_t *)&m_pf_gtia2[i];
*dst++ = GT2+((i>>4)&15);
*dst++ = GT2+((i>>4)&15);
*dst++ = GT2+(i&15);
*dst++ = GT2+(i&15);
/****** gtia mode 3 **********/
dst = (uint8_t *)&m_pf_gtia3[i];
*dst++ = GT3+((i>>4)&15);
*dst++ = GT3+((i>>4)&15);
*dst++ = GT3+(i&15);
*dst++ = GT3+(i&15);
}
/* setup used color tables */
for( i = 0; i < 256; i++ )
{
/* used colors in text modes 2,3 */
m_uc_21[i] = (i) ? PF2 | PF1 : PF2;
/* used colors in text modes 4,5 and graphics modes D,E */
switch( i & 0x03 )
{
case 0x01: m_uc_x10b[0x000+i] |= PF0; m_uc_x10b[0x100+i] |= PF0; break;
case 0x02: m_uc_x10b[0x000+i] |= PF1; m_uc_x10b[0x100+i] |= PF1; break;
case 0x03: m_uc_x10b[0x000+i] |= PF2; m_uc_x10b[0x100+i] |= PF3; break;
}
switch( i & 0x0c )
{
case 0x04: m_uc_x10b[0x000+i] |= PF0; m_uc_x10b[0x100+i] |= PF0; break;
case 0x08: m_uc_x10b[0x000+i] |= PF1; m_uc_x10b[0x100+i] |= PF1; break;
case 0x0c: m_uc_x10b[0x000+i] |= PF2; m_uc_x10b[0x100+i] |= PF3; break;
}
switch( i & 0x30 )
{
case 0x10: m_uc_x10b[0x000+i] |= PF0; m_uc_x10b[0x100+i] |= PF0; break;
case 0x20: m_uc_x10b[0x000+i] |= PF1; m_uc_x10b[0x100+i] |= PF1; break;
case 0x30: m_uc_x10b[0x000+i] |= PF2; m_uc_x10b[0x100+i] |= PF3; break;
}
switch( i & 0xc0 )
{
case 0x40: m_uc_x10b[0x000+i] |= PF0; m_uc_x10b[0x100+i] |= PF0; break;
case 0x80: m_uc_x10b[0x000+i] |= PF1; m_uc_x10b[0x100+i] |= PF1; break;
case 0xc0: m_uc_x10b[0x000+i] |= PF2; m_uc_x10b[0x100+i] |= PF3; break;
}
/* used colors in text modes 6,7 and graphics modes 9,B,C */
if( i )
{
m_uc_3210b2[0x000+i*2] |= PF0;
m_uc_3210b2[0x200+i*2] |= PF1;
m_uc_3210b2[0x400+i*2] |= PF2;
m_uc_3210b2[0x600+i*2] |= PF3;
}
/* used colors in graphics mode 8 */
switch( i & 0x03 )
{
case 0x01: m_uc_210b4[i*4] |= PF0; break;
case 0x02: m_uc_210b4[i*4] |= PF1; break;
case 0x03: m_uc_210b4[i*4] |= PF2; break;
}
switch( i & 0x0c )
{
case 0x04: m_uc_210b4[i*4] |= PF0; break;
case 0x08: m_uc_210b4[i*4] |= PF1; break;
case 0x0c: m_uc_210b4[i*4] |= PF2; break;
}
switch( i & 0x30 )
{
case 0x10: m_uc_210b4[i*4] |= PF0; break;
case 0x20: m_uc_210b4[i*4] |= PF1; break;
case 0x30: m_uc_210b4[i*4] |= PF2; break;
}
switch( i & 0xc0 )
{
case 0x40: m_uc_210b4[i*4] |= PF0; break;
case 0x80: m_uc_210b4[i*4] |= PF1; break;
case 0xc0: m_uc_210b4[i*4] |= PF2; break;
}
/* used colors in graphics mode A */
switch( i & 0x03 )
{
case 0x01: m_uc_210b2[i*2] |= PF0; break;
case 0x02: m_uc_210b2[i*2] |= PF1; break;
case 0x03: m_uc_210b2[i*2] |= PF2; break;
}
switch( i & 0x0c )
{
case 0x04: m_uc_210b2[i*2] |= PF0; break;
case 0x08: m_uc_210b2[i*2] |= PF1; break;
case 0x0c: m_uc_210b2[i*2] |= PF2; break;
}
switch( i & 0x30 )
{
case 0x10: m_uc_210b2[i*2] |= PF0; break;
case 0x20: m_uc_210b2[i*2] |= PF1; break;
case 0x30: m_uc_210b2[i*2] |= PF2; break;
}
switch( i & 0xc0 )
{
case 0x40: m_uc_210b2[i*2] |= PF0; break;
case 0x80: m_uc_210b2[i*2] |= PF1; break;
case 0xc0: m_uc_210b2[i*2] |= PF2; break;
}
/* used colors in graphics mode F */
if( i )
m_uc_1b[i] |= PF1;
/* used colors in GTIA graphics modes */
/* GTIA 1 is 16 different luminances with hue of colbk */
m_uc_g1[i] = 0x00;
/* GTIA 2 is all 9 colors (8..15 is colbk) */
switch( i & 0x0f )
{
case 0x00: m_uc_g2[i] = 0x10; break;
case 0x01: m_uc_g2[i] = 0x20; break;
case 0x02: m_uc_g2[i] = 0x40; break;
case 0x03: m_uc_g2[i] = 0x80; break;
case 0x04: m_uc_g2[i] = 0x01; break;
case 0x05: m_uc_g2[i] = 0x02; break;
case 0x06: m_uc_g2[i] = 0x04; break;
case 0x07: m_uc_g2[i] = 0x08; break;
default: m_uc_g2[i] = 0x00;
}
/* GTIA 3 is 16 different hues with luminance of colbk */
m_uc_g3[i] = 0x00;
}
}
/**************************************************************
*
* Read ANTIC hardware registers
*
**************************************************************/
READ8_MEMBER ( antic_device::read )
{
uint8_t data = 0xff;
switch (offset & 15)
{
case 0: /* nothing */
data = m_r.antic00;
break;
case 1: /* nothing */
data = m_r.antic01;
break;
case 2: /* nothing */
data = m_r.antic02;
break;
case 3: /* nothing */
data = m_r.antic03;
break;
case 4: /* nothing */
data = m_r.antic04;
break;
case 5: /* nothing */
data = m_r.antic05;
break;
case 6: /* nothing */
data = m_r.antic06;
break;
case 7: /* nothing */
data = m_r.antic07;
break;
case 8: /* nothing */
data = m_r.antic08;
break;
case 9: /* nothing */
data = m_r.antic09;
break;
case 10: /* WSYNC read */
m_maincpu->spin_until_trigger(TRIGGER_HSYNC);
m_w.wsync = 1;
data = m_r.antic0a;
break;
case 11: /* vert counter (scanline / 2) */
data = m_r.vcount = m_scanline >> 1;
break;
case 12: /* light pen horz pos */
data = m_r.penh;
break;
case 13: /* light pen vert pos */
data = m_r.penv;
break;
case 14: /* NMI enable */
data = m_r.antic0e;
break;
case 15: /* NMI status */
data = m_r.nmist;
break;
}
return data;
}
/**************************************************************
*
* Write ANTIC hardware registers
*
**************************************************************/
WRITE8_MEMBER ( antic_device::write )
{
int temp;
switch (offset & 15)
{
case 0:
if( data == m_w.dmactl )
break;
LOG(("ANTIC 00 write DMACTL $%02X\n", data));
m_w.dmactl = data;
switch (data & 3)
{
case 0: m_pfwidth = 0; break;
case 1: m_pfwidth = 32; break;
case 2: m_pfwidth = 40; break;
case 3: m_pfwidth = 48; break;
}
break;
case 1:
if( data == m_w.chactl )
break;
LOG(("ANTIC 01 write CHACTL $%02X\n", data));
m_w.chactl = data;
m_chand = (data & 1) ? 0x00 : 0xff;
m_chxor = (data & 2) ? 0xff : 0x00;
break;
case 2:
LOG(("ANTIC 02 write DLISTL $%02X\n", data));
m_w.dlistl = data;
temp = (m_w.dlisth << 8) + m_w.dlistl;
m_dpage = temp & DPAGE;
m_doffs = temp & DOFFS;
break;
case 3:
LOG(("ANTIC 03 write DLISTH $%02X\n", data));
m_w.dlisth = data;
temp = (m_w.dlisth << 8) + m_w.dlistl;
m_dpage = temp & DPAGE;
m_doffs = temp & DOFFS;
break;
case 4:
if( data == m_w.hscrol )
break;
LOG(("ANTIC 04 write HSCROL $%02X\n", data));
m_w.hscrol = data & 15;
break;
case 5:
if( data == m_w.vscrol )
break;
LOG(("ANTIC 05 write VSCROL $%02X\n", data));
m_w.vscrol = data & 15;
break;
case 6:
if( data == m_w.pmbasl )
break;
LOG(("ANTIC 06 write PMBASL $%02X\n", data));
/* m_w.pmbasl = data; */
break;
case 7:
if( data == m_w.pmbash )
break;
LOG(("ANTIC 07 write PMBASH $%02X\n", data));
m_w.pmbash = data;
m_pmbase_s = (data & 0xfc) << 8;
m_pmbase_d = (data & 0xf8) << 8;
break;
case 8:
if( data == m_w.chbasl )
break;
LOG(("ANTIC 08 write CHBASL $%02X\n", data));
/* m_w.chbasl = data; */
break;
case 9:
if( data == m_w.chbash )
break;
LOG(("ANTIC 09 write CHBASH $%02X\n", data));
m_w.chbash = data;
break;
case 10: /* WSYNC write */
LOG(("ANTIC 0A write WSYNC $%02X\n", data));
m_maincpu->spin_until_trigger(TRIGGER_HSYNC);
m_w.wsync = 1;
break;
case 11:
if( data == m_w.antic0b )
break;
LOG(("ANTIC 0B write ?????? $%02X\n", data));
m_w.antic0b = data;
break;
case 12:
if( data == m_w.antic0c )
break;
LOG(("ANTIC 0C write ?????? $%02X\n", data));
m_w.antic0c = data;
break;
case 13:
if( data == m_w.antic0d )
break;
LOG(("ANTIC 0D write ?????? $%02X\n", data));
m_w.antic0d = data;
break;
case 14:
if( data == m_w.nmien )
break;
LOG(("ANTIC 0E write NMIEN $%02X\n", data));
m_w.nmien = data;
break;
case 15:
LOG(("ANTIC 0F write NMIRES $%02X\n", data));
m_r.nmist = 0x1f;
m_w.nmires = data;
break;
}
}
/************* ANTIC mode 00: *********************************
* generate 1-8 empty scanlines
***************************************************************/
inline void antic_device::mode_0(address_space &space, VIDEO *video)
{
PREPARE();
memset(dst, PBK, HWIDTH*4);
POST();
}
/************* ANTIC mode 01: *********************************
* display list jump, eventually wait for vsync
***************************************************************/
/************* ANTIC mode 02: *********************************
* character mode 8x8:2 (32/40/48 byte per line)
***************************************************************/
#define MODE2(s) COPY4(dst, m_pf_21[video->data[s]])
inline void antic_device::mode_2(address_space &space, VIDEO *video, int bytes, int erase)
{
PREPARE_TXT2(space, bytes);
ERASE(erase);
REP(MODE2, bytes);
ERASE(erase);
POST_TXT(bytes);
}
/************* ANTIC mode 03: *********************************
* character mode 8x10:2 (32/40/48 byte per line)
***************************************************************/
#define MODE3(s) COPY4(dst, m_pf_21[video->data[s]])
inline void antic_device::mode_3(address_space &space, VIDEO *video, int bytes, int erase)
{
PREPARE_TXT3(space, bytes);
ERASE(erase);
REP(MODE3, bytes);
ERASE(erase);
POST_TXT(bytes);
}
/************* ANTIC mode 04: *********************************
* character mode 8x8:4 multi color (32/40/48 byte per line)
***************************************************************/
#define MODE4(s) COPY4(dst, m_pf_x10b[video->data[s]])
inline void antic_device::mode_4(address_space &space, VIDEO *video, int bytes, int erase)
{
PREPARE_TXT45(space, bytes, 0);
ERASE(erase);
REP(MODE4, bytes);
ERASE(erase);
POST_TXT(bytes);
}
/************* ANTIC mode 05: *********************************
* character mode 8x16:4 multi color (32/40/48 byte per line)
***************************************************************/
#define MODE5(s) COPY4(dst, m_pf_x10b[video->data[s]])
inline void antic_device::mode_5(address_space &space, VIDEO *video, int bytes, int erase)
{
PREPARE_TXT45(space, bytes, 1);
ERASE(erase);
REP(MODE5, bytes);
ERASE(erase);
POST_TXT(bytes);
}
/************* ANTIC mode 06: *********************************
* character mode 16x8:5 single color (16/20/24 byte per line)
***************************************************************/
#define MODE6(s) COPY8(dst, m_pf_3210b2[video->data[s]], m_pf_3210b2[video->data[s]+1])
inline void antic_device::mode_6(address_space &space, VIDEO *video, int bytes, int erase)
{
PREPARE_TXT67(space, bytes, 0);
ERASE(erase);
REP(MODE6, bytes);
ERASE(erase);
POST_TXT(bytes);
}
/************* ANTIC mode 07: *********************************
* character mode 16x16:5 single color (16/20/24 byte per line)
***************************************************************/
#define MODE7(s) COPY8(dst, m_pf_3210b2[video->data[s]], m_pf_3210b2[video->data[s]+1])
inline void antic_device::mode_7(address_space &space, VIDEO *video, int bytes, int erase)
{
PREPARE_TXT67(space, bytes, 1);
ERASE(erase);
REP(MODE7, bytes);
ERASE(erase);
POST_TXT(bytes);
}
/************* ANTIC mode 08: *********************************
* graphics mode 8x8:4 (8/10/12 byte per line)
***************************************************************/
#define MODE8(s) COPY16(dst, m_pf_210b4[video->data[s]],m_pf_210b4[video->data[s]+1],m_pf_210b4[video->data[s]+2],m_pf_210b4[video->data[s]+3])
inline void antic_device::mode_8(address_space &space, VIDEO *video, int bytes, int erase)
{
PREPARE_GFX8(space, bytes);
ERASE(erase);
REP(MODE8, bytes);
ERASE(erase);
POST_GFX(bytes);
}
/************* ANTIC mode 09: *********************************
* graphics mode 4x4:2 (8/10/12 byte per line)
***************************************************************/
#define MODE9(s) COPY8(dst, m_pf_3210b2[video->data[s]], m_pf_3210b2[video->data[s]+1])
inline void antic_device::mode_9(address_space &space, VIDEO *video, int bytes, int erase)
{
PREPARE_GFX9BC(space, bytes);
ERASE(erase);
REP(MODE9, bytes);
ERASE(erase);
POST_GFX(bytes);
}
/************* ANTIC mode 0A: *********************************
* graphics mode 4x4:4 (16/20/24 byte per line)
***************************************************************/
#define MODEA(s) COPY8(dst, m_pf_210b2[video->data[s]], m_pf_210b2[video->data[s]+1])
inline void antic_device::mode_a(address_space &space, VIDEO *video, int bytes, int erase)
{
PREPARE_GFXA(space, bytes);
ERASE(erase);
REP(MODEA, bytes);
ERASE(erase);
POST_GFX(bytes);
}
/************* ANTIC mode 0B: *********************************
* graphics mode 2x2:2 (16/20/24 byte per line)
***************************************************************/
#define MODEB(s) COPY8(dst, m_pf_3210b2[video->data[s]], m_pf_3210b2[video->data[s]+1])
inline void antic_device::mode_b(address_space &space, VIDEO *video, int bytes, int erase)
{
PREPARE_GFX9BC(space, bytes);
ERASE(erase);
REP(MODEB, bytes);
ERASE(erase);
POST_GFX(bytes);
}
/************* ANTIC mode 0C: *********************************
* graphics mode 2x1:2 (16/20/24 byte per line)
***************************************************************/
#define MODEC(s) COPY8(dst, m_pf_3210b2[video->data[s]], m_pf_3210b2[video->data[s]+1])
inline void antic_device::mode_c(address_space &space, VIDEO *video, int bytes, int erase)
{
PREPARE_GFX9BC(space, bytes);
ERASE(erase);
REP(MODEC, bytes);
ERASE(erase);
POST_GFX(bytes);
}
/************* ANTIC mode 0D: *********************************
* graphics mode 2x2:4 (32/40/48 byte per line)
***************************************************************/
#define MODED(s) COPY4(dst, m_pf_x10b[video->data[s]])
inline void antic_device::mode_d(address_space &space, VIDEO *video, int bytes, int erase)
{
PREPARE_GFXDE(space, bytes);
ERASE(erase);
REP(MODED, bytes);
ERASE(erase);
POST_GFX(bytes);
}
/************* ANTIC mode 0E: *********************************
* graphics mode 2x1:4 (32/40/48 byte per line)
***************************************************************/
#define MODEE(s) COPY4(dst, m_pf_x10b[video->data[s]])
inline void antic_device::mode_e(address_space &space, VIDEO *video, int bytes, int erase)
{
PREPARE_GFXDE(space, bytes);
ERASE(erase);
REP(MODEE, bytes);
ERASE(erase);
POST_GFX(bytes);
}
/************* ANTIC mode 0F: *********************************
* graphics mode 1x1:2 (32/40/48 byte per line)
***************************************************************/
#define MODEF(s) COPY4(dst, m_pf_1b[video->data[s]])
inline void antic_device::mode_f(address_space &space, VIDEO *video, int bytes, int erase)
{
PREPARE_GFXF(space, bytes);
ERASE(erase);
REP(MODEF, bytes);
ERASE(erase);
POST_GFX(bytes);
}
/************* ANTIC mode 0F : GTIA mode 1 ********************
* graphics mode 8x1:16 (32/40/48 byte per line)
***************************************************************/
#define GTIA1(s) COPY4(dst, m_pf_gtia1[video->data[s]])
inline void antic_device::mode_gtia1(address_space &space, VIDEO *video, int bytes, int erase)
{
PREPARE_GFXG1(space, bytes);
ERASE(erase);
REP(GTIA1, bytes);
ERASE(erase);
POST_GFX(bytes);
}
/************* ANTIC mode 0F : GTIA mode 2 ********************
* graphics mode 8x1:16 (32/40/48 byte per line)
***************************************************************/
#define GTIA2(s) COPY4(dst, m_pf_gtia2[video->data[s]])
inline void antic_device::mode_gtia2(address_space &space, VIDEO *video, int bytes, int erase)
{
PREPARE_GFXG2(space, bytes);
ERASE(erase);
REP(GTIA2, bytes);
ERASE(erase);
POST_GFX(bytes);
}
/************* ANTIC mode 0F : GTIA mode 3 ********************
* graphics mode 8x1:16 (32/40/48 byte per line)
***************************************************************/
#define GTIA3(s) COPY4(dst, m_pf_gtia3[video->data[s]])
inline void antic_device::mode_gtia3(address_space &space, VIDEO *video, int bytes, int erase)
{
PREPARE_GFXG3(space, bytes);
ERASE(erase);
REP(GTIA3, bytes);
ERASE(erase);
POST_GFX(bytes);
}
/************* ANTIC render ********************/
void antic_device::render(address_space &space, int param1, int param2, int param3)
{
VIDEO *video = m_video[m_scanline];
int add_bytes = 0, erase = 0;
if (param3 == 0 || param2 <= 1)
{
mode_0(space, video);
return;
}
if ((param3 == 1 || param3 == 2) && param1)
param3++;
switch (param3)
{
case 1:
add_bytes = 32;
erase = 8;
break;
case 2:
add_bytes = 40;
erase = 4;
break;
case 3:
add_bytes = 48;
erase = 0;
break;
}
switch (param2)
{
case 0x02:
mode_2(space, video, add_bytes, erase);
return;
case 0x03:
mode_3(space, video, add_bytes, erase);
return;
case 0x04:
mode_4(space, video, add_bytes, erase);
return;
case 0x05:
mode_5(space, video, add_bytes, erase);
return;
case 0x06:
mode_6(space, video, add_bytes >> 1, erase);
return;
case 0x07:
mode_7(space, video, add_bytes >> 1, erase);
return;
case 0x08:
mode_8(space, video, add_bytes >> 2, erase);
return;
case 0x09:
mode_9(space, video, add_bytes >> 1, erase);
return;
case 0x0a:
mode_a(space, video, add_bytes >> 1, erase);
return;
case 0x0b:
mode_b(space, video, add_bytes >> 1, erase);
return;
case 0x0c:
mode_c(space, video, add_bytes >> 1, erase);
return;
case 0x0d:
mode_d(space, video, add_bytes, erase);
return;
case 0x0e:
mode_e(space, video, add_bytes, erase);
return;
case 0x0f:
mode_f(space, video, add_bytes, erase);
return;
case 0x10:
mode_gtia1(space, video, add_bytes, erase);
return;
case 0x11:
mode_gtia2(space, video, add_bytes, erase);
return;
case 0x12:
mode_gtia3(space, video, add_bytes, erase);
return;
default:
return;
}
}
/************************************************************************
* atari_vh_screenrefresh
* Refresh screen bitmap.
* Note: Actual drawing is done scanline wise during atari_interrupt
************************************************************************/
uint32_t antic_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
uint32_t new_tv_artifacts = m_artifacts.read_safe(0);
copybitmap(bitmap, *m_bitmap, 0, 0, 0, 0, cliprect);
if (m_tv_artifacts != new_tv_artifacts)
m_tv_artifacts = new_tv_artifacts;
return 0;
}
void antic_device::artifacts_gfx(uint8_t *src, uint8_t *dst, int width)
{
uint8_t n, bits = 0;
uint8_t b = m_gtia->get_w_colbk() & 0xf0;
uint8_t c = m_gtia->get_w_colpf1() & 0x0f;
uint8_t atari_A = ((b + 0x30) & 0xf0) + c;
uint8_t atari_B = ((b + 0x70) & 0xf0) + c;
uint8_t atari_C = b + c;
uint8_t atari_D = m_gtia->get_w_colbk();
uint16_t *color_lookup = m_gtia->get_color_lookup();
for (int x = 0; x < width * 4; x++)
{
n = *src++;
bits <<= 2;
switch( n )
{
case G00:
break;
case G01:
bits |= 1;
break;
case G10:
bits |= 2;
break;
case G11:
bits |= 3;
break;
default:
*dst++ = color_lookup[n];
*dst++ = color_lookup[n];
continue;
}
switch ((bits >> 1) & 7)
{
case 0: /* 0 0 0 */
case 1: /* 0 0 1 */
case 4: /* 1 0 0 */
*dst++ = atari_D;
break;
case 3: /* 0 1 1 */
case 6: /* 1 1 0 */
case 7: /* 1 1 1 */
*dst++ = atari_C;
break;
case 2: /* 0 1 0 */
*dst++ = atari_B;
break;
case 5: /* 1 0 1 */
*dst++ = atari_A;
break;
}
switch (bits & 7)
{
case 0: /* 0 0 0 */
case 1: /* 0 0 1 */
case 4: /* 1 0 0 */
*dst++ = atari_D;
break;
case 3: /* 0 1 1 */
case 6: /* 1 1 0 */
case 7: /* 1 1 1 */
*dst++ = atari_C;
break;
case 2: /* 0 1 0 */
*dst++ = atari_A;
break;
case 5: /* 1 0 1 */
*dst++ = atari_B;
break;
}
}
}
void antic_device::artifacts_txt(uint8_t * src, uint8_t * dst, int width)
{
uint8_t n, bits = 0;
uint8_t b = m_gtia->get_w_colpf2() & 0xf0;
uint8_t c = m_gtia->get_w_colpf1() & 0x0f;
uint8_t atari_A = ((b+0x30)&0xf0)+c;
uint8_t atari_B = ((b+0x70)&0xf0)+c;
uint8_t atari_C = b+c;
uint8_t atari_D = m_gtia->get_w_colpf2();
uint16_t *color_lookup = m_gtia->get_color_lookup();
for (int x = 0; x < width * 4; x++)
{
n = *src++;
bits <<= 2;
switch( n )
{
case T00:
break;
case T01:
bits |= 1;
break;
case T10:
bits |= 2;
break;
case T11:
bits |= 3;
break;
default:
*dst++ = color_lookup[n];
*dst++ = color_lookup[n];
continue;
}
switch( (bits >> 1) & 7 )
{
case 0: /* 0 0 0 */
case 1: /* 0 0 1 */
case 4: /* 1 0 0 */
*dst++ = atari_D;
break;
case 3: /* 0 1 1 */
case 6: /* 1 1 0 */
case 7: /* 1 1 1 */
*dst++ = atari_C;
break;
case 2: /* 0 1 0 */
*dst++ = atari_A;
break;
case 5: /* 1 0 1 */
*dst++ = atari_B;
break;
}
switch( bits & 7 )
{
case 0:/* 0 0 0 */
case 1:/* 0 0 1 */
case 4:/* 1 0 0 */
*dst++ = atari_D;
break;
case 3: /* 0 1 1 */
case 6: /* 1 1 0 */
case 7: /* 1 1 1 */
*dst++ = atari_C;
break;
case 2: /* 0 1 0 */
*dst++ = atari_B;
break;
case 5: /* 1 0 1 */
*dst++ = atari_A;
break;
}
}
}
void antic_device::linerefresh()
{
int x, y;
uint8_t *src;
uint32_t *dst;
uint32_t scanline[4 + (HCHARS * 2) + 4];
uint16_t *color_lookup = m_gtia->get_color_lookup();
/* increment the scanline */
if( ++m_scanline == screen().height() )
{
/* and return to the top if the frame was complete */
m_scanline = 0;
m_modelines = 0;
/* count frames gone since last write to hitclr */
m_gtia->count_hitclr_frames();
}
if( m_scanline < MIN_Y || m_scanline > MAX_Y )
return;
y = m_scanline - MIN_Y;
src = &m_cclock[PMOFFSET - m_hscrol_old + 12];
dst = scanline;
if( m_tv_artifacts )
{
if( (m_cmd & 0x0f) == 2 || (m_cmd & 0x0f) == 3 )
{
artifacts_txt(src, (uint8_t*)(dst + 3), HCHARS);
return;
}
else
if( (m_cmd & 0x0f) == 15 )
{
artifacts_gfx(src, (uint8_t*)(dst + 3), HCHARS);
return;
}
}
dst[0] = color_lookup[PBK] | color_lookup[PBK] << 16;
dst[1] = color_lookup[PBK] | color_lookup[PBK] << 16;
dst[2] = color_lookup[PBK] | color_lookup[PBK] << 16;
if ( (m_cmd & ANTIC_HSCR) == 0 || (m_pfwidth == 48) || (m_pfwidth == 32))
{
/* no hscroll */
dst[3] = color_lookup[src[BYTE_XOR_LE(0)]] | color_lookup[src[BYTE_XOR_LE(1)]] << 16;
src += 2;
dst += 4;
for( x = 1; x < HCHARS-1; x++ )
{
*dst++ = color_lookup[src[BYTE_XOR_LE(0)]] | color_lookup[src[BYTE_XOR_LE(1)]] << 16;
*dst++ = color_lookup[src[BYTE_XOR_LE(2)]] | color_lookup[src[BYTE_XOR_LE(3)]] << 16;
src += 4;
}
dst[0] = color_lookup[src[BYTE_XOR_LE(0)]] | color_lookup[src[BYTE_XOR_LE(1)]] << 16;
}
else
{
/* if hscroll is enabled, more data are fetched by ANTIC, but it still renders playfield
of width defined by pfwidth. */
switch( m_pfwidth )
{
case 0:
{
dst[3] = color_lookup[PBK] | color_lookup[PBK] << 16;
dst += 4;
for ( x = 1; x < HCHARS-1; x++ )
{
*dst++ = color_lookup[PBK] | color_lookup[PBK] << 16;
*dst++ = color_lookup[PBK] | color_lookup[PBK] << 16;
}
dst[0] = color_lookup[PBK] | color_lookup[PBK] << 16;
}
break;
/* support for narrow playfield (32) with horizontal scrolling should be added here */
case 40:
{
dst[3] = color_lookup[PBK] | color_lookup[PBK] << 16;
dst += 4;
for ( x = 1; x < HCHARS-2; x++ )
{
if ( x == 1 )
{
*dst++ = color_lookup[PBK] | color_lookup[PBK] << 16;
}
else
{
*dst++ = color_lookup[src[BYTE_XOR_LE(0)]] | color_lookup[src[BYTE_XOR_LE(1)]] << 16;
}
*dst++ = color_lookup[src[BYTE_XOR_LE(2)]] | color_lookup[src[BYTE_XOR_LE(3)]] << 16;
src += 4;
}
for ( ; x < HCHARS-1; x++ )
{
*dst++ = color_lookup[PBK] | color_lookup[PBK] << 16;
*dst++ = color_lookup[PBK] | color_lookup[PBK] << 16;
}
dst[0] = color_lookup[PBK] | color_lookup[PBK] << 16;
}
break;
}
}
dst[1] = color_lookup[PBK] | color_lookup[PBK] << 16;
dst[2] = color_lookup[PBK] | color_lookup[PBK] << 16;
dst[3] = color_lookup[PBK] | color_lookup[PBK] << 16;
draw_scanline8(*m_bitmap, 12, y, std::min(size_t(m_bitmap->width() - 12), sizeof(scanline)), (const uint8_t *) scanline, nullptr);
}
#define ANTIC_TIME_FROM_CYCLES(cycles) \
(attotime)(screen().scan_period() * (cycles) / CYCLES_PER_LINE)
void antic_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
{
switch (id)
{
case TIMER_CYCLE_STEAL:
steal_cycles(ptr, param);
break;
case TIMER_ISSUE_DLI:
issue_dli(ptr, param);
break;
case TIMER_LINE_REND:
scanline_render(ptr, param);
break;
case TIMER_LINE_DONE:
line_done(ptr, param);
break;
}
}
int antic_device::cycle()
{
return screen().hpos() * CYCLES_PER_LINE / screen().width();
}
TIMER_CALLBACK_MEMBER( antic_device::issue_dli )
{
if( m_w.nmien & DLI_NMI )
{
LOG((" @cycle #%3d issue DLI\n", cycle()));
m_r.nmist |= DLI_NMI;
m_maincpu->pulse_input_line(INPUT_LINE_NMI, attotime::zero);
}
else
{
LOG((" @cycle #%3d DLI not enabled\n", cycle()));
}
}
/*****************************************************************************
*
* Antic Line Done
*
*****************************************************************************/
TIMER_CALLBACK_MEMBER( antic_device::line_done )
{
LOG((" @cycle #%3d line_done\n", cycle()));
if( m_w.wsync )
{
LOG((" @cycle #%3d release WSYNC\n", cycle()));
/* release the CPU if it was actually waiting for HSYNC */
machine().scheduler().trigger(TRIGGER_HSYNC);
/* and turn off the 'wait for hsync' flag */
m_w.wsync = 0;
}
LOG((" @cycle #%3d release CPU\n", cycle()));
/* release the CPU (held for emulating cycles stolen by ANTIC DMA) */
machine().scheduler().trigger(TRIGGER_STEAL);
/* refresh the display (translate color clocks to pixels) */
linerefresh();
}
/*****************************************************************************
*
* Antic Steal Cycles
* This is called once per scanline by a interrupt issued in the
* atari_scanline_render function. Set a new timer for the HSYNC
* position and release the CPU; but hold it again immediately until
* TRIGGER_HSYNC if WSYNC (D01A) was accessed
*
*****************************************************************************/
TIMER_CALLBACK_MEMBER( antic_device::steal_cycles )
{
LOG((" @cycle #%3d steal %d cycles\n", cycle(), m_steal_cycles));
timer_set(ANTIC_TIME_FROM_CYCLES(m_steal_cycles), TIMER_LINE_DONE);
m_steal_cycles = 0;
m_maincpu->spin_until_trigger(TRIGGER_STEAL);
}
/*****************************************************************************
*
* Antic Scan Line Render
* Render the scanline to the scrbitmap buffer.
* Also transport player/missile data to the grafp and grafm registers
* of the GTIA if enabled (DMA_PLAYER or DMA_MISSILE)
*
*****************************************************************************/
TIMER_CALLBACK_MEMBER( antic_device::scanline_render )
{
address_space &space = m_maincpu->space(AS_PROGRAM);
LOG((" @cycle #%3d render mode $%X lines to go #%d\n", cycle(), (m_cmd & 0x0f), m_modelines));
render(space, m_render1, m_render2, m_render3);
/* if player/missile graphics is enabled */
if( m_scanline < 256 && (m_w.dmactl & (DMA_PLAYER|DMA_MISSILE)) )
{
/* new player/missile graphics data for every scanline ? */
if( m_w.dmactl & DMA_PM_DBLLINE )
{
/* transport missile data to GTIA ? */
if( m_w.dmactl & DMA_MISSILE )
{
m_steal_cycles += 1;
m_gtia->write(space, 0x11, RDPMGFXD(space, 3*256));
}
/* transport player data to GTIA ? */
if( m_w.dmactl & DMA_PLAYER )
{
m_steal_cycles += 4;
m_gtia->write(space, 0x0d, RDPMGFXD(space, 4*256));
m_gtia->write(space, 0x0e, RDPMGFXD(space, 5*256));
m_gtia->write(space, 0x0f, RDPMGFXD(space, 6*256));
m_gtia->write(space, 0x10, RDPMGFXD(space, 7*256));
}
}
else
{
/* transport missile data to GTIA ? */
if( m_w.dmactl & DMA_MISSILE )
{
if( (m_scanline & 1) == 0 ) /* even line ? */
m_steal_cycles += 1;
m_gtia->write(space, 0x11, RDPMGFXS(space, 3*128));
}
/* transport player data to GTIA ? */
if( m_w.dmactl & DMA_PLAYER )
{
if( (m_scanline & 1) == 0 ) /* even line ? */
m_steal_cycles += 4;
m_gtia->write(space, 0x0d, RDPMGFXS(space, 4*128));
m_gtia->write(space, 0x0e, RDPMGFXS(space, 5*128));
m_gtia->write(space, 0x0f, RDPMGFXS(space, 6*128));
m_gtia->write(space, 0x10, RDPMGFXS(space, 7*128));
}
}
}
if (m_scanline >= VBL_END && m_scanline < 256)
m_gtia->render((uint8_t *)m_pmbits + PMOFFSET, (uint8_t *)m_cclock + PMOFFSET - m_hscrol_old, m_prio_table[m_gtia->get_w_prior() & 0x3f].get(), (uint8_t *)&m_pmbits);
m_steal_cycles += CYCLES_REFRESH;
LOG((" run CPU for %d cycles\n", CYCLES_HSYNC - CYCLES_HSTART - m_steal_cycles));
timer_set(ANTIC_TIME_FROM_CYCLES(CYCLES_HSYNC - CYCLES_HSTART - m_steal_cycles), TIMER_CYCLE_STEAL);
}
void antic_device::LMS(int new_cmd)
{
/**************************************************************
* If the LMS bit (load memory scan) of the current display
* list command is set, load the video source address from the
* following two bytes and split it up into video page/offset.
* Steal two more cycles from the CPU for fetching the address.
**************************************************************/
if( new_cmd & ANTIC_LMS )
{
address_space &space = m_maincpu->space(AS_PROGRAM);
int addr = RDANTIC(space);
m_doffs = (m_doffs + 1) & DOFFS;
addr += 256 * RDANTIC(space);
m_doffs = (m_doffs + 1) & DOFFS;
m_vpage = addr & VPAGE;
m_voffs = addr & VOFFS;
LOG((" LMS $%04x\n", addr));
/* steal two more clock cycles from the cpu */
m_steal_cycles += 2;
}
}
/*****************************************************************************
*
* Antic Scan Line DMA
* This is called once per scanline from Atari Interrupt
* If the ANTIC DMA is active (DMA_ANTIC) and the scanline not inside
* the VBL range (VBL_START - TOTAL_LINES or 0 - VBL_END)
* check if all mode lines of the previous ANTIC command were done and
* if so, read a new command and set up the renderer function
*
*****************************************************************************/
void antic_device::scanline_dma(int param)
{
address_space &space = m_maincpu->space(AS_PROGRAM);
LOG((" @cycle #%3d DMA fetch\n", cycle()));
if (m_scanline == VBL_END)
m_r.nmist &= ~VBL_NMI;
if( m_w.dmactl & DMA_ANTIC )
{
if( m_scanline >= VBL_END && m_scanline < VBL_START )
{
if( m_modelines <= 0 )
{
m_render1 = 0;
m_render3 = m_w.dmactl & 3;
uint8_t vscrol_subtract = 0;
uint8_t new_cmd;
new_cmd = RDANTIC(space);
m_doffs = (m_doffs + 1) & DOFFS;
/* steal at one clock cycle from the CPU for fetching the command */
m_steal_cycles += 1;
LOG((" ANTIC CMD $%02x\n", new_cmd));
/* command 1 .. 15 ? */
if (new_cmd & ANTIC_MODE)
{
m_w.chbasl = 0;
/* vertical scroll mode changed ? */
if( (m_cmd ^ new_cmd) & ANTIC_VSCR )
{
/* vertical scroll activate now ? */
if( new_cmd & ANTIC_VSCR )
{
m_vscrol_old =
vscrol_subtract =
m_w.chbasl = m_w.vscrol;
}
else
{
vscrol_subtract = ~m_vscrol_old;
}
}
/* does this command have horizontal scroll enabled ? */
if( new_cmd & ANTIC_HSCR )
{
m_render1 = 1;
m_hscrol_old = m_w.hscrol;
}
else
{
m_hscrol_old = 0;
}
}
/* Set the ANTIC mode renderer function */
m_render2 = new_cmd & ANTIC_MODE;
switch( new_cmd & ANTIC_MODE )
{
case 0x00:
/* generate 1 .. 8 empty lines */
m_modelines = ((new_cmd >> 4) & 7) + 1;
/* did the last ANTIC command have vertical scroll enabled ? */
if( m_cmd & ANTIC_VSCR )
{
/* yes, generate vscrol_old additional empty lines */
m_modelines += m_vscrol_old;
}
/* leave only bit 7 (DLI) set in ANTIC command */
new_cmd &= ANTIC_DLI;
break;
case 0x01:
/* ANTIC "jump" with DLI: issue interrupt immediately */
if( new_cmd & ANTIC_DLI )
{
/* remove the DLI bit */
new_cmd &= ~ANTIC_DLI;
timer_set(ANTIC_TIME_FROM_CYCLES(CYCLES_DLI_NMI), TIMER_ISSUE_DLI);
}
/* load memory scan bit set ? */
if( new_cmd & ANTIC_LMS )
{
int addr = RDANTIC(space);
m_doffs = (m_doffs + 1) & DOFFS;
addr += 256 * RDANTIC(space);
m_dpage = addr & DPAGE;
m_doffs = addr & DOFFS;
/* produce empty scanlines until vblank start */
m_modelines = VBL_START + 1 - m_scanline;
if( m_modelines < 0 )
m_modelines = screen().height() - m_scanline;
LOG((" JVB $%04x\n", m_dpage|m_doffs));
}
else
{
int addr = RDANTIC(space);
m_doffs = (m_doffs + 1) & DOFFS;
addr += 256 * RDANTIC(space);
m_dpage = addr & DPAGE;
m_doffs = addr & DOFFS;
/* produce a single empty scanline */
m_modelines = 1;
LOG((" JMP $%04x\n", m_dpage|m_doffs));
}
break;
case 0x02:
LMS(new_cmd);
m_chbase = (m_w.chbash & 0xfc) << 8;
m_modelines = 8 - (vscrol_subtract & 7);
if( m_w.chactl & 4 ) /* decrement chbasl? */
m_w.chbasl = m_modelines - 1;
break;
case 0x03:
LMS(new_cmd);
m_chbase = (m_w.chbash & 0xfc) << 8;
m_modelines = 10 - (vscrol_subtract & 9);
if( m_w.chactl & 4 ) /* decrement chbasl? */
m_w.chbasl = m_modelines - 1;
break;
case 0x04:
LMS(new_cmd);
m_chbase = (m_w.chbash & 0xfc) << 8;
m_modelines = 8 - (vscrol_subtract & 7);
if( m_w.chactl & 4 ) /* decrement chbasl? */
m_w.chbasl = m_modelines - 1;
break;
case 0x05:
LMS(new_cmd);
m_chbase = (m_w.chbash & 0xfc) << 8;
m_modelines = 16 - (vscrol_subtract & 15);
if( m_w.chactl & 4 ) /* decrement chbasl? */
m_w.chbasl = m_modelines - 1;
break;
case 0x06:
LMS(new_cmd);
m_chbase = (m_w.chbash & 0xfe) << 8;
m_modelines = 8 - (vscrol_subtract & 7);
if( m_w.chactl & 4 ) /* decrement chbasl? */
m_w.chbasl = m_modelines - 1;
break;
case 0x07:
LMS(new_cmd);
m_chbase = (m_w.chbash & 0xfe) << 8;
m_modelines = 16 - (vscrol_subtract & 15);
if( m_w.chactl & 4 ) /* decrement chbasl? */
m_w.chbasl = m_modelines - 1;
break;
case 0x08:
LMS(new_cmd);
m_modelines = 8 - (vscrol_subtract & 7);
break;
case 0x09:
LMS(new_cmd);
m_modelines = 4 - (vscrol_subtract & 3);
break;
case 0x0a:
LMS(new_cmd);
m_modelines = 4 - (vscrol_subtract & 3);
break;
case 0x0b:
LMS(new_cmd);
m_modelines = 2 - (vscrol_subtract & 1);
break;
case 0x0c:
LMS(new_cmd);
m_modelines = 1;
break;
case 0x0d:
LMS(new_cmd);
m_modelines = 2 - (vscrol_subtract & 1);
break;
case 0x0e:
LMS(new_cmd);
m_modelines = 1;
break;
case 0x0f:
LMS(new_cmd);
/* bits 6+7 of the priority select register determine */
/* if newer GTIA or plain graphics modes are used */
switch (m_gtia->get_w_prior() >> 6)
{
case 0: break;
case 1: m_render2 = 16; break;
case 2: m_render2 = 17; break;
case 3: m_render2 = 18; break;
}
m_modelines = 1;
break;
}
/* set new (current) antic command */
m_cmd = new_cmd;
}
}
else
{
LOG((" out of visible range\n"));
m_cmd = 0x00;
m_render1 = 0;
m_render2 = 0;
m_render3 = 0;
}
}
else
{
LOG((" DMA is off\n"));
m_cmd = 0x00;
m_render1 = 0;
m_render2 = 0;
m_render3 = 0;
}
m_r.nmist &= ~DLI_NMI;
if (m_modelines == 1 && (m_cmd & m_w.nmien & DLI_NMI))
timer_set(ANTIC_TIME_FROM_CYCLES(CYCLES_DLI_NMI), TIMER_ISSUE_DLI);
timer_set(ANTIC_TIME_FROM_CYCLES(CYCLES_HSTART), TIMER_LINE_REND);
}
/*****************************************************************************
*
* Generic Atari Interrupt Dispatcher
* This is called once per scanline and handles:
* vertical blank interrupt
* ANTIC DMA to possibly access the next display list command
*
*****************************************************************************/
void antic_device::generic_interrupt(int button_count)
{
LOG(("ANTIC #%3d @cycle #%d scanline interrupt\n", m_scanline, cycle()));
if( m_scanline < VBL_START )
{
scanline_dma(0);
return;
}
if( m_scanline == VBL_START )
{
/* specify buttons relevant to this Atari variant */
m_gtia->button_interrupt(button_count, m_djoy_b.read_safe(0));
/* do nothing new for the rest of the frame */
m_modelines = screen().height() - VBL_START;
m_render1 = 0;
m_render2 = 0;
m_render3 = 0;
/* if the CPU want's to be interrupted at vertical blank... */
if( m_w.nmien & VBL_NMI )
{
LOG((" cause VBL NMI\n"));
/* set the VBL NMI status bit */
m_r.nmist |= VBL_NMI;
m_maincpu->pulse_input_line(INPUT_LINE_NMI, attotime::zero);
}
}
/* refresh the display (translate color clocks to pixels) */
linerefresh();
}