mirror of
https://github.com/holub/mame
synced 2025-07-04 09:28:51 +03:00
Merge pull request #6835 from cam900/ics2115_space
ics2115.cpp: Use device_memory_interface for fetch external samples
This commit is contained in:
commit
1d057a673f
@ -1,14 +1,24 @@
|
|||||||
// license:BSD-3-Clause
|
// license:BSD-3-Clause
|
||||||
// copyright-holders:Alex Marshall,nimitz,austere
|
// copyright-holders:Alex Marshall,nimitz,austere
|
||||||
//ICS2115 by Raiden II team (c) 2010
|
/*
|
||||||
//members: austere, nimitz, Alex Marshal
|
ICS2115 by Raiden II team (c) 2010
|
||||||
//
|
members: austere, nimitz, Alex Marshal
|
||||||
//Original driver by O. Galibert, ElSemi
|
|
||||||
//
|
Original driver by O. Galibert, ElSemi
|
||||||
//Use tab size = 4 for your viewing pleasure.
|
|
||||||
|
Use tab size = 4 for your viewing pleasure.
|
||||||
|
|
||||||
|
TODO:
|
||||||
|
- Implement Panning, Chip has support stereo
|
||||||
|
- Verify BYTE/ROMEN pin behaviors
|
||||||
|
- DRAM, DMA, MIDI interface is unimplemented
|
||||||
|
- Verify interrupt, envelope, timer period
|
||||||
|
- Verify unemulated registers
|
||||||
|
*/
|
||||||
|
|
||||||
#include "emu.h"
|
#include "emu.h"
|
||||||
#include "ics2115.h"
|
#include "ics2115.h"
|
||||||
|
#include <algorithm>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
|
||||||
//#define ICS2115_DEBUG
|
//#define ICS2115_DEBUG
|
||||||
@ -18,15 +28,34 @@
|
|||||||
DEFINE_DEVICE_TYPE(ICS2115, ics2115_device, "ics2115", "ICS2115 WaveFront Synthesizer")
|
DEFINE_DEVICE_TYPE(ICS2115, ics2115_device, "ics2115", "ICS2115 WaveFront Synthesizer")
|
||||||
|
|
||||||
ics2115_device::ics2115_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
|
ics2115_device::ics2115_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
|
||||||
: device_t(mconfig, ICS2115, tag, owner, clock),
|
: device_t(mconfig, ICS2115, tag, owner, clock)
|
||||||
device_sound_interface(mconfig, *this), m_stream(nullptr),
|
, device_sound_interface(mconfig, *this)
|
||||||
m_rom(*this, DEVICE_SELF),
|
, device_memory_interface(mconfig, *this)
|
||||||
m_irq_cb(*this), m_active_osc(0), m_osc_select(0), m_reg_select(0), m_irq_enabled(0), m_irq_pending(0), m_irq_on(false), m_vmode(0)
|
, m_data_config("data", ENDIANNESS_LITTLE, 8, 24) // 24 bit address bus, 8 bit data bus(ROM), 11 bit address bus, 8 bit data bus, 4 banks(DRAM)
|
||||||
|
, m_stream(nullptr)
|
||||||
|
, m_rom(*this, DEVICE_SELF)
|
||||||
|
, m_irq_cb(*this)
|
||||||
|
, m_active_osc(0)
|
||||||
|
, m_osc_select(0)
|
||||||
|
, m_reg_select(0)
|
||||||
|
, m_irq_enabled(0)
|
||||||
|
, m_irq_pending(0)
|
||||||
|
, m_irq_on(false)
|
||||||
|
, m_vmode(0)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------
|
||||||
|
// device_start - device-specific startup
|
||||||
|
//-------------------------------------------------
|
||||||
|
|
||||||
void ics2115_device::device_start()
|
void ics2115_device::device_start()
|
||||||
{
|
{
|
||||||
|
if (m_rom && !has_configured_map(0))
|
||||||
|
space(0).install_rom(0, std::min<offs_t>((1 << 24) - 1, m_rom.bytes()), m_rom.target());
|
||||||
|
|
||||||
|
space(0).cache(m_cache);
|
||||||
|
|
||||||
m_timer[0].timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(ics2115_device::timer_cb_0),this), this);
|
m_timer[0].timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(ics2115_device::timer_cb_0),this), this);
|
||||||
m_timer[1].timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(ics2115_device::timer_cb_1),this), this);
|
m_timer[1].timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(ics2115_device::timer_cb_1),this), this);
|
||||||
m_stream = machine().sound().stream_alloc(*this, 0, 2, clock() / (32 * 32));
|
m_stream = machine().sound().stream_alloc(*this, 0, 2, clock() / (32 * 32));
|
||||||
@ -97,6 +126,9 @@ void ics2115_device::device_start()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------
|
||||||
|
// device_reset - device-specific reset
|
||||||
|
//-------------------------------------------------
|
||||||
|
|
||||||
void ics2115_device::device_reset()
|
void ics2115_device::device_reset()
|
||||||
{
|
{
|
||||||
@ -137,11 +169,29 @@ void ics2115_device::device_reset()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//-------------------------------------------------
|
||||||
|
// device_clock_changed - called if the clock
|
||||||
|
// changes
|
||||||
|
//-------------------------------------------------
|
||||||
|
|
||||||
void ics2115_device::device_clock_changed()
|
void ics2115_device::device_clock_changed()
|
||||||
{
|
{
|
||||||
m_stream->set_sample_rate(clock() / ((m_active_osc + 1) * 32));
|
m_stream->set_sample_rate(clock() / ((m_active_osc + 1) * 32));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//-------------------------------------------------
|
||||||
|
// memory_space_config - return a description of
|
||||||
|
// any address spaces owned by this device
|
||||||
|
//-------------------------------------------------
|
||||||
|
|
||||||
|
device_memory_interface::space_config_vector ics2115_device::memory_space_config() const
|
||||||
|
{
|
||||||
|
return space_config_vector{ std::make_pair(0, &m_data_config) };
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//TODO: improve using next-state logic from column 126 of patent 5809466
|
//TODO: improve using next-state logic from column 126 of patent 5809466
|
||||||
int ics2115_device::ics2115_voice::update_volume_envelope()
|
int ics2115_device::ics2115_voice::update_volume_envelope()
|
||||||
{
|
{
|
||||||
@ -263,39 +313,39 @@ int ics2115_device::ics2115_voice::update_oscillator()
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: proper interpolation for uLaw (fill_output doesn't use this) and 8-bit samples (looping)
|
//TODO: proper interpolation for 8-bit samples (looping)
|
||||||
stream_sample_t ics2115_device::get_sample(ics2115_voice& voice)
|
stream_sample_t ics2115_device::get_sample(ics2115_voice& voice)
|
||||||
{
|
{
|
||||||
u32 curaddr = ((voice.osc.saddr << 20) & 0xffffff) | (voice.osc.acc >> 12);
|
u32 curaddr = voice.osc.acc >> 12;
|
||||||
u32 nextaddr;
|
u32 nextaddr;
|
||||||
|
|
||||||
if (voice.state.bitflags.on && voice.osc_conf.bitflags.loop && !voice.osc_conf.bitflags.loop_bidir &&
|
if (voice.state.bitflags.on && voice.osc_conf.bitflags.loop && !voice.osc_conf.bitflags.loop_bidir &&
|
||||||
(voice.osc.left < (voice.osc.fc <<2)))
|
(voice.osc.left < (voice.osc.fc <<2)))
|
||||||
{
|
{
|
||||||
//logerror("C?[%x:%x]", voice.osc.left, voice.osc.acc);
|
//logerror("C?[%x:%x]", voice.osc.left, voice.osc.acc);
|
||||||
nextaddr = ((voice.osc.saddr << 20) & 0xffffff) | (voice.osc.start >> 12);
|
nextaddr = voice.osc.start >> 12;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
nextaddr = curaddr + 2;
|
nextaddr = curaddr + 2;
|
||||||
|
|
||||||
|
|
||||||
s16 sample1, sample2;
|
s16 sample1, sample2;
|
||||||
if (voice.osc_conf.bitflags.eightbit)
|
if (voice.osc_conf.bitflags.ulaw)
|
||||||
{
|
{
|
||||||
sample1 = ((s8)m_rom[curaddr]) << 8;
|
sample1 = m_ulaw[read_sample(voice, curaddr)];
|
||||||
sample2 = ((s8)m_rom[curaddr + 1]) << 8;
|
sample2 = m_ulaw[read_sample(voice, curaddr + 1)];
|
||||||
|
}
|
||||||
|
else if (voice.osc_conf.bitflags.eightbit)
|
||||||
|
{
|
||||||
|
sample1 = ((s8)read_sample(voice, curaddr)) << 8;
|
||||||
|
sample2 = ((s8)read_sample(voice, curaddr + 1)) << 8;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
sample1 = m_rom[curaddr + 0] | (((s8)m_rom[curaddr + 1]) << 8);
|
sample1 = read_sample(voice, curaddr + 0) | (((s8)read_sample(voice, curaddr + 1)) << 8);
|
||||||
sample2 = m_rom[nextaddr+ 0] | (((s8)m_rom[nextaddr+ 1]) << 8);
|
sample2 = read_sample(voice, nextaddr+ 0) | (((s8)read_sample(voice, nextaddr+ 1)) << 8);
|
||||||
//sample2 = m_rom[curaddr + 2] | (((s8)m_rom[curaddr + 3]) << 8);
|
//sample2 = read_sample(voice, curaddr + 2) | (((s8)read_sample(voice, curaddr + 3)) << 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
//no need for interpolation since it's around 1 note a cycle?
|
|
||||||
//if (voice.osc.fc >> 10)
|
|
||||||
// return sample1;
|
|
||||||
|
|
||||||
//linear interpolation as in US patent 6,246,774 B1, column 2 row 59
|
//linear interpolation as in US patent 6,246,774 B1, column 2 row 59
|
||||||
//LEN=1, BLEN=0, DIR=0, start+end interpolation
|
//LEN=1, BLEN=0, DIR=0, start+end interpolation
|
||||||
s32 sample, diff;
|
s32 sample, diff;
|
||||||
@ -303,6 +353,10 @@ stream_sample_t ics2115_device::get_sample(ics2115_voice& voice)
|
|||||||
diff = sample2 - sample1;
|
diff = sample2 - sample1;
|
||||||
fract = (voice.osc.acc >> 3) & 0x1ff;
|
fract = (voice.osc.acc >> 3) & 0x1ff;
|
||||||
|
|
||||||
|
//no need for interpolation since it's around 1 note a cycle?
|
||||||
|
//if (!fract)
|
||||||
|
// return sample1;
|
||||||
|
|
||||||
sample = (((s32)sample1 << 9) + diff * fract) >> 9;
|
sample = (((s32)sample1 << 9) + diff * fract) >> 9;
|
||||||
//sample = sample1;
|
//sample = sample1;
|
||||||
return sample;
|
return sample;
|
||||||
@ -349,14 +403,7 @@ int ics2115_device::fill_output(ics2115_voice& voice, stream_sample_t *outputs[2
|
|||||||
//final output, even if they are not running. This means that whatever data value
|
//final output, even if they are not running. This means that whatever data value
|
||||||
//that the voice is pointing at is contributing to the summation.
|
//that the voice is pointing at is contributing to the summation.
|
||||||
//(austere note: this will of course fix some of the glitches due to multiple transition)
|
//(austere note: this will of course fix some of the glitches due to multiple transition)
|
||||||
stream_sample_t sample;
|
stream_sample_t sample = get_sample(voice);
|
||||||
if (voice.osc_conf.bitflags.ulaw)
|
|
||||||
{
|
|
||||||
u32 curaddr = ((voice.osc.saddr << 20) & 0xffffff) | (voice.osc.acc >> 12);
|
|
||||||
sample = m_ulaw[m_rom[curaddr]];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
sample = get_sample(voice);
|
|
||||||
|
|
||||||
//15-bit volume + (5-bit worth of 32 channel sum) + 16-bit samples = 4-bit extra
|
//15-bit volume + (5-bit worth of 32 channel sum) + 16-bit samples = 4-bit extra
|
||||||
if (!m_vmode || voice.playing())
|
if (!m_vmode || voice.playing())
|
||||||
@ -396,11 +443,7 @@ void ics2115_device::sound_stream_update(sound_stream &stream, stream_sample_t *
|
|||||||
/*
|
/*
|
||||||
#ifdef ICS2115_DEBUG
|
#ifdef ICS2115_DEBUG
|
||||||
u32 curaddr = ((voice.osc.saddr << 20) & 0xffffff) | (voice.osc.acc >> 12);
|
u32 curaddr = ((voice.osc.saddr << 20) & 0xffffff) | (voice.osc.acc >> 12);
|
||||||
stream_sample_t sample;
|
stream_sample_t sample = get_sample(voice);
|
||||||
if (voice.osc_conf.bitflags.ulaw)
|
|
||||||
sample = m_ulaw[m_rom[curaddr]];
|
|
||||||
else
|
|
||||||
sample = get_sample(voice);
|
|
||||||
logerror("[%06x=%04x]", curaddr, (s16)sample);
|
logerror("[%06x=%04x]", curaddr, (s16)sample);
|
||||||
#endif
|
#endif
|
||||||
*/
|
*/
|
||||||
@ -587,6 +630,9 @@ u16 ics2115_device::reg_read()
|
|||||||
ret = m_irq_pending & 3;
|
ret = m_irq_pending & 3;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
// case 0x48: // Accumulator Monitor Status
|
||||||
|
// case 0x49: // Accumulator Monitor Data
|
||||||
|
|
||||||
case 0x4a: // IRQ Pending
|
case 0x4a: // IRQ Pending
|
||||||
ret = m_irq_pending;
|
ret = m_irq_pending;
|
||||||
break;
|
break;
|
||||||
@ -599,6 +645,17 @@ u16 ics2115_device::reg_read()
|
|||||||
ret = revision;
|
ret = revision;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
// case 0x4d: // System Control
|
||||||
|
|
||||||
|
// case 0x50: // MIDI Data Register
|
||||||
|
// case 0x51: // MIDI Status Register
|
||||||
|
// case 0x52: // Host Data Register
|
||||||
|
// case 0x53: // Host Status Register
|
||||||
|
// case 0x54: // MIDI Emulation Interrupt Control
|
||||||
|
// case 0x55: // Host Emulation Interrupt Control
|
||||||
|
// case 0x56: // Host/MIDI Emulation Interrupt Status
|
||||||
|
// case 0x57: // Emulation Mode
|
||||||
|
|
||||||
default:
|
default:
|
||||||
#ifdef ICS2115_DEBUG
|
#ifdef ICS2115_DEBUG
|
||||||
logerror("ICS2115: Unhandled read %x\n", m_reg_select);
|
logerror("ICS2115: Unhandled read %x\n", m_reg_select);
|
||||||
@ -794,6 +851,11 @@ void ics2115_device::reg_write(u16 data, u16 mem_mask)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
// case 0x44: // DMA Start Address Low (11:4)
|
||||||
|
// case 0x45: // DMA Start Address Low (19:12)
|
||||||
|
// case 0x46: // DMA Start Address Low (21:20)
|
||||||
|
// case 0x47: // DMA Control
|
||||||
|
|
||||||
case 0x4a: // IRQ Enable
|
case 0x4a: // IRQ Enable
|
||||||
if (ACCESSING_BITS_0_7)
|
if (ACCESSING_BITS_0_7)
|
||||||
{
|
{
|
||||||
@ -802,10 +864,22 @@ void ics2115_device::reg_write(u16 data, u16 mem_mask)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
// case 0x4c: // Memory Config
|
||||||
|
// case 0x4d: // System Control
|
||||||
|
|
||||||
case 0x4f: // Oscillator Address being Programmed
|
case 0x4f: // Oscillator Address being Programmed
|
||||||
if (ACCESSING_BITS_0_7)
|
if (ACCESSING_BITS_0_7)
|
||||||
m_osc_select = (data & 0xff) % (1+m_active_osc);
|
m_osc_select = (data & 0xff) % (1+m_active_osc);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
// case 0x50: // MIDI Data Register
|
||||||
|
// case 0x51: // MIDI Control Register
|
||||||
|
// case 0x52: // Host Data Register
|
||||||
|
// case 0x53: // Host Control Register
|
||||||
|
// case 0x54: // MIDI Emulation Interrupt Control
|
||||||
|
// case 0x55: // Host Emulation Interrupt Control
|
||||||
|
// case 0x57: // Emulation Mode
|
||||||
|
|
||||||
default:
|
default:
|
||||||
#ifdef ICS2115_DEBUG
|
#ifdef ICS2115_DEBUG
|
||||||
logerror("ICS2115: Unhandled write %x onto %x [voice = %d]\n", data, m_reg_select, m_osc_select);
|
logerror("ICS2115: Unhandled write %x onto %x [voice = %d]\n", data, m_reg_select, m_osc_select);
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
|
|
||||||
// ======================> ics2115_device
|
// ======================> ics2115_device
|
||||||
|
|
||||||
class ics2115_device : public device_t, public device_sound_interface
|
class ics2115_device : public device_t, public device_sound_interface, public device_memory_interface
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static constexpr feature_type imperfect_features() { return feature::SOUND; } // Incorrect/Unverified interrupt, interpolation;
|
static constexpr feature_type imperfect_features() { return feature::SOUND; } // Incorrect/Unverified interrupt, interpolation;
|
||||||
@ -33,6 +33,20 @@ public:
|
|||||||
TIMER_CALLBACK_MEMBER(timer_cb_1);
|
TIMER_CALLBACK_MEMBER(timer_cb_1);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
// device-level overrides
|
||||||
|
virtual void device_start() override;
|
||||||
|
virtual void device_reset() override;
|
||||||
|
virtual void device_clock_changed() override;
|
||||||
|
|
||||||
|
// device_sound_interface overrides
|
||||||
|
virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) override;
|
||||||
|
|
||||||
|
// device_memory_interface configuration
|
||||||
|
virtual space_config_vector memory_space_config() const override;
|
||||||
|
|
||||||
|
address_space_config m_data_config;
|
||||||
|
|
||||||
|
private:
|
||||||
static constexpr u16 revision = 0x1;
|
static constexpr u16 revision = 0x1;
|
||||||
|
|
||||||
struct ics2115_voice {
|
struct ics2115_voice {
|
||||||
@ -99,14 +113,6 @@ protected:
|
|||||||
void update_ramp();
|
void update_ramp();
|
||||||
};
|
};
|
||||||
|
|
||||||
// device-level overrides
|
|
||||||
virtual void device_start() override;
|
|
||||||
virtual void device_reset() override;
|
|
||||||
virtual void device_clock_changed() override;
|
|
||||||
|
|
||||||
// internal callbacks
|
|
||||||
virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) override;
|
|
||||||
|
|
||||||
//internal register helper functions
|
//internal register helper functions
|
||||||
u16 reg_read();
|
u16 reg_read();
|
||||||
void reg_write(u16 data, u16 mem_mask);
|
void reg_write(u16 data, u16 mem_mask);
|
||||||
@ -117,10 +123,12 @@ protected:
|
|||||||
//stream helper functions
|
//stream helper functions
|
||||||
int fill_output(ics2115_voice& voice, stream_sample_t *outputs[2], int samples);
|
int fill_output(ics2115_voice& voice, stream_sample_t *outputs[2], int samples);
|
||||||
stream_sample_t get_sample(ics2115_voice& voice);
|
stream_sample_t get_sample(ics2115_voice& voice);
|
||||||
|
u8 read_sample(ics2115_voice& voice, u32 addr) { return m_cache.read_byte((voice.osc.saddr << 20) | (addr & 0xfffff)); }
|
||||||
|
|
||||||
sound_stream *m_stream;
|
sound_stream *m_stream;
|
||||||
|
|
||||||
// internal state
|
// internal state
|
||||||
|
memory_access<24, 0, 0, ENDIANNESS_LITTLE>::cache m_cache;
|
||||||
required_region_ptr<u8> m_rom;
|
required_region_ptr<u8> m_rom;
|
||||||
devcb_write_line m_irq_cb;
|
devcb_write_line m_irq_cb;
|
||||||
|
|
||||||
@ -141,8 +149,10 @@ protected:
|
|||||||
u8 m_irq_enabled, m_irq_pending;
|
u8 m_irq_enabled, m_irq_pending;
|
||||||
bool m_irq_on;
|
bool m_irq_on;
|
||||||
|
|
||||||
//Unknown variable, seems to be effected by 0x12. Further investigation
|
/*
|
||||||
//Required.
|
Unknown variable, seems to be effected by 0x12. Further investigation
|
||||||
|
Required.
|
||||||
|
*/
|
||||||
u8 m_vmode;
|
u8 m_vmode;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user