mirror of
https://github.com/holub/mame
synced 2025-04-16 05:24:54 +03:00
exidysound: replace riot6532_device with mos6532_new_device, untangle exidy_sh8253_sound_device a bit,
mos6530n: use loops for repeated i/o callbacks, edge_w bits are on address, not data, add live timer status to savestate
This commit is contained in:
parent
04961b2ff5
commit
01f70846e0
@ -119,16 +119,18 @@ mos6530_device_base::mos6530_device_base(const machine_config &mconfig, device_t
|
||||
// mos6530_new_device - constructor
|
||||
//-------------------------------------------------
|
||||
|
||||
mos6530_new_device::mos6530_new_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
|
||||
: mos6530_device_base(mconfig, MOS6530_NEW, tag, owner, clock, 0x40) { }
|
||||
mos6530_new_device::mos6530_new_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
|
||||
mos6530_device_base(mconfig, MOS6530_NEW, tag, owner, clock, 0x40)
|
||||
{ }
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// mos6532_new_device - constructor
|
||||
//-------------------------------------------------
|
||||
|
||||
mos6532_new_device::mos6532_new_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
|
||||
: mos6530_device_base(mconfig, MOS6532_NEW, tag, owner, clock, 0x80) { }
|
||||
mos6532_new_device::mos6532_new_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
|
||||
mos6530_device_base(mconfig, MOS6532_NEW, tag, owner, clock, 0x80)
|
||||
{ }
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
@ -155,6 +157,20 @@ void mos6530_device_base::device_start()
|
||||
save_item(NAME(m_irq_edge));
|
||||
save_item(NAME(m_prescale));
|
||||
save_item(NAME(m_timer));
|
||||
|
||||
save_item(NAME(cur_live.tm));
|
||||
save_item(NAME(cur_live.tm_irq));
|
||||
save_item(NAME(cur_live.period));
|
||||
save_item(NAME(cur_live.state));
|
||||
save_item(NAME(cur_live.next_state));
|
||||
save_item(NAME(cur_live.value));
|
||||
|
||||
save_item(NAME(checkpoint_live.tm));
|
||||
save_item(NAME(checkpoint_live.tm_irq));
|
||||
save_item(NAME(checkpoint_live.period));
|
||||
save_item(NAME(checkpoint_live.state));
|
||||
save_item(NAME(checkpoint_live.next_state));
|
||||
save_item(NAME(checkpoint_live.value));
|
||||
}
|
||||
|
||||
|
||||
@ -183,9 +199,8 @@ void mos6530_device_base::device_reset()
|
||||
m_timer = 0xff;
|
||||
m_prescale = 1024;
|
||||
|
||||
if (cur_live.state != IDLE) {
|
||||
if (cur_live.state != IDLE)
|
||||
live_abort();
|
||||
}
|
||||
|
||||
live_start();
|
||||
live_run();
|
||||
@ -209,26 +224,14 @@ TIMER_CALLBACK_MEMBER(mos6530_device_base::update)
|
||||
|
||||
void mos6530_device_base::update_pa()
|
||||
{
|
||||
uint8_t out = m_pa_out;
|
||||
uint8_t ddr = m_pa_ddr;
|
||||
uint8_t data = (out & ddr) | (ddr ^ 0xff);
|
||||
uint8_t data = (m_pa_out & m_pa_ddr) | (m_pa_ddr ^ 0xff);
|
||||
|
||||
if (m_out8_pa_cb.isunset())
|
||||
{
|
||||
m_out_pa_cb[0](BIT(data, 0));
|
||||
m_out_pa_cb[1](BIT(data, 1));
|
||||
m_out_pa_cb[2](BIT(data, 2));
|
||||
m_out_pa_cb[3](BIT(data, 3));
|
||||
m_out_pa_cb[4](BIT(data, 4));
|
||||
m_out_pa_cb[5](BIT(data, 5));
|
||||
m_out_pa_cb[6](BIT(data, 6));
|
||||
m_out_pa_cb[7](BIT(data, 7));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_out8_pa_cb.isunset()) {
|
||||
for (int i = 0; i < 8; i++)
|
||||
m_out_pa_cb[i](BIT(data, i));
|
||||
} else
|
||||
m_out8_pa_cb(data);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
@ -237,58 +240,32 @@ void mos6530_device_base::update_pa()
|
||||
|
||||
void mos6530_device_base::update_pb()
|
||||
{
|
||||
uint8_t out = m_pb_out;
|
||||
uint8_t ddr = m_pb_ddr;
|
||||
uint8_t data = (out & ddr) | (ddr ^ 0xff);
|
||||
uint8_t data = (m_pb_out & m_pb_ddr) | (m_pb_ddr ^ 0xff);
|
||||
|
||||
if (m_out8_pb_cb.isunset())
|
||||
{
|
||||
m_out_pb_cb[0](BIT(data, 0));
|
||||
m_out_pb_cb[1](BIT(data, 1));
|
||||
m_out_pb_cb[2](BIT(data, 2));
|
||||
m_out_pb_cb[3](BIT(data, 3));
|
||||
m_out_pb_cb[4](BIT(data, 4));
|
||||
m_out_pb_cb[5](BIT(data, 5));
|
||||
m_out_pb_cb[6](BIT(data, 6));
|
||||
m_out_pb_cb[7](BIT(data, 7));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_out8_pb_cb.isunset()) {
|
||||
for (int i = 0; i < 8; i++)
|
||||
m_out_pb_cb[i](BIT(data, i));
|
||||
} else
|
||||
m_out8_pb_cb(data);
|
||||
}
|
||||
}
|
||||
|
||||
void mos6530_new_device::update_pb()
|
||||
{
|
||||
uint8_t out = m_pb_out;
|
||||
uint8_t ddr = m_pb_ddr;
|
||||
uint8_t data = (out & ddr) | (ddr ^ 0xff);
|
||||
uint8_t data = (m_pb_out & m_pb_ddr) | (m_pb_ddr ^ 0xff);
|
||||
|
||||
if (m_ie_timer)
|
||||
{
|
||||
if (m_irq_timer) {
|
||||
if (m_ie_timer) {
|
||||
if (m_irq_timer)
|
||||
data |= IRQ_TIMER;
|
||||
} else {
|
||||
else
|
||||
data &= ~IRQ_TIMER;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_out8_pb_cb.isunset())
|
||||
{
|
||||
m_out_pb_cb[0](BIT(data, 0));
|
||||
m_out_pb_cb[1](BIT(data, 1));
|
||||
m_out_pb_cb[2](BIT(data, 2));
|
||||
m_out_pb_cb[3](BIT(data, 3));
|
||||
m_out_pb_cb[4](BIT(data, 4));
|
||||
m_out_pb_cb[5](BIT(data, 5));
|
||||
m_out_pb_cb[6](BIT(data, 6));
|
||||
m_out_pb_cb[7](BIT(data, 7));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_out8_pb_cb.isunset()) {
|
||||
for (int i = 0; i < 8; i++)
|
||||
m_out_pb_cb[i](BIT(data, i));
|
||||
} else
|
||||
m_out8_pb_cb(data);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
@ -341,13 +318,10 @@ uint8_t mos6530_new_device::get_irq_flags()
|
||||
|
||||
void mos6530_device_base::edge_detect()
|
||||
{
|
||||
uint8_t ddr_out = m_pa_ddr;
|
||||
uint8_t ddr_in = m_pa_ddr ^ 0xff;
|
||||
uint8_t data = (m_pa_out & ddr_out) | (m_pa_in & ddr_in);
|
||||
uint8_t data = (m_pa_out & m_pa_ddr) | (m_pa_in & ~m_pa_ddr);
|
||||
int state = BIT(data, 7);
|
||||
|
||||
if ((m_pa7 ^ state) && (m_pa7_dir ^ state) == 0 && !m_irq_edge)
|
||||
{
|
||||
if ((m_pa7 ^ state) && !(m_pa7_dir ^ state) && !m_irq_edge) {
|
||||
LOG("%s %s edge-detect IRQ\n", machine().time().as_string(), name());
|
||||
|
||||
m_irq_edge = true;
|
||||
@ -394,26 +368,13 @@ uint8_t mos6530_device_base::pa_data_r()
|
||||
{
|
||||
uint8_t in = 0;
|
||||
|
||||
if (m_in8_pa_cb.isunset())
|
||||
{
|
||||
in |= (m_in_pa_cb[0].isunset() ? BIT(m_pa_in, 0) : m_in_pa_cb[0]());
|
||||
in |= (m_in_pa_cb[1].isunset() ? BIT(m_pa_in, 1) : m_in_pa_cb[1]()) << 1;
|
||||
in |= (m_in_pa_cb[2].isunset() ? BIT(m_pa_in, 2) : m_in_pa_cb[2]()) << 2;
|
||||
in |= (m_in_pa_cb[3].isunset() ? BIT(m_pa_in, 3) : m_in_pa_cb[3]()) << 3;
|
||||
in |= (m_in_pa_cb[4].isunset() ? BIT(m_pa_in, 4) : m_in_pa_cb[4]()) << 4;
|
||||
in |= (m_in_pa_cb[5].isunset() ? BIT(m_pa_in, 5) : m_in_pa_cb[5]()) << 5;
|
||||
in |= (m_in_pa_cb[6].isunset() ? BIT(m_pa_in, 6) : m_in_pa_cb[6]()) << 6;
|
||||
in |= (m_in_pa_cb[7].isunset() ? BIT(m_pa_in, 7) : m_in_pa_cb[7]()) << 7;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_in8_pa_cb.isunset()) {
|
||||
for (int i = 0; i < 8; i++)
|
||||
in |= (m_in_pa_cb[i].isunset() ? BIT(m_pa_in, i) : m_in_pa_cb[i]()) << i;
|
||||
} else
|
||||
in = m_in8_pa_cb();
|
||||
}
|
||||
|
||||
uint8_t out = m_pa_out;
|
||||
uint8_t ddr_out = m_pa_ddr;
|
||||
uint8_t ddr_in = m_pa_ddr ^ 0xff;
|
||||
uint8_t data = (out & ddr_out) | (in & ddr_in);
|
||||
uint8_t data = (m_pa_out & m_pa_ddr) | (in & ~m_pa_ddr);
|
||||
|
||||
LOG("%s %s %s Port A Data In %02x\n", machine().time().as_string(), machine().describe_context(), name(), data);
|
||||
|
||||
@ -459,26 +420,13 @@ uint8_t mos6530_device_base::pb_data_r()
|
||||
{
|
||||
uint8_t in = 0;
|
||||
|
||||
if (m_in8_pb_cb.isunset())
|
||||
{
|
||||
in |= (m_in_pb_cb[0].isunset() ? BIT(m_pb_in, 0) : m_in_pb_cb[0]());
|
||||
in |= (m_in_pb_cb[1].isunset() ? BIT(m_pb_in, 1) : m_in_pb_cb[1]()) << 1;
|
||||
in |= (m_in_pb_cb[2].isunset() ? BIT(m_pb_in, 2) : m_in_pb_cb[2]()) << 2;
|
||||
in |= (m_in_pb_cb[3].isunset() ? BIT(m_pb_in, 3) : m_in_pb_cb[3]()) << 3;
|
||||
in |= (m_in_pb_cb[4].isunset() ? BIT(m_pb_in, 4) : m_in_pb_cb[4]()) << 4;
|
||||
in |= (m_in_pb_cb[5].isunset() ? BIT(m_pb_in, 5) : m_in_pb_cb[5]()) << 5;
|
||||
in |= (m_in_pb_cb[6].isunset() ? BIT(m_pb_in, 6) : m_in_pb_cb[6]()) << 6;
|
||||
in |= (m_in_pb_cb[7].isunset() ? BIT(m_pb_in, 7) : m_in_pb_cb[7]()) << 7;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_in8_pb_cb.isunset()) {
|
||||
for (int i = 0; i < 8; i++)
|
||||
in |= (m_in_pb_cb[i].isunset() ? BIT(m_pb_in, i) : m_in_pb_cb[i]()) << i;
|
||||
} else
|
||||
in = m_in8_pb_cb();
|
||||
}
|
||||
|
||||
uint8_t out = m_pb_out;
|
||||
uint8_t ddr_out = m_pb_ddr;
|
||||
uint8_t ddr_in = m_pb_ddr ^ 0xff;
|
||||
uint8_t data = (out & ddr_out) | (in & ddr_in);
|
||||
uint8_t data = (m_pb_out & m_pb_ddr) | (in & ~m_pb_ddr);
|
||||
|
||||
LOG("%s %s %s Port B Data In %02x\n", machine().time().as_string(), machine().describe_context(), name(), data);
|
||||
|
||||
@ -541,9 +489,8 @@ uint8_t mos6530_device_base::timer_r(bool ie)
|
||||
live_sync();
|
||||
|
||||
m_ie_timer = ie;
|
||||
if (cur_live.tm_irq != machine().time()) {
|
||||
if (cur_live.tm_irq != machine().time())
|
||||
m_irq_timer = false;
|
||||
}
|
||||
update_irq();
|
||||
|
||||
data = cur_live.value;
|
||||
@ -604,18 +551,16 @@ void mos6530_device_base::timer_w(offs_t offset, uint8_t data, bool ie)
|
||||
}
|
||||
|
||||
m_ie_timer = ie;
|
||||
if (cur_live.tm_irq != machine().time()) {
|
||||
if (cur_live.tm_irq != machine().time())
|
||||
m_irq_timer = false;
|
||||
}
|
||||
update_irq();
|
||||
|
||||
LOGTIMER("%s %s %s Timer value %02x prescale %u IE %u\n", machine().time().as_string(), machine().describe_context(), name(), data, m_prescale, m_ie_timer ? 1 : 0);
|
||||
|
||||
checkpoint();
|
||||
|
||||
if (cur_live.state != IDLE) {
|
||||
if (cur_live.state != IDLE)
|
||||
live_abort();
|
||||
}
|
||||
|
||||
live_start();
|
||||
live_run();
|
||||
@ -626,10 +571,11 @@ void mos6530_device_base::timer_w(offs_t offset, uint8_t data, bool ie)
|
||||
// edge_w -
|
||||
//-------------------------------------------------
|
||||
|
||||
void mos6530_device_base::edge_w(uint8_t data)
|
||||
void mos6530_device_base::edge_w(offs_t offset, uint8_t data)
|
||||
{
|
||||
m_pa7_dir = BIT(data, 0);
|
||||
m_ie_edge = BIT(data, 1) ? false : true;
|
||||
m_pa7_dir = BIT(offset, 0);
|
||||
m_ie_edge = bool(BIT(offset, 1));
|
||||
update_irq();
|
||||
|
||||
LOG("%s %s %s %s edge-detect, %s interrupt\n", machine().time().as_string(), machine().describe_context(), name(), m_pa7_dir ? "positive" : "negative", m_ie_edge ? "enable" : "disable");
|
||||
}
|
||||
|
@ -136,7 +136,7 @@ protected:
|
||||
uint8_t irq_r();
|
||||
void timer_off_w(offs_t offset, uint8_t data);
|
||||
void timer_on_w(offs_t offset, uint8_t data);
|
||||
void edge_w(uint8_t data);
|
||||
void edge_w(offs_t offset, uint8_t data);
|
||||
|
||||
memory_share_creator<uint8_t> m_ram;
|
||||
optional_region_ptr<uint8_t> m_rom;
|
||||
|
@ -5,7 +5,7 @@
|
||||
Exidy 6502 hardware
|
||||
|
||||
TODO:
|
||||
- use ptm6840_device and pit8253_device, maybe mos6532_new_device too
|
||||
- use ptm6840_device and pit8253_device
|
||||
|
||||
*************************************************************************/
|
||||
|
||||
@ -27,6 +27,11 @@
|
||||
*
|
||||
*************************************/
|
||||
|
||||
#define LOG_VICTORY_SOUND (1U << 1)
|
||||
|
||||
#define VERBOSE (0)
|
||||
#include "logmacro.h"
|
||||
|
||||
#define CRYSTAL_OSC (3.579545_MHz_XTAL)
|
||||
#define SH8253_CLOCK (CRYSTAL_OSC / 2)
|
||||
#define SH6840_CLOCK (CRYSTAL_OSC / 4)
|
||||
@ -36,6 +41,7 @@
|
||||
#define BASE_VOLUME (32767 / 6)
|
||||
|
||||
|
||||
|
||||
/*************************************
|
||||
*
|
||||
* 6840 clock counting helper
|
||||
@ -44,23 +50,23 @@
|
||||
|
||||
inline void exidy_sound_device::sh6840_apply_clock(exidy_sound_device::sh6840_timer_channel *t, int clocks)
|
||||
{
|
||||
/* dual 8-bit case */
|
||||
// dual 8-bit case
|
||||
if (t->cr & 0x04)
|
||||
{
|
||||
/* handle full decrements */
|
||||
// handle full decrements
|
||||
while (clocks > t->counter.b.l)
|
||||
{
|
||||
clocks -= t->counter.b.l + 1;
|
||||
t->counter.b.l = t->timer;
|
||||
|
||||
/* decrement MSB */
|
||||
// decrement MSB
|
||||
if (!t->counter.b.h--)
|
||||
{
|
||||
t->state = 0;
|
||||
t->counter.w = t->timer;
|
||||
}
|
||||
|
||||
/* state goes high when MSB is 0 */
|
||||
// state goes high when MSB is 0
|
||||
else if (!t->counter.b.h)
|
||||
{
|
||||
t->state = 1;
|
||||
@ -68,14 +74,14 @@ inline void exidy_sound_device::sh6840_apply_clock(exidy_sound_device::sh6840_ti
|
||||
}
|
||||
}
|
||||
|
||||
/* subtract off the remainder */
|
||||
// subtract off the remainder
|
||||
t->counter.b.l -= clocks;
|
||||
}
|
||||
|
||||
/* 16-bit case */
|
||||
// 16-bit case
|
||||
else
|
||||
{
|
||||
/* handle full decrements */
|
||||
// handle full decrements
|
||||
while (clocks > t->counter.w)
|
||||
{
|
||||
clocks -= t->counter.w + 1;
|
||||
@ -84,7 +90,7 @@ inline void exidy_sound_device::sh6840_apply_clock(exidy_sound_device::sh6840_ti
|
||||
t->counter.w = t->timer;
|
||||
}
|
||||
|
||||
/* subtract off the remainder */
|
||||
// subtract off the remainder
|
||||
t->counter.w -= clocks;
|
||||
}
|
||||
}
|
||||
@ -101,17 +107,14 @@ inline int exidy_sound_device::sh6840_update_noise(int clocks)
|
||||
{
|
||||
uint32_t newxor;
|
||||
int noise_clocks = 0;
|
||||
int i;
|
||||
|
||||
/* loop over clocks */
|
||||
for (i = 0; i < clocks; i++)
|
||||
// loop over clocks
|
||||
for (int i = 0; i < clocks; i++)
|
||||
{
|
||||
/* shift the LFSR. its a LOOOONG LFSR, so we need
|
||||
* four longs to hold it all!
|
||||
* first we grab new sample, then shift the high bits,
|
||||
* then the low ones; finally or in the result and see if we've
|
||||
* had a 0->1 transition */
|
||||
newxor = (m_sh6840_LFSR_3 ^ m_sh6840_LFSR_2) >> 31; /* high bits of 3 and 2 xored is new xor */
|
||||
// shift the LFSR. its a LOOOONG LFSR, so we need four longs to hold it all!
|
||||
// first we grab new sample, then shift the high bits, then the low ones;
|
||||
// finally or in the result and see if we've had a 0->1 transition
|
||||
newxor = (m_sh6840_LFSR_3 ^ m_sh6840_LFSR_2) >> 31; // high bits of 3 and 2 xored is new xor
|
||||
m_sh6840_LFSR_3 <<= 1;
|
||||
m_sh6840_LFSR_3 |= m_sh6840_LFSR_2 >> 31;
|
||||
m_sh6840_LFSR_2 <<= 1;
|
||||
@ -121,9 +124,9 @@ inline int exidy_sound_device::sh6840_update_noise(int clocks)
|
||||
m_sh6840_LFSR_0 <<= 1;
|
||||
m_sh6840_LFSR_0 |= newxor ^ m_sh6840_LFSR_oldxor;
|
||||
m_sh6840_LFSR_oldxor = newxor;
|
||||
/*printf("LFSR: %4x, %4x, %4x, %4x\n", sh6840_LFSR_3, sh6840_LFSR_2, sh6840_LFSR_1, sh6840_LFSR_0);*/
|
||||
/* if we clocked 0->1, that will serve as an external clock */
|
||||
if ((m_sh6840_LFSR_2 & 0x03) == 0x01) /* tap is at 96th bit */
|
||||
//printf("LFSR: %4x, %4x, %4x, %4x\n", m_sh6840_LFSR_3, m_sh6840_LFSR_2, m_sh6840_LFSR_1, m_sh6840_LFSR_0);
|
||||
// if we clocked 0->1, that will serve as an external clock
|
||||
if ((m_sh6840_LFSR_2 & 0x03) == 0x01) // tap is at 96th bit
|
||||
{
|
||||
noise_clocks++;
|
||||
}
|
||||
@ -141,6 +144,15 @@ inline int exidy_sound_device::sh6840_update_noise(int clocks)
|
||||
|
||||
void exidy_sound_device::sh6840_register_state_globals()
|
||||
{
|
||||
save_item(STRUCT_MEMBER(m_sh6840_timer, cr));
|
||||
save_item(STRUCT_MEMBER(m_sh6840_timer, state));
|
||||
save_item(STRUCT_MEMBER(m_sh6840_timer, leftovers));
|
||||
save_item(STRUCT_MEMBER(m_sh6840_timer, timer));
|
||||
save_item(STRUCT_MEMBER(m_sh6840_timer, clocks));
|
||||
save_item(NAME(m_sh6840_timer[0].counter.w));
|
||||
save_item(NAME(m_sh6840_timer[1].counter.w));
|
||||
save_item(NAME(m_sh6840_timer[2].counter.w));
|
||||
|
||||
save_item(NAME(m_sh6840_volume));
|
||||
save_item(NAME(m_sh6840_MSB_latch));
|
||||
save_item(NAME(m_sh6840_LSB_latch));
|
||||
@ -151,27 +163,10 @@ void exidy_sound_device::sh6840_register_state_globals()
|
||||
save_item(NAME(m_sh6840_LFSR_3));
|
||||
save_item(NAME(m_sh6840_clock_count));
|
||||
save_item(NAME(m_sfxctrl));
|
||||
save_item(NAME(m_sh6840_timer[0].cr));
|
||||
save_item(NAME(m_sh6840_timer[0].state));
|
||||
save_item(NAME(m_sh6840_timer[0].leftovers));
|
||||
save_item(NAME(m_sh6840_timer[0].timer));
|
||||
save_item(NAME(m_sh6840_timer[0].clocks));
|
||||
save_item(NAME(m_sh6840_timer[0].counter.w));
|
||||
save_item(NAME(m_sh6840_timer[1].cr));
|
||||
save_item(NAME(m_sh6840_timer[1].state));
|
||||
save_item(NAME(m_sh6840_timer[1].leftovers));
|
||||
save_item(NAME(m_sh6840_timer[1].timer));
|
||||
save_item(NAME(m_sh6840_timer[1].clocks));
|
||||
save_item(NAME(m_sh6840_timer[1].counter.w));
|
||||
save_item(NAME(m_sh6840_timer[2].cr));
|
||||
save_item(NAME(m_sh6840_timer[2].state));
|
||||
save_item(NAME(m_sh6840_timer[2].leftovers));
|
||||
save_item(NAME(m_sh6840_timer[2].timer));
|
||||
save_item(NAME(m_sh6840_timer[2].clocks));
|
||||
save_item(NAME(m_sh6840_timer[2].counter.w));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*************************************
|
||||
*
|
||||
* Audio startup routines
|
||||
@ -184,7 +179,7 @@ void exidy_sound_device::common_sh_start()
|
||||
|
||||
m_sh6840_clocks_per_sample = (int)(SH6840_CLOCK.dvalue() / (double)sample_rate * (double)(1 << 24));
|
||||
|
||||
/* allocate the stream */
|
||||
// allocate the stream
|
||||
m_stream = stream_alloc(0, 1, sample_rate);
|
||||
|
||||
sh6840_register_state_globals();
|
||||
@ -197,18 +192,6 @@ exidy_sound_device::exidy_sound_device(const machine_config &mconfig, const char
|
||||
{
|
||||
}
|
||||
|
||||
exidy_sh8253_sound_device::exidy_sh8253_sound_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
|
||||
: exidy_sound_device(mconfig, type, tag, owner, clock)
|
||||
, m_riot(*this, "riot")
|
||||
, m_cvsd(*this, "cvsd")
|
||||
, m_cvsd_filter(*this, "cvsd_filter")
|
||||
, m_cvsd_filter2(*this, "cvsd_filter2")
|
||||
, m_cvsdcpu(*this, "cvsdcpu")
|
||||
, m_tms(*this, "tms")
|
||||
, m_pia(*this, "pia")
|
||||
{
|
||||
}
|
||||
|
||||
exidy_sound_device::exidy_sound_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)
|
||||
@ -227,6 +210,14 @@ exidy_sound_device::exidy_sound_device(const machine_config &mconfig, device_typ
|
||||
{
|
||||
}
|
||||
|
||||
exidy_sh8253_sound_device::exidy_sh8253_sound_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
|
||||
: exidy_sound_device(mconfig, type, tag, owner, clock)
|
||||
, m_riot(*this, "riot")
|
||||
, m_pia(*this, "pia")
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// device_start - device-specific startup
|
||||
//-------------------------------------------------
|
||||
@ -236,6 +227,7 @@ void exidy_sound_device::device_start()
|
||||
common_sh_start();
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// device_reset - device-specific reset
|
||||
//-------------------------------------------------
|
||||
@ -245,6 +237,7 @@ void exidy_sound_device::device_reset()
|
||||
common_sh_reset();
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// sound_stream_update - handle a stream update
|
||||
//-------------------------------------------------
|
||||
@ -253,33 +246,33 @@ void exidy_sound_device::sound_stream_update(sound_stream &stream, std::vector<r
|
||||
{
|
||||
sh6840_timer_channel *sh6840_timer = m_sh6840_timer;
|
||||
|
||||
/* hack to skip the expensive lfsr noise generation unless at least one of the 3 channels actually depends on it being generated */
|
||||
int noisy = ((sh6840_timer[0].cr & sh6840_timer[1].cr & sh6840_timer[2].cr & 0x02) == 0);
|
||||
// hack to skip the expensive lfsr noise generation unless at least one of the 3 channels actually depends on it being generated
|
||||
bool noisy = ((sh6840_timer[0].cr & sh6840_timer[1].cr & sh6840_timer[2].cr & 0x02) == 0);
|
||||
auto &buffer = outputs[0];
|
||||
|
||||
/* loop over samples */
|
||||
// loop over samples
|
||||
for (int sampindex = 0; sampindex < buffer.samples(); sampindex++)
|
||||
{
|
||||
sh6840_timer_channel *t;
|
||||
int clocks;
|
||||
s32 sample = 0;
|
||||
|
||||
/* determine how many 6840 clocks this sample */
|
||||
// determine how many 6840 clocks this sample
|
||||
m_sh6840_clock_count += m_sh6840_clocks_per_sample;
|
||||
int clocks_this_sample = m_sh6840_clock_count >> 24;
|
||||
m_sh6840_clock_count &= (1 << 24) - 1;
|
||||
|
||||
/* skip if nothing enabled */
|
||||
// skip if nothing enabled
|
||||
if ((sh6840_timer[0].cr & 0x01) == 0)
|
||||
{
|
||||
int noise_clocks_this_sample = 0;
|
||||
uint32_t chan0_clocks;
|
||||
|
||||
/* generate E-clocked noise if configured to do so */
|
||||
// generate E-clocked noise if configured to do so
|
||||
if (noisy && !(m_sfxctrl & 0x01))
|
||||
noise_clocks_this_sample = sh6840_update_noise(clocks_this_sample);
|
||||
|
||||
/* handle timer 0 if enabled */
|
||||
// handle timer 0 if enabled
|
||||
t = &sh6840_timer[0];
|
||||
chan0_clocks = t->clocks;
|
||||
clocks = (t->cr & 0x02) ? clocks_this_sample : noise_clocks_this_sample;
|
||||
@ -287,21 +280,22 @@ void exidy_sound_device::sound_stream_update(sound_stream &stream, std::vector<r
|
||||
if (t->state && !(m_sfxctrl & 0x02) && (t->cr & 0x80))
|
||||
sample += m_sh6840_volume[0];
|
||||
|
||||
/* generate channel 0-clocked noise if configured to do so */
|
||||
// generate channel 0-clocked noise if configured to do so
|
||||
if (noisy && (m_sfxctrl & 0x01))
|
||||
noise_clocks_this_sample = sh6840_update_noise(t->clocks - chan0_clocks);
|
||||
|
||||
/* handle timer 1 if enabled */
|
||||
// handle timer 1 if enabled
|
||||
t = &sh6840_timer[1];
|
||||
clocks = (t->cr & 0x02) ? clocks_this_sample : noise_clocks_this_sample;
|
||||
sh6840_apply_clock(t, clocks);
|
||||
if (t->state && (t->cr & 0x80))
|
||||
sample += m_sh6840_volume[1];
|
||||
|
||||
/* handle timer 2 if enabled */
|
||||
// handle timer 2 if enabled
|
||||
t = &sh6840_timer[2];
|
||||
clocks = (t->cr & 0x02) ? clocks_this_sample : noise_clocks_this_sample;
|
||||
/* prescale */
|
||||
|
||||
// prescale
|
||||
if (t->cr & 0x01)
|
||||
{
|
||||
clocks += t->leftovers;
|
||||
@ -313,25 +307,20 @@ void exidy_sound_device::sound_stream_update(sound_stream &stream, std::vector<r
|
||||
sample += m_sh6840_volume[2];
|
||||
}
|
||||
|
||||
/* music (if present) */
|
||||
// music (if present)
|
||||
sample += generate_music_sample();
|
||||
|
||||
/* stash */
|
||||
// stash
|
||||
buffer.put_int(sampindex, sample, 32768);
|
||||
}
|
||||
}
|
||||
|
||||
s32 exidy_sound_device::generate_music_sample()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
s32 exidy_sh8253_sound_device::generate_music_sample()
|
||||
{
|
||||
sh8253_timer_channel *c;
|
||||
s32 sample = 0;
|
||||
|
||||
/* music channel 0 */
|
||||
// music channel 0
|
||||
c = &m_sh8253_timer[0];
|
||||
if (c->enable)
|
||||
{
|
||||
@ -340,7 +329,7 @@ s32 exidy_sh8253_sound_device::generate_music_sample()
|
||||
sample += BASE_VOLUME;
|
||||
}
|
||||
|
||||
/* music channel 1 */
|
||||
// music channel 1
|
||||
c = &m_sh8253_timer[1];
|
||||
if (c->enable)
|
||||
{
|
||||
@ -349,7 +338,7 @@ s32 exidy_sh8253_sound_device::generate_music_sample()
|
||||
sample += BASE_VOLUME;
|
||||
}
|
||||
|
||||
/* music channel 2 */
|
||||
// music channel 2
|
||||
c = &m_sh8253_timer[2];
|
||||
if (c->enable)
|
||||
{
|
||||
@ -371,7 +360,7 @@ s32 exidy_sh8253_sound_device::generate_music_sample()
|
||||
|
||||
void exidy_sound_device::common_sh_reset()
|
||||
{
|
||||
/* 6840 */
|
||||
// 6840
|
||||
memset(m_sh6840_timer, 0, sizeof(m_sh6840_timer));
|
||||
m_sh6840_MSB_latch = 0;
|
||||
m_sh6840_LSB_latch = 0;
|
||||
@ -381,7 +370,7 @@ void exidy_sound_device::common_sh_reset()
|
||||
m_sh6840_clock_count = 0;
|
||||
m_sfxctrl = 0;
|
||||
|
||||
/* LFSR */
|
||||
// LFSR
|
||||
m_sh6840_LFSR_oldxor = 0;
|
||||
m_sh6840_LFSR_0 = 0xffffffff;
|
||||
m_sh6840_LFSR_1 = 0xffffffff;
|
||||
@ -390,57 +379,6 @@ void exidy_sound_device::common_sh_reset()
|
||||
}
|
||||
|
||||
|
||||
/*************************************
|
||||
*
|
||||
* 6532 interface
|
||||
*
|
||||
*************************************/
|
||||
|
||||
void exidy_sh8253_sound_device::r6532_porta_w(uint8_t data)
|
||||
{
|
||||
if (m_cvsd.found())
|
||||
m_cvsdcpu->set_input_line(INPUT_LINE_RESET, (data & 0x10) ? CLEAR_LINE : ASSERT_LINE);
|
||||
|
||||
if (m_tms.found())
|
||||
{
|
||||
logerror("(%f)%s:TMS5220 data write = %02X\n", machine().time().as_double(), machine().describe_context(), m_riot->porta_out_get());
|
||||
m_tms->data_w(data);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t exidy_sh8253_sound_device::r6532_porta_r()
|
||||
{
|
||||
uint8_t status = 0xff;
|
||||
if (m_tms.found())
|
||||
{
|
||||
status = m_tms->status_r();
|
||||
logerror("(%f)%s:TMS5220 status read = %02X\n", machine().time().as_double(), machine().describe_context(), status);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
void exidy_sh8253_sound_device::r6532_portb_w(uint8_t data)
|
||||
{
|
||||
if (m_tms.found())
|
||||
{
|
||||
m_tms->rsq_w(BIT(data, 0));
|
||||
m_tms->wsq_w(BIT(data, 1));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uint8_t exidy_sh8253_sound_device::r6532_portb_r()
|
||||
{
|
||||
uint8_t newdata = m_riot->portb_in_get();
|
||||
if (m_tms.found())
|
||||
{
|
||||
newdata &= ~0x0c;
|
||||
if (m_tms->readyq_r()) newdata |= 0x04;
|
||||
if (m_tms->intq_r()) newdata |= 0x08;
|
||||
}
|
||||
return newdata;
|
||||
}
|
||||
|
||||
|
||||
/*************************************
|
||||
*
|
||||
@ -450,24 +388,15 @@ uint8_t exidy_sh8253_sound_device::r6532_portb_r()
|
||||
|
||||
void exidy_sh8253_sound_device::sh8253_register_state_globals()
|
||||
{
|
||||
save_item(NAME(m_sh8253_timer[0].clstate));
|
||||
save_item(NAME(m_sh8253_timer[0].enable));
|
||||
save_item(NAME(m_sh8253_timer[0].count));
|
||||
save_item(NAME(m_sh8253_timer[0].step));
|
||||
save_item(NAME(m_sh8253_timer[0].fraction));
|
||||
save_item(NAME(m_sh8253_timer[1].clstate));
|
||||
save_item(NAME(m_sh8253_timer[1].enable));
|
||||
save_item(NAME(m_sh8253_timer[1].count));
|
||||
save_item(NAME(m_sh8253_timer[1].step));
|
||||
save_item(NAME(m_sh8253_timer[1].fraction));
|
||||
save_item(NAME(m_sh8253_timer[2].clstate));
|
||||
save_item(NAME(m_sh8253_timer[2].enable));
|
||||
save_item(NAME(m_sh8253_timer[2].count));
|
||||
save_item(NAME(m_sh8253_timer[2].step));
|
||||
save_item(NAME(m_sh8253_timer[2].fraction));
|
||||
save_item(STRUCT_MEMBER(m_sh8253_timer, clstate));
|
||||
save_item(STRUCT_MEMBER(m_sh8253_timer, enable));
|
||||
save_item(STRUCT_MEMBER(m_sh8253_timer, count));
|
||||
save_item(STRUCT_MEMBER(m_sh8253_timer, step));
|
||||
save_item(STRUCT_MEMBER(m_sh8253_timer, fraction));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*************************************
|
||||
*
|
||||
* 8253 timer handlers
|
||||
@ -519,27 +448,27 @@ void exidy_sh8253_sound_device::sh8253_w(offs_t offset, uint8_t data)
|
||||
|
||||
uint8_t exidy_sound_device::sh6840_r(offs_t offset)
|
||||
{
|
||||
/* force an update of the stream */
|
||||
// force an update of the stream
|
||||
m_stream->update();
|
||||
|
||||
switch (offset)
|
||||
{
|
||||
/* offset 0: Motorola datasheet says it isn't used, Hitachi datasheet says it reads as 0s always*/
|
||||
// offset 0: Motorola datasheet says it isn't used, Hitachi datasheet says it reads as 0s always
|
||||
case 0:
|
||||
return 0;
|
||||
|
||||
/* offset 1 reads the status register: bits 2 1 0 correspond to ints on channels 2,1,0, and bit 7 is an 'OR' of bits 2,1,0 */
|
||||
// offset 1 reads the status register: bits 2 1 0 correspond to ints on channels 2,1,0, and bit 7 is an 'OR' of bits 2,1,0
|
||||
case 1:
|
||||
logerror("%s:exidy_sh6840_r - unexpected read, status register is TODO!\n", machine().describe_context());
|
||||
return 0;
|
||||
|
||||
/* offsets 2,4,6 read channel 0,1,2 MSBs and latch the LSB*/
|
||||
// offsets 2,4,6 read channel 0,1,2 MSBs and latch the LSB
|
||||
case 2: case 4: case 6:
|
||||
m_sh6840_LSB_latch = m_sh6840_timer[((offset>>1)-1)].counter.b.l;
|
||||
return m_sh6840_timer[((offset>>1)-1)].counter.b.h;
|
||||
|
||||
/* offsets 3,5,7 read the LSB latch*/
|
||||
default: /* case 3,5,7 */
|
||||
// offsets 3,5,7 read the LSB latch
|
||||
default: // case 3,5,7
|
||||
return m_sh6840_LSB_latch;
|
||||
}
|
||||
}
|
||||
@ -549,49 +478,49 @@ void exidy_sound_device::sh6840_w(offs_t offset, uint8_t data)
|
||||
{
|
||||
sh6840_timer_channel *sh6840_timer = m_sh6840_timer;
|
||||
|
||||
/* force an update of the stream */
|
||||
// force an update of the stream
|
||||
m_stream->update();
|
||||
|
||||
switch (offset)
|
||||
{
|
||||
/* offset 0 writes to either channel 0 control or channel 2 control */
|
||||
// offset 0 writes to either channel 0 control or channel 2 control
|
||||
case 0:
|
||||
if (sh6840_timer[1].cr & 0x01)
|
||||
sh6840_timer[0].cr = data;
|
||||
else
|
||||
sh6840_timer[2].cr = data;
|
||||
|
||||
/* only support mode 0 and 2 */
|
||||
// only support mode 0 and 2
|
||||
if (((data >> 3) & 5) != 0)
|
||||
fatalerror("exidy_sh6840_w - channel %d configured for mode %d\n", (sh6840_timer[1].cr & 0x01) ? 0 : 2, (data >> 3) & 7);
|
||||
break;
|
||||
|
||||
/* offset 1 writes to channel 1 control */
|
||||
// offset 1 writes to channel 1 control
|
||||
case 1:
|
||||
sh6840_timer[1].cr = data;
|
||||
|
||||
/* only support mode 0 and 2 */
|
||||
// only support mode 0 and 2
|
||||
if (((data >> 3) & 5) != 0)
|
||||
fatalerror("exidy_sh6840_w - channel 1 configured for mode %d\n", (data >> 3) & 7);
|
||||
break;
|
||||
|
||||
/* offsets 2/4/6 write to the common MSB latch */
|
||||
// offsets 2/4/6 write to the common MSB latch
|
||||
case 2:
|
||||
case 4:
|
||||
case 6:
|
||||
m_sh6840_MSB_latch = data;
|
||||
break;
|
||||
|
||||
/* offsets 3/5/7 write to the LSB controls */
|
||||
// offsets 3/5/7 write to the LSB controls
|
||||
case 3:
|
||||
case 5:
|
||||
case 7:
|
||||
{
|
||||
/* latch the timer value */
|
||||
// latch the timer value
|
||||
int ch = (offset - 3) / 2;
|
||||
sh6840_timer[ch].timer = (m_sh6840_MSB_latch << 8) | (data & 0xff);
|
||||
|
||||
/* if CR4 is clear, the value is loaded immediately */
|
||||
// if CR4 is clear, the value is loaded immediately
|
||||
if (!(sh6840_timer[ch].cr & 0x10))
|
||||
sh6840_timer[ch].counter.w = sh6840_timer[ch].timer;
|
||||
break;
|
||||
@ -627,19 +556,6 @@ void exidy_sound_device::sfxctrl_w(offs_t offset, uint8_t data)
|
||||
|
||||
|
||||
|
||||
/*************************************
|
||||
*
|
||||
* Sound filter control
|
||||
*
|
||||
*************************************/
|
||||
|
||||
void venture_sound_device::filter_w(uint8_t data)
|
||||
{
|
||||
logerror("exidy_sound_filter_w = %02X\n", data);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*************************************
|
||||
*
|
||||
* Venture, etc.
|
||||
@ -662,6 +578,7 @@ venture_sound_device::venture_sound_device(const machine_config &mconfig, device
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// device_start - device-specific startup
|
||||
//-------------------------------------------------
|
||||
@ -670,12 +587,12 @@ void exidy_sh8253_sound_device::device_start()
|
||||
{
|
||||
common_sh_start();
|
||||
|
||||
/* 8253 */
|
||||
// 8253
|
||||
m_freq_to_step = (1 << 24) / SH8253_CLOCK;
|
||||
|
||||
sh8253_register_state_globals();
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// device_reset - device-specific reset
|
||||
//-------------------------------------------------
|
||||
@ -684,84 +601,50 @@ void exidy_sh8253_sound_device::device_reset()
|
||||
{
|
||||
common_sh_reset();
|
||||
|
||||
/* 8253 */
|
||||
// 8253
|
||||
memset(m_sh8253_timer, 0, sizeof(m_sh8253_timer));
|
||||
}
|
||||
|
||||
|
||||
void venture_sound_device::pa_w(uint8_t data)
|
||||
//-------------------------------------------------
|
||||
// I/O handlers
|
||||
//-------------------------------------------------
|
||||
|
||||
void venture_sound_device::filter_w(uint8_t data)
|
||||
{
|
||||
m_pia->porta_w(data);
|
||||
logerror("exidy_sound_filter_w = %02X\n", data);
|
||||
}
|
||||
|
||||
|
||||
void venture_sound_device::pb_w(uint8_t data)
|
||||
{
|
||||
m_pia->portb_w(data);
|
||||
}
|
||||
|
||||
|
||||
void venture_sound_device::ca_w(int state)
|
||||
{
|
||||
m_pia->ca1_w(state);
|
||||
}
|
||||
|
||||
|
||||
void venture_sound_device::cb_w(int state)
|
||||
{
|
||||
m_pia->cb1_w(state);
|
||||
}
|
||||
|
||||
|
||||
void venture_sound_device::pia_pa_w(uint8_t data)
|
||||
{
|
||||
m_pa_callback(data);
|
||||
}
|
||||
|
||||
|
||||
void venture_sound_device::pia_pb_w(uint8_t data)
|
||||
{
|
||||
m_pb_callback(data);
|
||||
}
|
||||
|
||||
|
||||
void venture_sound_device::pia_ca2_w(int state)
|
||||
{
|
||||
m_ca2_callback(state);
|
||||
}
|
||||
|
||||
|
||||
void venture_sound_device::pia_cb2_w(int state)
|
||||
{
|
||||
m_cb2_callback(state);
|
||||
}
|
||||
|
||||
//-------------------------------------------------
|
||||
// Address maps
|
||||
//-------------------------------------------------
|
||||
|
||||
void venture_sound_device::venture_audio_map(address_map &map)
|
||||
{
|
||||
map.global_mask(0x7fff);
|
||||
map(0x0000, 0x007f).mirror(0x0780).ram();
|
||||
map(0x0800, 0x087f).mirror(0x0780).rw("riot", FUNC(riot6532_device::read), FUNC(riot6532_device::write));
|
||||
map(0x1000, 0x1003).mirror(0x07fc).rw("pia", FUNC(pia6821_device::read), FUNC(pia6821_device::write));
|
||||
map(0x0000, 0x007f).mirror(0x0780).m(m_riot, FUNC(mos6532_new_device::ram_map));
|
||||
map(0x0800, 0x081f).mirror(0x07e0).m(m_riot, FUNC(mos6532_new_device::io_map));
|
||||
map(0x1000, 0x1003).mirror(0x07fc).rw(m_pia, FUNC(pia6821_device::read), FUNC(pia6821_device::write));
|
||||
map(0x1800, 0x1803).mirror(0x07fc).w(FUNC(venture_sound_device::sh8253_w)).nopr(); // no /RD
|
||||
map(0x2000, 0x27ff).w(FUNC(venture_sound_device::filter_w));
|
||||
map(0x2000, 0x2000).mirror(0x07ff).w(FUNC(venture_sound_device::filter_w));
|
||||
map(0x2800, 0x2807).mirror(0x07f8).rw(FUNC(venture_sound_device::sh6840_r), FUNC(venture_sound_device::sh6840_w));
|
||||
map(0x3000, 0x3003).mirror(0x07fc).w(FUNC(venture_sound_device::sfxctrl_w));
|
||||
map(0x5800, 0x7fff).rom();
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// Machine config
|
||||
//-------------------------------------------------
|
||||
|
||||
void venture_sound_device::device_add_mconfig(machine_config &config)
|
||||
{
|
||||
m6502_device &audiocpu(M6502(config, "audiocpu", 3.579545_MHz_XTAL / 4));
|
||||
audiocpu.set_addrmap(AS_PROGRAM, &venture_sound_device::venture_audio_map);
|
||||
|
||||
RIOT6532(config, m_riot, SH6532_CLOCK);
|
||||
m_riot->in_pa_callback().set(FUNC(venture_sound_device::r6532_porta_r));
|
||||
m_riot->out_pa_callback().set(FUNC(venture_sound_device::r6532_porta_w));
|
||||
m_riot->in_pb_callback().set(FUNC(venture_sound_device::r6532_portb_r));
|
||||
m_riot->out_pb_callback().set(FUNC(venture_sound_device::r6532_portb_w));
|
||||
m_riot->irq_callback().set("audioirq", FUNC(input_merger_device::in_w<0>));
|
||||
MOS6532_NEW(config, m_riot, SH6532_CLOCK);
|
||||
m_riot->irq_wr_callback().set("audioirq", FUNC(input_merger_device::in_w<0>));
|
||||
|
||||
PIA6821(config, m_pia, 0);
|
||||
m_pia->writepa_handler().set(FUNC(venture_sound_device::pia_pa_w));
|
||||
@ -790,10 +673,16 @@ DEFINE_DEVICE_TYPE(EXIDY_MTRAP, mtrap_sound_device, "mtrap_sound", "Exidy SFX+PS
|
||||
mtrap_sound_device::mtrap_sound_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
|
||||
: venture_sound_device(mconfig, EXIDY_MTRAP, tag, owner, clock)
|
||||
, m_cvsd_timer(*this, "cvsd_timer")
|
||||
, m_cvsd_clk(false)
|
||||
, m_cvsd(*this, "cvsd")
|
||||
, m_cvsd_filter(*this, "cvsd_filter")
|
||||
, m_cvsd_filter2(*this, "cvsd_filter2")
|
||||
, m_cvsdcpu(*this, "cvsdcpu")
|
||||
, m_cvsd_data(0)
|
||||
, m_cvsd_clk(0)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// device_start - device-specific startup
|
||||
//-------------------------------------------------
|
||||
@ -802,17 +691,22 @@ void mtrap_sound_device::device_start()
|
||||
{
|
||||
common_sh_start();
|
||||
|
||||
/* 8253 */
|
||||
// 8253
|
||||
m_freq_to_step = (1 << 24) / SH8253_CLOCK;
|
||||
|
||||
sh8253_register_state_globals();
|
||||
|
||||
save_item(NAME(m_cvsd_data));
|
||||
save_item(NAME(m_cvsd_clk));
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// I/O handlers
|
||||
//-------------------------------------------------
|
||||
|
||||
TIMER_DEVICE_CALLBACK_MEMBER(mtrap_sound_device::cvsd_timer)
|
||||
{
|
||||
m_cvsd_clk = !m_cvsd_clk;
|
||||
m_cvsd_clk ^= 1;
|
||||
m_cvsd->clock_w(m_cvsd_clk);
|
||||
}
|
||||
|
||||
@ -822,7 +716,7 @@ void mtrap_sound_device::voiceio_w(offs_t offset, uint8_t data)
|
||||
m_cvsd->digit_w(data & 1);
|
||||
|
||||
if (!(offset & 0x20))
|
||||
m_riot->portb_in_set(data & 1, 0xff);
|
||||
m_riot->pb0_w(data & 1);
|
||||
}
|
||||
|
||||
|
||||
@ -832,11 +726,7 @@ uint8_t mtrap_sound_device::voiceio_r(offs_t offset)
|
||||
if (!(offset & 0x80))
|
||||
{
|
||||
retval &= 0xf0;
|
||||
uint8_t porta = m_riot->porta_out_get();
|
||||
uint8_t data = (porta & 0x06) >> 1;
|
||||
data |= (porta & 0x01) << 2;
|
||||
data |= (porta & 0x08);
|
||||
retval |= data;
|
||||
retval |= bitswap(m_cvsd_data,3,0,2,1);
|
||||
}
|
||||
|
||||
if (!(offset & 0x40))
|
||||
@ -848,6 +738,16 @@ uint8_t mtrap_sound_device::voiceio_r(offs_t offset)
|
||||
return retval;
|
||||
}
|
||||
|
||||
void mtrap_sound_device::cvsd_data_w(uint8_t data)
|
||||
{
|
||||
m_cvsd_data = data;
|
||||
m_cvsdcpu->set_input_line(INPUT_LINE_RESET, (data & 0x10) ? CLEAR_LINE : ASSERT_LINE);
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// Address maps
|
||||
//-------------------------------------------------
|
||||
|
||||
void mtrap_sound_device::cvsd_map(address_map &map)
|
||||
{
|
||||
@ -863,10 +763,16 @@ void mtrap_sound_device::cvsd_iomap(address_map &map)
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// Machine config
|
||||
//-------------------------------------------------
|
||||
|
||||
void mtrap_sound_device::device_add_mconfig(machine_config &config)
|
||||
{
|
||||
venture_sound_device::device_add_mconfig(config);
|
||||
|
||||
m_riot->pa_wr_callback().set(FUNC(mtrap_sound_device::cvsd_data_w));
|
||||
|
||||
Z80(config, m_cvsdcpu, CVSD_Z80_CLOCK);
|
||||
m_cvsdcpu->set_addrmap(AS_PROGRAM, &mtrap_sound_device::cvsd_map);
|
||||
m_cvsdcpu->set_addrmap(AS_IO, &mtrap_sound_device::cvsd_iomap);
|
||||
@ -874,25 +780,72 @@ void mtrap_sound_device::device_add_mconfig(machine_config &config)
|
||||
// this is a 555 timer with 53% duty cycle, within margin of error of 50% duty cycle; the handler clocks on both clock edges, hence * 2.0
|
||||
TIMER(config, m_cvsd_timer).configure_periodic(FUNC(mtrap_sound_device::cvsd_timer), attotime::from_hz(CVSD_CLOCK * 2.0));
|
||||
|
||||
/* audio hardware */
|
||||
// audio hardware
|
||||
FILTER_BIQUAD(config, m_cvsd_filter2).opamp_mfb_lowpass_setup(RES_K(10), RES_K(3.9), RES_K(18), CAP_N(20), CAP_N(2.2));
|
||||
m_cvsd_filter2->add_route(ALL_OUTPUTS, "mono", 1.0);
|
||||
FILTER_BIQUAD(config, m_cvsd_filter).opamp_mfb_lowpass_setup(RES_K(10), RES_K(3.9), RES_K(18), CAP_N(20), CAP_N(2.2));
|
||||
m_cvsd_filter->add_route(ALL_OUTPUTS, m_cvsd_filter2, 1.0);
|
||||
MC3417(config, m_cvsd, 0).add_route(ALL_OUTPUTS, m_cvsd_filter, 0.3086); // each filter has gain of 1.8 for total gain of 3.24, 0.3086 cancels this out.
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*************************************
|
||||
*
|
||||
* Victory
|
||||
*
|
||||
*************************************/
|
||||
|
||||
#define VICTORY_AUDIO_CPU_CLOCK (3.579545_MHz_XTAL / 4)
|
||||
#define VICTORY_LOG_SOUND 0
|
||||
DEFINE_DEVICE_TYPE(EXIDY_VICTORY, victory_sound_device, "victory_sound", "Exidy SFX+PSG+Speech")
|
||||
|
||||
victory_sound_device::victory_sound_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
|
||||
: exidy_sh8253_sound_device(mconfig, EXIDY_VICTORY, tag, owner, clock)
|
||||
, m_tms(*this, "tms")
|
||||
, m_sound_response_ack_clk(0)
|
||||
, m_pia_ca1(0)
|
||||
, m_pia_cb1(0)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// device_start - device-specific startup
|
||||
//-------------------------------------------------
|
||||
|
||||
void victory_sound_device::device_start()
|
||||
{
|
||||
exidy_sh8253_sound_device::device_start();
|
||||
|
||||
save_item(NAME(m_sound_response_ack_clk));
|
||||
save_item(NAME(m_pia_ca1));
|
||||
save_item(NAME(m_pia_cb1));
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// device_reset - device-specific reset
|
||||
//-------------------------------------------------
|
||||
|
||||
void victory_sound_device::device_reset()
|
||||
{
|
||||
exidy_sh8253_sound_device::device_reset();
|
||||
|
||||
// the flip-flop @ F4 is reset
|
||||
m_sound_response_ack_clk = 0;
|
||||
m_pia_cb1 = 1;
|
||||
m_pia->cb1_w(m_pia_cb1);
|
||||
|
||||
// these two lines shouldn't be needed, but it avoids the log entry
|
||||
// as the sound CPU checks port A before the main CPU ever writes to it
|
||||
m_pia->porta_w(0);
|
||||
m_pia_ca1 = 1;
|
||||
m_pia->ca1_w(m_pia_ca1);
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// I/O handlers
|
||||
//-------------------------------------------------
|
||||
|
||||
uint8_t victory_sound_device::response_r()
|
||||
{
|
||||
@ -900,7 +853,7 @@ uint8_t victory_sound_device::response_r()
|
||||
|
||||
if (!machine().side_effects_disabled())
|
||||
{
|
||||
if (VICTORY_LOG_SOUND) logerror("%s:!!!! Sound response read = %02X\n", machine().describe_context(), ret);
|
||||
LOGMASKED(LOG_VICTORY_SOUND, "%s:!!!! Sound response read = %02X\n", machine().describe_context(), ret);
|
||||
|
||||
m_pia_cb1 = 0;
|
||||
m_pia->cb1_w(m_pia_cb1);
|
||||
@ -909,17 +862,14 @@ uint8_t victory_sound_device::response_r()
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
uint8_t victory_sound_device::status_r()
|
||||
{
|
||||
uint8_t ret = (m_pia_ca1 << 7) | (m_pia_cb1 << 6);
|
||||
|
||||
if (VICTORY_LOG_SOUND) logerror("%s:!!!! Sound status read = %02X\n", machine().describe_context(), ret);
|
||||
LOGMASKED(LOG_VICTORY_SOUND, "%s:!!!! Sound status read = %02X\n", machine().describe_context(), ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
TIMER_CALLBACK_MEMBER(victory_sound_device::delayed_command_w)
|
||||
{
|
||||
m_pia->porta_w(param);
|
||||
@ -929,15 +879,13 @@ TIMER_CALLBACK_MEMBER(victory_sound_device::delayed_command_w)
|
||||
|
||||
void victory_sound_device::command_w(uint8_t data)
|
||||
{
|
||||
if (VICTORY_LOG_SOUND) logerror("%s:!!!! Sound command = %02X\n", machine().describe_context(), data);
|
||||
|
||||
LOGMASKED(LOG_VICTORY_SOUND, "%s:!!!! Sound command = %02X\n", machine().describe_context(), data);
|
||||
machine().scheduler().synchronize(timer_expired_delegate(FUNC(victory_sound_device::delayed_command_w), this), data);
|
||||
}
|
||||
|
||||
|
||||
void victory_sound_device::irq_clear_w(int state)
|
||||
{
|
||||
if (VICTORY_LOG_SOUND) logerror("%s:!!!! Sound IRQ clear = %02X\n", machine().describe_context(), state);
|
||||
LOGMASKED(LOG_VICTORY_SOUND, "%s:!!!! Sound IRQ clear = %02X\n", machine().describe_context(), state);
|
||||
|
||||
if (!state)
|
||||
{
|
||||
@ -946,70 +894,30 @@ void victory_sound_device::irq_clear_w(int state)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void victory_sound_device::main_ack_w(int state)
|
||||
{
|
||||
if (VICTORY_LOG_SOUND) logerror("%s:!!!! Sound Main ACK W = %02X\n", machine().describe_context(), state);
|
||||
LOGMASKED(LOG_VICTORY_SOUND, "%s:!!!! Sound Main ACK W = %02X\n", machine().describe_context(), state);
|
||||
|
||||
if (m_victory_sound_response_ack_clk && !state)
|
||||
if (m_sound_response_ack_clk && !state)
|
||||
{
|
||||
m_pia_cb1 = 1;
|
||||
m_pia->cb1_w(m_pia_cb1);
|
||||
}
|
||||
|
||||
m_victory_sound_response_ack_clk = state;
|
||||
m_sound_response_ack_clk = state;
|
||||
}
|
||||
|
||||
|
||||
DEFINE_DEVICE_TYPE(EXIDY_VICTORY, victory_sound_device, "victory_sound", "Exidy SFX+PSG+Speech")
|
||||
|
||||
victory_sound_device::victory_sound_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
|
||||
: exidy_sh8253_sound_device(mconfig, EXIDY_VICTORY, tag, owner, clock)
|
||||
, m_victory_sound_response_ack_clk(0)
|
||||
, m_pia_ca1(0)
|
||||
, m_pia_cb1(0)
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------
|
||||
// device_start - device-specific startup
|
||||
// Address maps
|
||||
//-------------------------------------------------
|
||||
|
||||
void victory_sound_device::device_start()
|
||||
{
|
||||
save_item(NAME(m_victory_sound_response_ack_clk));
|
||||
save_item(NAME(m_pia_ca1));
|
||||
save_item(NAME(m_pia_cb1));
|
||||
|
||||
exidy_sh8253_sound_device::device_start();
|
||||
}
|
||||
|
||||
//-------------------------------------------------
|
||||
// device_reset - device-specific reset
|
||||
//-------------------------------------------------
|
||||
|
||||
void victory_sound_device::device_reset()
|
||||
{
|
||||
exidy_sh8253_sound_device::device_reset();
|
||||
|
||||
/* the flip-flop @ F4 is reset */
|
||||
m_victory_sound_response_ack_clk = 0;
|
||||
m_pia_cb1 = 1;
|
||||
m_pia->cb1_w(m_pia_cb1);
|
||||
|
||||
/* these two lines shouldn't be needed, but it avoids the log entry
|
||||
as the sound CPU checks port A before the main CPU ever writes to it */
|
||||
m_pia->porta_w(0);
|
||||
m_pia_ca1 = 1;
|
||||
m_pia->ca1_w(m_pia_ca1);
|
||||
}
|
||||
|
||||
|
||||
void victory_sound_device::victory_audio_map(address_map &map)
|
||||
{
|
||||
map(0x0000, 0x00ff).mirror(0x0f00).ram();
|
||||
map(0x1000, 0x107f).mirror(0x0f80).rw("riot", FUNC(riot6532_device::read), FUNC(riot6532_device::write));
|
||||
map(0x2000, 0x2003).mirror(0x0ffc).rw("pia", FUNC(pia6821_device::read), FUNC(pia6821_device::write));
|
||||
map(0x0000, 0x007f).mirror(0x0f00).m(m_riot, FUNC(mos6532_new_device::ram_map));
|
||||
map(0x0080, 0x00ff).mirror(0x0f00).ram();
|
||||
map(0x1000, 0x101f).mirror(0x0fe0).m(m_riot, FUNC(mos6532_new_device::io_map));
|
||||
map(0x2000, 0x2003).mirror(0x0ffc).rw(m_pia, FUNC(pia6821_device::read), FUNC(pia6821_device::write));
|
||||
map(0x3000, 0x3003).mirror(0x0ffc).w(FUNC(victory_sound_device::sh8253_w)).nopr(); // no /RD
|
||||
map(0x4000, 0x4fff).noprw();
|
||||
map(0x5000, 0x5007).mirror(0x0ff8).rw(FUNC(victory_sound_device::sh6840_r), FUNC(victory_sound_device::sh6840_w));
|
||||
@ -1019,17 +927,23 @@ void victory_sound_device::victory_audio_map(address_map &map)
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// Machine config
|
||||
//-------------------------------------------------
|
||||
|
||||
void victory_sound_device::device_add_mconfig(machine_config &config)
|
||||
{
|
||||
m6502_device &audiocpu(M6502(config, "audiocpu", VICTORY_AUDIO_CPU_CLOCK));
|
||||
m6502_device &audiocpu(M6502(config, "audiocpu", 3.579545_MHz_XTAL / 4));
|
||||
audiocpu.set_addrmap(AS_PROGRAM, &victory_sound_device::victory_audio_map);
|
||||
|
||||
RIOT6532(config, m_riot, SH6532_CLOCK);
|
||||
m_riot->in_pa_callback().set(FUNC(victory_sound_device::r6532_porta_r));
|
||||
m_riot->out_pa_callback().set(FUNC(victory_sound_device::r6532_porta_w));
|
||||
m_riot->in_pb_callback().set(FUNC(victory_sound_device::r6532_portb_r));
|
||||
m_riot->out_pb_callback().set(FUNC(victory_sound_device::r6532_portb_w));
|
||||
m_riot->irq_callback().set("audioirq", FUNC(input_merger_device::in_w<0>));
|
||||
MOS6532_NEW(config, m_riot, SH6532_CLOCK);
|
||||
m_riot->pa_wr_callback().set(m_tms, FUNC(tms5220_device::data_w));
|
||||
m_riot->pa_rd_callback().set(m_tms, FUNC(tms5220_device::status_r));
|
||||
m_riot->pb_wr_callback<0>().set(m_tms, FUNC(tms5220_device::rsq_w));
|
||||
m_riot->pb_wr_callback<1>().set(m_tms, FUNC(tms5220_device::wsq_w));
|
||||
m_riot->pb_rd_callback<2>().set(m_tms, FUNC(tms5220_device::readyq_r));
|
||||
m_riot->pb_rd_callback<3>().set(m_tms, FUNC(tms5220_device::intq_r));
|
||||
m_riot->irq_wr_callback().set("audioirq", FUNC(input_merger_device::in_w<0>));
|
||||
|
||||
PIA6821(config, m_pia, 0);
|
||||
m_pia->ca2_handler().set(FUNC(victory_sound_device::irq_clear_w));
|
||||
@ -1039,7 +953,6 @@ void victory_sound_device::device_add_mconfig(machine_config &config)
|
||||
INPUT_MERGER_ANY_HIGH(config, "audioirq").output_handler().set_inputline("audiocpu", m6502_device::IRQ_LINE); // open collector
|
||||
|
||||
SPEAKER(config, "mono").front_center();
|
||||
|
||||
this->add_route(ALL_OUTPUTS, "mono", 1.0);
|
||||
|
||||
TMS5220(config, m_tms, 640000).add_route(ALL_OUTPUTS, "mono", 1.0);
|
||||
|
@ -5,18 +5,17 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "machine/6532riot.h"
|
||||
#include "machine/6821pia.h"
|
||||
#include "machine/mos6530n.h"
|
||||
#include "machine/timer.h"
|
||||
#include "sound/flt_biquad.h"
|
||||
#include "sound/hc55516.h"
|
||||
#include "sound/tms5220.h"
|
||||
|
||||
|
||||
class exidy_sound_device : public device_t,
|
||||
public device_sound_interface
|
||||
class exidy_sound_device : public device_t, public device_sound_interface
|
||||
{
|
||||
/* 6840 variables */
|
||||
// 6840 variables
|
||||
struct sh6840_timer_channel
|
||||
{
|
||||
uint8_t cr = 0;
|
||||
@ -57,11 +56,11 @@ protected:
|
||||
|
||||
// sound stream update overrides
|
||||
virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
|
||||
virtual s32 generate_music_sample();
|
||||
virtual s32 generate_music_sample() { return 0; }
|
||||
|
||||
static inline void sh6840_apply_clock(sh6840_timer_channel *t, int clocks);
|
||||
|
||||
/* sound streaming variables */
|
||||
// sound streaming variables
|
||||
sound_stream *m_stream;
|
||||
double m_freq_to_step;
|
||||
|
||||
@ -86,6 +85,7 @@ private:
|
||||
|
||||
DECLARE_DEVICE_TYPE(EXIDY, exidy_sound_device)
|
||||
|
||||
|
||||
class exidy_sh8253_sound_device : public exidy_sound_device
|
||||
{
|
||||
struct sh8253_timer_channel
|
||||
@ -106,30 +106,16 @@ protected:
|
||||
|
||||
virtual s32 generate_music_sample() override;
|
||||
|
||||
void r6532_porta_w(uint8_t data);
|
||||
uint8_t r6532_porta_r();
|
||||
void r6532_portb_w(uint8_t data);
|
||||
uint8_t r6532_portb_r();
|
||||
|
||||
void sh8253_w(offs_t offset, uint8_t data);
|
||||
|
||||
void sh8253_register_state_globals();
|
||||
|
||||
/* 8253 variables */
|
||||
sh8253_timer_channel m_sh8253_timer[3];
|
||||
|
||||
/* 6532 variables */
|
||||
required_device<riot6532_device> m_riot;
|
||||
|
||||
/* 5220/CVSD variables */
|
||||
optional_device<mc3417_device> m_cvsd;
|
||||
optional_device<filter_biquad_device> m_cvsd_filter;
|
||||
optional_device<filter_biquad_device> m_cvsd_filter2;
|
||||
optional_device<cpu_device> m_cvsdcpu;
|
||||
optional_device<tms5220_device> m_tms;
|
||||
required_device<mos6532_new_device> m_riot;
|
||||
required_device<pia6821_device> m_pia;
|
||||
};
|
||||
|
||||
|
||||
class venture_sound_device : public exidy_sh8253_sound_device
|
||||
{
|
||||
public:
|
||||
@ -142,10 +128,10 @@ public:
|
||||
auto cb2_callback() { return m_cb2_callback.bind(); }
|
||||
|
||||
// external access
|
||||
void pa_w(uint8_t data);
|
||||
void pb_w(uint8_t data);
|
||||
void ca_w(int state);
|
||||
void cb_w(int state);
|
||||
void pa_w(uint8_t data) { m_pia->porta_w(data); }
|
||||
void pb_w(uint8_t data) { m_pia->portb_w(data); }
|
||||
void ca_w(int state) { m_pia->ca1_w(state); }
|
||||
void cb_w(int state) { m_pia->cb1_w(state); }
|
||||
|
||||
protected:
|
||||
venture_sound_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
|
||||
@ -158,10 +144,10 @@ protected:
|
||||
private:
|
||||
void filter_w(uint8_t data);
|
||||
|
||||
void pia_pa_w(uint8_t data);
|
||||
void pia_pb_w(uint8_t data);
|
||||
void pia_ca2_w(int state);
|
||||
void pia_cb2_w(int state);
|
||||
void pia_pa_w(uint8_t data) { m_pa_callback(data); }
|
||||
void pia_pb_w(uint8_t data) { m_pb_callback(data); }
|
||||
void pia_ca2_w(int state) { m_ca2_callback(state); }
|
||||
void pia_cb2_w(int state) { m_cb2_callback(state); }
|
||||
|
||||
void venture_audio(machine_config &config);
|
||||
|
||||
@ -173,6 +159,7 @@ private:
|
||||
|
||||
DECLARE_DEVICE_TYPE(EXIDY_VENTURE, venture_sound_device)
|
||||
|
||||
|
||||
class mtrap_sound_device : public venture_sound_device
|
||||
{
|
||||
public:
|
||||
@ -185,10 +172,18 @@ protected:
|
||||
|
||||
private:
|
||||
required_device<timer_device> m_cvsd_timer;
|
||||
required_device<mc3417_device> m_cvsd;
|
||||
required_device<filter_biquad_device> m_cvsd_filter;
|
||||
required_device<filter_biquad_device> m_cvsd_filter2;
|
||||
required_device<cpu_device> m_cvsdcpu;
|
||||
|
||||
TIMER_DEVICE_CALLBACK_MEMBER(cvsd_timer);
|
||||
void voiceio_w(offs_t offset, uint8_t data);
|
||||
uint8_t voiceio_r(offs_t offset);
|
||||
bool m_cvsd_clk;
|
||||
void cvsd_data_w(uint8_t data);
|
||||
|
||||
uint8_t m_cvsd_data;
|
||||
uint8_t m_cvsd_clk;
|
||||
|
||||
void cvsd_map(address_map &map);
|
||||
void cvsd_iomap(address_map &map);
|
||||
@ -196,6 +191,7 @@ private:
|
||||
|
||||
DECLARE_DEVICE_TYPE(EXIDY_MTRAP, mtrap_sound_device)
|
||||
|
||||
|
||||
class victory_sound_device : public exidy_sh8253_sound_device
|
||||
{
|
||||
public:
|
||||
@ -213,13 +209,15 @@ protected:
|
||||
virtual void device_add_mconfig(machine_config &config) override;
|
||||
|
||||
private:
|
||||
required_device<tms5220_device> m_tms;
|
||||
|
||||
void irq_clear_w(int state);
|
||||
void main_ack_w(int state);
|
||||
|
||||
void victory_audio_map(address_map &map);
|
||||
|
||||
// internal state
|
||||
uint8_t m_victory_sound_response_ack_clk; /* 7474 @ F4 */
|
||||
uint8_t m_sound_response_ack_clk; // 7474 @ F4
|
||||
|
||||
TIMER_CALLBACK_MEMBER(delayed_command_w);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user