2 * Emulation routines for the RF5C164 PCM chip
3 * (C) notaz, 2007, 2013
5 * This work is licensed under the terms of MAME license.
6 * See COPYING file in the top-level directory.
9 #include "../pico_int.h"
11 #define PCM_STEP_SHIFT 11
13 void pcd_pcm_write(unsigned int a, unsigned int d)
15 unsigned int cycles = SekCyclesDoneS68k();
16 if ((int)(cycles - Pico_mcd->pcm.update_cycles) >= 384)
21 Pico_mcd->pcm.ch[Pico_mcd->pcm.cur_ch].regs[a] = d;
23 else if (a == 7) // control register
26 Pico_mcd->pcm.cur_ch = d & 7;
28 Pico_mcd->pcm.bank = d & 0xf;
29 Pico_mcd->pcm.control = d;
30 elprintf(EL_CD, "pcm control %02x", Pico_mcd->pcm.control);
34 Pico_mcd->pcm.enabled = ~d;
36 Pico_mcd->pcm_regs_dirty = 1;
39 unsigned int pcd_pcm_read(unsigned int a)
41 unsigned int d, cycles = SekCyclesDoneS68k();
42 if ((int)(cycles - Pico_mcd->pcm.update_cycles) >= 384)
45 d = Pico_mcd->pcm.ch[(a >> 1) & 7].addr >> PCM_STEP_SHIFT;
52 void pcd_pcm_sync(unsigned int to)
54 unsigned int cycles = Pico_mcd->pcm.update_cycles;
55 int mul_l, mul_r, inc, smp;
62 if ((int)(to - cycles) < 384)
65 steps = (to - cycles) * ((1LL << 32) / 384) >> 32;
66 if (Pico_mcd->pcm_mixpos + steps > PCM_MIXBUF_LEN)
67 // shouldn't happen, but occasionally does
68 steps = PCM_MIXBUF_LEN - Pico_mcd->pcm_mixpos;
70 // PCM disabled or all channels off
71 enabled = Pico_mcd->pcm.enabled;
72 if (!(Pico_mcd->pcm.control & 0x80))
74 if (!enabled && !Pico_mcd->pcm_regs_dirty)
77 out = Pico_mcd->pcm_mixbuf + Pico_mcd->pcm_mixpos * 2;
78 Pico_mcd->pcm_mixbuf_dirty = 1;
79 Pico_mcd->pcm_regs_dirty = 0;
81 for (c = 0; c < 8; c++)
83 ch = &Pico_mcd->pcm.ch[c];
85 if (!(enabled & (1 << c))) {
86 ch->addr = ch->regs[6] << (PCM_STEP_SHIFT + 8);
87 continue; // channel disabled
91 inc = ch->regs[2] + (ch->regs[3]<<8);
92 mul_l = (int)ch->regs[0] * (ch->regs[1] & 0xf);
93 mul_r = (int)ch->regs[0] * (ch->regs[1] >> 4);
95 for (s = 0; s < steps; s++)
97 smp = Pico_mcd->pcm_ram[addr >> PCM_STEP_SHIFT];
99 // test for loop signal
102 addr = ch->regs[4] + (ch->regs[5]<<8); // loop_addr
103 smp = Pico_mcd->pcm_ram[addr];
104 addr <<= PCM_STEP_SHIFT;
108 addr = (addr + inc) & 0x07FFFFFF;
113 out[s*2 ] += (smp * mul_l) >> 5; // max 127 * 255 * 15 / 32 = 15180
114 out[s*2+1] += (smp * mul_r) >> 5;
120 Pico_mcd->pcm.update_cycles = cycles + steps * 384;
121 Pico_mcd->pcm_mixpos += steps;
124 void pcd_pcm_update(s32 *buf32, int length, int stereo)
129 pcd_pcm_sync(SekCyclesDoneS68k());
131 if (!Pico_mcd->pcm_mixbuf_dirty || !(PicoIn.opt & POPT_EN_MCD_PCM) || !buf32)
134 step = (Pico_mcd->pcm_mixpos << 16) / length;
135 pcm = Pico_mcd->pcm_mixbuf;
138 while (length-- > 0) {
143 pcm += (p >> 16) * 2;
148 while (length-- > 0) {
150 *buf32++ += (pcm[0] + pcm[1]) >> 1;
153 pcm += (p >> 16) * 2;
158 memset(Pico_mcd->pcm_mixbuf, 0,
159 Pico_mcd->pcm_mixpos * 2 * sizeof(Pico_mcd->pcm_mixbuf[0]));
162 Pico_mcd->pcm_mixbuf_dirty = 0;
163 Pico_mcd->pcm_mixpos = 0;
166 // vim:shiftwidth=2:ts=2:expandtab