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++) @@ -2815,6 +2817,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 the white flag, force the new field to pair with it */ - if (ldcore->metadata[fieldnum ^ 1].white) - ldcore->videofields[ldcore->videoindex] = 1; + /* 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; + + /* 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; - /* configure the codec and then read */ - if (ldcore->disc != NULL) - { - err = chd_codec_config(ldcore->disc, AV_CODEC_DECOMPRESS_CONFIG, &ldcore->avconfig); - if (err == CHDERR_NONE) - { - INT32 chdtrack = tracknum - 1 - VIRTUAL_LEAD_IN_TRACKS; + /* 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]); - /* 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; - } + /* configure the codec and then read */ + ldcore->readresult = CHDERR_FILE_NOT_FOUND; + if (ldcore->disc != NULL && !ldcore->videosquelch) + { + 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]); @@ -999,29 +1022,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 ); /*************************************************************************** - ROM AND MACHINE INTERFACES + INLINE FUNCTIONS ***************************************************************************/ -MACHINE_DRIVER_EXTERN( pr8210 ); +/*------------------------------------------------- + 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); +} + + + +/*************************************************************************** + PR-8210 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_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; + 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); } -} - -/*------------------------------------------------- - 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; - } - 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; - -//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) - { - pr8210_hle_command(ld); - player->lastcommand = 0; - } + 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 = newcommand; -#endif + player->lastcommand = player->pia.porta; + + /* log the command and wait for a keypress */ + if (LOG_SERIAL) + { + printf("--- Command = %02X\n", player->pia.porta >> 3); + while (input_code_pressed(KEYCODE_ENTER)) ; + while (!input_code_pressed(KEYCODE_ENTER)) ; + } + + /* 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 - + vsync_off - timer callback to clear the VSYNC + flag -------------------------------------------------*/ -/*------------------------------------------------- - simutrek_init - Simutrek-specific - initialization --------------------------------------------------*/ - -static void simutrek_init(laserdisc_state *ld) +static TIMER_CALLBACK( vsync_off ) { - /* do a soft reset */ - pr8210_soft_reset(ld); + laserdisc_state *ld = ptr; + ld->player->vsync = FALSE; } /*------------------------------------------------- - simutrek_status_r - Simutrek-specific - command 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 UINT8 simutrek_status_r(laserdisc_state *ld) -{ - return (ld->state.state != LDSTATE_SEEKING) ? ASSERT_LINE : CLEAR_LINE; -} - - -/*------------------------------------------------- - simutrek_data_w - Simutrek-specific - data processing --------------------------------------------------*/ - -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 + pr8210_pia_r - handle reads from the mystery + Pioneer PIA -------------------------------------------------*/ -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 --------------------------------------------------*/ - -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; + /* (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; + } - 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; + /* 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)); - default: - printf("%03X:pia_w(%02X) = %02X\n", activecpu_get_pc(), offset, data); - break; - } - player->pia[offset] = data; + 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)) + UINT8 prev = player->port1; + int direction; + + /* 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)) { - int direction = (data & 0x80) ? 1 : -1; - - 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)) + /* 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 + +/*************************************************************************** + SIMUTREK ROM AND MACHINE INTERFACES +***************************************************************************/ + +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 -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) -ADDRESS_MAP_END +MACHINE_DRIVER_START( simutrek ) + MDRV_CPU_ADD("simutrek", I8748, XTAL_6MHz) + MDRV_CPU_IO_MAP(simutrek_portmap,0) - -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) + 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); + + /* 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 & 0x10) && (controls & 0x10)) + 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; } @@ -185,7 +206,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 @@ -15,6 +15,46 @@ #define __VBIPARSE_H__ +/*************************************************************************** + 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 #include #include @@ -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"); @@ -1723,6 +1763,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;