cops.cpp: Promote Revelations to working (#12485)

* LDP1450: Added HLE of player and hookups to some games that use it
* LDP1450: Tweaked timings
* LDP1450 - added some more comms, and text overlay logging
* cops.cpp: Fixed loose input that stopped Nova games from booting
* cops.cpp: Add Revelations support
* LDP1450: Added multibyte command support
* Revelations: Add SHA1 for disc image (needs redump)
This commit is contained in:
James Wallace 2024-06-26 01:12:12 +01:00 committed by GitHub
parent 6f3eab7514
commit c8c09a8c88
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 2870 additions and 565 deletions

View File

@ -2082,6 +2082,18 @@ if (MACHINES["LDP1450"]~=null) then
}
end
---------------------------------------------------
--
--@src/devices/machine/ldp1450hle.h,MACHINES["LDP1450HLE"] = true
---------------------------------------------------
if (MACHINES["LDP1450HLE"]~=null) then
files {
MAME_DIR .. "src/devices/machine/ldp1450hle.cpp",
MAME_DIR .. "src/devices/machine/ldp1450hle.h",
}
end
---------------------------------------------------
--
--@src/devices/machine/ldvp931.h,MACHINES["LDVP931"] = true
@ -3035,6 +3047,18 @@ if (MACHINES["R10788"]~=null) then
}
end
---------------------------------------------------
--
--@src/devices/machine/r65c52.h,MACHINES["R65C52"] = true
---------------------------------------------------
if (MACHINES["R65C52"]~=null) then
files {
MAME_DIR .. "src/devices/machine/r65c52.cpp",
MAME_DIR .. "src/devices/machine/r65c52.h",
}
end
---------------------------------------------------
--
--@src/devices/machine/ra17xx.h,MACHINES["RA17XX"] = true

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,200 @@
// license:BSD-3-Clause
/*************************************************************************
ldp1450hle.h
*************************************************************************/
#ifndef MAME_MACHINE_LDP1450_H
#define MAME_MACHINE_LDP1450_H
#pragma once
#include "laserdsc.h"
#include "diserial.h"
//**************************************************************************
// GLOBAL VARIABLES
//**************************************************************************
// device type definition
DECLARE_DEVICE_TYPE(SONY_LDP1450HLE, sony_ldp1450hle_device)
//**************************************************************************
// TYPE DEFINITIONS
//**************************************************************************
// ======================> sony_ldp1450hle_device
class sony_ldp1450hle_device : public laserdisc_device, public device_serial_interface
{
public:
// construction/destruction
sony_ldp1450hle_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock = 0);
auto serial_tx() { return m_serial_tx.bind(); }
void set_baud(s32 clock) { m_baud = clock; }
protected:
// device-level overrides
virtual void device_start() override;
virtual void device_reset() override;
// laserdisc overrides
virtual void player_vsync(const vbi_metadata &vbi, int fieldnum, const attotime &curtime) override;
virtual s32 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;
TIMER_CALLBACK_MEMBER(process_vbi_data);
TIMER_CALLBACK_MEMBER(process_queue);
private:
enum player_command : u16
{
CMD_AUDIO_OFF =0x24,
CMD_AUDIO_ON =0x25,
CMD_VIDEO_OFF =0x26,
CMD_VIDEO_ON =0x27,
CMD_PSC_ON =0x28,
CMD_PSC_OFF =0x29,
CMD_EJECT =0x2a,
CMD_STEP_STILL =0x2b,
CMD_STEP_STILL_REVERSE =0x2c,
CMD_PLAY =0x3a,
CMD_FAST_FORWARD =0x3b,
CMD_SLOW_FORWARD =0x3c,
CMD_STEP_FORWARD =0x3d,
CMD_SCAN_FORWARD =0x3e,
CMD_STOP =0x3f,
CMD_ENTER =0x40,
CMD_CLEAR =0x41,
CMD_MENU =0x42,
CMD_SEARCH =0x43,
CMD_REPEAT =0x44,
CMD_CH1_ON =0x46,
CMD_CH1_OFF =0x47,
CMD_CH2_ON =0x48,
CMD_CH2_OFF =0x49,
CMD_PLAY_REVERSE =0x4a,
CMD_FAST_REVERSE =0x4b,
CMD_SLOW_REVERSE =0x4c,
CMD_STEP_REVERSE =0x4d,
CMD_SCAN_REVERSE =0x4e,
CMD_STILL =0x4f,
CMD_INDEX_ON =0x50,
CMD_INDEX_OFF =0x51,
CMD_FRAME_SET =0x55,
CMD_CLEAR_ALL =0x56,
CMD_ADDR_INQ =0x60,
CMD_STATUS_INQ =0x67,
CMD_CHAPTER_SET =0x69,
CMD_USER_INDEX_CTRL =0x80,
CMD_USER_INDEX_ON =0x81,
CMD_USER_INDEX_OFF =0x82,
};
enum player_mode : u8
{
MODE_PARK,
MODE_DOOR_OPEN,
MODE_PAUSE,
MODE_PLAY,
MODE_MS_FORWARD,
MODE_MS_REVERSE,
MODE_SEARCH,
MODE_SEARCH_CMD,
MODE_SEARCH_REP,
MODE_SEARCH_CL,
MODE_REPEAT_CMD_MARK,
MODE_REPEAT_CMD_REPS,
MODE_STILL,
SUBMODE_NORMAL,
SUBMODE_USER_INDEX,
SUBMODE_USER_INDEX_MODE_1,
SUBMODE_USER_INDEX_MODE_2,
SUBMODE_USER_INDEX_MODE_3,
SUBMODE_USER_INDEX_STRING_1,
SUBMODE_USER_INDEX_STRING_2,
SUBMODE_USER_INDEX_WINDOW,
};
enum address_mode : u8
{
ADDRESS_FRAME,
ADDRESS_CHAPTER
};
void queue_reply(u8 reply, float delay);
void queue_reply_buffer (const u8 reply[], float delay);
static u32 bcd_to_literal(u32 bcd);
static bool is_number(char value);
void add_command_byte(u8 command);
void begin_search(u32 value);
void update_audio_squelch();
void update_video_enable();
// internal state
devcb_write_line m_serial_tx;
emu_timer * m_vbi_fetch;
emu_timer * m_queue_timer;
bool m_cmd_running;
u8 m_reply_buffer[64];
u8 m_reply_write_index;
u8 m_reply_read_index;
u8 m_reply;
u8 m_mode; // current player mode
u8 m_submode;
u32 m_baud;
u32 m_chapter;
u32 m_time;
u32 m_frame; // raw frame index (CAV mode)
u32 m_search_chapter;
u32 m_search_frame;
s32 m_cmd_buffer;
u32 m_mark_chapter;
u32 m_mark_frame;
u32 m_repeat_chapter_start;
u32 m_repeat_chapter_end;
u32 m_repeat_frame_start;
u32 m_repeat_frame_end;
u32 m_repeat_repetitions;
u8 m_video_switch;
bool m_ch1_switch;
bool m_ch2_switch;
u8 m_display_switch;
u8 m_address_flag;
u16 m_base_speed;
u16 m_speed;
u32 m_speed_accum;
u32 m_curr_frame;
u8 m_user_index_x;
u8 m_user_index_y;
u8 m_user_index_mode;
u8 m_user_index_char_idx;
u8 m_user_index_window_idx;
char m_user_index_chars[32];
};
#endif // MAME_MACHINE_LDP1450_H

