Added proper laserdisc support for MACH 3, Us vs. Them, and Cobra

Commander (MACH 3 hardware). Old laserdisc hacks are now removed.
The code now talks to the standard Pioneer PR-8210 interface. Also
removed hacky "target list" from the MACH 3 ROMs; this information
is now decoded on the fly from the right channel laserdisc audio.
 
Other Gottlieb cleanups:
 - moved sound inputs to audio/gottlieb and included them in
    all relevant drivers
 - ordered input ports and ROM definitions consistently
 
Other laserdisc changes:
 - changed PR-8210 interface to work consistently for both Gottlieb
    and Stern games
 - added audio callback mechanism to allow drivers to peek at the
    raw audio streams
 - extended the VBI parser to be even more lenient
This commit is contained in:
Aaron Giles 2008-08-04 15:26:41 +00:00
parent d20e6b6151
commit 95e3753dd2
8 changed files with 1177 additions and 917 deletions

View File

@ -358,6 +358,12 @@ const char *attotime_string(attotime _time, int precision)
else if (precision <= 9)
{
UINT32 upper = _time.attoseconds / ATTOSECONDS_PER_SECOND_SQRT;
int temp = precision;
while (temp < 9)
{
upper /= 10;
temp++;
}
sprintf(buffer, "%d.%0*d", _time.seconds, precision, upper);
}
@ -366,6 +372,12 @@ const char *attotime_string(attotime _time, int precision)
{
UINT32 lower;
UINT32 upper = divu_64x32_rem(_time.attoseconds, ATTOSECONDS_PER_SECOND_SQRT, &lower);
int temp = precision;
while (temp < 18)
{
lower /= 10;
temp++;
}
sprintf(buffer, "%d.%09d%0*d", _time.seconds, upper, precision - 9, lower);
}
return buffer;

View File

