From 894101893997c8cc4149c417132f3a8eec6696cf Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Tue, 28 Sep 2010 07:54:25 +0000 Subject: [PATCH] Synced asc sound device from MESS (no whatsnew) R.B. sorry for this, was afraid it could be forgotten to be synced. --- src/emu/sound/asc.c | 464 ++++++++++++++++++++++++++++++++++++++++++-- src/emu/sound/asc.h | 55 ++++-- 2 files changed, 487 insertions(+), 32 deletions(-) diff --git a/src/emu/sound/asc.c b/src/emu/sound/asc.c index 312d3cf0948..ead09e83ef0 100644 --- a/src/emu/sound/asc.c +++ b/src/emu/sound/asc.c @@ -4,23 +4,41 @@ Apple Sound Chip (ASC) 344S0063 Enhanced Apple Sound Chip (EASC) 343S1063 - + Emulation by R. Belmont + Registers: + 0x800: VERSION + 0x801: MODE (1=FIFO mode, 2=wavetable mode) + 0x802: CONTROL (bit 0=analog or PWM output, 1=stereo/mono, 7=processing time exceeded) + 0x803: FIFO MODE (bit 7=clear FIFO, bit 1="non-ROM companding", bit 0="ROM companding") + 0x804: FIFO IRQ STATUS (bit 0=ch A 1/2 full, 1=ch A full, 2=ch B 1/2 full, 3=ch B full) + 0x805: WAVETABLE CONTROL (bits 0-3 wavetables 0-3 start) + 0x806: VOLUME (bits 2-4 = 3 bit internal ASC volume, bits 5-7 = volume control sent to Sony sound chip) + 0x807: CLOCK RATE (0 = Mac 22257 Hz, 1 = undefined, 2 = 22050 Hz, 3 = 44100 Hz) + 0x80a: PLAY REC A + 0x80f: TEST (bits 6-7 = digital test, bits 4-5 = analog test) + 0x810: WAVETABLE 0 PHASE (big-endian 8.16 fixed-point, only 24 bits valid) + 0x814: WAVETABLE 0 INCREMENT (big-endian 8.16 fixed-point, only 24 bits valid) + 0x818: WAVETABLE 1 PHASE + 0x81C: WAVETABLE 1 INCREMENT + 0x820: WAVETABLE 2 PHASE + 0x824: WAVETABLE 2 INCREMENT + 0x828: WAVETABLE 3 PHASE + 0x82C: WAVETABLE 3 INCREMENT + ***************************************************************************/ #include "emu.h" #include "streams.h" #include "asc.h" - //************************************************************************** // GLOBAL VARIABLES //************************************************************************** const device_type ASC = asc_device_config::static_alloc_device_config; - //************************************************************************** // DEVICE CONFIGURATION //************************************************************************** @@ -36,6 +54,18 @@ void asc_device_config::static_set_type(device_config *device, int type) asc->m_type = type; } +//------------------------------------------------- +// static_set_type - configuration helper to set +// the IRQ callback +//------------------------------------------------- + + +void asc_device_config::static_set_irqf(device_config *device, void (*irqf)(running_device *device, int state)) +{ + asc_device_config *asc = downcast(device); + asc->m_irq_func = irqf; +} + //------------------------------------------------- // asc_device_config - constructor //------------------------------------------------- @@ -79,7 +109,8 @@ asc_device::asc_device(running_machine &_machine, const asc_device_config &confi : device_t(_machine, config), device_sound_interface(_machine, config, *this), m_config(config), - m_chip_type(m_config.m_type) + m_chip_type(m_config.m_type), + m_irq_cb(m_config.m_irq_func) { } @@ -92,6 +123,8 @@ void asc_device::device_start() { // create the stream m_stream = stream_create(this, 0, 2, 22257, this, static_stream_generate); + + memset(m_regs, 0, sizeof(m_regs)); } @@ -102,6 +135,17 @@ void asc_device::device_start() void asc_device::device_reset() { stream_update(m_stream); + + memset(m_regs, 0, sizeof(m_regs)); + memset(m_fifo_a, 0, sizeof(m_fifo_a)); + memset(m_fifo_b, 0, sizeof(m_fifo_b)); + memset(m_phase, 0, sizeof(m_phase)); + memset(m_incr, 0, sizeof(m_incr)); + memset(m_fifo_a_wrhalf, 0, sizeof(m_fifo_a_wrhalf)); + memset(m_fifo_b_wrhalf, 0, sizeof(m_fifo_b_wrhalf)); + + m_fifo_a_rdptr = m_fifo_b_rdptr = 0; + m_fifo_a_wrptr = m_fifo_b_wrptr = 0; } //------------------------------------------------- @@ -116,8 +160,113 @@ STREAM_UPDATE( asc_device::static_stream_generate ) void asc_device::stream_generate(stream_sample_t **inputs, stream_sample_t **outputs, int samples) { - // reset the output stream - memset(outputs[0], 0, samples * sizeof(*outputs[0])); + stream_sample_t *outL, *outR; + int i, ch, halt = 0; + static UINT32 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++) + { + outL[i] = outR[i] = 0; + } + break; + + case 1: // FIFO mode + if ((m_fifo_a_rdptr == 0) && (!m_fifo_a_wrhalf[0])) + { + halt = 1; + } + else if ((m_fifo_a_rdptr == 0x200) && (!m_fifo_a_wrhalf[1])) + { + halt = 1; + } + + for (i = 0; i < samples; i++) + { + INT8 smpll, smplr; + + if (m_fifo_a_rdptr < 0x200) + { + m_fifo_a_wrhalf[0] = 0; + m_fifo_b_wrhalf[0] = 0; + } + else + { + m_fifo_a_wrhalf[1] = 0; + m_fifo_b_wrhalf[1] = 0; + } + + smpll = (INT8)m_fifo_a[m_fifo_a_rdptr++]^0x80; + smplr = (INT8)m_fifo_b[m_fifo_b_rdptr++]^0x80; + + if ((m_fifo_a_rdptr == 0x200) || (m_fifo_a_rdptr == 0x400)) + { + m_regs[R_FIFOSTAT-0x800] |= 1; // fifo A half-empty + if (m_irq_cb) + { + m_irq_cb(this, 1); + } + } + + if ((m_fifo_b_rdptr == 0x200) || (m_fifo_b_rdptr == 0x400)) + { + m_regs[R_FIFOSTAT-0x800] |= 4; // fifo B half-empty + if (m_irq_cb) + { + m_irq_cb(this, 1); + } + } + + m_fifo_a_rdptr &= 0x3ff; + m_fifo_b_rdptr &= 0x3ff; + + outL[i] = smpll * 64; + outR[i] = smplr * 64; + } + + if (halt) + { +// m_regs[R_MODE-0x800] = 0; + } + break; + + case 2: // wavetable mode + for (i = 0; i < samples; i++) + { + INT32 mixL, mixR; + INT8 smpl; + + mixL = mixR = 0; + + // update channel pointers + for (ch = 0; ch < 4; ch++) + { + m_phase[ch] += m_incr[ch]; + + if (ch < 2) + { + smpl = (INT8)m_fifo_a[((m_phase[ch]>>16)&0x1ff) + wtoffs[ch&1]]; + } + else + { + smpl = (INT8)m_fifo_b[((m_phase[ch]>>16)&0x1ff) + wtoffs[ch&1]]; + } + + smpl ^= 0x80; + mixL += smpl*256; + mixR += smpl*256; + } + + outL[i] = mixL>>2; + outR[i] = mixR>>2; + } + break; + } } //------------------------------------------------- @@ -126,40 +275,92 @@ void asc_device::stream_generate(stream_sample_t **inputs, stream_sample_t **out UINT8 asc_device::read(UINT16 offset) { + UINT8 rv; + +// printf("ASC: read at %x\n", offset); + + // not sure what actually happens when the CPU reads the FIFO... if (offset < 0x400) { - return fifo_a[offset]; + return m_fifo_a[offset]; } else if (offset < 0x800) { - return fifo_b[offset-0x400]; + return m_fifo_b[offset-0x400]; } else { + stream_update(m_stream); switch (offset) { - case 0x800: // VERSION + case R_VERSION: switch (m_chip_type) { case ASC_TYPE_ASC: return 0; case ASC_TYPE_V8: + case ASC_TYPE_EAGLE: + case ASC_TYPE_SPICE: + case ASC_TYPE_VASP: return 0xe8; case ASC_TYPE_SONORA: return 0xbc; - default: - return 0; + default: // return the actual register value + break; } break; - case 0x804: // FIFO Interrupt Status + case R_MODE: + switch (m_chip_type) + { + case ASC_TYPE_V8: + case ASC_TYPE_EAGLE: + case ASC_TYPE_SPICE: + case ASC_TYPE_VASP: + return 1; + + default: + break; + } + break; + + case R_CONTROL: + switch (m_chip_type) + { + case ASC_TYPE_V8: + case ASC_TYPE_EAGLE: + case ASC_TYPE_SPICE: + case ASC_TYPE_VASP: + return 1; + + default: + break; + } + break; + + case R_FIFOSTAT: if (m_chip_type == ASC_TYPE_V8) { - return 3; + rv = 3; } + else + { + rv = m_regs[R_FIFOSTAT-0x800]; + } + + // reading this register clears all bits + m_regs[R_FIFOSTAT-0x800] = 0; + + // reading this clears interrupts? + if (m_irq_cb) + { + m_irq_cb(this, 0); + } + + return rv; break; default: @@ -167,7 +368,39 @@ UINT8 asc_device::read(UINT16 offset) } } - return regs[offset-0x800]; + // 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]; + } + + return m_regs[offset-0x800]; } //------------------------------------------------- @@ -176,17 +409,212 @@ UINT8 asc_device::read(UINT16 offset) void asc_device::write(UINT16 offset, UINT8 data) { +// printf("ASC: write %02x to %x\n", data, offset); + if (offset < 0x400) { - fifo_a[offset] = data; + if (m_regs[R_MODE-0x800] == 1) + { + if (m_fifo_a_wrptr < 0x400) + { + m_fifo_a_wrhalf[0] = 1; + } + else + { + m_fifo_a_wrhalf[1] = 1; + } + + m_fifo_a[m_fifo_a_wrptr++] = data; + + if ((m_fifo_a_wrptr == 0x200) || (m_fifo_a_wrptr == 0x400)) + { + m_regs[R_FIFOSTAT-0x800] |= 2; // fifo A half-full + if (m_irq_cb) + { + m_irq_cb(this, 1); + } + } + + m_fifo_a_wrptr &= 0x3ff; + } + else + { + m_fifo_a[offset] = data; + } } else if (offset < 0x800) { - fifo_b[offset-0x400] = data; + if (m_regs[R_MODE-0x800] == 1) + { + if (m_fifo_b_wrptr < 0x400) + { + m_fifo_b_wrhalf[0] = 1; + } + else + { + m_fifo_b_wrhalf[1] = 1; + } + + m_fifo_b[m_fifo_b_wrptr++] = data; + + if ((m_fifo_a_wrptr == 0x200) || (m_fifo_a_wrptr == 0x400)) + { + m_regs[R_FIFOSTAT-0x800] |= 8; // fifo B half-full + if (m_irq_cb) + { + m_irq_cb(this, 1); + } + } + + m_fifo_b_wrptr &= 0x3ff; + } + else + { + m_fifo_b[offset-0x400] = data; + } } else { - regs[offset-0x800] = data; +// printf("ASC: %02x to %x (was %x)\n", data, offset, m_regs[offset-0x800]); + + stream_update(m_stream); + switch (offset) + { + case R_MODE: + data &= 3; // only bits 0 and 1 can be written + + memset(m_fifo_a_wrhalf, 0, sizeof(m_fifo_a_wrhalf)); + memset(m_fifo_b_wrhalf, 0, sizeof(m_fifo_b_wrhalf)); + + m_fifo_a_rdptr = m_fifo_b_rdptr = 0; + m_fifo_a_wrptr = m_fifo_b_wrptr = 0; + break; + + case R_WTCONTROL: +// printf("One-shot wavetable %02x\n", data); + break; + + case 0x811: + m_phase[0] &= 0x00ffff; + m_phase[0] |= data<<16; + break; + + case 0x812: + m_phase[0] &= 0xff00ff; + m_phase[0] |= data<<8; + break; + + case 0x813: + m_phase[0] &= 0xffff00; + m_phase[0] |= data; + break; + + case 0x815: + m_incr[0] &= 0x00ffff; + m_incr[0] |= data<<16; + break; + + case 0x816: + m_incr[0] &= 0xff00ff; + m_incr[0] |= data<<8; + break; + + case 0x817: + m_incr[0] &= 0xffff00; + m_incr[0] |= data; + break; + + case 0x819: + m_phase[1] &= 0x00ffff; + m_phase[1] |= data<<16; + break; + + case 0x81a: + m_phase[1] &= 0xff00ff; + m_phase[1] |= data<<8; + break; + + case 0x81b: + m_phase[1] &= 0xffff00; + m_phase[1] |= data; + break; + + case 0x81d: + m_incr[1] &= 0x00ffff; + m_incr[1] |= data<<16; + break; + + case 0x81e: + m_incr[1] &= 0xff00ff; + m_incr[1] |= data<<8; + break; + + case 0x81f: + m_incr[1] &= 0xffff00; + m_incr[1] |= data; + break; + + case 0x821: + m_phase[2] &= 0x00ffff; + m_phase[2] |= data<<16; + break; + + case 0x822: + m_phase[2] &= 0xff00ff; + m_phase[2] |= data<<8; + break; + + case 0x823: + m_phase[2] &= 0xffff00; + m_phase[2] |= data; + break; + + case 0x825: + m_incr[2] &= 0x00ffff; + m_incr[2] |= data<<16; + break; + + case 0x826: + m_incr[2] &= 0xff00ff; + m_incr[2] |= data<<8; + break; + + case 0x827: + m_incr[2] &= 0xffff00; + m_incr[2] |= data; + break; + + case 0x829: + m_phase[3] &= 0x00ffff; + m_phase[3] |= data<<16; + break; + + case 0x82a: + m_phase[3] &= 0xff00ff; + m_phase[3] |= data<<8; + break; + + case 0x82b: + m_phase[3] &= 0xffff00; + m_phase[3] |= data; + break; + + case 0x82d: + m_incr[3] &= 0x00ffff; + m_incr[3] |= data<<16; + break; + + case 0x82e: + m_incr[3] &= 0xff00ff; + m_incr[3] |= data<<8; + break; + + case 0x82f: + m_incr[3] &= 0xffff00; + m_incr[3] |= data; + break; + } + + m_regs[offset-0x800] = data; } } - diff --git a/src/emu/sound/asc.h b/src/emu/sound/asc.h index d86dc978575..11097596c1e 100644 --- a/src/emu/sound/asc.h +++ b/src/emu/sound/asc.h @@ -39,17 +39,21 @@ enum // INTERFACE CONFIGURATION MACROS //************************************************************************** -#define MDRV_ASC_ADD(_tag, _clock, _type) \ +#define MDRV_ASC_ADD(_tag, _clock, _type, _irqf) \ MDRV_DEVICE_ADD(_tag, ASC, _clock) \ - MDRV_ASC_TYPE(_type) + MDRV_ASC_TYPE(_type) \ + MDRV_IRQ_FUNC(_irqf) -#define MDRV_ASC_REPLACE(_tag, _clock, _type) \ +#define MDRV_ASC_REPLACE(_tag, _clock, _type, _irqf) \ MDRV_DEVICE_REPLACE(_tag, ASC, _clock) \ - MDRV_ASC_TYPE(_type) + MDRV_ASC_TYPE(_type) \ + MDRV_IRQ_FUNC(_irqf) #define MDRV_ASC_TYPE(_type) \ asc_device_config::static_set_type(device, _type); \ +#define MDRV_IRQ_FUNC(_irqf) \ + asc_device_config::static_set_irqf(device, _irqf); \ //************************************************************************** @@ -72,16 +76,12 @@ public: // inline configuration helpers static void static_set_type(device_config *device, int type); + static void static_set_irqf(device_config *device, void (*irqf)(running_device *device, int state)); protected: - // device_config overrides - virtual const address_space_config *memory_space_config(int spacenum = 0) const; - - // internal state - const address_space_config m_space_config; - // inline data - UINT8 m_type; + UINT8 m_type; + void (*m_irq_func)(running_device *device, int state); }; @@ -100,6 +100,26 @@ public: void write(UINT16 offset, UINT8 data); protected: + enum + { + R_VERSION = 0x800, + R_MODE, + R_CONTROL, + R_FIFOMODE, + R_FIFOSTAT, + R_WTCONTROL, + R_VOLUME, + R_CLOCK, + R_REG8, + R_REG9, + R_PLAYRECA, + R_REGB, + R_REGC, + R_REGD, + R_REGE, + R_TEST + }; + // device-level overrides virtual void device_start(); virtual void device_reset(); @@ -112,12 +132,19 @@ protected: const asc_device_config &m_config; UINT8 m_chip_type; + void (*m_irq_cb)(running_device *device, int state); sound_stream *m_stream; - UINT8 fifo_a[0x400]; - UINT8 fifo_b[0x400]; + UINT8 m_fifo_a[0x400]; + UINT8 m_fifo_b[0x400]; - UINT8 regs[0x100]; + UINT8 m_regs[0x100]; + + UINT32 m_phase[4], m_incr[4]; + + int m_fifo_a_rdptr, m_fifo_b_rdptr; + int m_fifo_a_wrptr, m_fifo_b_wrptr; + int m_fifo_a_wrhalf[2], m_fifo_b_wrhalf[2]; };