summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
author Olivier Galibert <galibert@pobox.com>2021-03-22 22:51:20 +0100
committer Olivier Galibert <galibert@pobox.com>2021-04-12 09:27:13 +0200
commitb59544c13ce0d2550a45c830050caee8b81ca7b9 (patch)
treedd521e944967046d6912649180a80cc30e0df5fe
parent22823416c10de513c899bf0ff55e5d5c829fdcd7 (diff)
swp30: Make the stream synchronous, add dummy-ish internal register read, more logging
-rw-r--r--src/devices/sound/swp30.cpp267
-rw-r--r--src/devices/sound/swp30.h5
-rw-r--r--src/mame/drivers/ymmu100.cpp70
3 files changed, 228 insertions, 114 deletions
diff --git a/src/devices/sound/swp30.cpp b/src/devices/sound/swp30.cpp
index aec573aa07a..e7ce8534993 100644
--- a/src/devices/sound/swp30.cpp
+++ b/src/devices/sound/swp30.cpp
@@ -6,6 +6,8 @@
#include "emu.h"
#include "swp30.h"
+static int scount = 0;
+
/*
The SWP30 is the combination of a rompler called AWM2 (Advanced Wave
Memory 2) and an effects DSP called MEG (Multiple Effects
@@ -52,7 +54,7 @@
25 bits address and 32 bits data wide. It applies four filters to
the sample data, two of fixed type (low pass then highpass) and two
free 3-point FIR filters (used for yet another lowpass and
- highpass). Envelopes are handled automatically, and the final
+ highpass). Envelopes are handled semi-automatically, and the final
panned result is sent to the mixer.
@@ -163,9 +165,9 @@ void swp30_device::device_add_mconfig(machine_config &config)
void swp30_device::device_start()
{
- m_stream = stream_alloc(0, 2, 44100);
+ m_stream = stream_alloc(0, 2, 44100, STREAM_SYNCHRONOUS);
- // Attenuantion for panning is 4.4 floating point. That means 0
+ // Attenuation for panning is 4.4 floating point. That means 0
// to -96.3dB. Since it's a nice range, we assume it's the same
// for other attenuation values. Computed value is 1.16
// format, to avoid overflow
@@ -226,6 +228,8 @@ void swp30_device::device_start()
save_item(NAME(m_eq_filter));
save_item(NAME(m_routing));
+ save_item(NAME(m_internal_adr));
+
save_item(NAME(m_program_address));
}
@@ -263,7 +267,7 @@ void swp30_device::device_reset()
void swp30_device::rom_bank_updated()
{
- m_stream->update();
+ // Nothing to do, stream is synchronous
}
void swp30_device::map(address_map &map)
@@ -306,7 +310,10 @@ void swp30_device::map(address_map &map)
// Control registers
// These appear as channel slots 0x0e and 0x0f
- // 00-0b missing
+ // 00-01 missing
+ rctrl(map, 0x02).rw(FUNC(swp30_device::internal_adr_r), FUNC(swp30_device::internal_adr_w));
+ rctrl(map, 0x03).r (FUNC(swp30_device::internal_r));
+ // 04-0b missing
rctrl(map, 0x0c).rw(FUNC(swp30_device::keyon_mask_r<3>), FUNC(swp30_device::keyon_mask_w<3>));
rctrl(map, 0x0d).rw(FUNC(swp30_device::keyon_mask_r<2>), FUNC(swp30_device::keyon_mask_w<2>));
rctrl(map, 0x0e).rw(FUNC(swp30_device::keyon_mask_r<1>), FUNC(swp30_device::keyon_mask_w<1>));
@@ -428,7 +435,7 @@ void swp30_device::lpf_cutoff_w(offs_t offset, u16 data)
{
m_stream->update();
u8 chan = offset >> 6;
- if(0 && m_lpf_cutoff[chan] != data)
+ if(1 || m_lpf_cutoff[chan] != data)
logerror("chan %02x lpf cutoff %04x\n", chan, data);
m_lpf_cutoff[chan] = data;
}
@@ -442,7 +449,7 @@ void swp30_device::lpf_cutoff_inc_w(offs_t offset, u16 data)
{
m_stream->update();
u8 chan = offset >> 6;
- if(0 && m_lpf_cutoff_inc[chan] != data)
+ if(1 || m_lpf_cutoff_inc[chan] != data)
logerror("chan %02x lpf cutoff increment %04x\n", chan, data);
m_lpf_cutoff_inc[chan] = data;
}
@@ -456,7 +463,7 @@ void swp30_device::hpf_cutoff_w(offs_t offset, u16 data)
{
m_stream->update();
u8 chan = offset >> 6;
- if(0 && m_hpf_cutoff[chan] != data)
+ if(1 || m_hpf_cutoff[chan] != data)
logerror("chan %02x hpf cutoff %04x\n", chan, data);
m_hpf_cutoff[chan] = data;
}
@@ -470,7 +477,7 @@ void swp30_device::lpf_reso_w(offs_t offset, u16 data)
{
m_stream->update();
u8 chan = offset >> 6;
- if(0 && m_lpf_reso[chan] != data)
+ if(1 || m_lpf_reso[chan] != data)
logerror("chan %02x lpf resonance %04x\n", chan, data);
m_lpf_reso[chan] = data;
}
@@ -583,7 +590,7 @@ template<int sel> void swp30_device::envelope_w(offs_t offset, u16 data)
u8 chan = offset >> 6;
bool ch = m_envelope[chan][sel] != data;
m_envelope[chan][sel] = data;
- if(0 && ch)
+ if(1 && ch)
logerror("snd chan %02x envelopes %04x %04x %04x\n", chan, m_envelope[chan][0], m_envelope[chan][1], m_envelope[chan][2]);
}
@@ -660,6 +667,52 @@ void swp30_device::address_l_w(offs_t offset, u16 data)
logerror("snd chan %02x format %s flags %02x address %06x\n", chan, formats[m_address[chan] >> 30], (m_address[chan] >> 24) & 0x3f, m_address[chan] & 0xffffff);
}
+u16 swp30_device::internal_adr_r()
+{
+ return m_internal_adr;
+}
+
+void swp30_device::internal_adr_w(u16 data)
+{
+ m_internal_adr = data;
+}
+
+u16 swp30_device::internal_r()
+{
+ u8 chan = m_internal_adr & 0x3f;
+ switch(m_internal_adr >> 8) {
+ case 0:
+ // used at d312
+ // r0 = [b15, b14, 0,0,0,0,0,0, !b13, !b12, !b11, !b10, !b9, !b8, 1, 1]
+ // voice[45] = (voice[4b] * r0l) >> 7 (unsigned)
+ // if(r0h == 0) voice[43] = 0xff
+ // else voice[43] = voice[51] - r0l; // 51 = inverse velocity
+ // if(r0l >= 0x80) ???
+ logerror("read %02x.0\n", chan);
+
+ // 3f -> active stays 2 until release where 1
+ // 7f, bf, ff -> active = 0 immediatly
+ return 0x0000 | 0x0000;
+
+ case 4:
+ // used at 44c4
+ // tests & 0x4000 only
+ logerror("read %02x.4\n", chan);
+ return 0x0000;
+
+ case 6:
+ // used at 3e7c
+ // tests & 0x8000 only, keyoff?
+ logerror("read %02x.6\n", chan);
+ return 0x0000;
+ }
+
+ logerror("%s internal_r port %x channel %02x sample %d\n", machine().time().to_string(), m_internal_adr >> 8, m_internal_adr & 0x1f, scount);
+ machine().debug_break();
+
+ return 0;
+}
+
// MEG registers forwarding
@@ -751,8 +804,8 @@ void swp30_device::snd_w(offs_t offset, u16 data)
preg = util::string_format("lf%02x", (slot-0x3e) + 2*chan);
else
preg = util::string_format("%02x.%02x", chan, slot);
- if((slot >= 0xa && slot <= 0xd) || (slot >= 0x2c && slot <= 0x2f))
- machine().debug_break();
+ // if((slot >= 0xa && slot <= 0xd) || (slot >= 0x2c && slot <= 0x2f))
+ // machine().debug_break();
logerror("snd_w [%04x %04x] %-5s, %04x\n", offset, offset*2, preg, data);
}
@@ -763,117 +816,117 @@ void swp30_device::snd_w(offs_t offset, u16 data)
void swp30_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
- // Loop first on the samples and not on the channels otherwise
- // effects will be annoying to implement.
-
- for(int sample = 0; sample < outputs[0].samples(); sample++) {
- // Accumulate on 64 bits, shift/clamp at the end
- s64 acc_left = 0, acc_right = 0;
-
- // Loop on channels
- for(int channel = 0; channel < 64; channel++)
- if(m_active_mask & (u64(1) << channel)) {
- // First, read the sample
-
- // - Find the base sample index and base address
- s32 spos = m_sample_pos[channel] >> 8;
- offs_t base_address = (m_address[channel] & 0x1ffffff) << 2;
- // - Read/decompress the sample
- s16 samp = 0;
- switch(m_address[channel] >> 30) {
- case 0: { // 16-bits linear
- offs_t adr = base_address + (spos << 1);
- samp = read_word(adr);
+ if(outputs[0].samples() != 1)
+ fatalerror("Sync stream not sync?\n");
+
+ scount++;
+
+ // Accumulate on 64 bits, shift/clamp at the end
+ s64 acc_left = 0, acc_right = 0;
+
+ // Loop on channels
+ for(int channel = 0; channel < 64; channel++)
+ if(m_active_mask & (u64(1) << channel)) {
+ // First, read the sample
+
+ // - Find the base sample index and base address
+ s32 spos = m_sample_pos[channel] >> 8;
+ offs_t base_address = (m_address[channel] & 0x1ffffff) << 2;
+ // - Read/decompress the sample
+ s16 samp = 0;
+ switch(m_address[channel] >> 30) {
+ case 0: { // 16-bits linear
+ offs_t adr = base_address + (spos << 1);
+ samp = read_word(adr);
+ break;
+ }
+
+ case 1: { // 12-bits linear
+ offs_t adr = base_address + (spos >> 2)*6;
+ switch(spos & 3) {
+ case 0: { // .abc .... ....
+ u16 w0 = read_word(adr);
+ samp = (w0 & 0x0fff) << 4;
break;
}
-
- case 1: { // 12-bits linear
- offs_t adr = base_address + (spos >> 2)*6;
- switch(spos & 3) {
- case 0: { // .abc .... ....
- u16 w0 = read_word(adr);
- samp = (w0 & 0x0fff) << 4;
- break;
- }
- case 1: { // C... ..AB ....
- u16 w0 = read_word(adr);
- u16 w1 = read_word(adr+2);
- samp = ((w0 & 0xf000) >> 8) | ((w1 & 0x00ff) << 8);
- break;
- }
- case 2: { // .... bc.. ...a
- u16 w0 = read_word(adr+2);
- u16 w1 = read_word(adr+4);
- samp = ((w0 & 0xff00) >> 4) | ((w1 & 0x000f) << 12);
- break;
- }
- case 3: { // .... .... ABC.
- u16 w1 = read_word(adr+4);
- samp = w1 & 0xfff0;
- break;
- }
- }
+ case 1: { // C... ..AB ....
+ u16 w0 = read_word(adr);
+ u16 w1 = read_word(adr+2);
+ samp = ((w0 & 0xf000) >> 8) | ((w1 & 0x00ff) << 8);
break;
}
-
- case 2: // 8-bits linear
- samp = read_byte(base_address + spos) << 8;
+ case 2: { // .... bc.. ...a
+ u16 w0 = read_word(adr+2);
+ u16 w1 = read_word(adr+4);
+ samp = ((w0 & 0xff00) >> 4) | ((w1 & 0x000f) << 12);
break;
-
- case 3: // 8-bits logarithmic
- samp = m_sample_log8[read_byte(base_address + spos)];
+ }
+ case 3: { // .... .... ABC.
+ u16 w1 = read_word(adr+4);
+ samp = w1 & 0xfff0;
break;
}
-
- //logerror("sample %02x %06x [%d] %+5d %04x %04x %04x\n", channel, base_address >> 2, m_address[channel] >> 30, spos, samp & 0xffff, m_volume[channel], m_pan[channel]);
-
- // Second, step the sample pos, loop/deactivate as needed
- m_sample_pos[channel] += m_sample_increment[m_freq[channel] & 0x3fff];
- s32 loop_size = (m_post_size[channel] << 8) | ((m_address[channel] >> 22) & 0xf8);
- if(m_sample_pos[channel] >= loop_size) {
- // We reached the loop point, stop if loop size is zero,
- // otherwise loop
- if(!loop_size)
- m_active_mask &= ~((u64(1) << channel));
- else
- do
- m_sample_pos[channel] -= loop_size;
- while(m_sample_pos[channel] >= loop_size);
}
+ break;
+ }
+
+ case 2: // 8-bits linear
+ samp = read_byte(base_address + spos) << 8;
+ break;
+
+ case 3: // 8-bits logarithmic
+ samp = m_sample_log8[read_byte(base_address + spos)];
+ break;
+ }
+
+ //logerror("sample %02x %06x [%d] %+5d %04x %04x %04x\n", channel, base_address >> 2, m_address[channel] >> 30, spos, samp & 0xffff, m_volume[channel], m_pan[channel]);
+
+ // Second, step the sample pos, loop/deactivate as needed
+ m_sample_pos[channel] += m_sample_increment[m_freq[channel] & 0x3fff];
+ s32 loop_size = (m_post_size[channel] << 8) | ((m_address[channel] >> 22) & 0xf8);
+ if(m_sample_pos[channel] >= loop_size) {
+ // We reached the loop point, stop if loop size is zero,
+ // otherwise loop
+ if(!loop_size)
+ m_active_mask &= ~((u64(1) << channel));
+ else
+ do
+ m_sample_pos[channel] -= loop_size;
+ while(m_sample_pos[channel] >= loop_size);
+ }
- // Third, filter the sample
- // - missing lpf_cutoff, lpf_reso, hpf_cutoff
+ // Third, filter the sample
+ // - missing lpf_cutoff, lpf_reso, hpf_cutoff
- // - eq lowpass
- s32 samp1 = (samp * m_eq_filter[channel][2] + m_sample_history[channel][0][0] * m_eq_filter[channel][1] + m_sample_history[channel][0][1] * m_eq_filter[channel][0]) >> 13;
- m_sample_history[channel][0][1] = m_sample_history[channel][0][0];
- m_sample_history[channel][0][0] = samp;
+ // - eq lowpass
+ s32 samp1 = (samp * m_eq_filter[channel][2] + m_sample_history[channel][0][0] * m_eq_filter[channel][1] + m_sample_history[channel][0][1] * m_eq_filter[channel][0]) >> 13;
+ m_sample_history[channel][0][1] = m_sample_history[channel][0][0];
+ m_sample_history[channel][0][0] = samp;
- // - eq highpass
- s32 samp2 = (samp1 * m_eq_filter[channel][5] + m_sample_history[channel][1][0] * m_eq_filter[channel][4] + m_sample_history[channel][1][1] * m_eq_filter[channel][3]) >> 13;
- m_sample_history[channel][1][1] = m_sample_history[channel][1][0];
- m_sample_history[channel][1][0] = samp1;
+ // - eq highpass
+ s32 samp2 = (samp1 * m_eq_filter[channel][5] + m_sample_history[channel][1][0] * m_eq_filter[channel][4] + m_sample_history[channel][1][1] * m_eq_filter[channel][3]) >> 13;
+ m_sample_history[channel][1][1] = m_sample_history[channel][1][0];
+ m_sample_history[channel][1][0] = samp1;
- // - anything else?
+ // - anything else?
- // Fourth, volume (disabled) and pan, clamp the attenuation at -96dB
- s32 sampl = samp2 * m_linear_attenuation[std::min(0xff, (m_volume[channel] & 0x00) + (m_pan[channel] >> 8))];
- s32 sampr = samp2 * m_linear_attenuation[std::min(0xff, (m_volume[channel] & 0x00) + (m_pan[channel] & 0xff))];
+ // Fourth, volume (disabled) and pan, clamp the attenuation at -96dB
+ s32 sampl = samp2 * m_linear_attenuation[std::min(0xff, (m_volume[channel] & 0x00) + (m_pan[channel] >> 8))];
+ s32 sampr = samp2 * m_linear_attenuation[std::min(0xff, (m_volume[channel] & 0x00) + (m_pan[channel] & 0xff))];
- // Fifth, add to the accumulators
- acc_left += sampl;
- acc_right += sampr;
+ // Fifth, add to the accumulators
+ acc_left += sampl;
+ acc_right += sampr;
- // Missing: reverb, chorus, effects in general
- }
+ // Missing: reverb, chorus, effects in general
+ }
- // Samples are 16 bits, there are up to 64 of them, and the accumulators are fixed-point signed 48.16
- // Global EQ is missing (it's done in the MEG)
+ // Samples are 16 bits, there are up to 64 of them, and the accumulators are fixed-point signed 48.16
+ // Global EQ is missing (it's done in the MEG)
- acc_left >>= (16+6);
- outputs[0].put_int_clamp(sample, acc_left, 32768);
+ acc_left >>= (16+6);
+ outputs[0].put_int_clamp(0, acc_left, 32768);
- acc_right >>= (16+6);
- outputs[1].put_int_clamp(sample, acc_right, 32768);
- }
+ acc_right >>= (16+6);
+ outputs[1].put_int_clamp(0, acc_right, 32768);
}
diff --git a/src/devices/sound/swp30.h b/src/devices/sound/swp30.h
index 1eb68270626..7237c2f880f 100644
--- a/src/devices/sound/swp30.h
+++ b/src/devices/sound/swp30.h
@@ -50,6 +50,8 @@ private:
u16 m_routing[0x40][3];
u16 m_map[8];
+ u16 m_internal_adr;
+
u16 m_program_address;
// AWM2 per-channel registers
@@ -87,6 +89,9 @@ private:
void dry_rev_w(offs_t offset, u16 data);
u16 cho_var_r(offs_t offset);
void cho_var_w(offs_t offset, u16 data);
+ u16 internal_adr_r();
+ void internal_adr_w(u16 data);
+ u16 internal_r();
template<int sel> u16 routing_r(offs_t offset);
template<int sel> void routing_w(offs_t offset, u16 data);
diff --git a/src/mame/drivers/ymmu100.cpp b/src/mame/drivers/ymmu100.cpp
index cf36b5a1741..0bd5d3c8b2f 100644
--- a/src/mame/drivers/ymmu100.cpp
+++ b/src/mame/drivers/ymmu100.cpp
@@ -176,6 +176,7 @@ public:
void regs_int_read_tap(offs_t address, u16 data, u16 mem_mask);
void regs_int_write_tap(offs_t address, u16 data, u16 mem_mask);
void voice_write_tap(offs_t address, u16 data, u16 mem_mask);
+ void voice_read_tap(offs_t address, u16 data, u16 mem_mask);
void chan_write_tap(offs_t address, u16 data, u16 mem_mask);
void prg_write_tap(offs_t address, u16 data, u16 mem_mask);
@@ -188,10 +189,14 @@ public:
m_maincpu->space(0).install_write_tap(0x20cb10, 0x20cb10 + 0x122*0x22 - 1, "chan debug", [this](offs_t offset, u16 &data, u16 mem_mask) {
chan_write_tap(offset, data, mem_mask);
});
- if(0)
+ if(1)
m_maincpu->space(0).install_write_tap(0x20f03e, 0x20f03e + 0x92*0x40 - 1, "voice debug", [this](offs_t offset, u16 &data, u16 mem_mask) {
voice_write_tap(offset, data, mem_mask);
});
+ if(1)
+ m_maincpu->space(0).install_read_tap(0x20f03e, 0x20f03e + 0x92*0x40 - 1, "voice debug", [this](offs_t offset, u16 &data, u16 mem_mask) {
+ voice_read_tap(offset, data, mem_mask);
+ });
if(0)
m_maincpu->space(0).install_readwrite_tap(0x214ca2+0x20, 0x214ca2+0x320-1, "regs fp",
[this](offs_t offset, u16 &data, u16 mem_mask) {
@@ -411,20 +416,71 @@ void mu100_state::regs_int_write_tap(offs_t address, u16 data, u16 mem_mask)
logerror("regs_int_w %03x, %04x @ %04x (%06x)\n", reg, data, mem_mask, pc);
}
+struct xmap {
+ int slot;
+ const char *name;
+};
+
+static xmap vmap[] = {
+ { 0x00, "instrumenthi" },
+ { 0x02, "instrumentlo" },
+ { 0x04, "midi_channelhi" },
+ { 0x06, "midi_channello" },
+ { 0x0c, "lpf_cutoff" },
+ { 0x42, "delay_time" },
+ { 0x48, "active" },
+ { 0x4a, "velocity" },
+ { 0x51, "inverse_velocity" },
+ { -1, "" },
+};
+
void mu100_state::voice_write_tap(offs_t address, u16 data, u16 mem_mask)
{
offs_t pc = m_maincpu->pc();
offs_t off = address - 0x20f03e;
int voice = off / 0x92;
int slot = off % 0x92;
+
+ if(mem_mask == 0xff00)
+ data >>= 8;
+ else if(mem_mask == 0x00ff)
+ slot++;
+
+ std::string slotname = util::string_format("%02x", slot);
+ for(int i=0; vmap[i].slot != -1; i++)
+ if(vmap[i].slot == slot)
+ slotname = vmap[i].name;
+
if(mem_mask == 0xffff) {
- logerror("voice_w %02x:%02x, %04x (%06x)\n", voice, slot, data, pc);
+ logerror("voice_w %02x:%s, %04x (%06x)\n", voice, slotname, data, pc);
} else {
- if(mem_mask == 0xff00)
- data >>= 8;
- else
- slot++;
- logerror("voice_w %02x:%02x, %02x (%06x)\n", voice, slot, data, pc);
+ logerror("voice_w %02x:%s, %02x (%06x)\n", voice, slotname, data, pc);
+ }
+}
+
+void mu100_state::voice_read_tap(offs_t address, u16 data, u16 mem_mask)
+{
+ offs_t pc = m_maincpu->pc();
+ offs_t off = address - 0x20f03e;
+ int voice = off / 0x92;
+ int slot = off % 0x92;
+
+ logerror("off %x voice %x slot %x mask %04x\n", off, voice, slot, mem_mask);
+ data &= mem_mask;
+ if(mem_mask == 0xff00)
+ data >>= 8;
+ else if(mem_mask == 0x00ff)
+ slot++;
+
+ std::string slotname = util::string_format("%02x", slot);
+ for(int i=0; vmap[i].slot != -1; i++)
+ if(vmap[i].slot == slot)
+ slotname = vmap[i].name;
+
+ if(mem_mask == 0xffff) {
+ logerror("voice_r %02x:%s, %04x (%06x)\n", voice, slotname, data, pc);
+ } else {
+ logerror("voice_r %02x:%s, %02x (%06x)\n", voice, slotname, data, pc);
}
}