furnace/extern/vgsound_emu-modified/vgsound_emu/src/n163/n163.cpp

121 lines
2.6 KiB
C++

/*
License: Zlib
see https://gitlab.com/cam900/vgsound_emu/-/blob/main/LICENSE for more details
Copyright holder(s): cam900
Namco 163 Sound emulation core
*/
#include "n163.hpp"
void n163_core::tick()
{
if (m_multiplex)
{
m_out = 0;
}
// 0xe000-0xe7ff Disable sound bits (bit 6, bit 0 to 5 are CPU ROM Bank
// 0x8000-0x9fff select.)
if (m_disable)
{
if (!m_multiplex)
{
m_out = 0;
}
return;
}
// tick per each clock
const u32 freq = m_ram[m_voice_cycle + 0] | (u32(m_ram[m_voice_cycle + 2]) << 8) |
(bitfield<u32>(m_ram[m_voice_cycle + 4], 0, 2) << 16); // 18 bit frequency
u32 accum = m_ram[m_voice_cycle + 1] | (u32(m_ram[m_voice_cycle + 3]) << 8) |
(u32(m_ram[m_voice_cycle + 5]) << 16); // 24 bit accumulator
const u16 length = 256 - (m_ram[m_voice_cycle + 4] & 0xfc);
const u8 addr = m_ram[m_voice_cycle + 6] + bitfield(accum, 16, 8);
const s16 wave = (bitfield(m_ram[bitfield(addr, 1, 7)], bitfield(addr, 0) << 2, 4) - 8);
const s16 volume = bitfield(m_ram[m_voice_cycle + 7], 0, 4);
// get per-voice output
const s16 voice_out = (wave * volume);
m_voice_out[(m_voice_cycle >> 3) & 7] = voice_out;
// accumulate address
accum = bitfield(accum + freq, 0, 24);
if (bitfield(accum, 16, 8) >= length)
{
accum = bitfield(accum, 0, 18);
}
// writeback to register
m_ram[m_voice_cycle + 1] = bitfield(accum, 0, 8);
m_ram[m_voice_cycle + 3] = bitfield(accum, 8, 8);
m_ram[m_voice_cycle + 5] = bitfield(accum, 16, 8);
// update voice cycle
bool flush = m_multiplex ? true : false;
m_voice_cycle -= 0x8;
if (m_voice_cycle < (0x78 - (bitfield(m_ram[0x7f], 4, 3) << 3)))
{
if (!m_multiplex)
{
flush = true;
}
m_voice_cycle = 0x78;
}
// output 4 bit waveform and volume, multiplexed
m_acc += voice_out;
if (flush)
{
m_out = m_acc / (m_multiplex ? 1 : (bitfield(m_ram[0x7f], 4, 3) + 1));
m_acc = 0;
}
}
void n163_core::reset()
{
// reset this chip
m_disable = false;
m_multiplex = true;
std::fill(m_ram.begin(), m_ram.end(), 0);
m_voice_cycle = 0x78;
m_addr_latch.reset();
m_out = 0;
m_acc = 0;
}
// accessor
void n163_core::addr_w(u8 data)
{
// 0xf800-0xffff Sound address, increment
m_addr_latch.write(data);
}
void n163_core::data_w(u8 data, bool cpu_access)
{
// 0x4800-0x4fff Sound data write
m_ram[m_addr_latch.addr()] = data;
// address latch increment
if (cpu_access && m_addr_latch.incr())
{
m_addr_latch.addr_inc();
}
}
u8 n163_core::data_r(bool cpu_access)
{
// 0x4800-0x4fff Sound data read
const u8 ret = m_ram[m_addr_latch.addr()];
// address latch increment
if (cpu_access && m_addr_latch.incr())
{
m_addr_latch.addr_inc();
}
return ret;
}