(from Mariusz Wojcieszek)

Attached is diff which makes Touchmaster games playable.

General changes:
- Added preliminary 68681 DUART (machine\68681.c)
- Moved Microtouch touch screen controller emulation to separate module (machine\microtch.c)

New games added or promoted from NOT_WORKING status
---------------------------------------------------
Touchmaster [Mariusz Wojcieszek]
Touchmaster 3000 [Mariusz Wojcieszek]
Touchmaster 4000 [Mariusz Wojcieszek]
Touchmaster 5000 [Mariusz Wojcieszek]
Touchmaster 7000 [Mariusz Wojcieszek]
This commit is contained in:
Aaron Giles 2008-04-21 00:00:55 +00:00
parent fc2eb1d343
commit e26f80fde0
8 changed files with 740 additions and 277 deletions

4
.gitattributes vendored
View File

@ -557,6 +557,8 @@ src/emu/machine/6840ptm.c svneol=native#text/plain
src/emu/machine/6840ptm.h svneol=native#text/plain
src/emu/machine/6850acia.c svneol=native#text/plain
src/emu/machine/6850acia.h svneol=native#text/plain
src/emu/machine/68681.c svneol=native#text/plain
src/emu/machine/68681.h svneol=native#text/plain
src/emu/machine/74123.c svneol=native#text/plain
src/emu/machine/74123.h svneol=native#text/plain
src/emu/machine/74148.c svneol=native#text/plain
@ -609,6 +611,8 @@ src/emu/machine/mb87078.c svneol=native#text/plain
src/emu/machine/mb87078.h svneol=native#text/plain
src/emu/machine/mc146818.c svneol=native#text/plain
src/emu/machine/mc146818.h svneol=native#text/plain
src/emu/machine/microtch.c svneol=native#text/plain
src/emu/machine/microtch.h svneol=native#text/plain
src/emu/machine/msm6242.c svneol=native#text/plain
src/emu/machine/msm6242.h svneol=native#text/plain
src/emu/machine/pc16552d.c svneol=native#text/plain

View File

@ -117,6 +117,7 @@ EMUMACHINEOBJS = \
$(EMUMACHINE)/6821pia.o \
$(EMUMACHINE)/6840ptm.o \
$(EMUMACHINE)/6850acia.o \
$(EMUMACHINE)/68681.o \
$(EMUMACHINE)/7474.o \
$(EMUMACHINE)/74123.o \
$(EMUMACHINE)/74148.o \
@ -142,6 +143,7 @@ EMUMACHINEOBJS = \
$(EMUMACHINE)/mb3773.o \
$(EMUMACHINE)/mb87078.o \
$(EMUMACHINE)/mc146818.o \
$(EMUMACHINE)/microtch.o \
$(EMUMACHINE)/msm6242.o \
$(EMUMACHINE)/pc16552d.o \
$(EMUMACHINE)/pci.o \

426
src/emu/machine/68681.c Normal file
View File

