diff options
Diffstat (limited to 'src/mame/machine/mcr.c')
-rw-r--r-- | src/mame/machine/mcr.c | 1026 |
1 files changed, 1026 insertions, 0 deletions
diff --git a/src/mame/machine/mcr.c b/src/mame/machine/mcr.c new file mode 100644 index 00000000000..82dc807d1ac --- /dev/null +++ b/src/mame/machine/mcr.c @@ -0,0 +1,1026 @@ +/*************************************************************************** + + Midway MCR system + +***************************************************************************/ + +#include "driver.h" +#include "machine/z80ctc.h" +#include "machine/z80pio.h" +#include "machine/z80sio.h" +#include "audio/mcr.h" +#include "cpu/m6800/m6800.h" +#include "cpu/m6809/m6809.h" +#include "cpu/z80/z80.h" +#include "cpu/z80/z80daisy.h" +#include "mcr.h" + + +#define LOG(x) logerror x + + +/************************************* + * + * Global variables + * + *************************************/ + +attotime mcr68_timing_factor; + +UINT8 mcr_cocktail_flip; + +UINT32 mcr_cpu_board; +UINT32 mcr_sprite_board; +UINT32 mcr_ssio_board; + + + +/************************************* + * + * Statics + * + *************************************/ + +static UINT8 m6840_status; +static UINT8 m6840_status_read_since_int; +static UINT8 m6840_msb_buffer; +static UINT8 m6840_lsb_buffer; +static struct counter_state +{ + UINT8 control; + UINT16 latch; + UINT16 count; + emu_timer * timer; + UINT8 timer_active; + attotime period; +} m6840_state[3]; + +/* MCR/68k interrupt states */ +static UINT8 m6840_irq_state; +static UINT8 m6840_irq_vector; +static UINT8 v493_irq_state; +static UINT8 v493_irq_vector; + +static void (*v493_callback)(running_machine *machine, int param); + +static UINT8 zwackery_sound_data; + +static attotime m6840_counter_periods[3]; +static attotime m6840_internal_counter_period; /* 68000 CLK / 10 */ + +static emu_timer *ipu_watchdog_timer; + + + +/************************************* + * + * Function prototypes + * + *************************************/ + +static void subtract_from_counter(int counter, int count); + +static TIMER_CALLBACK( mcr68_493_callback ); +static TIMER_CALLBACK( zwackery_493_callback ); + +static WRITE8_HANDLER( zwackery_pia_2_w ); +static WRITE8_HANDLER( zwackery_pia_3_w ); +static WRITE8_HANDLER( zwackery_ca2_w ); +static void zwackery_pia_irq(int state); + +static void reload_count(int counter); +static TIMER_CALLBACK( counter_fired_callback ); +static TIMER_CALLBACK( ipu_watchdog_reset ); +static WRITE8_HANDLER( ipu_break_changed ); + + + +/************************************* + * + * Graphics declarations + * + *************************************/ + +gfx_layout mcr_bg_layout = +{ + 8,8, + RGN_FRAC(1,2), + 4, + { STEP2(RGN_FRAC(1,2),1), STEP2(RGN_FRAC(0,2),1) }, + { STEP8(0,2) }, + { STEP8(0,16) }, + 16*8 +}; + + +gfx_layout mcr_sprite_layout = +{ + 32,32, + RGN_FRAC(1,4), + 4, + { STEP4(0,1) }, + { STEP2(RGN_FRAC(0,4)+0,4), STEP2(RGN_FRAC(1,4)+0,4), STEP2(RGN_FRAC(2,4)+0,4), STEP2(RGN_FRAC(3,4)+0,4), + STEP2(RGN_FRAC(0,4)+8,4), STEP2(RGN_FRAC(1,4)+8,4), STEP2(RGN_FRAC(2,4)+8,4), STEP2(RGN_FRAC(3,4)+8,4), + STEP2(RGN_FRAC(0,4)+16,4), STEP2(RGN_FRAC(1,4)+16,4), STEP2(RGN_FRAC(2,4)+16,4), STEP2(RGN_FRAC(3,4)+16,4), + STEP2(RGN_FRAC(0,4)+24,4), STEP2(RGN_FRAC(1,4)+24,4), STEP2(RGN_FRAC(2,4)+24,4), STEP2(RGN_FRAC(3,4)+24,4) }, + { STEP32(0,32) }, + 32*32 +}; + + + +/************************************* + * + * 6821 PIA declarations + * + *************************************/ + +READ8_HANDLER( zwackery_port_2_r ); + + +static READ8_HANDLER( zwackery_port_1_r ) +{ + UINT8 ret = readinputport(1); + + pia_set_port_a_z_mask(3, ret); + + return ret; +} + + +static READ8_HANDLER( zwackery_port_3_r ) +{ + UINT8 ret = readinputport(3); + + pia_set_port_a_z_mask(4, ret); + + return ret; +} + + +static const pia6821_interface zwackery_pia_2_intf = +{ + /*inputs : A/B,CA/B1,CA/B2 */ 0, input_port_0_r, 0, 0, 0, 0, + /*outputs: A/B,CA/B2 */ zwackery_pia_2_w, 0, 0, 0, + /*irqs : A/B */ zwackery_pia_irq, zwackery_pia_irq +}; + +static const pia6821_interface zwackery_pia_3_intf = +{ + /*inputs : A/B,CA/B1,CA/B2 */ zwackery_port_1_r, zwackery_port_2_r, 0, 0, 0, 0, + /*outputs: A/B,CA/B2 */ zwackery_pia_3_w, 0, zwackery_ca2_w, 0, + /*irqs : A/B */ 0, 0 +}; + +static const pia6821_interface zwackery_pia_4_intf = +{ + /*inputs : A/B,CA/B1,CA/B2 */ zwackery_port_3_r, input_port_4_r, 0, 0, 0, 0, + /*outputs: A/B,CA/B2 */ 0, 0, 0, 0, + /*irqs : A/B */ 0, 0 +}; + + + +/************************************* + * + * Generic MCR CTC interface + * + *************************************/ + +static void ctc_interrupt(int state) +{ + cpunum_set_input_line(0, 0, state); +} + + +static void ipu_ctc_interrupt(int state) +{ + cpunum_set_input_line(3, 0, state); +} + + +struct z80_irq_daisy_chain mcr_daisy_chain[] = +{ + { z80ctc_reset, z80ctc_irq_state, z80ctc_irq_ack, z80ctc_irq_reti, 0 }, /* CTC number 0 */ + { 0, 0, 0, 0, -1 } /* end mark */ +}; + + +struct z80_irq_daisy_chain mcr_ipu_daisy_chain[] = +{ + { z80ctc_reset, z80ctc_irq_state, z80ctc_irq_ack, z80ctc_irq_reti, 1 }, /* CTC number 1 */ + { z80pio_reset, z80pio_irq_state, z80pio_irq_ack, z80pio_irq_reti, 1 }, /* PIO number 1 */ + { z80sio_reset, z80sio_irq_state, z80sio_irq_ack, z80sio_irq_reti, 0 }, /* SIO number 0 */ + { z80pio_reset, z80pio_irq_state, z80pio_irq_ack, z80pio_irq_reti, 0 }, /* PIO number 0 */ + { 0, 0, 0, 0, -1 } /* end mark */ +}; + + +static z80ctc_interface ctc_intf = +{ + 0, /* clock (filled in from the CPU 0 clock) */ + 0, /* timer disables */ + ctc_interrupt, /* interrupt handler */ + z80ctc_0_trg1_w, /* ZC/TO0 callback */ + 0, /* ZC/TO1 callback */ + 0 /* ZC/TO2 callback */ +}; + + +static z80ctc_interface nflfoot_ctc_intf = +{ + 0, /* clock (filled in from the CPU 3 clock) */ + 0, /* timer disables */ + ipu_ctc_interrupt, /* interrupt handler */ + 0, /* ZC/TO0 callback */ + 0, /* ZC/TO1 callback */ + 0 /* ZC/TO2 callback */ +}; + + +static z80pio_interface nflfoot_pio_intf = +{ + ipu_ctc_interrupt, + 0, + 0 +}; + + +static z80sio_interface nflfoot_sio_intf = +{ + 0, /* clock (filled in from the CPU 3 clock) */ + ipu_ctc_interrupt, /* interrupt handler */ + 0, /* DTR changed handler */ + 0, /* RTS changed handler */ + ipu_break_changed, /* BREAK changed handler */ + mcr_ipu_sio_transmit/* transmit handler */ +}; + + + +/************************************* + * + * Generic MCR machine initialization + * + *************************************/ + +MACHINE_START( mcr ) +{ + /* initialize the CTC */ + ctc_intf.baseclock = machine->drv->cpu[0].clock; + z80ctc_init(0, &ctc_intf); + + state_save_register_global(mcr_cocktail_flip); +} + + +MACHINE_START( nflfoot ) +{ + /* initialize the CTC */ + ctc_intf.baseclock = machine->drv->cpu[0].clock; + z80ctc_init(0, &ctc_intf); + + nflfoot_ctc_intf.baseclock = machine->drv->cpu[3].clock; + z80ctc_init(1, &nflfoot_ctc_intf); + + z80pio_init(0, &nflfoot_pio_intf); + z80pio_init(1, &nflfoot_pio_intf); + + nflfoot_sio_intf.baseclock = machine->drv->cpu[3].clock; + z80sio_init(0, &nflfoot_sio_intf); + + /* allocate a timer for the IPU watchdog */ + ipu_watchdog_timer = timer_alloc(ipu_watchdog_reset); +} + + +MACHINE_RESET( mcr ) +{ + /* reset cocktail flip */ + mcr_cocktail_flip = 0; + + /* initialize the sound */ + mcr_sound_reset(); +} + + + +/************************************* + * + * Generic MCR/68k machine initialization + * + *************************************/ + +MACHINE_START( mcr68 ) +{ + int i; + + for (i = 0; i < 3; i++) + { + struct counter_state *m6840 = &m6840_state[i]; + + m6840->timer = timer_alloc(counter_fired_callback); + + state_save_register_item("m6840", i, m6840->control); + state_save_register_item("m6840", i, m6840->latch); + state_save_register_item("m6840", i, m6840->count); + state_save_register_item("m6840", i, m6840->timer_active); + } + + state_save_register_global(m6840_status); + state_save_register_global(m6840_status_read_since_int); + state_save_register_global(m6840_msb_buffer); + state_save_register_global(m6840_lsb_buffer); + state_save_register_global(m6840_irq_state); + state_save_register_global(v493_irq_state); + state_save_register_global(zwackery_sound_data); + + state_save_register_global(mcr_cocktail_flip); +} + + +static void mcr68_common_init(void) +{ + int i; + + /* reset the 6840's */ + m6840_counter_periods[0] = ATTOTIME_IN_HZ(30); /* clocked by /VBLANK */ + m6840_counter_periods[1] = attotime_never; /* grounded */ + m6840_counter_periods[2] = ATTOTIME_IN_HZ(512 * 30); /* clocked by /HSYNC */ + + m6840_status = 0x00; + m6840_status_read_since_int = 0x00; + m6840_msb_buffer = m6840_lsb_buffer = 0; + for (i = 0; i < 3; i++) + { + struct counter_state *m6840 = &m6840_state[i]; + + m6840->control = 0x00; + m6840->latch = 0xffff; + m6840->count = 0xffff; + timer_enable(m6840->timer, FALSE); + m6840->timer_active = 0; + m6840->period = m6840_counter_periods[i]; + } + + /* initialize the clock */ + m6840_internal_counter_period = ATTOTIME_IN_HZ(Machine->drv->cpu[0].clock / 10); + + /* reset cocktail flip */ + mcr_cocktail_flip = 0; + + /* initialize the sound */ + mcr_sound_reset(); +} + + +MACHINE_RESET( mcr68 ) +{ + /* for the most part all MCR/68k games are the same */ + mcr68_common_init(); + v493_callback = mcr68_493_callback; + + /* vectors are 1 and 2 */ + v493_irq_vector = 1; + m6840_irq_vector = 2; +} + + +MACHINE_START( zwackery ) +{ + /* append our PIA state onto the existing one and reinit */ + pia_config(2, &zwackery_pia_2_intf); + pia_config(3, &zwackery_pia_3_intf); + pia_config(4, &zwackery_pia_4_intf); + + machine_start_mcr68(machine); +} + + +MACHINE_RESET( zwackery ) +{ + /* for the most part all MCR/68k games are the same */ + mcr68_common_init(); + v493_callback = zwackery_493_callback; + + /* append our PIA state onto the existing one and reinit */ + pia_reset(); + + /* vectors are 5 and 6 */ + v493_irq_vector = 5; + m6840_irq_vector = 6; +} + + + +/************************************* + * + * Generic MCR interrupt handler + * + *************************************/ + +INTERRUPT_GEN( mcr_interrupt ) +{ + /* CTC line 2 is connected to VBLANK, which is once every 1/2 frame */ + /* for the 30Hz interlaced display */ + z80ctc_0_trg2_w(0, 1); + z80ctc_0_trg2_w(0, 0); + + /* CTC line 3 is connected to 493, which is signalled once every */ + /* frame at 30Hz */ + if (cpu_getiloops() == 0) + { + z80ctc_0_trg3_w(0, 1); + z80ctc_0_trg3_w(0, 0); + } +} + + +INTERRUPT_GEN( mcr_ipu_interrupt ) +{ + /* CTC line 3 is connected to 493, which is signalled once every */ + /* frame at 30Hz */ + if (cpu_getiloops() == 0) + { + z80ctc_1_trg3_w(0, 1); + z80ctc_1_trg3_w(0, 0); + } +} + + +INTERRUPT_GEN( mcr68_interrupt ) +{ + /* update the 6840 VBLANK clock */ + if (!m6840_state[0].timer_active) + subtract_from_counter(0, 1); + + logerror("--- VBLANK ---\n"); + + /* also set a timer to generate the 493 signal at a specific time before the next VBLANK */ + /* the timing of this is crucial for Blasted and Tri-Sports, which check the timing of */ + /* VBLANK and 493 using counter 2 */ + timer_set(attotime_sub(ATTOTIME_IN_HZ(30), mcr68_timing_factor), 0, v493_callback); +} + + + +/************************************* + * + * MCR/68k interrupt central + * + *************************************/ + +static void update_mcr68_interrupts(void) +{ + int newstate = 0; + + /* all interrupts go through an LS148, which gives priority to the highest */ + if (v493_irq_state) + newstate = v493_irq_vector; + if (m6840_irq_state) + newstate = m6840_irq_vector; + + /* set the new state of the IRQ lines */ + if (newstate) + cpunum_set_input_line(0, newstate, ASSERT_LINE); + else + cpunum_set_input_line(0, 7, CLEAR_LINE); +} + + +static TIMER_CALLBACK( mcr68_493_off_callback ) +{ + v493_irq_state = 0; + update_mcr68_interrupts(); +} + + +static TIMER_CALLBACK( mcr68_493_callback ) +{ + v493_irq_state = 1; + update_mcr68_interrupts(); + timer_set(video_screen_get_scan_period(0), 0, mcr68_493_off_callback); + logerror("--- (INT1) ---\n"); +} + + + +/************************************* + * + * Generic MCR port write handlers + * + *************************************/ + +WRITE8_HANDLER( mcr_control_port_w ) +{ + /* + Bit layout is as follows: + D7 = n/c + D6 = cocktail flip + D5 = red LED + D4 = green LED + D3 = n/c + D2 = coin meter 3 + D1 = coin meter 2 + D0 = coin meter 1 + */ + + coin_counter_w(0, (data >> 0) & 1); + coin_counter_w(1, (data >> 1) & 1); + coin_counter_w(2, (data >> 2) & 1); + mcr_cocktail_flip = (data >> 6) & 1; +} + + +WRITE8_HANDLER( mcrmono_control_port_w ) +{ + /* + Bit layout is as follows: + D7 = n/c + D6 = cocktail flip + D5 = n/c + D4 = n/c + D3 = n/c + D2 = n/c + D1 = n/c + D0 = coin meter 1 + */ + + coin_counter_w(0, (data >> 0) & 1); + mcr_cocktail_flip = (data >> 6) & 1; +} + + +WRITE8_HANDLER( mcr_scroll_value_w ) +{ + switch (offset) + { + case 0: + /* low 8 bits of horizontal scroll */ + spyhunt_scrollx = (spyhunt_scrollx & ~0xff) | data; + break; + + case 1: + /* upper 3 bits of horizontal scroll and upper 1 bit of vertical scroll */ + spyhunt_scrollx = (spyhunt_scrollx & 0xff) | ((data & 0x07) << 8); + spyhunt_scrolly = (spyhunt_scrolly & 0xff) | ((data & 0x80) << 1); + break; + + case 2: + /* low 8 bits of vertical scroll */ + spyhunt_scrolly = (spyhunt_scrolly & ~0xff) | data; + break; + } +} + + + +/************************************* + * + * Zwackery-specific interfaces + * + *************************************/ + +WRITE8_HANDLER( zwackery_pia_2_w ) +{ + /* bit 7 is the watchdog */ + if (!(data & 0x80)) watchdog_reset_w(offset, data); + + /* bits 5 and 6 control hflip/vflip */ + /* bits 3 and 4 control coin counters? */ + /* bits 0, 1 and 2 control meters? */ +} + + +WRITE8_HANDLER( zwackery_pia_3_w ) +{ + zwackery_sound_data = (data >> 4) & 0x0f; +} + + +WRITE8_HANDLER( zwackery_ca2_w ) +{ + csdeluxe_data_w(offset, (data << 4) | zwackery_sound_data); +} + + +void zwackery_pia_irq(int state) +{ + v493_irq_state = state; + update_mcr68_interrupts(); +} + + +static TIMER_CALLBACK( zwackery_493_off_callback ) +{ + pia_2_ca1_w(0, 0); +} + + +static TIMER_CALLBACK( zwackery_493_callback ) +{ + pia_2_ca1_w(0, 1); + timer_set(video_screen_get_scan_period(0), 0, zwackery_493_off_callback); +} + + + +/************************************* + * + * M6840 timer utilities + * + *************************************/ + +INLINE void update_interrupts(void) +{ + m6840_status &= ~0x80; + + if ((m6840_status & 0x01) && (m6840_state[0].control & 0x40)) m6840_status |= 0x80; + if ((m6840_status & 0x02) && (m6840_state[1].control & 0x40)) m6840_status |= 0x80; + if ((m6840_status & 0x04) && (m6840_state[2].control & 0x40)) m6840_status |= 0x80; + + m6840_irq_state = m6840_status >> 7; + update_mcr68_interrupts(); +} + + +static void subtract_from_counter(int counter, int count) +{ + /* dual-byte mode */ + if (m6840_state[counter].control & 0x04) + { + int lsb = m6840_state[counter].count & 0xff; + int msb = m6840_state[counter].count >> 8; + + /* count the clocks */ + lsb -= count; + + /* loop while we're less than zero */ + while (lsb < 0) + { + /* borrow from the MSB */ + lsb += (m6840_state[counter].latch & 0xff) + 1; + msb--; + + /* if MSB goes less than zero, we've expired */ + if (msb < 0) + { + m6840_status |= 1 << counter; + m6840_status_read_since_int &= ~(1 << counter); + update_interrupts(); + msb = (m6840_state[counter].latch >> 8) + 1; + LOG(("** Counter %d fired\n", counter)); + } + } + + /* store the result */ + m6840_state[counter].count = (msb << 8) | lsb; + } + + /* word mode */ + else + { + int word = m6840_state[counter].count; + + /* count the clocks */ + word -= count; + + /* loop while we're less than zero */ + while (word < 0) + { + /* borrow from the MSB */ + word += m6840_state[counter].latch + 1; + + /* we've expired */ + m6840_status |= 1 << counter; + m6840_status_read_since_int &= ~(1 << counter); + update_interrupts(); + LOG(("** Counter %d fired\n", counter)); + } + + /* store the result */ + m6840_state[counter].count = word; + } +} + + +static TIMER_CALLBACK( counter_fired_callback ) +{ + int count = param >> 2; + int counter = param & 3; + + /* reset the timer */ + m6840_state[counter].timer_active = 0; + + /* subtract it all from the counter; this will generate an interrupt */ + subtract_from_counter(counter, count); +} + + +static void reload_count(int counter) +{ + attotime period; + attotime total_period; + int count; + + /* copy the latched value in */ + m6840_state[counter].count = m6840_state[counter].latch; + + /* counter 0 is self-updating if clocked externally */ + if (counter == 0 && !(m6840_state[counter].control & 0x02)) + { + timer_adjust(m6840_state[counter].timer, attotime_never, 0, attotime_zero); + m6840_state[counter].timer_active = 0; + return; + } + + /* determine the clock period for this timer */ + if (m6840_state[counter].control & 0x02) + period = m6840_internal_counter_period; + else + period = m6840_counter_periods[counter]; + + /* determine the number of clock periods before we expire */ + count = m6840_state[counter].count; + if (m6840_state[counter].control & 0x04) + count = ((count >> 8) + 1) * ((count & 0xff) + 1); + else + count = count + 1; + + /* set the timer */ + total_period = attotime_make(0, attotime_to_attoseconds(period) * count); +LOG(("reload_count(%d): period = %f count = %d\n", counter, attotime_to_double(period), count)); + timer_adjust(m6840_state[counter].timer, total_period, (count << 2) + counter, attotime_zero); + m6840_state[counter].timer_active = 1; +} + + +static UINT16 compute_counter(int counter) +{ + attotime period; + int remaining; + + /* if there's no timer, return the count */ + if (!m6840_state[counter].timer_active) + return m6840_state[counter].count; + + /* determine the clock period for this timer */ + if (m6840_state[counter].control & 0x02) + period = m6840_internal_counter_period; + else + period = m6840_counter_periods[counter]; + + /* see how many are left */ + remaining = attotime_to_attoseconds(timer_timeleft(m6840_state[counter].timer)) / attotime_to_attoseconds(period); + + /* adjust the count for dual byte mode */ + if (m6840_state[counter].control & 0x04) + { + int divisor = (m6840_state[counter].count & 0xff) + 1; + int msb = remaining / divisor; + int lsb = remaining % divisor; + remaining = (msb << 8) | lsb; + } + + return remaining; +} + + + +/************************************* + * + * M6840 timer I/O + * + *************************************/ + +static WRITE8_HANDLER( mcr68_6840_w_common ) +{ + int i; + + /* offsets 0 and 1 are control registers */ + if (offset < 2) + { + int counter = (offset == 1) ? 1 : (m6840_state[1].control & 0x01) ? 0 : 2; + UINT8 diffs = data ^ m6840_state[counter].control; + + m6840_state[counter].control = data; + + /* reset? */ + if (counter == 0 && (diffs & 0x01)) + { + /* holding reset down */ + if (data & 0x01) + { + for (i = 0; i < 3; i++) + { + timer_adjust(m6840_state[i].timer, attotime_never, 0, attotime_zero); + m6840_state[i].timer_active = 0; + } + } + + /* releasing reset */ + else + { + for (i = 0; i < 3; i++) + reload_count(i); + } + + m6840_status = 0; + update_interrupts(); + } + + /* changing the clock source? (needed for Zwackery) */ + if (diffs & 0x02) + reload_count(counter); + + LOG(("%06X:Counter %d control = %02X\n", activecpu_get_previouspc(), counter, data)); + } + + /* offsets 2, 4, and 6 are MSB buffer registers */ + else if ((offset & 1) == 0) + { + LOG(("%06X:MSB = %02X\n", activecpu_get_previouspc(), data)); + m6840_msb_buffer = data; + } + + /* offsets 3, 5, and 7 are Write Timer Latch commands */ + else + { + int counter = (offset - 2) / 2; + m6840_state[counter].latch = (m6840_msb_buffer << 8) | (data & 0xff); + + /* clear the interrupt */ + m6840_status &= ~(1 << counter); + update_interrupts(); + + /* reload the count if in an appropriate mode */ + if (!(m6840_state[counter].control & 0x10)) + reload_count(counter); + + LOG(("%06X:Counter %d latch = %04X\n", activecpu_get_previouspc(), counter, m6840_state[counter].latch)); + } +} + + +static READ16_HANDLER( mcr68_6840_r_common ) +{ + /* offset 0 is a no-op */ + if (offset == 0) + return 0; + + /* offset 1 is the status register */ + else if (offset == 1) + { + LOG(("%06X:Status read = %04X\n", activecpu_get_previouspc(), m6840_status)); + m6840_status_read_since_int |= m6840_status & 0x07; + return m6840_status; + } + + /* offsets 2, 4, and 6 are Read Timer Counter commands */ + else if ((offset & 1) == 0) + { + int counter = (offset - 2) / 2; + int result = compute_counter(counter); + + /* clear the interrupt if the status has been read */ + if (m6840_status_read_since_int & (1 << counter)) + m6840_status &= ~(1 << counter); + update_interrupts(); + + m6840_lsb_buffer = result & 0xff; + + LOG(("%06X:Counter %d read = %04X\n", activecpu_get_previouspc(), counter, result)); + return result >> 8; + } + + /* offsets 3, 5, and 7 are LSB buffer registers */ + else + return m6840_lsb_buffer; +} + + +WRITE16_HANDLER( mcr68_6840_upper_w ) +{ + if (ACCESSING_MSB) + mcr68_6840_w_common(offset, (data >> 8) & 0xff); +} + + +WRITE16_HANDLER( mcr68_6840_lower_w ) +{ + if (ACCESSING_LSB) + mcr68_6840_w_common(offset, data & 0xff); +} + + +READ16_HANDLER( mcr68_6840_upper_r ) +{ + return (mcr68_6840_r_common(offset,0) << 8) | 0x00ff; +} + + +READ16_HANDLER( mcr68_6840_lower_r ) +{ + return mcr68_6840_r_common(offset,0) | 0xff00; +} + + + +/************************************* + * + * NFL Football IPU board + * + *************************************/ + +static WRITE8_HANDLER( ipu_break_changed ) +{ + /* channel B is connected to the CED player */ + if (offset == 1) + { + logerror("DTR changed -> %d\n", data); + if (data == 1) + z80sio_receive_data(0, 1, 0); + } +} + + +READ8_HANDLER( mcr_ipu_pio_0_r ) +{ + return (offset & 2) ? z80pio_c_r(0, offset & 1) : z80pio_d_r(0, offset & 1); +} + + +READ8_HANDLER( mcr_ipu_pio_1_r ) +{ + return (offset & 2) ? z80pio_c_r(1, offset & 1) : z80pio_d_r(1, offset & 1); +} + + +READ8_HANDLER( mcr_ipu_sio_r ) +{ + return (offset & 2) ? z80sio_c_r(0, offset & 1) : z80sio_d_r(0, offset & 1); +} + + +WRITE8_HANDLER( mcr_ipu_pio_0_w ) +{ + if (offset & 2) + z80pio_c_w(0, offset & 1, data); + else + z80pio_d_w(0, offset & 1, data); +} + + +WRITE8_HANDLER( mcr_ipu_pio_1_w ) +{ + if (offset & 2) + z80pio_c_w(1, offset & 1, data); + else + z80pio_d_w(1, offset & 1, data); +} + + +WRITE8_HANDLER( mcr_ipu_sio_w ) +{ + if (offset & 2) + z80sio_c_w(0, offset & 1, data); + else + z80sio_d_w(0, offset & 1, data); +} + + +WRITE8_HANDLER( mcr_ipu_laserdisk_w ) +{ + /* bit 3 enables (1) LD video regardless of PIX SW */ + /* bit 2 enables (1) LD right channel audio */ + /* bit 1 enables (1) LD left channel audio */ + /* bit 0 enables (1) LD video if PIX SW == 1 */ + if (data != 0) + logerror("%04X:mcr_ipu_laserdisk_w(%d) = %02X\n", activecpu_get_pc(), offset, data); +} + + +static TIMER_CALLBACK( ipu_watchdog_reset ) +{ + logerror("ipu_watchdog_reset\n"); + cpunum_set_input_line(3, INPUT_LINE_RESET, PULSE_LINE); + z80ctc_reset(1); + z80pio_reset(0); + z80pio_reset(1); + z80sio_reset(0); +} + + +READ8_HANDLER( mcr_ipu_watchdog_r ) +{ + /* watchdog counter is clocked by 7.3728MHz crystal / 16 */ + /* watchdog is tripped when 14-bit counter overflows => / 32768 = 14.0625Hz*/ + timer_adjust(ipu_watchdog_timer, ATTOTIME_IN_HZ(7372800 / 16 / 32768), 0, attotime_zero); + return 0xff; +} + + +WRITE8_HANDLER( mcr_ipu_watchdog_w ) +{ + mcr_ipu_watchdog_r(0); +} |