cff531af |
1 | /* |
2 | * Emulation routines for the RF5C164 PCM chip |
33be04ca |
3 | * (C) notaz, 2007, 2013 |
cff531af |
4 | * |
5 | * This work is licensed under the terms of MAME license. |
6 | * See COPYING file in the top-level directory. |
7 | */ |
6cadc2da |
8 | |
efcba75f |
9 | #include "../pico_int.h" |
abe0ea43 |
10 | |
33be04ca |
11 | #define PCM_STEP_SHIFT 11 |
abe0ea43 |
12 | |
33be04ca |
13 | void pcd_pcm_write(unsigned int a, unsigned int d) |
abe0ea43 |
14 | { |
33be04ca |
15 | unsigned int cycles = SekCyclesDoneS68k(); |
16 | if ((int)(cycles - Pico_mcd->pcm.update_cycles) >= 384) |
17 | pcd_pcm_sync(cycles); |
18 | |
19 | if (a < 7) |
20 | { |
21 | Pico_mcd->pcm.ch[Pico_mcd->pcm.cur_ch].regs[a] = d; |
22 | } |
23 | else if (a == 7) // control register |
24 | { |
25 | if (d & 0x40) |
26 | Pico_mcd->pcm.cur_ch = d & 7; |
27 | else |
28 | Pico_mcd->pcm.bank = d & 0xf; |
29 | Pico_mcd->pcm.control = d; |
30 | elprintf(EL_CD, "pcm control %02x", Pico_mcd->pcm.control); |
31 | } |
021e47b3 |
32 | else if (a == 8) |
33be04ca |
33 | { |
33be04ca |
34 | Pico_mcd->pcm.enabled = ~d; |
35 | } |
021e47b3 |
36 | Pico_mcd->pcm_regs_dirty = 1; |
abe0ea43 |
37 | } |
38 | |
33be04ca |
39 | unsigned int pcd_pcm_read(unsigned int a) |
abe0ea43 |
40 | { |
33be04ca |
41 | unsigned int d, cycles = SekCyclesDoneS68k(); |
42 | if ((int)(cycles - Pico_mcd->pcm.update_cycles) >= 384) |
43 | pcd_pcm_sync(cycles); |
44 | |
45 | d = Pico_mcd->pcm.ch[(a >> 1) & 7].addr >> PCM_STEP_SHIFT; |
46 | if (a & 1) |
47 | d >>= 8; |
48 | |
49 | return d & 0xff; |
abe0ea43 |
50 | } |
51 | |
33be04ca |
52 | void pcd_pcm_sync(unsigned int to) |
53 | { |
54 | unsigned int cycles = Pico_mcd->pcm.update_cycles; |
55 | int mul_l, mul_r, inc, smp; |
56 | struct pcm_chan *ch; |
57 | unsigned int addr; |
58 | int c, s, steps; |
021e47b3 |
59 | int enabled; |
33be04ca |
60 | int *out; |
61 | |
62 | if ((int)(to - cycles) < 384) |
63 | return; |
64 | |
65 | steps = (to - cycles) / 384; |
021e47b3 |
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; |
33be04ca |
69 | |
70 | // PCM disabled or all channels off |
021e47b3 |
71 | enabled = Pico_mcd->pcm.enabled; |
72 | if (!(Pico_mcd->pcm.control & 0x80)) |
73 | enabled = 0; |
74 | if (!enabled && !Pico_mcd->pcm_regs_dirty) |
33be04ca |
75 | goto end; |
76 | |
77 | out = Pico_mcd->pcm_mixbuf + Pico_mcd->pcm_mixpos * 2; |
78 | Pico_mcd->pcm_mixbuf_dirty = 1; |
021e47b3 |
79 | Pico_mcd->pcm_regs_dirty = 0; |
33be04ca |
80 | |
81 | for (c = 0; c < 8; c++) |
82 | { |
021e47b3 |
83 | ch = &Pico_mcd->pcm.ch[c]; |
84 | |
85 | if (!(enabled & (1 << c))) { |
86 | ch->addr = ch->regs[6] << (PCM_STEP_SHIFT + 8); |
33be04ca |
87 | continue; // channel disabled |
021e47b3 |
88 | } |
33be04ca |
89 | |
33be04ca |
90 | addr = ch->addr; |
91 | inc = *(unsigned short *)&ch->regs[2]; |
92 | mul_l = ((int)ch->regs[0] * (ch->regs[1] & 0xf)) >> (5+1); |
93 | mul_r = ((int)ch->regs[0] * (ch->regs[1] >> 4)) >> (5+1); |
94 | |
95 | for (s = 0; s < steps; s++, addr = (addr + inc) & 0x7FFFFFF) |
96 | { |
97 | smp = Pico_mcd->pcm_ram[addr >> PCM_STEP_SHIFT]; |
98 | |
99 | // test for loop signal |
100 | if (smp == 0xff) |
101 | { |
102 | addr = *(unsigned short *)&ch->regs[4]; // loop_addr |
103 | smp = Pico_mcd->pcm_ram[addr]; |
104 | addr <<= PCM_STEP_SHIFT; |
105 | if (smp == 0xff) |
106 | break; |
107 | } |
108 | |
109 | if (smp & 0x80) |
110 | smp = -(smp & 0x7f); |
111 | |
112 | out[s*2 ] += smp * mul_l; // max 128 * 119 = 15232 |
113 | out[s*2+1] += smp * mul_r; |
114 | } |
115 | ch->addr = addr; |
116 | } |
117 | |
118 | end: |
119 | Pico_mcd->pcm.update_cycles = cycles + steps * 384; |
120 | Pico_mcd->pcm_mixpos += steps; |
121 | } |
abe0ea43 |
122 | |
33be04ca |
123 | void pcd_pcm_update(int *buf32, int length, int stereo) |
abe0ea43 |
124 | { |
33be04ca |
125 | int step, *pcm; |
126 | int p = 0; |
127 | |
128 | pcd_pcm_sync(SekCyclesDoneS68k()); |
129 | |
130 | if (!Pico_mcd->pcm_mixbuf_dirty || !(PicoOpt & POPT_EN_MCD_PCM)) |
131 | goto out; |
132 | |
133 | step = (Pico_mcd->pcm_mixpos << 16) / length; |
134 | pcm = Pico_mcd->pcm_mixbuf; |
135 | |
136 | if (stereo) { |
137 | while (length-- > 0) { |
138 | *buf32++ += pcm[0]; |
139 | *buf32++ += pcm[1]; |
140 | |
141 | p += step; |
142 | pcm += (p >> 16) * 2; |
143 | p &= 0xffff; |
144 | } |
145 | } |
146 | else { |
147 | while (length-- > 0) { |
148 | // mostly unused |
149 | *buf32++ += pcm[0]; |
150 | |
151 | p += step; |
152 | pcm += (p >> 16) * 2; |
153 | p &= 0xffff; |
154 | } |
155 | } |
156 | |
157 | memset(Pico_mcd->pcm_mixbuf, 0, |
158 | Pico_mcd->pcm_mixpos * 2 * sizeof(Pico_mcd->pcm_mixbuf[0])); |
159 | |
160 | out: |
161 | Pico_mcd->pcm_mixbuf_dirty = 0; |
162 | Pico_mcd->pcm_mixpos = 0; |
abe0ea43 |
163 | } |
164 | |
33be04ca |
165 | // vim:shiftwidth=2:ts=2:expandtab |