Fixed Z80-PIO mode 3 interrupts, and mode 1 data writes.

meritm.c: Added scanline timer-based vblank interrupt to work around the broken V9938 interrupts. Megatouch games are now working again. [Curt Coder]
This commit is contained in:
Curt Coder 2010-02-18 07:30:20 +00:00
parent a3da167012
commit 651caf7f1b
2 changed files with 70 additions and 85 deletions

View File

@ -111,12 +111,36 @@ static void check_interrupts(running_device *device)
{
pio_port *port = &z80pio->port[index];
if (port->mode == MODE_BIT_CONTROL)
{
/* fetch input data (ignore output lines) */
UINT8 data = (port->input & port->ior) | (port->output & ~port->ior);
UINT8 mask = ~port->mask;
int match = 0;
data &= mask;
if ((port->icw & 0x60) == 0 && data != mask) match = 1;
else if ((port->icw & 0x60) == 0x20 && data != 0) match = 1;
else if ((port->icw & 0x60) == 0x40 && data == 0) match = 1;
else if ((port->icw & 0x60) == 0x60 && data == mask) match = 1;
if (!port->match && match)
{
/* trigger interrupt */
port->ip = 1;
if (LOG) logerror("Z80PIO '%s' Port %c Interrupt Pending\n", device->tag.cstr(), 'A' + index);
}
port->match = match;
}
if (port->ie && port->ip && !port->ius)
{
state = ASSERT_LINE;
}
}
devcb_call_write_line(&z80pio->out_int_func, state);
}
@ -254,6 +278,14 @@ WRITE8_DEVICE_HANDLER( z80pio_c_w )
case 0x07: /* set interrupt control word */
port->icw = data;
if (LOG)
{
logerror("Z80PIO '%s' Port %c Interrupt Enable: %u\n", device->tag.cstr(), 'A' + index, BIT(data, 7));
logerror("Z80PIO '%s' Port %c Logic: %s\n", device->tag.cstr(), 'A' + index, BIT(data, 6) ? "AND" : "OR");
logerror("Z80PIO '%s' Port %c Active %s\n", device->tag.cstr(), 'A' + index, BIT(data, 5) ? "High" : "Low");
logerror("Z80PIO '%s' Port %c Mask Follows: %u\n", device->tag.cstr(), 'A' + index, BIT(data, 4));
}
if (port->icw & ICW_MASK_FOLLOWS)
{
/* disable interrupts until mask is written */
@ -269,6 +301,11 @@ WRITE8_DEVICE_HANDLER( z80pio_c_w )
/* next word is mask control */
port->next_control_word = MASK;
}
else
{
/* monitor all bits */
port->mask = 0;
}
break;
case 0x03: /* set interrupt enable flip-flop */
@ -394,7 +431,8 @@ WRITE8_DEVICE_HANDLER( z80pio_d_w )
break;
case MODE_INPUT:
/* do nothing */
/* latch output data */
port->output = data;
break;
case MODE_BIDIRECTIONAL:
@ -497,60 +535,6 @@ READ8_DEVICE_HANDLER( z80pio_pa_r )
return data;
}
/*-------------------------------------------------
check_equation - check bit logic equation
-------------------------------------------------*/
static void check_equation(running_device *device, int index, UINT8 data)
{
z80pio_t *z80pio = get_safe_token(device);
pio_port *port = &z80pio->port[index];
if (port->mask == 0xff) return;
int bit;
int match = 0;
int edge = (port->icw & ICW_HIGH) ? 1 : 0;
UINT8 mask = port->mask;
UINT8 ior = port->ior;
UINT8 old_data = port->input;
if (old_data == data) return;
for (bit = 0; bit < 8; bit++)
{
if (BIT(mask, bit)) continue; /* masked out */
if (!BIT(ior, bit)) continue; /* output bit */
if ((BIT(old_data, bit) ^ edge) && !(BIT(data, bit) ^ edge)) /* falling edge */
{
/* logic equation is true, until proven otherwise */
match = 1;
if (LOG) logerror("Z80PIO '%s' Port %c Edge Transition detected on bit %u, data %02x %02x\n", device->tag.cstr(), 'A' + index, bit, old_data, data);
}
else if (port->icw & ICW_AND)
{
/* all bits must match in AND mode, so logic equation is false */
match = 0;
break;
}
}
if (!port->match && match) /* rising edge */
{
/* latch data */
port->input = data;
/* trigger interrupt only once */
trigger_interrupt(device, index);
}
port->match = match;
}
/*-------------------------------------------------
z80pio_pa_w - port A write
-------------------------------------------------*/
@ -562,7 +546,9 @@ WRITE8_DEVICE_HANDLER( z80pio_pa_w )
if (port->mode == MODE_BIT_CONTROL)
{
check_equation(device, PORT_A, data);
/* latch data */
port->input = data;
check_interrupts(device);
}
}
@ -602,7 +588,9 @@ WRITE8_DEVICE_HANDLER( z80pio_pb_w )
if (port->mode == MODE_BIT_CONTROL)
{
check_equation(device, PORT_B, data);
/* latch data */
port->input = data;
check_interrupts(device);
}
}
@ -760,11 +748,12 @@ static int z80pio_irq_ack(running_device *device)
/* clear interrupt pending flag */
port->ip = 0;
check_interrupts(device);
/* set interrupt under service flag */
port->ius = 1;
check_interrupts(device);
return port->vector;
}
}
@ -854,9 +843,6 @@ static DEVICE_RESET( z80pio )
/* set mode 1 */
set_mode(device, index, MODE_INPUT);
/* reset port mask registers */
port->mask = 0;
/* reset interrupt enable flip-flops */
port->icw &= ~ICW_ENABLE_INT;
port->ie = 0;

