summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/sound/asc.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/sound/asc.cpp')
-rw-r--r--src/devices/sound/asc.cpp155
1 files changed, 93 insertions, 62 deletions
diff --git a/src/devices/sound/asc.cpp b/src/devices/sound/asc.cpp
index 69d4c384f3a..231e6b2357f 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,38 @@ 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, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
- stream_sample_t *outL, *outR;
int i, ch;
static uint32_t wtoffs[2] = { 0, 0x200 };
- outL = outputs[0];
- outR = outputs[1];
+ auto &outL = outputs[0];
+ auto &outR = outputs[1];
switch (m_regs[R_MODE-0x800] & 3)
{
case 0: // chip off
- for (i = 0; i < samples; i++)
+ outL.fill(0);
+ outR.fill(0);
+
+ // 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 < outL.samples(); i++)
{
int8_t smpll, smplr;
@@ -193,8 +211,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 +222,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;
+ outL.put_int(i, smpll, 32768 / 64);
+ outR.put_int(i, smplr, 32768 / 64);
}
break;
+ }
case 2: // wavetable mode
- for (i = 0; i < samples; i++)
+ {
+ for (i = 0; i < outL.samples(); i++)
{
int32_t mixL, mixR;
int8_t smpl;
@@ -253,10 +291,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;
+ outL.put_int(i, mixL, 32768 * 4);
+ outR.put_int(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);
@@ -371,33 +410,17 @@ uint8_t asc_device::read(offs_t offset)
// 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)
@@ -423,11 +446,16 @@ void asc_device::write(offs_t offset, uint8_t data)
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 +470,16 @@ void asc_device::write(offs_t offset, uint8_t data)
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 +497,6 @@ void asc_device::write(offs_t offset, uint8_t data)
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;