summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/sound/ics2115.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/sound/ics2115.cpp')
-rw-r--r--src/devices/sound/ics2115.cpp384
1 files changed, 257 insertions, 127 deletions
diff --git a/src/devices/sound/ics2115.cpp b/src/devices/sound/ics2115.cpp
index 9ce19fe649f..bf52eb2a7a3 100644
--- a/src/devices/sound/ics2115.cpp
+++ b/src/devices/sound/ics2115.cpp
@@ -1,37 +1,67 @@
// license:BSD-3-Clause
-// copyright-holders:Alex Marshall,nimitz,austere
-//ICS2115 by Raiden II team (c) 2010
-//members: austere, nimitz, Alex Marshal
-//
-//Original driver by O. Galibert, ElSemi
-//
-//Use tab size = 4 for your viewing pleasure.
+// copyright-holders:Alex Marshall, nimitz, austere
+/*
+ ICS2115 by Raiden II team (c) 2010
+ members: austere, nimitz, Alex Marshal
+
+ Original driver by O. Galibert, ElSemi
+
+ Use tab size = 4 for your viewing pleasure.
+
+ TODO:
+ - Verify BYTE/ROMEN pin behavior
+ - DRAM, DMA, MIDI interface is unimplemented
+ - Verify interrupt, envelope, timer period
+ - Verify unemulated registers
+
+*/
#include "emu.h"
#include "ics2115.h"
+
+#include <algorithm>
#include <cmath>
+
//#define ICS2115_DEBUG
//#define ICS2115_ISOLATE 6
+
// device type definition
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)
- : device_t(mconfig, ICS2115, tag, owner, clock),
- device_sound_interface(mconfig, *this), 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_t(mconfig, ICS2115, tag, owner, clock)
+ , device_sound_interface(mconfig, *this)
+ , device_memory_interface(mconfig, *this)
+ , 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()
{
- 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_stream = machine().sound().stream_alloc(*this, 0, 2, 33075);
+ 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_irq_cb.resolve_safe();
+ m_timer[0].timer = timer_alloc(FUNC(ics2115_device::timer_cb_0), this);
+ m_timer[1].timer = timer_alloc(FUNC(ics2115_device::timer_cb_1), this);
+ m_stream = stream_alloc(0, 2, clock() / (32 * 32));
//Exact formula as per patent 5809466
//This seems to give the ok fit but it is not good enough.
@@ -48,16 +78,23 @@ void ics2115_device::device_start()
//u-Law table as per MIL-STD-188-113
u16 lut[8];
- u16 lut_initial = 33 << 2; //shift up 2-bits for 16-bit range.
+ const u16 lut_initial = 33 << 2; //shift up 2-bits for 16-bit range.
for (int i = 0; i < 8; i++)
lut[i] = (lut_initial << i) - lut_initial;
+
+ //pan law level
+ //log2(256*128) = 15 for -3db + 1 must be confirmed by real hardware owners
+ constexpr int PAN_LEVEL = 16;
+
for (int i = 0; i < 256; i++)
{
u8 exponent = (~i >> 4) & 0x07;
u8 mantissa = ~i & 0x0f;
s16 value = lut[exponent] + (mantissa << (exponent + 3));
m_ulaw[i] = (i & 0x80) ? -value : value;
+ m_panlaw[i] = PAN_LEVEL - (31 - count_leading_zeros_32(i)); //m_panlaw[i] = PAN_LEVEL - log2(i)
}
+ m_panlaw[0] = 0xfff; //all bits to one when no pan
save_item(NAME(m_timer[0].period));
save_item(NAME(m_timer[0].scale));
@@ -72,11 +109,14 @@ void ics2115_device::device_start()
save_item(NAME(m_irq_on));
save_item(NAME(m_active_osc));
save_item(NAME(m_vmode));
+ save_item(NAME(m_regs));
+ save_item(STRUCT_MEMBER(m_voice, regs));
for (int i = 0; i < 32; i++)
{
save_item(NAME(m_voice[i].osc_conf.value), i);
- save_item(NAME(m_voice[i].state.value), i);
+ save_item(NAME(m_voice[i].state.on), i);
+ save_item(NAME(m_voice[i].state.ramp), i);
save_item(NAME(m_voice[i].vol_ctrl.value), i);
save_item(NAME(m_voice[i].osc.left), i);
save_item(NAME(m_voice[i].osc.acc), i);
@@ -97,6 +137,9 @@ void ics2115_device::device_start()
}
}
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
void ics2115_device::device_reset()
{
@@ -104,6 +147,7 @@ void ics2115_device::device_reset()
m_irq_pending = 0;
//possible re-suss
m_active_osc = 31;
+ m_stream->set_sample_rate(clock() / ((m_active_osc + 1) * 32));
m_osc_select = 0;
m_reg_select = 0;
m_vmode = 0;
@@ -132,13 +176,60 @@ void ics2115_device::device_reset()
elem.vol.pan = 0x7f;
elem.vol_ctrl.value = 1;
elem.vol.mode = 0;
- elem.state.value = 0;
+ elem.state.on = false;
+ elem.state.ramp = 0;
}
}
-//TODO: improve using next-state logic from column 126 of patent 5809466
+
+//-------------------------------------------------
+// device_clock_changed - called if the clock
+// changes
+//-------------------------------------------------
+
+void ics2115_device::device_clock_changed()
+{
+ 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) };
+}
+
+
+/*
+ Using next-state logic from column 126 of patent 5809466.
+ VOL(L) = vol.acc
+ VINC = vol.inc
+ DIR = invert
+ BC = boundary cross (start or end )
+ BLEN = bi directional loop enable
+ LEN loop enable
+ UVOL LEN BLEN DIR BC Next VOL(L)
+ 0 x x x x VOL(L) // no change no vol envelope
+ 1 x x 0 0 VOL(L) + VINC // forward dir no bc
+ 1 x x 1 0 VOL(L) - VINC // invert no bc
+ 1 0 x x 1 VOL(L) // no env len no vol envelope
+ ----------------------------------------------------------------------------
+ 1 1 0 0 1 start - ( end - (VOL(L) + VINC) )
+ 1 1 0 1 1 end + ( (VOL(L) - VINC) - start)
+ 1 1 1 0 1 end + (end - (VOL(L) + VINC) ) // here
+ 1 1 1 1 1 start - ( (VOL(L) - VINC)- start)
+*/
int ics2115_device::ics2115_voice::update_volume_envelope()
{
+ // test for boundary cross
+ bool bc = false;
+ if (vol.acc >= vol.end || vol.acc <= vol.end)
+ bc = true;
+
int ret = 0;
if (vol_ctrl.bitflags.done || vol_ctrl.bitflags.stop)
return ret;
@@ -168,23 +259,26 @@ int ics2115_device::ics2115_voice::update_volume_envelope()
if (vol_ctrl.bitflags.loop)
{
- if (vol_ctrl.bitflags.loop_bidir)
- vol_ctrl.bitflags.invert = !vol_ctrl.bitflags.invert;
-
- if (vol_ctrl.bitflags.invert)
- vol.acc = vol.end + vol.left;
- else
- vol.acc = vol.start - vol.left;
+ if (bc)
+ {
+ if (!vol_ctrl.bitflags.loop_bidir)
+ {
+ if (!vol_ctrl.bitflags.invert)
+ vol.acc = vol.start - (vol.end - (vol.acc + vol.incr)); // uvol = 1* len = 1* blen = 0 dir = 0 bc = 1* start - ( end - (VOL(L) + VINC) )
+ else
+ vol.acc = vol.end + ((vol.acc - vol.incr) - vol.start); // 1 1 blen = 0 dir = 1 1 end + ( (VOL(L) - VINC) - start)
+ }
+ else
+ {
+ if (!vol_ctrl.bitflags.invert)
+ vol.acc = vol.end + (vol.end - (vol.acc + vol.incr)); // 1 1 blen = 1 dir = 0 1 end + (end - (VOL(L) + VINC) )
+ else
+ vol.acc = vol.start - ((vol.acc - vol.incr) - vol.start); // 1 1 beln = 1 dir = 1 1 start - ( (VOL(L) - VINC)- start)
+ }
+ }
}
else
- {
- state.bitflags.on = false;
vol_ctrl.bitflags.done = true;
- if (vol_ctrl.bitflags.invert)
- vol.acc = vol.end;
- else
- vol.acc = vol.start;
- }
return ret;
}
@@ -247,7 +341,7 @@ int ics2115_device::ics2115_voice::update_oscillator()
}
else
{
- state.bitflags.on = false;
+ state.on = false;
osc_conf.bitflags.stop = true;
if (!osc_conf.bitflags.invert)
osc.acc = osc.end;
@@ -257,108 +351,105 @@ int ics2115_device::ics2115_voice::update_oscillator()
return ret;
}
-//TODO: proper interpolation for uLaw (fill_output doesn't use this) and 8-bit samples (looping)
-stream_sample_t ics2115_device::get_sample(ics2115_voice& voice)
+//TODO: proper interpolation for 8-bit samples (looping)
+s32 ics2115_device::get_sample(ics2115_voice& voice)
{
- u32 curaddr = ((voice.osc.saddr << 20) & 0xffffff) | (voice.osc.acc >> 12);
+ const u32 curaddr = voice.osc.acc >> 12;
u32 nextaddr;
- if (voice.state.bitflags.on && voice.osc_conf.bitflags.loop && !voice.osc_conf.bitflags.loop_bidir &&
- (voice.osc.left < (voice.osc.fc <<2)))
+ if (voice.state.on && voice.osc_conf.bitflags.loop && !voice.osc_conf.bitflags.loop_bidir &&
+ (voice.osc.left < (voice.osc.fc << 2)))
{
//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
nextaddr = curaddr + 2;
-
s16 sample1, sample2;
- if (voice.osc_conf.bitflags.eightbit)
+ if (voice.osc_conf.bitflags.ulaw)
{
- sample1 = ((s8)m_rom[curaddr]) << 8;
- sample2 = ((s8)m_rom[curaddr + 1]) << 8;
+ sample1 = m_ulaw[read_sample(voice, curaddr)];
+ 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
{
- sample1 = m_rom[curaddr + 0] | (((s8)m_rom[curaddr + 1]) << 8);
- sample2 = m_rom[nextaddr+ 0] | (((s8)m_rom[nextaddr+ 1]) << 8);
- //sample2 = m_rom[curaddr + 2] | (((s8)m_rom[curaddr + 3]) << 8);
+ sample1 = read_sample(voice, curaddr + 0) | (((s8)read_sample(voice, curaddr + 1)) << 8);
+ sample2 = read_sample(voice, nextaddr+ 0) | (((s8)read_sample(voice, nextaddr+ 1)) << 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
//LEN=1, BLEN=0, DIR=0, start+end interpolation
- s32 sample, diff;
- u16 fract;
- diff = sample2 - sample1;
- fract = (voice.osc.acc >> 3) & 0x1ff;
+ const s32 diff = sample2 - sample1;
+ const u16 fract = (voice.osc.acc >> 3) & 0x1ff;
- sample = (((s32)sample1 << 9) + diff * fract) >> 9;
+ //no need for interpolation since it's around 1 note a cycle?
+ //if (!fract)
+ // return sample1;
+
+ const s32 sample = (((s32)sample1 << 9) + diff * fract) >> 9;
//sample = sample1;
return sample;
}
bool ics2115_device::ics2115_voice::playing()
{
- return state.bitflags.on && !((vol_ctrl.bitflags.done || vol_ctrl.bitflags.stop) && osc_conf.bitflags.stop);
+ return state.on && !(osc_conf.bitflags.stop);
}
void ics2115_device::ics2115_voice::update_ramp()
{
//slow attack
- if (state.bitflags.on && !osc_conf.bitflags.stop)
+ if (state.on && !osc_conf.bitflags.stop)
{
- if (state.bitflags.ramp < 0x40)
- state.bitflags.ramp += 0x1;
+ if (state.ramp < 0x40)
+ state.ramp += 0x1;
else
- state.bitflags.ramp = 0x40;
+ state.ramp = 0x40;
}
//slow release
else
{
- if (state.bitflags.ramp)
- state.bitflags.ramp -= 0x1;
+ if (state.ramp)
+ state.ramp -= 0x1;
}
}
-int ics2115_device::fill_output(ics2115_voice& voice, stream_sample_t *outputs[2], int samples)
+int ics2115_device::fill_output(ics2115_voice& voice, sound_stream &stream)
{
bool irq_invalid = false;
- u16 fine = 1 << (3*(voice.vol.incr >> 6));
+ const u16 fine = 1 << (3*(voice.vol.incr >> 6));
voice.vol.add = (voice.vol.incr & 0x3f)<< (10 - fine);
- for (int i = 0; i < samples; i++)
+ for (int i = 0; i < stream.samples(); i++)
{
- u32 volacc = (voice.vol.acc >> 10) & 0xffff;
- u32 volume = (m_volume[volacc >> 4] * voice.state.bitflags.ramp) >> 6;
- u16 vleft = volume; //* (255 - voice.vol.pan) / 0x80];
- u16 vright = volume; //* (voice.vol.pan + 1) / 0x80];
+ constexpr int RAMP_SHIFT = 6;
+ const u32 volacc = (voice.vol.acc >> 14) & 0xfff;
+ const s16 vlefti = volacc - m_panlaw[255 - voice.vol.pan]; // left index from acc - pan law
+ const s16 vrighti = volacc - m_panlaw[voice.vol.pan]; // right index from acc - pan law
+ //check negative values so no cracks, is it a hardware feature ?
+ const u16 vleft = vlefti > 0 ? (m_volume[vlefti] * voice.state.ramp >> RAMP_SHIFT) : 0;
+ const u16 vright = vrighti > 0 ? (m_volume[vrighti] * voice.state.ramp >> RAMP_SHIFT) : 0;
//From GUS doc:
//In general, it is necessary to remember that all voices are being summed in to the
//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.
//(austere note: this will of course fix some of the glitches due to multiple transition)
- stream_sample_t sample;
- 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);
+ s32 sample = get_sample(voice);
//15-bit volume + (5-bit worth of 32 channel sum) + 16-bit samples = 4-bit extra
+ //if (voice.playing())
if (!m_vmode || voice.playing())
{
- /*if (voice.playing())
- {*/
- outputs[0][i] += (sample * vleft) >> (5 + volume_bits - 16);
- outputs[1][i] += (sample * vright) >> (5 + volume_bits - 16);
+ stream.add_int(0, i, (sample * vleft) >> (5 + volume_bits), 32768);
+ stream.add_int(1, i, (sample * vright) >> (5 + volume_bits), 32768);
}
voice.update_ramp();
@@ -373,11 +464,8 @@ int ics2115_device::fill_output(ics2115_voice& voice, stream_sample_t *outputs[2
return irq_invalid;
}
-void ics2115_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples)
+void ics2115_device::sound_stream_update(sound_stream &stream)
{
- memset(outputs[0], 0, samples * sizeof(stream_sample_t));
- memset(outputs[1], 0, samples * sizeof(stream_sample_t));
-
bool irq_invalid = false;
for (int osc = 0; osc <= m_active_osc; osc++)
{
@@ -390,15 +478,11 @@ void ics2115_device::sound_stream_update(sound_stream &stream, stream_sample_t *
/*
#ifdef ICS2115_DEBUG
u32 curaddr = ((voice.osc.saddr << 20) & 0xffffff) | (voice.osc.acc >> 12);
- stream_sample_t sample;
- if (voice.osc_conf.bitflags.ulaw)
- sample = m_ulaw[m_rom[curaddr]];
- else
- sample = get_sample(voice);
+ s32 sample = get_sample(voice);
logerror("[%06x=%04x]", curaddr, (s16)sample);
#endif
*/
- if (fill_output(voice, outputs, samples))
+ if (fill_output(voice, stream))
irq_invalid = true;
#ifdef ICS2115_DEBUG
@@ -430,28 +514,30 @@ void ics2115_device::sound_stream_update(sound_stream &stream, stream_sample_t *
logerror("|");
#endif
- //rescale
- for (int i = 0; i < samples; i++)
- {
- outputs[0][i] >>= 16;
- outputs[1][i] >>= 16;
- }
-
if (irq_invalid)
recalc_irq();
-
}
//Helper Function (Reads off current register)
u16 ics2115_device::reg_read()
{
- u16 ret;
+ m_stream->update();
+
+ u16 ret = 0;
ics2115_voice& voice = m_voice[m_osc_select];
switch (m_reg_select)
{
case 0x00: // [osc] Oscillator Configuration
ret = voice.osc_conf.value;
+ if (voice.state.on)
+ {
+ ret |= 8;
+ }
+ else
+ {
+ ret &= ~8;
+ }
ret <<= 8;
break;
@@ -534,7 +620,8 @@ u16 ics2115_device::reg_read()
ret = m_active_osc;
break;
- case 0x0f:{// [osc] Interrupt source/oscillator
+ case 0x0f: // [osc] Interrupt source/oscillator
+ {
ret = 0xff;
for (int i = 0; i <= m_active_osc; i++)
{
@@ -542,9 +629,6 @@ u16 ics2115_device::reg_read()
if (v.osc_conf.bitflags.irq_pending || v.vol_ctrl.bitflags.irq_pending)
{
ret = i | 0xe0;
- ret &= v.vol_ctrl.bitflags.irq_pending ? (~0x40) : 0xff;
- ret &= v.osc_conf.bitflags.irq_pending ? (~0x80) : 0xff;
- recalc_irq();
if (v.osc_conf.bitflags.irq_pending)
{
v.osc_conf.bitflags.irq_pending = 0;
@@ -555,11 +639,13 @@ u16 ics2115_device::reg_read()
v.vol_ctrl.bitflags.irq_pending = 0;
ret &= ~0x40;
}
+ recalc_irq();
break;
}
}
ret <<= 8;
- break;}
+ break;
+ }
case 0x10: // [osc] Oscillator Control
ret = voice.osc.ctl << 8;
@@ -581,6 +667,9 @@ u16 ics2115_device::reg_read()
ret = m_irq_pending & 3;
break;
+ // case 0x48: // Accumulator Monitor Status
+ // case 0x49: // Accumulator Monitor Data
+
case 0x4a: // IRQ Pending
ret = m_irq_pending;
break;
@@ -593,6 +682,17 @@ u16 ics2115_device::reg_read()
ret = revision;
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:
#ifdef ICS2115_DEBUG
logerror("ICS2115: Unhandled read %x\n", m_reg_select);
@@ -605,7 +705,13 @@ u16 ics2115_device::reg_read()
void ics2115_device::reg_write(u16 data, u16 mem_mask)
{
+ m_stream->update();
+
ics2115_voice& voice = m_voice[m_osc_select];
+ if (m_reg_select < 0x20)
+ COMBINE_DATA(&voice.regs[m_reg_select]);
+ else if (m_reg_select >= 0x40 && m_reg_select < 0x80)
+ COMBINE_DATA(&m_regs[m_reg_select - 0x40]);
switch (m_reg_select)
{
@@ -614,6 +720,7 @@ void ics2115_device::reg_write(u16 data, u16 mem_mask)
{
voice.osc_conf.value &= 0x80;
voice.osc_conf.value |= (data >> 8) & 0x7f;
+ recalc_irq();
}
break;
@@ -713,13 +820,17 @@ void ics2115_device::reg_write(u16 data, u16 mem_mask)
{
voice.vol_ctrl.value &= 0x80;
voice.vol_ctrl.value |= (data >> 8) & 0x7f;
+ recalc_irq();
}
break;
case 0x0e: // Active Voices
//Does this value get added to 1? Not sure. Could trace for writes of 32.
if (ACCESSING_BITS_8_15)
+ {
m_active_osc = (data >> 8) & 0x1f; // & 0x1f ? (Guessing)
+ m_stream->set_sample_rate(clock() / ((m_active_osc + 1) * 32));
+ }
break;
//2X8 ?
case 0x10: // [osc] Oscillator Control
@@ -730,6 +841,7 @@ void ics2115_device::reg_write(u16 data, u16 mem_mask)
{
data >>= 8;
voice.osc.ctl = data;
+ voice.state.on = !voice.osc.ctl; // some early PGM games need this
if (!data)
keyon();
//guessing here
@@ -744,10 +856,9 @@ void ics2115_device::reg_write(u16 data, u16 mem_mask)
#endif
if (!m_vmode)
{
+ //try to key it off as well!
voice.osc_conf.bitflags.stop = true;
voice.vol_ctrl.bitflags.stop = true;
- //try to key it off as well!
- voice.state.bitflags.on = false;
}
}
#ifdef ICS2115_DEBUG
@@ -785,6 +896,11 @@ void ics2115_device::reg_write(u16 data, u16 mem_mask)
}
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
if (ACCESSING_BITS_0_7)
{
@@ -793,10 +909,22 @@ void ics2115_device::reg_write(u16 data, u16 mem_mask)
}
break;
+ // case 0x4c: // Memory Config
+ // case 0x4d: // System Control
+
case 0x4f: // Oscillator Address being Programmed
if (ACCESSING_BITS_0_7)
m_osc_select = (data & 0xff) % (1+m_active_osc);
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:
#ifdef ICS2115_DEBUG
logerror("ICS2115: Unhandled write %x onto %x [voice = %d]\n", data, m_reg_select, m_osc_select);
@@ -813,6 +941,7 @@ u8 ics2115_device::read(offs_t offset)
{
case 0:
//TODO: check this suspect code
+ m_stream->update();
if (m_irq_on)
{
ret |= 0x80;
@@ -929,9 +1058,8 @@ void ics2115_device::keyon()
return;
#endif
//set initial condition (may need to invert?) -- does NOT work since these are set to zero even
- m_voice[m_osc_select].state.bitflags.on = true;
//no ramp up...
- m_voice[m_osc_select].state.bitflags.ramp = 0x40;
+ m_voice[m_osc_select].state.ramp = 0x40;
#ifdef ICS2115_DEBUG
logerror("[%02d vs:%04x ve:%04x va:%04x vi:%02x vc:%02x os:%06x oe:%06x oa:%06x of:%04x SA:%02x oc:%02x][%04x]\n", m_osc_select,
@@ -958,40 +1086,42 @@ void ics2115_device::recalc_irq()
//Suspect
bool irq = (m_irq_pending & m_irq_enabled);
for (int i = 0; (!irq) && (i < 32); i++)
- irq |= m_voice[i].vol_ctrl.bitflags.irq_pending && m_voice[i].osc_conf.bitflags.irq_pending;
+ {
+ irq |= m_voice[i].osc_conf.bitflags.irq && m_voice[i].osc_conf.bitflags.irq_pending;
+ irq |= m_voice[i].vol_ctrl.bitflags.irq && m_voice[i].vol_ctrl.bitflags.irq_pending;
+ }
m_irq_on = irq;
- if (!m_irq_cb.isnull())
- m_irq_cb(irq ? ASSERT_LINE : CLEAR_LINE);
+ m_irq_cb(irq ? ASSERT_LINE : CLEAR_LINE);
}
TIMER_CALLBACK_MEMBER( ics2115_device::timer_cb_0 )
{
- m_irq_pending |= 1 << 0;
- recalc_irq();
+ if (!(m_irq_pending & (1 << 0)))
+ {
+ m_irq_pending |= 1 << 0;
+ recalc_irq();
+ }
}
TIMER_CALLBACK_MEMBER( ics2115_device::timer_cb_1 )
{
- m_irq_pending |= 1 << 1;
- recalc_irq();
+ if (!(m_irq_pending & (1 << 1)))
+ {
+ m_irq_pending |= 1 << 1;
+ recalc_irq();
+ }
}
void ics2115_device::recalc_timer(int timer)
{
- //Old regression-based formula (minus constant)
- //u64 period = m_timer[timer].preset * (m_timer[timer].scale << 16) / 60;
-
- //New formula based on O.Galibert's reverse engineering of ICS2115 card firmware
u64 period = ((m_timer[timer].scale & 0x1f) + 1) * (m_timer[timer].preset + 1);
- period = (period << (4 + (m_timer[timer].scale >> 5)))*78125/2646;
+ period = period << (4 + (m_timer[timer].scale >> 5));
if (m_timer[timer].period != period)
{
+ attotime tp = attotime::from_ticks(period, clock());
+ logerror("Timer %d period %dns (%dHz)\n", timer, int(tp.as_double()*1e9), int(1/tp.as_double()));
m_timer[timer].period = period;
- // Adjust the timer lengths
- if (period) // Reset the length
- m_timer[timer].timer->adjust(attotime::from_nsec(period), 0, attotime::from_nsec(period));
- else // Kill the timer if length == 0
- m_timer[timer].timer->adjust(attotime::never);
+ m_timer[timer].timer->adjust(tp, 0, tp);
}
}