Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
alexbevi
GitHub Repository: alexbevi/BizHawk
Path: blob/master/waterbox/gpgx/core/cd_hw/pcm.c
2 views
1
/***************************************************************************************
2
* Genesis Plus
3
* PCM sound chip (315-5476A) (RF5C164 compatible)
4
*
5
* Copyright (C) 2012 Eke-Eke (Genesis Plus GX)
6
*
7
* Redistribution and use of this code or any derivative works are permitted
8
* provided that the following conditions are met:
9
*
10
* - Redistributions may not be sold, nor may they be used in a commercial
11
* product or activity.
12
*
13
* - Redistributions that are modified from the original source must include the
14
* complete source code, including the source code for all components used by a
15
* binary built from the modified sources. However, as a special exception, the
16
* source code distributed need not include anything that is normally distributed
17
* (in either source or binary form) with the major components (compiler, kernel,
18
* and so on) of the operating system on which the executable runs, unless that
19
* component itself accompanies the executable.
20
*
21
* - Redistributions must reproduce the above copyright notice, this list of
22
* conditions and the following disclaimer in the documentation and/or other
23
* materials provided with the distribution.
24
*
25
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
26
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
29
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35
* POSSIBILITY OF SUCH DAMAGE.
36
*
37
****************************************************************************************/
38
#include "shared.h"
39
40
#define PCM_SCYCLES_RATIO (384 * 4)
41
42
#define pcm scd.pcm_hw
43
44
static blip_t* blip[2];
45
46
void pcm_init(blip_t* left, blip_t* right)
47
{
48
/* number of SCD master clocks run per second */
49
double mclk = snd.frame_rate ? (SCYCLES_PER_LINE * (vdp_pal ? 313 : 262) * snd.frame_rate) : SCD_CLOCK;
50
51
/* PCM chips is running at original rate and is synchronized with SUB-CPU */
52
/* Chip output is resampled to desired rate using Blip Buffer. */
53
blip[0] = left;
54
blip[1] = right;
55
blip_set_rates(left, mclk / PCM_SCYCLES_RATIO, snd.sample_rate);
56
blip_set_rates(right, mclk / PCM_SCYCLES_RATIO, snd.sample_rate);
57
}
58
59
void pcm_reset(void)
60
{
61
/* reset chip & clear external RAM */
62
memset(&pcm, 0, sizeof(pcm_t));
63
64
/* reset default bank */
65
pcm.bank = pcm.ram;
66
67
/* reset channels stereo panning */
68
pcm.chan[0].pan = 0xff;
69
pcm.chan[1].pan = 0xff;
70
pcm.chan[2].pan = 0xff;
71
pcm.chan[3].pan = 0xff;
72
pcm.chan[4].pan = 0xff;
73
pcm.chan[5].pan = 0xff;
74
pcm.chan[6].pan = 0xff;
75
pcm.chan[7].pan = 0xff;
76
77
/* reset master clocks counter */
78
pcm.cycles = 0;
79
80
/* clear blip buffers */
81
blip_clear(blip[0]);
82
blip_clear(blip[1]);
83
}
84
85
86
void pcm_run(unsigned int length)
87
{
88
#ifdef LOG_PCM
89
error("[%d][%d]run %d PCM samples (from %d)\n", v_counter, s68k.cycles, length, pcm.cycles);
90
#endif
91
/* check if PCM chip is running */
92
if (pcm.enabled)
93
{
94
int i, j, l, r;
95
96
/* generate PCM samples */
97
for (i=0; i<length; i++)
98
{
99
/* clear output */
100
l = r = 0;
101
102
/* run eight PCM channels */
103
for (j=0; j<8; j++)
104
{
105
/* check if channel is enabled */
106
if (pcm.status & (1 << j))
107
{
108
/* read from current WAVE RAM address */
109
short data = pcm.ram[(pcm.chan[j].addr >> 11) & 0xffff];
110
111
/* loop data ? */
112
if (data == 0xff)
113
{
114
/* reset WAVE RAM address */
115
pcm.chan[j].addr = pcm.chan[j].ls.w << 11;
116
117
/* read again from WAVE RAM address */
118
data = pcm.ram[pcm.chan[j].ls.w];
119
}
120
else
121
{
122
/* increment WAVE RAM address */
123
pcm.chan[j].addr += pcm.chan[j].fd.w;
124
}
125
126
/* infinite loop should not output any data */
127
if (data != 0xff)
128
{
129
/* check sign bit (output centered around 0) */
130
if (data & 0x80)
131
{
132
/* PCM data is positive */
133
data = data & 0x7f;
134
}
135
else
136
{
137
/* PCM data is negative */
138
data = -(data & 0x7f);
139
}
140
141
/* multiply PCM data with ENV & stereo PAN data then add to L/R outputs (14.5 fixed point) */
142
l += ((data * pcm.chan[j].env * (pcm.chan[j].pan & 0x0F)) >> 5);
143
r += ((data * pcm.chan[j].env * (pcm.chan[j].pan >> 4)) >> 5);
144
}
145
}
146
}
147
148
/* limiter */
149
if (l < -32768) l = -32768;
150
else if (l > 32767) l = 32767;
151
if (r < -32768) r = -32768;
152
else if (r > 32767) r = 32767;
153
154
/* check if PCM left output changed */
155
if (pcm.out[0] != l)
156
{
157
blip_add_delta_fast(blip[0], i, l-pcm.out[0]);
158
pcm.out[0] = l;
159
}
160
161
/* check if PCM right output changed */
162
if (pcm.out[1] != r)
163
{
164
blip_add_delta_fast(blip[1], i, r-pcm.out[1]);
165
pcm.out[1] = r;
166
}
167
}
168
}
169
else
170
{
171
/* check if PCM left output changed */
172
if (pcm.out[0])
173
{
174
blip_add_delta_fast(blip[0], 0, -pcm.out[0]);
175
pcm.out[0] = 0;
176
}
177
178
/* check if PCM right output changed */
179
if (pcm.out[1])
180
{
181
blip_add_delta_fast(blip[1], 0, -pcm.out[1]);
182
pcm.out[1] = 0;
183
}
184
}
185
186
/* end of blip buffer frame */
187
blip_end_frame(blip[0], length);
188
blip_end_frame(blip[1], length);
189
190
/* update PCM master clock counter */
191
pcm.cycles += length * PCM_SCYCLES_RATIO;
192
}
193
194
void pcm_update(unsigned int samples)
195
{
196
/* get number of internal clocks (samples) needed */
197
unsigned int clocks = blip_clocks_needed(blip[0], samples);
198
199
/* run PCM chip */
200
if (clocks > 0)
201
{
202
pcm_run(clocks);
203
}
204
205
/* reset PCM master clocks counter */
206
pcm.cycles = 0;
207
}
208
209
void pcm_write(unsigned int address, unsigned char data)
210
{
211
/* synchronize PCM chip with SUB-CPU */
212
int clocks = s68k.cycles - pcm.cycles;
213
if (clocks > 0)
214
{
215
/* number of internal clocks (samples) to run */
216
clocks = (clocks + PCM_SCYCLES_RATIO - 1) / PCM_SCYCLES_RATIO;
217
pcm_run(clocks);
218
}
219
220
#ifdef LOG_PCM
221
error("[%d][%d]PCM write %x -> 0x%02x (%X)\n", v_counter, s68k.cycles, address, data, s68k.pc);
222
#endif
223
224
/* external RAM is mapped to $1000-$1FFF */
225
if (address >= 0x1000)
226
{
227
/* 4K bank access */
228
pcm.bank[address & 0xfff] = data;
229
return;
230
}
231
232
/* internal area si mapped to $0000-$0FFF */
233
switch (address)
234
{
235
case 0x00: /* ENV register */
236
{
237
/* update channel ENV multiplier */
238
pcm.chan[pcm.index].env = data;
239
return;
240
}
241
242
case 0x01: /* PAN register */
243
{
244
/* update channel stereo panning value */
245
pcm.chan[pcm.index].pan = data;
246
return;
247
}
248
249
case 0x02: /* FD register (LSB) */
250
{
251
/* update channel WAVE RAM address increment LSB */
252
pcm.chan[pcm.index].fd.byte.l = data;
253
return;
254
}
255
256
case 0x03: /* FD register (MSB) */
257
{
258
/* update channel WAVE RAM address increment MSB */
259
pcm.chan[pcm.index].fd.byte.h = data;
260
return;
261
}
262
263
case 0x04: /* LS register (LSB) */
264
{
265
/* update channel WAVE RAM loop address LSB */
266
pcm.chan[pcm.index].ls.byte.l = data;
267
return;
268
}
269
270
case 0x05: /* LS register (MSB) */
271
{
272
/* update channel WAVE RAM loop address MSB */
273
pcm.chan[pcm.index].ls.byte.h = data;
274
return;
275
}
276
277
case 0x06: /* ST register */
278
{
279
/* update channel WAVE RAM start address (16.11 fixed point) */
280
pcm.chan[pcm.index].st = data << (8 + 11);
281
282
/* reload WAVE RAM address if channel is OFF */
283
if (!(pcm.status & (1 << pcm.index)))
284
{
285
pcm.chan[pcm.index].addr = pcm.chan[pcm.index].st;
286
}
287
return;
288
}
289
290
case 0x07: /* CTRL register */
291
{
292
if (data & 0x40)
293
{
294
/* channel selection (0-7) */
295
pcm.index = data & 0x07;
296
}
297
else
298
{
299
/* external RAM bank selection (16 x 4K) */
300
pcm.bank = &pcm.ram[(data & 0x0f) << 12];
301
}
302
303
/* update PCM chip status (bit 7) */
304
pcm.enabled = data & 0x80;
305
return;
306
}
307
308
case 0x08: /* ON/OFF register */
309
{
310
/* update PCM channels status */
311
pcm.status = ~data;
312
313
/* reload WAVE RAM address pointers when channels are OFF */
314
if (data & 0x01) pcm.chan[0].addr = pcm.chan[0].st;
315
if (data & 0x02) pcm.chan[1].addr = pcm.chan[1].st;
316
if (data & 0x04) pcm.chan[2].addr = pcm.chan[2].st;
317
if (data & 0x08) pcm.chan[3].addr = pcm.chan[3].st;
318
if (data & 0x10) pcm.chan[4].addr = pcm.chan[4].st;
319
if (data & 0x20) pcm.chan[5].addr = pcm.chan[5].st;
320
if (data & 0x40) pcm.chan[6].addr = pcm.chan[6].st;
321
if (data & 0x80) pcm.chan[7].addr = pcm.chan[7].st;
322
return;
323
}
324
325
default:
326
{
327
/* illegal access */
328
return;
329
}
330
}
331
}
332
333
unsigned char pcm_read(unsigned int address)
334
{
335
/* synchronize PCM chip with SUB-CPU */
336
int clocks = s68k.cycles - pcm.cycles;
337
if (clocks > 0)
338
{
339
/* number of internal clocks (samples) to run */
340
clocks = (clocks + PCM_SCYCLES_RATIO - 1) / PCM_SCYCLES_RATIO;
341
pcm_run(clocks);
342
}
343
344
#ifdef LOG_PCM
345
error("[%d][%d]PCM read (%X)\n", v_counter, s68k.cycles, address, s68k.pc);
346
#endif
347
348
/* external RAM (TODO: verify if possible to read, some docs claim it's not !) */
349
if (address >= 0x1000)
350
{
351
/* 4K bank access */
352
return pcm.bank[address & 0xfff];
353
}
354
355
/* read WAVE RAM address pointers */
356
if ((address >= 0x10) && (address < 0x20))
357
{
358
int index = (address >> 1) & 0x07;
359
360
if (address & 1)
361
{
362
return (pcm.chan[index].addr >> (11 + 8)) & 0xff;
363
}
364
else
365
{
366
return (pcm.chan[index].addr >> 11) & 0xff;
367
}
368
}
369
370
/* illegal access */
371
return 0xff;
372
}
373
374
void pcm_ram_dma_w(unsigned int words)
375
{
376
uint16 data;
377
378
/* CDC buffer source address */
379
uint16 src_index = cdc.dac.w & 0x3ffe;
380
381
/* PCM-RAM destination address*/
382
uint16 dst_index = (scd.regs[0x0a>>1].w << 2) & 0xffe;
383
384
/* update DMA destination address */
385
scd.regs[0x0a>>1].w += (words >> 1);
386
387
/* update DMA source address */
388
cdc.dac.w += (words << 1);
389
390
/* DMA transfer */
391
while (words--)
392
{
393
/* read 16-bit word from CDC buffer */
394
data = *(uint16 *)(cdc.ram + src_index);
395
396
/* write 16-bit word to PCM RAM (endianness does not matter since PCM RAM is always accessed as byte)*/
397
*(uint16 *)(pcm.bank + dst_index) = data ;
398
399
/* increment CDC buffer source address */
400
src_index = (src_index + 2) & 0x3ffe;
401
402
/* increment PCM-RAM destination address */
403
dst_index = (dst_index + 2) & 0xffe;
404
}
405
}
406
407
408