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(); 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.. // old savestates..
cycles = pcd_cycles_m68k_to_s68k(SekCycleAim); cycles = pcd_cycles_m68k_to_s68k(SekCycleAim);
diff = cycles - SekCycleAimS68k; diff = cycles - SekCycleAimS68k;
@ -340,6 +344,8 @@ void pcd_state_loaded(void)
if (Pico_mcd->scd.Status_CDC & 0x08) if (Pico_mcd->scd.Status_CDC & 0x08)
Update_CDC_TRansfer(Pico_mcd->s68k_regs[4] & 7); 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 // vim:shiftwidth=2:ts=2:expandtab

View file

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

View file

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

View file

@ -1,137 +1,166 @@
/* /*
* Emulation routines for the RF5C164 PCM chip * Emulation routines for the RF5C164 PCM chip
* (C) notaz, 2007 * (C) notaz, 2007, 2013
* *
* This work is licensed under the terms of MAME license. * This work is licensed under the terms of MAME license.
* See COPYING file in the top-level directory. * See COPYING file in the top-level directory.
*/ */
#include <assert.h>
#include "../pico_int.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) if (a < 7)
{ {
Pico_mcd->pcm.ch[Pico_mcd->pcm.cur_ch].regs[a] = d; Pico_mcd->pcm.ch[Pico_mcd->pcm.cur_ch].regs[a] = d;
} }
else if (a == 7) // control register else if (a == 7) // control register
{ {
if (d & 0x40) Pico_mcd->pcm.cur_ch = d & 7; if (d & 0x40)
else Pico_mcd->pcm.bank = d & 0xf; Pico_mcd->pcm.cur_ch = d & 7;
Pico_mcd->pcm.control = d; else
// dprintf("pcm control=%02x", Pico_mcd->pcm.control); Pico_mcd->pcm.bank = d & 0xf;
} Pico_mcd->pcm.control = d;
else if (a == 8) // sound on/off elprintf(EL_CD, "pcm control %02x", Pico_mcd->pcm.control);
{ }
if (!(Pico_mcd->pcm.enabled & 0x01)) Pico_mcd->pcm.ch[0].addr = else if (a == 8 && Pico_mcd->pcm.enabled != (u_char)~d)
Pico_mcd->pcm.ch[0].regs[6] << (PCM_STEP_SHIFT + 8); {
if (!(Pico_mcd->pcm.enabled & 0x02)) Pico_mcd->pcm.ch[1].addr = // sound on/off
Pico_mcd->pcm.ch[1].regs[6] << (PCM_STEP_SHIFT + 8); int was_enabled = Pico_mcd->pcm.enabled;
if (!(Pico_mcd->pcm.enabled & 0x04)) Pico_mcd->pcm.ch[2].addr = int i;
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);
Pico_mcd->pcm.enabled = ~d; for (i = 0; i < 8; i++)
//printf("enabled=%02x\n", Pico_mcd->pcm.enabled); 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;
}
} }
unsigned int pcd_pcm_read(unsigned int a)
PICO_INTERNAL void pcm_set_rate(int rate)
{ {
float step = 31.8 * 1024.0 / (float) rate; // max <4 @ 8000Hz unsigned int d, cycles = SekCyclesDoneS68k();
step *= 256*256/4; if ((int)(cycles - Pico_mcd->pcm.update_cycles) >= 384)
g_rate = (unsigned int) step; pcd_pcm_sync(cycles);
if (step - (float) g_rate >= 0.5) g_rate++;
elprintf(EL_STATUS, "g_rate: %f %08x\n", (double)step, g_rate); d = Pico_mcd->pcm.ch[(a >> 1) & 7].addr >> PCM_STEP_SHIFT;
if (a & 1)
d >>= 8;
return d & 0xff;
} }
void pcd_pcm_sync(unsigned int to)
PICO_INTERNAL void pcm_update(int *buffer, int length, int stereo)
{ {
struct pcm_chan *ch; unsigned int cycles = Pico_mcd->pcm.update_cycles;
unsigned int step, addr; int mul_l, mul_r, inc, smp;
int mul_l, mul_r, smp; struct pcm_chan *ch;
int i, j, k; unsigned int addr;
int *out; int c, s, steps;
int *out;
if ((int)(to - cycles) < 384)
return;
// PCM disabled or all channels off (to be checked by caller) steps = (to - cycles) / 384;
//if (!(Pico_mcd->pcm.control & 0x80) || !Pico_mcd->pcm.enabled) return;
//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++) out = Pico_mcd->pcm_mixbuf + Pico_mcd->pcm_mixpos * 2;
{ Pico_mcd->pcm_mixbuf_dirty = 1;
if (!(Pico_mcd->pcm.enabled & (1 << i))) continue; // channel disabled if (Pico_mcd->pcm_mixpos + steps > PCM_MIXBUF_LEN)
// shouldn't happen
steps = PCM_MIXBUF_LEN - Pico_mcd->pcm_mixpos;
out = buffer; for (c = 0; c < 8; c++)
ch = &Pico_mcd->pcm.ch[i]; {
if (!(Pico_mcd->pcm.enabled & (1 << c)))
continue; // channel disabled
addr = ch->addr; // >> PCM_STEP_SHIFT; ch = &Pico_mcd->pcm.ch[c];
mul_l = ((int)ch->regs[0] * (ch->regs[1] & 0xf)) >> (5+1); // (env * pan) >> 5 addr = ch->addr;
mul_r = ((int)ch->regs[0] * (ch->regs[1] >> 4)) >> (5+1); inc = *(unsigned short *)&ch->regs[2];
step = ((unsigned int)(*(unsigned short *)&ch->regs[2]) * g_rate) >> 14; // freq step mul_l = ((int)ch->regs[0] * (ch->regs[1] & 0xf)) >> (5+1);
// fprintf(stderr, "step=%i, cstep=%i, mul_l=%i, mul_r=%i, ch=%i, addr=%x, en=%02x\n", mul_r = ((int)ch->regs[0] * (ch->regs[1] >> 4)) >> (5+1);
// *(unsigned short *)&ch->regs[2], step, mul_l, mul_r, i, addr, Pico_mcd->pcm.enabled);
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++) // test for loop signal
{ if (smp == 0xff)
// printf("addr=%08x\n", addr); {
smp = Pico_mcd->pcm_ram[addr >> PCM_STEP_SHIFT]; 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 & 0x80)
if (smp == 0xff) smp = -(smp & 0x7f);
{
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); 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 end:
if(stereo) Pico_mcd->pcm.update_cycles = cycles + steps * 384;
*out++ += smp * mul_r; Pico_mcd->pcm_mixpos += steps;
// 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;
}
} }
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/LC89510.h"
#include "cd/gfx_cd.h" #include "cd/gfx_cd.h"
#define PCM_MIXBUF_LEN ((12500000 / 384) / 50 + 1)
struct mcd_pcm struct mcd_pcm
{ {
unsigned char control; // reg7 unsigned char control; // reg7
unsigned char enabled; // reg8 unsigned char enabled; // reg8
unsigned char cur_ch; unsigned char cur_ch;
unsigned char bank; unsigned char bank;
int pad1; unsigned int update_cycles;
struct pcm_chan // 08, size 0x10 struct pcm_chan // 08, size 0x10
{ {
@ -445,6 +447,9 @@ typedef struct
CDC cdc; CDC cdc;
_scd scd; _scd scd;
Rot_Comp rot_comp; Rot_Comp rot_comp;
int pcm_mixbuf[PCM_MIXBUF_LEN * 2];
int pcm_mixpos;
int pcm_mixbuf_dirty;
} mcd_state; } mcd_state;
// XXX: this will need to be reworked for cart+cd support. // 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_soft_reset(void);
void pcd_state_loaded(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/pico.c
PICO_INTERNAL void PicoInitPico(void); PICO_INTERNAL void PicoInitPico(void);
PICO_INTERNAL void PicoReratePico(void); PICO_INTERNAL void PicoReratePico(void);

View file

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