diff options
Diffstat (limited to 'src/devices/sound/es5506.cpp')
-rw-r--r-- | src/devices/sound/es5506.cpp | 2246 |
1 files changed, 1051 insertions, 1195 deletions
diff --git a/src/devices/sound/es5506.cpp b/src/devices/sound/es5506.cpp index bc690058fe7..455c991b94b 100644 --- a/src/devices/sound/es5506.cpp +++ b/src/devices/sound/es5506.cpp @@ -84,6 +84,7 @@ Ensoniq OTIS - ES5505 Ensoniq OTTO - #include "emu.h" #include "es5506.h" +#include <algorithm> #if ES5506_MAKE_WAVS #include "sound/wavwrite.h" @@ -96,79 +97,100 @@ Ensoniq OTIS - ES5505 Ensoniq OTTO - ***********************************************************************************************/ +#define LOG_SERIAL (1U << 1) + #define VERBOSE 0 #include "logmacro.h" #define RAINE_CHECK 0 +static constexpr u32 FINE_FILTER_BIT = 16; +static constexpr u32 FILTER_BIT = 12; +static constexpr u32 FILTER_SHIFT = FINE_FILTER_BIT - FILTER_BIT; + +static constexpr u32 ULAW_MAXBITS = 8; + +namespace { + +enum : u16 { + CONTROL_BS1 = 0x8000, + CONTROL_BS0 = 0x4000, + CONTROL_CMPD = 0x2000, + CONTROL_CA2 = 0x1000, + CONTROL_CA1 = 0x0800, + CONTROL_CA0 = 0x0400, + CONTROL_LP4 = 0x0200, + CONTROL_LP3 = 0x0100, + CONTROL_IRQ = 0x0080, + CONTROL_DIR = 0x0040, + CONTROL_IRQE = 0x0020, + CONTROL_BLE = 0x0010, + CONTROL_LPE = 0x0008, + CONTROL_LEI = 0x0004, + CONTROL_STOP1 = 0x0002, + CONTROL_STOP0 = 0x0001, + + CONTROL_BSMASK = (CONTROL_BS1 | CONTROL_BS0), + CONTROL_CAMASK = (CONTROL_CA2 | CONTROL_CA1 | CONTROL_CA0), + CONTROL_LPMASK = (CONTROL_LP4 | CONTROL_LP3), + CONTROL_LOOPMASK = (CONTROL_BLE | CONTROL_LPE), + CONTROL_STOPMASK = (CONTROL_STOP1 | CONTROL_STOP0), + + // ES5505 has sightly different control bit + CONTROL_5505_LP4 = 0x0800, + CONTROL_5505_LP3 = 0x0400, + CONTROL_5505_CA1 = 0x0200, + CONTROL_5505_CA0 = 0x0100, + + CONTROL_5505_LPMASK = (CONTROL_5505_LP4 | CONTROL_5505_LP3), + CONTROL_5505_CAMASK = (CONTROL_5505_CA1 | CONTROL_5505_CA0) +}; + +} -#define MAX_SAMPLE_CHUNK 10000 -#define ULAW_MAXBITS 8 - -#define CONTROL_BS1 0x8000 -#define CONTROL_BS0 0x4000 -#define CONTROL_CMPD 0x2000 -#define CONTROL_CA2 0x1000 -#define CONTROL_CA1 0x0800 -#define CONTROL_CA0 0x0400 -#define CONTROL_LP4 0x0200 -#define CONTROL_LP3 0x0100 -#define CONTROL_IRQ 0x0080 -#define CONTROL_DIR 0x0040 -#define CONTROL_IRQE 0x0020 -#define CONTROL_BLE 0x0010 -#define CONTROL_LPE 0x0008 -#define CONTROL_LEI 0x0004 -#define CONTROL_STOP1 0x0002 -#define CONTROL_STOP0 0x0001 - -#define CONTROL_BSMASK (CONTROL_BS1 | CONTROL_BS0) -#define CONTROL_CAMASK (CONTROL_CA2 | CONTROL_CA1 | CONTROL_CA0) -#define CONTROL_LPMASK (CONTROL_LP4 | CONTROL_LP3) -#define CONTROL_LOOPMASK (CONTROL_BLE | CONTROL_LPE) -#define CONTROL_STOPMASK (CONTROL_STOP1 | CONTROL_STOP0) - - -es550x_device::es550x_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), - m_stream(nullptr), - m_sample_rate(0), - m_write_latch(0), - m_read_latch(0), - m_master_clock(0), - m_current_page(0), - m_active_voices(0), - m_mode(0), - m_wst(0), - m_wend(0), - m_lrend(0), - m_irqv(0), - m_scratch(nullptr), - m_ulaw_lookup(nullptr), - m_volume_lookup(nullptr), +es550x_device::es550x_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock) + : device_t(mconfig, type, tag, owner, clock) + , device_sound_interface(mconfig, *this) + , device_memory_interface(mconfig, *this) + , m_stream(nullptr) + , m_sample_rate(0) + , m_master_clock(0) + , m_address_acc_shift(0) + , m_address_acc_mask(0) + , m_volume_shift(0) + , m_volume_acc_shift(0) + , m_current_page(0) + , m_active_voices(0x1f) + , m_mode(0) + , m_irqv(0x80) + , m_voice_index(0) #if ES5506_MAKE_WAVS - m_wavraw(nullptr), + , m_wavraw(nullptr) #endif - m_region0(nullptr), - m_region1(nullptr), - m_region2(nullptr), - m_region3(nullptr), - m_channels(0), - m_irq_cb(*this), - m_read_port_cb(*this), - m_sample_rate_changed_cb(*this) + , m_region0(*this, finder_base::DUMMY_TAG) + , m_region1(*this, finder_base::DUMMY_TAG) + , m_region2(*this, finder_base::DUMMY_TAG) + , m_region3(*this, finder_base::DUMMY_TAG) + , m_channels(0) + , m_irq_cb(*this) + , m_read_port_cb(*this, 0) + , m_sample_rate_changed_cb(*this) { - for (auto & elem : m_region_base) - { - elem = nullptr; - } } DEFINE_DEVICE_TYPE(ES5506, es5506_device, "es5506", "Ensoniq ES5506") -es5506_device::es5506_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) +es5506_device::es5506_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) : es550x_device(mconfig, ES5506, tag, owner, clock) + , m_bank0_config("bank0", ENDIANNESS_BIG, 16, 21, -1) // 21 bit address bus, word addressing only + , m_bank1_config("bank1", ENDIANNESS_BIG, 16, 21, -1) + , m_bank2_config("bank2", ENDIANNESS_BIG, 16, 21, -1) + , m_bank3_config("bank3", ENDIANNESS_BIG, 16, 21, -1) + , m_write_latch(0) + , m_read_latch(0) + , m_wst(0) + , m_wend(0) + , m_lrend(0) { } @@ -177,129 +199,94 @@ es5506_device::es5506_device(const machine_config &mconfig, const char *tag, dev //------------------------------------------------- void es550x_device::device_start() { + // initialize the rest of the structure + m_master_clock = clock(); + m_irqv = 0x80; + + // register save + save_item(NAME(m_sample_rate)); + + save_item(NAME(m_current_page)); + save_item(NAME(m_active_voices)); + save_item(NAME(m_mode)); + save_item(NAME(m_irqv)); + save_item(NAME(m_voice_index)); + + save_item(STRUCT_MEMBER(m_voice, control)); + save_item(STRUCT_MEMBER(m_voice, freqcount)); + save_item(STRUCT_MEMBER(m_voice, start)); + save_item(STRUCT_MEMBER(m_voice, end)); + save_item(STRUCT_MEMBER(m_voice, accum)); + save_item(STRUCT_MEMBER(m_voice, lvol)); + save_item(STRUCT_MEMBER(m_voice, rvol)); + save_item(STRUCT_MEMBER(m_voice, k2)); + save_item(STRUCT_MEMBER(m_voice, k1)); + save_item(STRUCT_MEMBER(m_voice, o4n1)); + save_item(STRUCT_MEMBER(m_voice, o3n1)); + save_item(STRUCT_MEMBER(m_voice, o3n2)); + save_item(STRUCT_MEMBER(m_voice, o2n1)); + save_item(STRUCT_MEMBER(m_voice, o2n2)); + save_item(STRUCT_MEMBER(m_voice, o1n1)); } void es5506_device::device_start() { - int j; - uint32_t accum_mask; - int channels = 1; /* 1 channel by default, for backward compatibility */ + es550x_device::device_start(); + int channels = 1; // 1 channel by default, for backward compatibility - /* only override the number of channels if the value is in the valid range 1 .. 6 */ + // only override the number of channels if the value is in the valid range 1 .. 6 if (1 <= m_channels && m_channels <= 6) channels = m_channels; - /* create the stream */ - m_stream = machine().sound().stream_alloc(*this, 0, 2 * channels, clock() / (16*32)); + // create the stream + m_stream = stream_alloc(0, 2 * channels, clock() / (16*32)); - /* initialize the regions */ - m_region_base[0] = m_region_base[1] = m_region_base[2] = m_region_base[3] = nullptr; - if (m_region0) - { - memory_region *region0 = machine().root_device().memregion(m_region0); - if (region0 != nullptr) - { - m_region_base[0] = (uint16_t *)region0->base(); - } - } - if (m_region1) - { - memory_region *region1 = machine().root_device().memregion(m_region1); - if (region1 != nullptr) - { - m_region_base[1] = (uint16_t *)region1->base(); - } - } - if (m_region2) - { - memory_region *region2 = machine().root_device().memregion(m_region2); - if (region2 != nullptr) - { - m_region_base[2] = (uint16_t *)region2->base(); - } - } - if (m_region3) - { - memory_region *region3 = machine().root_device().memregion(m_region3); - if (region3 != nullptr) - { - m_region_base[3] = (uint16_t *)region3->base(); - } - } + // initialize the regions + if (m_region0 && !has_configured_map(0)) + space(0).install_rom(0, std::min<offs_t>((1 << ADDRESS_INTEGER_BIT_ES5506) - 1, (m_region0->bytes() / 2) - 1), m_region0->base()); - /* initialize the rest of the structure */ - m_master_clock = clock(); - m_irq_cb.resolve(); - m_read_port_cb.resolve(); - m_sample_rate_changed_cb.resolve(); - m_irqv = 0x80; + if (m_region1 && !has_configured_map(1)) + space(1).install_rom(0, std::min<offs_t>((1 << ADDRESS_INTEGER_BIT_ES5506) - 1, (m_region1->bytes() / 2) - 1), m_region1->base()); + + if (m_region2 && !has_configured_map(2)) + space(2).install_rom(0, std::min<offs_t>((1 << ADDRESS_INTEGER_BIT_ES5506) - 1, (m_region2->bytes() / 2) - 1), m_region2->base()); + + if (m_region3 && !has_configured_map(3)) + space(3).install_rom(0, std::min<offs_t>((1 << ADDRESS_INTEGER_BIT_ES5506) - 1, (m_region3->bytes() / 2) - 1), m_region3->base()); + + for (int s = 0; s < 4; s++) + space(s).cache(m_cache[s]); + + // compute the tables + compute_tables(VOLUME_BIT_ES5506, 4, 8); // 4 bit exponent, 8 bit mantissa + + // initialize the rest of the structure m_channels = channels; - /* KT-76 assumes all voices are active on an ES5506 without setting them! */ + // KT-76 assumes all voices are active on an ES5506 without setting them! m_active_voices = 31; m_sample_rate = m_master_clock / (16 * (m_active_voices + 1)); m_stream->set_sample_rate(m_sample_rate); - /* compute the tables */ - compute_tables(); + // 21 bit integer and 11 bit fraction + get_accum_mask(ADDRESS_INTEGER_BIT_ES5506, ADDRESS_FRAC_BIT_ES5506); - /* init the voices */ - accum_mask = 0xffffffff; - for (j = 0; j < 32; j++) - { - m_voice[j].index = j; - m_voice[j].control = CONTROL_STOPMASK; - m_voice[j].lvol = 0xffff; - m_voice[j].rvol = 0xffff; - m_voice[j].exbank = 0; - m_voice[j].accum_mask = accum_mask; - } - - /* allocate memory */ - m_scratch = make_unique_clear<int32_t[]>(2 * MAX_SAMPLE_CHUNK); - - /* register save */ - save_item(NAME(m_sample_rate)); + // register save save_item(NAME(m_write_latch)); save_item(NAME(m_read_latch)); - save_item(NAME(m_current_page)); - save_item(NAME(m_active_voices)); - save_item(NAME(m_mode)); save_item(NAME(m_wst)); save_item(NAME(m_wend)); save_item(NAME(m_lrend)); - save_item(NAME(m_irqv)); - - save_pointer(NAME(m_scratch), 2 * MAX_SAMPLE_CHUNK); - for (j = 0; j < 32; j++) - { - save_item(NAME(m_voice[j].control), j); - save_item(NAME(m_voice[j].freqcount), j); - save_item(NAME(m_voice[j].start), j); - save_item(NAME(m_voice[j].lvol), j); - save_item(NAME(m_voice[j].end), j); - save_item(NAME(m_voice[j].lvramp), j); - save_item(NAME(m_voice[j].accum), j); - save_item(NAME(m_voice[j].rvol), j); - save_item(NAME(m_voice[j].rvramp), j); - save_item(NAME(m_voice[j].ecount), j); - save_item(NAME(m_voice[j].k2), j); - save_item(NAME(m_voice[j].k2ramp), j); - save_item(NAME(m_voice[j].k1), j); - save_item(NAME(m_voice[j].k1ramp), j); - save_item(NAME(m_voice[j].o4n1), j); - save_item(NAME(m_voice[j].o3n1), j); - save_item(NAME(m_voice[j].o3n2), j); - save_item(NAME(m_voice[j].o2n1), j); - save_item(NAME(m_voice[j].o2n2), j); - save_item(NAME(m_voice[j].o1n1), j); - save_item(NAME(m_voice[j].exbank), j); - save_item(NAME(m_voice[j].filtcount), j); - } + save_item(STRUCT_MEMBER(m_voice, ecount)); + save_item(STRUCT_MEMBER(m_voice, lvramp)); + save_item(STRUCT_MEMBER(m_voice, rvramp)); + save_item(STRUCT_MEMBER(m_voice, k2ramp)); + save_item(STRUCT_MEMBER(m_voice, k1ramp)); + save_item(STRUCT_MEMBER(m_voice, filtcount)); - /* success */ + // success } //------------------------------------------------- @@ -311,8 +298,7 @@ void es550x_device::device_clock_changed() m_master_clock = clock(); m_sample_rate = m_master_clock / (16 * (m_active_voices + 1)); m_stream->set_sample_rate(m_sample_rate); - if (!m_sample_rate_changed_cb.isnull()) - m_sample_rate_changed_cb(m_sample_rate); + m_sample_rate_changed_cb(m_sample_rate); } //------------------------------------------------- @@ -323,6 +309,13 @@ void es550x_device::device_reset() { } +void es5506_device::device_reset() // RESB for Reset input +{ + m_active_voices = 0x1f; // 32 voice at reset + m_mode = 0x17; // Dual, Slave, BCLK_EN high, WCLK_EN high, LRCLK_EN high + notify_clock_changed(); +} + //------------------------------------------------- // device_stop - device-specific stop //------------------------------------------------- @@ -331,21 +324,32 @@ void es550x_device::device_stop() { #if ES5506_MAKE_WAVS { - int i; - - for (i = 0; i < MAX_ES5506; i++) - { - if (es5506[i].m_wavraw) - wav_close(es5506[i].m_wavraw); - } + wav_close(m_wavraw); } #endif } +//------------------------------------------------- +// memory_space_config - return a description of +// any address spaces owned by this device +//------------------------------------------------- + +device_memory_interface::space_config_vector es5506_device::memory_space_config() const +{ + return space_config_vector{ + std::make_pair(0, &m_bank0_config), + std::make_pair(1, &m_bank1_config), + std::make_pair(2, &m_bank2_config), + std::make_pair(3, &m_bank3_config) + }; +} + DEFINE_DEVICE_TYPE(ES5505, es5505_device, "es5505", "Ensoniq ES5505") -es5505_device::es5505_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) +es5505_device::es5505_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) : es550x_device(mconfig, ES5505, tag, owner, clock) + , m_bank0_config("bank0", ENDIANNESS_BIG, 16, 20, -1) // 20 bit address bus, word addressing only + , m_bank1_config("bank1", ENDIANNESS_BIG, 16, 20, -1) { } @@ -355,100 +359,51 @@ es5505_device::es5505_device(const machine_config &mconfig, const char *tag, dev void es5505_device::device_start() { - int j; - uint32_t accum_mask; - int channels = 1; /* 1 channel by default, for backward compatibility */ + es550x_device::device_start(); + int channels = 1; // 1 channel by default, for backward compatibility - /* only override the number of channels if the value is in the valid range 1 .. 4 */ + // only override the number of channels if the value is in the valid range 1 .. 4 if (1 <= m_channels && m_channels <= 4) channels = m_channels; - /* create the stream */ - m_stream = machine().sound().stream_alloc(*this, 0, 2 * channels, clock() / (16*32)); - - /* initialize the regions */ - if (m_region0) - { - memory_region* region = machine().root_device().memregion(m_region0); - m_region_base[0] = region ? reinterpret_cast<uint16_t *>(region->base()) : nullptr; - } - if (m_region1) - { - memory_region* region = machine().root_device().memregion(m_region1); - m_region_base[1] = region ? reinterpret_cast<uint16_t *>(region->base()) : nullptr; - } + // create the stream + m_stream = stream_alloc(0, 2 * channels, clock() / (16*32)); - /* initialize the rest of the structure */ - m_master_clock = clock(); - m_irq_cb.resolve(); - m_read_port_cb.resolve(); - m_sample_rate_changed_cb.resolve(); - m_irqv = 0x80; - m_channels = channels; + // initialize the regions + if (m_region0 && !has_configured_map(0)) + space(0).install_rom(0, std::min<offs_t>((1 << ADDRESS_INTEGER_BIT_ES5505) - 1, (m_region0->bytes() / 2) - 1), m_region0->base()); - /* compute the tables */ - compute_tables(); + if (m_region1 && !has_configured_map(1)) + space(1).install_rom(0, std::min<offs_t>((1 << ADDRESS_INTEGER_BIT_ES5505) - 1, (m_region1->bytes() / 2) - 1), m_region1->base()); - /* init the voices */ - accum_mask = 0x7fffffff; - for (j = 0; j < 32; j++) - { - m_voice[j].index = j; - m_voice[j].control = CONTROL_STOPMASK; - m_voice[j].lvol = 0xffff; - m_voice[j].rvol = 0xffff; - m_voice[j].exbank = 0; - m_voice[j].accum_mask = accum_mask; - } + for (int s = 0; s < 2; s++) + space(s).cache(m_cache[s]); - /* allocate memory */ - m_scratch = make_unique_clear<int32_t[]>(2 * MAX_SAMPLE_CHUNK); + // compute the tables + compute_tables(VOLUME_BIT_ES5505, 4, 4); // 4 bit exponent, 4 bit mantissa - /* register save */ - save_item(NAME(m_sample_rate)); - save_item(NAME(m_write_latch)); - save_item(NAME(m_read_latch)); + // initialize the rest of the structure + m_channels = channels; - save_item(NAME(m_current_page)); - save_item(NAME(m_active_voices)); - save_item(NAME(m_mode)); - save_item(NAME(m_wst)); - save_item(NAME(m_wend)); - save_item(NAME(m_lrend)); - save_item(NAME(m_irqv)); + // 20 bit integer and 9 bit fraction + get_accum_mask(ADDRESS_INTEGER_BIT_ES5505, ADDRESS_FRAC_BIT_ES5505); - save_pointer(NAME(m_scratch), 2 * MAX_SAMPLE_CHUNK); + // success +} - for (j = 0; j < 32; j++) - { - save_item(NAME(m_voice[j].control), j); - save_item(NAME(m_voice[j].freqcount), j); - save_item(NAME(m_voice[j].start), j); - save_item(NAME(m_voice[j].lvol), j); - save_item(NAME(m_voice[j].end), j); - save_item(NAME(m_voice[j].lvramp), j); - save_item(NAME(m_voice[j].accum), j); - save_item(NAME(m_voice[j].rvol), j); - save_item(NAME(m_voice[j].rvramp), j); - save_item(NAME(m_voice[j].ecount), j); - save_item(NAME(m_voice[j].k2), j); - save_item(NAME(m_voice[j].k2ramp), j); - save_item(NAME(m_voice[j].k1), j); - save_item(NAME(m_voice[j].k1ramp), j); - save_item(NAME(m_voice[j].o4n1), j); - save_item(NAME(m_voice[j].o3n1), j); - save_item(NAME(m_voice[j].o3n2), j); - save_item(NAME(m_voice[j].o2n1), j); - save_item(NAME(m_voice[j].o2n2), j); - save_item(NAME(m_voice[j].o1n1), j); - save_item(NAME(m_voice[j].exbank), j); - save_item(NAME(m_voice[j].filtcount), j); - } +//------------------------------------------------- +// memory_space_config - return a description of +// any address spaces owned by this device +//------------------------------------------------- - /* success */ +device_memory_interface::space_config_vector es5505_device::memory_space_config() const +{ + return space_config_vector{ + std::make_pair(0, &m_bank0_config), + std::make_pair(1, &m_bank1_config) + }; } - /********************************************************************************************** update_irq_state -- update the IRQ state @@ -458,9 +413,8 @@ void es5505_device::device_start() void es550x_device::update_irq_state() { - /* ES5505/6 irq line has been set high - inform the host */ - if (!m_irq_cb.isnull()) - m_irq_cb(1); /* IRQB set high */ + // ES5505/6 irq line has been set high - inform the host + m_irq_cb(1); // IRQB set high } void es550x_device::update_internal_irq_state() @@ -474,10 +428,9 @@ void es550x_device::update_internal_irq_state() terms they get updated next time generate_samples() is called. */ - m_irqv=0x80; + m_irqv = 0x80; - if (!m_irq_cb.isnull()) - m_irq_cb(0); /* IRQB set low */ + m_irq_cb(0); // IRQB set low } /********************************************************************************************** @@ -486,42 +439,73 @@ void es550x_device::update_internal_irq_state() ***********************************************************************************************/ -void es550x_device::compute_tables() +void es550x_device::compute_tables(u32 total_volume_bit, u32 exponent_bit, u32 mantissa_bit) { - int i; - - /* allocate ulaw lookup table */ - m_ulaw_lookup = make_unique_clear<int16_t[]>(1 << ULAW_MAXBITS); + // allocate ulaw lookup table + m_ulaw_lookup.resize(1 << ULAW_MAXBITS); - /* generate ulaw lookup table */ - for (i = 0; i < (1 << ULAW_MAXBITS); i++) + // generate ulaw lookup table + for (int i = 0; i < (1 << ULAW_MAXBITS); i++) { - uint16_t rawval = (i << (16 - ULAW_MAXBITS)) | (1 << (15 - ULAW_MAXBITS)); - uint8_t exponent = rawval >> 13; - uint32_t mantissa = (rawval << 3) & 0xffff; + const u16 rawval = (i << (16 - ULAW_MAXBITS)) | (1 << (15 - ULAW_MAXBITS)); + const u8 exponent = rawval >> 13; + u32 mantissa = (rawval << 3) & 0xffff; if (exponent == 0) - m_ulaw_lookup[i] = (int16_t)mantissa >> 7; + m_ulaw_lookup[i] = s16(mantissa) >> 7; else { mantissa = (mantissa >> 1) | (~mantissa & 0x8000); - m_ulaw_lookup[i] = (int16_t)mantissa >> (7 - exponent); + m_ulaw_lookup[i] = s16(mantissa) >> (7 - exponent); } } - /* allocate volume lookup table */ - m_volume_lookup = make_unique_clear<uint16_t[]>(4096); + const u32 volume_bit = (exponent_bit + mantissa_bit); + m_volume_shift = total_volume_bit - volume_bit; + const u32 volume_len = 1 << volume_bit; + // allocate volume lookup table + m_volume_lookup.resize(volume_len); + + // generate volume lookup table + const u32 exponent_shift = 1 << exponent_bit; + const u32 exponent_mask = exponent_shift - 1; + + const u32 mantissa_len = (1 << mantissa_bit); + const u32 mantissa_mask = (mantissa_len - 1); + const u32 mantissa_shift = exponent_shift - mantissa_bit - 1; - /* generate volume lookup table */ - for (i = 0; i < 4096; i++) + for (int i = 0; i < volume_len; i++) { - uint8_t exponent = i >> 8; - uint32_t mantissa = (i & 0xff) | 0x100; + const u32 exponent = (i >> mantissa_bit) & exponent_mask; + const u32 mantissa = (i & mantissa_mask) | mantissa_len; - m_volume_lookup[i] = (mantissa << 11) >> (20 - exponent); + m_volume_lookup[i] = (mantissa << mantissa_shift) >> (exponent_shift - exponent); + } + m_volume_acc_shift = (16 + exponent_mask) - VOLUME_ACC_BIT; + + // init the voices + for (int j = 0; j < 32; j++) + { + m_voice[j].index = j; + m_voice[j].control = CONTROL_STOPMASK; + m_voice[j].lvol = (1 << (total_volume_bit - 1)); + m_voice[j].rvol = (1 << (total_volume_bit - 1)); } } +/********************************************************************************************** + + get_accum_mask -- get address accumulator mask + +***********************************************************************************************/ + +void es550x_device::get_accum_mask(u32 address_integer, u32 address_frac) +{ + m_address_acc_shift = ADDRESS_FRAC_BIT - address_frac; + m_address_acc_mask = lshift_signed<u64, s8>(((((1 << address_integer) - 1) << address_frac) | ((1 << address_frac) - 1)), m_address_acc_shift); + if (m_address_acc_shift > 0) + m_address_acc_mask |= ((1 << m_address_acc_shift) - 1); +} /********************************************************************************************** @@ -530,10 +514,14 @@ void es550x_device::compute_tables() ***********************************************************************************************/ -#define interpolate(sample1, sample2, accum) \ - (sample1 * (int32_t)(0x800 - (accum & 0x7ff)) + \ - sample2 * (int32_t)(accum & 0x7ff)) >> 11; - +inline s32 es550x_device::interpolate(s32 sample1, s32 sample2, u64 accum) +{ + const u32 shifted = 1 << ADDRESS_FRAC_BIT; + const u32 mask = shifted - 1; + accum &= mask & m_address_acc_mask; + return (sample1 * (s32)(shifted - accum) + + sample2 * (s32)(accum)) >> ADDRESS_FRAC_BIT; +} /********************************************************************************************** @@ -542,67 +530,83 @@ void es550x_device::compute_tables() ***********************************************************************************************/ -#define apply_filters(voice, sample) \ -do \ -{ \ - /* pole 1 is always low-pass using K1 */ \ - sample = ((int32_t)(voice->k1 >> 2) * (sample - voice->o1n1) / 16384) + voice->o1n1; \ - voice->o1n1 = sample; \ - \ - /* pole 2 is always low-pass using K1 */ \ - sample = ((int32_t)(voice->k1 >> 2) * (sample - voice->o2n1) / 16384) + voice->o2n1; \ - voice->o2n2 = voice->o2n1; \ - voice->o2n1 = sample; \ - \ - /* remaining poles depend on the current filter setting */ \ - switch (voice->control & CONTROL_LPMASK) \ - { \ - case 0: \ - /* pole 3 is high-pass using K2 */ \ - sample = sample - voice->o2n2 + ((int32_t)(voice->k2 >> 2) * voice->o3n1) / 32768 + voice->o3n1 / 2; \ - voice->o3n2 = voice->o3n1; \ - voice->o3n1 = sample; \ - \ - /* pole 4 is high-pass using K2 */ \ - sample = sample - voice->o3n2 + ((int32_t)(voice->k2 >> 2) * voice->o4n1) / 32768 + voice->o4n1 / 2; \ - voice->o4n1 = sample; \ - break; \ - \ - case CONTROL_LP3: \ - /* pole 3 is low-pass using K1 */ \ - sample = ((int32_t)(voice->k1 >> 2) * (sample - voice->o3n1) / 16384) + voice->o3n1; \ - voice->o3n2 = voice->o3n1; \ - voice->o3n1 = sample; \ - \ - /* pole 4 is high-pass using K2 */ \ - sample = sample - voice->o3n2 + ((int32_t)(voice->k2 >> 2) * voice->o4n1) / 32768 + voice->o4n1 / 2; \ - voice->o4n1 = sample; \ - break; \ - \ - case CONTROL_LP4: \ - /* pole 3 is low-pass using K2 */ \ - sample = ((int32_t)(voice->k2 >> 2) * (sample - voice->o3n1) / 16384) + voice->o3n1; \ - voice->o3n2 = voice->o3n1; \ - voice->o3n1 = sample; \ - \ - /* pole 4 is low-pass using K2 */ \ - sample = ((int32_t)(voice->k2 >> 2) * (sample - voice->o4n1) / 16384) + voice->o4n1; \ - voice->o4n1 = sample; \ - break; \ - \ - case CONTROL_LP4 | CONTROL_LP3: \ - /* pole 3 is low-pass using K1 */ \ - sample = ((int32_t)(voice->k1 >> 2) * (sample - voice->o3n1) / 16384) + voice->o3n1; \ - voice->o3n2 = voice->o3n1; \ - voice->o3n1 = sample; \ - \ - /* pole 4 is low-pass using K2 */ \ - sample = ((int32_t)(voice->k2 >> 2) * (sample - voice->o4n1) / 16384) + voice->o4n1; \ - voice->o4n1 = sample; \ - break; \ - } \ -} while (0) +// apply lowpass/highpass result +static inline s32 apply_lowpass(s32 out, s32 cutoff, s32 in) +{ + return ((s32)(cutoff >> FILTER_SHIFT) * (out - in) / (1 << FILTER_BIT)) + in; +} + +static inline s32 apply_highpass(s32 out, s32 cutoff, s32 in, s32 prev) +{ + return out - prev + ((s32)(cutoff >> FILTER_SHIFT) * in) / (1 << (FILTER_BIT + 1)) + in / 2; +} +// update poles from outputs +static inline void update_pole(s32 &pole, s32 sample) +{ + pole = sample; +} + +static inline void update_2_pole(s32 &prev, s32 &pole, s32 sample) +{ + prev = pole; + pole = sample; +} + +inline void es550x_device::apply_filters(es550x_voice *voice, s32 &sample) +{ + // pole 1 is always low-pass using K1 + sample = apply_lowpass(sample, voice->k1, voice->o1n1); + update_pole(voice->o1n1, sample); + + // pole 2 is always low-pass using K1 + sample = apply_lowpass(sample, voice->k1, voice->o2n1); + update_2_pole(voice->o2n2, voice->o2n1, sample); + + // remaining poles depend on the current filter setting + switch (get_lp(voice->control)) + { + case 0: + // pole 3 is high-pass using K2 + sample = apply_highpass(sample, voice->k2, voice->o3n1, voice->o2n2); + update_2_pole(voice->o3n2, voice->o3n1, sample); + + // pole 4 is high-pass using K2 + sample = apply_highpass(sample, voice->k2, voice->o4n1, voice->o3n2); + update_pole(voice->o4n1, sample); + break; + + case LP3: + // pole 3 is low-pass using K1 + sample = apply_lowpass(sample, voice->k1, voice->o3n1); + update_2_pole(voice->o3n2, voice->o3n1, sample); + + // pole 4 is high-pass using K2 + sample = apply_highpass(sample, voice->k2, voice->o4n1, voice->o3n2); + update_pole(voice->o4n1, sample); + break; + + case LP4: + // pole 3 is low-pass using K2 + sample = apply_lowpass(sample, voice->k2, voice->o3n1); + update_2_pole(voice->o3n2, voice->o3n1, sample); + + // pole 4 is low-pass using K2 + sample = apply_lowpass(sample, voice->k2, voice->o4n1); + update_pole(voice->o4n1, sample); + break; + + case LP3 | LP4: + // pole 3 is low-pass using K1 + sample = apply_lowpass(sample, voice->k1, voice->o3n1); + update_2_pole(voice->o3n2, voice->o3n1, sample); + + // pole 4 is low-pass using K2 + sample = apply_lowpass(sample, voice->k2, voice->o4n1); + update_pole(voice->o4n1, sample); + break; + } +} /********************************************************************************************** @@ -611,302 +615,285 @@ do ***********************************************************************************************/ -#define update_envelopes(voice, samples) \ -do \ -{ \ - int count = (samples > 1 && samples > voice->ecount) ? voice->ecount : samples; \ - \ - /* decrement the envelope counter */ \ - voice->ecount -= count; \ - \ - /* ramp left volume */ \ - if (voice->lvramp) \ - { \ - voice->lvol += (int8_t)voice->lvramp * count; \ - if ((int32_t)voice->lvol < 0) voice->lvol = 0; \ - else if (voice->lvol > 0xffff) voice->lvol = 0xffff; \ - } \ - \ - /* ramp right volume */ \ - if (voice->rvramp) \ - { \ - voice->rvol += (int8_t)voice->rvramp * count; \ - if ((int32_t)voice->rvol < 0) voice->rvol = 0; \ - else if (voice->rvol > 0xffff) voice->rvol = 0xffff; \ - } \ - \ - /* ramp k1 filter constant */ \ - if (voice->k1ramp && ((int32_t)voice->k1ramp >= 0 || !(voice->filtcount & 7))) \ - { \ - voice->k1 += (int8_t)voice->k1ramp * count; \ - if ((int32_t)voice->k1 < 0) voice->k1 = 0; \ - else if (voice->k1 > 0xffff) voice->k1 = 0xffff; \ - } \ - \ - /* ramp k2 filter constant */ \ - if (voice->k2ramp && ((int32_t)voice->k2ramp >= 0 || !(voice->filtcount & 7))) \ - { \ - voice->k2 += (int8_t)voice->k2ramp * count; \ - if ((int32_t)voice->k2 < 0) voice->k2 = 0; \ - else if (voice->k2 > 0xffff) voice->k2 = 0xffff; \ - } \ - \ - /* update the filter constant counter */ \ - voice->filtcount += count; \ - \ -} while (0) +inline void es5506_device::update_envelopes(es550x_voice *voice) +{ + const u32 volume_max = (1 << VOLUME_BIT_ES5506) - 1; + // decrement the envelope counter + voice->ecount--; + // ramp left volume + if (voice->lvramp) + { + voice->lvol += (int8_t)voice->lvramp; + if ((s32)voice->lvol < 0) voice->lvol = 0; + else if (voice->lvol > volume_max) voice->lvol = volume_max; + } + // ramp right volume + if (voice->rvramp) + { + voice->rvol += (int8_t)voice->rvramp; + if ((s32)voice->rvol < 0) voice->rvol = 0; + else if (voice->rvol > volume_max) voice->rvol = volume_max; + } -/********************************************************************************************** + // ramp k1 filter constant + if (voice->k1ramp && ((s32)voice->k1ramp >= 0 || !(voice->filtcount & 7))) + { + voice->k1 += (int8_t)voice->k1ramp; + if ((s32)voice->k1 < 0) voice->k1 = 0; + else if (voice->k1 > 0xffff) voice->k1 = 0xffff; + } - check_for_end_forward - check_for_end_reverse -- check for loop end and loop appropriately + // ramp k2 filter constant + if (voice->k2ramp && ((s32)voice->k2ramp >= 0 || !(voice->filtcount & 7))) + { + voice->k2 += (int8_t)voice->k2ramp; + if ((s32)voice->k2 < 0) voice->k2 = 0; + else if (voice->k2 > 0xffff) voice->k2 = 0xffff; + } -***********************************************************************************************/ + // update the filter constant counter + voice->filtcount++; -#define check_for_end_forward(voice, accum) \ -do \ -{ \ - /* are we past the end? */ \ - if (accum > voice->end && !(voice->control & CONTROL_LEI)) \ - { \ - /* generate interrupt if required */ \ - if (voice->control&CONTROL_IRQE) \ - voice->control |= CONTROL_IRQ; \ - \ - /* handle the different types of looping */ \ - switch (voice->control & CONTROL_LOOPMASK) \ - { \ - /* non-looping */ \ - case 0: \ - voice->control |= CONTROL_STOP0; \ - goto alldone; \ - \ - /* uni-directional looping */ \ - case CONTROL_LPE: \ - accum = (voice->start + (accum - voice->end)) & voice->accum_mask; \ - break; \ - \ - /* trans-wave looping */ \ - case CONTROL_BLE: \ - accum = (voice->start + (accum - voice->end)) & voice->accum_mask; \ - voice->control = (voice->control & ~CONTROL_LOOPMASK) | CONTROL_LEI;\ - break; \ - \ - /* bi-directional looping */ \ - case CONTROL_LPE | CONTROL_BLE: \ - accum = (voice->end - (accum - voice->end)) & voice->accum_mask; \ - voice->control ^= CONTROL_DIR; \ - goto reverse; \ - } \ - } \ -} while (0) - - -#define check_for_end_reverse(voice, accum) \ -do \ -{ \ - /* are we past the end? */ \ - if (accum < voice->start && !(voice->control & CONTROL_LEI)) \ - { \ - /* generate interrupt if required */ \ - if (voice->control&CONTROL_IRQE) \ - voice->control |= CONTROL_IRQ; \ - \ - /* handle the different types of looping */ \ - switch (voice->control & CONTROL_LOOPMASK) \ - { \ - /* non-looping */ \ - case 0: \ - voice->control |= CONTROL_STOP0; \ - goto alldone; \ - \ - /* uni-directional looping */ \ - case CONTROL_LPE: \ - accum = (voice->end - (voice->start - accum)) & voice->accum_mask; \ - break; \ - \ - /* trans-wave looping */ \ - case CONTROL_BLE: \ - accum = (voice->end - (voice->start - accum)) & voice->accum_mask; \ - voice->control = (voice->control & ~CONTROL_LOOPMASK) | CONTROL_LEI;\ - break; \ - \ - /* bi-directional looping */ \ - case CONTROL_LPE | CONTROL_BLE: \ - accum = (voice->start + (voice->start - accum)) & voice->accum_mask;\ - voice->control ^= CONTROL_DIR; \ - goto reverse; \ - } \ - } \ -} while (0) +} +inline void es5505_device::update_envelopes(es550x_voice *voice) +{ + // no envelopes in ES5505 + voice->ecount = 0; +} /********************************************************************************************** - generate_dummy -- generate nothing, just apply envelopes + check_for_end_forward + check_for_end_reverse -- check for loop end and loop appropriately ***********************************************************************************************/ -void es550x_device::generate_dummy(es550x_voice *voice, uint16_t *base, int32_t *lbuffer, int32_t *rbuffer, int samples) +inline void es5506_device::check_for_end_forward(es550x_voice *voice, u64 &accum) { - uint32_t freqcount = voice->freqcount; - uint32_t accum = voice->accum & voice->accum_mask; - - /* outer loop, in case we switch directions */ - while (samples > 0 && !(voice->control & CONTROL_STOPMASK)) + // are we past the end? + if (accum > voice->end && !(voice->control & CONTROL_LEI)) { -reverse: - /* two cases: first case is forward direction */ - if (!(voice->control & CONTROL_DIR)) + // generate interrupt if required + if (voice->control & CONTROL_IRQE) + voice->control |= CONTROL_IRQ; + + // handle the different types of looping + switch (voice->control & CONTROL_LOOPMASK) { - /* loop while we still have samples to generate */ - while (samples--) - { - /* fetch two samples */ - accum = (accum + freqcount) & voice->accum_mask; + // non-looping + case 0: + voice->control |= CONTROL_STOP0; + break; + + // uni-directional looping + case CONTROL_LPE: + accum = (voice->start + (accum - voice->end)) & m_address_acc_mask; + break; + + // trans-wave looping + case CONTROL_BLE: + accum = (voice->start + (accum - voice->end)) & m_address_acc_mask; + voice->control = (voice->control & ~CONTROL_LOOPMASK) | CONTROL_LEI; + break; + + // bi-directional looping + case CONTROL_LPE | CONTROL_BLE: + accum = (voice->end - (accum - voice->end)) & m_address_acc_mask; + voice->control ^= CONTROL_DIR; + break; + } + } +} - /* update filters/volumes */ - if (voice->ecount != 0) - update_envelopes(voice, 1); +inline void es5506_device::check_for_end_reverse(es550x_voice *voice, u64 &accum) +{ + // are we past the end? + if (accum < voice->start && !(voice->control & CONTROL_LEI)) + { + // generate interrupt if required + if (voice->control & CONTROL_IRQE) + voice->control |= CONTROL_IRQ; - /* check for loop end */ - check_for_end_forward(voice, accum); - } + // handle the different types of looping + switch (voice->control & CONTROL_LOOPMASK) + { + // non-looping + case 0: + voice->control |= CONTROL_STOP0; + break; + + // uni-directional looping + case CONTROL_LPE: + accum = (voice->end - (voice->start - accum)) & m_address_acc_mask; + break; + + // trans-wave looping + case CONTROL_BLE: + accum = (voice->end - (voice->start - accum)) & m_address_acc_mask; + voice->control = (voice->control & ~CONTROL_LOOPMASK) | CONTROL_LEI; + break; + + // bi-directional looping + case CONTROL_LPE | CONTROL_BLE: + accum = (voice->start + (voice->start - accum)) & m_address_acc_mask; + voice->control ^= CONTROL_DIR; + break; } + } +} - /* two cases: second case is backward direction */ - else +// ES5505 : BLE is ignored when LPE = 0 +inline void es5505_device::check_for_end_forward(es550x_voice *voice, u64 &accum) +{ + // are we past the end? + if (accum > voice->end) + { + // generate interrupt if required + if (voice->control & CONTROL_IRQE) + voice->control |= CONTROL_IRQ; + + // handle the different types of looping + switch (voice->control & CONTROL_LOOPMASK) { - /* loop while we still have samples to generate */ - while (samples--) - { - /* fetch two samples */ - accum = (accum - freqcount) & voice->accum_mask; + // non-looping + case 0: + case CONTROL_BLE: + voice->control |= CONTROL_STOP0; + break; + + // uni-directional looping + case CONTROL_LPE: + accum = (voice->start + (accum - voice->end)) & m_address_acc_mask; + break; + + // bi-directional looping + case CONTROL_LPE | CONTROL_BLE: + accum = (voice->end - (accum - voice->end)) & m_address_acc_mask; + voice->control ^= CONTROL_DIR; + break; + } + } +} - /* update filters/volumes */ - if (voice->ecount != 0) - update_envelopes(voice, 1); +inline void es5505_device::check_for_end_reverse(es550x_voice *voice, u64 &accum) +{ + // are we past the end? + if (accum < voice->start) + { + // generate interrupt if required + if (voice->control & CONTROL_IRQE) + voice->control |= CONTROL_IRQ; - /* check for loop end */ - check_for_end_reverse(voice, accum); - } + // handle the different types of looping + switch (voice->control & CONTROL_LOOPMASK) + { + // non-looping + case 0: + case CONTROL_BLE: + voice->control |= CONTROL_STOP0; + break; + + // uni-directional looping + case CONTROL_LPE: + accum = (voice->end - (voice->start - accum)) & m_address_acc_mask; + break; + + // bi-directional looping + case CONTROL_LPE | CONTROL_BLE: + accum = (voice->start + (voice->start - accum)) & m_address_acc_mask; + voice->control ^= CONTROL_DIR; + break; } } - - /* if we stopped, process any additional envelope */ -alldone: - voice->accum = accum; - if (samples > 0) - update_envelopes(voice, samples); } - /********************************************************************************************** generate_ulaw -- general u-law decoding routine ***********************************************************************************************/ -void es550x_device::generate_ulaw(es550x_voice *voice, uint16_t *base, int32_t *lbuffer, int32_t *rbuffer, int samples) +void es550x_device::generate_ulaw(es550x_voice *voice, s32 *dest) { - uint32_t freqcount = voice->freqcount; - uint32_t accum = voice->accum & voice->accum_mask; - int32_t lvol = m_volume_lookup[voice->lvol >> 4]; - int32_t rvol = m_volume_lookup[voice->rvol >> 4]; + const u32 freqcount = voice->freqcount; + u64 accum = voice->accum & m_address_acc_mask; - /* pre-add the bank offset */ - base += voice->exbank; - - /* outer loop, in case we switch directions */ - while (samples > 0 && !(voice->control & CONTROL_STOPMASK)) + // outer loop, in case we switch directions + if (!(voice->control & CONTROL_STOPMASK)) { -reverse: - /* two cases: first case is forward direction */ + // two cases: first case is forward direction if (!(voice->control & CONTROL_DIR)) { - /* loop while we still have samples to generate */ - while (samples--) - { - /* fetch two samples */ - int32_t val1 = base[accum >> 11]; - int32_t val2 = base[((accum + (1 << 11)) & voice->accum_mask) >> 11]; - - /* decompress u-law */ - val1 = m_ulaw_lookup[val1 >> (16 - ULAW_MAXBITS)]; - val2 = m_ulaw_lookup[val2 >> (16 - ULAW_MAXBITS)]; - - /* interpolate */ - val1 = interpolate(val1, val2, accum); - accum = (accum + freqcount) & voice->accum_mask; - - /* apply filters */ - apply_filters(voice, val1); - - /* update filters/volumes */ - if (voice->ecount != 0) - { - update_envelopes(voice, 1); - lvol = m_volume_lookup[voice->lvol >> 4]; - rvol = m_volume_lookup[voice->rvol >> 4]; - } - - /* apply volumes and add */ - *lbuffer++ += (val1 * lvol) >> 11; - *rbuffer++ += (val1 * rvol) >> 11; - - /* check for loop end */ - check_for_end_forward(voice, accum); - } + // fetch two samples + s32 val1 = read_sample(voice, get_integer_addr(accum)); + s32 val2 = read_sample(voice, get_integer_addr(accum, 1)); + + // decompress u-law + val1 = m_ulaw_lookup[val1 >> (16 - ULAW_MAXBITS)]; + val2 = m_ulaw_lookup[val2 >> (16 - ULAW_MAXBITS)]; + + // interpolate + val1 = interpolate(val1, val2, accum); + accum = (accum + freqcount) & m_address_acc_mask; + + // apply filters + apply_filters(voice, val1); + + // update filters/volumes + if (voice->ecount != 0) + update_envelopes(voice); + + // apply volumes and add + dest[0] += get_sample(val1, voice->lvol); + dest[1] += get_sample(val1, voice->rvol); + + // check for loop end + check_for_end_forward(voice, accum); } - /* two cases: second case is backward direction */ + // two cases: second case is backward direction else { - /* loop while we still have samples to generate */ - while (samples--) - { - /* fetch two samples */ - int32_t val1 = base[accum >> 11]; - int32_t val2 = base[((accum + (1 << 11)) & voice->accum_mask) >> 11]; - - /* decompress u-law */ - val1 = m_ulaw_lookup[val1 >> (16 - ULAW_MAXBITS)]; - val2 = m_ulaw_lookup[val2 >> (16 - ULAW_MAXBITS)]; - - /* interpolate */ - val1 = interpolate(val1, val2, accum); - accum = (accum - freqcount) & voice->accum_mask; - - /* apply filters */ - apply_filters(voice, val1); - - /* update filters/volumes */ - if (voice->ecount != 0) - { - update_envelopes(voice, 1); - lvol = m_volume_lookup[voice->lvol >> 4]; - rvol = m_volume_lookup[voice->rvol >> 4]; - } - - /* apply volumes and add */ - *lbuffer++ += (val1 * lvol) >> 11; - *rbuffer++ += (val1 * rvol) >> 11; - - /* check for loop end */ - check_for_end_reverse(voice, accum); - } + // fetch two samples + s32 val1 = read_sample(voice, get_integer_addr(accum)); + s32 val2 = read_sample(voice, get_integer_addr(accum, 1)); + + // decompress u-law + val1 = m_ulaw_lookup[val1 >> (16 - ULAW_MAXBITS)]; + val2 = m_ulaw_lookup[val2 >> (16 - ULAW_MAXBITS)]; + + // interpolate + val1 = interpolate(val1, val2, accum); + accum = (accum - freqcount) & m_address_acc_mask; + + // apply filters + apply_filters(voice, val1); + + // update filters/volumes + if (voice->ecount != 0) + update_envelopes(voice); + + // apply volumes and add + dest[0] += get_sample(val1, voice->lvol); + dest[1] += get_sample(val1, voice->rvol); + + // check for loop end + check_for_end_reverse(voice, accum); } } + else + { + // if we stopped, process any additional envelope + if (voice->ecount != 0) + update_envelopes(voice); + } - /* if we stopped, process any additional envelope */ -alldone: voice->accum = accum; - if (samples > 0) - update_envelopes(voice, samples); } @@ -917,233 +904,180 @@ alldone: ***********************************************************************************************/ -void es550x_device::generate_pcm(es550x_voice *voice, uint16_t *base, int32_t *lbuffer, int32_t *rbuffer, int samples) +void es550x_device::generate_pcm(es550x_voice *voice, s32 *dest) { - uint32_t freqcount = voice->freqcount; - uint32_t accum = voice->accum & voice->accum_mask; - int32_t lvol = m_volume_lookup[voice->lvol >> 4]; - int32_t rvol = m_volume_lookup[voice->rvol >> 4]; + const u32 freqcount = voice->freqcount; + u64 accum = voice->accum & m_address_acc_mask; - /* pre-add the bank offset */ - base += voice->exbank; - - /* outer loop, in case we switch directions */ - while (samples > 0 && !(voice->control & CONTROL_STOPMASK)) + // outer loop, in case we switch directions + if (!(voice->control & CONTROL_STOPMASK)) { -reverse: - /* two cases: first case is forward direction */ + // two cases: first case is forward direction if (!(voice->control & CONTROL_DIR)) { - /* loop while we still have samples to generate */ - while (samples--) - { - /* fetch two samples */ - int32_t val1 = (int16_t)base[accum >> 11]; - int32_t val2 = (int16_t)base[((accum + (1 << 11)) & voice->accum_mask) >> 11]; - - /* interpolate */ - val1 = interpolate(val1, val2, accum); - accum = (accum + freqcount) & voice->accum_mask; - - /* apply filters */ - apply_filters(voice, val1); - - /* update filters/volumes */ - if (voice->ecount != 0) - { - update_envelopes(voice, 1); - lvol = m_volume_lookup[voice->lvol >> 4]; - rvol = m_volume_lookup[voice->rvol >> 4]; - } - - /* apply volumes and add */ - *lbuffer++ += (val1 * lvol) >> 11; - *rbuffer++ += (val1 * rvol) >> 11; - - /* check for loop end */ - check_for_end_forward(voice, accum); - } + // fetch two samples + s32 val1 = (s16)read_sample(voice, get_integer_addr(accum)); + s32 val2 = (s16)read_sample(voice, get_integer_addr(accum, 1)); + + // interpolate + val1 = interpolate(val1, val2, accum); + accum = (accum + freqcount) & m_address_acc_mask; + + // apply filters + apply_filters(voice, val1); + + // update filters/volumes + if (voice->ecount != 0) + update_envelopes(voice); + + // apply volumes and add + dest[0] += get_sample(val1, voice->lvol); + dest[1] += get_sample(val1, voice->rvol); + + // check for loop end + check_for_end_forward(voice, accum); } - /* two cases: second case is backward direction */ + // two cases: second case is backward direction else { - /* loop while we still have samples to generate */ - while (samples--) - { - /* fetch two samples */ - int32_t val1 = (int16_t)base[accum >> 11]; - int32_t val2 = (int16_t)base[((accum + (1 << 11)) & voice->accum_mask) >> 11]; - - /* interpolate */ - val1 = interpolate(val1, val2, accum); - accum = (accum - freqcount) & voice->accum_mask; - - /* apply filters */ - apply_filters(voice, val1); - - /* update filters/volumes */ - if (voice->ecount != 0) - { - update_envelopes(voice, 1); - lvol = m_volume_lookup[voice->lvol >> 4]; - rvol = m_volume_lookup[voice->rvol >> 4]; - } - - /* apply volumes and add */ - *lbuffer++ += (val1 * lvol) >> 11; - *rbuffer++ += (val1 * rvol) >> 11; - - /* check for loop end */ - check_for_end_reverse(voice, accum); - } + // fetch two samples + s32 val1 = (s16)read_sample(voice, get_integer_addr(accum)); + s32 val2 = (s16)read_sample(voice, get_integer_addr(accum, 1)); + + // interpolate + val1 = interpolate(val1, val2, accum); + accum = (accum - freqcount) & m_address_acc_mask; + + // apply filters + apply_filters(voice, val1); + + // update filters/volumes + if (voice->ecount != 0) + update_envelopes(voice); + + // apply volumes and add + dest[0] += get_sample(val1, voice->lvol); + dest[1] += get_sample(val1, voice->rvol); + + // check for loop end + check_for_end_reverse(voice, accum); } } + else + { + // if we stopped, process any additional envelope + if (voice->ecount != 0) + update_envelopes(voice); + } - /* if we stopped, process any additional envelope */ -alldone: voice->accum = accum; - if (samples > 0) - update_envelopes(voice, samples); } - - /********************************************************************************************** - generate_samples -- tell each voice to generate samples + generate_irq -- general interrupt handling routine ***********************************************************************************************/ -void es5506_device::generate_samples(int32_t **outputs, int offset, int samples) +inline void es550x_device::generate_irq(es550x_voice *voice, int v) { - int v; + // does this voice have it's IRQ bit raised? + if (voice->control & CONTROL_IRQ) + { + LOG("es5506: IRQ raised on voice %d!!\n",v); - /* skip if nothing to do */ - if (!samples) - return; + // only update voice vector if existing IRQ is acked by host + if (m_irqv & 0x80) + { + // latch voice number into vector, and set high bit low + m_irqv = v & 0x1f; - /* clear out the accumulators */ - for (int i = 0; i < m_channels << 1; i++) - { - memset(outputs[i] + offset, 0, sizeof(int32_t) * samples); + // take down IRQ bit on voice + voice->control &= ~CONTROL_IRQ; + + // inform host of irq + update_irq_state(); + } } +} - /* loop over voices */ - for (v = 0; v <= m_active_voices; v++) - { - es550x_voice *voice = &m_voice[v]; - uint16_t *base = m_region_base[voice->control >> 14]; - /* special case: if end == start, stop the voice */ - if (voice->start == voice->end) - voice->control |= CONTROL_STOP0; +/********************************************************************************************** - int voice_channel = (voice->control & CONTROL_CAMASK) >> 10; - int channel = voice_channel % m_channels; - int l = channel << 1; - int r = l + 1; - int32_t *left = outputs[l] + offset; - int32_t *right = outputs[r] + offset; + generate_samples -- tell each voice to generate samples - /* generate from the appropriate source */ - if (!base) - { - LOG("es5506: nullptr region base %d\n",voice->control >> 14); - generate_dummy(voice, base, left, right, samples); - } - else if (voice->control & 0x2000) - generate_ulaw(voice, base, left, right, samples); - else - generate_pcm(voice, base, left, right, samples); +***********************************************************************************************/ - /* does this voice have it's IRQ bit raised? */ - if (voice->control&CONTROL_IRQ) +void es5506_device::generate_samples(sound_stream &stream) +{ + // loop while we still have samples to generate + for (int sampindex = 0; sampindex < stream.samples(); sampindex++) + { + // loop over voices + s32 cursample[12] = { 0 }; + for (int v = 0; v <= m_active_voices; v++) { - LOG("es5506: IRQ raised on voice %d!!\n",v); + es550x_voice *voice = &m_voice[v]; - /* only update voice vector if existing IRQ is acked by host */ - if (m_irqv&0x80) - { - /* latch voice number into vector, and set high bit low */ - m_irqv=v&0x7f; + // special case: if end == start, stop the voice + if (voice->start == voice->end) + voice->control |= CONTROL_STOP0; - /* take down IRQ bit on voice */ - voice->control&=~CONTROL_IRQ; + const int voice_channel = get_ca(voice->control); + const int channel = voice_channel % m_channels; + const int l = channel << 1; - /* inform host of irq */ - update_irq_state(); - } + // generate from the appropriate source + if (voice->control & CONTROL_CMPD) + generate_ulaw(voice, &cursample[l]); + else + generate_pcm(voice, &cursample[l]); + + // does this voice have it's IRQ bit raised? + generate_irq(voice, v); } + + for (int c = 0; c < stream.output_count(); c++) + stream.put_int(c, sampindex, cursample[c], 32768); } } -void es5505_device::generate_samples(int32_t **outputs, int offset, int samples) +void es5505_device::generate_samples(sound_stream &stream) { - int v; - - /* skip if nothing to do */ - if (!samples) - return; - - /* clear out the accumulators */ - for (int i = 0; i < m_channels << 1; i++) - { - memset(outputs[i] + offset, 0, sizeof(int32_t) * samples); - } - - /* loop over voices */ - for (v = 0; v <= m_active_voices; v++) + // loop while we still have samples to generate + for (int sampindex = 0; sampindex < stream.samples(); sampindex++) { - es550x_voice *voice = &m_voice[v]; - uint16_t *base = m_region_base[voice->control >> 14]; + // loop over voices + s32 cursample[12] = { 0 }; + for (int v = 0; v <= m_active_voices; v++) + { + es550x_voice *voice = &m_voice[v]; // This special case does not appear to match the behaviour observed in the es5505 in // actual Ensoniq synthesizers: those, it turns out, do set loop start and end to the // same value, and expect the voice to keep running. Examples can be found among the // transwaves on the VFX / SD-1 series of synthesizers. #if 0 - /* special case: if end == start, stop the voice */ - if (voice->start == voice->end) - voice->control |= CONTROL_STOP0; + // special case: if end == start, stop the voice + if (voice->start == voice->end) + voice->control |= CONTROL_STOP0; #endif - int voice_channel = (voice->control & CONTROL_CAMASK) >> 10; - int channel = voice_channel % m_channels; - int l = channel << 1; - int r = l + 1; - int32_t *left = outputs[l] + offset; - int32_t *right = outputs[r] + offset; - - /* generate from the appropriate source */ - if (!base) - { - LOG("es5506: nullptr region base %d\n",voice->control >> 14); - generate_dummy(voice, base, left, right, samples); - } - else if (voice->control & 0x2000) - generate_ulaw(voice, base, left, right, samples); - else - generate_pcm(voice, base, left, right, samples); - - /* does this voice have it's IRQ bit raised? */ - if (voice->control&CONTROL_IRQ) - { - LOG("es5506: IRQ raised on voice %d!!\n",v); - - /* only update voice vector if existing IRQ is acked by host */ - if (m_irqv&0x80) - { - /* latch voice number into vector, and set high bit low */ - m_irqv=v&0x7f; + const int voice_channel = get_ca(voice->control); + const int channel = voice_channel % m_channels; + const int l = channel << 1; - /* take down IRQ bit on voice */ - voice->control&=~CONTROL_IRQ; + // generate from the appropriate source + // no compressed sample support + generate_pcm(voice, &cursample[l]); - /* inform host of irq */ - update_irq_state(); - } + // does this voice have it's IRQ bit raised? + generate_irq(voice, v); } + + for (int c = 0; c < stream.output_count(); c++) + stream.put_int(c, sampindex, cursample[c], 32768); } } @@ -1155,250 +1089,256 @@ void es5505_device::generate_samples(int32_t **outputs, int offset, int samples) ***********************************************************************************************/ -inline void es5506_device::reg_write_low(es550x_voice *voice, offs_t offset, uint32_t data) +inline void es5506_device::reg_write_low(es550x_voice *voice, offs_t offset, u32 data) { switch (offset) { - case 0x00/8: /* CR */ + case 0x00/8: // CR voice->control = data & 0xffff; LOG("voice %d, control=%04x\n", m_current_page & 0x1f, voice->control); break; - case 0x08/8: /* FC */ - voice->freqcount = data & 0x1ffff; - LOG("voice %d, freq count=%08x\n", m_current_page & 0x1f, voice->freqcount); + case 0x08/8: // FC + voice->freqcount = get_address_acc_shifted_val(data & 0x1ffff); + LOG("voice %d, freq count=%08x\n", m_current_page & 0x1f, get_address_acc_res(voice->freqcount)); break; - case 0x10/8: /* LVOL */ - voice->lvol = data & 0xffff; + case 0x10/8: // LVOL + voice->lvol = data & 0xffff; // low 4 bit is used for finer envelope control LOG("voice %d, left vol=%04x\n", m_current_page & 0x1f, voice->lvol); break; - case 0x18/8: /* LVRAMP */ + case 0x18/8: // LVRAMP voice->lvramp = (data & 0xff00) >> 8; LOG("voice %d, left vol ramp=%04x\n", m_current_page & 0x1f, voice->lvramp); break; - case 0x20/8: /* RVOL */ - voice->rvol = data & 0xffff; + case 0x20/8: // RVOL + voice->rvol = data & 0xffff; // low 4 bit is used for finer envelope control LOG("voice %d, right vol=%04x\n", m_current_page & 0x1f, voice->rvol); break; - case 0x28/8: /* RVRAMP */ + case 0x28/8: // RVRAMP voice->rvramp = (data & 0xff00) >> 8; LOG("voice %d, right vol ramp=%04x\n", m_current_page & 0x1f, voice->rvramp); break; - case 0x30/8: /* ECOUNT */ + case 0x30/8: // ECOUNT voice->ecount = data & 0x1ff; voice->filtcount = 0; LOG("voice %d, envelope count=%04x\n", m_current_page & 0x1f, voice->ecount); break; - case 0x38/8: /* K2 */ - voice->k2 = data & 0xffff; + case 0x38/8: // K2 + voice->k2 = data & 0xffff; // low 4 bit is used for finer envelope control LOG("voice %d, K2=%04x\n", m_current_page & 0x1f, voice->k2); break; - case 0x40/8: /* K2RAMP */ + case 0x40/8: // K2RAMP voice->k2ramp = ((data & 0xff00) >> 8) | ((data & 0x0001) << 31); LOG("voice %d, K2 ramp=%04x\n", m_current_page & 0x1f, voice->k2ramp); break; - case 0x48/8: /* K1 */ - voice->k1 = data & 0xffff; + case 0x48/8: // K1 + voice->k1 = data & 0xffff; // low 4 bit is used for finer envelope control LOG("voice %d, K1=%04x\n", m_current_page & 0x1f, voice->k1); break; - case 0x50/8: /* K1RAMP */ + case 0x50/8: // K1RAMP voice->k1ramp = ((data & 0xff00) >> 8) | ((data & 0x0001) << 31); LOG("voice %d, K1 ramp=%04x\n", m_current_page & 0x1f, voice->k1ramp); break; - case 0x58/8: /* ACTV */ + case 0x58/8: // ACTV { m_active_voices = data & 0x1f; m_sample_rate = m_master_clock / (16 * (m_active_voices + 1)); m_stream->set_sample_rate(m_sample_rate); - if (!m_sample_rate_changed_cb.isnull()) - m_sample_rate_changed_cb(m_sample_rate); + m_sample_rate_changed_cb(m_sample_rate); LOG("active voices=%d, sample_rate=%d\n", m_active_voices, m_sample_rate); break; } - case 0x60/8: /* MODE */ - m_mode = data & 0x1f; + case 0x60/8: // MODE + // [4:3] = 00 : Single, Master, Early address mode + // [4:3] = 01 : Single, Master, Normal address mode + // [4:3] = 10 : Dual, Slave, Normal address mode + // [4:3] = 11 : Dual, Master, Normal address mode + m_mode = data & 0x1f; // MODE1[4], MODE0[3], BCLK_EN[2], WCLK_EN[1], LRCLK_EN[0] break; - case 0x68/8: /* PAR - read only */ - case 0x70/8: /* IRQV - read only */ + case 0x68/8: // PAR - read only + case 0x70/8: // IRQV - read only break; - case 0x78/8: /* PAGE */ + case 0x78/8: // PAGE m_current_page = data & 0x7f; break; } } -inline void es5506_device::reg_write_high(es550x_voice *voice, offs_t offset, uint32_t data) +inline void es5506_device::reg_write_high(es550x_voice *voice, offs_t offset, u32 data) { switch (offset) { - case 0x00/8: /* CR */ + case 0x00/8: // CR voice->control = data & 0xffff; LOG("voice %d, control=%04x\n", m_current_page & 0x1f, voice->control); break; - case 0x08/8: /* START */ - voice->start = data & 0xfffff800; - LOG("voice %d, loop start=%08x\n", m_current_page & 0x1f, voice->start); + case 0x08/8: // START + voice->start = get_address_acc_shifted_val(data & 0xfffff800); + LOG("voice %d, loop start=%08x\n", m_current_page & 0x1f, get_address_acc_res(voice->start)); break; - case 0x10/8: /* END */ - voice->end = data & 0xffffff80; - LOG("voice %d, loop end=%08x\n", m_current_page & 0x1f, voice->end); + case 0x10/8: // END + voice->end = get_address_acc_shifted_val(data & 0xffffff80); + LOG("voice %d, loop end=%08x\n", m_current_page & 0x1f, get_address_acc_res(voice->end)); break; - case 0x18/8: /* ACCUM */ - voice->accum = data; - LOG("voice %d, accum=%08x\n", m_current_page & 0x1f, voice->accum); + case 0x18/8: // ACCUM + voice->accum = get_address_acc_shifted_val(data); + LOG("voice %d, accum=%08x\n", m_current_page & 0x1f, get_address_acc_res(voice->accum)); break; - case 0x20/8: /* O4(n-1) */ - voice->o4n1 = (int32_t)(data << 14) >> 14; + case 0x20/8: // O4(n-1); TODO: 16.1 signed fixed point according to datasheet + voice->o4n1 = util::sext(data, 18); LOG("voice %d, O4(n-1)=%05x\n", m_current_page & 0x1f, voice->o4n1 & 0x3ffff); break; - case 0x28/8: /* O3(n-1) */ - voice->o3n1 = (int32_t)(data << 14) >> 14; + case 0x28/8: // O3(n-1) + voice->o3n1 = util::sext(data, 18); LOG("voice %d, O3(n-1)=%05x\n", m_current_page & 0x1f, voice->o3n1 & 0x3ffff); break; - case 0x30/8: /* O3(n-2) */ - voice->o3n2 = (int32_t)(data << 14) >> 14; + case 0x30/8: // O3(n-2) + voice->o3n2 = util::sext(data, 18); LOG("voice %d, O3(n-2)=%05x\n", m_current_page & 0x1f, voice->o3n2 & 0x3ffff); break; - case 0x38/8: /* O2(n-1) */ - voice->o2n1 = (int32_t)(data << 14) >> 14; + case 0x38/8: // O2(n-1) + voice->o2n1 = util::sext(data, 18); LOG("voice %d, O2(n-1)=%05x\n", m_current_page & 0x1f, voice->o2n1 & 0x3ffff); break; - case 0x40/8: /* O2(n-2) */ - voice->o2n2 = (int32_t)(data << 14) >> 14; + case 0x40/8: // O2(n-2) + voice->o2n2 = util::sext(data, 18); LOG("voice %d, O2(n-2)=%05x\n", m_current_page & 0x1f, voice->o2n2 & 0x3ffff); break; - case 0x48/8: /* O1(n-1) */ - voice->o1n1 = (int32_t)(data << 14) >> 14; + case 0x48/8: // O1(n-1) + voice->o1n1 = util::sext(data, 18); LOG("voice %d, O1(n-1)=%05x\n", m_current_page & 0x1f, voice->o1n1 & 0x3ffff); break; - case 0x50/8: /* W_ST */ + case 0x50/8: // W_ST m_wst = data & 0x7f; + LOGMASKED(LOG_SERIAL, "%s: word clock start = %02x\n", machine().describe_context(), m_wst); break; - case 0x58/8: /* W_END */ + case 0x58/8: // W_END m_wend = data & 0x7f; + LOGMASKED(LOG_SERIAL, "%s: word clock end = %02x\n", machine().describe_context(), m_wend); break; - case 0x60/8: /* LR_END */ + case 0x60/8: // LR_END m_lrend = data & 0x7f; + LOGMASKED(LOG_SERIAL, "%s: left/right clock end = %02x\n", machine().describe_context(), m_lrend); break; - case 0x68/8: /* PAR - read only */ - case 0x70/8: /* IRQV - read only */ + case 0x68/8: // PAR - read only + case 0x70/8: // IRQV - read only break; - case 0x78/8: /* PAGE */ + case 0x78/8: // PAGE m_current_page = data & 0x7f; break; } } -inline void es5506_device::reg_write_test(es550x_voice *voice, offs_t offset, uint32_t data) +inline void es5506_device::reg_write_test(es550x_voice *voice, offs_t offset, u32 data) { switch (offset) { - case 0x00/8: /* CHANNEL 0 LEFT */ + case 0x00/8: // CHANNEL 0 LEFT LOG("Channel 0 left test write %08x\n", data); break; - case 0x08/8: /* CHANNEL 0 RIGHT */ + case 0x08/8: // CHANNEL 0 RIGHT LOG("Channel 0 right test write %08x\n", data); break; - case 0x10/8: /* CHANNEL 1 LEFT */ + case 0x10/8: // CHANNEL 1 LEFT LOG("Channel 1 left test write %08x\n", data); break; - case 0x18/8: /* CHANNEL 1 RIGHT */ + case 0x18/8: // CHANNEL 1 RIGHT LOG("Channel 1 right test write %08x\n", data); break; - case 0x20/8: /* CHANNEL 2 LEFT */ + case 0x20/8: // CHANNEL 2 LEFT LOG("Channel 2 left test write %08x\n", data); break; - case 0x28/8: /* CHANNEL 2 RIGHT */ + case 0x28/8: // CHANNEL 2 RIGHT LOG("Channel 2 right test write %08x\n", data); break; - case 0x30/8: /* CHANNEL 3 LEFT */ + case 0x30/8: // CHANNEL 3 LEFT LOG("Channel 3 left test write %08x\n", data); break; - case 0x38/8: /* CHANNEL 3 RIGHT */ + case 0x38/8: // CHANNEL 3 RIGHT LOG("Channel 3 right test write %08x\n", data); break; - case 0x40/8: /* CHANNEL 4 LEFT */ + case 0x40/8: // CHANNEL 4 LEFT LOG("Channel 4 left test write %08x\n", data); break; - case 0x48/8: /* CHANNEL 4 RIGHT */ + case 0x48/8: // CHANNEL 4 RIGHT LOG("Channel 4 right test write %08x\n", data); break; - case 0x50/8: /* CHANNEL 5 LEFT */ + case 0x50/8: // CHANNEL 5 LEFT LOG("Channel 5 left test write %08x\n", data); break; - case 0x58/8: /* CHANNEL 6 RIGHT */ + case 0x58/8: // CHANNEL 6 RIGHT LOG("Channel 5 right test write %08x\n", data); break; - case 0x60/8: /* EMPTY */ + case 0x60/8: // EMPTY LOG("Test write EMPTY %08x\n", data); break; - case 0x68/8: /* PAR - read only */ - case 0x70/8: /* IRQV - read only */ + case 0x68/8: // PAR - read only + case 0x70/8: // IRQV - read only break; - case 0x78/8: /* PAGE */ + case 0x78/8: // PAGE m_current_page = data & 0x7f; break; } } -WRITE8_MEMBER( es5506_device::write ) +void es5506_device::write(offs_t offset, u8 data) { es550x_voice *voice = &m_voice[m_current_page & 0x1f]; int shift = 8 * (offset & 3); - /* accumulate the data */ + // accumulate the data m_write_latch = (m_write_latch & ~(0xff000000 >> shift)) | (data << (24 - shift)); - /* wait for a write to complete */ + // wait for a write to complete if (shift != 24) return; - /* force an update */ + // force an update m_stream->update(); - /* switch off the page and register */ + // switch off the page and register if (m_current_page < 0x20) reg_write_low(voice, offset / 4, m_write_latch); else if (m_current_page < 0x40) @@ -1406,7 +1346,7 @@ WRITE8_MEMBER( es5506_device::write ) else reg_write_test(voice, offset / 4, m_write_latch); - /* clear the write latch when done */ + // clear the write latch when done m_write_latch = 0; } @@ -1418,75 +1358,76 @@ WRITE8_MEMBER( es5506_device::write ) ***********************************************************************************************/ -inline uint32_t es5506_device::reg_read_low(es550x_voice *voice, offs_t offset) +inline u32 es5506_device::reg_read_low(es550x_voice *voice, offs_t offset) { - uint32_t result = 0; + u32 result = 0; switch (offset) { - case 0x00/8: /* CR */ + case 0x00/8: // CR result = voice->control; break; - case 0x08/8: /* FC */ - result = voice->freqcount; + case 0x08/8: // FC + result = get_address_acc_res(voice->freqcount); break; - case 0x10/8: /* LVOL */ + case 0x10/8: // LVOL result = voice->lvol; break; - case 0x18/8: /* LVRAMP */ + case 0x18/8: // LVRAMP result = voice->lvramp << 8; break; - case 0x20/8: /* RVOL */ + case 0x20/8: // RVOL result = voice->rvol; break; - case 0x28/8: /* RVRAMP */ + case 0x28/8: // RVRAMP result = voice->rvramp << 8; break; - case 0x30/8: /* ECOUNT */ + case 0x30/8: // ECOUNT result = voice->ecount; break; - case 0x38/8: /* K2 */ + case 0x38/8: // K2 result = voice->k2; break; - case 0x40/8: /* K2RAMP */ + case 0x40/8: // K2RAMP result = (voice->k2ramp << 8) | (voice->k2ramp >> 31); break; - case 0x48/8: /* K1 */ + case 0x48/8: // K1 result = voice->k1; break; - case 0x50/8: /* K1RAMP */ + case 0x50/8: // K1RAMP result = (voice->k1ramp << 8) | (voice->k1ramp >> 31); break; - case 0x58/8: /* ACTV */ + case 0x58/8: // ACTV result = m_active_voices; break; - case 0x60/8: /* MODE */ + case 0x60/8: // MODE result = m_mode; break; - case 0x68/8: /* PAR */ - if (!m_read_port_cb.isnull()) - result = m_read_port_cb(0); + case 0x68/8: // PAR + if (!m_read_port_cb.isunset()) + result = m_read_port_cb(0) & 0x3ff; // 10 bit, 9:0 break; - case 0x70/8: /* IRQV */ + case 0x70/8: // IRQV result = m_irqv; - update_internal_irq_state(); + if (!machine().side_effects_disabled()) + update_internal_irq_state(); break; - case 0x78/8: /* PAGE */ + case 0x78/8: // PAGE result = m_current_page; break; } @@ -1494,117 +1435,118 @@ inline uint32_t es5506_device::reg_read_low(es550x_voice *voice, offs_t offset) } -inline uint32_t es5506_device::reg_read_high(es550x_voice *voice, offs_t offset) +inline u32 es5506_device::reg_read_high(es550x_voice *voice, offs_t offset) { - uint32_t result = 0; + u32 result = 0; switch (offset) { - case 0x00/8: /* CR */ + case 0x00/8: // CR result = voice->control; break; - case 0x08/8: /* START */ - result = voice->start; + case 0x08/8: // START + result = get_address_acc_res(voice->start); break; - case 0x10/8: /* END */ - result = voice->end; + case 0x10/8: // END + result = get_address_acc_res(voice->end); break; - case 0x18/8: /* ACCUM */ - result = voice->accum; + case 0x18/8: // ACCUM + result = get_address_acc_res(voice->accum); break; - case 0x20/8: /* O4(n-1) */ + case 0x20/8: // O4(n-1); TODO: 16.1 signed fixed point according to datasheet result = voice->o4n1 & 0x3ffff; break; - case 0x28/8: /* O3(n-1) */ + case 0x28/8: // O3(n-1) result = voice->o3n1 & 0x3ffff; break; - case 0x30/8: /* O3(n-2) */ + case 0x30/8: // O3(n-2) result = voice->o3n2 & 0x3ffff; break; - case 0x38/8: /* O2(n-1) */ + case 0x38/8: // O2(n-1) result = voice->o2n1 & 0x3ffff; break; - case 0x40/8: /* O2(n-2) */ + case 0x40/8: // O2(n-2) result = voice->o2n2 & 0x3ffff; break; - case 0x48/8: /* O1(n-1) */ + case 0x48/8: // O1(n-1) result = voice->o1n1 & 0x3ffff; break; - case 0x50/8: /* W_ST */ + case 0x50/8: // W_ST result = m_wst; break; - case 0x58/8: /* W_END */ + case 0x58/8: // W_END result = m_wend; break; - case 0x60/8: /* LR_END */ + case 0x60/8: // LR_END result = m_lrend; break; - case 0x68/8: /* PAR */ - if (!m_read_port_cb.isnull()) - result = m_read_port_cb(0); + case 0x68/8: // PAR + if (!m_read_port_cb.isunset()) + result = m_read_port_cb(0) & 0x3ff; // 10 bit, 9:0 break; - case 0x70/8: /* IRQV */ + case 0x70/8: // IRQV result = m_irqv; - update_internal_irq_state(); + if (!machine().side_effects_disabled()) + update_internal_irq_state(); break; - case 0x78/8: /* PAGE */ + case 0x78/8: // PAGE result = m_current_page; break; } return result; } -inline uint32_t es5506_device::reg_read_test(es550x_voice *voice, offs_t offset) +inline u32 es5506_device::reg_read_test(es550x_voice *voice, offs_t offset) { - uint32_t result = 0; + u32 result = 0; switch (offset) { - case 0x68/8: /* PAR */ - if (!m_read_port_cb.isnull()) - result = m_read_port_cb(0); + case 0x68/8: // PAR + if (!m_read_port_cb.isunset()) + result = m_read_port_cb(0) & 0x3ff; // 10 bit, 9:0 break; - case 0x70/8: /* IRQV */ + case 0x70/8: // IRQV result = m_irqv; break; - case 0x78/8: /* PAGE */ + case 0x78/8: // PAGE result = m_current_page; break; } return result; } -READ8_MEMBER( es5506_device::read ) +u8 es5506_device::read(offs_t offset) { es550x_voice *voice = &m_voice[m_current_page & 0x1f]; int shift = 8 * (offset & 3); - /* only read on offset 0 */ + // only read on offset 0 if (shift != 0) return m_read_latch >> (24 - shift); LOG("read from %02x/%02x -> ", m_current_page, offset / 4 * 8); - /* force an update */ + // force an update m_stream->update(); - /* switch off the page and register */ + // switch off the page and register if (m_current_page < 0x20) m_read_latch = reg_read_low(voice, offset / 4); else if (m_current_page < 0x40) @@ -1614,159 +1556,147 @@ READ8_MEMBER( es5506_device::read ) LOG("%08x\n", m_read_latch); - /* return the high byte */ + // return the high byte return m_read_latch >> 24; } - -void es5506_device::voice_bank_w(int voice, int bank) -{ - m_voice[voice].exbank=bank; -} - - /********************************************************************************************** reg_write -- handle a write to the selected ES5505 register ***********************************************************************************************/ -inline void es5505_device::reg_write_low(es550x_voice *voice, offs_t offset, uint16_t data, uint16_t mem_mask) +inline void es5505_device::reg_write_low(es550x_voice *voice, offs_t offset, u16 data, u16 mem_mask) { switch (offset) { - case 0x00: /* CR */ + case 0x00: // CR + voice->control |= 0xf000; // bit 15-12 always 1 if (ACCESSING_BITS_0_7) { #if RAINE_CHECK voice->control &= ~(CONTROL_STOPMASK | CONTROL_LOOPMASK | CONTROL_DIR); #else - voice->control &= ~(CONTROL_STOPMASK | CONTROL_BS0 | CONTROL_LOOPMASK | CONTROL_IRQE | CONTROL_DIR | CONTROL_IRQ); + voice->control &= ~0x00ff; #endif - voice->control |= (data & (CONTROL_STOPMASK | CONTROL_LOOPMASK | CONTROL_IRQE | CONTROL_DIR | CONTROL_IRQ)) | - ((data << 12) & CONTROL_BS0); + voice->control |= (data & 0x00ff); } if (ACCESSING_BITS_8_15) - { - voice->control &= ~(CONTROL_CA0 | CONTROL_CA1 | CONTROL_LPMASK); - voice->control |= ((data >> 2) & CONTROL_LPMASK) | - ((data << 2) & (CONTROL_CA0 | CONTROL_CA1)); - } + voice->control = (voice->control & ~0x0f00) | (data & 0x0f00); LOG("%s:voice %d, control=%04x (raw=%04x & %04x)\n", machine().describe_context(), m_current_page & 0x1f, voice->control, data, mem_mask ^ 0xffff); break; - case 0x01: /* FC */ + case 0x01: // FC if (ACCESSING_BITS_0_7) - voice->freqcount = (voice->freqcount & ~0x001fe) | ((data & 0x00ff) << 1); + voice->freqcount = (voice->freqcount & ~get_address_acc_shifted_val(0x00fe, 1)) | (get_address_acc_shifted_val((data & 0x00fe), 1)); if (ACCESSING_BITS_8_15) - voice->freqcount = (voice->freqcount & ~0x1fe00) | ((data & 0xff00) << 1); - LOG("%s:voice %d, freq count=%08x\n", machine().describe_context(), m_current_page & 0x1f, voice->freqcount); + voice->freqcount = (voice->freqcount & ~get_address_acc_shifted_val(0xff00, 1)) | (get_address_acc_shifted_val((data & 0xff00), 1)); + LOG("%s:voice %d, freq count=%08x\n", machine().describe_context(), m_current_page & 0x1f, get_address_acc_res(voice->freqcount, 1)); break; - case 0x02: /* STRT (hi) */ + case 0x02: // STRT (hi) if (ACCESSING_BITS_0_7) - voice->start = (voice->start & ~0x03fc0000) | ((data & 0x00ff) << 18); + voice->start = (voice->start & ~get_address_acc_shifted_val(0x00ff0000)) | (get_address_acc_shifted_val((data & 0x00ff) << 16)); if (ACCESSING_BITS_8_15) - voice->start = (voice->start & ~0x7c000000) | ((data & 0x1f00) << 18); - LOG("%s:voice %d, loop start=%08x\n", machine().describe_context(), m_current_page & 0x1f, voice->start); + voice->start = (voice->start & ~get_address_acc_shifted_val(0x1f000000)) | (get_address_acc_shifted_val((data & 0x1f00) << 16)); + LOG("%s:voice %d, loop start=%08x\n", machine().describe_context(), m_current_page & 0x1f, get_address_acc_res(voice->start)); break; - case 0x03: /* STRT (lo) */ + case 0x03: // STRT (lo) if (ACCESSING_BITS_0_7) - voice->start = (voice->start & ~0x00000380) | ((data & 0x00e0) << 2); + voice->start = (voice->start & ~get_address_acc_shifted_val(0x000000e0)) | (get_address_acc_shifted_val(data & 0x00e0)); if (ACCESSING_BITS_8_15) - voice->start = (voice->start & ~0x0003fc00) | ((data & 0xff00) << 2); - LOG("%s:voice %d, loop start=%08x\n", machine().describe_context(), m_current_page & 0x1f, voice->start); + voice->start = (voice->start & ~get_address_acc_shifted_val(0x0000ff00)) | (get_address_acc_shifted_val(data & 0xff00)); + LOG("%s:voice %d, loop start=%08x\n", machine().describe_context(), m_current_page & 0x1f, get_address_acc_res(voice->start)); break; - case 0x04: /* END (hi) */ + case 0x04: // END (hi) if (ACCESSING_BITS_0_7) - voice->end = (voice->end & ~0x03fc0000) | ((data & 0x00ff) << 18); + voice->end = (voice->end & ~get_address_acc_shifted_val(0x00ff0000)) | (get_address_acc_shifted_val((data & 0x00ff) << 16)); if (ACCESSING_BITS_8_15) - voice->end = (voice->end & ~0x7c000000) | ((data & 0x1f00) << 18); + voice->end = (voice->end & ~get_address_acc_shifted_val(0x1f000000)) | (get_address_acc_shifted_val((data & 0x1f00) << 16)); #if RAINE_CHECK voice->control |= CONTROL_STOP0; #endif - LOG("%s:voice %d, loop end=%08x\n", machine().describe_context(), m_current_page & 0x1f, voice->end); + LOG("%s:voice %d, loop end=%08x\n", machine().describe_context(), m_current_page & 0x1f, get_address_acc_res(voice->end)); break; - case 0x05: /* END (lo) */ + case 0x05: // END (lo) if (ACCESSING_BITS_0_7) - voice->end = (voice->end & ~0x00000380) | ((data & 0x00e0) << 2); + voice->end = (voice->end & ~get_address_acc_shifted_val(0x000000e0)) | (get_address_acc_shifted_val(data & 0x00e0)); if (ACCESSING_BITS_8_15) - voice->end = (voice->end & ~0x0003fc00) | ((data & 0xff00) << 2); + voice->end = (voice->end & ~get_address_acc_shifted_val(0x0000ff00)) | (get_address_acc_shifted_val(data & 0xff00)); #if RAINE_CHECK voice->control |= CONTROL_STOP0; #endif - LOG("%s:voice %d, loop end=%08x\n", machine().describe_context(), m_current_page & 0x1f, voice->end); + LOG("%s:voice %d, loop end=%08x\n", machine().describe_context(), m_current_page & 0x1f, get_address_acc_res(voice->end)); break; - case 0x06: /* K2 */ + case 0x06: // K2 if (ACCESSING_BITS_0_7) voice->k2 = (voice->k2 & ~0x00f0) | (data & 0x00f0); if (ACCESSING_BITS_8_15) voice->k2 = (voice->k2 & ~0xff00) | (data & 0xff00); - LOG("%s:voice %d, K2=%04x\n", machine().describe_context(), m_current_page & 0x1f, voice->k2); + LOG("%s:voice %d, K2=%03x\n", machine().describe_context(), m_current_page & 0x1f, voice->k2 >> FILTER_SHIFT); break; - case 0x07: /* K1 */ + case 0x07: // K1 if (ACCESSING_BITS_0_7) voice->k1 = (voice->k1 & ~0x00f0) | (data & 0x00f0); if (ACCESSING_BITS_8_15) voice->k1 = (voice->k1 & ~0xff00) | (data & 0xff00); - LOG("%s:voice %d, K1=%04x\n", machine().describe_context(), m_current_page & 0x1f, voice->k1); + LOG("%s:voice %d, K1=%03x\n", machine().describe_context(), m_current_page & 0x1f, voice->k1 >> FILTER_SHIFT); break; - case 0x08: /* LVOL */ + case 0x08: // LVOL if (ACCESSING_BITS_8_15) - voice->lvol = (voice->lvol & ~0xff00) | (data & 0xff00); - LOG("%s:voice %d, left vol=%04x\n", machine().describe_context(), m_current_page & 0x1f, voice->lvol); + voice->lvol = (voice->lvol & ~0xff) | ((data & 0xff00) >> 8); + LOG("%s:voice %d, left vol=%02x\n", machine().describe_context(), m_current_page & 0x1f, voice->lvol); break; - case 0x09: /* RVOL */ + case 0x09: // RVOL if (ACCESSING_BITS_8_15) - voice->rvol = (voice->rvol & ~0xff00) | (data & 0xff00); - LOG("%s:voice %d, right vol=%04x\n", machine().describe_context(), m_current_page & 0x1f, voice->rvol); + voice->rvol = (voice->rvol & ~0xff) | ((data & 0xff00) >> 8); + LOG("%s:voice %d, right vol=%02x\n", machine().describe_context(), m_current_page & 0x1f, voice->rvol); break; - case 0x0a: /* ACC (hi) */ + case 0x0a: // ACC (hi) if (ACCESSING_BITS_0_7) - voice->accum = (voice->accum & ~0x03fc0000) | ((data & 0x00ff) << 18); + voice->accum = (voice->accum & ~get_address_acc_shifted_val(0x00ff0000)) | (get_address_acc_shifted_val((data & 0x00ff) << 16)); if (ACCESSING_BITS_8_15) - voice->accum = (voice->accum & ~0x7c000000) | ((data & 0x1f00) << 18); - LOG("%s:voice %d, accum=%08x\n", machine().describe_context(), m_current_page & 0x1f, voice->accum); + voice->accum = (voice->accum & ~get_address_acc_shifted_val(0x1f000000)) | (get_address_acc_shifted_val((data & 0x1f00) << 16)); + LOG("%s:voice %d, accum=%08x\n", machine().describe_context(), m_current_page & 0x1f, get_address_acc_res(voice->accum)); break; - case 0x0b: /* ACC (lo) */ + case 0x0b: // ACC (lo) if (ACCESSING_BITS_0_7) - voice->accum = (voice->accum & ~0x000003fc) | ((data & 0x00ff) << 2); + voice->accum = (voice->accum & ~get_address_acc_shifted_val(0x000000ff)) | (get_address_acc_shifted_val(data & 0x00ff)); if (ACCESSING_BITS_8_15) - voice->accum = (voice->accum & ~0x0003fc00) | ((data & 0xff00) << 2); - LOG("%s:voice %d, accum=%08x\n", machine().describe_context(), m_current_page & 0x1f, voice->accum); + voice->accum = (voice->accum & ~get_address_acc_shifted_val(0x0000ff00)) | (get_address_acc_shifted_val(data & 0xff00)); + LOG("%s:voice %d, accum=%08x\n", machine().describe_context(), m_current_page & 0x1f, get_address_acc_res(voice->accum)); break; - case 0x0c: /* unused */ + case 0x0c: // unused break; - case 0x0d: /* ACT */ + case 0x0d: // ACT if (ACCESSING_BITS_0_7) { m_active_voices = data & 0x1f; m_sample_rate = m_master_clock / (16 * (m_active_voices + 1)); m_stream->set_sample_rate(m_sample_rate); - if (!m_sample_rate_changed_cb.isnull()) - m_sample_rate_changed_cb(m_sample_rate); + m_sample_rate_changed_cb(m_sample_rate); LOG("active voices=%d, sample_rate=%d\n", m_active_voices, m_sample_rate); } break; - case 0x0e: /* IRQV - read only */ + case 0x0e: // IRQV - read only break; - case 0x0f: /* PAGE */ + case 0x0f: // PAGE if (ACCESSING_BITS_0_7) m_current_page = data & 0x7f; break; @@ -1774,72 +1704,66 @@ inline void es5505_device::reg_write_low(es550x_voice *voice, offs_t offset, uin } -inline void es5505_device::reg_write_high(es550x_voice *voice, offs_t offset, uint16_t data, uint16_t mem_mask) +inline void es5505_device::reg_write_high(es550x_voice *voice, offs_t offset, u16 data, u16 mem_mask) { switch (offset) { - case 0x00: /* CR */ + case 0x00: // CR + voice->control |= 0xf000; // bit 15-12 always 1 if (ACCESSING_BITS_0_7) - { - voice->control &= ~(CONTROL_STOPMASK | CONTROL_BS0 | CONTROL_LOOPMASK | CONTROL_IRQE | CONTROL_DIR | CONTROL_IRQ); - voice->control |= (data & (CONTROL_STOPMASK | CONTROL_LOOPMASK | CONTROL_IRQE | CONTROL_DIR | CONTROL_IRQ)) | - ((data << 12) & CONTROL_BS0); - } + voice->control = (voice->control & ~0x00ff) | (data & 0x00ff); if (ACCESSING_BITS_8_15) - { - voice->control &= ~(CONTROL_CA0 | CONTROL_CA1 | CONTROL_LPMASK); - voice->control |= ((data >> 2) & CONTROL_LPMASK) | - ((data << 2) & (CONTROL_CA0 | CONTROL_CA1)); - } + voice->control = (voice->control & ~0x0f00) | (data & 0x0f00); + LOG("%s:voice %d, control=%04x (raw=%04x & %04x)\n", machine().describe_context(), m_current_page & 0x1f, voice->control, data, mem_mask); break; - case 0x01: /* O4(n-1) */ + case 0x01: // O4(n-1) if (ACCESSING_BITS_0_7) voice->o4n1 = (voice->o4n1 & ~0x00ff) | (data & 0x00ff); if (ACCESSING_BITS_8_15) - voice->o4n1 = (int16_t)((voice->o4n1 & ~0xff00) | (data & 0xff00)); - LOG("%s:voice %d, O4(n-1)=%05x\n", machine().describe_context(), m_current_page & 0x1f, voice->o4n1 & 0x3ffff); + voice->o4n1 = (s16)((voice->o4n1 & ~0xff00) | (data & 0xff00)); + LOG("%s:voice %d, O4(n-1)=%04x\n", machine().describe_context(), m_current_page & 0x1f, voice->o4n1 & 0xffff); break; - case 0x02: /* O3(n-1) */ + case 0x02: // O3(n-1) if (ACCESSING_BITS_0_7) voice->o3n1 = (voice->o3n1 & ~0x00ff) | (data & 0x00ff); if (ACCESSING_BITS_8_15) - voice->o3n1 = (int16_t)((voice->o3n1 & ~0xff00) | (data & 0xff00)); - LOG("%s:voice %d, O3(n-1)=%05x\n", machine().describe_context(), m_current_page & 0x1f, voice->o3n1 & 0x3ffff); + voice->o3n1 = (s16)((voice->o3n1 & ~0xff00) | (data & 0xff00)); + LOG("%s:voice %d, O3(n-1)=%04x\n", machine().describe_context(), m_current_page & 0x1f, voice->o3n1 & 0xffff); break; - case 0x03: /* O3(n-2) */ + case 0x03: // O3(n-2) if (ACCESSING_BITS_0_7) voice->o3n2 = (voice->o3n2 & ~0x00ff) | (data & 0x00ff); if (ACCESSING_BITS_8_15) - voice->o3n2 = (int16_t)((voice->o3n2 & ~0xff00) | (data & 0xff00)); - LOG("%s:voice %d, O3(n-2)=%05x\n", machine().describe_context(), m_current_page & 0x1f, voice->o3n2 & 0x3ffff); + voice->o3n2 = (s16)((voice->o3n2 & ~0xff00) | (data & 0xff00)); + LOG("%s:voice %d, O3(n-2)=%04x\n", machine().describe_context(), m_current_page & 0x1f, voice->o3n2 & 0xffff); break; - case 0x04: /* O2(n-1) */ + case 0x04: // O2(n-1) if (ACCESSING_BITS_0_7) voice->o2n1 = (voice->o2n1 & ~0x00ff) | (data & 0x00ff); if (ACCESSING_BITS_8_15) - voice->o2n1 = (int16_t)((voice->o2n1 & ~0xff00) | (data & 0xff00)); - LOG("%s:voice %d, O2(n-1)=%05x\n", machine().describe_context(), m_current_page & 0x1f, voice->o2n1 & 0x3ffff); + voice->o2n1 = (s16)((voice->o2n1 & ~0xff00) | (data & 0xff00)); + LOG("%s:voice %d, O2(n-1)=%04x\n", machine().describe_context(), m_current_page & 0x1f, voice->o2n1 & 0xffff); break; - case 0x05: /* O2(n-2) */ + case 0x05: // O2(n-2) if (ACCESSING_BITS_0_7) voice->o2n2 = (voice->o2n2 & ~0x00ff) | (data & 0x00ff); if (ACCESSING_BITS_8_15) - voice->o2n2 = (int16_t)((voice->o2n2 & ~0xff00) | (data & 0xff00)); - LOG("%s:voice %d, O2(n-2)=%05x\n", machine().describe_context(), m_current_page & 0x1f, voice->o2n2 & 0x3ffff); + voice->o2n2 = (s16)((voice->o2n2 & ~0xff00) | (data & 0xff00)); + LOG("%s:voice %d, O2(n-2)=%04x\n", machine().describe_context(), m_current_page & 0x1f, voice->o2n2 & 0xffff); break; - case 0x06: /* O1(n-1) */ + case 0x06: // O1(n-1) if (ACCESSING_BITS_0_7) voice->o1n1 = (voice->o1n1 & ~0x00ff) | (data & 0x00ff); if (ACCESSING_BITS_8_15) - voice->o1n1 = (int16_t)((voice->o1n1 & ~0xff00) | (data & 0xff00)); - LOG("%s:voice %d, O1(n-1)=%05x (accum=%08x)\n", machine().describe_context(), m_current_page & 0x1f, voice->o2n1 & 0x3ffff, voice->accum); + voice->o1n1 = (s16)((voice->o1n1 & ~0xff00) | (data & 0xff00)); + LOG("%s:voice %d, O1(n-1)=%04x (accum=%08x)\n", machine().describe_context(), m_current_page & 0x1f, voice->o1n1 & 0xffff, get_address_acc_res(voice->accum)); break; case 0x07: @@ -1847,26 +1771,25 @@ inline void es5505_device::reg_write_high(es550x_voice *voice, offs_t offset, ui case 0x09: case 0x0a: case 0x0b: - case 0x0c: /* unused */ + case 0x0c: // unused break; - case 0x0d: /* ACT */ + case 0x0d: // ACT if (ACCESSING_BITS_0_7) { m_active_voices = data & 0x1f; m_sample_rate = m_master_clock / (16 * (m_active_voices + 1)); m_stream->set_sample_rate(m_sample_rate); - if (!m_sample_rate_changed_cb.isnull()) - m_sample_rate_changed_cb(m_sample_rate); + m_sample_rate_changed_cb(m_sample_rate); LOG("active voices=%d, sample_rate=%d\n", m_active_voices, m_sample_rate); } break; - case 0x0e: /* IRQV - read only */ + case 0x0e: // IRQV - read only break; - case 0x0f: /* PAGE */ + case 0x0f: // PAGE if (ACCESSING_BITS_0_7) m_current_page = data & 0x7f; break; @@ -1874,44 +1797,48 @@ inline void es5505_device::reg_write_high(es550x_voice *voice, offs_t offset, ui } -inline void es5505_device::reg_write_test(es550x_voice *voice, offs_t offset, uint16_t data, uint16_t mem_mask) +inline void es5505_device::reg_write_test(es550x_voice *voice, offs_t offset, u16 data, u16 mem_mask) { switch (offset) { - case 0x00: /* CH0L */ - case 0x01: /* CH0R */ - case 0x02: /* CH1L */ - case 0x03: /* CH1R */ - case 0x04: /* CH2L */ - case 0x05: /* CH2R */ - case 0x06: /* CH3L */ - case 0x07: /* CH3R */ - break; - - case 0x08: /* SERMODE */ - m_mode = data & 0x0007; + case 0x00: // CH0L + case 0x01: // CH0R + case 0x02: // CH1L + case 0x03: // CH1R + case 0x04: // CH2L + case 0x05: // CH2R + case 0x06: // CH3L + case 0x07: // CH3R + break; + + case 0x08: // SERMODE + m_mode |= 0x7f8; // bit 10-3 always 1 + if (ACCESSING_BITS_8_15) + m_mode = (m_mode & ~0xf800) | (data & 0xf800); // MSB[4:0] (unknown purpose) + if (ACCESSING_BITS_0_7) + m_mode = (m_mode & ~0x0007) | (data & 0x0007); // SONY/BB, TEST, A/D + LOGMASKED(LOG_SERIAL, "%s: serial mode = %04x & %04x", machine().describe_context(), m_mode, mem_mask); break; - case 0x09: /* PAR */ + case 0x09: // PAR break; - case 0x0d: /* ACT */ + case 0x0d: // ACT if (ACCESSING_BITS_0_7) { m_active_voices = data & 0x1f; m_sample_rate = m_master_clock / (16 * (m_active_voices + 1)); m_stream->set_sample_rate(m_sample_rate); - if (!m_sample_rate_changed_cb.isnull()) - m_sample_rate_changed_cb(m_sample_rate); + m_sample_rate_changed_cb(m_sample_rate); LOG("active voices=%d, sample_rate=%d\n", m_active_voices, m_sample_rate); } break; - case 0x0e: /* IRQV - read only */ + case 0x0e: // IRQV - read only break; - case 0x0f: /* PAGE */ + case 0x0f: // PAGE if (ACCESSING_BITS_0_7) m_current_page = data & 0x7f; break; @@ -1919,16 +1846,16 @@ inline void es5505_device::reg_write_test(es550x_voice *voice, offs_t offset, ui } -WRITE16_MEMBER( es5505_device::write ) +void es5505_device::write(offs_t offset, u16 data, u16 mem_mask) { es550x_voice *voice = &m_voice[m_current_page & 0x1f]; // logerror("%s:ES5505 write %02x/%02x = %04x & %04x\n", machine().describe_context(), m_current_page, offset, data, mem_mask); - /* force an update */ + // force an update m_stream->update(); - /* switch off the page and register */ + // switch off the page and register if (m_current_page < 0x20) reg_write_low(voice, offset, data, mem_mask); else if (m_current_page < 0x40) @@ -1945,77 +1872,74 @@ WRITE16_MEMBER( es5505_device::write ) ***********************************************************************************************/ -inline uint16_t es5505_device::reg_read_low(es550x_voice *voice, offs_t offset) +inline u16 es5505_device::reg_read_low(es550x_voice *voice, offs_t offset) { - uint16_t result = 0; + u16 result = 0; switch (offset) { - case 0x00: /* CR */ - result = (voice->control & (CONTROL_STOPMASK | CONTROL_LOOPMASK | CONTROL_IRQE | CONTROL_DIR | CONTROL_IRQ)) | - ((voice->control & CONTROL_BS0) >> 12) | - ((voice->control & CONTROL_LPMASK) << 2) | - ((voice->control & (CONTROL_CA0 | CONTROL_CA1)) >> 2) | - 0xf000; + case 0x00: // CR + result = voice->control | 0xf000; break; - case 0x01: /* FC */ - result = voice->freqcount >> 1; + case 0x01: // FC + result = get_address_acc_res(voice->freqcount, 1); break; - case 0x02: /* STRT (hi) */ - result = voice->start >> 18; + case 0x02: // STRT (hi) + result = get_address_acc_res(voice->start) >> 16; break; - case 0x03: /* STRT (lo) */ - result = voice->start >> 2; + case 0x03: // STRT (lo) + result = get_address_acc_res(voice->start); break; - case 0x04: /* END (hi) */ - result = voice->end >> 18; + case 0x04: // END (hi) + result = get_address_acc_res(voice->end) >> 16; break; - case 0x05: /* END (lo) */ - result = voice->end >> 2; + case 0x05: // END (lo) + result = get_address_acc_res(voice->end); break; - case 0x06: /* K2 */ + case 0x06: // K2 result = voice->k2; break; - case 0x07: /* K1 */ + case 0x07: // K1 result = voice->k1; break; - case 0x08: /* LVOL */ - result = voice->lvol; + case 0x08: // LVOL + result = voice->lvol << 8; break; - case 0x09: /* RVOL */ - result = voice->rvol; + case 0x09: // RVOL + result = voice->rvol << 8; break; - case 0x0a: /* ACC (hi) */ - result = voice->accum >> 18; + case 0x0a: // ACC (hi) + result = get_address_acc_res(voice->accum) >> 16; break; - case 0x0b: /* ACC (lo) */ - result = voice->accum >> 2; + case 0x0b: // ACC (lo) + result = get_address_acc_res(voice->accum); break; - case 0x0c: /* unused */ + case 0x0c: // unused break; - case 0x0d: /* ACT */ + case 0x0d: // ACT result = m_active_voices; break; - case 0x0e: /* IRQV */ + case 0x0e: // IRQV result = m_irqv; - update_internal_irq_state(); + if (!machine().side_effects_disabled()) + update_internal_irq_state(); break; - case 0x0f: /* PAGE */ + case 0x0f: // PAGE result = m_current_page; break; } @@ -2023,53 +1947,49 @@ inline uint16_t es5505_device::reg_read_low(es550x_voice *voice, offs_t offset) } -inline uint16_t es5505_device::reg_read_high(es550x_voice *voice, offs_t offset) +inline u16 es5505_device::reg_read_high(es550x_voice *voice, offs_t offset) { - uint16_t result = 0; + u16 result = 0; switch (offset) { - case 0x00: /* CR */ - result = (voice->control & (CONTROL_STOPMASK | CONTROL_LOOPMASK | CONTROL_IRQE | CONTROL_DIR | CONTROL_IRQ)) | - ((voice->control & CONTROL_BS0) >> 12) | - ((voice->control & CONTROL_LPMASK) << 2) | - ((voice->control & (CONTROL_CA0 | CONTROL_CA1)) >> 2) | - 0xf000; + case 0x00: // CR + result = voice->control | 0xf000; break; - case 0x01: /* O4(n-1) */ - result = voice->o4n1; + case 0x01: // O4(n-1) + result = voice->o4n1 & 0xffff; break; - case 0x02: /* O3(n-1) */ - result = voice->o3n1; + case 0x02: // O3(n-1) + result = voice->o3n1 & 0xffff; break; - case 0x03: /* O3(n-2) */ - result = voice->o3n2; + case 0x03: // O3(n-2) + result = voice->o3n2 & 0xffff; break; - case 0x04: /* O2(n-1) */ - result = voice->o2n1; + case 0x04: // O2(n-1) + result = voice->o2n1 & 0xffff; break; - case 0x05: /* O2(n-2) */ - result = voice->o2n2; + case 0x05: // O2(n-2) + result = voice->o2n2 & 0xffff; break; - case 0x06: /* O1(n-1) */ - /* special case for the Taito F3 games: they set the accumulator on a stopped */ - /* voice and assume the filters continue to process the data. They then read */ - /* the O1(n-1) in order to extract raw data from the sound ROMs. Since we don't */ - /* want to waste time filtering stopped channels, we just look for a read from */ - /* this register on a stopped voice, and return the raw sample data at the */ - /* accumulator */ - if ((voice->control & CONTROL_STOPMASK) && m_region_base[voice->control >> 14]) + case 0x06: // O1(n-1) + // special case for the Taito F3 games: they set the accumulator on a stopped + // voice and assume the filters continue to process the data. They then read + // the O1(n-1) in order to extract raw data from the sound ROMs. Since we don't + // want to waste time filtering stopped channels, we just look for a read from + // this register on a stopped voice, and return the raw sample data at the + // accumulator + if ((voice->control & CONTROL_STOPMASK)) { - voice->o1n1 = m_region_base[voice->control >> 14][voice->exbank + (voice->accum >> 11)]; - // logerror("%02x %08x ==> %08x\n",voice->o1n1,voice->control >> 14,voice->exbank + (voice->accum >> 11)); + voice->o1n1 = read_sample(voice, get_integer_addr(voice->accum)); + // logerror("%02x %08x ==> %08x\n",voice->o1n1,get_bank(voice->control),get_integer_addr(voice->accum)); } - result = voice->o1n1; + result = voice->o1n1 & 0xffff; break; case 0x07: @@ -2077,19 +1997,20 @@ inline uint16_t es5505_device::reg_read_high(es550x_voice *voice, offs_t offset) case 0x09: case 0x0a: case 0x0b: - case 0x0c: /* unused */ + case 0x0c: // unused break; - case 0x0d: /* ACT */ + case 0x0d: // ACT result = m_active_voices; break; - case 0x0e: /* IRQV */ + case 0x0e: // IRQV result = m_irqv; - update_internal_irq_state(); + if (!machine().side_effects_disabled()) + update_internal_irq_state(); break; - case 0x0f: /* PAGE */ + case 0x0f: // PAGE result = m_current_page; break; } @@ -2097,42 +2018,43 @@ inline uint16_t es5505_device::reg_read_high(es550x_voice *voice, offs_t offset) } -inline uint16_t es5505_device::reg_read_test(es550x_voice *voice, offs_t offset) +inline u16 es5505_device::reg_read_test(es550x_voice *voice, offs_t offset) { - uint16_t result = 0; + u16 result = 0; switch (offset) { - case 0x00: /* CH0L */ - case 0x01: /* CH0R */ - case 0x02: /* CH1L */ - case 0x03: /* CH1R */ - case 0x04: /* CH2L */ - case 0x05: /* CH2R */ - case 0x06: /* CH3L */ - case 0x07: /* CH3R */ + case 0x00: // CH0L + case 0x01: // CH0R + case 0x02: // CH1L + case 0x03: // CH1R + case 0x04: // CH2L + case 0x05: // CH2R + case 0x06: // CH3L + case 0x07: // CH3R break; - case 0x08: /* SERMODE */ - result = m_mode; + case 0x08: // SERMODE + result = m_mode | 0x7f8; break; - case 0x09: /* PAR */ - if (!m_read_port_cb.isnull()) - result = m_read_port_cb(0); + case 0x09: // PAR + if (!m_read_port_cb.isunset()) + result = m_read_port_cb(0) & 0xffc0; // 10 bit, 15:6 break; - /* The following are global, and thus accessible form all pages */ - case 0x0d: /* ACT */ + // The following are global, and thus accessible form all pages + case 0x0d: // ACT result = m_active_voices; break; - case 0x0e: /* IRQV */ + case 0x0e: // IRQV result = m_irqv; - update_internal_irq_state(); + if (!machine().side_effects_disabled()) + update_internal_irq_state(); break; - case 0x0f: /* PAGE */ + case 0x0f: // PAGE result = m_current_page; break; } @@ -2140,17 +2062,17 @@ inline uint16_t es5505_device::reg_read_test(es550x_voice *voice, offs_t offset) } -READ16_MEMBER( es5505_device::read ) +u16 es5505_device::read(offs_t offset) { es550x_voice *voice = &m_voice[m_current_page & 0x1f]; - uint16_t result; + u16 result; LOG("read from %02x/%02x -> ", m_current_page, offset); - /* force an update */ + // force an update m_stream->update(); - /* switch off the page and register */ + // switch off the page and register if (m_current_page < 0x20) result = reg_read_low(voice, offset); else if (m_current_page < 0x40) @@ -2160,33 +2082,19 @@ READ16_MEMBER( es5505_device::read ) LOG("%04x (accum=%08x)\n", result, voice->accum); - /* return the high byte */ + // return the high byte return result; } - -void es5505_device::voice_bank_w(int voice, int bank) -{ -#if RAINE_CHECK - m_voice[voice].control = CONTROL_STOPMASK; -#endif - m_voice[voice].exbank=bank; -} - - //------------------------------------------------- // sound_stream_update - handle a stream update //------------------------------------------------- -void es550x_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) -{ -} - -void es5506_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +void es550x_device::sound_stream_update(sound_stream &stream) { #if ES5506_MAKE_WAVS - /* start the logging once we have a sample rate */ + // start the logging once we have a sample rate if (m_sample_rate) { if (!m_wavraw) @@ -2194,83 +2102,31 @@ void es5506_device::sound_stream_update(sound_stream &stream, stream_sample_t ** } #endif - /* loop until all samples are output */ - int offset = 0; - while (samples) - { - int length = (samples > MAX_SAMPLE_CHUNK) ? MAX_SAMPLE_CHUNK : samples; - - generate_samples(outputs, offset, length); - -#if ES5506_MAKE_WAVS - /* log the raw data */ - if (m_wavraw) { - /* determine left/right source data */ - int32_t *lsrc = m_scratch, *rsrc = m_scratch + length; - int channel; - memset(lsrc, 0, sizeof(int32_t) * length * 2); - /* loop over the output channels */ - for (channel = 0; channel < m_channels; channel++) { - int32_t *l = outputs[(channel << 1)] + offset; - int32_t *r = outputs[(channel << 1) + 1] + offset; - /* add the current channel's samples to the WAV data */ - for (samp = 0; samp < length; samp++) { - lsrc[samp] += l[samp]; - rsrc[samp] += r[samp]; - } - } - wav_add_data_32lr(m_wavraw, lsrc, rsrc, length, 4); - } -#endif - - /* account for these samples */ - offset += length; - samples -= length; - } -} + // loop until all samples are output + generate_samples(stream); -void es5505_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) -{ #if ES5506_MAKE_WAVS - /* start the logging once we have a sample rate */ - if (m_sample_rate) - { - if (!m_wavraw) - m_wavraw = wav_open("raw.wav", m_sample_rate, 2); - } -#endif - - /* loop until all samples are output */ - int offset = 0; - while (samples) + // log the raw data + if (m_wavraw) { - int length = (samples > MAX_SAMPLE_CHUNK) ? MAX_SAMPLE_CHUNK : samples; + // determine left/right source data - generate_samples(outputs, offset, length); - -#if ES5506_MAKE_WAVS - /* log the raw data */ - if (m_wavraw) { - /* determine left/right source data */ - int32_t *lsrc = m_scratch, *rsrc = m_scratch + length; - int channel; - memset(lsrc, 0, sizeof(int32_t) * length * 2); - /* loop over the output channels */ - for (channel = 0; channel < m_channels; channel++) { - int32_t *l = outputs[(channel << 1)] + offset; - int32_t *r = outputs[(channel << 1) + 1] + offset; - /* add the current channel's samples to the WAV data */ - for (samp = 0; samp < length; samp++) { - lsrc[samp] += l[samp]; - rsrc[samp] += r[samp]; - } + s32 *lsrc = m_scratch, *rsrc = m_scratch + length; + int channel; + memset(lsrc, 0, sizeof(s32) * length * 2); + // loop over the output channels + for (channel = 0; channel < m_channels; channel++) + { + s32 *l = outputs[(channel << 1)] + sampindex; + s32 *r = outputs[(channel << 1) + 1] + sampindex; + // add the current channel's samples to the WAV data + for (samp = 0; samp < length; samp++) + { + lsrc[samp] += l[samp]; + rsrc[samp] += r[samp]; } - wav_add_data_32lr(m_wavraw, lsrc, rsrc, length, 4); } -#endif - - /* account for these samples */ - offset += length; - samples -= length; + wav_add_data_32lr(m_wavraw, lsrc, rsrc, length, 4); } +#endif } |