summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--scripts/src/cpu.lua16
-rw-r--r--scripts/src/sound.lua8
-rw-r--r--src/devices/sound/meg.cpp180
-rw-r--r--src/devices/sound/meg.h71
-rw-r--r--src/devices/sound/megd.cpp118
-rw-r--r--src/devices/sound/swp00.cpp15
-rw-r--r--src/devices/sound/swp30.cpp1044
-rw-r--r--src/devices/sound/swp30.h162
-rw-r--r--src/devices/sound/swp30d.cpp124
-rw-r--r--src/devices/sound/swp30d.h (renamed from src/devices/sound/megd.h)16
-rw-r--r--src/devices/sound/xt446.cpp8
-rw-r--r--src/mame/yamaha/ymmu100.cpp14
12 files changed, 982 insertions, 794 deletions
diff --git a/scripts/src/cpu.lua b/scripts/src/cpu.lua
index f7b332e8f01..182c6929e84 100644
--- a/scripts/src/cpu.lua
+++ b/scripts/src/cpu.lua
@@ -3370,20 +3370,20 @@ if opt_tool(CPUS, "HPC") then
end
--------------------------------------------------
--- Yamaha Multiple Effects Generator
---@src/devices/sound/meg.h,CPUS["MEG"] = true
+-- Yamaha SWP30
+--@src/devices/sound/swp30.h,CPUS["SWP30"] = true
--------------------------------------------------
-if CPUS["MEG"] then
+if CPUS["SWP30"] then
files {
- MAME_DIR .. "src/devices/sound/meg.cpp",
- MAME_DIR .. "src/devices/sound/meg.h",
+ MAME_DIR .. "src/devices/sound/swp30.cpp",
+ MAME_DIR .. "src/devices/sound/swp30.h",
}
end
-if opt_tool(CPUS, "MEG") then
- table.insert(disasm_files , MAME_DIR .. "src/devices/sound/megd.cpp")
- table.insert(disasm_files , MAME_DIR .. "src/devices/sound/megd.h")
+if opt_tool(CPUS, "SWP30") then
+ table.insert(disasm_files , MAME_DIR .. "src/devices/sound/swp30d.cpp")
+ table.insert(disasm_files , MAME_DIR .. "src/devices/sound/swp30d.h")
end
--------------------------------------------------
diff --git a/scripts/src/sound.lua b/scripts/src/sound.lua
index 56573224bfa..67aa52cfd68 100644
--- a/scripts/src/sound.lua
+++ b/scripts/src/sound.lua
@@ -1526,13 +1526,13 @@ end
---------------------------------------------------
--
---@src/devices/sound/swp30.h,SOUNDS["SWP30"] = true
+--@src/devices/sound/meg.h,SOUNDS["MEG"] = true
---------------------------------------------------
-if (SOUNDS["SWP30"]~=null) then
+if (SOUNDS["MEG"]~=null) then
files {
- MAME_DIR .. "src/devices/sound/swp30.cpp",
- MAME_DIR .. "src/devices/sound/swp30.h",
+ MAME_DIR .. "src/devices/sound/meg.cpp",
+ MAME_DIR .. "src/devices/sound/meg.h",
}
end
diff --git a/src/devices/sound/meg.cpp b/src/devices/sound/meg.cpp
index f6a90812d6a..5d36f34c014 100644
--- a/src/devices/sound/meg.cpp
+++ b/src/devices/sound/meg.cpp
@@ -6,179 +6,23 @@
// Audio dsp dedicated to effects generation
#include "emu.h"
-#include "debugger.h"
#include "meg.h"
DEFINE_DEVICE_TYPE(MEG, meg_device, "meg", "Multiple Effects Generator (HD62098 / XM309A00)")
-DEFINE_DEVICE_TYPE(MEGEMB, meg_embedded_device, "megemb", "Multiple Effects Generator (embedded)")
-void meg_base_device::prg_map(address_map &map)
-{
- map(0, m_prg_size - 1).ram();
-}
-
-void meg_base_device::fp_map(address_map &map)
-{
- map(0, m_prg_size - 1).ram();
-}
-
-void meg_base_device::offsets_map(address_map &map)
-{
- map(0, 0x7f).ram();
-}
-
-meg_base_device::meg_base_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, u32 prg_size) :
- cpu_device(mconfig, type, tag, owner, clock),
- m_program_config("program", ENDIANNESS_BIG, 64, prg_size > 256 ? 9 : 8, -3, address_map_constructor(FUNC(meg_base_device::prg_map), this)),
- m_fp_config("fp", ENDIANNESS_BIG, 16, prg_size > 256 ? 9 : 8, -1, address_map_constructor(FUNC(meg_base_device::fp_map), this)),
- m_offsets_config("offsets", ENDIANNESS_BIG, 16, prg_size > 256 ? 7 : 7, -1, address_map_constructor(FUNC(meg_base_device::offsets_map), this)),
- m_prg_size(prg_size)
-{
-}
-
-
-void meg_base_device::prg_w(u16 address, u64 opcode)
-{
- m_program->write_qword(address, opcode);
-}
-
-void meg_base_device::fp_w(u16 address, u16 value)
-{
- m_fp->write_word(address, value);
-}
-
-void meg_base_device::offset_w(u16 address, u16 value)
-{
- m_offsets->write_word(address, value);
-}
-
-void meg_base_device::lfo_w(u8 reg, u16 value)
-{
- m_lfo[reg] = value;
-
- static const int dt[8] = { 0, 32, 64, 128, 256, 512, 1024, 2048 };
- static const int sh[8] = { 0, 0, 1, 2, 3, 4, 5, 6 };
-
- int scale = (value >> 5) & 7;
- int step = ((value & 31) << sh[scale]) + dt[scale];
- logerror("lfo_w %02x freq=%5.2f phase=%6.4f\n", reg, step * 44100.0/4194304, (value >> 8)/256.0);
-}
-
-void meg_base_device::map_w(u8 reg, u16 value)
-{
- m_map[reg] = value;
- logerror("map %d: start = %06x size = %06x extra = %x\n", reg, (value & 0xff) << 10, 1 << (10 + ((value & 0x0700) >> 8)), (value & 0xf800) >> 11);
-}
-
-u64 meg_base_device::prg_r(u16 address) const
-{
- return m_program->read_qword(address);
-}
-
-u16 meg_base_device::fp_r(u16 address) const
-{
- return m_fp->read_word(address);
-}
-
-u16 meg_base_device::offset_r(u16 address) const
-{
- return m_offsets->read_word(address);
-}
-
-u16 meg_base_device::lfo_r(u8 reg) const
-{
- return m_lfo[reg];
-}
-
-u16 meg_base_device::map_r(u8 reg) const
-{
- return m_map[reg];
-}
-
-
-void meg_base_device::device_start()
-{
- m_program = &space(AS_PROGRAM);
- m_fp = &space(AS_FP);
- m_offsets = &space(AS_OFFSETS);
-
- state_add(STATE_GENPC, "GENPC", m_pc).noshow();
- state_add(STATE_GENPCBASE, "CURPC", m_pc).noshow();
- state_add(0, "PC", m_pc);
-
- set_icountptr(m_icount);
-
- save_item(NAME(m_lfo));
- save_item(NAME(m_map));
- save_item(NAME(m_pc));
-}
-
-void meg_base_device::device_reset()
-{
- memset(m_lfo, 0, sizeof(m_lfo));
- memset(m_map, 0, sizeof(m_map));
- m_pc = 0;
-}
-
-uint32_t meg_base_device::execute_min_cycles() const noexcept
-{
- return 1;
-}
-
-uint32_t meg_base_device::execute_max_cycles() const noexcept
-{
- return 1;
-}
-
-uint32_t meg_base_device::execute_input_lines() const noexcept
-{
- return 0;
-}
-
-void meg_base_device::execute_run()
-{
- if(machine().debug_flags & DEBUG_FLAG_ENABLED)
- debugger_instruction_hook(m_pc);
- m_icount = 0;
-}
-
-device_memory_interface::space_config_vector meg_base_device::memory_space_config() const
-{
- return space_config_vector {
- std::make_pair(AS_PROGRAM, &m_program_config),
- std::make_pair(AS_FP, &m_fp_config),
- std::make_pair(AS_OFFSETS, &m_offsets_config)
- };
-}
-
-void meg_base_device::state_import(const device_state_entry &entry)
-{
-}
-
-void meg_base_device::state_export(const device_state_entry &entry)
-{
-}
-
-void meg_base_device::state_string_export(const device_state_entry &entry, std::string &str) const
-{
-}
-
-std::unique_ptr<util::disasm_interface> meg_base_device::create_disassembler()
+meg_device::meg_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ device_t(mconfig, MEG, tag, owner, clock)
{
- return std::make_unique<meg_disassembler>(this);
}
-meg_embedded_device::meg_embedded_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
- meg_base_device(mconfig, MEGEMB, tag, owner, clock, 384)
+void meg_device::device_start()
{
}
-meg_device::meg_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
- meg_base_device(mconfig, MEG, tag, owner, clock, 256)
+void meg_device::device_reset()
{
}
-
// vl70:
// 6d1e: write 1, r0l
// 6d26: write 2, r0l
@@ -213,8 +57,8 @@ void meg_device::map(address_map &map)
map(0x08, 0x08).w(FUNC(meg_device::s8_w));
map(0x09, 0x09).w(FUNC(meg_device::s9_w));
map(0x0a, 0x0a).w(FUNC(meg_device::sa_w));
- map(0x0c, 0x0c).w(FUNC(meg_device::fph_w));
- map(0x0d, 0x0d).w(FUNC(meg_device::fpl_w));
+ map(0x0c, 0x0c).w(FUNC(meg_device::consth_w));
+ map(0x0d, 0x0d).w(FUNC(meg_device::constl_w));
map(0x0e, 0x0e).w(FUNC(meg_device::se_w));
map(0x0f, 0x0f).w(FUNC(meg_device::sf_w));
map(0x10, 0x10).r(FUNC(meg_device::s10_r));
@@ -297,15 +141,15 @@ void meg_device::sa_w(u8 data)
logerror("ra %02x %s\n", data, machine().describe_context());
}
-void meg_device::fph_w(u8 data)
+void meg_device::consth_w(u8 data)
{
- fp_w(m_reg, (fp_r(m_reg) & 0x00ff) | (data << 8));
+ m_const[m_reg] = (m_const[m_reg] & 0x00ff) | (data << 8);
}
-void meg_device::fpl_w(u8 data)
+void meg_device::constl_w(u8 data)
{
- fp_w(m_reg, (fp_r(m_reg) & 0xff00) | data);
+ m_const[m_reg] = (m_const[m_reg] & 0xff00) | data;
}
void meg_device::se_w(u8 data)
@@ -339,12 +183,12 @@ u8 meg_device::s11_r()
void meg_device::offseth_w(u8 data)
{
- offset_w(m_reg, (offset_r(m_reg) & 0x00ff) | (data << 8));
+ m_offset[m_reg] = (m_offset[m_reg] & 0x00ff) | (data << 8);
}
void meg_device::offsetl_w(u8 data)
{
- offset_w(m_reg, (offset_r(m_reg) & 0xff00) | data);
+ m_offset[m_reg] = (m_offset[m_reg] & 0xff00) | data;
}
void meg_device::s14_w(u8 data)
diff --git a/src/devices/sound/meg.h b/src/devices/sound/meg.h
index 40129158fc8..4f59c416603 100644
--- a/src/devices/sound/meg.h
+++ b/src/devices/sound/meg.h
@@ -3,75 +3,22 @@
// Yamaha MEG - Multiple effects generator
//
-// Audio dsp dedicated to effects generation
+// Audio dsp dedicated to effects generation, part of the SWP20 lineup
#ifndef DEVICES_SOUND_MEG_H
#define DEVICES_SOUND_MEG_H
#pragma once
-#include "megd.h"
-
-
-class meg_base_device : public cpu_device, public meg_disassembler::info
+class meg_device : public device_t
{
public:
- enum {
- AS_FP = 1,
- AS_OFFSETS = 2
- };
-
- meg_base_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, u32 prg_size);
-
- void prg_w(u16 address, u64 opcode);
- void fp_w(u16 address, u16 value);
- void offset_w(u16 address, u16 value);
- void lfo_w(u8 reg, u16 value);
- void map_w(u8 reg, u16 value);
- u64 prg_r(u16 address) const;
- virtual u16 fp_r(u16 address) const override;
- virtual u16 offset_r(u16 address) const override;
- u16 lfo_r(u8 reg) const;
- u16 map_r(u8 reg) const;
+ meg_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 44100*256);
+ void map(address_map &map);
protected:
virtual void device_start() override;
virtual void device_reset() override;
- virtual uint32_t execute_min_cycles() const noexcept override;
- virtual uint32_t execute_max_cycles() const noexcept override;
- virtual uint32_t execute_input_lines() const noexcept override;
- virtual void execute_run() override;
- virtual space_config_vector memory_space_config() const override;
- virtual void state_import(const device_state_entry &entry) override;
- virtual void state_export(const device_state_entry &entry) override;
- virtual void state_string_export(const device_state_entry &entry, std::string &str) const override;
- virtual std::unique_ptr<util::disasm_interface> create_disassembler() override;
-
-private:
- address_space_config m_program_config, m_fp_config, m_offsets_config;
- address_space *m_program, *m_fp, *m_offsets;
-
- u32 m_prg_size, m_pc;
- int m_icount;
-
- u16 m_lfo[0x18], m_map[8];
-
- void prg_map(address_map &map);
- void fp_map(address_map &map);
- void offsets_map(address_map &map);
-};
-
-class meg_embedded_device : public meg_base_device
-{
-public:
- meg_embedded_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 44100*384);
-};
-
-class meg_device : public meg_base_device
-{
-public:
- meg_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 44100*256);
- void map(address_map &map);
private:
u8 m_r4[256];
@@ -87,6 +34,10 @@ private:
u8 m_r17[256];
u8 m_r18[256];
u8 m_reg;
+
+ std::array<s16, 0xc0> m_const;
+ std::array<s16, 0x40> m_offset;
+
u8 s2_r();
u8 s10_r();
u8 s11_r();
@@ -100,8 +51,8 @@ private:
void s8_w(u8 data);
void s9_w(u8 data);
void sa_w(u8 data);
- void fph_w(u8 data);
- void fpl_w(u8 data);
+ void consth_w(u8 data);
+ void constl_w(u8 data);
void se_w(u8 data);
void sf_w(u8 data);
void s10_w(u8 data);
@@ -115,8 +66,6 @@ private:
void s18_w(u8 data);
};
-
DECLARE_DEVICE_TYPE(MEG, meg_device)
-DECLARE_DEVICE_TYPE(MEGEMB, meg_embedded_device)
#endif
diff --git a/src/devices/sound/megd.cpp b/src/devices/sound/megd.cpp
deleted file mode 100644
index 47ff6dfdb3d..00000000000
--- a/src/devices/sound/megd.cpp
+++ /dev/null
@@ -1,118 +0,0 @@
-// license:BSD-3-Clause
-// copyright-holders:Olivier Galibert
-
-// Yamaha MEG - Multiple effects generator
-//
-// Audio dsp dedicated to effects generation
-//
-// Disassembler
-
-#include "emu.h"
-#include "megd.h"
-
-meg_disassembler::meg_disassembler(info *inf) : m_info(inf)
-{
-}
-
-u32 meg_disassembler::opcode_alignment() const
-{
- return 1;
-}
-
-std::string meg_disassembler::gfp(offs_t address) const
-{
- if(!m_info)
- return util::string_format("fp%03x", address);
- s16 fp = m_info->fp_r(address);
- return util::string_format("%g", fp / 16384.0);
-}
-
-std::string meg_disassembler::goffset(offs_t address) const
-{
- return m_info ? util::string_format("%x", m_info->offset_r(address)) : util::string_format("of%02x", address);
-}
-
-u32 meg_disassembler::b(u64 opc, u32 start, u32 count)
-{
- return (opc >> start) & ((1 << count) - 1);
-}
-
-void meg_disassembler::append(std::string &r, const std::string &e)
-{
- if(r != "")
- r += " ; ";
- r += e;
-}
-
-// 33333333 33333333 22222222 22222222 11111111 11111111 00000000 00000000
-// fedcba98 76543210 fedcba98 76543210 fedcba98 76543210 fedcba98 76543210
-
-// 66665555 55555544 44444444 33333333 33222222 22221111 11111100 00000000
-// 32109876 54321098 76543210 98765432 10987654 32109876 54321098 76543210
-// XLB----- -rrrrrrr r--mmmmm m-MM---- -P-----* -----Arr rrrrrrmm mmmm----
-
-// m = low is read port, high is write port, memory register
-// r = low is read port, high is high port, rotating register
-
-// X = used for lo-fi variation only
-// L = lfo read
-// * = compute mul
-// A = mul input = m or r
-// P = P sent for register write
-// B = register write to mbuf
-// M = memory mode, none/read/write/read+1
-
-offs_t meg_disassembler::disassemble(std::ostream &stream, offs_t pc, const data_buffer &opcodes, const data_buffer &params)
-{
- u64 opc = opcodes.r64(pc);
-
- std::string r;
-
- r = util::string_format("[m%02x]", b(opc, 39, 6));
-
- if(b(opc, 62, 1))
- append(r, "lfo");
-
- if(b(opc, 23, 1))
- switch(b(opc, 24, 2)) {
- case 0:
- if(b(opc, 18, 1))
- append(r, util::string_format("p += %s*m%02x", gfp(pc), b(opc, 4, 6)));
- else
- append(r, util::string_format("p += %s*r%02x", gfp(pc), b(opc, 10, 8)));
- break;
- case 1:
- append(r, util::string_format("p = %s*(r%02x+m%02x)", gfp(pc), b(opc, 10, 8), b(opc, 4, 6)));
- break;
- case 2:
- append(r, util::string_format("p ?= %s*(r%02x+m%02x)", gfp(pc), b(opc, 10, 8), b(opc, 4, 6)));
- break;
- case 3:
- if(b(opc, 18, 1))
- append(r, util::string_format("p = %s*m%02x", gfp(pc), b(opc, 4, 6)));
- else
- append(r, util::string_format("p = %s*r%02x", gfp(pc), b(opc, 10, 8)));
- break;
- }
-
- if(b(opc, 30, 1)) {
- if(b(opc, 61, 1))
- append(r, "mb = p");
- else if(b(opc, 46, 1) == 1)
- append(r, util::string_format("m%02x = p", b(opc, 39, 6)));
- else
- append(r, util::string_format("r%02x = p", b(opc, 47, 8)));
- }
-
- u32 memmode = b(opc, 36, 2);
- if(memmode) {
- static const char *modes[4] = { nullptr, "w", "r", "rw" };
-
- append(r, util::string_format("mem_%s %x +%s", modes[memmode], b(opc, 33, 3), goffset(pc/3)));
- r += util::string_format("-> m%02x", b(opcodes.r64(pc+2), 39, 6));
- }
-
- stream << r;
-
- return 1 | SUPPORTED;
-}
diff --git a/src/devices/sound/swp00.cpp b/src/devices/sound/swp00.cpp
index 2aabf9f06fc..b1b3dad2742 100644
--- a/src/devices/sound/swp00.cpp
+++ b/src/devices/sound/swp00.cpp
@@ -720,7 +720,7 @@ void swp00_device::attack_speed_w(offs_t offset, u8 data)
return;
m_stream->update();
m_attack_speed[chan] = data;
- // logerror("attack_speed[%02x] = %02x\n", chan, m_attack_speed[chan]);
+ logerror("attack_speed[%02x] = %02x\n", chan, m_attack_speed[chan]);
}
u8 swp00_device::attack_speed_r(offs_t offset)
@@ -736,7 +736,7 @@ void swp00_device::attack_level_w(offs_t offset, u8 data)
return;
m_stream->update();
m_attack_level[chan] = data;
- // logerror("attack_level[%02x] = %02x\n", chan, m_attack_level[chan]);
+ logerror("attack_level[%02x] = %02x\n", chan, m_attack_level[chan]);
}
u8 swp00_device::attack_level_r(offs_t offset)
@@ -757,7 +757,7 @@ void swp00_device::decay_speed_w(offs_t offset, u8 data)
if(data & 0x80)
m_decay[chan] = true;
- // logerror("decay_speed[%02x] = %02x\n", chan, m_decay_speed[chan]);
+ logerror("decay_speed[%02x] = %02x\n", chan, m_decay_speed[chan]);
}
u8 swp00_device::decay_speed_r(offs_t offset)
@@ -773,7 +773,7 @@ void swp00_device::decay_level_w(offs_t offset, u8 data)
return;
m_stream->update();
m_decay_level[chan] = data;
- // logerror("decay_level[%02x] = %02x\n", chan, m_decay_level[chan]);
+ logerror("decay_level[%02x] = %02x\n", chan, m_decay_level[chan]);
}
u8 swp00_device::decay_level_r(offs_t offset)
@@ -900,7 +900,7 @@ u8 swp00_device::lfo_pmod_depth_r(offs_t offset)
void swp00_device::keyon(int chan)
{
m_stream->update();
- // logerror("keyon %02x a=%02x/%02x d=%02x/%02x\n", chan, m_attack_speed[chan], m_attack_level[chan], m_decay_speed[chan], m_decay_level[chan]);
+ logerror("keyon %02x a=%02x/%02x d=%02x/%02x glo=%02x pan=%02x [%x %x %x %x]\n", chan, m_attack_speed[chan], m_attack_level[chan], m_decay_speed[chan], m_decay_level[chan], m_glo_level[chan], m_panning[chan], m_sample_start[chan], m_sample_end[chan], m_sample_address[chan], m_sample_dec_and_format[chan]);
m_lfo_phase[chan] = 0;
m_sample_pos[chan] = -m_sample_start[chan] << 15;
@@ -1249,6 +1249,11 @@ s32 swp00_device::saturate(s32 value)
return value;
}
+double v2f2(s32 value)
+{
+ return (1.0 - (value & 0xffffff) / 33554432.0) / (1 << (value >> 24));
+}
+
void swp00_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
const delay_block brev(this, m_rev_buffer);
diff --git a/src/devices/sound/swp30.cpp b/src/devices/sound/swp30.cpp
index 46ebe70d0b3..471526cbc2b 100644
--- a/src/devices/sound/swp30.cpp
+++ b/src/devices/sound/swp30.cpp
@@ -4,6 +4,7 @@
// Yamaha SWP30/30B, rompler/dsp combo
#include "emu.h"
+#include "debugger.h"
#include "swp30.h"
static int scount = 0;
@@ -65,9 +66,9 @@ static int scount = 0;
ch04 fixed LPF resonance level
ch05 unknown
ch06 attack, bit 14-8 = step, bit 7 = skip
- ch07 decay, bit 14-8 = step, bit 7-0 = target attenuation (top 8 bits)
- ch08 release, bit 14-8 = step, bit 7-0 = target attenuation (top 8 bits)
- ch09 base volume bit 15 = activate release, bit 14-8 unknown, bit 7-0 = initial attenuation
+ ch07 decay1, bit 14-8 = step, bit 7-0 = target attenuation (top 8 bits)
+ ch08 decay2, bit 14-8 = step, bit 7-0 = target attenuation (top 8 bits)
+ ch09 base volume bit 15 = activate decay2, bit 14-8 unknown, bit 7-0 = initial attenuation
ch0a-0d unknown, probably something to do with pitch eg
ch10 unknown
@@ -102,7 +103,7 @@ static int scount = 0;
of 0x10 to 0x3c000, and a full sweep from -96dB to 0 in 95s (8) to
6.2ms (119).
- For decay and release the range is 1..120, e.g. 9 to 0x40000, or
+ For decay1 and decay2 the range is 1..120, e.g. 9 to 0x40000, or
169s to 5.8ms for a full sweep.
@@ -165,44 +166,176 @@ static int scount = 0;
ch35-37 routing for an AWM2 channel
-
*/
DEFINE_DEVICE_TYPE(SWP30, swp30_device, "swp30", "Yamaha SWP30 sound chip")
-swp30_device::swp30_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : device_t(mconfig, SWP30, tag, owner, clock),
- device_sound_interface(mconfig, *this),
- device_rom_interface(mconfig, *this),
- m_meg(*this, "meg")
+bool swp30_device::istep(s32 &value, s32 limit, s32 step)
+{
+ // fprintf(stderr, "istep(%x, %x, %x)\n", value, limit, step);
+ if(value < limit) {
+ value += step;
+ if(value >= limit) {
+ value = limit;
+ return true;
+ }
+ return false;
+ }
+
+ if(value > limit) {
+ value -= step;
+ if(value <= limit) {
+ value = limit;
+ return true;
+ }
+ return false;
+ }
+
+ return true;
+}
+
+s32 swp30_device::fpadd(s32 value, s32 step)
+{
+ s32 e = value >> 24;
+ s32 m = value & 0xffffff;
+
+ m += step << e;
+ if(m & 0xfe000000)
+ return 0xfffffff;
+
+ while(m & 0x01000000) {
+ m <<= 1;
+ e ++;
+ }
+ if(e >= 16)
+ return 0xfffffff;
+ return (e << 24) | (m & 0xffffff);
+}
+
+s32 swp30_device::fpsub(s32 value, s32 step)
+{
+ s32 e = value >> 24;
+ s32 m = (value & 0xffffff) | 0xfe000000;
+ m = e < 0xc ? m - (step << e) : (m >> (e - 0xb)) - (step << 0xb);
+ if(m >= 0)
+ return 0;
+ if(e >= 0xc)
+ e = 0xb;
+ while(m < 0xfe000000) {
+ if(!e)
+ return 0;
+ e --;
+ m >>= 1;
+ }
+ while(e != 0xf && (m >= 0xff000000)) {
+ e ++;
+ m <<= 1;
+ }
+
+ return (e << 24) | (m & 0xffffff);
+}
+
+bool swp30_device::fpstep(s32 &value, s32 limit, s32 step)
{
- (void)m_map;
+ // value, limit and step are 4.24 but step has its exponent and
+ // top four bits zero
+
+ if(value == limit)
+ return true;
+ if(value < limit) {
+ value = fpadd(value, step);
+ if(value >= limit) {
+ value = limit;
+ return true;
+ }
+ return false;
+ }
+
+ value = fpsub(value, step);
+ if(value <= limit) {
+ value = limit;
+ return true;
+ }
+ return false;
}
-void swp30_device::device_add_mconfig(machine_config &config)
+// sample is signed 24.8
+s32 swp30_device::fpapply(s32 value, s32 sample)
+{
+ if(value >= 0x10000000)
+ return 0;
+ return (s64(sample) - ((s64(sample) * ((value >> 9) & 0x7fff)) >> 16)) >> (value >> 24);
+}
+
+// sample is signed 24.8
+s32 swp30_device::lpffpapply(s32 value, s32 sample)
+{
+ return ((((value >> 7) & 0x7fff) | 0x8000) * s64(sample)) >> (31 - (value >> 22));
+}
+
+// Some tables we picked up from the swp00. May be different, may not be.
+
+const std::array<s32, 0x80> swp30_device::attack_linear_step = {
+ 0x00027, 0x0002b, 0x0002f, 0x00033, 0x00037, 0x0003d, 0x00042, 0x00048,
+ 0x0004d, 0x00056, 0x0005e, 0x00066, 0x0006f, 0x0007a, 0x00085, 0x00090,
+ 0x0009b, 0x000ac, 0x000bd, 0x000cc, 0x000de, 0x000f4, 0x00109, 0x00120,
+ 0x00135, 0x00158, 0x00179, 0x00199, 0x001bc, 0x001e7, 0x00214, 0x00240,
+ 0x0026b, 0x002af, 0x002f2, 0x00332, 0x00377, 0x003d0, 0x0042c, 0x00480,
+ 0x004dc, 0x0055e, 0x005e9, 0x0066e, 0x006f4, 0x007a4, 0x00857, 0x0090b,
+ 0x009c3, 0x00acb, 0x00bd6, 0x00ce6, 0x00e00, 0x00f5e, 0x010d2, 0x01234,
+ 0x0139e, 0x015d0, 0x017f3, 0x01a20, 0x01c4a, 0x01f52, 0x02232, 0x0250f,
+ 0x027ff, 0x02c72, 0x03109, 0x0338b, 0x039c4, 0x04038, 0x04648, 0x04c84,
+ 0x05262, 0x05c1c, 0x065af, 0x06f5c, 0x07895, 0x0866f, 0x09470, 0x0a19e,
+ 0x0ae4c, 0x0c566, 0x0db8d, 0x0f00f, 0x10625, 0x12937, 0x14954, 0x16c17,
+ 0x1886e, 0x1c71c, 0x20000, 0x239e1, 0x2647c, 0x2aaab, 0x2ecfc, 0x3241f,
+ 0x35e51, 0x3a83b, 0x40000, 0x4325c, 0x47dc1, 0x4c8f9, 0x50505, 0x55555,
+ 0x58160, 0x5d174, 0x60606, 0x62b2e, 0x67b24, 0x6a63c, 0x6d3a0, 0x6eb3e,
+ 0x71c72, 0x73616, 0x75075, 0x76b98, 0x78788, 0x78788, 0x7a44c, 0x7a44c,
+ 0x7a44c, 0x7a44c, 0x7a44c, 0x7a44c, 0x7a44c, 0x7a44c, 0x7a44c, 0x7a44c,
+};
+
+const std::array<s32, 0x20> swp30_device::decay_linear_step = {
+ 0x15083, 0x17ad2, 0x1a41a, 0x1cbe7, 0x1f16d, 0x22ef1, 0x26a44, 0x2a1e4,
+ 0x2da35, 0x34034, 0x3a197, 0x40000, 0x45b82, 0x4b809, 0x51833, 0x57262,
+ 0x5d9f7, 0x6483f, 0x6b15c, 0x71c72, 0x77976, 0x7d119, 0x83127, 0x88889,
+ 0x8d3dd, 0x939a8, 0x991f2, 0x9d89e, 0xa0a0a, 0xa57eb, 0xa72f0, 0xac769,
+};
+
+swp30_device::swp30_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : cpu_device(mconfig, SWP30, tag, owner, clock),
+ device_sound_interface(mconfig, *this),
+ m_program_config("meg_program", ENDIANNESS_LITTLE, 64, 9, -3, address_map_constructor(FUNC(swp30_device::meg_prg_map), this)),
+ m_rom_config("sample_rom", ENDIANNESS_LITTLE, 32, 25, -2)
{
- MEGEMB(config, m_meg);
}
void swp30_device::device_start()
{
- m_stream = stream_alloc(0, 2, 44100, STREAM_SYNCHRONOUS);
+ m_program = &space(AS_PROGRAM);
+ m_rom = &space(AS_DATA);
+ m_rom->cache(m_rom_cache);
- // Attenuation for panning is 4.4 floating point. That means 0
- // to -96.3dB. Since it's a nice range, we assume it's the same
- // for other attenuation values. Computed value is 1.16
- // format, to avoid overflow
+ state_add(STATE_GENPC, "GENPC", m_meg_pc).noshow();
+ state_add(STATE_GENPCBASE, "CURPC", m_meg_pc).noshow();
+ state_add(0, "PC", m_meg_pc);
- for(int i=0; i<256; i++)
- m_linear_attenuation[i] = ((32 - (i & 15)) << (0xf ^ (i >> 4))) >> 4;
+ set_icountptr(m_icount);
- // Relative playback frequency of a sample is encoded on signed 14
- // bits. The scale is logarithmic, with 0x400 = 1 octave (e.g. *2
- // or /2).
+ m_stream = stream_alloc(0, 2, 44100, STREAM_SYNCHRONOUS);
- for(int i=-0x2000; i<0x2000; i++)
- m_sample_increment[i & 0x3fff] = 256 * pow(2, i/1024.0);
+ for(int i=0; i != 128; i++) {
+ u32 v = 0;
+ switch(i >> 3) {
+ default: v = ((i & 7) + 8) << (1 + (i >> 3)); break;
+ case 0xb: v = ((i & 7) + 4) << 13; break;
+ case 0xc: v = ((i & 6) + 6) << 14; break;
+ case 0xd: v = ((i & 4) + 7) << 15; break;
+ case 0xe: v = 15 << 15; break;
+ case 0xf: v = 31 << 15; break;
+ }
+ m_global_step[i] = v;
+ }
// Log to linear 8-bits sample decompression. Statistics say
// that's what it should look like. Note that 0 can be encoded
@@ -223,29 +356,34 @@ void swp30_device::device_start()
m_sample_log8[i | 0x80] = -m_sample_log8[i];
}
- save_item(NAME(m_program));
-
save_item(NAME(m_keyon_mask));
- save_item(NAME(m_pre_size));
- save_item(NAME(m_post_size));
- save_item(NAME(m_address));
+ save_item(NAME(m_sample_start));
+ save_item(NAME(m_sample_end));
+ save_item(NAME(m_sample_address));
+ save_item(NAME(m_pitch));
+
+ save_item(NAME(m_release_glo));
+ save_item(NAME(m_pan));
+ save_item(NAME(m_dry_rev));
+ save_item(NAME(m_cho_var));
+
+ save_item(NAME(m_attack));
+ save_item(NAME(m_decay1));
+ save_item(NAME(m_decay2));
save_item(NAME(m_sample_pos));
- save_item(NAME(m_sample_history));
+ save_item(NAME(m_envelope_level));
+ save_item(NAME(m_envelope_on_timer));
+ save_item(NAME(m_envelope_timer));
+ save_item(NAME(m_decay2_done));
+ save_item(NAME(m_envelope_mode));
+ save_item(NAME(m_glo_level_cur));
+ save_item(NAME(m_pan_l));
+ save_item(NAME(m_pan_r));
- save_item(NAME(m_program_pfp));
- save_item(NAME(m_program_pint));
- save_item(NAME(m_program_plfo));
+ save_item(NAME(m_sample_history));
- save_item(NAME(m_base_volume));
- save_item(NAME(m_current_volume));
- save_item(NAME(m_mode));
- save_item(NAME(m_freq));
- save_item(NAME(m_pan));
- save_item(NAME(m_attack));
- save_item(NAME(m_decay));
- save_item(NAME(m_release));
save_item(NAME(m_lpf_cutoff));
save_item(NAME(m_lpf_cutoff_inc));
save_item(NAME(m_lpf_reso));
@@ -255,38 +393,55 @@ void swp30_device::device_start()
save_item(NAME(m_internal_adr));
- save_item(NAME(m_program_address));
+ save_item(NAME(m_meg_program_address));
save_item(NAME(m_waverom_adr));
save_item(NAME(m_waverom_mode));
save_item(NAME(m_waverom_access));
save_item(NAME(m_waverom_val));
+
+ save_item(NAME(m_meg_program));
+ save_item(NAME(m_meg_const));
+ save_item(NAME(m_meg_offset));
+ save_item(NAME(m_meg_lfo));
+ save_item(NAME(m_meg_map));
}
void swp30_device::device_reset()
{
- memset(m_program, 0, sizeof(m_program));
-
m_keyon_mask = 0;
- memset(m_pre_size, 0, sizeof(m_pre_size));
- memset(m_post_size, 0, sizeof(m_post_size));
- memset(m_address, 0, sizeof(m_address));
+ std::fill(m_sample_start.begin(), m_sample_start.end(), 0);
+ std::fill(m_sample_end.begin(), m_sample_end.end(), 0);
+ std::fill(m_sample_address.begin(), m_sample_address.end(), 0);
+ std::fill(m_pitch.begin(), m_pitch.end(), 0);
+
+ std::fill(m_release_glo.begin(), m_release_glo.end(), 0);
+ std::fill(m_pan.begin(), m_pan.end(), 0);
+ std::fill(m_dry_rev.begin(), m_dry_rev.end(), 0);
+ std::fill(m_cho_var.begin(), m_cho_var.end(), 0);
+
+ std::fill(m_attack.begin(), m_attack.end(), 0);
+ std::fill(m_decay1.begin(), m_decay1.end(), 0);
+ std::fill(m_decay2.begin(), m_decay2.end(), 0);
+
+ std::fill(m_sample_pos.begin(), m_sample_pos.end(), 0);
+ std::fill(m_envelope_level.begin(), m_envelope_level.end(), 0);
+ std::fill(m_envelope_timer.begin(), m_envelope_timer.end(), 0);
+ std::fill(m_envelope_on_timer.begin(), m_envelope_on_timer.end(), false);
+ std::fill(m_decay2_done.begin(), m_decay2_done.end(), false);
+ std::fill(m_envelope_mode.begin(), m_envelope_mode.end(), IDLE);
+ std::fill(m_glo_level_cur.begin(), m_glo_level_cur.end(), 0);
+ std::fill(m_pan_l.begin(), m_pan_l.end(), 0);
+ std::fill(m_pan_r.begin(), m_pan_r.end(), 0);
+
+ std::fill(m_meg_program.begin(), m_meg_program.end(), 0);
+ std::fill(m_meg_const.begin(), m_meg_const.end(), 0);
+ std::fill(m_meg_offset.begin(), m_meg_offset.end(), 0);
+ std::fill(m_meg_lfo.begin(), m_meg_lfo.end(), 0);
+ std::fill(m_meg_map.begin(), m_meg_map.end(), 0);
- memset(m_sample_pos, 0, sizeof(m_sample_pos));
memset(m_sample_history, 0, sizeof(m_sample_history));
- memset(m_program_pfp, 0, sizeof(m_program_pfp));
- memset(m_program_pint, 0, sizeof(m_program_pint));
- memset(m_program_plfo, 0, sizeof(m_program_plfo));
-
- memset(m_base_volume, 0, sizeof(m_base_volume));
- memset(m_current_volume, 0, sizeof(m_current_volume));
- memset(m_mode, IDLE, sizeof(m_mode));
- memset(m_freq, 0, sizeof(m_freq));
- memset(m_pan, 0, sizeof(m_pan));
- memset(m_attack, 0, sizeof(m_attack));
- memset(m_decay, 0, sizeof(m_decay));
- memset(m_release, 0, sizeof(m_release));
memset(m_lpf_cutoff, 0, sizeof(m_lpf_cutoff));
memset(m_lpf_cutoff_inc, 0, sizeof(m_lpf_cutoff_inc));
memset(m_lpf_reso, 0, sizeof(m_lpf_reso));
@@ -294,7 +449,7 @@ void swp30_device::device_reset()
memset(m_eq_filter, 0, sizeof(m_eq_filter));
memset(m_routing, 0, sizeof(m_routing));
- m_program_address = 0;
+ m_meg_program_address = 0;
m_waverom_adr = 0;
m_waverom_mode = 0;
m_waverom_access = 0;
@@ -312,18 +467,18 @@ void swp30_device::map(address_map &map)
rchan(map, 0x04).rw(FUNC(swp30_device::lpf_reso_r), FUNC(swp30_device::lpf_reso_w));
// 05 missing
rchan(map, 0x06).rw(FUNC(swp30_device::attack_r), FUNC(swp30_device::attack_w));
- rchan(map, 0x07).rw(FUNC(swp30_device::decay_r), FUNC(swp30_device::decay_w));
- rchan(map, 0x08).rw(FUNC(swp30_device::release_r), FUNC(swp30_device::release_w));
- rchan(map, 0x09).rw(FUNC(swp30_device::base_volume_r), FUNC(swp30_device::base_volume_w));
+ rchan(map, 0x07).rw(FUNC(swp30_device::decay1_r), FUNC(swp30_device::decay1_w));
+ rchan(map, 0x08).rw(FUNC(swp30_device::decay2_r), FUNC(swp30_device::decay2_w));
+ rchan(map, 0x09).rw(FUNC(swp30_device::release_glo_r), FUNC(swp30_device::release_glo_w));
// 0a-0d missing
// 10 missing
- rchan(map, 0x11).rw(FUNC(swp30_device::freq_r), FUNC(swp30_device::freq_w));
- rchan(map, 0x12).rw(FUNC(swp30_device::pre_size_h_r), FUNC(swp30_device::pre_size_h_w));
- rchan(map, 0x13).rw(FUNC(swp30_device::pre_size_l_r), FUNC(swp30_device::pre_size_l_w));
- rchan(map, 0x14).rw(FUNC(swp30_device::post_size_h_r), FUNC(swp30_device::post_size_h_w));
- rchan(map, 0x15).rw(FUNC(swp30_device::post_size_l_r), FUNC(swp30_device::post_size_l_w));
- rchan(map, 0x16).rw(FUNC(swp30_device::address_h_r), FUNC(swp30_device::address_h_w));
- rchan(map, 0x17).rw(FUNC(swp30_device::address_l_r), FUNC(swp30_device::address_l_w));
+ rchan(map, 0x11).rw(FUNC(swp30_device::pitch_r), FUNC(swp30_device::pitch_w));
+ rchan(map, 0x12).rw(FUNC(swp30_device::sample_start_h_r), FUNC(swp30_device::sample_start_h_w));
+ rchan(map, 0x13).rw(FUNC(swp30_device::sample_start_l_r), FUNC(swp30_device::sample_start_l_w));
+ rchan(map, 0x14).rw(FUNC(swp30_device::sample_end_h_r), FUNC(swp30_device::sample_end_h_w));
+ rchan(map, 0x15).rw(FUNC(swp30_device::sample_end_l_r), FUNC(swp30_device::sample_end_l_w));
+ rchan(map, 0x16).rw(FUNC(swp30_device::sample_address_h_r), FUNC(swp30_device::sample_address_h_w));
+ rchan(map, 0x17).rw(FUNC(swp30_device::sample_address_l_r), FUNC(swp30_device::sample_address_l_w));
rchan(map, 0x20).rw(FUNC(swp30_device::eq_filter_r<0>), FUNC(swp30_device::eq_filter_w<0>));
rchan(map, 0x22).rw(FUNC(swp30_device::eq_filter_r<1>), FUNC(swp30_device::eq_filter_w<1>));
rchan(map, 0x24).rw(FUNC(swp30_device::eq_filter_r<2>), FUNC(swp30_device::eq_filter_w<2>));
@@ -358,32 +513,32 @@ void swp30_device::map(address_map &map)
rctrl(map, 0x0f).rw(FUNC(swp30_device::keyon_mask_r<0>), FUNC(swp30_device::keyon_mask_w<0>));
rctrl(map, 0x10).rw(FUNC(swp30_device::keyon_r), FUNC(swp30_device::keyon_w));
// 11-20 missing
- rctrl(map, 0x21).rw(FUNC(swp30_device::prg_address_r), FUNC(swp30_device::prg_address_w));
- rctrl(map, 0x22).rw(FUNC(swp30_device::prg_r<0>), FUNC(swp30_device::prg_w<0>));
- rctrl(map, 0x23).rw(FUNC(swp30_device::prg_r<1>), FUNC(swp30_device::prg_w<1>));
- rctrl(map, 0x24).rw(FUNC(swp30_device::prg_r<2>), FUNC(swp30_device::prg_w<2>));
- rctrl(map, 0x25).rw(FUNC(swp30_device::prg_r<3>), FUNC(swp30_device::prg_w<3>));
+ rctrl(map, 0x21).rw(FUNC(swp30_device::meg_prg_address_r), FUNC(swp30_device::meg_prg_address_w));
+ rctrl(map, 0x22).rw(FUNC(swp30_device::meg_prg_r<0>), FUNC(swp30_device::meg_prg_w<0>));
+ rctrl(map, 0x23).rw(FUNC(swp30_device::meg_prg_r<1>), FUNC(swp30_device::meg_prg_w<1>));
+ rctrl(map, 0x24).rw(FUNC(swp30_device::meg_prg_r<2>), FUNC(swp30_device::meg_prg_w<2>));
+ rctrl(map, 0x25).rw(FUNC(swp30_device::meg_prg_r<3>), FUNC(swp30_device::meg_prg_w<3>));
// 26-7f missing
- rctrl(map, 0x30).rw(FUNC(swp30_device::map_r<0>), FUNC(swp30_device::map_w<0>));
- rctrl(map, 0x32).rw(FUNC(swp30_device::map_r<1>), FUNC(swp30_device::map_w<1>));
- rctrl(map, 0x34).rw(FUNC(swp30_device::map_r<2>), FUNC(swp30_device::map_w<2>));
- rctrl(map, 0x36).rw(FUNC(swp30_device::map_r<3>), FUNC(swp30_device::map_w<3>));
- rctrl(map, 0x38).rw(FUNC(swp30_device::map_r<4>), FUNC(swp30_device::map_w<4>));
- rctrl(map, 0x3a).rw(FUNC(swp30_device::map_r<5>), FUNC(swp30_device::map_w<5>));
- rctrl(map, 0x3c).rw(FUNC(swp30_device::map_r<6>), FUNC(swp30_device::map_w<6>));
- rctrl(map, 0x3e).rw(FUNC(swp30_device::map_r<7>), FUNC(swp30_device::map_w<7>));
+ rctrl(map, 0x30).rw(FUNC(swp30_device::meg_map_r<0>), FUNC(swp30_device::meg_map_w<0>));
+ rctrl(map, 0x32).rw(FUNC(swp30_device::meg_map_r<1>), FUNC(swp30_device::meg_map_w<1>));
+ rctrl(map, 0x34).rw(FUNC(swp30_device::meg_map_r<2>), FUNC(swp30_device::meg_map_w<2>));
+ rctrl(map, 0x36).rw(FUNC(swp30_device::meg_map_r<3>), FUNC(swp30_device::meg_map_w<3>));
+ rctrl(map, 0x38).rw(FUNC(swp30_device::meg_map_r<4>), FUNC(swp30_device::meg_map_w<4>));
+ rctrl(map, 0x3a).rw(FUNC(swp30_device::meg_map_r<5>), FUNC(swp30_device::meg_map_w<5>));
+ rctrl(map, 0x3c).rw(FUNC(swp30_device::meg_map_r<6>), FUNC(swp30_device::meg_map_w<6>));
+ rctrl(map, 0x3e).rw(FUNC(swp30_device::meg_map_r<7>), FUNC(swp30_device::meg_map_w<7>));
// MEG registers
- rchan(map, 0x21).rw(FUNC(swp30_device::prg_fp_r<0>), FUNC(swp30_device::prg_fp_w<0>));
- rchan(map, 0x23).rw(FUNC(swp30_device::prg_fp_r<1>), FUNC(swp30_device::prg_fp_w<1>));
- rchan(map, 0x25).rw(FUNC(swp30_device::prg_fp_r<2>), FUNC(swp30_device::prg_fp_w<2>));
- rchan(map, 0x27).rw(FUNC(swp30_device::prg_fp_r<3>), FUNC(swp30_device::prg_fp_w<3>));
- rchan(map, 0x29).rw(FUNC(swp30_device::prg_fp_r<4>), FUNC(swp30_device::prg_fp_w<4>));
- rchan(map, 0x2b).rw(FUNC(swp30_device::prg_fp_r<5>), FUNC(swp30_device::prg_fp_w<5>));
- rchan(map, 0x30).rw(FUNC(swp30_device::prg_off_r<0>), FUNC(swp30_device::prg_off_w<0>));
- rchan(map, 0x31).rw(FUNC(swp30_device::prg_off_r<1>), FUNC(swp30_device::prg_off_w<1>));
- rchan(map, 0x3e).rw(FUNC(swp30_device::prg_lfo_r<0>), FUNC(swp30_device::prg_lfo_w<0>));
- rchan(map, 0x3f).rw(FUNC(swp30_device::prg_lfo_r<1>), FUNC(swp30_device::prg_lfo_w<1>));
+ rchan(map, 0x21).rw(FUNC(swp30_device::meg_const_r<0>), FUNC(swp30_device::meg_const_w<0>));
+ rchan(map, 0x23).rw(FUNC(swp30_device::meg_const_r<1>), FUNC(swp30_device::meg_const_w<1>));
+ rchan(map, 0x25).rw(FUNC(swp30_device::meg_const_r<2>), FUNC(swp30_device::meg_const_w<2>));
+ rchan(map, 0x27).rw(FUNC(swp30_device::meg_const_r<3>), FUNC(swp30_device::meg_const_w<3>));
+ rchan(map, 0x29).rw(FUNC(swp30_device::meg_const_r<4>), FUNC(swp30_device::meg_const_w<4>));
+ rchan(map, 0x2b).rw(FUNC(swp30_device::meg_const_r<5>), FUNC(swp30_device::meg_const_w<5>));
+ rchan(map, 0x30).rw(FUNC(swp30_device::meg_offset_r<0>), FUNC(swp30_device::meg_offset_w<0>));
+ rchan(map, 0x31).rw(FUNC(swp30_device::meg_offset_r<1>), FUNC(swp30_device::meg_offset_w<1>));
+ rchan(map, 0x3e).rw(FUNC(swp30_device::meg_lfo_r<0>), FUNC(swp30_device::meg_lfo_w<0>));
+ rchan(map, 0x3f).rw(FUNC(swp30_device::meg_lfo_r<1>), FUNC(swp30_device::meg_lfo_w<1>));
}
// Control registers
@@ -404,63 +559,80 @@ u16 swp30_device::keyon_r()
void swp30_device::keyon_w(u16)
{
- for(int i=0; i<64; i++) {
- u64 mask = u64(1) << i;
+ for(int chan=0; chan<64; chan++) {
+ u64 mask = u64(1) << chan;
if(m_keyon_mask & mask) {
- m_sample_pos[i] = -s32(m_pre_size[i] << 8);
- m_current_volume[i] = (m_base_volume[i] & 0xff) << (26-8);
- change_mode(i, m_base_volume[i] & 0x8000 ? RELEASE : m_attack[i] & 0x80 ? DECAY : ATTACK);
+ m_sample_pos[chan] = -(m_sample_start[chan] & 0xffffff) << 8;
+ if(m_release_glo[chan] & 0x8000) {
+ m_envelope_level[chan] = 0;
+ m_envelope_on_timer[chan] = false;
+ m_envelope_mode[chan] = RELEASE;
+ } else if(m_attack[chan] & 0x80) {
+ m_envelope_level[chan] = 0x8000000;
+ m_envelope_on_timer[chan] = false;
+ m_envelope_mode[chan] = ATTACK;
+ } else {
+ m_envelope_level[chan] = 0;
+ m_envelope_on_timer[chan] = true;
+ m_envelope_timer[chan] = 0x8000000;
+ m_envelope_mode[chan] = ATTACK;
+ }
+
+ m_decay2_done[chan] = false;
+ m_glo_level_cur[chan] = (m_release_glo[chan] & 0xff) << 4;
+ m_pan_l[chan] = (m_pan[chan] & 0xff00) >> 4;
+ m_pan_r[chan] = (m_pan[chan] & 0x00ff) << 4;
if(1)
- logerror("[%08d] keyon %02x %08x %08x %08x vol %04x env %04x %04x %04x pan %04x disp %04x %04x\n", scount, i, m_pre_size[i], m_post_size[i], m_address[i], m_base_volume[i], m_attack[i], m_decay[i], m_release[i], m_pan[i], m_dry_rev[i], m_cho_var[i]);
+ logerror("[%08d] keyon %02x %08x %08x %08x vol %04x env %04x %04x %04x pan %04x disp %04x %04x\n", scount, chan, m_sample_start[chan], m_sample_end[chan], m_sample_address[chan], m_release_glo[chan], m_attack[chan], m_decay1[chan], m_decay2[chan], m_pan[chan], m_dry_rev[chan], m_cho_var[chan]);
}
}
m_keyon_mask = 0;
}
-u16 swp30_device::prg_address_r()
+u16 swp30_device::meg_prg_address_r()
{
- return m_program_address;
+ return m_meg_program_address;
}
-void swp30_device::prg_address_w(u16 data)
+void swp30_device::meg_prg_address_w(u16 data)
{
- m_program_address = data;
- if(m_program_address >= 0x180)
- m_program_address = 0;
+ m_meg_program_address = data;
+ if(m_meg_program_address >= 0x180)
+ m_meg_program_address = 0;
}
-template<int sel> u16 swp30_device::prg_r()
+template<int sel> u16 swp30_device::meg_prg_r()
{
constexpr offs_t shift = 48-16*sel;
- return m_meg->prg_r(m_program_address) >> shift;
+ return m_meg_program[m_meg_program_address] >> shift;
}
-template<int sel> void swp30_device::prg_w(u16 data)
+template<int sel> void swp30_device::meg_prg_w(u16 data)
{
constexpr offs_t shift = 48-16*sel;
constexpr u64 mask = ~(u64(0xffff) << shift);
- m_meg->prg_w(m_program_address, (m_meg->prg_r(m_program_address) & mask) | (u64(data) << shift));
+ m_meg_program[m_meg_program_address] = (m_meg_program[m_meg_program_address] & mask) | (u64(data) << shift);
if(sel == 3) {
if(0)
- logerror("program %03x %016x\n", m_program_address, m_program[m_program_address]);
- m_program_address ++;
- if(m_program_address == 0x180)
- m_program_address = 0;
+ logerror("program %03x %016x\n", m_meg_program_address, m_meg_program[m_meg_program_address]);
+ m_meg_program_address ++;
+ if(m_meg_program_address == 0x180)
+ m_meg_program_address = 0;
}
}
-template<int sel> u16 swp30_device::map_r()
+template<int sel> u16 swp30_device::meg_map_r()
{
- return m_meg->map_r(sel);
+ return m_meg_map[sel];
}
-template<int sel> void swp30_device::map_w(u16 data)
+template<int sel> void swp30_device::meg_map_w(u16 data)
{
- m_meg->map_w(sel, data);
+ m_meg_map[sel] = data;
}
@@ -494,7 +666,7 @@ void swp30_device::waverom_access_w(u16 data)
{
m_waverom_access = data;
if(data == 0x8000) {
- m_waverom_val = read_dword(m_waverom_adr << 2);
+ m_waverom_val = m_rom_cache.read_dword(m_waverom_adr);
logerror("waverom read adr=%08x mode=%08x -> %08x\n", m_waverom_adr, m_waverom_mode, m_waverom_val);
}
}
@@ -589,19 +761,21 @@ template<int sel> void swp30_device::routing_w(offs_t offset, u16 data)
m_routing[offset >> 6][sel] = data;
}
-u16 swp30_device::base_volume_r(offs_t offset)
+u16 swp30_device::release_glo_r(offs_t offset)
{
- return m_base_volume[offset >> 6];
+ return m_release_glo[offset >> 6];
}
-void swp30_device::base_volume_w(offs_t offset, u16 data)
+void swp30_device::release_glo_w(offs_t offset, u16 data)
{
u8 chan = offset >> 6;
- if(1 && m_base_volume[chan] != data)
- logerror("snd chan %02x volume %02x %02x\n", chan, data >> 8, data & 0xff);
- m_base_volume[chan] = data;
- if((data & 0x8000) && m_mode[chan] != IDLE && m_mode[chan] != RELEASE)
- change_mode(chan, RELEASE);
+ if(1 && m_release_glo[chan] != data)
+ logerror("snd chan %02x rel/glo %02x %02x\n", chan, data >> 8, data & 0xff);
+ m_release_glo[chan] = data;
+ if(data == 0xea13)
+ machine().debug_break();
+ if((data & 0x8000) && m_envelope_mode[chan] != IDLE && m_envelope_mode[chan] != RELEASE)
+ m_envelope_mode[chan] = RELEASE;
}
@@ -644,19 +818,19 @@ void swp30_device::cho_var_w(offs_t offset, u16 data)
m_cho_var[chan] = data;
}
-u16 swp30_device::freq_r(offs_t offset)
+u16 swp30_device::pitch_r(offs_t offset)
{
- return m_freq[offset >> 6];
+ return m_pitch[offset >> 6];
}
-void swp30_device::freq_w(offs_t offset, u16 data)
+void swp30_device::pitch_w(offs_t offset, u16 data)
{
u8 chan = offset >> 6;
// delta is 4*256 per octave, positive means higher freq, e.g 4.10 format.
s16 v = data & 0x2000 ? data | 0xc000 : data;
- if(0 && m_freq[chan] != data)
- logerror("snd chan %02x freq %c%c %d.%03x\n", chan, data & 0x8000 ? '#' : '.', data & 0x4000 ? '#' : '.', v / 1024, (v < 0 ? -v : v) & 0x3ff);
- m_freq[chan] = data;
+ if(0 && m_pitch[chan] != data)
+ logerror("snd chan %02x pitch %c%c %d.%03x\n", chan, data & 0x8000 ? '#' : '.', data & 0x4000 ? '#' : '.', v / 1024, (v < 0 ? -v : v) & 0x3ff);
+ m_pitch[chan] = data;
}
u16 swp30_device::attack_r(offs_t offset)
@@ -666,100 +840,102 @@ u16 swp30_device::attack_r(offs_t offset)
void swp30_device::attack_w(offs_t offset, u16 data)
{
+ if(data != m_attack[offset >> 6])
+ logerror("attack[%02x] = %04x\n", offset >> 6, data);
m_attack[offset >> 6] = data;
}
-u16 swp30_device::decay_r(offs_t offset)
+u16 swp30_device::decay1_r(offs_t offset)
{
- return m_decay[offset >> 6];
+ return m_decay1[offset >> 6];
}
-void swp30_device::decay_w(offs_t offset, u16 data)
+void swp30_device::decay1_w(offs_t offset, u16 data)
{
- m_decay[offset >> 6] = data;
+ logerror("decay1[%02x] = %04x\n", offset >> 6, data);
+ m_decay1[offset >> 6] = data;
}
-u16 swp30_device::release_r(offs_t offset)
+u16 swp30_device::decay2_r(offs_t offset)
{
- return m_release[offset >> 6];
+ return m_decay2[offset >> 6];
}
-void swp30_device::release_w(offs_t offset, u16 data)
+void swp30_device::decay2_w(offs_t offset, u16 data)
{
- m_release[offset >> 6] = data;
+ logerror("decay2[%02x] = %04x\n", offset >> 6, data);
+ m_decay2[offset >> 6] = data;
}
-u16 swp30_device::pre_size_h_r(offs_t offset)
+u16 swp30_device::sample_start_h_r(offs_t offset)
{
- return m_pre_size[offset >> 6] >> 16;
+ return m_sample_start[offset >> 6] >> 16;
}
-u16 swp30_device::pre_size_l_r(offs_t offset)
+u16 swp30_device::sample_start_l_r(offs_t offset)
{
- return m_pre_size[offset >> 6];
+ return m_sample_start[offset >> 6];
}
-void swp30_device::pre_size_h_w(offs_t offset, u16 data)
+void swp30_device::sample_start_h_w(offs_t offset, u16 data)
{
u8 chan = offset >> 6;
- m_pre_size[chan] = (m_pre_size[chan] & 0x0000ffff) | (data << 16);
+ m_sample_start[chan] = (m_sample_start[chan] & 0x0000ffff) | (data << 16);
}
-void swp30_device::pre_size_l_w(offs_t offset, u16 data)
+void swp30_device::sample_start_l_w(offs_t offset, u16 data)
{
u8 chan = offset >> 6;
- m_pre_size[chan] = (m_pre_size[chan] & 0xffff0000) | data;
- if(0)
- logerror("snd chan %02x pre-size %02x %06x\n", chan, m_pre_size[chan] >> 24, m_pre_size[chan] & 0xffffff);
+ m_sample_start[chan] = (m_sample_start[chan] & 0xffff0000) | data;
}
-u16 swp30_device::post_size_h_r(offs_t offset)
+u16 swp30_device::sample_end_h_r(offs_t offset)
{
- return m_post_size[offset >> 6] >> 16;
+ return m_sample_end[offset >> 6] >> 16;
}
-u16 swp30_device::post_size_l_r(offs_t offset)
+u16 swp30_device::sample_end_l_r(offs_t offset)
{
- return m_post_size[offset >> 6];
+ return m_sample_end[offset >> 6];
}
-void swp30_device::post_size_h_w(offs_t offset, u16 data)
+void swp30_device::sample_end_h_w(offs_t offset, u16 data)
{
u8 chan = offset >> 6;
- m_post_size[chan] = (m_post_size[chan] & 0x0000ffff) | (data << 16);
+ m_sample_end[chan] = (m_sample_end[chan] & 0x0000ffff) | (data << 16);
}
-void swp30_device::post_size_l_w(offs_t offset, u16 data)
+void swp30_device::sample_end_l_w(offs_t offset, u16 data)
{
u8 chan = offset >> 6;
- m_post_size[chan] = (m_post_size[chan] & 0xffff0000) | data;
+ m_sample_end[chan] = (m_sample_end[chan] & 0xffff0000) | data;
if(0)
- logerror("snd chan %02x post-size %02x %06x\n", chan, m_post_size[chan] >> 24, m_post_size[chan] & 0xffffff);
+ logerror("snd chan %02x post-size %02x %06x\n", chan, m_sample_end[chan] >> 24, m_sample_end[chan] & 0xffffff);
}
-u16 swp30_device::address_h_r(offs_t offset)
+u16 swp30_device::sample_address_h_r(offs_t offset)
{
- return m_address[offset >> 6] >> 16;
+ return m_sample_address[offset >> 6] >> 16;
}
-u16 swp30_device::address_l_r(offs_t offset)
+u16 swp30_device::sample_address_l_r(offs_t offset)
{
- return m_address[offset >> 6];
+ return m_sample_address[offset >> 6];
}
-void swp30_device::address_h_w(offs_t offset, u16 data)
+void swp30_device::sample_address_h_w(offs_t offset, u16 data)
{
u8 chan = offset >> 6;
- m_address[chan] = (m_address[chan] & 0x0000ffff) | (data << 16);
+ m_sample_address[chan] = (m_sample_address[chan] & 0x0000ffff) | (data << 16);
}
-void swp30_device::address_l_w(offs_t offset, u16 data)
+void swp30_device::sample_address_l_w(offs_t offset, u16 data)
{
u8 chan = offset >> 6;
static const char *const formats[4] = { "l16", "l12", "l8", "x8" };
- m_address[chan] = (m_address[chan] & 0xffff0000) | data;
+ m_sample_address[chan] = (m_sample_address[chan] & 0xffff0000) | data;
if(0)
- logerror("snd chan %02x format %s flags %02x address %06x\n", chan, formats[m_address[chan] >> 30], (m_address[chan] >> 24) & 0x3f, m_address[chan] & 0xffffff);
+ logerror("snd chan %02x format %s flags %02x address %06x\n", chan, formats[m_sample_address[chan] >> 30], (m_sample_address[chan] >> 24) & 0x3f, m_sample_address[chan] & 0xffffff);
}
u16 swp30_device::internal_adr_r()
@@ -777,19 +953,16 @@ u16 swp30_device::internal_r()
u8 chan = m_internal_adr & 0x3f;
switch(m_internal_adr >> 8) {
case 0:
- return m_mode[chan] == IDLE ? 0xffff : m_current_volume[chan] >> (26-14);
+ return m_envelope_mode[chan] == IDLE ? 0xffff : ((m_envelope_mode[chan] - 1) << 14) | (m_envelope_level[chan] >> (26-14));
case 4:
// used at 44c4
// tests & 0x4000 only
// logerror("read %02x.4\n", chan);
- return 0xffff;
+ return 0x0000;
case 6:
- // used at 3e7c
- // tests & 0x8000 only, keyoff?
- logerror("read %02x.6\n", chan);
- return 0x0000;
+ return m_decay2_done[chan] ? 0x0000 : 0x8000;
}
logerror("%s internal_r port %x channel %02x sample %d\n", machine().time().to_string(), m_internal_adr >> 8, m_internal_adr & 0x1f, scount);
@@ -801,34 +974,42 @@ u16 swp30_device::internal_r()
// MEG registers forwarding
-template<int sel> u16 swp30_device::prg_fp_r(offs_t offset)
+template<int sel> u16 swp30_device::meg_const_r(offs_t offset)
{
- return m_meg->fp_r((offset >> 6)*6 + sel);
+ return m_meg_const[(offset >> 6)*6 + sel];
}
-template<int sel> void swp30_device::prg_fp_w(offs_t offset, u16 data)
+template<int sel> void swp30_device::meg_const_w(offs_t offset, u16 data)
{
- m_meg->fp_w((offset >> 6)*6 + sel, data);
+ m_meg_const[(offset >> 6)*6 + sel] = data;
}
-template<int sel> u16 swp30_device::prg_off_r(offs_t offset)
+template<int sel> u16 swp30_device::meg_offset_r(offs_t offset)
{
- return m_meg->offset_r((offset >> 6)*2 + sel);
+ return m_meg_offset[(offset >> 6)*2 + sel];
}
-template<int sel> void swp30_device::prg_off_w(offs_t offset, u16 data)
+template<int sel> void swp30_device::meg_offset_w(offs_t offset, u16 data)
{
- m_meg->offset_w((offset >> 6)*2 + sel, data);
+ m_meg_offset[(offset >> 6)*2 + sel] = data;
}
-template<int sel> u16 swp30_device::prg_lfo_r(offs_t offset)
+template<int sel> u16 swp30_device::meg_lfo_r(offs_t offset)
{
- return m_meg->lfo_r((offset >> 6)*2 + sel);
+ return m_meg_lfo[(offset >> 6)*2 + sel];
}
-template<int sel> void swp30_device::prg_lfo_w(offs_t offset, u16 data)
+template<int sel> void swp30_device::meg_lfo_w(offs_t offset, u16 data)
{
- m_meg->lfo_w((offset >> 6)*2 + sel, data);
+ int slot = (offset >> 6)*2 + sel;
+ m_meg_lfo[slot] = data;
+
+ static const int dt[8] = { 0, 32, 64, 128, 256, 512, 1024, 2048 };
+ static const int sh[8] = { 0, 0, 1, 2, 3, 4, 5, 6 };
+
+ int scale = (data >> 5) & 7;
+ int step = ((data & 31) << sh[scale]) + dt[scale];
+ logerror("lfo_w %02x %04x freq=%5.2f phase=%6.4f\n", slot, m_meg_lfo[slot], step * 44100.0/4194304, (data >> 8)/256.0);
}
@@ -883,10 +1064,12 @@ void swp30_device::snd_w(offs_t offset, u16 data)
preg = util::string_format("sy%02x", (slot-0x0e) + 2*chan);
else if(slot == 0x30 || slot == 0x31)
preg = util::string_format("dt%02x", (slot-0x30) + 2*chan);
- else if(slot == 0x38)
- preg = util::string_format("vl%02x", chan);
+ else if(slot >= 0x38 && slot <= 0x3a)
+ preg = util::string_format("mix[%x, %02x]", slot - 0x38, chan);
+ else if(slot >= 0x3b && slot <= 0x3d)
+ preg = util::string_format("route[%x, %02x]", slot - 0x3b, chan);
else if(slot == 0x3e || slot == 0x3f)
- preg = util::string_format("lf%02x", (slot-0x3e) + 2*chan);
+ preg = util::string_format("lfo[%02x]", (slot-0x3e) + 2*chan);
else
preg = util::string_format("%02x.%02x", chan, slot);
// if((slot >= 0xa && slot <= 0xd) || (slot >= 0x2c && slot <= 0x2f))
@@ -899,39 +1082,6 @@ void swp30_device::snd_w(offs_t offset, u16 data)
// Synthesis
-void swp30_device::change_mode(int channel, u8 mode)
-{
- if(1)
- logerror("[%08d] channel %02x mode %s\n", scount, channel,
- mode == IDLE ? "idle" :
- mode == ATTACK ? "attack" :
- mode == DECAY ? "decay" :
- mode == SUSTAIN ? "sustain" :
- mode == RELEASE ? "release" :
- "?");
-
- m_mode[channel] = mode;
- if(mode == IDLE || mode == SUSTAIN) {
- m_step_volume[channel] = 0;
- return;
- }
-
- u16 reg = mode == ATTACK ? m_attack[channel] & 0xff00 : mode == DECAY ? m_decay[channel] : m_release[channel];
- u32 target = (reg & 0xff) << (26-8);
- s32 step = (8 + ((reg >> 8) & 7)) << ((reg >> 11) & 15);
- if(mode != ATTACK)
- step *= 8;
- if(target < m_current_volume[channel])
- step = -step;
- m_target_volume[channel] = target;
- m_step_volume[channel] = step;
-
- if(1) {
- double delay = (double(target) - double(m_current_volume[channel])) / (44100*step);
- logerror(" -> time until hit %f seconds\n", delay);
- }
-}
-
void swp30_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
if(outputs[0].samples() != 1)
@@ -939,154 +1089,344 @@ void swp30_device::sound_stream_update(sound_stream &stream, std::vector<read_st
scount++;
- // Accumulate on 64 bits, shift/clamp at the end
- s64 dry_left = 0, dry_right = 0;
+ s32 dry_l = 0, dry_r = 0;
// Loop on channels
- for(int channel = 0; channel < 64; channel++)
- if(m_mode[channel] != IDLE) {
- // First, read the sample
-
- // - Find the base sample index and base address
- s32 spos = m_sample_pos[channel] >> 8;
- offs_t base_address = (m_address[channel] & 0x1ffffff) << 2;
- // - Read/decompress the sample
- s16 samp = 0;
- switch(m_address[channel] >> 30) {
- case 0: { // 16-bits linear
- offs_t adr = base_address + (spos << 1);
- samp = read_word(adr);
+ for(int chan = 0; chan < 64; chan++) {
+ if(m_envelope_mode[chan] == IDLE)
+ continue;
+ // First, read the sample
+
+ // - Find the base sample index and base address
+ s32 sample_pos = m_sample_pos[chan];
+ if(m_sample_end[chan] & 0x80000000)
+ sample_pos = -sample_pos;
+
+ s32 spos = sample_pos >> 8;
+ offs_t base_address = m_sample_address[chan] & 0x1ffffff;
+
+ // - Read/decompress the sample
+ s16 val0, val1;
+ switch(m_sample_address[chan] >> 30) {
+ case 0: { // 16-bits linear
+ offs_t adr = base_address + (spos >> 1);
+ switch(spos & 1) {
+ case 0: { // ABCDabcd ........
+ u32 l0 = m_rom_cache.read_dword(adr);
+ val0 = l0;
+ val1 = l0 >> 16;
break;
}
+ case 1: { // abcd.... ....ABCD
+ u32 l0 = m_rom_cache.read_dword(adr);
+ u32 l1 = m_rom_cache.read_dword(adr+1);
+ val0 = l0 >> 16;
+ val1 = l1;
+ break;
+ }
+ }
+ break;
+ }
- case 1: { // 12-bits linear
- offs_t adr = base_address + (spos >> 2)*6;
- switch(spos & 3) {
- case 0: { // .abc .... ....
- u16 w0 = read_word(adr);
- samp = (w0 & 0x0fff) << 4;
- break;
- }
- case 1: { // C... ..AB ....
- u16 w0 = read_word(adr);
- u16 w1 = read_word(adr+2);
- samp = ((w0 & 0xf000) >> 8) | ((w1 & 0x00ff) << 8);
- break;
- }
- case 2: { // .... bc.. ...a
- u16 w0 = read_word(adr+2);
- u16 w1 = read_word(adr+4);
- samp = ((w0 & 0xff00) >> 4) | ((w1 & 0x000f) << 12);
- break;
- }
- case 3: { // .... .... ABC.
- u16 w1 = read_word(adr+4);
- samp = w1 & 0xfff0;
- break;
- }
- }
+ case 1: { // 12-bits linear
+ offs_t adr = base_address + (spos >> 3)*3;
+ switch(spos & 7) {
+ case 0: { // ..ABCabc ........ ........ ........
+ u32 l0 = m_rom_cache.read_dword(adr);
+ val0 = (l0 & 0x00000fff) << 4;
+ val1 = (l0 & 0x00fff000) >> 8;
+ break;
+ }
+ case 1: { // BCabc... .......A ........ ........
+ u32 l0 = m_rom_cache.read_dword(adr);
+ u32 l1 = m_rom_cache.read_dword(adr+1);
+ val0 = (l0 & 0x00fff000) >> 8;
+ val1 = ((l0 & 0xff000000) >> 20) | ((l1 & 0x0000000f) << 12);
+ break;
+ }
+ case 2: { // bc...... ....ABCa ........ ........
+ u32 l0 = m_rom_cache.read_dword(adr);
+ u32 l1 = m_rom_cache.read_dword(adr+1);
+ val0 = ((l0 & 0xff000000) >> 20) | ((l1 & 0x0000000f) << 12);
+ val1 = l1 & 0x0000fff0;
+ break;
+ }
+ case 3: { // ........ .ABCabc. ........ ........
+ u32 l1 = m_rom_cache.read_dword(adr+1);
+ val0 = l1 & 0x0000fff0;
+ val1 = (l1 & 0x0fff0000) >> 12;
break;
}
+ case 4: { // ........ Cabc.... ......AB ........
+ u32 l1 = m_rom_cache.read_dword(adr+1);
+ u32 l2 = m_rom_cache.read_dword(adr+2);
+ val0 = (l1 & 0x0fff0000) >> 12;
+ val1 = ((l1 & 0xf0000000) >> 24) | ((l2 & 0x000000ff) << 8);
+ break;
+ }
+ case 5: { // ........ c....... ...ABCab ........
+ u32 l1 = m_rom_cache.read_dword(adr+1);
+ u32 l2 = m_rom_cache.read_dword(adr+2);
+ val0 = ((l1 & 0xf0000000) >> 24) | ((l2 & 0x000000ff) << 8);
+ val1 = (l2 & 0x000fff00) >> 4;
+ break;
+ }
+ case 6: { // ........ ........ ABCabc.. ........
+ u32 l2 = m_rom_cache.read_dword(adr+2);
+ val0 = (l2 & 0x000fff00) >> 4;
+ val1 = (l2 & 0xfff00000) >> 16;
+ break;
+ }
+ case 7: { // ........ ........ abc..... .....ABC
+ u32 l2 = m_rom_cache.read_dword(adr+2);
+ u32 l3 = m_rom_cache.read_dword(adr+3);
+ val0 = (l2 & 0xfff00000) >> 16;
+ val1 = (l3 & 0x00000fff) << 4;
+ break;
+ }
+ }
+ break;
+ }
- case 2: // 8-bits linear
- samp = read_byte(base_address + spos) << 8;
+ case 2: { // 8-bits linear
+ offs_t adr = base_address + (spos >> 2);
+ switch(spos & 3) {
+ case 0: { // ....ABab ........
+ u32 l0 = m_rom_cache.read_dword(adr);
+ val0 = (l0 & 0x000000ff) << 8;
+ val1 = l0 & 0x0000ff00;
break;
+ }
+ case 1: { // ..ABab.. ........
+ u32 l0 = m_rom_cache.read_dword(adr);
+ val0 = l0 & 0x0000ff00;
+ val1 = (l0 & 0x00ff0000) >> 8;
+ break;
+ }
+ case 2: { // ABab.... ........
+ u32 l0 = m_rom_cache.read_dword(adr);
+ val0 = (l0 & 0x00ff0000) >> 8;
+ val1 = (l0 & 0xff000000) >> 16;
+ break;
+ }
+ case 3: { // ab...... ......AB
+ u32 l0 = m_rom_cache.read_dword(adr);
+ u32 l1 = m_rom_cache.read_dword(adr+1);
+ val0 = (l0 & 0xff000000) >> 16;
+ val1 = (l1 & 0x000000ff) << 8;
+ break;
+ }
+ }
+ break;
+ }
- case 3: // 8-bits logarithmic
- samp = m_sample_log8[read_byte(base_address + spos)];
+ case 3: { // 8-bits dpcm
+ offs_t adr = base_address + (spos >> 2);
+ switch(spos & 3) {
+ case 0: { // ....ABab ........
+ u32 l0 = m_rom_cache.read_dword(adr);
+ val0 = m_sample_log8[(l0 & 0x000000ff) ];
+ val1 = m_sample_log8[(l0 & 0x0000ff00) >> 8];
break;
}
+ case 1: { // ..ABab.. ........
+ u32 l0 = m_rom_cache.read_dword(adr);
+ val0 = m_sample_log8[(l0 & 0x0000ff00) >> 8];
+ val1 = m_sample_log8[(l0 & 0x00ff0000) >> 16];
+ break;
+ }
+ case 2: { // ABab.... ........
+ u32 l0 = m_rom_cache.read_dword(adr);
+ val0 = m_sample_log8[(l0 & 0x00ff0000) >> 16];
+ val1 = m_sample_log8[(l0 & 0xff000000) >> 24];
+ break;
+ }
+ case 3: { // ab...... ......AB
+ u32 l0 = m_rom_cache.read_dword(adr);
+ u32 l1 = m_rom_cache.read_dword(adr+1);
+ val0 = m_sample_log8[(l0 & 0xff000000) >> 24];
+ val1 = m_sample_log8[ l1 & 0x000000ff];
+ break;
+ }
+ }
+ break;
+ }
+ }
- //logerror("sample %02x %06x [%d] %+5d %04x %04x %04x\n", channel, base_address >> 2, m_address[channel] >> 30, spos, samp & 0xffff, m_volume[channel], m_pan[channel]);
-
- // Second, step the sample pos, loop/deactivate as needed
- m_sample_pos[channel] += m_sample_increment[m_freq[channel] & 0x3fff];
- s32 loop_size = (m_post_size[channel] << 8) | ((m_address[channel] >> 22) & 0xf8);
- if(m_sample_pos[channel] >= loop_size) {
- // We reached the loop point, stop if loop size is zero,
- // otherwise loop
- if(!loop_size)
- change_mode(channel, IDLE);
- else
- do
- m_sample_pos[channel] -= loop_size;
- while(m_sample_pos[channel] >= loop_size);
+ s32 mul = sample_pos & 0xff;
+ s32 sample = val1 * mul + val0 * (0x100 - mul);
+
+#if 0
+ // Third, filter the sample
+ // - missing lpf_cutoff, lpf_reso, hpf_cutoff
+
+ // - eq lowpass
+ s32 samp1 = (samp * m_eq_filter[chan][2] + m_sample_history[chan][0][0] * m_eq_filter[chan][1] + m_sample_history[chan][0][1] * m_eq_filter[chan][0]) >> 13;
+ m_sample_history[chan][0][1] = m_sample_history[chan][0][0];
+ m_sample_history[chan][0][0] = samp;
+
+ // - eq highpass
+ s32 samp2 = (samp1 * m_eq_filter[chan][5] + m_sample_history[chan][1][0] * m_eq_filter[chan][4] + m_sample_history[chan][1][1] * m_eq_filter[chan][3]) >> 13;
+ m_sample_history[chan][1][1] = m_sample_history[chan][1][0];
+ m_sample_history[chan][1][0] = samp1;
+
+#endif
+
+#if 1
+ s32 tremolo_level = 0;
+ dry_l += fpapply(m_envelope_level[chan] + (m_glo_level_cur[chan] << 16) + tremolo_level + ((m_dry_rev[chan] & 0xff00) << 12) + (m_pan_l[chan] << 16), sample);
+ dry_r += fpapply(m_envelope_level[chan] + (m_glo_level_cur[chan] << 16) + tremolo_level + ((m_dry_rev[chan] & 0xff00) << 12) + (m_pan_r[chan] << 16), sample);
+ // logerror("%x %x %x %x - %x %x\n", m_envelope_level[chan], (m_glo_level_cur[chan] << 16), ((m_dry_rev[chan] & 0xff00) << 12), (m_pan_l[chan] << 16), sample, dry_l);
+
+ // logerror("env %08x %d\n", m_envelope_level[chan], m_envelope_level[chan]);
+
+#else
+ dry_l += sample;
+ dry_r += sample;
+#endif
+
+ istep(m_glo_level_cur[chan], (m_release_glo[chan] & 0x00ff) << 4, 1);
+ istep(m_pan_l[chan], (m_pan[chan] & 0xff00) >> 4, 1);
+ istep(m_pan_r[chan], (m_pan[chan] & 0x00ff) << 4, 1);
+
+ u32 sample_increment = (((m_pitch[chan] & 0x3ff) | 0x400) << (8 + (s16(m_pitch[chan] << 2) >> 12))) >> 10;
+ m_sample_pos[chan] += sample_increment; //(sample_increment * (0x800 + ((lfo_p_phase * m_lfo_pmod_depth[chan]) >> (m_lfo_step[chan] & 0x40 ? 18 : 19)))) >> 11;
+ if((m_sample_pos[chan] >> 8) >= (m_sample_end[chan] & 0xffffff)) {
+ if(!(m_sample_end[chan] & 0xffffff))
+ m_envelope_mode[chan] = IDLE;
+ else {
+ do
+ m_sample_pos[chan] = m_sample_pos[chan] - ((m_sample_end[chan] & 0xffffff) << 8) + ((m_sample_address[chan] >> 22) & 0xfc);
+ while((m_sample_pos[chan] >> 8) >= (m_sample_end[chan] & 0xffffff));
}
+ }
- // Third, filter the sample
- // - missing lpf_cutoff, lpf_reso, hpf_cutoff
-
- // - eq lowpass
- s32 samp1 = (samp * m_eq_filter[channel][2] + m_sample_history[channel][0][0] * m_eq_filter[channel][1] + m_sample_history[channel][0][1] * m_eq_filter[channel][0]) >> 13;
- m_sample_history[channel][0][1] = m_sample_history[channel][0][0];
- m_sample_history[channel][0][0] = samp;
-
- // - eq highpass
- s32 samp2 = (samp1 * m_eq_filter[channel][5] + m_sample_history[channel][1][0] * m_eq_filter[channel][4] + m_sample_history[channel][1][1] * m_eq_filter[channel][3]) >> 13;
- m_sample_history[channel][1][1] = m_sample_history[channel][1][0];
- m_sample_history[channel][1][0] = samp1;
-
- // Fourth, establish the 8 volumes (only 2 for now, need the MEG) and update the envelope
- u32 raw_vol = m_current_volume[channel];
- u32 vol = raw_vol >> (26-8);
-
- u32 base_l = vol + (m_pan[channel] >> 8);
- u32 base_r = vol + (m_pan[channel] & 0xff);
-
- u32 dry_l = base_l + (m_dry_rev[channel] >> 8);
- u32 dry_r = base_r + (m_dry_rev[channel] >> 8);
-
- s32 step = m_step_volume[channel];
- u32 target = m_target_volume[channel];
-
- if(0) {
- u8 mode = m_mode[channel];
- logerror("[%08d] channel %02x state %s vol=%07x step=%c%07x target=%07x\n",
- scount,
- channel,
- mode == IDLE ? "idle" :
- mode == ATTACK ? "attack" :
- mode == DECAY ? "decay" :
- mode == SUSTAIN ? "sustain" :
- mode == RELEASE ? "release" :
- "?",
- raw_vol,
- step < 0 ? '-' : '+',
- step < 0 ? -step : step,
- target);
+ switch(m_envelope_mode[chan]) {
+ case ATTACK:
+ if(m_envelope_on_timer[chan]) {
+ if(istep(m_envelope_timer[chan], 0, m_global_step[(m_attack[chan] >> 8) & 0x7f] << 1))
+ change_mode_attack_decay1(chan);
+ } else {
+ if(fpstep(m_envelope_level[chan], 0, attack_linear_step[(m_attack[chan] >> 8) & 0x7f]))
+ change_mode_attack_decay1(chan);
}
- if(step) {
- raw_vol += step;
- if((step < 0 && (raw_vol <= target || raw_vol & 0x80000000)) ||
- (step > 0 && raw_vol >= target)) {
- raw_vol = target;
- m_current_volume[channel] = raw_vol;
-
- // IDLE and SUSTAIN have zero step.
- // current volume must be updated before calling change_mode
-
- switch(m_mode[channel]) {
- case ATTACK: change_mode(channel, DECAY); break;
- case DECAY: change_mode(channel, SUSTAIN); break;
- case RELEASE: change_mode(channel, IDLE); break;
- }
- } else
- m_current_volume[channel] = raw_vol;
+ break;
+
+ case DECAY1:
+ if(m_envelope_on_timer[chan]) {
+ if(istep(m_envelope_timer[chan], 0, m_global_step[(m_decay1[chan] >> 8) & 0x7f] << 1))
+ change_mode_decay1_decay2(chan);
+ } else if((m_decay1[chan] & 0x6000) == 0x6000) {
+ if(fpstep(m_envelope_level[chan], (m_decay1[chan] & 0xff) << 20, decay_linear_step[(m_decay1[chan] >> 8) & 0x1f]))
+ change_mode_decay1_decay2(chan);
+ } else {
+ if(fpstep(m_envelope_level[chan], (m_decay1[chan] & 0xff) << 20, m_global_step[(m_decay1[chan] >> 8) & 0x7f]))
+ change_mode_decay1_decay2(chan);
}
+ break;
+
+ case DECAY2:
+ if(m_envelope_on_timer[chan])
+ m_decay2_done[chan] = istep(m_envelope_timer[chan], 0, m_global_step[(m_decay1[chan] >> 8) & 0x7f] << 1);
+ else if((m_decay2[chan] & 0x6000) == 0x6000)
+ m_decay2_done[chan] = fpstep(m_envelope_level[chan], (m_decay2[chan] & 0xff) << 20, decay_linear_step[(m_decay2[chan] >> 8) & 0x1f]);
+ else
+ m_decay2_done[chan] = fpstep(m_envelope_level[chan], (m_decay2[chan] & 0xff) << 20, m_global_step[(m_decay2[chan] >> 8) & 0x7f]);
+ break;
+
+ case RELEASE:
+ if((m_release_glo[chan] & 0x6000) == 0x6000) {
+ if(fpstep(m_envelope_level[chan], 0x8000000, decay_linear_step[(m_release_glo[chan] >> 8) & 0x1f]))
+ m_envelope_mode[chan] = IDLE;
+ } else {
+ if(fpstep(m_envelope_level[chan], 0x8000000, m_global_step[(m_release_glo[chan] >> 8) & 0x7f]))
+ m_envelope_mode[chan] = IDLE;
+ }
+ break;
+ }
+ }
+
+ outputs[0].put_int_clamp(0, dry_l >> 8, 32768);
+ outputs[1].put_int_clamp(0, dry_r >> 8, 32768);
+}
- // Fifth, add to the (dry) accumulators
- dry_left += samp2 * m_linear_attenuation[std::min(0xffu, dry_l)];
- dry_right += samp2 * m_linear_attenuation[std::min(0xffu, dry_r)];
+void swp30_device::change_mode_attack_decay1(int chan)
+{
+ m_envelope_mode[chan] = DECAY1;
+ m_envelope_timer[chan] = 0x8000000;
+ m_envelope_on_timer[chan] = (m_decay1[chan] & 0xff) == 0;
+}
- // Missing: reverb, chorus, effects in general
- }
+void swp30_device::change_mode_decay1_decay2(int chan)
+{
+ m_envelope_mode[chan] = DECAY2;
+ m_envelope_timer[chan] = 0x8000000;
+ m_envelope_on_timer[chan] = (m_decay2[chan] & 0xff) == (m_decay1[chan] & 0xff);
+}
- // Samples are 16 bits, there are up to 64 of them, and the accumulators are fixed-point signed 48.16
- // Global EQ is missing (it's done in the MEG)
+uint32_t swp30_device::execute_min_cycles() const noexcept
+{
+ return 1;
+}
+
+uint32_t swp30_device::execute_max_cycles() const noexcept
+{
+ return 1;
+}
- dry_left >>= 14;
- outputs[0].put_int_clamp(0, dry_left, 32768);
+uint32_t swp30_device::execute_input_lines() const noexcept
+{
+ return 0;
+}
- dry_right >>= 14;
- outputs[1].put_int_clamp(0, dry_right, 32768);
+void swp30_device::execute_run()
+{
+ debugger_instruction_hook(m_meg_pc);
+ m_icount = 0;
}
+
+void swp30_device::meg_prg_map(address_map &map)
+{
+ map(0x000, 0x1bf).r(FUNC(swp30_device::meg_prg_map_r));
+}
+
+u64 swp30_device::meg_prg_map_r(offs_t address)
+{
+ return m_meg_program[address];
+}
+
+u16 swp30_device::swp30d_const_r(u16 address) const
+{
+ return m_meg_const[address];
+}
+
+u16 swp30_device::swp30d_offset_r(u16 address) const
+{
+ return m_meg_offset[address];
+}
+
+device_memory_interface::space_config_vector swp30_device::memory_space_config() const
+{
+ return space_config_vector {
+ std::make_pair(AS_PROGRAM, &m_program_config),
+ std::make_pair(AS_DATA, &m_rom_config),
+ };
+}
+
+std::unique_ptr<util::disasm_interface> swp30_device::create_disassembler()
+{
+ return std::make_unique<swp30_disassembler>(this);
+}
+
+void swp30_device::state_import(const device_state_entry &entry)
+{
+}
+
+void swp30_device::state_export(const device_state_entry &entry)
+{
+}
+
+void swp30_device::state_string_export(const device_state_entry &entry, std::string &str) const
+{
+}
+
diff --git a/src/devices/sound/swp30.h b/src/devices/sound/swp30.h
index 0ef1223eb4f..e787db3dfda 100644
--- a/src/devices/sound/swp30.h
+++ b/src/devices/sound/swp30.h
@@ -8,10 +8,9 @@
#pragma once
-#include "meg.h"
-#include "dirom.h"
+#include "swp30d.h"
-class swp30_device : public device_t, public device_sound_interface, public device_rom_interface<25+2, 2, 0, ENDIANNESS_LITTLE>
+class swp30_device : public cpu_device, public device_sound_interface, public swp30_disassembler::info
{
public:
swp30_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 33868800);
@@ -22,51 +21,81 @@ protected:
virtual void device_start() override;
virtual void device_reset() override;
virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
- virtual void device_add_mconfig(machine_config &config) override;
+ virtual uint32_t execute_min_cycles() const noexcept override;
+ virtual uint32_t execute_max_cycles() const noexcept override;
+ virtual uint32_t execute_input_lines() const noexcept override;
+ virtual void execute_run() override;
+ virtual space_config_vector memory_space_config() const override;
+ virtual void state_import(const device_state_entry &entry) override;
+ virtual void state_export(const device_state_entry &entry) override;
+ virtual void state_string_export(const device_state_entry &entry, std::string &str) const override;
+ virtual std::unique_ptr<util::disasm_interface> create_disassembler() override;
private:
enum {
IDLE,
ATTACK,
- DECAY,
- SUSTAIN,
+ DECAY1,
+ DECAY2,
RELEASE
};
- required_device<meg_embedded_device> m_meg;
+ address_space_config m_program_config, m_rom_config;
+ address_space *m_program, *m_rom;
+ memory_access<25, 2, -2, ENDIANNESS_LITTLE>::cache m_rom_cache;
sound_stream *m_stream;
- s32 m_sample_increment[0x4000];
- s32 m_linear_attenuation[0x100];
- s16 m_sample_log8[0x100];
+ static const std::array<s32, 0x80> attack_linear_step;
+ static const std::array<s32, 0x20> decay_linear_step;
+ static const std::array<s32, 16> panmap;
+ std::array<s32, 0x80> m_global_step;
+ std::array<s16, 0x100> m_sample_log8;
+
+ std::array<s32, 0x40> m_sample_start;
+ std::array<s32, 0x40> m_sample_end;
+ std::array<u32, 0x40> m_sample_address;
+ std::array<u16, 0x40> m_pitch;
+
+ std::array<u16, 0x40> m_attack;
+ std::array<u16, 0x40> m_decay1;
+ std::array<u16, 0x40> m_decay2;
+ std::array<u16, 0x40> m_release_glo;
+ std::array<u16, 0x40> m_pan;
+ std::array<u16, 0x40> m_dry_rev;
+ std::array<u16, 0x40> m_cho_var;
+
+ std::array<s32, 0x40> m_sample_pos;
+ std::array<s32, 0x40> m_envelope_level;
+ std::array<s32, 0x40> m_envelope_timer;
+ std::array<bool, 0x40> m_envelope_on_timer;
+ std::array<bool, 0x40> m_decay2_done;
+ std::array<u8, 0x40> m_envelope_mode;
+ std::array<s32, 0x40> m_glo_level_cur;
+ std::array<s32, 0x40> m_pan_l;
+ std::array<s32, 0x40> m_pan_r;
+
+ std::array<u64, 0x180> m_meg_program;
+ std::array<s16, 0x180> m_meg_const;
+ std::array<u16, 0x80> m_meg_offset;
+ std::array<u16, 0x18> m_meg_lfo;
+ std::array<u16, 8> m_meg_map;
- u64 m_program[0x180];
- u64 m_keyon_mask;
- u32 m_pre_size[0x40], m_post_size[0x40], m_address[0x40];
-
- s32 m_sample_pos[0x40];
s32 m_sample_history[0x40][2][2];
- u32 m_current_volume[0x40], m_target_volume[0x40];
- s32 m_step_volume[0x40];
u32 m_waverom_adr, m_waverom_mode, m_waverom_val;
u16 m_waverom_access;
- u16 m_program_pfp[0x180], m_program_pint[0x80], m_program_plfo[0x80];
-
- u16 m_base_volume[0x40], m_freq[0x40], m_pan[0x40], m_dry_rev[0x40], m_cho_var[0x40];
- u16 m_attack[0x40], m_decay[0x40], m_release[0x40];
u16 m_lpf_cutoff[0x40], m_lpf_cutoff_inc[0x40], m_lpf_reso[0x40], m_hpf_cutoff[0x40];
s16 m_eq_filter[0x40][6];
u16 m_routing[0x40][3];
- u16 m_map[8];
+ u64 m_keyon_mask;
u16 m_internal_adr;
- u16 m_program_address;
-
- u8 m_mode[0x40];
+ u16 m_meg_program_address;
+ u16 m_meg_pc;
+ int m_icount;
// AWM2 per-channel registers
u16 lpf_cutoff_r(offs_t offset);
@@ -79,34 +108,37 @@ private:
void lpf_reso_w(offs_t offset, u16 data);
u16 attack_r(offs_t offset);
void attack_w(offs_t offset, u16 data);
- u16 decay_r(offs_t offset);
- void decay_w(offs_t offset, u16 data);
- u16 release_r(offs_t offset);
- void release_w(offs_t offset, u16 data);
+ u16 decay1_r(offs_t offset);
+ void decay1_w(offs_t offset, u16 data);
+ u16 decay2_r(offs_t offset);
+ void decay2_w(offs_t offset, u16 data);
+ u16 release_glo_r(offs_t offset);
+ void release_glo_w(offs_t offset, u16 data);
template<int coef> u16 eq_filter_r(offs_t offset);
template<int coef> void eq_filter_w(offs_t offset, u16 data);
- u16 base_volume_r(offs_t offset);
- void base_volume_w(offs_t offset, u16 data);
- u16 freq_r(offs_t offset);
- void freq_w(offs_t offset, u16 data);
- u16 pre_size_h_r(offs_t offset);
- u16 pre_size_l_r(offs_t offset);
- void pre_size_h_w(offs_t offset, u16 data);
- void pre_size_l_w(offs_t offset, u16 data);
- u16 post_size_h_r(offs_t offset);
- u16 post_size_l_r(offs_t offset);
- void post_size_h_w(offs_t offset, u16 data);
- void post_size_l_w(offs_t offset, u16 data);
- u16 address_h_r(offs_t offset);
- u16 address_l_r(offs_t offset);
- void address_h_w(offs_t offset, u16 data);
- void address_l_w(offs_t offset, u16 data);
+
+ u16 sample_start_h_r(offs_t offset);
+ u16 sample_start_l_r(offs_t offset);
+ void sample_start_h_w(offs_t offset, u16 data);
+ void sample_start_l_w(offs_t offset, u16 data);
+ u16 sample_end_h_r(offs_t offset);
+ u16 sample_end_l_r(offs_t offset);
+ void sample_end_h_w(offs_t offset, u16 data);
+ void sample_end_l_w(offs_t offset, u16 data);
+ u16 sample_address_h_r(offs_t offset);
+ u16 sample_address_l_r(offs_t offset);
+ void sample_address_h_w(offs_t offset, u16 data);
+ void sample_address_l_w(offs_t offset, u16 data);
+ u16 pitch_r(offs_t offset);
+ void pitch_w(offs_t offset, u16 data);
+
u16 pan_r(offs_t offset);
void pan_w(offs_t offset, u16 data);
u16 dry_rev_r(offs_t offset);
void dry_rev_w(offs_t offset, u16 data);
u16 cho_var_r(offs_t offset);
void cho_var_w(offs_t offset, u16 data);
+
u16 internal_adr_r();
void internal_adr_w(u16 data);
u16 internal_r();
@@ -114,19 +146,26 @@ private:
template<int sel> void routing_w(offs_t offset, u16 data);
// Envelope control
- void change_mode(int channel, u8 mode);
+ void change_mode_attack_decay1(int chan);
+ void change_mode_decay1_decay2(int chan);
+ static bool istep(s32 &value, s32 limit, s32 step);
+ static bool fpstep(s32 &value, s32 limit, s32 step);
+ static s32 fpadd(s32 value, s32 step);
+ static s32 fpsub(s32 value, s32 step);
+ static s32 fpapply(s32 value, s32 sample);
+ static s32 lpffpapply(s32 value, s32 sample);
// Control registers
template<int sel> u16 keyon_mask_r();
template<int sel> void keyon_mask_w(u16 data);
u16 keyon_r();
void keyon_w(u16);
- u16 prg_address_r();
- void prg_address_w(u16 data);
- template<int sel> u16 prg_r();
- template<int sel> void prg_w(u16 data);
- template<int sel> u16 map_r();
- template<int sel> void map_w(u16 data);
+ u16 meg_prg_address_r();
+ void meg_prg_address_w(u16 data);
+ template<int sel> u16 meg_prg_r();
+ template<int sel> void meg_prg_w(u16 data);
+ template<int sel> u16 meg_map_r();
+ template<int sel> void meg_map_w(u16 data);
template<int sel> void waverom_adr_w(u16 data);
template<int sel> u16 waverom_adr_r();
template<int sel> void waverom_mode_w(u16 data);
@@ -137,13 +176,18 @@ private:
template<int sel> u16 waverom_val_r();
// MEG registers
- template<int sel> u16 prg_fp_r(offs_t offset);
- template<int sel> void prg_fp_w(offs_t offset, u16 data);
- template<int sel> u16 prg_off_r(offs_t offset);
- template<int sel> void prg_off_w(offs_t offset, u16 data);
- template<int sel> u16 prg_lfo_r(offs_t offset);
- template<int sel> void prg_lfo_w(offs_t offset, u16 data);
-
+ template<int sel> u16 meg_const_r(offs_t offset);
+ template<int sel> void meg_const_w(offs_t offset, u16 data);
+ template<int sel> u16 meg_offset_r(offs_t offset);
+ template<int sel> void meg_offset_w(offs_t offset, u16 data);
+ template<int sel> u16 meg_lfo_r(offs_t offset);
+ template<int sel> void meg_lfo_w(offs_t offset, u16 data);
+
+ void meg_prg_map(address_map &map);
+ u64 meg_prg_map_r(offs_t address);
+
+ virtual u16 swp30d_const_r(u16 address) const override;
+ virtual u16 swp30d_offset_r(u16 address) const override;
// Generic catch-all
u16 snd_r(offs_t offset);
diff --git a/src/devices/sound/swp30d.cpp b/src/devices/sound/swp30d.cpp
new file mode 100644
index 00000000000..d3863c3ccbc
--- /dev/null
+++ b/src/devices/sound/swp30d.cpp
@@ -0,0 +1,124 @@
+// license:BSD-3-Clause
+// copyright-holders:Olivier Galibert
+
+// Yamaha SWP30 - Multiple effects generator subpart
+//
+// Audio dsp dedicated to effects generation
+//
+// Disassembler
+
+#include "emu.h"
+#include "swp30d.h"
+
+swp30_disassembler::swp30_disassembler(info *inf) : m_info(inf)
+{
+}
+
+u32 swp30_disassembler::opcode_alignment() const
+{
+ return 1;
+}
+
+std::string swp30_disassembler::gconst(offs_t address) const
+{
+ if(!m_info)
+ return util::string_format("c%03x", address);
+ s16 value = m_info->swp30d_const_r(address);
+ return util::string_format("%g", value / 16384.0);
+}
+
+std::string swp30_disassembler::goffset(offs_t address) const
+{
+ return m_info ? util::string_format("%x", m_info->swp30d_offset_r(address)) : util::string_format("of%02x", address);
+}
+
+u32 swp30_disassembler::b(u64 opc, u32 start, u32 count)
+{
+ return (opc >> start) & ((1 << count) - 1);
+}
+
+void swp30_disassembler::append(std::string &r, const std::string &e)
+{
+ if(r != "")
+ r += " ; ";
+ r += e;
+}
+
+// 33333333 33333333 22222222 22222222 11111111 11111111 00000000 00000000
+// fedcba98 76543210 fedcba98 76543210 fedcba98 76543210 fedcba98 76543210
+
+// 66665555 55555544 44444444 33333333 33222222 22221111 11111100 00000000
+// 32109876 54321098 76543210 98765432 10987654 32109876 54321098 76543210
+// XLB----- -rrrrrrr rxlmmmmm m-MM---- -P-----* -----Arr rrrrrrmm mmmm----
+
+// m = low is read port, high is write port, memory register
+// r = low is read port, high is high port, rotating register
+
+// X = used for lo-fi variation only
+// L = lfo read for memory offset
+// * = compute mul
+// A = mul input = m or r
+// P = P sent for register write
+// B = register write to mbuf
+// M = memory mode, none/read/write/read+1
+// x = 0 register write to memory, 1 to rotating
+// l = 0 = lfo sent for register write
+
+offs_t swp30_disassembler::disassemble(std::ostream &stream, offs_t pc, const data_buffer &opcodes, const data_buffer &params)
+{
+ u64 opc = opcodes.r64(pc);
+
+ std::string r;
+
+ if(b(opc, 62, 1))
+ append(r, util::string_format("lfo.%02x", pc >> 4));
+
+ if(b(opc, 23, 1))
+ switch(b(opc, 24, 2)) {
+ case 0:
+ if(b(opc, 18, 1))
+ append(r, util::string_format("p += %s*m%02x", gconst(pc), b(opc, 4, 6)));
+ else
+ append(r, util::string_format("p += %s*r%02x", gconst(pc), b(opc, 10, 8)));
+ break;
+ case 1:
+ append(r, util::string_format("p = %s*(r%02x+m%02x)", gconst(pc), b(opc, 10, 8), b(opc, 4, 6)));
+ break;
+ case 2:
+ append(r, util::string_format("p ?= %s*(r%02x+m%02x)", gconst(pc), b(opc, 10, 8), b(opc, 4, 6)));
+ break;
+ case 3:
+ if(b(opc, 18, 1))
+ append(r, util::string_format("p = %s*m%02x", gconst(pc), b(opc, 4, 6)));
+ else
+ append(r, util::string_format("p = %s*r%02x", gconst(pc), b(opc, 10, 8)));
+ break;
+ }
+
+ std::string source;
+ if(b(opc, 30, 1))
+ source = "p";
+ else if(!b(opc, 45, 1))
+ source = util::string_format("lfo.%02x", pc >> 4);
+
+ if(!source.empty()) {
+ if(b(opc, 61, 1))
+ append(r, util::string_format("mb = %s", source));
+ else if(b(opc, 46, 1) == 1)
+ append(r, util::string_format("m%02x = %s", b(opc, 39, 6), source));
+ else
+ append(r, util::string_format("r%02x = %s", b(opc, 47, 8), source));
+ }
+
+ u32 memmode = b(opc, 36, 2);
+ if(memmode) {
+ static const char *modes[4] = { nullptr, "w", "r", "rr" };
+
+ append(r, util::string_format("mem_%s %x +%s", modes[memmode], b(opc, 33, 3), goffset(pc/3)));
+ r += util::string_format("-> m%02x", b(opcodes.r64(pc+2), 39, 6));
+ }
+
+ stream << r;
+
+ return 1 | SUPPORTED;
+}
diff --git a/src/devices/sound/megd.h b/src/devices/sound/swp30d.h
index 82bad8f4beb..d993f9f03f6 100644
--- a/src/devices/sound/megd.h
+++ b/src/devices/sound/swp30d.h
@@ -1,27 +1,27 @@
// license:BSD-3-Clause
// copyright-holders:Olivier Galibert
-// Yamaha MEG - Multiple effects generator
+// Yamaha SWP30 - Multiple effects generator subpart
//
// Audio dsp dedicated to effects generation
//
// Disassembler
-#ifndef DEVICES_SOUND_MEGD_H
-#define DEVICES_SOUND_MEGD_H
+#ifndef DEVICES_SOUND_SWP30D_H
+#define DEVICES_SOUND_SWP30D_H
#pragma once
-class meg_disassembler : public util::disasm_interface
+class swp30_disassembler : public util::disasm_interface
{
public:
class info {
public:
- virtual u16 fp_r(u16 address) const = 0;
- virtual u16 offset_r(u16 address) const = 0;
+ virtual u16 swp30d_const_r(u16 address) const = 0;
+ virtual u16 swp30d_offset_r(u16 address) const = 0;
};
- meg_disassembler(info *inf = nullptr);
+ swp30_disassembler(info *inf = nullptr);
virtual u32 opcode_alignment() const override;
virtual offs_t disassemble(std::ostream &stream, offs_t pc, const data_buffer &opcodes, const data_buffer &params) override;
@@ -29,7 +29,7 @@ public:
private:
info *m_info;
- std::string gfp(offs_t address) const;
+ std::string gconst(offs_t address) const;
std::string goffset(offs_t address) const;
static inline u32 b(u64 opc, u32 start, u32 count);
diff --git a/src/devices/sound/xt446.cpp b/src/devices/sound/xt446.cpp
index 82d8c1c76ab..06e5326371c 100644
--- a/src/devices/sound/xt446.cpp
+++ b/src/devices/sound/xt446.cpp
@@ -65,15 +65,15 @@ void xt446_device::xt446_map(address_map &map)
void xt446_device::swp30_map(address_map &map)
{
- map(0x000000*4, 0x200000*4-1).rom().region("swp30", 0).mirror(4*0x200000);
- map(0x400000*4, 0x500000*4-1).rom().region("swp30", 0x800000).mirror(4*0x300000);
- map(0x800000*4, 0xa00000*4-1).rom().region("swp30", 0x1000000).mirror(4*0x200000);
+ map(0x000000, 0x1fffff).rom().region("swp30", 0).mirror(0x200000);
+ map(0x400000, 0x4fffff).rom().region("swp30", 0x800000).mirror(0x300000);
+ map(0x800000, 0x9fffff).rom().region("swp30", 0x1000000).mirror(0x200000);
}
void xt446_device::device_add_mconfig(machine_config &config)
{
H8S2655(config, m_maincpu, 16_MHz_XTAL);
- m_maincpu->set_addrmap(AS_PROGRAM, &xt446_device::xt446_map);
+ m_maincpu->set_addrmap(AS_DATA, &xt446_device::xt446_map);
m_maincpu->read_adc<0>().set_constant(0);
m_maincpu->read_adc<1>().set_constant(0);
m_maincpu->read_adc<2>().set_constant(0);
diff --git a/src/mame/yamaha/ymmu100.cpp b/src/mame/yamaha/ymmu100.cpp
index d9191125e3a..94f49feecf3 100644
--- a/src/mame/yamaha/ymmu100.cpp
+++ b/src/mame/yamaha/ymmu100.cpp
@@ -670,9 +670,9 @@ void mu100_state::pg_w(u16 data)
void mu100_state::swp30_map(address_map &map)
{
- map(0x000000*4, 0x200000*4-1).rom().region("swp30", 0).mirror(4*0x200000);
- map(0x400000*4, 0x500000*4-1).rom().region("swp30", 0x800000).mirror(4*0x300000);
- map(0x800000*4, 0xa00000*4-1).rom().region("swp30", 0x1000000).mirror(4*0x200000);
+ map(0x000000, 0x1fffff).rom().region("swp30", 0).mirror(0x200000);
+ map(0x400000, 0x4fffff).rom().region("swp30", 0x800000).mirror(0x300000);
+ map(0x800000, 0x9fffff).rom().region("swp30", 0x1000000).mirror(0x200000);
}
void mu100_state::mu100(machine_config &config)
@@ -705,7 +705,7 @@ void mu100_state::mu100(machine_config &config)
SPEAKER(config, "rspeaker").front_right();
SWP30(config, m_swp30);
- m_swp30->set_addrmap(0, &mu100_state::swp30_map);
+ m_swp30->set_addrmap(AS_DATA, &mu100_state::swp30_map);
m_swp30->add_route(0, "lspeaker", 1.0);
m_swp30->add_route(1, "rspeaker", 1.0);
@@ -734,7 +734,7 @@ ROM_START( mu100 )
ROM_SYSTEM_BIOS( 2, "bios2", "xt714e0 (v1.03, Jul. 25, 1997)" )
ROM_LOAD16_WORD_SWAP_BIOS( 2, "xt714e0.ic11", 0x000000, 0x200000, CRC(2d8cf9fc) SHA1(a81f988a315efe92106f1e7d407cd3626c4f843f) )
- ROM_REGION( 0x1800000, "swp30", ROMREGION_ERASE00 )
+ ROM_REGION32_LE( 0x1800000, "swp30", ROMREGION_ERASE00 )
ROM_LOAD32_WORD( "sx518b0.ic34", 0x0000000, 0x400000, CRC(2550d44f) SHA1(fd3cce228c7d389a2fde25c808a5b26080588cba) )
ROM_LOAD32_WORD( "sx743b0.ic35", 0x0000002, 0x400000, CRC(a9109a6c) SHA1(a67bb49378a38a2d809bd717d286e18bc6496db0) )
ROM_LOAD32_WORD( "xt445a0-828.ic36", 0x0800000, 0x200000, CRC(225c2280) SHA1(23b5e046fd2e2ac01af3e6dc6357c5c6547b286b) )
@@ -753,7 +753,7 @@ ROM_START( mu100r )
ROM_SYSTEM_BIOS( 2, "bios2", "xt714e0 (v1.03, Jul. 25, 1997)" )
ROM_LOAD16_WORD_SWAP_BIOS( 2, "xt714e0.ic11", 0x000000, 0x200000, CRC(2d8cf9fc) SHA1(a81f988a315efe92106f1e7d407cd3626c4f843f) )
- ROM_REGION( 0x1800000, "swp30", ROMREGION_ERASE00 )
+ ROM_REGION32_LE( 0x1800000, "swp30", ROMREGION_ERASE00 )
ROM_LOAD32_WORD( "sx518b0.ic34", 0x000000, 0x400000, CRC(2550d44f) SHA1(fd3cce228c7d389a2fde25c808a5b26080588cba) )
ROM_LOAD32_WORD( "sx743b0.ic35", 0x000002, 0x400000, CRC(a9109a6c) SHA1(a67bb49378a38a2d809bd717d286e18bc6496db0) )
ROM_LOAD32_WORD( "xt445a0-828.ic36", 0x800000, 0x200000, CRC(225c2280) SHA1(23b5e046fd2e2ac01af3e6dc6357c5c6547b286b) )
@@ -767,7 +767,7 @@ ROM_START( mu100b )
// MU-100B v1.08 (Nov. 28, 1997)
ROM_LOAD16_WORD_SWAP( "xu50710-m27c160.bin", 0x000000, 0x200000, CRC(4b10bd27) SHA1(12d7c6e1bce7974b34916e1bfa5057ab55867476) )
- ROM_REGION( 0x1800000, "swp30", ROMREGION_ERASE00 )
+ ROM_REGION32_LE( 0x1800000, "swp30", ROMREGION_ERASE00 )
ROM_LOAD32_WORD( "sx518b0.ic34", 0x0000000, 0x400000, CRC(2550d44f) SHA1(fd3cce228c7d389a2fde25c808a5b26080588cba) )
ROM_LOAD32_WORD( "sx743b0.ic35", 0x0000002, 0x400000, CRC(a9109a6c) SHA1(a67bb49378a38a2d809bd717d286e18bc6496db0) )
ROM_LOAD32_WORD( "xt445a0-828.ic36", 0x0800000, 0x200000, CRC(225c2280) SHA1(23b5e046fd2e2ac01af3e6dc6357c5c6547b286b) )