05077: All playable sets in missile.c: Graphics corrupt in Missile Command [Phil Bennett]

Also moved some functions into the missile_state class -nw-
This commit is contained in:
Phil Bennett 2012-12-20 13:38:39 +00:00
parent 2a45b1ddc3
commit 5c8efb9b55

View File

@ -370,8 +370,7 @@ public:
UINT8 m_irq_state;
UINT8 m_ctrld;
UINT8 m_flipscreen;
UINT8 m_madsel_delay;
UINT16 m_madsel_lastpc;
UINT64 m_madsel_lastcycles;
DECLARE_WRITE8_MEMBER(missile_w);
DECLARE_READ8_MEMBER(missile_r);
@ -382,6 +381,15 @@ public:
virtual void machine_start();
virtual void machine_reset();
UINT32 screen_update_missile(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
inline int scanline_to_v(int scanline);
inline int v_to_scanline(int v);
inline void schedule_next_irq(int curv);
inline bool get_madsel();
inline offs_t get_bit3_addr(offs_t pixaddr);
void write_vram(address_space &space, offs_t address, UINT8 data);
UINT8 read_vram(address_space &space, offs_t address);
TIMER_CALLBACK_MEMBER(clock_irq);
TIMER_CALLBACK_MEMBER(adjust_cpu_speed);
};
@ -406,35 +414,34 @@ public:
*
*************************************/
INLINE int scanline_to_v(missile_state *state, int scanline)
int missile_state::scanline_to_v(int scanline)
{
/* since the vertical sync counter counts backwards when flipped,
this function returns the current effective V value, given
that vpos() only counts forward */
return state->m_flipscreen ? (256 - scanline) : scanline;
return m_flipscreen ? (256 - scanline) : scanline;
}
INLINE int v_to_scanline(missile_state *state, int v)
int missile_state::v_to_scanline(int v)
{
/* same as a above, but the opposite transformation */
return state->m_flipscreen ? (256 - v) : v;
return m_flipscreen ? (256 - v) : v;
}
INLINE void schedule_next_irq(running_machine &machine, int curv)
void missile_state::schedule_next_irq(int curv)
{
missile_state *state = machine.driver_data<missile_state>();
/* IRQ = /32V, clocked by /16V ^ flip */
/* When not flipped, clocks on 0, 64, 128, 192 */
/* When flipped, clocks on 16, 80, 144, 208 */
if (state->m_flipscreen)
if (m_flipscreen)
curv = ((curv - 32) & 0xff) | 0x10;
else
curv = ((curv + 32) & 0xff) & ~0x10;
/* next one at the start of this scanline */
state->m_irq_timer->adjust(machine.primary_screen->time_until_pos(v_to_scanline(state, curv)), curv);
m_irq_timer->adjust(machine().primary_screen->time_until_pos(v_to_scanline(curv)), curv);
}
@ -447,17 +454,16 @@ TIMER_CALLBACK_MEMBER(missile_state::clock_irq)
m_maincpu->set_input_line(0, m_irq_state ? ASSERT_LINE : CLEAR_LINE);
/* force an update while we're here */
machine().primary_screen->update_partial(v_to_scanline(this, curv));
machine().primary_screen->update_partial(v_to_scanline(curv));
/* find the next edge */
schedule_next_irq(machine(), curv);
schedule_next_irq(curv);
}
CUSTOM_INPUT_MEMBER(missile_state::get_vblank)
{
missile_state *state = machine().driver_data<missile_state>();
int v = scanline_to_v(state, machine().primary_screen->vpos());
int v = scanline_to_v(machine().primary_screen->vpos());
return v < 24;
}
@ -481,32 +487,7 @@ TIMER_CALLBACK_MEMBER(missile_state::adjust_cpu_speed)
/* scanline for the next run */
curv ^= 224;
m_cpu_timer->adjust(machine().primary_screen->time_until_pos(v_to_scanline(this, curv)), curv);
}
DIRECT_UPDATE_MEMBER(missile_state::missile_direct_handler)
{
/* offset accounts for lack of A15 decoding */
int offset = address & 0x8000;
address &= 0x7fff;
/* RAM? */
if (address < 0x4000)
{
direct.explicit_configure(0x0000 | offset, 0x3fff | offset, 0x3fff, m_videoram);
return ~0;
}
/* ROM? */
else if (address >= 0x5000)
{
direct.explicit_configure(0x5000 | offset, 0x7fff | offset, 0x7fff, direct.space().machine().root_device().memregion("maincpu")->base() + 0x5000);
return ~0;
}
/* anything else falls through */
return address;
m_cpu_timer->adjust(machine().primary_screen->time_until_pos(v_to_scanline(curv)), curv);
}
@ -517,25 +498,20 @@ void missile_state::machine_start()
m_writeprom = memregion("proms")->base();
m_flipscreen = 0;
/* set up an opcode base handler since we use mapped handlers for RAM */
address_space &space = m_maincpu->space(AS_PROGRAM);
space.set_direct_update_handler(direct_update_delegate(FUNC(missile_state::missile_direct_handler), this));
/* create a timer to speed/slow the CPU */
m_cpu_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(missile_state::adjust_cpu_speed),this));
m_cpu_timer->adjust(machine().primary_screen->time_until_pos(v_to_scanline(this, 0), 0));
m_cpu_timer->adjust(machine().primary_screen->time_until_pos(v_to_scanline(0), 0));
/* create a timer for IRQs and set up the first callback */
m_irq_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(missile_state::clock_irq),this));
m_irq_state = 0;
schedule_next_irq(machine(), -32);
schedule_next_irq(-32);
/* setup for save states */
save_item(NAME(m_irq_state));
save_item(NAME(m_ctrld));
save_item(NAME(m_flipscreen));
save_item(NAME(m_madsel_delay));
save_item(NAME(m_madsel_lastpc));
save_item(NAME(m_madsel_lastcycles));
}
@ -543,43 +519,38 @@ void missile_state::machine_reset()
{
m_maincpu->set_input_line(0, CLEAR_LINE);
m_irq_state = 0;
m_madsel_lastcycles = 0;
}
/*************************************
*
* VRAM access override
* VRAM access
*
*************************************/
INLINE int get_madsel(address_space &space)
bool missile_state::get_madsel()
{
missile_state *state = space.machine().driver_data<missile_state>();
UINT16 pc = space.device().safe_pcbase();
/* the MADSEL signal disables standard address decoding and routes
writes to video RAM; it goes high 5 cycles after an opcode
fetch where the low 5 bits are 0x01 and the IRQ signal is clear.
*/
bool madsel = false;
/* if we're at a different instruction than last time, reset our delay counter */
if (pc != state->m_madsel_lastpc)
state->m_madsel_delay = 0;
/* MADSEL signal disables standard address decoding and routes
writes to video RAM; it is enabled if the IRQ signal is clear
and the low 5 bits of the fetched opcode are 0x01 */
if (!state->m_irq_state && (space.direct().read_decrypted_byte(pc) & 0x1f) == 0x01)
if (m_madsel_lastcycles)
{
/* the MADSEL signal goes high 5 cycles after the opcode is identified;
this effectively skips the indirect memory read. Since this is difficult
to do in MAME, we just ignore the first two positive hits on MADSEL
and only return TRUE on the third or later */
state->m_madsel_lastpc = pc;
return (++state->m_madsel_delay >= 4);
}
state->m_madsel_delay = 0;
return 0;
madsel = (m_maincpu->total_cycles() - m_madsel_lastcycles) == 5;
/* reset the count until next time */
if (madsel)
m_madsel_lastcycles = 0;
}
return madsel;
}
INLINE offs_t get_bit3_addr(offs_t pixaddr)
offs_t missile_state::get_bit3_addr(offs_t pixaddr)
{
/* the 3rd bit of video RAM is scattered about various areas
we take a 16-bit pixel address here and convert it into
@ -591,10 +562,8 @@ INLINE offs_t get_bit3_addr(offs_t pixaddr)
}
static void write_vram(address_space &space, offs_t address, UINT8 data)
void missile_state::write_vram(address_space &space, offs_t address, UINT8 data)
{
missile_state *state = space.machine().driver_data<missile_state>();
UINT8 *videoram = state->m_videoram;
static const UINT8 data_lookup[4] = { 0x00, 0x0f, 0xf0, 0xff };
offs_t vramaddr;
UINT8 vramdata;
@ -605,8 +574,8 @@ static void write_vram(address_space &space, offs_t address, UINT8 data)
/* this should only be called if MADSEL == 1 */
vramaddr = address >> 2;
vramdata = data_lookup[data >> 6];
vrammask = state->m_writeprom[(address & 7) | 0x10];
videoram[vramaddr] = (videoram[vramaddr] & vrammask) | (vramdata & ~vrammask);
vrammask = m_writeprom[(address & 7) | 0x10];
m_videoram[vramaddr] = (m_videoram[vramaddr] & vrammask) | (vramdata & ~vrammask);
/* 3-bit VRAM writes use an extra clock to write the 3rd bit elsewhere */
/* on the schematics, this is the MUSHROOM == 1 case */
@ -614,8 +583,8 @@ static void write_vram(address_space &space, offs_t address, UINT8 data)
{
vramaddr = get_bit3_addr(address);
vramdata = -((data >> 5) & 1);
vrammask = state->m_writeprom[(address & 7) | 0x18];
videoram[vramaddr] = (videoram[vramaddr] & vrammask) | (vramdata & ~vrammask);
vrammask = m_writeprom[(address & 7) | 0x18];
m_videoram[vramaddr] = (m_videoram[vramaddr] & vrammask) | (vramdata & ~vrammask);
/* account for the extra clock cycle */
space.device().execute().adjust_icount(-1);
@ -623,10 +592,8 @@ static void write_vram(address_space &space, offs_t address, UINT8 data)
}
static UINT8 read_vram(address_space &space, offs_t address)
UINT8 missile_state::read_vram(address_space &space, offs_t address)
{
missile_state *state = space.machine().driver_data<missile_state>();
UINT8 *videoram = state->m_videoram;
offs_t vramaddr;
UINT8 vramdata;
UINT8 vrammask;
@ -637,7 +604,7 @@ static UINT8 read_vram(address_space &space, offs_t address)
/* this should only be called if MADSEL == 1 */
vramaddr = address >> 2;
vrammask = 0x11 << (address & 3);
vramdata = videoram[vramaddr] & vrammask;
vramdata = m_videoram[vramaddr] & vrammask;
if ((vramdata & 0xf0) == 0)
result &= ~0x80;
if ((vramdata & 0x0f) == 0)
@ -649,7 +616,7 @@ static UINT8 read_vram(address_space &space, offs_t address)
{
vramaddr = get_bit3_addr(address);
vrammask = 1 << (address & 7);
vramdata = videoram[vramaddr] & vrammask;
vramdata = m_videoram[vramaddr] & vrammask;
if (vramdata == 0)
result &= ~0x20;
@ -713,8 +680,8 @@ WRITE8_MEMBER(missile_state::missile_w)
{
UINT8 *videoram = m_videoram;
/* if we're in MADSEL mode, write to video RAM */
if (get_madsel(space))
/* if this is a MADSEL cycle, write to video RAM */
if (get_madsel())
{
write_vram(space, offset, data);
return;
@ -775,8 +742,8 @@ READ8_MEMBER(missile_state::missile_r)
UINT8 *videoram = m_videoram;
UINT8 result = 0xff;
/* if we're in MADSEL mode, read from video RAM */
if (get_madsel(space))
/* if this is a MADSEL cycle, read from video RAM */
if (get_madsel())
return read_vram(space, offset);
/* otherwise, strip A15 and handle manually */
@ -822,6 +789,12 @@ READ8_MEMBER(missile_state::missile_r)
/* anything else */
else
logerror("%04X:Unknown read from %04X\n", space.device().safe_pc(), offset);
/* update the MADSEL state */
if (!m_irq_state && ((result & 0x1f) == 0x01) && m_maincpu->get_sync())
m_madsel_lastcycles = m_maincpu->total_cycles();
return result;
}