diff options
Diffstat (limited to 'src/devices/sound/aica.cpp')
-rw-r--r-- | src/devices/sound/aica.cpp | 160 |
1 files changed, 69 insertions, 91 deletions
diff --git a/src/devices/sound/aica.cpp b/src/devices/sound/aica.cpp index 7143a116490..1e3eaac954e 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) @@ -429,26 +436,24 @@ void aica_device::StopSlot(AICA_SLOT *slot,int keyoff) void aica_device::Init() { - int i; - m_IrqTimA = m_IrqTimBC = m_IrqMidi = 0; 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) + for (int i = 0; i < 0x400; ++i) { float envDB = ((float)(3 * (i - 0x3ff))) / 32.0f; float scale = (float)(1 << SHIFT); m_EG_TABLE[i] = (s32)(powf(10.0f, envDB / 20.0f) * scale); } - for (i = 0; i < 0x20000; ++i) + for (int i = 0; i < 0x20000; ++i) { int iTL = (i >> 0x0) & 0xff; int iPAN = (i >> 0x8) & 0x1f; @@ -500,7 +505,7 @@ void aica_device::Init() m_ARTABLE[0] = m_DRTABLE[0] = 0; //Infinite time m_ARTABLE[1] = m_DRTABLE[1] = 0; //Infinite time - for (i=2; i < 64; ++i) + for (int i=2; i < 64; ++i) { double step,scale; double t = ARTimes[i]; //In ms @@ -521,7 +526,7 @@ void aica_device::Init() ClockChange(); // make sure all the slots are off - for (i = 0; i < 64; ++i) + for (int i = 0; i < 64; ++i) { m_Slots[i].slot = i; m_Slots[i].active = 0; @@ -655,7 +660,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 +679,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 +698,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 +725,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 +752,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 +815,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 +828,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 +842,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 +872,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 +912,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 +974,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 +1002,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 +1041,6 @@ u16 aica_device::r16(u32 addr) } -#ifdef UNUSED_FUNCTION void aica_device::TimersAddTicks(int ticks) { if (m_TimCnt[0] <= 0xff00) @@ -1071,7 +1079,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 +1119,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 +1128,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 +1149,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 +1195,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 +1234,11 @@ s32 aica_device::UpdateSlot(AICA_SLOT *slot) return sample; } -void aica_device::DoMasterSamples(int nsamples) +void aica_device::DoMasterSamples(sound_stream &stream) { - 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 < stream.samples(); ++s) { s32 smpl = 0, smpr = 0; @@ -1280,7 +1279,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(stream.get(i, 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 +1297,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; + stream.put_int(0, s, smpl * m_LPANTABLE[MVOL() << 0xd], 32768 << SHIFT); + // TODO: diverges with SCSP, also wut? + stream.put_int(1, s, smpr * m_LPANTABLE[MVOL() << 0xd], 32768 << SHIFT); } } @@ -1329,7 +1329,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 +1339,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 +1359,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 +1381,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) { - m_bufferl = outputs[0]; - m_bufferr = outputs[1]; - m_exts0 = inputs[0]; - m_exts1 = inputs[1]; - DoMasterSamples(samples); + DoMasterSamples(stream); } //------------------------------------------------- @@ -1408,18 +1396,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,11 +1552,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)); std::fill(std::begin(m_EFSPAN), std::end(m_EFSPAN), 0); @@ -1590,7 +1568,7 @@ aica_device::aica_device(const machine_config &mconfig, const char *tag, device_ std::fill(std::begin(m_ARTABLE), std::end(m_ARTABLE), 0); std::fill(std::begin(m_DRTABLE), std::end(m_DRTABLE), 0); - memset(&m_DSP, 0, sizeof(m_DSP)); + m_DSP.init(); std::fill(std::begin(m_EG_TABLE), std::end(m_EG_TABLE), 0); std::fill(std::begin(m_PLFO_TRI), std::end(m_PLFO_TRI), 0); |