summaryrefslogtreecommitdiffstatshomepage
path: root/trunk/src/emu/machine/ldvp931.c
diff options
context:
space:
mode:
Diffstat (limited to 'trunk/src/emu/machine/ldvp931.c')
-rw-r--r--trunk/src/emu/machine/ldvp931.c682
1 files changed, 682 insertions, 0 deletions
diff --git a/trunk/src/emu/machine/ldvp931.c b/trunk/src/emu/machine/ldvp931.c
new file mode 100644
index 00000000000..7adb45b6e75
--- /dev/null
+++ b/trunk/src/emu/machine/ldvp931.c
@@ -0,0 +1,682 @@
+/*************************************************************************
+
+ ldvp931.c
+
+ Philips 22VP931 laserdisc emulation.
+
+****************************************************************************
+
+ Copyright Aaron Giles
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+ * Neither the name 'MAME' nor the names of its contributors may be
+ used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY AARON GILES ''AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL AARON GILES BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+
+**************************************************************************
+
+ Still to do:
+
+ * determine actual slow/fast speeds
+ *
+
+*************************************************************************/
+
+
+#include "emu.h"
+#include "ldvp931.h"
+
+
+
+//**************************************************************************
+// DEBUGGING
+//**************************************************************************
+
+#define LOG_COMMANDS 0
+#define LOG_PORTS 0
+
+
+
+//**************************************************************************
+// CONSTANTS
+//**************************************************************************
+
+// scanning speeds
+#define SCAN_SPEED (2000 / 30) // 2000 frames/second
+#define SCAN_FAST_SPEED (4000 / 30) // 4000 frames/second
+
+
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+// devices
+const device_type PHILLIPS_22VP931 = &device_creator<phillips_22vp931_device>;
+
+
+
+//**************************************************************************
+// 22VP931 ROM AND MACHINE INTERFACES
+//**************************************************************************
+
+static ADDRESS_MAP_START( vp931_portmap, AS_IO, 8, phillips_22vp931_device )
+ AM_RANGE(0x00, 0x00) AM_MIRROR(0xcf) AM_READWRITE(i8049_keypad_r, i8049_output0_w)
+ AM_RANGE(0x10, 0x10) AM_MIRROR(0xcf) AM_READWRITE(i8049_unknown_r, i8049_output1_w)
+ AM_RANGE(0x20, 0x20) AM_MIRROR(0xcf) AM_READWRITE(i8049_datic_r, i8049_lcd_w)
+ AM_RANGE(0x30, 0x30) AM_MIRROR(0xcf) AM_READWRITE(i8049_from_controller_r, i8049_to_controller_w)
+ AM_RANGE(MCS48_PORT_P1, MCS48_PORT_P1) AM_READWRITE(i8049_port1_r, i8049_port1_w)
+ AM_RANGE(MCS48_PORT_P2, MCS48_PORT_P2) AM_READWRITE(i8049_port2_r, i8049_port2_w)
+ AM_RANGE(MCS48_PORT_T0, MCS48_PORT_T0) AM_READ(i8049_t0_r)
+ AM_RANGE(MCS48_PORT_T1, MCS48_PORT_T1) AM_READ(i8049_t1_r)
+ADDRESS_MAP_END
+
+
+static MACHINE_CONFIG_FRAGMENT( vp931 )
+ MCFG_CPU_ADD("vp931", I8049, XTAL_11MHz)
+ MCFG_CPU_IO_MAP(vp931_portmap)
+MACHINE_CONFIG_END
+
+
+ROM_START( vp931 )
+ ROM_REGION( 0x800, "vp931", 0 )
+ ROM_LOAD( "at-6-1_a.bin", 0x000, 0x800, CRC(e11b3c8d) SHA1(ea2d7f6a044ed085ce5e09d8b1b1a21c37f0e9b8) )
+ROM_END
+
+
+
+//**************************************************************************
+// PHILLIPS 22VP931 IMPLEMENTATION
+//**************************************************************************
+
+//-------------------------------------------------
+// phillips_22vp931_device - constructor
+//-------------------------------------------------
+
+phillips_22vp931_device::phillips_22vp931_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : laserdisc_device(mconfig, PHILLIPS_22VP931, "Phillips 22VP931", "22vp931", tag, owner, clock),
+ m_i8049_cpu(*this, "vp931"),
+ m_tracktimer(NULL),
+ m_i8049_out0(0),
+ m_i8049_out1(0),
+ m_i8049_port1(0),
+ m_daticval(0),
+ m_daticerp(0),
+ m_datastrobe(0),
+ m_fromcontroller(0),
+ m_fromcontroller_pending(false),
+ m_tocontroller(0),
+ m_tocontroller_pending(false),
+ m_trackdir(0),
+ m_trackstate(0),
+ m_cmdcount(0),
+ m_advanced(0)
+{
+}
+
+
+//-------------------------------------------------
+// reset_w - write to the reset line
+//-------------------------------------------------
+
+void phillips_22vp931_device::reset_w(UINT8 data)
+{
+ // control the CPU state
+ m_i8049_cpu->set_input_line(INPUT_LINE_RESET, data);
+
+ // on an assert, reset the device state as well
+ if (data == ASSERT_LINE)
+ reset();
+}
+
+
+//-------------------------------------------------
+// data_r - handle a parallel data read from the
+// 22VP931
+//-------------------------------------------------
+
+UINT8 phillips_22vp931_device::data_r()
+{
+ // if data is pending, clear the pending flag and notify any callbacks
+ if (m_tocontroller_pending)
+ {
+ m_tocontroller_pending = false;
+ if (!m_data_ready.isnull())
+ m_data_ready(*this, false);
+ }
+
+ // also boost interleave for 4 scanlines to ensure proper communications
+ machine().scheduler().boost_interleave(attotime::zero, screen().scan_period() * 4);
+ return m_tocontroller;
+}
+
+
+//-------------------------------------------------
+// device_start - device initialization
+//-------------------------------------------------
+
+void phillips_22vp931_device::device_start()
+{
+ // pass through to the parent
+ laserdisc_device::device_start();
+
+ // allocate a timer
+ m_tracktimer = timer_alloc(TID_HALF_TRACK);
+}
+
+
+//-------------------------------------------------
+// device_reset - device reset
+//-------------------------------------------------
+
+void phillips_22vp931_device::device_reset()
+{
+ // pass through to the parent
+ laserdisc_device::device_reset();
+
+ // reset our state
+ m_i8049_out0 = 0;
+ m_i8049_out1 = 0;
+ m_i8049_port1 = 0;
+
+ m_daticval = 0;
+ m_daticerp = 0;
+ m_datastrobe = 0;
+
+ m_fromcontroller = 0;
+ m_fromcontroller_pending = false;
+ m_tocontroller = 0;
+ m_tocontroller_pending = false;
+
+ m_trackdir = 0;
+ m_trackstate = 0;
+
+ m_cmdcount = 0;
+ m_advanced = 0;
+}
+
+
+//-------------------------------------------------
+// device_timer - handle timers set by this
+// device
+//-------------------------------------------------
+
+void phillips_22vp931_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+{
+ switch (id)
+ {
+ case TID_VBI_DATA_FETCH:
+ {
+ UINT32 line = param >> 2;
+ int which = param & 3;
+ UINT32 code = 0;
+
+ // fetch the code and compute the DATIC latched value
+ if (line >= LASERDISC_CODE_LINE16 && line <= LASERDISC_CODE_LINE18)
+ code = get_field_code(laserdisc_field_code(line), false);
+
+ // at the start of each line, signal an interrupt and use a timer to turn it off
+ if (which == 0)
+ {
+ m_i8049_cpu->set_input_line(MCS48_INPUT_IRQ, ASSERT_LINE);
+ timer_set(attotime::from_nsec(5580), TID_IRQ_OFF);
+ }
+
+ // clock the data strobe on each subsequent callback
+ else if (code != 0)
+ {
+ m_daticval = code >> (8 * (3 - which));
+ m_datastrobe = 1;
+ timer_set(attotime::from_nsec(5000), TID_DATA_STROBE_OFF);
+ }
+
+ // determine the next bit to fetch and reprime ourself
+ if (++which == 4)
+ {
+ which = 0;
+ line++;
+ }
+ if (line <= LASERDISC_CODE_LINE18 + 1)
+ timer_set(screen().time_until_pos(line*2, which * 2 * screen().width() / 4), TID_VBI_DATA_FETCH, (line << 2) + which);
+ break;
+ }
+
+ case TID_DEFERRED_DATA:
+ // set the value and mark it pending
+ if (LOG_COMMANDS && m_fromcontroller_pending)
+ printf("Dropped previous command byte\n");
+ m_fromcontroller = param;
+ m_fromcontroller_pending = true;
+
+ // track the commands for debugging purposes
+ if (m_cmdcount < ARRAY_LENGTH(m_cmdbuf))
+ {
+ m_cmdbuf[m_cmdcount++ % 3] = param;
+ if (LOG_COMMANDS && m_cmdcount % 3 == 0)
+ printf("Cmd: %02X %02X %02X\n", m_cmdbuf[0], m_cmdbuf[1], m_cmdbuf[2]);
+ }
+ break;
+
+ case TID_IRQ_OFF:
+ m_i8049_cpu->set_input_line(MCS48_INPUT_IRQ, CLEAR_LINE);
+ break;
+
+ case TID_DATA_STROBE_OFF:
+ m_datastrobe = 0;
+ break;
+
+ case TID_ERP_OFF:
+ m_daticerp = 0;
+ break;
+
+ case TID_HALF_TRACK:
+ // advance by the count and toggle the state
+ m_trackstate ^= 1;
+ if ((m_trackdir < 0 && !m_trackstate) || (m_trackdir > 0 && m_trackstate))
+ {
+ advance_slider(m_trackdir);
+ m_advanced += m_trackdir;
+ }
+ break;
+
+ // pass everything else onto the parent
+ default:
+ laserdisc_device::device_timer(timer, id, param, ptr);
+ break;
+ }
+}
+
+
+//-------------------------------------------------
+// device_rom_region - return a pointer to our
+// ROM region definitions
+//-------------------------------------------------
+
+const rom_entry *phillips_22vp931_device::device_rom_region() const
+{
+ return ROM_NAME(vp931);
+}
+
+
+//-------------------------------------------------
+// device_mconfig_additions - return a pointer to
+// our machine config fragment
+//-------------------------------------------------
+
+machine_config_constructor phillips_22vp931_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME(vp931);
+}
+
+
+//-------------------------------------------------
+// player_vsync - VSYNC callback, called at the
+// start of the blanking period
+//-------------------------------------------------
+
+void phillips_22vp931_device::player_vsync(const vbi_metadata &vbi, int fieldnum, attotime curtime)
+{
+ // reset our command counter (debugging only)
+ m_cmdcount = 0;
+
+ // set the ERP signal to 1 to indicate start of frame, and set a timer to turn it off
+ m_daticerp = 1;
+ timer_set(screen().time_until_pos(15*2), TID_ERP_OFF);
+}
+
+
+//-------------------------------------------------
+// player_update - update callback, called on
+// the first visible line of the frame
+//-------------------------------------------------
+
+INT32 phillips_22vp931_device::player_update(const vbi_metadata &vbi, int fieldnum, attotime curtime)
+{
+ // set the first VBI timer to go at the start of line 16
+ timer_set(screen().time_until_pos(16*2), TID_VBI_DATA_FETCH, LASERDISC_CODE_LINE16 << 2);
+
+ // play forward by default
+ return fieldnum;
+}
+
+
+//-------------------------------------------------
+// i8049_output0_w - controls audio/video squelch
+// and other bits
+//-------------------------------------------------
+
+WRITE8_MEMBER( phillips_22vp931_device::i8049_output0_w )
+{
+ /*
+ $80 = n/c
+ $40 = LED (?) -> C335
+ $20 = LED (?)
+ $10 = LED (?) -> CX
+ $08 = EJECT
+ $04 = inverted -> AUDIO MUTE II
+ $02 = inverted -> AUDIO MUTE I
+ $01 = inverted -> VIDEO MUTE
+ */
+
+ if (LOG_PORTS && (m_i8049_out0 ^ data) & 0xff)
+ {
+ printf("%03X:out0:", cpu_get_pc(&space.device()));
+ if ( (data & 0x80)) printf(" ???");
+ if ( (data & 0x40)) printf(" LED1");
+ if ( (data & 0x20)) printf(" LED2");
+ if ( (data & 0x10)) printf(" LED3");
+ if ( (data & 0x08)) printf(" EJECT");
+ if (!(data & 0x04)) printf(" AUDMUTE2");
+ if (!(data & 0x02)) printf(" AUDMUTE1");
+ if (!(data & 0x01)) printf(" VIDMUTE");
+ printf("\n");
+ m_i8049_out0 = data;
+ }
+
+ // update a/v squelch
+ set_audio_squelch(!(data & 0x02), !(data & 0x04));
+ set_video_squelch(!(data & 0x01));
+}
+
+
+//-------------------------------------------------
+// i8049_output1_w - controls scanning behaviors
+//-------------------------------------------------
+
+WRITE8_MEMBER( phillips_22vp931_device::i8049_output1_w )
+{
+ /*
+ $80 = n/c
+ $40 = n/c
+ $20 = n/c
+ $10 = n/c
+ $08 = inverted -> SMS
+ $04 = inverted -> SSS
+ $02 = inverted -> SCAN CMD
+ $01 = OSM
+ */
+
+ INT32 speed = 0;
+
+ if (LOG_PORTS && (m_i8049_out1 ^ data) & 0x08)
+ {
+ mame_printf_debug("%03X:out1:", cpu_get_pc(&space.device()));
+ if (!(data & 0x08)) mame_printf_debug(" SMS");
+ mame_printf_debug("\n");
+ m_i8049_out1 = data;
+ }
+
+ // speed is 0 unless SCAN CMD is clear
+ speed = 0;
+ if (!(data & 0x02))
+ {
+ // fast/slow is based on bit 2
+ speed = (data & 0x04) ? SCAN_FAST_SPEED : SCAN_SPEED;
+
+ // direction is based on bit 0
+ if (data & 0x01)
+ speed = -speed;
+ }
+
+ // update the speed
+ set_slider_speed(speed);
+}
+
+
+//-------------------------------------------------
+// i8049_lcd_w - vestigial LCD frame display
+//-------------------------------------------------
+
+WRITE8_MEMBER( phillips_22vp931_device::i8049_lcd_w )
+{
+ /*
+ Frame number is written as 5 digits here; however, it is not actually
+ connected
+ */
+}
+
+
+//-------------------------------------------------
+// i8049_unknown_r - unknown input port
+//-------------------------------------------------
+
+READ8_MEMBER( phillips_22vp931_device::i8049_unknown_r )
+{
+ // only bit $80 is checked and its effects are minor
+ return 0x00;
+}
+
+
+//-------------------------------------------------
+// i8049_keypad_r - vestigial keypad/button
+// controls
+//-------------------------------------------------
+
+READ8_MEMBER( phillips_22vp931_device::i8049_keypad_r )
+{
+ /*
+ From the code, this is apparently a vestigial keypad with basic controls:
+ $01 = play
+ $02 = still
+ $04 = jump 25 frames backward
+ $08 = jump 25 frames forward
+ $10 = search for frame 50(?)
+ $20 = search for frame 350(?)
+ $40 = reset
+ $80 = play reverse
+ */
+ return 0x00;
+}
+
+
+//-------------------------------------------------
+// i8049_datic_r - read the latched value from the
+// DATIC circuit
+//-------------------------------------------------
+
+READ8_MEMBER( phillips_22vp931_device::i8049_datic_r )
+{
+ return m_daticval;
+}
+
+
+//-------------------------------------------------
+// i8049_from_controller_r - read the value the
+// external controller wrote
+//-------------------------------------------------
+
+READ8_MEMBER( phillips_22vp931_device::i8049_from_controller_r )
+{
+ // clear the pending flag and return the data
+ m_fromcontroller_pending = false;
+ return m_fromcontroller;
+}
+
+
+//-------------------------------------------------
+// i8049_to_controller_w - write a value back to
+// the external controller
+//-------------------------------------------------
+
+WRITE8_MEMBER( phillips_22vp931_device::i8049_to_controller_w )
+{
+ // set the pending flag and stash the data
+ m_tocontroller_pending = TRUE;
+ m_tocontroller = data;
+
+ // signal to the callback if provided
+ if (!m_data_ready.isnull())
+ m_data_ready(*this, true);
+
+ // also boost interleave for 4 scanlines to ensure proper communications
+ machine().scheduler().boost_interleave(attotime::zero, screen().scan_period() * 4);
+}
+
+
+//-------------------------------------------------
+// i8049_port1_r - read the 8048 I/O port 1
+//-------------------------------------------------
+
+READ8_MEMBER( phillips_22vp931_device::i8049_port1_r )
+{
+ /*
+ $80 = P17 = (in) unsure
+ $40 = P16 = (in) /ERP from datic circuit
+ $20 = P15 = (in) D105
+ */
+
+ UINT8 result = 0x00;
+ if (!m_daticerp)
+ result |= 0x40;
+ return result;
+}
+
+
+//-------------------------------------------------
+// i8049_port1_w - write the 8048 I/O port 1
+//-------------------------------------------------
+
+WRITE8_MEMBER( phillips_22vp931_device::i8049_port1_w )
+{
+ /*
+ $10 = P14 = (out) D104 -> /SPEED
+ $08 = P13 = (out) D103 -> /TIMER ENABLE
+ $04 = P12 = (out) D102 -> /REV
+ $02 = P11 = (out) D101 -> /FORW
+ $01 = P10 = (out) D100 -> some op-amp then to C334, B56, B332
+ */
+
+ if (LOG_PORTS && (m_i8049_port1 ^ data) & 0x1f)
+ {
+ printf("%03X:port1:", cpu_get_pc(&space.device()));
+ if (!(data & 0x10)) printf(" SPEED");
+ if (!(data & 0x08)) printf(" TIMENABLE");
+ if (!(data & 0x04)) printf(" REV");
+ if (!(data & 0x02)) printf(" FORW");
+ if (!(data & 0x01)) printf(" OPAMP");
+ printf("\n");
+ }
+
+ // if bit 0 is set, we are not tracking
+ if (data & 0x01)
+ m_trackdir = 0;
+
+ // if bit 0 is clear and we weren't tracking before, initialize the state
+ else if (m_trackdir == 0)
+ {
+ m_advanced = 0;
+
+ // if bit 2 is clear, we are moving backwards
+ if (!(data & 0x04))
+ {
+ m_trackdir = -1;
+ m_trackstate = 1;
+ }
+
+ // if bit 1 is clear, we are moving forward
+ else if (!(data & 0x02))
+ {
+ m_trackdir = 1;
+ m_trackstate = 0;
+ }
+ }
+
+ // if we have a timer, adjust it
+ if (m_tracktimer != NULL)
+ {
+ // turn it off if we're not tracking
+ if (m_trackdir == 0)
+ m_tracktimer->reset();
+
+ // if we just started tracking, or if the speed was changed, reprime the timer
+ else if (((m_i8049_port1 ^ data) & 0x11) != 0)
+ {
+ // speeds here are just guesses, but work with the player logic; this is the time per half-track
+ attotime speed = (data & 0x10) ? attotime::from_usec(60) : attotime::from_usec(10);
+
+ // always start with an initial long delay; the code expects this
+ m_tracktimer->adjust(attotime::from_usec(100), 0, speed);
+ }
+ }
+
+ m_i8049_port1 = data;
+}
+
+
+//-------------------------------------------------
+// i8049_port2_r - read from the 8048 I/O port 2
+//-------------------------------------------------
+
+READ8_MEMBER( phillips_22vp931_device::i8049_port2_r )
+{
+ /*
+ $80 = P27 = (in) set/reset latch; set by FOC LS, reset by IGR
+ $20 = P25 = (in) D125 -> 0 when data written to controller is preset, reset to 1 when read
+ $10 = P24 = (in) D124 -> 0 when data from controller is present, reset to 1 on a read
+ */
+
+ UINT8 result = 0x00;
+ if (!m_tocontroller_pending)
+ result |= 0x20;
+ if (!m_fromcontroller_pending)
+ result |= 0x10;
+ return result;
+}
+
+
+//-------------------------------------------------
+// i8049_port2_w - write the 8048 I/O port 2
+//-------------------------------------------------
+
+WRITE8_MEMBER( phillips_22vp931_device::i8049_port2_w )
+{
+ /*
+ $40 = P26 = (out) cleared while data is sent back & forth; set afterwards
+ [Not actually connected, but this is done in the code]
+ */
+}
+
+
+//-------------------------------------------------
+// i8049_t0_r - return the T0 line status, which is
+// connected to the DATIC's data strobe line
+//-------------------------------------------------
+
+READ8_MEMBER( phillips_22vp931_device::i8049_t0_r )
+{
+ return m_datastrobe;
+}
+
+
+//-------------------------------------------------
+// i8049_t1_r - return the T1 line status, which
+// is connected to the tracking state and is used
+// to count the number of tracks advanced
+//-------------------------------------------------
+
+READ8_MEMBER( phillips_22vp931_device::i8049_t1_r )
+{
+ return m_trackstate;
+}