mirror of
https://github.com/holub/mame
synced 2025-07-02 00:29:37 +03:00
some more antic refactorization. nw.
This commit is contained in:
parent
f156d1704d
commit
885a377e22
@ -26,6 +26,8 @@ public:
|
||||
m_gtia(*this, "gtia"),
|
||||
tv_artifacts(0) { }
|
||||
|
||||
virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr);
|
||||
|
||||
virtual void video_start();
|
||||
UINT32 screen_update_atari(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
|
||||
|
||||
@ -44,6 +46,11 @@ public:
|
||||
POKEY_KEYBOARD_CB_MEMBER(a800_keyboard);
|
||||
|
||||
private:
|
||||
static const device_timer_id TIMER_CYCLE_STEAL = 0;
|
||||
static const device_timer_id TIMER_ISSUE_DLI = 1;
|
||||
static const device_timer_id TIMER_LINE_REND = 2;
|
||||
static const device_timer_id TIMER_LINE_DONE = 3;
|
||||
|
||||
required_device<gtia_device> m_gtia;
|
||||
UINT32 tv_artifacts;
|
||||
void prio_init();
|
||||
|
@ -1508,3 +1508,681 @@ static ANTIC_RENDERER( gtia_mode_3_48 )
|
||||
REP48(GTIA3);
|
||||
POST_GFX(48);
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
* atari_vh_screenrefresh
|
||||
* Refresh screen bitmap.
|
||||
* Note: Actual drawing is done scanline wise during atari_interrupt
|
||||
************************************************************************/
|
||||
UINT32 atari_common_state::screen_update_atari(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
|
||||
{
|
||||
UINT32 new_tv_artifacts = screen.ioport("artifacts")->read_safe(0);
|
||||
copybitmap(bitmap, *antic.bitmap, 0, 0, 0, 0, cliprect);
|
||||
|
||||
if (tv_artifacts != new_tv_artifacts)
|
||||
tv_artifacts = new_tv_artifacts;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void atari_common_state::artifacts_gfx(UINT8 *src, UINT8 *dst, int width)
|
||||
{
|
||||
UINT8 n, bits = 0;
|
||||
UINT8 b = m_gtia->get_w_colbk() & 0xf0;
|
||||
UINT8 c = m_gtia->get_w_colpf1() & 0x0f;
|
||||
UINT8 atari_A = ((b + 0x30) & 0xf0) + c;
|
||||
UINT8 atari_B = ((b + 0x70) & 0xf0) + c;
|
||||
UINT8 atari_C = b + c;
|
||||
UINT8 atari_D = m_gtia->get_w_colbk();
|
||||
UINT16 *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 atari_common_state::artifacts_txt(UINT8 * src, UINT8 * dst, int width)
|
||||
{
|
||||
UINT8 n, bits = 0;
|
||||
UINT8 b = m_gtia->get_w_colpf2() & 0xf0;
|
||||
UINT8 c = m_gtia->get_w_colpf1() & 0x0f;
|
||||
UINT8 atari_A = ((b+0x30)&0xf0)+c;
|
||||
UINT8 atari_B = ((b+0x70)&0xf0)+c;
|
||||
UINT8 atari_C = b+c;
|
||||
UINT8 atari_D = m_gtia->get_w_colpf2();
|
||||
UINT16 *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 atari_common_state::antic_linerefresh()
|
||||
{
|
||||
int x, y;
|
||||
UINT8 *src;
|
||||
UINT32 *dst;
|
||||
UINT32 scanline[4 + (HCHARS * 2) + 4];
|
||||
UINT16 *color_lookup = m_gtia->get_color_lookup();
|
||||
|
||||
/* increment the scanline */
|
||||
if( ++antic.scanline == machine().first_screen()->height() )
|
||||
{
|
||||
/* and return to the top if the frame was complete */
|
||||
antic.scanline = 0;
|
||||
antic.modelines = 0;
|
||||
/* count frames gone since last write to hitclr */
|
||||
m_gtia->count_hitclr_frames();
|
||||
}
|
||||
|
||||
if( antic.scanline < MIN_Y || antic.scanline > MAX_Y )
|
||||
return;
|
||||
|
||||
y = antic.scanline - MIN_Y;
|
||||
src = &antic.cclock[PMOFFSET - antic.hscrol_old + 12];
|
||||
dst = scanline;
|
||||
|
||||
if( tv_artifacts )
|
||||
{
|
||||
if( (antic.cmd & 0x0f) == 2 || (antic.cmd & 0x0f) == 3 )
|
||||
{
|
||||
artifacts_txt(src, (UINT8*)(dst + 3), HCHARS);
|
||||
return;
|
||||
}
|
||||
else
|
||||
if( (antic.cmd & 0x0f) == 15 )
|
||||
{
|
||||
artifacts_gfx(src, (UINT8*)(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 ( (antic.cmd & ANTIC_HSCR) == 0 || (antic.pfwidth == 48) || (antic.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( antic.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(*antic.bitmap, 12, y, MIN(antic.bitmap->width() - 12, sizeof(scanline)), (const UINT8 *) scanline, NULL);
|
||||
}
|
||||
|
||||
|
||||
#define ANTIC_TIME_FROM_CYCLES(cycles) \
|
||||
(attotime)(machine().first_screen()->scan_period() * (cycles) / CYCLES_PER_LINE)
|
||||
|
||||
void atari_common_state::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
|
||||
{
|
||||
switch (id)
|
||||
{
|
||||
case TIMER_CYCLE_STEAL:
|
||||
antic_steal_cycles(ptr, param);
|
||||
break;
|
||||
case TIMER_ISSUE_DLI:
|
||||
antic_issue_dli(ptr, param);
|
||||
break;
|
||||
case TIMER_LINE_REND:
|
||||
antic_scanline_render(ptr, param);
|
||||
break;
|
||||
case TIMER_LINE_DONE:
|
||||
antic_line_done(ptr, param);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int atari_common_state::cycle()
|
||||
{
|
||||
return machine().first_screen()->hpos() * CYCLES_PER_LINE / machine().first_screen()->width();
|
||||
}
|
||||
|
||||
TIMER_CALLBACK_MEMBER( atari_common_state::antic_issue_dli )
|
||||
{
|
||||
if( antic.w.nmien & DLI_NMI )
|
||||
{
|
||||
LOG((" @cycle #%3d issue DLI\n", cycle()));
|
||||
antic.r.nmist |= DLI_NMI;
|
||||
machine().device("maincpu")->execute().set_input_line(INPUT_LINE_NMI, PULSE_LINE);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG((" @cycle #%3d DLI not enabled\n", cycle()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* Antic Line Done
|
||||
*
|
||||
*****************************************************************************/
|
||||
TIMER_CALLBACK_MEMBER( atari_common_state::antic_line_done )
|
||||
{
|
||||
LOG((" @cycle #%3d antic_line_done\n", cycle()));
|
||||
if( antic.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 */
|
||||
antic.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) */
|
||||
antic_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( atari_common_state::antic_steal_cycles )
|
||||
{
|
||||
LOG((" @cycle #%3d steal %d cycles\n", cycle(), antic.steal_cycles));
|
||||
timer_set(ANTIC_TIME_FROM_CYCLES(antic.steal_cycles), TIMER_LINE_DONE);
|
||||
antic.steal_cycles = 0;
|
||||
machine().device("maincpu")->execute().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( atari_common_state::antic_scanline_render )
|
||||
{
|
||||
address_space &space = machine().device("maincpu")->memory().space(AS_PROGRAM);
|
||||
|
||||
LOG((" @cycle #%3d render mode $%X lines to go #%d\n", cycle(), (antic.cmd & 0x0f), antic.modelines));
|
||||
|
||||
antic_render(space, m_antic_render1, m_antic_render2, m_antic_render3);
|
||||
|
||||
/* if player/missile graphics is enabled */
|
||||
if( antic.scanline < 256 && (antic.w.dmactl & (DMA_PLAYER|DMA_MISSILE)) )
|
||||
{
|
||||
/* new player/missile graphics data for every scanline ? */
|
||||
if( antic.w.dmactl & DMA_PM_DBLLINE )
|
||||
{
|
||||
/* transport missile data to GTIA ? */
|
||||
if( antic.w.dmactl & DMA_MISSILE )
|
||||
{
|
||||
antic.steal_cycles += 1;
|
||||
m_gtia->write(space, 0x11, RDPMGFXD(space, 3*256));
|
||||
}
|
||||
/* transport player data to GTIA ? */
|
||||
if( antic.w.dmactl & DMA_PLAYER )
|
||||
{
|
||||
antic.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( antic.w.dmactl & DMA_MISSILE )
|
||||
{
|
||||
if( (antic.scanline & 1) == 0 ) /* even line ? */
|
||||
antic.steal_cycles += 1;
|
||||
m_gtia->write(space, 0x11, RDPMGFXS(space, 3*128));
|
||||
}
|
||||
/* transport player data to GTIA ? */
|
||||
if( antic.w.dmactl & DMA_PLAYER )
|
||||
{
|
||||
if( (antic.scanline & 1) == 0 ) /* even line ? */
|
||||
antic.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 (antic.scanline >= VBL_END && antic.scanline < 256)
|
||||
m_gtia->render((UINT8 *)antic.pmbits + PMOFFSET, (UINT8 *)antic.cclock + PMOFFSET - antic.hscrol_old, (UINT8 *)antic.prio_table[m_gtia->get_w_prior() & 0x3f], (UINT8 *)&antic.pmbits);
|
||||
|
||||
antic.steal_cycles += CYCLES_REFRESH;
|
||||
LOG((" run CPU for %d cycles\n", CYCLES_HSYNC - CYCLES_HSTART - antic.steal_cycles));
|
||||
timer_set(ANTIC_TIME_FROM_CYCLES(CYCLES_HSYNC - CYCLES_HSTART - antic.steal_cycles), TIMER_CYCLE_STEAL);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void atari_common_state::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 = machine().device("maincpu")->memory().space(AS_PROGRAM);
|
||||
int addr = RDANTIC(space);
|
||||
antic.doffs = (antic.doffs + 1) & DOFFS;
|
||||
addr += 256 * RDANTIC(space);
|
||||
antic.doffs = (antic.doffs + 1) & DOFFS;
|
||||
antic.vpage = addr & VPAGE;
|
||||
antic.voffs = addr & VOFFS;
|
||||
LOG((" LMS $%04x\n", addr));
|
||||
/* steal two more clock cycles from the cpu */
|
||||
antic.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 atari_common_state::antic_scanline_dma(int param)
|
||||
{
|
||||
address_space &space = machine().device("maincpu")->memory().space(AS_PROGRAM);
|
||||
LOG((" @cycle #%3d DMA fetch\n", cycle()));
|
||||
if (antic.scanline == VBL_END)
|
||||
antic.r.nmist &= ~VBL_NMI;
|
||||
if( antic.w.dmactl & DMA_ANTIC )
|
||||
{
|
||||
if( antic.scanline >= VBL_END && antic.scanline < VBL_START )
|
||||
{
|
||||
if( antic.modelines <= 0 )
|
||||
{
|
||||
m_antic_render1 = 0;
|
||||
m_antic_render3 = antic.w.dmactl & 3;
|
||||
UINT8 vscrol_subtract = 0;
|
||||
UINT8 new_cmd;
|
||||
|
||||
new_cmd = RDANTIC(space);
|
||||
antic.doffs = (antic.doffs + 1) & DOFFS;
|
||||
/* steal at one clock cycle from the CPU for fetching the command */
|
||||
antic.steal_cycles += 1;
|
||||
LOG((" ANTIC CMD $%02x\n", new_cmd));
|
||||
/* command 1 .. 15 ? */
|
||||
if (new_cmd & ANTIC_MODE)
|
||||
{
|
||||
antic.w.chbasl = 0;
|
||||
/* vertical scroll mode changed ? */
|
||||
if( (antic.cmd ^ new_cmd) & ANTIC_VSCR )
|
||||
{
|
||||
/* vertical scroll activate now ? */
|
||||
if( new_cmd & ANTIC_VSCR )
|
||||
{
|
||||
antic.vscrol_old =
|
||||
vscrol_subtract =
|
||||
antic.w.chbasl = antic.w.vscrol;
|
||||
}
|
||||
else
|
||||
{
|
||||
vscrol_subtract = ~antic.vscrol_old;
|
||||
}
|
||||
}
|
||||
/* does this command have horizontal scroll enabled ? */
|
||||
if( new_cmd & ANTIC_HSCR )
|
||||
{
|
||||
m_antic_render1 = 1;
|
||||
antic.hscrol_old = antic.w.hscrol;
|
||||
}
|
||||
else
|
||||
{
|
||||
antic.hscrol_old = 0;
|
||||
}
|
||||
}
|
||||
/* Set the ANTIC mode renderer function */
|
||||
m_antic_render2 = new_cmd & ANTIC_MODE;
|
||||
|
||||
switch( new_cmd & ANTIC_MODE )
|
||||
{
|
||||
case 0x00:
|
||||
/* generate 1 .. 8 empty lines */
|
||||
antic.modelines = ((new_cmd >> 4) & 7) + 1;
|
||||
/* did the last ANTIC command have vertical scroll enabled ? */
|
||||
if( antic.cmd & ANTIC_VSCR )
|
||||
{
|
||||
/* yes, generate vscrol_old additional empty lines */
|
||||
antic.modelines += antic.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);
|
||||
antic.doffs = (antic.doffs + 1) & DOFFS;
|
||||
addr += 256 * RDANTIC(space);
|
||||
antic.dpage = addr & DPAGE;
|
||||
antic.doffs = addr & DOFFS;
|
||||
/* produce empty scanlines until vblank start */
|
||||
antic.modelines = VBL_START + 1 - antic.scanline;
|
||||
if( antic.modelines < 0 )
|
||||
antic.modelines = machine().first_screen()->height() - antic.scanline;
|
||||
LOG((" JVB $%04x\n", antic.dpage|antic.doffs));
|
||||
}
|
||||
else
|
||||
{
|
||||
int addr = RDANTIC(space);
|
||||
antic.doffs = (antic.doffs + 1) & DOFFS;
|
||||
addr += 256 * RDANTIC(space);
|
||||
antic.dpage = addr & DPAGE;
|
||||
antic.doffs = addr & DOFFS;
|
||||
/* produce a single empty scanline */
|
||||
antic.modelines = 1;
|
||||
LOG((" JMP $%04x\n", antic.dpage|antic.doffs));
|
||||
}
|
||||
break;
|
||||
case 0x02:
|
||||
LMS(new_cmd);
|
||||
antic.chbase = (antic.w.chbash & 0xfc) << 8;
|
||||
antic.modelines = 8 - (vscrol_subtract & 7);
|
||||
if( antic.w.chactl & 4 ) /* decrement chbasl? */
|
||||
antic.w.chbasl = antic.modelines - 1;
|
||||
break;
|
||||
case 0x03:
|
||||
LMS(new_cmd);
|
||||
antic.chbase = (antic.w.chbash & 0xfc) << 8;
|
||||
antic.modelines = 10 - (vscrol_subtract & 9);
|
||||
if( antic.w.chactl & 4 ) /* decrement chbasl? */
|
||||
antic.w.chbasl = antic.modelines - 1;
|
||||
break;
|
||||
case 0x04:
|
||||
LMS(new_cmd);
|
||||
antic.chbase = (antic.w.chbash & 0xfc) << 8;
|
||||
antic.modelines = 8 - (vscrol_subtract & 7);
|
||||
if( antic.w.chactl & 4 ) /* decrement chbasl? */
|
||||
antic.w.chbasl = antic.modelines - 1;
|
||||
break;
|
||||
case 0x05:
|
||||
LMS(new_cmd);
|
||||
antic.chbase = (antic.w.chbash & 0xfc) << 8;
|
||||
antic.modelines = 16 - (vscrol_subtract & 15);
|
||||
if( antic.w.chactl & 4 ) /* decrement chbasl? */
|
||||
antic.w.chbasl = antic.modelines - 1;
|
||||
break;
|
||||
case 0x06:
|
||||
LMS(new_cmd);
|
||||
antic.chbase = (antic.w.chbash & 0xfe) << 8;
|
||||
antic.modelines = 8 - (vscrol_subtract & 7);
|
||||
if( antic.w.chactl & 4 ) /* decrement chbasl? */
|
||||
antic.w.chbasl = antic.modelines - 1;
|
||||
break;
|
||||
case 0x07:
|
||||
LMS(new_cmd);
|
||||
antic.chbase = (antic.w.chbash & 0xfe) << 8;
|
||||
antic.modelines = 16 - (vscrol_subtract & 15);
|
||||
if( antic.w.chactl & 4 ) /* decrement chbasl? */
|
||||
antic.w.chbasl = antic.modelines - 1;
|
||||
break;
|
||||
case 0x08:
|
||||
LMS(new_cmd);
|
||||
antic.modelines = 8 - (vscrol_subtract & 7);
|
||||
break;
|
||||
case 0x09:
|
||||
LMS(new_cmd);
|
||||
antic.modelines = 4 - (vscrol_subtract & 3);
|
||||
break;
|
||||
case 0x0a:
|
||||
LMS(new_cmd);
|
||||
antic.modelines = 4 - (vscrol_subtract & 3);
|
||||
break;
|
||||
case 0x0b:
|
||||
LMS(new_cmd);
|
||||
antic.modelines = 2 - (vscrol_subtract & 1);
|
||||
break;
|
||||
case 0x0c:
|
||||
LMS(new_cmd);
|
||||
antic.modelines = 1;
|
||||
break;
|
||||
case 0x0d:
|
||||
LMS(new_cmd);
|
||||
antic.modelines = 2 - (vscrol_subtract & 1);
|
||||
break;
|
||||
case 0x0e:
|
||||
LMS(new_cmd);
|
||||
antic.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_antic_render2 = 16; break;
|
||||
case 2: m_antic_render2 = 17; break;
|
||||
case 3: m_antic_render2 = 18; break;
|
||||
}
|
||||
antic.modelines = 1;
|
||||
break;
|
||||
}
|
||||
/* set new (current) antic command */
|
||||
antic.cmd = new_cmd;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG((" out of visible range\n"));
|
||||
antic.cmd = 0x00;
|
||||
m_antic_render1 = 0;
|
||||
m_antic_render2 = 0;
|
||||
m_antic_render3 = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG((" DMA is off\n"));
|
||||
antic.cmd = 0x00;
|
||||
m_antic_render1 = 0;
|
||||
m_antic_render2 = 0;
|
||||
m_antic_render3 = 0;
|
||||
}
|
||||
|
||||
antic.r.nmist &= ~DLI_NMI;
|
||||
if (antic.modelines == 1 && (antic.cmd & antic.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);
|
||||
}
|
||||
|
@ -34,668 +34,6 @@ void atari_common_state::video_start()
|
||||
antic_vstart(machine());
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
* atari_vh_screenrefresh
|
||||
* Refresh screen bitmap.
|
||||
* Note: Actual drawing is done scanline wise during atari_interrupt
|
||||
************************************************************************/
|
||||
UINT32 atari_common_state::screen_update_atari(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
|
||||
{
|
||||
UINT32 new_tv_artifacts = screen.ioport("artifacts")->read_safe(0);
|
||||
copybitmap(bitmap, *antic.bitmap, 0, 0, 0, 0, cliprect);
|
||||
|
||||
if (tv_artifacts != new_tv_artifacts)
|
||||
tv_artifacts = new_tv_artifacts;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void atari_common_state::artifacts_gfx(UINT8 *src, UINT8 *dst, int width)
|
||||
{
|
||||
UINT8 n, bits = 0;
|
||||
UINT8 b = m_gtia->get_w_colbk() & 0xf0;
|
||||
UINT8 c = m_gtia->get_w_colpf1() & 0x0f;
|
||||
UINT8 atari_A = ((b + 0x30) & 0xf0) + c;
|
||||
UINT8 atari_B = ((b + 0x70) & 0xf0) + c;
|
||||
UINT8 atari_C = b + c;
|
||||
UINT8 atari_D = m_gtia->get_w_colbk();
|
||||
UINT16 *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 atari_common_state::artifacts_txt(UINT8 * src, UINT8 * dst, int width)
|
||||
{
|
||||
UINT8 n, bits = 0;
|
||||
UINT8 b = m_gtia->get_w_colpf2() & 0xf0;
|
||||
UINT8 c = m_gtia->get_w_colpf1() & 0x0f;
|
||||
UINT8 atari_A = ((b+0x30)&0xf0)+c;
|
||||
UINT8 atari_B = ((b+0x70)&0xf0)+c;
|
||||
UINT8 atari_C = b+c;
|
||||
UINT8 atari_D = m_gtia->get_w_colpf2();
|
||||
UINT16 *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 atari_common_state::antic_linerefresh()
|
||||
{
|
||||
int x, y;
|
||||
UINT8 *src;
|
||||
UINT32 *dst;
|
||||
UINT32 scanline[4 + (HCHARS * 2) + 4];
|
||||
UINT16 *color_lookup = m_gtia->get_color_lookup();
|
||||
|
||||
/* increment the scanline */
|
||||
if( ++antic.scanline == machine().first_screen()->height() )
|
||||
{
|
||||
/* and return to the top if the frame was complete */
|
||||
antic.scanline = 0;
|
||||
antic.modelines = 0;
|
||||
/* count frames gone since last write to hitclr */
|
||||
m_gtia->count_hitclr_frames();
|
||||
}
|
||||
|
||||
if( antic.scanline < MIN_Y || antic.scanline > MAX_Y )
|
||||
return;
|
||||
|
||||
y = antic.scanline - MIN_Y;
|
||||
src = &antic.cclock[PMOFFSET - antic.hscrol_old + 12];
|
||||
dst = scanline;
|
||||
|
||||
if( tv_artifacts )
|
||||
{
|
||||
if( (antic.cmd & 0x0f) == 2 || (antic.cmd & 0x0f) == 3 )
|
||||
{
|
||||
artifacts_txt(src, (UINT8*)(dst + 3), HCHARS);
|
||||
return;
|
||||
}
|
||||
else
|
||||
if( (antic.cmd & 0x0f) == 15 )
|
||||
{
|
||||
artifacts_gfx(src, (UINT8*)(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 ( (antic.cmd & ANTIC_HSCR) == 0 || (antic.pfwidth == 48) || (antic.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( antic.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(*antic.bitmap, 12, y, MIN(antic.bitmap->width() - 12, sizeof(scanline)), (const UINT8 *) scanline, NULL);
|
||||
}
|
||||
|
||||
int atari_common_state::cycle()
|
||||
{
|
||||
return machine().first_screen()->hpos() * CYCLES_PER_LINE / machine().first_screen()->width();
|
||||
}
|
||||
|
||||
void atari_common_state::after(int cycles, timer_expired_delegate function)
|
||||
{
|
||||
attotime duration = machine().first_screen()->scan_period() * cycles / CYCLES_PER_LINE;
|
||||
//(void)funcname;
|
||||
//LOG((" after %3d (%5.1f us) %s\n", cycles, duration.as_double() * 1.0e6, funcname));
|
||||
machine().scheduler().timer_set(duration, function);
|
||||
}
|
||||
|
||||
TIMER_CALLBACK_MEMBER( atari_common_state::antic_issue_dli )
|
||||
{
|
||||
if( antic.w.nmien & DLI_NMI )
|
||||
{
|
||||
LOG((" @cycle #%3d issue DLI\n", cycle()));
|
||||
antic.r.nmist |= DLI_NMI;
|
||||
machine().device("maincpu")->execute().set_input_line(INPUT_LINE_NMI, PULSE_LINE);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG((" @cycle #%3d DLI not enabled\n", cycle()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* Antic Line Done
|
||||
*
|
||||
*****************************************************************************/
|
||||
TIMER_CALLBACK_MEMBER( atari_common_state::antic_line_done )
|
||||
{
|
||||
LOG((" @cycle #%3d antic_line_done\n", cycle()));
|
||||
if( antic.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 */
|
||||
antic.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) */
|
||||
antic_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( atari_common_state::antic_steal_cycles )
|
||||
{
|
||||
LOG((" @cycle #%3d steal %d cycles\n", cycle(), antic.steal_cycles));
|
||||
after(antic.steal_cycles, timer_expired_delegate(FUNC(atari_common_state::antic_line_done),this));
|
||||
antic.steal_cycles = 0;
|
||||
machine().device("maincpu")->execute().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( atari_common_state::antic_scanline_render )
|
||||
{
|
||||
address_space &space = machine().device("maincpu")->memory().space(AS_PROGRAM);
|
||||
|
||||
LOG((" @cycle #%3d render mode $%X lines to go #%d\n", cycle(), (antic.cmd & 0x0f), antic.modelines));
|
||||
|
||||
antic_render(space, m_antic_render1, m_antic_render2, m_antic_render3);
|
||||
|
||||
/* if player/missile graphics is enabled */
|
||||
if( antic.scanline < 256 && (antic.w.dmactl & (DMA_PLAYER|DMA_MISSILE)) )
|
||||
{
|
||||
/* new player/missile graphics data for every scanline ? */
|
||||
if( antic.w.dmactl & DMA_PM_DBLLINE )
|
||||
{
|
||||
/* transport missile data to GTIA ? */
|
||||
if( antic.w.dmactl & DMA_MISSILE )
|
||||
{
|
||||
antic.steal_cycles += 1;
|
||||
m_gtia->write(space, 0x11, RDPMGFXD(space, 3*256));
|
||||
}
|
||||
/* transport player data to GTIA ? */
|
||||
if( antic.w.dmactl & DMA_PLAYER )
|
||||
{
|
||||
antic.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( antic.w.dmactl & DMA_MISSILE )
|
||||
{
|
||||
if( (antic.scanline & 1) == 0 ) /* even line ? */
|
||||
antic.steal_cycles += 1;
|
||||
m_gtia->write(space, 0x11, RDPMGFXS(space, 3*128));
|
||||
}
|
||||
/* transport player data to GTIA ? */
|
||||
if( antic.w.dmactl & DMA_PLAYER )
|
||||
{
|
||||
if( (antic.scanline & 1) == 0 ) /* even line ? */
|
||||
antic.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 (antic.scanline >= VBL_END && antic.scanline < 256)
|
||||
m_gtia->render((UINT8 *)antic.pmbits + PMOFFSET, (UINT8 *)antic.cclock + PMOFFSET - antic.hscrol_old, (UINT8 *)antic.prio_table[m_gtia->get_w_prior() & 0x3f], (UINT8 *)&antic.pmbits);
|
||||
|
||||
antic.steal_cycles += CYCLES_REFRESH;
|
||||
LOG((" run CPU for %d cycles\n", CYCLES_HSYNC - CYCLES_HSTART - antic.steal_cycles));
|
||||
after(CYCLES_HSYNC - CYCLES_HSTART - antic.steal_cycles, timer_expired_delegate(FUNC(atari_common_state::antic_steal_cycles),this));
|
||||
}
|
||||
|
||||
|
||||
|
||||
void atari_common_state::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 = machine().device("maincpu")->memory().space(AS_PROGRAM);
|
||||
int addr = RDANTIC(space);
|
||||
antic.doffs = (antic.doffs + 1) & DOFFS;
|
||||
addr += 256 * RDANTIC(space);
|
||||
antic.doffs = (antic.doffs + 1) & DOFFS;
|
||||
antic.vpage = addr & VPAGE;
|
||||
antic.voffs = addr & VOFFS;
|
||||
LOG((" LMS $%04x\n", addr));
|
||||
/* steal two more clock cycles from the cpu */
|
||||
antic.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 atari_common_state::antic_scanline_dma(int param)
|
||||
{
|
||||
address_space &space = machine().device("maincpu")->memory().space(AS_PROGRAM);
|
||||
LOG((" @cycle #%3d DMA fetch\n", cycle()));
|
||||
if (antic.scanline == VBL_END)
|
||||
antic.r.nmist &= ~VBL_NMI;
|
||||
if( antic.w.dmactl & DMA_ANTIC )
|
||||
{
|
||||
if( antic.scanline >= VBL_END && antic.scanline < VBL_START )
|
||||
{
|
||||
if( antic.modelines <= 0 )
|
||||
{
|
||||
m_antic_render1 = 0;
|
||||
m_antic_render3 = antic.w.dmactl & 3;
|
||||
UINT8 vscrol_subtract = 0;
|
||||
UINT8 new_cmd;
|
||||
|
||||
new_cmd = RDANTIC(space);
|
||||
antic.doffs = (antic.doffs + 1) & DOFFS;
|
||||
/* steal at one clock cycle from the CPU for fetching the command */
|
||||
antic.steal_cycles += 1;
|
||||
LOG((" ANTIC CMD $%02x\n", new_cmd));
|
||||
/* command 1 .. 15 ? */
|
||||
if (new_cmd & ANTIC_MODE)
|
||||
{
|
||||
antic.w.chbasl = 0;
|
||||
/* vertical scroll mode changed ? */
|
||||
if( (antic.cmd ^ new_cmd) & ANTIC_VSCR )
|
||||
{
|
||||
/* vertical scroll activate now ? */
|
||||
if( new_cmd & ANTIC_VSCR )
|
||||
{
|
||||
antic.vscrol_old =
|
||||
vscrol_subtract =
|
||||
antic.w.chbasl = antic.w.vscrol;
|
||||
}
|
||||
else
|
||||
{
|
||||
vscrol_subtract = ~antic.vscrol_old;
|
||||
}
|
||||
}
|
||||
/* does this command have horizontal scroll enabled ? */
|
||||
if( new_cmd & ANTIC_HSCR )
|
||||
{
|
||||
m_antic_render1 = 1;
|
||||
antic.hscrol_old = antic.w.hscrol;
|
||||
}
|
||||
else
|
||||
{
|
||||
antic.hscrol_old = 0;
|
||||
}
|
||||
}
|
||||
/* Set the ANTIC mode renderer function */
|
||||
m_antic_render2 = new_cmd & ANTIC_MODE;
|
||||
|
||||
switch( new_cmd & ANTIC_MODE )
|
||||
{
|
||||
case 0x00:
|
||||
/* generate 1 .. 8 empty lines */
|
||||
antic.modelines = ((new_cmd >> 4) & 7) + 1;
|
||||
/* did the last ANTIC command have vertical scroll enabled ? */
|
||||
if( antic.cmd & ANTIC_VSCR )
|
||||
{
|
||||
/* yes, generate vscrol_old additional empty lines */
|
||||
antic.modelines += antic.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;
|
||||
after(CYCLES_DLI_NMI, timer_expired_delegate(FUNC(atari_common_state::antic_issue_dli),this));
|
||||
}
|
||||
/* load memory scan bit set ? */
|
||||
if( new_cmd & ANTIC_LMS )
|
||||
{
|
||||
int addr = RDANTIC(space);
|
||||
antic.doffs = (antic.doffs + 1) & DOFFS;
|
||||
addr += 256 * RDANTIC(space);
|
||||
antic.dpage = addr & DPAGE;
|
||||
antic.doffs = addr & DOFFS;
|
||||
/* produce empty scanlines until vblank start */
|
||||
antic.modelines = VBL_START + 1 - antic.scanline;
|
||||
if( antic.modelines < 0 )
|
||||
antic.modelines = machine().first_screen()->height() - antic.scanline;
|
||||
LOG((" JVB $%04x\n", antic.dpage|antic.doffs));
|
||||
}
|
||||
else
|
||||
{
|
||||
int addr = RDANTIC(space);
|
||||
antic.doffs = (antic.doffs + 1) & DOFFS;
|
||||
addr += 256 * RDANTIC(space);
|
||||
antic.dpage = addr & DPAGE;
|
||||
antic.doffs = addr & DOFFS;
|
||||
/* produce a single empty scanline */
|
||||
antic.modelines = 1;
|
||||
LOG((" JMP $%04x\n", antic.dpage|antic.doffs));
|
||||
}
|
||||
break;
|
||||
case 0x02:
|
||||
LMS(new_cmd);
|
||||
antic.chbase = (antic.w.chbash & 0xfc) << 8;
|
||||
antic.modelines = 8 - (vscrol_subtract & 7);
|
||||
if( antic.w.chactl & 4 ) /* decrement chbasl? */
|
||||
antic.w.chbasl = antic.modelines - 1;
|
||||
break;
|
||||
case 0x03:
|
||||
LMS(new_cmd);
|
||||
antic.chbase = (antic.w.chbash & 0xfc) << 8;
|
||||
antic.modelines = 10 - (vscrol_subtract & 9);
|
||||
if( antic.w.chactl & 4 ) /* decrement chbasl? */
|
||||
antic.w.chbasl = antic.modelines - 1;
|
||||
break;
|
||||
case 0x04:
|
||||
LMS(new_cmd);
|
||||
antic.chbase = (antic.w.chbash & 0xfc) << 8;
|
||||
antic.modelines = 8 - (vscrol_subtract & 7);
|
||||
if( antic.w.chactl & 4 ) /* decrement chbasl? */
|
||||
antic.w.chbasl = antic.modelines - 1;
|
||||
break;
|
||||
case 0x05:
|
||||
LMS(new_cmd);
|
||||
antic.chbase = (antic.w.chbash & 0xfc) << 8;
|
||||
antic.modelines = 16 - (vscrol_subtract & 15);
|
||||
if( antic.w.chactl & 4 ) /* decrement chbasl? */
|
||||
antic.w.chbasl = antic.modelines - 1;
|
||||
break;
|
||||
case 0x06:
|
||||
LMS(new_cmd);
|
||||
antic.chbase = (antic.w.chbash & 0xfe) << 8;
|
||||
antic.modelines = 8 - (vscrol_subtract & 7);
|
||||
if( antic.w.chactl & 4 ) /* decrement chbasl? */
|
||||
antic.w.chbasl = antic.modelines - 1;
|
||||
break;
|
||||
case 0x07:
|
||||
LMS(new_cmd);
|
||||
antic.chbase = (antic.w.chbash & 0xfe) << 8;
|
||||
antic.modelines = 16 - (vscrol_subtract & 15);
|
||||
if( antic.w.chactl & 4 ) /* decrement chbasl? */
|
||||
antic.w.chbasl = antic.modelines - 1;
|
||||
break;
|
||||
case 0x08:
|
||||
LMS(new_cmd);
|
||||
antic.modelines = 8 - (vscrol_subtract & 7);
|
||||
break;
|
||||
case 0x09:
|
||||
LMS(new_cmd);
|
||||
antic.modelines = 4 - (vscrol_subtract & 3);
|
||||
break;
|
||||
case 0x0a:
|
||||
LMS(new_cmd);
|
||||
antic.modelines = 4 - (vscrol_subtract & 3);
|
||||
break;
|
||||
case 0x0b:
|
||||
LMS(new_cmd);
|
||||
antic.modelines = 2 - (vscrol_subtract & 1);
|
||||
break;
|
||||
case 0x0c:
|
||||
LMS(new_cmd);
|
||||
antic.modelines = 1;
|
||||
break;
|
||||
case 0x0d:
|
||||
LMS(new_cmd);
|
||||
antic.modelines = 2 - (vscrol_subtract & 1);
|
||||
break;
|
||||
case 0x0e:
|
||||
LMS(new_cmd);
|
||||
antic.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_antic_render2 = 16; break;
|
||||
case 2: m_antic_render2 = 17; break;
|
||||
case 3: m_antic_render2 = 18; break;
|
||||
}
|
||||
antic.modelines = 1;
|
||||
break;
|
||||
}
|
||||
/* set new (current) antic command */
|
||||
antic.cmd = new_cmd;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG((" out of visible range\n"));
|
||||
antic.cmd = 0x00;
|
||||
m_antic_render1 = 0;
|
||||
m_antic_render2 = 0;
|
||||
m_antic_render3 = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG((" DMA is off\n"));
|
||||
antic.cmd = 0x00;
|
||||
m_antic_render1 = 0;
|
||||
m_antic_render2 = 0;
|
||||
m_antic_render3 = 0;
|
||||
}
|
||||
|
||||
antic.r.nmist &= ~DLI_NMI;
|
||||
if( antic.modelines == 1 && (antic.cmd & antic.w.nmien & DLI_NMI) )
|
||||
after(CYCLES_DLI_NMI, timer_expired_delegate(FUNC(atari_common_state::antic_issue_dli),this));
|
||||
|
||||
after(CYCLES_HSTART, timer_expired_delegate(FUNC(atari_common_state::antic_scanline_render),this));
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
|
Loading…
Reference in New Issue
Block a user