From 5c8efb9b559cfce177099f2613d2da4c5ab53227 Mon Sep 17 00:00:00 2001 From: Phil Bennett Date: Thu, 20 Dec 2012 13:38:39 +0000 Subject: [PATCH] 05077: All playable sets in missile.c: Graphics corrupt in Missile Command [Phil Bennett] Also moved some functions into the missile_state class -nw- --- src/mame/drivers/missile.c | 145 +++++++++++++++---------------------- 1 file changed, 59 insertions(+), 86 deletions(-) diff --git a/src/mame/drivers/missile.c b/src/mame/drivers/missile.c index cfb94113c4b..ba7cf9e3aeb 100644 --- a/src/mame/drivers/missile.c +++ b/src/mame/drivers/missile.c @@ -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(); /* 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(); - 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(); - 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); + madsel = (m_maincpu->total_cycles() - m_madsel_lastcycles) == 5; + + /* reset the count until next time */ + if (madsel) + m_madsel_lastcycles = 0; } - 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 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(); - 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(); - 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; }