mirror of
https://github.com/holub/mame
synced 2025-10-05 08:41:31 +03:00
iremga20: assume keyon is at reg 6 bit 1(not just any non-0 value), removed 2nd end of sample check, misc refactor and added notes (nw)
This commit is contained in:
parent
cc68d98dd6
commit
3b454a7a0a
@ -3,8 +3,17 @@
|
||||
/*********************************************************
|
||||
|
||||
Irem GA20 PCM Sound Chip
|
||||
80 pin QFP, label NANAO GA20 (Nanao Corporation was Irem's parent company)
|
||||
|
||||
It's not currently known whether this chip is stereo.
|
||||
TODO:
|
||||
- It's not currently known whether this chip is stereo.
|
||||
- Is sample position base(regs 0,1) used while sample is playing, or
|
||||
latched at key on? We've always emulated it the latter way.
|
||||
gunforc2 seems to be the only game updating the address regs sometimes
|
||||
while a sample is playing, but it doesn't seem intentional.
|
||||
- What is the 2nd sample address for? Is it end(cut-off) address, or
|
||||
loop start address? Every game writes a value that's past sample end.
|
||||
- All games write either 0 or 2 to reg #6, do other bits have any function?
|
||||
|
||||
|
||||
Revisions:
|
||||
@ -26,7 +35,7 @@ Revisions:
|
||||
02-03-2007 R. Belmont
|
||||
- Cleaned up faux x86 assembly.
|
||||
|
||||
09-25-2018 Valley Bell
|
||||
09-25-2018 Valley Bell & co
|
||||
- rewrote channel update to make data 0 act as sample terminator
|
||||
|
||||
*********************************************************/
|
||||
@ -36,8 +45,6 @@ Revisions:
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#define MAX_VOL 256
|
||||
|
||||
|
||||
// device type definition
|
||||
DEFINE_DEVICE_TYPE(IREMGA20, iremga20_device, "iremga20", "Irem GA20")
|
||||
@ -66,26 +73,16 @@ iremga20_device::iremga20_device(const machine_config &mconfig, const char *tag,
|
||||
|
||||
void iremga20_device::device_start()
|
||||
{
|
||||
int i;
|
||||
|
||||
iremga20_reset();
|
||||
|
||||
std::fill(std::begin(m_regs), std::end(m_regs), 0);
|
||||
|
||||
m_stream = stream_alloc(0, 2, clock()/4);
|
||||
|
||||
save_item(NAME(m_regs));
|
||||
for (i = 0; i < 4; i++)
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
save_item(NAME(m_channel[i].rate), i);
|
||||
save_item(NAME(m_channel[i].size), i);
|
||||
save_item(NAME(m_channel[i].start), i);
|
||||
save_item(NAME(m_channel[i].pos), i);
|
||||
save_item(NAME(m_channel[i].frac), i);
|
||||
save_item(NAME(m_channel[i].end), i);
|
||||
save_item(NAME(m_channel[i].volume), i);
|
||||
save_item(NAME(m_channel[i].pan), i);
|
||||
save_item(NAME(m_channel[i].effect), i);
|
||||
save_item(NAME(m_channel[i].play), i);
|
||||
}
|
||||
}
|
||||
@ -97,7 +94,16 @@ void iremga20_device::device_start()
|
||||
|
||||
void iremga20_device::device_reset()
|
||||
{
|
||||
iremga20_reset();
|
||||
std::fill(std::begin(m_regs), std::end(m_regs), 0);
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
m_channel[i].rate = 0;
|
||||
m_channel[i].pos = 0;
|
||||
m_channel[i].frac = 0;
|
||||
m_channel[i].end = 0;
|
||||
m_channel[i].volume = 0;
|
||||
m_channel[i].play = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------
|
||||
@ -142,12 +148,12 @@ void iremga20_device::sound_stream_update(sound_stream &stream, stream_sample_t
|
||||
if (sample == 0x00) // check for sample end marker
|
||||
ch.play = 0;
|
||||
else
|
||||
{
|
||||
sampleout += (sample - 0x80) * (int32_t)ch.volume;
|
||||
ch.frac += ch.rate;
|
||||
ch.pos += (ch.frac >> 24);
|
||||
ch.frac &= ((1 << 24) - 1);
|
||||
if (ch.pos >= ch.end) // for safety (the actual chip probably doesn't check this)
|
||||
ch.play = 0;
|
||||
ch.frac += ch.rate;
|
||||
ch.pos += (ch.frac >> 24);
|
||||
ch.frac &= ((1 << 24) - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -159,86 +165,64 @@ void iremga20_device::sound_stream_update(sound_stream &stream, stream_sample_t
|
||||
|
||||
WRITE8_MEMBER( iremga20_device::irem_ga20_w )
|
||||
{
|
||||
int channel;
|
||||
|
||||
//logerror("GA20: Offset %02x, data %04x\n",offset,data);
|
||||
|
||||
m_stream->update();
|
||||
|
||||
channel = offset >> 3;
|
||||
|
||||
offset &= 0x1f;
|
||||
m_regs[offset] = data;
|
||||
int ch = offset >> 3;
|
||||
|
||||
// channel regs:
|
||||
// 0,1: start address
|
||||
// 2,3: end? address
|
||||
// 4: rate
|
||||
// 5: volume
|
||||
// 6: control
|
||||
// 7: voice status (read-only)
|
||||
|
||||
switch (offset & 0x7)
|
||||
{
|
||||
case 0: /* start address low */
|
||||
m_channel[channel].start = ((m_channel[channel].start)&0xff000) | (data<<4);
|
||||
break;
|
||||
|
||||
case 1: /* start address high */
|
||||
m_channel[channel].start = ((m_channel[channel].start)&0x00ff0) | (data<<12);
|
||||
break;
|
||||
|
||||
case 2: /* end? address low */
|
||||
m_channel[channel].end = ((m_channel[channel].end)&0xff000) | (data<<4);
|
||||
break;
|
||||
|
||||
case 3: /* end? address high */
|
||||
m_channel[channel].end = ((m_channel[channel].end)&0x00ff0) | (data<<12);
|
||||
break;
|
||||
|
||||
case 4:
|
||||
m_channel[channel].rate = (1 << 24) / (256 - data);
|
||||
m_channel[ch].rate = (1 << 24) / (256 - data);
|
||||
break;
|
||||
|
||||
case 5: //AT: gain control
|
||||
m_channel[channel].volume = (data * MAX_VOL) / (data + 10);
|
||||
case 5:
|
||||
m_channel[ch].volume = (data * 256) / (data + 10);
|
||||
break;
|
||||
|
||||
case 6: //AT: this is always written 2(enabling both channels?)
|
||||
m_channel[channel].play = data;
|
||||
m_channel[channel].pos = m_channel[channel].start;
|
||||
m_channel[channel].frac = 0;
|
||||
case 6:
|
||||
// d1: key on/off
|
||||
if (data & 2)
|
||||
{
|
||||
m_channel[ch].play = 1;
|
||||
m_channel[ch].pos = (m_regs[ch << 3 | 0] | m_regs[ch << 3 | 1] << 8) << 4;
|
||||
m_channel[ch].end = (m_regs[ch << 3 | 2] | m_regs[ch << 3 | 3] << 8) << 4;
|
||||
m_channel[ch].frac = 0;
|
||||
}
|
||||
else
|
||||
m_channel[ch].play = 0;
|
||||
|
||||
// other: unknown/unused
|
||||
// possibilities are: loop flag, left/right speaker(stereo)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
READ8_MEMBER( iremga20_device::irem_ga20_r )
|
||||
{
|
||||
int channel;
|
||||
|
||||
m_stream->update();
|
||||
|
||||
channel = offset >> 3;
|
||||
offset &= 0x1f;
|
||||
int ch = offset >> 3;
|
||||
|
||||
switch (offset & 0x7)
|
||||
{
|
||||
case 7: // voice status. bit 0 is 1 if active. (routine around 0xccc in rtypeleo)
|
||||
return m_channel[channel].play ? 1 : 0;
|
||||
case 7: // voice status. bit 0 is 1 if active. (routine around 0xccc in rtypeleo)
|
||||
return m_channel[ch].play;
|
||||
|
||||
default:
|
||||
logerror("GA20: read unk. register %d, channel %d\n", offset & 0xf, channel);
|
||||
logerror("GA20: read unk. register %d, channel %d\n", offset & 0x7, ch);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void iremga20_device::iremga20_reset()
|
||||
{
|
||||
int i;
|
||||
|
||||
for( i = 0; i < 4; i++ ) {
|
||||
m_channel[i].rate = 0;
|
||||
m_channel[i].size = 0;
|
||||
m_channel[i].start = 0;
|
||||
m_channel[i].pos = 0;
|
||||
m_channel[i].frac = 0;
|
||||
m_channel[i].end = 0;
|
||||
m_channel[i].volume = 0;
|
||||
m_channel[i].pan = 0;
|
||||
m_channel[i].effect = 0;
|
||||
m_channel[i].play = 0;
|
||||
}
|
||||
}
|
||||
|
@ -44,21 +44,15 @@ private:
|
||||
struct channel_def
|
||||
{
|
||||
uint32_t rate;
|
||||
uint32_t size;
|
||||
uint32_t start;
|
||||
uint32_t pos;
|
||||
uint32_t frac;
|
||||
uint32_t end;
|
||||
uint32_t volume;
|
||||
uint32_t pan;
|
||||
uint32_t effect;
|
||||
uint32_t play;
|
||||
};
|
||||
|
||||
void iremga20_reset();
|
||||
|
||||
sound_stream *m_stream;
|
||||
uint8_t m_regs[0x40/2];
|
||||
uint8_t m_regs[0x20];
|
||||
channel_def m_channel[4];
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user