@ -90,7 +90,7 @@ typedef enum _playstate playstate;
#define STOP_SPEED INT_TO_FRAC(0) /* no movement */
#define PLAY_SPEED INT_TO_FRAC(1) /* regular playback speed */
#define GENERIC_SPINUP_TIME (attotime_make(3, 0))
#define GENERIC_SPINUP_TIME (attotime_make(5, 0))
#define GENERIC_LOAD_TIME (attotime_make(10, 0))
#define GENERIC_RESET_SPEED INT_TO_FRAC(5000)
@ -102,10 +102,6 @@ typedef enum _playstate playstate;
#define PR7820_SEARCH_SPEED INT_TO_FRAC(5000)
/* Pioneer PR-8210/LD-V1100 specific states */
#define PR8210_MODE_GET_1ST 0
#define PR8210_MODE_GET_2ND 1
#define PR8210_MODE_GET_3RD 2
#define PR8210_SCAN_SPEED (INT_TO_FRAC(2000) / 30)
#define PR8210_FAST_SPEED (PLAY_SPEED * 3)
#define PR8210_SLOW_SPEED (PLAY_SPEED / 5)
@ -159,9 +155,10 @@ typedef struct _pr8210_info pr8210_info;
struct _pr8210_info
{
UINT8 mode; /* current mode */
UINT16 commandtriplet[3]; /* current command triplet */
attotime commandtime; /* command time */
UINT8 commandbits; /* command bit count */
UINT8 lastcommand; /* last command byte received */
UINT16 accumulator; /* bit accumulator */
attotime lastbittime; /* time of last bit received */
attotime firstbittime; /* time of first bit in command */
UINT8 seekstate; /* state of the seek command */
};
@ -232,6 +229,7 @@ struct _laserdisc_state
bitmap_t * emptyframe; /* blank frame */
/* audio data */
laserdisc_audio_func audiocallback; /* callback function for audio processing */
INT16 * audiobuffer[2]; /* buffer for audio samples */
UINT32 audiobufsize; /* size of buffer */
UINT32 audiobufin; /* input index */
@ -313,8 +311,9 @@ struct _sound_token
/* generic helper functions */
static int update_position(laserdisc_state *ld);
static void read_track_data(laserdisc_state *ld);
static void process_track_data(laserdisc_state *ld);
static void process_track_data(const device_config *device);
static void parse_metadata(const UINT16 *videodata, UINT32 rowpixels, UINT32 width, UINT32 track, UINT8 which, field_metadata *metadata);
static void fake_metadata(UINT32 track, UINT8 which, field_metadata *metadata);
static void *custom_start(int clock, const struct CustomSound_interface *config);
static void custom_stream_callback(void *param, stream_sample_t **inputs, stream_sample_t **outputs, int samples);
@ -567,6 +566,19 @@ INLINE void set_hold_state(laserdisc_state *ld, attotime holdtime, playstate sta
}
/*-------------------------------------------------
reset_tracknum - reset the current track
number to 1 and clear out other state
-------------------------------------------------*/
INLINE void reset_tracknum(laserdisc_state *ld)
{
ld->curfractrack = ONE_TRACK;
ld->last_frame = 0;
ld->last_chapter = 0;
}
/*-------------------------------------------------
add_to_current_track - add a value to the
current track, stopping if we hit the min or
@ -713,7 +725,7 @@ void laserdisc_vsync(const device_config *device)
}
/* wait for previous read and decode to finish */
process_track_data(ld);
process_track_data(device);
/* update our position for this field */
hittarget = update_position(ld);
@ -1057,7 +1069,7 @@ static int update_position(laserdisc_state *ld)
{
/* if we're on the second field of a frame, the next frame is on the next track */
/* but don't do it if we're seeking to frame 1, since that might be the very first frame */
if (fieldnum == 1)// && (ld->last_frame == 1 || ld->targetframe != 1))
if (fieldnum == 1)
{
add_to_current_track(ld, ONE_TRACK);
LOG_POSITION(("on 2nd field, going to next track\n"));
@ -1070,8 +1082,9 @@ static int update_position(laserdisc_state *ld)
/* if we're in the lead-in or lead-out sections, advance more aggressively */
if (frame == 0)
{
LOG_POSITION(("in lead-in, advancing by 10\n"));
add_to_current_track(ld, 10 * ONE_TRACK);
LOG_POSITION(("in lead-in, advancing by 1\n"));
if (fieldnum == 1)
add_to_current_track(ld, 1 * ONE_TRACK);
return FALSE;
}
if (frame == 99999)
@ -1205,8 +1218,9 @@ static void read_track_data(laserdisc_state *ld)
track after it has been read
-------------------------------------------------*/
static void process_track_data(laserdisc_state *ld)
static void process_track_data(const device_config *device)
{
laserdisc_state *ld = get_safe_token(device);
UINT32 tracknum = FRAC_TO_INT(ld->curfractrack);
UINT32 fieldnum = ld->fieldnum & 1;
const UINT8 *rawdata = NULL;
@ -1226,15 +1240,15 @@ static void process_track_data(laserdisc_state *ld)
ld->readpending = FALSE;
/* parse the metadata */
if (ld->avconfig.video_buffer != NULL)
{
if (ld->disc != NULL && ld->avconfig.video_buffer != NULL)
parse_metadata((const UINT16 *)ld->avconfig.video_buffer, ld->avconfig.video_stride / 2, ld->videoframe[0]->width, tracknum, fieldnum, &ld->metadata[fieldnum]);
//printf("Track %5d: Metadata = %d %08X %08X %08X\n", tracknum, ld->metadata[fieldnum].whiteflag, ld->metadata[fieldnum].line16, ld->metadata[fieldnum].line17, ld->metadata[fieldnum].line18);
}
else
fake_metadata(tracknum, fieldnum, &ld->metadata[fieldnum]);
printf("Track %5d: Metadata = %d %08X %08X %08X\n", tracknum, ld->metadata[fieldnum].whiteflag, ld->metadata[fieldnum].line16, ld->metadata[fieldnum].line17, ld->metadata[fieldnum].line18);
/* update the last seen frame and chapter */
frame = frame_from_metadata(&ld->metadata[fieldnum]);
if (frame != -1)
if (frame >= 1 && frame < 99999)
ld->last_frame = frame;
chapter = chapter_from_metadata(&ld->metadata[fieldnum]);
if (chapter != -1)
@ -1253,6 +1267,10 @@ static void process_track_data(laserdisc_state *ld)
samples = (rawdata[6] << 8) + rawdata[7];
sampsource[0] = (const INT16 *)(rawdata + 12 + rawdata[4]) + 0 * samples;
sampsource[1] = sampsource[0] + samples;
/* let the audio callback at it first */
if (ld->audiocallback != NULL)
(*ld->audiocallback)(device, ld->samplerate, samples, sampsource[0], sampsource[1]);
/* loop until all samples are copied */
while (samples != 0)
@ -1319,6 +1337,29 @@ static void parse_metadata(const UINT16 *videodata, UINT32 rowpixels, UINT32 wid
}
/*-------------------------------------------------
fake_metadata - fake metadata when there's
no disc present
-------------------------------------------------*/
static void fake_metadata(UINT32 track, UINT8 which, field_metadata *metadata)
{
if (which == 0)
{
metadata->whiteflag = 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));
}
/*-------------------------------------------------
custom_start - custom audio start
for laserdiscs
@ -1327,7 +1368,7 @@ static void parse_metadata(const UINT16 *videodata, UINT32 rowpixels, UINT32 wid
static void *custom_start(int clock, const struct CustomSound_interface *config)
{
sound_token *token = auto_malloc(sizeof(*token));
token->stream = stream_create(0, 2, 44100, token, custom_stream_callback);
token->stream = stream_create(0, 2, 48000, token, custom_stream_callback);
token->ld = NULL;
return token;
}
@ -1405,7 +1446,7 @@ static void custom_stream_callback(void *param, stream_sample_t **inputs, stream
device start callback
-------------------------------------------------*/
static DEVICE_START( laserdisc )
static DEVICE_START(laserdisc)
{
int fps = 30, fpsfrac = 0, width = 720, height = 240, interlaced = 1, channels = 2, rate = 44100;
const laserdisc_config *config = device->inline_config;
@ -1417,6 +1458,9 @@ static DEVICE_START( laserdisc )
/* copy config data to the live state */
ld->type = config->type;
ld->audiocallback = config->audio;
/* find the disc */
ld->disc = get_disk_handle(device->tag);
for (sndnum = 0; sndnum < MAX_SOUND; sndnum++)
if (device->machine->config->sound[sndnum].tag != NULL && strcmp(device->machine->config->sound[sndnum].tag, device->tag) == 0)
@ -1474,7 +1518,7 @@ static DEVICE_START( laserdisc )
device exit callback
-------------------------------------------------*/
static DEVICE_STOP( laserdisc )
static DEVICE_STOP(laserdisc)
{
laserdisc_state *ld = get_safe_token(device);
@ -1551,7 +1595,7 @@ static DEVICE_RESET( laserdisc )
}
/* default to track 1 */
ld->curfractrack = ONE_TRACK;
reset_tracknum(ld);
}
@ -1559,7 +1603,7 @@ static DEVICE_RESET( laserdisc )
device set info callback
-------------------------------------------------*/
static DEVICE_SET_INFO( laserdisc )
static DEVICE_SET_INFO(laserdisc)
{
laserdisc_state *ld = get_safe_token(device);
switch (state)
@ -1580,7 +1624,7 @@ static DEVICE_SET_INFO( laserdisc )
device get info callback
-------------------------------------------------*/
DEVICE_GET_INFO( laserdisc )
DEVICE_GET_INFO(laserdisc)
{
const laserdisc_config *config = (device != NULL) ? device->inline_config : NULL;
switch (state)
@ -1921,8 +1965,7 @@ static void pr7820_enter_w(laserdisc_state *ld, UINT8 newstate)
set_state(ld, LASERDISC_LOADING, STOP_SPEED, NULL_TARGET_FRAME);
set_hold_state(ld, GENERIC_LOAD_TIME, LASERDISC_PLAYING_FORWARD, PLAY_SPEED);
}
ld->curfractrack = ONE_TRACK;
reset_tracknum(ld);
}
break;
@ -2055,10 +2098,9 @@ static void pr8210_soft_reset(laserdisc_state *ld)
ld->audio = AUDIO_CH1_ENABLE | AUDIO_CH2_ENABLE;
ld->display = 0;
pr8210->mode = PR8210_MODE_GET_1ST;
pr8210->commandtime = timer_get_time();
pr8210->commandbits = 0;
memset( pr8210->commandtriplet, 0, 3*sizeof(UINT16) );
pr8210->firstbittime = pr8210->lastbittime = timer_get_time();
pr8210->accumulator = 0;
pr8210->lastcommand = 0;
pr8210->seekstate = 0;
}
@ -2070,187 +2112,156 @@ static void pr8210_soft_reset(laserdisc_state *ld)
static void pr8210_command(laserdisc_state *ld)
{
static const UINT8 numbers[10] = { 0x01,0x11,0x09,0x19,0x05,0x15,0x0d,0x1d,0x03,0x13 };
pr8210_info *pr8210 = &ld->u.pr8210;
UINT8 cmd = pr8210->lastcommand;
/* if we don't have the entire command triplet yet, keep going */
if ( pr8210->mode < PR8210_MODE_GET_3RD )
/* look for and process numbers */
if (!process_number(ld, cmd, numbers))
{
/* do some sanity checks on the command data */
if ( pr8210->mode == PR8210_MODE_GET_2ND )
switch(cmd)
{
/* if the commands don't match, then reassign the new command to the first word, then keep fetching */
if ( pr8210->commandtriplet[PR8210_MODE_GET_1ST] != pr8210->commandtriplet[PR8210_MODE_GET_2ND] )
{
pr8210->commandtriplet[PR8210_MODE_GET_1ST] = pr8210->commandtriplet[PR8210_MODE_GET_2ND];
pr8210->mode = PR8210_MODE_GET_2ND;
return;
}
}
case 0x00: CMDPRINTF(("pr8210: EOC\n"));
/* EOC marker - can be safely ignored */
break;
pr8210->mode++;
}
else /* we're ready to process the command */
{
/* do some sanity checks on the command data */
static const UINT8 numbers[10] = { 0x01,0x11,0x09,0x19,0x05,0x15,0x0d,0x1d,0x03,0x13 };
UINT16 cmd = pr8210->commandtriplet[PR8210_MODE_GET_1ST];
case 0x02: CMDPRINTF(("pr8210: Slow reverse\n"));
/* slow reverse */
if (laserdisc_ready(ld))
set_state(ld, LASERDISC_PLAYING_SLOW_REVERSE, -PR8210_SLOW_SPEED, NULL_TARGET_FRAME);
break;
/* more sanity checking: bit 7 must be set for a valid command */
if ( cmd & 0x80 )
{
/* extract the actual command number */
cmd = ( cmd >> 2 ) & 0x1f;
case 0x04: CMDPRINTF(("pr8210: Step forward\n"));
/* step forward */
if (laserdisc_ready(ld))
set_state(ld, LASERDISC_STEPPING_FORWARD, PR8210_STEP_SPEED, NULL_TARGET_FRAME);
break;
/* look for and process numbers */
if (!process_number(ld, cmd, numbers))
{
switch( cmd )
case 0x06 : CMDPRINTF(("pr8210: Chapter\n"));
/* chapter -- not implemented */
break;
case 0x08: CMDPRINTF(("pr8210: Scan forward\n"));
/* scan forward */
if (laserdisc_ready(ld))
set_state(ld, LASERDISC_SCANNING_FORWARD, PR8210_SCAN_SPEED, NULL_TARGET_FRAME);
break;
case 0x0a: CMDPRINTF(("pr8210: Pause\n"));
/* still picture */
if (laserdisc_ready(ld))
set_state(ld, LASERDISC_STOPPED, STOP_SPEED, NULL_TARGET_FRAME);
break;
case 0x0b : CMDPRINTF(("pr8210: Frame\n"));
/* frame -- not implemented */
break;
case 0x0c: CMDPRINTF(("pr8210: Fast reverse\n"));
/* play reverse fast speed */
if (laserdisc_ready(ld))
set_state(ld, LASERDISC_PLAYING_FAST_REVERSE, -PR8210_FAST_SPEED, NULL_TARGET_FRAME);
break;
case 0x0e: CMDPRINTF(("pr8210: Ch1 toggle\n"));
/* channel 1 audio toggle */
ld->audio ^= AUDIO_CH1_ENABLE;
break;
case 0x10: CMDPRINTF(("pr8210: Fast forward\n"));
/* play forward fast speed */
if (laserdisc_ready(ld))
set_state(ld, LASERDISC_PLAYING_FAST_FORWARD, PR8210_FAST_SPEED, NULL_TARGET_FRAME);
break;
case 0x12: CMDPRINTF(("pr8210: Step reverse\n"));
/* step backwards one frame */
if (laserdisc_ready(ld))
{
case 0x00: CMDPRINTF(("pr8210: EOC\n"));
/* EOC marker - can be safely ignored */
break;
case 0x02: CMDPRINTF(("pr8210: Slow reverse\n"));
/* slow reverse */
if (laserdisc_ready(ld))
set_state(ld, LASERDISC_PLAYING_SLOW_REVERSE, -PR8210_SLOW_SPEED, NULL_TARGET_FRAME);
break;
case 0x04: CMDPRINTF(("pr8210: Step forward\n"));
/* step forward */
if (laserdisc_ready(ld))
set_state(ld, LASERDISC_STEPPING_FORWARD, PR8210_STEP_SPEED, NULL_TARGET_FRAME);
break;
case 0x06 : CMDPRINTF(("pr8210: Chapter\n"));
/* chapter -- not implemented */
break;
case 0x08: CMDPRINTF(("pr8210: Scan forward\n"));
/* scan forward */
if (laserdisc_ready(ld))
set_state(ld, LASERDISC_SCANNING_FORWARD, PR8210_SCAN_SPEED, NULL_TARGET_FRAME);
break;
case 0x0a: CMDPRINTF(("pr8210: Pause\n"));
/* still picture */
if (laserdisc_ready(ld))
set_state(ld, LASERDISC_STOPPED, STOP_SPEED, NULL_TARGET_FRAME);
break;
case 0x0b : CMDPRINTF(("pr8210: Frame\n"));
/* frame -- not implemented */
break;
case 0x0c: CMDPRINTF(("pr8210: Fast reverse\n"));
/* play reverse fast speed */
if (laserdisc_ready(ld))
set_state(ld, LASERDISC_PLAYING_FAST_REVERSE, -PR8210_FAST_SPEED, NULL_TARGET_FRAME);
break;
case 0x0e: CMDPRINTF(("pr8210: Ch1 toggle\n"));
/* channel 1 audio toggle */
ld->audio ^= AUDIO_CH1_ENABLE;
break;
case 0x10: CMDPRINTF(("pr8210: Fast forward\n"));
/* play forward fast speed */
if (laserdisc_ready(ld))
set_state(ld, LASERDISC_PLAYING_FAST_FORWARD, PR8210_FAST_SPEED, NULL_TARGET_FRAME);
break;
case 0x12: CMDPRINTF(("pr8210: Step reverse\n"));
/* step backwards one frame */
if (laserdisc_ready(ld))
{
set_state(ld, LASERDISC_STEPPING_REVERSE, STOP_SPEED, NULL_TARGET_FRAME);
add_to_current_track(ld, -ONE_TRACK);
}
break;
case 0x14: CMDPRINTF(("pr8210: Play\n"));
/* begin playing at regular speed, or load the disc if it is parked */
if (laserdisc_ready(ld))
set_state(ld, LASERDISC_PLAYING_FORWARD, PLAY_SPEED, NULL_TARGET_FRAME);
else
{
/* if we're already spinning up or loading, ignore */
if (ld->state != LASERDISC_SPINUP && ld->state != LASERDISC_LOADING)
{
if (ld->state == LASERDISC_PARKED)
{
set_state(ld, LASERDISC_SPINUP, STOP_SPEED, NULL_TARGET_FRAME);
set_hold_state(ld, GENERIC_SPINUP_TIME, LASERDISC_PLAYING_FORWARD, PLAY_SPEED);
}
else
{
set_state(ld, LASERDISC_LOADING, STOP_SPEED, NULL_TARGET_FRAME);
set_hold_state(ld, GENERIC_LOAD_TIME, LASERDISC_PLAYING_FORWARD, PLAY_SPEED);
}
ld->curfractrack = ONE_TRACK;
}
}
break;
case 0x16: CMDPRINTF(("pr8210: Ch2 toggle\n"));
/* channel 1 audio toggle */
ld->audio ^= AUDIO_CH2_ENABLE;
break;
case 0x18: CMDPRINTF(("pr8210: Slow forward\n"));
/* slow forward */
if (laserdisc_ready(ld))
set_state(ld, LASERDISC_PLAYING_SLOW_FORWARD, PR8210_SLOW_SPEED, NULL_TARGET_FRAME);
break;
case 0x1a: CMDPRINTF(("pr8210: Seek\n"));
/* seek */
if ( pr8210->seekstate )
{
CMDPRINTF(("pr8210: Seeking to frame:%d\n", ld->parameter));
/* we're ready to seek */
set_state(ld, LASERDISC_SEARCHING_FRAME, PR8210_SEARCH_SPEED, ld->parameter);
}
else
{
/* waiting for digits indicating position */
ld->parameter = 0;
}
pr8210->seekstate ^=1 ;
break;
case 0x1c: CMDPRINTF(("pr8210: Scan reverse\n"));
/* scan reverse */
if (laserdisc_ready(ld))
set_state(ld, LASERDISC_SCANNING_REVERSE, -PR8210_SCAN_SPEED, NULL_TARGET_FRAME);
break;
case 0x1e: CMDPRINTF(("pr8210: Reject\n"));
/* eject the disc */
if (laserdisc_ready(ld))
{
set_state(ld, LASERDISC_EJECTING, STOP_SPEED, NULL_TARGET_FRAME);
set_hold_state(ld, GENERIC_LOAD_TIME, LASERDISC_EJECTED, STOP_SPEED);
}
break;
default: CMDPRINTF(("pr8210: Unknown command %02X\n", cmd));
/* unknown command */
break;
set_state(ld, LASERDISC_STEPPING_REVERSE, STOP_SPEED, NULL_TARGET_FRAME);
add_to_current_track(ld, -ONE_TRACK);
}
}
}
break;
/* reset our command data */
memset( pr8210->commandtriplet, 0, 3*sizeof(UINT16) );
pr8210->mode = PR8210_MODE_GET_1ST;
case 0x14: CMDPRINTF(("pr8210: Play\n"));
/* begin playing at regular speed, or load the disc if it is parked */
if (laserdisc_ready(ld))
set_state(ld, LASERDISC_PLAYING_FORWARD, PLAY_SPEED, NULL_TARGET_FRAME);
else
{
/* if we're already spinning up or loading, ignore */
if (ld->state != LASERDISC_SPINUP && ld->state != LASERDISC_LOADING)
{
if (ld->state == LASERDISC_PARKED)
{
set_state(ld, LASERDISC_SPINUP, STOP_SPEED, NULL_TARGET_FRAME);
set_hold_state(ld, GENERIC_SPINUP_TIME, LASERDISC_PLAYING_FORWARD, PLAY_SPEED);
}
else
{
set_state(ld, LASERDISC_LOADING, STOP_SPEED, NULL_TARGET_FRAME);
set_hold_state(ld, GENERIC_LOAD_TIME, LASERDISC_PLAYING_FORWARD, PLAY_SPEED);
}
reset_tracknum(ld);
}
}
break;
case 0x16: CMDPRINTF(("pr8210: Ch2 toggle\n"));
/* channel 1 audio toggle */
ld->audio ^= AUDIO_CH2_ENABLE;
break;
case 0x18: CMDPRINTF(("pr8210: Slow forward\n"));
/* slow forward */
if (laserdisc_ready(ld))
set_state(ld, LASERDISC_PLAYING_SLOW_FORWARD, PR8210_SLOW_SPEED, NULL_TARGET_FRAME);
break;
case 0x1a: CMDPRINTF(("pr8210: Seek\n"));
/* seek */
if (pr8210->seekstate)
{
CMDPRINTF(("pr8210: Seeking to frame:%d\n", ld->parameter));
/* we're ready to seek */
set_state(ld, LASERDISC_SEARCHING_FRAME, PR8210_SEARCH_SPEED, ld->parameter);
/* before seeking, we hold in the searching state for 150usec, even if seeking to the same frame */
/* Us vs. Them requires at least this much "non-video" time in order to work */
set_hold_state(ld, ATTOTIME_IN_MSEC(150), LASERDISC_SEARCHING_FRAME, PR8210_SEARCH_SPEED);
}
else
{
/* waiting for digits indicating position */
ld->parameter = 0;
}
pr8210->seekstate ^= 1;
break;
case 0x1c: CMDPRINTF(("pr8210: Scan reverse\n"));
/* scan reverse */
if (laserdisc_ready(ld))
set_state(ld, LASERDISC_SCANNING_REVERSE, -PR8210_SCAN_SPEED, NULL_TARGET_FRAME);
break;
case 0x1e: CMDPRINTF(("pr8210: Reject\n"));
/* eject the disc */
if (laserdisc_ready(ld))
{
set_state(ld, LASERDISC_EJECTING, STOP_SPEED, NULL_TARGET_FRAME);
set_hold_state(ld, GENERIC_LOAD_TIME, LASERDISC_EJECTED, STOP_SPEED);
}
break;
default: CMDPRINTF(("pr8210: Unknown command %02X\n", cmd));
/* unknown command */
break;
}
}
}
/*-------------------------------------------------
pr8210_command_w - write callback when the
pr8210_control_w - write callback when the
CONTROL line is toggled
-------------------------------------------------*/
@ -2258,42 +2269,53 @@ static void pr8210_control_w(laserdisc_state *ld, UINT8 data)
{
pr8210_info *pr8210 = &ld->u.pr8210;
if ( data == ASSERT_LINE )
if (data == ASSERT_LINE)
{
attotime curtime = timer_get_time();
attotime delta;
int longpulse;
/* if we timed out, reset the accumulator */
delta = attotime_sub(curtime, pr8210->firstbittime);
if (delta.attoseconds > ATTOTIME_IN_USEC(25320).attoseconds)
{
pr8210->firstbittime = curtime;
pr8210->accumulator = 0x5555;
// printf("Reset accumulator\n");
}
/* get the time difference from the last assert */
attotime delta = attotime_sub(timer_get_time(), pr8210->commandtime);
/* and update our internal command time */
pr8210->commandtime = timer_get_time();
delta = attotime_sub(curtime, pr8210->lastbittime);
pr8210->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;
pr8210->accumulator = (pr8210->accumulator << 1) | longpulse;
#if 0
{
int usecdiff = (int)(delta.attoseconds / ATTOSECONDS_IN_USEC(1));
printf( "bitdelta = %d\n", usecdiff );
printf("bitdelta = %5d (%d) - accum = %04X\n", usecdiff, longpulse, pr8210->accumulator);
}
#endif
/* if the delay is less than 3 msec, we're receiving data */
if ( delta.attoseconds < ATTOTIME_IN_MSEC(3).attoseconds )
/* if we have a complete command, signal it */
/* a complete command is 0,0,1 followed by 5 bits, followed by 0,0 */
if ((pr8210->accumulator & 0x383) == 0x80)
{
/* 0 bit delta is 1.05 msec, 1 bit delta is 2.11 msec */
int longpulse = ( delta.attoseconds < ATTOTIME_IN_USEC(1500).attoseconds ) ? 0 : 1;
pr8210->commandtriplet[pr8210->mode] <<= 1;
pr8210->commandtriplet[pr8210->mode] |= longpulse;
UINT8 newcommand = (pr8210->accumulator >> 2) & 0x1f;
/* if we received 10 bits, see what we need to do */
if ( ++pr8210->commandbits >= 10 )
//printf("New command = %02X (last=%02X)\n", newcommand, pr8210->lastcommand);
/* if we got a double command, act on it */
if (newcommand == pr8210->lastcommand)
{
/* reset bit shift count */
pr8210->commandbits = 0;
/* mask just the 10 bits */
pr8210->commandtriplet[pr8210->mode] &= 0x3ff;
/* execute command */
pr8210_command( ld );
pr8210_command(ld);
pr8210->lastcommand = 0;
}
else
pr8210->lastcommand = newcommand;
}
}
}
@ -2623,8 +2645,7 @@ static void ldv1000_data_w(laserdisc_state *ld, UINT8 prev, UINT8 data)
set_state(ld, LASERDISC_LOADING, STOP_SPEED, NULL_TARGET_FRAME);
set_hold_state(ld, GENERIC_LOAD_TIME, LASERDISC_PLAYING_FORWARD, PLAY_SPEED);
}
ld->curfractrack = ONE_TRACK;
reset_tracknum(ld);
}
break;
@ -2793,7 +2814,7 @@ static void ldp1450_soft_reset(laserdisc_state *ld)
ld->audio = AUDIO_CH1_ENABLE | AUDIO_CH2_ENABLE;
ld->display = FALSE;
set_state(ld, LASERDISC_STOPPED, STOP_SPEED, NULL_TARGET_FRAME);
ld->curfractrack = ONE_TRACK;
reset_tracknum(ld);
}
@ -2994,8 +3015,7 @@ static void ldp1450_data_w(laserdisc_state *ld, UINT8 prev, UINT8 data)
set_state(ld, LASERDISC_LOADING, STOP_SPEED, NULL_TARGET_FRAME);
set_hold_state(ld, GENERIC_LOAD_TIME, LASERDISC_PLAYING_FORWARD, PLAY_SPEED);
}
ld->curfractrack = ONE_TRACK;
reset_tracknum(ld);
}
break;

