fixed PCM channels loop data & start address emulation

This commit is contained in:
EkeEke 2012-07-15 17:18:46 +02:00
parent ae1416aad4
commit e53d6e8aa4

View File

@ -93,8 +93,8 @@ void pcm_update(short *buffer, int length)
/* run eight PCM channels */ /* run eight PCM channels */
for (j=0; j<8; j++) for (j=0; j<8; j++)
{ {
/* check if channel is enabled (bit cleared) */ /* check if channel is enabled */
if (!(pcm.status & (1 << j))) if (pcm.status & (1 << j))
{ {
/* read current WAVE RAM address */ /* read current WAVE RAM address */
short data = pcm.ram[(pcm.chan[j].addr >> 11) & 0xffff]; short data = pcm.ram[(pcm.chan[j].addr >> 11) & 0xffff];
@ -107,24 +107,25 @@ void pcm_update(short *buffer, int length)
/* read WAVE RAM address again */ /* read WAVE RAM address again */
data = pcm.ram[pcm.chan[j].ls.w]; data = pcm.ram[pcm.chan[j].ls.w];
/* no output on infinite loop */
if (data == 0xff) break;
} }
/* output L & R subchannels */ /* infinite loop should not output any data */
if (data & 0x80) if (data != 0xff)
{ {
/* PCM data is negative */ /* output L & R subchannels */
data = -(data & 0x7f); if (data & 0x80)
{
/* PCM data is negative */
data = -(data & 0x7f);
}
/* multiply PCM data with ENV & stereo PAN data then add to outputs (13.6 fixed point) */
l += ((data * pcm.chan[j].env * (pcm.chan[j].pan & 0x0F)) >> 6);
r += ((data * pcm.chan[j].env * (pcm.chan[j].pan >> 4)) >> 6);
/* increment WAVE RAM address */
pcm.chan[j].addr += pcm.chan[j].fd.w;
} }
/* multiply PCM data with ENV & stereo PAN data then add to outputs (13.6 fixed point) */
l += ((data * pcm.chan[j].env * (pcm.chan[j].pan & 0x0F)) >> 6);
r += ((data * pcm.chan[j].env * (pcm.chan[j].pan >> 4)) >> 6);
/* increment WAVE RAM address */
pcm.chan[j].addr += pcm.chan[j].fd.w;
} }
} }
@ -175,6 +176,10 @@ void pcm_update(short *buffer, int length)
void pcm_write(unsigned int address, unsigned char data) void pcm_write(unsigned int address, unsigned char data)
{ {
#ifdef LOG_PCM
error("[%d][%d]PCM %x write -> 0x%02x (%X)\n", v_counter, s68k.cycles, address, data, s68k.pc);
#endif
/* external RAM is mapped to $1000-$1FFF */ /* external RAM is mapped to $1000-$1FFF */
if (address >= 0x1000) if (address >= 0x1000)
{ {
@ -232,6 +237,12 @@ void pcm_write(unsigned int address, unsigned char data)
{ {
/* update channel WAVE RAM start address (16.11 fixed point) */ /* update channel WAVE RAM start address (16.11 fixed point) */
pcm.chan[pcm.index].st = data << (8 + 11); pcm.chan[pcm.index].st = data << (8 + 11);
/* reload WAVE RAM address if channel is OFF */
if (~(pcm.status & (1 << pcm.index)))
{
pcm.chan[pcm.index].addr = pcm.chan[pcm.index].st;
}
return; return;
} }
@ -255,18 +266,18 @@ void pcm_write(unsigned int address, unsigned char data)
case 0x08: /* ON/OFF register */ case 0x08: /* ON/OFF register */
{ {
/* reload WAVE RAM address pointers when channels are switched ON (bit cleared) */
if ((pcm.status & 0x01) && !(data & 0x01)) pcm.chan[0].addr = pcm.chan[0].st;
if ((pcm.status & 0x02) && !(data & 0x02)) pcm.chan[1].addr = pcm.chan[1].st;
if ((pcm.status & 0x04) && !(data & 0x04)) pcm.chan[2].addr = pcm.chan[2].st;
if ((pcm.status & 0x08) && !(data & 0x08)) pcm.chan[3].addr = pcm.chan[3].st;
if ((pcm.status & 0x10) && !(data & 0x10)) pcm.chan[4].addr = pcm.chan[4].st;
if ((pcm.status & 0x20) && !(data & 0x20)) pcm.chan[5].addr = pcm.chan[5].st;
if ((pcm.status & 0x40) && !(data & 0x40)) pcm.chan[6].addr = pcm.chan[6].st;
if ((pcm.status & 0x80) && !(data & 0x80)) pcm.chan[7].addr = pcm.chan[7].st;
/* update PCM channels status */ /* update PCM channels status */
pcm.status = data; pcm.status = ~data;
/* reload WAVE RAM address pointers when channels are OFF */
if (data & 0x01) pcm.chan[0].addr = pcm.chan[0].st;
if (data & 0x02) pcm.chan[1].addr = pcm.chan[1].st;
if (data & 0x04) pcm.chan[2].addr = pcm.chan[2].st;
if (data & 0x08) pcm.chan[3].addr = pcm.chan[3].st;
if (data & 0x10) pcm.chan[4].addr = pcm.chan[4].st;
if (data & 0x20) pcm.chan[5].addr = pcm.chan[5].st;
if (data & 0x40) pcm.chan[6].addr = pcm.chan[6].st;
if (data & 0x80) pcm.chan[7].addr = pcm.chan[7].st;
return; return;
} }
@ -280,6 +291,10 @@ void pcm_write(unsigned int address, unsigned char data)
unsigned char pcm_read(unsigned int address) unsigned char pcm_read(unsigned int address)
{ {
#ifdef LOG_PCM
error("[%d][%d]PCM %x read (%X)\n", v_counter, s68k.cycles, address, s68k.pc);
#endif
/* external RAM (TODO: verify if possible to read, some docs claim it's not !) */ /* external RAM (TODO: verify if possible to read, some docs claim it's not !) */
if (address >= 0x1000) if (address >= 0x1000)
{ {
@ -294,7 +309,7 @@ unsigned char pcm_read(unsigned int address)
if (address & 1) if (address & 1)
{ {
return pcm.chan[index].addr >> (11 + 8); return (pcm.chan[index].addr >> (11 + 8)) & 0xff;
} }
else else
{ {