Added LD-V1000 HLE device, placeholder SSI-263A HLE device, and promoted Thayer's Quest. (#11915) [Ryan Holtz]

-cinematronics/thayers.cpp: Added CHD and promoted to working. [Ryan Holtz]
 * Fixed periodic IRQ hookup.
 * Fixed COP421 clock divisor.
 * Switched to LD-V1000 by default and removed LD-PR7820 support for now.
 * Switched to using logmacro and shorthand data types.
 * Adjusted IRQ triggering and acknowledgement according to schematics.

-sound/ssi263hle.cpp: Added a temporary SSI-263 device which remaps SC-02 phonemes onto the SC-01's phoneme set. [Ryan Holtz]
 * SSI-263 skeleton extracted from cinematronics/thayers.cpp.

-machine/ldv1000hle.cpp: Added an HLE version of the Pioneer LD-V1000 laserdisc player. [Ryan Holtz]

-machine/laserdsc.h: Added a general-purpose parallel LaserDisc player interface, to have a common class parent for LD-PR7820. [Ryan Holtz]

-sega/timetrv.cpp: Replaced timetrv2 LaserDisc image with a good capture. [Ryan Holtz, Matt Ownby, ld-decode Team]

Systems promoted to working
---------------------------
Thayer's Quest (set 1) [Ryan Holtz, Matt Ownby, ld-decode Team]

Clones promoted to working
--------------------------
Thayer's Quest (set 2) [Ryan Holtz, Matt Ownby, ld-decode Team]
This commit is contained in:
MooglyGuy 2024-01-07 17:47:49 +01:00 committed by GitHub
parent 46dbcf7f79
commit ba60c481b5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 2057 additions and 660 deletions

View File

@ -2048,6 +2048,18 @@ if (MACHINES["LDV1000"]~=null) then
}
end
---------------------------------------------------
--
--@src/devices/machine/ldv1000hle.h,MACHINES["LDV1000HLE"] = true
---------------------------------------------------
if (MACHINES["LDV1000HLE"]~=null) then
files {
MAME_DIR .. "src/devices/machine/ldv1000hle.cpp",
MAME_DIR .. "src/devices/machine/ldv1000hle.h",
}
end
---------------------------------------------------
--
--@src/devices/machine/ldv4200hle.h,MACHINES["LDV4200HLE"] = true

View File

@ -1010,6 +1010,20 @@ end
---------------------------------------------------
-- Silicon Systems SSI-263A HLE
--@src/devices/sound/ssi263hle.h,SOUNDS["SSI263HLE"] = true
---------------------------------------------------
if (SOUNDS["SSI263HLE"]~=null) then
files {
MAME_DIR .. "src/devices/sound/ssi263hle.cpp",
MAME_DIR .. "src/devices/sound/ssi263hle.h",
}
end
---------------------------------------------------
-- Texas Instruments TMS36xx doorbell chime
--@src/devices/sound/tms36xx.h,SOUNDS["TMS36XX"] = true

View File