@ -0,0 +1,426 @@
/*
68681 DUART
Written by Mariusz Wojcieszek
Emulation is preliminary, only features required by Touch Master games are implemented
ToDo:
- interrupts other than RXRDY
- timer/counter
- input port
- input port change
- output port
- output port when used as control signals
- MAME device interface
- multiple instances
*/
#include "driver.h"
#define INT_INPUT_PORT_CHANGE 0x80
#define INT_DELTA_BREAK_B 0x40
#define INT_RXRDY_FFULLB 0x20
#define INT_TXRDYB 0x10
#define INT_COUNTER_READY 0x08
#define INT_DELTA_BREAK_A 0x04
#define INT_RXRDY_FFULLA 0x02
#define INT_TXRDYA 0x01
#define STATUS_RECEIVED_BREAK 0x80
#define STATUS_FRAMING_ERROR 0x40
#define STATUS_PARITY_ERROR 0x20
#define STATUS_OVERRUN_ERROR 0x10
#define STATUS_TRANSMITTER_EMPTY 0x08
#define STATUS_TRANSMITTER_READY 0x04
#define STATUS_FIFO_FULL 0x02
#define STATUS_RECEIVER_READY 0x01
#define MODE_RX_INT_SELECT_BIT 6
#define RX_FIFO_SIZE 3
typedef struct
{
/* Registers */
UINT8 CR; /* Command register */
UINT8 CSR; /* Clock select register */
UINT8 MR1; /* Mode register 1 */
UINT8 MR2; /* Mode register 2 */
UINT8 MR_ptr; /* Mode register pointer */
UINT8 SR; /* Status register */
/* State */
int baud_rate;
/* Receiver */
UINT8 rx_enabled;
UINT8 rx_fifo[RX_FIFO_SIZE];
int rx_fifo_read_ptr;
int rx_fifo_write_ptr;
int rx_fifo_num;
/* Transmitter */
UINT8 tx_enabled;
UINT8 tx_data;
UINT8 tx_ready;
emu_timer *tx_timer;
} DUART_68681_CHANNEL;
typedef struct
{
int frequency;
// registers
UINT8 ACR; /* Auxiliary Control Register */
UINT8 IMR; /* Interrupt Mask Register */
UINT8 ISR; /* Interrupt Status Register */
UINT8 IVR; /* Interrupt Vector Register */
UINT8 OPCR; /* Output Port Conf. Register */
// state
UINT8 IP_last_state; /* last state of IP bits */
// callbacks
UINT8 (*input_port_read)(void);
void (*tx_callback)(int channel, UINT8 data);
void (*irq_handler)(UINT8 vector);
DUART_68681_CHANNEL channel[2];
} DUART_68681;
static DUART_68681 duart_68681;
static void duart_68681_update_interrupts( void )
{
if ( (duart_68681.ISR & duart_68681.IMR) != 0 )
{
if ( duart_68681.irq_handler )
{
duart_68681.irq_handler( duart_68681.IVR );
}
}
};
static void duart_68681_write_MR( int ch, UINT8 data )
{
if ( duart_68681.channel[ch].MR_ptr == 0 )
{
duart_68681.channel[ch].MR1 = data;
// TODO:
duart_68681.channel[ch].MR_ptr = 1;
}
else
{
duart_68681.channel[ch].MR2 = data;
// TODO:
}
};
static void duart_68681_write_CSR(int ch, UINT8 data, UINT8 ACR)
{
const int baud_rate_ACR_0[] = { 50, 110, 134, 200, 300, 600, 1200, 1050, 2400, 4800, 7200, 9600, 38400, 0, 0, 0 };
const int baud_rate_ACR_1[] = { 75, 110, 134, 150, 300, 600, 1200, 2000, 2400, 4800, 1800, 9600, 19200, 0, 0, 0 };
duart_68681.channel[ch].CSR = data;
if ( BIT(ACR,7) == 0 )
{
duart_68681.channel[ch].baud_rate = baud_rate_ACR_0[data & 0x0f];
}
else
{
duart_68681.channel[ch].baud_rate = baud_rate_ACR_1[data & 0x0f];
}
if ( duart_68681.channel[ch].baud_rate == 0 )
{
logerror( "Unsupported transmitter clock: channel %d, clock select = %02x\n", ch, data );
}
};
static void duart_68681_write_CR(int ch, UINT8 data)
{
duart_68681.channel[ch].CR = data;
if ( BIT(data,0) )
{
duart_68681.channel[ch].rx_enabled = 1;
}
if ( BIT(data,1) )
{
duart_68681.channel[ch].rx_enabled = 0;
duart_68681.channel[ch].SR &= ~STATUS_RECEIVER_READY;
}
if ( BIT(data,2) )
{
duart_68681.channel[ch].tx_enabled = 1;
duart_68681.channel[ch].tx_ready = 1;
duart_68681.channel[ch].SR |= STATUS_TRANSMITTER_READY;
}
if ( BIT(data,3) )
{
duart_68681.channel[ch].tx_enabled = 0;
duart_68681.channel[ch].tx_ready = 0;
duart_68681.channel[ch].SR &= ~STATUS_TRANSMITTER_READY;
}
switch( (data >> 4) & 0x07 )
{
case 0: /* No command */
break;
case 1: /* Reset MR pointer. Causes the Channel A MR pointer to point to MR1 */
duart_68681.channel[ch].MR_ptr = 0;
break;
case 2: /* Reset channel A receiver (disable receiver and flush fifo) */
duart_68681.channel[ch].rx_enabled = 0;
duart_68681.channel[ch].SR &= ~STATUS_RECEIVER_READY;
duart_68681.channel[ch].rx_fifo_read_ptr = 0;
duart_68681.channel[ch].rx_fifo_write_ptr = 0;
duart_68681.channel[ch].rx_fifo_num = 0;
break;
case 3: /* Reset channel A transmitter */
//TODO:
break;
case 4: /* Reset Error Status */
// TODO:
duart_68681.channel[ch].SR &= ~(STATUS_RECEIVED_BREAK | STATUS_FRAMING_ERROR | STATUS_PARITY_ERROR | STATUS_OVERRUN_ERROR);
break;
default:
logerror( "68681: Unhandled command (%x) in CR%d\n", ch, (data >> 4) & 0x07 );
break;
}
};
static UINT8 duart_68681_read_rx_fifo( int ch )
{
UINT8 r;
if ( duart_68681.channel[ch].rx_fifo_num == 0 )
{
logerror( "68681: rx fifo underflow\n" );
return 0;
}
r = duart_68681.channel[ch].rx_fifo[duart_68681.channel[ch].rx_fifo_read_ptr++];
if ( duart_68681.channel[ch].rx_fifo_read_ptr == RX_FIFO_SIZE )
{
duart_68681.channel[ch].rx_fifo_read_ptr = 0;
}
duart_68681.channel[ch].rx_fifo_num--;
if ( duart_68681.channel[ch].rx_fifo_num > 0 )
{
duart_68681.channel[ch].SR |= STATUS_RECEIVER_READY;
if ( ch == 0 )
{
duart_68681.ISR |= INT_RXRDY_FFULLA;
}
else
{
duart_68681.ISR |= INT_RXRDY_FFULLB;
}
}
else
{
duart_68681.channel[ch].SR &= ~STATUS_RECEIVER_READY;
if ( ch == 0 )
{
duart_68681.ISR &= ~INT_RXRDY_FFULLA;
}
else
{
duart_68681.ISR &= ~INT_RXRDY_FFULLB;
}
}
duart_68681_update_interrupts();
return r;
};
static TIMER_CALLBACK( tx_timer_callback )
{
int ch = param & 1;
if (duart_68681.tx_callback)
duart_68681.tx_callback(ch, duart_68681.channel[ch].tx_data);
duart_68681.channel[ch].tx_ready = 1;
duart_68681.channel[ch].SR |= STATUS_TRANSMITTER_READY;
if (ch == 0)
duart_68681.ISR |= INT_TXRDYA;
else
duart_68681.ISR |= INT_TXRDYB;
duart_68681_update_interrupts();
timer_adjust_oneshot(duart_68681.channel[ch].tx_timer, attotime_never, ch);
};
static void duart_68681_write_TX(int ch, UINT8 data)
{
attotime period;
duart_68681.channel[ch].tx_data = data;
duart_68681.channel[ch].tx_ready = 0;
duart_68681.channel[ch].SR &= ~STATUS_TRANSMITTER_READY;
if (ch == 0)
duart_68681.ISR &= ~INT_TXRDYA;
else
duart_68681.ISR &= ~INT_TXRDYB;
duart_68681_update_interrupts();
period = ATTOTIME_IN_HZ(duart_68681.channel[ch].baud_rate / 10 );
timer_adjust_oneshot(duart_68681.channel[ch].tx_timer, period, ch);
};
READ16_HANDLER(duart_68681_r)
{
UINT16 r = 0x0;
//logerror( "Reading 68681 reg %x\n", offset );
switch (offset)
{
case 0x01: /* SRA */
r = duart_68681.channel[0].SR;
break;
case 0x03: /* Rx Holding Register A */
r = duart_68681_read_rx_fifo(0);
break;
case 0x04: /* IPCR */
{
UINT8 IP;
if ( duart_68681.input_port_read != NULL )
IP = duart_68681.input_port_read();
else
IP = 0x0;
r = (((duart_68681.IP_last_state ^ IP) & 0x0f) << 4) | (IP & 0x0f);
duart_68681.IP_last_state = IP;
duart_68681.ISR &= ~INT_INPUT_PORT_CHANGE;
duart_68681_update_interrupts();
}
break;
case 0x09: /* SRB */
r = duart_68681.channel[1].SR;
break;
case 0x0b: /* RHRB */
r = duart_68681_read_rx_fifo(1);
break;
default:
logerror( "Reading unhandled 68681 reg %x\n", offset );
break;
}
return r;
}
WRITE16_HANDLER(duart_68681_w)
{
//logerror( "Writing 68681 reg %x with %04x\n", offset, data );
switch(offset)
{
case 0x00: /* MRA */
duart_68681_write_MR(0, data);
break;
case 0x01: /* CSRA */
duart_68681_write_CSR(0, data, duart_68681.ACR);
break;
case 0x02: /* CRA */
duart_68681_write_CR(0, data);
break;
case 0x03: /* THRA */
duart_68681_write_TX(0, data);
break;
case 0x04: /* ACR */
duart_68681.ACR = data;
// TODO:
// bits 6-4: Counter/Timer Mode And Clock Source Select
// bits 3-0: IP3-0 Change-Of-State Interrupt Enable
duart_68681_write_CSR(0, duart_68681.channel[0].CSR, data);
duart_68681_write_CSR(1, duart_68681.channel[1].CSR, data);
break;
case 0x05: /* IMR */
duart_68681.IMR = data;
// TODO: handle update interrupts?
break;
case 0x08: /* MRB */
duart_68681_write_MR(1, data);
break;
case 0x09: /* CSRB */
duart_68681_write_CSR(1, data, duart_68681.ACR);
break;
case 0x0a: /* CRB */
duart_68681_write_CR(1, data);
break;
case 0x0b: /* THRB */
duart_68681_write_TX(1, data);
break;
case 0x0c: /* IVR */
duart_68681.IVR = data;
break;
case 0x0d: /* OPCR */
duart_68681.OPCR = data;
break;
case 0x0e: /* Set Output Port Bits */
// TODO: bits set to 1 causes corresponding output port bit to be set to 0
break;
case 0x0f: /* Reset Output Port Bits */
// TODO: bits set to 1 causes corresponding output port bit to be set to 1
break;
default:
logerror( "Writing 68681 reg %x with %04x\n", offset, data );
break;
}
}
void duart_68681_rx_data( int ch, UINT8 data )
{
if ( duart_68681.channel[ch].rx_enabled )
{
if ( duart_68681.channel[ch].rx_fifo_num >= RX_FIFO_SIZE )
{
logerror( "68681: FIFO overflow\n" );
return;
}
duart_68681.channel[ch].rx_fifo[duart_68681.channel[ch].rx_fifo_write_ptr++] = data;
if ( duart_68681.channel[ch].rx_fifo_write_ptr == RX_FIFO_SIZE )
{
duart_68681.channel[ch].rx_fifo_write_ptr = 0;
}
duart_68681.channel[ch].rx_fifo_num++;
duart_68681.channel[ch].SR |= STATUS_RECEIVER_READY;
if ( BIT(duart_68681.channel[ch].MR1,MODE_RX_INT_SELECT_BIT) == 0 )
{
duart_68681.ISR |= (ch == 0) ? INT_RXRDY_FFULLA : INT_RXRDY_FFULLB;
}
if ( duart_68681.channel[ch].rx_fifo_num == RX_FIFO_SIZE )
{
duart_68681.channel[ch].SR |= STATUS_FIFO_FULL;
if ( BIT(duart_68681.channel[ch].MR1,MODE_RX_INT_SELECT_BIT) == 1 )
{
duart_68681.ISR |= (ch == 0) ? INT_RXRDY_FFULLA : INT_RXRDY_FFULLB;
}
}
duart_68681_update_interrupts();
}
};
void duart_68681_init(int frequency, void (*irq_handler)(UINT8 vector), void (*tx_callback)(int channel, UINT8 data))
{
memset(&duart_68681, 0, sizeof(duart_68681));
duart_68681.frequency = frequency;
duart_68681.tx_callback = tx_callback;
duart_68681.irq_handler = irq_handler;
// allocate timers
duart_68681.channel[0].tx_timer = timer_alloc(tx_timer_callback, NULL);
timer_adjust_oneshot(duart_68681.channel[0].tx_timer, attotime_never, 0);
duart_68681.channel[1].tx_timer = timer_alloc(tx_timer_callback, NULL);
timer_adjust_oneshot(duart_68681.channel[1].tx_timer, attotime_never, 1);
};

