From: notaz Date: Thu, 19 Sep 2013 00:51:30 +0000 (+0300) Subject: cd: rewrite pcm X-Git-Tag: v1.90~11 X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=33be04ca5fee314271f1959672e22cf94d670ea6;p=picodrive.git cd: rewrite pcm --- diff --git a/pico/cd/mcd.c b/pico/cd/mcd.c index b57fa162..8a84eb12 100644 --- a/pico/cd/mcd.c +++ b/pico/cd/mcd.c @@ -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 diff --git a/pico/cd/memory.c b/pico/cd/memory.c index af455f2f..8fce606f 100644 --- a/pico/cd/memory.c +++ b/pico/cd/memory.c @@ -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; } diff --git a/pico/cd/memory_arm.s b/pico/cd/memory_arm.s index 3e6f9db6..db5b8a23 100644 --- a/pico/cd/memory_arm.s +++ b/pico/cd/memory_arm.s @@ -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 diff --git a/pico/cd/pcm.c b/pico/cd/pcm.c index d9774aa2..a1276f9c 100644 --- a/pico/cd/pcm.c +++ b/pico/cd/pcm.c @@ -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 #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); - - 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); - - Pico_mcd->pcm.enabled = ~d; -//printf("enabled=%02x\n", Pico_mcd->pcm.enabled); - } + 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; + 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; + + 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; } +void pcd_pcm_sync(unsigned int to) +{ + 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; + + steps = (to - cycles) / 384; + + // PCM disabled or all channels off + if (!(Pico_mcd->pcm.control & 0x80) || !Pico_mcd->pcm.enabled) + goto end; + + 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; + + for (c = 0; c < 8; c++) + { + if (!(Pico_mcd->pcm.enabled & (1 << c))) + continue; // channel disabled + + 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); + + for (s = 0; s < steps; s++, addr = (addr + inc) & 0x7FFFFFF) + { + 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; + } + + 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; + } + +end: + Pico_mcd->pcm.update_cycles = cycles + steps * 384; + Pico_mcd->pcm_mixpos += steps; +} -PICO_INTERNAL void pcm_update(int *buffer, int length, int stereo) +void pcd_pcm_update(int *buf32, int length, int stereo) { - struct pcm_chan *ch; - unsigned int step, addr; - int mul_l, mul_r, smp; - int i, j, k; - int *out; - - - // PCM disabled or all channels off (to be checked by caller) - //if (!(Pico_mcd->pcm.control & 0x80) || !Pico_mcd->pcm.enabled) return; - -//printf("-- upd %i\n", length); - - for (i = 0; i < 8; i++) - { - if (!(Pico_mcd->pcm.enabled & (1 << i))) continue; // channel disabled - - out = buffer; - ch = &Pico_mcd->pcm.ch[i]; - - 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); - - if (!stereo && mul_l < mul_r) mul_l = mul_r; - - 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; - } - - if (smp & 0x80) smp = -(smp & 0x7f); - - *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; - } + 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 diff --git a/pico/cd/pcm.h b/pico/cd/pcm.h deleted file mode 100644 index 47e555cd..00000000 --- a/pico/cd/pcm.h +++ /dev/null @@ -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); - diff --git a/pico/pico_int.h b/pico/pico_int.h index 08c7a20c..ccc1a9bf 100644 --- a/pico/pico_int.h +++ b/pico/pico_int.h @@ -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); diff --git a/pico/sound/sound.c b/pico/sound/sound.c index 236a4834..ec0e2059 100644 --- a/pico/sound/sound.c +++ b/pico/sound/sound.c @@ -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; }