cd: rewrite pcm

This commit is contained in:
notaz 2013-09-19 03:51:30 +03:00
parent d0132772f7
commit 33be04ca5f
7 changed files with 171 additions and 160 deletions

View file

@ -318,6 +318,10 @@ void pcd_state_loaded(void)
pcd_state_loaded_mem();
memset(Pico_mcd->pcm_mixbuf, 0, sizeof(Pico_mcd->pcm_mixbuf));
Pico_mcd->pcm_mixbuf_dirty = 0;
Pico_mcd->pcm_mixpos = 0;
// old savestates..
cycles = pcd_cycles_m68k_to_s68k(SekCycleAim);
diff = cycles - SekCycleAimS68k;
@ -340,6 +344,8 @@ void pcd_state_loaded(void)
if (Pico_mcd->scd.Status_CDC & 0x08)
Update_CDC_TRansfer(Pico_mcd->s68k_regs[4] & 7);
}
if (Pico_mcd->pcm.update_cycles == 0)
Pico_mcd->pcm.update_cycles = cycles;
}
// vim:shiftwidth=2:ts=2:expandtab

View file

@ -10,7 +10,6 @@
#include "../memory.h"
#include "gfx_cd.h"
#include "pcm.h"
uptr s68k_read8_map [0x1000000 >> M68K_MEM_SHIFT];
uptr s68k_read16_map [0x1000000 >> M68K_MEM_SHIFT];
@ -834,13 +833,10 @@ regs_done:
a &= 0x7fff;
if (a >= 0x2000)
d = Pico_mcd->pcm_ram_b[Pico_mcd->pcm.bank][(a >> 1) & 0xfff];
else if (a >= 0x20) {
a &= 0x1e;
d = Pico_mcd->pcm.ch[a>>2].addr >> PCM_STEP_SHIFT;
if (a & 2)
d >>= 8;
}
return d & 0xff;
else if (a >= 0x20)
d = pcd_pcm_read(a >> 1);
return d;
}
return s68k_unmapped_read8(a);
@ -864,16 +860,12 @@ static u32 PicoReadS68k16_pr(u32 a)
// PCM
if ((a & 0x8000) == 0x0000) {
//elprintf(EL_ANOMALY, "FIXME: s68k_pcm r16: [%06x] @%06x", a, SekPcS68k);
a &= 0x7fff;
if (a >= 0x2000)
d = Pico_mcd->pcm_ram_b[Pico_mcd->pcm.bank][(a>>1)&0xfff];
else if (a >= 0x20) {
a &= 0x1e;
d = Pico_mcd->pcm.ch[a>>2].addr >> PCM_STEP_SHIFT;
if (a & 2) d >>= 8;
}
elprintf(EL_CDREGS, "ret = %04x", d);
d = Pico_mcd->pcm_ram_b[Pico_mcd->pcm.bank][(a >> 1) & 0xfff];
else if (a >= 0x20)
d = pcd_pcm_read(a >> 1);
return d;
}
@ -898,7 +890,7 @@ static void PicoWriteS68k8_pr(u32 a, u32 d)
if (a >= 0x2000)
Pico_mcd->pcm_ram_b[Pico_mcd->pcm.bank][(a>>1)&0xfff] = d;
else if (a < 0x12)
pcm_write(a>>1, d);
pcd_pcm_write(a>>1, d);
return;
}
@ -932,7 +924,7 @@ static void PicoWriteS68k16_pr(u32 a, u32 d)
if (a >= 0x2000)
Pico_mcd->pcm_ram_b[Pico_mcd->pcm.bank][(a>>1)&0xfff] = d;
else if (a < 0x12)
pcm_write(a>>1, d & 0xff);
pcd_pcm_write(a>>1, d & 0xff);
return;
}

View file

