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