1 /***************************************************************************************
3 * CD drive processor & CD-DA fader
5 * Copyright (C) 2012-2013 Eke-Eke (Genesis Plus GX)
7 * Redistribution and use of this code or any derivative works are permitted
8 * provided that the following conditions are met:
10 * - Redistributions may not be sold, nor may they be used in a commercial
11 * product or activity.
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.
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.
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.
37 ****************************************************************************************/
39 #include "../pico_int.h"
40 #include "genplus_macros.h"
45 #define SUPPORTED_EXT 20
47 #define SUPPORTED_EXT 10
52 #define is_audio(index) \
53 (cdd.toc.tracks[index].type & CT_AUDIO)
55 /* BCD conversion lookup tables */
56 static const uint8 lut_BCD_8[100] =
58 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
59 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19,
60 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29,
61 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
62 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
63 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
64 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
65 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
66 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
67 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99,
70 static const uint16 lut_BCD_16[100] =
72 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009,
73 0x0100, 0x0101, 0x0102, 0x0103, 0x0104, 0x0105, 0x0106, 0x0107, 0x0108, 0x0109,
74 0x0200, 0x0201, 0x0202, 0x0203, 0x0204, 0x0205, 0x0206, 0x0207, 0x0208, 0x0209,
75 0x0300, 0x0301, 0x0302, 0x0303, 0x0304, 0x0305, 0x0306, 0x0307, 0x0308, 0x0309,
76 0x0400, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0406, 0x0407, 0x0408, 0x0409,
77 0x0500, 0x0501, 0x0502, 0x0503, 0x0504, 0x0505, 0x0506, 0x0507, 0x0508, 0x0509,
78 0x0600, 0x0601, 0x0602, 0x0603, 0x0604, 0x0605, 0x0606, 0x0607, 0x0608, 0x0609,
79 0x0700, 0x0701, 0x0702, 0x0703, 0x0704, 0x0705, 0x0706, 0x0707, 0x0708, 0x0709,
80 0x0800, 0x0801, 0x0802, 0x0803, 0x0804, 0x0805, 0x0806, 0x0807, 0x0808, 0x0809,
81 0x0900, 0x0901, 0x0902, 0x0903, 0x0904, 0x0905, 0x0906, 0x0907, 0x0908, 0x0909,
85 static const uint16 toc_snatcher[21] =
87 56014, 495, 10120, 20555, 1580, 5417, 12502, 16090, 6553, 9681,
88 8148, 20228, 8622, 6142, 5858, 1287, 7424, 3535, 31697, 2485,
92 static const uint16 toc_lunar[52] =
94 5422, 1057, 7932, 5401, 6380, 6592, 5862, 5937, 5478, 5870,
95 6673, 6613, 6429, 4996, 4977, 5657, 3720, 5892, 3140, 3263,
96 6351, 5187, 3249, 1464, 1596, 1750, 1751, 6599, 4578, 5205,
97 1550, 1827, 2328, 1346, 1569, 1613, 7199, 4928, 1656, 2549,
98 1875, 3901, 1850, 2399, 2028, 1724, 4889, 14551, 1184, 2132,
102 static const uint32 toc_shadow[15] =
104 10226, 70054, 11100, 12532, 12444, 11923, 10059, 10167, 10138, 13792,
105 11637, 2547, 2521, 3856, 900
108 static const uint32 toc_dungeon[13] =
110 2250, 22950, 16350, 24900, 13875, 19950, 13800, 15375, 17400, 17100,
114 static const uint32 toc_ffight[26] =
116 11994, 9742, 10136, 9685, 9553, 14588, 9430, 8721, 9975, 9764,
117 9704, 12796, 585, 754, 951, 624, 9047, 1068, 817, 9191, 1024,
118 14562, 10320, 8627, 3795, 3047
121 static const uint32 toc_ffightj[29] =
123 11994, 9752, 10119, 9690, 9567, 14575, 9431, 8731, 9965, 9763,
124 9716, 12791, 579, 751, 958, 630, 9050, 1052, 825, 9193, 1026,
125 14553, 9834, 10542, 1699, 1792, 1781, 3783, 3052
129 /* supported WAVE file header (16-bit stereo samples @44.1kHz) */
130 static const unsigned char waveHeader[32] =
132 0x57,0x41,0x56,0x45,0x66,0x6d,0x74,0x20,0x10,0x00,0x00,0x00,0x01,0x00,0x02,0x00,
133 0x44,0xac,0x00,0x00,0x10,0xb1,0x02,0x00,0x04,0x00,0x10,0x00,0x64,0x61,0x74,0x61
138 #ifdef DISABLE_MANY_OGG_OPEN_FILES
139 static void ogg_free(int i)
141 /* clear OGG file descriptor to prevent file from being closed */
142 cdd.toc.tracks[i].vf.datasource = NULL;
144 /* close VORBIS file structure */
145 ov_clear(&cdd.toc.tracks[i].vf);
147 /* indicates that the track is a seekable VORBIS file */
148 cdd.toc.tracks[i].vf.seekable = 1;
150 /* reset file reading position */
151 fseek(cdd.toc.tracks[i].fd, 0, SEEK_SET);
156 static off_t read_pos = -1;
160 /* stop audio streaming */
161 Pico_mcd->cdda_stream = NULL;
163 /* reset cycle counter */
166 /* reset drive access latency */
169 /* reset track index */
172 /* reset logical block address */
176 cdd.status = NO_DISC;
178 /* reset CD-DA fader (full volume) */
181 /* clear CD-DA output */
182 cdd.audio[0] = cdd.audio[1] = 0;
184 /* no audio track playing */
185 Pico_mcd->s68k_regs[0x36+0] = 0x01;
186 /* reset file read position */
190 /* FIXME: use cdd_read_audio() instead */
191 void cdd_play_audio(int index, int lba)
193 int i, base, lba_offset, lb_len;
195 for (i = index; i >= 0; i--)
196 if (cdd.toc.tracks[i].fd != NULL)
198 // prevent playing from file with binary track if MD+ (Doom Fusion)
199 // TODO: this doesn't cover all tracks being in a single bin file properly:
200 // in that case, fd should be duplicated to work properly with this MD+ shit.
201 if (! is_audio(index) || (read_pos >= 0 && cdd.index == i && ! is_audio(i)))
204 Pico_mcd->cdda_stream = cdd.toc.tracks[i].fd;
205 Pico_mcd->cdda_type = cdd.toc.tracks[i].type;
206 base = cdd.toc.tracks[index].offset;
207 lba_offset = lba - cdd.toc.tracks[index].start;
208 lb_len = cdd.toc.tracks[index].end - cdd.toc.tracks[index].start;
210 elprintf(EL_CD, "play #%d lba %d base %d", index, lba, base);
212 cdda_start_play(base, lba_offset, lb_len);
215 static void cdd_seek(int index, int lba)
218 #ifdef DISABLE_MANY_OGG_OPEN_FILES
219 /* close previous track VORBIS file structure to save memory */
220 if (is_audio(cdd.index) && cdd.toc.tracks[cdd.index].vf.datasource)
225 /* open current track VORBIS file */
226 if (is_audio(index) && cdd.toc.tracks[index].vf.seekable)
228 ov_open(cdd.toc.tracks[index].fd,&cdd.toc.tracks[index].vf,0,0);
233 /* update current track index and LBA */
234 cdd.index = (index < 0 ? 0 : index);
236 if (index < 0) return;
238 /* stay within track limits when seeking files */
239 if (lba < cdd.toc.tracks[cdd.index].start)
241 lba = cdd.toc.tracks[cdd.index].start;
244 /* seek to current block */
245 if (!is_audio(cdd.index))
248 read_pos = lba * cdd.sectorSize;
249 pm_seek(cdd.toc.tracks[cdd.index].fd, read_pos, SEEK_SET);
252 else if (cdd.toc.tracks[cdd.index].vf.seekable)
254 /* VORBIS AUDIO track */
255 ov_pcm_seek(&cdd.toc.tracks[cdd.index].vf, (lba - cdd.toc.tracks[cdd.index].start) * 588 - cdd.toc.tracks[cdd.index].offset);
259 else if (cdd.toc.tracks[cdd.index].fd)
261 /* PCM AUDIO track */
262 fseek(cdd.toc.tracks[cdd.index].fd, (lba * 2352) - cdd.toc.tracks[cdd.index].offset, SEEK_SET);
267 cdd_play_audio(cdd.index, lba);
272 int cdd_context_save(uint8 *state)
276 save_param(&cdd.cycles, sizeof(cdd.cycles));
277 save_param(&cdd.latency, sizeof(cdd.latency));
278 save_param(&cdd.index, sizeof(cdd.index));
279 save_param(&cdd.lba, sizeof(cdd.lba));
280 save_param(&cdd.scanOffset, sizeof(cdd.scanOffset));
281 save_param(&cdd.volume, sizeof(cdd.volume));
282 save_param(&cdd.status, sizeof(cdd.status));
287 int cdd_context_load(uint8 *state)
291 load_param(&cdd.cycles, sizeof(cdd.cycles));
292 load_param(&cdd.latency, sizeof(cdd.latency));
293 load_param(&cdd.index, sizeof(cdd.index));
294 load_param(&cdd.lba, sizeof(cdd.lba));
295 load_param(&cdd.scanOffset, sizeof(cdd.scanOffset));
296 load_param(&cdd.volume, sizeof(cdd.volume));
297 load_param(&cdd.status, sizeof(cdd.status));
299 /* seek to current track position */
300 cdd_seek(cdd.index, cdd.lba);
305 int cdd_context_load_old(uint8 *state)
307 memcpy(&cdd.lba, state + 8, sizeof(cdd.lba));
308 cdd_seek(cdd.index, cdd.lba);
313 int cdd_load(const char *filename, int type)
318 /* first unmount any loaded disc */
321 /* genplus parses cue here, in PD we use our own parser */
322 ret = load_cd_image(filename, &type);
326 if (type == CT_ISO) {
327 /* ISO format (2048 bytes data blocks) */
328 cdd.sectorSize = 2048;
330 /* audio or BIN format (2352 bytes data blocks) */
331 cdd.sectorSize = 2352;
334 /* read first 16 bytes */
335 pm_read(header, 0x10, cdd.toc.tracks[0].fd);
337 /* look for valid CD image ID string */
338 if (!Pico.romsize && memcmp("SEGADISCSYSTEM", header, 14))
340 /* if not found, read next 16 bytes */
341 pm_read(header, 0x10, cdd.toc.tracks[0].fd);
343 /* look again for valid CD image ID string */
344 if (memcmp("SEGADISCSYSTEM", header, 14))
346 elprintf(EL_STATUS|EL_ANOMALY, "cd: bad cd image?");
347 /* assume bin without security code */
351 pm_sectorsize(cdd.sectorSize, cdd.toc.tracks[0].fd);
353 /* Simulate audio tracks if none found */
354 if (!Pico.romsize && cdd.toc.last == 1)
356 /* read CD image header + security code */
357 pm_read(header + 0x10, 0x200, cdd.toc.tracks[0].fd);
359 /* Some games require exact TOC infos */
360 if (strstr(header + 0x180,"T-95035") != NULL)
363 cdd.toc.last = cdd.toc.end = 0;
366 cdd.toc.tracks[cdd.toc.last].start = cdd.toc.end;
367 cdd.toc.tracks[cdd.toc.last].end = cdd.toc.tracks[cdd.toc.last].start + toc_snatcher[cdd.toc.last];
368 cdd.toc.end = cdd.toc.tracks[cdd.toc.last].end;
371 while (cdd.toc.last < 21);
373 else if (strstr(header + 0x180,"T-127015") != NULL)
375 /* Lunar - The Silver Star */
376 cdd.toc.last = cdd.toc.end = 0;
379 cdd.toc.tracks[cdd.toc.last].start = cdd.toc.end;
380 cdd.toc.tracks[cdd.toc.last].end = cdd.toc.tracks[cdd.toc.last].start + toc_lunar[cdd.toc.last];
381 cdd.toc.end = cdd.toc.tracks[cdd.toc.last].end;
384 while (cdd.toc.last < 52);
386 else if (strstr(header + 0x180,"T-113045") != NULL)
388 /* Shadow of the Beast II */
389 cdd.toc.last = cdd.toc.end = 0;
392 cdd.toc.tracks[cdd.toc.last].start = cdd.toc.end;
393 cdd.toc.tracks[cdd.toc.last].end = cdd.toc.tracks[cdd.toc.last].start + toc_shadow[cdd.toc.last];
394 cdd.toc.end = cdd.toc.tracks[cdd.toc.last].end;
397 while (cdd.toc.last < 15);
399 else if (strstr(header + 0x180,"T-143025") != NULL)
401 /* Dungeon Explorer */
402 cdd.toc.last = cdd.toc.end = 0;
405 cdd.toc.tracks[cdd.toc.last].start = cdd.toc.end;
406 cdd.toc.tracks[cdd.toc.last].end = cdd.toc.tracks[cdd.toc.last].start + toc_dungeon[cdd.toc.last];
407 cdd.toc.end = cdd.toc.tracks[cdd.toc.last].end;
410 while (cdd.toc.last < 13);
412 else if (strstr(header + 0x180,"MK-4410") != NULL)
414 /* Final Fight CD (USA, Europe) */
415 cdd.toc.last = cdd.toc.end = 0;
418 cdd.toc.tracks[cdd.toc.last].start = cdd.toc.end;
419 cdd.toc.tracks[cdd.toc.last].end = cdd.toc.tracks[cdd.toc.last].start + toc_ffight[cdd.toc.last];
420 cdd.toc.end = cdd.toc.tracks[cdd.toc.last].end;
423 while (cdd.toc.last < 26);
425 else if (strstr(header + 0x180,"G-6013") != NULL)
427 /* Final Fight CD (Japan) */
428 cdd.toc.last = cdd.toc.end = 0;
431 cdd.toc.tracks[cdd.toc.last].start = cdd.toc.end;
432 cdd.toc.tracks[cdd.toc.last].end = cdd.toc.tracks[cdd.toc.last].start + toc_ffightj[cdd.toc.last];
433 cdd.toc.end = cdd.toc.tracks[cdd.toc.last].end;
436 while (cdd.toc.last < 29);
441 /* default TOC (99 tracks & 2s per audio tracks) */
444 cdd.toc.tracks[cdd.toc.last].start = cdd.toc.end + 2*75;
445 cdd.toc.tracks[cdd.toc.last].end = cdd.toc.tracks[cdd.toc.last].start + 2*75;
446 cdd.toc.end = cdd.toc.tracks[cdd.toc.last].end;
449 while ((cdd.toc.last < 99) && (cdd.toc.end < 56*60*75));
455 cdd.toc.tracks[cdd.toc.last].start = cdd.toc.end;
460 /* disc not scanned yet */
461 cdd.status = NO_DISC;
468 int was_loaded = cdd.loaded;
474 /* stop audio streaming */
475 if (Pico_mcd) Pico_mcd->cdda_stream = NULL;
477 /* close CD tracks */
478 if (cdd.toc.tracks[0].fd)
480 pm_close(cdd.toc.tracks[0].fd);
481 cdd.toc.tracks[0].fd = NULL;
482 if (cdd.toc.tracks[0].fname)
483 free(cdd.toc.tracks[0].fname);
484 cdd.toc.tracks[0].fname = NULL;
487 for (i = 1; i < cdd.toc.last; i++)
490 if (cdd.toc.tracks[i].vf.datasource)
492 /* close VORBIS file (if still opened) */
493 ov_clear(&cdd.toc.tracks[i].vf);
497 if (cdd.toc.tracks[i].fd)
500 if (cdd.toc.tracks[i].type == CT_MP3)
501 fclose(cdd.toc.tracks[i].fd);
503 pm_close(cdd.toc.tracks[i].fd);
504 cdd.toc.tracks[i].fd = NULL;
505 if (cdd.toc.tracks[i].fname)
506 free(cdd.toc.tracks[i].fname);
507 cdd.toc.tracks[i].fname = NULL;
509 /* detect single file images */
510 if (cdd.toc.tracks[i+1].fd == cdd.toc.tracks[i].fd)
521 if (cdd.status != CD_OPEN)
522 cdd.status = NO_DISC;
526 memset(&cdd.toc, 0x00, sizeof(cdd.toc));
528 /* unknown CD image file format */
534 void cdd_read_data(uint8 *dst)
536 /* only read DATA track sectors */
537 if (!is_audio(cdd.index) && (cdd.lba >= cdd.toc.tracks[cdd.index].start) &&
538 (cdd.lba < cdd.toc.tracks[cdd.index].end))
543 if (cdd.sectorSize == 2352)
545 /* skip 16-byte header */
546 pos = cdd.lba * 2352 + 16;
550 pos = cdd.lba * cdd.sectorSize;
553 if (pos != read_pos) {
554 pm_seek(cdd.toc.tracks[cdd.index].fd, pos, SEEK_SET);
558 /* read sector data (Mode 1 = 2048 bytes) */
559 read_pos += pm_read(dst, 2048, cdd.toc.tracks[cdd.index].fd);
564 void cdd_read_audio(unsigned int samples)
566 /* previous audio outputs */
567 int16 l = cdd.audio[0];
568 int16 r = cdd.audio[1];
570 /* get number of internal clocks (samples) needed */
571 samples = blip_clocks_needed(blip[0], samples);
573 /* audio track playing ? */
574 if (!Pico_mcd->s68k_regs[0x36+0] && cdd.toc.tracks[cdd.index].fd)
578 /* current CD-DA fader volume */
579 int curVol = cdd.volume;
581 /* CD-DA fader volume setup (0-1024) */
582 int endVol = Pico_mcd->regs[0x34>>1].w >> 4;
584 /* read samples from current block */
586 if (cdd.toc.tracks[cdd.index].vf.datasource)
589 int16 *ptr = (int16 *) (cdc.ram);
590 samples = samples * 4;
591 while (done < samples)
593 len = ov_read(&cdd.toc.tracks[cdd.index].vf, (char *)(cdc.ram + done), samples - done, 0);
603 /* process 16-bit (host-endian) stereo samples */
604 for (i=0; i<samples; i++)
606 /* CD-DA fader multiplier (cf. LC7883 datasheet) */
607 /* (MIN) 0,1,2,3,4,8,12,16,20...,1020,1024 (MAX) */
608 mul = (curVol & 0x7fc) ? (curVol & 0x7fc) : (curVol & 0x03);
611 delta = ((ptr[0] * mul) / 1024) - l;
614 blip_add_delta_fast(blip[0], i, delta);
617 delta = ((ptr[0] * mul) / 1024) - r;
620 blip_add_delta_fast(blip[1], i, delta);
622 /* update CD-DA fader volume (one step/sample) */
628 else if (curVol > endVol)
635 /* audio will remain muted until next setup */
644 int16 *ptr = (int16 *) (cdc.ram);
646 uint8 *ptr = cdc.ram;
648 fread(cdc.ram, 1, samples * 4, cdd.toc.tracks[cdd.index].fd);
650 /* process 16-bit (little-endian) stereo samples */
651 for (i=0; i<samples; i++)
653 /* CD-DA fader multiplier (cf. LC7883 datasheet) */
654 /* (MIN) 0,1,2,3,4,8,12,16,20...,1020,1024 (MAX) */
655 mul = (curVol & 0x7fc) ? (curVol & 0x7fc) : (curVol & 0x03);
659 delta = ((ptr[0] * mul) / 1024) - l;
662 delta = (((int16)((ptr[0] + ptr[1]*256)) * mul) / 1024) - l;
666 blip_add_delta_fast(blip[0], i, delta);
670 delta = ((ptr[0] * mul) / 1024) - r;
673 delta = (((int16)((ptr[0] + ptr[1]*256)) * mul) / 1024) - r;
677 blip_add_delta_fast(blip[1], i, delta);
679 /* update CD-DA fader volume (one step/sample) */
685 else if (curVol > endVol)
692 /* audio will remain muted until next setup */
698 /* save current CD-DA fader volume */
701 /* save last audio output for next frame */
707 /* no audio output */
708 if (l) blip_add_delta_fast(blip[0], 0, -l);
709 if (r) blip_add_delta_fast(blip[1], 0, -r);
711 /* save audio output for next frame */
716 /* end of Blip Buffer timeframe */
717 blip_end_frame(blip[0], samples);
718 blip_end_frame(blip[1], samples);
723 void cdd_update(void)
726 error("LBA = %d (track n°%d)(latency=%d)\n", cdd.lba, cdd.index, cdd.latency);
729 /* update decoder, depending on track type */
730 if (cdd.status == CD_PLAY && !is_audio(cdd.index) && !cdd.latency)
732 /* DATA sector header (CD-ROM Mode 1) */
734 uint32 msf = cdd.lba + 150;
735 header[0] = lut_BCD_8[(msf / 75) / 60];
736 header[1] = lut_BCD_8[(msf / 75) % 60];
737 header[2] = lut_BCD_8[(msf % 75)];
740 /* data track sector read is controlled by CDC */
741 cdc_decoder_update(header);
745 uint8 header[4] = { 0, };
747 /* audio blocks are still sent to CDC as well as CD DAC/Fader */
748 cdc_decoder_update(header);
751 if (Pico_mcd->m.state_flags & PCD_ST_CDD_CMD) {
752 /* pending delayed command */
754 Pico_mcd->m.state_flags &= ~PCD_ST_CDD_CMD;
765 if (cdd.status == CD_PLAY)
767 if (cdd.index >= cdd.toc.last)
774 /* check against audio track start index */
775 if (is_audio(cdd.index) && cdd.lba >= cdd.toc.tracks[cdd.index].start)
777 /* audio track playing */
778 Pico_mcd->s68k_regs[0x36+0] = 0x00;
781 /* next block is automatically read */
784 /* check end of current track */
785 if (cdd.lba >= cdd.toc.tracks[cdd.index].end)
787 /* PAUSE between tracks */
788 Pico_mcd->s68k_regs[0x36+0] = 0x01;
790 /* seek to next audio track start */
791 cdd_seek(cdd.index + 1, cdd.lba);
796 else if (cdd.status == CD_SCAN)
798 /* fast-forward or fast-rewind */
799 cdd.lba += cdd.scanOffset;
801 /* check current track limits */
802 if (cdd.lba >= cdd.toc.tracks[cdd.index].end)
805 if (cdd.index >= cdd.toc.last)
807 /* no AUDIO track playing */
808 Pico_mcd->s68k_regs[0x36+0] = 0x01;
811 cdd.lba = cdd.toc.end;
816 cdd_seek(cdd.index + 1, cdd.toc.tracks[cdd.index+1].start);
818 /* AUDIO track playing ? */
819 if (cdd.status == CD_PLAY && is_audio(cdd.index))
821 Pico_mcd->s68k_regs[0x36+0] = 0x00;
825 else if (cdd.lba < cdd.toc.tracks[cdd.index].start)
834 cdd_seek(cdd.index - 1, cdd.toc.tracks[cdd.index-1].end);
838 if (!is_audio(cdd.index))
840 /* no AUDIO track playing */
841 Pico_mcd->s68k_regs[0x36+0] = 0x01;
846 #define set_reg16(r, v) { \
848 Pico_mcd->s68k_regs[(r)] = _v >> 8; \
849 Pico_mcd->s68k_regs[(r)+1] = _v; \
852 void cdd_process(void)
854 /* Process CDD command */
855 switch (Pico_mcd->s68k_regs[0x42+0] & 0x0f)
857 case 0x00: /* Drive Status */
859 if (cdd.latency == 0) {
860 /* RS1-RS8 normally unchanged */
861 Pico_mcd->s68k_regs[0x38+0] = cdd.status;
863 /* unless RS1 indicated invalid track infos */
864 if (Pico_mcd->s68k_regs[0x38+1] == 0x0f ||
865 Pico_mcd->s68k_regs[0x38+1] == 0x00 ||
866 Pico_mcd->s68k_regs[0x38+1] == 0x01)
868 int lba = cdd.lba + 150 - cdd.latency;
869 if (Pico_mcd->s68k_regs[0x38+1] == 0x01)
870 lba = abs(cdd.lba - cdd.toc.tracks[cdd.index].start);
871 if (Pico_mcd->s68k_regs[0x38+1] == 0x0f)
872 Pico_mcd->s68k_regs[0x38+1] = 0x00;
873 set_reg16(0x3a, lut_BCD_16[(lba/75)/60]);
874 set_reg16(0x3c, lut_BCD_16[(lba/75)%60]);
875 set_reg16(0x3e, lut_BCD_16[(lba%75)]);
876 Pico_mcd->s68k_regs[0x40+0] = is_audio(cdd.index) ? 0x00 : 0x04;
877 } else if (Pico_mcd->s68k_regs[0x38+1] == 0x02) {
878 /* then return valid track infos, e.g current track number in RS2-RS3 (fixes Lunar - The Silver Star) */
879 Pico_mcd->s68k_regs[0x38+1] = 0x02;
880 set_reg16(0x3a, (cdd.index < cdd.toc.last) ? lut_BCD_16[cdd.index + 1] : 0x0A0A);
886 case 0x01: /* Stop Drive */
889 cdd.status = cdd.loaded ? CD_STOP : NO_DISC;
891 /* no audio track playing */
892 Pico_mcd->s68k_regs[0x36+0] = 0x01;
894 /* RS1-RS8 ignored, expects 0x0 ("no disc" ?) in RS0 once */
895 set_reg16(0x38, 0x0000);
896 set_reg16(0x3a, 0x0000);
897 set_reg16(0x3c, 0x0000);
898 set_reg16(0x3e, 0x0000);
899 set_reg16(0x40, 0x000f);
901 /* reset to 1st track */
906 case 0x02: /* Read TOC */
908 if (cdd.status == NO_DISC)
909 cdd.status = cdd.loaded ? CD_STOP : NO_DISC;
911 /* Infos automatically retrieved by CDD processor from Q-Channel */
912 /* commands 0x00-0x02 (current block) and 0x03-0x05 (Lead-In) */
913 switch (Pico_mcd->s68k_regs[0x44+1])
915 case 0x00: /* Current Absolute Time (MM:SS:FF) */
917 int lba = cdd.lba + 150;
918 set_reg16(0x38, cdd.status << 8);
919 set_reg16(0x3a, lut_BCD_16[(lba/75)/60]);
920 set_reg16(0x3c, lut_BCD_16[(lba/75)%60]);
921 set_reg16(0x3e, lut_BCD_16[(lba%75)]);
922 Pico_mcd->s68k_regs[0x40+0] = is_audio(cdd.index) ? 0x00 : 0x04; /* Current block flags in RS8 (bit0 = mute status, bit1: pre-emphasis status, bit2: track type) */
926 case 0x01: /* Current Track Relative Time (MM:SS:FF) */
928 int lba = cdd.lba - cdd.toc.tracks[cdd.index].start;
929 if (lba < 0) lba = 0;
930 set_reg16(0x38, (cdd.status << 8) | 0x01);
931 set_reg16(0x3a, lut_BCD_16[(lba/75)/60]);
932 set_reg16(0x3c, lut_BCD_16[(lba/75)%60]);
933 set_reg16(0x3e, lut_BCD_16[(lba%75)]);
934 Pico_mcd->s68k_regs[0x40+0] = is_audio(cdd.index) ? 0x00 : 0x04; /* Current block flags in RS8 (bit0 = mute status, bit1: pre-emphasis status, bit2: track type) */
938 case 0x02: /* Current Track Number */
940 set_reg16(0x38, (cdd.status << 8) | 0x02);
941 set_reg16(0x3a, (cdd.index < cdd.toc.last) ? lut_BCD_16[cdd.index + 1] : 0x0A0A);
942 set_reg16(0x3c, 0x0000);
943 set_reg16(0x3e, 0x0000); /* Disk Control Code (?) in RS6 */
944 Pico_mcd->s68k_regs[0x40+0] = 0x00;
948 case 0x03: /* Total length (MM:SS:FF) */
950 int lba = cdd.toc.end + 150;
951 set_reg16(0x38, (cdd.status << 8) | 0x03);
952 set_reg16(0x3a, lut_BCD_16[(lba/75)/60]);
953 set_reg16(0x3c, lut_BCD_16[(lba/75)%60]);
954 set_reg16(0x3e, lut_BCD_16[(lba%75)]);
955 Pico_mcd->s68k_regs[0x40+0] = 0x00;
959 case 0x04: /* First & Last Track Numbers */
961 set_reg16(0x38, (cdd.status << 8) | 0x04);
962 set_reg16(0x3a, 0x0001);
963 set_reg16(0x3c, lut_BCD_16[cdd.toc.last]);
964 set_reg16(0x3e, 0x0000); /* Drive Version (?) in RS6-RS7 */
965 Pico_mcd->s68k_regs[0x40+0] = 0x00; /* Lead-In flags in RS8 (bit0 = mute status, bit1: pre-emphasis status, bit2: track type) */
969 case 0x05: /* Track Start Time (MM:SS:FF) */
971 int track = Pico_mcd->s68k_regs[0x46+0] * 10 + Pico_mcd->s68k_regs[0x46+1];
972 int lba = cdd.toc.tracks[track-1].start + 150;
973 set_reg16(0x38, (cdd.status << 8) | 0x05);
974 set_reg16(0x3a, lut_BCD_16[(lba/75)/60]);
975 set_reg16(0x3c, lut_BCD_16[(lba/75)%60]);
976 set_reg16(0x3e, lut_BCD_16[(lba%75)]);
977 Pico_mcd->s68k_regs[0x40+0] = track % 10; /* Track Number (low digit) */
980 /* RS6 bit 3 is set for the first (DATA) track */
981 Pico_mcd->s68k_regs[0x3e + 0] |= 0x08;
986 case 0x06: /* Latest Error Information */
988 set_reg16(0x38, (cdd.status << 8) | 0x06);
989 set_reg16(0x3a, 0x0000);
990 set_reg16(0x3c, 0x0000);
991 set_reg16(0x3e, 0x0000);
992 Pico_mcd->s68k_regs[0x40+0] = 0x00;
999 error("Unknown CDD Command %02X (%X)\n", Pico_mcd->s68k_regs[0x44+1], s68k.pc);
1007 case 0x03: /* Play */
1009 /* reset track index */
1012 /* new LBA position */
1013 int lba = ((Pico_mcd->s68k_regs[0x44+0] * 10 + Pico_mcd->s68k_regs[0x44+1]) * 60 +
1014 (Pico_mcd->s68k_regs[0x46+0] * 10 + Pico_mcd->s68k_regs[0x46+1])) * 75 +
1015 (Pico_mcd->s68k_regs[0x48+0] * 10 + Pico_mcd->s68k_regs[0x48+1]) - 150;
1017 /* return track index in RS2-RS3 */
1018 set_reg16(0x38, (CD_SEEK << 8) | 0x0f);
1019 set_reg16(0x3a, 0x0000);
1020 set_reg16(0x3c, 0x0000);
1021 set_reg16(0x3e, 0x0000);
1022 set_reg16(0x40, ~(CD_SEEK + 0xf) & 0x0f);
1024 /* seek delayed by max 2 blocks before the seek starts */
1025 if (!(Pico_mcd->m.state_flags & PCD_ST_CDD_CMD)) {
1026 Pico_mcd->m.state_flags |= PCD_ST_CDD_CMD;
1030 /* CD drive latency */
1033 /* Fixes a few games hanging during intro because they expect data to be read with some delay */
1034 /* Radical Rex needs at least one interrupt delay */
1035 /* Wolf Team games (Anet Futatabi, Cobra Command, Road Avenger & Time Gal) need at least 6 interrupts delay */
1036 /* Space Adventure Cobra (2nd morgue scene) needs at least 13 interrupts delay (incl. seek time, so 6 is OK) */
1037 /* Jeopardy & ESPN Sunday Night NFL are picky about this as well: 10 interrupts delay (+ seek time) seems OK */
1041 /* CD drive seek time */
1042 /* max. seek time = 1.5 s = 1.5 x 75 = 112.5 CDD interrupts (rounded to 120) for 270000 sectors max on disc. */
1043 /* Note: This is only a rough approximation since, on real hardware, seek time is much likely not linear and */
1044 /* latency much larger than above value, but this model works fine for Sonic CD (track 26 playback needs to */
1045 /* be enough delayed to start in sync with intro sequence, as compared with real hardware recording). */
1048 cdd.latency += (((lba - cdd.lba) * 120) / 270000);
1052 cdd.latency += (((cdd.lba - lba) * 120) / 270000);
1055 /* get track index */
1056 while ((cdd.toc.tracks[index].end <= lba) && (index < cdd.toc.last)) index++;
1058 /* seek to block; playing always starts 3 blocks earlier */
1059 cdd_seek(index, lba - 3);
1061 /* no audio track playing (yet) */
1062 Pico_mcd->s68k_regs[0x36+0] = 0x01;
1065 cdd.status = CD_PLAY;
1070 case 0x04: /* Seek */
1072 /* reset track index */
1075 /* new LBA position */
1076 int lba = ((Pico_mcd->s68k_regs[0x44+0] * 10 + Pico_mcd->s68k_regs[0x44+1]) * 60 +
1077 (Pico_mcd->s68k_regs[0x46+0] * 10 + Pico_mcd->s68k_regs[0x46+1])) * 75 +
1078 (Pico_mcd->s68k_regs[0x48+0] * 10 + Pico_mcd->s68k_regs[0x48+1]) - 150;
1080 /* 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) */
1081 set_reg16(0x38, (CD_SEEK << 8) | 0x0f);
1082 set_reg16(0x3a, 0x0000);
1083 set_reg16(0x3c, 0x0000);
1084 set_reg16(0x3e, 0x0000);
1085 set_reg16(0x40, ~(CD_SEEK + 0xf) & 0x0f);
1087 /* seek delayed by max 2 blocks before the seek starts */
1088 if (!(Pico_mcd->m.state_flags & PCD_ST_CDD_CMD)) {
1089 Pico_mcd->m.state_flags |= PCD_ST_CDD_CMD;
1093 /* CD drive seek time */
1094 /* We are using similar linear model as above, although still not exactly accurate, */
1095 /* it works fine for Switch/Panic! intro (Switch needs at least 30 interrupts while */
1096 /* seeking from 00:05:63 to 24:03:19, Panic! when seeking from 00:05:60 to 24:06:07) */
1099 cdd.latency = ((lba - cdd.lba) * 120) / 270000;
1103 cdd.latency = ((cdd.lba - lba) * 120) / 270000;
1106 /* get track index */
1107 while ((cdd.toc.tracks[index].end <= lba) && (index < cdd.toc.last)) index++;
1109 /* seek to block; playing always starts 3 blocks earlier */
1110 cdd_seek(index, lba - 3);
1112 /* no audio track playing */
1113 Pico_mcd->s68k_regs[0x36+0] = 0x01;
1116 cdd.status = CD_READY;
1121 case 0x06: /* Pause */
1123 /* update status (RS1-RS8 unchanged) */
1124 cdd.status = Pico_mcd->s68k_regs[0x38+0] = CD_READY;
1126 /* no audio track playing */
1127 Pico_mcd->s68k_regs[0x36+0] = 0x01;
1132 case 0x07: /* Resume */
1134 /* update status (RS1-RS8 unchanged) */
1135 cdd.status = Pico_mcd->s68k_regs[0x38+0] = CD_PLAY;
1139 case 0x08: /* Forward Scan */
1141 /* reset scanning direction / speed */
1142 cdd.scanOffset = CD_SCAN_SPEED;
1144 /* update status (RS1-RS8 unchanged) */
1145 cdd.status = Pico_mcd->s68k_regs[0x38+0] = CD_SCAN;
1149 case 0x09: /* Rewind Scan */
1151 /* reset scanning direction / speed */
1152 cdd.scanOffset = -CD_SCAN_SPEED;
1154 /* update status (RS1-RS8 unchanged) */
1155 cdd.status = Pico_mcd->s68k_regs[0x38+0] = CD_SCAN;
1160 case 0x0a: /* N-Track Jump Control ? (usually sent before CD_SEEK or CD_PLAY commands) */
1162 /* TC3 corresponds to seek direction (00=forward, FF=reverse) */
1163 /* TC4-TC7 are related to seek length (4x4 bits i.e parameter values are between -65535 and +65535) */
1164 /* Maybe related to number of auto-sequenced track jumps/moves for CD DSP (cf. CXD2500BQ datasheet) */
1165 /* also see US Patent nr. 5222054 for a detailled description of seeking operation using Track Jump */
1167 /* no audio track playing */
1168 Pico_mcd->s68k_regs[0x36+0] = 0x01;
1170 /* update status (RS1-RS8 unchanged) */
1171 cdd.status = Pico_mcd->s68k_regs[0x38+0] = CD_READY;
1175 case 0x0c: /* Close Tray */
1177 /* no audio track playing */
1178 Pico_mcd->s68k_regs[0x36+0] = 0x01;
1181 cdd.status = cdd.loaded ? CD_STOP : NO_DISC;
1183 /* RS1-RS8 ignored, expects 0x0 ("no disc" ?) in RS0 once */
1184 set_reg16(0x38, 0x0000);
1185 set_reg16(0x3a, 0x0000);
1186 set_reg16(0x3c, 0x0000);
1187 set_reg16(0x3e, 0x0000);
1188 set_reg16(0x40, 0x000f);
1190 if (PicoIn.mcdTrayClose)
1191 PicoIn.mcdTrayClose();
1196 case 0x0d: /* Open Tray */
1198 /* no audio track playing */
1199 Pico_mcd->s68k_regs[0x36+0] = 0x01;
1201 /* update status (RS1-RS8 ignored) */
1202 cdd.status = CD_OPEN;
1203 set_reg16(0x38, CD_OPEN << 8);
1204 set_reg16(0x3a, 0x0000);
1205 set_reg16(0x3c, 0x0000);
1206 set_reg16(0x3e, 0x0000);
1207 set_reg16(0x40, ~CD_OPEN & 0x0f);
1209 if (PicoIn.mcdTrayOpen)
1210 PicoIn.mcdTrayOpen();
1214 default: /* Unknown command */
1216 error("Unknown CDD Command !!!\n");
1218 Pico_mcd->s68k_regs[0x38+0] = cdd.status;
1222 /* only compute checksum when necessary */
1223 Pico_mcd->s68k_regs[0x40 + 1] =
1224 ~(Pico_mcd->s68k_regs[0x38 + 0] + Pico_mcd->s68k_regs[0x38 + 1] +
1225 Pico_mcd->s68k_regs[0x3a + 0] + Pico_mcd->s68k_regs[0x3a + 1] +
1226 Pico_mcd->s68k_regs[0x3c + 0] + Pico_mcd->s68k_regs[0x3c + 1] +
1227 Pico_mcd->s68k_regs[0x3e + 0] + Pico_mcd->s68k_regs[0x3e + 1] +
1228 Pico_mcd->s68k_regs[0x40 + 0]) & 0x0f;
1231 // vim:shiftwidth=2:ts=2:expandtab