@ -56,6 +56,8 @@
.extern s68k_poll_detect
.extern gfx_cd_read
.extern gfx_cd_write16
.extern pcd_pcm_write
.extern pcd_pcm_read
.extern PicoCpuCS68k
.extern PicoRead8_io
.extern PicoRead16_io
@ -447,23 +449,15 @@ m_s68k_read8_pcm:
@ must not trash r3 and r12
ldr r1, =(Pico+0x22200)
bic r0, r0, #0xff0000
@ bic r0, r0, #0x008000
ldr r1, [r1]
mov r2, #0x110000
orr r2, r2, #0x002200
cmp r0, #0x2000
bge m_s68k_read8_pcm_ram
cmp r0, #0x20
movlt r0, #0
bxlt lr
orr r2, r2, #(0x48+8) @ pcm.ch + addr_offset
add r1, r1, r2
and r2, r0, #0x1c
ldr r1, [r1, r2, lsl #2]
tst r0, #2
moveq r0, r1, lsr #PCM_STEP_SHIFT
movne r0, r1, lsr #(PCM_STEP_SHIFT+8)
and r0, r0, #0xff
movge r0, r0, lsr #1
bge pcd_pcm_read
mov r0, #0
bx lr
m_s68k_read8_pcm_ram:
@ -600,7 +594,7 @@ m_s68k_write8_pcm:
bic r0, r0, #0xff0000
cmp r0, #0x12
movlt r0, r0, lsr #1
blt pcm_write
blt pcd_pcm_write
cmp r0, #0x2000
bxlt lr

View file

@ -1,137 +1,166 @@
/*
* Emulation routines for the RF5C164 PCM chip
* (C) notaz, 2007
* (C) notaz, 2007, 2013
*
* This work is licensed under the terms of MAME license.
* See COPYING file in the top-level directory.
*/
#include <assert.h>
#include "../pico_int.h"
#include "pcm.h"
static unsigned int g_rate = 0; // 18.14 fixed point
#define PCM_STEP_SHIFT 11
PICO_INTERNAL_ASM void pcm_write(unsigned int a, unsigned int d)
void pcd_pcm_write(unsigned int a, unsigned int d)
{
//printf("pcm_write(%i, %02x)\n", a, d);
unsigned int cycles = SekCyclesDoneS68k();
if ((int)(cycles - Pico_mcd->pcm.update_cycles) >= 384)
pcd_pcm_sync(cycles);
if (a < 7)
{
Pico_mcd->pcm.ch[Pico_mcd->pcm.cur_ch].regs[a] = d;
}
else if (a == 7) // control register
{
if (d & 0x40) Pico_mcd->pcm.cur_ch = d & 7;
else Pico_mcd->pcm.bank = d & 0xf;
Pico_mcd->pcm.control = d;
// dprintf("pcm control=%02x", Pico_mcd->pcm.control);
}
else if (a == 8) // sound on/off
{
if (!(Pico_mcd->pcm.enabled & 0x01)) Pico_mcd->pcm.ch[0].addr =
Pico_mcd->pcm.ch[0].regs[6] << (PCM_STEP_SHIFT + 8);
if (!(Pico_mcd->pcm.enabled & 0x02)) Pico_mcd->pcm.ch[1].addr =
Pico_mcd->pcm.ch[1].regs[6] << (PCM_STEP_SHIFT + 8);
if (!(Pico_mcd->pcm.enabled & 0x04)) Pico_mcd->pcm.ch[2].addr =
Pico_mcd->pcm.ch[2].regs[6] << (PCM_STEP_SHIFT + 8);
if (!(Pico_mcd->pcm.enabled & 0x08)) Pico_mcd->pcm.ch[3].addr =
Pico_mcd->pcm.ch[3].regs[6] << (PCM_STEP_SHIFT + 8);
if (!(Pico_mcd->pcm.enabled & 0x10)) Pico_mcd->pcm.ch[4].addr =
Pico_mcd->pcm.ch[4].regs[6] << (PCM_STEP_SHIFT + 8);
if (!(Pico_mcd->pcm.enabled & 0x20)) Pico_mcd->pcm.ch[5].addr =
Pico_mcd->pcm.ch[5].regs[6] << (PCM_STEP_SHIFT + 8);
if (!(Pico_mcd->pcm.enabled & 0x40)) Pico_mcd->pcm.ch[6].addr =
Pico_mcd->pcm.ch[6].regs[6] << (PCM_STEP_SHIFT + 8);
if (!(Pico_mcd->pcm.enabled & 0x80)) Pico_mcd->pcm.ch[7].addr =
Pico_mcd->pcm.ch[7].regs[6] << (PCM_STEP_SHIFT + 8);
// printf("addr %x %x %x %x %x %x %x %x\n", Pico_mcd->pcm.ch[0].addr, Pico_mcd->pcm.ch[1].addr
// , Pico_mcd->pcm.ch[2].addr, Pico_mcd->pcm.ch[3].addr, Pico_mcd->pcm.ch[4].addr, Pico_mcd->pcm.ch[5].addr
// , Pico_mcd->pcm.ch[6].addr, Pico_mcd->pcm.ch[7].addr);
if (a < 7)
{
Pico_mcd->pcm.ch[Pico_mcd->pcm.cur_ch].regs[a] = d;
}
else if (a == 7) // control register
{
if (d & 0x40)
Pico_mcd->pcm.cur_ch = d & 7;
else
Pico_mcd->pcm.bank = d & 0xf;
Pico_mcd->pcm.control = d;
elprintf(EL_CD, "pcm control %02x", Pico_mcd->pcm.control);
}
else if (a == 8 && Pico_mcd->pcm.enabled != (u_char)~d)
{
// sound on/off
int was_enabled = Pico_mcd->pcm.enabled;
int i;
Pico_mcd->pcm.enabled = ~d;
//printf("enabled=%02x\n", Pico_mcd->pcm.enabled);
}
for (i = 0; i < 8; i++)
if (!(was_enabled & (1 << i)))
Pico_mcd->pcm.ch[i].addr =
Pico_mcd->pcm.ch[i].regs[6] << (PCM_STEP_SHIFT + 8);
Pico_mcd->pcm.enabled = ~d;
}
}
PICO_INTERNAL void pcm_set_rate(int rate)
unsigned int pcd_pcm_read(unsigned int a)
{
float step = 31.8 * 1024.0 / (float) rate; // max <4 @ 8000Hz
step *= 256*256/4;
g_rate = (unsigned int) step;
if (step - (float) g_rate >= 0.5) g_rate++;
elprintf(EL_STATUS, "g_rate: %f %08x\n", (double)step, g_rate);
unsigned int d, cycles = SekCyclesDoneS68k();
if ((int)(cycles - Pico_mcd->pcm.update_cycles) >= 384)
pcd_pcm_sync(cycles);
d = Pico_mcd->pcm.ch[(a >> 1) & 7].addr >> PCM_STEP_SHIFT;
if (a & 1)
d >>= 8;
return d & 0xff;
}
PICO_INTERNAL void pcm_update(int *buffer, int length, int stereo)
void pcd_pcm_sync(unsigned int to)
{
struct pcm_chan *ch;
unsigned int step, addr;
int mul_l, mul_r, smp;
int i, j, k;
int *out;
unsigned int cycles = Pico_mcd->pcm.update_cycles;
int mul_l, mul_r, inc, smp;
struct pcm_chan *ch;
unsigned int addr;
int c, s, steps;
int *out;
if ((int)(to - cycles) < 384)
return;
// PCM disabled or all channels off (to be checked by caller)
//if (!(Pico_mcd->pcm.control & 0x80) || !Pico_mcd->pcm.enabled) return;
steps = (to - cycles) / 384;
//printf("-- upd %i\n", length);
// PCM disabled or all channels off
if (!(Pico_mcd->pcm.control & 0x80) || !Pico_mcd->pcm.enabled)
goto end;
for (i = 0; i < 8; i++)
{
if (!(Pico_mcd->pcm.enabled & (1 << i))) continue; // channel disabled
out = Pico_mcd->pcm_mixbuf + Pico_mcd->pcm_mixpos * 2;
Pico_mcd->pcm_mixbuf_dirty = 1;
if (Pico_mcd->pcm_mixpos + steps > PCM_MIXBUF_LEN)
// shouldn't happen
steps = PCM_MIXBUF_LEN - Pico_mcd->pcm_mixpos;
out = buffer;
ch = &Pico_mcd->pcm.ch[i];
for (c = 0; c < 8; c++)
{
if (!(Pico_mcd->pcm.enabled & (1 << c)))
continue; // channel disabled
addr = ch->addr; // >> PCM_STEP_SHIFT;
mul_l = ((int)ch->regs[0] * (ch->regs[1] & 0xf)) >> (5+1); // (env * pan) >> 5
mul_r = ((int)ch->regs[0] * (ch->regs[1] >> 4)) >> (5+1);
step = ((unsigned int)(*(unsigned short *)&ch->regs[2]) * g_rate) >> 14; // freq step
// fprintf(stderr, "step=%i, cstep=%i, mul_l=%i, mul_r=%i, ch=%i, addr=%x, en=%02x\n",
// *(unsigned short *)&ch->regs[2], step, mul_l, mul_r, i, addr, Pico_mcd->pcm.enabled);
ch = &Pico_mcd->pcm.ch[c];
addr = ch->addr;
inc = *(unsigned short *)&ch->regs[2];
mul_l = ((int)ch->regs[0] * (ch->regs[1] & 0xf)) >> (5+1);
mul_r = ((int)ch->regs[0] * (ch->regs[1] >> 4)) >> (5+1);
if (!stereo && mul_l < mul_r) mul_l = mul_r;
for (s = 0; s < steps; s++, addr = (addr + inc) & 0x7FFFFFF)
{
smp = Pico_mcd->pcm_ram[addr >> PCM_STEP_SHIFT];
for (j = 0; j < length; j++)
{
// printf("addr=%08x\n", addr);
smp = Pico_mcd->pcm_ram[addr >> PCM_STEP_SHIFT];
// test for loop signal
if (smp == 0xff)
{
addr = *(unsigned short *)&ch->regs[4]; // loop_addr
smp = Pico_mcd->pcm_ram[addr];
addr <<= PCM_STEP_SHIFT;
if (smp == 0xff)
break;
}
// test for loop signal
if (smp == 0xff)
{
addr = *(unsigned short *)&ch->regs[4]; // loop_addr
smp = Pico_mcd->pcm_ram[addr];
addr <<= PCM_STEP_SHIFT;
if (smp == 0xff) break;
}
if (smp & 0x80)
smp = -(smp & 0x7f);
if (smp & 0x80) smp = -(smp & 0x7f);
out[s*2 ] += smp * mul_l; // max 128 * 119 = 15232
out[s*2+1] += smp * mul_r;
}
ch->addr = addr;
}
*out++ += smp * mul_l; // max 128 * 119 = 15232
if(stereo)
*out++ += smp * mul_r;
// update address register
k = (addr >> PCM_STEP_SHIFT) + 1;
addr = (addr + step) & 0x7FFFFFF;
for(; k < (addr >> PCM_STEP_SHIFT); k++)
{
if (Pico_mcd->pcm_ram[k] == 0xff)
{
addr = (unsigned int)(*(unsigned short *)&ch->regs[4]) << PCM_STEP_SHIFT; // loop_addr
break;
}
}
}
if (Pico_mcd->pcm_ram[addr >> PCM_STEP_SHIFT] == 0xff)
addr = (unsigned int)(*(unsigned short *)&ch->regs[4]) << PCM_STEP_SHIFT; // loop_addr
ch->addr = addr;
}
end:
Pico_mcd->pcm.update_cycles = cycles + steps * 384;
Pico_mcd->pcm_mixpos += steps;
}
void pcd_pcm_update(int *buf32, int length, int stereo)
{
int step, *pcm;
int p = 0;
pcd_pcm_sync(SekCyclesDoneS68k());
if (!Pico_mcd->pcm_mixbuf_dirty || !(PicoOpt & POPT_EN_MCD_PCM))
goto out;
step = (Pico_mcd->pcm_mixpos << 16) / length;
pcm = Pico_mcd->pcm_mixbuf;
if (stereo) {
while (length-- > 0) {
*buf32++ += pcm[0];
*buf32++ += pcm[1];
p += step;
pcm += (p >> 16) * 2;
p &= 0xffff;
}
}
else {
while (length-- > 0) {
// mostly unused
*buf32++ += pcm[0];
p += step;
pcm += (p >> 16) * 2;
p &= 0xffff;
}
}
memset(Pico_mcd->pcm_mixbuf, 0,
Pico_mcd->pcm_mixpos * 2 * sizeof(Pico_mcd->pcm_mixbuf[0]));
out:
Pico_mcd->pcm_mixbuf_dirty = 0;
Pico_mcd->pcm_mixpos = 0;
}
// vim:shiftwidth=2:ts=2:expandtab

View file

@ -1,7 +0,0 @@
#define PCM_STEP_SHIFT 11
PICO_INTERNAL_ASM void pcm_write(unsigned int a, unsigned int d);
PICO_INTERNAL void pcm_set_rate(int rate);
PICO_INTERNAL void pcm_update(int *buffer, int length, int stereo);

View file

@ -378,13 +378,15 @@ struct PicoSRAM
#include "cd/LC89510.h"
#include "cd/gfx_cd.h"
#define PCM_MIXBUF_LEN ((12500000 / 384) / 50 + 1)
struct mcd_pcm
{
unsigned char control; // reg7
unsigned char enabled; // reg8
unsigned char cur_ch;
unsigned char bank;
int pad1;
unsigned int update_cycles;
struct pcm_chan // 08, size 0x10
{
@ -445,6 +447,9 @@ typedef struct
CDC cdc;
_scd scd;
Rot_Comp rot_comp;
int pcm_mixbuf[PCM_MIXBUF_LEN * 2];
int pcm_mixpos;
int pcm_mixbuf_dirty;
} mcd_state;
// XXX: this will need to be reworked for cart+cd support.
@ -656,6 +661,12 @@ void pcd_run_cpus(int m68k_cycles);
void pcd_soft_reset(void);
void pcd_state_loaded(void);
// cd/pcm.c
void pcd_pcm_sync(unsigned int to);
void pcd_pcm_update(int *buffer, int length, int stereo);
void pcd_pcm_write(unsigned int a, unsigned int d);
unsigned int pcd_pcm_read(unsigned int a);
// pico/pico.c
PICO_INTERNAL void PicoInitPico(void);
PICO_INTERNAL void PicoReratePico(void);

View file

@ -11,7 +11,6 @@
#include "ym2612.h"
#include "sn76496.h"
#include "../pico_int.h"
#include "../cd/pcm.h"
#include "../cd/cue.h"
#include "mix.h"
@ -161,9 +160,6 @@ void PsndRerate(int preserve_state)
// recalculate dac info
dac_recalculate();
if (PicoAHW & PAHW_MCD)
pcm_set_rate(PsndRate);
// clear all buffers
memset32(PsndBuffer, 0, sizeof(PsndBuffer)/4);
memset(cdda_out_buffer, 0, sizeof(cdda_out_buffer));
@ -201,14 +197,6 @@ PICO_INTERNAL void PsndDoDAC(int line_to)
short *d = PsndOut + pos;
for (; len > 0; len--, d++) *d = dout;
}
#if 0
if (do_pcm) {
int *d = PsndBuffer;
d += (PicoOpt&8) ? pos*2 : pos;
pcm_update(d, len, 1);
}
#endif
}
// cdda
@ -309,9 +297,7 @@ static int PsndRender(int offset, int length)
int buf32_updated = 0;
int *buf32 = PsndBuffer+offset;
int stereo = (PicoOpt & 8) >> 3;
// emulating CD && PCM option enabled && PCM chip on && have enabled channels
int do_pcm = (PicoAHW & PAHW_MCD) && (PicoOpt&POPT_EN_MCD_PCM) &&
(Pico_mcd->pcm.control & 0x80) && Pico_mcd->pcm.enabled;
offset <<= stereo;
pprof_start(sound);
@ -346,8 +332,8 @@ static int PsndRender(int offset, int length)
(void)buf32_updated;
// CD: PCM sound
if (do_pcm) {
pcm_update(buf32, length, stereo);
if (PicoAHW & PAHW_MCD) {
pcd_pcm_update(buf32, length, stereo);
//buf32_updated = 1;
}