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:
parent
2a45b1ddc3
commit
5c8efb9b55
@ -370,8 +370,7 @@ public:
|
|||||||
UINT8 m_irq_state;
|
UINT8 m_irq_state;
|
||||||
UINT8 m_ctrld;
|
UINT8 m_ctrld;
|
||||||
UINT8 m_flipscreen;
|
UINT8 m_flipscreen;
|
||||||
UINT8 m_madsel_delay;
|
UINT64 m_madsel_lastcycles;
|
||||||
UINT16 m_madsel_lastpc;
|
|
||||||
|
|
||||||
DECLARE_WRITE8_MEMBER(missile_w);
|
DECLARE_WRITE8_MEMBER(missile_w);
|
||||||
DECLARE_READ8_MEMBER(missile_r);
|
DECLARE_READ8_MEMBER(missile_r);
|
||||||
@ -382,6 +381,15 @@ public:
|
|||||||
virtual void machine_start();
|
virtual void machine_start();
|
||||||
virtual void machine_reset();
|
virtual void machine_reset();
|
||||||
UINT32 screen_update_missile(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
|
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(clock_irq);
|
||||||
TIMER_CALLBACK_MEMBER(adjust_cpu_speed);
|
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,
|
/* since the vertical sync counter counts backwards when flipped,
|
||||||
this function returns the current effective V value, given
|
this function returns the current effective V value, given
|
||||||
that vpos() only counts forward */
|
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 */
|
/* 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 */
|
/* IRQ = /32V, clocked by /16V ^ flip */
|
||||||
/* When not flipped, clocks on 0, 64, 128, 192 */
|
/* When not flipped, clocks on 0, 64, 128, 192 */
|
||||||
/* When flipped, clocks on 16, 80, 144, 208 */
|
/* When flipped, clocks on 16, 80, 144, 208 */
|
||||||
if (state->m_flipscreen)
|
if (m_flipscreen)
|
||||||
curv = ((curv - 32) & 0xff) | 0x10;
|
curv = ((curv - 32) & 0xff) | 0x10;
|
||||||
else
|
else
|
||||||
curv = ((curv + 32) & 0xff) & ~0x10;
|
curv = ((curv + 32) & 0xff) & ~0x10;
|
||||||
|
|
||||||
/* next one at the start of this scanline */
|
/* 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);
|
m_maincpu->set_input_line(0, m_irq_state ? ASSERT_LINE : CLEAR_LINE);
|
||||||
|
|
||||||
/* force an update while we're here */
|
/* 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 */
|
/* find the next edge */
|
||||||
schedule_next_irq(machine(), curv);
|
schedule_next_irq(curv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
CUSTOM_INPUT_MEMBER(missile_state::get_vblank)
|
CUSTOM_INPUT_MEMBER(missile_state::get_vblank)
|
||||||
{
|
{
|
||||||
missile_state *state = machine().driver_data<missile_state>();
|
int v = scanline_to_v(machine().primary_screen->vpos());
|
||||||
int v = scanline_to_v(state, machine().primary_screen->vpos());
|
|
||||||
return v < 24;
|
return v < 24;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -481,32 +487,7 @@ TIMER_CALLBACK_MEMBER(missile_state::adjust_cpu_speed)
|
|||||||
|
|
||||||
/* scanline for the next run */
|
/* scanline for the next run */
|
||||||
curv ^= 224;
|
curv ^= 224;
|
||||||
m_cpu_timer->adjust(machine().primary_screen->time_until_pos(v_to_scanline(this, curv)), curv);
|
m_cpu_timer->adjust(machine().primary_screen->time_until_pos(v_to_scanline(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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -517,25 +498,20 @@ void missile_state::machine_start()
|
|||||||
m_writeprom = memregion("proms")->base();
|
m_writeprom = memregion("proms")->base();
|
||||||
m_flipscreen = 0;
|
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 */
|
/* 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 = 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 */
|
/* 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_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(missile_state::clock_irq),this));
|
||||||
m_irq_state = 0;
|
m_irq_state = 0;
|
||||||
schedule_next_irq(machine(), -32);
|
schedule_next_irq(-32);
|
||||||
|
|
||||||
/* setup for save states */
|
/* setup for save states */
|
||||||
save_item(NAME(m_irq_state));
|
save_item(NAME(m_irq_state));
|
||||||
save_item(NAME(m_ctrld));
|
save_item(NAME(m_ctrld));
|
||||||
save_item(NAME(m_flipscreen));
|
save_item(NAME(m_flipscreen));
|
||||||
save_item(NAME(m_madsel_delay));
|
save_item(NAME(m_madsel_lastcycles));
|
||||||
save_item(NAME(m_madsel_lastpc));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -543,43 +519,38 @@ void missile_state::machine_reset()
|
|||||||
{
|
{
|
||||||
m_maincpu->set_input_line(0, CLEAR_LINE);
|
m_maincpu->set_input_line(0, CLEAR_LINE);
|
||||||
m_irq_state = 0;
|
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>();
|
/* the MADSEL signal disables standard address decoding and routes
|
||||||
UINT16 pc = space.device().safe_pcbase();
|
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 (m_madsel_lastcycles)
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
/* the MADSEL signal goes high 5 cycles after the opcode is identified;
|
madsel = (m_maincpu->total_cycles() - m_madsel_lastcycles) == 5;
|
||||||
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
|
/* reset the count until next time */
|
||||||
and only return TRUE on the third or later */
|
if (madsel)
|
||||||
state->m_madsel_lastpc = pc;
|
m_madsel_lastcycles = 0;
|
||||||
return (++state->m_madsel_delay >= 4);
|
|
||||||
}
|
|
||||||
state->m_madsel_delay = 0;
|
|
||||||
return 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
|
/* the 3rd bit of video RAM is scattered about various areas
|
||||||
we take a 16-bit pixel address here and convert it into
|
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 };
|
static const UINT8 data_lookup[4] = { 0x00, 0x0f, 0xf0, 0xff };
|
||||||
offs_t vramaddr;
|
offs_t vramaddr;
|
||||||
UINT8 vramdata;
|
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 */
|
/* this should only be called if MADSEL == 1 */
|
||||||
vramaddr = address >> 2;
|
vramaddr = address >> 2;
|
||||||
vramdata = data_lookup[data >> 6];
|
vramdata = data_lookup[data >> 6];
|
||||||
vrammask = state->m_writeprom[(address & 7) | 0x10];
|
vrammask = m_writeprom[(address & 7) | 0x10];
|
||||||
videoram[vramaddr] = (videoram[vramaddr] & vrammask) | (vramdata & ~vrammask);
|
m_videoram[vramaddr] = (m_videoram[vramaddr] & vrammask) | (vramdata & ~vrammask);
|
||||||
|
|
||||||
/* 3-bit VRAM writes use an extra clock to write the 3rd bit elsewhere */
|
/* 3-bit VRAM writes use an extra clock to write the 3rd bit elsewhere */
|
||||||
/* on the schematics, this is the MUSHROOM == 1 case */
|
/* 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);
|
vramaddr = get_bit3_addr(address);
|
||||||
vramdata = -((data >> 5) & 1);
|
vramdata = -((data >> 5) & 1);
|
||||||
vrammask = state->m_writeprom[(address & 7) | 0x18];
|
vrammask = m_writeprom[(address & 7) | 0x18];
|
||||||
videoram[vramaddr] = (videoram[vramaddr] & vrammask) | (vramdata & ~vrammask);
|
m_videoram[vramaddr] = (m_videoram[vramaddr] & vrammask) | (vramdata & ~vrammask);
|
||||||
|
|
||||||
/* account for the extra clock cycle */
|
/* account for the extra clock cycle */
|
||||||
space.device().execute().adjust_icount(-1);
|
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;
|
offs_t vramaddr;
|
||||||
UINT8 vramdata;
|
UINT8 vramdata;
|
||||||
UINT8 vrammask;
|
UINT8 vrammask;
|
||||||
@ -637,7 +604,7 @@ static UINT8 read_vram(address_space &space, offs_t address)
|
|||||||
/* this should only be called if MADSEL == 1 */
|
/* this should only be called if MADSEL == 1 */
|
||||||
vramaddr = address >> 2;
|
vramaddr = address >> 2;
|
||||||
vrammask = 0x11 << (address & 3);
|
vrammask = 0x11 << (address & 3);
|
||||||
vramdata = videoram[vramaddr] & vrammask;
|
vramdata = m_videoram[vramaddr] & vrammask;
|
||||||
if ((vramdata & 0xf0) == 0)
|
if ((vramdata & 0xf0) == 0)
|
||||||
result &= ~0x80;
|
result &= ~0x80;
|
||||||
if ((vramdata & 0x0f) == 0)
|
if ((vramdata & 0x0f) == 0)
|
||||||
@ -649,7 +616,7 @@ static UINT8 read_vram(address_space &space, offs_t address)
|
|||||||
{
|
{
|
||||||
vramaddr = get_bit3_addr(address);
|
vramaddr = get_bit3_addr(address);
|
||||||
vrammask = 1 << (address & 7);
|
vrammask = 1 << (address & 7);
|
||||||
vramdata = videoram[vramaddr] & vrammask;
|
vramdata = m_videoram[vramaddr] & vrammask;
|
||||||
if (vramdata == 0)
|
if (vramdata == 0)
|
||||||
result &= ~0x20;
|
result &= ~0x20;
|
||||||
|
|
||||||
@ -713,8 +680,8 @@ WRITE8_MEMBER(missile_state::missile_w)
|
|||||||
{
|
{
|
||||||
UINT8 *videoram = m_videoram;
|
UINT8 *videoram = m_videoram;
|
||||||
|
|
||||||
/* if we're in MADSEL mode, write to video RAM */
|
/* if this is a MADSEL cycle, write to video RAM */
|
||||||
if (get_madsel(space))
|
if (get_madsel())
|
||||||
{
|
{
|
||||||
write_vram(space, offset, data);
|
write_vram(space, offset, data);
|
||||||
return;
|
return;
|
||||||
@ -775,8 +742,8 @@ READ8_MEMBER(missile_state::missile_r)
|
|||||||
UINT8 *videoram = m_videoram;
|
UINT8 *videoram = m_videoram;
|
||||||
UINT8 result = 0xff;
|
UINT8 result = 0xff;
|
||||||
|
|
||||||
/* if we're in MADSEL mode, read from video RAM */
|
/* if this is a MADSEL cycle, read from video RAM */
|
||||||
if (get_madsel(space))
|
if (get_madsel())
|
||||||
return read_vram(space, offset);
|
return read_vram(space, offset);
|
||||||
|
|
||||||
/* otherwise, strip A15 and handle manually */
|
/* otherwise, strip A15 and handle manually */
|
||||||
@ -822,6 +789,12 @@ READ8_MEMBER(missile_state::missile_r)
|
|||||||
/* anything else */
|
/* anything else */
|
||||||
else
|
else
|
||||||
logerror("%04X:Unknown read from %04X\n", space.device().safe_pc(), offset);
|
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;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user