View File

@ -27,7 +27,7 @@ enum
LASERDISC_TYPE_PIONEER_PR8210, /* Pioneer PR-8210 / LD-V1100 */
LASERDISC_TYPE_PIONEER_LDV1000, /* Pioneer LD-V1000 */
LASERDISC_TYPE_PHILLIPS_22VP932, /* Phillips 22VP932 (PAL) */
LASERDISC_TYPE_SONY_LDP1450, /* Sony LDP-1450 */
LASERDISC_TYPE_SONY_LDP1450 /* Sony LDP-1450 */
};
/* laserdisc control lines */
@ -60,10 +60,13 @@ enum
TYPE DEFINITIONS
***************************************************************************/
typedef void (*laserdisc_audio_func)(const device_config *device, int samplerate, int samples, const INT16 *ch0, const INT16 *ch1);
typedef struct _laserdisc_config laserdisc_config;
struct _laserdisc_config
{
int type;
int type;
laserdisc_audio_func audio;
};
@ -76,6 +79,9 @@ struct _laserdisc_config
MDRV_DEVICE_ADD(_tag, LASERDISC) \
MDRV_DEVICE_CONFIG_DATA32(laserdisc_config, type, LASERDISC_TYPE_##_type)
#define MDRV_LASERDISC_AUDIO(_func) \
MDRV_DEVICE_CONFIG_DATAPTR(laserdisc_config, audio, _func)
#define MDRV_LASERDISC_REMOVE(_tag, _type) \
MDRV_DEVICE_REMOVE(_tag, _type)
@ -93,19 +99,46 @@ extern const struct CustomSound_interface laserdisc_custom_interface;
FUNCTION PROTOTYPES
***************************************************************************/
/* ----- core control and status ----- */
/* call this once per field (i.e., 59.94 times/second for NTSC) */
void laserdisc_vsync(const device_config *device);
/* return a textual description of the current state (for debugging) */
const char *laserdisc_describe_state(const device_config *device);
/* get a bitmap for the current frame (and the frame number) */
UINT32 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);
/* ----- input and output ----- */
/* write to the parallel data port of the player */
void laserdisc_data_w(const device_config *device, UINT8 data);
/* assert or clear a signal line connected to the player */
void laserdisc_line_w(const device_config *device, UINT8 line, UINT8 newstate);
/* read from the parallel data port of the player */
UINT8 laserdisc_data_r(const device_config *device);
/* read the state of a signal line connected to the player */
UINT8 laserdisc_line_r(const device_config *device, UINT8 line);
/* ----- player specifics ----- */
/* specify the "slow" speed of the Pioneer PR-7820 */
void pr7820_set_slow_speed(const device_config *device, double frame_rate_scaler);
/* ----- device interface ----- */
/* device get info callback */

