Synced asc sound device from MESS (no whatsnew)

R.B. sorry for this, was afraid it could be forgotten to be synced.
This commit is contained in:
Miodrag Milanovic 2010-09-28 07:54:25 +00:00
parent 689a7d16d2
commit 8941018939
2 changed files with 487 additions and 32 deletions

View File

@ -4,23 +4,41 @@
Apple Sound Chip (ASC) 344S0063 Apple Sound Chip (ASC) 344S0063
Enhanced Apple Sound Chip (EASC) 343S1063 Enhanced Apple Sound Chip (EASC) 343S1063
Emulation by R. Belmont 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 "emu.h"
#include "streams.h" #include "streams.h"
#include "asc.h" #include "asc.h"
//************************************************************************** //**************************************************************************
// GLOBAL VARIABLES // GLOBAL VARIABLES
//************************************************************************** //**************************************************************************
const device_type ASC = asc_device_config::static_alloc_device_config; const device_type ASC = asc_device_config::static_alloc_device_config;
//************************************************************************** //**************************************************************************
// DEVICE CONFIGURATION // DEVICE CONFIGURATION
//************************************************************************** //**************************************************************************
@ -36,6 +54,18 @@ void asc_device_config::static_set_type(device_config *device, int type)
asc->m_type = 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<asc_device_config *>(device);
asc->m_irq_func = irqf;
}
//------------------------------------------------- //-------------------------------------------------
// asc_device_config - constructor // 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_t(_machine, config),
device_sound_interface(_machine, config, *this), device_sound_interface(_machine, config, *this),
m_config(config), 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 // create the stream
m_stream = stream_create(this, 0, 2, 22257, this, static_stream_generate); 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() void asc_device::device_reset()
{ {
stream_update(m_stream); 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) void asc_device::stream_generate(stream_sample_t **inputs, stream_sample_t **outputs, int samples)
{ {
// reset the output stream stream_sample_t *outL, *outR;
memset(outputs[0], 0, samples * sizeof(*outputs[0])); 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 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) if (offset < 0x400)
{ {
return fifo_a[offset]; return m_fifo_a[offset];
} }
else if (offset < 0x800) else if (offset < 0x800)
{ {
return fifo_b[offset-0x400]; return m_fifo_b[offset-0x400];
} }
else else
{ {
stream_update(m_stream);
switch (offset) switch (offset)
{ {
case 0x800: // VERSION case R_VERSION:
switch (m_chip_type) switch (m_chip_type)
{ {
case ASC_TYPE_ASC: case ASC_TYPE_ASC:
return 0; return 0;
case ASC_TYPE_V8: case ASC_TYPE_V8:
case ASC_TYPE_EAGLE:
case ASC_TYPE_SPICE:
case ASC_TYPE_VASP:
return 0xe8; return 0xe8;
case ASC_TYPE_SONORA: case ASC_TYPE_SONORA:
return 0xbc; return 0xbc;
default: default: // return the actual register value
return 0; break;
} }
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) 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; break;
default: 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) void asc_device::write(UINT16 offset, UINT8 data)
{ {
// printf("ASC: write %02x to %x\n", data, offset);
if (offset < 0x400) 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) 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 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;
} }
} }

View File

@ -39,17 +39,21 @@ enum
// INTERFACE CONFIGURATION MACROS // 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_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_DEVICE_REPLACE(_tag, ASC, _clock) \
MDRV_ASC_TYPE(_type) MDRV_ASC_TYPE(_type) \
MDRV_IRQ_FUNC(_irqf)
#define MDRV_ASC_TYPE(_type) \ #define MDRV_ASC_TYPE(_type) \
asc_device_config::static_set_type(device, _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 // inline configuration helpers
static void static_set_type(device_config *device, int type); 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: 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 // 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); void write(UINT16 offset, UINT8 data);
protected: 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 // device-level overrides
virtual void device_start(); virtual void device_start();
virtual void device_reset(); virtual void device_reset();
@ -112,12 +132,19 @@ protected:
const asc_device_config &m_config; const asc_device_config &m_config;
UINT8 m_chip_type; UINT8 m_chip_type;
void (*m_irq_cb)(running_device *device, int state);
sound_stream *m_stream; sound_stream *m_stream;
UINT8 fifo_a[0x400]; UINT8 m_fifo_a[0x400];
UINT8 fifo_b[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];
}; };