diff options
author | 2021-03-22 22:51:20 +0100 | |
---|---|---|
committer | 2021-04-12 09:27:13 +0200 | |
commit | b59544c13ce0d2550a45c830050caee8b81ca7b9 (patch) | |
tree | dd521e944967046d6912649180a80cc30e0df5fe | |
parent | 22823416c10de513c899bf0ff55e5d5c829fdcd7 (diff) |
swp30: Make the stream synchronous, add dummy-ish internal register read, more logging
-rw-r--r-- | src/devices/sound/swp30.cpp | 267 | ||||
-rw-r--r-- | src/devices/sound/swp30.h | 5 | ||||
-rw-r--r-- | src/mame/drivers/ymmu100.cpp | 70 |
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); } } |