10
src/emu/machine/68681.h Normal file
View File

@ -0,0 +1,10 @@
#ifndef _68681_H
#define _68681_H
void duart_68681_init(int frequency, void (*irq_handler)(UINT8 vector), void (*tx_callback)(int channel, UINT8 data));
void duart_68681_rx_data( int ch, UINT8 data );
READ16_HANDLER(duart_68681_r);
WRITE16_HANDLER(duart_68681_w);
#endif //_68681_H

185
src/emu/machine/microtch.c Normal file
View File

@ -0,0 +1,185 @@
/*
Microtouch touch screen controller
Written by Mariusz Wojcieszek
Notes/ToDo:
- calibration mode (command CX)
- only tablet format is supported for returning touch screen state
*/
#include "driver.h"
#include "microtch.h"
static struct
{
UINT8 rx_buffer[16];
int rx_buffer_ptr;
emu_timer* timer;
UINT8 tx_buffer[16];
UINT8 tx_buffer_num;
UINT8 tx_buffer_ptr;
int reset_done;
int format_tablet;
int mode_inactive;
int mode_stream;
int last_touch_state;
int last_x;
int last_y;
void (*tx_callback)(UINT8 data);
int (*touch_callback)(int *touch_x, int *touch_y);
} microtouch;
static int microtouch_check_command( const char* commandtocheck, int command_len, UINT8* command_data )
{
if ( (command_len == (strlen(commandtocheck) + 2)) &&
(command_data[0] == 0x01) &&
(strncmp(commandtocheck, (const char*)command_data + 1, strlen(commandtocheck)) == 0) &&
(command_data[command_len-1] == 0x0d) )
{
return 1;
}
else
{
return 0;
}
}
static void microtouch_send_format_table_packet(UINT8 flag, int x, int y)
{
microtouch.tx_buffer[microtouch.tx_buffer_num++] = flag;
// lower byte (7bits) of x coordinate
microtouch.tx_buffer[microtouch.tx_buffer_num++] = x & 0x7f;
// higher byte (7bits) of x coordinate
microtouch.tx_buffer[microtouch.tx_buffer_num++] = (x >> 7) & 0x7f;
// lower byte (7bits) of y coordinate
microtouch.tx_buffer[microtouch.tx_buffer_num++] = y & 0x7f;
// higher byte (7bits) of y coordinate
microtouch.tx_buffer[microtouch.tx_buffer_num++] = (y >> 7) & 0x7f;
};
static TIMER_CALLBACK(microtouch_timer_callback)
{
if ( microtouch.tx_buffer_ptr < microtouch.tx_buffer_num )
{
microtouch.tx_callback( microtouch.tx_buffer[microtouch.tx_buffer_ptr++] );
if ( microtouch.tx_buffer_ptr == microtouch.tx_buffer_num )
{
microtouch.tx_buffer_ptr = microtouch.tx_buffer_num = 0;
}
return;
}
if ( (microtouch.reset_done == 0) ||
(microtouch.format_tablet == 0) ||
(microtouch.mode_inactive == 1) ||
(microtouch.mode_stream == 0) )
{
return;
}
// send format tablet packet
if ( input_port_read(machine, "TOUCH") & 0x01 )
{
int tx = input_port_read(machine, "TOUCH_X");
int ty = input_port_read(machine, "TOUCH_Y");
if ( microtouch.touch_callback == NULL ||
microtouch.touch_callback( &tx, &ty ) != 0 )
{
ty = 0x4000 - ty;
microtouch_send_format_table_packet(0xc0, tx, ty);
microtouch.last_touch_state = 1;
microtouch.last_x = tx;
microtouch.last_y = ty;
}
}
else
{
if ( microtouch.last_touch_state == 1 )
{
microtouch.last_touch_state = 0;
microtouch_send_format_table_packet(0x80, microtouch.last_x, microtouch.last_y);
}
}
};
void microtouch_init(void (*tx_cb)(UINT8 data),
int (*touch_cb)(int *touch_x, int *touch_y))
{
memset(&microtouch, 0, sizeof(microtouch));
microtouch.last_touch_state = -1;
microtouch.tx_callback = tx_cb;
microtouch.touch_callback = touch_cb;
microtouch.timer = timer_alloc(microtouch_timer_callback, NULL);
timer_adjust_periodic(microtouch.timer, ATTOTIME_IN_HZ(167*5), 0, ATTOTIME_IN_HZ(167*5));
state_save_register_item("microtouch", 0, microtouch.reset_done);
state_save_register_item("microtouch", 0, microtouch.format_tablet);
state_save_register_item("microtouch", 0, microtouch.mode_inactive);
state_save_register_item("microtouch", 0, microtouch.mode_stream);
state_save_register_item("microtouch", 0, microtouch.last_touch_state);
state_save_register_item("microtouch", 0, microtouch.last_x);
state_save_register_item("microtouch", 0, microtouch.last_y);
state_save_register_item_array("microtouch", 0, microtouch.rx_buffer);
state_save_register_item("microtouch", 0, microtouch.rx_buffer_ptr);
state_save_register_item_array("microtouch", 0, microtouch.tx_buffer);
state_save_register_item("microtouch", 0, microtouch.tx_buffer_num);
state_save_register_item("microtouch", 0, microtouch.tx_buffer_ptr);
};
void microtouch_rx(int count, UINT8* data)
{
int i;
for ( i = 0; (i < count) && ((microtouch.rx_buffer_ptr + i) < 16); i++ )
{
microtouch.rx_buffer[i+microtouch.rx_buffer_ptr] = data[i];
microtouch.rx_buffer_ptr++;
}
if (microtouch.rx_buffer_ptr > 0 && (microtouch.rx_buffer[microtouch.rx_buffer_ptr-1] == 0x0d))
{
// check command
if ( microtouch_check_command( "MS", microtouch.rx_buffer_ptr, microtouch.rx_buffer ) )
{
microtouch.mode_stream = 1;
microtouch.mode_inactive = 0;
}
else if ( microtouch_check_command( "MI", microtouch.rx_buffer_ptr, microtouch.rx_buffer ) )
{
microtouch.mode_inactive = 1;
}
else if ( microtouch_check_command( "R", microtouch.rx_buffer_ptr, microtouch.rx_buffer ) )
{
microtouch.tx_buffer_num = 0;
microtouch.reset_done = 1;
}
else if ( microtouch_check_command( "FT", microtouch.rx_buffer_ptr, microtouch.rx_buffer ) )
{
microtouch.format_tablet = 1;
}
// send response
microtouch.tx_buffer[microtouch.tx_buffer_num++] = 0x01;
microtouch.tx_buffer[microtouch.tx_buffer_num++] = 0x30;
microtouch.tx_buffer[microtouch.tx_buffer_num++] = 0x0d;
microtouch.rx_buffer_ptr = 0;
}
};
INPUT_PORTS_START(microtouch)
PORT_START_TAG("TOUCH")
PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_IMPULSE(10) PORT_NAME( "Touch screen" )
PORT_START_TAG("TOUCH_X")
PORT_BIT( 0x3fff, 0x2000, IPT_LIGHTGUN_X ) PORT_CROSSHAIR(X, 1.0, 0.0, 0) PORT_SENSITIVITY(45) PORT_KEYDELTA(15)
PORT_START_TAG("TOUCH_Y")
PORT_BIT( 0x3fff, 0x2000, IPT_LIGHTGUN_Y ) PORT_CROSSHAIR(Y, 1.0, 0.0, 0) PORT_SENSITIVITY(45) PORT_KEYDELTA(15)
INPUT_PORTS_END