@ -60,49 +60,54 @@ const uint32_t VIRTUAL_LEAD_OUT_TRACKS = LEAD_OUT_MIN_SIZE_IN_UM * 1000 / NOMINA
ALLOW_SAVE_TYPE(laserdisc_device::player_state);
ALLOW_SAVE_TYPE(laserdisc_device::slider_position);
parallel_laserdisc_device::parallel_laserdisc_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
: laserdisc_device(mconfig, type, tag, owner, clock)
{
}
//-------------------------------------------------
// laserdisc_device - constructor
//-------------------------------------------------
laserdisc_device::laserdisc_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
: device_t(mconfig, type, tag, owner, clock),
device_sound_interface(mconfig, *this),
device_video_interface(mconfig, *this),
m_getdisc_callback(*this),
m_audio_callback(*this),
m_overwidth(0),
m_overheight(0),
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),
m_samplerate(0),
m_readresult(),
m_chdtracks(0),
m_work_queue(osd_work_queue_alloc(WORK_QUEUE_FLAG_IO)),
m_audiosquelch(0),
m_videosquelch(0),
m_fieldnum(0),
m_curtrack(0),
m_maxtrack(0),
m_attospertrack(0),
m_sliderupdate(attotime::zero),
m_videoindex(0),
m_stream(nullptr),
m_audiobufsize(0),
m_audiobufin(0),
m_audiobufout(0),
m_audiocursamples(0),
m_audiomaxsamples(0),
m_videoenable(false),
m_videotex(nullptr),
m_videopalette(nullptr),
m_overenable(false),
m_overindex(0),
m_overtex(nullptr)
: device_t(mconfig, type, tag, owner, clock)
, device_sound_interface(mconfig, *this)
, device_video_interface(mconfig, *this)
, m_getdisc_callback(*this)
, m_audio_callback(*this)
, m_overwidth(0)
, m_overheight(0)
, 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)
, m_samplerate(0)
, m_readresult()
, m_chdtracks(0)
, m_work_queue(osd_work_queue_alloc(WORK_QUEUE_FLAG_IO))
, m_audiosquelch(0)
, m_videosquelch(0)
, m_fieldnum(0)
, m_curtrack(0)
, m_maxtrack(0)
, m_attospertrack(0)
, m_sliderupdate(attotime::zero)
, m_videoindex(0)
, m_stream(nullptr)
, m_audiobufsize(0)
, m_audiobufin(0)
, m_audiobufout(0)
, m_audiocursamples(0)
, m_audiomaxsamples(0)
, m_videoenable(false)
, m_videotex(nullptr)
, m_videopalette(nullptr)
, m_overenable(false)
, m_overindex(0)
, m_overtex(nullptr)
{
// initialize overlay_config
m_orig_config.m_overposx = m_orig_config.m_overposy = 0.0f;
@ -453,30 +458,30 @@ void laserdisc_device::sound_stream_update(sound_stream &stream, std::vector<rea
//-------------------------------------------------
// set_slider_speed - dynamically change the
// slider speed
// slider speed, supports fractional values
//-------------------------------------------------
void laserdisc_device::set_slider_speed(int32_t tracks_per_vsync)
void laserdisc_device::set_slider_speed(const double tracks_per_vsync)
{
// update to the current time
update_slider_pos();
// if 0, set the time to 0
attotime vsyncperiod = screen().frame_period();
double vsyncperiod = screen().frame_period().as_double();
if (tracks_per_vsync == 0)
m_attospertrack = 0;
// positive values store positive times
else if (tracks_per_vsync > 0)
m_attospertrack = (vsyncperiod / tracks_per_vsync).as_attoseconds();
m_attospertrack = DOUBLE_TO_ATTOSECONDS(vsyncperiod / tracks_per_vsync);
// negative values store negative times
else
{
m_attospertrack = -(vsyncperiod / -tracks_per_vsync).as_attoseconds();
m_attospertrack = DOUBLE_TO_ATTOSECONDS(-vsyncperiod / -tracks_per_vsync);
}
LOGMASKED(LOG_SLIDER, "Slider speed = %d\n", tracks_per_vsync);
LOGMASKED(LOG_SLIDER, "Slider speed = %f\n", tracks_per_vsync);
}
@ -994,7 +999,7 @@ void laserdisc_device::read_track_data()
vbidata.line16 = 0;
vbidata.line17 = vbidata.line18 = vbidata.line1718 = VBI_CODE_LEADIN;
}
//printf("track %5d.%d: %06X %06X %06X\n", m_curtrack, m_fieldnum, vbidata.line16, vbidata.line17, vbidata.line18);
LOGMASKED(LOG_SLIDER, "track %5d.%d: %06X %06X %06X\n", m_curtrack, m_fieldnum, vbidata.line16, vbidata.line17, vbidata.line18);
// if we're about to read the first field in a frame, advance
frame_data *frame = &m_frame[m_videoindex];

View File

@ -221,7 +221,7 @@ protected:
// subclass helpers
void set_audio_squelch(bool squelchleft, bool squelchright) { m_stream->update(); m_audiosquelch = (squelchleft ? 1 : 0) | (squelchright ? 2 : 0); }
void set_video_squelch(bool squelch) { m_videosquelch = squelch; }
void set_slider_speed(int32_t tracks_per_vsync);
void set_slider_speed(const double tracks_per_vsync);
void advance_slider(int32_t numtracks);
slider_position get_slider_position();
int32_t generic_update(const vbi_metadata &vbi, int fieldnum, const attotime &curtime, player_state_info &curstate);
@ -304,7 +304,7 @@ private:
// audio data
sound_stream * m_stream;
std::vector<int16_t> m_audiobuffer[2]; // buffer for audio samples
std::vector<int16_t> m_audiobuffer[2]; // buffer for audio samples
uint32_t m_audiobufsize; // size of buffer
uint32_t m_audiobufin; // input index
uint32_t m_audiobufout; // output index
@ -335,6 +335,25 @@ typedef device_interface_enumerator<laserdisc_device> laserdisc_device_enumerato
// INLINE FUNCTIONS
//**************************************************************************
// ======================> parallel_laserdisc_device
class parallel_laserdisc_device : public laserdisc_device
{
public:
virtual void data_w(u8 data) = 0;
virtual u8 data_r() = 0;
virtual void enter_w(int state) {}
virtual int data_available_r() { return CLEAR_LINE; }
virtual int status_strobe_r() { return CLEAR_LINE; }
virtual int ready_r() { return ASSERT_LINE; }
protected:
parallel_laserdisc_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock = 0);
virtual void player_overlay(bitmap_yuy16 &bitmap) override { }
};
//-------------------------------------------------
// is_start_of_frame - return true if this is
// the start of a frame

View File

