a06568bf5abc96a98bf5e9240951a40433546494
[picodrive.git] / pico / cd / cdd.c
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
39 #include "../pico_int.h"
40 #include "genplus_macros.h"
41 #include "cd_parse.h"
42 #include "cdd.h"
43
44 #ifdef USE_LIBTREMOR
45 #define SUPPORTED_EXT 20
46 #else
47 #define SUPPORTED_EXT 10
48 #endif
49
50 cdd_t cdd;
51
52 #define is_audio(index) \
53   (cdd.toc.tracks[index].type & CT_AUDIO)
54
55 /* BCD conversion lookup tables */
56 static const uint8 lut_BCD_8[100] =
57 {
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, 
68 };
69
70 static const uint16 lut_BCD_16[100] =
71 {
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, 
82 };
83
84 /* pre-build TOC */
85 static const uint16 toc_snatcher[21] =
86 {
87   56014,   495, 10120, 20555, 1580, 5417, 12502, 16090,  6553, 9681,
88    8148, 20228,  8622,  6142, 5858, 1287,  7424,  3535, 31697, 2485,
89   31380
90 };
91
92 static const uint16 toc_lunar[52] =
93 {
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,
99   685, 3167
100 };
101
102 static const uint32 toc_shadow[15] =
103 {
104   10226, 70054, 11100, 12532, 12444, 11923, 10059, 10167, 10138, 13792,
105   11637,  2547,  2521,  3856, 900
106 };
107
108 static const uint32 toc_dungeon[13] =
109 {
110   2250, 22950, 16350, 24900, 13875, 19950, 13800, 15375, 17400, 17100,
111   3325,  6825, 25275
112 };
113
114 static const uint32 toc_ffight[26] =
115 {
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
119 };
120
121 static const uint32 toc_ffightj[29] =
122 {
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
126 };
127
128 #if 0
129 /* supported WAVE file header (16-bit stereo samples @44.1kHz) */
130 static const unsigned char waveHeader[32] =
131 {
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
134 };
135 #endif
136
137 #ifdef USE_LIBTREMOR
138 #ifdef DISABLE_MANY_OGG_OPEN_FILES
139 static void ogg_free(int i)
140 {
141   /* clear OGG file descriptor to prevent file from being closed */
142   cdd.toc.tracks[i].vf.datasource = NULL;
143
144   /* close VORBIS file structure */
145   ov_clear(&cdd.toc.tracks[i].vf);
146
147   /* indicates that the track is a seekable VORBIS file */
148   cdd.toc.tracks[i].vf.seekable = 1;
149
150   /* reset file reading position */
151   fseek(cdd.toc.tracks[i].fd, 0, SEEK_SET);
152 }
153 #endif
154 #endif
155
156 static off_t read_pos = -1;
157
158 void cdd_reset(void)
159 {
160   /* stop audio streaming */
161   Pico_mcd->cdda_stream = NULL;
162
163   /* reset cycle counter */
164   cdd.cycles = 0;
165   
166   /* reset drive access latency */
167   cdd.latency = 0;
168   
169   /* reset track index */
170   cdd.index = 0;
171   
172   /* reset logical block address */
173   cdd.lba = 0;
174
175   /* reset status */
176   cdd.status = NO_DISC;
177
178   /* reset CD-DA fader (full volume) */
179   cdd.volume = 0x400;
180
181   /* clear CD-DA output */
182   cdd.audio[0] = cdd.audio[1] = 0;
183
184   /* no audio track playing */
185   Pico_mcd->s68k_regs[0x36+0] = 0x01;
186   /* reset file read position */
187   read_pos = -1;
188 }
189
190 /* FIXME: use cdd_read_audio() instead */
191 void cdd_play_audio(int index, int lba)
192 {
193   int i, base, lba_offset, lb_len;
194
195   for (i = index; i >= 0; i--)
196     if (cdd.toc.tracks[i].fd != NULL)
197       break;
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)))
202     return;
203
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;
209
210   elprintf(EL_CD, "play #%d lba %d base %d", index, lba, base);
211
212   cdda_start_play(base, lba_offset, lb_len);
213 }
214
215 static void cdd_seek(int index, int lba)
216 {
217 #ifdef USE_LIBTREMOR
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)
221   {
222     ogg_free(cdd.index);
223   }
224
225   /* open current track VORBIS file */
226   if (is_audio(index) && cdd.toc.tracks[index].vf.seekable)
227   {
228     ov_open(cdd.toc.tracks[index].fd,&cdd.toc.tracks[index].vf,0,0);
229   }
230 #endif
231 #endif
232
233   /* update current track index and LBA */
234   cdd.index = (index < 0 ? 0 : index);
235   cdd.lba = lba;
236   if (index < 0) return;
237
238   /* stay within track limits when seeking files */
239   if (lba < cdd.toc.tracks[cdd.index].start)
240   {
241     lba = cdd.toc.tracks[cdd.index].start;
242   }
243
244   /* seek to current block */
245   if (!is_audio(cdd.index))
246   {
247     /* DATA track */
248     read_pos = lba * cdd.sectorSize;
249     pm_seek(cdd.toc.tracks[cdd.index].fd, read_pos, SEEK_SET);
250   }
251 #ifdef USE_LIBTREMOR
252   else if (cdd.toc.tracks[cdd.index].vf.seekable)
253   {
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);
256   }
257 #endif
258 #if 0
259   else if (cdd.toc.tracks[cdd.index].fd)
260   {
261     /* PCM AUDIO track */
262     fseek(cdd.toc.tracks[cdd.index].fd, (lba * 2352) - cdd.toc.tracks[cdd.index].offset, SEEK_SET);
263   }
264 #else
265   else
266   {
267     cdd_play_audio(cdd.index, lba);
268   }
269 #endif
270 }
271
272 int cdd_context_save(uint8 *state)
273 {
274   int bufferptr = 0;
275
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));
283
284   return bufferptr;
285 }
286
287 int cdd_context_load(uint8 *state)
288 {
289   int bufferptr = 0;
290
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));
298
299   /* seek to current track position */
300   cdd_seek(cdd.index, cdd.lba);
301
302   return bufferptr;
303 }
304
305 int cdd_context_load_old(uint8 *state)
306 {
307   memcpy(&cdd.lba, state + 8, sizeof(cdd.lba));
308   cdd_seek(cdd.index, cdd.lba);
309
310   return 12 * 4;
311 }
312
313 int cdd_load(const char *filename, int type)
314 {
315   char header[0x210];
316   int ret;
317
318   /* first unmount any loaded disc */
319   cdd_unload();
320
321   /* genplus parses cue here, in PD we use our own parser */
322   ret = load_cd_image(filename, &type);
323   if (ret != 0)
324     return ret;
325
326   if (type == CT_ISO) {
327     /* ISO format (2048 bytes data blocks) */
328     cdd.sectorSize = 2048;
329   } else {
330     /* audio or BIN format (2352 bytes data blocks) */
331     cdd.sectorSize = 2352;
332   }
333
334   /* read first 16 bytes */
335   pm_read(header, 0x10, cdd.toc.tracks[0].fd);
336
337   /* look for valid CD image ID string */
338   if (!Pico.romsize && memcmp("SEGADISCSYSTEM", header, 14))
339   {
340     /* if not found, read next 16 bytes */
341     pm_read(header, 0x10, cdd.toc.tracks[0].fd);
342
343     /* look again for valid CD image ID string */
344     if (memcmp("SEGADISCSYSTEM", header, 14))
345     {
346       elprintf(EL_STATUS|EL_ANOMALY, "cd: bad cd image?");
347       /* assume bin without security code */
348     }
349   }
350
351   pm_sectorsize(cdd.sectorSize, cdd.toc.tracks[0].fd);
352
353   /* Simulate audio tracks if none found */
354   if (!Pico.romsize && cdd.toc.last == 1)
355   {
356     /* read CD image header + security code */
357     pm_read(header + 0x10, 0x200, cdd.toc.tracks[0].fd);
358
359     /* Some games require exact TOC infos */
360     if (strstr(header + 0x180,"T-95035") != NULL)
361     {
362       /* Snatcher */
363       cdd.toc.last = cdd.toc.end = 0;
364       do
365       {
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;
369         cdd.toc.last++;
370       }
371       while (cdd.toc.last < 21);
372     }
373     else if (strstr(header + 0x180,"T-127015") != NULL)
374     {
375       /* Lunar - The Silver Star */
376       cdd.toc.last = cdd.toc.end = 0;
377       do
378       {
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;
382         cdd.toc.last++;
383       }
384       while (cdd.toc.last < 52);
385     }
386     else if (strstr(header + 0x180,"T-113045") != NULL)
387     {
388       /* Shadow of the Beast II */
389       cdd.toc.last = cdd.toc.end = 0;
390       do
391       {
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;
395         cdd.toc.last++;
396       }
397       while (cdd.toc.last < 15);
398     }
399     else if (strstr(header + 0x180,"T-143025") != NULL)
400     {
401       /* Dungeon Explorer */
402       cdd.toc.last = cdd.toc.end = 0;
403       do
404       {
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;
408         cdd.toc.last++;
409       }
410       while (cdd.toc.last < 13);
411     }
412     else if (strstr(header + 0x180,"MK-4410") != NULL)
413     {
414       /* Final Fight CD (USA, Europe) */
415       cdd.toc.last = cdd.toc.end = 0;
416       do
417       {
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;
421         cdd.toc.last++;
422       }
423       while (cdd.toc.last < 26);
424     }
425     else if (strstr(header + 0x180,"G-6013") != NULL)
426     {
427       /* Final Fight CD (Japan) */
428       cdd.toc.last = cdd.toc.end = 0;
429       do
430       {
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;
434         cdd.toc.last++;
435       }
436       while (cdd.toc.last < 29);
437     }
438 #if 0
439     else
440     {
441       /* default TOC (99 tracks & 2s per audio tracks) */
442       do
443       {
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;
447         cdd.toc.last++;
448       }
449       while ((cdd.toc.last < 99) && (cdd.toc.end < 56*60*75));
450     }
451 #endif
452   }
453
454   /* Lead-out */
455   cdd.toc.tracks[cdd.toc.last].start = cdd.toc.end;
456
457   /* CD loaded */
458   cdd.loaded = 1;
459
460   /* disc not scanned yet */
461   cdd.status = NO_DISC;
462
463   return 0;
464 }
465
466 int cdd_unload(void)
467 {
468   int was_loaded = cdd.loaded;
469
470   if (cdd.loaded)
471   {
472     int i;
473
474     /* stop audio streaming */
475     if (Pico_mcd) Pico_mcd->cdda_stream = NULL;
476
477     /* close CD tracks */
478     if (cdd.toc.tracks[0].fd)
479     {
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;
485     }
486
487     for (i = 1; i < cdd.toc.last; i++)
488     {
489 #ifdef USE_LIBTREMOR
490       if (cdd.toc.tracks[i].vf.datasource)
491       {
492         /* close VORBIS file (if still opened) */
493         ov_clear(&cdd.toc.tracks[i].vf);
494       }
495       else
496 #endif
497       if (cdd.toc.tracks[i].fd)
498       {
499         /* close file */
500         if (cdd.toc.tracks[i].type == CT_MP3)
501           fclose(cdd.toc.tracks[i].fd);
502         else
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;
508
509         /* detect single file images */
510         if (cdd.toc.tracks[i+1].fd == cdd.toc.tracks[i].fd)
511         {
512           /* exit loop */
513           i = cdd.toc.last;
514         }
515       }
516     }
517
518     /* CD unloaded */
519     cdd.loaded = 0;
520
521     if (cdd.status != CD_OPEN)
522       cdd.status = NO_DISC;
523   }
524
525   /* reset TOC */
526   memset(&cdd.toc, 0x00, sizeof(cdd.toc));
527     
528   /* unknown CD image file format */
529   cdd.sectorSize = 0;
530
531   return was_loaded;
532 }
533
534 void cdd_read_data(uint8 *dst)
535 {
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))
539   {
540     off_t pos;
541
542     /* BIN format ? */
543     if (cdd.sectorSize == 2352)
544     {
545       /* skip 16-byte header */
546       pos = cdd.lba * 2352 + 16;
547     }
548     else
549     {
550       pos = cdd.lba * cdd.sectorSize;
551     }
552
553     if (pos != read_pos) {
554       pm_seek(cdd.toc.tracks[cdd.index].fd, pos, SEEK_SET);
555       read_pos = pos;
556     }
557
558     /* read sector data (Mode 1 = 2048 bytes) */
559     read_pos += pm_read(dst, 2048, cdd.toc.tracks[cdd.index].fd);
560   }
561 }
562
563 #if 0
564 void cdd_read_audio(unsigned int samples)
565 {
566   /* previous audio outputs */
567   int16 l = cdd.audio[0];
568   int16 r = cdd.audio[1];
569
570   /* get number of internal clocks (samples) needed */
571   samples = blip_clocks_needed(blip[0], samples);
572
573   /* audio track playing ? */
574   if (!Pico_mcd->s68k_regs[0x36+0] && cdd.toc.tracks[cdd.index].fd)
575   {
576     int i, mul, delta;
577
578     /* current CD-DA fader volume */
579     int curVol = cdd.volume;
580
581     /* CD-DA fader volume setup (0-1024) */
582     int endVol = Pico_mcd->regs[0x34>>1].w >> 4;
583
584     /* read samples from current block */
585 #ifdef USE_LIBTREMOR
586     if (cdd.toc.tracks[cdd.index].vf.datasource)
587     {
588       int len, done = 0;
589       int16 *ptr = (int16 *) (cdc.ram);
590       samples = samples * 4;
591       while (done < samples)
592       {
593         len = ov_read(&cdd.toc.tracks[cdd.index].vf, (char *)(cdc.ram + done), samples - done, 0);
594         if (len <= 0) 
595         {
596           done = samples;
597           break;
598         }
599         done += len;
600       }
601       samples = done / 4;
602
603       /* process 16-bit (host-endian) stereo samples */
604       for (i=0; i<samples; i++)
605       {
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);
609
610         /* left channel */
611         delta = ((ptr[0] * mul) / 1024) - l;
612         ptr++;
613         l += delta;
614         blip_add_delta_fast(blip[0], i, delta);
615
616         /* right channel */
617         delta = ((ptr[0] * mul) / 1024) - r;
618         ptr++;
619         r += delta;
620         blip_add_delta_fast(blip[1], i, delta);
621
622         /* update CD-DA fader volume (one step/sample) */
623         if (curVol < endVol)
624         {
625           /* fade-in */
626           curVol++;
627         }
628         else if (curVol > endVol)
629         {
630           /* fade-out */
631           curVol--;
632         }
633         else if (!curVol)
634         {
635           /* audio will remain muted until next setup */
636           break;
637         }
638       }
639     }
640     else
641 #endif
642     {
643 #ifdef LSB_FIRST
644       int16 *ptr = (int16 *) (cdc.ram);
645 #else
646       uint8 *ptr = cdc.ram;
647 #endif
648       fread(cdc.ram, 1, samples * 4, cdd.toc.tracks[cdd.index].fd);
649
650       /* process 16-bit (little-endian) stereo samples */
651       for (i=0; i<samples; i++)
652       {
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);
656
657         /* left channel */
658   #ifdef LSB_FIRST
659         delta = ((ptr[0] * mul) / 1024) - l;
660         ptr++;
661   #else
662         delta = (((int16)((ptr[0] + ptr[1]*256)) * mul) / 1024) - l;
663         ptr += 2;
664   #endif
665         l += delta;
666         blip_add_delta_fast(blip[0], i, delta);
667
668         /* right channel */
669   #ifdef LSB_FIRST
670         delta = ((ptr[0] * mul) / 1024) - r;
671         ptr++;
672   #else
673         delta = (((int16)((ptr[0] + ptr[1]*256)) * mul) / 1024) - r;
674         ptr += 2;
675   #endif
676         r += delta;
677         blip_add_delta_fast(blip[1], i, delta);
678
679         /* update CD-DA fader volume (one step/sample) */
680         if (curVol < endVol)
681         {
682           /* fade-in */
683           curVol++;
684         }
685         else if (curVol > endVol)
686         {
687           /* fade-out */
688           curVol--;
689         }
690         else if (!curVol)
691         {
692           /* audio will remain muted until next setup */
693           break;
694         }
695       }
696     }
697
698     /* save current CD-DA fader volume */
699     cdd.volume = curVol;
700
701     /* save last audio output for next frame */
702     cdd.audio[0] = l;
703     cdd.audio[1] = r;
704   }
705   else
706   {
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);
710
711     /* save audio output for next frame */
712     cdd.audio[0] = 0;
713     cdd.audio[1] = 0;
714   }
715
716   /* end of Blip Buffer timeframe */
717   blip_end_frame(blip[0], samples);
718   blip_end_frame(blip[1], samples);
719 }
720 #endif
721
722
723 void cdd_update(void)
724 {
725 #ifdef LOG_CDD
726   error("LBA = %d (track n°%d)(latency=%d)\n", cdd.lba, cdd.index, cdd.latency);
727 #endif
728   
729   /* update decoder, depending on track type */
730   if (cdd.status == CD_PLAY && !is_audio(cdd.index) && !cdd.latency)
731   {
732     /* DATA sector header (CD-ROM Mode 1) */
733     uint8 header[4];
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)];
738     header[3] = 0x01;
739
740     /* data track sector read is controlled by CDC */
741     cdc_decoder_update(header);
742   }
743   else
744   {
745     uint8 header[4] = { 0, };
746
747     /* audio blocks are still sent to CDC as well as CD DAC/Fader */
748     cdc_decoder_update(header);
749   }
750
751   if (Pico_mcd->m.state_flags & PCD_ST_CDD_CMD) {
752     /* pending delayed command */
753     cdd_process();
754     Pico_mcd->m.state_flags &= ~PCD_ST_CDD_CMD;
755   }
756
757   /* drive latency */
758   if (cdd.latency > 0)
759   {
760     cdd.latency--;
761     return;
762   }
763
764   /* reading disc */
765   if (cdd.status == CD_PLAY)
766   {
767     if (cdd.index >= cdd.toc.last)
768     {
769       /* end of disc */
770       cdd.status = CD_END;
771       return;
772     }
773
774     /* check against audio track start index */
775     if (is_audio(cdd.index) && cdd.lba >= cdd.toc.tracks[cdd.index].start)
776     {
777       /* audio track playing */
778       Pico_mcd->s68k_regs[0x36+0] = 0x00;
779     }
780  
781     /* next block is automatically read */
782     cdd.lba++;
783
784     /* check end of current track */
785     if (cdd.lba >= cdd.toc.tracks[cdd.index].end)
786     {
787       /* PAUSE between tracks */
788       Pico_mcd->s68k_regs[0x36+0] = 0x01;
789
790       /* seek to next audio track start */
791       cdd_seek(cdd.index + 1, cdd.lba);
792     }
793   }
794
795   /* scanning disc */
796   else if (cdd.status == CD_SCAN)
797   {
798     /* fast-forward or fast-rewind */
799     cdd.lba += cdd.scanOffset;
800
801     /* check current track limits */
802     if (cdd.lba >= cdd.toc.tracks[cdd.index].end)
803     {
804       /* next track */
805       if (cdd.index >= cdd.toc.last)
806       {
807         /* no AUDIO track playing */
808         Pico_mcd->s68k_regs[0x36+0] = 0x01;
809
810         /* end of disc */
811         cdd.lba = cdd.toc.end;
812         cdd.status = CD_END;
813       }
814       else
815       {
816         cdd_seek(cdd.index + 1, cdd.toc.tracks[cdd.index+1].start);
817
818         /* AUDIO track playing ? */
819         if (cdd.status == CD_PLAY && is_audio(cdd.index))
820         {
821           Pico_mcd->s68k_regs[0x36+0] = 0x00;
822         }
823       }
824     }
825     else if (cdd.lba < cdd.toc.tracks[cdd.index].start)
826     {
827       /* previous track */
828       if (cdd.index <= 0)
829       {
830         cdd_seek(0, 0);
831       }
832       else
833       {
834         cdd_seek(cdd.index - 1, cdd.toc.tracks[cdd.index-1].end);
835       }
836     }
837
838     if (!is_audio(cdd.index))
839     {
840       /* no AUDIO track playing */
841       Pico_mcd->s68k_regs[0x36+0] = 0x01;
842     }
843   }
844 }
845
846 #define set_reg16(r, v) { \
847   uint16 _v = v; \
848   Pico_mcd->s68k_regs[(r)] = _v >> 8; \
849   Pico_mcd->s68k_regs[(r)+1] = _v; \
850 }
851
852 void cdd_process(void)
853 {
854   /* Process CDD command */
855   switch (Pico_mcd->s68k_regs[0x42+0] & 0x0f)
856   {
857     case 0x00:  /* Drive Status */
858     {
859       if (cdd.latency == 0) {
860         /* RS1-RS8 normally unchanged */
861         Pico_mcd->s68k_regs[0x38+0] = cdd.status;
862
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)
867         {
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);
881         }
882       }
883       break;
884     }
885
886     case 0x01:  /* Stop Drive */
887     {
888       /* update status */
889       cdd.status = cdd.loaded ? CD_STOP : NO_DISC;
890
891       /* no audio track playing */
892       Pico_mcd->s68k_regs[0x36+0] = 0x01;
893
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);
900
901       /* reset to 1st track */
902       cdd_seek(0, 0);
903       return;
904     }
905
906     case 0x02:  /* Read TOC */
907     {
908       if (cdd.status == NO_DISC)
909         cdd.status = cdd.loaded ? CD_STOP : NO_DISC;
910
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])
914       {
915         case 0x00:  /* Current Absolute Time (MM:SS:FF) */
916         {
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) */
923           break;
924         }
925
926         case 0x01:  /* Current Track Relative Time (MM:SS:FF) */
927         {
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) */
935           break;
936         }
937
938         case 0x02:  /* Current Track Number */
939         {
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;
945           break;
946         }
947
948         case 0x03:  /* Total length (MM:SS:FF) */
949         {
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;
956           break;
957         }
958
959         case 0x04:  /* First & Last Track Numbers */
960         {
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) */
966           break;
967         }
968
969         case 0x05:  /* Track Start Time (MM:SS:FF) */
970         {
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) */
978           if (track == 1)
979           {
980             /* RS6 bit 3 is set for the first (DATA) track */
981             Pico_mcd->s68k_regs[0x3e + 0] |= 0x08;
982           }
983           break;
984         }
985
986         case 0x06:  /* Latest Error Information */
987         {
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;
993           break;
994         }
995
996         default:
997         {
998 #ifdef LOG_ERROR
999           error("Unknown CDD Command %02X (%X)\n", Pico_mcd->s68k_regs[0x44+1], s68k.pc);
1000 #endif
1001           return;
1002         }
1003       }
1004       break;
1005     }
1006
1007     case 0x03:  /* Play  */
1008     {
1009       /* reset track index */
1010       int index = 0;
1011
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;
1016
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);
1023
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;
1027         return;
1028       }
1029
1030       /* CD drive latency */
1031       if (!cdd.latency)
1032       {
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 */
1038         cdd.latency = 11;
1039       }
1040
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).        */
1046       if (lba > cdd.lba)
1047       {
1048         cdd.latency += (((lba - cdd.lba) * 120) / 270000);
1049       }
1050       else 
1051       {
1052         cdd.latency += (((cdd.lba - lba) * 120) / 270000);
1053       }
1054
1055       /* get track index */
1056       while ((cdd.toc.tracks[index].end <= lba) && (index < cdd.toc.last)) index++;
1057
1058       /* seek to block; playing always starts 3 blocks earlier */
1059       cdd_seek(index, lba - 3);
1060
1061       /* no audio track playing (yet) */
1062       Pico_mcd->s68k_regs[0x36+0] = 0x01;
1063
1064       /* update status */
1065       cdd.status = CD_PLAY;
1066
1067       return;
1068     }
1069
1070     case 0x04:  /* Seek */
1071     {
1072       /* reset track index */
1073       int index = 0;
1074
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;
1079
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);
1086
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;
1090         return;
1091       }
1092
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) */
1097       if (lba > cdd.lba)
1098       {
1099         cdd.latency = ((lba - cdd.lba) * 120) / 270000;
1100       }
1101       else
1102       {
1103         cdd.latency = ((cdd.lba - lba) * 120) / 270000;
1104       }
1105
1106       /* get track index */
1107       while ((cdd.toc.tracks[index].end <= lba) && (index < cdd.toc.last)) index++;
1108
1109       /* seek to block; playing always starts 3 blocks earlier */
1110       cdd_seek(index, lba - 3);
1111
1112       /* no audio track playing */
1113       Pico_mcd->s68k_regs[0x36+0] = 0x01;
1114
1115       /* update status */
1116       cdd.status = CD_READY;
1117
1118       return;
1119     }
1120
1121     case 0x06:  /* Pause */
1122     {
1123       /* update status (RS1-RS8 unchanged) */
1124       cdd.status = Pico_mcd->s68k_regs[0x38+0] = CD_READY;
1125
1126       /* no audio track playing */
1127       Pico_mcd->s68k_regs[0x36+0] = 0x01;
1128
1129       break;
1130     }
1131
1132     case 0x07:  /* Resume */
1133     {
1134       /* update status (RS1-RS8 unchanged) */
1135       cdd.status = Pico_mcd->s68k_regs[0x38+0] = CD_PLAY;
1136       break;
1137     }
1138
1139     case 0x08:  /* Forward Scan */
1140     {
1141       /* reset scanning direction / speed */
1142       cdd.scanOffset = CD_SCAN_SPEED;
1143
1144       /* update status (RS1-RS8 unchanged) */
1145       cdd.status = Pico_mcd->s68k_regs[0x38+0] = CD_SCAN;
1146       break;
1147     }
1148
1149     case 0x09:  /* Rewind Scan */
1150     {
1151       /* reset scanning direction / speed */
1152       cdd.scanOffset = -CD_SCAN_SPEED;
1153
1154       /* update status (RS1-RS8 unchanged) */
1155       cdd.status = Pico_mcd->s68k_regs[0x38+0] = CD_SCAN;
1156       break;
1157     }
1158
1159
1160     case 0x0a:  /* N-Track Jump Control ? (usually sent before CD_SEEK or CD_PLAY commands) */
1161     {
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 */
1166
1167       /* no audio track playing */
1168       Pico_mcd->s68k_regs[0x36+0] = 0x01;
1169
1170       /* update status (RS1-RS8 unchanged) */
1171       cdd.status = Pico_mcd->s68k_regs[0x38+0] = CD_READY;
1172       break;
1173     }
1174
1175     case 0x0c:  /* Close Tray */
1176     {
1177       /* no audio track playing */
1178       Pico_mcd->s68k_regs[0x36+0] = 0x01;
1179
1180       /* update status */
1181       cdd.status = cdd.loaded ? CD_STOP : NO_DISC;
1182
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);
1189
1190       if (PicoIn.mcdTrayClose)
1191         PicoIn.mcdTrayClose();
1192
1193       return;
1194     }
1195
1196     case 0x0d:  /* Open Tray */
1197     {
1198       /* no audio track playing */
1199       Pico_mcd->s68k_regs[0x36+0] = 0x01;
1200
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);
1208
1209       if (PicoIn.mcdTrayOpen)
1210         PicoIn.mcdTrayOpen();
1211       return;
1212     }
1213
1214     default:  /* Unknown command */
1215 #ifdef LOG_CDD
1216       error("Unknown CDD Command !!!\n");
1217 #endif
1218       Pico_mcd->s68k_regs[0x38+0] = cdd.status;
1219       break;
1220   }
1221
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;
1229 }
1230
1231 // vim:shiftwidth=2:ts=2:expandtab