Previous 199869 Revisions Next

r19701 Thursday 20th December, 2012 at 13:38:39 UTC by Phil Bennett
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

trunk/src/mame/drivers/missile.c
r19700r19701
370370   UINT8 m_irq_state;
371371   UINT8 m_ctrld;
372372   UINT8 m_flipscreen;
373   UINT8 m_madsel_delay;
374   UINT16 m_madsel_lastpc;
373   UINT64 m_madsel_lastcycles;
375374
376375   DECLARE_WRITE8_MEMBER(missile_w);
377376   DECLARE_READ8_MEMBER(missile_r);
r19700r19701
382381   virtual void machine_start();
383382   virtual void machine_reset();
384383   UINT32 screen_update_missile(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
384
385   inline int scanline_to_v(int scanline);
386   inline int v_to_scanline(int v);
387   inline void schedule_next_irq(int curv);
388   inline bool get_madsel();
389   inline offs_t get_bit3_addr(offs_t pixaddr);
390   void write_vram(address_space &space, offs_t address, UINT8 data);
391   UINT8 read_vram(address_space &space, offs_t address);
392
385393   TIMER_CALLBACK_MEMBER(clock_irq);
386394   TIMER_CALLBACK_MEMBER(adjust_cpu_speed);
387395};
r19700r19701
406414 *
407415 *************************************/
408416
409INLINE int scanline_to_v(missile_state *state, int scanline)
417int missile_state::scanline_to_v(int scanline)
410418{
411419   /* since the vertical sync counter counts backwards when flipped,
412420        this function returns the current effective V value, given
413421        that vpos() only counts forward */
414   return state->m_flipscreen ? (256 - scanline) : scanline;
422   return m_flipscreen ? (256 - scanline) : scanline;
415423}
416424
417425
418INLINE int v_to_scanline(missile_state *state, int v)
426int missile_state::v_to_scanline(int v)
419427{
420428   /* same as a above, but the opposite transformation */
421   return state->m_flipscreen ? (256 - v) : v;
429   return m_flipscreen ? (256 - v) : v;
422430}
423431
424432
425INLINE void schedule_next_irq(running_machine &machine, int curv)
433void missile_state::schedule_next_irq(int curv)
426434{
427   missile_state *state = machine.driver_data<missile_state>();
428435   /* IRQ = /32V, clocked by /16V ^ flip */
429436   /* When not flipped, clocks on 0, 64, 128, 192 */
430437   /* When flipped, clocks on 16, 80, 144, 208 */
431   if (state->m_flipscreen)
438   if (m_flipscreen)
432439      curv = ((curv - 32) & 0xff) | 0x10;
433440   else
434441      curv = ((curv + 32) & 0xff) & ~0x10;
435442
436443   /* next one at the start of this scanline */
437   state->m_irq_timer->adjust(machine.primary_screen->time_until_pos(v_to_scanline(state, curv)), curv);
444   m_irq_timer->adjust(machine().primary_screen->time_until_pos(v_to_scanline(curv)), curv);
438445}
439446
440447
r19700r19701
447454   m_maincpu->set_input_line(0, m_irq_state ? ASSERT_LINE : CLEAR_LINE);
448455
449456   /* force an update while we're here */
450   machine().primary_screen->update_partial(v_to_scanline(this, curv));
457   machine().primary_screen->update_partial(v_to_scanline(curv));
451458
452459   /* find the next edge */
453   schedule_next_irq(machine(), curv);
460   schedule_next_irq(curv);
454461}
455462
456463
457464CUSTOM_INPUT_MEMBER(missile_state::get_vblank)
458465{
459   missile_state *state = machine().driver_data<missile_state>();
460   int v = scanline_to_v(state, machine().primary_screen->vpos());
466   int v = scanline_to_v(machine().primary_screen->vpos());
461467   return v < 24;
462468}
463469
r19700r19701
481487
482488   /* scanline for the next run */
483489   curv ^= 224;
484   m_cpu_timer->adjust(machine().primary_screen->time_until_pos(v_to_scanline(this, curv)), curv);
490   m_cpu_timer->adjust(machine().primary_screen->time_until_pos(v_to_scanline(curv)), curv);
485491}
486492
487493
488DIRECT_UPDATE_MEMBER(missile_state::missile_direct_handler)
489{
490   /* offset accounts for lack of A15 decoding */
491   int offset = address & 0x8000;
492   address &= 0x7fff;
493
494   /* RAM? */
495   if (address < 0x4000)
496   {
497      direct.explicit_configure(0x0000 | offset, 0x3fff | offset, 0x3fff, m_videoram);
498      return ~0;
499   }
500
501   /* ROM? */
502   else if (address >= 0x5000)
503   {
504      direct.explicit_configure(0x5000 | offset, 0x7fff | offset, 0x7fff, direct.space().machine().root_device().memregion("maincpu")->base() + 0x5000);
505      return ~0;
506   }
507
508   /* anything else falls through */
509   return address;
510}
511
512
513494void missile_state::machine_start()
514495{
515496
r19700r19701
517498   m_writeprom = memregion("proms")->base();
518499   m_flipscreen = 0;
519500
520   /* set up an opcode base handler since we use mapped handlers for RAM */
521   address_space &space = m_maincpu->space(AS_PROGRAM);
522   space.set_direct_update_handler(direct_update_delegate(FUNC(missile_state::missile_direct_handler), this));
523
524501   /* create a timer to speed/slow the CPU */
525502   m_cpu_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(missile_state::adjust_cpu_speed),this));
526   m_cpu_timer->adjust(machine().primary_screen->time_until_pos(v_to_scanline(this, 0), 0));
503   m_cpu_timer->adjust(machine().primary_screen->time_until_pos(v_to_scanline(0), 0));
527504
528505   /* create a timer for IRQs and set up the first callback */
529506   m_irq_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(missile_state::clock_irq),this));
530507   m_irq_state = 0;
531   schedule_next_irq(machine(), -32);
508   schedule_next_irq(-32);
532509
533510   /* setup for save states */
534511   save_item(NAME(m_irq_state));
535512   save_item(NAME(m_ctrld));
536513   save_item(NAME(m_flipscreen));
537   save_item(NAME(m_madsel_delay));
538   save_item(NAME(m_madsel_lastpc));
514   save_item(NAME(m_madsel_lastcycles));
539515}
540516
541517
r19700r19701
543519{
544520   m_maincpu->set_input_line(0, CLEAR_LINE);
545521   m_irq_state = 0;
522   m_madsel_lastcycles = 0;
546523}
547524
548525
549526
550527/*************************************
551528 *
552 *  VRAM access override
529 *  VRAM access
553530 *
554531 *************************************/
555532
556INLINE int get_madsel(address_space &space)
533bool missile_state::get_madsel()
557534{
558   missile_state *state = space.machine().driver_data<missile_state>();
559   UINT16 pc = space.device().safe_pcbase();
535   /* the MADSEL signal disables standard address decoding and routes
536      writes to video RAM; it goes high 5 cycles after an opcode
537      fetch where the low 5 bits are 0x01 and the IRQ signal is clear.
538   */
539   bool madsel = false;
560540
561   /* if we're at a different instruction than last time, reset our delay counter */
562   if (pc != state->m_madsel_lastpc)
563      state->m_madsel_delay = 0;
564
565   /* MADSEL signal disables standard address decoding and routes
566        writes to video RAM; it is enabled if the IRQ signal is clear
567        and the low 5 bits of the fetched opcode are 0x01 */
568   if (!state->m_irq_state && (space.direct().read_decrypted_byte(pc) & 0x1f) == 0x01)
541   if (m_madsel_lastcycles)
569542   {
570      /* the MADSEL signal goes high 5 cycles after the opcode is identified;
571            this effectively skips the indirect memory read. Since this is difficult
572            to do in MAME, we just ignore the first two positive hits on MADSEL
573            and only return TRUE on the third or later */
574      state->m_madsel_lastpc = pc;
575      return (++state->m_madsel_delay >= 4);
543      madsel = (m_maincpu->total_cycles() - m_madsel_lastcycles) == 5;
544
545      /* reset the count until next time */
546      if (madsel)
547         m_madsel_lastcycles = 0;
576548   }
577   state->m_madsel_delay = 0;
578   return 0;
549
550   return madsel;
579551}
580552
581
582INLINE offs_t get_bit3_addr(offs_t pixaddr)
553offs_t missile_state::get_bit3_addr(offs_t pixaddr)
583554{
584555   /* the 3rd bit of video RAM is scattered about various areas
585556        we take a 16-bit pixel address here and convert it into
r19700r19701
591562}
592563
593564
594static void write_vram(address_space &space, offs_t address, UINT8 data)
565void missile_state::write_vram(address_space &space, offs_t address, UINT8 data)
595566{
596   missile_state *state = space.machine().driver_data<missile_state>();
597   UINT8 *videoram = state->m_videoram;
598567   static const UINT8 data_lookup[4] = { 0x00, 0x0f, 0xf0, 0xff };
599568   offs_t vramaddr;
600569   UINT8 vramdata;
r19700r19701
605574   /* this should only be called if MADSEL == 1 */
606575   vramaddr = address >> 2;
607576   vramdata = data_lookup[data >> 6];
608   vrammask = state->m_writeprom[(address & 7) | 0x10];
609   videoram[vramaddr] = (videoram[vramaddr] & vrammask) | (vramdata & ~vrammask);
577   vrammask = m_writeprom[(address & 7) | 0x10];
578   m_videoram[vramaddr] = (m_videoram[vramaddr] & vrammask) | (vramdata & ~vrammask);
610579
611580   /* 3-bit VRAM writes use an extra clock to write the 3rd bit elsewhere */
612581   /* on the schematics, this is the MUSHROOM == 1 case */
r19700r19701
614583   {
615584      vramaddr = get_bit3_addr(address);
616585      vramdata = -((data >> 5) & 1);
617      vrammask = state->m_writeprom[(address & 7) | 0x18];
618      videoram[vramaddr] = (videoram[vramaddr] & vrammask) | (vramdata & ~vrammask);
586      vrammask = m_writeprom[(address & 7) | 0x18];
587      m_videoram[vramaddr] = (m_videoram[vramaddr] & vrammask) | (vramdata & ~vrammask);
619588
620589      /* account for the extra clock cycle */
621590      space.device().execute().adjust_icount(-1);
r19700r19701
623592}
624593
625594
626static UINT8 read_vram(address_space &space, offs_t address)
595UINT8 missile_state::read_vram(address_space &space, offs_t address)
627596{
628   missile_state *state = space.machine().driver_data<missile_state>();
629   UINT8 *videoram = state->m_videoram;
630597   offs_t vramaddr;
631598   UINT8 vramdata;
632599   UINT8 vrammask;
r19700r19701
637604   /* this should only be called if MADSEL == 1 */
638605   vramaddr = address >> 2;
639606   vrammask = 0x11 << (address & 3);
640   vramdata = videoram[vramaddr] & vrammask;
607   vramdata = m_videoram[vramaddr] & vrammask;
641608   if ((vramdata & 0xf0) == 0)
642609      result &= ~0x80;
643610   if ((vramdata & 0x0f) == 0)
r19700r19701
649616   {
650617      vramaddr = get_bit3_addr(address);
651618      vrammask = 1 << (address & 7);
652      vramdata = videoram[vramaddr] & vrammask;
619      vramdata = m_videoram[vramaddr] & vrammask;
653620      if (vramdata == 0)
654621         result &= ~0x20;
655622
r19700r19701
713680{
714681   UINT8 *videoram = m_videoram;
715682
716   /* if we're in MADSEL mode, write to video RAM */
717   if (get_madsel(space))
683   /* if this is a MADSEL cycle, write to video RAM */
684   if (get_madsel())
718685   {
719686      write_vram(space, offset, data);
720687      return;
r19700r19701
775742   UINT8 *videoram = m_videoram;
776743   UINT8 result = 0xff;
777744
778   /* if we're in MADSEL mode, read from video RAM */
779   if (get_madsel(space))
745   /* if this is a MADSEL cycle, read from video RAM */
746   if (get_madsel())
780747      return read_vram(space, offset);
781748
782749   /* otherwise, strip A15 and handle manually */
r19700r19701
822789   /* anything else */
823790   else
824791      logerror("%04X:Unknown read from %04X\n", space.device().safe_pc(), offset);
792
793
794   /* update the MADSEL state */
795   if (!m_irq_state && ((result & 0x1f) == 0x01) && m_maincpu->get_sync())
796      m_madsel_lastcycles = m_maincpu->total_cycles();
797
825798   return result;
826799}
827800

Previous 199869 Revisions Next


© 1997-2024 The MAME Team