summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--src/emu/cpu/mcs48/mcs48.c7
-rw-r--r--src/emu/cpu/mcs48/mcs48dsm.c4
-rw-r--r--src/emu/debug/debugcpu.c18
-rw-r--r--src/emu/machine/laserdsc.c6
-rw-r--r--src/emu/machine/laserdsc.h9
-rw-r--r--src/emu/machine/ldcore.c255
-rw-r--r--src/emu/machine/ldcore.h34
-rw-r--r--src/emu/machine/ldpr8210.c1514
-rw-r--r--src/emu/romload.c2
-rw-r--r--src/ldplayer/ldplayer.c190
-rw-r--r--src/lib/util/chd.h3
-rw-r--r--src/lib/util/vbiparse.c45
-rw-r--r--src/lib/util/vbiparse.h46
-rw-r--r--src/mame/drivers/cubeqst.c24
-rw-r--r--src/mame/drivers/gottlieb.c2
-rw-r--r--src/tools/chdman.c279
16 files changed, 1379 insertions, 1059 deletions
diff --git a/src/emu/cpu/mcs48/mcs48.c b/src/emu/cpu/mcs48/mcs48.c
index 11017e76d33..a3d3a798ec9 100644
--- a/src/emu/cpu/mcs48/mcs48.c
+++ b/src/emu/cpu/mcs48/mcs48.c
@@ -1114,10 +1114,11 @@ static void mcs48_get_info(UINT32 state, cpuinfo *info)
case CPUINFO_STR_CORE_CREDITS: strcpy(info->s, "Copyright Mirko Buffoni\nBased on the original work Copyright Dan Boris"); break;
case CPUINFO_STR_FLAGS:
- sprintf(info->s, "%c %c%c%c%c%c%c%c%c",
- mcs48.a11 ? 'M':'.',
+ sprintf(info->s, "%c%c %c%c%c%c%c%c%c%c",
+ mcs48.irq_state ? 'I':'.',
+ mcs48.a11 ? 'M':'.',
PSW & 0x80 ? 'C':'.',
- PSW & 0x40 ? 'a':'.',
+ PSW & 0x40 ? 'A':'.',
PSW & 0x20 ? 'F':'.',
PSW & 0x10 ? 'B':'.',
PSW & 0x08 ? '?':'.',
diff --git a/src/emu/cpu/mcs48/mcs48dsm.c b/src/emu/cpu/mcs48/mcs48dsm.c
index c26ccb7bd68..aad9f7304d2 100644
--- a/src/emu/cpu/mcs48/mcs48dsm.c
+++ b/src/emu/cpu/mcs48/mcs48dsm.c
@@ -278,8 +278,8 @@ offs_t mcs48_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opra
cp++;
switch (*cp++)
{
- case 'A': sprintf(num,"$%04X",a); break;
- case 'J': sprintf(num,"$%04X",((pc+1) & 0xf00) | a); break;
+ case 'A': sprintf(num,"$%03X",a); break;
+ case 'J': sprintf(num,"$%03X",((pc+1) & 0xf00) | a); break;
case 'B': sprintf(num,"%d",b); break;
case 'D': sprintf(num,"%d",d); break;
case 'X': sprintf(num,"%X",d); break;
diff --git a/src/emu/debug/debugcpu.c b/src/emu/debug/debugcpu.c
index d164e2ac0de..89f778df3c9 100644
--- a/src/emu/debug/debugcpu.c
+++ b/src/emu/debug/debugcpu.c
@@ -120,6 +120,7 @@ static UINT64 get_tempvar(void *ref);
static UINT64 get_logunmap(void *ref);
static UINT64 get_beamx(void *ref);
static UINT64 get_beamy(void *ref);
+static UINT64 get_frame(void *ref);
static void set_tempvar(void *ref, UINT64 value);
static void set_logunmap(void *ref, UINT64 value);
static UINT64 get_current_pc(void *ref);
@@ -200,6 +201,7 @@ void debug_cpu_init(running_machine *machine)
symtable_add_register(global_symtable, "logunmapi", (void *)ADDRESS_SPACE_IO, get_logunmap, set_logunmap);
symtable_add_register(global_symtable, "beamx", NULL, get_beamx, NULL);
symtable_add_register(global_symtable, "beamy", NULL, get_beamy, NULL);
+ symtable_add_register(global_symtable, "frame", NULL, get_frame, NULL);
/* add the temporary variables to the global symbol table */
for (regnum = 0; regnum < NUM_TEMP_VARIABLES; regnum++)
@@ -2816,6 +2818,22 @@ static UINT64 get_beamy(void *ref)
/*-------------------------------------------------
+ get_frame - get current frame number
+-------------------------------------------------*/
+
+static UINT64 get_frame(void *ref)
+{
+ UINT64 ret = 0;
+ const device_config *screen = device_list_find_by_index(Machine->config->devicelist, VIDEO_SCREEN, 0);
+
+ if (screen != NULL)
+ ret = video_screen_get_frame_number(screen);
+
+ return ret;
+}
+
+
+/*-------------------------------------------------
set_logunmap - setter callback for the logumap
symbols
-------------------------------------------------*/
diff --git a/src/emu/machine/laserdsc.c b/src/emu/machine/laserdsc.c
index 980a99cc243..efa1a883b4a 100644
--- a/src/emu/machine/laserdsc.c
+++ b/src/emu/machine/laserdsc.c
@@ -1086,7 +1086,7 @@ UINT8 laserdisc_line_r(const device_config *device, UINT8 line)
video frame
-------------------------------------------------*/
-UINT32 laserdisc_get_video(const device_config *device, bitmap_t **bitmap)
+int laserdisc_get_video(const device_config *device, bitmap_t **bitmap)
{
laserdisc_state *ld = get_safe_token(device);
int frameindex;
@@ -1100,12 +1100,12 @@ UINT32 laserdisc_get_video(const device_config *device, bitmap_t **bitmap)
if (!video_active(ld) || ld->videofields[frameindex] < 2)
{
*bitmap = ld->emptyframe;
- return 0;
+ return FALSE;
}
else
{
*bitmap = ld->videovisframe[frameindex];
- return ld->videoframenum[frameindex];
+ return TRUE;
}
}
diff --git a/src/emu/machine/laserdsc.h b/src/emu/machine/laserdsc.h
index ac7954f9854..407e2f2a804 100644
--- a/src/emu/machine/laserdsc.h
+++ b/src/emu/machine/laserdsc.h
@@ -129,7 +129,7 @@ struct _laserdisc_config
\
MDRV_SCREEN_ADD(_tag, RASTER) \
MDRV_SCREEN_FORMAT(_overlayformat) \
- MDRV_SCREEN_RAW_PARAMS(XTAL_14_31818MHz*2, 910, 0, 704, 525, 0, 480) \
+ MDRV_SCREEN_RAW_PARAMS(XTAL_14_31818MHz*2, 910, 0, 704, 525, 44, 524) \
/* not correct yet; fix me... */
#define MDRV_LASERDISC_SCREEN_ADD_PAL(_tag, _format) \
@@ -157,8 +157,8 @@ extern const custom_sound_interface laserdisc_custom_interface;
/* ----- core control and status ----- */
-/* get a bitmap for the current frame (and the frame number) */
-UINT32 laserdisc_get_video(const device_config *device, bitmap_t **bitmap);
+/* get a bitmap for the current frame; return TRUE if valid or FALSE if video off */
+int laserdisc_get_video(const device_config *device, bitmap_t **bitmap);
/* return the raw philips or white flag codes */
UINT32 laserdisc_get_field_code(const device_config *device, UINT8 code);
@@ -189,9 +189,6 @@ void pr7820_set_slow_speed(const device_config *device, double frame_rate_scaler
/* control the audio squelch of the Simutrek modified players */
void simutrek_set_audio_squelch(const device_config *device, int state);
-/* set the callback */
-void simutrek_set_cmd_ack_callback(const device_config *device, void (*callback)(void));
-
/* ----- video interface ----- */
diff --git a/src/emu/machine/ldcore.c b/src/emu/machine/ldcore.c
index af72f34a781..cb9bda03622 100644
--- a/src/emu/machine/ldcore.c
+++ b/src/emu/machine/ldcore.c
@@ -23,7 +23,7 @@
DEBUGGING
***************************************************************************/
-#define LOG_POSITION(x) /*printf x*/
+#define LOG_SLIDER 0
@@ -42,6 +42,17 @@
TYPE DEFINITIONS
***************************************************************************/
+/* video frame data */
+typedef struct _frame_data frame_data;
+struct _frame_data
+{
+ bitmap_t * bitmap; /* cached bitmap */
+ bitmap_t * visbitmap; /* wrapper around bitmap with only visible lines */
+ UINT8 numfields; /* number of fields in this frame */
+ INT32 lastfield; /* last absolute field number */
+};
+
+
/* core-specific data */
struct _ldcore_data
{
@@ -51,11 +62,12 @@ struct _ldcore_data
/* disc parameters */
chd_file * disc; /* handle to the disc itself */
+ UINT8 * vbidata; /* pointer to precomputed VBI data */
int width; /* width of video */
int height; /* height of video */
UINT32 fps_times_1million; /* frame rate of video */
int samplerate; /* audio samplerate */
- UINT8 readpending; /* true if a read is pending */
+ chd_error readresult; /* result of the most recent read */
UINT32 chdtracks; /* number of tracks in the CHD */
av_codec_decompress_config avconfig; /* decompression configuration */
@@ -69,10 +81,7 @@ struct _ldcore_data
attotime sliderupdate; /* time of last slider update */
/* video data */
- bitmap_t * videoframe[3]; /* currently cached frames */
- bitmap_t * videovisframe[3]; /* wrapper around videoframe with only visible lines */
- UINT8 videofields[3]; /* number of fields in each frame */
- UINT32 videoframenum[3]; /* frame number contained in each frame */
+ frame_data frame[3]; /* circular list of frames */
UINT8 videoindex; /* index of the current video buffer */
bitmap_t videotarget; /* fake target bitmap for decompression */
bitmap_t * emptyframe; /* blank frame */
@@ -88,8 +97,6 @@ struct _ldcore_data
/* metadata */
vbi_metadata metadata[2]; /* metadata parsed from the stream, for each field */
- int last_frame; /* last seen frame number */
- int last_chapter; /* last seen chapter number */
/* I/O data */
UINT8 datain; /* current input data value */
@@ -122,9 +129,9 @@ struct _sound_token
***************************************************************************/
/* generic helper functions */
+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 fake_metadata(UINT32 track, UINT8 which, vbi_metadata *metadata);
//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);
@@ -377,17 +384,35 @@ static void vblank_state_changed(const device_config *screen, void *param, int v
/* update current track based on slider speed */
update_slider_pos(ldcore, curtime);
- /* on rising edge, call the player-specific VSYNC function */
+ /* on rising edge, process previously-read frame and inform the player */
if (vblank_state)
{
+ /* call the player's VSYNC callback */
if (ldcore->intf.vsync != NULL)
- (*ldcore->intf.vsync)(ld);
- return;
+ (*ldcore->intf.vsync)(ld, &ldcore->metadata[ldcore->fieldnum], ldcore->fieldnum, curtime);
+
+ /* set a timer to begin fetching the next frame just before the VBI data would be fetched */
+ timer_set(video_screen_get_time_until_pos(screen, 16*2, 0), ld, 0, perform_player_update);
}
+}
+
+
+/*-------------------------------------------------
+ vblank_state_changed - called on each state
+ change of the VBLANK signal
+-------------------------------------------------*/
+
+static TIMER_CALLBACK( perform_player_update )
+{
+ laserdisc_state *ld = ptr;
+ ldcore_data *ldcore = ld->core;
+ attotime curtime = timer_get_time();
- /* on falling edge, do the bulk of the processing */
/* wait for previous read and decode to finish */
- process_track_data(device);
+ process_track_data(ld->device);
+
+ /* update current track based on slider speed */
+ update_slider_pos(ldcore, curtime);
/* update the state */
if (ldcore->intf.update != NULL)
@@ -501,30 +526,31 @@ UINT8 laserdisc_line_r(const device_config *device, UINT8 line)
/*-------------------------------------------------
laserdisc_get_video - return the current
- video frame
+ video frame; return TRUE if valid or FALSE
+ if video off
-------------------------------------------------*/
-UINT32 laserdisc_get_video(const device_config *device, bitmap_t **bitmap)
+int laserdisc_get_video(const device_config *device, bitmap_t **bitmap)
{
laserdisc_state *ld = get_safe_token(device);
ldcore_data *ldcore = ld->core;
- int frameindex;
+ frame_data *frame;
/* determine the most recent live set of frames */
- frameindex = ldcore->videoindex;
- if (ldcore->videofields[frameindex] < 2)
- frameindex = (frameindex + ARRAY_LENGTH(ldcore->videofields) - 1) % ARRAY_LENGTH(ldcore->videofields);
+ frame = &ldcore->frame[ldcore->videoindex];
+ if (frame->numfields < 2)
+ frame = &ldcore->frame[(ldcore->videoindex + ARRAY_LENGTH(ldcore->frame) - 1) % ARRAY_LENGTH(ldcore->frame)];
/* if no video present, return the empty frame */
- if (ldcore->videosquelch || ldcore->videofields[frameindex] < 2)
+ if (ldcore->videosquelch || frame->numfields < 2)
{
*bitmap = ldcore->emptyframe;
- return 0;
+ return FALSE;
}
else
{
- *bitmap = ldcore->videovisframe[frameindex];
- return ldcore->videoframenum[frameindex];
+ *bitmap = frame->visbitmap;
+ return TRUE;
}
}
@@ -538,11 +564,7 @@ UINT32 laserdisc_get_field_code(const device_config *device, UINT8 code)
{
laserdisc_state *ld = get_safe_token(device);
ldcore_data *ldcore = ld->core;
- int field = ldcore->fieldnum ^ 1;
-
- /* if no video present, return */
- if (ldcore->videosquelch)
- return 0;
+ int field = ldcore->fieldnum;
switch (code)
{
@@ -557,6 +579,9 @@ UINT32 laserdisc_get_field_code(const device_config *device, UINT8 code)
case LASERDISC_CODE_LINE18:
return ldcore->metadata[field].line18;
+
+ case LASERDISC_CODE_LINE1718:
+ return ldcore->metadata[field].line1718;
}
return 0;
@@ -626,7 +651,8 @@ void ldcore_set_slider_speed(laserdisc_state *ld, INT32 tracks_per_vsync)
else
ldcore->attospertrack = -attotime_to_attoseconds(attotime_div(vsyncperiod, -tracks_per_vsync));
-printf("Slider speed = %d\n", tracks_per_vsync);
+ if (LOG_SLIDER)
+ printf("Slider speed = %d\n", tracks_per_vsync);
}
@@ -641,7 +667,8 @@ void ldcore_advance_slider(laserdisc_state *ld, INT32 numtracks)
update_slider_pos(ldcore, timer_get_time());
add_and_clamp_track(ldcore, numtracks);
-printf("Advance by %d\n", numtracks);
+ if (LOG_SLIDER)
+ printf("Advance by %d\n", numtracks);
}
@@ -861,21 +888,38 @@ static void read_track_data(laserdisc_state *ld)
ldcore_data *ldcore = ld->core;
UINT32 tracknum = ldcore->curtrack;
UINT32 fieldnum = ldcore->fieldnum;
- chd_error err;
+ frame_data *frame;
+ UINT32 vbiframe;
+ UINT32 readhunk;
+ INT32 chdtrack;
+
+ /* if the previous field had a frame number, and the new field immediately follows it,
+ force the new field to pair with the previous one */
+ frame = &ldcore->frame[ldcore->videoindex];
+ if ((ldcore->metadata[fieldnum ^ 1].line1718 & VBI_MASK_CAV_PICTURE) == VBI_CODE_CAV_PICTURE && (tracknum * 2 + fieldnum == frame->lastfield + 1))
+ frame->numfields = 1;
- /* if the previous field had the white flag, force the new field to pair with it */
- if (ldcore->metadata[fieldnum ^ 1].white)
- ldcore->videofields[ldcore->videoindex] = 1;
+ /* otherwise, keep the frames in sync with the absolute field numbers */
+ else if (frame->numfields == 2 && fieldnum != 0)
+ frame->numfields--;
/* if we already have both fields on the current videoindex, advance */
- if (ldcore->videofields[ldcore->videoindex] >= 2)
+ else if (frame->numfields >= 2)
{
- ldcore->videoindex = (ldcore->videoindex + 1) % ARRAY_LENGTH(ldcore->videofields);
- ldcore->videofields[ldcore->videoindex] = 0;
+ ldcore->videoindex = (ldcore->videoindex + 1) % ARRAY_LENGTH(ldcore->frame);
+ frame = &ldcore->frame[ldcore->videoindex];
+ frame->numfields = 0;
}
+
+ /* if we're squelched, reset the frame counter */
+ if (ldcore->videosquelch)
+ frame->numfields = 0;
+
+ /* remember the last field number */
+ frame->lastfield = tracknum * 2 + fieldnum;
/* set the video target information */
- ldcore->videotarget = *ldcore->videoframe[ldcore->videoindex];
+ ldcore->videotarget = *frame->bitmap;
ldcore->videotarget.base = BITMAP_ADDR16(&ldcore->videotarget, fieldnum, 0);
ldcore->videotarget.height /= 2;
ldcore->videotarget.rowpixels *= 2;
@@ -900,20 +944,23 @@ static void read_track_data(laserdisc_state *ld)
ldcore->avconfig.actsamples = &ldcore->audiocursamples;
ldcore->audiocursamples = 0;
+ /* compute the chdhunk number we are going to read */
+ chdtrack = tracknum - 1 - VIRTUAL_LEAD_IN_TRACKS;
+ chdtrack = MAX(chdtrack, 0);
+ chdtrack = MIN(chdtrack, ldcore->chdtracks - 1);
+ readhunk = chdtrack * 2 + fieldnum;
+
+ /* set the VBI data for the new field from our precomputed data */
+ if (ldcore->vbidata != NULL)
+ vbi_metadata_unpack(&ldcore->metadata[fieldnum], &vbiframe, &ldcore->vbidata[readhunk * VBI_PACKED_BYTES]);
+
/* configure the codec and then read */
- if (ldcore->disc != NULL)
+ ldcore->readresult = CHDERR_FILE_NOT_FOUND;
+ if (ldcore->disc != NULL && !ldcore->videosquelch)
{
- err = chd_codec_config(ldcore->disc, AV_CODEC_DECOMPRESS_CONFIG, &ldcore->avconfig);
- if (err == CHDERR_NONE)
- {
- INT32 chdtrack = tracknum - 1 - VIRTUAL_LEAD_IN_TRACKS;
-
- /* clamp the track */
- chdtrack = MAX(chdtrack, 0);
- chdtrack = MIN(chdtrack, ldcore->chdtracks - 1);
- err = chd_read_async(ldcore->disc, chdtrack * 2 + fieldnum, NULL);
- ldcore->readpending = TRUE;
- }
+ ldcore->readresult = chd_codec_config(ldcore->disc, AV_CODEC_DECOMPRESS_CONFIG, &ldcore->avconfig);
+ if (ldcore->readresult == CHDERR_NONE)
+ ldcore->readresult = chd_read_async(ldcore->disc, readhunk, NULL);
}
}
@@ -927,47 +974,23 @@ static void process_track_data(const device_config *device)
{
laserdisc_state *ld = get_safe_token(device);
ldcore_data *ldcore = ld->core;
- UINT32 tracknum = ldcore->curtrack;
- UINT32 fieldnum = ldcore->fieldnum;
- int frame, chapter;
- chd_error chderr;
/* wait for the async operation to complete */
- if (ldcore->disc != NULL && ldcore->readpending)
- {
- /* complete the async operation */
- chderr = chd_async_complete(ldcore->disc);
- if (chderr != CHDERR_NONE && chderr != CHDERR_NO_ASYNC_OPERATION)
- ldcore->avconfig.video = NULL;
- }
- ldcore->readpending = FALSE;
-
- /* parse the metadata */
- if (ldcore->disc != NULL && ldcore->avconfig.video != NULL)
- vbi_parse_all((const UINT16 *)ldcore->avconfig.video->base, ldcore->avconfig.video->rowpixels, ldcore->avconfig.video->width, 8, &ldcore->metadata[fieldnum]);
- else
- fake_metadata(tracknum, fieldnum, &ldcore->metadata[fieldnum]);
-// printf("Track %5d: Metadata = %d %08X %08X %08X %08X\n", tracknum, ldcore->metadata[fieldnum].white, ldcore->metadata[fieldnum].line16, ldcore->metadata[fieldnum].line17, ldcore->metadata[fieldnum].line18, ldcore->metadata[fieldnum].line1718);
-
- /* update the last seen frame and chapter */
- frame = frame_from_metadata(&ldcore->metadata[fieldnum]);
- if (frame >= 1 && frame < 99999)
- ldcore->last_frame = frame;
- chapter = chapter_from_metadata(&ldcore->metadata[fieldnum]);
- if (chapter != -1)
- ldcore->last_chapter = chapter;
-
+ if (ldcore->readresult == CHDERR_OPERATION_PENDING)
+ ldcore->readresult = chd_async_complete(ldcore->disc);
+
+ /* remove the video if we had an error */
+ if (ldcore->readresult != CHDERR_NONE)
+ ldcore->avconfig.video = NULL;
+
+ /* count the field as read if we are successful */
+ if (ldcore->avconfig.video != NULL)
+ ldcore->frame[ldcore->videoindex].numfields++;
+
/* render the display if present */
// if (ldcore->display && ldcore->avconfig.video != NULL)
// render_display((UINT16 *)ldcore->avconfig.video->base, ldcore->avconfig.video->rowpixels, ldcore->avconfig.video->width, ldcore->last_frame);
- /* update video field */
- if (ldcore->avconfig.video != NULL)
- {
- ldcore->videofields[ldcore->videoindex]++;
- ldcore->videoframenum[ldcore->videoindex] = ldcore->last_frame;
- }
-
/* pass the audio to the callback */
if (ldcore->config.audio != NULL)
(*ldcore->config.audio)(device, ldcore->samplerate, ldcore->audiocursamples, ldcore->avconfig.audio[0], ldcore->avconfig.audio[1]);
@@ -1000,29 +1023,6 @@ static void process_track_data(const device_config *device)
/*-------------------------------------------------
- fake_metadata - fake metadata when there's
- no disc present
--------------------------------------------------*/
-
-static void fake_metadata(UINT32 track, UINT8 which, vbi_metadata *metadata)
-{
- if (which == 0)
- {
- metadata->white = 1;
- metadata->line16 = 0;
- metadata->line17 = metadata->line18 = 0xf80000 |
- (((track / 10000) % 10) << 16) |
- (((track / 1000) % 10) << 12) |
- (((track / 100) % 10) << 8) |
- (((track / 10) % 10) << 4) |
- (((track / 1) % 10) << 0);
- }
- else
- memset(metadata, 0, sizeof(*metadata));
-}
-
-
-/*-------------------------------------------------
render_display - draw the frame display
-------------------------------------------------*/
@@ -1321,6 +1321,7 @@ VIDEO_UPDATE( laserdisc )
const device_config *laserdisc = device_list_first(screen->machine->config->devicelist, LASERDISC);
if (laserdisc != NULL)
{
+ const rectangle *visarea = video_screen_get_visible_area(screen);
laserdisc_state *ld = laserdisc->token;
ldcore_data *ldcore = ld->core;
bitmap_t *overbitmap = ldcore->overbitmap[ldcore->overindex];
@@ -1335,12 +1336,14 @@ VIDEO_UPDATE( laserdisc )
clip.min_x = 0;
clip.max_x = ldcore->config.overwidth - 1;
clip.min_y = cliprect->min_y * overbitmap->height / bitmap->height;
+ if (cliprect->min_y == visarea->min_y)
+ clip.min_y = MIN(clip.min_y, ldcore->config.overclip.min_y);
clip.max_y = (cliprect->max_y + 1) * overbitmap->height / bitmap->height - 1;
(*ldcore->config.overupdate)(screen, overbitmap, &clip);
}
/* if this is the last update, do the rendering */
- if (cliprect->max_y == video_screen_get_visible_area(screen)->max_y)
+ if (cliprect->max_y == visarea->max_y)
{
float x0, y0, x1, y1;
@@ -1443,8 +1446,10 @@ static void init_disc(const device_config *device)
ldcore->maxtrack = VIRTUAL_LEAD_IN_TRACKS + MAX_TOTAL_TRACKS + VIRTUAL_LEAD_OUT_TRACKS;
if (ldcore->disc != NULL)
{
+ UINT32 totalhunks = chd_get_header(ldcore->disc)->totalhunks;
int fps, fpsfrac, interlaced, channels;
char metadata[256];
+ UINT32 vbilength;
/* require the A/V codec */
if (chd_get_header(ldcore->disc)->compression != CHDCOMPRESSION_AV)
@@ -1466,7 +1471,13 @@ static void init_disc(const device_config *device)
fatalerror("Laserdisc video must be interlaced!");
/* determine the maximum track and allocate a frame buffer */
- ldcore->chdtracks = chd_get_header(ldcore->disc)->totalhunks / 2;
+ ldcore->chdtracks = totalhunks / 2;
+
+ /* allocate memory for the precomputed per-frame metadata */
+ ldcore->vbidata = auto_malloc(totalhunks * VBI_PACKED_BYTES);
+ err = chd_get_metadata(ldcore->disc, AV_LD_METADATA_TAG, 0, ldcore->vbidata, totalhunks * VBI_PACKED_BYTES, &vbilength, NULL);
+ if (err != CHDERR_NONE || vbilength != totalhunks * VBI_PACKED_BYTES)
+ fatalerror("Precomputed VBI metadata missing or incorrect size");
}
ldcore->maxtrack = MAX(ldcore->maxtrack, VIRTUAL_LEAD_IN_TRACKS + VIRTUAL_LEAD_OUT_TRACKS + ldcore->chdtracks);
}
@@ -1487,18 +1498,20 @@ static void init_video(const device_config *device)
video_screen_register_vblank_callback(ld->screen, vblank_state_changed, (void *)device);
/* allocate video frames */
- for (index = 0; index < ARRAY_LENGTH(ldcore->videofields); index++)
+ for (index = 0; index < ARRAY_LENGTH(ldcore->frame); index++)
{
+ frame_data *frame = &ldcore->frame[index];
+
/* first allocate a YUY16 bitmap at 2x the height */
- ldcore->videoframe[index] = auto_bitmap_alloc(ldcore->width, ldcore->height * 2, BITMAP_FORMAT_YUY16);
- fillbitmap_yuy16(ldcore->videoframe[index], 40, 109, 240);
+ frame->bitmap = auto_bitmap_alloc(ldcore->width, ldcore->height * 2, BITMAP_FORMAT_YUY16);
+ fillbitmap_yuy16(frame->bitmap, 40, 109, 240);
/* make a copy of the bitmap that clips out the VBI and horizontal blanking areas */
- ldcore->videovisframe[index] = auto_malloc(sizeof(*ldcore->videovisframe[index]));
- *ldcore->videovisframe[index] = *ldcore->videoframe[index];
- ldcore->videovisframe[index]->base = BITMAP_ADDR16(ldcore->videovisframe[index], 44, ldcore->videoframe[index]->width * 8 / 720);
- ldcore->videovisframe[index]->height -= 44;
- ldcore->videovisframe[index]->width -= 2 * ldcore->videoframe[index]->width * 8 / 720;
+ frame->visbitmap = auto_malloc(sizeof(*frame->visbitmap));
+ *frame->visbitmap = *frame->bitmap;
+ frame->visbitmap->base = BITMAP_ADDR16(frame->visbitmap, 44, frame->bitmap->width * 8 / 720);
+ frame->visbitmap->height -= 44;
+ frame->visbitmap->width -= 2 * frame->bitmap->width * 8 / 720;
}
/* allocate an empty frame of the same size */
@@ -1674,10 +1687,6 @@ static DEVICE_RESET( laserdisc )
ldcore->attospertrack = 0;
ldcore->sliderupdate = curtime;
- /* reset metadata */
- ldcore->last_frame = 0;
- ldcore->last_chapter = 0;
-
/* reset the I/O lines */
for (line = 0; line < LASERDISC_INPUT_LINES; line++)
ldcore->linein[line] = CLEAR_LINE;
diff --git a/src/emu/machine/ldcore.h b/src/emu/machine/ldcore.h
index 8b4c4d366de..8a8521e3947 100644
--- a/src/emu/machine/ldcore.h
+++ b/src/emu/machine/ldcore.h
@@ -134,8 +134,9 @@ struct _laserdisc_state
/* player-specific callbacks */
typedef void (*laserdisc_init_func)(laserdisc_state *ld);
-typedef void (*laserdisc_vsync_func)(laserdisc_state *ld);
+typedef void (*laserdisc_vsync_func)(laserdisc_state *ld, const vbi_metadata *vbi, int fieldnum, attotime curtime);
typedef INT32 (*laserdisc_update_func)(laserdisc_state *ld, const vbi_metadata *vbi, int fieldnum, attotime curtime);
+typedef void (*laserdisc_overlay_func)(laserdisc_state *ld, bitmap_t *bitmap);
typedef void (*laserdisc_w_func)(laserdisc_state *ld, UINT8 prev, UINT8 new);
typedef UINT8 (*laserdisc_r_func)(laserdisc_state *ld);
@@ -151,7 +152,8 @@ struct _ldplayer_interface
const machine_config_token *machine_config; /* pointer to machine configuration */
laserdisc_init_func init; /* initialization callback */
laserdisc_vsync_func vsync; /* vsync begin callback */
- laserdisc_update_func update; /* update callback (vblank end) */
+ laserdisc_update_func update; /* update callback (line 16) */
+ laserdisc_overlay_func overlay; /* overlay callback */
laserdisc_w_func writedata; /* parallel data write */
laserdisc_w_func writeline[LASERDISC_INPUT_LINES]; /* single line write */
laserdisc_r_func readdata; /* parallel data read */
@@ -234,18 +236,13 @@ INLINE int is_start_of_frame(const vbi_metadata *vbi)
INLINE int frame_from_metadata(const vbi_metadata *metadata)
{
- UINT32 data;
-
- if ((metadata->line1718 & 0xf80000) == 0xf80000)
- data = metadata->line1718 & 0x7ffff;
- else if (metadata->line1718 == 0x88ffff)
+ if ((metadata->line1718 & VBI_MASK_CAV_PICTURE) == VBI_CODE_CAV_PICTURE)
+ return VBI_CAV_PICTURE(metadata->line1718);
+ else if (metadata->line1718 == VBI_CODE_LEADIN)
return FRAME_LEAD_IN;
- else if (metadata->line1718 == 0x80eeee)
+ else if (metadata->line1718 == VBI_CODE_LEADOUT)
return FRAME_LEAD_OUT;
- else
- return FRAME_NOT_PRESENT;
-
- return (((data >> 16) & 0x0f) * 10000) + (((data >> 12) & 0x0f) * 1000) + (((data >> 8) & 0x0f) * 100) + (((data >> 4) & 0x0f) * 10) + (data & 0x0f);
+ return FRAME_NOT_PRESENT;
}
@@ -257,18 +254,13 @@ INLINE int frame_from_metadata(const vbi_metadata *metadata)
INLINE int chapter_from_metadata(const vbi_metadata *metadata)
{
- UINT32 data;
-
if ((metadata->line1718 & 0xf00fff) == 0x800ddd)
- data = metadata->line1718 & 0x7f000;
- else if (metadata->line1718 == 0x88ffff)
+ return VBI_CHAPTER(metadata->line1718);
+ else if (metadata->line1718 == VBI_CODE_LEADIN)
return CHAPTER_LEAD_IN;
- else if (metadata->line1718 == 0x80eeee)
+ else if (metadata->line1718 == VBI_CODE_LEADOUT)
return CHAPTER_LEAD_OUT;
- else
- return CHAPTER_NOT_PRESENT;
-
- return (((data >> 16) & 0x0f) * 10) + ((data >> 12) & 0x0f);
+ return CHAPTER_NOT_PRESENT;
}
diff --git a/src/emu/machine/ldpr8210.c b/src/emu/machine/ldpr8210.c
index a9c890a77b2..b4f6bb97cfa 100644
--- a/src/emu/machine/ldpr8210.c
+++ b/src/emu/machine/ldpr8210.c
@@ -7,6 +7,16 @@
Copyright Nicola Salmoria and the MAME Team.
Visit http://mamedev.org for licensing and usage restrictions.
+**************************************************************************
+
+ 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)
+ * determine actual slow/fast speeds
+
*************************************************************************/
#include "ldcore.h"
@@ -18,10 +28,9 @@
DEBUGGING
***************************************************************************/
-#define EMULATE_PR8210_ROM 0
-
-#define PRINTF_COMMANDS 1
-#define CMDPRINTF(x) do { if (PRINTF_COMMANDS) mame_printf_debug x; } while (0)
+#define LOG_VBLANK_VBI 0
+#define LOG_SERIAL 0
+#define LOG_SIMUTREK 0
@@ -29,23 +38,17 @@
CONSTANTS
***************************************************************************/
-/* Player-specific states */
-enum
-{
- LDSTATE_STEPPING_BY_PARAMETER = LDSTATE_OTHER,
- LDSTATE_STEPPING_BY_PARAMETER_PAUSED
-};
-
/* Pioneer PR-8210 specific information */
-#define PR8210_SCAN_SPEED (2000 / 30) /* 2000 frames/second */
-#define PR8210_SCAN_DURATION (10) /* scan for 10 vsyncs each time */
-#define PR8210_SLOW_SPEED (5) /* 1/5x normal speed */
-#define PR8210_FAST_SPEED (3) /* 3x normal speed */
-#define PR8210_JUMP_REV_SPEED (15) /* 15x normal speed */
-#define PR8210_SEEK_FAST_SPEED (1000) /* 1000x normal speed */
+#define PR8210_SCAN_SPEED (2000 / 30) /* 2000 frames/second */
+#define PR8210_SEEK_FAST_SPEED (4000 / 30) /* 4000 frames/second */
-/* Us vs. Them requires at least this much "non-video" time in order to work */
-#define PR8210_MINIMUM_SEEK_TIME ATTOTIME_IN_MSEC(150)
+/* 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)
@@ -53,35 +56,55 @@ enum
TYPE DEFINITIONS
***************************************************************************/
+/* PIA data */
+typedef struct _pioneer_pia pioneer_pia;
+struct _pioneer_pia
+{
+ UINT8 frame[7]; /* (20-26) 7 characters for the chapter/frame */
+ UINT8 text[15]; /* (22-30) 15 characters for the display */
+ UINT8 control; /* (40) control lines */
+ UINT8 latchdisplay; /* flag: set if the display was latched */
+ UINT8 portb; /* (60) port B value (LEDs) */
+ UINT8 display; /* (80) display enable */
+ UINT8 porta; /* (A0) port A value (from serial decoder) */
+ UINT8 vbi1; /* (C0) VBI decoding state 1 */
+ UINT8 vbi2; /* (E0) VBI decoding state 2 */
+};
+
+
+/* Simutrek-specific data */
+typedef struct _simutrek_data simutrek_data;
+struct _simutrek_data
+{
+ int cpunum; /* CPU index of the 8748 */
+ UINT8 audio_squelch; /* audio squelch value */
+ UINT8 data; /* parallel data for simutrek */
+ UINT8 data_ready; /* ready flag for simutrek data */
+ UINT8 port2; /* 8748 port 2 state */
+ UINT8 jumphack;
+};
+
+
/* 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 */
-
/* serial/command interface processing */
- UINT8 lastcommand; /* last command byte received */
- UINT8 seekstate; /* state of the seek command */
+ UINT8 lastcommand; /* last command seen */
UINT16 accumulator; /* bit accumulator */
+ attotime lastcommandtime; /* time of the last command */
attotime lastbittime; /* time of last bit received */
attotime firstbittime; /* time of first bit in command */
- /* Simutrek-specific data */
- UINT8 cmdcnt; /* counter for multi-byte command */
- UINT8 cmdbytes[3]; /* storage for multi-byte command */
- void (*cmd_ack_callback)(void); /* callback to clear game command write flag */
-
/* low-level emulation data */
- int cpunum;
- UINT8 pia[0x100];
- UINT8 vsync;
- UINT8 porta;
- UINT8 portb;
- UINT8 pia_porta;
- UINT8 pia_portb;
+ int cpunum; /* CPU index of the 8049 */
+ attotime slowtrg; /* time of the last SLOW TRG */
+ pioneer_pia pia; /* PIA state */
+ UINT8 vsync; /* live VSYNC state */
+ UINT8 port1; /* 8049 port 1 state */
+ UINT8 port2; /* 8049 port 2 state */
+
+ /* Simutrek-specific data */
+ simutrek_data simutrek; /* Simutrek-specific data */
};
@@ -91,41 +114,106 @@ struct _ldplayer_data
***************************************************************************/
static void pr8210_init(laserdisc_state *ld);
-static void pr8210_soft_reset(laserdisc_state *ld);
-static void pr8210_update_squelch(laserdisc_state *ld);
-static int pr8210_switch_state(laserdisc_state *ld, UINT8 newstate, INT32 stateparam);
-static INT32 pr8210_hle_update(laserdisc_state *ld, const vbi_metadata *vbi, int fieldnum, attotime curtime);
-#if (EMULATE_PR8210_ROM)
-static void pr8210_vsync(laserdisc_state *ld);
+static void pr8210_vsync(laserdisc_state *ld, const vbi_metadata *vbi, int fieldnum, attotime curtime);
static INT32 pr8210_update(laserdisc_state *ld, const vbi_metadata *vbi, int fieldnum, attotime curtime);
-#else
-static void pr8210_hle_command(laserdisc_state *ld);
-#endif
+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 );
+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 simutrek_init(laserdisc_state *ld);
+static void simutrek_vsync(laserdisc_state *ld, const vbi_metadata *vbi, int fieldnum, attotime curtime);
+static INT32 simutrek_update(laserdisc_state *ld, const vbi_metadata *vbi, int fieldnum, attotime curtime);
+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 );
+static READ8_HANDLER( simutrek_t0_r );
+
+
+
+/***************************************************************************
+ INLINE FUNCTIONS
+***************************************************************************/
+
+/*-------------------------------------------------
+ find_pr8210 - find our device; assumes there
+ is only one
+-------------------------------------------------*/
+
+INLINE laserdisc_state *find_pr8210(running_machine *machine)
+{
+ return ldcore_get_safe_token(device_list_first(machine->config->devicelist, LASERDISC));
+}
+
+
+/*-------------------------------------------------
+ update_video_squelch - update the state of
+ the video squelch
+-------------------------------------------------*/
+
+INLINE void update_video_squelch(laserdisc_state *ld)
+{
+ ldplayer_data *player = ld->player;
+ ldcore_set_video_squelch(ld, (player->port1 & 0x20) != 0);
+}
+
+
+/*-------------------------------------------------
+ update_audio_squelch - update the state of
+ the audio squelch
+-------------------------------------------------*/
+
+INLINE void update_audio_squelch(laserdisc_state *ld)
+{
+ ldplayer_data *player = ld->player;
+ if (player->simutrek.cpunum == -1)
+ ldcore_set_audio_squelch(ld, (player->port1 & 0x40) || !(player->pia.portb & 0x01), (player->port1 & 0x40) || !(player->pia.portb & 0x02));
+ else
+ ldcore_set_audio_squelch(ld, player->simutrek.audio_squelch, player->simutrek.audio_squelch);
+}
/***************************************************************************
- ROM AND MACHINE INTERFACES
+ PR-8210 ROM AND MACHINE INTERFACES
***************************************************************************/
-MACHINE_DRIVER_EXTERN( pr8210 );
+static ADDRESS_MAP_START( pr8210_portmap, ADDRESS_SPACE_IO, 8 )
+ AM_RANGE(0x00, 0xff) AM_READWRITE(pr8210_pia_r, pr8210_pia_w)
+ AM_RANGE(MCS48_PORT_BUS, MCS48_PORT_BUS) AM_READ(pr8210_bus_r)
+ AM_RANGE(MCS48_PORT_P1, MCS48_PORT_P1) AM_WRITE(pr8210_port1_w)
+ AM_RANGE(MCS48_PORT_P2, MCS48_PORT_P2) AM_WRITE(pr8210_port2_w)
+ AM_RANGE(MCS48_PORT_T0, MCS48_PORT_T0) AM_READ(pr8210_t0_r)
+ AM_RANGE(MCS48_PORT_T1, MCS48_PORT_T1) AM_READ(pr8210_t1_r)
+ADDRESS_MAP_END
+
+
+static MACHINE_DRIVER_START( pr8210 )
+ MDRV_CPU_ADD("pr8210", I8049, XTAL_4_41MHz)
+ MDRV_CPU_IO_MAP(pr8210_portmap,0)
+MACHINE_DRIVER_END
+
-#if EMULATE_PR8210_ROM
ROM_START( pr8210 )
ROM_REGION( 0x800, "pr8210", ROMREGION_LOADBYNAME )
ROM_LOAD( "pr-8210_mcu_ud6005a.bin", 0x000, 0x800, CRC(120fa83b) SHA1(b514326ca1f52d6d89056868f9d17eabd4e3f31d) )
ROM_END
-#endif
/***************************************************************************
- INTERFACES
+ PR-8210 PLAYER INTERFACE
***************************************************************************/
const ldplayer_interface pr8210_interface =
@@ -133,19 +221,12 @@ const ldplayer_interface pr8210_interface =
LASERDISC_TYPE_PIONEER_PR8210, /* type of the player */
sizeof(ldplayer_data), /* size of the state */
"Pioneer PR-8210", /* name of the player */
-#if EMULATE_PR8210_ROM
rom_pr8210, /* pointer to ROM region information */
machine_config_pr8210, /* pointer to machine configuration */
pr8210_init, /* initialization callback */
pr8210_vsync, /* vsync callback */
pr8210_update, /* update callback */
-#else
- NULL, /* pointer to ROM region information */
- NULL, /* pointer to machine configuration */
- pr8210_init, /* initialization callback */
- NULL, /* vsync callback */
- pr8210_hle_update, /* update callback */
-#endif
+ pr8210_overlay, /* overlay callback */
NULL, /* parallel data write */
{ /* single line write: */
NULL, /* LASERDISC_LINE_ENTER */
@@ -161,62 +242,6 @@ const ldplayer_interface pr8210_interface =
};
-const ldplayer_interface simutrek_interface =
-{
- LASERDISC_TYPE_SIMUTREK_SPECIAL, /* type of the player */
- sizeof(ldplayer_data), /* size of the state */
- "Simutrek Modified PR-8210", /* name of the player */
- NULL, /* pointer to ROM region information */
- NULL, /* pointer to machine configuration */
- simutrek_init, /* initialization callback */
- NULL, /* vsync callback */
- pr8210_hle_update, /* update callback */
- simutrek_data_w, /* parallel data write */
- { /* single line write: */
- NULL, /* LASERDISC_LINE_ENTER */
- NULL /* LASERDISC_LINE_CONTROL */
- },
- NULL, /* parallel data read */
- { /* single line read: */
- NULL, /* LASERDISC_LINE_READY */
- simutrek_status_r, /* LASERDISC_LINE_STATUS */
- NULL, /* LASERDISC_LINE_COMMAND */
- NULL, /* LASERDISC_LINE_DATA_AVAIL */
- }
-};
-
-
-
-/***************************************************************************
- INLINE FUNCTIONS
-***************************************************************************/
-
-/*-------------------------------------------------
- requires_state_save - returns TRUE if the
- given state will return to the previous
- state when done
--------------------------------------------------*/
-
-INLINE int requires_state_save(UINT8 state)
-{
- return (state == LDSTATE_SCANNING);
-}
-
-
-/*-------------------------------------------------
- requires_state_save - returns TRUE if the
- given state will return to the previous
- state when done
--------------------------------------------------*/
-
-INLINE void update_audio_squelch(laserdisc_state *ld)
-{
- ldplayer_data *player = ld->player;
- ldcore_set_audio_squelch(ld, (player->porta & 0x40) || !(player->pia_portb & 0x01), (player->porta & 0x40) || !(player->pia_portb & 0x02));
-}
-
-
-
/***************************************************************************
PIONEER PR-8210 IMPLEMENTATION
@@ -230,227 +255,77 @@ INLINE void update_audio_squelch(laserdisc_state *ld)
static void pr8210_init(laserdisc_state *ld)
{
astring *tempstring = astring_alloc();
+ attotime curtime = timer_get_time();
+ ldplayer_data *player = ld->player;
/* find our CPU */
astring_printf(tempstring, "%s:%s", ld->device->tag, "pr8210");
- ld->player->cpunum = mame_find_cpu_index(ld->device->machine, astring_c(tempstring));
+ player->cpunum = mame_find_cpu_index(ld->device->machine, astring_c(tempstring));
astring_free(tempstring);
/* do a soft reset */
- pr8210_soft_reset(ld);
-}
-
-
-/*-------------------------------------------------
- pr8210_soft_reset - Pioneer PR-8210-specific
- soft reset
--------------------------------------------------*/
-
-static void pr8210_soft_reset(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->lastcommand = 0;
- player->seekstate = 0;
player->accumulator = 0;
+ player->lastcommandtime = curtime;
player->firstbittime = curtime;
player->lastbittime = curtime;
+ player->slowtrg = curtime;
- pr8210_switch_state(ld, LDSTATE_PARKED, 0);
+ /* we don't have the Simutrek player overrides */
+ player->simutrek.cpunum = -1;
+ player->simutrek.audio_squelch = FALSE;
}
/*-------------------------------------------------
- pr8210_update_squelch - update the squelch
- settings based on the current state
+ pr8210_vsync - VSYNC callback, called at the
+ start of the blanking period
-------------------------------------------------*/
-static void pr8210_update_squelch(laserdisc_state *ld)
+static void pr8210_vsync(laserdisc_state *ld, const vbi_metadata *vbi, int fieldnum, attotime curtime)
{
ldplayer_data *player = ld->player;
- switch (ld->state.state)
+ /* logging */
+ if (LOG_VBLANK_VBI)
{
- /* 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:
- ldcore_set_audio_squelch(ld, TRUE, TRUE);
- ldcore_set_video_squelch(ld, FALSE);
- break;
-
- /* video off, audio off */
- case LDSTATE_NONE:
- case LDSTATE_EJECTED:
- case LDSTATE_EJECTING:
- 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;
-
- /* Simutrek: stepping by parameter with explicit audio squelch controls */
- case LDSTATE_STEPPING_BY_PARAMETER:
- case LDSTATE_STEPPING_BY_PARAMETER_PAUSED:
- ldcore_set_video_squelch(ld, FALSE);
- break;
- }
-}
-
-
-/*-------------------------------------------------
- pr8210_switch_state - attempt to switch states
- if appropriate, and ensure the squelch values
- are correct
--------------------------------------------------*/
-
-static int pr8210_switch_state(laserdisc_state *ld, UINT8 newstate, INT32 parameter)
-{
- attotime curtime = timer_get_time();
-
- /* if this is the same state, ignore */
- if (ld->state.state == newstate)
- return TRUE;
-
- /* 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;
-
- /* set up appropriate squelch and timing */
- ld->state.state = newstate;
- ld->state.substate = 0;
- ld->state.param = parameter;
- ld->state.endtime = curtime;
- pr8210_update_squelch(ld);
-
- /* 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;
-
- case LDSTATE_SPINUP:
- ld->state.endtime = attotime_add(curtime, GENERIC_SPINUP_TIME);
- break;
-
- case LDSTATE_SEEKING:
- ld->state.endtime = attotime_add(curtime, PR8210_MINIMUM_SEEK_TIME);
- break;
+ if ((vbi->line1718 & VBI_MASK_CAV_PICTURE) == VBI_CODE_CAV_PICTURE)
+ printf("%3d:VSYNC(%d,%05d)\n", video_screen_get_vpos(ld->screen), fieldnum, VBI_CAV_PICTURE(vbi->line1718));
+ else
+ printf("%3d:VSYNC(%d)\n", video_screen_get_vpos(ld->screen), fieldnum);
}
- return TRUE;
-}
-
-/*-------------------------------------------------
- pr8210_vsync - Start of VSYNC callback
--------------------------------------------------*/
-
-#if (EMULATE_PR8210_ROM)
-static TIMER_CALLBACK( vsync_off )
-{
- ldplayer_data *player = ptr;
- player->vsync = FALSE;
-}
-
-static void pr8210_vsync(laserdisc_state *ld)
-{
- ldplayer_data *player = ld->player;
+ /* 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), player, 0, vsync_off);
+ 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);
}
-#endif
/*-------------------------------------------------
- pr8210_update - Pioneer PR-8210-specific
- update callback when using a ROM
+ pr8210_update - update callback, called on
+ the first visible line of the frame
-------------------------------------------------*/
-#if (EMULATE_PR8210_ROM)
-
static INT32 pr8210_update(laserdisc_state *ld, const vbi_metadata *vbi, int fieldnum, attotime curtime)
{
ldplayer_data *player = ld->player;
- UINT8 focus_on = !(player->porta & 0x08);
- UINT8 laser_on = !(player->portb & 0x01);
- UINT8 spdl_on = !(player->porta & 0x10);
- INT32 advanceby = 0;
- int frame, chapter;
-
- /* update PIA registers based on vbi code */
- frame = frame_from_metadata(vbi);
- chapter = chapter_from_metadata(vbi);
- if (focus_on && laser_on && !(player->pia[0x80] & 1))
- {
- if (frame == FRAME_LEAD_IN)
- player->pia[0xc0] = 0x10; /* or 0x12 */
- else if (frame == FRAME_LEAD_OUT)
- player->pia[0xc0] = 0x11;
- else if (frame != FRAME_NOT_PRESENT)
- {
- player->pia[0xc0] = 0x02; /* bit 0x02 must be set for forward scanning to work */
- player->pia[0x22] = 0xf0 | ((frame / 10000) % 10);
- player->pia[0x23] = 0xf0 | ((frame / 1000) % 10);
- player->pia[0x24] = 0xf0 | ((frame / 100) % 10);
- player->pia[0x25] = 0xf0 | ((frame / 10) % 10);
- player->pia[0x26] = 0xf0 | ((frame / 1) % 10);
-printf("Frame:%05d\n", frame);
- }
- else if (chapter != CHAPTER_NOT_PRESENT)
- {
- player->pia[0xc0] = 0x13;
- player->pia[0x20] = 0xf0 | ((chapter / 10) % 10);
- player->pia[0x21] = 0xf0 | ((chapter / 1) % 10);
- }
-// else
-// player->pia[0xc0] = 0x00;
- }
- player->pia[0xc0] |= 12;//4;//fieldnum << 2;
-
- if (spdl_on)
- advanceby = fieldnum;
+ UINT8 spdl_on = !(player->port1 & 0x10);
+
+ /* logging */
+ if (LOG_VBLANK_VBI)
+ printf("%3d:Update(%d)\n", video_screen_get_vpos(ld->screen), fieldnum);
/* update overlay */
- if ((player->pia[0x80] & 1) || player->framedisplay)
+ if (player->pia.display || player->pia.latchdisplay)
{
char buffer[16] = { 0 };
int i;
for (i = 0; i < 15; i++)
{
- UINT8 c = player->pia[0x22 + i];
+ UINT8 c = player->pia.text[i];
if (c >= 0xf0 && c <= 0xf9)
c = '0' + (c - 0xf0);
else if (c < 0x20 || c > 0x7f)
@@ -459,251 +334,27 @@ printf("Frame:%05d\n", frame);
}
popmessage("%s", buffer);
}
- player->framedisplay = 0;
+ else
+ popmessage(NULL);
+ player->pia.latchdisplay = 0;
-if (advanceby != 0)
- printf("Advancing by %d\n", advanceby);
- return advanceby;
+ /* if the spindle is on, we advance by 1 track after completing field #1 */
+ return (spdl_on) ? fieldnum : 0;
}
-#endif
/*-------------------------------------------------
- pr8210_hle_update - Pioneer PR-8210-specific
- update callback when using HLE
+ pr8210_overlay - overlay callback, called
+ during frame processing in update to overlay
+ player data
-------------------------------------------------*/
-static INT32 pr8210_hle_update(laserdisc_state *ld, const vbi_metadata *vbi, int fieldnum, attotime curtime)
+void pr8210_overlay(laserdisc_state *ld, bitmap_t *bitmap)
{
- ldplayer_state newstate;
- INT32 advanceby = 0;
- int frame;
-
- /* handle things based on the state */
- switch (ld->state.state)
- {
- 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:
- /* generic behaviors are appropriate for all of these commands */
- advanceby = ldcore_generic_update(ld, vbi, fieldnum, curtime, &newstate);
- pr8210_switch_state(ld, newstate.state, newstate.param);
- break;
-
- case LDSTATE_SEEKING:
- /* if we're in the final state, look for a matching frame and pause there */
- frame = frame_from_metadata(vbi);
- if (ld->state.substate == 3 && is_start_of_frame(vbi) && frame == ld->state.param)
- pr8210_switch_state(ld, LDSTATE_PAUSED, fieldnum);
-
- /* otherwise, if we got frame data from the VBI, update our seeking logic */
- else if (ld->state.substate < 3 && frame != FRAME_NOT_PRESENT)
- {
- static const INT32 seekspeed[] = { -PR8210_SEEK_FAST_SPEED, PR8210_SEEK_FAST_SPEED, -PR8210_JUMP_REV_SPEED };
- INT32 curseekspeed = seekspeed[ld->state.substate];
- INT32 delta = (ld->state.param - 1) - frame;
-
- if ((curseekspeed < 0 && delta <= 0) || (curseekspeed > 0 && delta >= 0))
- advanceby = curseekspeed;
- else
- ld->state.substate++;
- }
-
- /* otherwise, keep advancing until we know what's up */
- else if (fieldnum == 1)
- advanceby = 1;
- break;
-
- case LDSTATE_STEPPING_BY_PARAMETER:
- /* advance after the second field of each frame */
- if (fieldnum == 1)
- {
- /* note that we switch directly to PAUSED as we are not looking for frames */
- advanceby = ld->state.param;
- pr8210_switch_state(ld, LDSTATE_STEPPING_BY_PARAMETER_PAUSED, 0);
- }
- break;
-
- case LDSTATE_STEPPING_BY_PARAMETER_PAUSED:
- /* generic pause behavior */
- ld->state.state = LDSTATE_PAUSED;
- advanceby = ldcore_generic_update(ld, vbi, fieldnum, curtime, &newstate);
- if (newstate.state != LDSTATE_PAUSED)
- pr8210_switch_state(ld, newstate.state, newstate.param);
- else
- ld->state.state = LDSTATE_STEPPING_BY_PARAMETER_PAUSED;
- break;
- }
-
- return advanceby;
+// ldplayer_data *player = ld->player;
}
-
-/*-------------------------------------------------
- pr8210_hle_command - Pioneer PR-8210-specific
- command processing
--------------------------------------------------*/
-
-#if (!EMULATE_PR8210_ROM)
-static void pr8210_hle_command(laserdisc_state *ld)
-{
- ldplayer_data *player = ld->player;
- UINT8 cmd = player->lastcommand;
-
- switch (cmd)
- {
- case 0x00: CMDPRINTF(("pr8210: EOC\n"));
- /* EOC marker - can be safely ignored */
- break;
-
- case 0x01: CMDPRINTF(("pr8210: 0\n"));
- player->parameter = (player->parameter == -1) ? 0 : (player->parameter * 10 + 0);
- break;
-
- case 0x02: CMDPRINTF(("pr8210: Slow reverse\n"));
- pr8210_switch_state(ld, LDSTATE_PLAYING_SLOW_REVERSE, PR8210_SLOW_SPEED);
- break;
-
- case 0x03: CMDPRINTF(("pr8210: 8\n"));
- player->parameter = (player->parameter == -1) ? 8 : (player->parameter * 10 + 8);
- break;
-
- case 0x04: CMDPRINTF(("pr8210: Step forward\n"));
- pr8210_switch_state(ld, LDSTATE_STEPPING_FORWARD, 0);
- break;
-
- case 0x05: CMDPRINTF(("pr8210: 4\n"));
- player->parameter = (player->parameter == -1) ? 4 : (player->parameter * 10 + 4);
- break;
-
- case 0x06 : CMDPRINTF(("pr8210: Chapter\n"));
- /* chapter -- not implemented */
- break;
-
- case 0x08: CMDPRINTF(("pr8210: Scan forward\n"));
- if (ld->state.state != LDSTATE_SCANNING)
- pr8210_switch_state(ld, LDSTATE_SCANNING, SCANNING_PARAM(PR8210_SCAN_SPEED, PR8210_SCAN_DURATION));
- else
- ld->state.substate = 0;
- break;
-
- case 0x09: CMDPRINTF(("pr8210: 2\n"));
- player->parameter = (player->parameter == -1) ? 2 : (player->parameter * 10 + 2);
- break;
-
- case 0x0a: CMDPRINTF(("pr8210: Pause\n"));
- pr8210_switch_state(ld, LDSTATE_PAUSING, 0);
- break;
-
- case 0x0b : CMDPRINTF(("pr8210: Frame\n"));
- /* frame -- not implemented */
- break;
-
- case 0x0c: CMDPRINTF(("pr8210: Fast reverse\n"));
- pr8210_switch_state(ld, LDSTATE_PLAYING_FAST_REVERSE, PR8210_FAST_SPEED);
- break;
-
- case 0x0d: CMDPRINTF(("pr8210: 6\n"));
- player->parameter = (player->parameter == -1) ? 6 : (player->parameter * 10 + 6);
- break;
-
- case 0x0e: CMDPRINTF(("pr8210: Ch1 toggle\n"));
- player->audio1disable = !player->audio1disable;
- pr8210_update_squelch(ld);
- break;
-
- case 0x10: CMDPRINTF(("pr8210: Fast forward\n"));
- pr8210_switch_state(ld, LDSTATE_PLAYING_FAST_FORWARD, PR8210_FAST_SPEED);
- break;
-
- case 0x11: CMDPRINTF(("pr8210: 1\n"));
- player->parameter = (player->parameter == -1) ? 1 : (player->parameter * 10 + 1);
- break;
-
- case 0x12: CMDPRINTF(("pr8210: Step reverse\n"));
- pr8210_switch_state(ld, LDSTATE_STEPPING_REVERSE, 0);
- break;
-
- case 0x13: CMDPRINTF(("pr8210: 9\n"));
- player->parameter = (player->parameter == -1) ? 9 : (player->parameter * 10 + 9);
- break;
-
- case 0x14: CMDPRINTF(("pr8210: Play\n"));
- if (ld->state.state == LDSTATE_EJECTED)
- pr8210_switch_state(ld, LDSTATE_LOADING, 0);
- else if (ld->state.state == LDSTATE_PARKED)
- pr8210_switch_state(ld, LDSTATE_SPINUP, 0);
- else
- pr8210_switch_state(ld, LDSTATE_PLAYING, 0);
- break;
-
- case 0x15: CMDPRINTF(("pr8210: 5\n"));
- player->parameter = (player->parameter == -1) ? 5 : (player->parameter * 10 + 5);
- break;
-
- case 0x16: CMDPRINTF(("pr8210: Ch2 toggle\n"));
- player->audio2disable = !player->audio2disable;
- pr8210_update_squelch(ld);
- break;
-
- case 0x18: CMDPRINTF(("pr8210: Slow forward\n"));
- pr8210_switch_state(ld, LDSTATE_PLAYING_SLOW_FORWARD, PR8210_SLOW_SPEED);
- break;
-
- case 0x19: CMDPRINTF(("pr8210: 3\n"));
- player->parameter = (player->parameter == -1) ? 3 : (player->parameter * 10 + 3);
- break;
-
- case 0x1a: CMDPRINTF(("pr8210: Seek\n"));
- if (player->seekstate)
- {
- /* we're ready to seek */
- CMDPRINTF(("pr8210: Seeking to frame %d\n", player->parameter));
- pr8210_switch_state(ld, LDSTATE_SEEKING, player->parameter);
- }
- else
- {
- /* waiting for digits indicating position */
- player->parameter = 0;
- }
- player->seekstate ^= 1;
- break;
-
- case 0x1c: CMDPRINTF(("pr8210: Scan reverse\n"));
- if (ld->state.state != LDSTATE_SCANNING)
- pr8210_switch_state(ld, LDSTATE_SCANNING, SCANNING_PARAM(-PR8210_SCAN_SPEED, PR8210_SCAN_DURATION));
- else
- ld->state.substate = 0;
- break;
-
- case 0x1d: CMDPRINTF(("pr8210: 7\n"));
- player->parameter = (player->parameter == -1) ? 7 : (player->parameter * 10 + 7);
- break;
-
- case 0x1e: CMDPRINTF(("pr8210: Reject\n"));
- pr8210_switch_state(ld, LDSTATE_EJECTING, 0);
- break;
-
- default: CMDPRINTF(("pr8210: Unknown command %02X\n", cmd));
- break;
- }
-}
-#endif
-
-
/*-------------------------------------------------
pr8210_control_w - write callback when the
CONTROL line is toggled
@@ -713,19 +364,21 @@ static void pr8210_control_w(laserdisc_state *ld, UINT8 prev, UINT8 data)
{
ldplayer_data *player = ld->player;
- if (data == ASSERT_LINE)
+ /* handle rising edge */
+ if (prev != ASSERT_LINE && data == ASSERT_LINE)
{
attotime curtime = timer_get_time();
attotime delta;
int longpulse;
- /* if we timed out, reset the accumulator */
+ /* if we timed out since the first bit, reset the accumulator */
delta = attotime_sub(curtime, player->firstbittime);
- if (delta.attoseconds > ATTOTIME_IN_USEC(25320).attoseconds)
+ if (attotime_compare(delta, PR8210_MAX_WORD_TIME) > 0)
{
player->firstbittime = curtime;
player->accumulator = 0x5555;
-// printf("Reset accumulator\n");
+ if (LOG_SERIAL)
+ printf("Reset accumulator\n");
}
/* get the time difference from the last assert */
@@ -734,290 +387,245 @@ 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 = (delta.attoseconds < ATTOTIME_IN_USEC(1500).attoseconds) ? 0 : 1;
+ longpulse = (attotime_compare(delta, PR8210_MIDPOINT_TIME) < 0) ? 0 : 1;
player->accumulator = (player->accumulator << 1) | longpulse;
-#if 0
+ /* log the deltas for debugging */
+ if (LOG_SERIAL)
{
int usecdiff = (int)(delta.attoseconds / ATTOSECONDS_IN_USEC(1));
printf("bitdelta = %5d (%d) - accum = %04X\n", usecdiff, longpulse, player->accumulator);
}
-#endif
/* if we have a complete command, signal it */
/* a complete command is 0,0,1 followed by 5 bits, followed by 0,0 */
if ((player->accumulator & 0x383) == 0x80)
{
UINT8 newcommand = (player->accumulator >> 2) & 0x1f;
+ attotime rejectuntil;
+
+ /* data is stored to the PIA in bit-reverse order */
+ player->pia.porta = BITSWAP8(newcommand, 0,1,2,3,4,5,6,7);
+
+ /* 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);
+ player->lastcommandtime = curtime;
+ if (player->pia.porta == player->lastcommand && attotime_compare(curtime, rejectuntil) < 0)
+ player->pia.porta = 0x00;
+ else
+ player->lastcommand = player->pia.porta;
-//printf("New command = %02X (last=%02X)\n", newcommand, player->lastcommand);
-
-#if EMULATE_PR8210_ROM
- printf("Command = %02X\n", newcommand);
-// player->pia_porta = BITSWAP8(newcommand, 4,3,2,1,0,5,6,7);
- player->pia_porta = BITSWAP8(newcommand, 0,1,2,3,4,5,6,7);
-#else
- /* if we got a double command, act on it */
- if (newcommand == player->lastcommand)
+ /* log the command and wait for a keypress */
+ if (LOG_SERIAL)
{
- pr8210_hle_command(ld);
- player->lastcommand = 0;
+ printf("--- Command = %02X\n", player->pia.porta >> 3);
+ while (input_code_pressed(KEYCODE_ENTER)) ;
+ while (!input_code_pressed(KEYCODE_ENTER)) ;
}
- else
- player->lastcommand = newcommand;
-#endif
+
+ /* reset the first bit time so that the accumulator clears on the next write */
+ player->firstbittime = attotime_sub(curtime, PR8210_MAX_WORD_TIME);
}
}
}
-
-/***************************************************************************
- SIMUTREK MODIFIED PR-8210 PLAYER IMPLEMENTATION
-***************************************************************************/
-
-/*-------------------------------------------------
-
- Command Set:
-
- FX XX XX : Seek to frame XXXXX
- 01-19 : Skip forward 1-19 frames
- 99-81 : Skip back 1-19 frames
- 5a : Toggle frame display
-
--------------------------------------------------*/
-
-/*-------------------------------------------------
- simutrek_init - Simutrek-specific
- initialization
--------------------------------------------------*/
-
-static void simutrek_init(laserdisc_state *ld)
-{
- /* do a soft reset */
- pr8210_soft_reset(ld);
-}
-
-
/*-------------------------------------------------
- simutrek_status_r - Simutrek-specific
- command processing
+ vsync_off - timer callback to clear the VSYNC
+ flag
-------------------------------------------------*/
-static UINT8 simutrek_status_r(laserdisc_state *ld)
+static TIMER_CALLBACK( vsync_off )
{
- return (ld->state.state != LDSTATE_SEEKING) ? ASSERT_LINE : CLEAR_LINE;
+ laserdisc_state *ld = ptr;
+ ld->player->vsync = FALSE;
}
/*-------------------------------------------------
- simutrek_data_w - Simutrek-specific
- data processing
+ 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 void simutrek_data_w(laserdisc_state *ld, UINT8 prev, UINT8 data)
+static TIMER_CALLBACK( vbi_data_fetch )
{
+ laserdisc_state *ld = ptr;
ldplayer_data *player = ld->player;
+ UINT8 focus_on = !(player->port1 & 0x08);
+ UINT8 laser_on = !(player->port2 & 0x01);
+ UINT32 line16 = laserdisc_get_field_code(ld->device, LASERDISC_CODE_LINE16);
+ UINT32 line1718 = laserdisc_get_field_code(ld->device, LASERDISC_CODE_LINE1718);
- /* Acknowledge every command byte */
- if (player->cmd_ack_callback != NULL)
- (*player->cmd_ack_callback)();
-
- /* Is this byte part of a multi-byte seek command? */
- if (player->cmdcnt > 0)
+ /* logging */
+ if (LOG_VBLANK_VBI)
{
- CMDPRINTF(("Simutrek: Seek to frame byte %d of 3\n", player->cmdcnt + 1));
- player->cmdbytes[player->cmdcnt++] = data;
+ if ((line1718 & VBI_MASK_CAV_PICTURE) == VBI_CODE_CAV_PICTURE)
+ printf("%3d:VBI(%05d)\n", video_screen_get_vpos(ld->screen), VBI_CAV_PICTURE(line1718));
+ else
+ printf("%3d:VBI()\n", video_screen_get_vpos(ld->screen));
+ }
- if (player->cmdcnt == 3)
+ /* update PIA registers based on vbi code */
+ player->pia.vbi1 = 0xff;
+ player->pia.vbi2 = 0xff;
+ if (focus_on && laser_on)
+ {
+ if (line1718 == VBI_CODE_LEADIN)
+ player->pia.vbi1 &= ~0x01;
+ if (line1718 == VBI_CODE_LEADOUT)
+ player->pia.vbi1 &= ~0x02;
+ if (line16 == VBI_CODE_STOP)
+ player->pia.vbi1 &= ~0x04;
+ /* unsure what this bit means: player->pia.vbi1 &= ~0x08; */
+ if ((line1718 & VBI_MASK_CAV_PICTURE) == VBI_CODE_CAV_PICTURE)
{
- player->parameter = ((player->cmdbytes[0] & 0xf) * 10000) +
- ((player->cmdbytes[1] >> 4) * 1000) +
- ((player->cmdbytes[1] & 0xf) * 100) +
- ((player->cmdbytes[2] >> 4) * 10) +
- (player->cmdbytes[2] & 0xf);
-
- CMDPRINTF(("Simutrek: Seek to frame %d\n", player->parameter));
-
- pr8210_switch_state(ld, LDSTATE_SEEKING, player->parameter);
- player->cmdcnt = 0;
+ player->pia.vbi1 &= ~0x10;
+ player->pia.frame[2] = 0xf0 | ((line1718 >> 16) & 0x07);
+ player->pia.frame[3] = 0xf0 | ((line1718 >> 12) & 0x0f);
+ player->pia.frame[4] = 0xf0 | ((line1718 >> 8) & 0x0f);
+ player->pia.frame[5] = 0xf0 | ((line1718 >> 4) & 0x0f);
+ player->pia.frame[6] = 0xf0 | ((line1718 >> 0) & 0x0f);
+ }
+ if ((line1718 & VBI_MASK_CHAPTER) == VBI_CODE_CHAPTER)
+ {
+ player->pia.vbi2 &= ~0x01;
+ player->pia.frame[0] = 0xf0 | ((line1718 >> 16) & 0x07);
+ player->pia.frame[1] = 0xf0 | ((line1718 >> 12) & 0x0f);
}
}
- else if (data == 0)
- {
- CMDPRINTF(("Simutrek: 0 ?\n"));
- }
- else if ((data & 0xf0) == 0xf0)
- {
- CMDPRINTF(("Simutrek: Seek to frame byte 1 of 3\n"));
- player->cmdbytes[player->cmdcnt++] = data;
- }
- else if (data >= 1 && data <= 0x19)
- {
- int count = ((data >> 4) * 10) + (data & 0xf);
- CMDPRINTF(("Simutrek: Step forwards by %d frame(s)\n", count));
- pr8210_switch_state(ld, LDSTATE_STEPPING_BY_PARAMETER, count);
- }
- else if (data >= 0x81 && data <= 0x99)
- {
- int count = (((data >> 4) * 10) + (data & 0xf)) - 100;
- CMDPRINTF(("Simutrek: Step backwards by %d frame(s)\n", count));
- pr8210_switch_state(ld, LDSTATE_STEPPING_BY_PARAMETER, count);
- }
- else if (data == 0x5a)
- {
- CMDPRINTF(("Simutrek: Frame window toggle\n"));
- player->framedisplay ^= 1;
- }
- else
- {
- CMDPRINTF(("Simutrek: Unknown command (%.2x)\n", data));
- }
-}
-
-
-/*-------------------------------------------------
- simutrek_set_audio_squelch - Simutrek-specific
- command to enable/disable audio squelch
--------------------------------------------------*/
-
-void simutrek_set_audio_squelch(const device_config *device, int state)
-{
- laserdisc_state *ld = ldcore_get_safe_token(device);
- int squelch = (state == 0);
- if (squelch)
- ldcore_set_audio_squelch(ld, squelch, squelch);
- else
- ldcore_set_audio_squelch(ld, squelch, squelch);
}
/*-------------------------------------------------
- simutrek_set_audio_squelch - Simutrek-specific
- command to set callback function for
- player/interface command acknowledge
+ pr8210_pia_r - handle reads from the mystery
+ Pioneer PIA
-------------------------------------------------*/
-void simutrek_set_cmd_ack_callback(const device_config *device, void (*callback)(void))
-{
- laserdisc_state *ld = ldcore_get_safe_token(device);
- ldplayer_data *player = ld->player;
-
- player->cmd_ack_callback = callback;
-}
-
-
-
-/***************************************************************************
- RE-IMPLEMENTATION USING ACTUAL ROMS
-***************************************************************************/
-
-/*************************************
- *
- * Test PR-8210 ROM emulation
- *
- *************************************/
-
-static laserdisc_state *find_pr8210(running_machine *machine)
-{
- return ldcore_get_safe_token(device_list_first(machine->config->devicelist, LASERDISC));
-}
-
-
static READ8_HANDLER( pr8210_pia_r )
{
laserdisc_state *ld = find_pr8210(machine);
ldplayer_data *player = ld->player;
- UINT8 result = player->pia[offset];
+ UINT8 result = 0xff;
+
switch (offset)
{
- case 0x22:
- case 0x23:
- case 0x24:
- case 0x25:
- case 0x26:
- case 0x27:
- case 0xc0:
- case 0xe0:
+ /* (20-26) 7 characters for the chapter/frame */
+ case 0x20: case 0x21:
+ case 0x22: case 0x23: case 0x24: case 0x25: case 0x26:
+ result = player->pia.frame[offset - 0x20];
break;
-
+
+ /* (A0) port A value (from serial decoder) */
case 0xa0:
-// printf("%03X:pia_r(%02X) = %02X\n", activecpu_get_pc(), offset, player->pia_porta);
- result = player->pia_porta;
-// player->pia_porta = 0;
+ result = player->pia.porta;
+ break;
+
+ /* (C0) VBI decoding state 1 */
+ case 0xc0:
+ if (LOG_VBLANK_VBI)
+ printf("%3d:PIA(C0)\n", video_screen_get_vpos(ld->screen));
+ result = player->pia.vbi1;
+ break;
+
+ /* (E0) VBI decoding state 2 */
+ case 0xe0:
+ if (LOG_VBLANK_VBI)
+ printf("%3d:PIA(E0)\n", video_screen_get_vpos(ld->screen));
+ result = player->pia.vbi2;
break;
default:
- printf("%03X:pia_r(%02X)\n", activecpu_get_pc(), offset);
+ mame_printf_debug("%03X:Unknown PR-8210 PIA read from offset %02X\n", activecpu_get_pc(), offset);
break;
}
return result;
}
+
+/*-------------------------------------------------
+ pr8210_pia_w - handle writes to the mystery
+ Pioneer PIA
+-------------------------------------------------*/
+
static WRITE8_HANDLER( pr8210_pia_w )
{
- /*
- $22-26 (R) = read and copied to memory $23-27
- $23 (R) = something compared against $F4
- $22-26 (W) = SRCH. text
- $27-2B (W) = FRAME/CHAP. text
- $2C-30 (W) = frame or chapter number
- $40 (W) = $CF at initialization, tracked by ($78)
- $60 (W) = port B output, tracked by ($77)
- $80 = n/c
- $40 = (out) LED3
- $20 = (out) LED2
- $10 = (out) LED1
- 123 -> LHL = Play
- -> HLL = Slow fwd
- -> LLL = Slow rev
- -> HHL = Still
- -> LLH = Pause
- -> HHH = all off
- $08 = (out) CAV LED
- $04 = (out) CLV LED
- $02 = (out) A2 LED/AUDIO 2
- $01 = (out) A1 LED/AUDIO 1
- $80 (W) = 0 or 1
- $A0 (R) = port A input
- $C0 (R) = stored to ($2E)
- $E0 (R) = stored to ($2F)
- */
laserdisc_state *ld = find_pr8210(machine);
ldplayer_data *player = ld->player;
- if (player->pia[offset] != data)
+ UINT8 value;
+
+ switch (offset)
{
- switch (offset)
- {
- case 0x40:
- if (!(data & 0x02) && (player->pia[offset] & 0x02))
- player->framedisplay = 1;
- printf("%03X:pia_w(%02X) = %02X\n", activecpu_get_pc(), offset, data);
- break;
-
- case 0x60:
- printf("%03X:pia_w(%02X) = %02X (PORT B LEDS:", activecpu_get_pc(), offset, data);
- output_set_value("pr8210_audio1", (data & 0x01) != 0);
- output_set_value("pr8210_audio2", (data & 0x02) != 0);
- output_set_value("pr8210_clv", (data & 0x04) != 0);
- output_set_value("pr8210_cav", (data & 0x08) != 0);
- output_set_value("pr8210_led1", (data & 0x10) == 0);
- output_set_value("pr8210_led2", (data & 0x20) == 0);
- output_set_value("pr8210_led3", (data & 0x40) == 0);
- if (!(data & 0x80)) printf(" ???");
- printf(")\n");
- player->pia_portb = data;
- update_audio_squelch(ld);
- break;
-
- default:
- printf("%03X:pia_w(%02X) = %02X\n", activecpu_get_pc(), offset, data);
- break;
- }
- player->pia[offset] = data;
+ /* (22-30) 15 characters for the display */
+ case 0x22: case 0x23: case 0x24: case 0x25: case 0x26:
+ case 0x27: case 0x28: case 0x29: case 0x2a: case 0x2b:
+ case 0x2c: case 0x2d: case 0x2e: case 0x2f: case 0x30:
+ player->pia.text[offset - 0x22] = data;
+ break;
+
+ /* (40) control lines */
+ case 0x40:
+
+ /* toggle bit 0 to latch chapter number into display area */
+ if (!(data & 0x01) && (player->pia.control & 0x01))
+ {
+ memcpy(&player->pia.text[0], &player->pia.frame[0], 2);
+ memset(&player->pia.text[3], 0, 10);
+ player->pia.latchdisplay = 1;
+ }
+
+ /* toggle bit 1 to latch frame number into display area */
+ if (!(data & 0x02) && (player->pia.control & 0x02))
+ {
+ memcpy(&player->pia.text[0], &player->pia.frame[2], 5);
+ memset(&player->pia.text[5], 0, 10);
+ player->pia.latchdisplay = 1;
+ }
+ player->pia.control = data;
+ break;
+
+ /* (60) port B value (LEDs) */
+ case 0x60:
+
+ /* these 4 are direct-connect */
+ output_set_value("pr8210_audio1", (data & 0x01) != 0);
+ output_set_value("pr8210_audio2", (data & 0x02) != 0);
+ output_set_value("pr8210_clv", (data & 0x04) != 0);
+ output_set_value("pr8210_cav", (data & 0x08) != 0);
+
+ /* remaining 3 bits select one of 5 LEDs via a mux */
+ value = ((data & 0x40) >> 6) | ((data & 0x20) >> 4) | ((data & 0x10) >> 2);
+ output_set_value("pr8210_srev", (value == 0));
+ output_set_value("pr8210_sfwd", (value == 1));
+ output_set_value("pr8210_play", (value == 2));
+ output_set_value("pr8210_step", (value == 3));
+ output_set_value("pr8210_pause", (value == 4));
+
+ player->pia.portb = data;
+ update_audio_squelch(ld);
+ break;
+
+ /* (80) display enable */
+ case 0x80:
+ player->pia.display = data & 0x01;
+ break;
+
+ /* no other writes known */
+ default:
+ mame_printf_debug("%03X:Unknown PR-8210 PIA write to offset %02X = %02X\n", activecpu_get_pc(), offset, data);
+ break;
}
}
+
+/*-------------------------------------------------
+ pr8210_bus_r - handle reads from the 8049 BUS
+ input, which is enabled via the PIA above
+-------------------------------------------------*/
+
static READ8_HANDLER( pr8210_bus_r )
{
/*
@@ -1033,8 +641,8 @@ static READ8_HANDLER( pr8210_bus_r )
laserdisc_state *ld = find_pr8210(machine);
ldplayer_data *player = ld->player;
slider_position sliderpos = ldcore_get_slider_position(ld);
- UINT8 focus_on = !(player->porta & 0x08);
- UINT8 spdl_on = !(player->porta & 0x10);
+ UINT8 focus_on = !(player->port1 & 0x08);
+ UINT8 spdl_on = !(player->port1 & 0x10);
UINT8 result = 0x00;
/* bus bit 6: slider position limit detector, inside and outside */
@@ -1052,12 +660,21 @@ static READ8_HANDLER( pr8210_bus_r )
/* bus bit 1: spindle motor stop detector */
if (!spdl_on)
result |= 0x02;
+
+ /* bus bit 0: SLOW TIMER OUT */
+// if (attotime_compare(attotime_sub(timer_get_time(), player->slowtrg),
/* loop at beginning waits for $40=0, $02=1 */
return result;
}
-static WRITE8_HANDLER( pr8210_porta_w )
+
+/*-------------------------------------------------
+ pr8210_port1_w - handle writes to the 8049
+ port #1
+-------------------------------------------------*/
+
+static WRITE8_HANDLER( pr8210_port1_w )
{
/*
$80 = (out) SCAN C (F/R)
@@ -1071,35 +688,56 @@ static WRITE8_HANDLER( pr8210_porta_w )
*/
laserdisc_state *ld = find_pr8210(machine);
ldplayer_data *player = ld->player;
- if ((data & 0xfe) != (player->porta & 0xfe))
- {
- int direction = (data & 0x80) ? 1 : -1;
+ UINT8 prev = player->port1;
+ int direction;
- printf("%03X:porta_w = %02X", activecpu_get_pc(), data);
- if (!(data & 0x01) && (player->porta & 0x01))
- ldcore_advance_slider(ld, direction);
- if (!(data & 0x02))
- printf(" SCAN:%c:%c", (data & 0x80) ? 'F' : 'R', (data & 0x04) ? 'L' : 'H');
- if (!(data & 0x08)) printf(" /FOCUSON");
- if (!(data & 0x10)) printf(" /SPDLON");
- if (data & 0x20) printf(" VIDEOSQ");
- if (data & 0x40) printf(" AUDIOSQ");
- printf("\n");
- player->porta = data;
-
- ldcore_set_video_squelch(ld, (data & 0x20) != 0);
- update_audio_squelch(ld);
- if (!(data & 0x02))
+ /* set the new value */
+ player->port1 = data;
+
+ /* bit 7 selects the direction of slider movement for JUMP TRG and scanning */
+ direction = (data & 0x80) ? 1 : -1;
+
+ /* on the falling edge of bit 0, jump one track in either direction */
+ if (!(data & 0x01) && (prev & 0x01))
+ {
+ /* special override for the Simutrek, which takes over control of this is some situations */
+ if (player->simutrek.cpunum == -1 || (player->simutrek.port2 & 0x04) != 0 || player->simutrek.jumphack)
{
- int delta = (data & 0x04) ? PR8210_SCAN_SPEED : PR8210_SEEK_FAST_SPEED;
- ldcore_set_slider_speed(ld, delta * direction);
+ if (LOG_SIMUTREK)
+ printf("%3d:JUMP TRG\n", video_screen_get_vpos(ld->screen));
+ ldcore_advance_slider(ld, direction);
+ player->simutrek.jumphack = 0;
}
- else
- ldcore_set_slider_speed(ld, 0);
+ else if (LOG_SIMUTREK)
+ printf("%3d:Skipped JUMP TRG\n", video_screen_get_vpos(ld->screen));
+ }
+
+ /* bit 1 low enables scanning */
+ if (!(data & 0x02))
+ {
+ /* bit 2 selects the speed */
+ int delta = (data & 0x04) ? PR8210_SCAN_SPEED : PR8210_SEEK_FAST_SPEED;
+ ldcore_set_slider_speed(ld, delta * direction);
}
+
+ /* bit 1 high stops scanning */
+ else
+ ldcore_set_slider_speed(ld, 0);
+
+ /* video squelch is controlled by bit 5 */
+ update_video_squelch(ld);
+
+ /* audio squelch is controlled by bit 6 */
+ update_audio_squelch(ld);
}
-static WRITE8_HANDLER( pr8210_portb_w )
+
+/*-------------------------------------------------
+ pr8210_port2_w - handle writes to the 8049
+ port #2
+-------------------------------------------------*/
+
+static WRITE8_HANDLER( pr8210_port2_w )
{
/*
$80 = (out) /CS on PIA
@@ -1113,24 +751,28 @@ static WRITE8_HANDLER( pr8210_portb_w )
*/
laserdisc_state *ld = find_pr8210(machine);
ldplayer_data *player = ld->player;
- cpunum_set_input_line(machine, player->cpunum, 0, (data & 0x40) ? CLEAR_LINE : ASSERT_LINE);
- if ((data & 0x7f) != (player->portb & 0x7f))
- {
- printf("%03X:portb_w = %02X", activecpu_get_pc(), data);
- if (!(data & 0x01)) printf(" LASERON");
- if (!(data & 0x02)) printf(" ???");
- if (!(data & 0x04)) printf(" TP1");
- if (!(data & 0x08)) printf(" TP2");
- output_set_value("pr8210_standby", !(data & 0x10));
- if (!(data & 0x20)) printf(" SLOWTRG");
- if (!(data & 0x40)) printf(" IRQGEN");
-// if (data & 0x80) printf(" PIASEL");
- printf("\n");
- player->portb = data;
- }
+ UINT8 prev = player->port2;
+
+ /* set the new value */
+ player->port2 = data;
+
+ /* on the falling edge of bit 5, start the slow timer */
+ if (!(data & 0x20) && (prev & 0x20))
+ player->slowtrg = timer_get_time();
+
+ /* bit 6 when low triggers an IRQ on the MCU */
+ cpunum_set_input_line(machine, player->cpunum, MCS48_INPUT_IRQ, (data & 0x40) ? CLEAR_LINE : ASSERT_LINE);
+
+ /* standby LED is set accordingl to bit 4 */
+ output_set_value("pr8210_standby", (data & 0x10) != 0);
}
+/*-------------------------------------------------
+ pr8210_t0_r - return the state of the 8049
+ T0 input (connected to VSYNC)
+-------------------------------------------------*/
+
static READ8_HANDLER( pr8210_t0_r )
{
/* returns VSYNC state */
@@ -1139,30 +781,286 @@ static READ8_HANDLER( pr8210_t0_r )
}
+/*-------------------------------------------------
+ pr8210_t1_r - return the state of the 8049
+ T1 input (pulled high)
+-------------------------------------------------*/
+
static READ8_HANDLER( pr8210_t1_r )
{
- /* must return 1 or else it tries to jump to an external ROM */
return 1;
}
-static ADDRESS_MAP_START( pr8210_map, ADDRESS_SPACE_PROGRAM, 8 )
- AM_RANGE(0x000, 0x7ff) AM_ROM
-ADDRESS_MAP_END
+/***************************************************************************
+ SIMUTREK ROM AND MACHINE INTERFACES
+***************************************************************************/
-static ADDRESS_MAP_START( pr8210_portmap, ADDRESS_SPACE_IO, 8 )
- AM_RANGE(0x00, 0xff) AM_READWRITE(pr8210_pia_r, pr8210_pia_w)
- AM_RANGE(MCS48_PORT_BUS, MCS48_PORT_BUS) AM_READ(pr8210_bus_r)
- AM_RANGE(MCS48_PORT_P1, MCS48_PORT_P1) AM_WRITE(pr8210_porta_w)
- AM_RANGE(MCS48_PORT_P2, MCS48_PORT_P2) AM_WRITE(pr8210_portb_w)
- AM_RANGE(MCS48_PORT_T0, MCS48_PORT_T0) AM_READ(pr8210_t0_r)
- AM_RANGE(MCS48_PORT_T1, MCS48_PORT_T1) AM_READ(pr8210_t1_r)
+static ADDRESS_MAP_START( simutrek_portmap, ADDRESS_SPACE_IO, 8 )
+ AM_RANGE(0x00, 0xff) AM_READ(simutrek_data_r)
+ AM_RANGE(MCS48_PORT_P2, MCS48_PORT_P2) AM_READWRITE(simutrek_port2_r, simutrek_port2_w)
+ AM_RANGE(MCS48_PORT_T0, MCS48_PORT_T0) AM_READ(simutrek_t0_r)
ADDRESS_MAP_END
-MACHINE_DRIVER_START( pr8210 )
- MDRV_CPU_ADD("pr8210", I8049, XTAL_4_41MHz)
- MDRV_CPU_PROGRAM_MAP(pr8210_map,0)
- MDRV_CPU_IO_MAP(pr8210_portmap,0)
+MACHINE_DRIVER_START( simutrek )
+ MDRV_CPU_ADD("simutrek", I8748, XTAL_6MHz)
+ MDRV_CPU_IO_MAP(simutrek_portmap,0)
+
+ MDRV_IMPORT_FROM(pr8210)
MACHINE_DRIVER_END
+
+
+ROM_START( simutrek )
+ ROM_REGION( 0x800, "pr8210", ROMREGION_LOADBYNAME )
+ ROM_LOAD( "pr-8210_mcu_ud6005a.bin", 0x000, 0x800, CRC(120fa83b) SHA1(b514326ca1f52d6d89056868f9d17eabd4e3f31d) )
+
+ ROM_REGION( 0x400, "simutrek", ROMREGION_LOADBYNAME)
+ ROM_LOAD( "laser_player_interface_d8748_a308.bin", 0x0000, 0x0400, CRC(eed3e728) SHA1(1eb3467f1c41553375b2c21952cd593b167f5416) )
+ROM_END
+
+
+
+/***************************************************************************
+ SIMUTREK PLAYER INTERFACE
+***************************************************************************/
+
+const ldplayer_interface simutrek_interface =
+{
+ LASERDISC_TYPE_SIMUTREK_SPECIAL, /* type of the player */
+ sizeof(ldplayer_data), /* size of the state */
+ "Simutrek Modified PR-8210", /* name of the player */
+ rom_simutrek, /* pointer to ROM region information */
+ machine_config_simutrek, /* pointer to machine configuration */
+ simutrek_init, /* initialization callback */
+ simutrek_vsync, /* vsync callback */
+ simutrek_update, /* update callback */
+ pr8210_overlay, /* overlay callback */
+ simutrek_data_w, /* parallel data write */
+ { /* single line write: */
+ NULL, /* LASERDISC_LINE_ENTER */
+ NULL /* LASERDISC_LINE_CONTROL */
+ },
+ NULL, /* parallel data read */
+ { /* single line read: */
+ simutrek_ready_r, /* LASERDISC_LINE_READY */
+ simutrek_status_r, /* LASERDISC_LINE_STATUS */
+ NULL, /* LASERDISC_LINE_COMMAND */
+ NULL, /* LASERDISC_LINE_DATA_AVAIL */
+ }
+};
+
+
+
+/***************************************************************************
+ SIMUTREK IMPLEMENTATION
+***************************************************************************/
+
+/*-------------------------------------------------
+ simutrek_set_audio_squelch - Simutrek-specific
+ command to enable/disable audio squelch
+-------------------------------------------------*/
+
+void simutrek_set_audio_squelch(const device_config *device, int state)
+{
+ laserdisc_state *ld = ldcore_get_safe_token(device);
+ ldplayer_data *player = ld->player;
+ player->simutrek.audio_squelch = (state == 0);
+ update_audio_squelch(ld);
+}
+
+
+/*-------------------------------------------------
+ simutrek_init - Simutrek-specific
+ initialization
+-------------------------------------------------*/
+
+static void simutrek_init(laserdisc_state *ld)
+{
+ astring *tempstring = astring_alloc();
+
+ /* standard PR-8210 initialization */
+ pr8210_init(ld);
+
+ /* find the Simutrek CPU */
+ astring_printf(tempstring, "%s:%s", ld->device->tag, "simutrek");
+ ld->player->simutrek.cpunum = mame_find_cpu_index(ld->device->machine, astring_c(tempstring));
+ astring_free(tempstring);
+}
+
+
+/*-------------------------------------------------
+ simutrek_vsync - VSYNC callback, called at the
+ start of the blanking period
+-------------------------------------------------*/
+
+static TIMER_CALLBACK( irq_off )
+{
+ laserdisc_state *ld = ptr;
+ ldplayer_data *player = ld->player;
+ cpunum_set_input_line(ld->device->machine, player->simutrek.cpunum, MCS48_INPUT_IRQ, CLEAR_LINE);
+ if (LOG_SIMUTREK)
+ printf("%3d:**** Simutrek IRQ clear\n", video_screen_get_vpos(ld->screen));
+}
+
+static void simutrek_vsync(laserdisc_state *ld, const vbi_metadata *vbi, int fieldnum, attotime curtime)
+{
+ ldplayer_data *player = ld->player;
+
+ if (LOG_SIMUTREK)
+ printf("%3d:VSYNC(%d)\n", video_screen_get_vpos(ld->screen), fieldnum);
+ pr8210_vsync(ld, vbi, fieldnum, curtime);
+
+ if (player->simutrek.data_ready)
+ {
+ if (LOG_SIMUTREK)
+ printf("%3d:VSYNC IRQ\n", video_screen_get_vpos(ld->screen));
+ cpunum_set_input_line(ld->device->machine, player->simutrek.cpunum, MCS48_INPUT_IRQ, ASSERT_LINE);
+ timer_set(video_screen_get_scan_period(ld->screen), ld, 0, irq_off);
+ }
+}
+
+
+/*-------------------------------------------------
+ simutrek_update - update callback, called on
+ the first visible line of the frame
+-------------------------------------------------*/
+
+static INT32 simutrek_update(laserdisc_state *ld, const vbi_metadata *vbi, int fieldnum, attotime curtime)
+{
+ return pr8210_update(ld, vbi, fieldnum, curtime);
+}
+
+
+/*-------------------------------------------------
+ simutrek_ready_r - read callback when the
+ READY line is read
+-------------------------------------------------*/
+
+static UINT8 simutrek_ready_r(laserdisc_state *ld)
+{
+ return !ld->player->simutrek.data_ready;
+}
+
+
+/*-------------------------------------------------
+ simutrek_status_r - read callback when the
+ STATUS line is read
+-------------------------------------------------*/
+
+static UINT8 simutrek_status_r(laserdisc_state *ld)
+{
+ return ((ld->player->simutrek.port2 & 0x03) == 0x03) ? ASSERT_LINE : CLEAR_LINE;
+}
+
+
+/*-------------------------------------------------
+ simutrek_data_w - write callback when the
+ parallel data port is written to
+-------------------------------------------------*/
+
+static void simutrek_data_w(laserdisc_state *ld, UINT8 prev, UINT8 data)
+{
+ timer_call_after_resynch(ld, data, simutrek_latched_data_w);
+ if (LOG_SIMUTREK)
+ printf("%03d:**** Simutrek Command = %02X\n", video_screen_get_vpos(ld->screen), data);
+}
+
+
+/*-------------------------------------------------
+ simutrek_latched_data_w - deferred write
+ callback for when data is written
+-------------------------------------------------*/
+
+static TIMER_CALLBACK( simutrek_latched_data_w )
+{
+ laserdisc_state *ld = ptr;
+ ldplayer_data *player = ld->player;
+
+ /* store the data and set the ready flag */
+ player->simutrek.data = param;
+ player->simutrek.data_ready = TRUE;
+}
+
+
+/*-------------------------------------------------
+ simutrek_port2_r - handle reads from the 8748
+ port #2
+-------------------------------------------------*/
+
+static READ8_HANDLER( simutrek_port2_r )
+{
+ laserdisc_state *ld = find_pr8210(machine);
+ ldplayer_data *player = ld->player;
+
+ /* bit $80 is the pr8210 video squelch */
+ return (player->port1 & 0x20) ? 0x00 : 0x80;
+}
+
+
+/*-------------------------------------------------
+ simutrek_port2_w - handle writes to the 8748
+ port #2
+-------------------------------------------------*/
+
+static WRITE8_HANDLER( simutrek_port2_w )
+{
+ laserdisc_state *ld = find_pr8210(machine);
+ ldplayer_data *player = ld->player;
+ UINT8 prev = player->simutrek.port2;
+
+ /* update stat */
+ player->simutrek.port2 = data;
+
+ /* bit $20 goes to the serial line */
+ if ((data ^ prev) & 0x20)
+ pr8210_control_w(ld, (data & 0x20) ? ASSERT_LINE : CLEAR_LINE, (data & 0x20) ? CLEAR_LINE : ASSERT_LINE);
+
+ /* bit $10 goes to JUMP TRG */
+ /* bit $08 controls direction */
+ if (!(data & 0x10) && (prev & 0x10))
+ {
+ int direction = (data & 0x08) ? 1 : -1;
+ if (LOG_SIMUTREK)
+ printf("%3d:JUMP TRG (Simutrek PC=%03X)\n", video_screen_get_vpos(ld->screen), activecpu_get_pc());
+ ldcore_advance_slider(ld, direction);
+ }
+
+ /* bit $04 controls who owns the JUMP TRG command */
+ if (!(data & 0x04) && (prev & 0x04))
+ player->simutrek.jumphack = 1;
+
+ /* bits $03 control something (status?) */
+ if (LOG_SIMUTREK && ((data ^ prev) & 0x03))
+ printf("Simutrek Status = %d\n", data & 0x03);
+}
+
+
+/*-------------------------------------------------
+ simutrek_data_r - handle external 8748 data
+ reads
+-------------------------------------------------*/
+
+static READ8_HANDLER( simutrek_data_r )
+{
+ laserdisc_state *ld = find_pr8210(machine);
+ ldplayer_data *player = ld->player;
+
+ /* acknowledge the read and clear the data ready flag */
+ player->simutrek.data_ready = FALSE;
+ return player->simutrek.data;
+}
+
+
+/*-------------------------------------------------
+ simutrek_t0_r - return the status of the
+ 8748 T0 input
+-------------------------------------------------*/
+
+static READ8_HANDLER( simutrek_t0_r )
+{
+ /* return 1 if data is waiting from main CPU */
+ laserdisc_state *ld = find_pr8210(machine);
+ return ld->player->simutrek.data_ready;
+}
diff --git a/src/emu/romload.c b/src/emu/romload.c
index 4601bc24396..63d3cfb1f83 100644
--- a/src/emu/romload.c
+++ b/src/emu/romload.c
@@ -631,7 +631,7 @@ static int open_rom_file(running_machine *machine, rom_load_data *romdata, const
}
/* if the region is load by name, load the ROM from there */
- if (regiontag != NULL)
+ if (romdata->file == NULL && regiontag != NULL)
{
astring *fname = astring_assemble_3(astring_alloc(), regiontag, PATH_SEPARATOR, ROM_GETNAME(romp));
if (has_crc)
diff --git a/src/ldplayer/ldplayer.c b/src/ldplayer/ldplayer.c
index e533ee485ae..4cd172ab23b 100644
--- a/src/ldplayer/ldplayer.c
+++ b/src/ldplayer/ldplayer.c
@@ -29,12 +29,18 @@ enum
{
CMD_SCAN_REVERSE,
CMD_STEP_REVERSE,
+ CMD_SLOW_REVERSE,
+ CMD_FAST_REVERSE,
CMD_SCAN_FORWARD,
CMD_STEP_FORWARD,
+ CMD_SLOW_FORWARD,
+ CMD_FAST_FORWARD,
CMD_PLAY,
CMD_PAUSE,
- CMD_DISPLAY_ON,
- CMD_DISPLAY_OFF,
+ CMD_FRAME_TOGGLE,
+ CMD_CHAPTER_TOGGLE,
+ CMD_CH1_TOGGLE,
+ CMD_CH2_TOGGLE,
CMD_0,
CMD_1,
CMD_2,
@@ -60,7 +66,6 @@ static astring *filename;
static input_port_value last_controls;
static UINT8 playing;
-static UINT8 displaying;
static emu_timer *pr8210_bit_timer;
static UINT32 pr8210_command_buffer_in, pr8210_command_buffer_out;
@@ -81,51 +86,68 @@ static void process_commands(const device_config *laserdisc)
input_port_value controls = input_port_read(laserdisc->machine, "controls");
int number;
- /* scan/step backwards */
- if (playing)
- {
- if (controls & 0x01)
- (*execute_command)(laserdisc, CMD_SCAN_REVERSE);
- }
- else
- {
- if (!(last_controls & 0x01) && (controls & 0x01))
- (*execute_command)(laserdisc, CMD_STEP_REVERSE);
- }
+ /* step backwards */
+ if (!(last_controls & 0x01) && (controls & 0x01))
+ (*execute_command)(laserdisc, CMD_STEP_REVERSE);
- /* scan/step forwards */
- if (playing)
- {
- if (controls & 0x02)
- (*execute_command)(laserdisc, CMD_SCAN_FORWARD);
- }
- else
- {
- if (!(last_controls & 0x02) && (controls & 0x02))
- (*execute_command)(laserdisc, CMD_STEP_FORWARD);
- }
+ /* step forwards */
+ if (!(last_controls & 0x02) && (controls & 0x02))
+ (*execute_command)(laserdisc, CMD_STEP_FORWARD);
- /* play/pause */
+ /* scan backwards */
+ if (controls & 0x04)
+ (*execute_command)(laserdisc, CMD_SCAN_REVERSE);
+
+ /* scan forwards */
+ if (controls & 0x08)
+ (*execute_command)(laserdisc, CMD_SCAN_FORWARD);
+
+ /* slow backwards */
if (!(last_controls & 0x10) && (controls & 0x10))
+ (*execute_command)(laserdisc, CMD_SLOW_REVERSE);
+
+ /* slow forwards */
+ if (!(last_controls & 0x20) && (controls & 0x20))
+ (*execute_command)(laserdisc, CMD_SLOW_FORWARD);
+
+ /* fast backwards */
+ if (controls & 0x40)
+ (*execute_command)(laserdisc, CMD_FAST_REVERSE);
+
+ /* fast forwards */
+ if (controls & 0x80)
+ (*execute_command)(laserdisc, CMD_FAST_FORWARD);
+
+ /* play/pause */
+ if (!(last_controls & 0x100) && (controls & 0x100))
{
playing = !playing;
(*execute_command)(laserdisc, playing ? CMD_PLAY : CMD_PAUSE);
}
- /* toggle display */
- if (!(last_controls & 0x20) && (controls & 0x20))
- {
- displaying = !displaying;
- (*execute_command)(laserdisc, displaying ? CMD_DISPLAY_ON : CMD_DISPLAY_OFF);
- }
+ /* toggle frame display */
+ if (!(last_controls & 0x200) && (controls & 0x200))
+ (*execute_command)(laserdisc, CMD_FRAME_TOGGLE);
+
+ /* toggle chapter display */
+ if (!(last_controls & 0x400) && (controls & 0x400))
+ (*execute_command)(laserdisc, CMD_CHAPTER_TOGGLE);
+
+ /* toggle left channel */
+ if (!(last_controls & 0x800) && (controls & 0x800))
+ (*execute_command)(laserdisc, CMD_CH1_TOGGLE);
+
+ /* toggle right channel */
+ if (!(last_controls & 0x1000) && (controls & 0x1000))
+ (*execute_command)(laserdisc, CMD_CH2_TOGGLE);
/* numbers */
for (number = 0; number < 10; number++)
- if (!(last_controls & (0x100 << number)) && (controls & (0x100 << number)))
+ if (!(last_controls & (0x10000 << number)) && (controls & (0x10000 << number)))
(*execute_command)(laserdisc, CMD_0 + number);
/* enter */
- if (!(last_controls & 0x40000) && (controls & 0x40000))
+ if (!(last_controls & 0x4000000) && (controls & 0x4000000))
(*execute_command)(laserdisc, CMD_SEARCH);
last_controls = controls;
@@ -162,7 +184,6 @@ static TIMER_CALLBACK( autoplay )
/* start playing */
(*execute_command)(laserdisc, CMD_PLAY);
playing = TRUE;
- displaying = FALSE;
}
@@ -186,7 +207,6 @@ static MACHINE_RESET( ldplayer )
INLINE void pr8210_add_command(UINT8 command)
{
pr8210_command_buffer[pr8210_command_buffer_in++ % ARRAY_LENGTH(pr8210_command_buffer)] = (command & 0x1f) | 0x20;
- pr8210_command_buffer[pr8210_command_buffer_in++ % ARRAY_LENGTH(pr8210_command_buffer)] = (command & 0x1f) | 0x20;
pr8210_command_buffer[pr8210_command_buffer_in++ % ARRAY_LENGTH(pr8210_command_buffer)] = 0x00 | 0x20;
}
@@ -252,7 +272,8 @@ static void pr8210_execute(const device_config *laserdisc, int command)
switch (command)
{
case CMD_SCAN_REVERSE:
- if (pr8210_command_buffer_in == pr8210_command_buffer_out)
+ if (pr8210_command_buffer_in == pr8210_command_buffer_out ||
+ pr8210_command_buffer_in == (pr8210_command_buffer_out + 1) % ARRAY_LENGTH(pr8210_command_buffer))
{
pr8210_add_command(0x1c);
playing = TRUE;
@@ -264,8 +285,23 @@ static void pr8210_execute(const device_config *laserdisc, int command)
playing = FALSE;
break;
+ case CMD_SLOW_REVERSE:
+ pr8210_add_command(0x02);
+ playing = TRUE;
+ break;
+
+ case CMD_FAST_REVERSE:
+ if (pr8210_command_buffer_in == pr8210_command_buffer_out ||
+ pr8210_command_buffer_in == (pr8210_command_buffer_out + 1) % ARRAY_LENGTH(pr8210_command_buffer))
+ {
+ pr8210_add_command(0x0c);
+ playing = TRUE;
+ }
+ break;
+
case CMD_SCAN_FORWARD:
- if (pr8210_command_buffer_in == pr8210_command_buffer_out)
+ if (pr8210_command_buffer_in == pr8210_command_buffer_out ||
+ pr8210_command_buffer_in == (pr8210_command_buffer_out + 1) % ARRAY_LENGTH(pr8210_command_buffer))
{
pr8210_add_command(0x08);
playing = TRUE;
@@ -277,6 +313,20 @@ static void pr8210_execute(const device_config *laserdisc, int command)
playing = FALSE;
break;
+ case CMD_SLOW_FORWARD:
+ pr8210_add_command(0x18);
+ playing = TRUE;
+ break;
+
+ case CMD_FAST_FORWARD:
+ if (pr8210_command_buffer_in == pr8210_command_buffer_out ||
+ pr8210_command_buffer_in == (pr8210_command_buffer_out + 1) % ARRAY_LENGTH(pr8210_command_buffer))
+ {
+ pr8210_add_command(0x10);
+ playing = TRUE;
+ }
+ break;
+
case CMD_PLAY:
pr8210_add_command(0x14);
playing = TRUE;
@@ -287,11 +337,22 @@ static void pr8210_execute(const device_config *laserdisc, int command)
playing = FALSE;
break;
- case CMD_DISPLAY_ON:
- case CMD_DISPLAY_OFF:
+ case CMD_FRAME_TOGGLE:
pr8210_add_command(0x0b);
break;
+ case CMD_CHAPTER_TOGGLE:
+ pr8210_add_command(0x06);
+ break;
+
+ case CMD_CH1_TOGGLE:
+ pr8210_add_command(0x0e);
+ break;
+
+ case CMD_CH2_TOGGLE:
+ pr8210_add_command(0x16);
+ break;
+
case CMD_0:
case CMD_1:
case CMD_2:
@@ -355,13 +416,7 @@ static void ldv1000_execute(const device_config *laserdisc, int command)
playing = FALSE;
break;
- case CMD_DISPLAY_ON:
- laserdisc_data_w(laserdisc, digits[1]);
- laserdisc_data_w(laserdisc, 0xf1);
- break;
-
- case CMD_DISPLAY_OFF:
- laserdisc_data_w(laserdisc, digits[0]);
+ case CMD_FRAME_TOGGLE:
laserdisc_data_w(laserdisc, 0xf1);
break;
@@ -395,23 +450,30 @@ static void ldv1000_execute(const device_config *laserdisc, int command)
static INPUT_PORTS_START( ldplayer )
PORT_START("controls")
- PORT_BIT( 0x00001, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT )
- PORT_BIT( 0x00002, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT )
- PORT_BIT( 0x00004, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP )
- PORT_BIT( 0x00008, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN )
- PORT_BIT( 0x00010, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_CODE(KEYCODE_SPACE)
- PORT_BIT( 0x00020, IP_ACTIVE_HIGH, IPT_BUTTON2 )
- PORT_BIT( 0x00100, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_PLAYER(2) PORT_CODE(KEYCODE_0_PAD) PORT_CODE(KEYCODE_0)
- PORT_BIT( 0x00200, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_PLAYER(2) PORT_CODE(KEYCODE_1_PAD) PORT_CODE(KEYCODE_1)
- PORT_BIT( 0x00400, IP_ACTIVE_HIGH, IPT_BUTTON3 ) PORT_PLAYER(2) PORT_CODE(KEYCODE_2_PAD) PORT_CODE(KEYCODE_2)
- PORT_BIT( 0x00800, IP_ACTIVE_HIGH, IPT_BUTTON4 ) PORT_PLAYER(2) PORT_CODE(KEYCODE_3_PAD) PORT_CODE(KEYCODE_3)
- PORT_BIT( 0x01000, IP_ACTIVE_HIGH, IPT_BUTTON5 ) PORT_PLAYER(2) PORT_CODE(KEYCODE_4_PAD) PORT_CODE(KEYCODE_4)
- PORT_BIT( 0x02000, IP_ACTIVE_HIGH, IPT_BUTTON6 ) PORT_PLAYER(2) PORT_CODE(KEYCODE_5_PAD) PORT_CODE(KEYCODE_5)
- PORT_BIT( 0x04000, IP_ACTIVE_HIGH, IPT_BUTTON7 ) PORT_PLAYER(2) PORT_CODE(KEYCODE_6_PAD) PORT_CODE(KEYCODE_6)
- PORT_BIT( 0x08000, IP_ACTIVE_HIGH, IPT_BUTTON8 ) PORT_PLAYER(2) PORT_CODE(KEYCODE_7_PAD) PORT_CODE(KEYCODE_7)
- PORT_BIT( 0x10000, IP_ACTIVE_HIGH, IPT_BUTTON9 ) PORT_PLAYER(2) PORT_CODE(KEYCODE_8_PAD) PORT_CODE(KEYCODE_8)
- PORT_BIT( 0x20000, IP_ACTIVE_HIGH, IPT_BUTTON10 ) PORT_PLAYER(2) PORT_CODE(KEYCODE_9_PAD) PORT_CODE(KEYCODE_9)
- PORT_BIT( 0x40000, IP_ACTIVE_HIGH, IPT_BUTTON11 ) PORT_PLAYER(2) PORT_CODE(KEYCODE_ENTER_PAD) PORT_CODE(KEYCODE_ENTER)
+ PORT_BIT( 0x0000001, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_NAME("Step reverse") PORT_CODE(KEYCODE_LEFT)
+ PORT_BIT( 0x0000002, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_NAME("Step forward") PORT_CODE(KEYCODE_RIGHT)
+ PORT_BIT( 0x0000004, IP_ACTIVE_HIGH, IPT_BUTTON3 ) PORT_NAME("Scan reverse") PORT_CODE(KEYCODE_UP)
+ PORT_BIT( 0x0000008, IP_ACTIVE_HIGH, IPT_BUTTON4 ) PORT_NAME("Scan forward") PORT_CODE(KEYCODE_DOWN)
+ PORT_BIT( 0x0000010, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_NAME("Slow reverse") PORT_CODE(KEYCODE_OPENBRACE)
+ PORT_BIT( 0x0000020, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_NAME("Slow forward") PORT_CODE(KEYCODE_CLOSEBRACE)
+ PORT_BIT( 0x0000040, IP_ACTIVE_HIGH, IPT_BUTTON3 ) PORT_NAME("Fast reverse") PORT_CODE(KEYCODE_COMMA)
+ PORT_BIT( 0x0000080, IP_ACTIVE_HIGH, IPT_BUTTON4 ) PORT_NAME("Fast forward") PORT_CODE(KEYCODE_STOP)
+ PORT_BIT( 0x0000100, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_NAME("Play/Pause") PORT_CODE(KEYCODE_SPACE)
+ PORT_BIT( 0x0000200, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_NAME("Toggle frame display") PORT_CODE(KEYCODE_F)
+ PORT_BIT( 0x0000400, IP_ACTIVE_HIGH, IPT_BUTTON3 ) PORT_NAME("Toggle chapter display") PORT_CODE(KEYCODE_C)
+ PORT_BIT( 0x0000800, IP_ACTIVE_HIGH, IPT_BUTTON3 ) PORT_NAME("Toggle left channel") PORT_CODE(KEYCODE_L)
+ PORT_BIT( 0x0001000, IP_ACTIVE_HIGH, IPT_BUTTON3 ) PORT_NAME("Toggle right channel") PORT_CODE(KEYCODE_R)
+ PORT_BIT( 0x0010000, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_NAME("0") PORT_PLAYER(2) PORT_CODE(KEYCODE_0_PAD) PORT_CODE(KEYCODE_0)
+ PORT_BIT( 0x0020000, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_NAME("1") PORT_PLAYER(2) PORT_CODE(KEYCODE_1_PAD) PORT_CODE(KEYCODE_1)
+ PORT_BIT( 0x0040000, IP_ACTIVE_HIGH, IPT_BUTTON3 ) PORT_NAME("2") PORT_PLAYER(2) PORT_CODE(KEYCODE_2_PAD) PORT_CODE(KEYCODE_2)
+ PORT_BIT( 0x0080000, IP_ACTIVE_HIGH, IPT_BUTTON4 ) PORT_NAME("3") PORT_PLAYER(2) PORT_CODE(KEYCODE_3_PAD) PORT_CODE(KEYCODE_3)
+ PORT_BIT( 0x0100000, IP_ACTIVE_HIGH, IPT_BUTTON5 ) PORT_NAME("4") PORT_PLAYER(2) PORT_CODE(KEYCODE_4_PAD) PORT_CODE(KEYCODE_4)
+ PORT_BIT( 0x0200000, IP_ACTIVE_HIGH, IPT_BUTTON6 ) PORT_NAME("5") PORT_PLAYER(2) PORT_CODE(KEYCODE_5_PAD) PORT_CODE(KEYCODE_5)
+ PORT_BIT( 0x0400000, IP_ACTIVE_HIGH, IPT_BUTTON7 ) PORT_NAME("6") PORT_PLAYER(2) PORT_CODE(KEYCODE_6_PAD) PORT_CODE(KEYCODE_6)
+ PORT_BIT( 0x0800000, IP_ACTIVE_HIGH, IPT_BUTTON8 ) PORT_NAME("7") PORT_PLAYER(2) PORT_CODE(KEYCODE_7_PAD) PORT_CODE(KEYCODE_7)
+ PORT_BIT( 0x1000000, IP_ACTIVE_HIGH, IPT_BUTTON9 ) PORT_NAME("8") PORT_PLAYER(2) PORT_CODE(KEYCODE_8_PAD) PORT_CODE(KEYCODE_8)
+ PORT_BIT( 0x2000000, IP_ACTIVE_HIGH, IPT_BUTTON10 ) PORT_NAME("9") PORT_PLAYER(2) PORT_CODE(KEYCODE_9_PAD) PORT_CODE(KEYCODE_9)
+ PORT_BIT( 0x4000000, IP_ACTIVE_HIGH, IPT_BUTTON11 ) PORT_NAME("Enter") PORT_PLAYER(2) PORT_CODE(KEYCODE_ENTER_PAD) PORT_CODE(KEYCODE_ENTER)
INPUT_PORTS_END
diff --git a/src/lib/util/chd.h b/src/lib/util/chd.h
index 7914a9161f9..d8c74dca5d9 100644
--- a/src/lib/util/chd.h
+++ b/src/lib/util/chd.h
@@ -130,6 +130,9 @@
#define AV_METADATA_TAG 0x41564156 /* 'AVAV' */
#define AV_METADATA_FORMAT "FPS:%d.%06d WIDTH:%d HEIGHT:%d INTERLACED:%d CHANNELS:%d SAMPLERATE:%d"
+/* A/V laserdisc frame metadata */
+#define AV_LD_METADATA_TAG 0x41564C44 /* 'AVLD' */
+
/* CHD open values */
#define CHD_OPEN_READ 1
#define CHD_OPEN_READWRITE 2
diff --git a/src/lib/util/vbiparse.c b/src/lib/util/vbiparse.c
index 65f1061cf91..83a3331ca23 100644
--- a/src/lib/util/vbiparse.c
+++ b/src/lib/util/vbiparse.c
@@ -318,7 +318,7 @@ void vbi_parse_all(const UINT16 *source, int sourcerowpixels, int sourcewidth, i
else
{
/* if both are frame numbers, and one is not valid BCD, pick the other */
- if ((vbi->line17 & 0xf80000) == 0xf80000 && (vbi->line18 & 0xf80000) == 0xf80000)
+ if ((vbi->line17 & VBI_MASK_CAV_PICTURE) == VBI_CODE_CAV_PICTURE && (vbi->line18 & VBI_MASK_CAV_PICTURE) == VBI_CODE_CAV_PICTURE)
{
if ((vbi->line17 & 0xf000) > 0x9000 || (vbi->line17 & 0xf00) > 0x900 || (vbi->line17 & 0xf0) > 0x90 || (vbi->line17 & 0xf) > 0x9)
vbi->line1718 = vbi->line18;
@@ -332,3 +332,46 @@ void vbi_parse_all(const UINT16 *source, int sourcerowpixels, int sourcewidth, i
vbi->line1718 = (vbi->line1718 << 1) | ((bits[0][bitnum] > bits[1][bitnum]) ? (bits[0][bitnum] & 1) : (bits[1][bitnum] & 1));
}
}
+
+
+/*-------------------------------------------------
+ vbi_metadata_pack - pack the VBI data down
+ into a smaller form for storage
+-------------------------------------------------*/
+
+void vbi_metadata_pack(UINT8 *dest, UINT32 framenum, const vbi_metadata *vbi)
+{
+ dest[0] = framenum >> 16;
+ dest[1] = framenum >> 8;
+ dest[2] = framenum >> 0;
+ dest[3] = vbi->white;
+ dest[4] = vbi->line16 >> 16;
+ dest[5] = vbi->line16 >> 8;
+ dest[6] = vbi->line16 >> 0;
+ dest[7] = vbi->line17 >> 16;
+ dest[8] = vbi->line17 >> 8;
+ dest[9] = vbi->line17 >> 0;
+ dest[10] = vbi->line18 >> 16;
+ dest[11] = vbi->line18 >> 8;
+ dest[12] = vbi->line18 >> 0;
+ dest[13] = vbi->line1718 >> 16;
+ dest[14] = vbi->line1718 >> 8;
+ dest[15] = vbi->line1718 >> 0;
+}
+
+
+/*-------------------------------------------------
+ vbi_metadata_unpack - unpack the VBI data
+ from a smaller form into the full structure
+-------------------------------------------------*/
+
+void vbi_metadata_unpack(vbi_metadata *vbi, UINT32 *framenum, const UINT8 *source)
+{
+ *framenum = (source[0] << 16) | (source[1] << 8) | source[2];
+ vbi->white = source[3];
+ vbi->line16 = (source[4] << 16) | (source[5] << 8) | source[6];
+ vbi->line17 = (source[7] << 16) | (source[8] << 8) | source[9];
+ vbi->line18 = (source[10] << 16) | (source[11] << 8) | source[12];
+ vbi->line1718 = (source[13] << 16) | (source[14] << 8) | source[15];
+}
+
diff --git a/src/lib/util/vbiparse.h b/src/lib/util/vbiparse.h
index 5e4a594f6a1..02af240265d 100644
--- a/src/lib/util/vbiparse.h
+++ b/src/lib/util/vbiparse.h
@@ -16,6 +16,46 @@
/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+/* size of packed VBI data */
+#define VBI_PACKED_BYTES 16
+
+/* these codes are full 24-bit codes with no parameter data */
+#define VBI_CODE_LEADIN 0x88ffff
+#define VBI_CODE_LEADOUT 0x80eeee
+#define VBI_CODE_STOP 0x82cfff
+#define VBI_CODE_CLV 0x87ffff
+
+/* these codes require a mask because some bits are parameters */
+#define VBI_MASK_CAV_PICTURE 0xf00000
+#define VBI_CODE_CAV_PICTURE 0xf00000
+#define VBI_MASK_CHAPTER 0xf00fff
+#define VBI_CODE_CHAPTER 0x800ddd
+#define VBI_MASK_CLV_TIME 0xf0ff00
+#define VBI_CODE_CLV_TIME 0xf0dd00
+#define VBI_MASK_STATUS_CX_ON 0xfff000
+#define VBI_CODE_STATUS_CX_ON 0x8dc000
+#define VBI_MASK_STATUS_CX_OFF 0xfff000
+#define VBI_CODE_STATUS_CX_OFF 0x8bc000
+#define VBI_MASK_USER 0xf0f000
+#define VBI_CODE_USER 0x80d000
+#define VBI_MASK_CLV_PICTURE 0xf0f000
+#define VBI_CODE_CLV_PICTURE 0x80e000
+
+
+
+/***************************************************************************
+ MACROS
+***************************************************************************/
+
+#define VBI_CAV_PICTURE(x) (((((x) >> 16) & 0x07) * 10000) + ((((x) >> 12) & 0x0f) * 1000) + ((((x) >> 8) & 0x0f) * 100) + ((((x) >> 4) & 0x0f) * 10) + ((((x) >> 0) & 0x0f) * 1))
+#define VBI_CHAPTER(x) (((((x) >> 16) & 0x07) * 10) + ((((x) >> 12) & 0x0f) * 1))
+
+
+
+/***************************************************************************
TYPE DEFINITIONS
***************************************************************************/
@@ -44,5 +84,11 @@ int vbi_parse_white_flag(const UINT16 *source, int sourcewidth, int sourceshift)
/* parse everything from a video frame */
void vbi_parse_all(const UINT16 *source, int sourcerowpixels, int sourcewidth, int sourceshift, vbi_metadata *vbi);
+/* pack the VBI data down into a smaller form for storage */
+void vbi_metadata_pack(UINT8 *dest, UINT32 framenum, const vbi_metadata *vbi);
+
+/* unpack the VBI data from a smaller form into the full structure */
+void vbi_metadata_unpack(vbi_metadata *vbi, UINT32 *framenum, const UINT8 *source);
+
#endif /* __VBIPARSE_H__ */
diff --git a/src/mame/drivers/cubeqst.c b/src/mame/drivers/cubeqst.c
index dd6aba3e345..f42305e7896 100644
--- a/src/mame/drivers/cubeqst.c
+++ b/src/mame/drivers/cubeqst.c
@@ -5,7 +5,6 @@
driver by Phil Bennett
TODO:
- * Emulate D8478 laserdisc interface MCU
* Accurate video timings
- Derive from PROMs
* More accurate line fill circuitry emulation
@@ -61,7 +60,6 @@ static UINT8 io_latch;
static UINT8 reset_latch;
static int disk_on;
-static int ldp_command_flag;
static const device_config *laserdisc;
/*************************************
@@ -222,22 +220,16 @@ static INTERRUPT_GEN( vblank )
static WRITE16_HANDLER( laserdisc_w )
{
- ldp_command_flag = 1;
laserdisc_data_w(laserdisc, data & 0xff);
}
-/* Called by the player emulation to acknowledge the 68000 command */
-void ldp_ack_callback(void)
-{
- ldp_command_flag = 0;
-}
-
/*
D0: Command acknowledge
D1: Seek status (0 = searching, 1 = ready)
*/
static READ16_HANDLER( laserdisc_r )
{
+ int ldp_command_flag = (laserdisc_line_r(laserdisc, LASERDISC_LINE_READY) == ASSERT_LINE) ? 0 : 1;
int ldp_seek_status = (laserdisc_line_r(laserdisc, LASERDISC_LINE_STATUS) == ASSERT_LINE) ? 1 : 0;
return (ldp_seek_status << 1) | ldp_command_flag;
@@ -444,16 +436,12 @@ ADDRESS_MAP_END
static MACHINE_START( cubeqst )
{
laserdisc = device_list_find_by_tag(machine->config->devicelist, LASERDISC, "laserdisc");
- simutrek_set_cmd_ack_callback(laserdisc, ldp_ack_callback);
}
static MACHINE_RESET( cubeqst )
{
reset_latch = 0;
- /* Do this until we sort out the laserdisc interface properly */
- ldp_command_flag = 0;
-
/* Auxillary CPUs are held in reset */
cpunum_set_input_line(machine, SOUND_CPU, INPUT_LINE_RESET, ASSERT_LINE);
cpunum_set_input_line(machine, ROTATE_CPU, INPUT_LINE_RESET, ASSERT_LINE);
@@ -558,12 +546,6 @@ static MACHINE_DRIVER_START( cubeqst )
MDRV_CPU_PROGRAM_MAP(line_sound_map, 0)
MDRV_CPU_CONFIG(snd_config)
-#if 0
- MDRV_CPU_ADD("ldp_cpu", I8048, XTAL_10MHz / 2)
- MDRV_CPU_PROGRAM_MAP(ldp_mem, 0)
- MDRV_CPU_IO_MAP(ldp_io, 0)
-#endif
-
MDRV_INTERLEAVE(700)
MDRV_MACHINE_START(cubeqst)
@@ -580,6 +562,7 @@ static MACHINE_DRIVER_START( cubeqst )
MDRV_LASERDISC_OVERLAY(cubeqst, CUBEQST_HBLANK, CUBEQST_VCOUNT, BITMAP_FORMAT_INDEXED16)
MDRV_LASERDISC_OVERLAY_CLIP(0, 320-1, 0, 256-8)
MDRV_LASERDISC_OVERLAY_POSITION(0.002, -0.018)
+ MDRV_LASERDISC_OVERLAY_SCALE(1.0, 1.030)
MDRV_SPEAKER_STANDARD_STEREO("left", "right")
@@ -658,9 +641,6 @@ ROM_START( cubeqst )
ROMX_LOAD( "mother_sounds_82s129.9e", 0x4, 0x100, CRC(598687e7) SHA1(c5045ddaab7123ff0a4c8f4c2489f9d70b63fc76), ROM_NIBBLE | ROM_SHIFT_NIBBLE_HI | ROM_SKIP(7))
ROMX_LOAD( "mother_sounds_82s129.8e", 0x4, 0x100, CRC(68de17ed) SHA1(efefcb4ccdd012b767c4765304c6022b0c091066), ROM_NIBBLE | ROM_SHIFT_NIBBLE_LO | ROM_SKIP(7))
- ROM_REGION( 0x10000, "ldp_cpu", 0)
- ROM_LOAD( "laser_player_interface_d8748_a308.bin", 0x0000, 0x0400, CRC(eed3e728) SHA1(1eb3467f1c41553375b2c21952cd593b167f5416) )
-
ROM_REGION16_BE( 0x1000, "soundproms", 0)
ROMX_LOAD( "mother_sounds_82s185.17f", 0x0, 0x800, CRC(0f49d40e) SHA1(40340833ab27ccb5b60baf44ad01930f204f5318), ROM_NIBBLE | ROM_SHIFT_NIBBLE_LO | ROM_SKIP(1) )
ROMX_LOAD( "mother_sounds_82s185.19f", 0x0, 0x800, CRC(a041ce92) SHA1(9bc92992de22b830e479933c50650c7dc23f5713), ROM_NIBBLE | ROM_SHIFT_NIBBLE_HI | ROM_SKIP(1) )
diff --git a/src/mame/drivers/gottlieb.c b/src/mame/drivers/gottlieb.c
index 39b65454ee4..56228603943 100644
--- a/src/mame/drivers/gottlieb.c
+++ b/src/mame/drivers/gottlieb.c
@@ -680,7 +680,7 @@ static INTERRUPT_GEN( gottlieb_interrupt )
bitmap_t *dummy;
/* set the "disc ready" bit, which basically indicates whether or not we have a proper video frame */
- if (laserdisc_get_video(laserdisc, &dummy) == 0)
+ if (!laserdisc_get_video(laserdisc, &dummy))
laserdisc_status &= ~0x20;
else
laserdisc_status |= 0x20;
diff --git a/src/tools/chdman.c b/src/tools/chdman.c
index f5af8f22b40..06765cb910a 100644
--- a/src/tools/chdman.c
+++ b/src/tools/chdman.c
@@ -15,6 +15,7 @@
#include "bitmap.h"
#include "md5.h"
#include "sha1.h"
+#include "vbiparse.h"
#include <stdarg.h>
#include <stdio.h>
#include <time.h>
@@ -84,7 +85,8 @@ static clock_t lastprogress = 0;
***************************************************************************/
/*-------------------------------------------------
- print_big_int - 64-bit int printing with commas
+ print_big_int - 64-bit int printing with
+ commas
-------------------------------------------------*/
static void print_big_int(UINT64 intvalue, char *output)
@@ -105,7 +107,8 @@ static void print_big_int(UINT64 intvalue, char *output)
/*-------------------------------------------------
- big_int_string - return a string for a big int
+ big_int_string - return a string for a big
+ integer
-------------------------------------------------*/
static char *big_int_string(UINT64 intvalue)
@@ -162,6 +165,7 @@ static int usage(void)
printf(" or: chdman -merge parent.chd diff.chd output.chd\n");
printf(" or: chdman -diff parent.chd compare.chd diff.chd\n");
printf(" or: chdman -setchs inout.chd cylinders heads sectors\n");
+ printf(" or: chdman -fixavdata inout.chd\n");
return 1;
}
@@ -755,6 +759,7 @@ static int do_createav(int argc, char *argv[], int param)
const char *inputfile, *outputfile;
bitmap_t *fullbitmap = NULL;
const avi_movie_info *info;
+ UINT8 *ldframedata = NULL;
const chd_header *header;
chd_file *chd = NULL;
avi_file *avi = NULL;
@@ -837,6 +842,19 @@ static int do_createav(int argc, char *argv[], int param)
firstframe *= 2;
numframes *= 2;
}
+
+ /* allocate space for the frame data */
+ if (height == 524/2 || height == 624/2)
+ {
+ ldframedata = malloc(numframes * VBI_PACKED_BYTES);
+ if (ldframedata == NULL)
+ {
+ fprintf(stderr, "Out of memory allocating frame metadata\n");
+ err = CHDERR_OUT_OF_MEMORY;
+ goto cleanup;
+ }
+ memset(ldframedata, 0, numframes * VBI_PACKED_BYTES);
+ }
/* determine the number of bytes per frame */
max_samples_per_frame = ((UINT64)rate * 1000000 + fps_times_1million - 1) / fps_times_1million;
@@ -919,6 +937,15 @@ static int do_createav(int argc, char *argv[], int param)
fprintf(stderr, "Error reading frame %d from AVI file: %s\n", effframe, avi_error_string(avierr));
err = CHDERR_COMPRESSION_ERROR;
}
+
+ /* update metadata for this frame */
+ if (ldframedata != NULL)
+ {
+ /* parse the data and pack it */
+ vbi_metadata vbi;
+ vbi_parse_all((const UINT16 *)avconfig.video->base, avconfig.video->rowpixels, avconfig.video->width, 8, &vbi);
+ vbi_metadata_pack(&ldframedata[framenum * VBI_PACKED_BYTES], framenum, &vbi);
+ }
/* configure the compressor for this frame */
chd_codec_config(chd, AV_CODEC_COMPRESS_CONFIG, &avconfig);
@@ -929,6 +956,17 @@ static int do_createav(int argc, char *argv[], int param)
goto cleanup;
}
+ /* write the final metadata */
+ if (ldframedata != NULL)
+ {
+ err = chd_set_metadata(chd, AV_LD_METADATA_TAG, 0, ldframedata, numframes * VBI_PACKED_BYTES);
+ if (err != CHDERR_NONE)
+ {
+ fprintf(stderr, "Error adding AVLD metadata: %s\n", chd_error_string(err));
+ goto cleanup;
+ }
+ }
+
/* finish compression */
err = chd_compress_finish(chd);
if (err != CHDERR_NONE)
@@ -947,6 +985,8 @@ cleanup:
free(avconfig.audio[chnum]);
if (fullbitmap != NULL)
bitmap_free(fullbitmap);
+ if (ldframedata != NULL)
+ free(ldframedata);
if (err != CHDERR_NONE)
osd_rmfile(outputfile);
return (err != CHDERR_NONE);
@@ -1466,7 +1506,7 @@ static int do_extractav(int argc, char *argv[], int param)
numframes = MIN(totalframes - firstframe, numframes);
/* allocate a video buffer */
- fullbitmap = bitmap_alloc(width, height * (interlaced ? 2 : 1), BITMAP_FORMAT_YUY16);
+ fullbitmap = bitmap_alloc(width, height, BITMAP_FORMAT_YUY16);
if (fullbitmap == NULL)
{
fprintf(stderr, "Out of memory allocating temporary bitmap\n");
@@ -1724,6 +1764,236 @@ cleanup:
/*-------------------------------------------------
+ do_fixavdata - fix the AV metadata for an
+ A/V file
+-------------------------------------------------*/
+
+static int do_fixavdata(int argc, char *argv[], int param)
+{
+ int fps, fpsfrac, width, height, interlaced, channels, rate;
+ av_codec_decompress_config avconfig = { 0 };
+ bitmap_t *fullbitmap = NULL;
+ const char *inputfile;
+ UINT8 *vbidata = NULL;
+ int writeable = FALSE;
+ chd_file *chd = NULL;
+ bitmap_t fakebitmap;
+ char metadata[256];
+ chd_header header;
+ UINT32 actlength;
+ UINT32 framenum;
+ chd_error err;
+ int fixframes = 0;
+ int fixes = 0;
+
+ /* require 3 args total */
+ if (argc != 3)
+ return usage();
+
+ /* extract the data */
+ inputfile = argv[2];
+
+ /* print some info */
+ printf("Input file: %s\n", inputfile);
+
+ /* get the header */
+ err = chd_open(inputfile, CHD_OPEN_READ, NULL, &chd);
+ if (err != CHDERR_NONE)
+ {
+ fprintf(stderr, "Error opening CHD file '%s': %s\n", inputfile, chd_error_string(err));
+ goto cleanup;
+ }
+ header = *chd_get_header(chd);
+
+ /* get the metadata */
+ err = chd_get_metadata(chd, AV_METADATA_TAG, 0, metadata, sizeof(metadata), NULL, NULL);
+ if (err != CHDERR_NONE)
+ {
+ fprintf(stderr, "Error getting A/V metadata: %s\n", chd_error_string(err));
+ goto cleanup;
+ }
+
+ /* extract the info */
+ if (sscanf(metadata, AV_METADATA_FORMAT, &fps, &fpsfrac, &width, &height, &interlaced, &channels, &rate) != 7)
+ {
+ fprintf(stderr, "Improperly formatted metadata\n");
+ err = CHDERR_INVALID_METADATA;
+ goto cleanup;
+ }
+
+ /* allocate space for the frame data */
+ if ((height != 524/2 && height != 624/2) || !interlaced)
+ {
+ fprintf(stderr, "This file does not need VBI metadata\n");
+ err = CHDERR_INVALID_METADATA;
+ goto cleanup;
+ }
+
+ /* allocate a video buffer */
+ fullbitmap = bitmap_alloc(width, height, BITMAP_FORMAT_YUY16);
+ if (fullbitmap == NULL)
+ {
+ fprintf(stderr, "Out of memory allocating temporary bitmap\n");
+ err = CHDERR_OUT_OF_MEMORY;
+ goto cleanup;
+ }
+ avconfig.video = &fakebitmap;
+
+ /* allocate memory for VBI data */
+ vbidata = malloc(header.totalhunks * VBI_PACKED_BYTES);
+ if (vbidata == NULL)
+ {
+ fprintf(stderr, "Out of memory allocating VBI data\n");
+ err = CHDERR_OUT_OF_MEMORY;
+ goto cleanup;
+ }
+
+ /* read the metadata */
+ err = chd_get_metadata(chd, AV_LD_METADATA_TAG, 0, vbidata, header.totalhunks * VBI_PACKED_BYTES, &actlength, NULL);
+ if (err != CHDERR_NONE)
+ {
+ fprintf(stderr, "Error getting VBI metadata: %s\n", chd_error_string(err));
+ memset(vbidata, 0, header.totalhunks * VBI_PACKED_BYTES);
+ fixes++;
+ }
+ if (actlength != header.totalhunks * VBI_PACKED_BYTES)
+ {
+ fprintf(stderr, "VBI metadata incorrect size\n");
+ memset(vbidata, 0, header.totalhunks * VBI_PACKED_BYTES);
+ fixes++;
+ }
+
+ /* loop over hunks, reading */
+ for (framenum = 0; framenum < header.totalhunks; framenum++)
+ {
+ vbi_metadata origvbi;
+ vbi_metadata vbi;
+ UINT32 vbiframe;
+
+ /* progress */
+ progress(framenum == 0, "Processing hunk %d/%d... \r", framenum, header.totalhunks);
+
+ /* set up the fake bitmap for this frame */
+ *avconfig.video = *fullbitmap;
+
+ /* configure the decompressor for this frame */
+ chd_codec_config(chd, AV_CODEC_DECOMPRESS_CONFIG, &avconfig);
+
+ /* read the hunk into the buffers */
+ err = chd_read(chd, framenum, NULL);
+ if (err != CHDERR_NONE)
+ {
+ fprintf(stderr, "Error reading hunk %d from CHD file: %s\n", framenum, chd_error_string(err));
+ goto cleanup;
+ }
+
+ /* unpack the current data for this frame */
+ vbi_metadata_unpack(&origvbi, &vbiframe, &vbidata[framenum * VBI_PACKED_BYTES]);
+
+ /* parse the video data */
+ vbi_parse_all((const UINT16 *)avconfig.video->base, avconfig.video->rowpixels, avconfig.video->width, 8, &vbi);
+
+ /* verify the data */
+ if (vbiframe != 0 || origvbi.white != 0 || origvbi.line16 != 0 || origvbi.line17 != 0 || origvbi.line18 != 0 || origvbi.line1718 != 0)
+ {
+ int errors = 0;
+
+ if (vbiframe != framenum)
+ {
+ fprintf(stderr, "%d:Frame mismatch in VBI data (%d, should be %d)\n", framenum, vbiframe, framenum);
+ errors++;
+ }
+ if (vbi.white != origvbi.white)
+ {
+ fprintf(stderr, "%d:White flag mismatch in VBI data (%d, should be %d)\n", framenum, origvbi.white, vbi.white);
+ errors++;
+ }
+ if (vbi.line16 != origvbi.line16)
+ {
+ fprintf(stderr, "%d:Line 16 mismatch in VBI data (%06X, should be %06X)\n", framenum, origvbi.line16, vbi.line16);
+ errors++;
+ }
+ if (vbi.line17 != origvbi.line17)
+ {
+ fprintf(stderr, "%d:Line 17 mismatch in VBI data (%06X, should be %06X)\n", framenum, origvbi.line17, vbi.line17);
+ errors++;
+ }
+ if (vbi.line18 != origvbi.line18)
+ {
+ fprintf(stderr, "%d:Line 18 mismatch in VBI data (%06X, should be %06X)\n", framenum, origvbi.line18, vbi.line18);
+ errors++;
+ }
+ if (vbi.line1718 != origvbi.line1718)
+ {
+ fprintf(stderr, "%d:Line 17/18 mismatch in VBI data (%06X, should be %06X)\n", framenum, origvbi.line1718, vbi.line1718);
+ errors++;
+ }
+ fixes += errors;
+ fixframes += (errors != 0);
+ }
+
+ /* pack the new data */
+ vbi_metadata_pack(&vbidata[framenum * VBI_PACKED_BYTES], framenum, &vbi);
+ }
+ progress(TRUE, "Processing complete! \n");
+
+ /* print final results */
+ if (fixes == 0)
+ printf("\nNo fixes required\n");
+ else
+ printf("\nFound %d errors on %d frames\n", fixes, fixframes);
+
+ /* close the drive */
+ chd_close(chd);
+ chd = NULL;
+
+ /* apply fixes */
+ if (fixes > 0)
+ {
+ /* mark the CHD writeable */
+ header.flags |= CHDFLAGS_IS_WRITEABLE;
+ err = chd_set_header(inputfile, &header);
+ if (err != CHDERR_NONE)
+ fprintf(stderr, "Error writing new header: %s\n", chd_error_string(err));
+ header.flags &= ~CHDFLAGS_IS_WRITEABLE;
+ writeable = TRUE;
+
+ /* open the file */
+ err = chd_open(inputfile, CHD_OPEN_READWRITE, NULL, &chd);
+ if (err != CHDERR_NONE)
+ {
+ fprintf(stderr, "Error opening CHD file '%s': %s\n", inputfile, chd_error_string(err));
+ goto cleanup;
+ }
+
+ /* write new metadata */
+ err = chd_set_metadata(chd, AV_LD_METADATA_TAG, 0, vbidata, header.totalhunks * VBI_PACKED_BYTES);
+ if (err != CHDERR_NONE)
+ {
+ fprintf(stderr, "Error adding AVLD metadata: %s\n", chd_error_string(err));
+ goto cleanup;
+ }
+ else
+ printf("Updated metadata written successfully\n");
+
+ /* allow cleanup code to close the file and revert the header */
+ }
+
+cleanup:
+ /* clean up our mess */
+ if (fullbitmap != NULL)
+ bitmap_free(fullbitmap);
+ if (vbidata != NULL)
+ free(vbidata);
+ if (chd != NULL)
+ chd_close(chd);
+ if (writeable)
+ chd_set_header(inputfile, &header);
+ return (err != CHDERR_NONE);
+}
+
+
+/*-------------------------------------------------
do_info - dump the header information from
a drive image
-------------------------------------------------*/
@@ -2535,7 +2805,8 @@ int CLIB_DECL main(int argc, char **argv)
{ "-info", do_info, 0 },
{ "-merge", do_merge_update_chomp, OPERATION_MERGE },
{ "-diff", do_diff, 0 },
- { "-setchs", do_setchs, 0 }
+ { "-setchs", do_setchs, 0 },
+ { "-fixavdata", do_fixavdata, 0 }
};
extern char build_version[];
int i;