summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
author Aaron Giles <aaron@aarongiles.com>2008-10-09 05:31:15 +0000
committer Aaron Giles <aaron@aarongiles.com>2008-10-09 05:31:15 +0000
commit2d6453c98af8d4cae65a906c74e4e083fb48643b (patch)
treec0fc7591a43dff5569a78e8c795e14cf6de23555
parent3df44083f8d0d74b9c7b7b269976997e0472da27 (diff)
Made the Z80 daisy chain aware of referencing device-specific devices.
Added preliminary LD-V1000 emulation. Not fully working yet, but mostly there. Cleaned up and normalized the three existing laserdisc emulations. Removed obsolete code from the laserdisc core.
-rw-r--r--src/emu/cpu/z180/z180.c3
-rw-r--r--src/emu/cpu/z80/z80.c3
-rw-r--r--src/emu/cpu/z80/z80daisy.c8
-rw-r--r--src/emu/cpu/z80/z80daisy.h2
-rw-r--r--src/emu/machine/laserdsc.h4
-rw-r--r--src/emu/machine/ldcore.c170
-rw-r--r--src/emu/machine/ldcore.h4
-rw-r--r--src/emu/machine/ldpr8210.c52
-rw-r--r--src/emu/machine/ldv1000.c1140
-rw-r--r--src/emu/machine/ldvp931.c298
-rw-r--r--src/emu/validity.c2
-rw-r--r--src/ldplayer/ldplayer.mak1
12 files changed, 752 insertions, 935 deletions
diff --git a/src/emu/cpu/z180/z180.c b/src/emu/cpu/z180/z180.c
index c676dc06c40..588db55cb1b 100644
--- a/src/emu/cpu/z180/z180.c
+++ b/src/emu/cpu/z180/z180.c
@@ -78,6 +78,7 @@ Hitachi HD647180 series:
#include "debugger.h"
#include "deprecat.h"
+#include "driver.h"
#include "z180.h"
#include "cpu/z80/z80daisy.h"
@@ -1900,7 +1901,7 @@ static void z180_init(int index, int clock, const void *config, int (*irqcallbac
{
Z180.daisy = NULL;
if (config)
- Z180.daisy = z80daisy_init(Machine, config);
+ Z180.daisy = z80daisy_init(Machine, Machine->config->cpu[cpu_getactivecpu()].tag, config);
Z180.irq_callback = irqcallback;
state_save_register_item("z180", index, Z180.AF.w.l);
diff --git a/src/emu/cpu/z80/z80.c b/src/emu/cpu/z80/z80.c
index 39a73c7bd76..ecc21b67fe0 100644
--- a/src/emu/cpu/z80/z80.c
+++ b/src/emu/cpu/z80/z80.c
@@ -95,6 +95,7 @@
#include "debugger.h"
#include "deprecat.h"
+#include "driver.h"
#include "z80.h"
#include "z80daisy.h"
@@ -3499,7 +3500,7 @@ static void z80_init(int index, int clock, const void *config, int (*irqcallback
/* Reset registers to their initial values */
memset(&Z80, 0, sizeof(Z80));
if (config != NULL)
- Z80.daisy = z80daisy_init(Machine, config);
+ Z80.daisy = z80daisy_init(Machine, Machine->config->cpu[cpu_getactivecpu()].tag, config);
Z80.irq_callback = irqcallback;
IX = IY = 0xffff; /* IX and IY are FFFF after a reset! */
F = ZF; /* Zero flag is set */
diff --git a/src/emu/cpu/z80/z80daisy.c b/src/emu/cpu/z80/z80daisy.c
index a675ecd75ed..16417686f23 100644
--- a/src/emu/cpu/z80/z80daisy.c
+++ b/src/emu/cpu/z80/z80daisy.c
@@ -20,8 +20,9 @@ struct _z80_daisy_state
};
-z80_daisy_state *z80daisy_init(running_machine *machine, const z80_daisy_chain *daisy)
+z80_daisy_state *z80daisy_init(running_machine *machine, const char *cputag, const z80_daisy_chain *daisy)
{
+ astring *tempstring = astring_alloc();
z80_daisy_state *head = NULL;
z80_daisy_state **tailptr = &head;
@@ -30,13 +31,16 @@ z80_daisy_state *z80daisy_init(running_machine *machine, const z80_daisy_chain *
{
*tailptr = auto_malloc(sizeof(**tailptr));
(*tailptr)->next = NULL;
- (*tailptr)->device = devtag_get_device(machine, daisy->devtype, daisy->devname);
+ (*tailptr)->device = devtag_get_device(machine, daisy->devtype, device_inherit_tag(tempstring, cputag, daisy->devname));
+ if ((*tailptr)->device == NULL)
+ fatalerror("Unable to locate device '%s'", daisy->devname);
(*tailptr)->irq_state = (z80_daisy_irq_state)device_get_info_fct((*tailptr)->device, DEVINFO_FCT_IRQ_STATE);
(*tailptr)->irq_ack = (z80_daisy_irq_ack)device_get_info_fct((*tailptr)->device, DEVINFO_FCT_IRQ_ACK);
(*tailptr)->irq_reti = (z80_daisy_irq_reti)device_get_info_fct((*tailptr)->device, DEVINFO_FCT_IRQ_RETI);
tailptr = &(*tailptr)->next;
}
+ astring_free(tempstring);
return head;
}
diff --git a/src/emu/cpu/z80/z80daisy.h b/src/emu/cpu/z80/z80daisy.h
index 98b365abaeb..bb0434cb916 100644
--- a/src/emu/cpu/z80/z80daisy.h
+++ b/src/emu/cpu/z80/z80daisy.h
@@ -60,7 +60,7 @@ struct _z80_daisy_chain
FUNCTION PROTOTYPES
***************************************************************************/
-z80_daisy_state *z80daisy_init(running_machine *machine, const z80_daisy_chain *daisy);
+z80_daisy_state *z80daisy_init(running_machine *machine, const char *cputag, const z80_daisy_chain *daisy);
void z80daisy_reset(z80_daisy_state *daisy);
int z80daisy_update_irq_state(z80_daisy_state *chain);
diff --git a/src/emu/machine/laserdsc.h b/src/emu/machine/laserdsc.h
index 3fcc290f6e7..75993f7d2ff 100644
--- a/src/emu/machine/laserdsc.h
+++ b/src/emu/machine/laserdsc.h
@@ -68,6 +68,8 @@ enum
typedef void (*laserdisc_audio_func)(const device_config *device, int samplerate, int samples, const INT16 *ch0, const INT16 *ch1);
+typedef void (*vp931_data_ready_func)(const device_config *device, int state);
+
typedef struct _laserdisc_config laserdisc_config;
struct _laserdisc_config
{
@@ -188,7 +190,7 @@ UINT8 laserdisc_line_r(const device_config *device, UINT8 line);
void pr7820_set_slow_speed(const device_config *device, double frame_rate_scaler);
/* set a callback for data ready on the Phillips 22VP931 */
-void vp931_set_data_ready_callback(const device_config *device, void (*callback)(const device_config *device, int state));
+void vp931_set_data_ready_callback(const device_config *device, vp931_data_ready_func callback);
/* control the audio squelch of the Simutrek modified players */
void simutrek_set_audio_squelch(const device_config *device, int state);
diff --git a/src/emu/machine/ldcore.c b/src/emu/machine/ldcore.c
index 0fc82529563..d8800c08308 100644
--- a/src/emu/machine/ldcore.c
+++ b/src/emu/machine/ldcore.c
@@ -31,10 +31,22 @@
CONSTANTS
***************************************************************************/
+/* these specs code from IEC 60857, for NTSC players */
+#define LEAD_IN_MIN_RADIUS_IN_UM 53500 /* 53.5 mm */
+#define PROGRAM_MIN_RADIUS_IN_UM 55000 /* 55 mm */
+#define PROGRAM_MAX_RADIUS_IN_UM 145000 /* 145 mm */
+#define LEAD_OUT_MIN_SIZE_IN_UM 2000 /* 2 mm */
+
+/* the track pitch is defined as a range; we pick a nominal pitch
+ that ensures we can fit 54,000 tracks */
+#define MIN_TRACK_PITCH_IN_NM 1400 /* 1.4 um */
+#define MAX_TRACK_PITCH_IN_NM 2000 /* 2 um */
+#define NOMINAL_TRACK_PITCH_IN_NM ((PROGRAM_MAX_RADIUS_IN_UM - PROGRAM_MIN_RADIUS_IN_UM) * 1000 / 54000)
+
/* we simulate extra lead-in and lead-out tracks */
-#define VIRTUAL_LEAD_IN_TRACKS 200
+#define VIRTUAL_LEAD_IN_TRACKS ((PROGRAM_MIN_RADIUS_IN_UM - LEAD_IN_MIN_RADIUS_IN_UM) * 1000 / NOMINAL_TRACK_PITCH_IN_NM)
#define MAX_TOTAL_TRACKS 54000
-#define VIRTUAL_LEAD_OUT_TRACKS 200
+#define VIRTUAL_LEAD_OUT_TRACKS (LEAD_OUT_MIN_SIZE_IN_UM * 1000 / NOMINAL_TRACK_PITCH_IN_NM)
@@ -133,7 +145,6 @@ struct _sound_token
static TIMER_CALLBACK( perform_player_update );
static void read_track_data(laserdisc_state *ld);
static void process_track_data(const device_config *device);
-//static void render_display(UINT16 *videodata, UINT32 rowpixels, UINT32 width, int frame);
static void *custom_start(int clock, const custom_sound_interface *config);
static void custom_stream_callback(void *param, stream_sample_t **inputs, stream_sample_t **outputs, int samples);
static void configuration_load(running_machine *machine, int config_type, xml_data_node *parentnode);
@@ -161,100 +172,6 @@ const custom_sound_interface laserdisc_custom_interface =
custom_start
};
-static const UINT8 numberfont[10][8] =
-{
- {
- 0x30, // ..xx....
- 0x48, // .x..x...
- 0x84, // x....x..
- 0x84, // x....x..
- 0x84, // x....x..
- 0x48, // .x..x...
- 0x30 // ..xx....
- },
- {
- 0x10, // ...x....
- 0x30, // ..xx....
- 0x50, // .x.x....
- 0x10, // ...x....
- 0x10, // ...x....
- 0x10, // ...x....
- 0x7c // .xxxxx..
- },
- {
- 0x78, // .xxxx...
- 0x84, // x....x..
- 0x04, // .....x..
- 0x38, // ..xxx...
- 0x40, // .x......
- 0x80, // x.......
- 0xfc // xxxxxx..
- },
- {
- 0x78, // .xxxx...
- 0x84, // x....x..
- 0x04, // .....x..
- 0x38, // ..xxx...
- 0x04, // .....x..
- 0x84, // x....x..
- 0x78 // .xxxx...
- },
- {
- 0x08, // ....x...
- 0x18, // ...xx...
- 0x28, // ..x.x...
- 0x48, // .x..x...
- 0xfc, // xxxxxx..
- 0x08, // ....x...
- 0x08 // ....x...
- },
- {
- 0xfc, // xxxxxx..
- 0x80, // x.......
- 0x80, // x.......
- 0xf8, // xxxxx...
- 0x04, // .....x..
- 0x84, // x....x..
- 0x78 // .xxxx...
- },
- {
- 0x38, // ..xxx...
- 0x40, // .x......
- 0x80, // x.......
- 0xf8, // xxxxx...
- 0x84, // x....x..
- 0x84, // x....x..
- 0x78 // .xxxx...
- },
- {
- 0xfc, // xxxxxx..
- 0x04, // .....x..
- 0x08, // ....x...
- 0x10, // ...x....
- 0x20, // ..x.....
- 0x20, // ..x.....
- 0x20 // ..x.....
- },
- {
- 0x78, // .xxxx...
- 0x84, // x....x..
- 0x84, // x....x..
- 0x78, // .xxxx...
- 0x84, // x....x..
- 0x84, // x....x..
- 0x78 // .xxxx...
- },
- {
- 0x78, // .xxxx..
- 0x84, // x....x.
- 0x84, // x....x.
- 0x7c, // .xxxxx.
- 0x04, // .....x.
- 0x08, // ....x..
- 0x70, // .xxx...
- }
-};
-
/***************************************************************************
@@ -1022,65 +939,6 @@ static void process_track_data(const device_config *device)
/*-------------------------------------------------
- render_display - draw the frame display
--------------------------------------------------*/
-
-#ifdef UNUSED_FUNCTION
-static void render_display(UINT16 *videodata, UINT32 rowpixels, UINT32 width, int frame)
-{
- const int xscale = 4, yscale = 2;
- char buffer[10];
- int x = width / 10;
- int y = 50;
- int ch;
- int delta;
-
- /* do nothing if no data */
- if (videodata == NULL)
- return;
-
- /* convert to a character string and render */
- sprintf(buffer, "%5d", frame);
-
- /* iterate over 5 positions: (-1,-1), (-1,1), (1,-1), (1,1) and (0,0) */
- /* render all in black except the last one */
- for (delta = 0; delta < 5; delta++)
- {
- int color = (delta < 4) ? 0x0080 : 0xff80;
- int dx = (delta < 4) ? ((delta & 1) ? -1 : 1) : 0;
- int dy = (delta < 4) ? ((delta & 2) ? -1 : 1) : 0;
-
- /* iterate over 5 characters */
- for (ch = 0; ch < 5; ch++)
- if (buffer[ch] >= '0' && buffer[ch] <= '9')
- {
- const UINT8 *fontdata = &numberfont[buffer[ch] - '0'][0];
- int cy, cx;
-
- /* iterate over the rows of the character */
- for (cy = 0; cy < 8; cy++)
- {
- UINT8 bits = *fontdata++;
-
- /* and over the columns */
- for (cx = 0; cx < 8; cx++)
- if (bits & (0x80 >> cx))
- {
- int ix, iy;
-
- /* fill in an xscale x yscale pixel */
- for (iy = 0; iy < yscale; iy++)
- for (ix = 0; ix < xscale; ix++)
- videodata[(y + cy * yscale + iy + dy) * rowpixels + (x + (ch * 9 + cx) * xscale + ix + dx)] = color;
- }
- }
- }
- }
-}
-#endif
-
-
-/*-------------------------------------------------
custom_start - custom audio start
for laserdiscs
-------------------------------------------------*/
diff --git a/src/emu/machine/ldcore.h b/src/emu/machine/ldcore.h
index c4136843538..8856e828141 100644
--- a/src/emu/machine/ldcore.h
+++ b/src/emu/machine/ldcore.h
@@ -225,7 +225,7 @@ INLINE int is_start_of_frame(const vbi_metadata *vbi)
/* is it not known if the white flag or the presence of a frame code
determines the start of frame; the former seems to be the "official"
way, but the latter seems to be the practical implementation */
- return (vbi->white || (vbi->line1718 & 0xf80000) == 0xf80000);
+ return (vbi->white || (vbi->line1718 & VBI_MASK_CAV_PICTURE) == VBI_CODE_CAV_PICTURE);
}
@@ -255,7 +255,7 @@ INLINE int frame_from_metadata(const vbi_metadata *metadata)
INLINE int chapter_from_metadata(const vbi_metadata *metadata)
{
- if ((metadata->line1718 & 0xf00fff) == 0x800ddd)
+ if ((metadata->line1718 & VBI_MASK_CHAPTER) == VBI_CODE_CHAPTER)
return VBI_CHAPTER(metadata->line1718);
else if (metadata->line1718 == VBI_CODE_LEADIN)
return CHAPTER_LEAD_IN;
diff --git a/src/emu/machine/ldpr8210.c b/src/emu/machine/ldpr8210.c
index 8f2d61ad0aa..4fcae2a04b9 100644
--- a/src/emu/machine/ldpr8210.c
+++ b/src/emu/machine/ldpr8210.c
@@ -11,7 +11,6 @@
Still to do:
- * add overlay properly (need capture)
* implement SLOW TRG
* figure out Simutrek without jump hack
* figure out serial protocol issues (current hack works nicely)
@@ -49,17 +48,17 @@
#define OVERLAY_X_PIXELS 5
#define OVERLAY_Y_PIXELS 7
-/* Pioneer PR-8210 specific information */
-#define PR8210_SCAN_SPEED (2000 / 30) /* 2000 frames/second */
-#define PR8210_SEEK_FAST_SPEED (4000 / 30) /* 4000 frames/second */
+/* scanning speeds */
+#define SCAN_SPEED (2000 / 30) /* 2000 frames/second */
+#define SEEK_FAST_SPEED (4000 / 30) /* 4000 frames/second */
/* serial timing, mostly from the service manual, derived from the XTAL */
-#define PR8210_SERIAL_CLOCK XTAL_455kHz
-#define PR8210_0_BIT_TIME ATTOTIME_IN_HZ(PR8210_SERIAL_CLOCK / 512)
-#define PR8210_1_BIT_TIME ATTOTIME_IN_HZ(PR8210_SERIAL_CLOCK / 1024)
-#define PR8210_MIDPOINT_TIME ATTOTIME_IN_HZ(PR8210_SERIAL_CLOCK / 600)
-#define PR8210_MAX_WORD_TIME ATTOTIME_IN_HZ(PR8210_SERIAL_CLOCK / 11520)
-#define PR8210_REJECT_DUPLICATE_TIME ATTOTIME_IN_HZ(PR8210_SERIAL_CLOCK / 11520 / 4)
+#define SERIAL_CLOCK XTAL_455kHz
+#define SERIAL_0_BIT_TIME ATTOTIME_IN_HZ(SERIAL_CLOCK / 512)
+#define SERIAL_1_BIT_TIME ATTOTIME_IN_HZ(SERIAL_CLOCK / 1024)
+#define SERIAL_MIDPOINT_TIME ATTOTIME_IN_HZ(SERIAL_CLOCK / 600)
+#define SERIAL_MAX_WORD_TIME ATTOTIME_IN_HZ(SERIAL_CLOCK / 11520)
+#define SERIAL_REJECT_DUPLICATE_TIME ATTOTIME_IN_HZ(SERIAL_CLOCK / 11520 / 4)
@@ -129,8 +128,10 @@ static void pr8210_vsync(laserdisc_state *ld, const vbi_metadata *vbi, int field
static INT32 pr8210_update(laserdisc_state *ld, const vbi_metadata *vbi, int fieldnum, attotime curtime);
static void pr8210_overlay(laserdisc_state *ld, bitmap_t *bitmap);
static void pr8210_control_w(laserdisc_state *ld, UINT8 prev, UINT8 data);
+
static TIMER_CALLBACK( vsync_off );
static TIMER_CALLBACK( vbi_data_fetch );
+
static READ8_HANDLER( pr8210_pia_r );
static WRITE8_HANDLER( pr8210_pia_w );
static READ8_HANDLER( pr8210_bus_r );
@@ -138,6 +139,7 @@ static WRITE8_HANDLER( pr8210_port1_w );
static WRITE8_HANDLER( pr8210_port2_w );
static READ8_HANDLER( pr8210_t0_r );
static READ8_HANDLER( pr8210_t1_r );
+
static void overlay_draw_group(bitmap_t *bitmap, const UINT8 *text, int count, float xstart);
static void overlay_erase(bitmap_t *bitmap, float xstart, float xend);
static void overlay_draw_char(bitmap_t *bitmap, UINT8 ch, float xstart);
@@ -148,7 +150,9 @@ static INT32 simutrek_update(laserdisc_state *ld, const vbi_metadata *vbi, int f
static UINT8 simutrek_ready_r(laserdisc_state *ld);
static UINT8 simutrek_status_r(laserdisc_state *ld);
static void simutrek_data_w(laserdisc_state *ld, UINT8 prev, UINT8 data);
+
static TIMER_CALLBACK( simutrek_latched_data_w );
+
static READ8_HANDLER( simutrek_port2_r );
static WRITE8_HANDLER( simutrek_port2_w );
static READ8_HANDLER( simutrek_data_r );
@@ -169,7 +173,7 @@ static const UINT8 text_bitmap[0x40][7] =
{ 0x70,0x88,0x80,0x80,0x80,0x88,0x70 }, /* C */
{ 0 }, /* D */
{ 0xf8,0x80,0x80,0xf0,0x80,0x80,0xf8 }, /* E */
- { 0xf8,0x80,0x80,0xf0,0x80,0x80,0x80 }, /* E */
+ { 0xf8,0x80,0x80,0xf0,0x80,0x80,0x80 }, /* F */
{ 0 }, /* G */
{ 0x88,0x88,0x88,0xf8,0x88,0x88,0x88 }, /* H */
{ 0 }, /* I */
@@ -338,8 +342,7 @@ const ldplayer_interface pr8210_interface =
***************************************************************************/
/*-------------------------------------------------
- pr8210_init - Pioneer PR-8210-specific
- initialization
+ pr8210_init - player-specific initialization
-------------------------------------------------*/
static void pr8210_init(laserdisc_state *ld)
@@ -348,18 +351,17 @@ static void pr8210_init(laserdisc_state *ld)
attotime curtime = timer_get_time();
ldplayer_data *player = ld->player;
- /* find our CPU */
- player->cpunum = mame_find_cpu_index(ld->device->machine, device_build_tag(tempstring, ld->device->tag, "pr8210"));
- astring_free(tempstring);
-
- /* do a soft reset */
- player->lastcommand = 0;
- player->accumulator = 0;
+ /* reset our state */
+ memset(player, 0, sizeof(*player));
player->lastcommandtime = curtime;
player->firstbittime = curtime;
player->lastbittime = curtime;
player->slowtrg = curtime;
+ /* find our CPU */
+ player->cpunum = mame_find_cpu_index(ld->device->machine, device_build_tag(tempstring, ld->device->tag, "pr8210"));
+ astring_free(tempstring);
+
/* we don't have the Simutrek player overrides */
player->simutrek.cpunum = -1;
player->simutrek.audio_squelch = FALSE;
@@ -463,7 +465,7 @@ static void pr8210_control_w(laserdisc_state *ld, UINT8 prev, UINT8 data)
/* if we timed out since the first bit, reset the accumulator */
delta = attotime_sub(curtime, player->firstbittime);
- if (attotime_compare(delta, PR8210_MAX_WORD_TIME) > 0)
+ if (attotime_compare(delta, SERIAL_MAX_WORD_TIME) > 0)
{
player->firstbittime = curtime;
player->accumulator = 0x5555;
@@ -477,7 +479,7 @@ static void pr8210_control_w(laserdisc_state *ld, UINT8 prev, UINT8 data)
player->lastbittime = curtime;
/* 0 bit delta is 1.05 msec, 1 bit delta is 2.11 msec */
- longpulse = (attotime_compare(delta, PR8210_MIDPOINT_TIME) < 0) ? 0 : 1;
+ longpulse = (attotime_compare(delta, SERIAL_MIDPOINT_TIME) < 0) ? 0 : 1;
player->accumulator = (player->accumulator << 1) | longpulse;
/* log the deltas for debugging */
@@ -500,7 +502,7 @@ static void pr8210_control_w(laserdisc_state *ld, UINT8 prev, UINT8 data)
/* the MCU logic requires a 0 to execute many commands; however, nobody
consistently sends a 0, whereas they do tend to send duplicate commands...
if we assume that each duplicate causes a 0, we get the correct results */
- rejectuntil = attotime_add(player->lastcommandtime, PR8210_REJECT_DUPLICATE_TIME);
+ rejectuntil = attotime_add(player->lastcommandtime, SERIAL_REJECT_DUPLICATE_TIME);
player->lastcommandtime = curtime;
if (player->pia.porta == player->lastcommand && attotime_compare(curtime, rejectuntil) < 0)
player->pia.porta = 0x00;
@@ -516,7 +518,7 @@ static void pr8210_control_w(laserdisc_state *ld, UINT8 prev, UINT8 data)
}
/* reset the first bit time so that the accumulator clears on the next write */
- player->firstbittime = attotime_sub(curtime, PR8210_MAX_WORD_TIME);
+ player->firstbittime = attotime_sub(curtime, SERIAL_MAX_WORD_TIME);
}
}
}
@@ -810,7 +812,7 @@ static WRITE8_HANDLER( pr8210_port1_w )
if (!(data & 0x02))
{
/* bit 2 selects the speed */
- int delta = (data & 0x04) ? PR8210_SCAN_SPEED : PR8210_SEEK_FAST_SPEED;
+ int delta = (data & 0x04) ? SCAN_SPEED : SEEK_FAST_SPEED;
ldcore_set_slider_speed(ld, delta * direction);
}
diff --git a/src/emu/machine/ldv1000.c b/src/emu/machine/ldv1000.c
index 5a620dce8de..a30af75c888 100644
--- a/src/emu/machine/ldv1000.c
+++ b/src/emu/machine/ldv1000.c
@@ -7,9 +7,19 @@
Copyright Nicola Salmoria and the MAME Team.
Visit http://mamedev.org for licensing and usage restrictions.
+**************************************************************************
+
+ Still to do:
+
+ * fix issues
+ * add OSD
+
*************************************************************************/
#include "ldcore.h"
+#include "machine/8255ppi.h"
+#include "machine/z80ctc.h"
+#include "cpu/z80/z80daisy.h"
@@ -17,10 +27,10 @@
DEBUGGING
***************************************************************************/
-#define PRINTF_COMMANDS 1
-#define CMDPRINTF(x) do { if (PRINTF_COMMANDS) mame_printf_debug x; } while (0)
-
-#define EMULATE_ROM 0
+#define LOG_PORT_IO 0
+#define LOG_STATUS_CHANGES 0
+#define LOG_FRAMES_SEEN 0
+#define LOG_COMMANDS 0
@@ -28,25 +38,10 @@
CONSTANTS
***************************************************************************/
-/* Player-specific states */
-enum
-{
- LDSTATE_SKIPPING = LDSTATE_OTHER,
- LDSTATE_WAITING
-};
+#define SCAN_SPEED (2000 / 30) /* 2000 frames/second */
+#define SEEK_FAST_SPEED (4000 / 30) /* 4000 frames/second */
-/* Pioneer LD-V1000 specific information */
-enum
-{
- LDV1000_MODE_STATUS,
- LDV1000_MODE_GET_FRAME,
- LDV1000_MODE_GET_1ST,
- LDV1000_MODE_GET_2ND,
- LDV1000_MODE_GET_RAM
-};
-
-#define LDV1000_SCAN_SPEED (2000 / 30) /* 2000 frames/second */
-#define LDV1000_SCAN_DURATION (4) /* scan for 4 vsyncs each time */
+#define MULTIJUMP_TRACK_TIME ATTOTIME_IN_USEC(50)
@@ -57,21 +52,30 @@ enum
/* player-specific data */
struct _ldplayer_data
{
- /* general modes and states */
- UINT8 audio1disable; /* explicit disable for audio 1 */
- UINT8 audio2disable; /* explicit disable for audio 2 */
- UINT8 framedisplay; /* frame display */
- INT32 parameter; /* parameter for numbers */
-
- UINT8 mode; /* current mode */
- UINT8 lastchapter; /* last chapter seen */
- UINT16 lastframe; /* last frame seen */
- UINT32 activereg; /* active register index */
- UINT8 ram[1024]; /* RAM */
- UINT32 readpos; /* current read position */
- UINT32 readtotal; /* current read position */
- UINT8 readbuf[256]; /* temporary read buffer */
- attotime lastvsynctime; /* time of last update/vsync */
+ /* low-level emulation data */
+ int cpunum; /* CPU index of the Z80 */
+ const device_config *ctc; /* CTC device */
+ const device_config *multitimer; /* multi-jump timer device */
+
+ /* communication status */
+ UINT8 command; /* command byte to the player */
+ UINT8 status; /* status byte from the player */
+ UINT8 vsync; /* VSYNC state */
+
+ /* I/O port states */
+ UINT8 counter_start; /* starting value for counter */
+ UINT8 counter; /* current counter value */
+ UINT8 portc0; /* port C on PPI 0 */
+ UINT8 portb1; /* port B on PPI 1 */
+ UINT8 portc1; /* port C on PPI 1 */
+
+ /* display/decode circuit emulation */
+ UINT8 portselect; /* selection of which port to access */
+ UINT8 display[2][20]; /* display lines */
+ UINT8 dispindex; /* index within the display line */
+ UINT8 vbi[7*3]; /* VBI data */
+ UINT8 vbiready; /* VBI ready flag */
+ UINT8 vbiindex; /* index within the VBI data */
};
@@ -81,90 +85,110 @@ struct _ldplayer_data
***************************************************************************/
static void ldv1000_init(laserdisc_state *ld);
-static void ldv1000_soft_reset(laserdisc_state *ld);
-static void ldv1000_update_squelch(laserdisc_state *ld);
-static int ldv1000_switch_state(laserdisc_state *ld, UINT8 newstate, INT32 stateparam);
+static void ldv1000_vsync(laserdisc_state *ld, const vbi_metadata *vbi, int fieldnum, attotime curtime);
static INT32 ldv1000_update(laserdisc_state *ld, const vbi_metadata *vbi, int fieldnum, attotime curtime);
static void ldv1000_data_w(laserdisc_state *ld, UINT8 prev, UINT8 data);
static UINT8 ldv1000_status_strobe_r(laserdisc_state *ld);
static UINT8 ldv1000_command_strobe_r(laserdisc_state *ld);
static UINT8 ldv1000_status_r(laserdisc_state *ld);
+static TIMER_CALLBACK( vsync_off );
+static TIMER_CALLBACK( vbi_data_fetch );
+static TIMER_DEVICE_CALLBACK( multijump_timer );
+
+static void ctc_interrupt(const device_config *device, int state);
+
+static WRITE8_HANDLER( decoder_display_port_w );
+static READ8_HANDLER( decoder_display_port_r );
+static READ8_HANDLER( controller_r );
+static WRITE8_HANDLER( controller_w );
+static WRITE8_DEVICE_HANDLER( ppi0_porta_w );
+static READ8_DEVICE_HANDLER( ppi0_portb_r );
+static READ8_DEVICE_HANDLER( ppi0_portc_r );
+static WRITE8_DEVICE_HANDLER( ppi0_portc_w );
+static READ8_DEVICE_HANDLER( ppi1_porta_r );
+static WRITE8_DEVICE_HANDLER( ppi1_portb_w );
+static WRITE8_DEVICE_HANDLER( ppi1_portc_w );
+
/***************************************************************************
- 22VP931 ROM AND MACHINE INTERFACES
+ INLINE FUNCTIONS
***************************************************************************/
-#if EMULATE_ROM
-static WRITE8_HANDLER( ld_controls )
+/*-------------------------------------------------
+ find_ldv1000 - find our device; assumes there
+ is only one
+-------------------------------------------------*/
+
+INLINE laserdisc_state *find_ldv1000(running_machine *machine)
{
- switch (offset)
- {
- case 0:
- // write $00 at startup/reject
- break;
+ return ldcore_get_safe_token(device_list_first(machine->config->devicelist, LASERDISC));
+}
+
- case 2:
- // write $06 at startup/reject
- break;
- case 3:
- // write $8A at startup
- break;
+/***************************************************************************
+ LD-V1000 ROM AND MACHINE INTERFACES
+***************************************************************************/
- case 5:
- // write $9F at startup/reject
- break;
+static ADDRESS_MAP_START( ldv1000_map, ADDRESS_SPACE_PROGRAM, 8 )
+ AM_RANGE(0x0000, 0x1fff) AM_MIRROR(0x6000) AM_ROM
+ AM_RANGE(0x8000, 0x87ff) AM_MIRROR(0x3800) AM_RAM
+ AM_RANGE(0xc000, 0xc003) AM_MIRROR(0x9ff0) AM_DEVREADWRITE(PPI8255, "ldvppi0", ppi8255_r, ppi8255_w)
+ AM_RANGE(0xc004, 0xc007) AM_MIRROR(0x9ff0) AM_DEVREADWRITE(PPI8255, "ldvppi1", ppi8255_r, ppi8255_w)
+ADDRESS_MAP_END
- case 6:
- // write $C3 at startup/reject
- break;
- case 7:
- // write $90 at startup
- break;
- }
-}
+static ADDRESS_MAP_START( ldv1000_portmap, ADDRESS_SPACE_IO, 8 )
+ ADDRESS_MAP_GLOBAL_MASK(0xff)
+ AM_RANGE(0x00, 0x07) AM_MIRROR(0x38) AM_READWRITE(decoder_display_port_r, decoder_display_port_w)
+ AM_RANGE(0x40, 0x40) AM_MIRROR(0x3f) AM_READ(controller_r)
+ AM_RANGE(0x80, 0x80) AM_MIRROR(0x3f) AM_WRITE(controller_w)
+ AM_RANGE(0xc0, 0xc3) AM_MIRROR(0x3c) AM_DEVREADWRITE(Z80CTC, "ldvctc", z80ctc_r, z80ctc_w)
+ADDRESS_MAP_END
-static READ8_HANDLER( ld_controls )
+static const ppi8255_interface ppi0intf =
{
- switch (offset)
- {
- case 4:
-
- }
-}
+ NULL, ppi0_portb_r, ppi0_portc_r,
+ ppi0_porta_w, NULL, ppi0_portc_w
+};
-static WRITE8_HANDLER( unknown_port_w )
+static const ppi8255_interface ppi1intf =
{
- // Writes to $00/$02/$00
- // Values:
- // $04/$09/$0F
- // $04/$0E/$0F
- // $04/ /$0F
-}
+ ppi1_porta_r, NULL, NULL,
+ NULL, ppi1_portb_w, ppi1_portc_w
+};
-static ADDRESS_MAP_START( ldv1000_map, ADDRESS_SPACE_PROGRAM, 8 )
- AM_RANGE(0x0000, 0x1fff) AM_ROM
- AM_RANGE(0x8000, 0x83ff) AM_MIRROR(0x400) AM_RAM
- AM_RANGE(0xc000, 0xc007) AM_READWRITE(ld_controls)
-ADDRESS_MAP_END
+static const z80ctc_interface ctcintf =
+{
+ "ldv1000",
+ 0,
+ 0,
+ ctc_interrupt
+};
-static ADDRESS_MAP_START( ldv1000_portmap, ADDRESS_SPACE_PROGRAM, 8 )
- ADDRESS_MAP_GLOBAL_MASK(0xff)
- AM_RANGE(0x00, 0x03) AM_WRITE(unknown_port_w)
- AM_RANGE(0xc0, 0xc3) AM_DEVREADWRITE(Z80CTC, "ctc", z80ctc_r, z80ctc_w)
-ADDRESS_MAP_END
+static const z80_daisy_chain daisy_chain[] =
+{
+ { Z80CTC, "ldvctc" },
+ { NULL }
+};
static MACHINE_DRIVER_START( ldv1000 )
- MDRV_CPU_ADD("ldv1000", Z80, 4000000)
+ MDRV_CPU_ADD("ldv1000", Z80, XTAL_5MHz/2)
+ MDRV_CPU_CONFIG(daisy_chain)
MDRV_CPU_PROGRAM_MAP(ldv1000_map,0)
+ MDRV_CPU_IO_MAP(ldv1000_portmap,0)
+
+ MDRV_Z80CTC_ADD("ldvctc", ctcintf)
+ MDRV_PPI8255_ADD("ldvppi0", ppi0intf)
+ MDRV_PPI8255_ADD("ldvppi1", ppi1intf)
+ MDRV_TIMER_ADD("multitimer", multijump_timer)
MACHINE_DRIVER_END
@@ -172,7 +196,6 @@ ROM_START( ldv1000 )
ROM_REGION( 0x2000, "ldv1000", ROMREGION_LOADBYNAME )
ROM_LOAD( "z03_1001_vyw-053_v1-0.bin", 0x0000, 0x2000, CRC(31ec4687) SHA1(52f91c304a878ba02b2fa1cda1a9489d6dd5a34f) )
ROM_END
-#endif
@@ -185,15 +208,10 @@ const ldplayer_interface ldv1000_interface =
LASERDISC_TYPE_PIONEER_LDV1000, /* type of the player */
sizeof(ldplayer_data), /* size of the state */
"Pioneer LD-V1000", /* name of the player */
-#if EMULATE_ROM
rom_ldv1000, /* pointer to ROM region information */
machine_config_ldv1000, /* pointer to machine configuration */
-#else
- NULL,
- NULL,
-#endif
ldv1000_init, /* initialization callback */
- NULL, /* vsync callback */
+ ldv1000_vsync, /* vsync callback */
ldv1000_update, /* update callback */
NULL, /* overlay callback */
ldv1000_data_w, /* parallel data write */
@@ -213,625 +231,543 @@ const ldplayer_interface ldv1000_interface =
/***************************************************************************
- INLINE FUNCTIONS
+ PIONEER LD-V1000 IMPLEMENTATION
***************************************************************************/
/*-------------------------------------------------
- requires_state_save - returns TRUE if the
- given state will return to the previous
- state when done
+ ldv1000_init - player-specific initialization
-------------------------------------------------*/
-INLINE int requires_state_save(UINT8 state)
+static void ldv1000_init(laserdisc_state *ld)
{
- return (state == LDSTATE_SCANNING ||
- state == LDSTATE_SKIPPING ||
- state == LDSTATE_WAITING);
+ astring *tempstring = astring_alloc();
+ ldplayer_data *player = ld->player;
+
+ /* reset our state */
+ memset(player, 0, sizeof(*player));
+
+ /* find our devices */
+ player->cpunum = mame_find_cpu_index(ld->device->machine, device_build_tag(tempstring, ld->device->tag, "ldv1000"));
+ player->ctc = devtag_get_device(ld->device->machine, Z80CTC, device_build_tag(tempstring, ld->device->tag, "ldvctc"));
+ player->multitimer = devtag_get_device(ld->device->machine, TIMER, device_build_tag(tempstring, ld->device->tag, "multitimer"));
+ timer_device_set_ptr(player->multitimer, ld);
+ astring_free(tempstring);
}
/*-------------------------------------------------
- read_16bits_from_ram_be - read 16 bits from
- player RAM in big-endian format
+ ldv1000_vsync - VSYNC callback, called at the
+ start of the blanking period
-------------------------------------------------*/
-INLINE UINT16 read_16bits_from_ram_be(UINT8 *ram, UINT32 offset)
+static void ldv1000_vsync(laserdisc_state *ld, const vbi_metadata *vbi, int fieldnum, attotime curtime)
{
- return (ram[offset + 0] << 8) | ram[offset + 1];
+ slider_position sliderpos = ldcore_get_slider_position(ld);
+ ldplayer_data *player = ld->player;
+
+ /* generate interrupts if we hit the edges */
+ z80ctc_trg1_w(player->ctc, 0, sliderpos == SLIDER_MINIMUM);
+ z80ctc_trg2_w(player->ctc, 0, sliderpos == SLIDER_MAXIMUM);
+
+ /* signal VSYNC and set a timer to turn it off */
+ player->vsync = TRUE;
+ timer_set(attotime_mul(video_screen_get_scan_period(ld->screen), 4), ld, 0, vsync_off);
+
+ /* also set a timer to fetch the VBI data when it is ready */
+ timer_set(video_screen_get_time_until_pos(ld->screen, 19*2, 0), ld, 0, vbi_data_fetch);
+
+ /* boost interleave for the first 1ms to improve communications */
+ cpu_boost_interleave(attotime_zero, ATTOTIME_IN_MSEC(1));
}
/*-------------------------------------------------
- write_16bits_to_ram_be - write 16 bits to
- player RAM in big endian format
+ ldv1000_update - update callback, called on
+ the first visible line of the frame
-------------------------------------------------*/
-INLINE void write_16bits_to_ram_be(UINT8 *ram, UINT32 offset, UINT16 data)
+static INT32 ldv1000_update(laserdisc_state *ld, const vbi_metadata *vbi, int fieldnum, attotime curtime)
{
- ram[offset + 0] = data >> 8;
- ram[offset + 1] = data >> 0;
+ if (LOG_FRAMES_SEEN)
+ {
+ int frame = frame_from_metadata(vbi);
+ if (frame != FRAME_NOT_PRESENT) printf("== %d\n", frame);
+ }
+ return fieldnum;
}
+/*-------------------------------------------------
+ ldv1000_data_w - handle a parallel data write
+ to the LD-V1000
+-------------------------------------------------*/
+
+static void ldv1000_data_w(laserdisc_state *ld, UINT8 prev, UINT8 data)
+{
+ ld->player->command = data;
+ if (LOG_COMMANDS)
+ printf("-> COMMAND = %02X (%s)\n", data, (ld->player->portc1 & 0x10) ? "valid" : "invalid");
+}
-/***************************************************************************
- PIONEER LD-V1000 IMPLEMENTATION
-***************************************************************************/
/*-------------------------------------------------
- ldv1000_init - Pioneer PR-8210-specific
- initialization
+ ldv1000_status_strobe_r - return state of the
+ status strobe
-------------------------------------------------*/
-static void ldv1000_init(laserdisc_state *ld)
+static UINT8 ldv1000_status_strobe_r(laserdisc_state *ld)
{
- /* do a soft reset */
- ldv1000_soft_reset(ld);
+ return (ld->player->portc1 & 0x20) ? ASSERT_LINE : CLEAR_LINE;
}
/*-------------------------------------------------
- ldv1000_soft_reset - Pioneer LDV-1000-specific
- soft reset
+ ldv1000_command_strobe_r - return state of the
+ command strobe
-------------------------------------------------*/
-static void ldv1000_soft_reset(laserdisc_state *ld)
+static UINT8 ldv1000_command_strobe_r(laserdisc_state *ld)
{
- ldplayer_data *player = ld->player;
- attotime curtime = timer_get_time();
-
- ld->state.state = LDSTATE_NONE;
- ld->state.substate = 0;
- ld->state.param = 0;
- ld->state.endtime = curtime;
-
- player->audio1disable = 0;
- player->audio2disable = 0;
- player->parameter = 0;
-
- player->mode = 0;
- player->activereg = 0;
- memset(player->ram, 0, sizeof(player->ram));
- player->readpos = 0;
- player->readtotal = 0;
- memset(player->readbuf, 0, sizeof(player->readbuf));
- player->lastvsynctime = curtime;
-
- ldv1000_switch_state(ld, LDSTATE_PARKED, 0);
+ return (ld->player->portc1 & 0x10) ? ASSERT_LINE : CLEAR_LINE;
}
/*-------------------------------------------------
- ldv1000_update_squelch - update the squelch
- settings based on the current state
+ ldv1000_status_r - handle a parallel data read
+ from the LD-V1000
-------------------------------------------------*/
-static void ldv1000_update_squelch(laserdisc_state *ld)
+static UINT8 ldv1000_status_r(laserdisc_state *ld)
{
- ldplayer_data *player = ld->player;
+ return ld->player->status;
+}
+
+
+/*-------------------------------------------------
+ vsync_off - timer callback to clear the VSYNC
+ flag
+-------------------------------------------------*/
+
+static TIMER_CALLBACK( vsync_off )
+{
+ laserdisc_state *ld = ptr;
+ ld->player->vsync = FALSE;
+}
+
- switch (ld->state.state)
+/*-------------------------------------------------
+ vbi_data_fetch - timer callback to update the
+ VBI data in the PIA as soon as it is ready;
+ this must happy early in the frame because
+ the player logic relies on fetching it here
+-------------------------------------------------*/
+
+static TIMER_CALLBACK( vbi_data_fetch )
+{
+ laserdisc_state *ld = ptr;
+ ldplayer_data *player = ld->player;
+ UINT8 focus_on = !(player->portb1 & 0x01);
+ UINT8 laser_on = (player->portb1 & 0x40);
+ UINT32 lines[3];
+
+ /* appears to return data in reverse order */
+ lines[0] = laserdisc_get_field_code(ld->device, LASERDISC_CODE_LINE1718);
+ lines[1] = laserdisc_get_field_code(ld->device, LASERDISC_CODE_LINE17);
+ lines[2] = laserdisc_get_field_code(ld->device, LASERDISC_CODE_LINE16);
+
+ /* fill in the details */
+ memset(player->vbi, 0, sizeof(player->vbi));
+ if (focus_on && laser_on)
{
- /* video on, audio on */
- case LDSTATE_PLAYING:
- ldcore_set_audio_squelch(ld, player->audio1disable, player->audio2disable);
- ldcore_set_video_squelch(ld, FALSE);
- break;
-
- /* video on, audio off */
- case LDSTATE_PAUSING:
- case LDSTATE_PAUSED:
- case LDSTATE_PLAYING_SLOW_REVERSE:
- case LDSTATE_PLAYING_SLOW_FORWARD:
- case LDSTATE_PLAYING_FAST_REVERSE:
- case LDSTATE_PLAYING_FAST_FORWARD:
- case LDSTATE_STEPPING_REVERSE:
- case LDSTATE_STEPPING_FORWARD:
- case LDSTATE_SCANNING:
- case LDSTATE_SKIPPING:
- case LDSTATE_WAITING:
- ldcore_set_audio_squelch(ld, TRUE, TRUE);
- ldcore_set_video_squelch(ld, FALSE);
- break;
-
- /* video off, audio off */
- case LDSTATE_NONE:
- case LDSTATE_EJECTING:
- case LDSTATE_EJECTED:
- case LDSTATE_PARKED:
- case LDSTATE_LOADING:
- case LDSTATE_SPINUP:
- case LDSTATE_SEEKING:
- ldcore_set_audio_squelch(ld, TRUE, TRUE);
- ldcore_set_video_squelch(ld, TRUE);
- break;
+ int line;
+
+ /* loop over lines */
+ for (line = 0; line < 3; line++)
+ {
+ UINT8 *dest = &player->vbi[line * 7];
+ UINT32 data = lines[line];
+
+ /* the logic only processes leadin/leadout/frame number codes */
+ if (data == VBI_CODE_LEADIN || data == VBI_CODE_LEADOUT || (data & VBI_MASK_CAV_PICTURE) == VBI_CODE_CAV_PICTURE)
+ {
+ *dest++ = 0x09 | (((data & VBI_MASK_CAV_PICTURE) == VBI_CODE_CAV_PICTURE) ? 0x02 : 0x00);
+ *dest++ = 0x08;
+ *dest++ = (data >> 16) & 0x0f;
+ *dest++ = (data >> 12) & 0x0f;
+ *dest++ = (data >> 8) & 0x0f;
+ *dest++ = (data >> 4) & 0x0f;
+ *dest++ = (data >> 0) & 0x0f;
+ }
+ }
}
+
+ /* signal that data is ready and reset the readback index */
+ player->vbiready = TRUE;
+ player->vbiindex = 0;
}
/*-------------------------------------------------
- ldv1000_switch_state - attempt to switch states
- if appropriate, and ensure the squelch values
- are correct
+ multijump_timer - called once for each track
+ in a multijump sequence; we decrement the
+ down counter and autostop when we hit 0
-------------------------------------------------*/
-static int ldv1000_switch_state(laserdisc_state *ld, UINT8 newstate, INT32 parameter)
+static TIMER_DEVICE_CALLBACK( multijump_timer )
{
- attotime curtime = timer_get_time();
-
- /* if this is the same state, ignore */
- if (ld->state.state == newstate)
- return TRUE;
+ laserdisc_state *ld = ptr;
+ ldplayer_data *player = ld->player;
+ int direction;
+
+ /* bit 5 of port B on PPI 1 selects the direction of slider movement */
+ direction = (player->portb1 & 0x20) ? 1 : -1;
+ ldcore_advance_slider(ld, direction);
+
+ /* update down counter and reschedule */
+ if (--player->counter != 0)
+ timer_device_adjust_oneshot(timer, MULTIJUMP_TRACK_TIME, 0);
+}
- /* if we're in a timed state, we ignore changes until the time elapses */
- if (attotime_compare(curtime, ld->state.endtime) < 0)
- return FALSE;
- /* if moving to a state that requires it, save the old state */
- if (requires_state_save(newstate) && !requires_state_save(ld->state.state))
- ld->savestate = ld->state;
+/*-------------------------------------------------
+ ctc_interrupt - called when the CTC triggers
+ an interrupt in the daisy chain
+-------------------------------------------------*/
- /* set up appropriate squelch and timing */
- ld->state.state = newstate;
- ld->state.substate = 0;
- ld->state.param = parameter;
- ld->state.endtime = curtime;
- ldv1000_update_squelch(ld);
+static void ctc_interrupt(const device_config *device, int state)
+{
+ laserdisc_state *ld = find_ldv1000(device->machine);
+ cpunum_set_input_line(device->machine, ld->player->cpunum, 0, state ? ASSERT_LINE : CLEAR_LINE);
+}
- /* if we're switching to a timed state, set the appropriate timer */
- switch (ld->state.state)
- {
- case LDSTATE_EJECTING:
- ld->state.endtime = attotime_add(curtime, GENERIC_EJECT_TIME);
- break;
- case LDSTATE_LOADING:
- ld->state.endtime = attotime_add(curtime, GENERIC_LOAD_TIME);
- break;
+/*-------------------------------------------------
+ decoder_display_port_w - handle writes to the
+ decoder/display chips
+-------------------------------------------------*/
- case LDSTATE_SPINUP:
- ld->state.endtime = attotime_add(curtime, GENERIC_SPINUP_TIME);
- break;
+static WRITE8_HANDLER( decoder_display_port_w )
+{
+ /*
+ TX/RX = /A0 (A0=0 -> TX, A0=1 -> RX)
+
+ Display is 6-bit
+ Decoder is 4-bit
+ */
+ laserdisc_state *ld = find_ldv1000(machine);
+ ldplayer_data *player = ld->player;
- case LDSTATE_WAITING:
- ld->state.endtime = attotime_add(curtime, attotime_mul(ATTOTIME_IN_MSEC(100), ld->state.param));
- break;
+ /* writes to offset 0 select the target for reads/writes of actual data */
+ if (offset == 0)
+ {
+ player->portselect = data;
+ player->dispindex = 0;
+ }
+
+ /* writes to offset 2 constitute actual writes targeted toward the display and decoder chips */
+ else if (offset == 2)
+ {
+ /* selections 0 and 1 represent the two display lines; only 6 bits are transferred */
+ if (player->portselect < 2)
+ player->display[player->portselect][player->dispindex++ % 20] = data & 0x3f;
}
- return TRUE;
}
/*-------------------------------------------------
- ldv1000_update - Pioneer PR-8210-specific
- update callback
+ decoder_display_port_r - handle reads from the
+ decoder/display chips
-------------------------------------------------*/
-static INT32 ldv1000_update(laserdisc_state *ld, const vbi_metadata *vbi, int fieldnum, attotime curtime)
+static READ8_HANDLER( decoder_display_port_r )
{
+ laserdisc_state *ld = find_ldv1000(machine);
ldplayer_data *player = ld->player;
- ldplayer_state newstate;
- INT32 advanceby = 0;
- int frame, chapter;
-
- /* remember the last frame and chapter */
- player->lastvsynctime = curtime;
- frame = frame_from_metadata(vbi);
- if (frame != FRAME_NOT_PRESENT)
- player->lastframe = frame;
- chapter = chapter_from_metadata(vbi);
- if (chapter != CHAPTER_NOT_PRESENT)
- player->lastchapter = chapter;
-
- /* handle things based on the state */
- switch (ld->state.state)
+ UINT8 result = 0;
+
+ /* reads from offset 3 constitute actual reads from the display and decoder chips */
+ if (offset == 3)
{
- case LDSTATE_EJECTING:
- case LDSTATE_EJECTED:
- case LDSTATE_PARKED:
- case LDSTATE_LOADING:
- case LDSTATE_SPINUP:
- case LDSTATE_PAUSING:
- case LDSTATE_PAUSED:
- case LDSTATE_PLAYING:
- case LDSTATE_PLAYING_SLOW_REVERSE:
- case LDSTATE_PLAYING_SLOW_FORWARD:
- case LDSTATE_PLAYING_FAST_REVERSE:
- case LDSTATE_PLAYING_FAST_FORWARD:
- case LDSTATE_STEPPING_REVERSE:
- case LDSTATE_STEPPING_FORWARD:
- case LDSTATE_SCANNING:
- case LDSTATE_SEEKING:
- /* generic behaviors are appropriate for all of these commands */
- advanceby = ldcore_generic_update(ld, vbi, fieldnum, curtime, &newstate);
- ldv1000_switch_state(ld, newstate.state, newstate.param);
- break;
-
- case LDSTATE_SKIPPING:
- /* just advance and return to previous state */
- advanceby = ld->state.param;
- ldv1000_switch_state(ld, ld->savestate.state, ld->savestate.param);
- break;
-
- case LDSTATE_WAITING:
- /* keep trying to switch to the previous state until we succeed */
- ldv1000_switch_state(ld, ld->savestate.state, ld->savestate.param);
- break;
+ /* selection 4 represents the VBI data reading */
+ if (player->portselect == 4)
+ {
+ player->vbiready = FALSE;
+ result = player->vbi[player->vbiindex++ % ARRAY_LENGTH(player->vbi)];
+ }
}
+ return result;
+}
+
- return advanceby;
+/*-------------------------------------------------
+ controller_r - handle read of the data from
+ the controlling system
+-------------------------------------------------*/
+
+static READ8_HANDLER( controller_r )
+{
+ laserdisc_state *ld = find_ldv1000(machine);
+
+ /* note that this is a cheesy implementation; the real thing relies on exquisite timing */
+ UINT8 result = ld->player->command ^ 0xff;
+ ld->player->command = 0xff;
+ return result;
}
/*-------------------------------------------------
- ldv1000_data_w - write callback when the
- ENTER state is written
+ controller_w - handle status latch writes
-------------------------------------------------*/
-static void ldv1000_data_w(laserdisc_state *ld, UINT8 prev, UINT8 data)
+static WRITE8_HANDLER( controller_w )
+{
+ laserdisc_state *ld = find_ldv1000(machine);
+ if (LOG_STATUS_CHANGES && data != ld->player->status)
+ printf("%04X:CONTROLLER.W=%02X\n", activecpu_get_pc(), data);
+ ld->player->status = data;
+}
+
+
+/*-------------------------------------------------
+ ppi0_porta_w - handle writes to port A of
+ PPI #0
+-------------------------------------------------*/
+
+static WRITE8_DEVICE_HANDLER( ppi0_porta_w )
+{
+ laserdisc_state *ld = find_ldv1000(device->machine);
+ ld->player->counter_start = data;
+ if (LOG_PORT_IO)
+ printf("%04X:PORTA.0=%02X\n", activecpu_get_pc(), data);
+}
+
+
+/*-------------------------------------------------
+ ppi0_portb_r - handle reads from port B of
+ PPI #0
+-------------------------------------------------*/
+
+static READ8_DEVICE_HANDLER( ppi0_portb_r )
{
+ laserdisc_state *ld = find_ldv1000(device->machine);
+ return ld->player->counter;
+}
+
+
+/*-------------------------------------------------
+ ppi0_portc_r - handle reads from port C of
+ PPI #0
+-------------------------------------------------*/
+
+static READ8_DEVICE_HANDLER( ppi0_portc_r )
+{
+ /*
+ $10 = /VSYNC
+ $20 = IRQ from decoder chip
+ $40 = TRKG LOOP (N24-1)
+ $80 = DUMP (N20-1) -- code reads the state and waits for it to change
+ */
+ laserdisc_state *ld = find_ldv1000(device->machine);
ldplayer_data *player = ld->player;
- int target;
+ UINT8 result = 0x00;
- /* 0xff bytes are used for synchronization */
- if (data == 0xff)
- return;
+ if (!player->vsync)
+ result |= 0x10;
+ if (!player->vbiready)
+ result |= 0x20;
- /* handle commands */
- switch (data)
+ return result;
+}
+
+
+/*-------------------------------------------------
+ ppi0_portc_w - handle writes to port C of
+ PPI #0
+-------------------------------------------------*/
+
+static WRITE8_DEVICE_HANDLER( ppi0_portc_w )
+{
+ /*
+ $01 = preload on up/down counters
+ $02 = /MULTI JUMP TRIG
+ $04 = SCAN MODE
+ $08 = n/c
+ */
+ laserdisc_state *ld = find_ldv1000(device->machine);
+ ldplayer_data *player = ld->player;
+ UINT8 prev = player->portc0;
+
+ /* set the new value */
+ player->portc0 = data;
+ if (LOG_PORT_IO && ((data ^ prev) & 0x0f) != 0)
{
- case 0x3f: CMDPRINTF(("ldv1000: 0\n"));
- player->parameter = (player->parameter == -1) ? 0 : (player->parameter * 10 + 0);
- return;
-
- case 0x0f: CMDPRINTF(("ldv1000: 1\n"));
- player->parameter = (player->parameter == -1) ? 1 : (player->parameter * 10 + 1);
- return;
-
- case 0x8f: CMDPRINTF(("ldv1000: 2\n"));
- player->parameter = (player->parameter == -1) ? 2 : (player->parameter * 10 + 2);
- return;
-
- case 0x4f: CMDPRINTF(("ldv1000: 3\n"));
- player->parameter = (player->parameter == -1) ? 3 : (player->parameter * 10 + 3);
- return;
-
- case 0x2f: CMDPRINTF(("ldv1000: 4\n"));
- player->parameter = (player->parameter == -1) ? 4 : (player->parameter * 10 + 4);
- return;
-
- case 0xaf: CMDPRINTF(("ldv1000: 5\n"));
- player->parameter = (player->parameter == -1) ? 5 : (player->parameter * 10 + 5);
- return;
-
- case 0x6f: CMDPRINTF(("ldv1000: 6\n"));
- player->parameter = (player->parameter == -1) ? 6 : (player->parameter * 10 + 6);
- return;
-
- case 0x1f: CMDPRINTF(("ldv1000: 7\n"));
- player->parameter = (player->parameter == -1) ? 7 : (player->parameter * 10 + 7);
- return;
-
- case 0x9f: CMDPRINTF(("ldv1000: 8\n"));
- player->parameter = (player->parameter == -1) ? 8 : (player->parameter * 10 + 8);
- return;
-
- case 0x5f: CMDPRINTF(("ldv1000: 9\n"));
- player->parameter = (player->parameter == -1) ? 9 : (player->parameter * 10 + 9);
- return;
-
- case 0x7f: CMDPRINTF(("ldv1000: %d Recall\n", player->parameter));
- /* set the active register */
- player->activereg = player->parameter;
- /* should also display the register value */
- break;
-
- case 0x20: CMDPRINTF(("ldv1000: x0 reverse (stop) - Badlands special\n"));
- ldv1000_switch_state(ld, LDSTATE_PLAYING_FAST_REVERSE, 0);
- break;
-
- case 0x21: CMDPRINTF(("ldv1000: x1/4 reverse - Badlands special\n"));
- ldv1000_switch_state(ld, LDSTATE_PLAYING_SLOW_REVERSE, 4);
- break;
-
- case 0x22: CMDPRINTF(("ldv1000: x1/2 reverse - Badlands special\n"));
- ldv1000_switch_state(ld, LDSTATE_PLAYING_SLOW_REVERSE, 2);
- break;
-
- case 0x23:
- case 0x24:
- case 0x25:
- case 0x26:
- case 0x27: CMDPRINTF(("ldv1000: x%d reverse - Badlands special\n", (data & 0x07) - 2));
- ldv1000_switch_state(ld, LDSTATE_PLAYING_FAST_REVERSE, (data & 0x07) - 2);
- break;
-
- case 0xa0: CMDPRINTF(("ldv1000: x0 forward (stop)\n"));
- ldv1000_switch_state(ld, LDSTATE_PLAYING_FAST_FORWARD, 0);
- break;
-
- case 0xa1: CMDPRINTF(("ldv1000: x1/4 forward\n"));
- ldv1000_switch_state(ld, LDSTATE_PLAYING_SLOW_FORWARD, 4);
- break;
-
- case 0xa2: CMDPRINTF(("ldv1000: x1/2 forward\n"));
- ldv1000_switch_state(ld, LDSTATE_PLAYING_SLOW_FORWARD, 2);
- break;
-
- case 0xa3:
- case 0xa4:
- case 0xa5:
- case 0xa6:
- case 0xa7: CMDPRINTF(("ldv1000: x%d forward\n", (data & 0x07) - 2));
- ldv1000_switch_state(ld, LDSTATE_PLAYING_FAST_FORWARD, (data & 0x07) - 2);
- break;
-
- case 0xb1:
- case 0xb2:
- case 0xb3:
- case 0xb4:
- case 0xb5:
- case 0xb6:
- case 0xb7:
- case 0xb8:
- case 0xb9:
- case 0xba: CMDPRINTF(("ldv1000: Skip forward %d0\n", data & 0x0f));
- /* note that this skips tracks, not frames */
- ldv1000_switch_state(ld, LDSTATE_SKIPPING, 10 * (data & 0x0f));
- break;
-
- case 0x31:
- case 0x32:
- case 0x33:
- case 0x34:
- case 0x35:
- case 0x36:
- case 0x37:
- case 0x38:
- case 0x39:
- case 0x3a: CMDPRINTF(("ldv1000: Skip backwards %d0 - Badlands special\n", data & 0x0f));
- /* note that this skips tracks, not frames */
- ldv1000_switch_state(ld, LDSTATE_SKIPPING, -10 * (data & 0x0f));
- break;
-
- case 0xbf: CMDPRINTF(("ldv1000: %d Clear\n", player->parameter));
- /* clears register display and removes pending arguments */
- player->parameter = -1;
- break;
-
- case 0xc2: CMDPRINTF(("ldv1000: Get frame no.\n"));
- /* returns the current frame number */
- player->mode = LDV1000_MODE_GET_FRAME;
- player->readpos = 0;
- player->readtotal = 5;
- sprintf((char *)player->readbuf, "%05d", player->lastframe);
- break;
-
- case 0xc3: CMDPRINTF(("ldv1000: Get 2nd display\n"));
- /* returns the data from the 2nd display line */
- player->mode = LDV1000_MODE_GET_2ND;
- player->readpos = 0;
- player->readtotal = 8;
- sprintf((char *)player->readbuf, " \x1c\x1c\x1c");
- break;
-
- case 0xc4: CMDPRINTF(("ldv1000: Get 1st display\n"));
- /* returns the data from the 1st display line */
- player->mode = LDV1000_MODE_GET_1ST;
- player->readpos = 0;
- player->readtotal = 8;
- sprintf((char *)player->readbuf, " \x1c\x1c\x1c");
- break;
-
- case 0xc8: CMDPRINTF(("ldv1000: Transfer memory\n"));
- /* returns the data from RAM */
- player->mode = LDV1000_MODE_GET_RAM;
- player->readpos = 0;
- player->readtotal = 1024;
- break;
-
- case 0xcc: CMDPRINTF(("ldv1000: Load\n"));
- /* load program from disc -- not implemented */
- break;
-
- case 0xcd: CMDPRINTF(("ldv1000: Display disable\n"));
- /* disables the display of current command -- not implemented */
- break;
-
- case 0xce: CMDPRINTF(("ldv1000: Display enable\n"));
- /* enables the display of current command -- not implemented */
- break;
-
- case 0xf0: CMDPRINTF(("ldv1000: Scan forward\n"));
- if (ld->state.state != LDSTATE_SCANNING)
- ldv1000_switch_state(ld, LDSTATE_SCANNING, SCANNING_PARAM(LDV1000_SCAN_SPEED, LDV1000_SCAN_DURATION));
- else
- ld->state.substate = 0;
- break;
-
- case 0xf1: CMDPRINTF(("ldv1000: %d Display\n", player->parameter));
- player->framedisplay = (player->parameter == -1) ? !player->framedisplay : (player->parameter & 1);
- break;
-
- case 0xf3: CMDPRINTF(("ldv1000: %d Autostop\n", player->parameter));
- target = (player->parameter != -1) ? player->parameter : read_16bits_from_ram_be(player->ram, (player->activereg++ * 2) % 1024);
- if (target > player->lastframe)
- ldv1000_switch_state(ld, LDSTATE_PLAYING, target);
- else
- ldv1000_switch_state(ld, LDSTATE_SEEKING, target);
- break;
-
- case 0xf4: CMDPRINTF(("ldv1000: %d Audio track 1\n", player->parameter));
- if (player->parameter == -1)
- player->audio1disable ^= 1;
- else
- player->audio1disable = ~player->parameter & 1;
- break;
-
- case 0xf5: CMDPRINTF(("ldv1000: %d Store\n", player->parameter));
- /* store either the current frame number or an explicit value into the active register */
- if (player->parameter == -1)
- write_16bits_to_ram_be(player->ram, (player->activereg * 2) % 1024, player->lastframe);
- else
- write_16bits_to_ram_be(player->ram, (player->activereg * 2) % 1024, player->parameter);
- player->activereg++;
- break;
-
- case 0xf6: CMDPRINTF(("ldv1000: Step forward\n"));
- ldv1000_switch_state(ld, LDSTATE_STEPPING_FORWARD, 0);
- break;
-
- case 0xf7: CMDPRINTF(("ldv1000: %d Search\n", player->parameter));
- target = (player->parameter != -1) ? player->parameter : read_16bits_from_ram_be(player->ram, (player->activereg * 2) % 1024);
- player->activereg++;
- ldv1000_switch_state(ld, LDSTATE_SEEKING, target);
- break;
-
- case 0xf8: CMDPRINTF(("ldv1000: Scan reverse\n"));
- if (ld->state.state != LDSTATE_SCANNING)
- ldv1000_switch_state(ld, LDSTATE_SCANNING, SCANNING_PARAM(-LDV1000_SCAN_SPEED, LDV1000_SCAN_DURATION));
- else
- ld->state.substate = 0;
- break;
-
- case 0xf9: CMDPRINTF(("ldv1000: Reject\n"));
- ldv1000_switch_state(ld, LDSTATE_EJECTING, 0);
- break;
-
- case 0xfb: CMDPRINTF(("ldv1000: %d Stop/Wait\n", player->parameter));
- ldv1000_switch_state(ld, LDSTATE_WAITING, player->parameter);
- break;
-
- case 0xfc: CMDPRINTF(("ldv1000: %d Audio track 2\n", player->parameter));
- if (player->parameter == -1)
- player->audio2disable ^= 1;
- else
- player->audio2disable = ~player->parameter & 1;
- break;
-
- case 0xfd: CMDPRINTF(("ldv1000: Play\n"));
- if (ld->state.state == LDSTATE_EJECTED)
- ldv1000_switch_state(ld, LDSTATE_LOADING, 0);
- else if (ld->state.state == LDSTATE_PARKED)
- ldv1000_switch_state(ld, LDSTATE_SPINUP, 0);
- else
- ldv1000_switch_state(ld, LDSTATE_PLAYING, -1);
- break;
-
- case 0xfe: CMDPRINTF(("ldv1000: Step reverse\n"));
- ldv1000_switch_state(ld, LDSTATE_STEPPING_REVERSE, 0);
- break;
-
- default: CMDPRINTF(("ldv1000: %d Unknown command %02X\n", player->parameter, data));
- /* unknown command */
- break;
+ printf("%04X:PORTC.0=%02X", activecpu_get_pc(), data);
+ if (data & 0x01) printf(" PRELOAD");
+ if (!(data & 0x02)) printf(" /MULTIJUMP");
+ if (data & 0x04) printf(" SCANMODE");
+ printf("\n");
}
-
- /* reset the parameter after executing a command */
- player->parameter = -1;
+
+ /* on the rising edge of bit 0, clock the down counter load */
+ if ((data & 0x01) && !(prev & 0x01))
+ player->counter = player->counter_start;
+
+ /* on the falling edge of bit 1, start the multi-jump timer */
+ if (!(data & 0x02) && (prev & 0x02))
+ timer_device_adjust_oneshot(player->multitimer, MULTIJUMP_TRACK_TIME, 0);
}
/*-------------------------------------------------
- ldv1000_status_strobe_r - return state of the
- status strobe
+ ppi1_porta_r - handle reads from port A of
+ PPI #1
-------------------------------------------------*/
-static UINT8 ldv1000_status_strobe_r(laserdisc_state *ld)
+static READ8_DEVICE_HANDLER( ppi1_porta_r )
{
+ /*
+ $01 = /FOCS LOCK
+ $02 = /SPDL LOCK
+ $04 = INSIDE
+ $08 = OUTSIDE
+ $10 = MOTOR STOP
+ $20 = +5V/test point
+ $40 = /INT LOCK
+ $80 = 8 INCH CHK
+ */
+ laserdisc_state *ld = find_ldv1000(device->machine);
ldplayer_data *player = ld->player;
+ slider_position sliderpos = ldcore_get_slider_position(ld);
+ UINT8 focus_on = !(player->portb1 & 0x01);
+ UINT8 spdl_on = !(player->portb1 & 0x02);
+ UINT8 result = 0x00;
+
+ /* bit 0: /FOCUS LOCK */
+ if (!focus_on)
+ result |= 0x01;
+
+ /* bit 1: /SPDL LOCK */
+ if (!spdl_on)
+ result |= 0x02;
+
+ /* bit 2: INSIDE signal */
+ if (sliderpos == SLIDER_MINIMUM)
+ result |= 0x04;
+
+ /* bit 3: OUTSIDE signal */
+ if (sliderpos == SLIDER_MAXIMUM)
+ result |= 0x08;
+
+ /* bit 4: MOTOR STOP */
- /* the status strobe is asserted (active low) 500-650usec after VSYNC */
- /* for a duration of 26usec; we pick 600-626usec */
- attotime delta = attotime_sub(timer_get_time(), player->lastvsynctime);
- if (delta.attoseconds >= ATTOTIME_IN_USEC(600).attoseconds && delta.attoseconds < ATTOTIME_IN_USEC(626).attoseconds)
- return ASSERT_LINE;
+ /* bit 5: +5V/test point */
+ result |= 0x20;
- return CLEAR_LINE;
+ /* bit 6: /INT LOCK */
+
+ /* bit 7: 8 INCH CHK */
+
+ return result;
}
/*-------------------------------------------------
- ldv1000_command_strobe_r - return state of the
- command strobe
+ ppi1_portb_w - handle writes to port B of
+ PPI #1
-------------------------------------------------*/
-static UINT8 ldv1000_command_strobe_r(laserdisc_state *ld)
+static WRITE8_DEVICE_HANDLER( ppi1_portb_w )
{
+ /*
+ $01 = /FOCS ON
+ $02 = /SPDL RUN
+ $04 = /JUMP TRIG
+ $08 = /SCAN A
+ $10 = SCAN B
+ $20 = SCAN C
+ $40 = /LASER ON
+ $80 = /SYNC ST0
+ */
+ laserdisc_state *ld = find_ldv1000(device->machine);
ldplayer_data *player = ld->player;
+ UINT8 prev = player->portb1;
+ int direction;
- /* the command strobe is asserted (active low) 54 or 84usec after the status */
- /* strobe for a duration of 25usec; we pick 600+84 = 684-709usec */
- /* for a duration of 26usec; we pick 600-626usec */
- attotime delta = attotime_sub(timer_get_time(), player->lastvsynctime);
- if (delta.attoseconds >= ATTOTIME_IN_USEC(684).attoseconds && delta.attoseconds < ATTOTIME_IN_USEC(709).attoseconds)
- return ASSERT_LINE;
+ /* set the new value */
+ player->portb1 = data;
+ if (LOG_PORT_IO && ((data ^ prev) & 0xff) != 0)
+ {
+ printf("%04X:PORTB.1=%02X:", activecpu_get_pc(), data);
+ if (!(data & 0x01)) printf(" FOCSON");
+ if (!(data & 0x02)) printf(" SPDLRUN");
+ if (!(data & 0x04)) printf(" JUMPTRIG");
+ if (!(data & 0x08)) printf(" SCANA (%c %c)", (data & 0x10) ? 'L' : 'H', (data & 0x20) ? 'F' : 'R');
+ if ( (data & 0x40)) printf(" LASERON");
+ if (!(data & 0x80)) printf(" SYNCST0");
+ printf("\n");
+ }
+
+ /* bit 5 selects the direction of slider movement for JUMP TRG and scanning */
+ direction = (data & 0x20) ? 1 : -1;
+
+ /* on the falling edge of bit 2, jump one track in either direction */
+ if (!(data & 0x04) && (prev & 0x04))
+ ldcore_advance_slider(ld, direction);
+
+ /* bit 3 low enables scanning */
+ if (!(data & 0x08))
+ {
+ /* bit 4 selects the speed */
+ int delta = (data & 0x10) ? SCAN_SPEED : SEEK_FAST_SPEED;
+ ldcore_set_slider_speed(ld, delta * direction);
+ }
- return CLEAR_LINE;
+ /* bit 3 high stops scanning */
+ else
+ ldcore_set_slider_speed(ld, 0);
}
/*-------------------------------------------------
- ldv1000_status_r - return state of the ready
- line
+ ppi1_portc_w - handle writes to port C of
+ PPI #1
-------------------------------------------------*/
-static UINT8 ldv1000_status_r(laserdisc_state *ld)
+static WRITE8_DEVICE_HANDLER( ppi1_portc_w )
{
+ /*
+ $01 = AUD 1
+ $02 = AUD 2
+ $04 = AUDIO ENABLE
+ $08 = /VIDEO SQ
+ $10 = COMMAND
+ $20 = STATUS
+ $40 = SIZE 8/12
+ $80 = /LED CAV
+ */
+ laserdisc_state *ld = find_ldv1000(device->machine);
ldplayer_data *player = ld->player;
- UINT8 status = 0xff;
+ UINT8 prev = player->portc1;
- /* switch off the current mode */
- switch (player->mode)
+ /* set the new value */
+ player->portc1 = data;
+ if (LOG_PORT_IO && ((data ^ prev) & 0xcf) != 0)
{
- /* reading frame number returns 5 characters */
- /* reading display lines returns 8 characters */
- case LDV1000_MODE_GET_FRAME:
- case LDV1000_MODE_GET_1ST:
- case LDV1000_MODE_GET_2ND:
- assert(player->readpos < player->readtotal);
- status = player->readbuf[player->readpos++];
- if (player->readpos == player->readtotal)
- player->mode = LDV1000_MODE_STATUS;
- break;
-
- /* reading RAM returns 1024 bytes */
- case LDV1000_MODE_GET_RAM:
- assert(player->readpos < player->readtotal);
- status = player->ram[1023 - player->readpos++];
- if (player->readpos == player->readtotal)
- player->mode = LDV1000_MODE_STATUS;
- break;
-
- /* otherwise, we just compute a status code */
- default:
- case LDV1000_MODE_STATUS:
- switch (ld->state.state)
- {
- case LDSTATE_EJECTING: status = 0x60; break;
- case LDSTATE_EJECTED: status = 0xe0; break;
- case LDSTATE_PARKED: status = 0xfc; break;
- case LDSTATE_LOADING: status = 0x48; break;
- case LDSTATE_SPINUP: status = 0x48; break;
- case LDSTATE_PAUSING: status = 0xe5; break;
- case LDSTATE_PAUSED: status = 0xe5; break;
- case LDSTATE_PLAYING: status = 0xe4; break;
- case LDSTATE_PLAYING_SLOW_REVERSE: status = 0xae; break;
- case LDSTATE_PLAYING_SLOW_FORWARD: status = 0xae; break;
- case LDSTATE_PLAYING_FAST_REVERSE: status = 0xae; break;
- case LDSTATE_PLAYING_FAST_FORWARD: status = 0xae; break;
- case LDSTATE_STEPPING_FORWARD: status = 0xe5; break;
- case LDSTATE_STEPPING_REVERSE: status = 0xe5; break;
- case LDSTATE_SCANNING: status = 0x4c; break;
- case LDSTATE_SEEKING: status = 0x50; break;
-// case LASERDISC_SEARCH_FINISHED: status = 0xd0; break;
-// case LASERDISC_AUTOSTOPPED: status = 0x54; break;
- default:
- fatalerror("Unexpected disc state in ldv1000_status_r\n");
- break;
- }
- break;
+ printf("%04X:PORTC.1=%02X", activecpu_get_pc(), data);
+ if (data & 0x01) printf(" AUD1");
+ if (data & 0x02) printf(" AUD2");
+ if (data & 0x04) printf(" AUDEN");
+ if (!(data & 0x08)) printf(" VIDEOSQ");
+ if (data & 0x10) printf(" COMMAND");
+ if (data & 0x20) printf(" STATUS");
+ if (data & 0x40) printf(" SIZE8");
+ if (!(data & 0x80)) printf(" CAV");
+ printf("\n");
}
- /* bit 7 indicates our busy status */
- return status;
+ /* video squelch is controlled by bit 3 */
+ ldcore_set_video_squelch(ld, (data & 0x08) == 0);
+
+ /* audio squelch is controlled by bits 0-2 */
+ ldcore_set_audio_squelch(ld, !(data & 0x04) || !(data & 0x01), !(data & 0x04) || !(data & 0x02));
}
diff --git a/src/emu/machine/ldvp931.c b/src/emu/machine/ldvp931.c
index 57c49b823ec..acf95513133 100644
--- a/src/emu/machine/ldvp931.c
+++ b/src/emu/machine/ldvp931.c
@@ -34,9 +34,9 @@
CONSTANTS
***************************************************************************/
-/* Philips 22VP931 specific information */
-#define VP931_SCAN_SPEED (2000 / 30) /* 2000 frames/second */
-#define VP931_SCAN_FAST_SPEED (4000 / 30) /* 4000 frames/second */
+/* scanning speeds */
+#define SCAN_SPEED (2000 / 30) /* 2000 frames/second */
+#define SCAN_FAST_SPEED (4000 / 30) /* 4000 frames/second */
@@ -50,23 +50,32 @@ struct _ldplayer_data
/* low-level emulation data */
int cpunum; /* CPU index of the 8049 */
const device_config *tracktimer; /* timer device */
- int lastframe;
+ 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 */
- void (*data_ready_cb)(const device_config *device, int state); /* data ready callback */
};
@@ -83,6 +92,13 @@ 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 );
@@ -96,12 +112,6 @@ static READ8_HANDLER( port2_r );
static WRITE8_HANDLER( port2_w );
static READ8_HANDLER( t0_r );
static READ8_HANDLER( t1_r );
-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 );
@@ -152,7 +162,7 @@ ROM_END
/***************************************************************************
- PR-8210 PLAYER INTERFACE
+ 22VP931 PLAYER INTERFACE
***************************************************************************/
const ldplayer_interface vp931_interface =
@@ -191,7 +201,7 @@ const ldplayer_interface vp931_interface =
ready callback
-------------------------------------------------*/
-void vp931_set_data_ready_callback(const device_config *device, void (*callback)(const device_config *device, int state))
+void vp931_set_data_ready_callback(const device_config *device, vp931_data_ready_func callback)
{
laserdisc_state *ld = ldcore_get_safe_token(device);
ld->player->data_ready_cb = callback;
@@ -204,22 +214,24 @@ void vp931_set_data_ready_callback(const device_config *device, void (*callback)
***************************************************************************/
/*-------------------------------------------------
- vp931_init - Pioneer PR-8210-specific
- initialization
+ vp931_init - player-specific initialization
-------------------------------------------------*/
static void vp931_init(laserdisc_state *ld)
{
astring *tempstring = astring_alloc();
ldplayer_data *player = ld->player;
-
- /* find our CPU */
+ 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->cpunum = mame_find_cpu_index(ld->device->machine, device_build_tag(tempstring, ld->device->tag, "vp931"));
-
- /* find our timer */
- player->tracktimer = device_list_find_by_tag(ld->device->machine->config->devicelist, TIMER, device_build_tag(tempstring, ld->device->tag, "tracktimer"));
+ player->tracktimer = devtag_get_device(ld->device->machine, TIMER, device_build_tag(tempstring, ld->device->tag, "tracktimer"));
timer_device_set_ptr(player->tracktimer, ld);
-
astring_free(tempstring);
}
@@ -317,6 +329,127 @@ static UINT8 vp931_data_ready(laserdisc_state *ld)
/*-------------------------------------------------
+ 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 = 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);
+
+ /* at the start of each line, signal an interrupt and use a timer to turn it off */
+ if (which == 0)
+ {
+ cpunum_set_input_line(machine, player->cpunum, MCS48_INPUT_IRQ, ASSERT_LINE);
+ timer_set(ATTOTIME_IN_NSEC(5580), ld, 0, irq_off);
+ }
+
+ /* clock the data strobe on each subsequent callback */
+ else if (code != 0)
+ {
+ player->daticval = code >> (8 * (3 - which));
+ player->datastrobe = 1;
+ timer_set(ATTOTIME_IN_NSEC(5000), ld, 0, datastrobe_off);
+ }
+
+ /* determine the next bit to fetch and reprime ourself */
+ if (++which == 4)
+ {
+ which = 0;
+ line++;
+ }
+ if (line <= LASERDISC_CODE_LINE18 + 1)
+ timer_set(video_screen_get_time_until_pos(ld->screen, line*2, which * 2 * video_screen_get_width(ld->screen) / 4), ld, (line << 2) | which, vbi_data_fetch);
+}
+
+
+/*-------------------------------------------------
+ deferred_data_w - handle a write from the
+ external controller
+-------------------------------------------------*/
+
+static TIMER_CALLBACK( deferred_data_w )
+{
+ laserdisc_state *ld = ptr;
+ ldplayer_data *player = ld->player;
+
+ /* set the value and mark it pending */
+ player->fromcontroller = param;
+ player->fromcontroller_pending = TRUE;
+
+ /* track the commands for debugging purposes */
+ if (player->cmdcount < ARRAY_LENGTH(player->cmdbuf))
+ {
+ player->cmdbuf[player->cmdcount++] = param;
+ if (LOG_COMMANDS && player->cmdcount == 3)
+ 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 = ptr;
+ cpunum_set_input_line(machine, ld->player->cpunum, MCS48_INPUT_IRQ, CLEAR_LINE);
+}
+
+
+/*-------------------------------------------------
+ datastrobe_off - turn off the DATIC data
+ strobe signal
+-------------------------------------------------*/
+
+static TIMER_CALLBACK( datastrobe_off )
+{
+ laserdisc_state *ld = ptr;
+ ld->player->datastrobe = 0;
+}
+
+
+/*-------------------------------------------------
+ erp_off - turn off the DATIC ERP signal
+-------------------------------------------------*/
+
+static TIMER_CALLBACK( erp_off )
+{
+ laserdisc_state *ld = ptr;
+ ld->player->daticerp = 0;
+}
+
+
+/*-------------------------------------------------
+ track_timer - advance by one half-track
+-------------------------------------------------*/
+
+static TIMER_DEVICE_CALLBACK( track_timer )
+{
+ laserdisc_state *ld = 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
-------------------------------------------------*/
@@ -392,7 +525,7 @@ static WRITE8_HANDLER( output1_w )
if (!(data & 0x02))
{
/* fast/slow is based on bit 2 */
- speed = (data & 0x04) ? VP931_SCAN_FAST_SPEED : VP931_SCAN_SPEED;
+ speed = (data & 0x04) ? SCAN_FAST_SPEED : SCAN_SPEED;
/* direction is based on bit 0 */
if (data & 0x01)
@@ -647,124 +780,3 @@ static READ8_HANDLER( t1_r )
laserdisc_state *ld = find_vp931(machine);
return ld->player->trackstate;
}
-
-
-/*-------------------------------------------------
- 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 = 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);
-
- /* at the start of each line, signal an interrupt and use a timer to turn it off */
- if (which == 0)
- {
- cpunum_set_input_line(machine, player->cpunum, MCS48_INPUT_IRQ, ASSERT_LINE);
- timer_set(ATTOTIME_IN_NSEC(5580), ld, 0, irq_off);
- }
-
- /* clock the data strobe on each subsequent callback */
- else if (code != 0)
- {
- player->daticval = code >> (8 * (3 - which));
- player->datastrobe = 1;
- timer_set(ATTOTIME_IN_NSEC(5000), ld, 0, datastrobe_off);
- }
-
- /* determine the next bit to fetch and reprime ourself */
- if (++which == 4)
- {
- which = 0;
- line++;
- }
- if (line <= LASERDISC_CODE_LINE18 + 1)
- timer_set(video_screen_get_time_until_pos(ld->screen, line*2, which * 2 * video_screen_get_width(ld->screen) / 4), ld, (line << 2) | which, vbi_data_fetch);
-}
-
-
-/*-------------------------------------------------
- deferred_data_w - handle a write from the
- external controller
--------------------------------------------------*/
-
-static TIMER_CALLBACK( deferred_data_w )
-{
- laserdisc_state *ld = ptr;
- ldplayer_data *player = ld->player;
-
- /* set the value and mark it pending */
- player->fromcontroller = param;
- player->fromcontroller_pending = TRUE;
-
- /* track the commands for debugging purposes */
- if (player->cmdcount < ARRAY_LENGTH(player->cmdbuf))
- {
- player->cmdbuf[player->cmdcount++] = param;
- if (LOG_COMMANDS && player->cmdcount == 3)
- 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 = ptr;
- cpunum_set_input_line(machine, ld->player->cpunum, MCS48_INPUT_IRQ, CLEAR_LINE);
-}
-
-
-/*-------------------------------------------------
- datastrobe_off - turn off the DATIC data
- strobe signal
--------------------------------------------------*/
-
-static TIMER_CALLBACK( datastrobe_off )
-{
- laserdisc_state *ld = ptr;
- ld->player->datastrobe = 0;
-}
-
-
-/*-------------------------------------------------
- erp_off - turn off the DATIC ERP signal
--------------------------------------------------*/
-
-static TIMER_CALLBACK( erp_off )
-{
- laserdisc_state *ld = ptr;
- ld->player->daticerp = 0;
-}
-
-
-/*-------------------------------------------------
- track_timer - advance by one half-track
--------------------------------------------------*/
-
-static TIMER_DEVICE_CALLBACK( track_timer )
-{
- laserdisc_state *ld = 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;
- }
-}
diff --git a/src/emu/validity.c b/src/emu/validity.c
index 44b14d39ac6..2b6e26726b1 100644
--- a/src/emu/validity.c
+++ b/src/emu/validity.c
@@ -807,7 +807,7 @@ static int validate_cpu(int drivnum, const machine_config *config, const input_p
/* validate the global map parameters */
if (map->spacenum != spacenum)
{
- mame_printf_error("%s: %s CPU #%d space %d has address space %d handlers!", driver->source_file, driver->name, cpunum, spacenum, map->spacenum);
+ mame_printf_error("%s: %s CPU #%d space %d has address space %d handlers!\n", driver->source_file, driver->name, cpunum, spacenum, map->spacenum);
error = TRUE;
}
if (map->databits != databus_width)
diff --git a/src/ldplayer/ldplayer.mak b/src/ldplayer/ldplayer.mak
index c3344034e26..fd707a7d9a2 100644
--- a/src/ldplayer/ldplayer.mak
+++ b/src/ldplayer/ldplayer.mak
@@ -26,6 +26,7 @@ OBJDIRS += \
#-------------------------------------------------
CPUS += I8049
+CPUS += Z80