From b72de1cf6e544f8d4515a9745c686135f17447a6 Mon Sep 17 00:00:00 2001 From: Olivier Galibert Date: Sat, 21 Oct 2023 12:50:08 +0200 Subject: [PATCH] mu80: Add the fixed interrupt swp20: Add some more identified registers --- src/devices/sound/swp20.cpp | 138 +++++++++++++++++++++++++++++------- src/devices/sound/swp20.h | 31 ++++++-- src/mame/yamaha/ymmu80.cpp | 17 ++++- 3 files changed, 152 insertions(+), 34 deletions(-) diff --git a/src/devices/sound/swp20.cpp b/src/devices/sound/swp20.cpp index 96ec6c0b15e..8acd83e9bbf 100644 --- a/src/devices/sound/swp20.cpp +++ b/src/devices/sound/swp20.cpp @@ -29,8 +29,8 @@ void swp20_device::device_reset() m_waverom_access = 0; m_waverom_val = 0; - m_p3c_port = 0x00; - m_p3c_address = true; + m_eq_port = 0x00; + m_eq_address = true; m_voice = 0x00; m_keyon = 0; m_keyoff = 0; @@ -42,6 +42,19 @@ void swp20_device::map(address_map &map) map(0x01, 0x01).w(FUNC(swp20_device::voice_w)); + map(0x10, 0x10).rw(FUNC(swp20_device::pitch_r<1>), FUNC(swp20_device::pitch_w<1>)); + map(0x11, 0x11).rw(FUNC(swp20_device::pitch_r<0>), FUNC(swp20_device::pitch_w<0>)); + + map(0x14, 0x14).rw(FUNC(swp20_device::pan_l_r), FUNC(swp20_device::pan_l_w)); + map(0x15, 0x15).rw(FUNC(swp20_device::pan_r_r), FUNC(swp20_device::pan_r_w)); + + map(0x26, 0x26).rw(FUNC(swp20_device::sample_start_r<2>), FUNC(swp20_device::sample_start_w<2>)); + map(0x27, 0x27).rw(FUNC(swp20_device::sample_start_r<1>), FUNC(swp20_device::sample_start_w<1>)); + map(0x28, 0x28).rw(FUNC(swp20_device::sample_start_r<0>), FUNC(swp20_device::sample_start_w<0>)); + map(0x29, 0x29).rw(FUNC(swp20_device::sample_format_r), FUNC(swp20_device::sample_format_w)); + map(0x2a, 0x2a).rw(FUNC(swp20_device::sample_end_r<1>), FUNC(swp20_device::sample_end_w<1>)); + map(0x2b, 0x2b).rw(FUNC(swp20_device::sample_end_r<0>), FUNC(swp20_device::sample_end_w<0>)); + map(0x2c, 0x2c).rw(FUNC(swp20_device::sample_address_r<3>), FUNC(swp20_device::sample_address_w<3>)); map(0x2d, 0x2d).rw(FUNC(swp20_device::sample_address_r<2>), FUNC(swp20_device::sample_address_w<2>)); map(0x2e, 0x2e).rw(FUNC(swp20_device::sample_address_r<1>), FUNC(swp20_device::sample_address_w<1>)); map(0x2f, 0x2f).rw(FUNC(swp20_device::sample_address_r<0>), FUNC(swp20_device::sample_address_w<0>)); @@ -50,23 +63,15 @@ void swp20_device::map(address_map &map) map(0x3a, 0x3a).r(FUNC(swp20_device::waverom_val_r<1>)); map(0x3b, 0x3b).r(FUNC(swp20_device::waverom_val_r<0>)); - map(0x3c, 0x3c).w(FUNC(swp20_device::p3c_w)); + map(0x3c, 0x3c).w(FUNC(swp20_device::eq_w)); } -// init mu80: -// 48394: <- 47aea -// write 04.7f 00.14 01.90 to +3c -// write 01.90 80-ff, 473ea++ -// write 01.94 80-ff, 4746a++ -// write 01.98 80-ff, 474ea++ -// write 01.9c 80-ff, 4756a++ - -// write 01.a0 -// write 40-5f.data -// etc - void swp20_device::voice_w(u8 data) { + // Code uses 20-3f for voices on the second swp, it looks like + // just leaking internal information and the top bits are not + // significant + m_voice = data & 0x1f; } @@ -80,7 +85,79 @@ template u8 swp20_device::waverom_val_r() return read_word(m_sample_address[0x1f]*2) >> (8*sel); } -template void swp20_device::sample_address_w(offs_t offset, u8 data) +void swp20_device::pan_l_w(u8 data) +{ + m_stream->update(); + m_pan_l[m_voice] = data; +} + +u8 swp20_device::pan_l_r() +{ + return m_pan_l[m_voice]; +} + +void swp20_device::pan_r_w(u8 data) +{ + m_stream->update(); + m_pan_r[m_voice] = data; +} + +u8 swp20_device::pan_r_r() +{ + return m_pan_r[m_voice]; +} + +template void swp20_device::pitch_w(u8 data) +{ + m_stream->update(); + m_pitch[m_voice] = (m_pitch[m_voice] & ~(0xff << (8*sel))) | (data << (8*sel)); +} + +template u8 swp20_device::pitch_r() +{ + return m_pitch[m_voice] >> (8*sel); +} +template void swp20_device::sample_start_w(u8 data) +{ + m_stream->update(); + + m_sample_start[m_voice] = (m_sample_start[m_voice] & ~(0xff << (8*sel))) | (data << (8*sel)); + // if(!sel) + // logerror("sample_start[%02x] = %04x\n", m_voice, m_sample_start[m_voice]); +} + +template u8 swp20_device::sample_start_r() +{ + return m_sample_start[m_voice] >> (8*sel); +} + +template void swp20_device::sample_end_w(u8 data) +{ + m_stream->update(); + + m_sample_end[m_voice] = (m_sample_end[m_voice] & ~(0xff << (8*sel))) | (data << (8*sel)); + // if(!sel) + // logerror("sample_end[%02x] = %04x\n", m_voice, m_sample_end[m_voice]); +} + +template u8 swp20_device::sample_end_r() +{ + return m_sample_end[m_voice] >> (8*sel); +} + +void swp20_device::sample_format_w(u8 data) +{ + m_stream->update(); + + m_sample_format[m_voice] = data; +} + +u8 swp20_device::sample_format_r() +{ + return m_sample_format[m_voice]; +} + +template void swp20_device::sample_address_w(u8 data) { m_stream->update(); @@ -89,27 +166,31 @@ template void swp20_device::sample_address_w(offs_t offset, u8 data) logerror("sample_address[%02x] = %04x\n", m_voice, m_sample_address[m_voice]); } -template u8 swp20_device::sample_address_r(offs_t offset) +template u8 swp20_device::sample_address_r() { return m_sample_address[m_voice] >> (8*sel); } -void swp20_device::p3c_w(u8 data) +void swp20_device::eq_w(u8 data) { - if(m_p3c_address) - m_p3c_port = data; - else - logerror("p3c %02x = %02x\n", m_p3c_port, data); + if(m_eq_address) + m_eq_port = data; + else { + if(0) + logerror("eq %02x = %02x\n", m_eq_port, data); + } - m_p3c_address = !m_p3c_address; + m_eq_address = !m_eq_address; } u8 swp20_device::snd_r(offs_t offset) { - logerror("r %02x %s\n", offset, machine().describe_context()); + // logerror("r %02x %s\n", offset, machine().describe_context()); return 0; } +static u8 rr[0x20*0x40]; + void swp20_device::snd_w(offs_t offset, u8 data) { // Registers 0-f are global, 10-3f per-voice @@ -129,8 +210,13 @@ void swp20_device::snd_w(offs_t offset, u8 data) break; } - default: - logerror("w %02x.%02x, %02x %s\n", m_voice, offset, data, machine().describe_context()); + default: { + if(data != rr[m_voice * 0x40 + offset]) { + rr[m_voice * 0x40 + offset] = data; + if(offset != 0x34) + logerror("w %02x.%02x, %02x %s\n", m_voice, offset, data, machine().describe_context()); + } + } } } diff --git a/src/devices/sound/swp20.h b/src/devices/sound/swp20.h index 2deb1752700..9c2eeafefd6 100644 --- a/src/devices/sound/swp20.h +++ b/src/devices/sound/swp20.h @@ -25,26 +25,45 @@ protected: private: sound_stream *m_stream; + std::array m_pan_l; + std::array m_pan_r; + std::array m_pitch; + std::array m_sample_start; + std::array m_sample_end; + std::array m_sample_format; std::array m_sample_address; u16 m_waverom_val; u8 m_waverom_access; - u8 m_p3c_port; - bool m_p3c_address; + u8 m_eq_port; + bool m_eq_address; u8 m_voice; u32 m_keyon; u32 m_keyoff; void voice_w(u8 data); - template void sample_address_w(offs_t offset, u8 data); - template u8 sample_address_r(offs_t offset); + + void pan_l_w(u8 data); + u8 pan_l_r(); + void pan_r_w(u8 data); + u8 pan_r_r(); + template void pitch_w(u8 data); + template u8 pitch_r(); + template void sample_start_w(u8 data); + template u8 sample_start_r(); + template void sample_end_w(u8 data); + template u8 sample_end_r(); + void sample_format_w(u8 data); + u8 sample_format_r(); + template void sample_address_w(u8 data); + template u8 sample_address_r(); void waverom_access_w(u8 data); template u8 waverom_val_r(); - // Generic upload port - void p3c_w(u8 data); + // Generic upload port, connected to the EQ on the first swp20 + void eq_w(u8 data); // Generic catch-all u8 snd_r(offs_t offset); diff --git a/src/mame/yamaha/ymmu80.cpp b/src/mame/yamaha/ymmu80.cpp index 58dd06e5659..4d639a7e709 100644 --- a/src/mame/yamaha/ymmu80.cpp +++ b/src/mame/yamaha/ymmu80.cpp @@ -2,11 +2,17 @@ // copyright-holders:R. Belmont, Olivier Galibert /************************************************************************************* - Yamaha MU-80 and MU-100 : 32-voice polyphonic/multitimbral General MIDI/GS/XG tone modules + Yamaha MU-80 : 32-part, 64-note polyphonic/multitimbral General MIDI/GS/XG + tone module Preliminary driver by R. Belmont and O. Galibert + The first XG-capable module (mu15 and mu50 came out later). Uses a distributed + structure of chips, with two chained SWP20 providing 32-notes each with a MEG + effects processor at the end of the chain followed by an EQ chip on the result. + MU80 CPU: Hitachi H8/3002 (HD6413D02F16), strapped for mode 4, with a 12 MHz oscillator - Sound ASICs: 2x Yamaha YMM275-F/SWP20 + 2x YMM279-F/SWD wave decoders + HD62908 "MEG" effects processor + Sound ASICs: 2x Yamaha YMM275-F/SWP20 + 2x YMM279-F/SWD wave decoders + HD62908 "MEG" + effects processor I/O ports from service manual: @@ -213,6 +219,7 @@ private: u16 pb_r(); virtual void machine_start() override; + virtual void machine_reset() override; void mu80_map(address_map &map); }; @@ -221,6 +228,12 @@ void mu80_state::machine_start() cur_p6 = cur_pa = cur_pb = cur_ic32 = 0xff; } +void mu80_state::machine_reset() +{ + // Active-low, wired to gnd + m_mu80cpu->set_input_line(0, ASSERT_LINE); +} + void mu80_state::mu80_map(address_map &map) { map(0x000000, 0x07ffff).rom().region("mu80cpu", 0);