View File

@ -299,7 +299,7 @@ static int meritm_touch_coord_transform(running_machine *machine, int *touch_x,
*
*************************************/
static int meritm_vint = 0x00;
static int meritm_vint = 0x18;
static int meritm_interrupt_vdp0_state = 0;
static int meritm_interrupt_vdp1_state = 0;
static bitmap_t *vdp0_bitmap, *vdp1_bitmap;
@ -317,32 +317,14 @@ static INTERRUPT_GEN( meritm_interrupt )
static void meritm_vdp0_interrupt(running_machine *machine, int i)
{
if ( meritm_interrupt_vdp0_state != i )
{
meritm_interrupt_vdp0_state = i;
if (i)
meritm_vint &= ~0x08;
else
meritm_vint |= 0x08;
if(i)
z80pio_pa_w(meritm_z80pio[0], 0, meritm_vint);
}
/* this is not used as the v9938 interrupt callbacks are broken
interrupts seem to be fired quite randomly */
}
static void meritm_vdp1_interrupt(running_machine *machine, int i)
{
if ( meritm_interrupt_vdp1_state != i )
{
meritm_interrupt_vdp1_state = i;
if (i)
meritm_vint &= ~0x10;
else
meritm_vint |= 0x10;
if(i)
z80pio_pa_w(meritm_z80pio[0], 0, meritm_vint);
}
/* this is not used as the v9938 interrupt callbacks are broken
interrupts seem to be fired quite randomly */
}
static int layer0_enabled, layer1_enabled;
@ -1051,6 +1033,20 @@ static NVRAM_HANDLER(meritm_crt260)
#define MSX2_VISIBLE_XBORDER_PIXELS 8 * 2
#define MSX2_VISIBLE_YBORDER_PIXELS 14 * 2
static TIMER_DEVICE_CALLBACK( vblank_start_tick )
{
/* this is a workaround to signal the v9938 vblank interrupt correctly */
meritm_vint = 0x08;
z80pio_pa_w(meritm_z80pio[0], 0, meritm_vint);
}
static TIMER_DEVICE_CALLBACK( vblank_end_tick )
{
/* this is a workaround to signal the v9938 vblank interrupt correctly */
meritm_vint = 0x18;
z80pio_pa_w(meritm_z80pio[0], 0, meritm_vint);
}
static MACHINE_DRIVER_START(meritm_crt250)
MDRV_CPU_ADD("maincpu", Z80, SYSTEM_CLK/6)
MDRV_CPU_PROGRAM_MAP(meritm_crt250_map)
@ -1065,6 +1061,9 @@ static MACHINE_DRIVER_START(meritm_crt250)
MDRV_Z80PIO_ADD( "z80pio_0", SYSTEM_CLK/6, meritm_audio_pio_intf )
MDRV_Z80PIO_ADD( "z80pio_1", SYSTEM_CLK/6, meritm_io_pio_intf )
MDRV_TIMER_ADD_SCANLINE("vblank_start", vblank_start_tick, "screen", 259, 262)
MDRV_TIMER_ADD_SCANLINE("vblank_end", vblank_end_tick, "screen", 262, 262)
MDRV_NVRAM_HANDLER(generic_0fill)
MDRV_VIDEO_ATTRIBUTES(VIDEO_UPDATE_BEFORE_VBLANK)