@ -22,12 +22,12 @@ DEFINE_DEVICE_TYPE(PHILIPS_22VP932, philips_22vp932_device, "22vp932", "Philips
pioneer_pr7820_device::pioneer_pr7820_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: laserdisc_device(mconfig, PIONEER_PR7820, tag, owner, clock)
: parallel_laserdisc_device(mconfig, PIONEER_PR7820, tag, owner, clock)
{
}
philips_22vp932_device::philips_22vp932_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: laserdisc_device(mconfig, PHILIPS_22VP932, tag, owner, clock)
: parallel_laserdisc_device(mconfig, PHILIPS_22VP932, tag, owner, clock)
{
}

View File

@ -31,18 +31,15 @@ DECLARE_DEVICE_TYPE(PHILIPS_22VP932, philips_22vp932_device)
// ======================> pioneer_pr7820_device
class pioneer_pr7820_device : public laserdisc_device
class pioneer_pr7820_device : public parallel_laserdisc_device
{
public:
// construction/destruction
pioneer_pr7820_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
// input/output
uint8_t data_available_r() { return CLEAR_LINE; }
uint8_t ready_r() { return ASSERT_LINE; }
uint8_t data_r() { return 0; }
void data_w(uint8_t data) { }
void enter_w(uint8_t data) { }
virtual void data_w(uint8_t data) override { }
virtual uint8_t data_r() override { return 0; }
protected:
// subclass overrides
@ -54,16 +51,15 @@ protected:
// ======================> philips_22vp932_device
class philips_22vp932_device : public laserdisc_device
class philips_22vp932_device : public parallel_laserdisc_device
{
public:
// construction/destruction
philips_22vp932_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
// input/output
uint8_t data_r() { return 0; }
void data_w(uint8_t data) { }
void enter_w(uint8_t data) { }
virtual void data_w(uint8_t data) override { }
virtual uint8_t data_r() override { return 0; }
protected:
// subclass overrides

View File

@ -34,6 +34,7 @@
#define LOG_STATUS_CHANGES (1U << 2)
#define LOG_FRAMES_SEEN (1U << 3)
#define LOG_COMMANDS (1U << 4)
#define VERBOSE (0)
#include "logmacro.h"
@ -104,7 +105,7 @@ ROM_END
//-------------------------------------------------
pioneer_ldv1000_device::pioneer_ldv1000_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: laserdisc_device(mconfig, PIONEER_LDV1000, tag, owner, clock),
: parallel_laserdisc_device(mconfig, PIONEER_LDV1000, tag, owner, clock),
m_z80_cpu(*this, "ldv1000"),
m_z80_ctc(*this, "ldvctc"),
m_multitimer(nullptr),
@ -137,15 +138,6 @@ void pioneer_ldv1000_device::data_w(uint8_t data)
}
//-------------------------------------------------
// enter_w - set the state of the ENTER strobe
//-------------------------------------------------
void pioneer_ldv1000_device::enter_w(uint8_t data)
{
}
//-------------------------------------------------
// device_start - device initialization
//-------------------------------------------------

View File

@ -35,7 +35,7 @@ DECLARE_DEVICE_TYPE(PIONEER_LDV1000, pioneer_ldv1000_device)
// ======================> pioneer_ldv1000_device
// base ldv1000 class
class pioneer_ldv1000_device : public laserdisc_device
class pioneer_ldv1000_device : public parallel_laserdisc_device
{
public:
// construction/destruction
@ -44,11 +44,11 @@ public:
auto command_strobe_callback() { return m_command_strobe_cb.bind(); }
// input and output
void data_w(uint8_t data);
void enter_w(uint8_t data);
uint8_t status_r() const { return m_status; }
uint8_t status_strobe_r() const { return (m_portc1 & 0x20) ? ASSERT_LINE : CLEAR_LINE; }
uint8_t command_strobe_r() const { return (m_portc1 & 0x10) ? ASSERT_LINE : CLEAR_LINE; }
virtual void data_w(uint8_t data) override;
virtual void enter_w(int state) override { }
virtual uint8_t data_r() override { return m_status; }
virtual int status_strobe_r() override { static int old_val = 0; int value = BIT(m_portc1, 5); if (value != old_val) { old_val = value; printf("status_strobe_r: %d\n", value); } return value; }
virtual int ready_r() override { static int old_val = 0; int value = BIT(m_portc1, 4); if (value != old_val) { old_val = value; printf("ready_r: %d\n", value); } return value; }
protected:
// device-level overrides

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,201 @@
// license:BSD-3-Clause
// copyright-holders:Ryan Holtz
/*************************************************************************
ldv1000hle.h
Pioneer LDV-1000 laserdisc player simulation.
*************************************************************************/
#ifndef MAME_MACHINE_LDV1000HLE_H
#define MAME_MACHINE_LDV1000HLE_H
#pragma once
#include "laserdsc.h"
//**************************************************************************
// GLOBAL VARIABLES
//**************************************************************************
// device type definition
DECLARE_DEVICE_TYPE(PIONEER_LDV1000HLE, pioneer_ldv1000hle_device)
//**************************************************************************
// TYPE DEFINITIONS
//**************************************************************************
class pioneer_ldv1000hle_device : public parallel_laserdisc_device
{
public:
// construction/destruction
pioneer_ldv1000hle_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock = 0);
virtual void data_w(u8 data) override;
virtual u8 data_r() override;
virtual void enter_w(int state) override;
virtual int status_strobe_r() override { return m_status_strobe; }
virtual int ready_r() override { return m_command_strobe; }
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;
TIMER_CALLBACK_MEMBER(process_vbi_data);
TIMER_CALLBACK_MEMBER(resume_from_stop);
TIMER_CALLBACK_MEMBER(park_strobe_tick);
TIMER_CALLBACK_MEMBER(assert_status_strobe);
TIMER_CALLBACK_MEMBER(deassert_status_strobe);
TIMER_CALLBACK_MEMBER(assert_command_strobe);
TIMER_CALLBACK_MEMBER(deassert_command_strobe);
private:
enum player_command : u8
{
CMD_CLEAR = 0xbf,
CMD_0 = 0x3f,
CMD_1 = 0x0f,
CMD_2 = 0x8f,
CMD_3 = 0x4f,
CMD_4 = 0x2f,
CMD_5 = 0xaf,
CMD_6 = 0x6f,
CMD_7 = 0x1f,
CMD_8 = 0x9f,
CMD_9 = 0x5f,
CMD_STORE = 0xf5,
CMD_RECALL = 0x7f,
CMD_DISPLAY = 0xf1,
CMD_AUDIO1 = 0xf4,
CMD_AUDIO2 = 0xfc,
CMD_PLAY = 0xfd,
CMD_STOP = 0xfb,
CMD_AUTOSTOP = 0xf3,
CMD_SEARCH = 0xf7,
CMD_SCAN_FWD = 0xf0,
CMD_SCAN_REV = 0xf8,
CMD_STEP_FWD = 0xf6,
CMD_STEP_REV = 0xfe,
CMD_REJECT = 0xf9,
CMD_NO_ENTRY = 0xff,
CMD_LOAD = 0xcc,
CMD_DISPLAY_DISABLE = 0xcd,
CMD_DISPLAY_ENABLE = 0xce,
CMD_GET_FRAME_NUM = 0xc2,
CMD_GET_2ND_DISPLAY = 0xc3,
CMD_GET_1ST_DISPLAY = 0xc4,
CMD_TRANSFER_MEMORY = 0xc8,
CMD_FWD_X0 = 0xa0,
CMD_FWD_X1_4 = 0xa1,
CMD_FWD_X1_2 = 0xa2,
CMD_FWD_X1 = 0xa3,
CMD_FWD_X2 = 0xa4,
CMD_FWD_X3 = 0xa5,
CMD_FWD_X4 = 0xa6,
CMD_FWD_X5 = 0xa7,
CMD_SKIP_FWD_10 = 0xb1,
CMD_SKIP_FWD_20 = 0xb2,
CMD_SKIP_FWD_30 = 0xb3,
CMD_SKIP_FWD_40 = 0xb4,
CMD_SKIP_FWD_50 = 0xb5,
CMD_SKIP_FWD_60 = 0xb6,
CMD_SKIP_FWD_70 = 0xb7,
CMD_SKIP_FWD_80 = 0xb8,
CMD_SKIP_FWD_90 = 0xb9,
CMD_SKIP_FWD_100 = 0xba
};
enum player_status : u8
{
STATUS_PARK = 0x7c,
STATUS_PLAY = 0x64,
STATUS_STOP = 0x65,
STATUS_SEARCH = 0x50,
STATUS_SEARCH_FINISH = 0xd0,
STATUS_SEARCH_ERROR = 0x90,
STATUS_AUTOSTOP = 0x54,
STATUS_SCAN = 0x4c,
STATUS_FORWARD = 0x2e,
STATUS_LOAD = 0x48,
STATUS_LOAD_END = 0xc8,
STATUS_LOAD_ERROR = 0xc4,
STATUS_FOCUS_UNLOCK = 0xbc,
STATUS_LEADIN = 0x58,
STATUS_LEADOUT = 0x5c,
STATUS_REJECT = 0x60,
STATUS_READY = 0x80
};
enum player_mode : u8
{
MODE_PARK,
MODE_PLAY,
MODE_SCAN_FORWARD,
MODE_SCAN_REVERSE,
MODE_SEARCH,
MODE_STOP
};
void process_command_buffer();
bool is_command_byte(const u8 data);
bool is_command_number(const u8 data);
void process_command(size_t cmd_index);
static u32 bcd_to_literal(u32 bcd);
u32 literal_to_bcd(u32 value);
u32 cmd_number_to_bcd();
u8 cmd_to_number(const u8 cmd);
void set_mode(const u8 mode);
void set_playing(const u8 new_status, const double fields_per_vsync);
void set_stopped(const u8 new_status);
void cmd_play();
void cmd_stop();
void cmd_step(const int direction);
void cmd_play_forward(const double fields_per_vsync);
void cmd_search(const u32 frame);
void cmd_skip_forward(const s32 amount);
void update_video_enable();
void update_audio_enable();
// internal state
emu_timer * m_vbi_fetch;
emu_timer * m_stop_timer;
emu_timer * m_park_strobe_timer;
emu_timer * m_assert_status_strobe_timer;
emu_timer * m_deassert_status_strobe_timer;
emu_timer * m_assert_command_strobe_timer;
emu_timer * m_deassert_command_strobe_timer;
u8 m_cmd_buffer[21];
u32 m_cmd_length;
u8 m_status;
u8 m_pre_stop_status;
u8 m_mode; // current player mode
u32 m_curr_frame; // frame number
u32 m_search_frame;
u32 m_stop_frame;
u8 m_cmd_number[5];
u32 m_cmd_number_length;
u16 m_user_ram[1024];
u32 m_curr_register;
u32 m_scan_speed;
u32 m_scan_speed_accum;
double m_play_speed;
bool m_audio_enable[2];
bool m_status_strobe;
bool m_command_strobe;
};
#endif // MAME_MACHINE_LDV1000HLE_H

View File

@ -2,7 +2,7 @@
// copyright-holders:Ryan Holtz
/*************************************************************************
ldv1000hle.h
ldv4200hle.h
Pioneer LD-V4200 laserdisc player simulation.

View File

@ -0,0 +1,230 @@
// license:BSD-3-Clause
// copyright-holders:Ryan Holtz
/***************************************************************************
Silicon Systems SSI-263A Phoneme Speech Synthesizer
Temporary implementation using the Votrax SC-01A
NOTE: This is completely wrong, and exists only to have
working audio in Thayer's Quest, which would not otherwise
be playable due to relying on speech output for important
gameplay cues.
****************************************************************************/
#include "emu.h"
#include "ssi263hle.h"
DEFINE_DEVICE_TYPE(SSI263HLE, ssi263hle_device, "ssi263hle", "SSI-263A Speech Synthesizer")
namespace
{
static const char PHONEME_NAMES[0x40][5] =
{
"PA", "E", "E1", "Y", "YI", "AY", "IE", "I", "A", "AI", "EH", "EH1", "AE", "AE1", "AH", "AH1", "W", "O", "OU", "OO", "IU", "IU1", "U", "U1", "UH", "UH1", "UH2", "UH3", "ER", "R", "R1", "R2",
"L", "L1", "LF", "W", "B", "D", "KV", "P", "T", "K", "HV", "HVC", "HF", "HFC", "HN", "Z", "S", "J", "SCH", "V", "F", "THV", "TH", "M", "N", "NG", ":A", ":OH", ":U", ":UH", "E2", "LB"
};
static const u8 PHONEMES_TO_SC01[0x40] =
{
0x03, 0x2c, 0x3b, 0x3c, 0x22, 0x21, 0x29, 0x27, 0x20, 0x05, 0x01, 0x00, 0x2e, 0x2f, 0x15, 0x15,
0x13, 0x26, 0x35, 0x17, 0x36, 0x16, 0x28, 0x37, 0x32, 0x32, 0x31, 0x23, 0x3a, 0x2b, 0x2b, 0x2b,
0x18, 0x18, 0x18, 0x2d, 0x0e, 0x1e, 0x1c, 0x25, 0x2a, 0x19, 0x03, 0x03, 0x1b, 0x03, 0x03, 0x12,
0x1f, 0x07, 0x11, 0x0f, 0x1d, 0x38, 0x39, 0x0c, 0x0d, 0x14, 0x08, 0x34, 0x28, 0x37, 0x02, 0x18
};
} // anonymous namespace
ssi263hle_device::ssi263hle_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
: device_t(mconfig, SSI263HLE, tag, owner, clock)
, device_mixer_interface(mconfig, *this, 1)
, m_votrax(*this, "votrax")
, m_ar_cb(*this)
, m_phoneme_timer(nullptr)
, m_duration(0)
, m_phoneme(0)
, m_inflection(0)
, m_rate(0)
, m_articulation(0)
, m_control(false)
, m_amplitude(0)
, m_filter(0)
, m_mode(0)
, m_data_request(1)
, m_votrax_fifo_wr(0)
, m_votrax_fifo_rd(0)
, m_votrax_fifo_cnt(0)
{
}
void ssi263hle_device::device_start()
{
m_phoneme_timer = timer_alloc(FUNC(ssi263hle_device::phoneme_tick), this);
save_item(NAME(m_duration));
save_item(NAME(m_phoneme));
save_item(NAME(m_inflection));
save_item(NAME(m_rate));
save_item(NAME(m_articulation));
save_item(NAME(m_control));
save_item(NAME(m_amplitude));
save_item(NAME(m_filter));
save_item(NAME(m_mode));
save_item(NAME(m_votrax_fifo));
save_item(NAME(m_votrax_fifo_wr));
save_item(NAME(m_votrax_fifo_rd));
save_item(NAME(m_votrax_fifo_cnt));
}
void ssi263hle_device::device_reset()
{
m_phoneme_timer->adjust(attotime::never);
m_duration = 0;
m_phoneme = 0;
m_inflection = 0;
m_rate = 0;
m_articulation = 0;
m_control = false;
m_amplitude = 0;
m_filter = 0;
m_mode = 0;
m_data_request = 1;
std::fill(std::begin(m_votrax_fifo), std::end(m_votrax_fifo), 0);
m_votrax_fifo_wr = 0;
m_votrax_fifo_rd = 0;
m_votrax_fifo_cnt = 0;
}
void ssi263hle_device::map(address_map &map)
{
map(0x00, 0x00).rw(FUNC(ssi263hle_device::status_r), FUNC(ssi263hle_device::duration_phoneme_w));
map(0x01, 0x01).rw(FUNC(ssi263hle_device::status_r), FUNC(ssi263hle_device::inflection_w));
map(0x02, 0x02).rw(FUNC(ssi263hle_device::status_r), FUNC(ssi263hle_device::rate_inflection_w));
map(0x03, 0x03).rw(FUNC(ssi263hle_device::status_r), FUNC(ssi263hle_device::control_articulation_amplitude_w));
map(0x04, 0x07).rw(FUNC(ssi263hle_device::status_r), FUNC(ssi263hle_device::filter_frequency_w));
}
void ssi263hle_device::device_add_mconfig(machine_config &config)
{
VOTRAX_SC01(config, m_votrax, DERIVED_CLOCK(1, 1));
m_votrax->ar_callback().set(FUNC(ssi263hle_device::votrax_request));
m_votrax->add_route(ALL_OUTPUTS, *this, 1.0, AUTO_ALLOC_INPUT, 0);
}
TIMER_CALLBACK_MEMBER(ssi263hle_device::phoneme_tick)
{
m_data_request = 0;
m_ar_cb(m_data_request);
}
void ssi263hle_device::duration_phoneme_w(u8 data)
{
const int frame_time = ((4096 * (16 - m_rate)) / 2); // microseconds, should actually be derived from our clock, but this way we get microseconds directly
const int phoneme_time = frame_time * (4 - m_duration); // microseconds
m_duration = (data >> 5) & 0x03;
m_phoneme = data & 0x3f;
m_data_request = 1;
m_ar_cb(m_data_request);
switch (m_mode)
{
case 0:
case 1:
// phoneme timing response
m_phoneme_timer->adjust(attotime::from_usec(phoneme_time));
break;
case 2:
// frame timing response
m_phoneme_timer->adjust(attotime::from_usec(frame_time));
break;
case 3:
// disable A/_R output
break;
}
if (m_phoneme)
{
if (m_votrax_fifo_cnt < std::size(m_votrax_fifo))
{
m_votrax_fifo[m_votrax_fifo_wr] = PHONEMES_TO_SC01[m_phoneme];
if (m_votrax_fifo_cnt == 0)
{
m_votrax->write(PHONEMES_TO_SC01[m_phoneme]);
}
m_votrax_fifo_wr = (m_votrax_fifo_wr + 1) % std::size(m_votrax_fifo);
m_votrax_fifo_cnt++;
}
}
}
void ssi263hle_device::inflection_w(u8 data)
{
m_inflection &= 0x807;
m_inflection |= data << 3;
}
void ssi263hle_device::rate_inflection_w(u8 data)
{
m_inflection &= 0x7f8;
m_inflection |= (BIT(data, 3) << 11) | (data & 0x07);
m_rate = data >> 4;
m_votrax->inflection_w(1);
}
void ssi263hle_device::control_articulation_amplitude_w(u8 data)
{
if (m_control && !BIT(data, 7))
{
m_mode = m_duration;
}
m_control = BIT(data, 7);
m_articulation = (data >> 4) & 0x07;
m_amplitude = data & 0x0f;
}
void ssi263hle_device::filter_frequency_w(u8 data)
{
m_filter = data;
}
u8 ssi263hle_device::status_r()
{
// D7 is an output for the inverted state of A/_R. Register address bits are ignored.
return BIT(~m_data_request, 0) << 7;
}
void ssi263hle_device::votrax_request(int state)
{
if (m_votrax_fifo_cnt == 0 || state != ASSERT_LINE)
{
return;
}
m_votrax_fifo_cnt--;
const u8 previous_phoneme = m_votrax_fifo[m_votrax_fifo_rd];
m_votrax_fifo_rd = (m_votrax_fifo_rd + 1) % std::size(m_votrax_fifo);
if (m_votrax_fifo_cnt == 0)
{
if (previous_phoneme != 0x3f)
{
m_votrax_fifo[m_votrax_fifo_wr] = 0x3f;
m_votrax_fifo_wr = (m_votrax_fifo_wr + 1) % std::size(m_votrax_fifo);
m_votrax_fifo_cnt++;
m_votrax->write(0x3f);
}
return;
}
m_votrax->write(m_votrax_fifo[m_votrax_fifo_rd]);
}

View File

@ -0,0 +1,76 @@
// license:BSD-3-Clause
// copyright-holders:Ryan Holtz
/**********************************************************************
Silicon Systems SSI-263A Phoneme Speech Synthesizer
Temporary implementation using the Votrax SC-01A
NOTE: This is completely wrong, and exists only to have
working audio in Thayer's Quest, which would not otherwise
be playable due to relying on speech output for important
gameplay cues.
**********************************************************************/
#ifndef MAME_SOUND_SSI263HLE_H
#define MAME_SOUND_SSI263HLE_H
#pragma once
#include "sound/votrax.h"
class ssi263hle_device : public device_t, public device_mixer_interface
{
public:
static constexpr feature_type imperfect_features() { return feature::SOUND; }
ssi263hle_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock = 0);
void map(address_map &map);
auto ar_callback() { return m_ar_cb.bind(); }
protected:
virtual void device_start() override;
virtual void device_reset() override;
virtual void device_add_mconfig(machine_config &config) override;
private:
required_device<votrax_sc01_device> m_votrax;
TIMER_CALLBACK_MEMBER(phoneme_tick);
void duration_phoneme_w(u8 data);
void inflection_w(u8 data);
void rate_inflection_w(u8 data);
void control_articulation_amplitude_w(u8 data);
void filter_frequency_w(u8 data);
u8 status_r();
void votrax_request(int state);
devcb_write_line m_ar_cb;
emu_timer *m_phoneme_timer = nullptr;
u8 m_duration;
u8 m_phoneme;
u16 m_inflection;
u8 m_rate;
u8 m_articulation;
bool m_control;
u8 m_amplitude;
u8 m_filter;
u8 m_mode;
u8 m_data_request;
u8 m_votrax_fifo[1024];
u32 m_votrax_fifo_wr;
u32 m_votrax_fifo_rd;
u32 m_votrax_fifo_cnt;
};
DECLARE_DEVICE_TYPE(SSI263HLE, ssi263hle_device)
#endif

View File

@ -96,7 +96,7 @@ private:
uint8_t laserdisc_data_r()
{
if (m_ldv1000 != nullptr) return m_ldv1000->status_r();
if (m_ldv1000 != nullptr) return m_ldv1000->data_r();
if (m_pr7820 != nullptr) return m_pr7820->data_r();
if (m_22vp932 != nullptr) return m_22vp932->data_r();
return 0;
@ -115,7 +115,7 @@ private:
uint8_t laserdisc_ready_r()
{
if (m_ldv1000 != nullptr) return m_ldv1000->command_strobe_r();
if (m_ldv1000 != nullptr) return m_ldv1000->ready_r();
if (m_pr7820 != nullptr) return m_pr7820->ready_r();
return CLEAR_LINE;
}

View File

@ -126,7 +126,7 @@ uint32_t konblands_state::screen_update(screen_device &screen, bitmap_rgb32 &bit
uint8_t konblands_state::ldp_r()
{
return m_laserdisc->status_r();
return m_laserdisc->data_r();
}
void konblands_state::nmi_enable_w(uint8_t data)

View File

@ -9,78 +9,16 @@ license:CC0-1.0
</led7seg>
</element>
<view name="Simple LEDs">
<element name="text_time"><text string="TIME" align="1"><color red="1.0" green="0.87" blue="0.4" /></text></element>
<view name="Internal Layout">
<bounds x="0" y="0" width="4000" height="3362" />
<screen index="0">
<bounds left="0" top="0" right="4" bottom="3" />
<bounds x="0" y="362" width="4000" height="3000" />
</screen>
<element name="digit0" ref="digit">
<bounds x="1.4" y="-1.5" width="0.2" height="0.3" />
</element>
<element name="digit1" ref="digit">
<bounds x="1.6" y="-1.5" width="0.2" height="0.3" />
</element>
<element name="digit2" ref="digit">
<bounds x="1.8" y="-1.5" width="0.2" height="0.3" />
</element>
<element name="digit3" ref="digit">
<bounds x="2.0" y="-1.5" width="0.2" height="0.3" />
</element>
<element name="digit4" ref="digit">
<bounds x="2.2" y="-1.5" width="0.2" height="0.3" />
</element>
<element name="digit5" ref="digit">
<bounds x="2.4" y="-1.5" width="0.2" height="0.3" />
</element>
<element name="digit6" ref="digit">
<bounds x="1.9" y="-1.2" width="0.2" height="0.3" />
</element>
<element name="digit8" ref="digit">
<bounds x="1.4" y="-0.9" width="0.2" height="0.3" />
</element>
<element name="digit9" ref="digit">
<bounds x="1.6" y="-0.9" width="0.2" height="0.3" />
</element>
<element name="digit10" ref="digit">
<bounds x="1.8" y="-0.9" width="0.2" height="0.3" />
</element>
<element name="digit11" ref="digit">
<bounds x="2.0" y="-0.9" width="0.2" height="0.3" />
</element>
<element name="digit12" ref="digit">
<bounds x="2.2" y="-0.9" width="0.2" height="0.3" />
</element>
<element name="digit13" ref="digit">
<bounds x="2.4" y="-0.9" width="0.2" height="0.3" />
</element>
<element name="digit7" ref="digit">
<bounds x="1.9" y="-0.6" width="0.2" height="0.3" />
</element>
<element name="digit14" ref="digit">
<bounds x="1.7" y="-0.3" width="0.2" height="0.3" />
</element>
<element name="digit15" ref="digit">
<bounds x="1.9" y="-0.3" width="0.2" height="0.3" />
</element>
<element ref="text_time"><bounds x="2400" y="112" width="800" height="170" /></element>
<element name="digit14" ref="digit"><bounds x="1748" y="16" width="236" height="330" /></element>
<element name="digit15" ref="digit"><bounds x="2016" y="16" width="236" height="330" /></element>
</view>
</mamelayout>

View File

@ -148,7 +148,7 @@ uint32_t esh_state::screen_update_esh(screen_device &screen, bitmap_rgb32 &bitma
uint8_t esh_state::ldp_read()
{
return m_laserdisc->status_r();
return m_laserdisc->data_r();
}
void esh_state::misc_write(uint8_t data)

View File

@ -177,7 +177,7 @@ void istellar_state::machine_start()
// Z80 2 R/W
uint8_t istellar_state::z80_2_ldp_read()
{
uint8_t readResult = m_laserdisc->status_r();
uint8_t readResult = m_laserdisc->data_r();
LOGCPU2("CPU2 : reading LDP : %x\n", readResult);
return readResult;
}

File diff suppressed because it is too large Load Diff

View File

@ -459,7 +459,7 @@ INTERRUPT_GEN_MEMBER(gpworld_state::vblank_callback)
if (m_nmi_enable)
{
m_laserdisc->data_w(m_ldp_write_latch);
m_ldp_read_latch = m_laserdisc->status_r();
m_ldp_read_latch = m_laserdisc->data_r();
device.execute().pulse_input_line(INPUT_LINE_NMI, attotime::zero);
}

View File

@ -137,7 +137,7 @@ uint32_t segald_state::screen_update_astron(screen_device &screen, bitmap_rgb32
uint8_t segald_state::astron_DISC_read(offs_t offset)
{
if (m_nmi_enable)
m_ldv1000_input_latch = m_laserdisc->status_r();
m_ldv1000_input_latch = m_laserdisc->data_r();
logerror("DISC read (0x%04x) @ 0x%04x [0x%x]\n", m_ldv1000_input_latch, offset, m_maincpu->pc());

View File

@ -352,7 +352,7 @@ ROM_START( timetrv2 )
ROM_LOAD( "epr-72491.u9", 0xc0000, 0x40000, CRC(c7998e2f) SHA1(26060653b2368f52c304e6433b4f447f99a36839) )
DISK_REGION( "laserdisc" )
DISK_IMAGE_READONLY( "timetrv", 0, SHA1(8abb5e6aa58ab49477ef89f507264d35454f99d3) BAD_DUMP )
DISK_IMAGE_READONLY( "timetrv2", 0, SHA1(0bb0c34df0aae2b5e019c6dc2fc071e23c82ba75) )
ROM_END
} // anonymous namespace

View File

@ -154,7 +154,7 @@ uint32_t lgp_state::screen_update_lgp(screen_device &screen, bitmap_rgb32 &bitma
/* Main Z80 R/W */
uint8_t lgp_state::ldp_read()
{
return m_laserdisc->status_r();
return m_laserdisc->data_r();
}
/* Sound Z80 R/W */

View File

@ -155,7 +155,7 @@ INTERRUPT_GEN_MEMBER(superdq_state::superdq_vblank)
/* status is read when the STATUS line from the laserdisc
toggles (600usec after the vblank). We could set up a
timer to do that, but this works as well */
m_ld_in_latch = m_laserdisc->status_r();
m_ld_in_latch = m_laserdisc->data_r();
/* command is written when the COMMAND line from the laserdisc
toggles (680usec after the vblank). We could set up a