View File

@ -18,6 +18,7 @@
***************************************************************************/
#define MAX_SOURCE_WIDTH 1024
#define MAX_CLOCK_DIFF 3
@ -92,29 +93,21 @@ int vbi_parse_manchester_code(const UINT16 *source, int sourcewidth, int sources
for (x = 1; x < expectedbits; x++)
{
int curbit = firstedge + (double)x * clock;
int offby;
/* exact match? */
if (srcabs[curbit + 0] != srcabs[curbit + 1])
continue;
/* off-by-one? */
if (srcabs[curbit + 1 + 0] != srcabs[curbit + 1 + 1] || srcabs[curbit - 1 + 0] != srcabs[curbit - 1 + 1])
{
/* only continue if we're still in the running */
if ((error += 1) < besterr)
continue;
}
/* look for a match that is off by an amount up to the maximum */
for (offby = 0; offby <= MAX_CLOCK_DIFF; offby++)
if (srcabs[curbit + offby + 0] != srcabs[curbit + offby + 1] || srcabs[curbit - offby + 0] != srcabs[curbit - offby + 1])
break;
/* off-by-two? */
if (srcabs[curbit + 2 + 0] != srcabs[curbit + 2 + 1] || srcabs[curbit - 2 + 0] != srcabs[curbit - 2 + 1])
{
/* only continue if we're still in the running */
if ((error += 2) < besterr)
continue;
}
/* if we never found the edge, fail immediately */
if (offby > MAX_CLOCK_DIFF)
break;
/* anything else fails immediately */
break;
/* only continue if we're still in the running */
error += offby;
if (error >= besterr)
break;
}
/* if we got to the end, this is the best candidate so far */

View File

@ -31,13 +31,12 @@ static UINT8 nmi_state;
static UINT8 speech_control;
static UINT8 sp0250_drq;
static UINT8 last_command;
static UINT8 *dac_data;
static UINT8 *psg_latch;
static UINT8 *sp0250_latch;
static UINT8 last_command;
static void gottlieb1_sh_w(const device_config *riot, UINT8 data);
static void gottlieb2_sh_w(running_machine *machine, UINT8 data);
@ -342,6 +341,28 @@ MACHINE_DRIVER_END
/*************************************
*
* Rev. 1 input ports
*
*************************************/
INPUT_PORTS_START( gottlieb1_sound )
PORT_START_TAG("SB1")
PORT_DIPUNKNOWN_DIPLOC( 0x01, 0x01, "SB1:7" )
PORT_DIPUNKNOWN_DIPLOC( 0x02, 0x02, "SB1:6" )
PORT_DIPUNKNOWN_DIPLOC( 0x04, 0x04, "SB1:5" )
PORT_DIPUNKNOWN_DIPLOC( 0x08, 0x08, "SB1:1" )
PORT_DIPUNKNOWN_DIPLOC( 0x10, 0x10, "SB1:4" )
PORT_DIPUNKNOWN_DIPLOC( 0x20, 0x20, "SB1:3" )
PORT_DIPNAME( 0x40, 0x40, "Sound Test" )
PORT_DIPSETTING( 0x40, DEF_STR( Off ) )
PORT_DIPSETTING( 0x00, DEF_STR( On ) )
PORT_BIT( 0x80, 0x80, IPT_UNKNOWN ) /* To U3-6 on QBert */
INPUT_PORTS_END
/*************************************
*
* Rev. 2 communication handlers

File diff suppressed because it is too large Load Diff

View File

@ -7,6 +7,12 @@
#include "machine/6532riot.h"
#define GOTTLIEB_VIDEO_HCOUNT 318
#define GOTTLIEB_VIDEO_HBLANK 256
#define GOTTLIEB_VIDEO_VCOUNT 256
#define GOTTLIEB_VIDEO_VBLANK 240
/*----------- defined in audio/gottlieb.c -----------*/
WRITE8_HANDLER( gottlieb_sh_w );
@ -14,6 +20,7 @@ WRITE8_HANDLER( gottlieb_sh_w );
MACHINE_DRIVER_EXTERN( gottlieb_soundrev1 );
MACHINE_DRIVER_EXTERN( gottlieb_soundrev2 );
INPUT_PORTS_EXTERN( gottlieb1_sound );
INPUT_PORTS_EXTERN( gottlieb2_sound );
@ -31,4 +38,6 @@ extern WRITE8_HANDLER( gottlieb_laserdisc_video_control_w );
extern WRITE8_HANDLER( gottlieb_paletteram_w );
VIDEO_START( gottlieb );
VIDEO_START( gottlieb_laserdisc );
VIDEO_UPDATE( gottlieb );
VIDEO_UPDATE( gottlieb_laserdisc );

View File

@ -5,6 +5,8 @@
***************************************************************************/
#include "driver.h"
#include "gottlieb.h"
#include "machine/laserdsc.h"
#include "video/resnet.h"
UINT8 *gottlieb_charram;
@ -12,12 +14,16 @@ UINT8 *gottlieb_charram;
UINT8 gottlieb_gfxcharlo;
UINT8 gottlieb_gfxcharhi;
static int background_priority = 0;
static int spritebank;
static UINT8 background_priority = 0;
static UINT8 spritebank;
static tilemap *bg_tilemap;
static double weights[4];
static render_texture *video_texture;
static render_texture *overlay_texture;
static const rectangle overlay_clip = { 0, GOTTLIEB_VIDEO_HBLANK-1, 0, GOTTLIEB_VIDEO_VBLANK-8 };
/*************************************
@ -41,7 +47,7 @@ WRITE8_HANDLER( gottlieb_paletteram_w )
val = paletteram[offset | 1];
r = combine_4_weights(weights, (val >> 0) & 1, (val >> 1) & 1, (val >> 2) & 1, (val >> 3) & 1);
palette_set_color(machine, offset / 2, MAKE_RGB(r, g, b));
palette_set_color(machine, offset / 2, MAKE_ARGB(((offset & ~1) == 0) ? 0x00 : 0xff, r, g, b));
}
@ -89,6 +95,7 @@ WRITE8_HANDLER( gottlieb_laserdisc_video_control_w )
/* bit 2 video enable (0 = black screen) */
/* bit 3 genlock control (1 = show laserdisc image) */
render_container_set_palette_alpha(render_container_get_screen(machine->primary_screen), 0, (data & 0x08) ? 0x00 : 0xff);
}
@ -150,6 +157,27 @@ VIDEO_START( gottlieb )
bg_tilemap = tilemap_create(get_bg_tile_info, tilemap_scan_rows, 8, 8, 32, 32);
tilemap_set_transparent_pen(bg_tilemap, 0);
tilemap_set_scrolldx(bg_tilemap, 0, 318 - 256);
/* save some state */
state_save_register_global(background_priority);
state_save_register_global(spritebank);
}
VIDEO_START( gottlieb_laserdisc )
{
/* handle normal video */
VIDEO_START_CALL(gottlieb);
/* allocate an overlay texture */
overlay_texture = render_texture_alloc(NULL, NULL);
if (overlay_texture == NULL)
fatalerror("Out of memory allocating overlay texture");
/* allocate a video texture */
video_texture = render_texture_alloc(NULL, NULL);
if (video_texture == NULL)
fatalerror("Out of memory allocating video texture");
}
@ -209,3 +237,37 @@ VIDEO_UPDATE( gottlieb )
return 0;
}
VIDEO_UPDATE( gottlieb_laserdisc )
{
const device_config *laserdisc = device_list_first(screen->machine->config->devicelist, LASERDISC);
rectangle clip = *cliprect;
bitmap_t *video_bitmap;
/* scale the cliprect to the screen and render it */
clip.min_x = 0;
clip.max_x = GOTTLIEB_VIDEO_HBLANK - 1;
clip.min_y = cliprect->min_y * GOTTLIEB_VIDEO_VCOUNT / bitmap->height;
clip.max_y = (cliprect->max_y + 1) * GOTTLIEB_VIDEO_VCOUNT / bitmap->height - 1;
video_update_gottlieb(screen, bitmap, &clip);
/* if this is the last update, handle it */
if (cliprect->max_y == video_screen_get_visible_area(screen)->max_y)
{
/* update the texture with the overlay contents */
render_texture_set_bitmap(overlay_texture, bitmap, &overlay_clip, 0, TEXFORMAT_PALETTEA16);
/* now talk to the laserdisc */
laserdisc_get_video(laserdisc, &video_bitmap);
if (video_bitmap != NULL)
render_texture_set_bitmap(video_texture, video_bitmap, NULL, 0, TEXFORMAT_YUY16);
/* add both quads to the screen */
render_container_empty(render_container_get_screen(screen));
render_screen_add_quad(screen, 0.0f, 0.0f, 1.0f, 1.0f, MAKE_ARGB(0xff,0xff,0xff,0xff), video_texture, PRIMFLAG_BLENDMODE(BLENDMODE_NONE) | PRIMFLAG_SCREENTEX(1));
render_screen_add_quad(screen, 0.0f, 0.0f, 1.0f, 1.0f, MAKE_ARGB(0xff,0xff,0xff,0xff), overlay_texture, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_SCREENTEX(1));
}
return 0;
}