diff options
Diffstat (limited to 'src/devices/sound/asc.cpp')
-rw-r--r-- | src/devices/sound/asc.cpp | 155 |
1 files changed, 90 insertions, 65 deletions
diff --git a/src/devices/sound/asc.cpp b/src/devices/sound/asc.cpp index d0a2c491679..347f9104649 100644 --- a/src/devices/sound/asc.cpp +++ b/src/devices/sound/asc.cpp @@ -4,11 +4,15 @@ asc.c - Apple Sound Chip (ASC) 344S0063 - Enhanced Apple Sound Chip (EASC) 343S1063 + Apple Sound Chip (ASC) 344S0053 (original), 344S0063 (cost-reduced) + Enhanced Apple Sound Chip (EASC) 343S1036 Emulation by R. Belmont + The four-voice wavetable mode is unique to the first-generation ASC. + EASC (which was codenamed "Batman") and other ASC clones remove it + entirely. + Registers: 0x800: VERSION 0x801: MODE (0=inactive, 1=FIFO mode, 2=wavetable mode) @@ -29,11 +33,15 @@ 0x828: WAVETABLE 3 PHASE 0x82C: WAVETABLE 3 INCREMENT + TODO: rewrite this, we know so much more now and the "chip variant type" pattern must die. + ***************************************************************************/ #include "emu.h" #include "asc.h" +#include "multibyte.h" + // device type definition DEFINE_DEVICE_TYPE(ASC, asc_device, "asc", "ASC") @@ -62,11 +70,11 @@ asc_device::asc_device(const machine_config &mconfig, const char *tag, device_t void asc_device::device_start() { // create the stream - m_stream = machine().sound().stream_alloc(*this, 0, 2, 22257); + m_stream = stream_alloc(0, 2, 22257); memset(m_regs, 0, sizeof(m_regs)); - m_timer = timer_alloc(0, nullptr); + m_timer = timer_alloc(FUNC(asc_device::delayed_stream_update), this); save_item(NAME(m_fifo_a_rdptr)); save_item(NAME(m_fifo_b_rdptr)); @@ -79,8 +87,6 @@ void asc_device::device_start() save_item(NAME(m_regs)); save_item(NAME(m_phase)); save_item(NAME(m_incr)); - - write_irq.resolve_safe(); } @@ -104,10 +110,10 @@ void asc_device::device_reset() } //------------------------------------------------- -// device_timer - called when our device timer expires +// delayed_stream_update - //------------------------------------------------- -void asc_device::device_timer(emu_timer &timer, device_timer_id tid, int param, void *ptr) +TIMER_CALLBACK_MEMBER(asc_device::delayed_stream_update) { m_stream->update(); } @@ -117,26 +123,32 @@ void asc_device::device_timer(emu_timer &timer, device_timer_id tid, int param, // our sound stream //------------------------------------------------- -void asc_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +void asc_device::sound_stream_update(sound_stream &stream) { - stream_sample_t *outL, *outR; int i, ch; static uint32_t wtoffs[2] = { 0, 0x200 }; - outL = outputs[0]; - outR = outputs[1]; - switch (m_regs[R_MODE-0x800] & 3) { case 0: // chip off - for (i = 0; i < samples; i++) + // IIvx/IIvi bootrom indicates VASP updates this flag even when the chip is off + if (m_chip_type == asc_type::VASP) { - outL[i] = outR[i] = 0; + if (m_fifo_cap_a < 0x1ff) + { + m_regs[R_FIFOSTAT-0x800] |= 1; // fifo A less than half full + + if (m_fifo_cap_a == 0) // fifo A fully empty + { + m_regs[R_FIFOSTAT-0x800] |= 2; // fifo A empty + } + } } break; case 1: // FIFO mode - for (i = 0; i < samples; i++) + { + for (i = 0; i < stream.samples(); i++) { int8_t smpll, smplr; @@ -193,8 +205,10 @@ void asc_device::sound_stream_update(sound_stream &stream, stream_sample_t **inp } break; - default: // V8/Sonora/Eagle/etc - if (m_fifo_cap_a < 0x1ff) + // Sonora sets the 1/2 full flag continuously, ASC/EASC only does it when it happens + case asc_type::SONORA: + case asc_type::ARDBEG: + if (m_fifo_cap_a <= 0x200) { m_regs[R_FIFOSTAT-0x800] |= 1; // fifo A less than half full @@ -202,32 +216,50 @@ void asc_device::sound_stream_update(sound_stream &stream, stream_sample_t **inp { m_regs[R_FIFOSTAT-0x800] |= 2; // fifo A empty } - write_irq(ASSERT_LINE); + if (!(m_regs[0xf09 - 0x800] & 1)) + { + write_irq(ASSERT_LINE); + } } - if (m_chip_type == asc_type::SONORA) + if (m_fifo_cap_b <= 0x200) { - if (m_fifo_cap_b < 0x1ff) - { - m_regs[R_FIFOSTAT-0x800] |= 4; // fifo B less than half full + m_regs[R_FIFOSTAT-0x800] |= 4; // fifo B less than half full - if (m_fifo_cap_b == 0) // fifo B fully empty - { - m_regs[R_FIFOSTAT-0x800] |= 8; // fifo B empty - } + if (m_fifo_cap_b == 0) // fifo B fully empty + { + m_regs[R_FIFOSTAT-0x800] |= 8; // fifo B empty + } + if (!(m_regs[0xf29 - 0x800] & 1)) + { write_irq(ASSERT_LINE); } } break; + + default: // V8/Eagle/etc + if (m_fifo_cap_a < 0x1ff) + { + m_regs[R_FIFOSTAT-0x800] |= 1; // fifo A less than half full + + if (m_fifo_cap_a == 0) // fifo A fully empty + { + m_regs[R_FIFOSTAT-0x800] |= 2; // fifo A empty + } + write_irq(ASSERT_LINE); + } + break; } - outL[i] = smpll * 64; - outR[i] = smplr * 64; + stream.put_int(0, i, smpll, 32768 / 64); + stream.put_int(1, i, smplr, 32768 / 64); } break; + } case 2: // wavetable mode - for (i = 0; i < samples; i++) + { + for (i = 0; i < stream.samples(); i++) { int32_t mixL, mixR; int8_t smpl; @@ -253,10 +285,11 @@ void asc_device::sound_stream_update(sound_stream &stream, stream_sample_t **inp mixR += smpl*256; } - outL[i] = mixL>>2; - outR[i] = mixR>>2; + stream.put_int(0, i, mixL, 32768 * 4); + stream.put_int(1, i, mixR, 32768 * 4); } break; + } } // printf("rdA %04x rdB %04x wrA %04x wrB %04x (capA %04x B %04x)\n", m_fifo_a_rdptr, m_fifo_b_rdptr, m_fifo_a_wrptr, m_fifo_b_wrptr, m_fifo_cap_a, m_fifo_cap_b); @@ -266,7 +299,7 @@ void asc_device::sound_stream_update(sound_stream &stream, stream_sample_t **inp // read - read from the chip's registers and internal RAM //------------------------------------------------- -READ8_MEMBER( asc_device::read ) +uint8_t asc_device::read(offs_t offset) { uint8_t rv; @@ -371,33 +404,17 @@ READ8_MEMBER( asc_device::read ) // WT inc/phase registers - rebuild from "live" copies" if ((offset >= 0x810) && (offset <= 0x82f)) { - m_regs[0x11] = m_phase[0]>>16; - m_regs[0x12] = m_phase[0]>>8; - m_regs[0x13] = m_phase[0]; - m_regs[0x15] = m_incr[0]>>16; - m_regs[0x16] = m_incr[0]>>8; - m_regs[0x17] = m_incr[0]; - - m_regs[0x19] = m_phase[1]>>16; - m_regs[0x1a] = m_phase[1]>>8; - m_regs[0x1b] = m_phase[1]; - m_regs[0x1d] = m_incr[1]>>16; - m_regs[0x1e] = m_incr[1]>>8; - m_regs[0x1f] = m_incr[1]; - - m_regs[0x21] = m_phase[2]>>16; - m_regs[0x22] = m_phase[2]>>8; - m_regs[0x23] = m_phase[2]; - m_regs[0x25] = m_incr[2]>>16; - m_regs[0x26] = m_incr[2]>>8; - m_regs[0x27] = m_incr[2]; - - m_regs[0x29] = m_phase[3]>>16; - m_regs[0x2a] = m_phase[3]>>8; - m_regs[0x2b] = m_phase[3]; - m_regs[0x2d] = m_incr[3]>>16; - m_regs[0x2e] = m_incr[3]>>8; - m_regs[0x2f] = m_incr[3]; + put_u24be(&m_regs[0x11], m_phase[0]); + put_u24be(&m_regs[0x15], m_incr[0]); + + put_u24be(&m_regs[0x19], m_phase[1]); + put_u24be(&m_regs[0x1d], m_incr[1]); + + put_u24be(&m_regs[0x21], m_phase[2]); + put_u24be(&m_regs[0x25], m_incr[2]); + + put_u24be(&m_regs[0x29], m_phase[3]); + put_u24be(&m_regs[0x2d], m_incr[3]); } if (offset >= 0x1000) @@ -412,7 +429,7 @@ READ8_MEMBER( asc_device::read ) // write - write to the chip's registers and internal RAM //------------------------------------------------- -WRITE8_MEMBER( asc_device::write ) +void asc_device::write(offs_t offset, uint8_t data) { //printf("ASC: write %02x to %x\n", data, offset); @@ -423,11 +440,16 @@ WRITE8_MEMBER( asc_device::write ) m_fifo_a[m_fifo_a_wrptr++] = data; m_fifo_cap_a++; - if (m_fifo_cap_a == 0x3ff) + if (m_fifo_cap_a == 0x400) { m_regs[R_FIFOSTAT-0x800] |= 2; // fifo A full } + if (m_fifo_cap_a > 0x200) + { + m_regs[R_FIFOSTAT-0x800] &= ~1; + } + m_fifo_a_wrptr &= 0x3ff; } else @@ -442,11 +464,16 @@ WRITE8_MEMBER( asc_device::write ) m_fifo_b[m_fifo_b_wrptr++] = data; m_fifo_cap_b++; - if (m_fifo_cap_b == 0x3ff) + if (m_fifo_cap_b == 0x400) { m_regs[R_FIFOSTAT-0x800] |= 8; // fifo B full } + if (m_fifo_cap_b > 0x200) + { + m_regs[R_FIFOSTAT-0x800] &= ~4; + } + m_fifo_b_wrptr &= 0x3ff; } else @@ -464,8 +491,6 @@ WRITE8_MEMBER( asc_device::write ) case R_MODE: data &= 3; // only bits 0 and 1 can be written - //printf("%d to MODE\n", data); - if (data != m_regs[R_MODE-0x800]) { m_fifo_a_rdptr = m_fifo_b_rdptr = 0; |