View File

@ -0,0 +1,9 @@
#ifndef _MICROTOUCH_H
#define _MICROTOUCH_H
INPUT_PORTS_EXTERN(microtouch);
void microtouch_init(void (*tx_cb)(UINT8 data), int (*touch_cb)(int *touch_x, int *touch_y));
void microtouch_rx(int count, UINT8* data);
#endif //_MICROTOUCH_H

View File

@ -46,7 +46,6 @@
- blinking on Meagtouch title screen is probably incorrect
- clean up V9938 interrupt implementation
- finish inputs, dsw, outputs (lamps)
- calibration mode in Microtouch emulation (command CX)
- problem with registering touches on the bottom of the screen (currently hacked to work)
- megat3: u37 has bad size, should be 8MBit
- megat4: rom u32 was bad, currently using u32 from megat4te
@ -62,6 +61,7 @@
#include "machine/8255ppi.h"
#include "machine/z80pio.h"
#include "machine/pc16552d.h"
#include "machine/microtch.h"
/*************************************
*
@ -199,166 +199,6 @@ static void ds1204_init(const UINT8* key, const UINT8* nvram)
state_save_register_item_array("ds1204", 0, ds1204.command);
};
/*************************************
*
* Microtouch touch screen controller
*
*************************************/
static struct
{
UINT8 tx_buffer[16];
int tx_buffer_ptr;
emu_timer* timer;
int reset_done;
int format_tablet;
int mode_inactive;
int mode_stream;
int last_touch_state;
int last_x;
int last_y;
void (*tx_callback)(UINT8 data);
int (*touch_callback)(int *touch_x, int *touch_y);
} microtouch;
static int microtouch_check_command( const char* commandtocheck, int command_len, UINT8* command_data )
{
if ( (command_len == (strlen(commandtocheck) + 2)) &&
(command_data[0] == 0x01) &&
(strncmp(commandtocheck, (const char*)command_data + 1, strlen(commandtocheck)) == 0) &&
(command_data[command_len-1] == 0x0d) )
{
return 1;
}
else
{
return 0;
}
}
static void microtouch_send_format_table_packet(UINT8 flag, int x, int y)
{
microtouch.tx_callback(flag);
// lower byte (7bits) of x coordinate
microtouch.tx_callback(x & 0x7f);
// higher byte (7bits) of x coordinate
microtouch.tx_callback((x >> 7) & 0x7f);
// lower byte (7bits) of y coordinate
microtouch.tx_callback(y & 0x7f);
// higher byte (7bits) of y coordinate
microtouch.tx_callback((y >> 7) & 0x7f);
};
static TIMER_CALLBACK(microtouch_timer_callback)
{
if ( (microtouch.reset_done == 0) ||
(microtouch.format_tablet == 0) ||
(microtouch.mode_inactive == 1) ||
(microtouch.mode_stream == 0) )
{
return;
}
// send format tablet packet
if ( input_port_read(machine, "TOUCH") & 0x01 )
{
int tx = input_port_read(machine, "TOUCH_X");
int ty = input_port_read(machine, "TOUCH_Y");
if ( microtouch.touch_callback == NULL ||
microtouch.touch_callback( &tx, &ty ) != 0 )
{
ty = 0x4000 - ty;
microtouch_send_format_table_packet(0xc0, tx, ty);
microtouch.last_touch_state = 1;
microtouch.last_x = tx;
microtouch.last_y = ty;
}
}
else
{
if ( microtouch.last_touch_state == 1 )
{
microtouch.last_touch_state = 0;
microtouch_send_format_table_packet(0x80, microtouch.last_x, microtouch.last_y);
}
}
};
static void microtouch_init(void (*tx_cb)(UINT8 data),
int (*touch_cb)(int *touch_x, int *touch_y))
{
memset(&microtouch, 0, sizeof(microtouch));
microtouch.last_touch_state = -1;
microtouch.tx_callback = tx_cb;
microtouch.touch_callback = touch_cb;
microtouch.timer = timer_alloc(microtouch_timer_callback, NULL);
timer_adjust_periodic(microtouch.timer, ATTOTIME_IN_HZ(167), 0, ATTOTIME_IN_HZ(167));
state_save_register_item("microtouch", 0, microtouch.reset_done);
state_save_register_item("microtouch", 0, microtouch.format_tablet);
state_save_register_item("microtouch", 0, microtouch.mode_inactive);
state_save_register_item("microtouch", 0, microtouch.mode_stream);
state_save_register_item("microtouch", 0, microtouch.last_touch_state);
state_save_register_item("microtouch", 0, microtouch.last_x);
state_save_register_item("microtouch", 0, microtouch.last_y);
state_save_register_item_array("microtouch", 0, microtouch.tx_buffer);
state_save_register_item("microtouch", 0, microtouch.tx_buffer_ptr);
};
static void microtouch_rx(int count, UINT8* data)
{
int i;
for ( i = 0; (i < count) && ((microtouch.tx_buffer_ptr + i) < 16); i++ )
{
microtouch.tx_buffer[i+microtouch.tx_buffer_ptr] = data[i];
microtouch.tx_buffer_ptr++;
}
if (microtouch.tx_buffer_ptr > 0 && (microtouch.tx_buffer[microtouch.tx_buffer_ptr-1] == 0x0d))
{
// check command
if ( microtouch_check_command( "MS", microtouch.tx_buffer_ptr, microtouch.tx_buffer ) )
{
microtouch.mode_stream = 1;
microtouch.mode_inactive = 0;
}
else if ( microtouch_check_command( "MI", microtouch.tx_buffer_ptr, microtouch.tx_buffer ) )
{
microtouch.mode_inactive = 1;
}
else if ( microtouch_check_command( "R", microtouch.tx_buffer_ptr, microtouch.tx_buffer ) )
{
microtouch.reset_done = 1;
}
else if ( microtouch_check_command( "FT", microtouch.tx_buffer_ptr, microtouch.tx_buffer ) )
{
microtouch.format_tablet = 1;
}
// send response
microtouch.tx_callback(0x01);
microtouch.tx_callback(0x30);
microtouch.tx_callback(0x0d);
microtouch.tx_buffer_ptr = 0;
}
};
static INPUT_PORTS_START(microtouch)
PORT_START_TAG("TOUCH")
PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_IMPULSE(10) PORT_NAME( "Touch screen" )
PORT_START_TAG("TOUCH_X")
PORT_BIT( 0x3fff, 0x2000, IPT_LIGHTGUN_X ) PORT_CROSSHAIR(X, 1.0, 0.0, 0) PORT_SENSITIVITY(45) PORT_KEYDELTA(15)
PORT_START_TAG("TOUCH_Y")
PORT_BIT( 0x3fff, 0x2000, IPT_LIGHTGUN_Y ) PORT_CROSSHAIR(Y, 1.0, 0.0, 0) PORT_SENSITIVITY(45) PORT_KEYDELTA(15)
INPUT_PORTS_END
/*************************************
*
* Microtouch <-> pc16650 interface

View File

@ -2,7 +2,7 @@
-= Touch Master / Galaxy Games =-
driver by Luca Elia (l.elia@tin.it)
driver by Luca Elia (l.elia@tin.it) and Mariusz Wojcieszek
CPU: 68000
@ -11,16 +11,13 @@ Sound: OKI6295
[Touch Master]
Input: Pressure sensitive touch screen
Input: Microtouch touch screen
Other: Dallas NVRAM + optional RTC
To Do:
- Proper touchscreen controller emulation. Currently it's flakey and
tends to stop registering user input (try coining up in that case)
- Protection in tm4k and later games
- Protection in tm4k and later games (where is DS1204 mapped?)
- Coin optics
- RTC emulation (there's code to check the upper bytes of NVRAM to see if
the real time clock is present, and to only use it in that case)
- Is sound banking correct?
To be dumped and added:
@ -64,6 +61,8 @@ To Do:
#include "deprecat.h"
#include "sound/okim6295.h"
#include "machine/eeprom.h"
#include "machine/microtch.h"
#include "machine/68681.h"
/***************************************************************************
@ -89,74 +88,70 @@ static WRITE16_HANDLER( tmaster_oki_bank_w )
/***************************************************************************
Touch Screen Controller - PRELIMINARY
68681 DUART <-> Microtouch touch screen controller communication
***************************************************************************/
static int touchscreen;
static void show_touchscreen(running_machine *machine)
static void duart_irq_handler(UINT8 vector)
{
#ifdef MAME_DEBUG
popmessage("% d] %03x %03x - %d",touchscreen,input_port_read(machine, "TSCREEN_X")&0x1ff,input_port_read(machine, "TSCREEN_Y"),okibank);
#endif
cpunum_set_input_line_and_vector(Machine, 0, 4, HOLD_LINE, vector);
};
static void duart_tx(int channel, UINT8 data)
{
if ( channel == 0 )
{
//logerror( "duart->microtouch: %02x %c\n", data, (char)data);
microtouch_rx(1, &data);
}
};
static void microtouch_tx(UINT8 data)
{
//logerror( "microtouch->duart: %02x %c\n", data, (char)data);
duart_68681_rx_data(0, data);
}
static WRITE16_HANDLER( tmaster_tscreen_reset_w )
/***************************************************************************
DS1644 RTC
***************************************************************************/
static UINT8 rtc_ram[8];
static UINT8 binary_to_BCD(UINT8 data)
{
if (ACCESSING_BITS_0_7 && data == 0x05)
data %= 100;
return ((data / 10) << 4) | (data %10);
}
static READ16_HANDLER(rtc_r)
{
mame_system_time systime;
mame_get_current_datetime(Machine, &systime);
rtc_ram[0x1] = binary_to_BCD(systime.local_time.second);
rtc_ram[0x2] = binary_to_BCD(systime.local_time.minute);
rtc_ram[0x3] = binary_to_BCD(systime.local_time.hour);
rtc_ram[0x4] = binary_to_BCD(systime.local_time.weekday+1);
rtc_ram[0x5] = binary_to_BCD(systime.local_time.mday);
rtc_ram[0x6] = binary_to_BCD(systime.local_time.month+1);
rtc_ram[0x7] = binary_to_BCD(systime.local_time.year % 100);
return rtc_ram[offset];
}
static WRITE16_HANDLER(rtc_w)
{
if ( offset == 0 )
{
touchscreen = 0;
show_touchscreen(machine);
rtc_ram[0x0] = data & 0xff;
}
}
static READ16_HANDLER( tmaster_tscreen_next_r )
{
if (touchscreen != -1)
touchscreen++;
if (touchscreen == 6)
touchscreen = -1;
show_touchscreen(machine);
return 0;
}
static READ16_HANDLER( tmaster_tscreen_x_hi_r )
{
switch (touchscreen)
{
case -1: return 0xf1;
}
return 0x01;
}
static READ16_HANDLER( tmaster_tscreen_x_lo_r )
{
UINT16 val = 0;
int press1 = input_port_read(machine, "TSCREEN_X") & 0x4000;
int press2 = input_port_read(machine, "TSCREEN_X") & 0x8000;
if (press1) press2 = 1;
switch (touchscreen)
{
case 1: val = press1 ? 0 : 1<<6; break; // press
case 2: val = input_port_read(machine, "TSCREEN_X") & 0x003; break;
case 3: val = (input_port_read(machine, "TSCREEN_X") >> 2) & 0x7f; break;
case 4: val = 0; break;
case 5: val = ((input_port_read(machine, "TSCREEN_Y")^0xff) >> 1) & 0x7f; break;
default:
return 0;
}
return val | (press2 ? 0x80 : 0); // away : hover
}
static READ16_HANDLER( tmaster_tscreen_y_hi_r ) { return 0x01; }
static READ16_HANDLER( tmaster_tscreen_y_lo_r ) { return 0x00; }
/***************************************************************************
@ -390,16 +385,12 @@ static READ16_HANDLER( tmaster_coins_r )
static ADDRESS_MAP_START( tmaster_map, ADDRESS_SPACE_PROGRAM, 16 )
AM_RANGE( 0x000000, 0x1fffff ) AM_ROM
AM_RANGE( 0x200000, 0x27ffff ) AM_RAM
AM_RANGE( 0x280000, 0x28ffff ) AM_RAM AM_BASE(&generic_nvram16) AM_SIZE(&generic_nvram_size)
AM_RANGE( 0x280000, 0x28ffef ) AM_RAM AM_BASE(&generic_nvram16) AM_SIZE(&generic_nvram_size)
AM_RANGE( 0x28fff0, 0x28ffff ) AM_READWRITE( rtc_r, rtc_w )
AM_RANGE( 0x300010, 0x300011 ) AM_READ( tmaster_coins_r )
AM_RANGE( 0x300022, 0x300023 ) AM_READ ( tmaster_tscreen_x_hi_r )
AM_RANGE( 0x300024, 0x300025 ) AM_WRITE( tmaster_tscreen_reset_w )
AM_RANGE( 0x300026, 0x300027 ) AM_READ ( tmaster_tscreen_x_lo_r )
AM_RANGE( 0x300028, 0x300029 ) AM_READ ( tmaster_tscreen_next_r )
AM_RANGE( 0x300032, 0x300033 ) AM_READ ( tmaster_tscreen_y_hi_r )
AM_RANGE( 0x300036, 0x300037 ) AM_READ ( tmaster_tscreen_y_lo_r )
AM_RANGE( 0x300020, 0x30003f ) AM_READWRITE( duart_68681_r, duart_68681_w )
AM_RANGE( 0x300040, 0x300041 ) AM_WRITE( tmaster_oki_bank_w )
@ -603,20 +594,13 @@ ADDRESS_MAP_END
Input Ports
***************************************************************************/
static INPUT_PORTS_START( tmaster )
PORT_START_TAG("TSCREEN_X")
PORT_BIT( 0x01ff, 0x100, IPT_LIGHTGUN_X ) PORT_CROSSHAIR(X, 1, 0, 0) PORT_SENSITIVITY(35) PORT_KEYDELTA(3) PORT_PLAYER(1)
PORT_BIT( 0x4000, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_IMPULSE(5) // press
PORT_BIT( 0x8000, IP_ACTIVE_HIGH, IPT_BUTTON2 ) // hover
PORT_START_TAG("TSCREEN_Y")
PORT_BIT( 0x0ff, 0x80, IPT_LIGHTGUN_Y ) PORT_CROSSHAIR(Y, 1, 0, 0) PORT_SENSITIVITY(35) PORT_KEYDELTA(3) PORT_PLAYER(1)
static INPUT_PORTS_START( tm )
PORT_INCLUDE(microtouch)
PORT_START_TAG("COIN") // IN3
PORT_BIT( 0x0001, IP_ACTIVE_LOW, IPT_COIN1 ) PORT_IMPULSE(2) // m. coin 1 (coin optics?)
PORT_BIT( 0x0002, IP_ACTIVE_LOW, IPT_COIN1 ) PORT_IMPULSE(4) // m. coin 2 (coin optics?)
PORT_BIT( 0x0004, IP_ACTIVE_LOW, IPT_COIN1 ) PORT_IMPULSE(6) // dbv input (coin optics?)
PORT_BIT( 0x0001, IP_ACTIVE_LOW, IPT_UNKNOWN ) // m. coin 1 (coin optics?)
PORT_BIT( 0x0002, IP_ACTIVE_LOW, IPT_UNKNOWN ) // m. coin 2 (coin optics?)
PORT_BIT( 0x0004, IP_ACTIVE_LOW, IPT_UNKNOWN ) // dbv input (coin optics?)
PORT_BIT( 0x0008, IP_ACTIVE_LOW, IPT_UNKNOWN )
PORT_BIT( 0x0010, IP_ACTIVE_LOW, IPT_COIN1 ) // (service coin?)
PORT_SERVICE_NO_TOGGLE( 0x0020, IP_ACTIVE_LOW )
@ -626,10 +610,32 @@ static INPUT_PORTS_START( tmaster )
PORT_BIT( 0x0200, IP_ACTIVE_LOW, IPT_UNKNOWN )
PORT_BIT( 0x0400, IP_ACTIVE_LOW, IPT_UNKNOWN )
PORT_BIT( 0x0800, IP_ACTIVE_HIGH, IPT_SPECIAL )
PORT_BIT( 0x1000, IP_ACTIVE_LOW, IPT_COIN1 ) // e. coin 1
PORT_BIT( 0x2000, IP_ACTIVE_LOW, IPT_COIN2 ) // e. coin 2
PORT_BIT( 0x4000, IP_ACTIVE_LOW, IPT_COIN3 ) // e. coin 3
PORT_BIT( 0x8000, IP_ACTIVE_LOW, IPT_COIN4 ) // e. coin 4
PORT_BIT( 0x1000, IP_ACTIVE_LOW, IPT_COIN1 ) PORT_IMPULSE(2) // e. coin 1
PORT_BIT( 0x2000, IP_ACTIVE_LOW, IPT_UNKNOWN ) // e. coin 2
PORT_BIT( 0x4000, IP_ACTIVE_LOW, IPT_UNKNOWN ) // e. coin 3
PORT_BIT( 0x8000, IP_ACTIVE_LOW, IPT_UNKNOWN ) // e. coin 4
INPUT_PORTS_END
static INPUT_PORTS_START( tmaster )
PORT_INCLUDE(microtouch)
PORT_START_TAG("COIN") // IN3
PORT_BIT( 0x0001, IP_ACTIVE_LOW, IPT_COIN1 ) PORT_IMPULSE(2) // m. coin 1 (coin optics?)
PORT_BIT( 0x0002, IP_ACTIVE_LOW, IPT_UNKNOWN ) // m. coin 2 (coin optics?)
PORT_BIT( 0x0004, IP_ACTIVE_LOW, IPT_UNKNOWN ) // dbv input (coin optics?)
PORT_BIT( 0x0008, IP_ACTIVE_LOW, IPT_UNKNOWN )
PORT_BIT( 0x0010, IP_ACTIVE_LOW, IPT_COIN1 ) // (service coin?)
PORT_SERVICE_NO_TOGGLE( 0x0020, IP_ACTIVE_LOW )
PORT_BIT( 0x0040, IP_ACTIVE_LOW, IPT_SERVICE1 ) // calibrate
PORT_BIT( 0x0080, IP_ACTIVE_LOW, IPT_UNKNOWN )
PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_UNKNOWN )
PORT_BIT( 0x0200, IP_ACTIVE_LOW, IPT_UNKNOWN )
PORT_BIT( 0x0400, IP_ACTIVE_LOW, IPT_UNKNOWN )
PORT_BIT( 0x0800, IP_ACTIVE_HIGH, IPT_SPECIAL )
PORT_BIT( 0x1000, IP_ACTIVE_LOW, IPT_UNKNOWN ) // e. coin 1
PORT_BIT( 0x2000, IP_ACTIVE_LOW, IPT_UNKNOWN ) // e. coin 2
PORT_BIT( 0x4000, IP_ACTIVE_LOW, IPT_UNKNOWN ) // e. coin 3
PORT_BIT( 0x8000, IP_ACTIVE_LOW, IPT_UNKNOWN ) // e. coin 4
INPUT_PORTS_END
static INPUT_PORTS_START( galgames )
@ -684,9 +690,10 @@ INPUT_PORTS_END
***************************************************************************/
static MACHINE_RESET( tmaster )
static MACHINE_START( tmaster )
{
touchscreen = -1;
duart_68681_init(0, duart_irq_handler, duart_tx);
microtouch_init(microtouch_tx, 0);
}
static INTERRUPT_GEN( tm3k_interrupt )
@ -695,13 +702,6 @@ static INTERRUPT_GEN( tm3k_interrupt )
{
case 0: cpunum_set_input_line(machine, 0, 2, HOLD_LINE); break;
case 1: cpunum_set_input_line(machine, 0, 3, HOLD_LINE); break;
case 2:
case 3:
case 4:
case 5:
case 6: cpunum_set_input_line_and_vector(machine, 0, 4, HOLD_LINE, 0x100/4); break; // touch screen controller
default: cpunum_set_input_line(machine, 0, 1, HOLD_LINE); break;
}
}
@ -709,9 +709,9 @@ static INTERRUPT_GEN( tm3k_interrupt )
static MACHINE_DRIVER_START( tm3k )
MDRV_CPU_ADD_TAG("main", M68000, 12000000)
MDRV_CPU_PROGRAM_MAP(tmaster_map,0)
MDRV_CPU_VBLANK_INT_HACK(tm3k_interrupt,2+5+20) // ??
MDRV_CPU_VBLANK_INT_HACK(tm3k_interrupt,2+20) // ??
MDRV_MACHINE_RESET(tmaster)
MDRV_MACHINE_START(tmaster)
MDRV_NVRAM_HANDLER(generic_0fill)
@ -735,21 +735,8 @@ static MACHINE_DRIVER_START( tm3k )
MACHINE_DRIVER_END
static INTERRUPT_GEN( tm_interrupt )
{
switch (cpu_getiloops())
{
case 0: cpunum_set_input_line(machine, 0, 2, HOLD_LINE); break;
case 1: cpunum_set_input_line(machine, 0, 3, HOLD_LINE); break;
case 2: cpunum_set_input_line_and_vector(machine, 0, 4, HOLD_LINE, 0x100/4); break; // touch screen controller
default: cpunum_set_input_line(machine, 0, 1, HOLD_LINE); break;
}
}
static MACHINE_DRIVER_START( tm )
MDRV_IMPORT_FROM(tm3k)
MDRV_CPU_MODIFY("main")
MDRV_CPU_VBLANK_INT_HACK(tm_interrupt,3+20) // ??
MDRV_SOUND_REPLACE("OKI",OKIM6295, 1122000)
MDRV_SOUND_CONFIG(okim6295_interface_region_1_pin7high) // clock frequency & pin 7 not verified
@ -1176,9 +1163,9 @@ static DRIVER_INIT( galgames )
memory_configure_bank(4, 0, 1, memory_region(REGION_CPU1)+0x200000, 0x40000);
}
GAME( 1996, tm, 0, tm, tmaster, 0, ROT0, "Midway", "Touchmaster", GAME_NOT_WORKING )
GAME( 1997, tm3k, 0, tm3k, tmaster, tm3k, ROT0, "Midway", "Touchmaster 3000 (v5.01)", GAME_NOT_WORKING | GAME_IMPERFECT_GRAPHICS) // imp. graphics due to bad dump
GAME( 1998, tm4k, 0, tm3k, tmaster, tm4k, ROT0, "Midway", "Touchmaster 4000 (v6.02)", GAME_NOT_WORKING )
GAME( 1998, tm5k, 0, tm3k, tmaster, tm5k, ROT0, "Midway", "Touchmaster 5000 (v7.10)", GAME_NOT_WORKING )
GAME( 1999, tm7k, 0, tm3k, tmaster, tm7k, ROT0, "Midway", "Touchmaster 7000 (v8.00)", GAME_NOT_WORKING )
GAME( 1996, tm, 0, tm, tm, 0, ROT0, "Midway", "Touchmaster", 0 )
GAME( 1997, tm3k, 0, tm3k, tmaster, tm3k, ROT0, "Midway", "Touchmaster 3000 (v5.01)", GAME_IMPERFECT_GRAPHICS) // imp. graphics due to bad dump
GAME( 1998, tm4k, 0, tm3k, tmaster, tm4k, ROT0, "Midway", "Touchmaster 4000 (v6.02)", 0 )
GAME( 1998, tm5k, 0, tm3k, tmaster, tm5k, ROT0, "Midway", "Touchmaster 5000 (v7.10)", 0 )
GAME( 1999, tm7k, 0, tm3k, tmaster, tm7k, ROT0, "Midway", "Touchmaster 7000 (v8.00)", 0 )
GAME( 1998, galgbios, 0, galgames, galgames, galgames, ROT0, "Creative Electonics & Software", "Galaxy Games (BIOS v1.90)", GAME_IS_BIOS_ROOT )