summaryrefslogtreecommitdiffstatshomepage
path: root/trunk/src/emu/machine/ldvp931.c
diff options
context:
space:
mode:
Diffstat (limited to 'trunk/src/emu/machine/ldvp931.c')
-rw-r--r--trunk/src/emu/machine/ldvp931.c781
1 files changed, 781 insertions, 0 deletions
diff --git a/trunk/src/emu/machine/ldvp931.c b/trunk/src/emu/machine/ldvp931.c
new file mode 100644
index 00000000000..f9738c9fcc3
--- /dev/null
+++ b/trunk/src/emu/machine/ldvp931.c
@@ -0,0 +1,781 @@
+/*************************************************************************
+
+ ldvp931.c
+
+ Philips 22VP931 laserdisc emulation.
+
+ Copyright Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**************************************************************************
+
+ Still to do:
+
+ * determine actual slow/fast speeds
+ *
+
+*************************************************************************/
+
+#include "emu.h"
+#include "ldcore.h"
+#include "cpu/mcs48/mcs48.h"
+
+
+
+/***************************************************************************
+ DEBUGGING
+***************************************************************************/
+
+#define LOG_COMMANDS 0
+#define LOG_PORTS 0
+
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+/* scanning speeds */
+#define SCAN_SPEED (2000 / 30) /* 2000 frames/second */
+#define SCAN_FAST_SPEED (4000 / 30) /* 4000 frames/second */
+
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+/* player-specific data */
+struct _ldplayer_data
+{
+ /* low-level emulation data */
+ device_t *cpu; /* CPU index of the 8049 */
+ timer_device * tracktimer; /* timer device */
+ vp931_data_ready_func data_ready_cb; /* data ready callback */
+
+ /* I/O port states */
+ UINT8 out0; /* output 0 state */
+ UINT8 out1; /* output 1 state */
+ UINT8 port1; /* port 1 state */
+
+ /* DATIC circuit implementation */
+ UINT8 daticval; /* latched DATIC value */
+ UINT8 daticerp; /* /ERP value from DATIC */
+ UINT8 datastrobe; /* DATA STROBE line from DATIC */
+
+ /* communication status */
+ UINT8 fromcontroller; /* command byte from the controller */
+ UINT8 fromcontroller_pending; /* TRUE if data is pending */
+ UINT8 tocontroller; /* command byte to the controller */
+ UINT8 tocontroller_pending; /* TRUE if data is pending */
+
+ /* tracking */
+ INT8 trackdir; /* direction of tracking */
+ UINT8 trackstate; /* state of tracking */
+
+ /* debugging */
+ UINT8 cmdbuf[3]; /* 3 bytes worth of commands */
+ UINT8 cmdcount; /* number of command bytes seen */
+ INT16 advanced; /* number of frames advanced */
+};
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+static void vp931_init(laserdisc_state *ld);
+static void vp931_vsync(laserdisc_state *ld, const vbi_metadata *vbi, int fieldnum, attotime curtime);
+static INT32 vp931_update(laserdisc_state *ld, const vbi_metadata *vbi, int fieldnum, attotime curtime);
+static void vp931_data_w(laserdisc_state *ld, UINT8 prev, UINT8 data);
+static UINT8 vp931_data_r(laserdisc_state *ld);
+static UINT8 vp931_ready(laserdisc_state *ld);
+static UINT8 vp931_data_ready(laserdisc_state *ld);
+
+static TIMER_CALLBACK( vbi_data_fetch );
+static TIMER_CALLBACK( deferred_data_w );
+static TIMER_CALLBACK( irq_off );
+static TIMER_CALLBACK( datastrobe_off );
+static TIMER_CALLBACK( erp_off );
+static TIMER_DEVICE_CALLBACK( track_timer );
+
+static WRITE8_HANDLER( output0_w );
+static WRITE8_HANDLER( output1_w );
+static WRITE8_HANDLER( lcd_w );
+static READ8_HANDLER( unknown_r );
+static READ8_HANDLER( keypad_r );
+static READ8_HANDLER( datic_r );
+static READ8_HANDLER( from_controller_r );
+static WRITE8_HANDLER( to_controller_w );
+static READ8_HANDLER( port1_r );
+static WRITE8_HANDLER( port1_w );
+static READ8_HANDLER( port2_r );
+static WRITE8_HANDLER( port2_w );
+static READ8_HANDLER( t0_r );
+static READ8_HANDLER( t1_r );
+
+
+
+/***************************************************************************
+ 22VP931 ROM AND MACHINE INTERFACES
+***************************************************************************/
+
+static ADDRESS_MAP_START( vp931_portmap, AS_IO, 8 )
+ AM_RANGE(0x00, 0x00) AM_MIRROR(0xcf) AM_READWRITE(keypad_r, output0_w)
+ AM_RANGE(0x10, 0x10) AM_MIRROR(0xcf) AM_READWRITE(unknown_r, output1_w)
+ AM_RANGE(0x20, 0x20) AM_MIRROR(0xcf) AM_READWRITE(datic_r, lcd_w)
+ AM_RANGE(0x30, 0x30) AM_MIRROR(0xcf) AM_READWRITE(from_controller_r, to_controller_w)
+ AM_RANGE(MCS48_PORT_P1, MCS48_PORT_P1) AM_READWRITE(port1_r, port1_w)
+ AM_RANGE(MCS48_PORT_P2, MCS48_PORT_P2) AM_READWRITE(port2_r, port2_w)
+ AM_RANGE(MCS48_PORT_T0, MCS48_PORT_T0) AM_READ(t0_r)
+ AM_RANGE(MCS48_PORT_T1, MCS48_PORT_T1) AM_READ(t1_r)
+ADDRESS_MAP_END
+
+
+static MACHINE_CONFIG_FRAGMENT( vp931 )
+ MCFG_CPU_ADD("vp931", I8049, XTAL_11MHz)
+ MCFG_CPU_IO_MAP(vp931_portmap)
+ MCFG_TIMER_ADD("tracktimer", track_timer)
+MACHINE_CONFIG_END
+
+
+ROM_START( vp931 )
+ ROM_REGION( 0x800, "vp931", 0 )
+ ROM_LOAD( "at-6-1_a.bin", 0x000, 0x800, CRC(e11b3c8d) SHA1(ea2d7f6a044ed085ce5e09d8b1b1a21c37f0e9b8) )
+ROM_END
+
+
+
+/***************************************************************************
+ 22VP931 PLAYER INTERFACE
+***************************************************************************/
+
+const ldplayer_interface vp931_interface =
+{
+ LASERDISC_TYPE_PHILLIPS_22VP931, /* type of the player */
+ sizeof(ldplayer_data), /* size of the state */
+ "Phillips 22VP931", /* name of the player */
+ "22vp931", /* shortname of the player */
+ ROM_NAME(vp931), /* pointer to ROM region information */
+ MACHINE_CONFIG_NAME(vp931), /* pointer to machine configuration */
+ vp931_init, /* initialization callback */
+ vp931_vsync, /* vsync callback */
+ vp931_update, /* update callback */
+ NULL, /* overlay callback */
+ vp931_data_w, /* parallel data write */
+ { /* single line write: */
+ NULL, /* LASERDISC_LINE_ENTER */
+ NULL /* LASERDISC_LINE_CONTROL */
+ },
+ vp931_data_r, /* parallel data read */
+ { /* single line read: */
+ vp931_ready, /* LASERDISC_LINE_READY */
+ NULL, /* LASERDISC_LINE_STATUS */
+ NULL, /* LASERDISC_LINE_COMMAND */
+ vp931_data_ready, /* LASERDISC_LINE_DATA_AVAIL */
+ }
+};
+
+
+
+/***************************************************************************
+ PUBLIC FUNCTIONS
+***************************************************************************/
+
+/*-------------------------------------------------
+ vp931_set_data_ready_callback - set the data
+ ready callback
+-------------------------------------------------*/
+
+void vp931_set_data_ready_callback(device_t *device, vp931_data_ready_func callback)
+{
+ laserdisc_state *ld = ldcore_get_safe_token(device);
+ ld->player->data_ready_cb = callback;
+}
+
+
+
+/***************************************************************************
+ PHILLIPS 22VP931 IMPLEMENTATION
+***************************************************************************/
+
+/*-------------------------------------------------
+ vp931_init - player-specific initialization
+-------------------------------------------------*/
+
+static void vp931_init(laserdisc_state *ld)
+{
+ astring tempstring;
+ ldplayer_data *player = ld->player;
+ vp931_data_ready_func cbsave;
+
+ /* reset our state */
+ cbsave = player->data_ready_cb;
+ memset(player, 0, sizeof(*player));
+ player->data_ready_cb = cbsave;
+
+ /* find our devices */
+ player->cpu = ld->device->subdevice("vp931");
+ player->tracktimer = downcast<timer_device *>(ld->device->subdevice("tracktimer"));
+ player->tracktimer->set_ptr(ld);
+}
+
+
+/*-------------------------------------------------
+ vp931_vsync - VSYNC callback, called at the
+ start of the blanking period
+-------------------------------------------------*/
+
+static void vp931_vsync(laserdisc_state *ld, const vbi_metadata *vbi, int fieldnum, attotime curtime)
+{
+ /* reset our command counter (debugging only) */
+ ld->player->cmdcount = 0;
+
+ /* set the ERP signal to 1 to indicate start of frame, and set a timer to turn it off */
+ ld->player->daticerp = 1;
+ ld->device->machine().scheduler().timer_set(ld->screen->time_until_pos(15*2), FUNC(erp_off), 0, ld);
+}
+
+
+/*-------------------------------------------------
+ vp931_update - update callback, called on
+ the first visible line of the frame
+-------------------------------------------------*/
+
+static INT32 vp931_update(laserdisc_state *ld, const vbi_metadata *vbi, int fieldnum, attotime curtime)
+{
+ /* set the first VBI timer to go at the start of line 16 */
+ ld->device->machine().scheduler().timer_set(ld->screen->time_until_pos(16*2), FUNC(vbi_data_fetch), LASERDISC_CODE_LINE16 << 2, ld);
+
+ /* play forward by default */
+ return fieldnum;
+}
+
+
+/*-------------------------------------------------
+ vp931_data_w - handle a parallel data write
+ to the 22VP931
+-------------------------------------------------*/
+
+static void vp931_data_w(laserdisc_state *ld, UINT8 prev, UINT8 data)
+{
+ /* set a timer to synchronize execution before sending the data */
+ ld->device->machine().scheduler().synchronize(FUNC(deferred_data_w), data, ld);
+}
+
+
+/*-------------------------------------------------
+ vp931_data_r - handle a parallel data read
+ from the 22VP931
+-------------------------------------------------*/
+
+static UINT8 vp931_data_r(laserdisc_state *ld)
+{
+ ldplayer_data *player = ld->player;
+
+ /* if data is pending, clear the pending flag and notify any callbacks */
+ if (player->tocontroller_pending)
+ {
+ player->tocontroller_pending = FALSE;
+ if (player->data_ready_cb != NULL)
+ (*player->data_ready_cb)(ld->device, FALSE);
+ }
+
+ /* also boost interleave for 4 scanlines to ensure proper communications */
+ ld->device->machine().scheduler().boost_interleave(attotime::zero, ld->screen->scan_period() * 4);
+ return player->tocontroller;
+}
+
+
+/*-------------------------------------------------
+ vp931_ready - return the status of "ready"
+ to the caller (ready to accept another
+ command)
+-------------------------------------------------*/
+
+static UINT8 vp931_ready(laserdisc_state *ld)
+{
+ /* if data is pending, we are not ready */
+ ldplayer_data *player = ld->player;
+ return player->fromcontroller_pending ? CLEAR_LINE : ASSERT_LINE;
+}
+
+
+/*-------------------------------------------------
+ vp931_data_ready - return the status of
+ "data available" to the caller
+-------------------------------------------------*/
+
+static UINT8 vp931_data_ready(laserdisc_state *ld)
+{
+ ldplayer_data *player = ld->player;
+ return player->tocontroller_pending ? ASSERT_LINE : CLEAR_LINE;
+}
+
+
+/*-------------------------------------------------
+ vbi_data_fetch - called 4 times per scanline
+ on lines 16, 17, and 18 to feed the VBI data
+ through one byte at a time
+-------------------------------------------------*/
+
+static TIMER_CALLBACK( vbi_data_fetch )
+{
+ laserdisc_state *ld = (laserdisc_state *)ptr;
+ ldplayer_data *player = ld->player;
+ int which = param & 3;
+ int line = param >> 2;
+ UINT32 code = 0;
+
+ /* fetch the code and compute the DATIC latched value */
+ if (line >= LASERDISC_CODE_LINE16 && line <= LASERDISC_CODE_LINE18)
+ code = laserdisc_get_field_code(ld->device, line, FALSE);
+
+ /* at the start of each line, signal an interrupt and use a timer to turn it off */
+ if (which == 0)
+ {
+ device_set_input_line(player->cpu, MCS48_INPUT_IRQ, ASSERT_LINE);
+ machine.scheduler().timer_set(attotime::from_nsec(5580), FUNC(irq_off), 0, ld);
+ }
+
+ /* clock the data strobe on each subsequent callback */
+ else if (code != 0)
+ {
+ player->daticval = code >> (8 * (3 - which));
+ player->datastrobe = 1;
+ machine.scheduler().timer_set(attotime::from_nsec(5000), FUNC(datastrobe_off), 0, ld);
+ }
+
+ /* determine the next bit to fetch and reprime ourself */
+ if (++which == 4)
+ {
+ which = 0;
+ line++;
+ }
+ if (line <= LASERDISC_CODE_LINE18 + 1)
+ machine.scheduler().timer_set(ld->screen->time_until_pos(line*2, which * 2 * ld->screen->width() / 4), FUNC(vbi_data_fetch), (line << 2), ld);
+}
+
+
+/*-------------------------------------------------
+ deferred_data_w - handle a write from the
+ external controller
+-------------------------------------------------*/
+
+static TIMER_CALLBACK( deferred_data_w )
+{
+ laserdisc_state *ld = (laserdisc_state *)ptr;
+ ldplayer_data *player = ld->player;
+
+ /* set the value and mark it pending */
+ if (LOG_COMMANDS && player->fromcontroller_pending)
+ printf("Dropped previous command byte\n");
+ player->fromcontroller = param;
+ player->fromcontroller_pending = TRUE;
+
+ /* track the commands for debugging purposes */
+ if (player->cmdcount < ARRAY_LENGTH(player->cmdbuf))
+ {
+ player->cmdbuf[player->cmdcount++ % 3] = param;
+ if (LOG_COMMANDS && player->cmdcount % 3 == 0)
+ printf("Cmd: %02X %02X %02X\n", player->cmdbuf[0], player->cmdbuf[1], player->cmdbuf[2]);
+ }
+}
+
+
+/*-------------------------------------------------
+ irq_off - turn off the 8048 IRQ signal
+-------------------------------------------------*/
+
+static TIMER_CALLBACK( irq_off )
+{
+ laserdisc_state *ld = (laserdisc_state *)ptr;
+ device_set_input_line(ld->player->cpu, MCS48_INPUT_IRQ, CLEAR_LINE);
+}
+
+
+/*-------------------------------------------------
+ datastrobe_off - turn off the DATIC data
+ strobe signal
+-------------------------------------------------*/
+
+static TIMER_CALLBACK( datastrobe_off )
+{
+ laserdisc_state *ld = (laserdisc_state *)ptr;
+ ld->player->datastrobe = 0;
+}
+
+
+/*-------------------------------------------------
+ erp_off - turn off the DATIC ERP signal
+-------------------------------------------------*/
+
+static TIMER_CALLBACK( erp_off )
+{
+ laserdisc_state *ld = (laserdisc_state *)ptr;
+ ld->player->daticerp = 0;
+}
+
+
+/*-------------------------------------------------
+ track_timer - advance by one half-track
+-------------------------------------------------*/
+
+static TIMER_DEVICE_CALLBACK( track_timer )
+{
+ laserdisc_state *ld = (laserdisc_state *)ptr;
+ ldplayer_data *player = ld->player;
+
+ /* advance by the count and toggle the state */
+ player->trackstate ^= 1;
+ if ((player->trackdir < 0 && !player->trackstate) || (player->trackdir > 0 && player->trackstate))
+ {
+ ldcore_advance_slider(ld, player->trackdir);
+ player->advanced += player->trackdir;
+ }
+}
+
+
+/*-------------------------------------------------
+ output0_w - controls audio/video squelch
+ and other bits
+-------------------------------------------------*/
+
+static WRITE8_HANDLER( output0_w )
+{
+ laserdisc_state *ld = ldcore_get_safe_token(space->device().owner());
+ ldplayer_data *player = ld->player;
+
+ /*
+ $80 = n/c
+ $40 = LED (?) -> C335
+ $20 = LED (?)
+ $10 = LED (?) -> CX
+ $08 = EJECT
+ $04 = inverted -> AUDIO MUTE II
+ $02 = inverted -> AUDIO MUTE I
+ $01 = inverted -> VIDEO MUTE
+ */
+
+ if (LOG_PORTS && (player->out0 ^ data) & 0xff)
+ {
+ printf("%03X:out0:", cpu_get_pc(&space->device()));
+ if ( (data & 0x80)) printf(" ???");
+ if ( (data & 0x40)) printf(" LED1");
+ if ( (data & 0x20)) printf(" LED2");
+ if ( (data & 0x10)) printf(" LED3");
+ if ( (data & 0x08)) printf(" EJECT");
+ if (!(data & 0x04)) printf(" AUDMUTE2");
+ if (!(data & 0x02)) printf(" AUDMUTE1");
+ if (!(data & 0x01)) printf(" VIDMUTE");
+ printf("\n");
+ player->out0 = data;
+ }
+
+ /* update a/v squelch */
+ ldcore_set_audio_squelch(ld, !(data & 0x02), !(data & 0x04));
+ ldcore_set_video_squelch(ld, !(data & 0x01));
+}
+
+
+/*-------------------------------------------------
+ output1_w - controls scanning behaviors
+-------------------------------------------------*/
+
+static WRITE8_HANDLER( output1_w )
+{
+ laserdisc_state *ld = ldcore_get_safe_token(space->device().owner());
+ ldplayer_data *player = ld->player;
+ INT32 speed = 0;
+
+ /*
+ $80 = n/c
+ $40 = n/c
+ $20 = n/c
+ $10 = n/c
+ $08 = inverted -> SMS
+ $04 = inverted -> SSS
+ $02 = inverted -> SCAN CMD
+ $01 = OSM
+ */
+
+ if (LOG_PORTS && (player->out1 ^ data) & 0x08)
+ {
+ mame_printf_debug("%03X:out1:", cpu_get_pc(&space->device()));
+ if (!(data & 0x08)) mame_printf_debug(" SMS");
+ mame_printf_debug("\n");
+ player->out1 = data;
+ }
+
+ /* speed is 0 unless SCAN CMD is clear */
+ speed = 0;
+ if (!(data & 0x02))
+ {
+ /* fast/slow is based on bit 2 */
+ speed = (data & 0x04) ? SCAN_FAST_SPEED : SCAN_SPEED;
+
+ /* direction is based on bit 0 */
+ if (data & 0x01)
+ speed = -speed;
+ }
+
+ /* update the speed */
+ ldcore_set_slider_speed(ld, speed);
+}
+
+
+/*-------------------------------------------------
+ lcd_w - vestigial LCD frame display
+-------------------------------------------------*/
+
+static WRITE8_HANDLER( lcd_w )
+{
+ /*
+ Frame number is written as 5 digits here; however, it is not actually
+ connected
+ */
+}
+
+
+/*-------------------------------------------------
+ unknown_r - unknown input port
+-------------------------------------------------*/
+
+static READ8_HANDLER( unknown_r )
+{
+ /* only bit $80 is checked and its effects are minor */
+ return 0x00;
+}
+
+
+/*-------------------------------------------------
+ keypad_r - vestigial keypad/button controls
+-------------------------------------------------*/
+
+static READ8_HANDLER( keypad_r )
+{
+ /*
+ From the code, this is apparently a vestigial keypad with basic controls:
+ $01 = play
+ $02 = still
+ $04 = jump 25 frames backward
+ $08 = jump 25 frames forward
+ $10 = search for frame 50(?)
+ $20 = search for frame 350(?)
+ $40 = reset
+ $80 = play reverse
+ */
+ return 0x00;
+}
+
+
+/*-------------------------------------------------
+ datic_r - read the latched value from the
+ DATIC circuit
+-------------------------------------------------*/
+
+static READ8_HANDLER( datic_r )
+{
+ laserdisc_state *ld = ldcore_get_safe_token(space->device().owner());
+ return ld->player->daticval;
+}
+
+
+/*-------------------------------------------------
+ from_controller_r - read the value the
+ external controller wrote
+-------------------------------------------------*/
+
+static READ8_HANDLER( from_controller_r )
+{
+ laserdisc_state *ld = ldcore_get_safe_token(space->device().owner());
+ ldplayer_data *player = ld->player;
+
+ /* clear the pending flag and return the data */
+ player->fromcontroller_pending = FALSE;
+ return player->fromcontroller;
+}
+
+
+/*-------------------------------------------------
+ to_controller_w - write a value back to the
+ external controller
+-------------------------------------------------*/
+
+static WRITE8_HANDLER( to_controller_w )
+{
+ laserdisc_state *ld = ldcore_get_safe_token(space->device().owner());
+ ldplayer_data *player = ld->player;
+
+ /* set the pending flag and stash the data */
+ player->tocontroller_pending = TRUE;
+ player->tocontroller = data;
+
+ /* signal to the callback if provided */
+ if (player->data_ready_cb != NULL)
+ (*player->data_ready_cb)(ld->device, TRUE);
+
+ /* also boost interleave for 4 scanlines to ensure proper communications */
+ ld->device->machine().scheduler().boost_interleave(attotime::zero, ld->screen->scan_period() * 4);
+}
+
+
+/*-------------------------------------------------
+ port1_r - read the 8048 I/O port 1
+-------------------------------------------------*/
+
+static READ8_HANDLER( port1_r )
+{
+ laserdisc_state *ld = ldcore_get_safe_token(space->device().owner());
+ ldplayer_data *player = ld->player;
+ UINT8 result = 0x00;
+
+ /*
+ $80 = P17 = (in) unsure
+ $40 = P16 = (in) /ERP from datic circuit
+ $20 = P15 = (in) D105
+ */
+
+ if (!player->daticerp)
+ result |= 0x40;
+
+ return result;
+}
+
+
+/*-------------------------------------------------
+ port1_w - write the 8048 I/O port 1
+-------------------------------------------------*/
+
+static WRITE8_HANDLER( port1_w )
+{
+ laserdisc_state *ld = ldcore_get_safe_token(space->device().owner());
+ ldplayer_data *player = ld->player;
+
+ /*
+ $10 = P14 = (out) D104 -> /SPEED
+ $08 = P13 = (out) D103 -> /TIMER ENABLE
+ $04 = P12 = (out) D102 -> /REV
+ $02 = P11 = (out) D101 -> /FORW
+ $01 = P10 = (out) D100 -> some op-amp then to C334, B56, B332
+ */
+
+ if (LOG_PORTS && (player->port1 ^ data) & 0x1f)
+ {
+ printf("%03X:port1:", cpu_get_pc(&space->device()));
+ if (!(data & 0x10)) printf(" SPEED");
+ if (!(data & 0x08)) printf(" TIMENABLE");
+ if (!(data & 0x04)) printf(" REV");
+ if (!(data & 0x02)) printf(" FORW");
+ if (!(data & 0x01)) printf(" OPAMP");
+ printf("\n");
+ }
+
+ /* if bit 0 is set, we are not tracking */
+ if (data & 0x01)
+ player->trackdir = 0;
+
+ /* if bit 0 is clear and we weren't tracking before, initialize the state */
+ else if (player->trackdir == 0)
+ {
+ player->advanced = 0;
+
+ /* if bit 2 is clear, we are moving backwards */
+ if (!(data & 0x04))
+ {
+ player->trackdir = -1;
+ player->trackstate = 1;
+ }
+
+ /* if bit 1 is clear, we are moving forward */
+ else if (!(data & 0x02))
+ {
+ player->trackdir = 1;
+ player->trackstate = 0;
+ }
+ }
+
+ /* if we have a timer, adjust it */
+ if (player->tracktimer != NULL)
+ {
+ /* turn it off if we're not tracking */
+ if (player->trackdir == 0)
+ player->tracktimer->reset();
+
+ /* if we just started tracking, or if the speed was changed, reprime the timer */
+ else if (((player->port1 ^ data) & 0x11) != 0)
+ {
+ /* speeds here are just guesses, but work with the player logic; this is the time per half-track */
+ attotime speed = (data & 0x10) ? attotime::from_usec(60) : attotime::from_usec(10);
+
+ /* always start with an initial long delay; the code expects this */
+ player->tracktimer->adjust(attotime::from_usec(100), 0, speed);
+ }
+ }
+
+ player->port1 = data;
+}
+
+
+/*-------------------------------------------------
+ port2_r - read from the 8048 I/O port 2
+-------------------------------------------------*/
+
+static READ8_HANDLER( port2_r )
+{
+ laserdisc_state *ld = ldcore_get_safe_token(space->device().owner());
+ ldplayer_data *player = ld->player;
+ UINT8 result = 0x00;
+
+ /*
+ $80 = P27 = (in) set/reset latch; set by FOC LS, reset by IGR
+ $20 = P25 = (in) D125 -> 0 when data written to controller is preset, reset to 1 when read
+ $10 = P24 = (in) D124 -> 0 when data from controller is present, reset to 1 on a read
+ */
+
+ if (!player->tocontroller_pending)
+ result |= 0x20;
+ if (!player->fromcontroller_pending)
+ result |= 0x10;
+
+ return result;
+}
+
+
+/*-------------------------------------------------
+ port2_w - write the 8048 I/O port 2
+-------------------------------------------------*/
+
+static WRITE8_HANDLER( port2_w )
+{
+ /*
+ $40 = P26 = (out) cleared while data is sent back & forth; set afterwards
+ [Not actually connected, but this is done in the code]
+ */
+}
+
+
+/*-------------------------------------------------
+ t0_r - return the T0 line status, which is
+ connected to the DATIC's data strobe line
+-------------------------------------------------*/
+
+static READ8_HANDLER( t0_r )
+{
+ laserdisc_state *ld = ldcore_get_safe_token(space->device().owner());
+ return ld->player->datastrobe;
+}
+
+
+/*-------------------------------------------------
+ t1_r - return the T1 line status, which is
+ connected to the tracking state and is used
+ to count the number of tracks advanced
+-------------------------------------------------*/
+
+static READ8_HANDLER( t1_r )
+{
+ laserdisc_state *ld = ldcore_get_safe_token(space->device().owner());
+ return ld->player->trackstate;
+}