mirror of
https://github.com/holub/mame
synced 2025-06-27 06:39:03 +03:00
Merge pull request #1954 from ajrhacker/msm5205_change_clock
MSM5205 architectural cleanups (nw)
This commit is contained in:
commit
936498261b
@ -28,6 +28,9 @@
|
|||||||
|
|
||||||
Data is streamed from a CPU by means of a clock generated on the chip.
|
Data is streamed from a CPU by means of a clock generated on the chip.
|
||||||
|
|
||||||
|
Holding the rate selector lines (S1 and S2) both high places the MSM5205 in an undocumented
|
||||||
|
mode which disables the sampling clock generator and makes VCK an input line.
|
||||||
|
|
||||||
A reset signal is set high or low to determine whether playback (and interrupts) are occurring.
|
A reset signal is set high or low to determine whether playback (and interrupts) are occurring.
|
||||||
|
|
||||||
MSM6585: is an upgraded MSM5205 voice synth IC.
|
MSM6585: is an upgraded MSM5205 voice synth IC.
|
||||||
@ -38,7 +41,7 @@
|
|||||||
|
|
||||||
Differences between MSM6585 & MSM5205:
|
Differences between MSM6585 & MSM5205:
|
||||||
|
|
||||||
MSM6586 MSM5205
|
MSM6585 MSM5205
|
||||||
Master clock frequency 640kHz 384kHz
|
Master clock frequency 640kHz 384kHz
|
||||||
Sampling frequency 4k/8k/16k/32kHz 4k/6k/8kHz
|
Sampling frequency 4k/8k/16k/32kHz 4k/6k/8kHz
|
||||||
ADPCM bit length 4-bit 3-bit/4-bit
|
ADPCM bit length 4-bit 3-bit/4-bit
|
||||||
@ -46,7 +49,7 @@
|
|||||||
Low-pass filter -40dB/oct N/A
|
Low-pass filter -40dB/oct N/A
|
||||||
Overflow prevent circuit Included N/A
|
Overflow prevent circuit Included N/A
|
||||||
|
|
||||||
Timer callback at VCLK low edge on MSM5205 (at rising edge on MSM6585)
|
Data input follows VCK falling edge on MSM5205 (VCK rising edge on MSM6585)
|
||||||
|
|
||||||
TODO:
|
TODO:
|
||||||
- lowpass filter for MSM6585
|
- lowpass filter for MSM6585
|
||||||
@ -57,39 +60,50 @@ const device_type MSM5205 = &device_creator<msm5205_device>;
|
|||||||
const device_type MSM6585 = &device_creator<msm6585_device>;
|
const device_type MSM6585 = &device_creator<msm6585_device>;
|
||||||
|
|
||||||
|
|
||||||
msm5205_device::msm5205_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
|
msm5205_device::msm5205_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
|
||||||
: device_t(mconfig, MSM5205, "MSM5205", tag, owner, clock, "msm5205", __FILE__),
|
: device_t(mconfig, MSM5205, "MSM5205", tag, owner, clock, "msm5205", __FILE__),
|
||||||
device_sound_interface(mconfig, *this),
|
device_sound_interface(mconfig, *this),
|
||||||
m_prescaler(0),
|
m_s1(false),
|
||||||
m_bitwidth(0),
|
m_s2(false),
|
||||||
m_select(0),
|
m_bitwidth(4),
|
||||||
m_vclk_cb(*this)
|
m_vclk_cb(*this)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
msm5205_device::msm5205_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, uint32_t clock, const char *shortname, const char *source)
|
msm5205_device::msm5205_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, u32 clock, const char *shortname, const char *source)
|
||||||
: device_t(mconfig, type, name, tag, owner, clock, shortname, source),
|
: device_t(mconfig, type, name, tag, owner, clock, shortname, source),
|
||||||
device_sound_interface(mconfig, *this),
|
device_sound_interface(mconfig, *this),
|
||||||
m_prescaler(0),
|
m_s1(false),
|
||||||
m_bitwidth(0),
|
m_s2(false),
|
||||||
m_select(0),
|
m_bitwidth(4),
|
||||||
m_vclk_cb(*this)
|
m_vclk_cb(*this)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
msm6585_device::msm6585_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
|
msm6585_device::msm6585_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
|
||||||
: msm5205_device(mconfig, MSM6585, "MSM6585", tag, owner, clock, "msm6585", __FILE__)
|
: msm5205_device(mconfig, MSM6585, "MSM6585", tag, owner, clock, "msm6585", __FILE__)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------
|
||||||
|
// set_prescaler_selector - configuration helper
|
||||||
|
//-------------------------------------------------
|
||||||
|
|
||||||
|
void msm5205_device::set_prescaler_selector(device_t &device, int select)
|
||||||
|
{
|
||||||
|
msm5205_device &msm = downcast<msm5205_device &>(device);
|
||||||
|
msm.m_s1 = BIT(select, 1);
|
||||||
|
msm.m_s2 = BIT(select, 0);
|
||||||
|
msm.m_bitwidth = (select & 4) ? 4 : 3;
|
||||||
|
}
|
||||||
|
|
||||||
//-------------------------------------------------
|
//-------------------------------------------------
|
||||||
// device_start - device-specific startup
|
// device_start - device-specific startup
|
||||||
//-------------------------------------------------
|
//-------------------------------------------------
|
||||||
|
|
||||||
void msm5205_device::device_start()
|
void msm5205_device::device_start()
|
||||||
{
|
{
|
||||||
m_mod_clock = clock();
|
|
||||||
m_vclk_cb.resolve();
|
m_vclk_cb.resolve();
|
||||||
|
|
||||||
/* compute the difference tables */
|
/* compute the difference tables */
|
||||||
@ -100,11 +114,11 @@ void msm5205_device::device_start()
|
|||||||
m_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(msm5205_device::vclk_callback), this));
|
m_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(msm5205_device::vclk_callback), this));
|
||||||
|
|
||||||
/* register for save states */
|
/* register for save states */
|
||||||
save_item(NAME(m_mod_clock));
|
|
||||||
save_item(NAME(m_data));
|
save_item(NAME(m_data));
|
||||||
save_item(NAME(m_vclk));
|
save_item(NAME(m_vclk));
|
||||||
save_item(NAME(m_reset));
|
save_item(NAME(m_reset));
|
||||||
save_item(NAME(m_prescaler));
|
save_item(NAME(m_s1));
|
||||||
|
save_item(NAME(m_s2));
|
||||||
save_item(NAME(m_bitwidth));
|
save_item(NAME(m_bitwidth));
|
||||||
save_item(NAME(m_signal));
|
save_item(NAME(m_signal));
|
||||||
save_item(NAME(m_step));
|
save_item(NAME(m_step));
|
||||||
@ -122,9 +136,6 @@ void msm5205_device::device_reset()
|
|||||||
m_reset = 0;
|
m_reset = 0;
|
||||||
m_signal = 0;
|
m_signal = 0;
|
||||||
m_step = 0;
|
m_step = 0;
|
||||||
|
|
||||||
/* timer and bitwidth set */
|
|
||||||
playmode_w(m_select);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -170,17 +181,17 @@ void msm5205_device::compute_tables()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* timer callback at VCLK low edge on MSM5205 (at rising edge on MSM6585) */
|
// timer callback at VCK low edge on MSM5205 (at rising edge on MSM6585)
|
||||||
TIMER_CALLBACK_MEMBER( msm5205_device::vclk_callback )
|
TIMER_CALLBACK_MEMBER( msm5205_device::vclk_callback )
|
||||||
{
|
{
|
||||||
int val;
|
int val;
|
||||||
int new_signal;
|
int new_signal;
|
||||||
|
|
||||||
/* callback user handler and latch next data */
|
// callback user handler and latch next data
|
||||||
if (!m_vclk_cb.isnull())
|
if (!m_vclk_cb.isnull())
|
||||||
m_vclk_cb(1);
|
m_vclk_cb(1);
|
||||||
|
|
||||||
/* reset check at last hiedge of VCLK */
|
// reset check at last hiedge of VCK
|
||||||
if (m_reset)
|
if (m_reset)
|
||||||
{
|
{
|
||||||
new_signal = 0;
|
new_signal = 0;
|
||||||
@ -213,19 +224,19 @@ TIMER_CALLBACK_MEMBER( msm5205_device::vclk_callback )
|
|||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Handle an update of the vclk status of a chip (1 is reset ON, 0 is reset OFF)
|
* Handle an update of the VCK status of a chip (1 is reset ON, 0 is reset OFF)
|
||||||
* This function can use selector = MSM5205_SEX only
|
* This function can use selector = MSM5205_SEX only
|
||||||
*/
|
*/
|
||||||
void msm5205_device::vclk_w(int vclk)
|
WRITE_LINE_MEMBER(msm5205_device::vclk_w)
|
||||||
{
|
{
|
||||||
if (m_prescaler != 0)
|
if (get_prescaler() != 0)
|
||||||
logerror("error: msm5205_vclk_w() called with chip = '%s', but VCLK selected master mode\n", this->device().tag());
|
logerror("Error: vclk_w() called but VCK selected master mode\n");
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (m_vclk != vclk)
|
if (m_vclk != state)
|
||||||
{
|
{
|
||||||
m_vclk = vclk;
|
m_vclk = state;
|
||||||
if (!vclk)
|
if (!state)
|
||||||
vclk_callback(this, 0);
|
vclk_callback(this, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -235,9 +246,9 @@ void msm5205_device::vclk_w(int vclk)
|
|||||||
* Handle an update of the reset status of a chip (1 is reset ON, 0 is reset OFF)
|
* Handle an update of the reset status of a chip (1 is reset ON, 0 is reset OFF)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void msm5205_device::reset_w(int reset)
|
WRITE_LINE_MEMBER(msm5205_device::reset_w)
|
||||||
{
|
{
|
||||||
m_reset = reset;
|
m_reset = state;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -257,34 +268,36 @@ WRITE8_MEMBER(msm5205_device::data_w)
|
|||||||
data_w(data);
|
data_w(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int msm5205_device::get_prescaler() const
|
||||||
|
{
|
||||||
|
if (m_s1)
|
||||||
|
return m_s2 ? 0 : 64;
|
||||||
|
else
|
||||||
|
return m_s2 ? 48 : 96;
|
||||||
|
}
|
||||||
|
|
||||||
|
int msm6585_device::get_prescaler() const
|
||||||
|
{
|
||||||
|
return (m_s1 ? 20 : 40) * (m_s2 ? 1 : 4);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Handle a change of the selector
|
* Handle a change of the selector
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void msm5205_device::playmode_w(int select)
|
void msm5205_device::playmode_w(int select)
|
||||||
{
|
{
|
||||||
static const int prescaler_table[2][4] =
|
|
||||||
{
|
|
||||||
{ 96, 48, 64, 0},
|
|
||||||
{160, 40, 80, 20}
|
|
||||||
};
|
|
||||||
int prescaler = prescaler_table[select >> 3 & 1][select & 3];
|
|
||||||
int bitwidth = (select & 4) ? 4 : 3;
|
int bitwidth = (select & 4) ? 4 : 3;
|
||||||
|
|
||||||
if (m_prescaler != prescaler)
|
if ((select & 3) != ((m_s1 << 1) | m_s2))
|
||||||
{
|
{
|
||||||
m_stream->update();
|
m_stream->update();
|
||||||
|
|
||||||
m_prescaler = prescaler;
|
m_s1 = BIT(select, 1);
|
||||||
|
m_s2 = BIT(select, 0);
|
||||||
|
|
||||||
/* timer set */
|
/* timer set */
|
||||||
if (prescaler)
|
notify_clock_changed();
|
||||||
{
|
|
||||||
attotime period = attotime::from_hz(m_mod_clock) * prescaler;
|
|
||||||
m_timer->adjust(period, 0, period);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
m_timer->adjust(attotime::never);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_bitwidth != bitwidth)
|
if (m_bitwidth != bitwidth)
|
||||||
@ -294,16 +307,43 @@ void msm5205_device::playmode_w(int select)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WRITE_LINE_MEMBER(msm5205_device::s1_w)
|
||||||
void msm5205_device::change_clock_w(int32_t clock)
|
|
||||||
{
|
{
|
||||||
attotime period;
|
if (m_s1 != bool(state))
|
||||||
|
{
|
||||||
|
m_stream->update();
|
||||||
|
m_s1 = state;
|
||||||
|
notify_clock_changed();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
m_mod_clock = clock;
|
WRITE_LINE_MEMBER(msm5205_device::s2_w)
|
||||||
|
{
|
||||||
|
if (m_s2 != bool(state))
|
||||||
|
{
|
||||||
|
m_stream->update();
|
||||||
|
m_s2 = state;
|
||||||
|
notify_clock_changed();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
period = attotime::from_hz(m_mod_clock) * m_prescaler;
|
|
||||||
|
//-------------------------------------------------
|
||||||
|
// device_clock_changed - called when the
|
||||||
|
// device clock is altered in any way
|
||||||
|
//-------------------------------------------------
|
||||||
|
|
||||||
|
void msm5205_device::device_clock_changed()
|
||||||
|
{
|
||||||
|
int prescaler = get_prescaler();
|
||||||
|
if (prescaler != 0)
|
||||||
|
{
|
||||||
|
attotime period = attotime::from_hz(clock()) * prescaler;
|
||||||
m_timer->adjust(period, 0, period);
|
m_timer->adjust(period, 0, period);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
m_timer->adjust(attotime::never);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//-------------------------------------------------
|
//-------------------------------------------------
|
||||||
|
@ -43,15 +43,15 @@ class msm5205_device : public device_t,
|
|||||||
public device_sound_interface
|
public device_sound_interface
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
msm5205_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
|
msm5205_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
|
||||||
msm5205_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, uint32_t clock, const char *shortname, const char *source);
|
msm5205_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, u32 clock, const char *shortname, const char *source);
|
||||||
~msm5205_device() {}
|
~msm5205_device() {}
|
||||||
|
|
||||||
static void set_prescaler_selector(device_t &device, int select) { downcast<msm5205_device &>(device).m_select = select; }
|
static void set_prescaler_selector(device_t &device, int select);
|
||||||
template<class _Object> static devcb_base &set_vclk_callback(device_t &device, _Object object) { return downcast<msm5205_device &>(device).m_vclk_cb.set_callback(object); }
|
template<class _Object> static devcb_base &set_vclk_callback(device_t &device, _Object object) { return downcast<msm5205_device &>(device).m_vclk_cb.set_callback(object); }
|
||||||
|
|
||||||
// reset signal should keep for 2cycle of VCLK
|
// reset signal should keep for 2cycle of VCLK
|
||||||
void reset_w(int reset);
|
DECLARE_WRITE_LINE_MEMBER(reset_w);
|
||||||
|
|
||||||
// adpcmata is latched after vclk_interrupt callback
|
// adpcmata is latched after vclk_interrupt callback
|
||||||
void data_w(int data);
|
void data_w(int data);
|
||||||
@ -60,17 +60,18 @@ public:
|
|||||||
// VCLK slave mode option
|
// VCLK slave mode option
|
||||||
// if VCLK and reset or data is changed at the same time,
|
// if VCLK and reset or data is changed at the same time,
|
||||||
// call vclk_w after data_w and reset_w.
|
// call vclk_w after data_w and reset_w.
|
||||||
void vclk_w(int vclk);
|
DECLARE_WRITE_LINE_MEMBER(vclk_w);
|
||||||
|
|
||||||
// option , selected pin selector
|
// option , selected pin selector
|
||||||
void playmode_w(int select);
|
void playmode_w(int select);
|
||||||
|
DECLARE_WRITE_LINE_MEMBER(s1_w);
|
||||||
void change_clock_w(int32_t clock);
|
DECLARE_WRITE_LINE_MEMBER(s2_w);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// device-level overrides
|
// device-level overrides
|
||||||
virtual void device_start() override;
|
virtual void device_start() override;
|
||||||
virtual void device_reset() override;
|
virtual void device_reset() override;
|
||||||
|
virtual void device_clock_changed() override;
|
||||||
|
|
||||||
TIMER_CALLBACK_MEMBER(vclk_callback);
|
TIMER_CALLBACK_MEMBER(vclk_callback);
|
||||||
|
|
||||||
@ -78,20 +79,20 @@ protected:
|
|||||||
virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) override;
|
virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) override;
|
||||||
|
|
||||||
void compute_tables();
|
void compute_tables();
|
||||||
|
virtual int get_prescaler() const;
|
||||||
|
|
||||||
// internal state
|
// internal state
|
||||||
sound_stream * m_stream; /* number of stream system */
|
sound_stream * m_stream; // number of stream system
|
||||||
int32_t m_mod_clock; /* clock rate */
|
emu_timer *m_timer; // VCK callback timer
|
||||||
emu_timer *m_timer; /* VCLK callback timer */
|
u8 m_data; // next adpcm data
|
||||||
int32_t m_data; /* next adpcm data */
|
bool m_vclk; // VCK signal (external mode)
|
||||||
int32_t m_vclk; /* vclk signal (external mode) */
|
bool m_reset; // reset pin signal
|
||||||
int32_t m_reset; /* reset pin signal */
|
bool m_s1; // prescaler selector S1
|
||||||
int32_t m_prescaler; /* prescaler selector S1 and S2 */
|
bool m_s2; // prescaler selector S2
|
||||||
int32_t m_bitwidth; /* bit width selector -3B/4B */
|
u8 m_bitwidth; // bit width selector -3B/4B
|
||||||
int32_t m_signal; /* current ADPCM signal */
|
s32 m_signal; // current ADPCM signal
|
||||||
int32_t m_step; /* current ADPCM step */
|
s32 m_step; // current ADPCM step
|
||||||
int m_diff_lookup[49*16];
|
int m_diff_lookup[49*16];
|
||||||
int m_select;
|
|
||||||
devcb_write_line m_vclk_cb;
|
devcb_write_line m_vclk_cb;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -100,7 +101,10 @@ extern const device_type MSM5205;
|
|||||||
class msm6585_device : public msm5205_device
|
class msm6585_device : public msm5205_device
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
msm6585_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
|
msm6585_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual int get_prescaler() const override;
|
||||||
|
|
||||||
// sound stream update overrides
|
// sound stream update overrides
|
||||||
virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) override;
|
virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) override;
|
||||||
|
@ -234,7 +234,7 @@ WRITE8_MEMBER(joctronic_state::resint_w)
|
|||||||
WRITE8_MEMBER(joctronic_state::slalom03_oki_bank_w)
|
WRITE8_MEMBER(joctronic_state::slalom03_oki_bank_w)
|
||||||
{
|
{
|
||||||
m_soundbank->set_entry((data & 0xc0) >> 6);
|
m_soundbank->set_entry((data & 0xc0) >> 6);
|
||||||
m_oki->playmode_w(BIT(data, 1) ? MSM5205_S48_4B : MSM5205_S96_4B); // to S1 on MSM5205
|
m_oki->s1_w(BIT(data, 1));
|
||||||
m_oki->reset_w(BIT(data, 0));
|
m_oki->reset_w(BIT(data, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -229,7 +229,7 @@ void pce_cd_device::late_setup()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// MSM5205 might be initialized after PCE CD as well...
|
// MSM5205 might be initialized after PCE CD as well...
|
||||||
m_msm->change_clock_w((PCE_CD_CLOCK / 6) / m_adpcm_clock_divider);
|
m_msm->set_unscaled_clock((PCE_CD_CLOCK / 6) / m_adpcm_clock_divider);
|
||||||
}
|
}
|
||||||
|
|
||||||
void pce_cd_device::nvram_init(nvram_device &nvram, void *data, size_t size)
|
void pce_cd_device::nvram_init(nvram_device &nvram, void *data, size_t size)
|
||||||
@ -1180,7 +1180,7 @@ WRITE8_MEMBER(pce_cd_device::intf_w)
|
|||||||
break;
|
break;
|
||||||
case 0x0E: /* ADPCM playback rate */
|
case 0x0E: /* ADPCM playback rate */
|
||||||
m_adpcm_clock_divider = 0x10 - (data & 0x0f);
|
m_adpcm_clock_divider = 0x10 - (data & 0x0f);
|
||||||
m_msm->change_clock_w((PCE_CD_CLOCK / 6) / m_adpcm_clock_divider);
|
m_msm->set_unscaled_clock((PCE_CD_CLOCK / 6) / m_adpcm_clock_divider);
|
||||||
break;
|
break;
|
||||||
case 0x0F: /* ADPCM and CD audio fade timer */
|
case 0x0F: /* ADPCM and CD audio fade timer */
|
||||||
/* TODO: timers needs HW tests */
|
/* TODO: timers needs HW tests */
|
||||||
|
Loading…
Reference in New Issue
Block a user