View File

@ -0,0 +1,987 @@
// license:BSD-3-Clause
// copyright-holders:jwallace
/**********************************************************************
Rockwell 65C52 Dual Asynchronous Communication Interface Adapter
A slightly tweaked combination of two 6551 ACIAs on a single chip
**********************************************************************/
#include "emu.h"
#include "r65c52.h"
#define VERBOSE 0
#include "logmacro.h"
DEFINE_DEVICE_TYPE(R65C52, r65c52_device, "r65c52", "Rockwell 65C52 DACIA")
r65c52_device::r65c52_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) : device_t(mconfig, R65C52, tag, owner, clock),
m_internal_clock1(*this, "clock1"),
m_internal_clock2(*this, "clock2"),
m_irq_handler(*this),
m_txd_handler(*this),
m_rxc_handler(*this),
m_rts_handler(*this),
m_dtr_handler(*this),
m_aux_ctrl{0, 0}, m_control{0, 0},
m_compare{0, 0},
m_format{0, 0}, m_status{0, 0},
m_tdr{0, 0}, m_tdre{true, true},
m_rdr{0, 0}, m_rdrf{false, false},
m_ier{0, 0}, m_isr{0, 0},
m_irq{0, 0},
m_overrun{false, false},
m_parity_err{false, false},
m_parity_err_mode{0, 0},
m_txd{0, 0},
m_rxc(0),
m_rts{0, 0},
m_dtr{0, 0},
m_xtal(clock),
m_divide{0, 0},
m_cts{0, 0},
m_dsr{0, 0},
m_dcd{0, 0},
m_rxd{0, 0}, m_wordlength{0, 0}, m_stoplength{0, 0}, m_brk{0, 0}, m_echo_mode{0, 0}, m_parity{0, 0},
m_rx_state{STATE_START, STATE_START},
m_rx_clock{0, 0}, m_rx_bits{0, 0}, m_rx_shift{0, 0}, m_rx_parity{0, 0},
m_rx_counter{0, 0},
m_tx_state{STATE_START, STATE_START},
m_tx_output{OUTPUT_MARK, OUTPUT_MARK},
m_tx_clock{0, 0}, m_tx_bits{0, 0}, m_tx_shift{0, 0}, m_tx_parity{0, 0},
m_tx_counter{0, 0}
{
}
const int r65c52_device::internal_divider[16] =
{
4608,
2096,
1713,
1536,
768,
384,
192,
128,
96,
64,
48,
32,
24,
12,
6,
1};
void r65c52_device::device_add_mconfig(machine_config &config)
{
CLOCK(config, m_internal_clock1, 0);
CLOCK(config, m_internal_clock2, 0);
m_internal_clock1->signal_handler().set(FUNC(r65c52_device::internal_clock1));
m_internal_clock2->signal_handler().set(FUNC(r65c52_device::internal_clock2));
}
void r65c52_device::device_start()
{
// state saving
save_item(NAME(m_aux_ctrl));
save_item(NAME(m_compare));
save_item(NAME(m_control));
save_item(NAME(m_format));
save_item(NAME(m_status));
save_item(NAME(m_tdr));
save_item(NAME(m_tdre));
save_item(NAME(m_rdr));
save_item(NAME(m_rdrf));
save_item(NAME(m_ier));
save_item(NAME(m_isr));
save_item(NAME(m_irq));
save_item(NAME(m_overrun));
save_item(NAME(m_parity_err));
save_item(NAME(m_parity_err_mode));
save_item(NAME(m_txd));
save_item(NAME(m_rxc));
save_item(NAME(m_rts));
save_item(NAME(m_dtr));
save_item(NAME(m_xtal));
save_item(NAME(m_divide));
save_item(NAME(m_cts));
save_item(NAME(m_dsr));
save_item(NAME(m_dcd));
save_item(NAME(m_rxd));
save_item(NAME(m_wordlength));
save_item(NAME(m_stoplength));
save_item(NAME(m_brk));
save_item(NAME(m_echo_mode));
save_item(NAME(m_parity));
save_item(NAME(m_rx_state));
save_item(NAME(m_rx_clock));
save_item(NAME(m_rx_bits));
save_item(NAME(m_rx_shift));
save_item(NAME(m_rx_parity));
save_item(NAME(m_rx_counter));
save_item(NAME(m_tx_state));
save_item(NAME(m_tx_output));
save_item(NAME(m_tx_clock));
save_item(NAME(m_tx_bits));
save_item(NAME(m_tx_shift));
save_item(NAME(m_tx_parity));
save_item(NAME(m_tx_counter));
m_internal_clock1->set_unscaled_clock(m_xtal);
m_internal_clock2->set_unscaled_clock(m_xtal);
set_xtal(m_xtal);
}
void r65c52_device::device_reset()
{
for (int i = 0; i < 2; i++)
{
m_tdre[i] = true;
m_rdrf[i] = true;
m_status[i] = SR_FRAMING_ERROR;
m_aux_ctrl[i] = 0;
m_compare[i] = 0;
m_rdr[i] = 0x00;
m_isr[i] = 0x80;
m_ier[i] = 0x80;
m_rts[i] = 1;
m_dtr[i] = 1;
output_rts(i, 1);
output_dtr(i, 1);
m_rx_state[i] = STATE_START;
m_rx_counter[i] = 0;
}
}
u8 r65c52_device::stoplengthcounter(int idx)
{
if (m_stoplength[idx] == 2)
{
if (m_wordlength[idx] == 5 && m_parity[idx] == PARITY_NONE)
{
return m_divide[idx] + (m_divide[idx] / 2);
}
if (m_wordlength[idx] < 8 || m_parity[idx] == PARITY_NONE)
{
return m_divide[idx] * 2;
}
}
return m_divide[idx];
}
void r65c52_device::output_irq(int idx, int irq)
{
LOG("R65C52: %x IRQ %x \n", idx + 1, irq);
if (m_irq[idx] != irq)
{
m_irq[idx] = irq;
m_irq_handler[idx](!m_irq[idx]);
}
}
void r65c52_device::output_txd(int idx, int txd)
{
switch (m_tx_output[idx])
{
case OUTPUT_MARK:
txd = 1;
break;
case OUTPUT_BREAK:
txd = 0;
break;
}
if (m_txd[idx] != txd)
{
m_txd[idx] = txd;
m_txd_handler[idx](m_txd[idx]);
}
}
void r65c52_device::output_rts(int idx, int rts)
{
LOG("R65C52: %x RTS %x \n", idx + 1, rts);
if (m_rts[idx] != rts)
{
m_rts[idx] = rts;
m_rts_handler[idx](m_rts[idx]);
if (rts)
{
m_status[idx] |= SR_RTS;
}
else
{
m_status[idx] &= ~SR_RTS;
}
}
}
void r65c52_device::output_dtr(int idx, int dtr)
{
LOG("R65C52: %x DTR %x \n", idx + 1, dtr);
if (m_dtr[idx] != dtr)
{
m_dtr[idx] = dtr;
m_dtr_handler[idx](m_dtr[idx]);
if (dtr)
{
m_status[idx] |= SR_DTR;
}
else
{
m_status[idx] &= ~SR_DTR;
}
}
}
void r65c52_device::update_irq(int idx)
{
bool irq = false;
LOG("R65C52: %x IER %x ISR %x\n", idx + 1, m_ier[idx], m_isr[idx]);
for (int i = 0; i < 8; i++)
{
if ((m_ier[idx] & (1 >> i)) && ((m_isr[idx] & (1 >> i))))
{
irq = true;
}
}
output_irq(idx, irq);
}
void r65c52_device::update_divider(int idx)
{
// bits 0-3
double scale = internal_divider[(m_control[idx] >> 0) & 0xf];
if (m_xtal != 0)
{
m_divide[idx] = 16;
if (!m_dtr[idx] || m_rx_state[idx] != STATE_START)
{
scale = (double)1 / scale;
}
else
{
scale = 0;
}
LOG("R65C52: %x CLOCK %d SCALE %f \n", idx + 1, m_xtal * scale, scale);
}
else
{
m_divide[idx] = scale * 16;
scale = 0;
}
if (idx == 0)
{
m_internal_clock1->set_clock_scale(scale);
}
else
{
m_internal_clock2->set_clock_scale(scale);
}
}
u8 r65c52_device::read_rdr(int idx)
{
m_status[idx] &= ~(SR_BRK | SR_FRAMING_ERROR);
m_isr[idx] &= ~(IRQ_PAR | IRQ_FOB | IRQ_RDRF);
m_rdrf[idx] = false;
m_parity_err[idx] = false;
m_overrun[idx] = false;
update_irq(idx);
LOG("R65C52: %x RDR %x \n", idx + 1, m_rdr[idx]);
return m_rdr[idx];
}
u8 r65c52_device::read_status(int idx)
{
LOG("R65C52: %x STATUS %x \n", idx + 1, m_status[idx]);
m_dtr[idx] = false;
m_rts[idx] = false;
return m_status[idx];
}
void r65c52_device::write_ier(int idx, u8 data)
{
if (data & 0x80)
{
m_ier[idx] |= (data & 0x7f);
}
else
{
m_ier[idx] &= ~(data & 0x7f);
}
LOG("R65C52: %x IER %x \n", idx + 1, m_ier[idx]);
}
void r65c52_device::write_tdr(int idx, u8 data)
{
m_tdr[idx] = data;
m_tdre[idx] = false;
m_isr[idx] &= ~IRQ_TDRE;
LOG("R65C52: %x TDR %x \n", idx + 1, m_tdr[idx]);
}
void r65c52_device::write_control(int idx, u8 data)
{
m_control[idx] = data;
// bits 0-3
update_divider(idx);
// bit 4
m_echo_mode[idx] = (m_control[idx] >> 4) & 1;
// bit 5
m_stoplength[idx] = 1 + ((m_control[idx] >> 5) & 1);
LOG("R65C52: %x CTRL%X ECHO %x STOP%x\n", idx + 1, m_control[idx], m_echo_mode[idx], m_stoplength[idx]);
}
void r65c52_device::write_format(int idx, u8 data)
{
m_format[idx] = data;
// bit 0
output_rts(idx, ((m_format[idx] >> 0) & 1));
// bit 1
output_dtr(idx, ((m_format[idx] >> 1) & 1));
// bit 2
if (!((m_format[idx] >> 2) & 1))
{
m_parity[idx] = PARITY_NONE;
}
else
{
// bits 3-4
m_parity[idx] = (m_format[idx] >> 3) & 3;
}
// bits 5-6
m_wordlength[idx] = 5 + ((m_format[idx] >> 5) & 3);
LOG("R65C52: %x FMT %x RTS %x DTR %x PARITY %x WORDLENGTH %x \n", idx + 1, m_format[idx], (m_format[idx] >> 0) & 1, (m_format[idx] >> 1) & 1, m_parity[idx], m_wordlength[idx]);
update_divider(idx);
}
void r65c52_device::write_aux_ctrl(int idx, u8 data)
{
m_aux_ctrl[idx] = data;
// bit 0
m_parity_err_mode[idx] = (m_format[idx] >> 0) & 1;
// bit 1
m_brk[idx] = (m_format[idx] >> 1) & 1;
LOG("R65C52: %x AUX CTRL %x \n", idx + 1, m_aux_ctrl[idx]);
}
void r65c52_device::write_compare(int idx, u8 data)
{
LOG("R65C52: %x COMPARE %x \n", idx + 1, data);
m_compare[idx] = data;
}
u8 r65c52_device::read_isr(int idx)
{
if (m_status[idx] & SR_BRK || m_status[idx] & SR_FRAMING_ERROR || m_overrun[idx])
{
m_isr[idx] |= IRQ_FOB;
}
u8 isr = m_isr[idx];
if (isr != 0)
{
isr |= 0x80;
}
if (!m_echo_mode[idx])
{
if (m_cts[idx])
{
isr |= 0x80;
}
}
else
{
isr &= ~0x80;
}
m_isr[idx] &= ~(IRQ_CTS | IRQ_DCD | IRQ_DSR | IRQ_FOB);
LOG("R65C52: %x ISR %x \n", idx + 1, m_isr[idx]);
return isr;
}
void r65c52_device::map(address_map &map)
{
map(0x00, 0x00).rw(FUNC(r65c52_device::isr_0_r), FUNC(r65c52_device::ier_0_w));
map(0x01, 0x01).rw(FUNC(r65c52_device::status_0_r), FUNC(r65c52_device::format_ctrl_0_w));
map(0x02, 0x02).nopr().w(FUNC(r65c52_device::aux_compare_0_w));
map(0x03, 0x03).rw(FUNC(r65c52_device::rdr_0_r), FUNC(r65c52_device::tdr_0_w));
map(0x04, 0x04).rw(FUNC(r65c52_device::isr_1_r), FUNC(r65c52_device::ier_1_w));
map(0x05, 0x05).rw(FUNC(r65c52_device::status_1_r), FUNC(r65c52_device::format_ctrl_1_w));
map(0x06, 0x06).nopr().w(FUNC(r65c52_device::aux_compare_1_w));
map(0x07, 0x07).rw(FUNC(r65c52_device::rdr_1_r), FUNC(r65c52_device::tdr_1_w));
}
void r65c52_device::format_ctrl_0_w(u8 data)
{
if (data & 0x80)
{
write_format(0, data);
}
else
{
write_control(0, data);
}
}
void r65c52_device::format_ctrl_1_w(u8 data)
{
if (data & 0x80)
{
write_format(1, data);
}
else
{
write_control(1, data);
}
}
void r65c52_device::aux_compare_0_w(u8 data)
{
if (data & 0x40)
{
write_aux_ctrl(0, data);
}
else
{
write_compare(0, data);
}
}
void r65c52_device::aux_compare_1_w(u8 data)
{
if (data & 0x40)
{
write_aux_ctrl(1, data);
}
else
{
write_compare(1, data);
}
}
void r65c52_device::set_xtal(u32 xtal)
{
m_xtal = xtal;
if (started())
{
m_internal_clock1->set_unscaled_clock(m_xtal);
m_internal_clock2->set_unscaled_clock(m_xtal);
update_divider(0);
update_divider(1);
}
}
void r65c52_device::internal_clock1(int state)
{
transmitter_clock(0, state);
receiver_clock(0, state);
}
void r65c52_device::internal_clock2(int state)
{
transmitter_clock(1, state);
receiver_clock(1, state);
}
void r65c52_device::write_rxc(int state)
{
for (int i = 0; i < 2; i++)
{
receiver_clock(i, state);
}
}
void r65c52_device::write_txc(int state)
{
for (int i = 0; i < 2; i++)
{
transmitter_clock(i, state);
}
}
void r65c52_device::write_rxd1(int state)
{
m_rxd[0] = state;
}
void r65c52_device::write_rxd2(int state)
{
m_rxd[1] = state;
}
void r65c52_device::write_cts1(int state)
{
_write_cts(0, state);
}
void r65c52_device::write_cts2(int state)
{
_write_cts(1, state);
}
void r65c52_device::_write_cts(int idx, int state)
{
if (m_cts[idx] != state)
{
m_cts[idx] = state;
m_isr[idx] |= IRQ_CTS;
if (m_cts[idx])
{
m_status[idx] |= SR_CTS;
if (m_tx_output[idx] == OUTPUT_TXD)
{
m_tx_output[idx] = OUTPUT_MARK;
output_txd(idx, 1);
}
}
else
{
m_status[idx] &= ~SR_CTS;
}
update_irq(idx);
}
LOG("R65C52: %x CTS STATUS %x \n", idx + 1, m_status[idx]);
}
void r65c52_device::write_dsr1(int state)
{
_write_dsr(0, state);
}
void r65c52_device::write_dsr2(int state)
{
_write_dsr(1, state);
}
void r65c52_device::_write_dsr(int idx, int state)
{
if (m_dsr[idx] != state)
{
m_dsr[idx] = state;
m_isr[idx] |= IRQ_DSR;
if (m_dsr[idx])
{
m_status[idx] |= SR_DSR;
}
else
{
m_status[idx] &= ~SR_DSR;
}
update_irq(idx);
}
LOG("R65C52: %x DSR STATUS %x \n", idx + 1, m_status[idx]);
}
void r65c52_device::write_dcd1(int state)
{
_write_dcd(0, state);
}
void r65c52_device::write_dcd2(int state)
{
_write_dcd(1, state);
}
void r65c52_device::_write_dcd(int idx, int state)
{
if (m_dcd[idx] != state)
{
m_dcd[idx] = state;
m_isr[idx] |= IRQ_DCD;
if (m_dcd[idx])
{
m_status[idx] |= SR_DCD;
}
else
{
m_status[idx] &= ~SR_DCD;
}
update_irq(idx);
}
LOG("R65C52: %x DCD STATUS %x \n", idx + 1, m_status[idx]);
}
void r65c52_device::receiver_clock(int idx, int state)
{
if (m_rx_clock[idx] != state)
{
m_rx_clock[idx] = state;
if (m_rx_clock[idx])
{
m_rx_counter[idx]++;
switch (m_rx_state[idx])
{
case STATE_START:
if (m_rx_counter[idx] == 1)
{
if (!m_rxd[idx] && !m_dtr[idx])
{
LOG("R65C52: RX%x START BIT \n", idx + 1);
}
else
{
m_rx_counter[idx] = 0;
}
}
if (m_rx_counter[idx] >= m_divide[idx] / 2)
{
if (!m_rxd[idx])
{
m_rx_state[idx] = STATE_DATA;
m_rx_counter[idx] = 0;
m_rx_shift[idx] = 0;
m_rx_parity[idx] = 0;
m_rx_bits[idx] = 0;
}
else
{
m_rx_counter[idx] = 0;
LOG("R65C52: RX%x false START BIT\n", idx + 1);
}
}
break;
case STATE_DATA:
if (m_rx_counter[idx] == m_divide[idx])
{
m_rx_counter[idx] = 0;
if (m_rx_bits[idx] < m_wordlength[idx])
{
LOG("R65C52: RX%x DATA BIT %d %d\n", idx + 1, m_rx_bits[idx], m_rxd[idx]);
}
else
{
LOG("R65C52: RX%x PARITY BIT %x\n", idx + 1, m_rxd[idx]);
}
if (m_rxd[idx])
{
m_rx_shift[idx] |= 1 << m_rx_bits[idx];
}
m_rx_bits[idx]++;
m_rx_parity[idx] ^= m_rxd[idx];
if ((m_rx_bits[idx] == m_wordlength[idx] && m_parity[idx] == PARITY_NONE) ||
(m_rx_bits[idx] == (m_wordlength[idx] + 1) && m_parity[idx] != PARITY_NONE))
{
m_rx_state[idx] = STATE_STOP;
}
}
break;
case STATE_STOP:
if (m_rx_counter[idx] >= stoplengthcounter(idx))
{
m_rx_counter[idx] = 0;
LOG("R65C52: RX%x STOP BIT\n", idx + 1);
if (!(m_rdrf[idx]))
{
if (!m_rxd[idx])
{
m_status[idx] |= SR_FRAMING_ERROR;
}
if ((m_parity[idx] == PARITY_ODD && !m_rx_parity[idx]) ||
(m_parity[idx] == PARITY_EVEN && m_rx_parity[idx]))
{
m_parity_err[idx] = true;
}
else
{
m_parity_err[idx] = false;
}
if (m_parity_err_mode[idx])
{
if (m_parity_err[idx])
{
m_isr[idx] |= IRQ_PAR;
}
else
{
m_isr[idx] &= ~IRQ_PAR;
}
update_irq(idx);
}
m_rdr[idx] = m_rx_shift[idx];
if (m_wordlength[idx] == 7 && m_parity[idx] != PARITY_NONE)
{
m_rdr[idx] &= 0x7f;
}
// In compare mode, we only flip RDRF if the data matches
if (m_compare[idx] == 0 || (m_compare[idx] == m_rdr[idx]))
{
m_rdrf[idx] = true;
m_isr[idx] |= IRQ_RDRF;
m_compare[idx] = 0;
update_irq(idx);
}
m_overrun[idx] = false;
}
else
{
m_overrun[idx] = true;
}
LOG("R65C52: RX%x DATA %x\n", idx + 1, m_rdr[idx]);
m_rx_state[idx] = STATE_START;
if (m_dtr[idx])
{
update_divider(idx);
}
}
break;
}
}
}
}
void r65c52_device::transmitter_clock(int idx, int state)
{
if (m_tx_clock[idx] != state)
{
m_tx_clock[idx] = state;
if (!m_tx_clock[idx] && !m_dtr[idx])
{
if (m_echo_mode[idx])
{
if (!(m_overrun[idx]))
{
output_txd(idx, m_rxd[idx]);
}
else
{
output_txd(idx, 1);
}
}
if (!m_cts[idx] && m_tx_output[idx] == OUTPUT_MARK && !(m_tdre[idx]))
{
m_tx_state[idx] = STATE_START;
m_tx_counter[idx] = 0;
}
m_tx_counter[idx]++;
switch (m_tx_state[idx])
{
case STATE_START:
{
m_tx_counter[idx] = 0;
m_tx_state[idx] = STATE_DATA;
m_tx_shift[idx] = m_tdr[idx];
m_tx_bits[idx] = 0;
m_tx_parity[idx] = 0;
if (m_cts[idx])
{
m_tx_output[idx] = OUTPUT_MARK;
LOG("R65C52: TX%x CTS MARK START\n", idx + 1);
}
else if (!(m_tdre[idx]))
{
LOG("R65C52: TX%x DATA %x\n", idx + 1, m_tdr[idx]);
m_tx_output[idx] = OUTPUT_TXD;
LOG("R65C52: TX%x START BIT\n", idx + 1);
m_tdre[idx] = true;
m_isr[idx] |= IRQ_TDRE;
update_irq(idx);
}
else if (m_brk[idx])
{
m_tx_output[idx] = OUTPUT_BREAK;
LOG("R65C52: TX%x BREAK START\n", idx + 1);
}
else
{
m_tx_output[idx] = OUTPUT_MARK;
LOG("R65C52: TX%x MARK START\n", idx + 1);
}
if (m_tx_output[idx] != OUTPUT_BREAK)
{
m_tdre[idx] = true;
m_isr[idx] |= IRQ_TDRE;
update_irq(idx);
}
// fatalerror("setup");
output_txd(idx, 0);
break;
}
case STATE_DATA:
{
if (m_tx_counter[idx] == m_divide[idx])
{
m_tx_counter[idx] = 0;
if (m_tx_bits[idx] < m_wordlength[idx])
{
output_txd(idx, (m_tx_shift[idx] >> m_tx_bits[idx]) & 1);
m_tx_bits[idx]++;
m_tx_parity[idx] ^= m_txd[idx];
if (m_tx_output[idx] == OUTPUT_TXD)
{
LOG("R65C52: TX%x DATA BIT TXD %d %d\n", idx + 1, m_tx_bits[idx], m_txd[idx]);
}
}
else if (m_tx_bits[idx] == m_wordlength[idx] && m_parity[idx] != PARITY_NONE)
{
m_tx_bits[idx]++;
switch (m_parity[idx])
{
case PARITY_ODD:
m_tx_parity[idx] = !m_tx_parity[idx];
break;
case PARITY_MARK:
m_tx_parity[idx] = 1;
break;
case PARITY_SPACE:
m_tx_parity[idx] = 0;
break;
}
output_txd(idx, m_tx_parity[idx]);
if (m_tx_output[idx] == OUTPUT_TXD)
{
LOG("R65C52: TX%x PARITY BIT %d\n", idx + 1, m_txd);
}
if (!m_parity_err_mode[idx])
{
if (m_tx_parity[idx])
{
m_isr[idx] |= IRQ_PAR;
}
else
{
m_isr[idx] &= ~IRQ_PAR;
}
update_irq(idx);
}
}
else
{
m_tx_state[idx] = STATE_STOP;
output_txd(idx, 1);
// m_tdre[idx] = true;
// m_isr[idx] |= IRQ_TDRE;
// update_irq(idx);
if (m_tx_output[idx] == OUTPUT_TXD)
{
LOG("R65C52: TX%x STOP BIT\n", idx + 1);
}
}
}
break;
}
case STATE_STOP:
{
if (m_tx_counter[idx] >= stoplengthcounter(idx))
{
if (m_tx_output[idx] == OUTPUT_BREAK)
{
if (!m_brk[idx])
{
LOG("R65C52: TX%x BREAK END\n", idx + 1);
m_tx_counter[idx] = 0;
m_tx_state[idx] = STATE_STOP;
m_tx_output[idx] = OUTPUT_TXD;
output_txd(idx, 1);
}
else
{
m_tx_counter[idx]--;
}
}
else
{
m_tx_state[idx] = STATE_START;
m_tx_counter[idx] = 0;
}
}
break;
}
}
}
}
}

