summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/sound/aica.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/sound/aica.cpp')
-rw-r--r--src/devices/sound/aica.cpp147
1 files changed, 64 insertions, 83 deletions
diff --git a/src/devices/sound/aica.cpp b/src/devices/sound/aica.cpp
index 7143a116490..bb6cc9de495 100644
--- a/src/devices/sound/aica.cpp
+++ b/src/devices/sound/aica.cpp
@@ -14,7 +14,14 @@
- Some minor other tweeks (no EGHOLD, slighly more capable DSP)
TODO:
+ - Convert I/O registers to space addresses;
- Timebases are based on 44100KHz case?
+ - Derive from SCSP device;
+ - Sound clips a bit too much (cfr. deathcox, bdrdown, samba title screen, cfield).
+ According to skmp note: "The [ADX] sound decompression code on the sh4 uses FTRC
+ (float -> int) to convert the samples. Make sure you saturate the value when converting"
+ -> Verify this statement.
+
*/
#include "emu.h"
@@ -22,8 +29,8 @@
#include <algorithm>
-static constexpr s32 clip16(int x) { return std::min(32767, std::max(-32768, x)); }
-static constexpr s32 clip18(int x) { return std::min(131071, std::max(-131072, x)); }
+static constexpr s32 clip16(int x) { return std::clamp(x, -32768, 32767); }
+static constexpr s32 clip18(int x) { return std::clamp(x, -131072, 131071); }
#define SHIFT 12
#define FIX(v) ((u32)((float)(1 << SHIFT) * (v)))
@@ -84,8 +91,8 @@ static constexpr s32 clip18(int x) { return std::min(131071, std::max(-131072, x
#define DISDL(slot) ((slot->udata.data[0x24 / 2] >> 0x8) & 0x000F)
#define DIPAN(slot) (MONO() ? 0 : ((slot->udata.data[0x24 / 2] >> 0x0) & 0x001F))
-#define EFSDL(slot) ((m_EFSPAN[slot * 4] >> 8) & 0x000f)
-#define EFPAN(slot) (MONO() ? 0 : ((m_EFSPAN[slot * 4] >> 0) & 0x001f))
+#define EFSDL(slot) ((m_EFSPAN[slot] >> 8) & 0x000f)
+#define EFPAN(slot) (MONO() ? 0 : ((m_EFSPAN[slot] >> 0) & 0x001f))
//Unimplemented
#define Q(slot) ((slot->udata.data[0x28 / 2] >> 0x0) & 0x001F) // (0.75 × register value - 3)
@@ -435,11 +442,11 @@ void aica_device::Init()
m_MidiR = m_MidiW = 0;
m_MidiOutR = m_MidiOutW = 0;
- m_DSP.space = m_data;
- m_DSP.cache = m_cache;
- m_timerA = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(aica_device::timerA_cb), this));
- m_timerB = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(aica_device::timerB_cb), this));
- m_timerC = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(aica_device::timerC_cb), this));
+ space().specific(m_DSP.space);
+ space().cache(m_DSP.cache);
+ m_timerA = timer_alloc(FUNC(aica_device::timerA_cb), this);
+ m_timerB = timer_alloc(FUNC(aica_device::timerB_cb), this);
+ m_timerC = timer_alloc(FUNC(aica_device::timerC_cb), this);
for (i = 0; i < 0x400; ++i)
{
@@ -655,7 +662,7 @@ void aica_device::UpdateReg(int reg)
case 0x90:
case 0x91:
- if (!m_irq_cb.isnull())
+ if (!m_irq_cb.isunset())
{
u32 time;
@@ -674,7 +681,7 @@ void aica_device::UpdateReg(int reg)
break;
case 0x94:
case 0x95:
- if (!m_irq_cb.isnull())
+ if (!m_irq_cb.isunset())
{
u32 time;
@@ -693,7 +700,7 @@ void aica_device::UpdateReg(int reg)
break;
case 0x98:
case 0x99:
- if (!m_irq_cb.isnull())
+ if (!m_irq_cb.isunset())
{
u32 time;
@@ -720,7 +727,7 @@ void aica_device::UpdateReg(int reg)
case 0xa4: //SCIRE
case 0xa5:
- if (!m_irq_cb.isnull())
+ if (!m_irq_cb.isunset())
{
m_udata.data[0xa0 / 2] &= ~m_udata.data[0xa4 / 2];
ResetInterrupts();
@@ -747,7 +754,7 @@ void aica_device::UpdateReg(int reg)
case 0xad:
case 0xb0:
case 0xb1:
- if (!m_irq_cb.isnull())
+ if (!m_irq_cb.isunset())
{
m_IrqTimA = DecodeSCI(SCITMA);
m_IrqTimBC = DecodeSCI(SCITMB);
@@ -810,6 +817,7 @@ void aica_device::UpdateRegR(int reg)
u16 LP;
if (!(AFSEL()))
{
+ // AEG monitor
LP = slot->lpend ? 0x8000 : 0x0000;
slot->lpend = 0;
u16 SGC = (slot->EG.state << 13) & 0x6000;
@@ -822,7 +830,9 @@ void aica_device::UpdateRegR(int reg)
}
else
{
+ // FEG monitor
LP = slot->lpend ? 0x8000 : 0x0000;
+ // TODO: no EG monitoring? Documentation suggests otherwise
m_udata.data[0x10 / 2] = LP;
}
}
@@ -834,19 +844,10 @@ void aica_device::UpdateRegR(int reg)
//m_stream->update();
int slotnum = MSLC();
AICA_SLOT *slot = m_Slots + slotnum;
- u32 CA;
-
- if (PCMS(slot) == 0) // 16-bit samples
- {
- CA = (slot->cur_addr >> (SHIFT - 1)) & ~1;
- }
- else // 8-bit PCM and 4-bit ADPCM
- {
- CA = (slot->cur_addr >> SHIFT);
- }
-
- //printf("%08x %08x\n",CA,slot->cur_addr & ~1);
-
+ // NB: despite previous implementation this does not depend on PCMS setting.
+ // Was "CA = (slot->cur_addr >> (SHIFT - 1)) & ~1;" on 16-bit path,
+ // causing repeated samples/hangs in several ADX driven entries.
+ u32 CA = (slot->cur_addr >> SHIFT);
m_udata.data[0x14 / 2] = CA;
}
break;
@@ -873,7 +874,7 @@ void aica_device::w16(u32 addr,u16 val)
if (addr <= 0x2044)
{
// printf("%x to EFSxx slot %d (addr %x)\n", val, (addr - 0x2000)/4, addr & 0x7f);
- m_EFSPAN[addr & 0x7f] = val;
+ m_EFSPAN[(addr & 0x7f) >> 2] = val;
}
}
else if (addr < 0x3000)
@@ -913,7 +914,12 @@ void aica_device::w16(u32 addr,u16 val)
else if (addr < 0x3300)
*((u16 *)(m_DSP.MADRS+(addr - 0x3200) / 2)) = val;
else if (addr < 0x3400)
- popmessage("AICADSP write to undocumented reg %04x -> %04x", addr, val);
+ {
+ // 3300-fc zapped along with the full 0x3000-0x3bfc range,
+ // most likely done by the SDK for convenience in resetting DSP in one go.
+ if (val)
+ logerror("%s: AICADSP write to undocumented reg %04x -> %04x\n", machine().describe_context(), addr, val);
+ }
else if (addr < 0x3c00)
{
*((u16 *)(m_DSP.MPRO+(addr - 0x3400) / 2)) = val;
@@ -970,15 +976,16 @@ u16 aica_device::r16(u32 addr)
{
if (addr <= 0x2044)
{
- v = m_EFSPAN[addr & 0x7f];
+ v = m_EFSPAN[(addr & 0x7f) >> 2];
}
else if (addr < 0x2800)
- popmessage("AICA read undocumented reg %04x", addr);
+ {
+ //logerror("%s: AICA read to undocumented reg %04x\n", machine().describe_context(), addr);
+ }
else if (addr < 0x28be)
{
UpdateRegR(addr & 0xff);
v= *((u16 *)(m_udata.datab+((addr & 0xff))));
- if ((addr & 0xfffe) == 0x2810) m_udata.data[0x10 / 2] &= 0x7FFF; // reset LP on read
}
else if (addr == 0x2d00)
{
@@ -997,11 +1004,15 @@ u16 aica_device::r16(u32 addr)
else if (addr < 0x3300)
v= *((u16 *)(m_DSP.MADRS+(addr - 0x3200) / 2));
else if (addr < 0x3400)
- popmessage("AICADSP read undocumented reg %04x", addr);
+ {
+ //logerror("%s: AICADSP read to undocumented reg %04x\n", machine().describe_context(), addr);
+ }
else if (addr < 0x3c00)
v= *((u16 *)(m_DSP.MPRO+(addr - 0x3400) / 2));
else if (addr < 0x4000)
- popmessage("AICADSP read undocumented reg %04x",addr);
+ {
+ //logerror("%s: AICADSP read to undocumented reg %04x\n", machine().describe_context(), addr);
+ }
else if (addr < 0x4400)
{
if (addr & 4)
@@ -1032,7 +1043,6 @@ u16 aica_device::r16(u32 addr)
}
-#ifdef UNUSED_FUNCTION
void aica_device::TimersAddTicks(int ticks)
{
if (m_TimCnt[0] <= 0xff00)
@@ -1071,7 +1081,6 @@ void aica_device::TimersAddTicks(int ticks)
m_udata.data[0x98 / 2] |= m_TimCnt[2] >> 8;
}
}
-#endif
s32 aica_device::UpdateSlot(AICA_SLOT *slot)
{
@@ -1112,8 +1121,8 @@ s32 aica_device::UpdateSlot(AICA_SLOT *slot)
if (PCMS(slot) == 1) // 8-bit signed
{
- s8 p1 = m_cache->read_byte(SA(slot) + addr1);
- s8 p2 = m_cache->read_byte(SA(slot) + addr2);
+ s8 p1 = m_cache.read_byte(SA(slot) + addr1);
+ s8 p2 = m_cache.read_byte(SA(slot) + addr2);
s32 s;
s32 fpart=slot->cur_addr & ((1 << SHIFT) - 1);
s = (int)(p1 << 8) * ((1 << SHIFT) - fpart) + (int)(p2 << 8) * fpart;
@@ -1121,8 +1130,8 @@ s32 aica_device::UpdateSlot(AICA_SLOT *slot)
}
else if (PCMS(slot) == 0) //16 bit signed
{
- s16 p1 = m_cache->read_word(SA(slot) + addr1);
- s16 p2 = m_cache->read_word(SA(slot) + addr2);
+ s16 p1 = m_cache.read_word(SA(slot) + addr1);
+ s16 p2 = m_cache.read_word(SA(slot) + addr2);
s32 s;
s32 fpart = slot->cur_addr & ((1 << SHIFT) - 1);
s = (int)(p1) * ((1 << SHIFT) - fpart) + (int)(p2) * fpart;
@@ -1142,7 +1151,7 @@ s32 aica_device::UpdateSlot(AICA_SLOT *slot)
while (curstep < steps_to_go)
{
int shift1 = 4 & (curstep << 2);
- u8 delta1 = (m_cache->read_byte(base) >> shift1) & 0xf;
+ u8 delta1 = (m_cache.read_byte(base) >> shift1) & 0xf;
DecodeADPCM(&(slot->cur_sample), delta1, &(slot->cur_quant));
if (!(++curstep & 1))
base++;
@@ -1188,8 +1197,6 @@ s32 aica_device::UpdateSlot(AICA_SLOT *slot)
StopSlot(slot,0);
}
break;
- // TODO: causes an hang in Border Down/Metal Slug 6/Karous etc.
- // for mslug6 culprit RAM address is 0x13880 ARM side (a flag that should be zeroed somehow)
case 1: //normal loop
if (*addr[addr_select] >= chanlea)
{
@@ -1229,17 +1236,11 @@ s32 aica_device::UpdateSlot(AICA_SLOT *slot)
return sample;
}
-void aica_device::DoMasterSamples(int nsamples)
+void aica_device::DoMasterSamples(std::vector<read_stream_view> const &inputs, write_stream_view &bufl, write_stream_view &bufr)
{
- stream_sample_t *exts[2];
int i;
- stream_sample_t *bufr = m_bufferr;
- stream_sample_t *bufl = m_bufferl;
- exts[0] = m_exts0;
- exts[1] = m_exts1;
-
- for (int s = 0; s < nsamples; ++s)
+ for (int s = 0; s < bufl.samples(); ++s)
{
s32 smpl = 0, smpr = 0;
@@ -1280,7 +1281,7 @@ void aica_device::DoMasterSamples(int nsamples)
{
if (EFSDL(i + 16)) // 16,17 for EXTS
{
- m_DSP.EXTS[i] = exts[i][s];
+ m_DSP.EXTS[i] = s16(inputs[i].get(s) * 32767.0);
u32 Enc = ((EFPAN(i + 16)) << 0x8) | ((EFSDL(i + 16)) << 0xd);
smpl += (m_DSP.EXTS[i] * m_LPANTABLE[Enc]) >> SHIFT;
smpr += (m_DSP.EXTS[i] * m_RPANTABLE[Enc]) >> SHIFT;
@@ -1298,8 +1299,9 @@ void aica_device::DoMasterSamples(int nsamples)
smpr = clip16(smpr >> 3);
}
- *bufl++ = (smpl * m_LPANTABLE[MVOL() << 0xd]) >> SHIFT;
- *bufr++ = (smpr * m_LPANTABLE[MVOL() << 0xd]) >> SHIFT;
+ bufl.put_int(s, smpl * m_LPANTABLE[MVOL() << 0xd], 32768 << SHIFT);
+ // TODO: diverges with SCSP, also wut?
+ bufr.put_int(s, smpr * m_LPANTABLE[MVOL() << 0xd], 32768 << SHIFT);
}
}
@@ -1329,7 +1331,7 @@ void aica_device::exec_dma()
{
for (i = 0; i < m_dma.dlg; i+=2)
{
- m_data->write_word(m_dma.dmea, 0);
+ m_data.write_word(m_dma.dmea, 0);
m_dma.dmea += 2;
}
}
@@ -1339,7 +1341,7 @@ void aica_device::exec_dma()
{
u16 tmp;
tmp = r16(m_dma.drga);
- m_data->write_word(m_dma.dmea, tmp);
+ m_data.write_word(m_dma.dmea, tmp);
m_dma.dmea += 4;
m_dma.drga += 4;
}
@@ -1359,7 +1361,7 @@ void aica_device::exec_dma()
{
for (i = 0; i < m_dma.dlg; i+=2)
{
- u16 tmp = m_cache->read_word(m_dma.dmea);
+ u16 tmp = m_cache.read_word(m_dma.dmea);
w16(m_dma.drga, tmp);
m_dma.dmea += 4;
m_dma.drga += 4;
@@ -1381,25 +1383,13 @@ void aica_device::exec_dma()
CheckPendingIRQ_SH4();
}
-#ifdef UNUSED_FUNCTION
-int aica_device::IRQCB(void *param)
-{
- CheckPendingIRQ(param);
- return -1;
-}
-#endif
-
//-------------------------------------------------
// sound_stream_update - handle a stream update
//-------------------------------------------------
-void aica_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples)
+void aica_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
- m_bufferl = outputs[0];
- m_bufferr = outputs[1];
- m_exts0 = inputs[0];
- m_exts1 = inputs[1];
- DoMasterSamples(samples);
+ DoMasterSamples(inputs, outputs[0], outputs[1]);
}
//-------------------------------------------------
@@ -1408,18 +1398,13 @@ void aica_device::sound_stream_update(sound_stream &stream, stream_sample_t **in
void aica_device::device_start()
{
- m_data = &space(0);
- // Find our direct access
- m_cache = space().cache<1, 0, ENDIANNESS_LITTLE>();
+ space().specific(m_data);
+ space().cache(m_cache);
// init the emulation
Init();
- // set up the IRQ callbacks
- m_irq_cb.resolve_safe();
- m_main_irq_cb.resolve_safe();
-
- m_stream = machine().sound().stream_alloc(*this, 2, 2, (int)m_rate);
+ m_stream = stream_alloc(2, 2, (int)m_rate);
// save state
save_item(NAME(m_udata.data));
@@ -1569,10 +1554,6 @@ aica_device::aica_device(const machine_config &mconfig, const char *tag, device_
, m_MidiR(0)
, m_mcieb(0)
, m_mcipd(0)
- , m_bufferl(nullptr)
- , m_bufferr(nullptr)
- , m_exts0(nullptr)
- , m_exts1(nullptr)
{
memset(&m_udata.data, 0, sizeof(m_udata.data));