mirror of
https://github.com/holub/mame
synced 2025-10-06 09:00:04 +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
|
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:
|
Revisions:
|
||||||
@ -26,7 +35,7 @@ Revisions:
|
|||||||
02-03-2007 R. Belmont
|
02-03-2007 R. Belmont
|
||||||
- Cleaned up faux x86 assembly.
|
- 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
|
- rewrote channel update to make data 0 act as sample terminator
|
||||||
|
|
||||||
*********************************************************/
|
*********************************************************/
|
||||||
@ -36,8 +45,6 @@ Revisions:
|
|||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
#define MAX_VOL 256
|
|
||||||
|
|
||||||
|
|
||||||
// device type definition
|
// device type definition
|
||||||
DEFINE_DEVICE_TYPE(IREMGA20, iremga20_device, "iremga20", "Irem GA20")
|
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()
|
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);
|
m_stream = stream_alloc(0, 2, clock()/4);
|
||||||
|
|
||||||
save_item(NAME(m_regs));
|
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].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].pos), i);
|
||||||
save_item(NAME(m_channel[i].frac), i);
|
save_item(NAME(m_channel[i].frac), i);
|
||||||
save_item(NAME(m_channel[i].end), i);
|
save_item(NAME(m_channel[i].end), i);
|
||||||
save_item(NAME(m_channel[i].volume), 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);
|
save_item(NAME(m_channel[i].play), i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -97,7 +94,16 @@ void iremga20_device::device_start()
|
|||||||
|
|
||||||
void iremga20_device::device_reset()
|
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
|
if (sample == 0x00) // check for sample end marker
|
||||||
ch.play = 0;
|
ch.play = 0;
|
||||||
else
|
else
|
||||||
|
{
|
||||||
sampleout += (sample - 0x80) * (int32_t)ch.volume;
|
sampleout += (sample - 0x80) * (int32_t)ch.volume;
|
||||||
ch.frac += ch.rate;
|
ch.frac += ch.rate;
|
||||||
ch.pos += (ch.frac >> 24);
|
ch.pos += (ch.frac >> 24);
|
||||||
ch.frac &= ((1 << 24) - 1);
|
ch.frac &= ((1 << 24) - 1);
|
||||||
if (ch.pos >= ch.end) // for safety (the actual chip probably doesn't check this)
|
}
|
||||||
ch.play = 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -159,86 +165,64 @@ void iremga20_device::sound_stream_update(sound_stream &stream, stream_sample_t
|
|||||||
|
|
||||||
WRITE8_MEMBER( iremga20_device::irem_ga20_w )
|
WRITE8_MEMBER( iremga20_device::irem_ga20_w )
|
||||||
{
|
{
|
||||||
int channel;
|
|
||||||
|
|
||||||
//logerror("GA20: Offset %02x, data %04x\n",offset,data);
|
|
||||||
|
|
||||||
m_stream->update();
|
m_stream->update();
|
||||||
|
|
||||||
channel = offset >> 3;
|
offset &= 0x1f;
|
||||||
|
|
||||||
m_regs[offset] = data;
|
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)
|
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:
|
case 4:
|
||||||
m_channel[channel].rate = (1 << 24) / (256 - data);
|
m_channel[ch].rate = (1 << 24) / (256 - data);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 5: //AT: gain control
|
case 5:
|
||||||
m_channel[channel].volume = (data * MAX_VOL) / (data + 10);
|
m_channel[ch].volume = (data * 256) / (data + 10);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 6: //AT: this is always written 2(enabling both channels?)
|
case 6:
|
||||||
m_channel[channel].play = data;
|
// d1: key on/off
|
||||||
m_channel[channel].pos = m_channel[channel].start;
|
if (data & 2)
|
||||||
m_channel[channel].frac = 0;
|
{
|
||||||
|
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;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
READ8_MEMBER( iremga20_device::irem_ga20_r )
|
READ8_MEMBER( iremga20_device::irem_ga20_r )
|
||||||
{
|
{
|
||||||
int channel;
|
|
||||||
|
|
||||||
m_stream->update();
|
m_stream->update();
|
||||||
|
|
||||||
channel = offset >> 3;
|
offset &= 0x1f;
|
||||||
|
int ch = offset >> 3;
|
||||||
|
|
||||||
switch (offset & 0x7)
|
switch (offset & 0x7)
|
||||||
{
|
{
|
||||||
case 7: // voice status. bit 0 is 1 if active. (routine around 0xccc in rtypeleo)
|
case 7: // voice status. bit 0 is 1 if active. (routine around 0xccc in rtypeleo)
|
||||||
return m_channel[channel].play ? 1 : 0;
|
return m_channel[ch].play;
|
||||||
|
|
||||||
default:
|
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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
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
|
struct channel_def
|
||||||
{
|
{
|
||||||
uint32_t rate;
|
uint32_t rate;
|
||||||
uint32_t size;
|
|
||||||
uint32_t start;
|
|
||||||
uint32_t pos;
|
uint32_t pos;
|
||||||
uint32_t frac;
|
uint32_t frac;
|
||||||
uint32_t end;
|
uint32_t end;
|
||||||
uint32_t volume;
|
uint32_t volume;
|
||||||
uint32_t pan;
|
|
||||||
uint32_t effect;
|
|
||||||
uint32_t play;
|
uint32_t play;
|
||||||
};
|
};
|
||||||
|
|
||||||
void iremga20_reset();
|
|
||||||
|
|
||||||
sound_stream *m_stream;
|
sound_stream *m_stream;
|
||||||
uint8_t m_regs[0x40/2];
|
uint8_t m_regs[0x20];
|
||||||
channel_def m_channel[4];
|
channel_def m_channel[4];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user