mirror of
https://github.com/holub/mame
synced 2025-04-16 05:24:54 +03:00
Time Traveler (set 1) - promoted to working (#9468) [Ryan Holtz]
* machine/laserdsc.cpp: Added functionality to retrieve if a disc is CAV. * machine/ldv4200hle.cpp: Added high-level Pioneer LD-V4200 player emulation. Machines promoted to working ---------------------------- Time Traveler (set 1) [Ryan Holtz, Matt O, ld-decode Team]
This commit is contained in:
parent
524986a648
commit
06e60e848f
@ -1974,6 +1974,18 @@ if (MACHINES["LDV1000"]~=null) then
|
||||
}
|
||||
end
|
||||
|
||||
---------------------------------------------------
|
||||
--
|
||||
--@src/devices/machine/ldv4200hle.h,MACHINES["LDV4200HLE"] = true
|
||||
---------------------------------------------------
|
||||
|
||||
if (MACHINES["LDV4200HLE"]~=null) then
|
||||
files {
|
||||
MAME_DIR .. "src/devices/machine/ldv4200hle.cpp",
|
||||
MAME_DIR .. "src/devices/machine/ldv4200hle.h",
|
||||
}
|
||||
end
|
||||
|
||||
---------------------------------------------------
|
||||
--
|
||||
--@src/devices/machine/ldp1000.h,MACHINES["LDP1000"] = true
|
||||
|
@ -542,6 +542,7 @@ MACHINES["LC89510"] = true
|
||||
MACHINES["LDPR8210"] = true
|
||||
MACHINES["LDSTUB"] = true
|
||||
MACHINES["LDV1000"] = true
|
||||
MACHINES["LDV4200HLE"] = true
|
||||
MACHINES["LDP1000"] = true
|
||||
MACHINES["LDP1450"] = true
|
||||
MACHINES["LDVP931"] = true
|
||||
|
@ -69,6 +69,7 @@ laserdisc_device::laserdisc_device(const machine_config &mconfig, device_type ty
|
||||
m_overclip(0, -1, 0, -1),
|
||||
m_overupdate_rgb32(*this),
|
||||
m_disc(nullptr),
|
||||
m_is_cav_disc(false),
|
||||
m_width(0),
|
||||
m_height(0),
|
||||
m_fps_times_1million(0),
|
||||
@ -398,7 +399,9 @@ void laserdisc_device::set_slider_speed(int32_t tracks_per_vsync)
|
||||
|
||||
// negative values store negative times
|
||||
else
|
||||
{
|
||||
m_attospertrack = -(vsyncperiod / -tracks_per_vsync).as_attoseconds();
|
||||
}
|
||||
|
||||
if (LOG_SLIDER)
|
||||
printf("Slider speed = %d\n", tracks_per_vsync);
|
||||
@ -685,6 +688,23 @@ void laserdisc_device::init_disc()
|
||||
err = m_disc->read_metadata(AV_LD_METADATA_TAG, 0, m_vbidata);
|
||||
if (err || (m_vbidata.size() != totalhunks * VBI_PACKED_BYTES))
|
||||
throw emu_fatalerror("Precomputed VBI metadata missing or incorrect size");
|
||||
|
||||
m_is_cav_disc = false;
|
||||
vbi_metadata vbidata_even = { 0 };
|
||||
vbi_metadata_unpack(&vbidata_even, nullptr, &m_vbidata[m_chdtracks * VBI_PACKED_BYTES]);
|
||||
if ((vbidata_even.line1718 & VBI_MASK_CAV_PICTURE) == VBI_CODE_CAV_PICTURE)
|
||||
{
|
||||
m_is_cav_disc = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
vbi_metadata vbidata_odd = { 0 };
|
||||
vbi_metadata_unpack(&vbidata_odd, nullptr, &m_vbidata[(m_chdtracks + 1) * VBI_PACKED_BYTES]);
|
||||
if ((vbidata_odd.line1718 & VBI_MASK_CAV_PICTURE) == VBI_CODE_CAV_PICTURE)
|
||||
{
|
||||
m_is_cav_disc = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
m_maxtrack = std::max(m_maxtrack, VIRTUAL_LEAD_IN_TRACKS + VIRTUAL_LEAD_OUT_TRACKS + m_chdtracks);
|
||||
}
|
||||
|
@ -233,6 +233,7 @@ protected:
|
||||
int32_t generic_update(const vbi_metadata &vbi, int fieldnum, const attotime &curtime, player_state_info &curstate);
|
||||
|
||||
// general helpers
|
||||
bool is_cav_disc() const { return m_is_cav_disc; }
|
||||
bool is_start_of_frame(const vbi_metadata &vbi);
|
||||
int frame_from_metadata(const vbi_metadata &metadata);
|
||||
int chapter_from_metadata(const vbi_metadata &metadata);
|
||||
@ -277,6 +278,7 @@ private:
|
||||
// disc parameters
|
||||
chd_file * m_disc; // handle to the disc itself
|
||||
std::vector<uint8_t> m_vbidata; // pointer to precomputed VBI data
|
||||
bool m_is_cav_disc; // precomputed check if the mounted disc is CAV
|
||||
int m_width; // width of video
|
||||
int m_height; // height of video
|
||||
uint32_t m_fps_times_1million; // frame rate of video
|
||||
|
948
src/devices/machine/ldv4200hle.cpp
Normal file
948
src/devices/machine/ldv4200hle.cpp
Normal file
@ -0,0 +1,948 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:Ryan Holtz
|
||||
/*************************************************************************
|
||||
|
||||
ldv4200hle.cpp
|
||||
|
||||
Pioneer LD-V4200 laserdisc player simulation.
|
||||
|
||||
**************************************************************************
|
||||
|
||||
To do:
|
||||
|
||||
* On-screen display support
|
||||
* Better CLV support
|
||||
* Chapter-search support
|
||||
* Commands that Time Traveler doesn't use:
|
||||
- Door Open/Close
|
||||
- Reject
|
||||
- Pause/Still
|
||||
- Scan Forward/Reverse
|
||||
- Multitrack-Jump Forward/Reverse
|
||||
- Clear
|
||||
- Leadout Symbol
|
||||
- Key Lock and on-screen functions
|
||||
- Status Requests
|
||||
- Registers A-D
|
||||
|
||||
*************************************************************************/
|
||||
|
||||
|
||||
#include "emu.h"
|
||||
#include "ldv4200hle.h"
|
||||
|
||||
|
||||
#define LOG_COMMAND_BYTES (1 << 1U)
|
||||
#define LOG_COMMANDS (1 << 2U)
|
||||
#define LOG_COMMAND_BUFFERS (1 << 3U)
|
||||
#define LOG_REPLIES (1 << 4U)
|
||||
#define LOG_REPLY_BYTES (1 << 5U)
|
||||
#define LOG_SEARCHES (1 << 6U)
|
||||
#define LOG_STOPS (1 << 7U)
|
||||
#define LOG_SQUELCHES (1 << 8U)
|
||||
#define LOG_FRAMES (1 << 9U)
|
||||
#define LOG_ALL (LOG_COMMAND_BYTES | LOG_COMMANDS | LOG_COMMAND_BUFFERS | LOG_REPLY_BYTES | LOG_SEARCHES | LOG_STOPS | LOG_SQUELCHES | LOG_FRAMES)
|
||||
|
||||
#define VERBOSE (0)
|
||||
#include "logmacro.h"
|
||||
|
||||
|
||||
|
||||
//**************************************************************************
|
||||
// GLOBAL VARIABLES
|
||||
//**************************************************************************
|
||||
|
||||
// devices
|
||||
DEFINE_DEVICE_TYPE(PIONEER_LDV4200HLE, pioneer_ldv4200hle_device, "ldv4200hle", "Pioneer LD-V4200 HLE")
|
||||
|
||||
|
||||
|
||||
//**************************************************************************
|
||||
// PIONEER LD-V4200 HLE IMPLEMENTATION
|
||||
//**************************************************************************
|
||||
|
||||
//-------------------------------------------------
|
||||
// pioneer_ldv4200hle_device - constructor
|
||||
//-------------------------------------------------
|
||||
|
||||
pioneer_ldv4200hle_device::pioneer_ldv4200hle_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
|
||||
: laserdisc_device(mconfig, PIONEER_LDV4200HLE, tag, owner, clock)
|
||||
, device_serial_interface(mconfig, *this)
|
||||
, m_serial_tx(*this)
|
||||
, m_vbi_fetch(nullptr)
|
||||
, m_cmd_length(0)
|
||||
, m_cmd_running(false)
|
||||
, m_reply_write_index(0)
|
||||
, m_reply_read_index(0)
|
||||
, m_mode(MODE_PARK)
|
||||
, m_chapter(0)
|
||||
, m_time(0)
|
||||
, m_frame(0)
|
||||
, m_search_chapter(~0U)
|
||||
, m_search_frame(~0U)
|
||||
, m_mark_chapter(~0U)
|
||||
, m_mark_frame(~0U)
|
||||
, m_key_lock(0)
|
||||
, m_video_switch(1)
|
||||
, m_audio_switch(0)
|
||||
, m_display_switch(0)
|
||||
, m_address_flag(ADDRESS_FRAME)
|
||||
, m_speed(60)
|
||||
, m_speed_accum(0)
|
||||
, m_comm_ctrl(3)
|
||||
, m_reg_a(3)
|
||||
, m_reg_b(0)
|
||||
, m_reg_c(0)
|
||||
, m_reg_d(0)
|
||||
, m_aux_port(3)
|
||||
, m_curr_frame(0)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// add_command_byte - handle a new data byte
|
||||
// received over the serial link
|
||||
//-------------------------------------------------
|
||||
|
||||
void pioneer_ldv4200hle_device::add_command_byte(uint8_t data)
|
||||
{
|
||||
// Space and L/F codes are ignored in command sequences, per LD-V4400 Level I & III User's Manual, pg. 4-8
|
||||
if (data == 0x20 || data == 0x0a)
|
||||
return;
|
||||
|
||||
LOGMASKED(LOG_COMMAND_BYTES, "Command byte added: %02x\n", data);
|
||||
if (m_cmd_length < std::size(m_cmd_buffer))
|
||||
{
|
||||
m_cmd_buffer[m_cmd_length] = data;
|
||||
m_cmd_length++;
|
||||
}
|
||||
if (data == 0x0d)
|
||||
{
|
||||
normalize_command_buffer();
|
||||
process_command_buffer();
|
||||
m_cmd_length = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// queue_reply - queues a reply string to send
|
||||
// back to the host
|
||||
//-------------------------------------------------
|
||||
|
||||
void pioneer_ldv4200hle_device::queue_reply(const char *reply)
|
||||
{
|
||||
char print_buf[128];
|
||||
|
||||
uint8_t max_writable = (uint8_t)std::size(m_reply_buffer);
|
||||
for (uint8_t i = 0; i < max_writable && reply[i] != 0; i++)
|
||||
{
|
||||
m_reply_buffer[m_reply_write_index] = reply[i];
|
||||
m_reply_write_index = (m_reply_write_index + 1) % max_writable;
|
||||
print_buf[i] = (reply[i] == '\x0d' ? 0 : reply[i]);
|
||||
}
|
||||
LOGMASKED(LOG_REPLIES, "Sending reply: %s\n", print_buf);
|
||||
|
||||
if (!m_replying)
|
||||
{
|
||||
m_replying = true;
|
||||
LOGMASKED(LOG_REPLY_BYTES, "Sending reply byte: %02x\n", (uint8_t)m_reply_buffer[m_reply_read_index]);
|
||||
transmit_register_setup(m_reply_buffer[m_reply_read_index]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// queue_error - queues an error-code string to
|
||||
// send back to the host
|
||||
//-------------------------------------------------
|
||||
|
||||
void pioneer_ldv4200hle_device::queue_error(error_code err)
|
||||
{
|
||||
char buf[5] = { 'E', '0', '0', '\x0d', '\0' };
|
||||
buf[1] += err / 10;
|
||||
buf[2] += err % 10;
|
||||
queue_reply(buf);
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// normalize_command_buffer - ensure any alphabet
|
||||
// characters in the command buffer are
|
||||
// upper-cased for matching purposes.
|
||||
//-------------------------------------------------
|
||||
|
||||
void pioneer_ldv4200hle_device::normalize_command_buffer()
|
||||
{
|
||||
char print_buf[64];
|
||||
for (uint8_t i = 0; i < m_cmd_length; i++)
|
||||
{
|
||||
if (m_cmd_buffer[i] >= 'a' && m_cmd_buffer[i] <= 'z')
|
||||
{
|
||||
m_cmd_buffer[i] &= ~0x20;
|
||||
}
|
||||
print_buf[i] = (char)m_cmd_buffer[i];
|
||||
}
|
||||
print_buf[m_cmd_length - 1] = '\0';
|
||||
LOGMASKED(LOG_COMMAND_BUFFERS, "Command Buffer: %02d:%02d:%02d: %s\n", (int)(machine().time().seconds() / 60), (int)(machine().time().seconds()) % 60, (machine().time() * 100).seconds() % 100, print_buf);
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// process_command_buffer - process a command
|
||||
// line sent from the host
|
||||
//-------------------------------------------------
|
||||
|
||||
void pioneer_ldv4200hle_device::process_command_buffer()
|
||||
{
|
||||
if (m_cmd_length <= 1)
|
||||
return;
|
||||
|
||||
error_code err = ERR_NONE;
|
||||
uint8_t cmd_index = 0;
|
||||
bool send_reply = true;
|
||||
while (cmd_index < m_cmd_length && err == ERR_NONE)
|
||||
{
|
||||
if (cmd_index == (m_cmd_length - 1) && m_cmd_buffer[cmd_index] == 0x0d)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
uint32_t value = ~0U;
|
||||
if (is_number(m_cmd_buffer[cmd_index]))
|
||||
{
|
||||
cmd_index += parse_numeric_value(cmd_index, value, err);
|
||||
}
|
||||
if (err == ERR_NONE)
|
||||
{
|
||||
cmd_index += process_command(cmd_index, value, err);
|
||||
if (m_cmd_running)
|
||||
{
|
||||
send_reply = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (send_reply)
|
||||
{
|
||||
if (err == ERR_NONE)
|
||||
{
|
||||
queue_reply("R\x0d");
|
||||
}
|
||||
else
|
||||
{
|
||||
queue_error(err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// bcd_to_literal - converts a BCD value used in
|
||||
// commands a direct numeric value
|
||||
//-------------------------------------------------
|
||||
|
||||
uint32_t pioneer_ldv4200hle_device::bcd_to_literal(uint32_t bcd)
|
||||
{
|
||||
uint32_t value = 0;
|
||||
uint32_t shift = 28;
|
||||
uint32_t multiplier = 10000000;
|
||||
for (uint32_t i = 0; i < 8; i++)
|
||||
{
|
||||
uint32_t digit = (bcd >> shift) & 0xf;
|
||||
bcd &= ~(0xf << shift);
|
||||
|
||||
value += digit * multiplier;
|
||||
|
||||
multiplier /= 10;
|
||||
shift -= 4;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// is_number - indicates if a given character is
|
||||
// a numeric value
|
||||
//-------------------------------------------------
|
||||
|
||||
bool pioneer_ldv4200hle_device::is_number(char value)
|
||||
{
|
||||
return value >= '0' && value <= '9';
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// parse_numeric_value - parses a numeric value
|
||||
// from the command buffer
|
||||
//-------------------------------------------------
|
||||
|
||||
uint8_t pioneer_ldv4200hle_device::parse_numeric_value(uint8_t cmd_index, uint32_t &value, error_code &err)
|
||||
{
|
||||
static const uint8_t MAX_NUMBER_LENGTH = 7;
|
||||
uint8_t number_length = 0;
|
||||
value = 0;
|
||||
while (number_length < MAX_NUMBER_LENGTH && is_number(m_cmd_buffer[cmd_index]) && cmd_index < m_cmd_length)
|
||||
{
|
||||
value *= 10;
|
||||
value += m_cmd_buffer[cmd_index] - '0';
|
||||
cmd_index++;
|
||||
number_length++;
|
||||
}
|
||||
|
||||
if (cmd_index == m_cmd_length)
|
||||
{
|
||||
err = ERR_COMMUNICATION;
|
||||
return number_length;
|
||||
}
|
||||
|
||||
if (number_length == MAX_NUMBER_LENGTH && is_number(m_cmd_buffer[cmd_index]))
|
||||
{
|
||||
err = ERR_MISSING_ARGUMENT;
|
||||
return number_length;
|
||||
}
|
||||
|
||||
return number_length;
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// process_command - processes a single command
|
||||
// from the command buffer
|
||||
//-------------------------------------------------
|
||||
|
||||
uint8_t pioneer_ldv4200hle_device::process_command(uint8_t cmd_index, uint32_t value, error_code &err)
|
||||
{
|
||||
const uint8_t remaining_bytes = m_cmd_length - cmd_index;
|
||||
if (remaining_bytes == 1 && m_cmd_buffer[cmd_index] == 0x0d)
|
||||
{
|
||||
// Done processing
|
||||
return remaining_bytes;
|
||||
}
|
||||
else if (remaining_bytes < 3)
|
||||
{
|
||||
// Not enough data in the buffer to form a valid command
|
||||
err = ERR_COMMUNICATION;
|
||||
return remaining_bytes;
|
||||
}
|
||||
|
||||
uint16_t command = (m_cmd_buffer[cmd_index] << 8) | m_cmd_buffer[cmd_index + 1];
|
||||
switch (command)
|
||||
{
|
||||
case CMD_DOOR_OPEN:
|
||||
LOGMASKED(LOG_COMMANDS, "%s: Command: Door Open\n", machine().describe_context());
|
||||
break;
|
||||
case CMD_DOOR_CLOSE:
|
||||
LOGMASKED(LOG_COMMANDS, "%s: Command: Door Close\n", machine().describe_context());
|
||||
break;
|
||||
case CMD_REJECT:
|
||||
LOGMASKED(LOG_COMMANDS, "%s: Command: Reject\n", machine().describe_context());
|
||||
break;
|
||||
case CMD_START:
|
||||
LOGMASKED(LOG_COMMANDS | LOG_SQUELCHES, "%s: Command: Start (squelching audio, unsquelching + disabling video)\n", machine().describe_context());
|
||||
m_mode = MODE_PAUSE;
|
||||
video_enable(false);
|
||||
set_video_squelch(false);
|
||||
set_audio_squelch(true, true);
|
||||
break;
|
||||
case CMD_PLAY:
|
||||
LOGMASKED(LOG_COMMANDS, "%s: Command: Play [%d] (cancelling search)\n", machine().describe_context(), value == ~0U ? 0 : value);
|
||||
m_speed_accum = 0;
|
||||
m_mode = MODE_PLAY;
|
||||
update_audio_squelch();
|
||||
update_video_enable();
|
||||
if (value != ~0U)
|
||||
{
|
||||
LOGMASKED(LOG_COMMANDS, "%s: Setting stop frame\n", machine().describe_context());
|
||||
m_mark_frame = value + 1;
|
||||
m_cmd_running = true;
|
||||
}
|
||||
m_search_frame = ~0U;
|
||||
m_search_chapter = ~0U;
|
||||
break;
|
||||
case CMD_PAUSE:
|
||||
LOGMASKED(LOG_COMMANDS, "%s: Command: Pause\n", machine().describe_context());
|
||||
m_mode = MODE_PAUSE;
|
||||
video_enable(false);
|
||||
set_audio_squelch(true, true);
|
||||
break;
|
||||
case CMD_STILL:
|
||||
LOGMASKED(LOG_COMMANDS, "%s: Command: Still\n", machine().describe_context());
|
||||
m_mode = MODE_STILL;
|
||||
set_audio_squelch(true, true);
|
||||
break;
|
||||
case CMD_STEP_FORWARD:
|
||||
LOGMASKED(LOG_COMMANDS, "%s: Command: Step Forward\n", machine().describe_context());
|
||||
m_mode = MODE_STILL;
|
||||
set_audio_squelch(true, true);
|
||||
m_mark_frame = ~0U;
|
||||
advance_slider(1);
|
||||
break;
|
||||
case CMD_STEP_REVERSE:
|
||||
LOGMASKED(LOG_COMMANDS, "%s: Command: Step Reverse\n", machine().describe_context());
|
||||
m_mode = MODE_STILL;
|
||||
set_audio_squelch(true, true);
|
||||
m_mark_frame = ~0U;
|
||||
advance_slider(-1);
|
||||
break;
|
||||
case CMD_SCAN_FORWARD:
|
||||
LOGMASKED(LOG_COMMANDS, "%s: Command: Scan Forward\n", machine().describe_context());
|
||||
break;
|
||||
case CMD_SCAN_REVERSE:
|
||||
LOGMASKED(LOG_COMMANDS, "%s: Command: Scan Reverse\n", machine().describe_context());
|
||||
break;
|
||||
case CMD_MULTISPEED_FORWARD:
|
||||
LOGMASKED(LOG_COMMANDS, "%s: Command: Multi-Speed Forward (%d) (cancelling search)\n", machine().describe_context(), value == ~0U ? 0 : value);
|
||||
m_mode = MODE_MS_FORWARD;
|
||||
m_search_frame = ~0U;
|
||||
m_search_chapter = ~0U;
|
||||
if (value != ~0U)
|
||||
{
|
||||
LOGMASKED(LOG_COMMANDS, "%s: Setting stop frame\n", machine().describe_context());
|
||||
m_mark_frame = value + 1;
|
||||
m_cmd_running = true;
|
||||
}
|
||||
break;
|
||||
case CMD_MULTISPEED_REVERSE:
|
||||
LOGMASKED(LOG_COMMANDS, "%s: Command: Multi-Speed Reverse (%d) (cancelling search)\n", machine().describe_context(), value == ~0U ? 0 : value);
|
||||
m_mode = MODE_MS_REVERSE;
|
||||
m_search_frame = ~0U;
|
||||
m_search_chapter = ~0U;
|
||||
if (value != ~0U)
|
||||
{
|
||||
LOGMASKED(LOG_COMMANDS, "%s: Setting stop frame\n", machine().describe_context());
|
||||
m_mark_frame = value + 1;
|
||||
m_cmd_running = true;
|
||||
}
|
||||
break;
|
||||
case CMD_SPEED_SET:
|
||||
LOGMASKED(LOG_COMMANDS, "%s: Command: Speed Set %05d\n", machine().describe_context(), value);
|
||||
if (is_cav_disc())
|
||||
{
|
||||
m_speed = value;
|
||||
if (m_speed == 0)
|
||||
{
|
||||
m_speed = 1;
|
||||
}
|
||||
else if (m_speed > 255)
|
||||
{
|
||||
m_speed = 255;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
err = ERR_NOT_AVAILABLE;
|
||||
}
|
||||
break;
|
||||
case CMD_SEARCH:
|
||||
LOGMASKED(LOG_COMMANDS, "%s: Command: Search %d\n", machine().describe_context(), value);
|
||||
begin_search(value);
|
||||
m_cmd_running = true;
|
||||
m_mode = MODE_SEARCH;
|
||||
break;
|
||||
case CMD_MULTITRACK_FORWARD:
|
||||
LOGMASKED(LOG_COMMANDS, "%s: Command: Multi-Track Jump Forward %05d\n", machine().describe_context(), value);
|
||||
break;
|
||||
case CMD_MULTITRACK_REVERSE:
|
||||
LOGMASKED(LOG_COMMANDS, "%s: Command: Multi-Track Jump Reverse %05d\n", machine().describe_context(), value);
|
||||
break;
|
||||
case CMD_STOP_MARKER:
|
||||
LOGMASKED(LOG_COMMANDS, "%s: Command: Stop Marker %d\n", machine().describe_context(), value);
|
||||
if (m_address_flag == ADDRESS_FRAME)
|
||||
{
|
||||
m_mark_frame = value + 1;
|
||||
}
|
||||
else if (m_address_flag == ADDRESS_CHAPTER)
|
||||
{
|
||||
m_mark_chapter = value;
|
||||
}
|
||||
break;
|
||||
case CMD_FRAME_SET:
|
||||
LOGMASKED(LOG_COMMANDS, "%s: Command: Frame Set\n", machine().describe_context());
|
||||
m_address_flag = ADDRESS_FRAME;
|
||||
break;
|
||||
case CMD_TIME_SET:
|
||||
LOGMASKED(LOG_COMMANDS, "%s: Command: Time Set\n", machine().describe_context());
|
||||
if (!is_cav_disc())
|
||||
{
|
||||
m_address_flag = ADDRESS_TIME;
|
||||
}
|
||||
else
|
||||
{
|
||||
err = ERR_NOT_AVAILABLE;
|
||||
}
|
||||
break;
|
||||
case CMD_CHAPTER_SET:
|
||||
LOGMASKED(LOG_COMMANDS, "%s: Command: Chapter Set\n", machine().describe_context());
|
||||
m_address_flag = ADDRESS_CHAPTER;
|
||||
break;
|
||||
case CMD_CLEAR:
|
||||
LOGMASKED(LOG_COMMANDS, "%s: Command: Clear\n", machine().describe_context());
|
||||
break;
|
||||
case CMD_LEADOUT_SYMBOL:
|
||||
LOGMASKED(LOG_COMMANDS, "%s: Command: Lead-Out Symbol\n", machine().describe_context());
|
||||
break;
|
||||
case CMD_AUDIO_CTRL:
|
||||
m_audio_switch = value;
|
||||
LOGMASKED(LOG_COMMANDS, "%s: Command: Audio Control %05d\n", machine().describe_context(), value);
|
||||
update_audio_squelch();
|
||||
break;
|
||||
case CMD_VIDEO_CTRL:
|
||||
LOGMASKED(LOG_COMMANDS, "%s: Command: Video Control %05d\n", machine().describe_context(), value);
|
||||
m_video_switch = value;
|
||||
update_video_enable();
|
||||
break;
|
||||
case CMD_KEY_LOCK:
|
||||
LOGMASKED(LOG_COMMANDS, "%s: Command: Key Lock %05d\n", machine().describe_context(), value);
|
||||
break;
|
||||
case CMD_DISPLAY_CONTROL:
|
||||
LOGMASKED(LOG_COMMANDS, "%s: Command: Display Control %05d\n", machine().describe_context(), value);
|
||||
break;
|
||||
case CMD_CLEAR_SCREEN:
|
||||
LOGMASKED(LOG_COMMANDS, "%s: Command: Clear Screen\n", machine().describe_context());
|
||||
break;
|
||||
case CMD_PRINT_CHAR:
|
||||
LOGMASKED(LOG_COMMANDS, "%s: Command: Print Character %05d\n", machine().describe_context(), value);
|
||||
break;
|
||||
case CMD_REQ_FRAME_NUMBER:
|
||||
LOGMASKED(LOG_COMMANDS, "%s: Command: Frame Number Request\n", machine().describe_context());
|
||||
break;
|
||||
case CMD_REQ_TIME_CODE:
|
||||
LOGMASKED(LOG_COMMANDS, "%s: Command: Time Code Request\n", machine().describe_context());
|
||||
break;
|
||||
case CMD_REQ_CHAPTER_NUMBER:
|
||||
LOGMASKED(LOG_COMMANDS, "%s: Command: Chapter Number Request\n", machine().describe_context());
|
||||
break;
|
||||
case CMD_REQ_PLAYER_MODE:
|
||||
LOGMASKED(LOG_COMMANDS, "%s: Command: Player Active Mode Request\n", machine().describe_context());
|
||||
break;
|
||||
case CMD_REQ_DISC_STATUS:
|
||||
LOGMASKED(LOG_COMMANDS, "%s: Command: Disc Status Request\n", machine().describe_context());
|
||||
break;
|
||||
case CMD_REQ_LDP_MODEL:
|
||||
LOGMASKED(LOG_COMMANDS, "%s: Command: LDP Model Name Request\n", machine().describe_context());
|
||||
break;
|
||||
case CMD_REQ_PIONEER_DISC_ID:
|
||||
LOGMASKED(LOG_COMMANDS, "%s: Command: Pioneer User's Code Request (Disc ID)\n", machine().describe_context());
|
||||
break;
|
||||
case CMD_REQ_STANDARD_DISC_ID:
|
||||
LOGMASKED(LOG_COMMANDS, "%s: Command: Standard User's Code Request (Disc ID)\n", machine().describe_context());
|
||||
break;
|
||||
case CMD_REQ_TV_SYSTEM:
|
||||
LOGMASKED(LOG_COMMANDS, "%s: Command: Television System Request\n", machine().describe_context());
|
||||
break;
|
||||
case CMD_COMMUNICATION_CTRL:
|
||||
LOGMASKED(LOG_COMMANDS, "%s: Command: Communication Control %05d\n", machine().describe_context(), value);
|
||||
break;
|
||||
case CMD_REQ_CCR_MODE:
|
||||
LOGMASKED(LOG_COMMANDS, "%s: Command: CCR Mode Request\n", machine().describe_context());
|
||||
break;
|
||||
case CMD_REGISTER_A_SET:
|
||||
LOGMASKED(LOG_COMMANDS, "%s: Command: Register A Set (Display) %d\n", machine().describe_context(), value);
|
||||
break;
|
||||
case CMD_REGISTER_B_SET:
|
||||
LOGMASKED(LOG_COMMANDS, "%s: Command: Register B Set (Squelch Control) %d\n", machine().describe_context(), value);
|
||||
break;
|
||||
case CMD_REGISTER_C_SET:
|
||||
LOGMASKED(LOG_COMMANDS, "%s: Command: Register C Set (Miscellaneous) %d\n", machine().describe_context(), value);
|
||||
break;
|
||||
case CMD_REGISTER_D_SET:
|
||||
LOGMASKED(LOG_COMMANDS, "%s: Command: Register D Set (RS-232) %d\n", machine().describe_context(), value);
|
||||
break;
|
||||
case CMD_REQ_REGISTER_A:
|
||||
LOGMASKED(LOG_COMMANDS, "%s: Command: Register A Request (Display)\n", machine().describe_context());
|
||||
break;
|
||||
case CMD_REQ_REGISTER_B:
|
||||
LOGMASKED(LOG_COMMANDS, "%s: Command: Register B Request (Squelch Control)\n", machine().describe_context());
|
||||
break;
|
||||
case CMD_REQ_REGISTER_C:
|
||||
LOGMASKED(LOG_COMMANDS, "%s: Command: Register C Request (Miscellaneous)\n", machine().describe_context());
|
||||
break;
|
||||
case CMD_REQ_REGISTER_D:
|
||||
LOGMASKED(LOG_COMMANDS, "%s: Command: Register D Request (RS-232)\n", machine().describe_context());
|
||||
break;
|
||||
case CMD_REQ_INPUT_UNIT:
|
||||
LOGMASKED(LOG_COMMANDS, "%s: Command: Input Unit Request\n", machine().describe_context());
|
||||
break;
|
||||
case CMD_INPUT_NUMBER_WAIT:
|
||||
LOGMASKED(LOG_COMMANDS, "%s: Command: Input Number Wait\n", machine().describe_context());
|
||||
break;
|
||||
default:
|
||||
LOGMASKED(LOG_COMMANDS, "%s: Command: Unknown (%c%c)\n", machine().describe_context(), m_cmd_buffer[cmd_index], m_cmd_buffer[cmd_index + 1]);
|
||||
err = ERR_NOT_AVAILABLE;
|
||||
break;
|
||||
}
|
||||
|
||||
return 2;
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// begin_search - initiates a search operation
|
||||
//-------------------------------------------------
|
||||
|
||||
void pioneer_ldv4200hle_device::begin_search(uint32_t value)
|
||||
{
|
||||
if (m_address_flag == ADDRESS_FRAME)
|
||||
{
|
||||
m_search_frame = value + 1;
|
||||
LOGMASKED(LOG_SEARCHES, "%s: Beginning search from frame address %d\n", machine().describe_context(), value);
|
||||
}
|
||||
else if (m_address_flag == ADDRESS_CHAPTER)
|
||||
{
|
||||
m_search_chapter = value;
|
||||
LOGMASKED(LOG_SEARCHES, "%s: Beginning search from chapter address %d\n", machine().describe_context(), value);
|
||||
}
|
||||
|
||||
set_audio_squelch(true, true);
|
||||
|
||||
if (std::abs((int32_t)m_search_frame - (int32_t)m_curr_frame) > 100)
|
||||
{
|
||||
LOGMASKED(LOG_SEARCHES | LOG_SQUELCHES, "%s: Search distance is outside +/- 100 frames, squelching audio+video\n", machine().describe_context());
|
||||
video_enable(false);
|
||||
set_audio_squelch(true, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOGMASKED(LOG_SEARCHES | LOG_SQUELCHES, "%s: Search distance is within +/- 100 frames, squelching audio and doing live search\n", machine().describe_context());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// update_audio_squelch - set audio squelch state
|
||||
// on the base device based on our audio switch
|
||||
//-------------------------------------------------
|
||||
|
||||
void pioneer_ldv4200hle_device::update_audio_squelch()
|
||||
{
|
||||
const bool squelch_both = (m_mode == MODE_STILL || m_mode == MODE_PAUSE || m_mode == MODE_SEARCH);
|
||||
const bool squelch_left = !(m_audio_switch == 1 || m_audio_switch == 3) || squelch_both;
|
||||
const bool squelch_right = !(m_audio_switch == 2 || m_audio_switch == 3) || squelch_both;
|
||||
set_audio_squelch(squelch_left, squelch_right);
|
||||
LOGMASKED(LOG_SQUELCHES, "%s: Updating audio squelch (L:%d, R:%d)\n", machine().describe_context(), squelch_left, squelch_right);
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// update_video_enable - set video enable state
|
||||
// on the base device based on our video switch
|
||||
//-------------------------------------------------
|
||||
|
||||
void pioneer_ldv4200hle_device::update_video_enable()
|
||||
{
|
||||
video_enable(m_video_switch == 1 && (m_mode == MODE_STILL || m_mode == MODE_PLAY || m_mode == MODE_MS_FORWARD || m_mode == MODE_MS_REVERSE));
|
||||
LOGMASKED(LOG_SQUELCHES, "%s: Updating video enable (Switch:%d, Mode:%d)\n", machine().describe_context(), m_video_switch, m_mode);
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// device_start - device initialization
|
||||
//-------------------------------------------------
|
||||
|
||||
void pioneer_ldv4200hle_device::device_start()
|
||||
{
|
||||
// pass through to the parent
|
||||
laserdisc_device::device_start();
|
||||
|
||||
m_serial_tx.resolve_safe();
|
||||
|
||||
// allocate timers
|
||||
m_vbi_fetch = timer_alloc(TID_VBI_DATA_FETCH);
|
||||
|
||||
// register state saving
|
||||
save_item(NAME(m_cmd_buffer));
|
||||
save_item(NAME(m_cmd_length));
|
||||
save_item(NAME(m_cmd_running));
|
||||
save_item(NAME(m_reply_buffer));
|
||||
save_item(NAME(m_reply_write_index));
|
||||
save_item(NAME(m_reply_read_index));
|
||||
save_item(NAME(m_replying));
|
||||
save_item(NAME(m_mode));
|
||||
save_item(NAME(m_chapter));
|
||||
save_item(NAME(m_time));
|
||||
save_item(NAME(m_frame));
|
||||
save_item(NAME(m_search_chapter));
|
||||
save_item(NAME(m_search_frame));
|
||||
save_item(NAME(m_mark_chapter));
|
||||
save_item(NAME(m_mark_frame));
|
||||
save_item(NAME(m_key_lock));
|
||||
save_item(NAME(m_video_switch));
|
||||
save_item(NAME(m_audio_switch));
|
||||
save_item(NAME(m_display_switch));
|
||||
save_item(NAME(m_address_flag));
|
||||
save_item(NAME(m_speed));
|
||||
save_item(NAME(m_speed_accum));
|
||||
save_item(NAME(m_comm_ctrl));
|
||||
save_item(NAME(m_reg_a));
|
||||
save_item(NAME(m_reg_b));
|
||||
save_item(NAME(m_reg_c));
|
||||
save_item(NAME(m_reg_d));
|
||||
save_item(NAME(m_aux_port));
|
||||
save_item(NAME(m_curr_frame));
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// device_reset - device reset
|
||||
//-------------------------------------------------
|
||||
|
||||
void pioneer_ldv4200hle_device::device_reset()
|
||||
{
|
||||
// pass through to the parent
|
||||
laserdisc_device::device_reset();
|
||||
|
||||
// initialize diserial
|
||||
set_tra_rate(attotime::from_hz(4800));
|
||||
set_rcv_rate(attotime::from_hz(4800));
|
||||
set_data_frame(1, 8, PARITY_NONE, STOP_BITS_1);
|
||||
|
||||
// reset our state
|
||||
m_vbi_fetch->adjust(attotime::never);
|
||||
|
||||
std::fill_n(m_cmd_buffer, 0, std::size(m_cmd_buffer));
|
||||
m_cmd_length = 0;
|
||||
m_cmd_running = false;
|
||||
std::fill_n(m_reply_buffer, 0, std::size(m_reply_buffer));
|
||||
m_reply_write_index = 0;
|
||||
m_reply_read_index = 0;
|
||||
m_replying = false;
|
||||
m_mode = MODE_PARK;
|
||||
m_chapter = 0;
|
||||
m_time = 0;
|
||||
m_frame = 0;
|
||||
m_search_chapter = ~0U;
|
||||
m_search_frame = ~0U;
|
||||
m_mark_chapter = ~0U;
|
||||
m_mark_frame = ~0U;
|
||||
m_key_lock = 0;
|
||||
m_video_switch = 1;
|
||||
m_audio_switch = 0;
|
||||
m_display_switch = 0;
|
||||
m_address_flag = ADDRESS_FRAME;
|
||||
m_speed = 60;
|
||||
m_speed_accum = 0;
|
||||
m_comm_ctrl = 3;
|
||||
m_reg_a = 3;
|
||||
m_reg_b = 0;
|
||||
m_reg_c = 0;
|
||||
m_reg_d = 0;
|
||||
m_aux_port = 3;
|
||||
m_curr_frame = 0;
|
||||
|
||||
video_enable(false);
|
||||
set_audio_squelch(true, true);
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// device_timer - handle timers set by this
|
||||
// device
|
||||
//-------------------------------------------------
|
||||
|
||||
void pioneer_ldv4200hle_device::device_timer(emu_timer &timer, device_timer_id id, int param)
|
||||
{
|
||||
switch (id)
|
||||
{
|
||||
case TID_VBI_DATA_FETCH:
|
||||
{
|
||||
uint32_t line = get_field_code(LASERDISC_CODE_LINE1718, false);
|
||||
if ((line & 0xf80000) == 0xf80000 || line == VBI_CODE_LEADIN || line == VBI_CODE_LEADOUT)
|
||||
{
|
||||
uint32_t old_frame = m_curr_frame;
|
||||
if (line == VBI_CODE_LEADIN)
|
||||
m_curr_frame = 0;
|
||||
else if (line == VBI_CODE_LEADOUT)
|
||||
m_curr_frame = 54000;
|
||||
else
|
||||
m_curr_frame = bcd_to_literal(line & 0x7ffff);
|
||||
|
||||
LOGMASKED(LOG_FRAMES, "Current frame is %d (VBI 16: %06x, VBI 17: %06x, VBI 18: %06x, VBI 1718: %06x\n", m_curr_frame,
|
||||
get_field_code(LASERDISC_CODE_LINE16, false),
|
||||
get_field_code(LASERDISC_CODE_LINE17, false),
|
||||
get_field_code(LASERDISC_CODE_LINE18, false),
|
||||
line);
|
||||
|
||||
if (m_mode != MODE_STILL && m_mode != MODE_PAUSE)
|
||||
{
|
||||
if (m_mark_frame != ~0U && m_search_frame == ~0U)
|
||||
{
|
||||
int32_t old_delta = (int32_t)old_frame - (int32_t)m_mark_frame;
|
||||
int32_t curr_delta = (int32_t)m_curr_frame - (int32_t)m_mark_frame;
|
||||
LOGMASKED(LOG_STOPS, "%s: Stop Mark is currently %d, old frame is %d, current frame is %d, old delta %d, curr delta %d\n", machine().describe_context(), m_mark_frame, old_frame, m_curr_frame, old_delta, curr_delta);
|
||||
if (curr_delta == 0 || std::signbit(old_delta) != std::signbit(curr_delta))
|
||||
{
|
||||
m_mark_frame = ~0U;
|
||||
if (is_cav_disc())
|
||||
{
|
||||
LOGMASKED(LOG_STOPS | LOG_SQUELCHES, "%s: Stop Mark: Zero delta w/ CAV disc, entering still mode and squelching audio\n", machine().describe_context());
|
||||
m_mode = MODE_STILL;
|
||||
update_video_enable();
|
||||
}
|
||||
else
|
||||
{
|
||||
LOGMASKED(LOG_STOPS | LOG_SQUELCHES, "%s: Stop Mark: Zero delta w/ CLV disc, entering still mode and squelching video+audio\n", machine().describe_context());
|
||||
m_mode = MODE_PAUSE;
|
||||
video_enable(false);
|
||||
}
|
||||
|
||||
set_audio_squelch(true, true);
|
||||
|
||||
if (m_cmd_running)
|
||||
{
|
||||
LOGMASKED(LOG_SEARCHES | LOG_COMMANDS, "%s: Stop Mark: Command running, sending reply\n", machine().describe_context());
|
||||
m_cmd_running = false;
|
||||
queue_reply("R\x0d");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (m_search_frame != ~0U)
|
||||
{
|
||||
// TODO: Chapter-search support
|
||||
int32_t delta = (int32_t)m_curr_frame - (int32_t)m_search_frame;
|
||||
LOGMASKED(LOG_SEARCHES, "%s: Searching from current frame %d with delta %d\n", machine().describe_context(), m_curr_frame, delta);
|
||||
if (delta == 0)
|
||||
{
|
||||
// We've found our frame, enter play, pause or still mode.
|
||||
m_search_frame = ~0U;
|
||||
if (is_cav_disc())
|
||||
{
|
||||
LOGMASKED(LOG_SEARCHES | LOG_SQUELCHES, "%s: Search Mark: Zero delta w/ CAV disc, entering still mode and squelching audio\n", machine().describe_context());
|
||||
m_mode = MODE_STILL;
|
||||
update_video_enable();
|
||||
}
|
||||
else
|
||||
{
|
||||
LOGMASKED(LOG_SEARCHES | LOG_SQUELCHES, "%s: Search Mark: Zero delta w/ CLV disc, entering still mode and squelching video+audio\n", machine().describe_context());
|
||||
m_mode = MODE_PAUSE;
|
||||
video_enable(false);
|
||||
}
|
||||
|
||||
set_audio_squelch(true, true);
|
||||
|
||||
if (m_cmd_running)
|
||||
{
|
||||
LOGMASKED(LOG_SEARCHES | LOG_COMMANDS, "%s: Search Mark: Command running, sending reply\n", machine().describe_context());
|
||||
m_cmd_running = false;
|
||||
queue_reply("R\x0d");
|
||||
}
|
||||
}
|
||||
else if (delta >= -2 && delta < 0)
|
||||
{
|
||||
LOGMASKED(LOG_SEARCHES, "%s: Negative-near delta, letting disc run to current\n", machine().describe_context());
|
||||
// We're approaching our frame, let it run up.
|
||||
}
|
||||
else
|
||||
{
|
||||
if (delta < 0)
|
||||
{
|
||||
advance_slider(std::max(1, -delta / 2));
|
||||
}
|
||||
else
|
||||
{
|
||||
advance_slider(std::min(-2, -delta / 2));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// pass everything else onto the parent
|
||||
default:
|
||||
laserdisc_device::device_timer(timer, id, param);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// player_vsync - VSYNC callback, called at the
|
||||
// start of the blanking period
|
||||
//-------------------------------------------------
|
||||
|
||||
void pioneer_ldv4200hle_device::player_vsync(const vbi_metadata &vbi, int fieldnum, const attotime &curtime)
|
||||
{
|
||||
// set a timer to fetch the VBI data when it is ready
|
||||
if (m_mode > MODE_DOOR_OPEN)
|
||||
{
|
||||
m_vbi_fetch->adjust(screen().time_until_pos(19*2));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// player_update - update callback, called on
|
||||
// the first visible line of the frame
|
||||
//-------------------------------------------------
|
||||
|
||||
int32_t pioneer_ldv4200hle_device::player_update(const vbi_metadata &vbi, int fieldnum, const attotime &curtime)
|
||||
{
|
||||
if (!fieldnum)
|
||||
return 0;
|
||||
|
||||
if (m_mode == MODE_MS_FORWARD || m_mode == MODE_MS_REVERSE)
|
||||
{
|
||||
m_speed_accum += m_speed;
|
||||
int elapsed_tracks = m_speed_accum / 60;
|
||||
m_speed_accum -= elapsed_tracks * 60;
|
||||
if (m_mode == MODE_MS_REVERSE)
|
||||
elapsed_tracks *= -1;
|
||||
return elapsed_tracks;
|
||||
}
|
||||
|
||||
|
||||
if (m_mode == MODE_PLAY || m_mode == MODE_SEARCH)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// rcv_complete - called by diserial when we
|
||||
// have received a complete byte
|
||||
//-------------------------------------------------
|
||||
|
||||
void pioneer_ldv4200hle_device::rcv_complete()
|
||||
{
|
||||
receive_register_extract();
|
||||
add_command_byte(get_received_char());
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// tra_complete - called by diserial when we
|
||||
// have transmitted a complete byte
|
||||
//-------------------------------------------------
|
||||
|
||||
void pioneer_ldv4200hle_device::tra_complete()
|
||||
{
|
||||
m_reply_read_index = (m_reply_read_index + 1) % (uint8_t)std::size(m_reply_buffer);
|
||||
if (m_reply_read_index != m_reply_write_index)
|
||||
{
|
||||
uint8_t data = (uint8_t)m_reply_buffer[m_reply_read_index];
|
||||
LOGMASKED(LOG_REPLY_BYTES, "Sending reply byte: %02x\n", data);
|
||||
transmit_register_setup(data);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_replying = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// tra_callback - called by diserial when we
|
||||
// transmit a single bit
|
||||
//-------------------------------------------------
|
||||
|
||||
void pioneer_ldv4200hle_device::tra_callback()
|
||||
{
|
||||
m_serial_tx(transmit_register_get_data_bit());
|
||||
}
|
217
src/devices/machine/ldv4200hle.h
Normal file
217
src/devices/machine/ldv4200hle.h
Normal file
@ -0,0 +1,217 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:Ryan Holtz
|
||||
/*************************************************************************
|
||||
|
||||
ldv1000hle.h
|
||||
|
||||
Pioneer LD-V4200 laserdisc player simulation.
|
||||
|
||||
*************************************************************************/
|
||||
|
||||
#ifndef MAME_MACHINE_LDV4200_H
|
||||
#define MAME_MACHINE_LDV4200_H
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "laserdsc.h"
|
||||
#include "diserial.h"
|
||||
|
||||
|
||||
//**************************************************************************
|
||||
// GLOBAL VARIABLES
|
||||
//**************************************************************************
|
||||
|
||||
// device type definition
|
||||
DECLARE_DEVICE_TYPE(PIONEER_LDV4200HLE, pioneer_ldv4200hle_device)
|
||||
|
||||
|
||||
|
||||
//**************************************************************************
|
||||
// GLOBAL HELPERS
|
||||
//**************************************************************************
|
||||
|
||||
// Note: This should be included within the class rather than the global namespace.
|
||||
// However, doing so results in a "called in a constant expression before its definition is complete" error for the enum values.
|
||||
static constexpr uint16_t make_ldv4000_command(const char *str) { return ((uint8_t)str[0] << 8) | (uint8_t)str[1]; }
|
||||
|
||||
|
||||
|
||||
//**************************************************************************
|
||||
// TYPE DEFINITIONS
|
||||
//**************************************************************************
|
||||
|
||||
// ======================> pioneer_ldv4200hle_device
|
||||
|
||||
class pioneer_ldv4200hle_device : public laserdisc_device, public device_serial_interface
|
||||
{
|
||||
public:
|
||||
// construction/destruction
|
||||
pioneer_ldv4200hle_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
|
||||
|
||||
auto serial_tx() { return m_serial_tx.bind(); }
|
||||
|
||||
protected:
|
||||
// timer IDs
|
||||
enum
|
||||
{
|
||||
TID_VBI_DATA_FETCH = TID_FIRST_PLAYER_TIMER
|
||||
};
|
||||
|
||||
// device-level overrides
|
||||
virtual void device_start() override;
|
||||
virtual void device_reset() override;
|
||||
virtual void device_timer(emu_timer &timer, device_timer_id id, int param) override;
|
||||
|
||||
// laserdisc overrides
|
||||
virtual void player_vsync(const vbi_metadata &vbi, int fieldnum, const attotime &curtime) override;
|
||||
virtual int32_t player_update(const vbi_metadata &vbi, int fieldnum, const attotime &curtime) override;
|
||||
virtual void player_overlay(bitmap_yuy16 &bitmap) override { }
|
||||
|
||||
// diserial overrides
|
||||
virtual void rcv_complete() override;
|
||||
virtual void tra_complete() override;
|
||||
virtual void tra_callback() override;
|
||||
|
||||
private:
|
||||
enum player_command : uint16_t
|
||||
{
|
||||
CMD_DOOR_OPEN = make_ldv4000_command("OP"),
|
||||
CMD_DOOR_CLOSE = make_ldv4000_command("CO"),
|
||||
CMD_REJECT = make_ldv4000_command("RJ"),
|
||||
CMD_START = make_ldv4000_command("SA"),
|
||||
CMD_PLAY = make_ldv4000_command("PL"),
|
||||
CMD_PAUSE = make_ldv4000_command("PA"),
|
||||
CMD_STILL = make_ldv4000_command("ST"),
|
||||
CMD_STEP_FORWARD = make_ldv4000_command("SF"),
|
||||
CMD_STEP_REVERSE = make_ldv4000_command("SR"),
|
||||
CMD_SCAN_FORWARD = make_ldv4000_command("NF"),
|
||||
CMD_SCAN_REVERSE = make_ldv4000_command("NR"),
|
||||
CMD_MULTISPEED_FORWARD = make_ldv4000_command("MF"),
|
||||
CMD_MULTISPEED_REVERSE = make_ldv4000_command("MR"),
|
||||
CMD_SPEED_SET = make_ldv4000_command("SP"),
|
||||
CMD_SEARCH = make_ldv4000_command("SE"),
|
||||
CMD_MULTITRACK_FORWARD = make_ldv4000_command("JF"),
|
||||
CMD_MULTITRACK_REVERSE = make_ldv4000_command("JR"),
|
||||
CMD_STOP_MARKER = make_ldv4000_command("SM"),
|
||||
CMD_FRAME_SET = make_ldv4000_command("FR"),
|
||||
CMD_TIME_SET = make_ldv4000_command("TM"),
|
||||
CMD_CHAPTER_SET = make_ldv4000_command("CH"),
|
||||
CMD_CLEAR = make_ldv4000_command("CL"),
|
||||
CMD_LEADOUT_SYMBOL = make_ldv4000_command("LO"),
|
||||
CMD_AUDIO_CTRL = make_ldv4000_command("AD"),
|
||||
CMD_VIDEO_CTRL = make_ldv4000_command("VD"),
|
||||
CMD_KEY_LOCK = make_ldv4000_command("KL"),
|
||||
CMD_DISPLAY_CONTROL = make_ldv4000_command("DS"),
|
||||
CMD_CLEAR_SCREEN = make_ldv4000_command("CS"),
|
||||
CMD_PRINT_CHAR = make_ldv4000_command("PR"),
|
||||
CMD_REQ_FRAME_NUMBER = make_ldv4000_command("?F"),
|
||||
CMD_REQ_TIME_CODE = make_ldv4000_command("?T"),
|
||||
CMD_REQ_CHAPTER_NUMBER = make_ldv4000_command("?C"),
|
||||
CMD_REQ_PLAYER_MODE = make_ldv4000_command("?P"),
|
||||
CMD_REQ_DISC_STATUS = make_ldv4000_command("?D"),
|
||||
CMD_REQ_LDP_MODEL = make_ldv4000_command("?X"),
|
||||
CMD_REQ_PIONEER_DISC_ID = make_ldv4000_command("?U"),
|
||||
CMD_REQ_STANDARD_DISC_ID = make_ldv4000_command("$Y"),
|
||||
CMD_REQ_TV_SYSTEM = make_ldv4000_command("?S"),
|
||||
CMD_COMMUNICATION_CTRL = make_ldv4000_command("CM"),
|
||||
CMD_REQ_CCR_MODE = make_ldv4000_command("?M"),
|
||||
CMD_REGISTER_A_SET = make_ldv4000_command("RA"),
|
||||
CMD_REGISTER_B_SET = make_ldv4000_command("RB"),
|
||||
CMD_REGISTER_C_SET = make_ldv4000_command("RC"),
|
||||
CMD_REGISTER_D_SET = make_ldv4000_command("RD"),
|
||||
CMD_REQ_REGISTER_A = make_ldv4000_command("$A"),
|
||||
CMD_REQ_REGISTER_B = make_ldv4000_command("$B"),
|
||||
CMD_REQ_REGISTER_C = make_ldv4000_command("$C"),
|
||||
CMD_REQ_REGISTER_D = make_ldv4000_command("$D"),
|
||||
CMD_REQ_INPUT_UNIT = make_ldv4000_command("#I"),
|
||||
CMD_INPUT_NUMBER_WAIT = make_ldv4000_command("?N")
|
||||
};
|
||||
|
||||
enum player_mode : uint8_t
|
||||
{
|
||||
MODE_PARK,
|
||||
MODE_DOOR_OPEN,
|
||||
MODE_PAUSE,
|
||||
MODE_PLAY,
|
||||
MODE_MS_FORWARD,
|
||||
MODE_MS_REVERSE,
|
||||
MODE_SEARCH,
|
||||
MODE_STILL
|
||||
};
|
||||
|
||||
enum address_mode : uint8_t
|
||||
{
|
||||
ADDRESS_FRAME,
|
||||
ADDRESS_TIME,
|
||||
ADDRESS_CHAPTER
|
||||
};
|
||||
|
||||
enum error_code : uint8_t
|
||||
{
|
||||
ERR_NONE = 0xff,
|
||||
ERR_COMMUNICATION = 0,
|
||||
ERR_NOT_AVAILABLE = 4,
|
||||
ERR_MISSING_ARGUMENT = 6,
|
||||
ERR_DISC_NOT_LOADED = 11,
|
||||
ERR_SEARCH = 12,
|
||||
ERR_DEFOCUS = 13,
|
||||
ERR_PICTURE_STOP = 15,
|
||||
ERR_OTHER_INPUT = 16,
|
||||
ERR_PANIC = 99
|
||||
};
|
||||
|
||||
void add_command_byte(uint8_t data);
|
||||
|
||||
void queue_reply(const char *reply);
|
||||
void queue_error(error_code err);
|
||||
|
||||
void normalize_command_buffer();
|
||||
void process_command_buffer();
|
||||
|
||||
static uint32_t bcd_to_literal(uint32_t bcd);
|
||||
static bool is_number(char value);
|
||||
uint8_t parse_numeric_value(uint8_t cmd_index, uint32_t &value, error_code &err);
|
||||
uint8_t process_command(uint8_t cmd_index, uint32_t value, error_code &err);
|
||||
|
||||
void begin_search(uint32_t value);
|
||||
|
||||
void update_audio_squelch();
|
||||
void update_video_enable();
|
||||
|
||||
// internal state
|
||||
devcb_write_line m_serial_tx;
|
||||
emu_timer * m_vbi_fetch;
|
||||
char m_cmd_buffer[21];
|
||||
uint8_t m_cmd_length;
|
||||
bool m_cmd_running;
|
||||
char m_reply_buffer[64];
|
||||
uint8_t m_reply_write_index;
|
||||
uint8_t m_reply_read_index;
|
||||
bool m_replying;
|
||||
|
||||
uint8_t m_mode; // current player mode
|
||||
uint32_t m_chapter;
|
||||
uint32_t m_time;
|
||||
uint32_t m_frame; // raw frame index (CAV mode)
|
||||
uint32_t m_search_chapter;
|
||||
uint32_t m_search_frame;
|
||||
uint32_t m_mark_chapter;
|
||||
uint32_t m_mark_frame;
|
||||
|
||||
uint8_t m_key_lock;
|
||||
uint8_t m_video_switch;
|
||||
uint8_t m_audio_switch;
|
||||
uint8_t m_display_switch;
|
||||
uint8_t m_address_flag;
|
||||
uint16_t m_speed;
|
||||
uint32_t m_speed_accum;
|
||||
uint8_t m_comm_ctrl;
|
||||
uint8_t m_reg_a;
|
||||
uint8_t m_reg_b;
|
||||
uint8_t m_reg_c;
|
||||
uint8_t m_reg_d;
|
||||
uint8_t m_aux_port;
|
||||
uint32_t m_curr_frame;
|
||||
};
|
||||
|
||||
#endif // MAME_MACHINE_LDV4200_H
|
@ -1,23 +1,20 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:Angelo Salese
|
||||
// copyright-holders:Angelo Salese, Ryan Holtz
|
||||
/*************************************************************************************************
|
||||
|
||||
(Hologram) Time Traveler (c) 1991 Virtual Image Productions / Sega
|
||||
|
||||
preliminary driver by Angelo Salese
|
||||
Driver by Angelo Salese
|
||||
LaserDisc and artwork hookup by Ryan Holtz
|
||||
|
||||
TODO:
|
||||
- unemulated Pioneer LDV-4200 and Sony LDP-1450 players, needs a dump of the BIOSes and proper
|
||||
hook-up;
|
||||
- ICM7243B 14-segment alphanumeric LED display driver
|
||||
- Unemulated Sony LDP-1450 player, and Pioneer LD-V4200 is HLE; needs a dump of the BIOSes and
|
||||
proper hook-up.
|
||||
- Unknown how the bill validator is hooked up.
|
||||
|
||||
==================================================================================================
|
||||
|
||||
Time Traveler ROM image
|
||||
|
||||
warren@dragons-lair-project.com
|
||||
6/25/01
|
||||
|
||||
Time Traveler ROM image courtesy of Warren O of the Dragon's Lair Project, 25 Jun. 2001
|
||||
|
||||
ROM is a 27C020 (256kbit x 8 = 256 KB)
|
||||
ROM sticker says 6/18/91
|
||||
@ -31,79 +28,189 @@ CPU is an Intel 80188
|
||||
#include "machine/eeprompar.h"
|
||||
#include "machine/i8255.h"
|
||||
#include "machine/ins8250.h"
|
||||
#include "machine/ldv4200hle.h"
|
||||
#include "emupal.h"
|
||||
#include "screen.h"
|
||||
#include "speaker.h"
|
||||
|
||||
#include "timetrv.lh"
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
class timetrv_state : public driver_device
|
||||
{
|
||||
public:
|
||||
timetrv_state(const machine_config &mconfig, device_type type, const char *tag)
|
||||
: driver_device(mconfig, type, tag),
|
||||
m_led_vram_lo(*this, "led_vralo"),
|
||||
m_led_vram_hi(*this, "led_vrahi"),
|
||||
m_maincpu(*this, "maincpu") { }
|
||||
: driver_device(mconfig, type, tag)
|
||||
, m_led_vram_lo(*this, "led_vramlo")
|
||||
, m_led_vram_hi(*this, "led_vramhi")
|
||||
, m_maincpu(*this, "maincpu")
|
||||
, m_uart(*this, "uart")
|
||||
, m_laserdisc(*this, "laserdisc")
|
||||
, m_digits(*this, "digit%u", 0U)
|
||||
, m_decimals(*this, "decimal%u", 0U)
|
||||
, m_cube_lamp(*this, "cube_lamp")
|
||||
, m_player_lamps(*this, "player_lamp%u", 1U)
|
||||
{ }
|
||||
|
||||
void timetrv(machine_config &config);
|
||||
|
||||
private:
|
||||
virtual void machine_start() override;
|
||||
|
||||
void timetrv_map(address_map &map);
|
||||
void timetrv_io(address_map &map);
|
||||
|
||||
void ppi1_pc_w(uint8_t data);
|
||||
|
||||
uint32_t screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);
|
||||
|
||||
template <offs_t Bank> void led_w(offs_t offset, uint8_t data);
|
||||
|
||||
required_shared_ptr<uint8_t> m_led_vram_lo;
|
||||
required_shared_ptr<uint8_t> m_led_vram_hi;
|
||||
uint8_t test1_r();
|
||||
uint8_t test2_r();
|
||||
uint8_t in_r();
|
||||
virtual void video_start() override;
|
||||
uint32_t screen_update_timetrv(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);
|
||||
|
||||
required_device<cpu_device> m_maincpu;
|
||||
void timetrv_io(address_map &map);
|
||||
void timetrv_map(address_map &map);
|
||||
required_device<ns16450_device> m_uart;
|
||||
required_device<pioneer_ldv4200hle_device> m_laserdisc;
|
||||
output_finder<16> m_digits;
|
||||
output_finder<16> m_decimals;
|
||||
output_finder<> m_cube_lamp;
|
||||
output_finder<2> m_player_lamps;
|
||||
};
|
||||
|
||||
|
||||
|
||||
void timetrv_state::video_start()
|
||||
void timetrv_state::machine_start()
|
||||
{
|
||||
m_digits.resolve();
|
||||
m_decimals.resolve();
|
||||
m_cube_lamp.resolve();
|
||||
m_player_lamps.resolve();
|
||||
}
|
||||
|
||||
uint32_t timetrv_state::screen_update_timetrv(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
|
||||
void timetrv_state::ppi1_pc_w(uint8_t data)
|
||||
{
|
||||
// Bit 3: 2P Start lamp
|
||||
// Bit 4: 1P Start lamp
|
||||
// Bit 5: Time Reversal Cube button-lamp
|
||||
// Bit 6: Coin-up/start 'bip' noise
|
||||
m_cube_lamp = BIT(data, 5);
|
||||
m_player_lamps[0] = BIT(data, 4);
|
||||
m_player_lamps[1] = BIT(data, 3);
|
||||
}
|
||||
|
||||
uint32_t timetrv_state::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
|
||||
{
|
||||
popmessage("%s%s",reinterpret_cast<char *>(m_led_vram_lo.target()),reinterpret_cast<char *>(m_led_vram_hi.target()));
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t timetrv_state::test1_r()
|
||||
template <offs_t Bank>
|
||||
void timetrv_state::led_w(offs_t offset, uint8_t data)
|
||||
{
|
||||
return ioport("IN0")->read();//machine().rand();
|
||||
}
|
||||
/*
|
||||
000000000
|
||||
5B 8 C1
|
||||
5 B 8 C 1
|
||||
5 B 8 C 1
|
||||
6666 7777
|
||||
4 A 9 D 2
|
||||
4 A 9 D 2
|
||||
4A 9 D2
|
||||
333EEE333
|
||||
|
||||
uint8_t timetrv_state::test2_r()
|
||||
{
|
||||
/*bit 7,eeprom read bit*/
|
||||
return (ioport("IN1")->read() & 0x7f);//machine().rand();
|
||||
}
|
||||
00: 0000 0001 1011 1011 0x01bb @
|
||||
01: 0000 0000 1111 0111 0x00f7 A
|
||||
02: 0000 0011 1000 1111 0x038f B
|
||||
03: 0000 0000 0011 1001 0x0039 C
|
||||
04: 0000 0011 0000 1111 0x030f D
|
||||
05: 0000 0000 0111 1001 0x0079 E
|
||||
06: 0000 0000 0111 0001 0x0071 F
|
||||
07: 0000 0000 1011 1101 0x00bd G
|
||||
08: 0000 0000 1111 0110 0x00f6 H
|
||||
09: 0000 0011 0000 0000 0x0300 I
|
||||
0A: 0000 0000 0001 1110 0x001e J
|
||||
0B: 0011 0000 0111 0000 0x3070 K
|
||||
0C: 0000 0000 0011 1000 0x0038 L
|
||||
0D: 0001 1000 0011 0110 0x1836 M
|
||||
0E: 0010 1000 0011 0110 0x2836 N
|
||||
0F: 0000 0000 0011 1111 0x003f O
|
||||
10: 0000 0000 1111 0011 0x00f3 P
|
||||
11: 0010 0000 0011 1111 0x203f Q
|
||||
12: 0010 0000 1111 0011 0x20f3 R
|
||||
13: 0000 0000 1110 1101 0x00ed S
|
||||
14: 0000 0011 0000 0001 0x0301 T
|
||||
15: 0000 0000 0011 1110 0x003e U
|
||||
16: 0001 0100 0011 0000 0x1430 V
|
||||
17: 0010 0100 0011 0110 0x2436 W
|
||||
18: 0011 1100 0000 0000 0x3c00 X
|
||||
19: 0001 1010 0000 0000 0x1a00 Y
|
||||
1A: 0001 0100 0000 1001 0x1409 Z
|
||||
1B: 0011 0000 1000 0000 0x3080 [
|
||||
1C: 0010 1000 0000 0000 0x2800 Backslash
|
||||
1D: 0000 1100 0100 0000 0x0c40 ]
|
||||
1E: 0001 0100 0000 0011 0x1403 Arrow
|
||||
1F: 0000 0000 0000 1000 0x0008 _
|
||||
20: 0000 0000 0000 0000 0x0000 Space
|
||||
21: 0100 0001 0000 0000 0x4100 !
|
||||
22: 0000 0000 0010 0010 0x0022 "
|
||||
23: 0000 0011 1100 1110 0x03ce #
|
||||
24: 0000 0011 1110 1101 0x03ed $
|
||||
25: 0011 1100 1110 0100 0x3ce4 %
|
||||
26: 0011 1100 0000 1101 0x3c0d &
|
||||
27: 0000 0001 0000 0000 0x0100 '
|
||||
28: 0011 0000 0000 0000 0x3000 (
|
||||
29: 0000 1100 0000 0000 0x0c00 )
|
||||
2A: 0011 1111 1100 0000 0x3fc0 *
|
||||
2B: 0000 0011 1100 0000 0x03c0 +
|
||||
2C: 0000 0100 0000 0000 0x0400 ,
|
||||
2D: 0000 0000 1100 0000 0x00c0 -
|
||||
2E: 0100 0000 0000 0000 0x4000 .
|
||||
2F: 0001 0100 0000 0000 0x1400 /
|
||||
30: 0001 0100 0011 1111 0x143f 0
|
||||
31: 0000 0011 0000 0000 0x0300 1
|
||||
32: 0000 0000 1101 1011 0x00db 2
|
||||
33: 0000 0000 1100 1111 0x00cf 3
|
||||
34: 0000 0000 1110 0110 0x00e6 4
|
||||
35: 0010 0000 0110 1001 0x2069 5
|
||||
36: 0000 0000 1111 1101 0x00fd 6
|
||||
37: 0000 0000 0000 0111 0x0007 7
|
||||
38: 0000 0000 1111 1111 0x00ff 8
|
||||
39: 0000 0000 1110 1111 0x00ef 9
|
||||
3A: 0100 0000 0000 0000 0x4000 :
|
||||
3B: 0000 0100 0000 0000 0x0400 ;
|
||||
3C: 0000 0100 0000 1000 0x0408 <
|
||||
3D: 0000 0000 1100 1000 0x00c8 =
|
||||
3E: 0010 0000 0000 1000 0x2008 >
|
||||
3F: 0000 0010 1000 0011 0x0283 ?
|
||||
*/
|
||||
|
||||
static uint16_t const s_digit_data[0x40] =
|
||||
{
|
||||
0x01bb, 0x00f7, 0x038f, 0x0039, 0x030f, 0x0079, 0x0071, 0x00bd, 0x00f6, 0x0300, 0x001e, 0x3070, 0x0038, 0x1836, 0x2836, 0x003f,
|
||||
0x00f3, 0x203f, 0x20f3, 0x00ed, 0x0301, 0x003e, 0x1430, 0x2436, 0x3c00, 0x1a00, 0x1409, 0x3080, 0x2800, 0x0c40, 0x1403, 0x0008,
|
||||
0x0000, 0x4100, 0x0022, 0x03ce, 0x03ed, 0x3ce4, 0x3c0d, 0x0100, 0x3000, 0x0c00, 0x3fc0, 0x03c0, 0x0400, 0x00c0, 0x4000, 0x1400,
|
||||
0x143f, 0x0300, 0x00db, 0x00cf, 0x00e6, 0x2069, 0x00fd, 0x0007, 0x00ff, 0x00ef, 0x4000, 0x0400, 0x0408, 0x00c8, 0x2008, 0x0283
|
||||
};
|
||||
|
||||
uint8_t timetrv_state::in_r()
|
||||
{
|
||||
return 0xff;
|
||||
const uint16_t digit_data = s_digit_data[data & 0x3f];
|
||||
m_digits[Bank + offset] = digit_data & 0x3fff;
|
||||
m_decimals[Bank + offset] = BIT(digit_data, 14);
|
||||
}
|
||||
|
||||
void timetrv_state::timetrv_map(address_map &map)
|
||||
{
|
||||
map(0x00000, 0x0ffff).ram(); //irq vectors + work ram
|
||||
map(0x00000, 0x0ffff).ram(); // IRQ vectors + work RAM
|
||||
map(0x10000, 0x107ff).rw("eeprom", FUNC(eeprom_parallel_28xx_device::read), FUNC(eeprom_parallel_28xx_device::write));
|
||||
map(0xc0000, 0xfffff).rom();
|
||||
}
|
||||
|
||||
void timetrv_state::timetrv_io(address_map &map)
|
||||
{
|
||||
map(0x0122, 0x0123).nopw(); //eeprom write bits
|
||||
map(0x1000, 0x1003).rw("ppi1", FUNC(i8255_device::read), FUNC(i8255_device::write));
|
||||
map(0x1080, 0x1083).rw("ppi2", FUNC(i8255_device::read), FUNC(i8255_device::write));
|
||||
map(0x1100, 0x1107).rw("uart", FUNC(ins8250_device::ins8250_r), FUNC(ins8250_device::ins8250_w));
|
||||
map(0x1180, 0x1187).ram().share("led_vralo");//led string,part 1
|
||||
map(0x1200, 0x1207).ram().share("led_vrahi");//led string,part 2
|
||||
map(0xff80, 0xffff).ram(); //am80188-em-like cpu internal regs?
|
||||
map(0x1180, 0x1187).ram().w(FUNC(timetrv_state::led_w<0>)).share(m_led_vram_lo);
|
||||
map(0x1200, 0x1207).ram().w(FUNC(timetrv_state::led_w<8>)).share(m_led_vram_hi);
|
||||
map(0xff80, 0xffff).ram(); // CPU internal registers on 80188
|
||||
}
|
||||
|
||||
|
||||
@ -119,32 +226,77 @@ static INPUT_PORTS_START( timetrv )
|
||||
PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_COIN2 )
|
||||
|
||||
PORT_START("IN1")
|
||||
PORT_DIPNAME( 0x01, 0x01, DEF_STR( Unknown ) )
|
||||
PORT_BIT( 0x8f, IP_ACTIVE_LOW, IPT_UNUSED )
|
||||
PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_NAME("Attack")
|
||||
PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_NAME("Reversal Cube")
|
||||
PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_SERVICE )
|
||||
|
||||
PORT_START("DSW1")
|
||||
PORT_DIPNAME( 0x03, 0x02, DEF_STR( Coinage ) ) PORT_DIPLOCATION("SW1:1,2")
|
||||
PORT_DIPSETTING( 0x00, DEF_STR( 1C_1C ) )
|
||||
PORT_DIPSETTING( 0x01, DEF_STR( 2C_1C ) )
|
||||
PORT_DIPSETTING( 0x02, DEF_STR( 3C_1C ) )
|
||||
PORT_DIPSETTING( 0x03, DEF_STR( 4C_1C ) )
|
||||
PORT_DIPNAME( 0x0c, 0x04, DEF_STR( Lives ) ) PORT_DIPLOCATION("SW1:3,4")
|
||||
PORT_DIPSETTING( 0x00, "2" )
|
||||
PORT_DIPSETTING( 0x04, "3" )
|
||||
PORT_DIPSETTING( 0x08, "4" )
|
||||
PORT_DIPSETTING( 0x0c, "5" )
|
||||
PORT_DIPUNUSED_DIPLOC( 0xf0, 0x00, "SW1:5,6,7,8" )
|
||||
|
||||
PORT_START("DSW2")
|
||||
PORT_DIPNAME( 0x01, 0x00, "Max Reversal Cubes" ) PORT_DIPLOCATION("SW2:1")
|
||||
PORT_DIPSETTING( 0x00, "6" )
|
||||
PORT_DIPSETTING( 0x01, "36" )
|
||||
PORT_DIPNAME( 0x0e, 0x04, "Reversal Cube Cost" ) PORT_DIPLOCATION("SW2:2,3,4")
|
||||
PORT_DIPSETTING( 0x00, "1 Coin / 1 Cube" )
|
||||
PORT_DIPSETTING( 0x02, "2 Coins / 1 Cube" )
|
||||
PORT_DIPSETTING( 0x04, "1 Coins / 2 Cubes" )
|
||||
PORT_DIPSETTING( 0x0a, "2 Coins / 3 Cubes" )
|
||||
PORT_DIPSETTING( 0x08, "1 Coin / 3 Cubes" )
|
||||
PORT_DIPSETTING( 0x0e, "1/2 Coins / 1/3 Cubes" )
|
||||
PORT_DIPSETTING( 0x0c, DEF_STR( Unknown ) )
|
||||
PORT_DIPSETTING( 0x06, DEF_STR( Unknown ) )
|
||||
PORT_DIPNAME( 0x10, 0x00, DEF_STR( Level_Select ) ) PORT_DIPLOCATION("SW2:5")
|
||||
PORT_DIPSETTING( 0x00, DEF_STR( Off ) )
|
||||
PORT_DIPSETTING( 0x10, DEF_STR( On ) )
|
||||
PORT_DIPNAME( 0x60, 0x00, "Devil Behavior" ) PORT_DIPLOCATION("SW2:6,7")
|
||||
PORT_DIPSETTING( 0x00, "Devil Can Take Lives" )
|
||||
PORT_DIPSETTING( 0x20, "Devil Never Takes Lives" )
|
||||
PORT_DIPSETTING( 0x40, "Devil Not In Game" )
|
||||
PORT_DIPSETTING( 0x60, DEF_STR( Unknown ) )
|
||||
PORT_DIPUNUSED_DIPLOC( 0x80, 0x80, "SW2:8" )
|
||||
|
||||
PORT_START("DSW3")
|
||||
PORT_DIPNAME( 0x01, 0x01, DEF_STR( Free_Play ) ) PORT_DIPLOCATION("SW3:1")
|
||||
PORT_DIPSETTING( 0x01, DEF_STR( Off ) )
|
||||
PORT_DIPSETTING( 0x00, DEF_STR( On ) )
|
||||
PORT_DIPNAME( 0x02, 0x02, DEF_STR( Unknown ) )
|
||||
PORT_DIPSETTING( 0x02, DEF_STR( Off ) )
|
||||
PORT_DIPSETTING( 0x00, DEF_STR( On ) )
|
||||
PORT_DIPNAME( 0x04, 0x04, DEF_STR( Unknown ) )
|
||||
PORT_DIPSETTING( 0x04, DEF_STR( Off ) )
|
||||
PORT_DIPSETTING( 0x00, DEF_STR( On ) )
|
||||
PORT_DIPNAME( 0x08, 0x08, DEF_STR( Unknown ) )
|
||||
PORT_DIPSETTING( 0x08, DEF_STR( Off ) )
|
||||
PORT_DIPSETTING( 0x00, DEF_STR( On ) )
|
||||
PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_BUTTON1 )
|
||||
PORT_DIPNAME( 0x20, 0x20, DEF_STR( Unknown ) )
|
||||
PORT_DIPSETTING( 0x20, DEF_STR( Off ) )
|
||||
PORT_DIPSETTING( 0x00, DEF_STR( On ) )
|
||||
PORT_DIPNAME( 0x40, 0x40, DEF_STR( Service_Mode ) )
|
||||
PORT_DIPSETTING( 0x40, DEF_STR( Off ) )
|
||||
PORT_DIPSETTING( 0x00, DEF_STR( On ) )
|
||||
// 0x80 eeprom read bit
|
||||
PORT_DIPNAME( 0x02, 0x02, DEF_STR( Demo_Sounds ) ) PORT_DIPLOCATION("SW3:2")
|
||||
PORT_DIPSETTING( 0x02, DEF_STR( On ) )
|
||||
PORT_DIPSETTING( 0x00, DEF_STR( Off ) )
|
||||
PORT_DIPNAME( 0x0c, 0x0c, DEF_STR( Difficulty ) ) PORT_DIPLOCATION("SW3:4,3")
|
||||
PORT_DIPSETTING( 0x0c, DEF_STR( Medium ) )
|
||||
PORT_DIPSETTING( 0x08, DEF_STR( Easy ) )
|
||||
PORT_DIPSETTING( 0x04, DEF_STR( Difficult ) )
|
||||
PORT_DIPSETTING( 0x0c, DEF_STR( Very_Difficult ) )
|
||||
PORT_DIPNAME( 0x10, 0x10, "LaserDisc Player Protocol" ) PORT_DIPLOCATION("SW3:5")
|
||||
PORT_DIPSETTING( 0x10, "Pioneer LDV-4200" )
|
||||
PORT_DIPSETTING( 0x00, "Sony LDP-1450" )
|
||||
PORT_DIPNAME( 0xe0, 0x60, "Bill Multiplier" ) PORT_DIPLOCATION("SW3:6,7,8")
|
||||
PORT_DIPSETTING( 0x00, "1" )
|
||||
PORT_DIPSETTING( 0x20, "2" )
|
||||
PORT_DIPSETTING( 0x60, "4" )
|
||||
PORT_DIPSETTING( 0xe0, "8" )
|
||||
PORT_DIPSETTING( 0x40, "10" )
|
||||
PORT_DIPSETTING( 0x80, DEF_STR( Unknown ) )
|
||||
PORT_DIPSETTING( 0xa0, DEF_STR( Unknown ) )
|
||||
PORT_DIPSETTING( 0xc0, DEF_STR( Unknown ) )
|
||||
INPUT_PORTS_END
|
||||
|
||||
void timetrv_state::timetrv(machine_config &config)
|
||||
{
|
||||
/* basic machine hardware */
|
||||
I80188(config, m_maincpu, 20000000); //???
|
||||
I80188(config, m_maincpu, 16_MHz_XTAL); // Confirmed from PCB layout diagram
|
||||
m_maincpu->set_addrmap(AS_PROGRAM, &timetrv_state::timetrv_map);
|
||||
m_maincpu->set_addrmap(AS_IO, &timetrv_state::timetrv_io);
|
||||
// interrupts are generated by internally-driven timers
|
||||
@ -152,27 +304,28 @@ void timetrv_state::timetrv(machine_config &config)
|
||||
EEPROM_2816(config, "eeprom");
|
||||
|
||||
i8255_device &ppi1(I8255(config, "ppi1"));
|
||||
ppi1.in_pa_callback().set(FUNC(timetrv_state::test1_r)); //inputs
|
||||
ppi1.in_pb_callback().set(FUNC(timetrv_state::test2_r)); //eeprom read bit + inputs
|
||||
ppi1.in_pa_callback().set_ioport("IN0");
|
||||
ppi1.in_pb_callback().set_ioport("IN1");
|
||||
ppi1.out_pc_callback().set(FUNC(timetrv_state::ppi1_pc_w));
|
||||
|
||||
i8255_device &ppi2(I8255(config, "ppi2"));
|
||||
ppi2.in_pa_callback().set(FUNC(timetrv_state::in_r)); //dsw
|
||||
ppi2.in_pb_callback().set(FUNC(timetrv_state::in_r)); //dsw
|
||||
ppi2.in_pc_callback().set(FUNC(timetrv_state::in_r)); //dsw
|
||||
ppi2.in_pa_callback().set_ioport("DSW1");
|
||||
ppi2.in_pb_callback().set_ioport("DSW2");
|
||||
ppi2.in_pc_callback().set_ioport("DSW3");
|
||||
|
||||
NS16450(config, "uart", 1843200); // P82050 (serial interface for laserdisc)
|
||||
NS16450(config, m_uart, 768000); // P82050 (serial interface for Laserdisc player)
|
||||
m_uart->out_tx_callback().set(m_laserdisc, FUNC(pioneer_ldv4200hle_device::rx_w));
|
||||
|
||||
/* video hardware */
|
||||
screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_RASTER));
|
||||
screen.set_refresh_hz(60);
|
||||
screen.set_vblank_time(ATTOSECONDS_IN_USEC(0));
|
||||
screen.set_size(512, 512);
|
||||
screen.set_visarea(0*8, 512-1, 0*8, 512-1);
|
||||
screen.set_screen_update(FUNC(timetrv_state::screen_update_timetrv));
|
||||
|
||||
PALETTE(config, "palette").set_entries(512);
|
||||
PIONEER_LDV4200HLE(config, m_laserdisc, 0);
|
||||
m_laserdisc->set_overlay(256, 256, FUNC(timetrv_state::screen_update));
|
||||
m_laserdisc->add_route(0, "mono", 0.4);
|
||||
m_laserdisc->add_route(1, "mono", 0.4);
|
||||
m_laserdisc->add_ntsc_screen(config, "screen");
|
||||
m_laserdisc->serial_tx().set(m_uart, FUNC(ns16450_device::rx_w));
|
||||
|
||||
/* sound hardware */
|
||||
SPEAKER(config, "mono").front_center();
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
@ -186,7 +339,7 @@ ROM_START( timetrv )
|
||||
ROM_LOAD( "tt061891.bin", 0xc0000, 0x40000, CRC(a3d44219) SHA1(7c5003b6d3df1e472db45abd725e7d3d43f0dfb4) )
|
||||
|
||||
DISK_REGION( "laserdisc" )
|
||||
DISK_IMAGE_READONLY( "timetrv", 0, NO_DUMP )
|
||||
DISK_IMAGE_READONLY( "timetrv", 0, SHA1(8abb5e6aa58ab49477ef89f507264d35454f99d3) )
|
||||
ROM_END
|
||||
|
||||
ROM_START( timetrv2 )
|
||||
@ -194,8 +347,12 @@ ROM_START( timetrv2 )
|
||||
ROM_LOAD( "epr-72491.u9", 0xc0000, 0x40000, CRC(c7998e2f) SHA1(26060653b2368f52c304e6433b4f447f99a36839) )
|
||||
|
||||
DISK_REGION( "laserdisc" )
|
||||
DISK_IMAGE_READONLY( "timetrv", 0, NO_DUMP )
|
||||
DISK_IMAGE_READONLY( "timetrv", 0, SHA1(8abb5e6aa58ab49477ef89f507264d35454f99d3) BAD_DUMP )
|
||||
ROM_END
|
||||
|
||||
GAME( 1991, timetrv, 0, timetrv, timetrv, timetrv_state, empty_init, ROT0, "Virtual Image Productions (Sega license)", "Time Traveler (set 1)", MACHINE_NO_SOUND | MACHINE_NOT_WORKING )
|
||||
GAME( 1991, timetrv2, timetrv, timetrv, timetrv, timetrv_state, empty_init, ROT0, "Virtual Image Productions (Sega license)", "Time Traveler (set 2)", MACHINE_NO_SOUND | MACHINE_NOT_WORKING ) // Europe?
|
||||
} // anonymous namespace
|
||||
|
||||
|
||||
|
||||
GAMEL( 1991, timetrv, 0, timetrv, timetrv, timetrv_state, empty_init, ORIENTATION_FLIP_Y, "Virtual Image Productions (Sega license)", "Time Traveler (set 1)", MACHINE_IMPERFECT_SOUND, layout_timetrv )
|
||||
GAMEL( 1991, timetrv2, timetrv, timetrv, timetrv, timetrv_state, empty_init, ORIENTATION_FLIP_Y, "Virtual Image Productions (Sega license)", "Time Traveler (set 2)", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_SOUND, layout_timetrv ) // Different frame indices; Europe?
|
||||
|
65
src/mame/layout/timetrv.lay
Normal file
65
src/mame/layout/timetrv.lay
Normal file
@ -0,0 +1,65 @@
|
||||
<?xml version="1.0"?>
|
||||
<!--
|
||||
license:CC0
|
||||
copyright-holders:Ryan Holtz
|
||||
-->
|
||||
|
||||
<mamelayout version="2">
|
||||
<element name="led">
|
||||
<led14seg>
|
||||
<color red="0.0" green="1.0" blue="0.0" />
|
||||
</led14seg>
|
||||
</element>
|
||||
|
||||
<element name="dp">
|
||||
<rect state="0"><color alpha="0.125" red="0.0" green="1.0" blue="0.0" /></rect>
|
||||
<rect state="1"><color alpha="1.0" red="0.0" green="1.0" blue="0.0" /></rect>
|
||||
</element>
|
||||
|
||||
<element name="reversal_cube" defstate="0">
|
||||
<rect state="0"><color red="0.0" green="0.447" blue="0.682" /></rect>
|
||||
<rect state="1"><color red="0.357" green="0.882" blue="1.0" /></rect>
|
||||
</element>
|
||||
|
||||
<element name="p1_lamp" defstate="0">
|
||||
<rect state="0"><color red="0.1" green="0.1" blue="0.1" /></rect>
|
||||
<rect state="1"><color red="0.9" green="0.9" blue="0.9" /></rect>
|
||||
<text string="PLAYER 1"><color red="0.3" green="0.3" blue="0.3" /></text>
|
||||
</element>
|
||||
|
||||
<element name="p2_lamp" defstate="0">
|
||||
<rect state="0"><color red="0.1" green="0.1" blue="0.1" /></rect>
|
||||
<rect state="1"><color red="0.9" green="0.9" blue="0.9" /></rect>
|
||||
<text string="PLAYER 2"><color red="0.3" green="0.3" blue="0.3" /></text>
|
||||
</element>
|
||||
|
||||
<view name="Lamps and LEDs">
|
||||
<screen index="0">
|
||||
<bounds left="0" top="0" right="704" bottom="480" />
|
||||
</screen>
|
||||
|
||||
<repeat count="16">
|
||||
<param name="digit" start="0" increment="1" />
|
||||
<param name="digit_x" start="256" increment="12" />
|
||||
<param name="dp_x" start="265" increment="12" />
|
||||
<element name="digit~digit~" ref="led" blend="add" state="0">
|
||||
<bounds x="~digit_x~" y="0" width="10" height="16"/>
|
||||
</element>
|
||||
<element name="decimal~digit~" ref="dp" blend="add" state="0">
|
||||
<bounds x="~dp_x~" y="14" width="2" height="2"/>
|
||||
</element>
|
||||
</repeat>
|
||||
|
||||
<element name="cube_lamp" ref="reversal_cube">
|
||||
<bounds x="120" y="0" width="16" height="16" />
|
||||
</element>
|
||||
|
||||
<element name="player_lamp1" ref="p1_lamp">
|
||||
<bounds x="464" y="0" width="96" height="16" />
|
||||
</element>
|
||||
|
||||
<element name="player_lamp2" ref="p2_lamp">
|
||||
<bounds x="592" y="0" width="96" height="16" />
|
||||
</element>
|
||||
</view>
|
||||
</mamelayout>
|
Loading…
Reference in New Issue
Block a user