summaryrefslogtreecommitdiffstatshomepage
path: root/src
diff options
context:
space:
mode:
author wd40yasu <wd40yasu@users.noreply.github.com>2022-03-26 22:57:54 +0900
committer wd40yasu <wd40yasu@users.noreply.github.com>2022-03-26 22:57:54 +0900
commite862652255b13ae8328710bbec96abc9fd394f34 (patch)
tree82720ce2c421ea4711855a86ba5cab4006c825e4 /src
parentfe8a7fbdac755ea506a3c2b98a49c5b74eda4143 (diff)
parentf415b816165a6dc5034e453ed05f9900100ea960 (diff)
Merge branch 'master' of https://github.com/mamedev/mame
Diffstat (limited to 'src')
-rw-r--r--src/devices/cpu/b5000/b5000base.cpp3
-rw-r--r--src/devices/machine/laserdsc.cpp20
-rw-r--r--src/devices/machine/laserdsc.h2
-rw-r--r--src/devices/machine/ldv4200hle.cpp948
-rw-r--r--src/devices/machine/ldv4200hle.h217
-rw-r--r--src/mame/drivers/hh_b5000.cpp7
-rw-r--r--src/mame/drivers/jpmsys5sw.cpp2
-rw-r--r--src/mame/drivers/timetrv.cpp319
-rw-r--r--src/mame/layout/timetrv.lay65
9 files changed, 1497 insertions, 86 deletions
diff --git a/src/devices/cpu/b5000/b5000base.cpp b/src/devices/cpu/b5000/b5000base.cpp
index 08211dfa334..e6acd3a5aed 100644
--- a/src/devices/cpu/b5000/b5000base.cpp
+++ b/src/devices/cpu/b5000/b5000base.cpp
@@ -5,7 +5,7 @@
Rockwell B5000 family MCU cores
This MCU series sits between A4000 and the more publicly available PPS4/1.
-Known part numbers: A/B5000, A/B5300, A/B5500, A/B5900, B6000, B6100.
+Known part numbers: A/B5000, A5300, A/B5500, A/B5900, B6000, B6100.
The latter two were manufactured for Mattel, with small modifications
useful for making handheld games. In fact, the programmer of the first
Mattel handheld games was a circuit designer at Rockwell.
@@ -13,6 +13,7 @@ Mattel handheld games was a circuit designer at Rockwell.
The main difference between Axxxx and Bxxxx is that B runs on low power,
there's also a small change with the way they output LEDs.
+A5300 might not be in this series, the page size is 0x3f instead of 0x40.
A4000 is similar, but too many differences to emulate in this device, probably.
*/
diff --git a/src/devices/machine/laserdsc.cpp b/src/devices/machine/laserdsc.cpp
index 4d04ea68505..475014f4f83 100644
--- a/src/devices/machine/laserdsc.cpp
+++ b/src/devices/machine/laserdsc.cpp
@@ -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);
}
diff --git a/src/devices/machine/laserdsc.h b/src/devices/machine/laserdsc.h
index b706afb5816..9466a869505 100644
--- a/src/devices/machine/laserdsc.h
+++ b/src/devices/machine/laserdsc.h
@@ -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
diff --git a/src/devices/machine/ldv4200hle.cpp b/src/devices/machine/ldv4200hle.cpp
new file mode 100644
index 00000000000..c86b3e4cee7
--- /dev/null
+++ b/src/devices/machine/ldv4200hle.cpp
@@ -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());
+}
diff --git a/src/devices/machine/ldv4200hle.h b/src/devices/machine/ldv4200hle.h
new file mode 100644
index 00000000000..f57763698eb
--- /dev/null
+++ b/src/devices/machine/ldv4200hle.h
@@ -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
diff --git a/src/mame/drivers/hh_b5000.cpp b/src/mame/drivers/hh_b5000.cpp
index b9ebda9e3da..accc1d4c5dc 100644
--- a/src/mame/drivers/hh_b5000.cpp
+++ b/src/mame/drivers/hh_b5000.cpp
@@ -235,14 +235,15 @@ ROM_END
/***************************************************************************
- Mattel Missile Attack (model 2048) / Battlestar Galactica: Space Alert (model 2448)
+ Mattel Missile Attack (model 2048) / Space Alert (model 2448)
* B6000 MCU (label B6001CA/EA, die label B6001)
* 2-digit 7seg display, 21 other leds, 1-bit sound
The initial release was called Missile Attack, it didn't sell well (Mattel
blamed it on NBC for refusing to air their commercial). They changed the
title/setting and advertised an upcoming rerelease as "Flash Gordon", but
- changed plans and named it "Battlestar Galactica: Space Alert".
+ changed plans and named it "Space Alert" (aka "Battlestar Galactica:
+ Space Alert").
***************************************************************************/
@@ -716,7 +717,7 @@ ROM_END
// YEAR NAME PARENT CMP MACHINE INPUT CLASS INIT COMPANY, FULLNAME, FLAGS
CONS( 1976, autorace, 0, 0, autorace, autorace, autorace_state, empty_init, "Mattel Electronics", "Auto Race", MACHINE_SUPPORTS_SAVE )
-CONS( 1977, misatk, 0, 0, misatk, misatk, misatk_state, empty_init, "Mattel Electronics", "Missile Attack (Mattel)", MACHINE_SUPPORTS_SAVE )
+CONS( 1977, misatk, 0, 0, misatk, misatk, misatk_state, empty_init, "Mattel Electronics", "Missile Attack / Space Alert", MACHINE_SUPPORTS_SAVE )
CONS( 1977, mfootb, 0, 0, mfootb, mfootb, mfootb_state, empty_init, "Mattel Electronics", "Football (Mattel)", MACHINE_SUPPORTS_SAVE )
CONS( 1978, mbaseb, 0, 0, mbaseb, mbaseb, mbaseb_state, empty_init, "Mattel Electronics", "Baseball (Mattel)", MACHINE_SUPPORTS_SAVE )
CONS( 1980, gravity, 0, 0, gravity, gravity, gravity_state, empty_init, "Mattel Electronics", "Gravity (Mattel)", MACHINE_SUPPORTS_SAVE )
diff --git a/src/mame/drivers/jpmsys5sw.cpp b/src/mame/drivers/jpmsys5sw.cpp
index 4c188005b41..8e226fab7db 100644
--- a/src/mame/drivers/jpmsys5sw.cpp
+++ b/src/mame/drivers/jpmsys5sw.cpp
@@ -1632,4 +1632,4 @@ GAME( 199?, j5revoa, j5revo, jpmsys5_ym, popeye, jpmsys5_state, empty_init,
GAMEL( 199?, j5sizl, 0, jpmsys5_ym, popeye, jpmsys5_state, empty_init, ROT0, "JPM", "Sizzling (JPM) (SYSTEM5)", GAME_FLAGS, layout_j5sizl )
-GAME( 1990, j5hilos, 0, jpmsys5_ym, popeye, jpmsys5_state, empty_init, ROT0, "JPM", "Hi-Ho Silver (JPM) (SYSTEM5)", GAME_FLAGS )
+GAME( 1990, j5hilos, 0, jpmsys5_ym, popeye, jpmsys5_state, empty_init, ROT0, "JPM", "Hi-Lo Silver (JPM) (SYSTEM5)", GAME_FLAGS )
diff --git a/src/mame/drivers/timetrv.cpp b/src/mame/drivers/timetrv.cpp
index c05012458a7..a326c3d14d3 100644
--- a/src/mame/drivers/timetrv.cpp
+++ b/src/mame/drivers/timetrv.cpp
@@ -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:
- 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);
+ 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);
-void timetrv_state::video_start()
-{
-}
+ 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;
-uint32_t timetrv_state::screen_update_timetrv(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
+ required_device<cpu_device> m_maincpu;
+ 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::machine_start()
{
- popmessage("%s%s",reinterpret_cast<char *>(m_led_vram_lo.target()),reinterpret_cast<char *>(m_led_vram_hi.target()));
- return 0;
+ m_digits.resolve();
+ m_decimals.resolve();
+ m_cube_lamp.resolve();
+ m_player_lamps.resolve();
}
-uint8_t timetrv_state::test1_r()
+void timetrv_state::ppi1_pc_w(uint8_t data)
{
- return ioport("IN0")->read();//machine().rand();
+ // 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);
}
-uint8_t timetrv_state::test2_r()
+uint32_t timetrv_state::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
- /*bit 7,eeprom read bit*/
- return (ioport("IN1")->read() & 0x7f);//machine().rand();
+ return 0;
}
-
-uint8_t timetrv_state::in_r()
+template <offs_t Bank>
+void timetrv_state::led_w(offs_t offset, uint8_t data)
{
- return 0xff;
+ /*
+ 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
+
+ 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
+ };
+
+ 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?
diff --git a/src/mame/layout/timetrv.lay b/src/mame/layout/timetrv.lay
new file mode 100644
index 00000000000..cad88c53a3c
--- /dev/null
+++ b/src/mame/layout/timetrv.lay
@@ -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>