View File

@ -0,0 +1,250 @@
// license:BSD-3-Clause
// copyright-holders:jwallace
/**********************************************************************
Rockwell 65C52 Dual Asynchronous Communication Interface Adapter
A slightly tweaked combination of two 6551 ACIAs on a single chip
**********************************************************************
_____ _____
RES 1 |* \_/ | 40 Vcc
NC 2 | | 39 _CS
XTALI 3 | | 38 R/_W
XTALO 4 | | 37 RS2
CLKOUT 5 | | 36 RS1
NC 6 | | 35 RS0
_DSR2 7 | | 34 NC
_DCD2 8 | | 33 _DSR1
_CTS2 9 | | 32 _DCD1
_RTS2 10 | R65C52 | 31 _CTS1
_IRQ2 11 | | 30 _RTS1
RxD2 12 | | 29 _IRQ1
_DTR2 13 | | 28 RxD1
TxD2 14 | | 27 _DTR1
TxC 15 | | 26 TxD1
D7 16 | | 25 RxC
D6 17 | | 24 D0
D5 18 | | 23 D1
D4 19 | | 22 D2
Vss 20 |_____________| 21 D3
**********************************************************************/
#ifndef MAME_MACHINE_R65C52_H
#define MAME_MACHINE_R65C52_H
#pragma once
#include "machine/clock.h"
class r65c52_device : public device_t
{
public:
r65c52_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock = 0);
void map(address_map &map);
auto irq1_handler() { return m_irq_handler[0].bind(); }
auto irq2_handler() { return m_irq_handler[1].bind(); }
auto txd1_handler() { return m_txd_handler[0].bind(); }
auto txd2_handler() { return m_txd_handler[1].bind(); }
auto rts1_handler() { return m_rts_handler[0].bind(); }
auto rts2_handler() { return m_rts_handler[1].bind(); }
auto dtr1_handler() { return m_dtr_handler[0].bind(); }
auto dtr2_handler() { return m_dtr_handler[1].bind(); }
u8 read(offs_t offset);
void write_txc(int state); // txc
void write_rxc(int state);
void write_rxd1(int state);
void write_rxd2(int state);
void write_cts1(int state);
void write_cts2(int state);
void write_dsr1(int state);
void write_dsr2(int state);
void write_dcd1(int state);
void write_dcd2(int state);
void _write_cts(int idx, int state);
void _write_dsr(int idx, int state);
void _write_dcd(int idx, int state);
void set_xtal(u32 clock);
void set_xtal(const XTAL &clock) { set_xtal(clock.value()); }
protected:
virtual void device_start() override;
virtual void device_reset() override;
virtual void device_add_mconfig(machine_config &config) override;
private:
enum
{
SR_RTS = 0x01,
SR_DTR = 0x02,
SR_BRK = 0x04,
SR_DSR = 0x08,
SR_DCD = 0x10,
SR_CTS = 0x20,
SR_TUR = 0x40,
SR_FRAMING_ERROR = 0x80,
};
enum
{
PARITY_ODD = 0,
PARITY_EVEN = 1,
PARITY_MARK = 2,
PARITY_SPACE = 3,
PARITY_NONE = -1
};
enum
{
IRQ_RDRF= 0x01,
IRQ_FOB = 0x02,
IRQ_PAR = 0x04,
IRQ_DSR = 0x08,
IRQ_DCD = 0x10,
IRQ_CTS = 0x20,
IRQ_TDRE= 0x40,
};
enum
{
STATE_START,
STATE_DATA,
STATE_STOP
};
enum
{
OUTPUT_TXD,
OUTPUT_MARK,
OUTPUT_BREAK
};
u8 stoplengthcounter(int idx);
void output_irq(int idx, int irq);
void output_txd(int idx, int txd);
void output_rts(int idx, int rts);
void output_dtr(int idx, int dtr);
void update_irq(int idx);
void update_divider(int idx);
u8 read_isr(int idx);
u8 read_rdr(int idx);
u8 read_status(int idx);
u8 read_command(int idx);
void ier_0_w(u8 data) { write_ier(0, data); }
void ier_1_w(u8 data) { write_ier(1, data); }
u8 isr_0_r() { return read_isr(0); }
u8 isr_1_r() { return read_isr(1); }
u8 rdr_0_r() { return read_rdr(0); }
u8 rdr_1_r() { return read_rdr(1); }
u8 status_0_r() { return read_status(0); }
u8 status_1_r() { return read_status(1); }
void tdr_0_w(u8 data) { write_tdr(0, data); }
void tdr_1_w(u8 data) { write_tdr(1, data); }
void write_ier(int idx, u8 data);
void write_tdr(int idx, u8 data);
void aux_compare_0_w(u8 data);
void aux_compare_1_w(u8 data);
void format_ctrl_0_w(u8 data);
void format_ctrl_1_w(u8 data);
void write_aux_ctrl(int idx, u8 data);
void write_compare(int idx, u8 data);
void write_control(int idx, u8 data);
void write_format(int idx, u8 data);
void isr_bit_set(int idx);
void internal_clock1(int state);
void internal_clock2(int state);
void receiver_clock(int idx, int state);
void transmitter_clock(int idx, int state);
static const int internal_divider[16];
static const int transmitter_controls[4][3];
required_device<clock_device> m_internal_clock1;
required_device<clock_device> m_internal_clock2;
devcb_write_line::array<2> m_irq_handler;
devcb_write_line::array<2> m_txd_handler;
devcb_write_line m_rxc_handler;
devcb_write_line::array<2> m_rts_handler;
devcb_write_line::array<2> m_dtr_handler;
u8 m_aux_ctrl[2];
u8 m_control[2];
u8 m_compare[2];
u8 m_format[2];
u8 m_status[2];
u8 m_tdr[2];
bool m_tdre[2];
u8 m_rdr[2];
bool m_rdrf[2];
u8 m_ier[2];
u8 m_isr[2];
u8 m_irq[2];
bool m_overrun[2];
bool m_parity_err[2];
u8 m_parity_err_mode[2];
u8 m_txd[2];
u8 m_rxc;
u8 m_rts[2];
u8 m_dtr[2];
u32 m_xtal;
u8 m_divide[2];
u8 m_cts[2];
u8 m_dsr[2];
u8 m_dcd[2];
u8 m_rxd[2];
u8 m_wordlength[2];
u8 m_stoplength[2];
u8 m_brk[2];
u8 m_echo_mode[2];
int m_parity[2];
u8 m_rx_state[2];
u8 m_rx_clock[2];
u8 m_rx_bits[2];
u8 m_rx_shift[2];
int m_rx_parity[2];
u8 m_rx_counter[2];
u8 m_tx_state[2];
u8 m_tx_output[2];
u8 m_tx_clock[2];
u8 m_tx_bits[2];
u8 m_tx_shift[2];
int m_tx_parity[2];
u8 m_tx_counter[2];
};
DECLARE_DEVICE_TYPE(R65C52, r65c52_device)
#endif // MAME_MACHINE_R65C52_H

