Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
alexbevi
GitHub Repository: alexbevi/BizHawk
Path: blob/master/waterbox/gpgx/core/cd_hw/cdd.c
2 views
1
/***************************************************************************************
2
* Genesis Plus
3
* CD drive processor & CD-DA fader
4
*
5
* Copyright (C) 2012-2013 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
#include "../cinterface/callbacks.h"
40
41
/* BCD conversion lookup tables */
42
static const uint8 lut_BCD_8[100] =
43
{
44
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
45
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19,
46
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29,
47
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
48
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
49
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
50
0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
51
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
52
0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
53
0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99,
54
};
55
56
static const uint16 lut_BCD_16[100] =
57
{
58
0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009,
59
0x0100, 0x0101, 0x0102, 0x0103, 0x0104, 0x0105, 0x0106, 0x0107, 0x0108, 0x0109,
60
0x0200, 0x0201, 0x0202, 0x0203, 0x0204, 0x0205, 0x0206, 0x0207, 0x0208, 0x0209,
61
0x0300, 0x0301, 0x0302, 0x0303, 0x0304, 0x0305, 0x0306, 0x0307, 0x0308, 0x0309,
62
0x0400, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0406, 0x0407, 0x0408, 0x0409,
63
0x0500, 0x0501, 0x0502, 0x0503, 0x0504, 0x0505, 0x0506, 0x0507, 0x0508, 0x0509,
64
0x0600, 0x0601, 0x0602, 0x0603, 0x0604, 0x0605, 0x0606, 0x0607, 0x0608, 0x0609,
65
0x0700, 0x0701, 0x0702, 0x0703, 0x0704, 0x0705, 0x0706, 0x0707, 0x0708, 0x0709,
66
0x0800, 0x0801, 0x0802, 0x0803, 0x0804, 0x0805, 0x0806, 0x0807, 0x0808, 0x0809,
67
0x0900, 0x0901, 0x0902, 0x0903, 0x0904, 0x0905, 0x0906, 0x0907, 0x0908, 0x0909,
68
};
69
70
/* pre-build TOC */
71
static const uint16 toc_snatcher[21] =
72
{
73
56014, 495, 10120, 20555, 1580, 5417, 12502, 16090, 6553, 9681,
74
8148, 20228, 8622, 6142, 5858, 1287, 7424, 3535, 31697, 2485,
75
31380
76
};
77
78
static const uint16 toc_lunar[52] =
79
{
80
5422, 1057, 7932, 5401, 6380, 6592, 5862, 5937, 5478, 5870,
81
6673, 6613, 6429, 4996, 4977, 5657, 3720, 5892, 3140, 3263,
82
6351, 5187, 3249, 1464, 1596, 1750, 1751, 6599, 4578, 5205,
83
1550, 1827, 2328, 1346, 1569, 1613, 7199, 4928, 1656, 2549,
84
1875, 3901, 1850, 2399, 2028, 1724, 4889, 14551, 1184, 2132,
85
685, 3167
86
};
87
88
static const uint32 toc_shadow[15] =
89
{
90
10226, 70054, 11100, 12532, 12444, 11923, 10059, 10167, 10138, 13792,
91
11637, 2547, 2521, 3856, 900
92
};
93
94
static const uint32 toc_dungeon[13] =
95
{
96
2250, 22950, 16350, 24900, 13875, 19950, 13800, 15375, 17400, 17100,
97
3325, 6825, 25275
98
};
99
100
static const uint32 toc_ffight[26] =
101
{
102
11994, 9742, 10136, 9685, 9553, 14588, 9430, 8721, 9975, 9764,
103
9704, 12796, 585, 754, 951, 624, 9047, 1068, 817, 9191, 1024,
104
14562, 10320, 8627, 3795, 3047
105
};
106
107
static const uint32 toc_ffightj[29] =
108
{
109
11994, 9752, 10119, 9690, 9567, 14575, 9431, 8731, 9965, 9763,
110
9716, 12791, 579, 751, 958, 630, 9050, 1052, 825, 9193, 1026,
111
14553, 9834, 10542, 1699, 1792, 1781, 3783, 3052
112
};
113
114
/* supported WAVE file header (16-bit stereo samples @44.1kHz) */
115
static const unsigned char waveHeader[32] =
116
{
117
0x57,0x41,0x56,0x45,0x66,0x6d,0x74,0x20,0x10,0x00,0x00,0x00,0x01,0x00,0x02,0x00,
118
0x44,0xac,0x00,0x00,0x10,0xb1,0x02,0x00,0x04,0x00,0x10,0x00,0x64,0x61,0x74,0x61
119
};
120
121
static blip_t* blip[2];
122
123
typedef struct
124
{
125
toc_t toc;
126
} frontendcd_t;
127
128
int cdd_load(const char *key, char *header)
129
{
130
frontendcd_t fecd;
131
char data[2048];
132
int startoffs;
133
134
135
int bytes = sizeof(frontendcd_t);
136
if (load_archive(key, (unsigned char *)&fecd, bytes, NULL) != bytes)
137
return 0;
138
139
// look for valid header
140
cdd_readcallback(0, data, 0);
141
if (memcmp("SEGADISCSYSTEM", data, 14) == 0)
142
startoffs = 0;
143
else if (memcmp("SEGADISCSYSTEM", data + 16, 14) == 0)
144
startoffs = 16;
145
else
146
return 0;
147
// copy security block
148
memcpy(header, data + startoffs, 0x210);
149
150
// copy disk information
151
memcpy(&cdd.toc, &fecd.toc, sizeof(toc_t));
152
153
cdd.loaded = 1;
154
return 1;
155
}
156
157
void cdd_init(blip_t* left, blip_t* right)
158
{
159
/* CD-DA is running by default at 44100 Hz */
160
/* Audio stream is resampled to desired rate using Blip Buffer */
161
blip[0] = left;
162
blip[1] = right;
163
blip_set_rates(left, 44100, snd.sample_rate);
164
blip_set_rates(right, 44100, snd.sample_rate);
165
}
166
167
void cdd_reset(void)
168
{
169
/* reset cycle counter */
170
cdd.cycles = 0;
171
172
/* reset drive access latency */
173
cdd.latency = 0;
174
175
/* reset track index */
176
cdd.index = 0;
177
178
/* reset logical block address */
179
cdd.lba = 0;
180
181
// reset audio subblock position
182
cdd.sampleOffset = 0;
183
184
// reset audio read position
185
cdd.sampleLba = 0;
186
187
/* reset status */
188
cdd.status = cdd.loaded ? CD_STOP : NO_DISC;
189
190
/* reset CD-DA fader (full volume) */
191
cdd.volume = 0x400;
192
193
/* clear CD-DA output */
194
cdd.audio[0] = cdd.audio[1] = 0;
195
}
196
197
void cdd_unload(void)
198
{
199
cdd.loaded = 0;
200
cdd_readcallback = NULL;
201
202
/* reset TOC */
203
memset(&cdd.toc, 0x00, sizeof(cdd.toc));
204
}
205
206
void cdd_read_data(uint8 *dst)
207
{
208
/* only read DATA track sectors */
209
if ((cdd.lba >= 0) && (cdd.lba < cdd.toc.tracks[0].end))
210
{
211
cdd_readcallback(cdd.lba, dst, 0);
212
}
213
}
214
215
void cdd_read_audio(unsigned int samples)
216
{
217
// previous audio outputs //
218
int16 l = cdd.audio[0];
219
int16 r = cdd.audio[1];
220
221
// get number of internal clocks (samples) needed //
222
samples = blip_clocks_needed(blip[0], samples);
223
224
// audio track playing ? //
225
if (!scd.regs[0x36>>1].byte.h)
226
{
227
int i, mul, delta;
228
229
// current CD-DA fader volume //
230
int curVol = cdd.volume;
231
232
// CD-DA fader volume setup (0-1024) //
233
int endVol = scd.regs[0x34>>1].w >> 4;
234
235
// read samples from current block //
236
{
237
#ifdef LSB_FIRST
238
int16 *ptr = (int16 *) (cdc.ram);
239
#else
240
uint8 *ptr = cdc.ram;
241
#endif
242
{
243
char scratch[2352];
244
// copy the end of current sector
245
int nsampreq = samples;
246
unsigned char *dest = cdc.ram;
247
cdd_readcallback(cdd.sampleLba, scratch, 1);
248
memcpy(cdc.ram, scratch + cdd.sampleOffset * 4, 2352 - cdd.sampleOffset * 4);
249
cdd.sampleLba++;
250
nsampreq -= 588 - cdd.sampleOffset;
251
dest += 2352 - cdd.sampleOffset * 4;
252
cdd.sampleOffset = 0;
253
// fill full sectors
254
while (nsampreq >= 588)
255
{
256
cdd_readcallback(cdd.sampleLba, scratch, 1);
257
memcpy(dest, scratch, 2352);
258
cdd.sampleLba++;
259
nsampreq -= 588;
260
dest += 2352;
261
}
262
// do last partial sector
263
if (nsampreq > 0)
264
{
265
cdd_readcallback(cdd.sampleLba, scratch, 1);
266
memcpy(dest, scratch, nsampreq * 4);
267
cdd.sampleOffset = nsampreq;
268
dest += nsampreq * 4;
269
nsampreq = 0;
270
}
271
//printf("samples: %i\n", samples);
272
//memset(cdc.ram, 0, samples * 4);
273
//fread(cdc.ram, 1, samples * 4, cdd.toc.tracks[cdd.index].fd);
274
}
275
276
// process 16-bit (little-endian) stereo samples //
277
for (i=0; i<samples; i++)
278
{
279
// CD-DA fader multiplier (cf. LC7883 datasheet) //
280
// (MIN) 0,1,2,3,4,8,12,16,20...,1020,1024 (MAX) //
281
mul = (curVol & 0x7fc) ? (curVol & 0x7fc) : (curVol & 0x03);
282
283
// left channel //
284
#ifdef LSB_FIRST
285
delta = ((ptr[0] * mul) / 1024) - l;
286
ptr++;
287
#else
288
delta = (((int16)((ptr[0] + ptr[1]*256)) * mul) / 1024) - l;
289
ptr += 2;
290
#endif
291
l += delta;
292
blip_add_delta_fast(blip[0], i, delta);
293
294
// right channel //
295
#ifdef LSB_FIRST
296
delta = ((ptr[0] * mul) / 1024) - r;
297
ptr++;
298
#else
299
delta = (((int16)((ptr[0] + ptr[1]*256)) * mul) / 1024) - r;
300
ptr += 2;
301
#endif
302
r += delta;
303
blip_add_delta_fast(blip[1], i, delta);
304
305
// update CD-DA fader volume (one step/sample) //
306
if (curVol < endVol)
307
{
308
// fade-in //
309
curVol++;
310
}
311
else if (curVol > endVol)
312
{
313
// fade-out //
314
curVol--;
315
}
316
else if (!curVol)
317
{
318
// audio will remain muted until next setup //
319
break;
320
}
321
}
322
}
323
324
// save current CD-DA fader volume //
325
cdd.volume = curVol;
326
327
// save last audio output for next frame //
328
cdd.audio[0] = l;
329
cdd.audio[1] = r;
330
}
331
else
332
{
333
// no audio output //
334
if (l) blip_add_delta_fast(blip[0], 0, -l);
335
if (r) blip_add_delta_fast(blip[1], 0, -r);
336
337
// save audio output for next frame //
338
cdd.audio[0] = 0;
339
cdd.audio[1] = 0;
340
}
341
342
// end of Blip Buffer timeframe //
343
blip_end_frame(blip[0], samples);
344
blip_end_frame(blip[1], samples);
345
}
346
347
348
void cdd_update(void)
349
{
350
#ifdef LOG_CDD
351
error("LBA = %d (track n�%d)(latency=%d)\n", cdd.lba, cdd.index, cdd.latency);
352
#endif
353
354
/* seeking disc */
355
if (cdd.status == CD_SEEK)
356
{
357
/* drive latency */
358
if (cdd.latency > 0)
359
{
360
cdd.latency--;
361
return;
362
}
363
364
/* drive is ready */
365
cdd.status = CD_READY;
366
}
367
368
/* reading disc */
369
else if (cdd.status == CD_PLAY)
370
{
371
/* drive latency */
372
if (cdd.latency > 0)
373
{
374
cdd.latency--;
375
return;
376
}
377
378
/* track type */
379
if (!cdd.index)
380
{
381
/* DATA sector header (CD-ROM Mode 1) */
382
uint8 header[4];
383
uint32 msf = cdd.lba + 150;
384
header[0] = lut_BCD_8[(msf / 75) / 60];
385
header[1] = lut_BCD_8[(msf / 75) % 60];
386
header[2] = lut_BCD_8[(msf % 75)];
387
header[3] = 0x01;
388
389
/* data track sector read is controlled by CDC */
390
cdd.lba += cdc_decoder_update(*(uint32 *)(header));
391
}
392
else if (cdd.index < cdd.toc.last)
393
{
394
/* check against audio track start index */
395
if (cdd.lba >= cdd.toc.tracks[cdd.index].start)
396
{
397
/* audio track playing */
398
// if it wasn't before, set the audio start position
399
if (scd.regs[0x36>>1].byte.h)
400
{
401
cdd.sampleLba = cdd.lba + 1;
402
cdd.sampleOffset = 0;
403
}
404
scd.regs[0x36>>1].byte.h = 0x00;
405
}
406
407
/* audio blocks are still sent to CDC as well as CD DAC/Fader */
408
cdc_decoder_update(0);
409
410
/* next audio block is automatically read */
411
cdd.lba++;
412
}
413
else
414
{
415
/* end of disc */
416
cdd.status = CD_END;
417
return;
418
}
419
420
/* check end of current track */
421
if (cdd.lba >= cdd.toc.tracks[cdd.index].end)
422
{
423
/* play next track */
424
cdd.index++;
425
426
/* PAUSE between tracks */
427
scd.regs[0x36>>1].byte.h = 0x01;
428
}
429
}
430
431
/* scanning disc */
432
else if (cdd.status == CD_SCAN)
433
{
434
/* fast-forward or fast-rewind */
435
cdd.lba += cdd.scanOffset;
436
cdd.sampleLba += cdd.scanOffset;
437
438
/* check current track limits */
439
if (cdd.lba >= cdd.toc.tracks[cdd.index].end)
440
{
441
/* next track */
442
cdd.index++;
443
444
/* skip directly to track start position */
445
cdd.lba = cdd.toc.tracks[cdd.index].start;
446
447
/* AUDIO track playing ? */
448
if (cdd.status == CD_PLAY)
449
{
450
scd.regs[0x36>>1].byte.h = 0x00;
451
// set audio start point
452
cdd.sampleLba = cdd.lba;
453
cdd.sampleOffset = 0;
454
}
455
}
456
else if (cdd.lba < cdd.toc.tracks[cdd.index].start)
457
{
458
/* previous track */
459
cdd.index--;
460
461
/* skip directly to track end position */
462
cdd.lba = cdd.toc.tracks[cdd.index].end;
463
}
464
465
/* check disc limits */
466
if (cdd.index < 0)
467
{
468
cdd.index = 0;
469
cdd.lba = 0;
470
}
471
else if (cdd.index >= cdd.toc.last)
472
{
473
/* no AUDIO track playing */
474
scd.regs[0x36>>1].byte.h = 0x01;
475
476
/* end of disc */
477
cdd.index = cdd.toc.last;
478
cdd.lba = cdd.toc.end;
479
cdd.status = CD_END;
480
return;
481
}
482
}
483
}
484
485
void cdd_process(void)
486
{
487
/* Process CDD command */
488
switch (scd.regs[0x42>>1].byte.h & 0x0f)
489
{
490
case 0x00: /* Drive Status */
491
{
492
/* RS1-RS8 normally unchanged */
493
scd.regs[0x38>>1].byte.h = cdd.status;
494
495
/* unless RS1 indicated invalid track infos */
496
if (scd.regs[0x38>>1].byte.l == 0x0f)
497
{
498
/* and SEEK has ended */
499
if (cdd.status != CD_SEEK)
500
{
501
/* then return valid track infos, e.g current track number in RS2-RS3 (fixes Lunar - The Silver Star) */
502
scd.regs[0x38>>1].byte.l = 0x02;
503
scd.regs[0x3a>>1].w = (cdd.index < cdd.toc.last) ? lut_BCD_16[cdd.index + 1] : 0x0A0A;
504
}
505
}
506
break;
507
}
508
509
case 0x01: /* Stop Drive */
510
{
511
/* update status */
512
cdd.status = cdd.loaded ? CD_STOP : NO_DISC;
513
514
/* no audio track playing */
515
scd.regs[0x36>>1].byte.h = 0x01;
516
517
/* RS1-RS8 ignored, expects 0x0 ("no disc" ?) in RS0 once */
518
scd.regs[0x38>>1].w = 0x0000;
519
scd.regs[0x3a>>1].w = 0x0000;
520
scd.regs[0x3c>>1].w = 0x0000;
521
scd.regs[0x3e>>1].w = 0x0000;
522
scd.regs[0x40>>1].w = 0x000f;
523
return;
524
}
525
526
case 0x02: /* Read TOC */
527
{
528
/* Infos automatically retrieved by CDD processor from Q-Channel */
529
/* commands 0x00-0x02 (current block) and 0x03-0x05 (Lead-In) */
530
switch (scd.regs[0x44>>1].byte.l)
531
{
532
case 0x00: /* Current Absolute Time (MM:SS:FF) */
533
{
534
int lba = cdd.lba + 150;
535
scd.regs[0x38>>1].w = cdd.status << 8;
536
scd.regs[0x3a>>1].w = lut_BCD_16[(lba/75)/60];
537
scd.regs[0x3c>>1].w = lut_BCD_16[(lba/75)%60];
538
scd.regs[0x3e>>1].w = lut_BCD_16[(lba%75)];
539
scd.regs[0x40>>1].byte.h = cdd.index ? 0x00 : 0x04; /* Current block flags in RS8 (bit0 = mute status, bit1: pre-emphasis status, bit2: track type) */
540
break;
541
}
542
543
case 0x01: /* Current Track Relative Time (MM:SS:FF) */
544
{
545
int lba = cdd.lba - cdd.toc.tracks[cdd.index].start;
546
scd.regs[0x38>>1].w = (cdd.status << 8) | 0x01;
547
scd.regs[0x3a>>1].w = lut_BCD_16[(lba/75)/60];
548
scd.regs[0x3c>>1].w = lut_BCD_16[(lba/75)%60];
549
scd.regs[0x3e>>1].w = lut_BCD_16[(lba%75)];
550
scd.regs[0x40>>1].byte.h = cdd.index ? 0x00 : 0x04; /* Current block flags in RS8 (bit0 = mute status, bit1: pre-emphasis status, bit2: track type) */
551
break;
552
}
553
554
case 0x02: /* Current Track Number */
555
{
556
scd.regs[0x38>>1].w = (cdd.status << 8) | 0x02;
557
scd.regs[0x3a>>1].w = (cdd.index < cdd.toc.last) ? lut_BCD_16[cdd.index + 1] : 0x0A0A;
558
scd.regs[0x3c>>1].w = 0x0000;
559
scd.regs[0x3e>>1].w = 0x0000; /* Disk Control Code (?) in RS6 */
560
scd.regs[0x40>>1].byte.h = 0x00;
561
break;
562
}
563
564
case 0x03: /* Total length (MM:SS:FF) */
565
{
566
int lba = cdd.toc.end + 150;
567
scd.regs[0x38>>1].w = (cdd.status << 8) | 0x03;
568
scd.regs[0x3a>>1].w = lut_BCD_16[(lba/75)/60];
569
scd.regs[0x3c>>1].w = lut_BCD_16[(lba/75)%60];
570
scd.regs[0x3e>>1].w = lut_BCD_16[(lba%75)];
571
scd.regs[0x40>>1].byte.h = 0x00;
572
break;
573
}
574
575
case 0x04: /* First & Last Track Numbers */
576
{
577
scd.regs[0x38>>1].w = (cdd.status << 8) | 0x04;
578
scd.regs[0x3a>>1].w = 0x0001;
579
scd.regs[0x3c>>1].w = lut_BCD_16[cdd.toc.last];
580
scd.regs[0x3e>>1].w = 0x0000; /* Drive Version (?) in RS6-RS7 */
581
scd.regs[0x40>>1].byte.h = 0x00; /* Lead-In flags in RS8 (bit0 = mute status, bit1: pre-emphasis status, bit2: track type) */
582
break;
583
}
584
585
case 0x05: /* Track Start Time (MM:SS:FF) */
586
{
587
int track = scd.regs[0x46>>1].byte.h * 10 + scd.regs[0x46>>1].byte.l;
588
int lba = cdd.toc.tracks[track-1].start + 150;
589
scd.regs[0x38>>1].w = (cdd.status << 8) | 0x05;
590
scd.regs[0x3a>>1].w = lut_BCD_16[(lba/75)/60];
591
scd.regs[0x3c>>1].w = lut_BCD_16[(lba/75)%60];
592
scd.regs[0x3e>>1].w = lut_BCD_16[(lba%75)];
593
scd.regs[0x40>>1].byte.h = track % 10; /* Track Number (low digit) */
594
if (track == 1)
595
{
596
/* RS6 bit 3 is set for the first (DATA) track */
597
scd.regs[0x3e>>1].byte.h |= 0x08;
598
}
599
break;
600
}
601
602
default:
603
{
604
#ifdef LOG_ERROR
605
error("Unknown CDD Command %02X (%X)\n", scd.regs[0x44>>1].byte.l, s68k.pc);
606
#endif
607
return;
608
}
609
}
610
break;
611
}
612
613
case 0x03: /* Play */
614
{
615
/* reset track index */
616
int index = 0;
617
618
/* new LBA position */
619
int lba = ((scd.regs[0x44>>1].byte.h * 10 + scd.regs[0x44>>1].byte.l) * 60 +
620
(scd.regs[0x46>>1].byte.h * 10 + scd.regs[0x46>>1].byte.l)) * 75 +
621
(scd.regs[0x48>>1].byte.h * 10 + scd.regs[0x48>>1].byte.l) - 150;
622
623
/* CD drive latency */
624
if (!cdd.latency)
625
{
626
/* Fixes a few games hanging during intro because they expect data to be read with some delay */
627
/* Radical Rex needs at least one interrupt delay */
628
/* Wolf Team games (Anet Futatabi, Cobra Command, Road Avenger & Time Gal) need at least 6 interrupts delay */
629
/* Space Adventure Cobra (2nd morgue scene) needs at least 13 interrupts delay (incl. seek time, so 6 is OK) */
630
/* Jeopardy & ESPN Sunday Night NFL are picky about this as well: 10 interrupts delay (+ seek time) seems OK */
631
cdd.latency = 10;
632
}
633
634
/* CD drive seek time */
635
/* max. seek time = 1.5 s = 1.5 x 75 = 112.5 CDD interrupts (rounded to 120) for 270000 sectors max on disc. */
636
/* Note: This is only a rough approximation since, on real hardware, seek time is much likely not linear and */
637
/* latency much larger than above value, but this model works fine for Sonic CD (track 26 playback needs to */
638
/* be enough delayed to start in sync with intro sequence, as compared with real hardware recording). */
639
if (lba > cdd.lba)
640
{
641
cdd.latency += (((lba - cdd.lba) * 120) / 270000);
642
}
643
else
644
{
645
cdd.latency += (((cdd.lba - lba) * 120) / 270000);
646
}
647
648
/* update current LBA */
649
cdd.lba = lba;
650
651
/* get track index */
652
while ((cdd.toc.tracks[index].end <= lba) && (index < cdd.toc.last)) index++;
653
654
/* update current track index */
655
cdd.index = index;
656
657
/* no audio track playing (yet) */
658
scd.regs[0x36>>1].byte.h = 0x01;
659
660
/* update status */
661
cdd.status = CD_PLAY;
662
663
/* return track index in RS2-RS3 */
664
scd.regs[0x38>>1].w = (CD_PLAY << 8) | 0x02;
665
scd.regs[0x3a>>1].w = (cdd.index < cdd.toc.last) ? lut_BCD_16[index + 1] : 0x0A0A;
666
scd.regs[0x3c>>1].w = 0x0000;
667
scd.regs[0x3e>>1].w = 0x0000;
668
scd.regs[0x40>>1].byte.h = 0x00;
669
break;
670
}
671
672
case 0x04: /* Seek */
673
{
674
/* reset track index */
675
int index = 0;
676
677
/* new LBA position */
678
int lba = ((scd.regs[0x44>>1].byte.h * 10 + scd.regs[0x44>>1].byte.l) * 60 +
679
(scd.regs[0x46>>1].byte.h * 10 + scd.regs[0x46>>1].byte.l)) * 75 +
680
(scd.regs[0x48>>1].byte.h * 10 + scd.regs[0x48>>1].byte.l) - 150;
681
682
/* CD drive seek time */
683
/* We are using similar linear model as above, although still not exactly accurate, */
684
/* it works fine for Switch/Panic! intro (Switch needs at least 30 interrupts while */
685
/* seeking from 00:05:63 to 24:03:19, Panic! when seeking from 00:05:60 to 24:06:07) */
686
if (lba > cdd.lba)
687
{
688
cdd.latency = ((lba - cdd.lba) * 120) / 270000;
689
}
690
else
691
{
692
cdd.latency = ((cdd.lba - lba) * 120) / 270000;
693
}
694
695
/* update current LBA */
696
cdd.lba = lba;
697
698
/* get current track index */
699
while ((cdd.toc.tracks[index].end <= lba) && (index < cdd.toc.last)) index++;
700
701
/* update current track index */
702
cdd.index = index;
703
704
/* no audio track playing */
705
scd.regs[0x36>>1].byte.h = 0x01;
706
707
/* update status */
708
cdd.status = CD_SEEK;
709
710
/* unknown RS1-RS8 values (returning 0xF in RS1 invalidates track infos in RS2-RS8 and fixes Final Fight CD intro when seek time is emulated) */
711
scd.regs[0x38>>1].w = (CD_SEEK << 8) | 0x0f;
712
scd.regs[0x3a>>1].w = 0x0000;
713
scd.regs[0x3c>>1].w = 0x0000;
714
scd.regs[0x3e>>1].w = 0x0000;
715
scd.regs[0x40>>1].w = ~(CD_SEEK + 0xf) & 0x0f;
716
return;
717
}
718
719
case 0x06: /* Pause */
720
{
721
/* no audio track playing */
722
scd.regs[0x36>>1].byte.h = 0x01;
723
724
/* update status (RS1-RS8 unchanged) */
725
cdd.status = scd.regs[0x38>>1].byte.h = CD_READY;
726
break;
727
}
728
729
case 0x07: /* Resume */
730
{
731
/* update status (RS1-RS8 unchanged) */
732
cdd.status = scd.regs[0x38>>1].byte.h = CD_PLAY;
733
break;
734
}
735
736
case 0x08: /* Forward Scan */
737
{
738
/* reset scanning direction / speed */
739
cdd.scanOffset = CD_SCAN_SPEED;
740
741
/* update status (RS1-RS8 unchanged) */
742
cdd.status = scd.regs[0x38>>1].byte.h = CD_SCAN;
743
break;
744
}
745
746
case 0x09: /* Rewind Scan */
747
{
748
/* reset scanning direction / speed */
749
cdd.scanOffset = -CD_SCAN_SPEED;
750
751
/* update status (RS1-RS8 unchanged) */
752
cdd.status = scd.regs[0x38>>1].byte.h = CD_SCAN;
753
break;
754
}
755
756
757
case 0x0a: /* N-Track Jump Control ? (usually sent before CD_SEEK or CD_PLAY commands) */
758
{
759
/* TC3 corresponds to seek direction (00=forward, FF=reverse) */
760
/* TC4-TC7 are related to seek length (4x4 bits i.e parameter values are between -65535 and +65535) */
761
/* Maybe related to number of auto-sequenced track jumps/moves for CD DSP (cf. CXD2500BQ datasheet) */
762
/* also see US Patent nr. 5222054 for a detailled description of seeking operation using Track Jump */
763
764
/* no audio track playing */
765
scd.regs[0x36>>1].byte.h = 0x01;
766
767
/* update status (RS1-RS8 unchanged) */
768
cdd.status = scd.regs[0x38>>1].byte.h = CD_READY;
769
break;
770
}
771
772
case 0x0c: /* Close Tray */
773
{
774
/* no audio track playing */
775
scd.regs[0x36>>1].byte.h = 0x01;
776
777
/* update status */
778
cdd.status = cdd.loaded ? CD_STOP : NO_DISC;
779
780
/* RS1-RS8 ignored, expects 0x0 ("no disc" ?) in RS0 once */
781
scd.regs[0x38>>1].w = 0x0000;
782
scd.regs[0x3a>>1].w = 0x0000;
783
scd.regs[0x3c>>1].w = 0x0000;
784
scd.regs[0x3e>>1].w = 0x0000;
785
scd.regs[0x40>>1].w = 0x000f;
786
787
#ifdef CD_TRAY_CALLBACK
788
CD_TRAY_CALLBACK
789
#endif
790
return;
791
}
792
793
case 0x0d: /* Open Tray */
794
{
795
/* no audio track playing */
796
scd.regs[0x36>>1].byte.h = 0x01;
797
798
/* update status (RS1-RS8 ignored) */
799
cdd.status = CD_OPEN;
800
scd.regs[0x38>>1].w = CD_OPEN << 8;
801
scd.regs[0x3a>>1].w = 0x0000;
802
scd.regs[0x3c>>1].w = 0x0000;
803
scd.regs[0x3e>>1].w = 0x0000;
804
scd.regs[0x40>>1].w = ~CD_OPEN & 0x0f;
805
806
#ifdef CD_TRAY_CALLBACK
807
CD_TRAY_CALLBACK
808
#endif
809
return;
810
}
811
812
default: /* Unknown command */
813
#ifdef LOG_CDD
814
error("Unknown CDD Command !!!\n");
815
#endif
816
scd.regs[0x38>>1].byte.h = cdd.status;
817
break;
818
}
819
820
/* only compute checksum when necessary */
821
scd.regs[0x40>>1].byte.l = ~(scd.regs[0x38>>1].byte.h + scd.regs[0x38>>1].byte.l +
822
scd.regs[0x3a>>1].byte.h + scd.regs[0x3a>>1].byte.l +
823
scd.regs[0x3c>>1].byte.h + scd.regs[0x3c>>1].byte.l +
824
scd.regs[0x3e>>1].byte.h + scd.regs[0x3e>>1].byte.l +
825
scd.regs[0x40>>1].byte.h) & 0x0f;
826
}
827
828