summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/sound
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/sound')
-rw-r--r--src/devices/sound/c6280.cpp104
-rw-r--r--src/devices/sound/c6280.h9
-rw-r--r--src/devices/sound/es8712.cpp2
-rw-r--r--src/devices/sound/meg.cpp384
-rw-r--r--src/devices/sound/meg.h122
-rw-r--r--src/devices/sound/megd.cpp118
-rw-r--r--src/devices/sound/megd.h39
-rw-r--r--src/devices/sound/namco_163.cpp176
-rw-r--r--src/devices/sound/namco_163.h42
-rw-r--r--src/devices/sound/swp30.cpp61
-rw-r--r--src/devices/sound/swp30.h9
-rw-r--r--src/devices/sound/vrc6.cpp99
-rw-r--r--src/devices/sound/vrc6.h14
-rw-r--r--src/devices/sound/ym2413.cpp124
-rw-r--r--src/devices/sound/ym2413.h23
15 files changed, 1136 insertions, 190 deletions
diff --git a/src/devices/sound/c6280.cpp b/src/devices/sound/c6280.cpp
index 0e5873c86de..6c6f2410166 100644
--- a/src/devices/sound/c6280.cpp
+++ b/src/devices/sound/c6280.cpp
@@ -92,16 +92,16 @@ void c6280_device::sound_stream_update(sound_stream &stream, stream_sample_t **i
if((ch >= 4) && (m_channel[ch].m_noise_control & 0x80))
{
/* Noise mode */
- uint32_t step = m_noise_freq_tab[(m_channel[ch].m_noise_control & 0x1F) ^ 0x1F];
+ uint32_t step = (m_channel[ch].m_noise_control & 0x1F) ^ 0x1F;
for (int i = 0; i < samples; i += 1)
{
static int data = 0;
- m_channel[ch].m_noise_counter += step;
- if(m_channel[ch].m_noise_counter >= 0x800)
+ if(m_channel[ch].m_noise_counter <= 0)
{
+ m_channel[ch].m_noise_counter = step << 2;
data = (machine().rand() & 1) ? 0x1F : 0;
}
- m_channel[ch].m_noise_counter &= 0x7FF;
+ m_channel[ch].m_noise_counter--;
outputs[0][i] += (int16_t)(vll * (data - 16));
outputs[1][i] += (int16_t)(vlr * (data - 16));
}
@@ -118,28 +118,40 @@ void c6280_device::sound_stream_update(sound_stream &stream, stream_sample_t **i
}
else
{
- if ((m_lfo_control & 0x80) && (ch < 2))
+ if ((m_lfo_control & 3) && (ch < 2))
{
if (ch == 0) // CH 0 only, CH 1 is muted
{
/* Waveform mode with LFO */
- uint32_t step = m_channel[0].m_frequency;
- uint16_t lfo_step = m_channel[1].m_frequency;
+ uint16_t lfo_step = m_channel[1].m_frequency ? m_channel[1].m_frequency : 0x1000;
for (int i = 0; i < samples; i += 1)
{
- int offset, lfooffset;
- int16_t data, lfo_data;
- lfooffset = (m_channel[1].m_counter >> 12) & 0x1F;
- m_channel[1].m_counter += m_wave_freq_tab[(lfo_step * m_lfo_frequency) & 0xfff]; // TODO : multiply? verify this from real hardware.
- m_channel[1].m_counter &= 0x1FFFF;
- lfo_data = m_channel[1].m_waveform[lfooffset];
- if (m_lfo_control & 3)
+ int32_t step = m_channel[0].m_frequency ? m_channel[0].m_frequency : 0x1000;
+ if (m_lfo_control & 0x80) // reset LFO
+ {
+ m_channel[1].m_tick = lfo_step * m_lfo_frequency;
+ m_channel[1].m_counter = 0;
+ }
+ else
+ {
+ int lfooffset = m_channel[1].m_counter;
+ m_channel[1].m_tick--;
+ if (m_channel[1].m_tick <= 0)
+ {
+ m_channel[1].m_tick = lfo_step * m_lfo_frequency; // TODO : multiply? verify this from real hardware.
+ m_channel[1].m_counter = (m_channel[1].m_counter + 1) & 0x1f;
+ }
+ int16_t lfo_data = m_channel[1].m_waveform[lfooffset];
step += ((lfo_data - 16) << (((m_lfo_control & 3)-1)<<1)); // verified from patent, TODO : same in real hardware?
-
- offset = (m_channel[0].m_counter >> 12) & 0x1F;
- m_channel[0].m_counter += m_wave_freq_tab[step & 0xfff];
- m_channel[0].m_counter &= 0x1FFFF;
- data = m_channel[0].m_waveform[offset];
+ }
+ int offset = m_channel[0].m_counter;
+ m_channel[0].m_tick--;
+ if (m_channel[0].m_tick <= 0)
+ {
+ m_channel[0].m_tick = step;
+ m_channel[0].m_counter = (m_channel[0].m_counter + 1) & 0x1f;
+ }
+ int16_t data = m_channel[0].m_waveform[offset];
outputs[0][i] += (int16_t)(vll * (data - 16));
outputs[1][i] += (int16_t)(vlr * (data - 16));
}
@@ -148,15 +160,17 @@ void c6280_device::sound_stream_update(sound_stream &stream, stream_sample_t **i
else
{
/* Waveform mode */
- uint32_t step = m_wave_freq_tab[m_channel[ch].m_frequency];
+ uint32_t step = m_channel[ch].m_frequency ? m_channel[ch].m_frequency : 0x1000;
for (int i = 0; i < samples; i += 1)
{
- int offset;
- int16_t data;
- offset = (m_channel[ch].m_counter >> 12) & 0x1F;
- m_channel[ch].m_counter += step;
- m_channel[ch].m_counter &= 0x1FFFF;
- data = m_channel[ch].m_waveform[offset];
+ int offset = m_channel[ch].m_counter;
+ m_channel[ch].m_tick--;
+ if (m_channel[ch].m_tick <= 0)
+ {
+ m_channel[ch].m_tick = step;
+ m_channel[ch].m_counter = (m_channel[ch].m_counter + 1) & 0x1f;
+ }
+ int16_t data = m_channel[ch].m_waveform[offset];
outputs[0][i] += (int16_t)(vll * (data - 16));
outputs[1][i] += (int16_t)(vlr * (data - 16));
}
@@ -205,6 +219,10 @@ WRITE8_MEMBER( c6280_device::c6280_w )
{
chan->m_index = 0;
}
+ if(((chan->m_control & 0x80) == 0) && (data & 0x80))
+ {
+ chan->m_tick = chan->m_frequency;
+ }
chan->m_control = data;
break;
@@ -261,38 +279,9 @@ c6280_device::c6280_device(const machine_config &mconfig, const char *tag, devic
{
}
-//-------------------------------------------------
-// calculate_clocks - (re)calculate clock-derived
-// members
-//-------------------------------------------------
-
-void c6280_device::calculate_clocks()
-{
- int rate = clock() / 16;
-
- /* Make waveform frequency table */
- for (int i = 0; i < 4096; i += 1)
- {
- double step = (16 * 4096) / (i + 1);
- m_wave_freq_tab[(1 + i) & 0xFFF] = (uint32_t)step;
- }
-
- /* Make noise frequency table */
- for (int i = 0; i < 32; i += 1)
- {
- double step = (16 * 32) / (i+1);
- m_noise_freq_tab[i] = (uint32_t)step;
- }
-
- if (m_stream != nullptr)
- m_stream->set_sample_rate(rate);
- else
- m_stream = machine().sound().stream_alloc(*this, 0, 2, rate);
-}
-
void c6280_device::device_clock_changed()
{
- calculate_clocks();
+ m_stream->set_sample_rate(clock());
}
//-------------------------------------------------
@@ -311,7 +300,7 @@ void c6280_device::device_start()
m_lfo_control = 0;
memset(m_channel, 0, sizeof(channel) * 8);
- calculate_clocks();
+ m_stream = machine().sound().stream_alloc(*this, 0, 2, clock());
/* Make volume table */
/* PSG has 48dB volume range spread over 32 steps */
@@ -338,5 +327,6 @@ void c6280_device::device_start()
save_item(NAME(m_channel[chan].m_noise_control), chan);
save_item(NAME(m_channel[chan].m_noise_counter), chan);
save_item(NAME(m_channel[chan].m_counter), chan);
+ save_item(NAME(m_channel[chan].m_tick), chan);
}
}
diff --git a/src/devices/sound/c6280.h b/src/devices/sound/c6280.h
index 5b7f94bce7f..0cfdc34799b 100644
--- a/src/devices/sound/c6280.h
+++ b/src/devices/sound/c6280.h
@@ -8,6 +8,8 @@
class c6280_device : public device_t, public device_sound_interface
{
public:
+ static constexpr feature_type imperfect_features() { return feature::SOUND; } // Incorrect / Not verified noise / LFO output
+
c6280_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
// write only
@@ -22,8 +24,6 @@ protected:
virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) override;
private:
- void calculate_clocks();
-
struct channel {
uint16_t m_frequency;
uint8_t m_control;
@@ -32,8 +32,9 @@ private:
uint8_t m_index;
int16_t m_dda;
uint8_t m_noise_control;
- uint32_t m_noise_counter;
+ int32_t m_noise_counter;
uint32_t m_counter;
+ int32_t m_tick;
};
// internal state
@@ -44,8 +45,6 @@ private:
uint8_t m_lfo_control;
channel m_channel[8];
int16_t m_volume_table[32];
- uint32_t m_noise_freq_tab[32];
- uint32_t m_wave_freq_tab[4096];
};
DECLARE_DEVICE_TYPE(C6280, c6280_device)
diff --git a/src/devices/sound/es8712.cpp b/src/devices/sound/es8712.cpp
index e0b2699edd0..00ec7fe90d3 100644
--- a/src/devices/sound/es8712.cpp
+++ b/src/devices/sound/es8712.cpp
@@ -228,7 +228,7 @@ WRITE_LINE_MEMBER(es8712_device::msm_int)
}
else
{
- m_adpcm_select->write_ab(read_byte(m_base_offset));
+ m_adpcm_select->ab_w(read_byte(m_base_offset));
m_adpcm_select->select_w(m_adpcm_trigger);
m_adpcm_trigger ^= 1;
if (m_adpcm_trigger == 0)
diff --git a/src/devices/sound/meg.cpp b/src/devices/sound/meg.cpp
new file mode 100644
index 00000000000..a1f9d67b293
--- /dev/null
+++ b/src/devices/sound/meg.cpp
@@ -0,0 +1,384 @@
+// license:BSD-3-Clause
+// copyright-holders:Olivier Galibert
+
+// Yamaha MEG - Multiple effects generator
+//
+// 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;
+}
+
+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
+{
+ return 1;
+}
+
+uint32_t meg_base_device::execute_max_cycles() const
+{
+ return 1;
+}
+
+uint32_t meg_base_device::execute_input_lines() const
+{
+ 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()
+{
+ 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)
+{
+}
+
+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)
+{
+}
+
+
+// vl70:
+// 6d1e: write 1, r0l
+// 6d26: write 2, r0l
+// 6d2e: read 2
+// 6d36: write 3, r0l
+// 6d3e: write reg 4:r0h, r0l
+// 6d52: write reg 5:r0h, r0l-1
+// 6d68: write 7, r0l
+// 6d70: write reg 8:r0h, r0l
+// 6d84: write reg 9:r0h, r0l
+// 6dac: write a, r0l
+// 6db4: write reg cd:r1l, r0
+// 6dd4: write reg e:r0h, r0l
+// 6dee: write reg f:r0h, r0l
+// 6e08: read 10,11
+// 6e1c: write reg 1213:r1l, r0
+// 6e3c: write reg 14:r0h, r0l
+// 6e50: write 15, r0l
+// 6e58: write reg 16:r0h, r0l
+// 6e6c: write reg 17:r0h, r0l
+// 6e80: write reg 18:e0h, e0l
+
+void meg_device::map(address_map &map)
+{
+ map(0x00, 0x00).w(FUNC(meg_device::select_w));
+ map(0x01, 0x01).w(FUNC(meg_device::s1_w));
+ map(0x02, 0x02).rw(FUNC(meg_device::s2_r), FUNC(meg_device::s2_w));
+ map(0x03, 0x03).w(FUNC(meg_device::s3_w));
+ map(0x04, 0x04).w(FUNC(meg_device::s4_w));
+ map(0x05, 0x05).w(FUNC(meg_device::s5_w));
+ map(0x07, 0x07).w(FUNC(meg_device::s7_w));
+ 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(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));
+ map(0x11, 0x11).r(FUNC(meg_device::s11_r));
+ map(0x12, 0x12).w(FUNC(meg_device::offseth_w));
+ map(0x13, 0x13).w(FUNC(meg_device::offsetl_w));
+ map(0x14, 0x14).w(FUNC(meg_device::s14_w));
+ map(0x15, 0x15).w(FUNC(meg_device::s15_w));
+ map(0x16, 0x16).w(FUNC(meg_device::s16_w));
+ map(0x17, 0x17).w(FUNC(meg_device::s17_w));
+ map(0x18, 0x18).w(FUNC(meg_device::s18_w));
+}
+
+u8 meg_device::s2_r()
+{
+ logerror("read r2 %s\n", machine().describe_context());
+ return 0x00;
+}
+
+void meg_device::select_w(u8 data)
+{
+ m_reg = data;
+}
+
+void meg_device::s1_w(u8 data)
+{
+ logerror("r1 %02x %s\n", data, machine().describe_context());
+}
+
+void meg_device::s2_w(u8 data)
+{
+ logerror("r2 %02x %s\n", data, machine().describe_context());
+}
+
+void meg_device::s3_w(u8 data)
+{
+ logerror("r3 %02x %s\n", data, machine().describe_context());
+}
+
+void meg_device::s4_w(u8 data)
+{
+ if(m_r4[m_reg] != data) {
+ m_r4[m_reg] = data;
+ logerror("r4[%02x] = %02x %s\n", m_reg, data, machine().describe_context());
+ }
+}
+
+void meg_device::s5_w(u8 data)
+{
+ if(m_r5[m_reg] != data) {
+ m_r5[m_reg] = data;
+ logerror("r5[%02x] = %02x %s\n", m_reg, data, machine().describe_context());
+ }
+}
+
+void meg_device::s7_w(u8 data)
+{
+ logerror("r7 %02x %s\n", data, machine().describe_context());
+}
+
+void meg_device::s8_w(u8 data)
+{
+ if(m_r8[m_reg] != data) {
+ m_r8[m_reg] = data;
+ logerror("r8[%02x] = %02x %s\n", m_reg, data, machine().describe_context());
+ }
+}
+
+
+void meg_device::s9_w(u8 data)
+{
+ if(m_r9[m_reg] != data) {
+ m_r9[m_reg] = data;
+ logerror("r9[%02x] = %02x %s\n", m_reg, data, machine().describe_context());
+ }
+}
+
+void meg_device::sa_w(u8 data)
+{
+ logerror("ra %02x %s\n", data, machine().describe_context());
+}
+
+void meg_device::fph_w(u8 data)
+{
+ fp_w(m_reg, (fp_r(m_reg) & 0x00ff) | (data << 8));
+}
+
+
+void meg_device::fpl_w(u8 data)
+{
+ fp_w(m_reg, (fp_r(m_reg) & 0xff00) | data);
+}
+
+void meg_device::se_w(u8 data)
+{
+ if(m_re[m_reg] != data) {
+ m_re[m_reg] = data;
+ logerror("re[%02x] = %02x %s\n", m_reg, data, machine().describe_context());
+ }
+}
+
+
+void meg_device::sf_w(u8 data)
+{
+ if(m_rf[m_reg] != data) {
+ m_rf[m_reg] = data;
+ logerror("rf[%02x] = %02x %s\n", m_reg, data, machine().describe_context());
+ }
+}
+
+u8 meg_device::s10_r()
+{
+ logerror("read r10 %s\n", machine().describe_context());
+ return 0x00;
+}
+
+u8 meg_device::s11_r()
+{
+ logerror("read r11 %s\n", machine().describe_context());
+ return 0x00;
+}
+
+void meg_device::offseth_w(u8 data)
+{
+ offset_w(m_reg, (offset_r(m_reg) & 0x00ff) | (data << 8));
+}
+
+void meg_device::offsetl_w(u8 data)
+{
+ offset_w(m_reg, (offset_r(m_reg) & 0xff00) | data);
+}
+
+void meg_device::s14_w(u8 data)
+{
+ if(m_r14[m_reg] != data) {
+ m_r14[m_reg] = data;
+ logerror("r14[%02x] = %02x %s\n", m_reg, data, machine().describe_context());
+ }
+}
+
+void meg_device::s15_w(u8 data)
+{
+ logerror("r15 %02x %s\n", data, machine().describe_context());
+}
+
+void meg_device::s16_w(u8 data)
+{
+ if(m_r16[m_reg] != data) {
+ m_r16[m_reg] = data;
+ logerror("r16[%02x] = %02x %s\n", m_reg, data, machine().describe_context());
+ }
+}
+
+void meg_device::s17_w(u8 data)
+{
+ if(m_r17[m_reg] != data) {
+ m_r17[m_reg] = data;
+ logerror("r17[%02x] = %02x %s\n", m_reg, data, machine().describe_context());
+ }
+}
+
+void meg_device::s18_w(u8 data)
+{
+ if(m_r18[m_reg] != data) {
+ m_r18[m_reg] = data;
+ logerror("r18[%02x] = %02x %s\n", m_reg, data, machine().describe_context());
+ }
+}
diff --git a/src/devices/sound/meg.h b/src/devices/sound/meg.h
new file mode 100644
index 00000000000..e9ff44f990a
--- /dev/null
+++ b/src/devices/sound/meg.h
@@ -0,0 +1,122 @@
+// license:BSD-3-Clause
+// copyright-holders:Olivier Galibert
+
+// Yamaha MEG - Multiple effects generator
+//
+// Audio dsp dedicated to effects generation
+
+#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
+{
+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;
+
+protected:
+ virtual void device_start() override;
+ virtual void device_reset() override;
+ virtual uint32_t execute_min_cycles() const override;
+ virtual uint32_t execute_max_cycles() const override;
+ virtual uint32_t execute_input_lines() const 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];
+ u8 m_r5[256];
+ u8 m_r8[256];
+ u8 m_r9[256];
+ u8 m_re[256];
+ u8 m_rf[256];
+ u8 m_r12[256];
+ u8 m_r13[256];
+ u8 m_r14[256];
+ u8 m_r16[256];
+ u8 m_r17[256];
+ u8 m_r18[256];
+ u8 m_reg;
+ u8 s2_r();
+ u8 s10_r();
+ u8 s11_r();
+ void select_w(u8 reg);
+ void s1_w(u8 data);
+ void s2_w(u8 data);
+ void s3_w(u8 data);
+ void s4_w(u8 data);
+ void s5_w(u8 data);
+ void s7_w(u8 data);
+ 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 se_w(u8 data);
+ void sf_w(u8 data);
+ void s10_w(u8 data);
+ void s11_w(u8 data);
+ void offseth_w(u8 data);
+ void offsetl_w(u8 data);
+ void s14_w(u8 data);
+ void s15_w(u8 data);
+ void s16_w(u8 data);
+ void s17_w(u8 data);
+ 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
new file mode 100644
index 00000000000..2790a7ca69c
--- /dev/null
+++ b/src/devices/sound/megd.cpp
@@ -0,0 +1,118 @@
+// 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, 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/megd.h b/src/devices/sound/megd.h
new file mode 100644
index 00000000000..59a13aa0ea4
--- /dev/null
+++ b/src/devices/sound/megd.h
@@ -0,0 +1,39 @@
+// license:BSD-3-Clause
+// copyright-holders:Olivier Galibert
+
+// Yamaha MEG - Multiple effects generator
+//
+// Audio dsp dedicated to effects generation
+//
+// Disassembler
+
+#ifndef DEVICES_SOUND_MEGD_H
+#define DEVICES_SOUND_MEGD_H
+
+#pragma once
+
+class meg_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;
+ };
+
+ meg_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;
+
+private:
+ info *m_info;
+
+ std::string gfp(offs_t address) const;
+ std::string goffset(offs_t address) const;
+
+ static inline u32 b(u64 opc, u32 start, u32 count);
+ static inline void append(std::string &r, std::string e);
+};
+
+#endif
diff --git a/src/devices/sound/namco_163.cpp b/src/devices/sound/namco_163.cpp
new file mode 100644
index 00000000000..6fdde572537
--- /dev/null
+++ b/src/devices/sound/namco_163.cpp
@@ -0,0 +1,176 @@
+// license:BSD-3-Clause
+// copyright-holders:cam900
+/***************************************************************************
+
+ Namco 163 internal sound emulation by cam900
+ 4 bit wavetable (variable length), 1 ~ 8 channel
+ Reference : https://wiki.nesdev.com/w/index.php/Namco_163_audio
+
+***************************************************************************/
+
+#include "emu.h"
+#include "namco_163.h"
+
+
+DEFINE_DEVICE_TYPE(NAMCO_163, namco_163_sound_device, "namco_163_sound", "Namco 163 (Sound)")
+
+namco_163_sound_device::namco_163_sound_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
+ : device_t(mconfig, NAMCO_163, tag, owner, clock)
+ , device_sound_interface(mconfig, *this)
+ , m_ram(nullptr)
+ , m_reg_addr(0x78)
+ , m_addr(0)
+ , m_inc(false)
+ , m_disable(false)
+ , m_stream(nullptr)
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void namco_163_sound_device::device_start()
+{
+ m_ram = make_unique_clear<u8[]>(0x80);
+ m_stream = machine().sound().stream_alloc(*this, 0, 1, clock() / 15);
+
+ save_pointer(NAME(m_ram), 0x80);
+ save_item(NAME(m_reg_addr));
+ save_item(NAME(m_addr));
+ save_item(NAME(m_inc));
+ save_item(NAME(m_disable));
+}
+
+
+//-------------------------------------------------
+// device_clock_changed - called if the clock
+// changes
+//-------------------------------------------------
+
+void namco_163_sound_device::device_clock_changed()
+{
+ m_stream->set_sample_rate(clock() / 15);
+}
+
+
+inline s8 namco_163_sound_device::get_sample(u16 addr)
+{
+ return ((m_ram[(addr >> 1) & 0x7f] >> ((addr & 1) << 2)) & 0xf) - 8;
+}
+
+
+WRITE_LINE_MEMBER(namco_163_sound_device::disable_w)
+{
+ m_disable = state;
+}
+
+
+/********************************************************************************/
+
+/*
+ Register Map (in RAM)
+
+ 40 ffff ffff Channel 0 Frequency bits 0 - 7
+ 41 pppp pppp Channel 0 Phase bits 0 - 7
+ 42 ffff ffff Channel 0 Frequency bits 8 - 15
+ 43 pppp pppp Channel 0 Phase bits 8 - 15
+ 44 ---- --ff Channel 0 Frequency bits 16 - 17
+ llll ll-- Channel 0 Waveform Length (256 - (l * 4)) 4 bit samples
+ 45 pppp pppp Channel 0 Phase bits 16 - 23
+ 46 oooo oooo Channel 0 Waveform Offset at 4 bit samples
+ 47 ---- cccc Channel 0 Volume
+
+ 48 ffff ffff Channel 1 Frequency bits 0 - 7
+ 49 pppp pppp Channel 1 Phase bits 0 - 7
+ 4a ffff ffff Channel 1 Frequency bits 8 - 15
+ 4b pppp pppp Channel 1 Phase bits 8 - 15
+ 4c ---- --ff Channel 1 Frequency bits 16 - 17
+ llll ll-- Channel 1 Waveform Length (256 - (l * 4)) 4 bit samples
+ 4d pppp pppp Channel 1 Phase bits 16 - 23
+ 4e oooo oooo Channel 1 Waveform Offset at 4 bit samples
+ 4f ---- cccc Channel 1 Volume
+
+ .
+ .
+ .
+
+ 78 ffff ffff Channel 7 Frequency bits 0 - 7
+ 79 pppp pppp Channel 7 Phase bits 0 - 7
+ 7a ffff ffff Channel 7 Frequency bits 8 - 15
+ 7b pppp pppp Channel 7 Phase bits 8 - 15
+ 7c ---- --ff Channel 7 Frequency bits 16 - 17
+ llll ll-- Channel 7 Waveform Length (256 - (l * 4)) 4 bit samples
+ 7d pppp pppp Channel 7 Phase bits 16 - 23
+ 7e oooo oooo Channel 7 Waveform Offset at 4 bit samples
+ 7f ---- cccc Channel 7 Volume
+ -ccc ---- Enable channels
+ -000 ---- Enable channel 7 only
+ -001 ---- Enable channel 7, 6
+ -010 ---- Enable channel 7, 6, 5
+
+ .
+ .
+ .
+
+ -111 ---- Enable all channels
+*/
+
+void namco_163_sound_device::addr_w(u8 data)
+{
+ m_inc = data & 0x80;
+ m_addr = data & 0x7f;
+}
+
+
+void namco_163_sound_device::data_w(u8 data)
+{
+ m_stream->update();
+ m_ram[m_addr] = data;
+ if (m_inc)
+ m_addr = (m_addr + 1) & 0x7f;
+}
+
+
+u8 namco_163_sound_device::data_r()
+{
+ u8 val = m_ram[m_addr];
+ if (m_inc)
+ m_addr = (m_addr + 1) & 0x7f;
+
+ return val;
+}
+
+
+void namco_163_sound_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples)
+{
+ std::fill_n(&outputs[0][0], samples, 0);
+
+ if (m_disable)
+ return;
+
+ // Slightly noisy but closer to real hardware behavior
+ for (int s = 0; s < samples; s++)
+ {
+ u32 phase = (m_ram[m_reg_addr + 5] << 16) | (m_ram[m_reg_addr + 3] << 8) | m_ram[m_reg_addr + 1];
+ const u32 freq = ((m_ram[m_reg_addr + 4] & 0x3) << 16) | (m_ram[m_reg_addr + 2] << 8) | m_ram[m_reg_addr + 0];
+ const u16 length = 256 - (m_ram[m_reg_addr + 4] & 0xfc);
+ const u16 offset = m_ram[m_reg_addr + 6];
+ const u8 vol = m_ram[m_reg_addr + 7] & 0xf;
+
+ phase = (phase + freq) % (length << 16);
+ s32 output = get_sample((phase >> 16) + offset) * vol;
+
+ m_ram[m_reg_addr + 1] = phase & 0xff;
+ m_ram[m_reg_addr + 3] = phase >> 8;
+ m_ram[m_reg_addr + 5] = phase >> 16;
+
+ m_reg_addr += 8;
+ if (m_reg_addr >= 0x80)
+ {
+ m_reg_addr = 0x78 - ((m_ram[0x7f] & 0x70) >> 1);
+ }
+ outputs[0][s] = (output << 8);
+ }
+}
diff --git a/src/devices/sound/namco_163.h b/src/devices/sound/namco_163.h
new file mode 100644
index 00000000000..1256884242b
--- /dev/null
+++ b/src/devices/sound/namco_163.h
@@ -0,0 +1,42 @@
+// license:BSD-3-Clause
+// copyright-holders:cam900
+#ifndef MAME_SOUND_NAMCO_163_H
+#define MAME_SOUND_NAMCO_163_H
+
+#pragma once
+
+
+class namco_163_sound_device : public device_t,
+ public device_sound_interface
+{
+public:
+ namco_163_sound_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
+
+ DECLARE_WRITE_LINE_MEMBER(disable_w);
+
+ void addr_w(u8 data);
+ void data_w(u8 data);
+ u8 data_r();
+
+protected:
+ // device-level overrides
+ virtual void device_start() override;
+ virtual void device_clock_changed() override;
+
+ // global sound parameters
+ std::unique_ptr<u8[]> m_ram;
+ u8 m_reg_addr;
+ u8 m_addr;
+ bool m_inc;
+ bool m_disable;
+ sound_stream *m_stream;
+
+ // internals
+ inline s8 get_sample(u16 addr);
+
+ virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) override;
+};
+
+DECLARE_DEVICE_TYPE(NAMCO_163, namco_163_sound_device)
+
+#endif // MAME_SOUND_NAMCO_163_H
diff --git a/src/devices/sound/swp30.cpp b/src/devices/sound/swp30.cpp
index 56870df5ec7..f43df8084f9 100644
--- a/src/devices/sound/swp30.cpp
+++ b/src/devices/sound/swp30.cpp
@@ -150,8 +150,15 @@ 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, 25+2, ENDIANNESS_LITTLE, 32)
+ device_rom_interface(mconfig, *this, 25+2, ENDIANNESS_LITTLE, 32),
+ m_meg(*this, "meg")
{
+ (void)m_map;
+}
+
+void swp30_device::device_add_mconfig(machine_config &config)
+{
+ MEGEMB(config, m_meg);
}
void swp30_device::device_start()
@@ -160,7 +167,7 @@ void swp30_device::device_start()
// Attenuantion 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 is 1.16
+ // for other attenuation values. Computed value is 1.16
// format, to avoid overflow
for(int i=0; i<256; i++)
@@ -328,8 +335,8 @@ void swp30_device::map(address_map &map)
rchan(map, 0x27).rw(FUNC(swp30_device::prg_fp_r<3>), FUNC(swp30_device::prg_fp_w<3>));
rchan(map, 0x29).rw(FUNC(swp30_device::prg_fp_r<4>), FUNC(swp30_device::prg_fp_w<4>));
rchan(map, 0x2b).rw(FUNC(swp30_device::prg_fp_r<5>), FUNC(swp30_device::prg_fp_w<5>));
- rchan(map, 0x30).rw(FUNC(swp30_device::prg_int_r<0>), FUNC(swp30_device::prg_int_w<0>));
- rchan(map, 0x31).rw(FUNC(swp30_device::prg_int_r<1>), FUNC(swp30_device::prg_int_w<1>));
+ rchan(map, 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>));
}
@@ -381,14 +388,14 @@ void swp30_device::prg_address_w(u16 data)
template<int sel> u16 swp30_device::prg_r()
{
constexpr offs_t shift = 48-16*sel;
- return m_program[m_program_address] >> shift;
+ return m_meg->prg_r(m_program_address) >> shift;
}
template<int sel> void swp30_device::prg_w(u16 data)
{
constexpr offs_t shift = 48-16*sel;
constexpr u64 mask = ~(u64(0xffff) << shift);
- m_program[m_program_address] = (m_program[m_program_address] & mask) | (u64(data) << shift);
+ m_meg->prg_w(m_program_address, (m_meg->prg_r(m_program_address) & mask) | (u64(data) << shift));
if(sel == 3) {
if(0)
@@ -402,14 +409,12 @@ template<int sel> void swp30_device::prg_w(u16 data)
template<int sel> u16 swp30_device::map_r()
{
- return m_map[sel];
+ return m_meg->map_r(sel);
}
template<int sel> void swp30_device::map_w(u16 data)
{
- m_map[sel] = data;
- if(0)
- logerror("map %d: type=%02x offset=%05x size=%05x\n", sel, data >> 11, (data & 0xff) << 10, 0x400 << ((data >> 8) & 7));
+ m_meg->map_w(sel, data);
}
@@ -656,54 +661,36 @@ void swp30_device::address_l_w(offs_t offset, u16 data)
}
-// MEG registers (Multiple Effects Generator)
+// MEG registers forwarding
template<int sel> u16 swp30_device::prg_fp_r(offs_t offset)
{
- offs_t adr = (offset >> 6)*6 + sel;
- return m_program_pfp[adr];
+ return m_meg->fp_r((offset >> 6)*6 + sel);
}
template<int sel> void swp30_device::prg_fp_w(offs_t offset, u16 data)
{
- offs_t adr = (offset >> 6)*6 + sel;
- m_program_pfp[adr] = data;
- if(0)
- logerror("prg_fp_w %03x, %04x\n", adr, data);
+ m_meg->fp_w((offset >> 6)*6 + sel, data);
}
-template<int sel> u16 swp30_device::prg_int_r(offs_t offset)
+template<int sel> u16 swp30_device::prg_off_r(offs_t offset)
{
- offs_t adr = (offset >> 6)*2 + sel;
- return m_program_pint[adr];
+ return m_meg->offset_r((offset >> 6)*2 + sel);
}
-template<int sel> void swp30_device::prg_int_w(offs_t offset, u16 data)
+template<int sel> void swp30_device::prg_off_w(offs_t offset, u16 data)
{
- offs_t adr = (offset >> 6)*2 + sel;
- m_program_pint[adr] = data;
- if(0)
- logerror("prg_int_w %02x, %04x\n", adr, data);
+ m_meg->offset_w((offset >> 6)*2 + sel, data);
}
template<int sel> u16 swp30_device::prg_lfo_r(offs_t offset)
{
- offs_t adr = (offset >> 6)*2 + sel;
- return m_program_plfo[adr];
+ return m_meg->lfo_r((offset >> 6)*2 + sel);
}
template<int sel> void swp30_device::prg_lfo_w(offs_t offset, u16 data)
{
- offs_t adr = (offset >> 6)*2 + sel;
- m_program_plfo[adr] = data;
-
- static const int dt[8] = { 0, 32, 64, 128, 256, 512, 1024, 2048 };
- static const int sh[8] = { 0, 0, 1, 2, 3, 4, 5, 6 };
-
- int scale = (data >> 5) & 7;
- int step = ((data & 31) << sh[scale]) + dt[scale];
- if(0)
- logerror("prg_lfo_w %02x freq=%5.2f phase=%6.4f\n", adr, step * 44100.0/4194304, (data >> 8)/256.0);
+ m_meg->lfo_w((offset >> 6)*2 + sel, data);
}
diff --git a/src/devices/sound/swp30.h b/src/devices/sound/swp30.h
index 56e24b453f0..dd95a8dd85f 100644
--- a/src/devices/sound/swp30.h
+++ b/src/devices/sound/swp30.h
@@ -8,6 +8,8 @@
#pragma once
+#include "meg.h"
+
class swp30_device : public device_t, public device_sound_interface, public device_rom_interface
{
public:
@@ -20,8 +22,11 @@ protected:
virtual void device_reset() override;
virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) override;
virtual void rom_bank_updated() override;
+ virtual void device_add_mconfig(machine_config &config) override;
private:
+ required_device<meg_embedded_device> m_meg;
+
sound_stream *m_stream;
s32 m_sample_increment[0x4000];
@@ -99,8 +104,8 @@ private:
// 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_int_r(offs_t offset);
- template<int sel> void prg_int_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);
diff --git a/src/devices/sound/vrc6.cpp b/src/devices/sound/vrc6.cpp
index 29729fc9fcc..b769fde4043 100644
--- a/src/devices/sound/vrc6.cpp
+++ b/src/devices/sound/vrc6.cpp
@@ -2,7 +2,7 @@
// copyright-holders:R. Belmont
/***************************************************************************
- vrc6.c
+ vrc6.cpp
Konami VRC6 additional sound channels
Emulation by R. Belmont
@@ -16,8 +16,6 @@
#include "emu.h"
#include "vrc6.h"
-#define DISABLE_VRC6_SOUND // not ready yet
-
// device type definition
DEFINE_DEVICE_TYPE(VRC6, vrc6snd_device, "vrc6snd", "Konami VRC6 (Sound)")
@@ -29,10 +27,10 @@ DEFINE_DEVICE_TYPE(VRC6, vrc6snd_device, "vrc6snd", "Konami VRC6 (Sound)")
// vrc6snd_device - constructor
//-------------------------------------------------
-vrc6snd_device::vrc6snd_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+vrc6snd_device::vrc6snd_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
: device_t(mconfig, VRC6, tag, owner, clock)
, device_sound_interface(mconfig, *this)
- , m_freqctrl(0), m_pulsectrl{ 0, 0 }, m_sawrate(0)
+ , m_freqctrl(0), m_pulsectrl{ 0, 0 }, m_sawrate(0), m_master_freq(0)
, m_pulsefrql{ 0, 0 }, m_pulsefrqh{ 0, 0 }, m_pulseduty{ 0, 0 }
, m_sawfrql(0), m_sawfrqh(0), m_sawclock(0), m_sawaccum(0)
, m_ticks{ 0, 0, 0 }
@@ -55,10 +53,12 @@ void vrc6snd_device::device_start()
m_ticks[0] = m_ticks[1] = m_ticks[2] = 0;
m_output[0] = m_output[1] = m_output[2] = 0;
m_pulseduty[0] = m_pulseduty[1] = 15;
+ m_master_freq = 0;
save_item(NAME(m_freqctrl));
save_item(NAME(m_pulsectrl));
save_item(NAME(m_sawrate));
+ save_item(NAME(m_master_freq));
save_item(NAME(m_sawaccum));
save_item(NAME(m_pulsefrql));
save_item(NAME(m_pulsefrqh));
@@ -85,6 +85,7 @@ void vrc6snd_device::device_reset()
m_output[0] = m_output[1] = m_output[2] = 0;
m_pulseduty[0] = m_pulseduty[1] = 15;
m_pulsefrqh[0] = m_pulsefrqh[1] = m_sawfrqh = 0;
+ m_master_freq = 0;
}
//-------------------------------------------------
@@ -94,27 +95,22 @@ void vrc6snd_device::device_reset()
void vrc6snd_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples)
{
- stream_sample_t *out = outputs[0];
- int16_t tmp;
- int i;
+ std::fill_n(&outputs[0][0], samples, 0);
// check global halt bit
if (m_freqctrl & 1)
- {
return;
- }
- for (i = 0; i < samples; i++)
+ for (int i = 0; i < samples; i++)
{
// update pulse1
if (m_pulsefrqh[0] & 0x80)
{
- m_ticks[0]--;
if (m_ticks[0] == 0)
{
- m_ticks[0] = m_pulsefrql[0] | (m_pulsefrqh[0] & 0xf)<<4;
+ m_ticks[0] = (m_pulsefrql[0] | ((m_pulsefrqh[0] & 0xf) << 8)) >> m_master_freq;
- m_pulseduty[0]--;
+ m_pulseduty[0] = (m_pulseduty[0] - 1) & 0xf;
if (m_pulsectrl[0] & 0x80)
{
m_output[0] = m_pulsectrl[0] & 0xf;
@@ -130,12 +126,9 @@ void vrc6snd_device::sound_stream_update(sound_stream &stream, stream_sample_t *
m_output[0] = 0;
}
}
-
- if (m_pulseduty[0] == 0)
- {
- m_pulseduty[0] = 15;
- }
}
+ else
+ m_ticks[0]--;
}
else
{
@@ -145,12 +138,11 @@ void vrc6snd_device::sound_stream_update(sound_stream &stream, stream_sample_t *
// update pulse2
if (m_pulsefrqh[1] & 0x80)
{
- m_ticks[1]--;
if (m_ticks[1] == 0)
{
- m_ticks[1] = m_pulsefrql[1] | (m_pulsefrqh[1] & 0xf)<<4;
+ m_ticks[1] = (m_pulsefrql[1] | ((m_pulsefrqh[1] & 0xf) << 8)) >> m_master_freq;
- m_pulseduty[1]--;
+ m_pulseduty[1] = (m_pulseduty[1] - 1) & 0xf;
if (m_pulsectrl[1] & 0x80)
{
m_output[1] = m_pulsectrl[1] & 0xf;
@@ -166,12 +158,9 @@ void vrc6snd_device::sound_stream_update(sound_stream &stream, stream_sample_t *
m_output[1] = 0;
}
}
-
- if (m_pulseduty[1] == 0)
- {
- m_pulseduty[1] = 15;
- }
}
+ else
+ m_ticks[1]--;
}
else
{
@@ -181,10 +170,9 @@ void vrc6snd_device::sound_stream_update(sound_stream &stream, stream_sample_t *
// update saw
if (m_sawfrqh & 0x80)
{
- m_ticks[2]--;
if (m_ticks[2] == 0)
{
- m_ticks[2] = m_sawfrql | (m_sawfrqh & 0xf)<<4;
+ m_ticks[2] = (m_sawfrql | ((m_sawfrqh & 0xf) << 8)) >> m_master_freq;
// only update on even steps
if ((m_sawclock > 0) && (!(m_sawclock & 1)))
@@ -200,6 +188,8 @@ void vrc6snd_device::sound_stream_update(sound_stream &stream, stream_sample_t *
m_output[2] = 0;
}
}
+ else
+ m_ticks[2]--;
}
else
{
@@ -207,10 +197,10 @@ void vrc6snd_device::sound_stream_update(sound_stream &stream, stream_sample_t *
}
// sum 2 4-bit pulses, 1 5-bit saw = unsigned 6 bit output
- tmp = (int16_t)(uint8_t)(m_output[0] + m_output[1] + m_output[2]);
+ s16 tmp = (s16)(u8)(m_output[0] + m_output[1] + m_output[2]);
tmp <<= 8;
- out[i] = tmp;
+ outputs[0][i] = tmp;
}
}
@@ -218,7 +208,7 @@ void vrc6snd_device::sound_stream_update(sound_stream &stream, stream_sample_t *
// write - write to the chip's registers
//---------------------------------------
-void vrc6snd_device::write(offs_t offset, uint8_t data)
+void vrc6snd_device::write(offs_t offset, u8 data)
{
switch (offset >> 8)
{
@@ -232,28 +222,43 @@ void vrc6snd_device::write(offs_t offset, uint8_t data)
case 1:
m_pulsefrql[0] = data;
- if (!(m_pulsefrqh[1] & 0x80))
+ if (!(m_pulsefrqh[0] & 0x80))
{
- m_ticks[0] &= ~0xff;
- m_ticks[0] |= m_pulsefrql[0];
+ m_ticks[0] = (m_pulsefrql[0] | ((m_pulsefrqh[0] & 0xf) << 8)) >> m_master_freq;
}
break;
case 2:
- #ifndef DISABLE_VRC6_SOUND
m_pulsefrqh[0] = data;
// if disabling channel, reset phase
if (!(data & 0x80))
{
m_pulseduty[0] = 15;
- m_ticks[0] &= 0xff;
- m_ticks[0] |= (m_pulsefrqh[0] & 0xf)<<4;
+ m_ticks[0] = (m_pulsefrql[0] | ((m_pulsefrqh[0] & 0xf) << 8)) >> m_master_freq;
}
- #endif
break;
case 3:
m_freqctrl = data;
+ if (m_freqctrl & 4)
+ m_master_freq = 0x8;
+ else if (m_freqctrl & 2)
+ m_master_freq = 0x4;
+ else
+ m_master_freq = 0;
+
+ if (!(m_pulsefrqh[0] & 0x80))
+ {
+ m_ticks[0] = (m_pulsefrql[0] | ((m_pulsefrqh[0] & 0xf) << 8)) >> m_master_freq;
+ }
+ if (!(m_pulsefrqh[1] & 0x80))
+ {
+ m_ticks[1] = (m_pulsefrql[1] | ((m_pulsefrqh[1] & 0xf) << 8)) >> m_master_freq;
+ }
+ if (!(m_sawfrqh & 0x80))
+ {
+ m_ticks[2] = (m_sawfrql | ((m_sawfrqh & 0xf) << 8)) >> m_master_freq;
+ }
break;
}
break;
@@ -270,22 +275,18 @@ void vrc6snd_device::write(offs_t offset, uint8_t data)
m_pulsefrql[1] = data;
if (!(m_pulsefrqh[1] & 0x80))
{
- m_ticks[1] &= ~0xff;
- m_ticks[1] |= m_pulsefrql[1];
+ m_ticks[1] = (m_pulsefrql[1] | ((m_pulsefrqh[1] & 0xf) << 8)) >> m_master_freq;
}
break;
case 2:
- #ifndef DISABLE_VRC6_SOUND
m_pulsefrqh[1] = data;
// if disabling channel, reset phase
if (!(data & 0x80))
{
m_pulseduty[1] = 15;
- m_ticks[1] &= 0xff;
- m_ticks[1] |= (m_pulsefrqh[1] & 0xf)<<4;
+ m_ticks[1] = (m_pulsefrql[1] | ((m_pulsefrqh[1] & 0xf) << 8)) >> m_master_freq;
}
- #endif
break;
}
break;
@@ -302,22 +303,18 @@ void vrc6snd_device::write(offs_t offset, uint8_t data)
m_sawfrql = data;
if (!(m_sawfrqh & 0x80))
{
- m_ticks[2] &= ~0xff;
- m_ticks[2] |= m_sawfrql;
+ m_ticks[2] = (m_sawfrql | ((m_sawfrqh & 0xf) << 8)) >> m_master_freq;
}
break;
case 2:
- #ifndef DISABLE_VRC6_SOUND
m_sawfrqh = data;
// if disabling channel, reset phase
if (!(data & 0x80))
{
m_sawaccum = 0;
- m_ticks[2] &= 0xff;
- m_ticks[2] |= (m_sawfrqh & 0xf)<<4;
+ m_ticks[2] = (m_sawfrql | ((m_sawfrqh & 0xf) << 8)) >> m_master_freq;
}
- #endif
break;
}
break;
diff --git a/src/devices/sound/vrc6.h b/src/devices/sound/vrc6.h
index a24d34a90c4..f1ea8f5c9e3 100644
--- a/src/devices/sound/vrc6.h
+++ b/src/devices/sound/vrc6.h
@@ -22,9 +22,9 @@ class vrc6snd_device : public device_t, public device_sound_interface
{
public:
// construction/destruction
- vrc6snd_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+ vrc6snd_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
- void write(offs_t offset, uint8_t data);
+ void write(offs_t offset, u8 data);
protected:
// device-level overrides
@@ -34,11 +34,11 @@ protected:
virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) override;
private:
- uint8_t m_freqctrl, m_pulsectrl[2], m_sawrate;
- uint8_t m_pulsefrql[2], m_pulsefrqh[2], m_pulseduty[2];
- uint8_t m_sawfrql, m_sawfrqh, m_sawclock, m_sawaccum;
- uint16_t m_ticks[3];
- uint8_t m_output[3];
+ u8 m_freqctrl, m_pulsectrl[2], m_sawrate, m_master_freq;
+ u8 m_pulsefrql[2], m_pulsefrqh[2], m_pulseduty[2];
+ u8 m_sawfrql, m_sawfrqh, m_sawclock, m_sawaccum;
+ u16 m_ticks[3];
+ u8 m_output[3];
sound_stream *m_stream;
};
diff --git a/src/devices/sound/ym2413.cpp b/src/devices/sound/ym2413.cpp
index 3935b1baa0e..755e66ea629 100644
--- a/src/devices/sound/ym2413.cpp
+++ b/src/devices/sound/ym2413.cpp
@@ -42,6 +42,8 @@ to do:
#include "emu.h"
#include "ym2413.h"
+#include <algorithm>
+
#define FREQ_SH 16 /* 16.16 fixed point (frequency calculations) */
#define EG_SH 16 /* 16.16 fixed point (EG timing) */
#define LFO_SH 24 /* 8.24 fixed point (LFO calculations) */
@@ -131,7 +133,7 @@ const uint32_t ym2413_device::sl_tab[16] = {
};
#undef SC
-const unsigned char ym2413_device::eg_inc[15*RATE_STEPS] = {
+const uint8_t ym2413_device::eg_inc[15*RATE_STEPS] = {
/*cycle:0 1 2 3 4 5 6 7*/
/* 0 */ 0,1, 0,1, 0,1, 0,1, /* rates 00..12 0 (increment by 0 or 1) */
@@ -158,7 +160,7 @@ const unsigned char ym2413_device::eg_inc[15*RATE_STEPS] = {
#define O(a) (a*RATE_STEPS)
/*note that there is no O(13) in this table - it's directly in the code */
-const unsigned char ym2413_device::eg_rate_select[16+64+16] = { /* Envelope Generator rates (16 + 64 rates + 16 RKS) */
+const uint8_t ym2413_device::eg_rate_select[16+64+16] = { /* Envelope Generator rates (16 + 64 rates + 16 RKS) */
/* 16 infinite time rates */
O(14),O(14),O(14),O(14),O(14),O(14),O(14),O(14),
O(14),O(14),O(14),O(14),O(14),O(14),O(14),O(14),
@@ -199,7 +201,7 @@ const unsigned char ym2413_device::eg_rate_select[16+64+16] = { /* Envelope Ge
/*mask 8191, 4095, 2047, 1023, 511, 255, 127, 63, 31, 15, 7, 3, 1, 0, 0, 0 */
#define O(a) (a*1)
-const unsigned char ym2413_device::eg_rate_shift[16+64+16] = { /* Envelope Generator counter shifts (16 + 64 rates + 16 RKS) */
+const uint8_t ym2413_device::eg_rate_shift[16+64+16] = { /* Envelope Generator counter shifts (16 + 64 rates + 16 RKS) */
/* 16 infinite time rates */
O(0),O(0),O(0),O(0),O(0),O(0),O(0),O(0),
O(0),O(0),O(0),O(0),O(0),O(0),O(0),O(0),
@@ -350,9 +352,10 @@ const int8_t ym2413_device::lfo_pm_table[8*8] = {
- waveform DC and DM select are 100% correct
*/
-const unsigned char ym2413_device::table[19][8] = {
+const uint8_t ym2413_device::table[19][8] = {
/* MULT MULT modTL DcDmFb AR/DR AR/DR SL/RR SL/RR */
/* 0 1 2 3 4 5 6 7 */
+/* These YM2413(OPLL) patch dumps are done via audio analysis (and a/b testing?) from Jarek and are known to be inaccurate */
{0x49, 0x4c, 0x4c, 0x12, 0x00, 0x00, 0x00, 0x00 }, //0
{0x61, 0x61, 0x1e, 0x17, 0xf0, 0x78, 0x00, 0x17 }, //1
@@ -385,9 +388,45 @@ const unsigned char ym2413_device::table[19][8] = {
/* drum instruments definitions */
/* MULTI MULTI modTL xxx AR/DR AR/DR SL/RR SL/RR */
/* 0 1 2 3 4 5 6 7 */
- {0x01, 0x01, 0x16, 0x00, 0xfd, 0xf8, 0x2f, 0x6d },/* BD(multi verified, modTL verified, mod env - verified(close), carr. env verifed) */
- {0x01, 0x01, 0x00, 0x00, 0xd8, 0xd8, 0xf9, 0xf8 },/* HH(multi verified), SD(multi not used) */
- {0x05, 0x01, 0x00, 0x00, 0xf8, 0xba, 0x49, 0x55 },/* TOM(multi,env verified), TOP CYM(multi verified, env verified) */
+/* old dumps via audio analysis (and a/b testing?) from Jarek */
+//{0x01, 0x01, 0x16, 0x00, 0xfd, 0xf8, 0x2f, 0x6d },/* BD(multi verified, modTL verified, mod env - verified(close), carr. env verifed) */
+//{0x01, 0x01, 0x00, 0x00, 0xd8, 0xd8, 0xf9, 0xf8 },/* HH(multi verified), SD(multi not used) */
+//{0x05, 0x01, 0x00, 0x00, 0xf8, 0xba, 0x49, 0x55 },/* TOM(multi,env verified), TOP CYM(multi verified, env verified) */
+/* Drums dumped from the VRC7 using debug mode, these are likely also correct for ym2413(OPLL) but need verification */
+ {0x01, 0x01, 0x18, 0x0f, 0xdf, 0xf8, 0x6a, 0x6d },/* BD */
+ {0x01, 0x01, 0x00, 0x00, 0xc8, 0xd8, 0xa7, 0x68 },/* HH, SD */
+ {0x05, 0x01, 0x00, 0x00, 0xf8, 0xaa, 0x59, 0x55 },/* TOM, TOP CYM */
+};
+
+// VRC7 Instruments : Dumped from internal ROM
+// reference : https://siliconpr0n.org/archive/doku.php?id=vendor:yamaha:opl2
+const uint8_t vrc7snd_device::vrc7_table[19][8] = {
+/* MULT MULT modTL DcDmFb AR/DR AR/DR SL/RR SL/RR */
+/* 0 1 2 3 4 5 6 7 */
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, //0 (This is the user-defined instrument, should this default to anything?)
+
+ {0x03, 0x21, 0x05, 0x06, 0xe8, 0x81, 0x42, 0x27 }, //1
+ {0x13, 0x41, 0x14, 0x0d, 0xd8, 0xf6, 0x23, 0x12 }, //2
+ {0x11, 0x11, 0x08, 0x08, 0xfa, 0xb2, 0x20, 0x12 }, //3
+ {0x31, 0x61, 0x0c, 0x07, 0xa8, 0x64, 0x61, 0x27 }, //4
+ {0x32, 0x21, 0x1e, 0x06, 0xe1, 0x76, 0x01, 0x28 }, //5
+ {0x02, 0x01, 0x06, 0x00, 0xa3, 0xe2, 0xf4, 0xf4 }, //6
+ {0x21, 0x61, 0x1d, 0x07, 0x82, 0x81, 0x11, 0x07 }, //7
+ {0x23, 0x21, 0x22, 0x17, 0xa2, 0x72, 0x01, 0x17 }, //8
+ {0x35, 0x11, 0x25, 0x00, 0x40, 0x73, 0x72, 0x01 }, //9
+ {0xb5, 0x01, 0x0f, 0x0f, 0xa8, 0xa5, 0x51, 0x02 }, //A
+ {0x17, 0xc1, 0x24, 0x07, 0xf8, 0xf8, 0x22, 0x12 }, //B
+ {0x71, 0x23, 0x11, 0x06, 0x65, 0x74, 0x18, 0x16 }, //C
+ {0x01, 0x02, 0xd3, 0x05, 0xc9, 0x95, 0x03, 0x02 }, //D
+ {0x61, 0x63, 0x0c, 0x00, 0x94, 0xc0, 0x33, 0xf6 }, //E
+ {0x21, 0x72, 0x0d, 0x00, 0xc1, 0xd5, 0x56, 0x06 }, //F
+
+/* Drums (silent due to no RO output pin(?) on VRC7, but present internally; these are probably shared with YM2413) */
+/* MULTI MULTI modTL xxx AR/DR AR/DR SL/RR SL/RR */
+/* 0 1 2 3 4 5 6 7 */
+ {0x01, 0x01, 0x18, 0x0f, 0xdf, 0xf8, 0x6a, 0x6d },/* BD */
+ {0x01, 0x01, 0x00, 0x00, 0xc8, 0xd8, 0xa7, 0x68 },/* HH, SD */
+ {0x05, 0x01, 0x00, 0x00, 0xf8, 0xaa, 0x59, 0x55 },/* TOM, TOP CYM */
};
/* work table */
@@ -823,21 +862,21 @@ void ym2413_device::rhythm_calc( OPLL_CH *CH, unsigned int noise )
*/
/* base frequency derived from operator 1 in channel 7 */
- unsigned char bit7 = ((SLOT7_1->phase>>FREQ_SH)>>7)&1;
- unsigned char bit3 = ((SLOT7_1->phase>>FREQ_SH)>>3)&1;
- unsigned char bit2 = ((SLOT7_1->phase>>FREQ_SH)>>2)&1;
+ uint8_t bit7 = ((SLOT7_1->phase>>FREQ_SH)>>7)&1;
+ uint8_t bit3 = ((SLOT7_1->phase>>FREQ_SH)>>3)&1;
+ uint8_t bit2 = ((SLOT7_1->phase>>FREQ_SH)>>2)&1;
- unsigned char res1 = (bit2 ^ bit7) | bit3;
+ uint8_t res1 = (bit2 ^ bit7) | bit3;
/* when res1 = 0 phase = 0x000 | 0xd0; */
/* when res1 = 1 phase = 0x200 | (0xd0>>2); */
uint32_t phase = res1 ? (0x200|(0xd0>>2)) : 0xd0;
/* enable gate based on frequency of operator 2 in channel 8 */
- unsigned char bit5e= ((SLOT8_2->phase>>FREQ_SH)>>5)&1;
- unsigned char bit3e= ((SLOT8_2->phase>>FREQ_SH)>>3)&1;
+ uint8_t bit5e= ((SLOT8_2->phase>>FREQ_SH)>>5)&1;
+ uint8_t bit3e= ((SLOT8_2->phase>>FREQ_SH)>>3)&1;
- unsigned char res2 = (bit3e | bit5e);
+ uint8_t res2 = (bit3e | bit5e);
/* when res2 = 0 pass the phase from calculation above (res1); */
/* when res2 = 1 phase = 0x200 | (0xd0>>2); */
@@ -868,7 +907,7 @@ void ym2413_device::rhythm_calc( OPLL_CH *CH, unsigned int noise )
if( env < ENV_QUIET )
{
/* base frequency derived from operator 1 in channel 7 */
- unsigned char bit8 = ((SLOT7_1->phase>>FREQ_SH)>>8)&1;
+ uint8_t bit8 = ((SLOT7_1->phase>>FREQ_SH)>>8)&1;
/* when bit8 = 0 phase = 0x100; */
/* when bit8 = 1 phase = 0x200; */
@@ -894,21 +933,21 @@ void ym2413_device::rhythm_calc( OPLL_CH *CH, unsigned int noise )
if( env < ENV_QUIET )
{
/* base frequency derived from operator 1 in channel 7 */
- unsigned char bit7 = ((SLOT7_1->phase>>FREQ_SH)>>7)&1;
- unsigned char bit3 = ((SLOT7_1->phase>>FREQ_SH)>>3)&1;
- unsigned char bit2 = ((SLOT7_1->phase>>FREQ_SH)>>2)&1;
+ uint8_t bit7 = ((SLOT7_1->phase>>FREQ_SH)>>7)&1;
+ uint8_t bit3 = ((SLOT7_1->phase>>FREQ_SH)>>3)&1;
+ uint8_t bit2 = ((SLOT7_1->phase>>FREQ_SH)>>2)&1;
- unsigned char res1 = (bit2 ^ bit7) | bit3;
+ uint8_t res1 = (bit2 ^ bit7) | bit3;
/* when res1 = 0 phase = 0x000 | 0x100; */
/* when res1 = 1 phase = 0x200 | 0x100; */
uint32_t phase = res1 ? 0x300 : 0x100;
/* enable gate based on frequency of operator 2 in channel 8 */
- unsigned char bit5e= ((SLOT8_2->phase>>FREQ_SH)>>5)&1;
- unsigned char bit3e= ((SLOT8_2->phase>>FREQ_SH)>>3)&1;
+ uint8_t bit5e= ((SLOT8_2->phase>>FREQ_SH)>>5)&1;
+ uint8_t bit3e= ((SLOT8_2->phase>>FREQ_SH)>>3)&1;
- unsigned char res2 = (bit3e | bit5e);
+ uint8_t res2 = (bit3e | bit5e);
/* when res2 = 0 pass the phase from calculation above (res1); */
/* when res2 = 1 phase = 0x200 | 0x100; */
if (res2)
@@ -1635,11 +1674,14 @@ void ym2413_device::device_reset()
noise_rng = 1; /* noise shift register */
/* setup instruments table */
- for (int i=0; i<19; i++)
+ if (m_inst_table != nullptr)
{
- for (int c=0; c<8; c++)
+ for (int i=0; i<19; i++)
{
- inst_tab[i][c] = table[i][c];
+ for (int c=0; c<8; c++)
+ {
+ inst_tab[i][c] = m_inst_table[i][c];
+ }
}
}
@@ -1686,7 +1728,37 @@ void ym2413_device::data_port_w(u8 data)
DEFINE_DEVICE_TYPE(YM2413, ym2413_device, "ym2413", "Yamaha YM2413 OPLL")
ym2413_device::ym2413_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : device_t(mconfig, YM2413, tag, owner, clock)
+ : ym2413_device(mconfig, YM2413, tag, owner, clock)
+{
+ for (int i = 0; i < 19; i++)
+ {
+ for (int c = 0; c < 8; c++)
+ {
+ m_inst_table[i][c] = table[i][c];
+ }
+ }
+}
+
+ym2413_device::ym2413_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
+ : device_t(mconfig, type, tag, owner, clock)
, device_sound_interface(mconfig, *this)
{
+ for (int i = 0; i < 19; i++)
+ {
+ std::fill_n(&m_inst_table[i][0], 8, 0);
+ }
+}
+
+DEFINE_DEVICE_TYPE(VRC7, vrc7snd_device, "vrc7snd", "Konami VRC7 (Sound)")
+
+vrc7snd_device::vrc7snd_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : ym2413_device(mconfig, VRC7, tag, owner, clock)
+{
+ for (int i = 0; i < 19; i++)
+ {
+ for (int c = 0; c < 8; c++)
+ {
+ m_inst_table[i][c] = vrc7_table[i][c];
+ }
+ }
}
diff --git a/src/devices/sound/ym2413.h b/src/devices/sound/ym2413.h
index 32114624eff..1b0d9869770 100644
--- a/src/devices/sound/ym2413.h
+++ b/src/devices/sound/ym2413.h
@@ -17,6 +17,8 @@ public:
void data_port_w(u8 data);
protected:
+ ym2413_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
+
// device-level overrides
virtual void device_start() override;
virtual void device_clock_changed() override;
@@ -25,6 +27,8 @@ protected:
// sound stream update overrides
virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) override;
+ uint8_t m_inst_table[19][8];
+
private:
struct OPLL_SLOT
{
@@ -106,13 +110,13 @@ private:
static const double ksl_tab[8*16];
static const uint32_t ksl_shift[4];
static const uint32_t sl_tab[16];
- static const unsigned char eg_inc[15*RATE_STEPS];
- static const unsigned char eg_rate_select[16+64+16];
- static const unsigned char eg_rate_shift[16+64+16];
+ static const uint8_t eg_inc[15*RATE_STEPS];
+ static const uint8_t eg_rate_select[16+64+16];
+ static const uint8_t eg_rate_shift[16+64+16];
static const uint8_t mul_tab[16];
static const uint8_t lfo_am_table[LFO_AM_TAB_ELEMENTS];
static const int8_t lfo_pm_table[8*8];
- static const unsigned char table[19][8];
+ static const uint8_t table[19][8];
int tl_tab[TL_TAB_LEN];
@@ -185,4 +189,15 @@ private:
DECLARE_DEVICE_TYPE(YM2413, ym2413_device)
+class vrc7snd_device : public ym2413_device
+{
+public:
+ vrc7snd_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+private:
+ static const uint8_t vrc7_table[19][8];
+};
+
+DECLARE_DEVICE_TYPE(VRC7, vrc7snd_device)
+
#endif // MAME_SOUND_YM2413_H