From 6aef7adadd20a4fe351692fc899c8879b11ec42b Mon Sep 17 00:00:00 2001 From: cam900 Date: Sat, 4 Apr 2020 21:59:50 +0900 Subject: Split S-SMP and S-DSP implement in snes_snd.cpp (#6417) * Split S-SMP and S-DSP implement in snes_snd.cpp both convert memory handler into device_memory_interface, Internalize ROM region of S-SMP s_smp.cpp : Use callback for S-DSP interface, Split internal and external memory space snes.cpp : Convert WRAM into shared_ptr * s_dsp.cpp : Reduce #define macros --- scripts/src/machine.lua | 12 + scripts/src/sound.lua | 12 + scripts/target/mame/arcade.lua | 4 +- scripts/target/mame/mess.lua | 4 +- src/devices/cpu/spc700/spc700.cpp | 9 +- src/devices/cpu/spc700/spc700.h | 6 +- src/devices/machine/s_smp.cpp | 321 ++++++++++ src/devices/machine/s_smp.h | 90 +++ src/devices/sound/s_dsp.cpp | 1080 +++++++++++++++++++++++++++++++ src/devices/sound/s_dsp.h | 116 ++++ src/mame/audio/snes_snd.cpp | 1266 ------------------------------------- src/mame/audio/snes_snd.h | 132 ---- src/mame/drivers/nss.cpp | 42 +- src/mame/drivers/sfcbox.cpp | 38 +- src/mame/drivers/snes.cpp | 92 ++- src/mame/drivers/snesb.cpp | 66 +- src/mame/includes/snes.h | 24 +- src/mame/machine/snes.cpp | 18 +- 18 files changed, 1747 insertions(+), 1585 deletions(-) create mode 100644 src/devices/machine/s_smp.cpp create mode 100644 src/devices/machine/s_smp.h create mode 100644 src/devices/sound/s_dsp.cpp create mode 100644 src/devices/sound/s_dsp.h delete mode 100644 src/mame/audio/snes_snd.cpp delete mode 100644 src/mame/audio/snes_snd.h diff --git a/scripts/src/machine.lua b/scripts/src/machine.lua index e72a653f5b9..4e7352c3e41 100644 --- a/scripts/src/machine.lua +++ b/scripts/src/machine.lua @@ -4269,6 +4269,18 @@ if (MACHINES["I3002"]~=null) then } end +--------------------------------------------------- +-- +--@src/devices/machine/s_smp.h,MACHINES["S_SMP"] = true +--------------------------------------------------- + +if (MACHINES["S_SMP"]~=null) then + files { + MAME_DIR .. "src/devices/machine/s_smp.cpp", + MAME_DIR .. "src/devices/machine/s_smp.h", + } +end + --------------------------------------------------- -- --@src/devices/machine/cxd1185.h,MACHINES["CXD1185"] = true diff --git a/scripts/src/sound.lua b/scripts/src/sound.lua index dc0a1a93f07..3b98b9095ce 100644 --- a/scripts/src/sound.lua +++ b/scripts/src/sound.lua @@ -1566,6 +1566,18 @@ if (SOUNDS["VGMVIZ"]~=null) then } end +--------------------------------------------------- +-- +--@src/devices/sound/s_dsp.h,SOUNDS["S_DSP"] = true +--------------------------------------------------- + +if (SOUNDS["S_DSP"]~=null) then + files { + MAME_DIR .. "src/devices/sound/s_dsp.cpp", + MAME_DIR .. "src/devices/sound/s_dsp.h", + } +end + --------------------------------------------------- -- --@src/devices/sound/ks0164.h,SOUNDS["KS0164"] = true diff --git a/scripts/target/mame/arcade.lua b/scripts/target/mame/arcade.lua index a23f7e6d066..81bf00505b6 100644 --- a/scripts/target/mame/arcade.lua +++ b/scripts/target/mame/arcade.lua @@ -279,6 +279,7 @@ SOUNDS["MM5837"] = true --SOUNDS["DAVE"] = true SOUNDS["LC7535"] = true --SOUNDS["UPD934G"] = true +SOUNDS["S_DSP"] = true SOUNDS["KS0164"] = true -------------------------------------------------- @@ -595,6 +596,7 @@ MACHINES["RSTBUF"] = true MACHINES["RTC4543"] = true MACHINES["RTC65271"] = true MACHINES["RTC9701"] = true +MACHINES["S_SMP"] = true MACHINES["S2636"] = true MACHINES["S3520CF"] = true MACHINES["S3C24XX"] = true @@ -3099,8 +3101,6 @@ files { MAME_DIR .. "src/mame/video/n8080.cpp", MAME_DIR .. "src/mame/drivers/nss.cpp", MAME_DIR .. "src/mame/machine/snes.cpp", - MAME_DIR .. "src/mame/audio/snes_snd.cpp", - MAME_DIR .. "src/mame/audio/snes_snd.h", MAME_DIR .. "src/mame/drivers/playch10.cpp", MAME_DIR .. "src/mame/includes/playch10.h", MAME_DIR .. "src/mame/machine/playch10.cpp", diff --git a/scripts/target/mame/mess.lua b/scripts/target/mame/mess.lua index a8912c103db..545bf4646e0 100644 --- a/scripts/target/mame/mess.lua +++ b/scripts/target/mame/mess.lua @@ -302,6 +302,7 @@ SOUNDS["IOPSPU"] = true SOUNDS["SWP00"] = true SOUNDS["SWP20"] = true SOUNDS["SWP30"] = true +SOUNDS["S_DSP"] = true SOUNDS["ROLANDPCM"] = true -------------------------------------------------- @@ -617,6 +618,7 @@ MACHINES["RSTBUF"] = true MACHINES["RTC4543"] = true MACHINES["RTC65271"] = true MACHINES["RTC9701"] = true +MACHINES["S_SMP"] = true --MACHINES["S2636"] = true MACHINES["S3520CF"] = true MACHINES["S3C24XX"] = true @@ -1419,8 +1421,6 @@ files { MAME_DIR .. "src/mame/machine/kabuki.h", MAME_DIR .. "src/mame/video/pk8000.cpp", MAME_DIR .. "src/mame/machine/snes.cpp", - MAME_DIR .. "src/mame/audio/snes_snd.cpp", - MAME_DIR .. "src/mame/audio/snes_snd.h", MAME_DIR .. "src/mame/machine/n64.cpp", MAME_DIR .. "src/mame/video/n64.cpp", MAME_DIR .. "src/mame/video/n64types.h", diff --git a/src/devices/cpu/spc700/spc700.cpp b/src/devices/cpu/spc700/spc700.cpp index 57d2b5c5df8..7f5a35d6757 100644 --- a/src/devices/cpu/spc700/spc700.cpp +++ b/src/devices/cpu/spc700/spc700.cpp @@ -222,8 +222,13 @@ DEFINE_DEVICE_TYPE(SPC700, spc700_device, "spc700", "Sony SPC700") spc700_device::spc700_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) - : cpu_device(mconfig, SPC700, tag, owner, clock) - , m_program_config("program", ENDIANNESS_LITTLE, 8, 16, 0) + : spc700_device(mconfig, SPC700, tag, owner, clock) +{ +} + +spc700_device::spc700_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, address_map_constructor internal_map) + : cpu_device(mconfig, type, tag, owner, clock) + , m_program_config("program", ENDIANNESS_LITTLE, 8, 16, 0, internal_map) , m_a(0) , m_x(0) , m_y(0) diff --git a/src/devices/cpu/spc700/spc700.h b/src/devices/cpu/spc700/spc700.h index bd1b90c475e..33e3190ac10 100644 --- a/src/devices/cpu/spc700/spc700.h +++ b/src/devices/cpu/spc700/spc700.h @@ -13,6 +13,9 @@ public: spc700_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); protected: + // construction/destruction + spc700_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, address_map_constructor internal_map = address_map_constructor()); + // device-level overrides virtual void device_start() override; virtual void device_reset() override; @@ -36,9 +39,8 @@ protected: // device_disasm_interface overrides virtual std::unique_ptr create_disassembler() override; -private: address_space_config m_program_config; - +private: uint32_t m_a; /* Accumulator */ uint32_t m_x; /* Index Register X */ uint32_t m_y; /* Index Register Y */ diff --git a/src/devices/machine/s_smp.cpp b/src/devices/machine/s_smp.cpp new file mode 100644 index 00000000000..d71b0449f65 --- /dev/null +++ b/src/devices/machine/s_smp.cpp @@ -0,0 +1,321 @@ +// license:LGPL-2.1+ +// copyright-holders:R. Belmont, Brad Martin +/*************************************************************************** + + s_smp.cpp + + File to handle the S-SMP emulation used in Nintendo Super NES. + + By R. Belmont, adapted from OpenSPC 0.3.99 by Brad Martin with permission. + Thanks to Brad and also to Charles Bilyu? of SNeESe. + + OpenSPC's license terms (the LGPL) follow: + + --------------------------------------------------------------------------- + + Copyright Brad Martin. + + OpenSPC is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + OpenSPC is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + +***************************************************************************/ + +#include "emu.h" +#include "s_smp.h" + +/*************************************************************************** + CONSTANTS AND MACROS +***************************************************************************/ + + +// Nintendo/Sony S-SMP internal ROM region +ROM_START( s_smp ) + ROM_REGION( 0x40, "sound_ipl", 0 ) /* IPL ROM */ + ROM_LOAD( "spc700.rom", 0, 0x40, CRC(44bb3a40) SHA1(97e352553e94242ae823547cd853eecda55c20f0) ) /* boot rom */ +ROM_END + + +void s_smp_device::internal_map(address_map &map) +{ + map(0x0000, 0x00ef).lrw8( + [this](offs_t offset) -> u8 { return data_read_byte(offset); }, "data_r", + [this](offs_t offset, u8 data) { data_write_byte(offset, data); }, "data_w"); + map(0x00f0, 0x00ff).rw(FUNC(s_smp_device::io_r), FUNC(s_smp_device::io_w)); + map(0x0100, 0xffff).lrw8( + [this](offs_t offset) -> u8 { return data_read_byte(offset + 0x100); }, "data_100_r", + [this](offs_t offset, u8 data) { data_write_byte(offset + 0x100, data); }, "data_100_w"); +} + + +DEFINE_DEVICE_TYPE(S_SMP, s_smp_device, "s_smp", "Nintendo/Sony S-SMP") + + +s_smp_device::s_smp_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) + : spc700_device(mconfig, S_SMP, tag, owner, clock, address_map_constructor(FUNC(s_smp_device::internal_map), this)) + , m_data_config("data", ENDIANNESS_LITTLE, 8, 16) + , m_ipl_region(*this, "sound_ipl") + , m_dsp_io_r_cb(*this) + , m_dsp_io_w_cb(*this) +{ +} + + +//------------------------------------------------- +// rom_region - return a pointer to the device's +// internal ROM region +//------------------------------------------------- + +const tiny_rom_entry *s_smp_device::device_rom_region() const +{ + return ROM_NAME( s_smp ); +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void s_smp_device::device_start() +{ + m_dsp_io_r_cb.resolve_safe(0); + m_dsp_io_w_cb.resolve_safe(); + + m_data = &space(AS_DATA); + // Find our direct access + m_dcache = m_data->cache<0, 0, ENDIANNESS_LITTLE>(); + + m_tick_timer = timer_alloc(TIMER_TICK_ID); + + save_item(NAME(m_timer_enabled)); + save_item(NAME(m_subcounter)); + save_item(NAME(m_counter)); + save_item(NAME(m_port_in)); + save_item(NAME(m_port_out)); + save_item(NAME(m_test)); + save_item(NAME(m_ctrl)); + save_item(NAME(m_counter_reg)); + + save_item(NAME(m_TnDIV)); + spc700_device::device_start(); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void s_smp_device::device_reset() +{ + int i; + /* default to ROM visible */ + m_ctrl = 0x80; + + /* Sort out the ports */ + for (i = 0; i < 4; i++) + { + m_port_in[i] = 0; + m_port_out[i] = 0; + } + + for (i = 0; i < 3; i++) + { + m_timer_enabled[i] = false; + m_TnDIV[i] = 256; + m_counter[i] = 0; + m_subcounter[i] = 0; + } + + attotime period = attotime::from_ticks(32, clock()); + m_tick_timer->adjust(period, 0, period); + spc700_device::device_reset(); +} + +//------------------------------------------------- +// device_clock_changed - called if the clock +// changes +//------------------------------------------------- + +void s_smp_device::device_clock_changed() +{ + attotime period = attotime::from_ticks(32, clock()); + m_tick_timer->adjust(period, 0, period); +} + +//------------------------------------------------- +// memory_space_config - return a description of +// any address spaces owned by this device +//------------------------------------------------- + +device_memory_interface::space_config_vector s_smp_device::memory_space_config() const +{ + return space_config_vector{ + std::make_pair(AS_PROGRAM, &m_program_config), + std::make_pair(AS_DATA, &m_data_config) + }; +} + +inline void s_smp_device::update_timer_tick(u8 which) +{ + if (m_timer_enabled[which] == false) + return; + + m_subcounter[which]++; + + // if timer channel is 0 or 1 we update at 64000/8 + if (m_subcounter[which] >= 8 || which == 2) + { + m_subcounter[which] = 0; + m_counter[which]++; + if (m_counter[which] >= m_TnDIV[which] ) // minus = + { + m_counter[which] = 0; + m_counter_reg[which]++; + m_counter_reg[which] &= 0x0f; + } + } +} + +void s_smp_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + if (id != TIMER_TICK_ID) + throw emu_fatalerror("Unknown id in s_smp_device::device_timer"); + + for (int ch = 0; ch < 3; ch++) + update_timer_tick(ch); +} + + +/***************************************************************************** + IMPLEMENTATION +*****************************************************************************/ + + +/*************************** + I/O for S-SMP + ***************************/ + +u8 s_smp_device::io_r(offs_t offset) +{ + switch (offset) /* Offset is from 0x00f0 */ + { + case 0x0: //FIXME: Super Bomberman PBW reads from there, is it really write-only? + return 0; + case 0x1: + return 0; //Super Kick Boxing reads port 1 and wants it to be zero. + case 0x2: /* Register address */ + case 0x3: /* Register data */ + return m_dsp_io_r_cb(offset - 0x2); + case 0x4: /* Port 0 */ + case 0x5: /* Port 1 */ + case 0x6: /* Port 2 */ + case 0x7: /* Port 3 */ + // osd_printf_debug("%s SPC: rd %02x @ %d\n", machine().describe_context(), m_port_in[offset - 4], offset - 4); + return m_port_in[offset - 4]; + case 0x8: //normal RAM, can be read even if the ram disabled flag ($f0 bit 1) is active + case 0x9: + return data_read_byte(0xf0 + offset); + case 0xa: /* Timer 0 */ + case 0xb: /* Timer 1 */ + case 0xc: /* Timer 2 */ + break; + case 0xd: /* Counter 0 */ + case 0xe: /* Counter 1 */ + case 0xf: /* Counter 2 */ + { + u8 value = m_counter_reg[offset - 0xd] & 0x0f; + if (!machine().side_effects_disabled()) + m_counter_reg[offset - 0xd] = 0; + return value; + } + } + + return 0; +} + +void s_smp_device::io_w(offs_t offset, u8 data) +{ + switch (offset) /* Offset is from 0x00f0 */ + { + case 0x0: + m_test = data; + logerror("Warning: write to SOUND TEST register with data %02x!\n", data); + break; + case 0x1: /* Control */ + m_ctrl = data; + for (int i = 0; i < 3; i++) + { + if (BIT(data, i) && m_timer_enabled[i] == false) + { + m_subcounter[i] = 0; + m_counter[i] = 0; + m_counter_reg[i] = 0; + } + + m_timer_enabled[i] = BIT(data, i); + //m_timer[i]->enable(m_timer_enabled[i]); + } + + if (BIT(data, 4)) + { + m_port_in[0] = 0; + m_port_in[1] = 0; + } + + if (BIT(data, 5)) + { + m_port_in[2] = 0; + m_port_in[3] = 0; + } + + /* bit 7 = IPL ROM enable */ + break; + case 0x2: /* Register address */ + case 0x3: /* Register data - 0x80-0xff is a read-only mirror of 0x00-0x7f */ + m_dsp_io_w_cb(offset - 0x2, data); + break; + case 0x4: /* Port 0 */ + case 0x5: /* Port 1 */ + case 0x6: /* Port 2 */ + case 0x7: /* Port 3 */ + // osd_printf_debug("%s SPC: %02x to APU @ %d\n", machine().describe_context(), data, offset & 3); + m_port_out[offset - 4] = data; + // Unneeded, we already run at perfect_interleave + // machine().scheduler().boost_interleave(attotime::zero, attotime::from_usec(20)); + break; + case 0xa: /* Timer 0 */ + case 0xb: /* Timer 1 */ + case 0xc: /* Timer 2 */ + // if 0 then TnDiv is divided by 256, otherwise it's divided by 1 to 255 + if (data == 0) + m_TnDIV[offset - 0xa] = 256; + else + m_TnDIV[offset - 0xa] = data; + break; + case 0xd: /* Counter 0 */ + case 0xe: /* Counter 1 */ + case 0xf: /* Counter 2 */ + return; + } + + data_write_byte(0xf0 + offset, data); +} + + +u8 s_smp_device::spc_port_out_r(offs_t offset) +{ + assert(offset < 4); + + return m_port_out[offset]; +} + +void s_smp_device::spc_port_in_w(offs_t offset, u8 data) +{ + assert(offset < 4); + + m_port_in[offset] = data; +} diff --git a/src/devices/machine/s_smp.h b/src/devices/machine/s_smp.h new file mode 100644 index 00000000000..5fe04b1880a --- /dev/null +++ b/src/devices/machine/s_smp.h @@ -0,0 +1,90 @@ +// license:LGPL-2.1+ +// copyright-holders:R. Belmont, Brad Martin +/***************************************************************************** + * + * Nintendo/Sony S-SMP emulation + * + ****************************************************************************/ + +#ifndef MAME_MACHINE_S_SMP_H +#define MAME_MACHINE_S_SMP_H + +#include "cpu/spc700/spc700.h" + +/*************************************************************************** + TYPE DEFINITIONS + ***************************************************************************/ + +class s_smp_device : public spc700_device +{ +public: + s_smp_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); + + auto dsp_io_read_callback() { return m_dsp_io_r_cb.bind(); } + auto dsp_io_write_callback() { return m_dsp_io_w_cb.bind(); } + + u8 spc_port_out_r(offs_t offset); + void spc_port_in_w(offs_t offset, u8 data); + +protected: + tiny_rom_entry const *device_rom_region() const override; + virtual void device_start() override; + virtual void device_reset() override; + virtual void device_clock_changed() override; + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override; + + // device_memory_interface configuration + virtual space_config_vector memory_space_config() const override; + + address_space_config m_data_config; + +private: + address_space *m_data; + memory_access_cache<0, 0, ENDIANNESS_LITTLE> *m_dcache; + inline u8 data_read_byte(offs_t a) + { + /* IPL ROM enabled */ + if (a >= 0xffc0 && m_ctrl & 0x80) + return m_ipl_region[a & 0x3f]; + + return m_dcache->read_byte(a); + } + inline void data_write_byte(offs_t a, u8 d) { m_data->write_byte(a, d); } + + required_region_ptr m_ipl_region; /* SPC top 64 bytes */ + + u8 io_r(offs_t offset); + void io_w(offs_t offset, u8 data); + + enum + { + TIMER_TICK_ID = 1 + }; + /* timers */ + emu_timer *m_tick_timer; + bool m_timer_enabled[3]; + u16 m_counter[3]; + u8 m_subcounter[3]; + inline void update_timer_tick(u8 which); + + /* IO ports */ + u8 m_port_in[4]; /* SPC input ports */ + u8 m_port_out[4]; /* SPC output ports */ + + u16 m_TnDIV[3]; /**< Timer N Divider */ + + // registers + u8 m_test; + u8 m_ctrl; + u8 m_counter_reg[3]; + + devcb_read8 m_dsp_io_r_cb; + devcb_write8 m_dsp_io_w_cb; + + void internal_map(address_map &map); +}; + +DECLARE_DEVICE_TYPE(S_SMP, s_smp_device) + + +#endif // MAME_MACHINE_S_SMP_H diff --git a/src/devices/sound/s_dsp.cpp b/src/devices/sound/s_dsp.cpp new file mode 100644 index 00000000000..976fb33f5a2 --- /dev/null +++ b/src/devices/sound/s_dsp.cpp @@ -0,0 +1,1080 @@ +// license:LGPL-2.1+ +// copyright-holders:R. Belmont, Brad Martin +/*************************************************************************** + + s_dsp.cpp + + File to handle the S-DSP emulation used in Nintendo Super NES. + + By R. Belmont, adapted from OpenSPC 0.3.99 by Brad Martin with permission. + Thanks to Brad and also to Charles Bilyu? of SNeESe. + + OpenSPC's license terms (the LGPL) follow: + + --------------------------------------------------------------------------- + + Copyright Brad Martin. + + OpenSPC is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + OpenSPC is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + +***************************************************************************/ + +#include "emu.h" +#include "s_dsp.h" + +/*************************************************************************** + CONSTANTS AND MACROS +***************************************************************************/ + +static const int gauss[]= +{ + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x001, 0x001, 0x001, 0x001, 0x001, 0x001, 0x001, 0x001, + 0x001, 0x001, 0x001, 0x002, 0x002, 0x002, 0x002, 0x002, + 0x002, 0x002, 0x003, 0x003, 0x003, 0x003, 0x003, 0x004, + 0x004, 0x004, 0x004, 0x004, 0x005, 0x005, 0x005, 0x005, + 0x006, 0x006, 0x006, 0x006, 0x007, 0x007, 0x007, 0x008, + 0x008, 0x008, 0x009, 0x009, 0x009, 0x00A, 0x00A, 0x00A, + 0x00B, 0x00B, 0x00B, 0x00C, 0x00C, 0x00D, 0x00D, 0x00E, + 0x00E, 0x00F, 0x00F, 0x00F, 0x010, 0x010, 0x011, 0x011, + 0x012, 0x013, 0x013, 0x014, 0x014, 0x015, 0x015, 0x016, + 0x017, 0x017, 0x018, 0x018, 0x019, 0x01A, 0x01B, 0x01B, + 0x01C, 0x01D, 0x01D, 0x01E, 0x01F, 0x020, 0x020, 0x021, + 0x022, 0x023, 0x024, 0x024, 0x025, 0x026, 0x027, 0x028, + 0x029, 0x02A, 0x02B, 0x02C, 0x02D, 0x02E, 0x02F, 0x030, + 0x031, 0x032, 0x033, 0x034, 0x035, 0x036, 0x037, 0x038, + 0x03A, 0x03B, 0x03C, 0x03D, 0x03E, 0x040, 0x041, 0x042, + 0x043, 0x045, 0x046, 0x047, 0x049, 0x04A, 0x04C, 0x04D, + 0x04E, 0x050, 0x051, 0x053, 0x054, 0x056, 0x057, 0x059, + 0x05A, 0x05C, 0x05E, 0x05F, 0x061, 0x063, 0x064, 0x066, + 0x068, 0x06A, 0x06B, 0x06D, 0x06F, 0x071, 0x073, 0x075, + 0x076, 0x078, 0x07A, 0x07C, 0x07E, 0x080, 0x082, 0x084, + 0x086, 0x089, 0x08B, 0x08D, 0x08F, 0x091, 0x093, 0x096, + 0x098, 0x09A, 0x09C, 0x09F, 0x0A1, 0x0A3, 0x0A6, 0x0A8, + 0x0AB, 0x0AD, 0x0AF, 0x0B2, 0x0B4, 0x0B7, 0x0BA, 0x0BC, + 0x0BF, 0x0C1, 0x0C4, 0x0C7, 0x0C9, 0x0CC, 0x0CF, 0x0D2, + 0x0D4, 0x0D7, 0x0DA, 0x0DD, 0x0E0, 0x0E3, 0x0E6, 0x0E9, + 0x0EC, 0x0EF, 0x0F2, 0x0F5, 0x0F8, 0x0FB, 0x0FE, 0x101, + 0x104, 0x107, 0x10B, 0x10E, 0x111, 0x114, 0x118, 0x11B, + 0x11E, 0x122, 0x125, 0x129, 0x12C, 0x130, 0x133, 0x137, + 0x13A, 0x13E, 0x141, 0x145, 0x148, 0x14C, 0x150, 0x153, + 0x157, 0x15B, 0x15F, 0x162, 0x166, 0x16A, 0x16E, 0x172, + 0x176, 0x17A, 0x17D, 0x181, 0x185, 0x189, 0x18D, 0x191, + 0x195, 0x19A, 0x19E, 0x1A2, 0x1A6, 0x1AA, 0x1AE, 0x1B2, + 0x1B7, 0x1BB, 0x1BF, 0x1C3, 0x1C8, 0x1CC, 0x1D0, 0x1D5, + 0x1D9, 0x1DD, 0x1E2, 0x1E6, 0x1EB, 0x1EF, 0x1F3, 0x1F8, + 0x1FC, 0x201, 0x205, 0x20A, 0x20F, 0x213, 0x218, 0x21C, + 0x221, 0x226, 0x22A, 0x22F, 0x233, 0x238, 0x23D, 0x241, + 0x246, 0x24B, 0x250, 0x254, 0x259, 0x25E, 0x263, 0x267, + 0x26C, 0x271, 0x276, 0x27B, 0x280, 0x284, 0x289, 0x28E, + 0x293, 0x298, 0x29D, 0x2A2, 0x2A6, 0x2AB, 0x2B0, 0x2B5, + 0x2BA, 0x2BF, 0x2C4, 0x2C9, 0x2CE, 0x2D3, 0x2D8, 0x2DC, + 0x2E1, 0x2E6, 0x2EB, 0x2F0, 0x2F5, 0x2FA, 0x2FF, 0x304, + 0x309, 0x30E, 0x313, 0x318, 0x31D, 0x322, 0x326, 0x32B, + 0x330, 0x335, 0x33A, 0x33F, 0x344, 0x349, 0x34E, 0x353, + 0x357, 0x35C, 0x361, 0x366, 0x36B, 0x370, 0x374, 0x379, + 0x37E, 0x383, 0x388, 0x38C, 0x391, 0x396, 0x39B, 0x39F, + 0x3A4, 0x3A9, 0x3AD, 0x3B2, 0x3B7, 0x3BB, 0x3C0, 0x3C5, + 0x3C9, 0x3CE, 0x3D2, 0x3D7, 0x3DC, 0x3E0, 0x3E5, 0x3E9, + 0x3ED, 0x3F2, 0x3F6, 0x3FB, 0x3FF, 0x403, 0x408, 0x40C, + 0x410, 0x415, 0x419, 0x41D, 0x421, 0x425, 0x42A, 0x42E, + 0x432, 0x436, 0x43A, 0x43E, 0x442, 0x446, 0x44A, 0x44E, + 0x452, 0x455, 0x459, 0x45D, 0x461, 0x465, 0x468, 0x46C, + 0x470, 0x473, 0x477, 0x47A, 0x47E, 0x481, 0x485, 0x488, + 0x48C, 0x48F, 0x492, 0x496, 0x499, 0x49C, 0x49F, 0x4A2, + 0x4A6, 0x4A9, 0x4AC, 0x4AF, 0x4B2, 0x4B5, 0x4B7, 0x4BA, + 0x4BD, 0x4C0, 0x4C3, 0x4C5, 0x4C8, 0x4CB, 0x4CD, 0x4D0, + 0x4D2, 0x4D5, 0x4D7, 0x4D9, 0x4DC, 0x4DE, 0x4E0, 0x4E3, + 0x4E5, 0x4E7, 0x4E9, 0x4EB, 0x4ED, 0x4EF, 0x4F1, 0x4F3, + 0x4F5, 0x4F6, 0x4F8, 0x4FA, 0x4FB, 0x4FD, 0x4FF, 0x500, + 0x502, 0x503, 0x504, 0x506, 0x507, 0x508, 0x50A, 0x50B, + 0x50C, 0x50D, 0x50E, 0x50F, 0x510, 0x511, 0x511, 0x512, + 0x513, 0x514, 0x514, 0x515, 0x516, 0x516, 0x517, 0x517, + 0x517, 0x518, 0x518, 0x518, 0x518, 0x518, 0x519, 0x519, + 0x519, 0x519, 0x519, 0x519, 0x519, 0x519, 0x519, 0x519 +}; + +#undef DEBUG +#undef DBG_KEY +#undef DBG_ENV +#undef DBG_PMOD +#undef DBG_BRR +#undef DBG_ECHO +#undef DBG_INTRP + +#undef NO_PMOD +#undef NO_ECHO + +/* Ptrs to Gaussian table */ +static const int *const G1 = &gauss[256]; +static const int *const G2 = &gauss[512]; +static const int *const G3 = &gauss[255]; +static const int *const G4 = &gauss[0]; + +static const int mask = 0xFF; + +/* This table is for envelope timing. It represents the number of counts + that should be subtracted from the counter each sample period (32kHz). + The counter starts at 30720 (0x7800). */ +static const int CNT_INIT = 0x7800; +static const int ENVCNT[0x20] + = { + 0x0000, 0x000F, 0x0014, 0x0018, 0x001E, 0x0028, 0x0030, 0x003C, + 0x0050, 0x0060, 0x0078, 0x00A0, 0x00C0, 0x00F0, 0x0140, 0x0180, + 0x01E0, 0x0280, 0x0300, 0x03C0, 0x0500, 0x0600, 0x0780, 0x0A00, + 0x0C00, 0x0F00, 0x1400, 0x1800, 0x1E00, 0x2800, 0x3C00, 0x7800 + }; + + +ALLOW_SAVE_TYPE(s_dsp_device::env_state_t32); + + +DEFINE_DEVICE_TYPE(S_DSP, s_dsp_device, "s_dsp", "Nintendo/Sony S-DSP") + + +s_dsp_device::s_dsp_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) + : device_t(mconfig, S_DSP, tag, owner, clock) + , device_sound_interface(mconfig, *this) + , device_memory_interface(mconfig, *this) + , m_data_config("data", ENDIANNESS_LITTLE, 8, 16) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void s_dsp_device::device_start() +{ + m_data = &space(0); + // Find our direct access + m_cache = m_data->cache<0, 0, ENDIANNESS_LITTLE>(); + + m_channel = machine().sound().stream_alloc(*this, 0, 2, clock() / 64); + + state_register(); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void s_dsp_device::device_reset() +{ + dsp_reset(); +} + +//------------------------------------------------- +// device_clock_changed - called if the clock +// changes +//------------------------------------------------- + +void s_dsp_device::device_clock_changed() +{ + m_channel->set_sample_rate(clock() / 64); +} + +//------------------------------------------------- +// memory_space_config - return a description of +// any address spaces owned by this device +//------------------------------------------------- + +device_memory_interface::space_config_vector s_dsp_device::memory_space_config() const +{ + return space_config_vector{ std::make_pair(0, &m_data_config) }; +} + + +/***************************************************************************** + IMPLEMENTATION +*****************************************************************************/ + + +/*------------------------------------------------- + dsp_reset + + Reset emulated DSP +-------------------------------------------------*/ + +void s_dsp_device::dsp_reset() +{ +#ifdef MAME_DEBUG + logerror("dsp_reset\n"); +#endif + + for (int i = 0; i < 8; i++) + { +#ifndef NO_ECHO + m_fir_lbuf[i] = 0; + m_fir_rbuf[i] = 0; +#endif + m_voice_state[i].on_cnt = 0; + } + +#ifndef NO_ECHO + m_fir_ptr = 0; + m_echo_ptr = 0; +#endif + + m_keys = 0; + m_keyed_on = 0; + m_noise_cnt = 0; + m_noise_lev = 0x4000; + m_dsp_regs[0x6c] |= 0xe0; + m_dsp_regs[0x4c] = 0; + m_dsp_regs[0x5c] = 0; +} + + +/*------------------------------------------------- + dsp_update + + Mix one sample of audio. sound_ptr is a pointer + to mix audio into +-------------------------------------------------*/ + +void s_dsp_device::dsp_update( s16 *sound_ptr ) +{ + int V; + + int envx; + int m; + int v; + int vl; + voice_state_type * vp; + int vr; + + const u16 sd = m_dsp_regs[0x5d]; + + /* Check for reset */ + if (m_dsp_regs[0x6c] & 0x80) + dsp_reset(); + + /* Here we check for keys on/off. Docs say that successive writes to KON/KOF + must be separated by at least 2 Ts periods or risk being neglected. + Therefore DSP only looks at these during an update, and not at the time of + the write. Only need to do this once however, since the regs haven't + changed over the whole period we need to catch up with. */ +#ifdef DBG_KEY + m_dsp_regs[0x4c] &= mask; +#endif + + /* Keying on a voice resets that bit in ENDX */ + m_dsp_regs[0x7c] &= ~m_dsp_regs[0x4c]; + + /* Question: what is the expected behavior when pitch modulation is enabled on + voice 0? Jurassic Park 2 does this. For now, using outx of zero for first + voice. */ + s32 outx = 0; /* Smpl height (must be signed) */ + + /* Same table for noise and envelope */ + m_noise_cnt -= ENVCNT[m_dsp_regs[0x6c] & 0x1f]; + if (m_noise_cnt <= 0) + { + m_noise_cnt = CNT_INIT; + m_noise_lev = (((m_noise_lev << 13) ^ (m_noise_lev << 14)) & 0x4000) | (m_noise_lev >> 1); + } + + int outl = 0; + int outr = 0; + +#ifndef NO_ECHO + int echol = 0; + int echor = 0; +#endif + + for (v = 0, m = 1, V = 0; v < 8; v++, V += 16, m <<= 1) + { + vp = &m_voice_state[v]; + + if (vp->on_cnt && (--vp->on_cnt == 0)) + { + /* Voice was keyed on */ + m_keys |= m; + m_keyed_on |= m; +#ifdef DBG_KEY + vl = m_dsp_regs[(v << 4) + 4]; +#endif + vp->samp_id = (vptr(sd, V) << 16) | lptr(sd, V); + vp->mem_ptr = vptr(sd, V); + +#ifdef DBG_KEY + logerror("Keying on voice %d, samp=0x%04X (0x%02X)\n", v, vp->mem_ptr, vl); +#endif + + vp->header_cnt = 0; + vp->half = 0; + vp->envx = 0; + vp->end = 0; + vp->sampptr = 0; + vp->mixfrac = 3 * 4096; + + /* NOTE: Real SNES does *not* appear to initialize the envelope + counter to anything in particular. The first cycle always seems to + come at a random time sooner than expected; as yet, I have been + unable to find any pattern. I doubt it will matter though, so + we'll go ahead and do the full time for now. */ + vp->envcnt = CNT_INIT; + vp->envstate = env_state_t32::ATTACK; + } + + if (m_dsp_regs[0x4c] & m & ~m_dsp_regs[0x5c]) + { + /* Voice doesn't come on if key off is set */ + m_dsp_regs[0x4c] &= ~m; + vp->on_cnt = 8; + +#ifdef DBG_KEY + logerror("Key on set for voice %d\n", v); +#endif + } + + if (m_keys & m_dsp_regs[0x5c] & m) + { + /* Voice was keyed off */ + vp->envstate = env_state_t32::RELEASE; + vp->on_cnt = 0; + +#ifdef DBG_KEY + logerror("Keying off voice %d\n", v); +#endif + } + + if (!(m_keys & m & mask) || ((envx = advance_envelope(v)) < 0)) + { + m_dsp_regs[V + 8] = 0; + m_dsp_regs[V + 9] = 0; + outx = 0; + continue; + } + + vp->pitch = pitch(V); + +#ifndef NO_PMOD + /* Pitch mod uses OUTX from last voice for this one. Luckily we haven't + modified OUTX since it was used for last voice. */ + if (m_dsp_regs[0x2d] & m) + { +#ifdef DBG_PMOD + logerror("Pitch Modulating voice %d, outx=%ld, old pitch=%d, ", v, outx, vp->pitch); +#endif + vp->pitch = (vp->pitch * (outx + 32768)) >> 15; + } +#endif + +#ifdef DBG_PMOD + logerror("pitch=%d\n", vp->pitch); +#endif + + for ( ; vp->mixfrac >= 0; vp->mixfrac -= 4096) + { + /* This part performs the BRR decode 'on-the-fly'. This is more + correct than the old way, which could be fooled if the data and/or + the loop point changed while the sample was playing, or if the BRR + decode didn't produce the same result every loop because of the + filters. The event interface still has no chance of keeping up + with those kinds of tricks, though. */ + if (!vp->header_cnt) + { + if (vp->end & 1) + { + /* Docs say ENDX bit is set when decode of block with source + end flag set is done. Does this apply to looping samples? + Some info I've seen suggests yes. */ + m_dsp_regs[0x7c] |= m; + if (vp->end & 2) + { + vp->mem_ptr = lptr(sd, V); + +#ifdef DBG_BRR + logerror("BRR looping to 0x%04X\n", vp->mem_ptr); +#endif + } + else + { +#ifdef DBG_KEY + logerror("BRR decode end, voice %d\n", v); +#endif + + m_keys &= ~m; + m_dsp_regs[V + 8] = 0; + vp->envx = 0; + while (vp->mixfrac >= 0) + { + vp->sampbuf[vp->sampptr] = 0; + outx = 0; + vp->sampptr = (vp->sampptr + 1) & 3; + vp->mixfrac -= 4096; + } + break; + } + } + + vp->header_cnt = 8; + vl = (u8)read_byte(vp->mem_ptr++); + vp->range = vl >> 4; + vp->end = vl & 3; + vp->filter = (vl & 12) >> 2; + +#ifdef DBG_BRR + logerror("V%d: header read, range=%d, end=%d, filter=%d\n", v, vp->range, vp->end, vp->filter); +#endif + } + + if (vp->half == 0) + { + vp->half = 1; + outx = ((s8)read_byte(vp->mem_ptr)) >> 4; + } + else + { + vp->half = 0; + /* Funkiness to get 4-bit signed to carry through */ + outx = (s8)(read_byte(vp->mem_ptr++) << 4); + outx >>= 4; + vp->header_cnt--; + } + +#ifdef DBG_BRR + logerror("V%d: nybble=%X, ptr=%04X, smp1=%d, smp2=%d\n", v, outx & 0x0f, vp->mem_ptr, vp->smp1, vp->smp2); +#endif + + /* For invalid ranges (D,E,F): if the nybble is negative, the result + is F000. If positive, 0000. Nothing else like previous range, + etc. seems to have any effect. If range is valid, do the shift + normally. Note these are both shifted right once to do the filters + properly, but the output will be shifted back again at the end. */ + if (vp->range <= 0xc) + { + outx = (outx << vp->range) >> 1; + } + else + { + outx &= ~0x7ff; + +#ifdef DBG_BRR + logerror("V%d: invalid range! (%X)\n", v, vp->range); +#endif + } + +#ifdef DBG_BRR + logerror("V%d: shifted delta=%04X\n", v, (u16)outx); +#endif + + switch (vp->filter) + { + case 0: + break; + + case 1: + outx += (vp->smp1 >> 1) + ((-vp->smp1) >> 5); + break; + + case 2: + outx += vp->smp1 + ((-(vp->smp1 + (vp->smp1 >> 1))) >> 5) - (vp->smp2 >> 1) + (vp->smp2 >> 5); + break; + + case 3: + outx += vp->smp1 + ((-(vp->smp1 + (vp->smp1 << 2) + (vp->smp1 << 3))) >> 7) + - (vp->smp2 >> 1) + ((vp->smp2 + (vp->smp2 >> 1)) >> 4); + break; + } + + if (outx < (s16)0x8000) + { + outx = (s16)0x8000; + } + else if (outx > (s16)0x7fff) + { + outx = (s16)0x7fff; + } + +#ifdef DBG_BRR + logerror("V%d: filter + delta=%04X\n", v, (u16)outx); +#endif + + vp->smp2 = (s16)vp->smp1; + vp->smp1 = (s16)(outx << 1); + vp->sampbuf[vp->sampptr] = vp->smp1; + +#ifdef DBG_BRR + logerror("V%d: final output: %04X\n", v, vp->sampbuf[vp->sampptr]); +#endif + + vp->sampptr = (vp->sampptr + 1) & 3; + } + + if (m_dsp_regs[0x3d] & m) + { +#ifdef DBG_PMOD + logerror("Noise enabled, voice %d\n", v); +#endif + outx = (s16)(m_noise_lev << 1); + } + else + { + /* Perform 4-Point Gaussian interpolation. Take an approximation of a + Gaussian bell-curve, and move it through the sample data at a rate + determined by the pitch. The sample output at any given time is + the sum of the products of each input sample point with the value + of the bell-curve corresponding to that point. */ + vl = vp->mixfrac >> 4; + vr = ((G4[-vl-1] * vp->sampbuf[vp->sampptr]) >> 11 ) & ~1; + vr += ((G3[-vl] * vp->sampbuf[(vp->sampptr + 1) & 3]) >> 11) & ~1; + vr += ((G2[vl] * vp->sampbuf[(vp->sampptr + 2) & 3]) >> 11 ) & ~1; + + /* This is to do the wrapping properly. Based on my tests with the + SNES, it appears clipping is done only if it is the fourth addition + that would cause a wrap. If it has already wrapped before the + fourth addition, it is not clipped. */ + vr = (s16)vr; + vr += ((G1[vl] * vp->sampbuf[(vp->sampptr + 3) & 3]) >> 11) & ~1; + + if (vr > 32767) + vr = 32767; + else if (vr < -32768) + vr = -32768; + + outx = (s16)vr; + +#ifdef DBG_INTRP + logerror("V%d: mixfrac=%d: [%d]*%d + [%d]*%d + [%d]*%d + [%d]*%d = %d\n", v, vl, + G1[vl], + vp->sampbuf[(vp->sampptr + 3) & 3], + G2[vl], + vp->sampbuf[(vp->sampptr + 2) & 3], + G3[-vl], + vp->sampbuf[(vp->sampptr + 1) & 3], + G4[-vl-1], + vp->sampbuf[vp->sampptr], + outx); +#endif + } + + /* Advance the sample position for next update. */ + vp->mixfrac += vp->pitch; + + outx = ((outx * envx) >> 11) & ~1; + m_dsp_regs[V + 9] = outx >> 8; + + vl = (((int)(s8)m_dsp_regs[V ]) * outx) >> 7; + vr = (((int)(s8)m_dsp_regs[V + 1]) * outx) >> 7; + outl += vl; + outr += vr; + + if (m_dsp_regs[0x4d] & m) + { +#ifndef NO_ECHO + echol += vl; + echor += vr; +#endif + } + } + + outl = (outl * (s8)m_dsp_regs[0x0c]) >> 7; + outr = (outr * (s8)m_dsp_regs[0x1c]) >> 7; + +#ifndef NO_ECHO + /* Perform echo. First, read mem at current location, and put those samples + into the FIR filter queue. */ +#ifdef DBG_ECHO + logerror("Echo delay=%dms, feedback=%d%%\n", m_dsp_regs[0x7d] * 16, + ((s8)m_dsp_regs[0x0d] * 100) / 0x7f); +#endif + + int echo_base = ((m_dsp_regs[0x6d] << 8) + m_echo_ptr) & 0xffff; + m_fir_lbuf[m_fir_ptr] = (s16)read_word(echo_base); + m_fir_rbuf[m_fir_ptr] = (s16)read_word(echo_base + sizeof(s16)); + + /* Now, evaluate the FIR filter, and add the results into the final output. */ + vl = m_fir_lbuf[m_fir_ptr] * (s8)m_dsp_regs[0x7f]; + vr = m_fir_rbuf[m_fir_ptr] * (s8)m_dsp_regs[0x7f]; + m_fir_ptr = (m_fir_ptr + 1) & 7; + vl += m_fir_lbuf[m_fir_ptr] * (s8)m_dsp_regs[0x6f]; + vr += m_fir_rbuf[m_fir_ptr] * (s8)m_dsp_regs[0x6f]; + m_fir_ptr = (m_fir_ptr + 1) & 7; + vl += m_fir_lbuf[m_fir_ptr] * (s8)m_dsp_regs[0x5f]; + vr += m_fir_rbuf[m_fir_ptr] * (s8)m_dsp_regs[0x5f]; + m_fir_ptr = (m_fir_ptr + 1) & 7; + vl += m_fir_lbuf[m_fir_ptr] * (s8)m_dsp_regs[0x4f]; + vr += m_fir_rbuf[m_fir_ptr] * (s8)m_dsp_regs[0x4f]; + m_fir_ptr = (m_fir_ptr + 1) & 7; + vl += m_fir_lbuf[m_fir_ptr] * (s8)m_dsp_regs[0x3f]; + vr += m_fir_rbuf[m_fir_ptr] * (s8)m_dsp_regs[0x3f]; + m_fir_ptr = (m_fir_ptr + 1) & 7; + vl += m_fir_lbuf[m_fir_ptr] * (s8)m_dsp_regs[0x2f]; + vr += m_fir_rbuf[m_fir_ptr] * (s8)m_dsp_regs[0x2f]; + m_fir_ptr = (m_fir_ptr + 1) & 7; + vl += m_fir_lbuf[m_fir_ptr] * (s8)m_dsp_regs[0x1f]; + vr += m_fir_rbuf[m_fir_ptr] * (s8)m_dsp_regs[0x1f]; + m_fir_ptr = (m_fir_ptr + 1) & 7; + vl += m_fir_lbuf[m_fir_ptr] * (s8)m_dsp_regs[0x0f]; + vr += m_fir_rbuf[m_fir_ptr] * (s8)m_dsp_regs[0x0f]; + +#ifdef DBG_ECHO + logerror("FIR Coefficients: %02X %02X %02X %02X %02X %02X %02X %02X\n", + m_dsp_regs[0x0f], + m_dsp_regs[0x1f], + m_dsp_regs[0x2f], + m_dsp_regs[0x3f], + m_dsp_regs[0x4f], + m_dsp_regs[0x5f], + m_dsp_regs[0x6f], + m_dsp_regs[0x7f]); +#endif + + /* FIR_ptr is left in the position of the oldest sample, the one that will be replaced next update. */ + outl += vl * (s8)m_dsp_regs[0x2c] >> 14; + outr += vr * (s8)m_dsp_regs[0x3c] >> 14; + + if (!(m_dsp_regs[0x6c] & 0x20)) + { + /* Add the echo feedback back into the original result, and save that into memory for use later. */ + echol += vl * (s8)m_dsp_regs[0x0d] >> 14; + + if (echol > 32767) + echol = 32767; + else if (echol < -32768) + echol = -32768; + + echor += vr * (s8)m_dsp_regs[0x0D ] >> 14; + + if (echor > 32767) + echor = 32767; + else if (echor < -32768) + echor = -32768; + +#ifdef DBG_ECHO + logerror("Echo: Writing %04X,%04X at location %04X\n", (u16)echol, (u16)echor, echo_base); +#endif + + write_word(echo_base, (u16)echol); + write_word(echo_base + sizeof(s16), (u16)echor); + } + + m_echo_ptr += 2 * sizeof(s16); + + if (m_echo_ptr >= ((m_dsp_regs[0x7d] & 0x0f) << 11)) + { + m_echo_ptr = 0; + } +#endif /* !defined( NO_ECHO ) */ + + if (sound_ptr != nullptr) + { + if (m_dsp_regs[0x6c] & 0x40) + { + /* MUTE */ +#ifdef MAME_DEBUG + logerror("MUTED!\n"); +#endif + + *sound_ptr = 0; + sound_ptr++; + *sound_ptr = 0; + sound_ptr++; + } + else + { + if (outl > 32767) + *sound_ptr = 32767; + else if (outl < -32768) + *sound_ptr = -32768; + else + *sound_ptr = outl; + + sound_ptr++; + + if (outr > 32767) + *sound_ptr = 32767; + else if (outr < -32768) + *sound_ptr = -32768; + else + *sound_ptr = outr; + + sound_ptr++; + } + } +} + + +/*------------------------------------------------- + advance_envelope + + Run envelope step & return ENVX. v is the voice + to process envelope for. +-------------------------------------------------*/ + +int s_dsp_device::advance_envelope( int v ) +{ + int t; + + int envx = m_voice_state[v].envx; + + if (m_voice_state[v].envstate == env_state_t32::RELEASE) + { + /* Docs: "When in the state of "key off". the "click" sound is prevented + by the addition of the fixed value 1/256" WTF??? Alright, I'm going + to choose to interpret that this way: When a note is keyed off, start + the RELEASE state, which subtracts 1/256th each sample period (32kHz). + Note there's no need for a count because it always happens every + update. */ + envx -= 0x8; /* 0x8 / 0x800 = 1/256th */ + if (envx <= 0) + { + envx = 0; + m_keys &= ~(1 << v); + return -1; + } + + m_voice_state[v].envx = envx; + m_dsp_regs[(v << 4) + 8] = envx >> 8; + +#ifdef DBG_ENV + logerror("ENV voice %d: envx=%03X, state=RELEASE\n", v, envx); +#endif + + return envx; + } + + int cnt = m_voice_state[v].envcnt; + int adsr1 = m_dsp_regs[(v << 4) + 5]; + + if (adsr1 & 0x80) + { + switch (m_voice_state[v].envstate) + { + case env_state_t32::ATTACK: + /* Docs are very confusing. "AR is multiplied by the fixed value + 1/64..." I believe it means to add 1/64th to ENVX once every + time ATTACK is updated, and that's what I'm going to implement. */ + t = adsr1 & 0x0f; + + if (t == 0x0f) + { +#ifdef DBG_ENV + logerror("ENV voice %d: instant attack\n", v); +#endif + + envx += 0x400; + } + else + { + cnt -= ENVCNT[(t << 1) + 1]; + + if (cnt > 0) + break; + + envx += 0x20; /* 0x020 / 0x800 = 1/64 */ + cnt = CNT_INIT; + } + + if (envx > 0x7ff) + { + envx = 0x7ff; + m_voice_state[v].envstate = env_state_t32::DECAY; + } + +#ifdef DBG_ENV + logerror("ENV voice %d: envx=%03X, state=ATTACK\n", v, envx); +#endif + + m_voice_state[v].envx = envx; + break; + + case env_state_t32::DECAY: + /* Docs: "DR... [is multiplied] by the fixed value 1-1/256." + Well, at least that makes some sense. Multiplying ENVX by + 255/256 every time DECAY is updated. */ + cnt -= ENVCNT[((adsr1 >> 3) & 0x0e) + 0x10]; + + if (cnt <= 0) + { + cnt = CNT_INIT; + envx -= ((envx - 1) >> 8) + 1; + m_voice_state[v].envx = envx; + } + + if (envx <= 0x100 * (SL(v) + 1)) + m_voice_state[v].envstate = env_state_t32::SUSTAIN; + +#ifdef DBG_ENV + logerror("ENV voice %d: envx=%03X, state=DECAY\n", v, envx); +#endif + + break; + + case env_state_t32::SUSTAIN: + /* Docs: "SR [is multiplied] by the fixed value 1-1/256." + Multiplying ENVX by 255/256 every time SUSTAIN is updated. */ +#ifdef DBG_ENV + if (ENVCNT[SR(v)] == 0) + logerror("ENV voice %d: envx=%03X, state=SUSTAIN, zero rate\n", v, envx); +#endif + + cnt -= ENVCNT[SR(v)]; + if (cnt > 0) + break; + + cnt = CNT_INIT; + envx -= ((envx - 1) >> 8) + 1; + +#ifdef DBG_ENV + logerror("ENV voice %d: envx=%03X, state=SUSTAIN\n", v, envx); +#endif + + m_voice_state[v].envx = envx; + + /* Note: no way out of this state except by explicit KEY OFF (or switch to GAIN). */ + break; + + case env_state_t32::RELEASE: /* Handled earlier to prevent GAIN mode from stopping KEY OFF events */ + break; + } + } + else + { + /* GAIN mode is set + Note: if the game switches between ADSR and GAIN modes partway + through, should the count be reset, or should it continue from + where it was? Does the DSP actually watch for that bit to + change, or does it just go along with whatever it sees when it + performs the update? I'm going to assume the latter and not + update the count, unless I see a game that obviously wants the + other behavior. The effect would be pretty subtle, in any case. + */ + t = m_dsp_regs[(v << 4) + 7]; + + if (t < 0x80) + { + envx = t << 4; + m_voice_state[v].envx = envx; + +#ifdef DBG_ENV + logerror("ENV voice %d: envx=%03X, state=DIRECT\n", v, envx); +#endif + } + else + { + switch (t >> 5) + { + case 4: + /* Docs: "Decrease (linear): Subtraction of the fixed value 1/64." */ + cnt -= ENVCNT[t & 0x1f]; + + if (cnt > 0) + break; + + cnt = CNT_INIT; + envx -= 0x020; /* 0x020 / 0x800 = 1/64th */ + + if (envx < 0) + envx = 0; + +#ifdef DBG_ENV + logerror("ENV voice %d: envx=%03X, state=DECREASE\n", v, envx); +#endif + + m_voice_state[v].envx = envx; + break; + + case 5: + /* Docs: "Drecrease (exponential): Multiplication by the fixed value 1-1/256." */ + cnt -= ENVCNT[t & 0x1f]; + + if (cnt > 0) + break; + + cnt = CNT_INIT; + envx -= ((envx - 1) >> 8) + 1; + +#ifdef DBG_ENV + logerror("ENV voice %d: envx=%03X, state=EXP\n", v, envx); +#endif + + m_voice_state[v].envx = envx; + break; + + case 6: + /* Docs: "Increase (linear): Addition of the fixed value 1/64." */ + cnt -= ENVCNT[t & 0x1f]; + + if (cnt > 0) + break; + + cnt = CNT_INIT; + envx += 0x020; /* 0x020 / 0x800 = 1/64th */ + if (envx > 0x7ff) + envx = 0x7ff; + +#ifdef DBG_ENV + logerror("ENV voice %d: envx=%03X, state=INCREASE\n", v, envx); +#endif + + m_voice_state[v].envx = envx; + break; + + case 7: + /* Docs: "Increase (bent line): Addition of the constant + 1/64 up to .75 of the constaint 1/256 from .75 to 1." */ + cnt -= ENVCNT[t & 0x1f]; + + if (cnt > 0) + break; + + cnt = CNT_INIT; + + if (envx < 0x600) /* 0x600 / 0x800 = .75 */ + envx += 0x020; /* 0x020 / 0x800 = 1/64 */ + else + envx += 0x008; /* 0x008 / 0x800 = 1/256 */ + + if (envx > 0x7ff) + envx=0x7ff; + +#ifdef DBG_ENV + logerror("ENV voice %d: envx=%03X, state=INCREASE\n", v, envx); +#endif + + m_voice_state[v].envx = envx; + break; + } + } + } + + m_voice_state[v].envcnt = cnt; + m_dsp_regs[(v << 4) + 8] = envx >> 4; + + return envx; +} + +/*------------------------------------------------- + set_volume - sets S-DSP volume level + for both speakers, used for fade in/out effects +-------------------------------------------------*/ + +void s_dsp_device::set_volume(int volume) +{ + m_channel->set_output_gain(0, volume / 100.0); + m_channel->set_output_gain(1, volume / 100.0); +} + + +/*************************** + I/O for DSP + ***************************/ + +u8 s_dsp_device::dsp_io_r(offs_t offset) +{ + m_channel->update(); + +#ifdef NO_ENVX + if (!machine().side_effects_disabled()) + if (8 == (m_dsp_addr & 0x0f)) + m_dsp_regs[m_dsp_addr] = 0; +#endif + + /* All reads simply return the contents of the addressed register. */ + if (offset & 1) + return m_dsp_regs[m_dsp_addr & 0x7f]; + + return m_dsp_addr; +} + +void s_dsp_device::dsp_io_w(offs_t offset, u8 data) +{ + m_channel->update(); + + if (offset & 1) + { + if (!(m_dsp_addr & 0x80)) + { + offset = m_dsp_addr & 0x7f; + if (offset == 0x7c) + { + /* Writes to register 0x7c (ENDX) clear ALL bits no matter which value is written */ + m_dsp_regs[offset & 0x7f] = 0; + } + else + { + /* All other writes store the value in the addressed register as expected. */ + m_dsp_regs[offset & 0x7f] = data; + } + } + } + else + m_dsp_addr = data; +} + +/***************************************************************************** + DEVICE INTERFACE +*****************************************************************************/ + +void s_dsp_device::state_register() +{ + save_item(NAME(m_dsp_addr)); + save_item(NAME(m_dsp_regs)); + + save_item(NAME(m_keyed_on)); + save_item(NAME(m_keys)); + + save_item(NAME(m_noise_cnt)); + save_item(NAME(m_noise_lev)); + +#ifndef NO_ECHO + save_item(NAME(m_fir_lbuf)); + save_item(NAME(m_fir_rbuf)); + save_item(NAME(m_fir_ptr)); + save_item(NAME(m_echo_ptr)); +#endif + + for (int v = 0; v < 8; v++) + { + save_item(NAME(m_voice_state[v].mem_ptr), v); + save_item(NAME(m_voice_state[v].end), v); + save_item(NAME(m_voice_state[v].envcnt), v); + save_item(NAME(m_voice_state[v].envstate), v); + save_item(NAME(m_voice_state[v].envx), v); + save_item(NAME(m_voice_state[v].filter), v); + save_item(NAME(m_voice_state[v].half), v); + save_item(NAME(m_voice_state[v].header_cnt), v); + save_item(NAME(m_voice_state[v].mixfrac), v); + save_item(NAME(m_voice_state[v].on_cnt), v); + save_item(NAME(m_voice_state[v].pitch), v); + save_item(NAME(m_voice_state[v].range), v); + save_item(NAME(m_voice_state[v].samp_id), v); + save_item(NAME(m_voice_state[v].sampptr), v); + save_item(NAME(m_voice_state[v].smp1), v); + save_item(NAME(m_voice_state[v].smp2), v); + save_item(NAME(m_voice_state[v].sampbuf), v); + } +} + +//------------------------------------------------- +// sound_stream_update - handle a stream update +//------------------------------------------------- + +void s_dsp_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + s16 mix[2]; + + for (int i = 0; i < samples; i++) + { + mix[0] = mix[1] = 0; + dsp_update(mix); + + /* Update the buffers */ + outputs[0][i] = (stream_sample_t)mix[0]; + outputs[1][i] = (stream_sample_t)mix[1]; + } +} diff --git a/src/devices/sound/s_dsp.h b/src/devices/sound/s_dsp.h new file mode 100644 index 00000000000..934a0a6d88e --- /dev/null +++ b/src/devices/sound/s_dsp.h @@ -0,0 +1,116 @@ +// license:LGPL-2.1+ +// copyright-holders:R. Belmont, Brad Martin +/***************************************************************************** + * + * Nintendo/Sony S-DSP emulation + * + ****************************************************************************/ + +#ifndef MAME_SOUND_S_DSP_H +#define MAME_SOUND_S_DSP_H + +/*************************************************************************** + TYPE DEFINITIONS + ***************************************************************************/ + +class s_dsp_device : public device_t, public device_sound_interface, public device_memory_interface +{ +public: + s_dsp_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); + + void set_volume(int volume); + + u8 dsp_io_r(offs_t offset); + void dsp_io_w(offs_t offset, u8 data); + +protected: + // device-level overrides + virtual void device_start() override; + virtual void device_reset() override; + virtual void device_clock_changed() override; + + // sound stream update overrides + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) override; + + // device_memory_interface configuration + virtual space_config_vector memory_space_config() const override; + + address_space_config m_data_config; + +private: + address_space *m_data; + memory_access_cache<0, 0, ENDIANNESS_LITTLE> *m_cache; + inline u8 read_byte(offs_t a) { return m_cache->read_byte(a); } + inline u16 read_word(offs_t a) { return read_byte(a) | (read_byte(a + 1) << 8); } + inline void write_byte(offs_t a, u8 d) { m_data->write_byte(a, d); } + inline void write_word(offs_t a, u16 d) { write_byte(a, d & 0xff); write_byte(a + 1, (d >> 8) & 0xff); } + + enum class env_state_t32 : u8 + { + ATTACK, + DECAY, + SUSTAIN, + RELEASE + }; + + struct voice_state_type /* Voice state type */ + { + u16 mem_ptr; /* Sample data memory pointer */ + int end; /* End or loop after block */ + int envcnt; /* Counts to envelope update */ + env_state_t32 envstate; /* Current envelope state */ + int envx; /* Last env height (0-0x7FFF) */ + int filter; /* Last header's filter */ + int half; /* Active nybble of BRR */ + int header_cnt; /* Bytes before new header (0-8)*/ + int mixfrac; /* Fractional part of smpl pstn */ + int on_cnt; /* Is it time to turn on yet? */ + int pitch; /* Sample pitch (4096->32000Hz) */ + int range; /* Last header's range */ + u32 samp_id; /* Sample ID# */ + int sampptr; /* Where in sampbuf we are */ + s32 smp1; /* Last sample (for BRR filter) */ + s32 smp2; /* Second-to-last sample decoded*/ + s16 sampbuf[4]; /* Buffer for Gaussian interp */ + }; + + inline u16 vptr(u8 sd, u8 v) { return read_word((sd << 8) + (m_dsp_regs[v + 4] << 2)); } /* Ptr to start of sample data */ + inline u16 lptr(u8 sd, u8 v) { return read_word((sd << 8) + (m_dsp_regs[v + 4] << 2) + 2); } /* Loop pointer in sample data */ + inline u16 pitch(u8 v) { (m_dsp_regs[v + 2] | (m_dsp_regs[v + 3] << 8)) & 0x3fff; } + + /* Make reading the ADSR code easier */ + inline u8 SL(u8 v) { return m_dsp_regs[(v << 4) + 6] >> 5; } /* Returns SUSTAIN level */ + inline u8 SR(u8 v) { return m_dsp_regs[(v << 4) + 6] & 0x1f; } /* Returns SUSTAIN rate */ + + void dsp_reset(); + void dsp_update(s16 *sound_ptr); + int advance_envelope(int v); + void state_register(); + + // internal state + sound_stream *m_channel; + u8 m_dsp_addr; + u8 m_dsp_regs[256]; /* DSP registers */ + + int m_keyed_on; + int m_keys; /* 8-bits for 8 voices */ + voice_state_type m_voice_state[8]; + + /* Noise stuff */ + int m_noise_cnt; + int m_noise_lev; + + /* These are for the FIR echo filter */ +#ifndef NO_ECHO + s16 m_fir_lbuf[8]; + s16 m_fir_rbuf[8]; + int m_fir_ptr; + int m_echo_ptr; +#endif + +}; + +DECLARE_DEVICE_TYPE(S_DSP, s_dsp_device) + + +#endif // MAME_SOUND_S_DSP_H diff --git a/src/mame/audio/snes_snd.cpp b/src/mame/audio/snes_snd.cpp deleted file mode 100644 index 8983b6df3a2..00000000000 --- a/src/mame/audio/snes_snd.cpp +++ /dev/null @@ -1,1266 +0,0 @@ -// license:LGPL-2.1+ -// copyright-holders:R. Belmont, Brad Martin -/*************************************************************************** - - snes_snd.cpp - - File to handle the sound emulation of the Nintendo Super NES. - - By R. Belmont, adapted from OpenSPC 0.3.99 by Brad Martin with permission. - Thanks to Brad and also to Charles Bilyu? of SNeESe. - - OpenSPC's license terms (the LGPL) follow: - - --------------------------------------------------------------------------- - - Copyright Brad Martin. - - OpenSPC is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - OpenSPC is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - -***************************************************************************/ - -#include "emu.h" -#include "audio/snes_snd.h" - -/*************************************************************************** - CONSTANTS AND MACROS -***************************************************************************/ - -static const int gauss[]= -{ - 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, - 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, - 0x001, 0x001, 0x001, 0x001, 0x001, 0x001, 0x001, 0x001, - 0x001, 0x001, 0x001, 0x002, 0x002, 0x002, 0x002, 0x002, - 0x002, 0x002, 0x003, 0x003, 0x003, 0x003, 0x003, 0x004, - 0x004, 0x004, 0x004, 0x004, 0x005, 0x005, 0x005, 0x005, - 0x006, 0x006, 0x006, 0x006, 0x007, 0x007, 0x007, 0x008, - 0x008, 0x008, 0x009, 0x009, 0x009, 0x00A, 0x00A, 0x00A, - 0x00B, 0x00B, 0x00B, 0x00C, 0x00C, 0x00D, 0x00D, 0x00E, - 0x00E, 0x00F, 0x00F, 0x00F, 0x010, 0x010, 0x011, 0x011, - 0x012, 0x013, 0x013, 0x014, 0x014, 0x015, 0x015, 0x016, - 0x017, 0x017, 0x018, 0x018, 0x019, 0x01A, 0x01B, 0x01B, - 0x01C, 0x01D, 0x01D, 0x01E, 0x01F, 0x020, 0x020, 0x021, - 0x022, 0x023, 0x024, 0x024, 0x025, 0x026, 0x027, 0x028, - 0x029, 0x02A, 0x02B, 0x02C, 0x02D, 0x02E, 0x02F, 0x030, - 0x031, 0x032, 0x033, 0x034, 0x035, 0x036, 0x037, 0x038, - 0x03A, 0x03B, 0x03C, 0x03D, 0x03E, 0x040, 0x041, 0x042, - 0x043, 0x045, 0x046, 0x047, 0x049, 0x04A, 0x04C, 0x04D, - 0x04E, 0x050, 0x051, 0x053, 0x054, 0x056, 0x057, 0x059, - 0x05A, 0x05C, 0x05E, 0x05F, 0x061, 0x063, 0x064, 0x066, - 0x068, 0x06A, 0x06B, 0x06D, 0x06F, 0x071, 0x073, 0x075, - 0x076, 0x078, 0x07A, 0x07C, 0x07E, 0x080, 0x082, 0x084, - 0x086, 0x089, 0x08B, 0x08D, 0x08F, 0x091, 0x093, 0x096, - 0x098, 0x09A, 0x09C, 0x09F, 0x0A1, 0x0A3, 0x0A6, 0x0A8, - 0x0AB, 0x0AD, 0x0AF, 0x0B2, 0x0B4, 0x0B7, 0x0BA, 0x0BC, - 0x0BF, 0x0C1, 0x0C4, 0x0C7, 0x0C9, 0x0CC, 0x0CF, 0x0D2, - 0x0D4, 0x0D7, 0x0DA, 0x0DD, 0x0E0, 0x0E3, 0x0E6, 0x0E9, - 0x0EC, 0x0EF, 0x0F2, 0x0F5, 0x0F8, 0x0FB, 0x0FE, 0x101, - 0x104, 0x107, 0x10B, 0x10E, 0x111, 0x114, 0x118, 0x11B, - 0x11E, 0x122, 0x125, 0x129, 0x12C, 0x130, 0x133, 0x137, - 0x13A, 0x13E, 0x141, 0x145, 0x148, 0x14C, 0x150, 0x153, - 0x157, 0x15B, 0x15F, 0x162, 0x166, 0x16A, 0x16E, 0x172, - 0x176, 0x17A, 0x17D, 0x181, 0x185, 0x189, 0x18D, 0x191, - 0x195, 0x19A, 0x19E, 0x1A2, 0x1A6, 0x1AA, 0x1AE, 0x1B2, - 0x1B7, 0x1BB, 0x1BF, 0x1C3, 0x1C8, 0x1CC, 0x1D0, 0x1D5, - 0x1D9, 0x1DD, 0x1E2, 0x1E6, 0x1EB, 0x1EF, 0x1F3, 0x1F8, - 0x1FC, 0x201, 0x205, 0x20A, 0x20F, 0x213, 0x218, 0x21C, - 0x221, 0x226, 0x22A, 0x22F, 0x233, 0x238, 0x23D, 0x241, - 0x246, 0x24B, 0x250, 0x254, 0x259, 0x25E, 0x263, 0x267, - 0x26C, 0x271, 0x276, 0x27B, 0x280, 0x284, 0x289, 0x28E, - 0x293, 0x298, 0x29D, 0x2A2, 0x2A6, 0x2AB, 0x2B0, 0x2B5, - 0x2BA, 0x2BF, 0x2C4, 0x2C9, 0x2CE, 0x2D3, 0x2D8, 0x2DC, - 0x2E1, 0x2E6, 0x2EB, 0x2F0, 0x2F5, 0x2FA, 0x2FF, 0x304, - 0x309, 0x30E, 0x313, 0x318, 0x31D, 0x322, 0x326, 0x32B, - 0x330, 0x335, 0x33A, 0x33F, 0x344, 0x349, 0x34E, 0x353, - 0x357, 0x35C, 0x361, 0x366, 0x36B, 0x370, 0x374, 0x379, - 0x37E, 0x383, 0x388, 0x38C, 0x391, 0x396, 0x39B, 0x39F, - 0x3A4, 0x3A9, 0x3AD, 0x3B2, 0x3B7, 0x3BB, 0x3C0, 0x3C5, - 0x3C9, 0x3CE, 0x3D2, 0x3D7, 0x3DC, 0x3E0, 0x3E5, 0x3E9, - 0x3ED, 0x3F2, 0x3F6, 0x3FB, 0x3FF, 0x403, 0x408, 0x40C, - 0x410, 0x415, 0x419, 0x41D, 0x421, 0x425, 0x42A, 0x42E, - 0x432, 0x436, 0x43A, 0x43E, 0x442, 0x446, 0x44A, 0x44E, - 0x452, 0x455, 0x459, 0x45D, 0x461, 0x465, 0x468, 0x46C, - 0x470, 0x473, 0x477, 0x47A, 0x47E, 0x481, 0x485, 0x488, - 0x48C, 0x48F, 0x492, 0x496, 0x499, 0x49C, 0x49F, 0x4A2, - 0x4A6, 0x4A9, 0x4AC, 0x4AF, 0x4B2, 0x4B5, 0x4B7, 0x4BA, - 0x4BD, 0x4C0, 0x4C3, 0x4C5, 0x4C8, 0x4CB, 0x4CD, 0x4D0, - 0x4D2, 0x4D5, 0x4D7, 0x4D9, 0x4DC, 0x4DE, 0x4E0, 0x4E3, - 0x4E5, 0x4E7, 0x4E9, 0x4EB, 0x4ED, 0x4EF, 0x4F1, 0x4F3, - 0x4F5, 0x4F6, 0x4F8, 0x4FA, 0x4FB, 0x4FD, 0x4FF, 0x500, - 0x502, 0x503, 0x504, 0x506, 0x507, 0x508, 0x50A, 0x50B, - 0x50C, 0x50D, 0x50E, 0x50F, 0x510, 0x511, 0x511, 0x512, - 0x513, 0x514, 0x514, 0x515, 0x516, 0x516, 0x517, 0x517, - 0x517, 0x518, 0x518, 0x518, 0x518, 0x518, 0x519, 0x519, - 0x519, 0x519, 0x519, 0x519, 0x519, 0x519, 0x519, 0x519 -}; - -#undef DEBUG -#undef DBG_KEY -#undef DBG_ENV -#undef DBG_PMOD -#undef DBG_BRR -#undef DBG_ECHO -#undef DBG_INTRP - -#undef NO_PMOD -#undef NO_ECHO - -/* Ptrs to Gaussian table */ -static const int *const G1 = &gauss[256]; -static const int *const G2 = &gauss[512]; -static const int *const G3 = &gauss[255]; -static const int *const G4 = &gauss[0]; - -static const int mask = 0xFF; - -/* This table is for envelope timing. It represents the number of counts - that should be subtracted from the counter each sample period (32kHz). - The counter starts at 30720 (0x7800). */ -static const int CNT_INIT = 0x7800; -static const int ENVCNT[0x20] - = { - 0x0000, 0x000F, 0x0014, 0x0018, 0x001E, 0x0028, 0x0030, 0x003C, - 0x0050, 0x0060, 0x0078, 0x00A0, 0x00C0, 0x00F0, 0x0140, 0x0180, - 0x01E0, 0x0280, 0x0300, 0x03C0, 0x0500, 0x0600, 0x0780, 0x0A00, - 0x0C00, 0x0F00, 0x1400, 0x1800, 0x1E00, 0x2800, 0x3C00, 0x7800 - }; - - -/* Make reading the ADSR code easier */ -#define SL( v ) (m_dsp_regs[((v) << 4) + 6] >> 5) /* Returns SUSTAIN level */ -#define SR( v ) (m_dsp_regs[((v) << 4) + 6] & 0x1f) /* Returns SUSTAIN rate */ - -/* Handle endianness */ -#define LEtoME16( x ) little_endianize_int16(x) -#define MEtoLE16( x ) little_endianize_int16(x) - -ALLOW_SAVE_TYPE(snes_sound_device::env_state_t32); - - -DEFINE_DEVICE_TYPE(SNES_SOUND, snes_sound_device, "snes_sound", "SNES Custom DSP (SPC700)") - -snes_sound_device::snes_sound_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) - : device_t(mconfig, SNES_SOUND, tag, owner, clock) - , device_sound_interface(mconfig, *this) -{ -} - -//------------------------------------------------- -// device_start - device-specific startup -//------------------------------------------------- - -void snes_sound_device::device_start() -{ - m_channel = machine().sound().stream_alloc(*this, 0, 2, clock() / 64); - - m_ram = make_unique_clear(SNES_SPCRAM_SIZE); - - /* put IPL image at the top of RAM */ - memcpy(m_ipl_region, machine().root_device().memregion("sound_ipl")->base(), 64); - - m_tick_timer = timer_alloc(TIMER_TICK_ID); - - state_register(); - save_pointer(NAME(m_ram), SNES_SPCRAM_SIZE); -} - -//------------------------------------------------- -// device_reset - device-specific reset -//------------------------------------------------- - -void snes_sound_device::device_reset() -{ - int i; - /* default to ROM visible */ - m_ram[0xf1] = 0x80; - - /* Sort out the ports */ - for (i = 0; i < 4; i++) - { - m_port_in[i] = 0; - m_port_out[i] = 0; - } - - for (i = 0; i < 3; i++) - { - m_timer_enabled[i] = false; - m_TnDIV[i] = 256; - m_counter[i] = 0; - m_subcounter[i] = 0; - } - - attotime period = attotime::from_ticks(32, clock()); - m_tick_timer->adjust(period, 0, period); - - dsp_reset(); -} - -//------------------------------------------------- -// device_clock_changed - called if the clock -// changes -//------------------------------------------------- - -void snes_sound_device::device_clock_changed() -{ - m_channel->set_sample_rate(clock() / 64); - attotime period = attotime::from_ticks(32, clock()); - m_tick_timer->adjust(period, 0, period); -} - -inline void snes_sound_device::update_timer_tick(u8 which) -{ - if (m_timer_enabled[which] == false) - return; - - m_subcounter[which]++; - - // if timer channel is 0 or 1 we update at 64000/8 - if (m_subcounter[which] >= 8 || which == 2) - { - m_subcounter[which] = 0; - m_counter[which]++; - if (m_counter[which] >= m_TnDIV[which] ) // minus = - { - m_counter[which] = 0; - m_ram[0xfd + which]++; - m_ram[0xfd + which] &= 0x0f; - } - } -} - -void snes_sound_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) -{ - if (id != TIMER_TICK_ID) - throw emu_fatalerror("Unknown id in snes_sound_device::device_timer"); - - for (int ch = 0; ch < 3; ch++) - update_timer_tick(ch); -} - - -/***************************************************************************** - IMPLEMENTATION -*****************************************************************************/ - - -/*------------------------------------------------- - dsp_reset - - Reset emulated DSP --------------------------------------------------*/ - -void snes_sound_device::dsp_reset() -{ -#ifdef MAME_DEBUG - logerror("dsp_reset\n"); -#endif - - for (int i = 0; i < 8; i++) - { -#ifndef NO_ECHO - m_fir_lbuf[i] = 0; - m_fir_rbuf[i] = 0; -#endif - m_voice_state[i].on_cnt = 0; - } - -#ifndef NO_ECHO - m_fir_ptr = 0; - m_echo_ptr = 0; -#endif - - m_keys = 0; - m_keyed_on = 0; - m_noise_cnt = 0; - m_noise_lev = 0x4000; - m_dsp_regs[0x6c] |= 0xe0; - m_dsp_regs[0x4c] = 0; - m_dsp_regs[0x5c] = 0; -} - - -/*------------------------------------------------- - dsp_update - - Mix one sample of audio. sound_ptr is a pointer - to mix audio into --------------------------------------------------*/ - -void snes_sound_device::dsp_update( s16 *sound_ptr ) -{ - int V; - - int envx; - int m; - src_dir_type * sd; - int v; - int vl; - voice_state_type * vp; - int vr; - - sd = (src_dir_type *) &m_ram[(int) m_dsp_regs[0x5d] << 8]; - - /* Check for reset */ - if (m_dsp_regs[0x6c] & 0x80) - dsp_reset(); - - /* Here we check for keys on/off. Docs say that successive writes to KON/KOF - must be separated by at least 2 Ts periods or risk being neglected. - Therefore DSP only looks at these during an update, and not at the time of - the write. Only need to do this once however, since the regs haven't - changed over the whole period we need to catch up with. */ -#ifdef DBG_KEY - m_dsp_regs[0x4c] &= mask; -#endif - - /* Keying on a voice resets that bit in ENDX */ - m_dsp_regs[0x7c] &= ~m_dsp_regs[0x4c]; - - /* Question: what is the expected behavior when pitch modulation is enabled on - voice 0? Jurassic Park 2 does this. For now, using outx of zero for first - voice. */ - s32 outx = 0; /* Smpl height (must be signed) */ - - /* Same table for noise and envelope */ - m_noise_cnt -= ENVCNT[m_dsp_regs[0x6c] & 0x1f]; - if (m_noise_cnt <= 0) - { - m_noise_cnt = CNT_INIT; - m_noise_lev = (((m_noise_lev << 13) ^ (m_noise_lev << 14)) & 0x4000) | (m_noise_lev >> 1); - } - - int outl = 0; - int outr = 0; - -#ifndef NO_ECHO - int echol = 0; - int echor = 0; -#endif - - for (v = 0, m = 1, V = 0; v < 8; v++, V += 16, m <<= 1) - { - vp = &m_voice_state[v]; - - if (vp->on_cnt && (--vp->on_cnt == 0)) - { - /* Voice was keyed on */ - m_keys |= m; - m_keyed_on |= m; - vl = m_dsp_regs[(v << 4) + 4]; - vp->samp_id = *( u32 * )&sd[vl]; - vp->mem_ptr = LEtoME16(sd[vl].vptr); - -#ifdef DBG_KEY - logerror("Keying on voice %d, samp=0x%04X (0x%02X)\n", v, vp->mem_ptr, vl); -#endif - - vp->header_cnt = 0; - vp->half = 0; - vp->envx = 0; - vp->end = 0; - vp->sampptr = 0; - vp->mixfrac = 3 * 4096; - - /* NOTE: Real SNES does *not* appear to initialize the envelope - counter to anything in particular. The first cycle always seems to - come at a random time sooner than expected; as yet, I have been - unable to find any pattern. I doubt it will matter though, so - we'll go ahead and do the full time for now. */ - vp->envcnt = CNT_INIT; - vp->envstate = env_state_t32::ATTACK; - } - - if (m_dsp_regs[0x4c] & m & ~m_dsp_regs[0x5c]) - { - /* Voice doesn't come on if key off is set */ - m_dsp_regs[0x4c] &= ~m; - vp->on_cnt = 8; - -#ifdef DBG_KEY - logerror("Key on set for voice %d\n", v); -#endif - } - - if (m_keys & m_dsp_regs[0x5c] & m) - { - /* Voice was keyed off */ - vp->envstate = env_state_t32::RELEASE; - vp->on_cnt = 0; - -#ifdef DBG_KEY - logerror("Keying off voice %d\n", v); -#endif - } - - if (!(m_keys & m & mask) || ((envx = advance_envelope(v)) < 0)) - { - m_dsp_regs[V + 8] = 0; - m_dsp_regs[V + 9] = 0; - outx = 0; - continue; - } - - vp->pitch = LEtoME16(*((u16 *)&m_dsp_regs[V + 2])) & 0x3fff; - -#ifndef NO_PMOD - /* Pitch mod uses OUTX from last voice for this one. Luckily we haven't - modified OUTX since it was used for last voice. */ - if (m_dsp_regs[0x2d] & m) - { -#ifdef DBG_PMOD - logerror("Pitch Modulating voice %d, outx=%ld, old pitch=%d, ", v, outx, vp->pitch); -#endif - vp->pitch = (vp->pitch * (outx + 32768)) >> 15; - } -#endif - -#ifdef DBG_PMOD - logerror("pitch=%d\n", vp->pitch); -#endif - - for ( ; vp->mixfrac >= 0; vp->mixfrac -= 4096) - { - /* This part performs the BRR decode 'on-the-fly'. This is more - correct than the old way, which could be fooled if the data and/or - the loop point changed while the sample was playing, or if the BRR - decode didn't produce the same result every loop because of the - filters. The event interface still has no chance of keeping up - with those kinds of tricks, though. */ - if (!vp->header_cnt) - { - if (vp->end & 1) - { - /* Docs say ENDX bit is set when decode of block with source - end flag set is done. Does this apply to looping samples? - Some info I've seen suggests yes. */ - m_dsp_regs[0x7c] |= m; - if (vp->end & 2) - { - vp->mem_ptr = LEtoME16(sd[m_dsp_regs[V + 4]].lptr); - -#ifdef DBG_BRR - logerror("BRR looping to 0x%04X\n", vp->mem_ptr); -#endif - } - else - { -#ifdef DBG_KEY - logerror("BRR decode end, voice %d\n", v); -#endif - - m_keys &= ~m; - m_dsp_regs[V + 8] = 0; - vp->envx = 0; - while (vp->mixfrac >= 0) - { - vp->sampbuf[vp->sampptr] = 0; - outx = 0; - vp->sampptr = (vp->sampptr + 1) & 3; - vp->mixfrac -= 4096; - } - break; - } - } - - vp->header_cnt = 8; - vl = (u8)m_ram[vp->mem_ptr++]; - vp->range = vl >> 4; - vp->end = vl & 3; - vp->filter = (vl & 12) >> 2; - -#ifdef DBG_BRR - logerror("V%d: header read, range=%d, end=%d, filter=%d\n", v, vp->range, vp->end, vp->filter); -#endif - } - - if (vp->half == 0) - { - vp->half = 1; - outx = ((s8)m_ram[vp->mem_ptr]) >> 4; - } - else - { - vp->half = 0; - /* Funkiness to get 4-bit signed to carry through */ - outx = (s8)(m_ram[vp->mem_ptr++] << 4); - outx >>= 4; - vp->header_cnt--; - } - -#ifdef DBG_BRR - logerror("V%d: nybble=%X, ptr=%04X, smp1=%d, smp2=%d\n", v, outx & 0x0f, vp->mem_ptr, vp->smp1, vp->smp2); -#endif - - /* For invalid ranges (D,E,F): if the nybble is negative, the result - is F000. If positive, 0000. Nothing else like previous range, - etc. seems to have any effect. If range is valid, do the shift - normally. Note these are both shifted right once to do the filters - properly, but the output will be shifted back again at the end. */ - if (vp->range <= 0xc) - { - outx = (outx << vp->range) >> 1; - } - else - { - outx &= ~0x7ff; - -#ifdef DBG_BRR - logerror("V%d: invalid range! (%X)\n", v, vp->range); -#endif - } - -#ifdef DBG_BRR - logerror("V%d: shifted delta=%04X\n", v, (u16)outx); -#endif - - switch (vp->filter) - { - case 0: - break; - - case 1: - outx += (vp->smp1 >> 1) + ((-vp->smp1) >> 5); - break; - - case 2: - outx += vp->smp1 + ((-(vp->smp1 + (vp->smp1 >> 1))) >> 5) - (vp->smp2 >> 1) + (vp->smp2 >> 5); - break; - - case 3: - outx += vp->smp1 + ((-(vp->smp1 + (vp->smp1 << 2) + (vp->smp1 << 3))) >> 7) - - (vp->smp2 >> 1) + ((vp->smp2 + (vp->smp2 >> 1)) >> 4); - break; - } - - if (outx < (s16)0x8000) - { - outx = (s16)0x8000; - } - else if (outx > (s16)0x7fff) - { - outx = (s16)0x7fff; - } - -#ifdef DBG_BRR - logerror("V%d: filter + delta=%04X\n", v, (u16)outx); -#endif - - vp->smp2 = (s16)vp->smp1; - vp->smp1 = (s16)(outx << 1); - vp->sampbuf[vp->sampptr] = vp->smp1; - -#ifdef DBG_BRR - logerror("V%d: final output: %04X\n", v, vp->sampbuf[vp->sampptr]); -#endif - - vp->sampptr = (vp->sampptr + 1) & 3; - } - - if (m_dsp_regs[0x3d] & m) - { -#ifdef DBG_PMOD - logerror("Noise enabled, voice %d\n", v); -#endif - outx = (s16)(m_noise_lev << 1); - } - else - { - /* Perform 4-Point Gaussian interpolation. Take an approximation of a - Gaussian bell-curve, and move it through the sample data at a rate - determined by the pitch. The sample output at any given time is - the sum of the products of each input sample point with the value - of the bell-curve corresponding to that point. */ - vl = vp->mixfrac >> 4; - vr = ((G4[-vl-1] * vp->sampbuf[vp->sampptr]) >> 11 ) & ~1; - vr += ((G3[-vl] * vp->sampbuf[(vp->sampptr + 1) & 3]) >> 11) & ~1; - vr += ((G2[vl] * vp->sampbuf[(vp->sampptr + 2) & 3]) >> 11 ) & ~1; - - /* This is to do the wrapping properly. Based on my tests with the - SNES, it appears clipping is done only if it is the fourth addition - that would cause a wrap. If it has already wrapped before the - fourth addition, it is not clipped. */ - vr = (s16)vr; - vr += ((G1[vl] * vp->sampbuf[(vp->sampptr + 3) & 3]) >> 11) & ~1; - - if (vr > 32767) - vr = 32767; - else if (vr < -32768) - vr = -32768; - - outx = (s16)vr; - -#ifdef DBG_INTRP - logerror("V%d: mixfrac=%d: [%d]*%d + [%d]*%d + [%d]*%d + [%d]*%d = %d\n", v, vl, - G1[vl], - vp->sampbuf[(vp->sampptr + 3) & 3], - G2[vl], - vp->sampbuf[(vp->sampptr + 2) & 3], - G3[-vl], - vp->sampbuf[(vp->sampptr + 1) & 3], - G4[-vl-1], - vp->sampbuf[vp->sampptr], - outx); -#endif - } - - /* Advance the sample position for next update. */ - vp->mixfrac += vp->pitch; - - outx = ((outx * envx) >> 11) & ~1; - m_dsp_regs[V + 9] = outx >> 8; - - vl = (((int)(s8)m_dsp_regs[V ]) * outx) >> 7; - vr = (((int)(s8)m_dsp_regs[V + 1]) * outx) >> 7; - outl += vl; - outr += vr; - - if (m_dsp_regs[0x4d] & m) - { -#ifndef NO_ECHO - echol += vl; - echor += vr; -#endif - } - } - - outl = (outl * (s8)m_dsp_regs[0x0c]) >> 7; - outr = (outr * (s8)m_dsp_regs[0x1c]) >> 7; - -#ifndef NO_ECHO - /* Perform echo. First, read mem at current location, and put those samples - into the FIR filter queue. */ -#ifdef DBG_ECHO - logerror("Echo delay=%dms, feedback=%d%%\n", m_dsp_regs[0x7d] * 16, - ((s8)m_dsp_regs[0x0d] * 100) / 0x7f); -#endif - - int echo_base = ((m_dsp_regs[0x6d] << 8) + m_echo_ptr) & 0xffff; - m_fir_lbuf[m_fir_ptr] = (s16)LEtoME16(*(u16 *)&m_ram[echo_base]); - m_fir_rbuf[m_fir_ptr] = (s16)LEtoME16(*(u16 *)&m_ram[echo_base + sizeof(s16)]); - - /* Now, evaluate the FIR filter, and add the results into the final output. */ - vl = m_fir_lbuf[m_fir_ptr] * (s8)m_dsp_regs[0x7f]; - vr = m_fir_rbuf[m_fir_ptr] * (s8)m_dsp_regs[0x7f]; - m_fir_ptr = (m_fir_ptr + 1) & 7; - vl += m_fir_lbuf[m_fir_ptr] * (s8)m_dsp_regs[0x6f]; - vr += m_fir_rbuf[m_fir_ptr] * (s8)m_dsp_regs[0x6f]; - m_fir_ptr = (m_fir_ptr + 1) & 7; - vl += m_fir_lbuf[m_fir_ptr] * (s8)m_dsp_regs[0x5f]; - vr += m_fir_rbuf[m_fir_ptr] * (s8)m_dsp_regs[0x5f]; - m_fir_ptr = (m_fir_ptr + 1) & 7; - vl += m_fir_lbuf[m_fir_ptr] * (s8)m_dsp_regs[0x4f]; - vr += m_fir_rbuf[m_fir_ptr] * (s8)m_dsp_regs[0x4f]; - m_fir_ptr = (m_fir_ptr + 1) & 7; - vl += m_fir_lbuf[m_fir_ptr] * (s8)m_dsp_regs[0x3f]; - vr += m_fir_rbuf[m_fir_ptr] * (s8)m_dsp_regs[0x3f]; - m_fir_ptr = (m_fir_ptr + 1) & 7; - vl += m_fir_lbuf[m_fir_ptr] * (s8)m_dsp_regs[0x2f]; - vr += m_fir_rbuf[m_fir_ptr] * (s8)m_dsp_regs[0x2f]; - m_fir_ptr = (m_fir_ptr + 1) & 7; - vl += m_fir_lbuf[m_fir_ptr] * (s8)m_dsp_regs[0x1f]; - vr += m_fir_rbuf[m_fir_ptr] * (s8)m_dsp_regs[0x1f]; - m_fir_ptr = (m_fir_ptr + 1) & 7; - vl += m_fir_lbuf[m_fir_ptr] * (s8)m_dsp_regs[0x0f]; - vr += m_fir_rbuf[m_fir_ptr] * (s8)m_dsp_regs[0x0f]; - -#ifdef DBG_ECHO - logerror("FIR Coefficients: %02X %02X %02X %02X %02X %02X %02X %02X\n", - m_dsp_regs[0x0f], - m_dsp_regs[0x1f], - m_dsp_regs[0x2f], - m_dsp_regs[0x3f], - m_dsp_regs[0x4f], - m_dsp_regs[0x5f], - m_dsp_regs[0x6f], - m_dsp_regs[0x7f]); -#endif - - /* FIR_ptr is left in the position of the oldest sample, the one that will be replaced next update. */ - outl += vl * (s8)m_dsp_regs[0x2c] >> 14; - outr += vr * (s8)m_dsp_regs[0x3c] >> 14; - - if (!(m_dsp_regs[0x6c] & 0x20)) - { - /* Add the echo feedback back into the original result, and save that into memory for use later. */ - echol += vl * (s8)m_dsp_regs[0x0d] >> 14; - - if (echol > 32767) - echol = 32767; - else if (echol < -32768) - echol = -32768; - - echor += vr * (s8)m_dsp_regs[0x0D ] >> 14; - - if (echor > 32767) - echor = 32767; - else if (echor < -32768) - echor = -32768; - -#ifdef DBG_ECHO - logerror("Echo: Writing %04X,%04X at location %04X\n", (u16)echol, (u16)echor, echo_base); -#endif - - *(u16 *)&m_ram[echo_base] = MEtoLE16((u16)echol); - *(u16 *)&m_ram[echo_base + sizeof(s16)] = MEtoLE16((u16)echor); - } - - m_echo_ptr += 2 * sizeof(s16); - - if (m_echo_ptr >= ((m_dsp_regs[0x7d] & 0x0f) << 11)) - { - m_echo_ptr = 0; - } -#endif /* !defined( NO_ECHO ) */ - - if (sound_ptr != nullptr) - { - if (m_dsp_regs[0x6c] & 0x40) - { - /* MUTE */ -#ifdef MAME_DEBUG - logerror("MUTED!\n"); -#endif - - *sound_ptr = 0; - sound_ptr++; - *sound_ptr = 0; - sound_ptr++; - } - else - { - if (outl > 32767) - *sound_ptr = 32767; - else if (outl < -32768) - *sound_ptr = -32768; - else - *sound_ptr = outl; - - sound_ptr++; - - if (outr > 32767) - *sound_ptr = 32767; - else if (outr < -32768) - *sound_ptr = -32768; - else - *sound_ptr = outr; - - sound_ptr++; - } - } -} - - -/*------------------------------------------------- - advance_envelope - - Run envelope step & return ENVX. v is the voice - to process envelope for. --------------------------------------------------*/ - -int snes_sound_device::advance_envelope( int v ) -{ - int t; - - int envx = m_voice_state[v].envx; - - if (m_voice_state[v].envstate == env_state_t32::RELEASE) - { - /* Docs: "When in the state of "key off". the "click" sound is prevented - by the addition of the fixed value 1/256" WTF??? Alright, I'm going - to choose to interpret that this way: When a note is keyed off, start - the RELEASE state, which subtracts 1/256th each sample period (32kHz). - Note there's no need for a count because it always happens every - update. */ - envx -= 0x8; /* 0x8 / 0x800 = 1/256th */ - if (envx <= 0) - { - envx = 0; - m_keys &= ~(1 << v); - return -1; - } - - m_voice_state[v].envx = envx; - m_dsp_regs[(v << 4) + 8] = envx >> 8; - -#ifdef DBG_ENV - logerror("ENV voice %d: envx=%03X, state=RELEASE\n", v, envx); -#endif - - return envx; - } - - int cnt = m_voice_state[v].envcnt; - int adsr1 = m_dsp_regs[(v << 4) + 5]; - - if (adsr1 & 0x80) - { - switch (m_voice_state[v].envstate) - { - case env_state_t32::ATTACK: - /* Docs are very confusing. "AR is multiplied by the fixed value - 1/64..." I believe it means to add 1/64th to ENVX once every - time ATTACK is updated, and that's what I'm going to implement. */ - t = adsr1 & 0x0f; - - if (t == 0x0f) - { -#ifdef DBG_ENV - logerror("ENV voice %d: instant attack\n", v); -#endif - - envx += 0x400; - } - else - { - cnt -= ENVCNT[(t << 1) + 1]; - - if (cnt > 0) - break; - - envx += 0x20; /* 0x020 / 0x800 = 1/64 */ - cnt = CNT_INIT; - } - - if (envx > 0x7ff) - { - envx = 0x7ff; - m_voice_state[v].envstate = env_state_t32::DECAY; - } - -#ifdef DBG_ENV - logerror("ENV voice %d: envx=%03X, state=ATTACK\n", v, envx); -#endif - - m_voice_state[v].envx = envx; - break; - - case env_state_t32::DECAY: - /* Docs: "DR... [is multiplied] by the fixed value 1-1/256." - Well, at least that makes some sense. Multiplying ENVX by - 255/256 every time DECAY is updated. */ - cnt -= ENVCNT[((adsr1 >> 3) & 0x0e) + 0x10]; - - if (cnt <= 0) - { - cnt = CNT_INIT; - envx -= ((envx - 1) >> 8) + 1; - m_voice_state[v].envx = envx; - } - - if (envx <= 0x100 * (SL(v) + 1)) - m_voice_state[v].envstate = env_state_t32::SUSTAIN; - -#ifdef DBG_ENV - logerror("ENV voice %d: envx=%03X, state=DECAY\n", v, envx); -#endif - - break; - - case env_state_t32::SUSTAIN: - /* Docs: "SR [is multiplied] by the fixed value 1-1/256." - Multiplying ENVX by 255/256 every time SUSTAIN is updated. */ -#ifdef DBG_ENV - if (ENVCNT[SR(v)] == 0) - logerror("ENV voice %d: envx=%03X, state=SUSTAIN, zero rate\n", v, envx); -#endif - - cnt -= ENVCNT[SR(v)]; - if (cnt > 0) - break; - - cnt = CNT_INIT; - envx -= ((envx - 1) >> 8) + 1; - -#ifdef DBG_ENV - logerror("ENV voice %d: envx=%03X, state=SUSTAIN\n", v, envx); -#endif - - m_voice_state[v].envx = envx; - - /* Note: no way out of this state except by explicit KEY OFF (or switch to GAIN). */ - break; - - case env_state_t32::RELEASE: /* Handled earlier to prevent GAIN mode from stopping KEY OFF events */ - break; - } - } - else - { - /* GAIN mode is set - Note: if the game switches between ADSR and GAIN modes partway - through, should the count be reset, or should it continue from - where it was? Does the DSP actually watch for that bit to - change, or does it just go along with whatever it sees when it - performs the update? I'm going to assume the latter and not - update the count, unless I see a game that obviously wants the - other behavior. The effect would be pretty subtle, in any case. - */ - t = m_dsp_regs[(v << 4) + 7]; - - if (t < 0x80) - { - envx = t << 4; - m_voice_state[v].envx = envx; - -#ifdef DBG_ENV - logerror("ENV voice %d: envx=%03X, state=DIRECT\n", v, envx); -#endif - } - else - { - switch (t >> 5) - { - case 4: - /* Docs: "Decrease (linear): Subtraction of the fixed value 1/64." */ - cnt -= ENVCNT[t & 0x1f]; - - if (cnt > 0) - break; - - cnt = CNT_INIT; - envx -= 0x020; /* 0x020 / 0x800 = 1/64th */ - - if (envx < 0) - envx = 0; - -#ifdef DBG_ENV - logerror("ENV voice %d: envx=%03X, state=DECREASE\n", v, envx); -#endif - - m_voice_state[v].envx = envx; - break; - - case 5: - /* Docs: "Drecrease (exponential): Multiplication by the fixed value 1-1/256." */ - cnt -= ENVCNT[t & 0x1f]; - - if (cnt > 0) - break; - - cnt = CNT_INIT; - envx -= ((envx - 1) >> 8) + 1; - -#ifdef DBG_ENV - logerror("ENV voice %d: envx=%03X, state=EXP\n", v, envx); -#endif - - m_voice_state[v].envx = envx; - break; - - case 6: - /* Docs: "Increase (linear): Addition of the fixed value 1/64." */ - cnt -= ENVCNT[t & 0x1f]; - - if (cnt > 0) - break; - - cnt = CNT_INIT; - envx += 0x020; /* 0x020 / 0x800 = 1/64th */ - if (envx > 0x7ff) - envx = 0x7ff; - -#ifdef DBG_ENV - logerror("ENV voice %d: envx=%03X, state=INCREASE\n", v, envx); -#endif - - m_voice_state[v].envx = envx; - break; - - case 7: - /* Docs: "Increase (bent line): Addition of the constant - 1/64 up to .75 of the constaint 1/256 from .75 to 1." */ - cnt -= ENVCNT[t & 0x1f]; - - if (cnt > 0) - break; - - cnt = CNT_INIT; - - if (envx < 0x600) /* 0x600 / 0x800 = .75 */ - envx += 0x020; /* 0x020 / 0x800 = 1/64 */ - else - envx += 0x008; /* 0x008 / 0x800 = 1/256 */ - - if (envx > 0x7ff) - envx=0x7ff; - -#ifdef DBG_ENV - logerror("ENV voice %d: envx=%03X, state=INCREASE\n", v, envx); -#endif - - m_voice_state[v].envx = envx; - break; - } - } - } - - m_voice_state[v].envcnt = cnt; - m_dsp_regs[(v << 4) + 8] = envx >> 4; - - return envx; -} - -/*------------------------------------------------- - spc700_set_volume - sets SPC700 volume level - for both speakers, used for fade in/out effects --------------------------------------------------*/ - -void snes_sound_device::set_volume(int volume) -{ - m_channel->set_output_gain(0, volume / 100.0); - m_channel->set_output_gain(1, volume / 100.0); -} - - -/*************************** - I/O for DSP - ***************************/ - -u8 snes_sound_device::dsp_io_r(offs_t offset) -{ - m_channel->update(); - -#ifdef NO_ENVX - if (8 == (m_ram[0xf2] & 0x0f)) - m_dsp_regs[m_ram[0xf2]] = 0; -#endif - - /* All reads simply return the contents of the addressed register. */ - return m_dsp_regs[offset & 0x7f]; -} - -void snes_sound_device::dsp_io_w(offs_t offset, u8 data) -{ - m_channel->update(); - - if (offset == 0x7c) - { - /* Writes to register 0x7c (ENDX) clear ALL bits no matter which value is written */ - m_dsp_regs[offset] = 0; - } - else - { - /* All other writes store the value in the addressed register as expected. */ - m_dsp_regs[offset] = data; - } -} - -/*************************** - I/O for SPC700 - ***************************/ - -u8 snes_sound_device::spc_io_r(offs_t offset) -{ - switch (offset) /* Offset is from 0x00f0 */ - { - case 0x0: //FIXME: Super Bomberman PBW reads from there, is it really write-only? - return 0; - case 0x1: - return 0; //Super Kick Boxing reads port 1 and wants it to be zero. - case 0x2: /* Register address */ - return m_ram[0xf2]; - case 0x3: /* Register data */ - return dsp_io_r(m_ram[0xf2]); - case 0x4: /* Port 0 */ - case 0x5: /* Port 1 */ - case 0x6: /* Port 2 */ - case 0x7: /* Port 3 */ - // osd_printf_debug("%s SPC: rd %02x @ %d\n", machine().describe_context(), m_port_in[offset - 4], offset - 4); - return m_port_in[offset - 4]; - case 0x8: //normal RAM, can be read even if the ram disabled flag ($f0 bit 1) is active - case 0x9: - return m_ram[0xf0 + offset]; - case 0xa: /* Timer 0 */ - case 0xb: /* Timer 1 */ - case 0xc: /* Timer 2 */ - break; - case 0xd: /* Counter 0 */ - case 0xe: /* Counter 1 */ - case 0xf: /* Counter 2 */ - { - u8 value = m_ram[0xf0 + offset] & 0x0f; - m_ram[0xf0 + offset] = 0; - return value; - } - } - - return 0; -} - -void snes_sound_device::spc_io_w(offs_t offset, u8 data) -{ - switch (offset) /* Offset is from 0x00f0 */ - { - case 0x0: - logerror("Warning: write to SOUND TEST register with data %02x!\n", data); - break; - case 0x1: /* Control */ - for (int i = 0; i < 3; i++) - { - if (BIT(data, i) && m_timer_enabled[i] == false) - { - m_subcounter[i] = 0; - m_counter[i] = 0; - m_ram[0xfd + i] = 0; - } - - m_timer_enabled[i] = BIT(data, i); - //m_timer[i]->enable(m_timer_enabled[i]); - } - - if (BIT(data, 4)) - { - m_port_in[0] = 0; - m_port_in[1] = 0; - } - - if (BIT(data, 5)) - { - m_port_in[2] = 0; - m_port_in[3] = 0; - } - - /* bit 7 = IPL ROM enable */ - break; - case 0x2: /* Register address */ - break; - case 0x3: /* Register data - 0x80-0xff is a read-only mirror of 0x00-0x7f */ - if (!(m_ram[0xf2] & 0x80)) - dsp_io_w(m_ram[0xf2] & 0x7f, data); - break; - case 0x4: /* Port 0 */ - case 0x5: /* Port 1 */ - case 0x6: /* Port 2 */ - case 0x7: /* Port 3 */ - // osd_printf_debug("%s SPC: %02x to APU @ %d\n", machine().describe_context(), data, offset & 3); - m_port_out[offset - 4] = data; - // Unneeded, we already run at perfect_interleave - // machine().scheduler().boost_interleave(attotime::zero, attotime::from_usec(20)); - break; - case 0xa: /* Timer 0 */ - case 0xb: /* Timer 1 */ - case 0xc: /* Timer 2 */ - // if 0 then TnDiv is divided by 256, otherwise it's divided by 1 to 255 - if (data == 0) - m_TnDIV[offset - 0xa] = 256; - else - m_TnDIV[offset - 0xa] = data; - break; - case 0xd: /* Counter 0 */ - case 0xe: /* Counter 1 */ - case 0xf: /* Counter 2 */ - return; - } - - m_ram[0xf0 + offset] = data; -} - -u8 snes_sound_device::spc_ram_r(offs_t offset) -{ - /* IPL ROM enabled */ - if (offset >= 0xffc0 && m_ram[0xf1] & 0x80) - return m_ipl_region[offset & 0x3f]; - - return m_ram[offset]; -} - -void snes_sound_device::spc_ram_w(offs_t offset, u8 data) -{ - m_ram[offset] = data; -} - - -u8 snes_sound_device::spc_port_out(offs_t offset) -{ - assert(offset < 4); - - return m_port_out[offset]; -} - -void snes_sound_device::spc_port_in(offs_t offset, u8 data) -{ - assert(offset < 4); - - m_port_in[offset] = data; -} - - -/***************************************************************************** - DEVICE INTERFACE -*****************************************************************************/ - -void snes_sound_device::state_register() -{ - save_item(NAME(m_dsp_regs)); - save_item(NAME(m_ipl_region)); - - save_item(NAME(m_keyed_on)); - save_item(NAME(m_keys)); - - save_item(NAME(m_noise_cnt)); - save_item(NAME(m_noise_lev)); - -#ifndef NO_ECHO - save_item(NAME(m_fir_lbuf)); - save_item(NAME(m_fir_rbuf)); - save_item(NAME(m_fir_ptr)); - save_item(NAME(m_echo_ptr)); -#endif - - save_item(NAME(m_timer_enabled)); - save_item(NAME(m_subcounter)); - save_item(NAME(m_counter)); - save_item(NAME(m_port_in)); - save_item(NAME(m_port_out)); - - save_item(NAME(m_TnDIV)); - - for (int v = 0; v < 8; v++) - { - save_item(NAME(m_voice_state[v].mem_ptr), v); - save_item(NAME(m_voice_state[v].end), v); - save_item(NAME(m_voice_state[v].envcnt), v); - save_item(NAME(m_voice_state[v].envstate), v); - save_item(NAME(m_voice_state[v].envx), v); - save_item(NAME(m_voice_state[v].filter), v); - save_item(NAME(m_voice_state[v].half), v); - save_item(NAME(m_voice_state[v].header_cnt), v); - save_item(NAME(m_voice_state[v].mixfrac), v); - save_item(NAME(m_voice_state[v].on_cnt), v); - save_item(NAME(m_voice_state[v].pitch), v); - save_item(NAME(m_voice_state[v].range), v); - save_item(NAME(m_voice_state[v].samp_id), v); - save_item(NAME(m_voice_state[v].sampptr), v); - save_item(NAME(m_voice_state[v].smp1), v); - save_item(NAME(m_voice_state[v].smp2), v); - save_item(NAME(m_voice_state[v].sampbuf), v); - } -} - -//------------------------------------------------- -// sound_stream_update - handle a stream update -//------------------------------------------------- - -void snes_sound_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) -{ - s16 mix[2]; - - for (int i = 0; i < samples; i++) - { - mix[0] = mix[1] = 0; - dsp_update(mix); - - /* Update the buffers */ - outputs[0][i] = (stream_sample_t)mix[0]; - outputs[1][i] = (stream_sample_t)mix[1]; - } -} diff --git a/src/mame/audio/snes_snd.h b/src/mame/audio/snes_snd.h deleted file mode 100644 index 81dffe6024d..00000000000 --- a/src/mame/audio/snes_snd.h +++ /dev/null @@ -1,132 +0,0 @@ -// license:LGPL-2.1+ -// copyright-holders:R. Belmont, Brad Martin -/***************************************************************************** - * - * audio/snes_snd.h - * - ****************************************************************************/ - -#ifndef MAME_AUDIO_SNES_SND_H -#define MAME_AUDIO_SNES_SND_H - - -/*************************************************************************** - TYPE DEFINITIONS - ***************************************************************************/ - -class snes_sound_device : public device_t, public device_sound_interface -{ -public: - snes_sound_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); - - void set_volume(int volume); - - u8 spc_io_r(offs_t offset); - u8 spc_ram_r(offs_t offset); - u8 spc_port_out(offs_t offset); - void spc_io_w(offs_t offset, u8 data); - void spc_ram_w(offs_t offset, u8 data); - void spc_port_in(offs_t offset, u8 data); - -// u8 *spc_get_ram() { return m_ram; } - -protected: - // device-level overrides - virtual void device_start() override; - virtual void device_reset() override; - virtual void device_clock_changed() override; - - // sound stream update overrides - virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) override; - virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override; - -private: - enum class env_state_t32 : u8 - { - ATTACK, - DECAY, - SUSTAIN, - RELEASE - }; - - static constexpr unsigned SNES_SPCRAM_SIZE = 0x10000; - - struct voice_state_type /* Voice state type */ - { - u16 mem_ptr; /* Sample data memory pointer */ - int end; /* End or loop after block */ - int envcnt; /* Counts to envelope update */ - env_state_t32 envstate; /* Current envelope state */ - int envx; /* Last env height (0-0x7FFF) */ - int filter; /* Last header's filter */ - int half; /* Active nybble of BRR */ - int header_cnt; /* Bytes before new header (0-8)*/ - int mixfrac; /* Fractional part of smpl pstn */ - int on_cnt; /* Is it time to turn on yet? */ - int pitch; /* Sample pitch (4096->32000Hz) */ - int range; /* Last header's range */ - u32 samp_id; /* Sample ID# */ - int sampptr; /* Where in sampbuf we are */ - s32 smp1; /* Last sample (for BRR filter) */ - s32 smp2; /* Second-to-last sample decoded*/ - s16 sampbuf[4]; /* Buffer for Gaussian interp */ - }; - - struct src_dir_type /* Source directory entry */ - { - u16 vptr; /* Ptr to start of sample data */ - u16 lptr; /* Loop pointer in sample data */ - }; - - u8 dsp_io_r(offs_t offset); - void dsp_io_w(offs_t offset, u8 data); -// TIMER_CALLBACK_MEMBER(spc_timer); - void dsp_reset(); - void dsp_update(s16 *sound_ptr); - int advance_envelope(int v); - void state_register(); - - // internal state - std::unique_ptr m_ram; - sound_stream *m_channel; - u8 m_dsp_regs[256]; /* DSP registers */ - u8 m_ipl_region[64]; /* SPC top 64 bytes */ - - int m_keyed_on; - int m_keys; /* 8-bits for 8 voices */ - voice_state_type m_voice_state[8]; - - /* Noise stuff */ - int m_noise_cnt; - int m_noise_lev; - - /* These are for the FIR echo filter */ -#ifndef NO_ECHO - s16 m_fir_lbuf[8]; - s16 m_fir_rbuf[8]; - int m_fir_ptr; - int m_echo_ptr; -#endif - - enum - { - TIMER_TICK_ID = 1 - }; - /* timers */ - emu_timer *m_tick_timer; - bool m_timer_enabled[3]; - u16 m_counter[3]; - u8 m_subcounter[3]; - inline void update_timer_tick(u8 which); - - /* IO ports */ - u8 m_port_in[4]; /* SPC input ports */ - u8 m_port_out[4]; /* SPC output ports */ - - u16 m_TnDIV[3]; /**< Timer N Divider */ -}; - -DECLARE_DEVICE_TYPE(SNES_SOUND, snes_sound_device) - - -#endif // MAME_AUDIO_SNES_SND_H diff --git a/src/mame/drivers/nss.cpp b/src/mame/drivers/nss.cpp index 342521c4536..e18a3675cea 100644 --- a/src/mame/drivers/nss.cpp +++ b/src/mame/drivers/nss.cpp @@ -353,12 +353,10 @@ private: virtual void machine_start() override; virtual void machine_reset() override; DECLARE_WRITE_LINE_MEMBER(nss_vblank_irq); - DECLARE_READ8_MEMBER(spc_ram_100_r); - DECLARE_WRITE8_MEMBER(spc_ram_100_w); void bios_io_map(address_map &map); void bios_map(address_map &map); void snes_map(address_map &map); - void spc_mem(address_map &map); + void spc_map(address_map &map); }; @@ -374,25 +372,13 @@ uint32_t nss_state::screen_update( screen_device &screen, bitmap_rgb32 &bitmap, void nss_state::snes_map(address_map &map) { map(0x000000, 0x7dffff).rw(FUNC(nss_state::snes_r_bank1), FUNC(nss_state::snes_w_bank1)); - map(0x7e0000, 0x7fffff).ram(); /* 8KB Low RAM, 24KB High RAM, 96KB Expanded RAM */ + map(0x7e0000, 0x7fffff).ram().share("wram"); /* 8KB Low RAM, 24KB High RAM, 96KB Expanded RAM */ map(0x800000, 0xffffff).rw(FUNC(nss_state::snes_r_bank2), FUNC(nss_state::snes_w_bank2)); /* Mirror and ROM */ } -READ8_MEMBER(nss_state::spc_ram_100_r) +void nss_state::spc_map(address_map &map) { - return m_spc700->spc_ram_r(offset + 0x100); -} - -WRITE8_MEMBER(nss_state::spc_ram_100_w) -{ - m_spc700->spc_ram_w(offset + 0x100, data); -} - -void nss_state::spc_mem(address_map &map) -{ - map(0x0000, 0x00ef).rw(m_spc700, FUNC(snes_sound_device::spc_ram_r), FUNC(snes_sound_device::spc_ram_w)); /* lower 32k ram */ - map(0x00f0, 0x00ff).rw(m_spc700, FUNC(snes_sound_device::spc_io_r), FUNC(snes_sound_device::spc_io_w)); /* spc io */ - map(0x0100, 0xffff).rw(FUNC(nss_state::spc_ram_100_r), FUNC(nss_state::spc_ram_100_w)); + map(0x0000, 0xffff).ram().share("aram"); } /* NSS specific */ @@ -577,7 +563,7 @@ WRITE8_MEMBER(nss_state::port_01_w) ---- ---x Maybe SNES CPU/PPU reset? (0=Reset, 1=Run) */ m_input_disabled = BIT(data, 7) ^ 1; - m_spc700->set_volume((data & 0x20) ? 0.0 : 100.0); + m_s_dsp->set_volume((data & 0x20) ? 0.0 : 100.0); m_cart_sel = (data & 0xc) >> 2; @@ -587,7 +573,7 @@ WRITE8_MEMBER(nss_state::port_01_w) m_soundcpu->set_input_line(INPUT_LINE_RESET, (data & 1) ? CLEAR_LINE : ASSERT_LINE); /* also reset the device */ if (!(data & 1)) - m_spc700->reset(); + m_s_dsp->reset(); } WRITE8_MEMBER(nss_state::port_02_w) @@ -839,8 +825,10 @@ void nss_state::nss(machine_config &config) m_maincpu->set_addrmap(AS_PROGRAM, &nss_state::snes_map); // runs at 24.576 MHz / 12 = 2.048 MHz - SPC700(config, m_soundcpu, XTAL(24'576'000) / 12); - m_soundcpu->set_addrmap(AS_PROGRAM, &nss_state::spc_mem); + S_SMP(config, m_soundcpu, XTAL(24'576'000) / 12); + m_soundcpu->set_addrmap(AS_DATA, &nss_state::spc_map); + m_soundcpu->dsp_io_read_callback().set(m_s_dsp, FUNC(s_dsp_device::dsp_io_r)); + m_soundcpu->dsp_io_write_callback().set(m_s_dsp, FUNC(s_dsp_device::dsp_io_w)); config.set_perfect_quantum(m_maincpu); @@ -857,9 +845,11 @@ void nss_state::nss(machine_config &config) /* sound hardware */ SPEAKER(config, "lspeaker").front_left(); SPEAKER(config, "rspeaker").front_right(); - SNES_SOUND(config, m_spc700, XTAL(24'576'000) / 12); - m_spc700->add_route(0, "lspeaker", 1.00); - m_spc700->add_route(1, "rspeaker", 1.00); + + S_DSP(config, m_s_dsp, XTAL(24'576'000) / 12); + m_s_dsp->set_addrmap(0, &nss_state::spc_map); + m_s_dsp->add_route(0, "lspeaker", 1.00); + m_s_dsp->add_route(1, "rspeaker", 1.00); /* video hardware */ /* TODO: the screen should actually superimpose, but for the time being let's just separate outputs */ @@ -892,8 +882,6 @@ void nss_state::nss(machine_config &config) ***************************************************************************/ #define NSS_BIOS \ - ROM_REGION(0x100, "sound_ipl", 0) /* IPL ROM */ \ - ROM_LOAD("spc700.rom", 0, 0x40, CRC(44bb3a40) SHA1(97e352553e94242ae823547cd853eecda55c20f0) ) \ ROM_REGION(0x8000, "bios", 0) /* Bios CPU */ \ ROM_SYSTEM_BIOS( 0, "single", "Nintendo Super System (Single Cart BIOS)" ) \ ROMX_LOAD("nss-ic14.02.ic14", 0x00000, 0x8000, CRC(e06cb58f) SHA1(62f507e91a2797919a78d627af53f029c7d81477), ROM_BIOS(0) ) /* bios */ \ diff --git a/src/mame/drivers/sfcbox.cpp b/src/mame/drivers/sfcbox.cpp index ec46a34fd43..e6a4b7649b5 100644 --- a/src/mame/drivers/sfcbox.cpp +++ b/src/mame/drivers/sfcbox.cpp @@ -155,12 +155,10 @@ private: DECLARE_WRITE8_MEMBER( snes_map_1_w ); virtual void machine_start() override; virtual void machine_reset() override; - DECLARE_READ8_MEMBER(spc_ram_100_r); - DECLARE_WRITE8_MEMBER(spc_ram_100_w); void sfcbox_io(address_map &map); void sfcbox_map(address_map &map); void snes_map(address_map &map); - void spc_mem(address_map &map); + void spc_map(address_map &map); }; uint32_t sfcbox_state::screen_update( screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect ) @@ -172,25 +170,13 @@ uint32_t sfcbox_state::screen_update( screen_device &screen, bitmap_rgb32 &bitma void sfcbox_state::snes_map(address_map &map) { map(0x000000, 0x7dffff).rw(FUNC(sfcbox_state::snes_r_bank1), FUNC(sfcbox_state::snes_w_bank1)); - map(0x7e0000, 0x7fffff).ram(); /* 8KB Low RAM, 24KB High RAM, 96KB Expanded RAM */ + map(0x7e0000, 0x7fffff).ram().share("wram"); /* 8KB Low RAM, 24KB High RAM, 96KB Expanded RAM */ map(0x800000, 0xffffff).rw(FUNC(sfcbox_state::snes_r_bank2), FUNC(sfcbox_state::snes_w_bank2)); /* Mirror and ROM */ } -READ8_MEMBER(sfcbox_state::spc_ram_100_r) +void sfcbox_state::spc_map(address_map &map) { - return m_spc700->spc_ram_r(offset + 0x100); -} - -WRITE8_MEMBER(sfcbox_state::spc_ram_100_w) -{ - m_spc700->spc_ram_w(offset + 0x100, data); -} - -void sfcbox_state::spc_mem(address_map &map) -{ - map(0x0000, 0x00ef).rw(m_spc700, FUNC(snes_sound_device::spc_ram_r), FUNC(snes_sound_device::spc_ram_w)); /* lower 32k ram */ - map(0x00f0, 0x00ff).rw(m_spc700, FUNC(snes_sound_device::spc_io_r), FUNC(snes_sound_device::spc_io_w)); /* spc io */ - map(0x0100, 0xffff).rw(FUNC(sfcbox_state::spc_ram_100_r), FUNC(sfcbox_state::spc_ram_100_w)); + map(0x0000, 0xffff).ram().share("aram"); } void sfcbox_state::sfcbox_map(address_map &map) @@ -463,8 +449,10 @@ void sfcbox_state::sfcbox(machine_config &config) m_maincpu->set_addrmap(AS_PROGRAM, &sfcbox_state::snes_map); // runs at 24.576 MHz / 12 = 2.048 MHz - SPC700(config, m_soundcpu, XTAL(24'576'000) / 12); - m_soundcpu->set_addrmap(AS_PROGRAM, &sfcbox_state::spc_mem); + S_SMP(config, m_soundcpu, XTAL(24'576'000) / 12); + m_soundcpu->set_addrmap(AS_DATA, &sfcbox_state::spc_map); + m_soundcpu->dsp_io_read_callback().set(m_s_dsp, FUNC(s_dsp_device::dsp_io_r)); + m_soundcpu->dsp_io_write_callback().set(m_s_dsp, FUNC(s_dsp_device::dsp_io_w)); config.set_perfect_quantum(m_maincpu); @@ -479,9 +467,11 @@ void sfcbox_state::sfcbox(machine_config &config) /* sound hardware */ SPEAKER(config, "lspeaker").front_left(); SPEAKER(config, "rspeaker").front_right(); - SNES_SOUND(config, m_spc700, XTAL(24'576'000) / 12); - m_spc700->add_route(0, "lspeaker", 1.00); - m_spc700->add_route(1, "rspeaker", 1.00); + + S_DSP(config, m_s_dsp, XTAL(24'576'000) / 12); + m_s_dsp->set_addrmap(0, &sfcbox_state::spc_map); + m_s_dsp->add_route(0, "lspeaker", 1.00); + m_s_dsp->add_route(1, "rspeaker", 1.00); /* video hardware */ /* TODO: the screen should actually superimpose, but for the time being let's just separate outputs */ @@ -516,8 +506,6 @@ void sfcbox_state::sfcbox(machine_config &config) #define SFCBOX_BIOS \ ROM_REGION( 0x1000000, "maincpu", ROMREGION_ERASE00 ) \ - ROM_REGION( 0x100, "sound_ipl", 0 ) \ - ROM_LOAD( "spc700.rom", 0x00, 0x40, CRC(44bb3a40) SHA1(97e352553e94242ae823547cd853eecda55c20f0) ) \ ROM_REGION( 0x10000, "krom", 0 ) \ ROM_LOAD( "krom1.ic1", 0x00000, 0x10000, CRC(c9010002) SHA1(f4c74086a83b728b1c1af3a021a60efa80eff5a4) ) \ ROM_REGION( 0x100000, "user3", 0 ) \ diff --git a/src/mame/drivers/snes.cpp b/src/mame/drivers/snes.cpp index 9c54f5665c3..851a73bc3e4 100644 --- a/src/mame/drivers/snes.cpp +++ b/src/mame/drivers/snes.cpp @@ -28,9 +28,7 @@ #include "emu.h" #include "includes/snes.h" -#include "audio/snes_snd.h" -#include "cpu/spc700/spc700.h" #include "machine/snescx4.h" #include "bus/snes/snes_slot.h" @@ -92,9 +90,6 @@ private: DECLARE_READ8_MEMBER( pfest94_lo_r ); DECLARE_WRITE8_MEMBER( pfest94_lo_w ); - DECLARE_READ8_MEMBER( spc_ram_100_r ); - DECLARE_WRITE8_MEMBER( spc_ram_100_w ); - // input related SNESCTRL_ONSCREEN_CB(onscreen_cb); SNESCTRL_GUNLATCH_CB(gun_latch_cb); @@ -122,18 +117,6 @@ private: * *************************************/ -// SPC access - -READ8_MEMBER(snes_console_state::spc_ram_100_r ) -{ - return m_spc700->spc_ram_r(offset + 0x100); -} - -WRITE8_MEMBER(snes_console_state::spc_ram_100_w ) -{ - m_spc700->spc_ram_w(offset + 0x100, data); -} - // Memory access for the various types of carts //--------------------------------------------------------------------------------- @@ -165,7 +148,7 @@ READ8_MEMBER( snes_console_state::snes20_hi_r ) if (offset < 0x400000) { if (address < 0x2000) - return space.read_byte(0x7e0000 + address); + return m_wram[address]; else if (address < 0x6000) return snes_r_io(space, address); else if (address < 0x8000) @@ -225,7 +208,7 @@ WRITE8_MEMBER( snes_console_state::snes20_hi_w ) if (offset < 0x400000) { if (address < 0x2000) - space.write_byte(0x7e0000 + address, data); + m_wram[address] = data; else if (address < 0x6000) snes_w_io(space, address, data); } @@ -260,7 +243,7 @@ READ8_MEMBER( snes_console_state::snes20_lo_r ) if (offset < 0x400000) { if (address < 0x2000) - return space.read_byte(0x7e0000 + address); + return m_wram[address]; else if (address < 0x6000) return snes_r_io(space, address); else if (address < 0x8000) @@ -321,7 +304,7 @@ READ8_MEMBER( snes_console_state::snes21_lo_r ) if (offset < 0x400000 && address < 0x8000) { if (address < 0x2000) - return space.read_byte(0x7e0000 + address); + return m_wram[address]; else if (address < 0x6000) return snes_r_io(space, address); else @@ -354,7 +337,7 @@ WRITE8_MEMBER( snes_console_state::snes21_lo_w ) if (offset < 0x400000 && address < 0x8000) { if (address < 0x2000) - space.write_byte(0x7e0000 + address, data); + m_wram[address] = data; else if (address < 0x6000) snes_w_io(space, address, data); else @@ -383,7 +366,7 @@ READ8_MEMBER( snes_console_state::snes21_hi_r ) if (offset < 0x400000 && address < 0x8000) { if (address < 0x2000) - return space.read_byte(0x7e0000 + address); + return m_wram[address]; else if (address < 0x6000) return snes_r_io(space, address); else @@ -416,7 +399,7 @@ WRITE8_MEMBER( snes_console_state::snes21_hi_w ) if (offset < 0x400000 && address < 0x8000) { if (address < 0x2000) - space.write_byte(0x7e0000 + address, data); + m_wram[address] = data; else if (address < 0x6000) snes_w_io(space, address, data); else @@ -449,7 +432,7 @@ READ8_MEMBER( snes_console_state::snessfx_hi_r ) if (offset < 0x400000) { if (address < 0x2000) - return space.read_byte(0x7e0000 + address); + return m_wram[address]; else if (address < 0x6000) { if (address >= 0x3000 && address < 0x3300) @@ -475,7 +458,7 @@ READ8_MEMBER( snes_console_state::snessfx_lo_r ) if (offset < 0x400000) { if (address < 0x2000) - return space.read_byte(0x7e0000 + address); + return m_wram[address]; else if (address < 0x6000) { if (address >= 0x3000 && address < 0x3300) @@ -500,7 +483,7 @@ WRITE8_MEMBER( snes_console_state::snessfx_hi_w ) if (offset < 0x400000) { if (address < 0x2000) - space.write_byte(0x7e0000 + address, data); + m_wram[address] = data; else if (address < 0x6000) { if (address >= 0x3000 && address < 0x3300) @@ -531,7 +514,7 @@ READ8_MEMBER( snes_console_state::snessa1_hi_r ) if (offset < 0x400000) { if (address < 0x2000) - return space.read_byte(0x7e0000 + address); + return m_wram[address]; else if (address < 0x6000) { if (address >= 0x2200 && address < 0x2400) @@ -557,7 +540,7 @@ READ8_MEMBER( snes_console_state::snessa1_lo_r ) if (offset < 0x400000) { if (address < 0x2000) - return space.read_byte(0x7e0000 + address); + return m_wram[address]; else if (address < 0x6000) { if (address >= 0x2200 && address < 0x2400) @@ -584,7 +567,7 @@ WRITE8_MEMBER( snes_console_state::snessa1_hi_w ) if (offset < 0x400000) { if (address < 0x2000) - space.write_byte(0x7e0000 + address, data); + m_wram[address] = data; else if (address < 0x6000) { if (address >= 0x2200 && address < 0x2400) @@ -618,7 +601,7 @@ READ8_MEMBER( snes_console_state::snes7110_hi_r ) if (offset < 0x400000) { if (address < 0x2000) - return space.read_byte(0x7e0000 + address); + return m_wram[address]; else if (address < 0x6000) { uint16_t limit = (m_cartslot->get_type() == SNES_SPC7110_RTC) ? 0x4843 : 0x4840; @@ -647,7 +630,7 @@ READ8_MEMBER( snes_console_state::snes7110_lo_r ) if (offset < 0x400000) { if (address < 0x2000) - return space.read_byte(0x7e0000 + address); + return m_wram[address]; else if (address < 0x6000) { uint16_t limit = (m_cartslot->get_type() == SNES_SPC7110_RTC) ? 0x4843 : 0x4840; @@ -683,7 +666,7 @@ WRITE8_MEMBER( snes_console_state::snes7110_lo_w ) if (offset < 0x400000) { if (address < 0x2000) - space.write_byte(0x7e0000 + address, data); + m_wram[address] = data; else if (address < 0x6000) { uint16_t limit = (m_cartslot->get_type() == SNES_SPC7110_RTC) ? 0x4843 : 0x4840; @@ -716,7 +699,7 @@ READ8_MEMBER( snes_console_state::snessdd1_lo_r ) if (offset < 0x400000) { if (address < 0x2000) - return space.read_byte(0x7e0000 + address); + return m_wram[address]; else if (address < 0x6000) { if (address >= 0x4800 && address < 0x4808) @@ -754,7 +737,7 @@ WRITE8_MEMBER( snes_console_state::snessdd1_hi_w ) if (offset < 0x400000) { if (address < 0x2000) - space.write_byte(0x7e0000 + address, data); + m_wram[address] = data; else if (address < 0x6000) { if (address >= 0x4300 && address < 0x4380) @@ -786,7 +769,7 @@ READ8_MEMBER( snes_console_state::snesbsx_hi_r ) if (offset < 0x400000) { if (address < 0x2000) - return space.read_byte(0x7e0000 + address); + return m_wram[address]; else if (address < 0x6000) { if (address >= 0x2188 && address < 0x21a0) @@ -814,7 +797,7 @@ WRITE8_MEMBER( snes_console_state::snesbsx_hi_w ) if (offset < 0x400000) { if (address < 0x2000) - space.write_byte(0x7e0000 + address, data); + m_wram[address] = data; else if (address < 0x6000) { if (address >= 0x2188 && address < 0x21a0) @@ -847,7 +830,7 @@ READ8_MEMBER( snes_console_state::snesbsx_lo_r ) if (offset < 0x400000) { if (address < 0x2000) - return space.read_byte(0x7e0000 + address); + return m_wram[address]; else if (address < 0x6000) { if (address >= 0x2188 && address < 0x21a0) @@ -886,7 +869,7 @@ READ8_MEMBER( snes_console_state::snessgb_hi_r ) if (offset < 0x400000) { if (address < 0x2000) - return space.read_byte(0x7e0000 + address); + return m_wram[address]; else if (address < 0x6000) return snes_r_io(space, address); else if (address < 0x8000) @@ -911,7 +894,7 @@ WRITE8_MEMBER( snes_console_state::snessgb_hi_w ) if (offset < 0x400000) { if (address < 0x2000) - space.write_byte(0x7e0000 + address, data); + m_wram[address] = data; else if (address < 0x6000) snes_w_io(space, address, data); else if (address < 0x8000) @@ -935,7 +918,7 @@ READ8_MEMBER( snes_console_state::pfest94_hi_r ) if (offset < 0x400000) { if (address < 0x2000) - return space.read_byte(0x7e0000 + address); + return m_wram[address]; else if (address < 0x6000) return snes_r_io(space, address); else if (address < 0x8000) @@ -961,7 +944,7 @@ WRITE8_MEMBER( snes_console_state::pfest94_hi_w ) if (offset < 0x400000) { if (address < 0x2000) - space.write_byte(0x7e0000 + address, data); + m_wram[address] = data; else if (address < 0x6000) snes_w_io(space, address, data); else if (address < 0x8000) @@ -983,7 +966,7 @@ READ8_MEMBER( snes_console_state::pfest94_lo_r ) if (offset < 0x400000) { if (address < 0x2000) - return space.read_byte(0x7e0000 + address); + return m_wram[address]; else if (address < 0x6000) return snes_r_io(space, address); else if (address < 0x8000) @@ -1018,15 +1001,13 @@ WRITE8_MEMBER( snes_console_state::pfest94_lo_w ) void snes_console_state::snes_map(address_map &map) { // map(0x000000, 0x7dffff).rw(FUNC(snes_console_state::snes20_lo_r), FUNC(snes_console_state::snes20_lo_w)); - map(0x7e0000, 0x7fffff).ram(); /* 8KB Low RAM, 24KB High RAM, 96KB Expanded RAM */ + map(0x7e0000, 0x7fffff).ram().share("wram"); /* 8KB Low RAM, 24KB High RAM, 96KB Expanded RAM */ // map(0x800000, 0xffffff).rw(FUNC(snes_console_state::snes20_hi_r), FUNC(snes_console_state::snes20_hi_w)); } void snes_console_state::spc_map(address_map &map) { - map(0x0000, 0x00ef).rw(m_spc700, FUNC(snes_sound_device::spc_ram_r), FUNC(snes_sound_device::spc_ram_w)); /* lower 32k ram */ - map(0x00f0, 0x00ff).rw(m_spc700, FUNC(snes_sound_device::spc_io_r), FUNC(snes_sound_device::spc_io_w)); /* spc io */ - map(0x0100, 0xffff).rw(FUNC(snes_console_state::spc_ram_100_r), FUNC(snes_console_state::spc_ram_100_w)); + map(0x0000, 0xffff).ram().share("aram"); } @@ -1340,8 +1321,10 @@ void snes_console_state::snes(machine_config &config) m_maincpu->set_addrmap(AS_PROGRAM, &snes_console_state::snes_map); // runs at 24.576 MHz / 12 = 2.048 MHz - SPC700(config, m_soundcpu, XTAL(24'576'000) / 12); - m_soundcpu->set_addrmap(AS_PROGRAM, &snes_console_state::spc_map); + S_SMP(config, m_soundcpu, XTAL(24'576'000) / 12); + m_soundcpu->set_addrmap(AS_DATA, &snes_console_state::spc_map); + m_soundcpu->dsp_io_read_callback().set(m_s_dsp, FUNC(s_dsp_device::dsp_io_r)); + m_soundcpu->dsp_io_write_callback().set(m_s_dsp, FUNC(s_dsp_device::dsp_io_w)); //config.set_maximum_quantum(attotime::from_hz(48000)); config.set_perfect_quantum(m_maincpu); @@ -1365,9 +1348,11 @@ void snes_console_state::snes(machine_config &config) /* sound hardware */ SPEAKER(config, "lspeaker").front_left(); SPEAKER(config, "rspeaker").front_right(); - SNES_SOUND(config, m_spc700, XTAL(24'576'000) / 12); - m_spc700->add_route(0, "lspeaker", 1.00); - m_spc700->add_route(1, "rspeaker", 1.00); + + S_DSP(config, m_s_dsp, XTAL(24'576'000) / 12); + m_s_dsp->set_addrmap(0, &snes_console_state::spc_map); + m_s_dsp->add_route(0, "lspeaker", 1.00); + m_s_dsp->add_route(1, "rspeaker", 1.00); SNS_CART_SLOT(config, m_cartslot, MCLK_NTSC, snes_cart, nullptr); m_cartslot->irq_callback().set_inputline(m_maincpu, G65816_LINE_IRQ); @@ -1399,9 +1384,6 @@ void snes_console_state::snespal(machine_config &config) ROM_START( snes ) ROM_REGION( 0x1000000, "maincpu", ROMREGION_ERASE00 ) - - ROM_REGION( 0x100, "sound_ipl", 0 ) /* IPL ROM */ - ROM_LOAD( "spc700.rom", 0, 0x40, CRC(44bb3a40) SHA1(97e352553e94242ae823547cd853eecda55c20f0) ) /* boot rom */ ROM_END #define rom_snespal rom_snes diff --git a/src/mame/drivers/snesb.cpp b/src/mame/drivers/snesb.cpp index 1854e3605fc..8490830a4a9 100644 --- a/src/mame/drivers/snesb.cpp +++ b/src/mame/drivers/snesb.cpp @@ -192,12 +192,10 @@ private: DECLARE_READ8_MEMBER(snesb_dsw1_r); DECLARE_READ8_MEMBER(snesb_dsw2_r); DECLARE_READ8_MEMBER(snesb_coin_r); - DECLARE_READ8_MEMBER(spc_ram_100_r); - DECLARE_WRITE8_MEMBER(spc_ram_100_w); DECLARE_MACHINE_RESET(ffight2b); void mcu_io_map(address_map &map); void snesb_map(address_map &map); - void spc_mem(address_map &map); + void spc_map(address_map &map); }; @@ -332,25 +330,13 @@ READ8_MEMBER(snesb_state::snesb_coin_r) void snesb_state::snesb_map(address_map &map) { map(0x000000, 0x7dffff).rw(FUNC(snesb_state::snes_r_bank1), FUNC(snesb_state::snes_w_bank1)); - map(0x7e0000, 0x7fffff).ram(); /* 8KB Low RAM, 24KB High RAM, 96KB Expanded RAM */ + map(0x7e0000, 0x7fffff).ram().share("wram"); /* 8KB Low RAM, 24KB High RAM, 96KB Expanded RAM */ map(0x800000, 0xffffff).rw(FUNC(snesb_state::snes_r_bank2), FUNC(snesb_state::snes_w_bank2)); /* Mirror and ROM */ } -READ8_MEMBER(snesb_state::spc_ram_100_r) +void snesb_state::spc_map(address_map &map) { - return m_spc700->spc_ram_r(offset + 0x100); -} - -WRITE8_MEMBER(snesb_state::spc_ram_100_w) -{ - m_spc700->spc_ram_w(offset + 0x100, data); -} - -void snesb_state::spc_mem(address_map &map) -{ - map(0x0000, 0x00ef).rw(m_spc700, FUNC(snes_sound_device::spc_ram_r), FUNC(snes_sound_device::spc_ram_w)); /* lower 32k ram */ - map(0x00f0, 0x00ff).rw(m_spc700, FUNC(snes_sound_device::spc_io_r), FUNC(snes_sound_device::spc_io_w)); /* spc io */ - map(0x0100, 0xffff).rw(FUNC(snesb_state::spc_ram_100_r), FUNC(snesb_state::spc_ram_100_w)); + map(0x0000, 0xffff).ram().share("aram"); } static INPUT_PORTS_START( snes_common ) @@ -821,8 +807,10 @@ void snesb_state::kinstb(machine_config &config) /* audio CPU */ // runs at 24.576 MHz / 12 = 2.048 MHz - SPC700(config, m_soundcpu, XTAL(24'576'000) / 12); - m_soundcpu->set_addrmap(AS_PROGRAM, &snesb_state::spc_mem); + S_SMP(config, m_soundcpu, XTAL(24'576'000) / 12); + m_soundcpu->set_addrmap(AS_DATA, &snesb_state::spc_map); + m_soundcpu->dsp_io_read_callback().set(m_s_dsp, FUNC(s_dsp_device::dsp_io_r)); + m_soundcpu->dsp_io_write_callback().set(m_s_dsp, FUNC(s_dsp_device::dsp_io_w)); config.set_perfect_quantum(m_maincpu); @@ -839,9 +827,11 @@ void snesb_state::kinstb(machine_config &config) /* sound hardware */ SPEAKER(config, "lspeaker").front_left(); SPEAKER(config, "rspeaker").front_right(); - SNES_SOUND(config, m_spc700, XTAL(24'576'000) / 12); - m_spc700->add_route(0, "lspeaker", 1.00); - m_spc700->add_route(1, "rspeaker", 1.00); + + S_DSP(config, m_s_dsp, XTAL(24'576'000) / 12); + m_s_dsp->set_addrmap(0, &snesb_state::spc_map); + m_s_dsp->add_route(0, "lspeaker", 1.00); + m_s_dsp->add_route(1, "rspeaker", 1.00); } MACHINE_RESET_MEMBER( snesb_state, ffight2b ) @@ -1371,9 +1361,6 @@ ROM_START( kinstb ) ROM_LOAD( "3.u16", 0x200000, 0x100000, CRC(7a40f7dd) SHA1(cebe632e8d2d68d0619077cc1e931af73c9a723b) ) ROM_LOAD( "4.u17", 0x300000, 0x100000, CRC(3d7564c1) SHA1(392b513991897668d5dd469ac84a34f785895774) ) - ROM_REGION(0x100, "sound_ipl", 0) - ROM_LOAD("spc700.rom", 0, 0x40, CRC(44bb3a40) SHA1(97e352553e94242ae823547cd853eecda55c20f0) ) - ROM_REGION(0x800, "user6", ROMREGION_ERASEFF) ROM_END @@ -1413,9 +1400,6 @@ ROM_START( ffight2b ) ROM_CONTINUE( 0x078000, 0x008000 ) ROM_LOAD( "ff2_1.u8", 0x100000, 0x040000, CRC(ea315ac1) SHA1(a85de091882d35bc77dc99677511828ff7c20350) ) - ROM_REGION(0x100, "sound_ipl", 0) - ROM_LOAD("spc700.rom", 0, 0x40, CRC(44bb3a40) SHA1(97e352553e94242ae823547cd853eecda55c20f0) ) - ROM_REGION(0x800, "user6", ROMREGION_ERASEFF) ROM_END @@ -1425,9 +1409,6 @@ ROM_START( iron ) ROM_LOAD( "5.c10.bin", 0x080000, 0x080000, CRC(0c3a0b5b) SHA1(1e8ab860689137e0e94731f1af2cfc561492b5bd) ) ROM_LOAD( "4.c11.bin", 0x100000, 0x040000, CRC(2aa417c7) SHA1(24b375e5bbd4be5dcd31b63ea98fbbadd53d543e) ) - ROM_REGION(0x100, "sound_ipl", 0) - ROM_LOAD("spc700.rom", 0, 0x40, CRC(44bb3a40) SHA1(97e352553e94242ae823547cd853eecda55c20f0) ) - ROM_REGION(0x800, "user6", ROMREGION_ERASEFF) ROM_END @@ -1438,18 +1419,12 @@ ROM_START( denseib ) ROM_LOAD( "dj.u16", 0x100000, 0x0080000, CRC(7cb71fd7) SHA1(7673e9dcaabe804e2d637e67eabca1683dad4245) ) ROM_LOAD( "dj.u17", 0x180000, 0x0080000, CRC(de29dd89) SHA1(441aefbc7ee64515ee66431ef504e76dc8dc5ca3) ) - ROM_REGION(0x100, "sound_ipl", 0) - ROM_LOAD("spc700.rom", 0, 0x40, CRC(44bb3a40) SHA1(97e352553e94242ae823547cd853eecda55c20f0) ) - ROM_REGION(0x800, "user6", ROMREGION_ERASEFF) ROM_END ROM_START( denseib2 ) ROM_REGION( 0x200000, "user3", ROMREGION_ERASEFF ) - ROM_REGION(0x100, "sound_ipl", 0) - ROM_LOAD("spc700.rom", 0, 0x40, CRC(44bb3a40) SHA1(97e352553e94242ae823547cd853eecda55c20f0) ) - ROM_REGION(0x800, "user6", ROMREGION_ERASEFF) ROM_REGION( 0x200000, "user7", 0 ) @@ -1462,9 +1437,6 @@ ROM_END ROM_START( sblast2b ) ROM_REGION( 0x180000, "user3", ROMREGION_ERASEFF ) - ROM_REGION(0x100, "sound_ipl", 0) - ROM_LOAD("spc700.rom", 0, 0x40, CRC(44bb3a40) SHA1(97e352553e94242ae823547cd853eecda55c20f0) ) - ROM_REGION(0x800, "user6", ROMREGION_ERASEFF) ROM_REGION( 0x180000, "user7", 0 ) @@ -1511,18 +1483,12 @@ ROM_START( legendsb ) ROM_CONTINUE( 0x0f0000, 0x008000 ) ROM_CONTINUE( 0x078000, 0x008000 ) - ROM_REGION(0x100, "sound_ipl", 0) - ROM_LOAD("spc700.rom", 0, 0x40, CRC(44bb3a40) SHA1(97e352553e94242ae823547cd853eecda55c20f0) ) - ROM_REGION(0x800, "user6", ROMREGION_ERASEFF) ROM_END ROM_START( endless ) ROM_REGION( 0x200000, "user3", ROMREGION_ERASEFF ) - ROM_REGION(0x100, "sound_ipl", 0) - ROM_LOAD("spc700.rom", 0, 0x40, CRC(44bb3a40) SHA1(97e352553e94242ae823547cd853eecda55c20f0) ) - ROM_REGION(0x800, "user6", ROMREGION_ERASEFF) ROM_REGION( 0x200000, "user7", 0 ) @@ -1535,9 +1501,6 @@ ROM_END ROM_START( rushbets ) ROM_REGION( 0x200000, "user3", ROMREGION_ERASEFF ) - ROM_REGION(0x100, "sound_ipl", 0) - ROM_LOAD("spc700.rom", 0, 0x40, CRC(44bb3a40) SHA1(97e352553e94242ae823547cd853eecda55c20f0) ) - ROM_REGION(0x800, "user6", ROMREGION_ERASEFF) ROM_REGION( 0x200000, "user7", 0 ) @@ -1550,9 +1513,6 @@ ROM_END ROM_START( venom ) ROM_REGION( 0x300000, "user3", ROMREGION_ERASEFF ) - ROM_REGION(0x100, "sound_ipl", 0) - ROM_LOAD("spc700.rom", 0, 0x40, CRC(44bb3a40) SHA1(97e352553e94242ae823547cd853eecda55c20f0) ) - ROM_REGION(0x800, "user6", ROMREGION_ERASEFF) ROM_REGION( 0x300000, "user7", 0 ) diff --git a/src/mame/includes/snes.h b/src/mame/includes/snes.h index cc87ecfef0a..5577d0d0d9c 100644 --- a/src/mame/includes/snes.h +++ b/src/mame/includes/snes.h @@ -4,9 +4,9 @@ #ifndef MAME_INCLUDES_SNES_H #define MAME_INCLUDES_SNES_H -#include "cpu/spc700/spc700.h" #include "cpu/g65816/g65816.h" -#include "audio/snes_snd.h" +#include "machine/s_smp.h" +#include "sound/s_dsp.h" #include "video/snes_ppu.h" #include "screen.h" @@ -303,9 +303,10 @@ public: driver_device(mconfig, type, tag), m_maincpu(*this, "maincpu"), m_soundcpu(*this, "soundcpu"), - m_spc700(*this, "spc700"), + m_s_dsp(*this, "s_dsp"), m_ppu(*this, "ppu"), - m_screen(*this, "screen") + m_screen(*this, "screen"), + m_wram(*this, "wram") { } void init_snes(); @@ -316,6 +317,11 @@ public: uint32_t screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); protected: + virtual void machine_start() override; + virtual void machine_reset() override; + + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override; + enum { TIMER_NMI_TICK, @@ -385,11 +391,13 @@ protected: /* devices */ required_device<_5a22_device> m_maincpu; - required_device m_soundcpu; - required_device m_spc700; + required_device m_soundcpu; + required_device m_s_dsp; required_device m_ppu; required_device m_screen; + required_shared_ptr m_wram; + inline int dma_abus_valid(uint32_t address); inline uint8_t abus_read(address_space &space, uint32_t abus); inline void dma_transfer(address_space &space, uint8_t dma, uint32_t abus, uint16_t bbus); @@ -432,10 +440,6 @@ protected: DECLARE_DEVICE_IMAGE_LOAD_MEMBER(load_snes_cart); DECLARE_DEVICE_IMAGE_LOAD_MEMBER(load_sufami_cart); void snes_init_timers(); - virtual void machine_start() override; - virtual void machine_reset() override; - - virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override; }; /* Special chips, checked at init and used in memory handlers */ diff --git a/src/mame/machine/snes.cpp b/src/mame/machine/snes.cpp index 60f95f0ebde..de23003f30b 100644 --- a/src/mame/machine/snes.cpp +++ b/src/mame/machine/snes.cpp @@ -390,7 +390,7 @@ READ8_MEMBER( snes_state::snes_r_io ) // APU is mirrored from 2140 to 217f if (offset >= APU00 && offset < WMDATA) { - return m_spc700->spc_port_out(offset & 0x3); + return m_soundcpu->spc_port_out_r(offset & 0x3); } // DMA accesses are from 4300 to 437f @@ -404,7 +404,7 @@ READ8_MEMBER( snes_state::snes_r_io ) switch (offset) // offset is from 0x000000 { case WMDATA: /* Data to read from WRAM */ - value = m_maincpu->space(AS_PROGRAM).read_byte(0x7e0000 + m_wram_address++); + value = m_wram[m_wram_address++]; m_wram_address &= 0x1ffff; return value; @@ -480,7 +480,7 @@ WRITE8_MEMBER( snes_state::snes_w_io ) if (offset >= APU00 && offset < WMDATA) { // printf("816: %02x to APU @ %d (PC=%06x)\n", data, offset & 3,m_maincpu->pc()); - m_spc700->spc_port_in(offset & 0x3, data); + m_soundcpu->spc_port_in_w(offset & 0x3, data); machine().scheduler().boost_interleave(attotime::zero, attotime::from_usec(20)); return; } @@ -496,7 +496,7 @@ WRITE8_MEMBER( snes_state::snes_w_io ) switch (offset) { case WMDATA: /* Data to write to WRAM */ - m_maincpu->space(AS_PROGRAM).write_byte(0x7e0000 + m_wram_address++, data ); + m_wram[m_wram_address++] = data; m_wram_address &= 0x1ffff; return; case WMADDL: /* Address to read/write to wram (low) */ @@ -720,7 +720,7 @@ READ8_MEMBER(snes_state::snes_r_bank1) if (offset < 0x400000) { if (address < 0x2000) /* Mirror of Low RAM */ - value = m_maincpu->space(AS_PROGRAM).read_byte(0x7e0000 + address); + value = m_wram[address]; else if (address < 0x6000) /* I/O */ value = snes_r_io(space, address); else if (address < 0x8000) @@ -831,7 +831,7 @@ WRITE8_MEMBER(snes_state::snes_w_bank1) if (offset < 0x400000) { if (address < 0x2000) /* Mirror of Low RAM */ - m_maincpu->space(AS_PROGRAM).write_byte(0x7e0000 + address, data); + m_wram[address] = data; else if (address < 0x6000) /* I/O */ snes_w_io(space, address, data); else if (address < 0x8000) @@ -1034,14 +1034,14 @@ void snes_state::snes_init_timers() void snes_state::snes_init_ram() { - address_space &cpu0space = m_maincpu->space(AS_PROGRAM); int i; /* Init work RAM - 0x55 isn't exactly right but it's close */ /* make sure it happens to the 65816 (CPU 0) */ - for (i = 0; i < (128*1024); i++) + const size_t size = m_wram.bytes(); + for (i = 0; i < size; i++) { - cpu0space.write_byte(0x7e0000 + i, 0x55); + m_wram[i] = 0x55; } /* Inititialize registers/variables */ -- cgit v1.2.3