File diff suppressed because it is too large Load Diff

View File

@ -17,7 +17,7 @@ license:CC0-1.0
<param name="digit" start="0" increment="1" />
<param name="x" start="60" increment="9" />
<element name="digit~digit~" ref="led" blend="add" state="0">
<bounds x="~x~" y="240" width="9" height="9"/>
<bounds x="~x~" y="270" width="9" height="9"/>
</element>
</repeat>
</view>

View File

@ -0,0 +1,136 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!--
license:CC0-1.0
-->
<mamelayout version="2">
<element name="led">
<led14segsc>
<color red="0.8" green="0.2" blue="0" />
</led14segsc>
</element>
<element name="A" defstate="0">
<rect state="0"><color red="0.4" green="0.1" blue="0" /></rect>
<rect state="1"><color red="0.8" green="0.2" blue="0" /></rect>
<text string="A"><color red="0.7" green="0.7" blue="0.7" /></text>
</element>
<element name="B" defstate="0">
<rect state="0"><color red="0.4" green="0.1" blue="0" /></rect>
<rect state="1"><color red="0.8" green="0.2" blue="0" /></rect>
<text string="B"><color red="0.7" green="0.7" blue="0.7" /></text>
</element>
<element name="C" defstate="0">
<rect state="0"><color red="0.4" green="0.1" blue="0" /></rect>
<rect state="1"><color red="0.8" green="0.2" blue="0" /></rect>
<text string="C"><color red="0.7" green="0.7" blue="0.7" /></text>
</element>
<element name="COLLECT" defstate="0">
<rect state="0"><color red="0.4" green="0.1" blue="0" /></rect>
<rect state="1"><color red="0.8" green="0.2" blue="0" /></rect>
<text string="COLLECT"><color red="0.7" green="0.7" blue="0.7" /></text>
</element>
<element name="CONTINUE" defstate="0">
<rect state="0"><color red="0.4" green="0.1" blue="0" /></rect>
<rect state="1"><color red="0.8" green="0.2" blue="0" /></rect>
<text string="CONTINUE"><color red="0.7" green="0.7" blue="0.7" /></text>
</element>
<element name="*" defstate="0">
<rect state="0"><color red="0.4" green="0.1" blue="0" /></rect>
<rect state="1"><color red="0.8" green="0.2" blue="0" /></rect>
<text string="*"><color red="0.7" green="0.7" blue="0.7" /></text>
</element>
<element name="20p" defstate="0">
<text state="1" string="20p"><color red="0.7" green="0.7" blue="0.7" /></text>
</element>
<element name="40p" defstate="0">
<text state="1" string="40p"><color red="0.7" green="0.7" blue="0.7" /></text>
</element>
<element name="£1" defstate="0">
<text state="1" string="£1"><color red="0.7" green="0.7" blue="0.7" /></text>
</element>
<element name="£2" defstate="0">
<text state="1" string="£2"><color red="0.7" green="0.7" blue="0.7" /></text>
</element>
<element name="£5" defstate="0">
<text state="1" string="£5"><color red="0.7" green="0.7" blue="0.7" /></text>
</element>
<element name="£10" defstate="0">
<text state="1" string="£10"><color red="0.7" green="0.7" blue="0.7" /></text>
</element>
<element name="£20" defstate="0">
<text state="1" string="£20"><color red="0.7" green="0.7" blue="0.7" /></text>
</element>
<element name="WIN" defstate="0">
<text state="1" string="WIN"><color red="0.7" green="0.7" blue="0.7" /></text>
</element>
<view name="LED Overlay">
<screen index="0">
<bounds left="0" top="16" right="704" bottom="544" />
</screen>
<element name="lamp0" ref="20p">
<bounds x="0" y="560" width="60" height="24" />
</element>
<element name="lamp1" ref="40p">
<bounds x="0" y="590" width="60" height="24" />
</element>
<element name="lamp2" ref="£1">
<bounds x="0" y="620" width="60" height="24" />
</element>
<element name="lamp3" ref="£2">
<bounds x="0" y="650" width="60" height="24" />
</element>
<element name="lamp7" ref="WIN">
<bounds x="600" y="560" width="60" height="24" />
</element>
<element name="lamp4" ref="£5">
<bounds x="600" y="590" width="60" height="24" />
</element>
<element name="lamp5" ref="£10">
<bounds x="600" y="620" width="60" height="24" />
</element>
<element name="lamp6" ref="£20">
<bounds x="600" y="650" width="60" height="24" />
</element>
<element name="lamp8" ref="A" inputtag="SW0" inputmask="0x01">
<bounds x="148" y="560" width="120" height="24" />
</element>
<element name="lamp9" ref="B" inputtag="SW0" inputmask="0x80">
<bounds x="278" y="560" width="120" height="24" />
</element>
<element name="lamp11" ref="C" inputtag="SW0" inputmask="0x02">
<bounds x="408" y="560" width="120" height="24" />
</element>
<element name="lamp10" ref="COLLECT" inputtag="SW0" inputmask="0x04">
<bounds x="148" y="590" width="120" height="24" />
</element>
<element name="lamp13" ref="*" inputtag="SW1" inputmask="0x20">
<bounds x="278" y="590" width="120" height="24" />
</element>
<element name="lamp12" ref="CONTINUE" inputtag="SW0" inputmask="0x40">
<bounds x="408" y="590" width="120" height="24" />
</element>
<repeat count="16">
<param name="digit" start="0" increment="1" />
<param name="x" start="140" increment="28" />
<element name="digit~digit~" ref="led" blend="add" state="0">
<bounds x="~x~" y="630" width="28" height="28"/>
</element>
</repeat>
</view>
</mamelayout>

View File

@ -8,7 +8,7 @@ Driver by Angelo Salese
LaserDisc and artwork hookup by Ryan Holtz
TODO:
- Unemulated Sony LDP-1450 player, and Pioneer LD-V4200 is HLE; needs a dump of the BIOSes and
- Sony LDP-1450 player (not hooked up) and Pioneer LD-V4200 are HLE; needs a dump of the BIOSes and
proper hook-up.
==================================================================================================