From 8f534764f968b989488dec085dd607c51f125e6d Mon Sep 17 00:00:00 2001 From: Olivier Galibert Date: Wed, 14 Nov 2018 14:15:16 +0100 Subject: mu100: Add missing roms, also some wip [Guru, O. Galibert] --- src/devices/sound/swp30.cpp | 756 ++++++++++++++++++++++++++----------------- src/devices/sound/swp30.h | 106 +++--- src/emu/debug/debugcpu.cpp | 6 +- src/mame/drivers/ymmu100.cpp | 492 ++++++++++++++-------------- 4 files changed, 760 insertions(+), 600 deletions(-) diff --git a/src/devices/sound/swp30.cpp b/src/devices/sound/swp30.cpp index ebae8eb73e8..6f02329993f 100644 --- a/src/devices/sound/swp30.cpp +++ b/src/devices/sound/swp30.cpp @@ -7,91 +7,121 @@ #include "swp30.h" /* - mode hall 1 reverb 0.3/2.0/2.1/30.0 - 5ab/b56: 1ff2 - 5e1/bc2: 1ff1 - 5e3/bc6, 521/a42, 527/a4e, 563/ac6, 56b/ad6, 5a7/b4e, 5e3/bc6: 1d - 529/a52: 1a21/13d2/134f/ 70c - 4e9/9d2, 4eb/9d6: 5/14d0/1585/1ec3 - 565/aca: 1a21/12cb/1247/ 684 - 523/a46, 525/a4a: 10/1631/16d4/1eef - 5a1/b42: 1a21/11c2/113d/ 606 - 561/ac2, 52b/ac2: a2/176f/1801/1f15 - 5a9/b5a: 1a20/10fb/1077/ 5ae - 567/ace, 569/ad2: 4d/1847/18cd/1f2e - 5e5/bca: 1a1f/ f74/ ef5/ 50b - 5a3/b46, 5a5/b46: d2/19c2/1a31/1f58 - 623/c46: 1a21/130d/1289/ 6a5 - 5ab/b56, 5e1/bc2: c/15dc/1683/1ee4 - - -72814: move e0 to reg r0 - -62fcc: compute stuff + The SWP30 is the combination of a rompler called AWM2 (Advanced Wave + Memory 2) and an effects DSP called MEG (Multiple Effects + Generator). It also includes some routing/mixing capabilities, + moving data between AWM2, MEG and serial inputs and outputs with + volume management capabilities everywhere. Its clock is 33.9MHz and + the output is at 44100Hz stereo (768 cycles per sample pair) per dac + output. + + I/O wise, the chip has 8 generic audio serial inputs and 8 outputs + for external plugins, and two dac outputs. The DAC output is + stereo, and so is the first generic input. It's unclear whether the + outputs and the other inputs are stereo. The MU100 connects a stereo ADC to the fist input, and routes + + In practice the chip has the pin for a second DAC, so is + probably 4-channel capable on output. + + The + + + The AWM2 manages 64 channels internally, and has inputs for 8 + external sources, one at least being stereo (they probably all are). + The sound data can be four formats (8 bits, 12 bits, 16 bits, and a + 8-bits log format with roughly 10 bits of dynamic). The rom bus is + 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 + panned result is accumulated on four stereo accumulators which will + be passed to the MEG. Two of the channels (that includes the + external ones) can also have their value sent to the MEG. + + + + + The MEG is a DSP with 384 program steps. Instructions are 64 bits + wide, and to each instruction is associated a 2.14 fixed point value + and, for every third instruction a 16-bit integer memory offset + value. In addition 24 LFOs are available, and possibly more. It is + connected to a dram of 262144 samples, theorically 18 bits but in + practice only the top 16 bits are connected. + + The chip interface presents 4096 16-bits registers in a 64x64 grid. + Some of this grid is for per-channel values for AWM2, but parts are + isolated and renumbered for MEG regisrers or for general control + functions. + + General register address: (64 * channel + slot) * 2 (16-bits values) + MEG fixed point constants (n=0-383) : channel = n/6, slot = 0x21 + 2*(n%6) + MEG integer constants (n=0-127): channel = n/2, slot = 0x30 + (n%2) + MEG LFOs (n=0..23): channel = n/2, slot = 0x3e + (n%2) + + Control registers (n=0..127): channel = n/2, slot = 0x + + Note that the LFOs may be 128 instead of 24, but the mu100 code only + reserves 24 values in its structures. OTOH, the mu100 code never + uses channel >= 12 slot 3e-3f either. + + + AWM2 (per-channel) registers: + slot(s) function + 00 fixed LPF frequency cutoff index + 01 fixed LPF frequency cutoff index increment? + 02 fixed HPF frequency cutoff + 03 40ff at startup, 5010 always afterwards? + 04 fixed LPF resonane level + 05 unknown + 06-09 envelope information, not understood yet + 0a-0d unknown, probably something to do with vibrato + 10 unknown + 11 channel replay frequency, signed 4.10 fixed point, log2 scale, positive is higher resulting frequency + 12-13 number of samples before the loop point + 14-15 number of samples in the loop + 16-17 bit 31-30 = sample format, bits 29-25 = loop samples decimal part, 24-0 = loop start address in rom + 20,22,24 first FIR coefficients + 26,28,2a second FIR coefficients + 2c-2f unknown + 32 pan left/right, 2x8 bits of attenuation + 33-34 attenuation levels to add to the four accumulators (dry, reverb, chorus, variation for the mu100) + 35-37 routing, in particular for the taps. Rather unclear + + Slots e-f are system control, 21,23,25,27,29,2b MEG fixed point + registers, 30,31 MEG offset registers, 3e,3f MEG LFO registers. + 38-3d are special, not per-channel. + + Known system registers: + number function + 02 internal register selector, msb = 0 or 6, lsb = channel + 03 internal register read port, used for envelope/keyoff management + 0c-0f keyon mask + 10 write something to trigger a keyon + 21 MEG program write address + 22-25 MEG program opcode, writing to 25 triggers an auto-increment + 30-3e even slots only, MEG buffer mappings + + + The LFO registers internal counters are 22 bits wide. The LSB of + the register gives the increment per sample, encoded in a special + 3.5 format. + With scale = 3bits and v = 5bits, step = base[scale] + (v << shift[scale]) + base = { 0, 32, 64, 128, 256, 512, 1024, 2048 } + shift = { 0, 0, 1, 2, 3, 4, 5, 6 } + + The 21th bit of the counter inverts bits 20-0 on read, those are + interpreted as a 0-1 value, giving a sawtooth wave. + + + 8 mappings can be setup, which allow to manage rotating buffers in + the MEG-attached ram easily by automating masking and offset adding. + The register format is: tttttsss oooooooo. 't' is not understood + yet. 's' is the sub-buffer size, defined as 1 << (10+s). The base + offset is o << 10. There are no alignment issues, e.g. you can have + a buffer at 0x28000 which is 0x10000 samples long. -*/ -#if 0 -// 929a6: 00 2e 30 32 33 34 35 36 37 3a 3c - -// 3fb80: list of reverb times as text, 4chars/entry - -// 84268: 7c 76 77 78 -// 80 79 7a 7b -// 84 7e 7d 7f -// 88 81 82 83 -// 8c 85 86 87 -// 91 89 8a 8b - - -void f_62fcc(e0, r0, e1, r1l, er5) // 8 (11/12) 1 6 84268 -{ - // 929b1 - // 00 00 00 00 00 00 - // 38 3c 40 43 49 3b - // 46 4a 4e 51 55 43 - // 3e 3f 41 43 48 3c - // 4b 51 59 5c 00 4e - - // 92560 - // 00 01 12 1c 23 28 2d 30 34 37 39 3c 3e 40 42 43 - // 45 46 48 49 4a 4c 4d 4e 4f 50 51 52 53 54 54 55 - // 56 57 58 58 59 5a 5a 5b 5c 5c 5d 5d 5e 5e 5f 60 - // 60 61 61 63 66 68 69 6b 6d 6e 70 71 72 75 77 79 - // 7b 7c 7e 7f 81 82 - - l8 = 929b1 + 6*e1; - r6 = r1l == 6 ? 0x15 : r1l == 4 ? 0xd : r1l == 3 ? 0x9 : e1; - f_64a34(0x01, 01, t929a6[e0].b << 8, 0x40, 0, er5 + 2*r6); // 0101 3700 40 0 84292 - writes 1ff2/1ff1 - pr0 = r0; - for(r3h=0; r3h<6; r3h++) { - r0l = *l8++; - if(r0l) { - r6 = clamp(r0l + l92560[pr0] - 0x38, 0, 0xff); - r6, e6 = l925a6[r6].l; // 13d2 5368 - } else - r6, e6 = 0, 0; - - } - er0 = *er5.w++; - g214ca4[0x10 + er0].w = e6; - lc = &g214ca4[0x20 + er0].w - er0 = float(r6); -} -// 80914 = convert unsigned short to float - -void write_regs(r0b, er1) // 728c0, r0=3, er1=84292 -{ - if(!g214c98) - return; - for(r5=0; r5> 4))) >> 4; // Relative playback frequency of a sample is encoded on signed 14 // bits. The scale is logarithmic, with 0x400 = 1 octave (e.g. *2 // or /2). + for(int i=-0x20000; i<0x2000; i++) m_sample_increment[i & 0x3fff] = 256 * pow(2, i/1024.0); // Log to linear 8-bits sample decompression. Statistics say // that's what it should look like. Note that 0 can be encoded // both as 0x00 and 0x80, and as it happens 0x80 is never used in - // these samples. + // these samples. Ends up with a 55dB dynamic range, to compare + // with 8bits 48dB, 12bits 72dB and 16bits 96dB. // Rescale so that it's roughly 16 bits. Range ends up being +/- 78c0. @@ -138,10 +171,40 @@ void swp30_device::device_start() m_sample_log8[i | 0x80] = -m_sample_log8[i]; } + save_item(NAME(m_program)); + + save_item(NAME(m_keyon_mask)); + save_item(NAME(m_active_mask)); + + save_item(NAME(m_pre_size)); + save_item(NAME(m_post_size)); + save_item(NAME(m_address)); + + save_item(NAME(m_sample_pos)); + save_item(NAME(m_sample_history)); + + save_item(NAME(m_program_pfp)); + save_item(NAME(m_program_pint)); + save_item(NAME(m_program_plfo)); + + save_item(NAME(m_volume)); + save_item(NAME(m_freq)); + save_item(NAME(m_pan)); + save_item(NAME(m_envelope)); + save_item(NAME(m_lpf_cutoff)); + save_item(NAME(m_lpf_cutoff_inc)); + save_item(NAME(m_lpf_reso)); + save_item(NAME(m_hpf_cutoff)); + save_item(NAME(m_eq_filter)); + save_item(NAME(m_routing)); + + save_item(NAME(m_program_address)); } void swp30_device::device_reset() { + memset(m_program, 0, sizeof(m_program)); + m_keyon_mask = 0; m_active_mask = 0; @@ -152,25 +215,22 @@ void swp30_device::device_reset() memset(m_sample_pos, 0, sizeof(m_sample_pos)); memset(m_sample_history, 0, sizeof(m_sample_history)); + memset(m_program_pfp, 0, sizeof(m_program_pfp)); + memset(m_program_pint, 0, sizeof(m_program_pint)); + memset(m_program_plfo, 0, sizeof(m_program_plfo)); + memset(m_volume, 0, sizeof(m_volume)); memset(m_freq, 0, sizeof(m_freq)); memset(m_pan, 0, sizeof(m_pan)); + memset(m_envelope, 0, sizeof(m_envelope)); memset(m_lpf_cutoff, 0, sizeof(m_lpf_cutoff)); + memset(m_lpf_cutoff_inc, 0, sizeof(m_lpf_cutoff_inc)); memset(m_lpf_reso, 0, sizeof(m_lpf_reso)); memset(m_hpf_cutoff, 0, sizeof(m_hpf_cutoff)); memset(m_eq_filter, 0, sizeof(m_eq_filter)); + memset(m_routing, 0, sizeof(m_routing)); - memset(m_variation_delay, 0, sizeof(m_variation_delay)); - memset(m_variation_fb_level, 0, sizeof(m_variation_fb_level)); - memset(m_variation_final_level, 0, sizeof(m_variation_final_level)); - memset(m_variation_high_damp, 0, sizeof(m_variation_high_damp)); - memset(m_variation_inv_high_damp, 0, sizeof(m_variation_inv_high_damp)); - - memset(m_insertion_delay, 0, sizeof(m_insertion_delay)); - memset(m_insertion_fb_level, 0, sizeof(m_insertion_fb_level)); - memset(m_insertion_final_level, 0, sizeof(m_insertion_final_level)); - memset(m_insertion_high_damp, 0, sizeof(m_insertion_high_damp)); - memset(m_insertion_inv_high_damp, 0, sizeof(m_insertion_inv_high_damp)); + m_program_address = 0; } void swp30_device::rom_bank_updated() @@ -181,78 +241,79 @@ void swp30_device::rom_bank_updated() void swp30_device::map(address_map &map) { map(0x0000, 0x1fff).rw(FUNC(swp30_device::snd_r), FUNC(swp30_device::snd_w)); - map(0x0000, 0x0001).select(0x1f80).rw(FUNC(swp30_device::lpf_cutoff_r), FUNC(swp30_device::lpf_cutoff_w)); - map(0x0004, 0x0005).select(0x1f80).rw(FUNC(swp30_device::hpf_cutoff_r), FUNC(swp30_device::hpf_cutoff_w)); - map(0x0008, 0x0009).select(0x1f80).rw(FUNC(swp30_device::lpf_reso_r), FUNC(swp30_device::lpf_reso_w)); - map(0x0012, 0x0013).select(0x1f80).rw(FUNC(swp30_device::volume_r), FUNC(swp30_device::volume_w)); - map(0x0022, 0x0023).select(0x1f80).rw(FUNC(swp30_device::freq_r), FUNC(swp30_device::freq_w)); - map(0x0024, 0x0027).select(0x1f80).rw(FUNC(swp30_device::pre_size_r), FUNC(swp30_device::pre_size_w)); - map(0x0028, 0x002b).select(0x1f80).rw(FUNC(swp30_device::post_size_r), FUNC(swp30_device::post_size_w)); - map(0x002c, 0x002f).select(0x1f80).rw(FUNC(swp30_device::address_r), FUNC(swp30_device::address_w)); - map(0x0040, 0x0041).select(0x1f80).rw(&swp30_device::eq_filter_r<0, 0>, "swp30_device::eq_filter_r<0, 0>", &swp30_device::eq_filter_w<0, 0>, "swp30_device::eq_filter_w<0, 0>"); - map(0x0044, 0x0045).select(0x1f80).rw(&swp30_device::eq_filter_r<0, 1>, "swp30_device::eq_filter_r<0, 1>", &swp30_device::eq_filter_w<0, 1>, "swp30_device::eq_filter_w<0, 1>"); - map(0x0048, 0x0049).select(0x1f80).rw(&swp30_device::eq_filter_r<0, 2>, "swp30_device::eq_filter_r<0, 2>", &swp30_device::eq_filter_w<0, 2>, "swp30_device::eq_filter_w<0, 2>"); - map(0x004c, 0x004d).select(0x1f80).rw(&swp30_device::eq_filter_r<1, 0>, "swp30_device::eq_filter_r<1, 0>", &swp30_device::eq_filter_w<1, 0>, "swp30_device::eq_filter_w<1, 0>"); - map(0x0050, 0x0051).select(0x1f80).rw(&swp30_device::eq_filter_r<1, 1>, "swp30_device::eq_filter_r<1, 1>", &swp30_device::eq_filter_w<1, 1>, "swp30_device::eq_filter_w<1, 1>"); - map(0x0054, 0x0055).select(0x1f80).rw(&swp30_device::eq_filter_r<1, 2>, "swp30_device::eq_filter_r<1, 2>", &swp30_device::eq_filter_w<1, 2>, "swp30_device::eq_filter_w<1, 2>"); - map(0x0064, 0x0065).select(0x1f80).rw(FUNC(swp30_device::pan_r), FUNC(swp30_device::pan_w)); - map(0x031c, 0x031d). rw(FUNC(swp30_device::keyon_mask_r<3>), FUNC(swp30_device::keyon_mask_w<3>)); - map(0x031e, 0x031f). rw(FUNC(swp30_device::keyon_mask_r<2>), FUNC(swp30_device::keyon_mask_w<2>)); - map(0x039c, 0x039d). rw(FUNC(swp30_device::keyon_mask_r<1>), FUNC(swp30_device::keyon_mask_w<1>)); - map(0x039e, 0x039f). rw(FUNC(swp30_device::keyon_mask_r<0>), FUNC(swp30_device::keyon_mask_w<0>)); - map(0x041c, 0x041d). rw(FUNC(swp30_device::keyon_r), FUNC(swp30_device::keyon_w)); - - map(0x1060, 0x1061). rw(&swp30_device::insertion_delay_r<0, 0>, "swp30_device::insertion_delay_r<0, 0>", &swp30_device::insertion_delay_w<0, 0>, "swp30_device::insertion_delay_w<0, 0>"); - map(0x1062, 0x1063). rw(&swp30_device::insertion_delay_r<0, 1>, "swp30_device::insertion_delay_r<0, 1>", &swp30_device::insertion_delay_w<0, 1>, "swp30_device::insertion_delay_w<0, 1>"); - map(0x10e0, 0x10e1). rw(&swp30_device::insertion_delay_r<0, 2>, "swp30_device::insertion_delay_r<0, 2>", &swp30_device::insertion_delay_w<0, 2>, "swp30_device::insertion_delay_w<0, 2>"); - map(0x10e2, 0x10e3). rw(&swp30_device::insertion_delay_r<0, 3>, "swp30_device::insertion_delay_r<0, 3>", &swp30_device::insertion_delay_w<0, 3>, "swp30_device::insertion_delay_w<0, 3>"); - map(0x1152, 0x1153). rw(&swp30_device::insertion_inv_high_damp_r<0, 0>, "swp30_device::insertion_inv_high_damp_r<0, 0>", &swp30_device::insertion_inv_high_damp_w<0, 0>, "swp30_device::insertion_inv_high_damp_w<0, 0>"); - map(0x1156, 0x1157). rw(&swp30_device::insertion_high_damp_r<0, 0>, "swp30_device::insertion_high_damp_r<0, 0>", &swp30_device::insertion_high_damp_w<0, 0>, "swp30_device::insertion_high_damp_w<0, 0>"); - map(0x11ca, 0x11cb). rw(&swp30_device::insertion_inv_high_damp_r<0, 1>, "swp30_device::insertion_inv_high_damp_r<0, 1>", &swp30_device::insertion_inv_high_damp_w<0, 1>, "swp30_device::insertion_inv_high_damp_w<0, 1>"); - map(0x11ce, 0x11cf). rw(&swp30_device::insertion_high_damp_r<0, 1>, "swp30_device::insertion_high_damp_r<0, 1>", &swp30_device::insertion_high_damp_w<0, 1>, "swp30_device::insertion_high_damp_w<0, 1>"); - map(0x1242, 0x1243). rw(&swp30_device::insertion_fb_level_r<0, 0>, "swp30_device::insertion_fb_level_r<0, 0>", &swp30_device::insertion_fb_level_w<0, 0>, "swp30_device::insertion_fb_level_w<0, 0>"); - map(0x1246, 0x1247). rw(&swp30_device::insertion_fb_level_r<0, 1>, "swp30_device::insertion_fb_level_r<0, 1>", &swp30_device::insertion_fb_level_w<0, 1>, "swp30_device::insertion_fb_level_w<0, 1>"); - map(0x124e, 0x124f). rw(&swp30_device::insertion_fb_level_r<0, 2>, "swp30_device::insertion_fb_level_r<0, 2>", &swp30_device::insertion_fb_level_w<0, 2>, "swp30_device::insertion_fb_level_w<0, 2>"); - map(0x12d6, 0x12d7). rw(&swp30_device::insertion_final_level_r<0, 0>, "swp30_device::insertion_final_level_r<0, 0>", &swp30_device::insertion_final_level_w<0, 0>, "swp30_device::insertion_final_level_w<0, 0>"); - map(0x1342, 0x1343). rw(&swp30_device::insertion_final_level_r<0, 1>, "swp30_device::insertion_final_level_r<0, 1>", &swp30_device::insertion_final_level_w<0, 1>, "swp30_device::insertion_final_level_w<0, 1>"); - map(0x1346, 0x1347). rw(&swp30_device::insertion_final_level_r<0, 2>, "swp30_device::insertion_final_level_r<0, 2>", &swp30_device::insertion_final_level_w<0, 2>, "swp30_device::insertion_final_level_w<0, 2>"); - map(0x134a, 0x134b). rw(&swp30_device::insertion_final_level_r<0, 3>, "swp30_device::insertion_final_level_r<0, 3>", &swp30_device::insertion_final_level_w<0, 3>, "swp30_device::insertion_final_level_w<0, 3>"); - - map(0x1460, 0x1461). rw(&swp30_device::insertion_delay_r<1, 0>, "swp30_device::insertion_delay_r<1, 0>", &swp30_device::insertion_delay_w<1, 0>, "swp30_device::insertion_delay_w<1, 0>"); - map(0x1462, 0x1463). rw(&swp30_device::insertion_delay_r<1, 1>, "swp30_device::insertion_delay_r<1, 1>", &swp30_device::insertion_delay_w<1, 1>, "swp30_device::insertion_delay_w<1, 1>"); - map(0x14e0, 0x14e1). rw(&swp30_device::insertion_delay_r<1, 2>, "swp30_device::insertion_delay_r<1, 2>", &swp30_device::insertion_delay_w<1, 2>, "swp30_device::insertion_delay_w<1, 2>"); - map(0x14e2, 0x14e3). rw(&swp30_device::insertion_delay_r<1, 3>, "swp30_device::insertion_delay_r<1, 3>", &swp30_device::insertion_delay_w<1, 3>, "swp30_device::insertion_delay_w<1, 3>"); - map(0x1552, 0x1553). rw(&swp30_device::insertion_inv_high_damp_r<1, 0>, "swp30_device::insertion_inv_high_damp_r<1, 0>", &swp30_device::insertion_inv_high_damp_w<1, 0>, "swp30_device::insertion_inv_high_damp_w<1, 0>"); - map(0x1556, 0x1557). rw(&swp30_device::insertion_high_damp_r<1, 0>, "swp30_device::insertion_high_damp_r<1, 0>", &swp30_device::insertion_high_damp_w<1, 0>, "swp30_device::insertion_high_damp_w<1, 0>"); - map(0x15ca, 0x15cb). rw(&swp30_device::insertion_inv_high_damp_r<1, 1>, "swp30_device::insertion_inv_high_damp_r<1, 1>", &swp30_device::insertion_inv_high_damp_w<1, 1>, "swp30_device::insertion_inv_high_damp_w<1, 1>"); - map(0x15ce, 0x15cf). rw(&swp30_device::insertion_high_damp_r<1, 1>, "swp30_device::insertion_high_damp_r<1, 1>", &swp30_device::insertion_high_damp_w<1, 1>, "swp30_device::insertion_high_damp_w<1, 1>"); - map(0x1642, 0x1643). rw(&swp30_device::insertion_fb_level_r<1, 0>, "swp30_device::insertion_fb_level_r<1, 0>", &swp30_device::insertion_fb_level_w<1, 0>, "swp30_device::insertion_fb_level_w<1, 0>"); - map(0x1646, 0x1647). rw(&swp30_device::insertion_fb_level_r<1, 1>, "swp30_device::insertion_fb_level_r<1, 1>", &swp30_device::insertion_fb_level_w<1, 1>, "swp30_device::insertion_fb_level_w<1, 1>"); - map(0x164e, 0x164f). rw(&swp30_device::insertion_fb_level_r<1, 2>, "swp30_device::insertion_fb_level_r<1, 2>", &swp30_device::insertion_fb_level_w<1, 2>, "swp30_device::insertion_fb_level_w<1, 2>"); - map(0x16d6, 0x16d7). rw(&swp30_device::insertion_final_level_r<1, 0>, "swp30_device::insertion_final_level_r<1, 0>", &swp30_device::insertion_final_level_w<1, 0>, "swp30_device::insertion_final_level_w<1, 0>"); - map(0x1742, 0x1743). rw(&swp30_device::insertion_final_level_r<1, 1>, "swp30_device::insertion_final_level_r<1, 1>", &swp30_device::insertion_final_level_w<1, 1>, "swp30_device::insertion_final_level_w<1, 1>"); - map(0x1746, 0x1747). rw(&swp30_device::insertion_final_level_r<1, 2>, "swp30_device::insertion_final_level_r<1, 2>", &swp30_device::insertion_final_level_w<1, 2>, "swp30_device::insertion_final_level_w<1, 2>"); - map(0x174a, 0x174b). rw(&swp30_device::insertion_final_level_r<1, 3>, "swp30_device::insertion_final_level_r<1, 3>", &swp30_device::insertion_final_level_w<1, 3>, "swp30_device::insertion_final_level_w<1, 3>"); - - map(0x18e0, 0x18e1). rw(FUNC(swp30_device::variation_delay_r<0>), FUNC(swp30_device::variation_delay_w<0>)); - map(0x1960, 0x1961). rw(FUNC(swp30_device::variation_delay_r<1>), FUNC(swp30_device::variation_delay_w<1>)); - map(0x19e0, 0x19e1). rw(FUNC(swp30_device::variation_delay_r<2>), FUNC(swp30_device::variation_delay_w<2>)); - map(0x1ae0, 0x1ae1). rw(FUNC(swp30_device::variation_delay_r<3>), FUNC(swp30_device::variation_delay_w<3>)); - map(0x1bd6, 0x1bd7). rw(FUNC(swp30_device::variation_inv_high_damp_r<0>), FUNC(swp30_device::variation_inv_high_damp_w<0>)); - map(0x1c46, 0x1c47). rw(FUNC(swp30_device::variation_high_damp_r<0>), FUNC(swp30_device::variation_high_damp_w<0>)); - map(0x1c52, 0x1c53). rw(FUNC(swp30_device::variation_inv_high_damp_r<1>), FUNC(swp30_device::variation_inv_high_damp_w<1>)); - map(0x1cc2, 0x1cc3). rw(FUNC(swp30_device::variation_high_damp_r<1>), FUNC(swp30_device::variation_high_damp_w<1>)); - map(0x1cce, 0x1ccf). rw(FUNC(swp30_device::variation_fb_level_r<0>), FUNC(swp30_device::variation_fb_level_w<0>)); - map(0x1cd2, 0x1cd3). rw(FUNC(swp30_device::variation_fb_level_r<1>), FUNC(swp30_device::variation_fb_level_w<1>)); - map(0x1d46, 0x1d47). rw(FUNC(swp30_device::variation_fb_level_r<2>), FUNC(swp30_device::variation_fb_level_w<2>)); - map(0x1f4a, 0x1f4b). rw(FUNC(swp30_device::variation_final_level_r<0>), FUNC(swp30_device::variation_final_level_w<0>)); - map(0x1f52, 0x1f53). rw(FUNC(swp30_device::variation_final_level_r<1>), FUNC(swp30_device::variation_final_level_w<1>)); - map(0x1f56, 0x1f57). rw(FUNC(swp30_device::variation_final_level_r<2>), FUNC(swp30_device::variation_final_level_w<2>)); - map(0x1fc6, 0x1fc7). rw(FUNC(swp30_device::variation_final_level_r<3>), FUNC(swp30_device::variation_final_level_w<3>)); - -} - + rchan(map, 0x00).rw(FUNC(swp30_device::lpf_cutoff_r), FUNC(swp30_device::lpf_cutoff_w)); + rchan(map, 0x01).rw(FUNC(swp30_device::lpf_cutoff_inc_r), FUNC(swp30_device::lpf_cutoff_inc_w)); + rchan(map, 0x02).rw(FUNC(swp30_device::hpf_cutoff_r), FUNC(swp30_device::hpf_cutoff_w)); + // 03 seems to always get 5010 except at startup where it's 40ff + rchan(map, 0x04).rw(FUNC(swp30_device::lpf_reso_r), FUNC(swp30_device::lpf_reso_w)); + // 05 missing + rchan(map, 0x06).rw(FUNC(swp30_device::envelope_r<0>), FUNC(swp30_device::envelope_w<0>)); + rchan(map, 0x07).rw(FUNC(swp30_device::envelope_r<1>), FUNC(swp30_device::envelope_w<1>)); + rchan(map, 0x08).rw(FUNC(swp30_device::envelope_r<2>), FUNC(swp30_device::envelope_w<2>)); + rchan(map, 0x09).rw(FUNC(swp30_device::volume_r), FUNC(swp30_device::volume_w)); + // 0a-0d missing + // 10 missing + rchan(map, 0x11).rw(FUNC(swp30_device::freq_r), FUNC(swp30_device::freq_w)); + rchan(map, 0x12).rw(FUNC(swp30_device::pre_size_h_r), FUNC(swp30_device::pre_size_h_w)); + rchan(map, 0x13).rw(FUNC(swp30_device::pre_size_l_r), FUNC(swp30_device::pre_size_l_w)); + rchan(map, 0x14).rw(FUNC(swp30_device::post_size_h_r), FUNC(swp30_device::post_size_h_w)); + rchan(map, 0x15).rw(FUNC(swp30_device::post_size_l_r), FUNC(swp30_device::post_size_l_w)); + rchan(map, 0x16).rw(FUNC(swp30_device::address_h_r), FUNC(swp30_device::address_h_w)); + rchan(map, 0x17).rw(FUNC(swp30_device::address_l_r), FUNC(swp30_device::address_l_w)); + rchan(map, 0x20).rw(FUNC(swp30_device::eq_filter_r<0>), FUNC(swp30_device::eq_filter_w<0>)); + rchan(map, 0x22).rw(FUNC(swp30_device::eq_filter_r<1>), FUNC(swp30_device::eq_filter_w<1>)); + rchan(map, 0x24).rw(FUNC(swp30_device::eq_filter_r<2>), FUNC(swp30_device::eq_filter_w<2>)); + rchan(map, 0x26).rw(FUNC(swp30_device::eq_filter_r<3>), FUNC(swp30_device::eq_filter_w<3>)); + rchan(map, 0x28).rw(FUNC(swp30_device::eq_filter_r<4>), FUNC(swp30_device::eq_filter_w<4>)); + rchan(map, 0x2a).rw(FUNC(swp30_device::eq_filter_r<5>), FUNC(swp30_device::eq_filter_w<5>)); + // 2c-2f missing + rchan(map, 0x32).rw(FUNC(swp30_device::pan_r), FUNC(swp30_device::pan_w)); + rchan(map, 0x33).rw(FUNC(swp30_device::dry_rev_r), FUNC(swp30_device::dry_rev_w)); + rchan(map, 0x34).rw(FUNC(swp30_device::cho_var_r), FUNC(swp30_device::cho_var_w)); + rchan(map, 0x35).rw(FUNC(swp30_device::routing_r<0>), FUNC(swp30_device::routing_w<0>)); + rchan(map, 0x36).rw(FUNC(swp30_device::routing_r<1>), FUNC(swp30_device::routing_w<1>)); + rchan(map, 0x37).rw(FUNC(swp30_device::routing_r<2>), FUNC(swp30_device::routing_w<2>)); + // 38-3d missing, are special + + // Control registers + // These appear as channel slots 0x0e and 0x0f + // 00-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>)); + rctrl(map, 0x0f).rw(FUNC(swp30_device::keyon_mask_r<0>), FUNC(swp30_device::keyon_mask_w<0>)); + rctrl(map, 0x10).rw(FUNC(swp30_device::keyon_r), FUNC(swp30_device::keyon_w)); + // 11-20 missing + rctrl(map, 0x21).rw(FUNC(swp30_device::prg_address_r), FUNC(swp30_device::prg_address_w)); + rctrl(map, 0x22).rw(FUNC(swp30_device::prg_r<0>), FUNC(swp30_device::prg_w<0>)); + rctrl(map, 0x23).rw(FUNC(swp30_device::prg_r<1>), FUNC(swp30_device::prg_w<1>)); + rctrl(map, 0x24).rw(FUNC(swp30_device::prg_r<2>), FUNC(swp30_device::prg_w<2>)); + rctrl(map, 0x25).rw(FUNC(swp30_device::prg_r<3>), FUNC(swp30_device::prg_w<3>)); + // 26-7f missing + rctrl(map, 0x30).rw(FUNC(swp30_device::map_r<0>), FUNC(swp30_device::map_w<0>)); + rctrl(map, 0x32).rw(FUNC(swp30_device::map_r<1>), FUNC(swp30_device::map_w<1>)); + rctrl(map, 0x34).rw(FUNC(swp30_device::map_r<2>), FUNC(swp30_device::map_w<2>)); + rctrl(map, 0x36).rw(FUNC(swp30_device::map_r<3>), FUNC(swp30_device::map_w<3>)); + rctrl(map, 0x38).rw(FUNC(swp30_device::map_r<4>), FUNC(swp30_device::map_w<4>)); + rctrl(map, 0x3a).rw(FUNC(swp30_device::map_r<5>), FUNC(swp30_device::map_w<5>)); + rctrl(map, 0x3c).rw(FUNC(swp30_device::map_r<6>), FUNC(swp30_device::map_w<6>)); + rctrl(map, 0x3e).rw(FUNC(swp30_device::map_r<7>), FUNC(swp30_device::map_w<7>)); + + // MEG registers + rchan(map, 0x21).rw(FUNC(swp30_device::prg_fp_r<0>), FUNC(swp30_device::prg_fp_w<0>)); + rchan(map, 0x23).rw(FUNC(swp30_device::prg_fp_r<1>), FUNC(swp30_device::prg_fp_w<1>)); + rchan(map, 0x25).rw(FUNC(swp30_device::prg_fp_r<2>), FUNC(swp30_device::prg_fp_w<2>)); + rchan(map, 0x27).rw(FUNC(swp30_device::prg_fp_r<3>), FUNC(swp30_device::prg_fp_w<3>)); + rchan(map, 0x29).rw(FUNC(swp30_device::prg_fp_r<4>), FUNC(swp30_device::prg_fp_w<4>)); + rchan(map, 0x2b).rw(FUNC(swp30_device::prg_fp_r<5>), FUNC(swp30_device::prg_fp_w<5>)); + rchan(map, 0x30).rw(FUNC(swp30_device::prg_int_r<0>), FUNC(swp30_device::prg_int_w<0>)); + rchan(map, 0x31).rw(FUNC(swp30_device::prg_int_r<1>), FUNC(swp30_device::prg_int_w<1>)); + rchan(map, 0x3e).rw(FUNC(swp30_device::prg_lfo_r<0>), FUNC(swp30_device::prg_lfo_w<0>)); + rchan(map, 0x3f).rw(FUNC(swp30_device::prg_lfo_r<1>), FUNC(swp30_device::prg_lfo_w<1>)); +} + +// Control registers template u16 swp30_device::keyon_mask_r() { return m_keyon_mask >> (16*sel); @@ -268,7 +329,6 @@ u16 swp30_device::keyon_r() return 0; } -static int ncount = 0; void swp30_device::keyon_w(u16) { m_stream->update(); @@ -276,14 +336,60 @@ void swp30_device::keyon_w(u16) u64 mask = u64(1) << i; if((m_keyon_mask & mask) && !(m_active_mask & mask) && !(m_volume[i] & 0x8000)) { m_sample_pos[i] = -s32(m_pre_size[i] << 8); - logerror("sample count %3d %02x %08x %08x %08x vol %04x pan %04x\n", ncount, i, m_pre_size[i], m_post_size[i], m_address[i], m_volume[i], m_pan[i]); + logerror("keyon %02x %08x %08x %08x vol %04x pan %04x\n", i, m_pre_size[i], m_post_size[i], m_address[i], m_volume[i], m_pan[i]); m_active_mask |= mask; - ncount++; } } m_keyon_mask = 0; } + +u16 swp30_device::prg_address_r() +{ + return m_program_address; +} + +void swp30_device::prg_address_w(u16 data) +{ + m_program_address = data; + if(m_program_address >= 0x180) + m_program_address = 0; +} + +template u16 swp30_device::prg_r() +{ + constexpr offs_t shift = 48-16*sel; + return m_program[m_program_address] >> shift; +} + +template void swp30_device::prg_w(u16 data) +{ + constexpr offs_t shift = 48-16*sel; + constexpr u64 mask = ~(u64(0xffff) << shift); + m_program[m_program_address] = (m_program[m_program_address] & mask) | (u64(data) << shift); + + if(sel == 3) { + logerror("program %03x %016x\n", m_program_address, m_program[m_program_address]); + m_program_address ++; + if(m_program_address == 0x180) + m_program_address = 0; + } +} + + +template u16 swp30_device::map_r() +{ + return m_map[sel]; +} + +template void swp30_device::map_w(u16 data) +{ + m_map[sel] = data; + logerror("map %d: type=%02x offset=%05x size=%05x\n", sel, data >> 11, (data & 0xff) << 10, 0x400 << ((data >> 8) & 7)); +} + + +// AWM2 per-channel registers u16 swp30_device::lpf_cutoff_r(offs_t offset) { return m_lpf_cutoff[offset >> 6]; @@ -293,11 +399,25 @@ void swp30_device::lpf_cutoff_w(offs_t offset, u16 data) { m_stream->update(); u8 chan = offset >> 6; - if(m_lpf_cutoff[chan] != data) + if(m_lpf_cutoff[chan] != data && 0) logerror("chan %02x lpf cutoff %04x\n", chan, data); m_lpf_cutoff[chan] = data; } +u16 swp30_device::lpf_cutoff_inc_r(offs_t offset) +{ + return m_lpf_cutoff_inc[offset >> 6]; +} + +void swp30_device::lpf_cutoff_inc_w(offs_t offset, u16 data) +{ + m_stream->update(); + u8 chan = offset >> 6; + if(m_lpf_cutoff_inc[chan] != data && 0) + logerror("chan %02x lpf cutoff increment %04x\n", chan, data); + m_lpf_cutoff_inc[chan] = data; +} + u16 swp30_device::hpf_cutoff_r(offs_t offset) { return m_hpf_cutoff[offset >> 6]; @@ -326,17 +446,27 @@ void swp30_device::lpf_reso_w(offs_t offset, u16 data) m_lpf_reso[chan] = data; } -template u16 swp30_device::eq_filter_r(offs_t offset) +template u16 swp30_device::eq_filter_r(offs_t offset) { - return m_eq_filter[offset >> 6][filter][coef]; + return m_eq_filter[offset >> 6][coef]; } -template void swp30_device::eq_filter_w(offs_t offset, u16 data) +template void swp30_device::eq_filter_w(offs_t offset, u16 data) { m_stream->update(); - m_eq_filter[offset >> 6][filter][coef] = data; + m_eq_filter[offset >> 6][coef] = data; } +template u16 swp30_device::routing_r(offs_t offset) +{ + return m_routing[offset >> 6][sel]; +} + +template void swp30_device::routing_w(offs_t offset, u16 data) +{ + m_stream->update(); + m_routing[offset >> 6][sel] = data; +} u16 swp30_device::volume_r(offs_t offset) { @@ -351,8 +481,12 @@ void swp30_device::volume_w(offs_t offset, u16 data) if(m_volume[chan] != data) logerror("snd chan %02x volume %02x %02x\n", chan, data >> 8, data & 0xff); m_volume[chan] = data; - if(data & 0x8000) - m_active_mask &= ~(u64(1) << chan); + if(data & 0x8000) { + if(m_active_mask & (u64(1) << chan)) { + if(m_post_size[chan]) + m_active_mask &= ~(u64(1) << chan); + } + } } @@ -364,213 +498,211 @@ u16 swp30_device::pan_r(offs_t offset) void swp30_device::pan_w(offs_t offset, u16 data) { u8 chan = offset >> 6; - double p1 = pow(2, -(data >> 8)/16.0); - double p2 = pow(2, -(data & 0xff)/16.0); if(m_pan[chan] != data) - logerror("snd chan %02x pan l %02x r %02x (%g %g %g)\n", chan, data >> 8, data & 0xff, p1, p2, sqrt(p1*p1+p2*p2)); + logerror("snd chan %02x pan l %02x r %02x\n", chan, data >> 8, data & 0xff); m_pan[chan] = data; } -u16 swp30_device::freq_r(offs_t offset) +u16 swp30_device::dry_rev_r(offs_t offset) { - return m_freq[offset >> 6]; + return m_dry_rev[offset >> 6]; } -void swp30_device::freq_w(offs_t offset, u16 data) +void swp30_device::dry_rev_w(offs_t offset, u16 data) { u8 chan = offset >> 6; - // delta is 4*256 per octave, positive means higher freq, e.g 4.10 format. - s16 v = data & 0x2000 ? data | 0xc000 : data; - if(m_freq[chan] != data) - logerror("snd chan %02x freq %c%c %d.%03x\n", chan, data & 0x8000 ? '#' : '.', data & 0x4000 ? '#' : '.', v / 1024, (v < 0 ? -v : v) & 0x3ff); - m_freq[chan] = data; + if(m_dry_rev[chan] != data) + logerror("snd chan %02x dry %02x rev %02x\n", chan, data >> 8, data & 0xff); + m_dry_rev[chan] = data; } -u16 swp30_device::pre_size_r(offs_t offset) +u16 swp30_device::cho_var_r(offs_t offset) { - if(offset & 1) - return m_pre_size[offset >> 6]; - else - return m_pre_size[offset >> 6] >> 16; + return m_dry_rev[offset >> 6]; } -void swp30_device::pre_size_w(offs_t offset, u16 data) +void swp30_device::cho_var_w(offs_t offset, u16 data) { u8 chan = offset >> 6; - if(offset & 1) { - m_pre_size[chan] = (m_pre_size[chan] & 0xffff0000) | data; - logerror("snd chan %02x pre-size %02x %06x\n", chan, m_pre_size[chan] >> 24, m_pre_size[chan] & 0xffffff); - } else - m_pre_size[chan] = (m_pre_size[chan] & 0x0000ffff) | (data << 16); + if(m_dry_rev[chan] != data) + logerror("snd chan %02x cho %02x var %02x\n", chan, data >> 8, data & 0xff); + m_dry_rev[chan] = data; } -u16 swp30_device::post_size_r(offs_t offset) +u16 swp30_device::freq_r(offs_t offset) { - if(offset & 1) - return m_post_size[offset >> 6]; - else - return m_post_size[offset >> 6] >> 16; + return m_freq[offset >> 6]; } -void swp30_device::post_size_w(offs_t offset, u16 data) +void swp30_device::freq_w(offs_t offset, u16 data) { u8 chan = offset >> 6; - if(offset & 1) { - m_post_size[chan] = (m_post_size[chan] & 0xffff0000) | data; - logerror("snd chan %02x post-size %02x %06x\n", chan, m_post_size[chan] >> 24, m_post_size[chan] & 0xffffff); - } else - m_post_size[chan] = (m_post_size[chan] & 0x0000ffff) | (data << 16); + // delta is 4*256 per octave, positive means higher freq, e.g 4.10 format. + s16 v = data & 0x2000 ? data | 0xc000 : data; + if(m_freq[chan] != data) + logerror("snd chan %02x freq %c%c %d.%03x\n", chan, data & 0x8000 ? '#' : '.', data & 0x4000 ? '#' : '.', v / 1024, (v < 0 ? -v : v) & 0x3ff); + m_freq[chan] = data; } -u16 swp30_device::address_r(offs_t offset) +template u16 swp30_device::envelope_r(offs_t offset) { - if(offset & 1) - return m_address[offset >> 6]; - else - return m_address[offset >> 6] >> 16; + return m_envelope[offset >> 6][sel]; } -void swp30_device::address_w(offs_t offset, u16 data) +template void swp30_device::envelope_w(offs_t offset, u16 data) { u8 chan = offset >> 6; - if(offset & 1) { - // The address may be 25 bits - static const char *const formats[4] = { "l16", "l12", "l8", "x8" }; - m_address[chan] = (m_address[chan] & 0xffff0000) | 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); - } else - m_address[chan] = (m_address[chan] & 0x0000ffff) | (data << 16); + bool ch = m_envelope[chan][sel] != data; + m_envelope[chan][sel] = data; + if(ch) + logerror("snd chan %02x envelopes %04x %04x %04x\n", chan, m_envelope[chan][0], m_envelope[chan][1], m_envelope[chan][2]); } -template void swp30_device::variation_delay_w(u16 data) +u16 swp30_device::pre_size_h_r(offs_t offset) { - m_variation_delay[id] = data; - logerror("variation delay %d: %04x (%fms)\n", id, data, data/44.100); + return m_pre_size[offset >> 6] >> 16; } -template u16 swp30_device::variation_delay_r() +u16 swp30_device::pre_size_l_r(offs_t offset) { - return m_variation_delay[id]; + return m_pre_size[offset >> 6]; } -template void swp30_device::variation_fb_level_w(u16 data) +void swp30_device::pre_size_h_w(offs_t offset, u16 data) { - m_variation_fb_level[id] = data; - logerror("variation feedback level %d: %04x (%+f)\n", id, data, s16(data)/500.0); + u8 chan = offset >> 6; + m_pre_size[chan] = (m_pre_size[chan] & 0x0000ffff) | (data << 16); } -template u16 swp30_device::variation_fb_level_r() +void swp30_device::pre_size_l_w(offs_t offset, u16 data) { - return m_variation_fb_level[id]; + u8 chan = offset >> 6; + m_pre_size[chan] = (m_pre_size[chan] & 0xffff0000) | data; + logerror("snd chan %02x pre-size %02x %06x\n", chan, m_pre_size[chan] >> 24, m_pre_size[chan] & 0xffffff); } -template void swp30_device::variation_final_level_w(u16 data) +u16 swp30_device::post_size_h_r(offs_t offset) { - m_variation_final_level[id] = data; - logerror("variation final level %s %s: %04x (%f)\n", id & 1 ? "wet" : "dry", id & 2 ? "left" : "right", data, data/16383.0); + return m_post_size[offset >> 6] >> 16; } -template u16 swp30_device::variation_final_level_r() +u16 swp30_device::post_size_l_r(offs_t offset) { - return m_variation_final_level[id]; + return m_post_size[offset >> 6]; } -template void swp30_device::variation_high_damp_w(u16 data) +void swp30_device::post_size_h_w(offs_t offset, u16 data) { - m_variation_high_damp[id] = data; - logerror("variation high damp %d: %04x (%f)\n", id, data, 0.1+double(data-0x2000)/0x2000*0.9); + u8 chan = offset >> 6; + m_post_size[chan] = (m_post_size[chan] & 0x0000ffff) | (data << 16); } -template u16 swp30_device::variation_high_damp_r() +void swp30_device::post_size_l_w(offs_t offset, u16 data) { - return m_variation_high_damp[id]; + u8 chan = offset >> 6; + m_post_size[chan] = (m_post_size[chan] & 0xffff0000) | data; + logerror("snd chan %02x post-size %02x %06x\n", chan, m_post_size[chan] >> 24, m_post_size[chan] & 0xffffff); } -template void swp30_device::variation_inv_high_damp_w(u16 data) +u16 swp30_device::address_h_r(offs_t offset) { - m_variation_inv_high_damp[id] = data; - logerror("variation inverse high damp %d: %04x (%f)\n", id, data, 0.1+double(0x2000-data)/0x2000*0.9); + return m_address[offset >> 6] >> 16; } -template u16 swp30_device::variation_inv_high_damp_r() +u16 swp30_device::address_l_r(offs_t offset) { - return m_variation_inv_high_damp[id]; + return m_address[offset >> 6]; } - -template void swp30_device::insertion_delay_w(u16 data) +void swp30_device::address_h_w(offs_t offset, u16 data) { - m_insertion_delay[ins][id] = data; - logerror("insertion %d delay %d: %04x (%fms)\n", ins, id, data, data/44.100); + u8 chan = offset >> 6; + m_address[chan] = (m_address[chan] & 0x0000ffff) | (data << 16); } -template u16 swp30_device::insertion_delay_r() +void swp30_device::address_l_w(offs_t offset, u16 data) { - return m_insertion_delay[ins][id]; + u8 chan = offset >> 6; + // The address probably is 25 bits + static const char *const formats[4] = { "l16", "l12", "l8", "x8" }; + m_address[chan] = (m_address[chan] & 0xffff0000) | 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); } -template void swp30_device::insertion_fb_level_w(u16 data) -{ - m_insertion_fb_level[ins][id] = data; - logerror("insertion %d feedback level %d: %04x (%+f)\n", ins, id, data, s16(data)/500.0); -} -template u16 swp30_device::insertion_fb_level_r() -{ - return m_insertion_fb_level[ins][id]; -} +// MEG registers (Multiple Effects Generator) -template void swp30_device::insertion_final_level_w(u16 data) +template u16 swp30_device::prg_fp_r(offs_t offset) { - m_insertion_final_level[ins][id] = data; - logerror("insertion %d final level %s %s: %04x (%f)\n", ins, id & 1 ? "wet" : "dry", id & 2 ? "left" : "right", data, data/8191.0); + offs_t adr = (offset >> 6)*6 + sel; + return m_program_pfp[adr]; } -template u16 swp30_device::insertion_final_level_r() +template void swp30_device::prg_fp_w(offs_t offset, u16 data) { - return m_insertion_final_level[ins][id]; + offs_t adr = (offset >> 6)*6 + sel; + m_program_pfp[adr] = data; + logerror("prg_fp_w %03x, %04x\n", adr, data); } -template void swp30_device::insertion_high_damp_w(u16 data) +template u16 swp30_device::prg_int_r(offs_t offset) { - m_insertion_high_damp[ins][id] = data; - logerror("insertion %d high damp %d: %04x (%f)\n", ins, id, data, 0.1+double(data-0x4000)/0x4000*0.9); + offs_t adr = (offset >> 6)*2 + sel; + return m_program_pint[adr]; } -template u16 swp30_device::insertion_high_damp_r() +template void swp30_device::prg_int_w(offs_t offset, u16 data) { - return m_insertion_high_damp[ins][id]; + offs_t adr = (offset >> 6)*2 + sel; + m_program_pint[adr] = data; + logerror("prg_int_w %02x, %04x\n", adr, data); } -template void swp30_device::insertion_inv_high_damp_w(u16 data) +template u16 swp30_device::prg_lfo_r(offs_t offset) { - m_insertion_inv_high_damp[ins][id] = data; - logerror("insertion %s inverse high damp %d: %04x (%f)\n", ins, id, data, 0.1+double(0x4000-data)/0x4000*0.9); + offs_t adr = (offset >> 6)*2 + sel; + return m_program_plfo[adr]; } -template u16 swp30_device::insertion_inv_high_damp_r() +template void swp30_device::prg_lfo_w(offs_t offset, u16 data) { - return m_insertion_inv_high_damp[ins][id]; + offs_t adr = (offset >> 6)*2 + sel; + m_program_plfo[adr] = data; + + static const int dt[8] = { 0, 32, 64, 128, 256, 512, 1024, 2048 }; + static const int sh[8] = { 0, 0, 1, 2, 3, 4, 5, 6 }; + + int scale = (data >> 5) & 7; + int step = ((data & 31) << sh[scale]) + dt[scale]; + logerror("prg_lfo_w %02x freq=%5.2f phase=%6.4f\n", adr, step * 44100.0/4194304, (data >> 8)/256.0); } +// Catch-all + static u16 rr[0x40*0x40]; u16 swp30_device::snd_r(offs_t offset) { - if(0) { + if(1) { int chan = (offset >> 6) & 0x3f; int slot = offset & 0x3f; std::string preg = "-"; if(slot >= 0x21 && slot <= 0x2b && (slot & 1)) - preg = util::string_format("%03x", (slot-0x21)/2 + 6*chan); - logerror("snd_r [%04x %04x - %-4s] %02x.%02x %04x\n", offset, offset*2, preg, chan, slot, rr[offset]); - } - if(offset == 0x080f) { - return rr[offset] & ~8; - // return chan == 0x20 && slot == 0xf ? 0 : 0xffff; + preg = util::string_format("fp%03x", (slot-0x21)/2 + 6*chan); + else if(slot == 0x30 || slot == 0x31) + preg = util::string_format("dt%02x", (slot-0x30) + 2*chan); + else if(slot == 0x0e || slot == 0x0f) + preg = util::string_format("ct%02x", (slot-0x0e) + 2*chan); + else + preg = util::string_format("%02x.%02x", chan, slot); + logerror("snd_r [%04x %04x] %-5s, %04x\n", offset, offset*2, preg, rr[offset]); } + if(0 && offset == 0x080f) + machine().debug_break(); + if(offset == 0x080f) + return 0; return rr[offset]; } @@ -578,25 +710,45 @@ void swp30_device::snd_w(offs_t offset, u16 data) { if(rr[offset] == data) return; - if(offset == 0x4e && (data ^ rr[offset]) == 0x400) { - rr[offset] = data; - return; - } + rr[offset] = data; - if(offset == 0x4e) - return; + int chan = (offset >> 6) & 0x3f; int slot = offset & 0x3f; + + if(offset == 0x04e) + return; + + if(0 && slot == 0x03) + machine().debug_break(); + std::string preg = "-"; if(slot >= 0x21 && slot <= 0x2b && (slot & 1)) - preg = util::string_format("%03x", (slot-0x21)/2 + 6*chan); - logerror("snd_w [%04x %04x - %-4s] %02x.%02x, %04x\n", offset, offset*2, preg, chan, slot, data); + preg = util::string_format("fp%03x", (slot-0x21)/2 + 6*chan); + else if(slot == 0x0e || slot == 0x0f) + preg = util::string_format("sy%02x", (slot-0x0e) + 2*chan); + else if(slot == 0x30 || slot == 0x31) + preg = util::string_format("dt%02x", (slot-0x30) + 2*chan); + else if(slot == 0x38) + preg = util::string_format("vl%02x", chan); + else if(slot == 0x3e || slot == 0x3f) + 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(); + + logerror("snd_w [%04x %04x] %-5s, %04x\n", offset, offset*2, preg, data); } + + +// Synthesis + void swp30_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) { // Loop first on the samples and not on the channels otherwise - // effects will be impossible to implement. + // effects will be annoying to implement. for(int sample = 0; sample < samples; sample++) { // Accumulate on 64 bits, shift/clamp at the end @@ -661,7 +813,7 @@ void swp30_device::sound_stream_update(sound_stream &stream, stream_sample_t **i // 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; + 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 @@ -677,12 +829,12 @@ void swp30_device::sound_stream_update(sound_stream &stream, stream_sample_t **i // - missing lpf_cutoff, lpf_reso, hpf_cutoff // - eq lowpass - s32 samp1 = (samp * m_eq_filter[channel][0][2] + m_sample_history[channel][0][0] * m_eq_filter[channel][0][1] + m_sample_history[channel][0][1] * m_eq_filter[channel][0][0]) >> 13; + 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][1][2] + m_sample_history[channel][1][0] * m_eq_filter[channel][1][1] + m_sample_history[channel][1][1] * m_eq_filter[channel][1][0]) >> 13; + 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; @@ -700,7 +852,7 @@ void swp30_device::sound_stream_update(sound_stream &stream, stream_sample_t **i } // Samples are 16 bits, there are up to 64 of them, and the accumulators are fixed-point signed 48.16 - // Global EQ is missing + // Global EQ is missing (it's done in the MEG) acc_left >>= (16+6); if(acc_left < -0x8000) diff --git a/src/devices/sound/swp30.h b/src/devices/sound/swp30.h index b33cd99299a..56e24b453f0 100644 --- a/src/devices/sound/swp30.h +++ b/src/devices/sound/swp30.h @@ -11,7 +11,7 @@ class swp30_device : public device_t, public device_sound_interface, public device_rom_interface { public: - swp30_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0); + swp30_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 33868800); void map(address_map &map); @@ -28,75 +28,95 @@ private: s32 m_linear_attenuation[0x100]; s16 m_sample_log8[0x100]; + u64 m_program[0x180]; u64 m_keyon_mask, m_active_mask; u32 m_pre_size[0x40], m_post_size[0x40], m_address[0x40]; s32 m_sample_pos[64]; s32 m_sample_history[0x40][2][2]; - u16 m_volume[0x40], m_freq[0x40], m_pan[0x40]; - u16 m_lpf_cutoff[0x40], m_lpf_reso[0x40], m_hpf_cutoff[0x40]; - s16 m_eq_filter[0x40][2][3]; + u16 m_program_pfp[0x180], m_program_pint[0x80], m_program_plfo[0x80]; - u16 m_variation_delay[4]; - u16 m_variation_fb_level[3]; - u16 m_variation_final_level[4]; - u16 m_variation_high_damp[2], m_variation_inv_high_damp[2]; + u16 m_volume[0x40], m_freq[0x40], m_pan[0x40], m_dry_rev[0x40], m_cho_var[0x40]; + u16 m_envelope[0x40][3]; + u16 m_lpf_cutoff[0x40], m_lpf_cutoff_inc[0x40], m_lpf_reso[0x40], m_hpf_cutoff[0x40]; + s16 m_eq_filter[0x40][6]; + u16 m_routing[0x40][3]; + u16 m_map[8]; - u16 m_insertion_delay[2][4]; - u16 m_insertion_fb_level[2][3]; - u16 m_insertion_final_level[2][4]; - u16 m_insertion_high_damp[2][2], m_insertion_inv_high_damp[2][2]; + u16 m_program_address; + // AWM2 per-channel registers u16 lpf_cutoff_r(offs_t offset); void lpf_cutoff_w(offs_t offset, u16 data); + u16 lpf_cutoff_inc_r(offs_t offset); + void lpf_cutoff_inc_w(offs_t offset, u16 data); u16 hpf_cutoff_r(offs_t offset); void hpf_cutoff_w(offs_t offset, u16 data); u16 lpf_reso_r(offs_t offset); void lpf_reso_w(offs_t offset, u16 data); - template u16 eq_filter_r(offs_t offset); - template void eq_filter_w(offs_t offset, u16 data); + template u16 envelope_r(offs_t offset); + template void envelope_w(offs_t offset, u16 data); + template u16 eq_filter_r(offs_t offset); + template void eq_filter_w(offs_t offset, u16 data); u16 volume_r(offs_t offset); void volume_w(offs_t offset, u16 data); u16 freq_r(offs_t offset); void freq_w(offs_t offset, u16 data); - u16 pre_size_r(offs_t offset); - void pre_size_w(offs_t offset, u16 data); - u16 post_size_r(offs_t offset); - void post_size_w(offs_t offset, u16 data); - u16 address_r(offs_t offset); - void address_w(offs_t offset, u16 data); + u16 pre_size_h_r(offs_t offset); + u16 pre_size_l_r(offs_t offset); + void pre_size_h_w(offs_t offset, u16 data); + void pre_size_l_w(offs_t offset, u16 data); + u16 post_size_h_r(offs_t offset); + u16 post_size_l_r(offs_t offset); + void post_size_h_w(offs_t offset, u16 data); + void post_size_l_w(offs_t offset, u16 data); + u16 address_h_r(offs_t offset); + u16 address_l_r(offs_t offset); + void address_h_w(offs_t offset, u16 data); + void address_l_w(offs_t offset, u16 data); u16 pan_r(offs_t offset); void pan_w(offs_t offset, u16 data); + u16 dry_rev_r(offs_t offset); + 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); + template u16 routing_r(offs_t offset); + template void routing_w(offs_t offset, u16 data); + + // Control registers template u16 keyon_mask_r(); template void keyon_mask_w(u16 data); u16 keyon_r(); void keyon_w(u16); - - template void variation_delay_w(u16 data); - template u16 variation_delay_r(); - template void variation_fb_level_w(u16 data); - template u16 variation_fb_level_r(); - template void variation_final_level_w(u16 data); - template u16 variation_final_level_r(); - template void variation_high_damp_w(u16 data); - template u16 variation_high_damp_r(); - template void variation_inv_high_damp_w(u16 data); - template u16 variation_inv_high_damp_r(); - - template void insertion_delay_w(u16 data); - template u16 insertion_delay_r(); - template void insertion_fb_level_w(u16 data); - template u16 insertion_fb_level_r(); - template void insertion_final_level_w(u16 data); - template u16 insertion_final_level_r(); - template void insertion_high_damp_w(u16 data); - template u16 insertion_high_damp_r(); - template void insertion_inv_high_damp_w(u16 data); - template u16 insertion_inv_high_damp_r(); - + u16 prg_address_r(); + void prg_address_w(u16 data); + template u16 prg_r(); + template void prg_w(u16 data); + template u16 map_r(); + template void map_w(u16 data); + + // MEG registers + template u16 prg_fp_r(offs_t offset); + template void prg_fp_w(offs_t offset, u16 data); + template u16 prg_int_r(offs_t offset); + template void prg_int_w(offs_t offset, u16 data); + template u16 prg_lfo_r(offs_t offset); + template void prg_lfo_w(offs_t offset, u16 data); + + + // Generic catch-all u16 snd_r(offs_t offset); void snd_w(offs_t offset, u16 data); + + inline auto &rchan(address_map &map, int idx) { + return map(idx*2, idx*2+1).select(0x1f80); + } + + inline auto &rctrl(address_map &map, int idx) { + int slot = 0x40*(idx >> 1) | 0xe | (idx & 1); + return map(slot*2, slot*2+1); + } }; DECLARE_DEVICE_TYPE(SWP30, swp30_device) diff --git a/src/emu/debug/debugcpu.cpp b/src/emu/debug/debugcpu.cpp index c3e4ece9470..73739a44411 100644 --- a/src/emu/debug/debugcpu.cpp +++ b/src/emu/debug/debugcpu.cpp @@ -2895,12 +2895,12 @@ void device_debug::watchpoint::setEnabled(bool value) void device_debug::watchpoint::install(read_or_write mode) { - if(m_installing) + if (m_installing) return; m_installing = true; - if ((u32(mode) & u32(read_or_write::READ) && m_phr) + if ((u32(mode) & u32(read_or_write::READ)) && m_phr) m_phr->remove(); - if ((u32(mode) & u32(read_or_write::WRITE) && m_phw) + if ((u32(mode) & u32(read_or_write::WRITE)) && m_phw) m_phw->remove(); std::string name = util::string_format("wp@%x", m_address); switch (m_space.data_width()) diff --git a/src/mame/drivers/ymmu100.cpp b/src/mame/drivers/ymmu100.cpp index c0e258aa305..9fa97e92680 100644 --- a/src/mame/drivers/ymmu100.cpp +++ b/src/mame/drivers/ymmu100.cpp @@ -6,7 +6,7 @@ Preliminary driver by R. Belmont and O. Galibert CPU: Hitachi H8S/2655 (HD6432655F), strapped for mode 4 (24-bit address, 16-bit data, no internal ROM) - Sound ASIC: Yamaha XS725A0 + Sound ASIC: Yamaha XS725A0/SWP30 RAM: 1 MSM51008 (1 meg * 1 bit = 128KBytes) I/O ports from service manual: @@ -149,105 +149,6 @@ static INPUT_PORTS_START( mu100 ) PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_UNUSED) INPUT_PORTS_END -/* 40 41 42 43 - -reads - .09 at 3e5a, tests & 0x8000 - .05 at 3e4a: read current to change bits (sets xaxx) - .0a at 4070: read current to change bits (keeps 14-15) - -01.0f at d320: put bits 6-13 in r0l inverted, bits 14-15 in r0h 6-7, does complex calcs from it - - - -[:] snd_w 00.09, f000 (0020a0) -[:] snd_w 00.10, 4000 (00d376) -[:] snd_w 00.00, 169b (00d3be) -[:] snd_w 00.01, e0ff (00d3d0) -[:] snd_w 00.02, 8000 (00d3f8) -[:] snd_w 00.03, 5010 (00d400) -[:] snd_w 00.04, 0000 (00d412) -[:] snd_w 00.05, fb00 (00d434) -[:] snd_w 00.20, e05d (00d43e) -[:] snd_w 00.22, 1fa3 (00d448) -[:] snd_w 00.24, 2000 (00d452) -[:] snd_w 00.26, 0257 (00d45c) -[:] snd_w 00.28, fda9 (00d466) -[:] snd_w 00.2a, 2000 (00d470) -[:] snd_w 00.06, 5d80 (00d48e) -[:] snd_w 00.07, 1414 (00d4ae) 1614 1614 1614 -[:] snd_w 00.08, 18fe (00d4ce) 1afe 1afe 1afe -[:] snd_w 00.0a, 5f00 (00d510) -[:] snd_w 00.0b, 0000 (00d530) -[:] snd_w 00.0b, 6f00 (00d53a) -[:] snd_w 00.11, be29 (00d54e) be7e bdd2 be27 -[:] snd_w 00.12, 0000 (00d56c) -[:] snd_w 00.13, 5c74 (00d570) 6f0b -[:] snd_w 00.14, 0000 (00d586) -[:] snd_w 00.15, 749d (00d58a) 749d 5951 5951 -[:] snd_w 00.16, ee42 (00d5d6) -[:] snd_w 00.17, a89b (00d5da) -[:] snd_w 00.32, 0808 (00d5ea) -[:] snd_w 00.33, 182b (00d5fa) -[:] snd_w 00.34, ff10 (00d60a) -[:] snd_w 00.35, 0d00 (00d614) -[:] snd_w 00.36, 0800 (00d61e) -[:] snd_w 00.37, 0400 (00d628) -[:] snd_w 00.09, 70e0 (00d634) -[:] snd_r 00.0b (00d638) -[:] snd_r 00.0b (00d63c) -[:] snd_r 00.09 (00d658) -[:] snd_r 00.09 (00d65c) - - e3 = (note - ->m1b) * 100 + s8(->m2b) - - compute freq adjustment in 1/100th of semitone (ex. 737) -clamp to +/- 9599 -(2d74) -div/rem by 300 -> e6 = 137, r6 = 2 -lookup d14c[rem].b (0-299 -> 00-ff, perfectly linear), tack div on top -> 274 -put sign back in, and with 3fff, -> g58 - - - - - - - 9 = attenuation? -11 = 52|58 -> 15 flag, 14 zero, 13-0 cents frequency adjustment -12-13 = pre-size + flags -14-15 = post-size + flags -16-17 = address + flags + loop size? -32 = 6a/6b = pan l/r -33 = 6c/6d = ? / reverb attenuation -34 = 6e/6f = chorus attenuation / ? -35 = 70 -36 = 72 -37 = 74 -3e = ? / chorus lfo frequency -3f = ? / chorus lfo frequency - -09 = 0x7000 + 4c -read 0b twice, store the second is 2114c7 - -d510: - r6 = ffec54 (0) - if(!0) { ... } - r5 = r6 - +0b = r5 - r5h = ffec50 - +0b = r5 - +11 = ffec58 | (ffec52 << 8) - +12, +13 = ffec5c.l | (ffec5a << 24) - +14, +15 = ffec60.l | (ffec64 << 24) - -50: 6f 40 80 00 00 00 00 00 3e 27 00 00 00 00 6f 0b -60: 00 00 59 51 00 ee 00 42 e1 87 08 08 18 2b ff 10 - -2e1c computes everything - -*/ - class mu100_state : public driver_device { public: @@ -264,21 +165,101 @@ public: int seq; + void regs_s1_write_tap(offs_t address, u16 data, u16 mem_mask); + void regs_s2_write_tap(offs_t address, u16 data, u16 mem_mask); + void regs_s3_write_tap(offs_t address, u16 data, u16 mem_mask); + void regs_s4a_write_tap(offs_t address, u16 data, u16 mem_mask); + void regs_s4b_write_tap(offs_t address, u16 data, u16 mem_mask); + void regs_s4c_write_tap(offs_t address, u16 data, u16 mem_mask); + void regs_lfo_write_tap(offs_t address, u16 data, u16 mem_mask); + void regs_s6_write_tap(offs_t address, u16 data, u16 mem_mask); + void regs_fp_read_tap(offs_t address, u16 data, u16 mem_mask); + void regs_fp_write_tap(offs_t address, u16 data, u16 mem_mask); + 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 chan_write_tap(offs_t address, u16 data, u16 mem_mask); + void prg_write_tap(offs_t address, u16 data, u16 mem_mask); + virtual void machine_reset() override { - timer_alloc()->adjust(attotime::from_double(5)); + timer_alloc()->adjust(attotime::from_double(5)); seq = 0; + act = false; + if(0) + m_maincpu->space(0).install_write_tap(0x214cb8, 0x214cbf, "prg select", [this](offs_t offset, u16 &data, u16 mem_mask) { + prg_write_tap(offset, data, mem_mask); + }); + if(0) + 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) + 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(0) + m_maincpu->space(0).install_readwrite_tap(0x214ca2+0x20, 0x214ca2+0x320-1, "regs fp", + [this](offs_t offset, u16 &data, u16 mem_mask) { + regs_fp_read_tap(offset, data, mem_mask); + }, + [this](offs_t offset, u16 &data, u16 mem_mask) { + regs_fp_write_tap(offset, data, mem_mask); + }); + if(0) + m_maincpu->space(0).install_readwrite_tap(0x214ca2+0x320, 0x214ca2+0x420-1, "regs int", + [this](offs_t offset, u16 &data, u16 mem_mask) { + regs_int_read_tap(offset, data, mem_mask); + }, + [this](offs_t offset, u16 &data, u16 mem_mask) { + regs_int_write_tap(offset, data, mem_mask); + }); + if(0) + m_maincpu->space(0).install_write_tap(0x214ca2+0x420, 0x214ca2+0x440-1, "regs s1", [this](offs_t offset, u16 &data, u16 mem_mask) { + regs_s1_write_tap(offset, data, mem_mask); + }); + if(0) + m_maincpu->space(0).install_write_tap(0x214ca2+0x440, 0x214ca2+0x460-1, "regs s2", [this](offs_t offset, u16 &data, u16 mem_mask) { + regs_s2_write_tap(offset, data, mem_mask); + }); + if(0) + m_maincpu->space(0).install_write_tap(0x214ca2+0x460, 0x214ca2+0x480-1, "regs s3", [this](offs_t offset, u16 &data, u16 mem_mask) { + regs_s3_write_tap(offset, data, mem_mask); + }); + if(0) + m_maincpu->space(0).install_write_tap(0x214ca2+0x480, 0x214ca2+0x4a0-1, "regs s4a", [this](offs_t offset, u16 &data, u16 mem_mask) { + regs_s4a_write_tap(offset, data, mem_mask); + }); + if(0) + m_maincpu->space(0).install_write_tap(0x214ca2+0x4a0, 0x214ca2+0x4c0-1, "regs s4b", [this](offs_t offset, u16 &data, u16 mem_mask) { + regs_s4b_write_tap(offset, data, mem_mask); + }); + if(0) + m_maincpu->space(0).install_write_tap(0x214ca2+0x4c0, 0x214ca2+0x4e0-1, "regs s4c", [this](offs_t offset, u16 &data, u16 mem_mask) { + regs_s4c_write_tap(offset, data, mem_mask); + }); + if(0) + m_maincpu->space(0).install_write_tap(0x214ca2+0x4e0, 0x214ca2+0x510-1, "regs lfo", [this](offs_t offset, u16 &data, u16 mem_mask) { + regs_lfo_write_tap(offset, data, mem_mask); + }); + if(0) + m_maincpu->space(0).install_write_tap(0x214ca2+0x510, 0x214ca2+0x520-1, "regs s6", [this](offs_t offset, u16 &data, u16 mem_mask) { + regs_s6_write_tap(offset, data, mem_mask); + }); } virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override { static u8 xnote[8] = { 60, 62, 64, 65, 67, 69, 71, 72 }; static int note = 0; + act = true; + if(1) { seq = 42; return; } + switch(seq) { - case 0: push(0x90); logerror("swp30 midi keyon %d\n", note); timer.adjust(attotime::from_double(0.0005)); if(1) machine().debug_break(); break; + case 0: push(0x90); logerror("swp30 midi keyon %d\n", note); timer.adjust(attotime::from_double(0.0005)); if(0) machine().debug_break(); break; case 1: push(xnote[note]); timer.adjust(attotime::from_double(0.0005)); break; - case 2: push(0x7f); timer.adjust(attotime::from_double(0.5)); break; + case 2: push(0x25); timer.adjust(attotime::from_double(1.0)); break; case 3: push(0x80); logerror("swp30 midi keyoff\n"); timer.adjust(attotime::from_double(0.0005)); if(0) machine().debug_break(); break; case 4: push(xnote[note]); timer.adjust(attotime::from_double(0.0005)); ; if(note == 8) note = 0; break; - case 5: push(0x7f); timer.adjust(attotime::from_double(0.05)); seq=0; return; + case 5: push(0x01); timer.adjust(attotime::from_double(0.05)); seq=0; return; } seq ++; } @@ -343,160 +324,167 @@ private: virtual u16 adc7_r() override; }; -#include "../drivers/ymmu100.hxx" +void mu100_state::prg_write_tap(offs_t address, u16 data, u16 mem_mask) +{ + if(mem_mask == 0x00ff) { + static const char *names[4] = { "chorus", "variation", "insertion1", "insertion2" }; + logerror("prg_select %s %d\n", names[(address - 0x214cb8)/2], data); + } +} -struct v1 { - u32 m0; - u8 m4; - u8 m5; - u16 m6; - u8 m8; - u8 m9; - u16 ma; - u8 mc; - u8 md; - u16 me; -}; +void mu100_state::regs_s1_write_tap(offs_t address, u16 data, u16 mem_mask) +{ + offs_t pc = m_maincpu->pc(); + offs_t reg = (address - 0x214ca2-0x420)/2; + if(pc != 0x72912) + logerror("regs_s1_w %03x, %04x @ %04x (%06x)\n", reg, data, mem_mask, pc); +} -// g base = ffec00 - -// fcf30: 0010 27 1b 00 00b0f5 00 006bc4 ee 402c3e -// ... -// fcfd0: 0048 c9 45 00 006f0b 00 005951 ee 42e187 - -// 4772 616e 6450 2023 GrandP # -// f5b1e: 0225 007f 017f 58f0 8040 7000 4040 3c77 -// 3c3f 3f3f 3f40 4040 4040 0100 441f 3c54 -// 6c42 4042 45d7 093c 3f01 020d 404e 4640 -// 406c 183c 505c 4045 3e3b 9748 902f 0b0d -// 2075 0000 0000 0050 - -//20f03e: 000f5b1e 0020de54 00000000 0000fdd5 - -#if 0 -// samp2: -// 000000 - 00 20 27 1b 00 00b0f5 00 006bc4 ee 402c3e -// 004734 - 00 23 f9 1f 00 00bafd 00 007d3c ee 4075f0 -// 009544 - 00 28 2b 23 00 00cbc6 00 007d50 e4 40c832 -// 00e78b - 00 2b c7 28 00 00c0a6 00 007b70 e4 4117b1 -// 013691 - 00 32 29 2d 00 00bd5e 00 007c62 ee 4165e6 - - -// g34 = 0x43 = note - -// checksums -// 2.ef = (0/4000000) | (1 << n) -// 3.e = 0000 -// 3.f = 0001 -// 4.e = 8000 -// wait until 4.f.b != 0 -// read 5.ef and compare -// 4.e = 0000 - -// 0..13 for 32M, 0..12 for 16M - -// list of checksums at 58712/58766 -// ff49 ffa0 -// feb3 ff03 -// fd93 fdd7 -// fb76 fbb0 -// f79d f7e7 - -// f1e40 = select instrument -void f1e40() -{ - er3 = g04; // 20de54 - r5 = g29; // 7f - global volume? - r4 = er3->mcb; // 40 - global volume? - r5 = r4*r5 >> 6; // -> 7f - r5 += 2*(er3->md - 0x40); - r5 = clamp(r5, 1, 0x7f); - g29 = r5; - r5 = g20f034; // 01 - if(r5 & 1) { - r4 = er3->m1b; // 00 - r4 = lcb098[r4]; // byte, 00 - if(!r4) { - r4 = er3->m2b; - r6 = g20f031; - if(!r6) - r4 = lcb118[r4]; - else { - r6 = g20f034; - if(r6 == 3) - r4 = lcb118[r4]; - else - r4 = lcb218[r4]; - } - } else { - if(r4 != 0x48) - r4 = lcb198[er3->m2b]; - } - } else - r4 = lcb518[er3->m1b]; +void mu100_state::regs_s2_write_tap(offs_t address, u16 data, u16 mem_mask) +{ + offs_t pc = m_maincpu->pc(); + offs_t reg = (address - 0x214ca2-0x440)/2; + if(pc != 0x72912) + logerror("regs_s2_w %03x, %04x @ %04x (%06x)\n", reg, data, mem_mask, pc); +} - // r4 -> 55 - r4 = (r4 << 8) | (er3->m3b << 1); - r4 = cb710 + lb4898[r4 >> 1]; // dword 2a404 -> f5b14 005a GrandP # - g0c = r4 + 0xe; +void mu100_state::regs_s3_write_tap(offs_t address, u16 data, u16 mem_mask) +{ + offs_t pc = m_maincpu->pc(); + offs_t reg = (address - 0x214ca2-0x460)/2; + if(pc != 0x72912) + logerror("regs_s3_w %03x, %04x @ %04x (%06x)\n", reg, data, mem_mask, pc); +} +void mu100_state::regs_s4a_write_tap(offs_t address, u16 data, u16 mem_mask) +{ + offs_t pc = m_maincpu->pc(); + offs_t reg = (address - 0x214ca2-0x480)/2; + if(pc != 0x72912) + logerror("regs_s4a_w %03x, %04x @ %04x (%06x)\n", reg, data, mem_mask, pc); +} +void mu100_state::regs_s4b_write_tap(offs_t address, u16 data, u16 mem_mask) +{ + offs_t pc = m_maincpu->pc(); + offs_t reg = (address - 0x214ca2-0x4a0)/2; + if(pc != 0x72912) + logerror("regs_s4b_w %03x, %04x @ %04x (%06x)\n", reg, data, mem_mask, pc); } -void f2ace(er4 *instrument) // f5b1e +void mu100_state::regs_s4c_write_tap(offs_t address, u16 data, u16 mem_mask) { - r6 = (er4->m0 << 7) | er4->m1; - if(r6 < 0x125) - r6 = lf692e + tfccde[r6].w; - else if(r6 < 0x147) - r6 = lfcf30 + tfdf80[r6 - 0x125].w; - else - r6 = lfdfc4 + t100c34[r6 - 0x147].w; - // r6 = fcf30 - while(r6->m3 & 0x7f <= g34) - r6 += 0x10; + offs_t pc = m_maincpu->pc(); + offs_t reg = (address - 0x214ca2-0x4c0)/2; + if(pc != 0x72912) + logerror("regs_s4c_w %03x, %04x @ %04x (%06x)\n", reg, data, mem_mask, pc); } -void f2d0a(...) +void mu100_state::regs_lfo_write_tap(offs_t address, u16 data, u16 mem_mask) { - // - f2f26(); // calc freq + offs_t pc = m_maincpu->pc(); + offs_t reg = (address - 0x214ca2-0x4e0)/2; + if(pc != 0x72912) + logerror("regs_lfo_w %03x, %04x @ %04x (%06x)\n", reg, data, mem_mask, pc); +} - // ... - g3f = f6b14(); // r6h - f330a(); // sets 6a/6b - f2e1c(); // sets 5a/64/5c/66/60/65 - f3038(); // sets 38 - f31f8(er4); // sets 46 47 48 4a - f32a4(); // sets 40 - f3486(); // sets 90/92/94/96/98/9a - f309c(); +void mu100_state::regs_s6_write_tap(offs_t address, u16 data, u16 mem_mask) +{ + offs_t pc = m_maincpu->pc(); + offs_t reg = (address - 0x214ca2-0x510)/2; + if(pc != 0x72912) + logerror("regs_s6_w %03x, %04x @ %04x (%06x)\n", reg, data, mem_mask, pc); } -void f2e1c(er4 **instrument) // 20f03e -> f5b1e +void mu100_state::regs_fp_read_tap(offs_t address, u16 data, u16 mem_mask) { - v1 *xv1 = g18; // fcfd0 - g5a = xv1->m4; - g64 = xv1->m8; - er1 = (xv1->m5 << 16) | xv1->m6; - er2 = (xv1->md << 16) | xv1->me; - er3 = (xv1->m9 << 16) | xv1->ma; - er6 = *er4; - r0 = xv1->mc << 8; - r5 = (er6->m43 << 7) + er6->m44; - if(!(g64 & 0x80)) { - er1 = max(0, er1 - er5); + offs_t pc = m_maincpu->pc(); + offs_t reg = (address - 0x214ca2-0x20)/2; + if(pc != 0x72912) + logerror("regs_fp_r %03x, %04x @ %04x (%06x)\n", reg, data, mem_mask, pc); +} +void mu100_state::regs_fp_write_tap(offs_t address, u16 data, u16 mem_mask) +{ + offs_t pc = m_maincpu->pc(); + offs_t reg = (address - 0x214ca2-0x20)/2; + logerror("regs_fp_w %03x, %04x @ %04x (%06x)\n", reg, data, mem_mask, pc); +} + +void mu100_state::regs_int_read_tap(offs_t address, u16 data, u16 mem_mask) +{ + offs_t pc = m_maincpu->pc(); + offs_t reg = (address - 0x214ca2-0x320)/2; + if(pc != 0x729c6) + logerror("regs_int_r %03x, %04x @ %04x (%06x)\n", reg, data, mem_mask, pc); +} + +void mu100_state::regs_int_write_tap(offs_t address, u16 data, u16 mem_mask) +{ + offs_t pc = m_maincpu->pc(); + offs_t reg = (address - 0x214ca2-0x320)/2; + logerror("regs_int_w %03x, %04x @ %04x (%06x)\n", reg, data, mem_mask, pc); +} + +void mu100_state::voice_write_tap(offs_t address, u16 data, u16 mem_mask) +{ + offs_t pc = m_maincpu->pc(); + if(!act) + return; + offs_t off = address - 0x20f03e; + int voice = off / 0x92; + int slot = off % 0x92; + if(mem_mask == 0xffff) { + logerror("voice_w %02x:%02x, %04x (%06x)\n", voice, slot, data, pc); } else { - // 2ae2 + if(mem_mask == 0xff00) + data >>= 8; + else + slot++; + logerror("voice_w %02x:%02x, %02x (%06x)\n", voice, slot, data, pc); } - // 2ef8 - g5c = er1; - g66 = er2; - g60 = er3; - g65 = r0 >> 8; } -#endif + +void mu100_state::chan_write_tap(offs_t address, u16 data, u16 mem_mask) +{ + offs_t pc = m_maincpu->pc(); + if(!act) + return; + offs_t off = address - 0x20cb10; + int voice = off / 0x112; + int slot = off % 0x112; + if(mem_mask == 0xffff) { + if(slot == 0x102 && data == 0) + return; + if(slot == 0x100 && data == 0) + return; + if(slot == 0x0fe && data == 0) + return; + logerror("chan_w %02x:%03x, %04x (%06x)\n", voice, slot, data, pc); + } else { + if(mem_mask == 0xff00) + data >>= 8; + else + slot++; + if(slot == 0x106 && data == 0) + return; + if(slot == 0x108 && data == 0) + return; + if(slot == 0x105) // volume + return; + if(slot == 0x109 && data == 0) + return; + if(slot == 0x0e7 && data == 0) + return; + if(slot == 0x0e5 && data == 0) + return; + if(slot == 0x111 && data == 0x40) + return; + logerror("chan_w %02x:%03x, %02x (%06x)\n", voice, slot, data, pc); + } +} + +#include "../drivers/ymmu100.hxx" void mu100_state::machine_start() { @@ -560,7 +548,7 @@ void mu100_state::mu100_map(address_map &map) u16 mu100_state::adc0_r() { - logerror("adc0_r\n"); + // logerror("adc0_r\n"); return 0; } @@ -658,7 +646,7 @@ void mu100_state::p6_w(u16 data) u16 mu100_state::p6_r() { - logerror("plug in detect read\n"); + // logerror("plug in detect read\n"); return 0x00; } @@ -706,9 +694,9 @@ void mu100_state::mu100_iomap(address_map &map) void mu100_state::swp30_map(address_map &map) { - map(0x000000*4, 0x200000*4-1).rom().region("swp30", 0).mirror(4*0x200000); - map(0x400000*4, 0x500000*4-1).rom().region("swp30", 0x800000).mirror(4*0x300000); - map(0x800000*4, 0xa00000*4-1).rom().region("swp30", 0x1000000).mirror(4*0x200000); // Missing roms... + map(0x000000*4, 0x200000*4-1).rom().region("swp30", 0).mirror(4*0x200000); + map(0x400000*4, 0x500000*4-1).rom().region("swp30", 0x800000).mirror(4*0x300000); + map(0x800000*4, 0xa00000*4-1).rom().region("swp30", 0x1000000).mirror(4*0x200000); } void mu100_state::mu100(machine_config &config) @@ -756,12 +744,12 @@ ROM_START( mu100 ) ROM_LOAD16_WORD_SWAP_BIOS( 1, "xt71420.ic11", 0x000000, 0x200000, CRC(0e5b3bae) SHA1(3148c5bd59a3d00809d3ab1921216215fe2582c5) ) ROM_REGION( 0x1800000, "swp30", ROMREGION_ERASE00 ) - ROM_LOAD32_WORD( "sx518b0.ic34", 0x000000, 0x400000, CRC(2550d44f) SHA1(fd3cce228c7d389a2fde25c808a5b26080588cba) ) - ROM_LOAD32_WORD( "sx743b0.ic35", 0x000002, 0x400000, CRC(a9109a6c) SHA1(a67bb49378a38a2d809bd717d286e18bc6496db0) ) - ROM_LOAD32_WORD( "xt445a0-828.ic36", 0x800000, 0x200000, CRC(225c2280) SHA1(23b5e046fd2e2ac01af3e6dc6357c5c6547b286b) ) - ROM_LOAD32_WORD( "xt461a0-829.ic37", 0x800002, 0x200000, CRC(a1d138a3) SHA1(46a7a7225cd7e1818ba551325d2af5ac1bf5b2bf) ) - ROM_LOAD32_WORD( "xt963a0.ic38", 0x1000000, 0x400000, NO_DUMP ) - ROM_LOAD32_WORD( "xt964a0.ic39", 0x1000002, 0x400000, NO_DUMP ) + ROM_LOAD32_WORD( "sx518b0.ic34", 0x0000000, 0x400000, CRC(2550d44f) SHA1(fd3cce228c7d389a2fde25c808a5b26080588cba) ) + ROM_LOAD32_WORD( "sx743b0.ic35", 0x0000002, 0x400000, CRC(a9109a6c) SHA1(a67bb49378a38a2d809bd717d286e18bc6496db0) ) + ROM_LOAD32_WORD( "xt445a0-828.ic36", 0x0800000, 0x200000, CRC(225c2280) SHA1(23b5e046fd2e2ac01af3e6dc6357c5c6547b286b) ) + ROM_LOAD32_WORD( "xt461a0-829.ic37", 0x0800002, 0x200000, CRC(a1d138a3) SHA1(46a7a7225cd7e1818ba551325d2af5ac1bf5b2bf) ) + ROM_LOAD32_WORD( "xt462a0.ic39", 0x1000000, 0x400000, CRC(cbf037da) SHA1(37449e741243305de38cb913b17041942ad334cd) ) + ROM_LOAD32_WORD( "xt463a0.ic38", 0x1000002, 0x400000, CRC(cce5f8d3) SHA1(bdca8c5158f452f2b5535c7d658c9b22c6d66048) ) ROM_REGION( 0x1000, "lcd", 0) // Hand made, 3 characters unused @@ -781,8 +769,8 @@ ROM_START( mu100r ) ROM_LOAD32_WORD( "sx743b0.ic35", 0x000002, 0x400000, CRC(a9109a6c) SHA1(a67bb49378a38a2d809bd717d286e18bc6496db0) ) ROM_LOAD32_WORD( "xt445a0-828.ic36", 0x800000, 0x200000, CRC(225c2280) SHA1(23b5e046fd2e2ac01af3e6dc6357c5c6547b286b) ) ROM_LOAD32_WORD( "xt461a0-829.ic37", 0x800002, 0x200000, CRC(a1d138a3) SHA1(46a7a7225cd7e1818ba551325d2af5ac1bf5b2bf) ) - ROM_LOAD32_WORD( "xt963a0.ic38", 0x1000000, 0x400000, NO_DUMP ) - ROM_LOAD32_WORD( "xt964a0.ic39", 0x1000002, 0x400000, NO_DUMP ) + ROM_LOAD32_WORD( "xt462a0.ic39", 0x1000000, 0x400000, CRC(cbf037da) SHA1(37449e741243305de38cb913b17041942ad334cd) ) + ROM_LOAD32_WORD( "xt463a0.ic38", 0x1000002, 0x400000, CRC(cce5f8d3) SHA1(bdca8c5158f452f2b5535c7d658c9b22c6d66048) ) ROM_REGION( 0x1000, "lcd", 0) // Hand made, 3 characters unused -- cgit v1.2.3