cd: switch to CD drive emu code from genplus
authornotaz <notasas@gmail.com>
Sun, 6 Oct 2013 18:08:07 +0000 (21:08 +0300)
committernotaz <notasas@gmail.com>
Sun, 6 Oct 2013 21:11:31 +0000 (00:11 +0300)
same license, much cleaner code

25 files changed:
pico/cart.c
pico/cd/LC89510.h [deleted file]
pico/cd/buffering.c [deleted file]
pico/cd/cd_file.c [deleted file]
pico/cd/cd_file.h [deleted file]
pico/cd/cd_image.c [new file with mode: 0644]
pico/cd/cd_sys.c [deleted file]
pico/cd/cd_sys.h [deleted file]
pico/cd/cdc.c
pico/cd/cdd.c [new file with mode: 0644]
pico/cd/cdd.h [new file with mode: 0644]
pico/cd/cue.c
pico/cd/mcd.c
pico/cd/memory.c
pico/media.c
pico/pico.h
pico/pico_int.h
pico/sound/sound.c
pico/state.c
platform/base_readme.txt
platform/common/common.mak
platform/common/config_file.c
platform/common/emu.c
platform/common/menu_pico.c
platform/libretro.c

index 6a835b6..a5c563d 100644 (file)
@@ -157,7 +157,7 @@ zip_failed:
     if (f == NULL)\r
       goto cso_failed;\r
 \r
-#ifndef __EPOC32__\r
+#ifdef __GP2X__\r
     /* we use our own buffering */\r
     setvbuf(f, NULL, _IONBF, 0);\r
 #endif\r
@@ -227,7 +227,7 @@ cso_failed:
   strncpy(file->ext, ext, sizeof(file->ext) - 1);\r
   fseek(f, 0, SEEK_SET);\r
 \r
-#ifndef __EPOC32__ // makes things worse on Symbian\r
+#ifdef __GP2X__\r
   if (file->size > 0x400000)\r
     /* we use our own buffering */\r
     setvbuf(f, NULL, _IONBF, 0);\r
diff --git a/pico/cd/LC89510.h b/pico/cd/LC89510.h
deleted file mode 100644 (file)
index d641ebb..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-/***********************************************************\r
- *                                                         *\r
- * This source was taken from the Gens project             *\r
- * Written by Stéphane Dallongeville                       *\r
- * Copyright (c) 2002 by Stéphane Dallongeville            *\r
- * Modified/adapted for PicoDrive by notaz, 2007           *\r
- *                                                         *\r
- ***********************************************************/\r
-\r
-#ifndef _LC89510_H\r
-#define _LC89510_H\r
-\r
-#ifdef __cplusplus\r
-extern "C" {\r
-#endif\r
-\r
-typedef struct\r
-{\r
-//     unsigned short Fader;   // 34\r
-//     unsigned short Control; // 36\r
-//     unsigned short Cur_Comm;// unused\r
-\r
-       // "Receive status"\r
-       unsigned short Status;\r
-       unsigned short Minute;\r
-       unsigned short Seconde;\r
-       unsigned short Frame;\r
-       unsigned char  Ext;\r
-       unsigned char  pad[3];\r
-} CDD;\r
-\r
-\r
-PICO_INTERNAL void CDD_Export_Status(void);\r
-PICO_INTERNAL void CDD_Import_Command(void);\r
-\r
-void CDD_Reset(void);\r
-\r
-#ifdef __cplusplus\r
-};\r
-#endif\r
-\r
-#endif\r
-\r
diff --git a/pico/cd/buffering.c b/pico/cd/buffering.c
deleted file mode 100644 (file)
index 8420336..0000000
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * Buffering handling
- * (C) notaz, 2007,2008
- *
- * This work is licensed under the terms of MAME license.
- * See COPYING file in the top-level directory.
- */
-
-#include "../pico_int.h"
-#include "../cd/cue.h"
-
-int PicoCDBuffers = 0;
-static unsigned char *cd_buffer = NULL;
-static int prev_lba = 0x80000000;
-
-static int hits, reads;
-
-#undef dprintf
-#define dprintf(...)
-
-void PicoCDBufferInit(void)
-{
-       void *tmp = NULL;
-
-       prev_lba = 0x80000000;
-       hits = reads = 0;
-
-       if (PicoCDBuffers <= 1) {
-               PicoCDBuffers = 0;
-               return; /* buffering off */
-       }
-
-       /* try alloc'ing until we succeed */
-       while (PicoCDBuffers > 0)
-       {
-               tmp = realloc(cd_buffer, PicoCDBuffers * 2048 + 304);
-               if (tmp != NULL) break;
-               PicoCDBuffers >>= 1;
-       }
-
-       if (PicoCDBuffers <= 0) return; /* buffering became off */
-
-       cd_buffer = tmp;
-}
-
-
-void PicoCDBufferFree(void)
-{
-       if (cd_buffer) {
-               free(cd_buffer);
-               cd_buffer = NULL;
-       }
-       if (reads)
-               elprintf(EL_STATUS, "CD buffer hits: %i/%i (%i%%)\n", hits, reads, hits * 100 / reads);
-}
-
-
-void PicoCDBufferFlush(void)
-{
-       prev_lba = 0x80000000;
-}
-
-
-/* this is was a try to fight slow SD access of GP2X */
-PICO_INTERNAL void PicoCDBufferRead(void *dest, int lba)
-{
-       int is_bin, offs, read_len, moved = 0;
-       reads++;
-
-       is_bin = Pico_mcd->TOC.Tracks[0].ftype == CT_BIN;
-
-       if (PicoCDBuffers <= 0)
-       {
-               /* no buffering */
-               int where_seek = is_bin ? (lba * 2352 + 16) : (lba << 11);
-               pm_seek(Pico_mcd->TOC.Tracks[0].F, where_seek, SEEK_SET);
-               pm_read(dest, 2048, Pico_mcd->TOC.Tracks[0].F);
-               return;
-       }
-
-       /* hit? */
-       offs = lba - prev_lba;
-       if (offs >= 0 && offs < PicoCDBuffers)
-       {
-               hits++;
-               if (offs == 0) dprintf("CD buffer seek to old %i -> %i\n", prev_lba, lba);
-               memcpy32(dest, (int *)(cd_buffer + offs*2048), 2048/4);
-               return;
-       }
-
-       if (prev_lba + PicoCDBuffers != lba)
-       {
-               int where_seek = is_bin ? (lba * 2352 + 16) : (lba << 11);
-               dprintf("CD buffer seek %i -> %i\n", prev_lba, lba);
-               pm_seek(Pico_mcd->TOC.Tracks[0].F, where_seek, SEEK_SET);
-       }
-
-       dprintf("CD buffer miss %i -> %i\n", prev_lba, lba);
-
-       if (lba < prev_lba && prev_lba - lba < PicoCDBuffers)
-       {
-               read_len = prev_lba - lba;
-               dprintf("CD buffer move=%i, read_len=%i", PicoCDBuffers - read_len, read_len);
-               memmove(cd_buffer + read_len*2048, cd_buffer, (PicoCDBuffers - read_len)*2048);
-               moved = 1;
-       }
-       else
-       {
-               read_len = PicoCDBuffers;
-       }
-
-       if (PicoMessage != NULL && read_len >= 512)
-       {
-               PicoMessage("Buffering data...");
-       }
-
-       if (is_bin)
-       {
-               int i = 0;
-#ifdef _PSP_FW_VERSION
-               int bufs = (read_len*2048) / (2048+304);
-               pm_read(cd_buffer, bufs*(2048+304), Pico_mcd->TOC.Tracks[0].F);
-               for (i = 1; i < bufs; i++)
-                       // should really use memmove here, but my memcpy32 implementation is also suitable here
-                       memcpy32((int *)(cd_buffer + i*2048), (int *)(cd_buffer + i*(2048+304)), 2048/4);
-#endif
-               for (; i < read_len - 1; i++)
-               {
-                       pm_read(cd_buffer + i*2048, 2048 + 304, Pico_mcd->TOC.Tracks[0].F);
-                       // pm_seek(Pico_mcd->TOC.Tracks[0].F, 304, SEEK_CUR); // seeking is slower, in PSP case even more
-               }
-               // further data might be moved, do not overwrite
-               pm_read(cd_buffer + i*2048, 2048, Pico_mcd->TOC.Tracks[0].F);
-               pm_seek(Pico_mcd->TOC.Tracks[0].F, 304, SEEK_CUR);
-       }
-       else
-       {
-               pm_read(cd_buffer, read_len*2048, Pico_mcd->TOC.Tracks[0].F);
-       }
-       memcpy32(dest, (int *) cd_buffer, 2048/4);
-       prev_lba = lba;
-
-       if (moved)
-       {
-               /* file pointer must point to the same data in file, as would-be data after our buffer */
-               int where_seek;
-               lba += PicoCDBuffers;
-               where_seek = is_bin ? (lba * 2352 + 16) : (lba << 11);
-               pm_seek(Pico_mcd->TOC.Tracks[0].F, where_seek, SEEK_SET);
-       }
-}
-
diff --git a/pico/cd/cd_file.c b/pico/cd/cd_file.c
deleted file mode 100644 (file)
index 43bbb5d..0000000
+++ /dev/null
@@ -1,402 +0,0 @@
-/***********************************************************
- *                                                         *
- * This source was taken from the Gens project             *
- * Written by Stéphane Dallongeville                       *
- * Copyright (c) 2002 by Stéphane Dallongeville            *
- * Modified/adapted for PicoDrive by notaz, 2007           *
- *                                                         *
- ***********************************************************/
-
-#include "../pico_int.h"
-#include "cd_file.h"
-#include "cue.h"
-
-//#define cdprintf(f,...) printf(f "\n",##__VA_ARGS__) // tmp
-
-static void to_upper(char *d, const char *s)
-{
-       for (; *s != 0; d++, s++) {
-               if ('a' <= *s && *s <= 'z')
-                       *d = *s - 'a' + 'A';
-               else
-                       *d = *s;
-       }
-}
-
-static int audio_track_mp3(const char *fname, int index)
-{
-       _scd_track *Tracks = Pico_mcd->TOC.Tracks;
-       FILE *tmp_file;
-       int fs, ret;
-
-       tmp_file = fopen(fname, "rb");
-       if (tmp_file == NULL)
-               return -1;
-
-       ret = fseek(tmp_file, 0, SEEK_END);
-       fs = ftell(tmp_file);                           // used to calculate length
-       fseek(tmp_file, 0, SEEK_SET);
-
-#ifdef _PSP_FW_VERSION
-       // some systems (like PSP) can't have many open files at a time,
-       // so we work with their names instead.
-       fclose(tmp_file);
-       tmp_file = (void *) strdup(fname);
-#endif
-       Tracks[index].KBtps = (short) mp3_get_bitrate(tmp_file, fs);
-       Tracks[index].KBtps >>= 3;
-       if (ret != 0 || Tracks[index].KBtps <= 0)
-       {
-               elprintf(EL_STATUS, "track %2i: mp3 bitrate %i", index+1, Tracks[index].KBtps);
-#ifdef _PSP_FW_VERSION
-               free(tmp_file);
-#else
-               fclose(tmp_file);
-#endif
-               return -1;
-       }
-
-       Tracks[index].F = tmp_file;
-
-       // MP3 File
-       Tracks[index].ftype = CT_MP3;
-       fs *= 75;
-       fs /= Tracks[index].KBtps * 1000;
-       Tracks[index].Length = fs;
-       Tracks[index].Offset = 0;
-
-       return 0;
-}
-
-PICO_INTERNAL int Load_CD_Image(const char *cd_img_name, cd_img_type type)
-{
-       int i, j, num_track, Cur_LBA, index, ret;
-       int iso_name_len, missed, cd_img_sectors;
-       _scd_track *Tracks = Pico_mcd->TOC.Tracks;
-       char tmp_name[256], tmp_ext[10], tmp_ext_u[10];
-       cue_data_t *cue_data = NULL;
-       pm_file *pmf;
-       static const char *exts[] = {
-               "%02d.mp3", " %02d.mp3", "-%02d.mp3", "_%02d.mp3", " - %02d.mp3",
-               "%d.mp3", " %d.mp3", "-%d.mp3", "_%d.mp3", " - %d.mp3",
-       };
-
-       if (PicoCDLoadProgressCB != NULL)
-               PicoCDLoadProgressCB(cd_img_name, 1);
-
-       Unload_ISO();
-
-       /* is this a .cue? */
-       cue_data = cue_parse(cd_img_name);
-       if (cue_data != NULL) {
-               cd_img_name = cue_data->tracks[1].fname;
-               Tracks[0].ftype = cue_data->tracks[1].type;
-       }
-       else
-               Tracks[0].ftype = type == CIT_BIN ? CT_BIN : CT_ISO;
-
-       Tracks[0].F = pmf = pm_open(cd_img_name);
-       if (Tracks[0].F == NULL)
-       {
-               Tracks[0].ftype = 0;
-               Tracks[0].Length = 0;
-               if (cue_data != NULL)
-                       cue_destroy(cue_data);
-               return -1;
-       }
-
-       if (Tracks[0].ftype == CT_ISO)
-            cd_img_sectors = pmf->size >>= 11; // size in sectors
-       else cd_img_sectors = pmf->size /= 2352;
-       Tracks[0].Offset = 0;
-
-       Tracks[0].MSF.M = 0; // minutes
-       Tracks[0].MSF.S = 2; // seconds
-       Tracks[0].MSF.F = 0; // frames
-
-       elprintf(EL_STATUS, "Track  1: %02d:%02d:%02d %9i DATA  %s",
-               Tracks[0].MSF.M, Tracks[0].MSF.S, Tracks[0].MSF.F,
-               Tracks[0].Length, cd_img_name);
-
-       Cur_LBA = Tracks[0].Length = cd_img_sectors;
-
-       if (cue_data != NULL)
-       {
-               if (cue_data->tracks[2].fname == NULL) { // NULL means track2 is in same file as track1
-                       Cur_LBA = Tracks[0].Length = cue_data->tracks[2].sector_offset;
-               }
-               i = 100 / cue_data->track_count+1;
-               for (num_track = 2; num_track <= cue_data->track_count; num_track++)
-               {
-                       if (PicoCDLoadProgressCB != NULL)
-                               PicoCDLoadProgressCB(cd_img_name, i * num_track);
-                       index = num_track - 1;
-                       Cur_LBA += cue_data->tracks[num_track].pregap;
-                       if (cue_data->tracks[num_track].type == CT_MP3) {
-                               ret = audio_track_mp3(cue_data->tracks[num_track].fname, index);
-                               if (ret != 0) break;
-                       }
-                       else
-                       {
-                               Tracks[index].ftype = cue_data->tracks[num_track].type;
-                               if (cue_data->tracks[num_track].fname != NULL)
-                               {
-                                       pm_file *pmfn = pm_open(cue_data->tracks[num_track].fname);
-                                       if (pmfn != NULL)
-                                       {
-                                               // addume raw, ignore header for wav..
-                                               Tracks[index].F = pmfn;
-                                               Tracks[index].Length = pmfn->size / 2352;
-                                               Tracks[index].Offset = cue_data->tracks[num_track].sector_offset;
-                                       }
-                                       else
-                                       {
-                                               elprintf(EL_STATUS, "track %2i (%s): can't determine length",
-                                                       num_track, cue_data->tracks[num_track].fname);
-                                               Tracks[index].Length = 2*75;
-                                               Tracks[index].Offset = 0;
-                                       }
-                               }
-                               else
-                               {
-                                       if (num_track < cue_data->track_count)
-                                               Tracks[index].Length = cue_data->tracks[num_track+1].sector_offset -
-                                                       cue_data->tracks[num_track].sector_offset;
-                                       else
-                                               Tracks[index].Length = cd_img_sectors - cue_data->tracks[num_track].sector_offset;
-                                       Tracks[index].Offset = cue_data->tracks[num_track].sector_offset;
-                               }
-                       }
-
-                       if (cue_data->tracks[num_track].sector_xlength != 0)
-                               // overriden by custom cue command
-                               Tracks[index].Length = cue_data->tracks[num_track].sector_xlength;
-
-                       LBA_to_MSF(Cur_LBA, &Tracks[index].MSF);
-                       Cur_LBA += Tracks[index].Length;
-
-                       elprintf(EL_STATUS, "Track %2i: %02d:%02d:%02d %9i AUDIO %s", num_track, Tracks[index].MSF.M,
-                               Tracks[index].MSF.S, Tracks[index].MSF.F, Tracks[index].Length,
-                               cue_data->tracks[num_track].fname);
-               }
-               cue_destroy(cue_data);
-               goto finish;
-       }
-
-       /* mp3 track autosearch, Gens-like */
-       iso_name_len = strlen(cd_img_name);
-       if (iso_name_len >= sizeof(tmp_name))
-               iso_name_len = sizeof(tmp_name) - 1;
-
-       for (num_track = 2, i = 0, missed = 0; i < 100 && missed < 4; i++)
-       {
-               if (PicoCDLoadProgressCB != NULL && i > 1)
-                       PicoCDLoadProgressCB(cd_img_name, i + (100-i)*missed/4);
-
-               for (j = 0; j < sizeof(exts)/sizeof(char *); j++)
-               {
-                       int ext_len;
-                       char *p;
-
-                       index = num_track - 1;
-
-                       sprintf(tmp_ext, exts[j], i);
-                       ext_len = strlen(tmp_ext);
-                       to_upper(tmp_ext_u, tmp_ext);
-
-                       memcpy(tmp_name, cd_img_name, iso_name_len + 1);
-                       p = tmp_name + iso_name_len - 4;
-
-                       strcpy(p, tmp_ext);
-                       ret = audio_track_mp3(tmp_name, index);
-                       if (ret != 0) {
-                               strcpy(p, tmp_ext_u);
-                               ret = audio_track_mp3(tmp_name, index);
-                       }
-
-                       if (ret != 0 && i > 1 && iso_name_len > ext_len) {
-                               p = tmp_name + iso_name_len - ext_len;
-                               strcpy(p, tmp_ext);
-                               ret = audio_track_mp3(tmp_name, index);
-                               if (ret != 0) {
-                                       strcpy(p, tmp_ext_u);
-                                       ret = audio_track_mp3(tmp_name, index);
-                               }
-                       }
-
-                       if (ret == 0)
-                       {
-                               LBA_to_MSF(Cur_LBA, &Tracks[index].MSF);
-                               Cur_LBA += Tracks[index].Length;
-
-                               elprintf(EL_STATUS, "Track %2i: %02d:%02d:%02d %9i AUDIO - %s", num_track, Tracks[index].MSF.M,
-                                       Tracks[index].MSF.S, Tracks[index].MSF.F, Tracks[index].Length, tmp_name);
-
-                               num_track++;
-                               missed = 0;
-                               break;
-                       }
-               }
-               if (ret != 0 && i > 1) missed++;
-       }
-
-finish:
-       Pico_mcd->TOC.Last_Track = num_track - 1;
-
-       index = num_track - 1;
-
-       LBA_to_MSF(Cur_LBA, &Tracks[index].MSF);
-
-       elprintf(EL_STATUS, "End CD -  %02d:%02d:%02d\n", Tracks[index].MSF.M,
-               Tracks[index].MSF.S, Tracks[index].MSF.F);
-
-       if (PicoCDLoadProgressCB != NULL)
-               PicoCDLoadProgressCB(cd_img_name, 100);
-
-       return 0;
-}
-
-
-PICO_INTERNAL void Unload_ISO(void)
-{
-       int i;
-
-       if (Pico_mcd == NULL) return;
-
-       if (Pico_mcd->TOC.Tracks[0].F) pm_close(Pico_mcd->TOC.Tracks[0].F);
-
-       for(i = 1; i < 100; i++)
-       {
-               if (Pico_mcd->TOC.Tracks[i].F != NULL)
-               {
-                       if (Pico_mcd->TOC.Tracks[i].ftype == CT_MP3)
-#ifdef _PSP_FW_VERSION
-                               free(Pico_mcd->TOC.Tracks[i].F);
-#else
-                               fclose(Pico_mcd->TOC.Tracks[i].F);
-#endif
-                       else
-                               pm_close(Pico_mcd->TOC.Tracks[i].F);
-               }
-       }
-       memset(Pico_mcd->TOC.Tracks, 0, sizeof(Pico_mcd->TOC.Tracks));
-}
-
-#if 1*0
-
-PICO_INTERNAL int FILE_Read_One_LBA_CDC(void)
-{
-       if (Pico_mcd->s68k_regs[0x36] & 1)                                      // DATA
-       {
-               if (Pico_mcd->TOC.Tracks[0].F == NULL) return -1;
-
-               // moved below..
-               //fseek(Pico_mcd->TOC.Tracks[0].F, where_read, SEEK_SET);
-               //fread(cp_buf, 1, 2048, Pico_mcd->TOC.Tracks[0].F);
-
-               cdprintf("Read file CDC 1 data sector :\n");
-       }
-       else                                                                    // AUDIO
-       {
-               cdprintf("Read file CDC 1 audio sector :\n");
-       }
-
-       // Update CDC stuff
-
-       CDC_Update_Header();
-
-       if (Pico_mcd->s68k_regs[0x36] & 1)              // DATA track
-       {
-               if (Pico_mcd->cdc.CTRL.B.B0 & 0x80)             // DECEN = decoding enable
-               {
-                       if (Pico_mcd->cdc.CTRL.B.B0 & 0x04)     // WRRQ : this bit enable write to buffer
-                       {
-                               int where_read = 0;
-
-                               // CAUTION : lookahead bit not implemented
-
-                               if (Pico_mcd->scd.Cur_LBA < 0)
-                                       where_read = 0;
-                               else if (Pico_mcd->scd.Cur_LBA >= Pico_mcd->TOC.Tracks[0].Length)
-                                       where_read = Pico_mcd->TOC.Tracks[0].Length - 1;
-                               else where_read = Pico_mcd->scd.Cur_LBA;
-
-                               Pico_mcd->scd.Cur_LBA++;
-
-                               Pico_mcd->cdc.WA.N = (Pico_mcd->cdc.WA.N + 2352) & 0x7FFF;              // add one sector to WA
-                               Pico_mcd->cdc.PT.N = (Pico_mcd->cdc.PT.N + 2352) & 0x7FFF;
-
-                               *(unsigned int *)(Pico_mcd->cdc.Buffer + Pico_mcd->cdc.PT.N) = Pico_mcd->cdc.HEAD.N;
-                               //memcpy(&Pico_mcd->cdc.Buffer[Pico_mcd->cdc.PT.N + 4], cp_buf, 2048);
-
-                               //pm_seek(Pico_mcd->TOC.Tracks[0].F, where_read, SEEK_SET);
-                               //pm_read(Pico_mcd->cdc.Buffer + Pico_mcd->cdc.PT.N + 4, 2048, Pico_mcd->TOC.Tracks[0].F);
-                               PicoCDBufferRead(Pico_mcd->cdc.Buffer + Pico_mcd->cdc.PT.N + 4, where_read);
-
-                               cdprintf("Read -> WA = %d  Buffer[%d] =", Pico_mcd->cdc.WA.N, Pico_mcd->cdc.PT.N & 0x3FFF);
-                               cdprintf("Header 1 = %.2X %.2X %.2X %.2X", Pico_mcd->cdc.HEAD.B.B0,
-                                       Pico_mcd->cdc.HEAD.B.B1, Pico_mcd->cdc.HEAD.B.B2, Pico_mcd->cdc.HEAD.B.B3);
-                               cdprintf("Header 2 = %.2X %.2X %.2X %.2X --- %.2X %.2X\n\n",
-                                       Pico_mcd->cdc.Buffer[(Pico_mcd->cdc.PT.N + 0) & 0x3FFF],
-                                       Pico_mcd->cdc.Buffer[(Pico_mcd->cdc.PT.N + 1) & 0x3FFF],
-                                       Pico_mcd->cdc.Buffer[(Pico_mcd->cdc.PT.N + 2) & 0x3FFF],
-                                       Pico_mcd->cdc.Buffer[(Pico_mcd->cdc.PT.N + 3) & 0x3FFF],
-                                       Pico_mcd->cdc.Buffer[(Pico_mcd->cdc.PT.N + 4) & 0x3FFF],
-                                       Pico_mcd->cdc.Buffer[(Pico_mcd->cdc.PT.N + 5) & 0x3FFF]);
-                       }
-
-               }
-       }
-       else            // music track
-       {
-               Pico_mcd->scd.Cur_LBA++;
-
-               Pico_mcd->cdc.WA.N = (Pico_mcd->cdc.WA.N + 2352) & 0x7FFF;              // add one sector to WA
-               Pico_mcd->cdc.PT.N = (Pico_mcd->cdc.PT.N + 2352) & 0x7FFF;
-
-               if (Pico_mcd->cdc.CTRL.B.B0 & 0x80)             // DECEN = decoding enable
-               {
-                       if (Pico_mcd->cdc.CTRL.B.B0 & 0x04)     // WRRQ : this bit enable write to buffer
-                       {
-                               // CAUTION : lookahead bit not implemented
-
-                               // this is pretty rough, but oh well - not much depends on this anyway
-                               memcpy(&Pico_mcd->cdc.Buffer[Pico_mcd->cdc.PT.N], cdda_out_buffer, 2352);
-                       }
-               }
-       }
-
-       if (Pico_mcd->cdc.CTRL.B.B0 & 0x80)             // DECEN = decoding enable
-       {
-               Pico_mcd->cdc.STAT.B.B0 = 0x80;
-
-               if (Pico_mcd->cdc.CTRL.B.B0 & 0x10)     // determine form bit form sub header ?
-               {
-                       Pico_mcd->cdc.STAT.B.B2 = Pico_mcd->cdc.CTRL.B.B1 & 0x08;
-               }
-               else
-               {
-                       Pico_mcd->cdc.STAT.B.B2 = Pico_mcd->cdc.CTRL.B.B1 & 0x0C;
-               }
-
-               if (Pico_mcd->cdc.CTRL.B.B0 & 0x02) Pico_mcd->cdc.STAT.B.B3 = 0x20;     // ECC done
-               else Pico_mcd->cdc.STAT.B.B3 = 0x00;    // ECC not done
-
-               if (Pico_mcd->cdc.IFCTRL & 0x20)
-               {
-                       if (Pico_mcd->s68k_regs[0x33] & (1<<5))
-                       {
-                               elprintf(EL_INTS, "cdc dec irq 5");
-                               SekInterruptS68k(5);
-                       }
-
-                       Pico_mcd->cdc.IFSTAT &= ~0x20;          // DEC interrupt happen
-                       Pico_mcd->cdc.Decode_Reg_Read = 0;      // Reset read after DEC int
-               }
-       }
-
-
-       return 0;
-}
-
-#endif
diff --git a/pico/cd/cd_file.h b/pico/cd/cd_file.h
deleted file mode 100644 (file)
index f9bb8ea..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-#ifndef _CD_FILE_H
-#define _CD_FILE_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef enum
-{
-       CIT_NOT_CD = 0,
-       CIT_ISO,
-       CIT_BIN,
-       CIT_CUE
-}
-cd_img_type;
-
-
-PICO_INTERNAL int  Load_CD_Image(const char *iso_name, cd_img_type type);
-PICO_INTERNAL void Unload_ISO(void);
-PICO_INTERNAL int  FILE_Read_One_LBA_CDC(void);
-
-
-#ifdef __cplusplus
-};
-#endif
-
-#endif
diff --git a/pico/cd/cd_image.c b/pico/cd/cd_image.c
new file mode 100644 (file)
index 0000000..97c8f3f
--- /dev/null
@@ -0,0 +1,266 @@
+/*
+ * CD image handler
+ * (C) notaz, 2007,2013
+ *
+ * This work is licensed under the terms of MAME license.
+ * See COPYING file in the top-level directory.
+ */
+
+#include "../pico_int.h"
+#include "genplus_macros.h"
+#include "cdd.h"
+#include "cue.h"
+
+static int handle_mp3(const char *fname, int index)
+{
+  track_t *track = &cdd.toc.tracks[index];
+  FILE *tmp_file;
+  int kBps;
+  int fs, ret;
+
+  tmp_file = fopen(fname, "rb");
+  if (tmp_file == NULL)
+    return -1;
+
+  ret = fseek(tmp_file, 0, SEEK_END);
+  fs = ftell(tmp_file);
+  fseek(tmp_file, 0, SEEK_SET);
+
+#ifdef _PSP_FW_VERSION
+  // some systems (like PSP) can't have many open files at a time,
+  // so we work with their names instead.
+  fclose(tmp_file);
+  tmp_file = (void *) strdup(fname);
+#endif
+
+  kBps = mp3_get_bitrate(tmp_file, fs) / 8;
+  if (ret != 0 || kBps <= 0)
+  {
+    elprintf(EL_STATUS, "track %2i: mp3 bitrate %i", index+1, kBps);
+#ifdef _PSP_FW_VERSION
+    free(tmp_file);
+#else
+    fclose(tmp_file);
+#endif
+    return -1;
+  }
+
+  track->fd = tmp_file;
+  track->offset = 0;
+
+  fs *= 75;
+  fs /= kBps * 1000;
+  return fs;
+}
+
+static void to_upper(char *d, const char *s)
+{
+  for (; *s != 0; d++, s++) {
+    if ('a' <= *s && *s <= 'z')
+      *d = *s - 'a' + 'A';
+    else
+      *d = *s;
+  }
+}
+
+// cdd.c uses lba - 150
+static void sprintf_lba(char *buf, size_t size, int lba)
+{
+  lba += 150;
+  snprintf(buf, size, "%02d:%02d:%02d", lba / 60 / 75,
+    (lba / 75) % 60, lba % 75);
+}
+
+int load_cd_image(const char *cd_img_name, int *type)
+{
+  static const char *exts[] = {
+    "%02d.mp3", " %02d.mp3", "-%02d.mp3", "_%02d.mp3", " - %02d.mp3",
+    "%d.mp3", " %d.mp3", "-%d.mp3", "_%d.mp3", " - %d.mp3",
+  };
+  int i, j, n, lba, index, length, ret;
+  int iso_name_len, missed, cd_img_sectors;
+  char tmp_name[256], tmp_ext[10], tmp_ext_u[10];
+  track_t *tracks = cdd.toc.tracks;
+  cue_data_t *cue_data = NULL;
+  pm_file *pmf;
+
+  if (PicoCDLoadProgressCB != NULL)
+    PicoCDLoadProgressCB(cd_img_name, 1);
+
+  Pico_mcd->cdda_type = CT_UNKNOWN;
+
+  /* is this a .cue? */
+  cue_data = cue_parse(cd_img_name);
+  if (cue_data != NULL) {
+    cd_img_name = cue_data->tracks[1].fname;
+    *type = cue_data->tracks[1].type;
+  }
+
+  pmf = pm_open(cd_img_name);
+  if (pmf == NULL)
+  {
+    if (cue_data != NULL)
+      cue_destroy(cue_data);
+    return -1;
+  }
+  tracks[0].fd = pmf;
+
+  if (*type == CT_ISO)
+       cd_img_sectors = pmf->size >>= 11;  // size in sectors
+  else cd_img_sectors = pmf->size /= 2352;
+
+  // cdd.c operates with lba - 150
+  tracks[0].start = 0;
+  tracks[0].end = cd_img_sectors;
+  tracks[0].offset = 0;
+
+  sprintf_lba(tmp_ext, sizeof(tmp_ext), 0);
+  elprintf(EL_STATUS, "Track  1: %s %9i DATA  %s",
+    tmp_ext, tracks[0].end, cd_img_name);
+
+  lba = cd_img_sectors;
+
+  if (cue_data != NULL)
+  {
+    if (cue_data->tracks[2].fname == NULL) {
+      // NULL fname means track2 is in same file as track1
+      lba = tracks[0].end = cue_data->tracks[2].sector_offset;
+    }
+    i = 100 / cue_data->track_count + 1; // progress display
+
+    for (n = 2; n <= cue_data->track_count; n++)
+    {
+      if (PicoCDLoadProgressCB != NULL)
+        PicoCDLoadProgressCB(cd_img_name, i * n);
+
+      index = n - 1;
+      lba += cue_data->tracks[n].pregap;
+      if (cue_data->tracks[n].type == CT_MP3) {
+        ret = handle_mp3(cue_data->tracks[n].fname, index);
+        if (ret < 0)
+          break;
+        length = ret;
+      }
+      else if (cue_data->tracks[n].fname != NULL)
+      {
+        pm_file *f = pm_open(cue_data->tracks[n].fname);
+        if (f != NULL)
+        {
+          // assume raw, ignore header for wav..
+          tracks[index].fd = f;
+          tracks[index].offset = cue_data->tracks[n].sector_offset;
+          length = f->size / 2352;
+        }
+        else
+        {
+          elprintf(EL_STATUS, "track %2i (%s): can't determine length",
+            n, cue_data->tracks[n].fname);
+          tracks[index].offset = 0;
+          length = 2*75;
+        }
+      }
+      else
+      {
+        if (n < cue_data->track_count)
+          length = cue_data->tracks[n+1].sector_offset -
+            cue_data->tracks[n].sector_offset;
+        else
+          length = cd_img_sectors - cue_data->tracks[n].sector_offset;
+        tracks[index].offset = cue_data->tracks[n].sector_offset;
+      }
+
+      if (cue_data->tracks[n].sector_xlength != 0)
+        // overriden by custom cue command
+        length = cue_data->tracks[n].sector_xlength;
+
+      Pico_mcd->cdda_type = cue_data->tracks[n].type;
+
+      tracks[index].start = lba;
+      lba += length;
+      tracks[index].end = lba;
+
+      sprintf_lba(tmp_ext, sizeof(tmp_ext), tracks[index].start);
+      elprintf(EL_STATUS, "Track %2i: %s %9i AUDIO %s",
+        n, tmp_ext, length, cue_data->tracks[n].fname);
+    }
+    cue_destroy(cue_data);
+    goto finish;
+  }
+
+  /* mp3 track autosearch, Gens-like */
+  iso_name_len = strlen(cd_img_name);
+  if (iso_name_len >= sizeof(tmp_name))
+    iso_name_len = sizeof(tmp_name) - 1;
+
+  for (n = 2, i = 0, missed = 0; i < 100 && missed < 4; i++)
+  {
+    if (PicoCDLoadProgressCB != NULL && i > 1)
+      PicoCDLoadProgressCB(cd_img_name, i + (100-i)*missed/4);
+
+    for (j = 0; j < sizeof(exts)/sizeof(char *); j++)
+    {
+      int ext_len;
+      char *p;
+
+      index = n - 1;
+
+      snprintf(tmp_ext, sizeof(tmp_ext), exts[j], i);
+      ext_len = strlen(tmp_ext);
+      to_upper(tmp_ext_u, tmp_ext);
+
+      memcpy(tmp_name, cd_img_name, iso_name_len + 1);
+      p = tmp_name + iso_name_len - 4;
+
+      strcpy(p, tmp_ext);
+      ret = handle_mp3(tmp_name, index);
+      if (ret <= 0) {
+        strcpy(p, tmp_ext_u);
+        ret = handle_mp3(tmp_name, index);
+      }
+
+      if (ret <= 0 && i > 1 && iso_name_len > ext_len) {
+        p = tmp_name + iso_name_len - ext_len;
+        strcpy(p, tmp_ext);
+        ret = handle_mp3(tmp_name, index);
+        if (ret <= 0) {
+          strcpy(p, tmp_ext_u);
+          ret = handle_mp3(tmp_name, index);
+        }
+      }
+
+      if (ret > 0)
+      {
+        length = ret;
+        tracks[index].start = lba;
+        lba += length;
+        tracks[index].end = lba;
+
+        Pico_mcd->cdda_type = CT_MP3;
+
+        sprintf_lba(tmp_ext, sizeof(tmp_ext), tracks[index].start);
+        elprintf(EL_STATUS, "Track %2i: %s %9i AUDIO - %s",
+          n, tmp_ext, length, tmp_name);
+
+        n++;
+        missed = 0;
+        break;
+      }
+    }
+    if (ret <= 0 && i > 1)
+      missed++;
+  }
+
+finish:
+  cdd.toc.last = n - 1;
+  cdd.toc.end = lba;
+
+  sprintf_lba(tmp_ext, sizeof(tmp_ext), cdd.toc.end);
+  elprintf(EL_STATUS, "End CD -  %s\n", tmp_ext);
+
+  if (PicoCDLoadProgressCB != NULL)
+    PicoCDLoadProgressCB(cd_img_name, 100);
+
+  return 0;
+}
+
+// vim:shiftwidth=2:ts=2:expandtab
diff --git a/pico/cd/cd_sys.c b/pico/cd/cd_sys.c
deleted file mode 100644 (file)
index f7cd7b5..0000000
+++ /dev/null
@@ -1,933 +0,0 @@
-/***********************************************************\r
- *                                                         *\r
- * This source file was taken from the Gens project        *\r
- * Written by Stéphane Dallongeville                       *\r
- * Copyright (c) 2002 by Stéphane Dallongeville            *\r
- * Modified/adapted for PicoDrive by notaz, 2007           *\r
- *                                                         *\r
- ***********************************************************/\r
-\r
-#include <stdio.h>\r
-\r
-#include "../pico_int.h"\r
-#include "cd_sys.h"\r
-#include "cd_file.h"\r
-\r
-#define DEBUG_CD\r
-\r
-#define TRAY_OPEN      0x0500          // TRAY OPEN CDD status\r
-#define NOCD           0x0000          // CD removed CDD status\r
-#define STOPPED                0x0900          // STOPPED CDD status (happen after stop or close tray command)\r
-#define READY          0x0400          // READY CDD status (also used for seeking)\r
-#define FAST_FOW       0x0300          // FAST FORWARD track CDD status\r
-#define FAST_REV       0x10300         // FAST REVERSE track CDD status\r
-#define PLAYING                0x0100          // PLAYING audio track CDD status\r
-\r
-//#undef cdprintf\r
-//#define cdprintf(x, ...) elprintf(EL_STATUS, x, ##__VA_ARGS__)\r
-\r
-#define CDC_Update_Header()\r
-\r
-static int CD_Present = 0;\r
-\r
-\r
-#define CHECK_TRAY_OPEN                                \\r
-if (Pico_mcd->scd.Status_CDD == TRAY_OPEN)     \\r
-{                                                                      \\r
-       Pico_mcd->cdd.Status = Pico_mcd->scd.Status_CDD;        \\r
-                                                                       \\r
-       Pico_mcd->cdd.Minute = 0;                                       \\r
-       Pico_mcd->cdd.Seconde = 0;                              \\r
-       Pico_mcd->cdd.Frame = 0;                                        \\r
-       Pico_mcd->cdd.Ext = 0;                                  \\r
-                                                                       \\r
-       Pico_mcd->scd.CDD_Complete = 1;                         \\r
-                                                                       \\r
-       return 2;                                               \\r
-}\r
-\r
-\r
-#define CHECK_CD_PRESENT                       \\r
-if (!CD_Present)                                       \\r
-{                                                                      \\r
-       Pico_mcd->scd.Status_CDD = NOCD;                        \\r
-       Pico_mcd->cdd.Status = Pico_mcd->scd.Status_CDD;        \\r
-                                                                       \\r
-       Pico_mcd->cdd.Minute = 0;                                       \\r
-       Pico_mcd->cdd.Seconde = 0;                              \\r
-       Pico_mcd->cdd.Frame = 0;                                        \\r
-       Pico_mcd->cdd.Ext = 0;                                  \\r
-                                                                       \\r
-       Pico_mcd->scd.CDD_Complete = 1;                         \\r
-                                                                       \\r
-       return 3;                                               \\r
-}\r
-\r
-\r
-static int MSF_to_LBA(_msf *MSF)\r
-{\r
-       return (MSF->M * 60 * 75) + (MSF->S * 75) + MSF->F - 150;\r
-}\r
-\r
-\r
-PICO_INTERNAL void LBA_to_MSF(int lba, _msf *MSF)\r
-{\r
-       if (lba < -150) lba = 0;\r
-       else lba += 150;\r
-       MSF->M = lba / (60 * 75);\r
-       MSF->S = (lba / 75) % 60;\r
-       MSF->F = lba % 75;\r
-}\r
-\r
-\r
-static unsigned int MSF_to_Track(_msf *MSF)\r
-{\r
-       int i, Start, Cur;\r
-\r
-       Start = (MSF->M << 16) + (MSF->S << 8) + MSF->F;\r
-\r
-       for(i = 1; i <= (Pico_mcd->TOC.Last_Track + 1); i++)\r
-       {\r
-               Cur = Pico_mcd->TOC.Tracks[i - 1].MSF.M << 16;\r
-               Cur += Pico_mcd->TOC.Tracks[i - 1].MSF.S << 8;\r
-               Cur += Pico_mcd->TOC.Tracks[i - 1].MSF.F;\r
-\r
-               if (Cur > Start) break;\r
-       }\r
-\r
-       --i;\r
-\r
-       if (i > Pico_mcd->TOC.Last_Track) return 100;\r
-       else if (i < 1) i = 1;\r
-\r
-       return (unsigned) i;\r
-}\r
-\r
-\r
-static unsigned int LBA_to_Track(int lba)\r
-{\r
-       _msf MSF;\r
-\r
-       LBA_to_MSF(lba, &MSF);\r
-       return MSF_to_Track(&MSF);\r
-}\r
-\r
-\r
-static void Track_to_MSF(int track, _msf *MSF)\r
-{\r
-       if (track < 1) track = 1;\r
-       else if (track > Pico_mcd->TOC.Last_Track) track = Pico_mcd->TOC.Last_Track;\r
-\r
-       MSF->M = Pico_mcd->TOC.Tracks[track - 1].MSF.M;\r
-       MSF->S = Pico_mcd->TOC.Tracks[track - 1].MSF.S;\r
-       MSF->F = Pico_mcd->TOC.Tracks[track - 1].MSF.F;\r
-}\r
-\r
-\r
-PICO_INTERNAL int Track_to_LBA(int track)\r
-{\r
-       _msf MSF;\r
-\r
-       Track_to_MSF(track, &MSF);\r
-       return MSF_to_LBA(&MSF);\r
-}\r
-\r
-\r
-PICO_INTERNAL void Check_CD_Command(void)\r
-{\r
-       cdprintf("CHECK CD COMMAND");\r
-\r
-       // Check CDC\r
-       if (Pico_mcd->scd.Status_CDC & 1)                       // CDC is reading data ...\r
-       {\r
-               cdprintf("Got a read command");\r
-\r
-               // DATA ?\r
-               if (Pico_mcd->scd.Cur_Track == 1) {\r
-                    Pico_mcd->s68k_regs[0x36] |=  0x01;\r
-\r
-                 if (Pico_mcd->scd.File_Add_Delay == 0)\r
-                 {\r
-                       unsigned char header[4];\r
-                       _msf MSF;\r
-\r
-                       LBA_to_MSF(Pico_mcd->scd.Cur_LBA, &MSF);\r
-\r
-                       header[0] = INT_TO_BCDB(MSF.M);\r
-                       header[1] = INT_TO_BCDB(MSF.S);\r
-                       header[2] = INT_TO_BCDB(MSF.F);\r
-                       header[3] = 0x01;\r
-\r
-                       //FILE_Read_One_LBA_CDC();\r
-                       Pico_mcd->scd.Cur_LBA +=\r
-                         cdc_decoder_update(header);\r
-                 }\r
-                 else Pico_mcd->scd.File_Add_Delay--;\r
-               }\r
-               else {\r
-                       Pico_mcd->s68k_regs[0x36] &= ~0x01;                     // AUDIO\r
-                       unsigned char header[4] = { 0, };\r
-                       cdc_decoder_update(header);\r
-               }\r
-       }\r
-\r
-       // Check CDD\r
-       if (Pico_mcd->scd.CDD_Complete)\r
-       {\r
-               Pico_mcd->scd.CDD_Complete = 0;\r
-\r
-               CDD_Export_Status();\r
-       }\r
-\r
-       if (Pico_mcd->scd.Status_CDD == FAST_FOW)\r
-       {\r
-               Pico_mcd->scd.Cur_LBA += 10;\r
-               CDC_Update_Header();\r
-\r
-       }\r
-       else if (Pico_mcd->scd.Status_CDD == FAST_REV)\r
-       {\r
-               Pico_mcd->scd.Cur_LBA -= 10;\r
-               if (Pico_mcd->scd.Cur_LBA < -150) Pico_mcd->scd.Cur_LBA = -150;\r
-               CDC_Update_Header();\r
-       }\r
-}\r
-\r
-\r
-PICO_INTERNAL int Init_CD_Driver(void)\r
-{\r
-       return 0;\r
-}\r
-\r
-\r
-PICO_INTERNAL void End_CD_Driver(void)\r
-{\r
-       Unload_ISO();\r
-}\r
-\r
-\r
-PICO_INTERNAL void Reset_CD(void)\r
-{\r
-       Pico_mcd->scd.Cur_Track = 0;\r
-       Pico_mcd->scd.Cur_LBA = -150;\r
-       Pico_mcd->scd.Status_CDC &= ~1;\r
-       if (Pico_mcd->scd.Status_CDD != TRAY_OPEN)\r
-               Pico_mcd->scd.Status_CDD = CD_Present ? READY : NOCD;\r
-       Pico_mcd->scd.CDD_Complete = 0;\r
-       Pico_mcd->scd.File_Add_Delay = 0;\r
-}\r
-\r
-\r
-int Insert_CD(const char *cdimg_name, int type)\r
-{\r
-       int ret = 1;\r
-\r
-       CD_Present = 0;\r
-\r
-       if (cdimg_name != NULL && type != CIT_NOT_CD)\r
-       {\r
-               ret = Load_CD_Image(cdimg_name, type);\r
-               if (ret == 0) {\r
-                       CD_Present = 1;\r
-\r
-                       if (Pico_mcd->scd.Status_CDD == TRAY_OPEN)\r
-                       {\r
-                               if (Pico_mcd->bios[0x122 ^ 1] == '2')\r
-                                       Close_Tray_CDD_cC();\r
-                               // else bios will issue it\r
-                       }\r
-                       else\r
-                       {\r
-                               Pico_mcd->scd.Status_CDD = READY;\r
-                       }\r
-               }\r
-       }\r
-\r
-       if (Pico_mcd->scd.Status_CDD != TRAY_OPEN && !CD_Present)\r
-               Pico_mcd->scd.Status_CDD = NOCD;\r
-\r
-       return ret;\r
-}\r
-\r
-\r
-int Stop_CD(void)\r
-{\r
-       int ret = CD_Present;\r
-\r
-       Unload_ISO();\r
-       CD_Present = 0;\r
-\r
-       return ret;\r
-}\r
-\r
-\r
-/*\r
-PICO_INTERNAL void Change_CD(void)\r
-{\r
-       if (Pico_mcd->scd.Status_CDD == TRAY_OPEN) Close_Tray_CDD_cC();\r
-       else Open_Tray_CDD_cD();\r
-}\r
-*/\r
-\r
-PICO_INTERNAL int Get_Status_CDD_c0(void)\r
-{\r
-       cdprintf("Status command : Cur LBA = %d", Pico_mcd->scd.Cur_LBA);\r
-\r
-       // Clear immediat status\r
-       if ((Pico_mcd->cdd.Status & 0x0F00) == 0x0200)\r
-               Pico_mcd->cdd.Status = (Pico_mcd->scd.Status_CDD & 0xFF00) | (Pico_mcd->cdd.Status & 0x00FF);\r
-       else if ((Pico_mcd->cdd.Status & 0x0F00) == 0x0700)\r
-               Pico_mcd->cdd.Status = (Pico_mcd->scd.Status_CDD & 0xFF00) | (Pico_mcd->cdd.Status & 0x00FF);\r
-       else if ((Pico_mcd->cdd.Status & 0x0F00) == 0x0E00)\r
-               Pico_mcd->cdd.Status = (Pico_mcd->scd.Status_CDD & 0xFF00) | (Pico_mcd->cdd.Status & 0x00FF);\r
-\r
-       Pico_mcd->scd.CDD_Complete = 1;\r
-\r
-       return 0;\r
-}\r
-\r
-\r
-PICO_INTERNAL int Stop_CDD_c1(void)\r
-{\r
-       CHECK_TRAY_OPEN\r
-\r
-       Pico_mcd->scd.Status_CDC &= ~1;                         // Stop CDC read\r
-\r
-       if (CD_Present) Pico_mcd->scd.Status_CDD = STOPPED;\r
-       else Pico_mcd->scd.Status_CDD = NOCD;\r
-       Pico_mcd->cdd.Status = 0x0000;\r
-\r
-       Pico_mcd->s68k_regs[0x36] |= 0x01;                      // Data bit set because stopped\r
-\r
-       Pico_mcd->cdd.Minute = 0;\r
-       Pico_mcd->cdd.Seconde = 0;\r
-       Pico_mcd->cdd.Frame = 0;\r
-       Pico_mcd->cdd.Ext = 0;\r
-\r
-       Pico_mcd->scd.CDD_Complete = 1;\r
-\r
-       return 0;\r
-}\r
-\r
-\r
-PICO_INTERNAL int Get_Pos_CDD_c20(void)\r
-{\r
-       _msf MSF;\r
-\r
-       cdprintf("command 200 : Cur LBA = %d", Pico_mcd->scd.Cur_LBA);\r
-\r
-       CHECK_TRAY_OPEN\r
-\r
-       Pico_mcd->cdd.Status &= 0xFF;\r
-       if (!CD_Present)\r
-       {\r
-               Pico_mcd->scd.Status_CDD = NOCD;\r
-               Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;\r
-       }\r
-//     else if (!(CDC.CTRL.B.B0 & 0x80)) Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;\r
-       Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;\r
-\r
-       cdprintf("Status CDD = %.4X  Status = %.4X", Pico_mcd->scd.Status_CDD, Pico_mcd->cdd.Status);\r
-\r
-       LBA_to_MSF(Pico_mcd->scd.Cur_LBA, &MSF);\r
-\r
-       Pico_mcd->cdd.Minute = INT_TO_BCDW(MSF.M);\r
-       Pico_mcd->cdd.Seconde = INT_TO_BCDW(MSF.S);\r
-       Pico_mcd->cdd.Frame = INT_TO_BCDW(MSF.F);\r
-       Pico_mcd->cdd.Ext = 0;\r
-\r
-       Pico_mcd->scd.CDD_Complete = 1;\r
-\r
-       return 0;\r
-}\r
-\r
-\r
-PICO_INTERNAL int Get_Track_Pos_CDD_c21(void)\r
-{\r
-       int elapsed_time;\r
-       _msf MSF;\r
-\r
-       cdprintf("command 201 : Cur LBA = %d", Pico_mcd->scd.Cur_LBA);\r
-\r
-       CHECK_TRAY_OPEN\r
-\r
-       Pico_mcd->cdd.Status &= 0xFF;\r
-       if (!CD_Present)\r
-       {\r
-               Pico_mcd->scd.Status_CDD = NOCD;\r
-               Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;\r
-       }\r
-//     else if (!(CDC.CTRL.B.B0 & 0x80)) Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;\r
-       Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;\r
-\r
-       elapsed_time = Pico_mcd->scd.Cur_LBA - Track_to_LBA(LBA_to_Track(Pico_mcd->scd.Cur_LBA));\r
-       LBA_to_MSF(elapsed_time - 150, &MSF);\r
-\r
-       cdprintf("   elapsed = %d", elapsed_time);\r
-\r
-       Pico_mcd->cdd.Minute = INT_TO_BCDW(MSF.M);\r
-       Pico_mcd->cdd.Seconde = INT_TO_BCDW(MSF.S);\r
-       Pico_mcd->cdd.Frame = INT_TO_BCDW(MSF.F);\r
-       Pico_mcd->cdd.Ext = 0;\r
-\r
-       Pico_mcd->scd.CDD_Complete = 1;\r
-\r
-       return 0;\r
-}\r
-\r
-\r
-PICO_INTERNAL int Get_Current_Track_CDD_c22(void)\r
-{\r
-       cdprintf("Status CDD = %.4X  Status = %.4X", Pico_mcd->scd.Status_CDD, Pico_mcd->cdd.Status);\r
-\r
-       CHECK_TRAY_OPEN\r
-\r
-       Pico_mcd->cdd.Status &= 0xFF;\r
-       if (!CD_Present)\r
-       {\r
-               Pico_mcd->scd.Status_CDD = NOCD;\r
-               Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;\r
-       }\r
-//     else if (!(CDC.CTRL.B.B0 & 0x80)) Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;\r
-       Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;\r
-\r
-       Pico_mcd->scd.Cur_Track = LBA_to_Track(Pico_mcd->scd.Cur_LBA);\r
-\r
-       if (Pico_mcd->scd.Cur_Track == 100) Pico_mcd->cdd.Minute = 0x0A02;\r
-       else Pico_mcd->cdd.Minute = INT_TO_BCDW(Pico_mcd->scd.Cur_Track);\r
-       Pico_mcd->cdd.Seconde = 0;\r
-       Pico_mcd->cdd.Frame = 0;\r
-       Pico_mcd->cdd.Ext = 0;\r
-\r
-       Pico_mcd->scd.CDD_Complete = 1;\r
-\r
-       return 0;\r
-}\r
-\r
-\r
-PICO_INTERNAL int Get_Total_Lenght_CDD_c23(void)\r
-{\r
-       CHECK_TRAY_OPEN\r
-\r
-       Pico_mcd->cdd.Status &= 0xFF;\r
-       if (!CD_Present)\r
-       {\r
-               Pico_mcd->scd.Status_CDD = NOCD;\r
-               Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;\r
-       }\r
-//     else if (!(CDC.CTRL.B.B0 & 0x80)) Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;\r
-       Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;\r
-\r
-       Pico_mcd->cdd.Minute = INT_TO_BCDW(Pico_mcd->TOC.Tracks[Pico_mcd->TOC.Last_Track].MSF.M);\r
-       Pico_mcd->cdd.Seconde = INT_TO_BCDW(Pico_mcd->TOC.Tracks[Pico_mcd->TOC.Last_Track].MSF.S);\r
-       Pico_mcd->cdd.Frame = INT_TO_BCDW(Pico_mcd->TOC.Tracks[Pico_mcd->TOC.Last_Track].MSF.F);\r
-       Pico_mcd->cdd.Ext = 0;\r
-\r
-       Pico_mcd->scd.CDD_Complete = 1;\r
-\r
-       return 0;\r
-}\r
-\r
-\r
-PICO_INTERNAL int Get_First_Last_Track_CDD_c24(void)\r
-{\r
-       CHECK_TRAY_OPEN\r
-\r
-       Pico_mcd->cdd.Status &= 0xFF;\r
-       if (!CD_Present)\r
-       {\r
-               Pico_mcd->scd.Status_CDD = NOCD;\r
-       }\r
-//     else if (!(CDC.CTRL.B.B0 & 0x80)) Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;\r
-       Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;\r
-\r
-       Pico_mcd->cdd.Minute = INT_TO_BCDW(1);\r
-       Pico_mcd->cdd.Seconde = INT_TO_BCDW(Pico_mcd->TOC.Last_Track);\r
-       Pico_mcd->cdd.Frame = 0;\r
-       Pico_mcd->cdd.Ext = 0;\r
-\r
-       Pico_mcd->scd.CDD_Complete = 1;\r
-\r
-       return 0;\r
-}\r
-\r
-\r
-PICO_INTERNAL int Get_Track_Adr_CDD_c25(void)\r
-{\r
-       int track_number;\r
-\r
-       CHECK_TRAY_OPEN\r
-\r
-       // track number in TC4 & TC5\r
-\r
-       track_number = (Pico_mcd->s68k_regs[0x38+10+4] & 0xF) * 10 + (Pico_mcd->s68k_regs[0x38+10+5] & 0xF);\r
-\r
-       Pico_mcd->cdd.Status &= 0xFF;\r
-       if (!CD_Present)\r
-       {\r
-               Pico_mcd->scd.Status_CDD = NOCD;\r
-               Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;\r
-       }\r
-//     else if (!(CDC.CTRL.B.B0 & 0x80)) Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;\r
-       Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;\r
-\r
-       if (track_number > Pico_mcd->TOC.Last_Track) track_number = Pico_mcd->TOC.Last_Track;\r
-       else if (track_number < 1) track_number = 1;\r
-\r
-       Pico_mcd->cdd.Minute = INT_TO_BCDW(Pico_mcd->TOC.Tracks[track_number - 1].MSF.M);\r
-       Pico_mcd->cdd.Seconde = INT_TO_BCDW(Pico_mcd->TOC.Tracks[track_number - 1].MSF.S);\r
-       Pico_mcd->cdd.Frame = INT_TO_BCDW(Pico_mcd->TOC.Tracks[track_number - 1].MSF.F);\r
-       Pico_mcd->cdd.Ext = track_number % 10;\r
-\r
-       if (track_number == 1) Pico_mcd->cdd.Frame |= 0x0800; // data track\r
-\r
-       Pico_mcd->scd.CDD_Complete = 1;\r
-       return 0;\r
-}\r
-\r
-\r
-PICO_INTERNAL int Play_CDD_c3(void)\r
-{\r
-       _msf MSF;\r
-       int delay, new_lba;\r
-\r
-       CHECK_TRAY_OPEN\r
-       CHECK_CD_PRESENT\r
-\r
-       // MSF of the track to play in TC buffer\r
-\r
-       MSF.M = (Pico_mcd->s68k_regs[0x38+10+2] & 0xF) * 10 + (Pico_mcd->s68k_regs[0x38+10+3] & 0xF);\r
-       MSF.S = (Pico_mcd->s68k_regs[0x38+10+4] & 0xF) * 10 + (Pico_mcd->s68k_regs[0x38+10+5] & 0xF);\r
-       MSF.F = (Pico_mcd->s68k_regs[0x38+10+6] & 0xF) * 10 + (Pico_mcd->s68k_regs[0x38+10+7] & 0xF);\r
-\r
-       Pico_mcd->scd.Cur_Track = MSF_to_Track(&MSF);\r
-\r
-       new_lba = MSF_to_LBA(&MSF);\r
-       delay = new_lba - Pico_mcd->scd.Cur_LBA;\r
-       if (delay < 0) delay = -delay;\r
-       delay >>= 12;\r
-\r
-       if (Pico_mcd->scd.Cur_LBA > 0 && delay < 13)\r
-               // based on genplus GX\r
-               delay = 13;\r
-\r
-       Pico_mcd->scd.Cur_LBA = new_lba;\r
-       CDC_Update_Header();\r
-\r
-       cdprintf("Read : Cur LBA = %d, M=%d, S=%d, F=%d", Pico_mcd->scd.Cur_LBA, MSF.M, MSF.S, MSF.F);\r
-\r
-       if (Pico_mcd->scd.Status_CDD != PLAYING) delay += 20;\r
-\r
-       Pico_mcd->scd.Status_CDD = PLAYING;\r
-       Pico_mcd->cdd.Status = 0x0102;\r
-//     Pico_mcd->cdd.Status = COMM_OK;\r
-\r
-       if (Pico_mcd->scd.File_Add_Delay == 0) Pico_mcd->scd.File_Add_Delay = delay;\r
-\r
-       if (Pico_mcd->scd.Cur_Track == 1)\r
-       {\r
-               Pico_mcd->s68k_regs[0x36] |=  0x01;                             // DATA\r
-       }\r
-       else\r
-       {\r
-               Pico_mcd->s68k_regs[0x36] &= ~0x01;                             // AUDIO\r
-               cdda_start_play();\r
-       }\r
-\r
-       if (Pico_mcd->scd.Cur_Track == 100) Pico_mcd->cdd.Minute = 0x0A02;\r
-       else Pico_mcd->cdd.Minute = INT_TO_BCDW(Pico_mcd->scd.Cur_Track);\r
-       Pico_mcd->cdd.Seconde = 0;\r
-       Pico_mcd->cdd.Frame = 0;\r
-       Pico_mcd->cdd.Ext = 0;\r
-\r
-       Pico_mcd->scd.Status_CDC |= 1;                  // Read data with CDC\r
-\r
-       Pico_mcd->scd.CDD_Complete = 1;\r
-       return 0;\r
-}\r
-\r
-\r
-PICO_INTERNAL int Seek_CDD_c4(void)\r
-{\r
-       _msf MSF;\r
-\r
-       CHECK_TRAY_OPEN\r
-       CHECK_CD_PRESENT\r
-\r
-       // MSF to seek in TC buffer\r
-\r
-       MSF.M = (Pico_mcd->s68k_regs[0x38+10+2] & 0xF) * 10 + (Pico_mcd->s68k_regs[0x38+10+3] & 0xF);\r
-       MSF.S = (Pico_mcd->s68k_regs[0x38+10+4] & 0xF) * 10 + (Pico_mcd->s68k_regs[0x38+10+5] & 0xF);\r
-       MSF.F = (Pico_mcd->s68k_regs[0x38+10+6] & 0xF) * 10 + (Pico_mcd->s68k_regs[0x38+10+7] & 0xF);\r
-\r
-       Pico_mcd->scd.Cur_Track = MSF_to_Track(&MSF);\r
-       Pico_mcd->scd.Cur_LBA = MSF_to_LBA(&MSF);\r
-       CDC_Update_Header();\r
-\r
-       Pico_mcd->scd.Status_CDC &= ~1;                         // Stop CDC read\r
-\r
-       Pico_mcd->scd.Status_CDD = READY;\r
-       Pico_mcd->cdd.Status = 0x0200;\r
-\r
-       // DATA ?\r
-       if (Pico_mcd->scd.Cur_Track == 1)\r
-            Pico_mcd->s68k_regs[0x36] |=  0x01;\r
-       else Pico_mcd->s68k_regs[0x36] &= ~0x01;                // AUDIO\r
-\r
-       Pico_mcd->cdd.Minute = 0;\r
-       Pico_mcd->cdd.Seconde = 0;\r
-       Pico_mcd->cdd.Frame = 0;\r
-       Pico_mcd->cdd.Ext = 0;\r
-\r
-       Pico_mcd->scd.CDD_Complete = 1;\r
-\r
-       return 0;\r
-}\r
-\r
-\r
-PICO_INTERNAL int Pause_CDD_c6(void)\r
-{\r
-       CHECK_TRAY_OPEN\r
-       CHECK_CD_PRESENT\r
-\r
-       Pico_mcd->scd.Status_CDC &= ~1;                 // Stop CDC read to start a new one if raw data\r
-\r
-       Pico_mcd->scd.Status_CDD = READY;\r
-       Pico_mcd->cdd.Status = Pico_mcd->scd.Status_CDD;\r
-\r
-       Pico_mcd->s68k_regs[0x36] |= 0x01;              // Data bit set because stopped\r
-\r
-       Pico_mcd->cdd.Minute = 0;\r
-       Pico_mcd->cdd.Seconde = 0;\r
-       Pico_mcd->cdd.Frame = 0;\r
-       Pico_mcd->cdd.Ext = 0;\r
-\r
-       Pico_mcd->scd.CDD_Complete = 1;\r
-\r
-       return 0;\r
-}\r
-\r
-\r
-PICO_INTERNAL int Resume_CDD_c7(void)\r
-{\r
-       CHECK_TRAY_OPEN\r
-       CHECK_CD_PRESENT\r
-\r
-       Pico_mcd->scd.Cur_Track = LBA_to_Track(Pico_mcd->scd.Cur_LBA);\r
-\r
-#ifdef DEBUG_CD\r
-       {\r
-               _msf MSF;\r
-               LBA_to_MSF(Pico_mcd->scd.Cur_LBA, &MSF);\r
-               cdprintf("Resume read : Cur LBA = %d, M=%d, S=%d, F=%d", Pico_mcd->scd.Cur_LBA, MSF.M, MSF.S, MSF.F);\r
-       }\r
-#endif\r
-\r
-       Pico_mcd->scd.Status_CDD = PLAYING;\r
-       Pico_mcd->cdd.Status = 0x0102;\r
-\r
-       if (Pico_mcd->scd.Cur_Track == 1)\r
-       {\r
-               Pico_mcd->s68k_regs[0x36] |=  0x01;                             // DATA\r
-       }\r
-       else\r
-       {\r
-               Pico_mcd->s68k_regs[0x36] &= ~0x01;                             // AUDIO\r
-               cdda_start_play();\r
-       }\r
-\r
-       if (Pico_mcd->scd.Cur_Track == 100) Pico_mcd->cdd.Minute = 0x0A02;\r
-       else Pico_mcd->cdd.Minute = INT_TO_BCDW(Pico_mcd->scd.Cur_Track);\r
-       Pico_mcd->cdd.Seconde = 0;\r
-       Pico_mcd->cdd.Frame = 0;\r
-       Pico_mcd->cdd.Ext = 0;\r
-\r
-       Pico_mcd->scd.Status_CDC |= 1;                  // Read data with CDC\r
-\r
-       Pico_mcd->scd.CDD_Complete = 1;\r
-       return 0;\r
-}\r
-\r
-\r
-PICO_INTERNAL int Fast_Foward_CDD_c8(void)\r
-{\r
-       CHECK_TRAY_OPEN\r
-       CHECK_CD_PRESENT\r
-\r
-       Pico_mcd->scd.Status_CDC &= ~1;                         // Stop CDC read\r
-\r
-       Pico_mcd->scd.Status_CDD = FAST_FOW;\r
-       Pico_mcd->cdd.Status = Pico_mcd->scd.Status_CDD | 2;\r
-\r
-       Pico_mcd->cdd.Minute = INT_TO_BCDW(Pico_mcd->scd.Cur_Track);\r
-       Pico_mcd->cdd.Seconde = 0;\r
-       Pico_mcd->cdd.Frame = 0;\r
-       Pico_mcd->cdd.Ext = 0;\r
-\r
-       Pico_mcd->scd.CDD_Complete = 1;\r
-\r
-       return 0;\r
-}\r
-\r
-\r
-PICO_INTERNAL int Fast_Rewind_CDD_c9(void)\r
-{\r
-       CHECK_TRAY_OPEN\r
-       CHECK_CD_PRESENT\r
-\r
-       Pico_mcd->scd.Status_CDC &= ~1;                         // Stop CDC read\r
-\r
-       Pico_mcd->scd.Status_CDD = FAST_REV;\r
-       Pico_mcd->cdd.Status = Pico_mcd->scd.Status_CDD | 2;\r
-\r
-       Pico_mcd->cdd.Minute = INT_TO_BCDW(Pico_mcd->scd.Cur_Track);\r
-       Pico_mcd->cdd.Seconde = 0;\r
-       Pico_mcd->cdd.Frame = 0;\r
-       Pico_mcd->cdd.Ext = 0;\r
-\r
-       Pico_mcd->scd.CDD_Complete = 1;\r
-\r
-       return 0;\r
-}\r
-\r
-\r
-PICO_INTERNAL int Close_Tray_CDD_cC(void)\r
-{\r
-       Pico_mcd->scd.Status_CDC &= ~1;                 // Stop CDC read\r
-\r
-       elprintf(EL_STATUS, "tray close\n");\r
-\r
-       if (PicoMCDcloseTray != NULL)\r
-               PicoMCDcloseTray();\r
-\r
-       Pico_mcd->scd.Status_CDD = CD_Present ? STOPPED : NOCD;\r
-       Pico_mcd->cdd.Status = 0x0000;\r
-\r
-       Pico_mcd->cdd.Minute = 0;\r
-       Pico_mcd->cdd.Seconde = 0;\r
-       Pico_mcd->cdd.Frame = 0;\r
-       Pico_mcd->cdd.Ext = 0;\r
-\r
-       Pico_mcd->scd.CDD_Complete = 1;\r
-\r
-       return 0;\r
-}\r
-\r
-\r
-PICO_INTERNAL int Open_Tray_CDD_cD(void)\r
-{\r
-       CHECK_TRAY_OPEN\r
-\r
-       Pico_mcd->scd.Status_CDC &= ~1;                 // Stop CDC read\r
-\r
-       elprintf(EL_STATUS, "tray open\n");\r
-\r
-       Unload_ISO();\r
-       CD_Present = 0;\r
-\r
-       if (PicoMCDopenTray != NULL)\r
-               PicoMCDopenTray();\r
-\r
-       Pico_mcd->scd.Status_CDD = TRAY_OPEN;\r
-       Pico_mcd->cdd.Status = 0x0E00;\r
-\r
-       Pico_mcd->cdd.Minute = 0;\r
-       Pico_mcd->cdd.Seconde = 0;\r
-       Pico_mcd->cdd.Frame = 0;\r
-       Pico_mcd->cdd.Ext = 0;\r
-\r
-       Pico_mcd->scd.CDD_Complete = 1;\r
-\r
-       return 0;\r
-}\r
-\r
-\r
-PICO_INTERNAL int CDD_cA(void)\r
-{\r
-       CHECK_TRAY_OPEN\r
-       CHECK_CD_PRESENT\r
-\r
-       Pico_mcd->scd.Status_CDC &= ~1;\r
-\r
-       Pico_mcd->scd.Status_CDD = READY;\r
-       Pico_mcd->cdd.Status = Pico_mcd->scd.Status_CDD;\r
-\r
-       Pico_mcd->cdd.Minute = 0;\r
-       Pico_mcd->cdd.Seconde = INT_TO_BCDW(1);\r
-       Pico_mcd->cdd.Frame = INT_TO_BCDW(1);\r
-       Pico_mcd->cdd.Ext = 0;\r
-\r
-       Pico_mcd->scd.CDD_Complete = 1;\r
-\r
-       return 0;\r
-}\r
-\r
-\r
-PICO_INTERNAL int CDD_Def(void)\r
-{\r
-       Pico_mcd->cdd.Status = Pico_mcd->scd.Status_CDD;\r
-\r
-       Pico_mcd->cdd.Minute = 0;\r
-       Pico_mcd->cdd.Seconde = 0;\r
-       Pico_mcd->cdd.Frame = 0;\r
-       Pico_mcd->cdd.Ext = 0;\r
-\r
-       return 0;\r
-}\r
-\r
-\r
-static int bswapwrite(int a, unsigned short d)\r
-{\r
-       *(unsigned short *)(Pico_mcd->s68k_regs + a) = (d>>8)|(d<<8);\r
-       return d + (d >> 8);\r
-}\r
-\r
-PICO_INTERNAL void CDD_Export_Status(void)\r
-{\r
-       unsigned int csum;\r
-\r
-       csum  = bswapwrite( 0x38+0, Pico_mcd->cdd.Status);\r
-       csum += bswapwrite( 0x38+2, Pico_mcd->cdd.Minute);\r
-       csum += bswapwrite( 0x38+4, Pico_mcd->cdd.Seconde);\r
-       csum += bswapwrite( 0x38+6, Pico_mcd->cdd.Frame);\r
-       Pico_mcd->s68k_regs[0x38+8] = Pico_mcd->cdd.Ext;\r
-       csum += Pico_mcd->cdd.Ext;\r
-       Pico_mcd->s68k_regs[0x38+9] = ~csum & 0xf;\r
-\r
-       Pico_mcd->s68k_regs[0x37] &= 3; // CDD.Control\r
-\r
-       if (Pico_mcd->s68k_regs[0x33] & PCDS_IEN4)\r
-       {\r
-               elprintf(EL_INTS, "cdd export irq 4");\r
-               SekInterruptS68k(4);\r
-       }\r
-\r
-//     cdprintf("CDD exported status\n");\r
-       cdprintf("out:  Status=%.4X, Minute=%.4X, Second=%.4X, Frame=%.4X  Checksum=%.4X",\r
-               (Pico_mcd->s68k_regs[0x38+0] << 8) | Pico_mcd->s68k_regs[0x38+1],\r
-               (Pico_mcd->s68k_regs[0x38+2] << 8) | Pico_mcd->s68k_regs[0x38+3],\r
-               (Pico_mcd->s68k_regs[0x38+4] << 8) | Pico_mcd->s68k_regs[0x38+5],\r
-               (Pico_mcd->s68k_regs[0x38+6] << 8) | Pico_mcd->s68k_regs[0x38+7],\r
-               (Pico_mcd->s68k_regs[0x38+8] << 8) | Pico_mcd->s68k_regs[0x38+9]);\r
-}\r
-\r
-\r
-PICO_INTERNAL void CDD_Import_Command(void)\r
-{\r
-//     cdprintf("CDD importing command\n");\r
-       cdprintf("in:  Command=%.4X, Minute=%.4X, Second=%.4X, Frame=%.4X  Checksum=%.4X",\r
-               (Pico_mcd->s68k_regs[0x38+10+0] << 8) | Pico_mcd->s68k_regs[0x38+10+1],\r
-               (Pico_mcd->s68k_regs[0x38+10+2] << 8) | Pico_mcd->s68k_regs[0x38+10+3],\r
-               (Pico_mcd->s68k_regs[0x38+10+4] << 8) | Pico_mcd->s68k_regs[0x38+10+5],\r
-               (Pico_mcd->s68k_regs[0x38+10+6] << 8) | Pico_mcd->s68k_regs[0x38+10+7],\r
-               (Pico_mcd->s68k_regs[0x38+10+8] << 8) | Pico_mcd->s68k_regs[0x38+10+9]);\r
-\r
-       switch (Pico_mcd->s68k_regs[0x38+10+0])\r
-       {\r
-               case 0x0:       // STATUS (?)\r
-                       Get_Status_CDD_c0();\r
-                       break;\r
-\r
-               case 0x1:       // STOP ALL (?)\r
-                       Stop_CDD_c1();\r
-                       break;\r
-\r
-               case 0x2:       // GET TOC INFORMATIONS\r
-                       switch(Pico_mcd->s68k_regs[0x38+10+3])\r
-                       {\r
-                               case 0x0:       // get current position (MSF format)\r
-                                       Pico_mcd->cdd.Status = (Pico_mcd->cdd.Status & 0xFF00);\r
-                                       Get_Pos_CDD_c20();\r
-                                       break;\r
-\r
-                               case 0x1:       // get elapsed time of current track played/scanned (relative MSF format)\r
-                                       Pico_mcd->cdd.Status = (Pico_mcd->cdd.Status & 0xFF00) | 1;\r
-                                       Get_Track_Pos_CDD_c21();\r
-                                       break;\r
-\r
-                               case 0x2:       // get current track in RS2-RS3\r
-                                       Pico_mcd->cdd.Status =  (Pico_mcd->cdd.Status & 0xFF00) | 2;\r
-                                       Get_Current_Track_CDD_c22();\r
-                                       break;\r
-\r
-                               case 0x3:       // get total length (MSF format)\r
-                                       Pico_mcd->cdd.Status = (Pico_mcd->cdd.Status & 0xFF00) | 3;\r
-                                       Get_Total_Lenght_CDD_c23();\r
-                                       break;\r
-\r
-                               case 0x4:       // first & last track number\r
-                                       Pico_mcd->cdd.Status = (Pico_mcd->cdd.Status & 0xFF00) | 4;\r
-                                       Get_First_Last_Track_CDD_c24();\r
-                                       break;\r
-\r
-                               case 0x5:       // get track addresse (MSF format)\r
-                                       Pico_mcd->cdd.Status = (Pico_mcd->cdd.Status & 0xFF00) | 5;\r
-                                       Get_Track_Adr_CDD_c25();\r
-                                       break;\r
-\r
-                               default :       // invalid, then we return status\r
-                                       Pico_mcd->cdd.Status = (Pico_mcd->cdd.Status & 0xFF00) | 0xF;\r
-                                       Get_Status_CDD_c0();\r
-                                       break;\r
-                       }\r
-                       break;\r
-\r
-               case 0x3:       // READ\r
-                       Play_CDD_c3();\r
-                       break;\r
-\r
-               case 0x4:       // SEEK\r
-                       Seek_CDD_c4();\r
-                       break;\r
-\r
-               case 0x6:       // PAUSE/STOP\r
-                       Pause_CDD_c6();\r
-                       break;\r
-\r
-               case 0x7:       // RESUME\r
-                       Resume_CDD_c7();\r
-                       break;\r
-\r
-               case 0x8:       // FAST FOWARD\r
-                       Fast_Foward_CDD_c8();\r
-                       break;\r
-\r
-               case 0x9:       // FAST REWIND\r
-                       Fast_Rewind_CDD_c9();\r
-                       break;\r
-\r
-               case 0xA:       // RECOVER INITIAL STATE (?)\r
-                       CDD_cA();\r
-                       break;\r
-\r
-               case 0xC:       // CLOSE TRAY\r
-                       Close_Tray_CDD_cC();\r
-                       break;\r
-\r
-               case 0xD:       // OPEN TRAY\r
-                       Open_Tray_CDD_cD();\r
-                       break;\r
-\r
-               default:        // UNKNOWN\r
-                       CDD_Def();\r
-                       break;\r
-       }\r
-}\r
-\r
-void CDD_Reset(void)\r
-{\r
-       // Reseting CDD\r
-\r
-       memset(Pico_mcd->s68k_regs+0x34, 0, 2*2); // CDD.Fader, CDD.Control\r
-       Pico_mcd->cdd.Status = 0;\r
-       Pico_mcd->cdd.Minute = 0;\r
-       Pico_mcd->cdd.Seconde = 0;\r
-       Pico_mcd->cdd.Frame = 0;\r
-       Pico_mcd->cdd.Ext = 0;\r
-\r
-       // clear receive status and transfer command\r
-       memset(Pico_mcd->s68k_regs+0x38, 0, 20);\r
-       Pico_mcd->s68k_regs[0x38+9] = 0xF;              // Default checksum\r
-}\r
-\r
-\r
diff --git a/pico/cd/cd_sys.h b/pico/cd/cd_sys.h
deleted file mode 100644 (file)
index 6291c2c..0000000
+++ /dev/null
@@ -1,109 +0,0 @@
-/***********************************************************\r
- *                                                         *\r
- * This source was taken from the Gens project             *\r
- * Written by Stéphane Dallongeville                       *\r
- * Copyright (c) 2002 by Stéphane Dallongeville            *\r
- * Modified/adapted for PicoDrive by notaz, 2007           *\r
- *                                                         *\r
- ***********************************************************/\r
-\r
-#ifndef _CD_SYS_H\r
-#define _CD_SYS_H\r
-\r
-#include "cd_file.h"\r
-\r
-#ifdef __cplusplus\r
-extern "C" {\r
-#endif\r
-\r
-\r
-#define INT_TO_BCDB(c)                                                                         \\r
-((c) > 99)?(0x99):((((c) / 10) << 4) + ((c) % 10));\r
-\r
-#define INT_TO_BCDW(c)                                                                         \\r
-((c) > 99)?(0x0909):((((c) / 10) << 8) + ((c) % 10));\r
-\r
-#define BCDB_TO_INT(c)                                                                         \\r
-(((c) >> 4) * 10) + ((c) & 0xF);\r
-\r
-#define BCDW_TO_INT(c)                                                                         \\r
-(((c) >> 8) * 10) + ((c) & 0xF);\r
-\r
-\r
-typedef struct\r
-{\r
-  unsigned char M;\r
-  unsigned char S;\r
-  unsigned char F;\r
-} _msf;\r
-\r
-typedef struct\r
-{\r
-       _msf MSF;\r
-       //\r
-       char ftype; // cue_track_type\r
-       void *F;\r
-       int Length;\r
-       int Offset;  // sector offset, when single file is used for multiple virtual tracks\r
-       short KBtps; // kbytes per sec for mp3s (bitrate / 1000 / 8)\r
-       short pad;\r
-} _scd_track;\r
-\r
-typedef struct\r
-{\r
-//     unsigned char First_Track; // always 1\r
-       _scd_track Tracks[100];\r
-       unsigned int Last_Track;\r
-} _scd_toc;\r
-\r
-typedef struct {\r
-       unsigned int Status_CDD;\r
-       unsigned int Status_CDC;\r
-       int Cur_LBA;\r
-       unsigned int Cur_Track;\r
-       int File_Add_Delay;\r
-       char CDD_Complete;\r
-       int pad[6];\r
-} _scd;\r
-\r
-\r
-PICO_INTERNAL void LBA_to_MSF(int lba, _msf *MSF);\r
-PICO_INTERNAL int  Track_to_LBA(int track);\r
-\r
-// moved to pico.h\r
-// int  Insert_CD(char *iso_name, int is_bin);\r
-// void Stop_CD(void);\r
-\r
-PICO_INTERNAL void Check_CD_Command(void);\r
-\r
-PICO_INTERNAL int  Init_CD_Driver(void);\r
-PICO_INTERNAL void End_CD_Driver(void);\r
-PICO_INTERNAL void Reset_CD(void);\r
-\r
-PICO_INTERNAL int Get_Status_CDD_c0(void);\r
-PICO_INTERNAL int Stop_CDD_c1(void);\r
-PICO_INTERNAL int Get_Pos_CDD_c20(void);\r
-PICO_INTERNAL int Get_Track_Pos_CDD_c21(void);\r
-PICO_INTERNAL int Get_Current_Track_CDD_c22(void);\r
-PICO_INTERNAL int Get_Total_Lenght_CDD_c23(void);\r
-PICO_INTERNAL int Get_First_Last_Track_CDD_c24(void);\r
-PICO_INTERNAL int Get_Track_Adr_CDD_c25(void);\r
-PICO_INTERNAL int Play_CDD_c3(void);\r
-PICO_INTERNAL int Seek_CDD_c4(void);\r
-PICO_INTERNAL int Pause_CDD_c6(void);\r
-PICO_INTERNAL int Resume_CDD_c7(void);\r
-PICO_INTERNAL int Fast_Foward_CDD_c8(void);\r
-PICO_INTERNAL int Fast_Rewind_CDD_c9(void);\r
-PICO_INTERNAL int CDD_cA(void);\r
-PICO_INTERNAL int Close_Tray_CDD_cC(void);\r
-PICO_INTERNAL int Open_Tray_CDD_cD(void);\r
-\r
-PICO_INTERNAL int CDD_Def(void);\r
-\r
-\r
-#ifdef __cplusplus\r
-};\r
-#endif\r
-\r
-#endif\r
-\r
index aa1ded9..8b47b3d 100644 (file)
@@ -341,19 +341,6 @@ update_dma:
   Pico_mcd->s68k_regs[0x0b] = dma_addr;
 }
 
-// tmp
-static void cdd_read_data(uint8 *dst)
-{
-  int lba = Pico_mcd->scd.Cur_LBA;
-
-  /* only read DATA track sectors */
-  if (0 <= lba && lba < Pico_mcd->TOC.Tracks[0].Length)
-  {
-    /* read sector data (Mode 1 = 2048 bytes) */
-    PicoCDBufferRead(dst, lba);
-  }
-}
-
 void cdc_dma_update(void)
 {
   /* end of DMA transfer ? */
diff --git a/pico/cd/cdd.c b/pico/cd/cdd.c
new file mode 100644 (file)
index 0000000..58a6053
--- /dev/null
@@ -0,0 +1,1328 @@
+/***************************************************************************************
+ *  Genesis Plus
+ *  CD drive processor & CD-DA fader
+ *
+ *  Copyright (C) 2012-2013  Eke-Eke (Genesis Plus GX)
+ *
+ *  Redistribution and use of this code or any derivative works are permitted
+ *  provided that the following conditions are met:
+ *
+ *   - Redistributions may not be sold, nor may they be used in a commercial
+ *     product or activity.
+ *
+ *   - Redistributions that are modified from the original source must include the
+ *     complete source code, including the source code for all components used by a
+ *     binary built from the modified sources. However, as a special exception, the
+ *     source code distributed need not include anything that is normally distributed
+ *     (in either source or binary form) with the major components (compiler, kernel,
+ *     and so on) of the operating system on which the executable runs, unless that
+ *     component itself accompanies the executable.
+ *
+ *   - Redistributions must reproduce the above copyright notice, this list of
+ *     conditions and the following disclaimer in the documentation and/or other
+ *     materials provided with the distribution.
+ *
+ *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ *  POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************************/
+
+#include "../pico_int.h"
+#include "genplus_macros.h"
+#include "cue.h"
+#include "cdd.h"
+
+#ifdef USE_LIBTREMOR
+#define SUPPORTED_EXT 20
+#else
+#define SUPPORTED_EXT 10
+#endif
+
+cdd_t cdd;
+
+/* BCD conversion lookup tables */
+static const uint8 lut_BCD_8[100] =
+{
+  0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 
+  0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 
+  0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 
+  0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 
+  0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 
+  0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 
+  0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 
+  0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 
+  0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 
+  0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 
+};
+
+static const uint16 lut_BCD_16[100] =
+{
+  0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 
+  0x0100, 0x0101, 0x0102, 0x0103, 0x0104, 0x0105, 0x0106, 0x0107, 0x0108, 0x0109, 
+  0x0200, 0x0201, 0x0202, 0x0203, 0x0204, 0x0205, 0x0206, 0x0207, 0x0208, 0x0209, 
+  0x0300, 0x0301, 0x0302, 0x0303, 0x0304, 0x0305, 0x0306, 0x0307, 0x0308, 0x0309, 
+  0x0400, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0406, 0x0407, 0x0408, 0x0409, 
+  0x0500, 0x0501, 0x0502, 0x0503, 0x0504, 0x0505, 0x0506, 0x0507, 0x0508, 0x0509, 
+  0x0600, 0x0601, 0x0602, 0x0603, 0x0604, 0x0605, 0x0606, 0x0607, 0x0608, 0x0609, 
+  0x0700, 0x0701, 0x0702, 0x0703, 0x0704, 0x0705, 0x0706, 0x0707, 0x0708, 0x0709, 
+  0x0800, 0x0801, 0x0802, 0x0803, 0x0804, 0x0805, 0x0806, 0x0807, 0x0808, 0x0809, 
+  0x0900, 0x0901, 0x0902, 0x0903, 0x0904, 0x0905, 0x0906, 0x0907, 0x0908, 0x0909, 
+};
+
+/* pre-build TOC */
+static const uint16 toc_snatcher[21] =
+{
+  56014,   495, 10120, 20555, 1580, 5417, 12502, 16090,  6553, 9681,
+   8148, 20228,  8622,  6142, 5858, 1287,  7424,  3535, 31697, 2485,
+  31380
+};
+
+static const uint16 toc_lunar[52] =
+{
+  5422, 1057, 7932, 5401, 6380, 6592, 5862,  5937, 5478, 5870,
+  6673, 6613, 6429, 4996, 4977, 5657, 3720,  5892, 3140, 3263,
+  6351, 5187, 3249, 1464, 1596, 1750, 1751,  6599, 4578, 5205,
+  1550, 1827, 2328, 1346, 1569, 1613, 7199,  4928, 1656, 2549,
+  1875, 3901, 1850, 2399, 2028, 1724, 4889, 14551, 1184, 2132,
+  685, 3167
+};
+
+static const uint32 toc_shadow[15] =
+{
+  10226, 70054, 11100, 12532, 12444, 11923, 10059, 10167, 10138, 13792,
+  11637,  2547,  2521,  3856, 900
+};
+
+static const uint32 toc_dungeon[13] =
+{
+  2250, 22950, 16350, 24900, 13875, 19950, 13800, 15375, 17400, 17100,
+  3325,  6825, 25275
+};
+
+static const uint32 toc_ffight[26] =
+{
+  11994, 9742, 10136, 9685, 9553, 14588, 9430, 8721, 9975, 9764,
+  9704, 12796, 585, 754, 951, 624, 9047, 1068, 817, 9191, 1024,
+  14562, 10320, 8627, 3795, 3047
+};
+
+static const uint32 toc_ffightj[29] =
+{
+  11994, 9752, 10119, 9690, 9567, 14575, 9431, 8731, 9965, 9763,
+  9716, 12791, 579, 751, 958, 630, 9050, 1052, 825, 9193, 1026,
+  14553, 9834, 10542, 1699, 1792, 1781, 3783, 3052
+};
+
+/* supported WAVE file header (16-bit stereo samples @44.1kHz) */
+static const unsigned char waveHeader[32] =
+{
+  0x57,0x41,0x56,0x45,0x66,0x6d,0x74,0x20,0x10,0x00,0x00,0x00,0x01,0x00,0x02,0x00,
+  0x44,0xac,0x00,0x00,0x10,0xb1,0x02,0x00,0x04,0x00,0x10,0x00,0x64,0x61,0x74,0x61
+};
+
+#ifdef USE_LIBTREMOR
+#ifdef DISABLE_MANY_OGG_OPEN_FILES
+static void ogg_free(int i)
+{
+  /* clear OGG file descriptor to prevent file from being closed */
+  cdd.toc.tracks[i].vf.datasource = NULL;
+
+  /* close VORBIS file structure */
+  ov_clear(&cdd.toc.tracks[i].vf);
+
+  /* indicates that the track is a seekable VORBIS file */
+  cdd.toc.tracks[i].vf.seekable = 1;
+
+  /* reset file reading position */
+  fseek(cdd.toc.tracks[i].fd, 0, SEEK_SET);
+}
+#endif
+#endif
+
+void cdd_reset(void)
+{
+  /* reset cycle counter */
+  cdd.cycles = 0;
+  
+  /* reset drive access latency */
+  cdd.latency = 0;
+  
+  /* reset track index */
+  cdd.index = 0;
+  
+  /* reset logical block address */
+  cdd.lba = 0;
+
+  /* reset status */
+  cdd.status = cdd.loaded ? CD_STOP : NO_DISC;
+  
+  /* reset CD-DA fader (full volume) */
+  cdd.volume = 0x400;
+
+  /* clear CD-DA output */
+  cdd.audio[0] = cdd.audio[1] = 0;
+}
+
+/* FIXME: use cdd_read_audio() instead */
+static void cdd_change_track(int index, int lba)
+{
+  int i, base, lba_offset, lb_len;
+
+  for (i = index; i > 0; i--)
+    if (cdd.toc.tracks[i].fd != NULL)
+      break;
+
+  Pico_mcd->cdda_stream = cdd.toc.tracks[i].fd;
+  base = cdd.toc.tracks[index].offset;
+  lba_offset = lba - cdd.toc.tracks[index].start;
+  lb_len = cdd.toc.tracks[index].end - cdd.toc.tracks[index].start;
+
+  elprintf(EL_CD, "play #%d lba %d base %d", index, lba, base);
+
+  cdda_start_play(base, lba_offset, lb_len);
+}
+
+int cdd_context_save(uint8 *state)
+{
+  int bufferptr = 0;
+
+  save_param(&cdd.cycles, sizeof(cdd.cycles));
+  save_param(&cdd.latency, sizeof(cdd.latency));
+  save_param(&cdd.index, sizeof(cdd.index));
+  save_param(&cdd.lba, sizeof(cdd.lba));
+  save_param(&cdd.scanOffset, sizeof(cdd.scanOffset));
+  save_param(&cdd.volume, sizeof(cdd.volume));
+  save_param(&cdd.status, sizeof(cdd.status));
+
+  return bufferptr;
+}
+
+int cdd_context_load(uint8 *state)
+{
+  int lba;
+  int bufferptr = 0;
+
+#ifdef USE_LIBTREMOR
+#ifdef DISABLE_MANY_OGG_OPEN_FILES
+  /* close previous track VORBIS file structure to save memory */
+  if (cdd.toc.tracks[cdd.index].vf.datasource)
+  {
+    ogg_free(cdd.index);
+  }
+#endif
+#endif
+
+  load_param(&cdd.cycles, sizeof(cdd.cycles));
+  load_param(&cdd.latency, sizeof(cdd.latency));
+  load_param(&cdd.index, sizeof(cdd.index));
+  load_param(&cdd.lba, sizeof(cdd.lba));
+  load_param(&cdd.scanOffset, sizeof(cdd.scanOffset));
+  load_param(&cdd.volume, sizeof(cdd.volume));
+  load_param(&cdd.status, sizeof(cdd.status));
+
+  /* adjust current LBA within track limit */
+  lba = cdd.lba;
+  if (lba < cdd.toc.tracks[cdd.index].start)
+  {
+    lba = cdd.toc.tracks[cdd.index].start;
+  }
+
+  /* seek to current track position */
+  if (!cdd.index)
+  {
+    /* DATA track */
+    if (cdd.toc.tracks[0].fd)
+    {
+      pm_seek(cdd.toc.tracks[0].fd, lba * cdd.sectorSize, SEEK_SET);
+    }
+  }
+#ifdef USE_LIBTREMOR
+  else if (cdd.toc.tracks[cdd.index].vf.seekable)
+  {
+#ifdef DISABLE_MANY_OGG_OPEN_FILES
+    /* VORBIS file need to be opened first */
+    ov_open(cdd.toc.tracks[cdd.index].fd,&cdd.toc.tracks[cdd.index].vf,0,0);
+#endif
+    /* VORBIS AUDIO track */
+    ov_pcm_seek(&cdd.toc.tracks[cdd.index].vf, (lba - cdd.toc.tracks[cdd.index].start) * 588 - cdd.toc.tracks[cdd.index].offset);
+  }
+#endif
+#if 0
+  else if (cdd.toc.tracks[cdd.index].fd)
+  {
+    /* PCM AUDIO track */
+    fseek(cdd.toc.tracks[cdd.index].fd, (lba * 2352) - cdd.toc.tracks[cdd.index].offset, SEEK_SET);
+  }
+#else
+  else
+  {
+    cdd_change_track(cdd.index, lba);
+  }
+#endif
+
+  return bufferptr;
+}
+
+int cdd_context_load_old(uint8 *state)
+{
+  memcpy(&cdd.lba, state + 8, sizeof(cdd.lba));
+  return 12 * 4;
+}
+
+int cdd_load(const char *filename, int type)
+{
+  char header[0x210];
+  int ret;
+
+  /* first unmount any loaded disc */
+  cdd_unload();
+
+  /* genplus parses cue here, in PD we use our own parser */
+  ret = load_cd_image(filename, &type);
+  if (ret != 0)
+    return ret;
+
+  /* read first 16 bytes */
+  pm_read(header, 0x10, cdd.toc.tracks[0].fd);
+
+  /* look for valid CD image ID string */
+  if (memcmp("SEGADISCSYSTEM", header, 14))
+  {    
+    /* if not found, read next 16 bytes */
+    pm_read(header, 0x10, cdd.toc.tracks[0].fd);
+
+    /* look again for valid CD image ID string */
+    if (memcmp("SEGADISCSYSTEM", header, 14))
+    {
+      elprintf(EL_STATUS|EL_ANOMALY, "cd: bad cd image?");
+      /* assume bin without security code */
+    }
+
+    /* BIN format (2352 bytes data blocks) */
+    cdd.sectorSize = 2352;
+  }
+  else
+  {
+    /* ISO format (2048 bytes data blocks) */
+    cdd.sectorSize = 2048;
+  }
+
+  ret = (type == CT_BIN) ? 2352 : 2048;
+  if (ret != cdd.sectorSize)
+    elprintf(EL_STATUS|EL_ANOMALY, "cd: type detection mismatch");
+
+  /* read CD image header + security code */
+  pm_read(header + 0x10, 0x200, cdd.toc.tracks[0].fd);
+
+  /* Simulate audio tracks if none found */
+  if (cdd.toc.last == 1)
+  {
+    /* Some games require exact TOC infos */
+    if (strstr(header + 0x180,"T-95035") != NULL)
+    {
+      /* Snatcher */
+      cdd.toc.last = cdd.toc.end = 0;
+      do
+      {
+        cdd.toc.tracks[cdd.toc.last].start = cdd.toc.end;
+        cdd.toc.tracks[cdd.toc.last].end = cdd.toc.tracks[cdd.toc.last].start + toc_snatcher[cdd.toc.last];
+        cdd.toc.end = cdd.toc.tracks[cdd.toc.last].end;
+        cdd.toc.last++;
+      }
+      while (cdd.toc.last < 21);
+    }
+    else if (strstr(header + 0x180,"T-127015") != NULL)
+    {
+      /* Lunar - The Silver Star */
+      cdd.toc.last = cdd.toc.end = 0;
+      do
+      {
+        cdd.toc.tracks[cdd.toc.last].start = cdd.toc.end;
+        cdd.toc.tracks[cdd.toc.last].end = cdd.toc.tracks[cdd.toc.last].start + toc_lunar[cdd.toc.last];
+        cdd.toc.end = cdd.toc.tracks[cdd.toc.last].end;
+        cdd.toc.last++;
+      }
+      while (cdd.toc.last < 52);
+    }
+    else if (strstr(header + 0x180,"T-113045") != NULL)
+    {
+      /* Shadow of the Beast II */
+      cdd.toc.last = cdd.toc.end = 0;
+      do
+      {
+        cdd.toc.tracks[cdd.toc.last].start = cdd.toc.end;
+        cdd.toc.tracks[cdd.toc.last].end = cdd.toc.tracks[cdd.toc.last].start + toc_shadow[cdd.toc.last];
+        cdd.toc.end = cdd.toc.tracks[cdd.toc.last].end;
+        cdd.toc.last++;
+      }
+      while (cdd.toc.last < 15);
+    }
+    else if (strstr(header + 0x180,"T-143025") != NULL)
+    {
+      /* Dungeon Explorer */
+      cdd.toc.last = cdd.toc.end = 0;
+      do
+      {
+        cdd.toc.tracks[cdd.toc.last].start = cdd.toc.end;
+        cdd.toc.tracks[cdd.toc.last].end = cdd.toc.tracks[cdd.toc.last].start + toc_dungeon[cdd.toc.last];
+        cdd.toc.end = cdd.toc.tracks[cdd.toc.last].end;
+        cdd.toc.last++;
+      }
+      while (cdd.toc.last < 13);
+    }
+    else if (strstr(header + 0x180,"MK-4410") != NULL)
+    {
+      /* Final Fight CD (USA, Europe) */
+      cdd.toc.last = cdd.toc.end = 0;
+      do
+      {
+        cdd.toc.tracks[cdd.toc.last].start = cdd.toc.end;
+        cdd.toc.tracks[cdd.toc.last].end = cdd.toc.tracks[cdd.toc.last].start + toc_ffight[cdd.toc.last];
+        cdd.toc.end = cdd.toc.tracks[cdd.toc.last].end;
+        cdd.toc.last++;
+      }
+      while (cdd.toc.last < 26);
+    }
+    else if (strstr(header + 0x180,"G-6013") != NULL)
+    {
+      /* Final Fight CD (Japan) */
+      cdd.toc.last = cdd.toc.end = 0;
+      do
+      {
+        cdd.toc.tracks[cdd.toc.last].start = cdd.toc.end;
+        cdd.toc.tracks[cdd.toc.last].end = cdd.toc.tracks[cdd.toc.last].start + toc_ffightj[cdd.toc.last];
+        cdd.toc.end = cdd.toc.tracks[cdd.toc.last].end;
+        cdd.toc.last++;
+      }
+      while (cdd.toc.last < 29);
+    }
+#if 0
+    else
+    {
+      /* default TOC (99 tracks & 2s per audio tracks) */
+      do
+      {
+        cdd.toc.tracks[cdd.toc.last].start = cdd.toc.end + 2*75;
+        cdd.toc.tracks[cdd.toc.last].end = cdd.toc.tracks[cdd.toc.last].start + 2*75;
+        cdd.toc.end = cdd.toc.tracks[cdd.toc.last].end;
+        cdd.toc.last++;
+      }
+      while ((cdd.toc.last < 99) && (cdd.toc.end < 56*60*75));
+    }
+#endif
+  }
+
+  /* Lead-out */
+  cdd.toc.tracks[cdd.toc.last].start = cdd.toc.end;
+
+  /* CD loaded */
+  cdd.loaded = 1;
+  return 0;
+}
+
+int cdd_unload(void)
+{
+  int was_loaded = cdd.loaded;
+
+  if (cdd.loaded)
+  {
+    int i;
+
+    /* close CD tracks */
+    if (cdd.toc.tracks[0].fd)
+    {
+      pm_close(cdd.toc.tracks[0].fd);
+      cdd.toc.tracks[0].fd = NULL;
+    }
+
+    for (i = 1; i < cdd.toc.last; i++)
+    {
+#ifdef USE_LIBTREMOR
+      if (cdd.toc.tracks[i].vf.datasource)
+      {
+        /* close VORBIS file (if still opened) */
+        ov_clear(&cdd.toc.tracks[i].vf);
+      }
+      else
+#endif
+      if (cdd.toc.tracks[i].fd)
+      {
+        /* close file */
+        if (Pico_mcd->cdda_type == CT_MP3)
+          fclose(cdd.toc.tracks[i].fd);
+        else
+          pm_close(cdd.toc.tracks[0].fd);
+
+        /* detect single file images */
+        if (cdd.toc.tracks[i+1].fd == cdd.toc.tracks[i].fd)
+        {
+          /* exit loop */
+          i = cdd.toc.last;
+        }
+      }
+    }
+
+    /* CD unloaded */
+    cdd.loaded = 0;
+  }
+
+  /* reset TOC */
+  memset(&cdd.toc, 0x00, sizeof(cdd.toc));
+    
+  /* unknown CD image file format */
+  cdd.sectorSize = 0;
+
+  return was_loaded;
+}
+
+void cdd_read_data(uint8 *dst)
+{
+  /* only read DATA track sectors */
+  if ((cdd.lba >= 0) && (cdd.lba < cdd.toc.tracks[0].end))
+  {
+    /* BIN format ? */
+    if (cdd.sectorSize == 2352)
+    {
+      /* skip 16-byte header */
+      pm_seek(cdd.toc.tracks[0].fd, cdd.lba * 2352 + 16, SEEK_SET);
+    }
+
+    /* read sector data (Mode 1 = 2048 bytes) */
+    pm_read(dst, 2048, cdd.toc.tracks[0].fd);
+  }
+}
+
+#if 0
+void cdd_read_audio(unsigned int samples)
+{
+  /* previous audio outputs */
+  int16 l = cdd.audio[0];
+  int16 r = cdd.audio[1];
+
+  /* get number of internal clocks (samples) needed */
+  samples = blip_clocks_needed(blip[0], samples);
+
+  /* audio track playing ? */
+  if (!Pico_mcd->regs[0x36>>1].byte.h && cdd.toc.tracks[cdd.index].fd)
+  {
+    int i, mul, delta;
+
+    /* current CD-DA fader volume */
+    int curVol = cdd.volume;
+
+    /* CD-DA fader volume setup (0-1024) */
+    int endVol = Pico_mcd->regs[0x34>>1].w >> 4;
+
+    /* read samples from current block */
+#ifdef USE_LIBTREMOR
+    if (cdd.toc.tracks[cdd.index].vf.datasource)
+    {
+      int len, done = 0;
+      int16 *ptr = (int16 *) (cdc.ram);
+      samples = samples * 4;
+      while (done < samples)
+      {
+        len = ov_read(&cdd.toc.tracks[cdd.index].vf, (char *)(cdc.ram + done), samples - done, 0);
+        if (len <= 0) 
+        {
+          done = samples;
+          break;
+        }
+        done += len;
+      }
+      samples = done / 4;
+
+      /* process 16-bit (host-endian) stereo samples */
+      for (i=0; i<samples; i++)
+      {
+        /* CD-DA fader multiplier (cf. LC7883 datasheet) */
+        /* (MIN) 0,1,2,3,4,8,12,16,20...,1020,1024 (MAX) */
+        mul = (curVol & 0x7fc) ? (curVol & 0x7fc) : (curVol & 0x03);
+
+        /* left channel */
+        delta = ((ptr[0] * mul) / 1024) - l;
+        ptr++;
+        l += delta;
+        blip_add_delta_fast(blip[0], i, delta);
+
+        /* right channel */
+        delta = ((ptr[0] * mul) / 1024) - r;
+        ptr++;
+        r += delta;
+        blip_add_delta_fast(blip[1], i, delta);
+
+        /* update CD-DA fader volume (one step/sample) */
+        if (curVol < endVol)
+        {
+          /* fade-in */
+          curVol++;
+        }
+        else if (curVol > endVol)
+        {
+          /* fade-out */
+          curVol--;
+        }
+        else if (!curVol)
+        {
+          /* audio will remain muted until next setup */
+          break;
+        }
+      }
+    }
+    else
+#endif
+    {
+#ifdef LSB_FIRST
+      int16 *ptr = (int16 *) (cdc.ram);
+#else
+      uint8 *ptr = cdc.ram;
+#endif
+      fread(cdc.ram, 1, samples * 4, cdd.toc.tracks[cdd.index].fd);
+
+      /* process 16-bit (little-endian) stereo samples */
+      for (i=0; i<samples; i++)
+      {
+        /* CD-DA fader multiplier (cf. LC7883 datasheet) */
+        /* (MIN) 0,1,2,3,4,8,12,16,20...,1020,1024 (MAX) */
+        mul = (curVol & 0x7fc) ? (curVol & 0x7fc) : (curVol & 0x03);
+
+        /* left channel */
+  #ifdef LSB_FIRST
+        delta = ((ptr[0] * mul) / 1024) - l;
+        ptr++;
+  #else
+        delta = (((int16)((ptr[0] + ptr[1]*256)) * mul) / 1024) - l;
+        ptr += 2;
+  #endif
+        l += delta;
+        blip_add_delta_fast(blip[0], i, delta);
+
+        /* right channel */
+  #ifdef LSB_FIRST
+        delta = ((ptr[0] * mul) / 1024) - r;
+        ptr++;
+  #else
+        delta = (((int16)((ptr[0] + ptr[1]*256)) * mul) / 1024) - r;
+        ptr += 2;
+  #endif
+        r += delta;
+        blip_add_delta_fast(blip[1], i, delta);
+
+        /* update CD-DA fader volume (one step/sample) */
+        if (curVol < endVol)
+        {
+          /* fade-in */
+          curVol++;
+        }
+        else if (curVol > endVol)
+        {
+          /* fade-out */
+          curVol--;
+        }
+        else if (!curVol)
+        {
+          /* audio will remain muted until next setup */
+          break;
+        }
+      }
+    }
+
+    /* save current CD-DA fader volume */
+    cdd.volume = curVol;
+
+    /* save last audio output for next frame */
+    cdd.audio[0] = l;
+    cdd.audio[1] = r;
+  }
+  else
+  {
+    /* no audio output */
+    if (l) blip_add_delta_fast(blip[0], 0, -l);
+    if (r) blip_add_delta_fast(blip[1], 0, -r);
+
+    /* save audio output for next frame */
+    cdd.audio[0] = 0;
+    cdd.audio[1] = 0;
+  }
+
+  /* end of Blip Buffer timeframe */
+  blip_end_frame(blip[0], samples);
+  blip_end_frame(blip[1], samples);
+}
+#endif
+
+
+void cdd_update(void)
+{  
+#ifdef LOG_CDD
+  error("LBA = %d (track n°%d)(latency=%d)\n", cdd.lba, cdd.index, cdd.latency);
+#endif
+  
+  /* seeking disc */
+  if (cdd.status == CD_SEEK)
+  {
+    /* drive latency */
+    if (cdd.latency > 0)
+    {
+      cdd.latency--;
+      return;
+    }
+
+    /* drive is ready */
+    cdd.status = CD_READY;
+  }
+
+  /* reading disc */
+  else if (cdd.status == CD_PLAY)
+  {
+    /* drive latency */
+    if (cdd.latency > 0)
+    {
+      cdd.latency--;
+      return;
+    }
+
+    /* track type */
+    if (!cdd.index)
+    {
+      /* DATA sector header (CD-ROM Mode 1) */
+      uint8 header[4];
+      uint32 msf = cdd.lba + 150;
+      header[0] = lut_BCD_8[(msf / 75) / 60];
+      header[1] = lut_BCD_8[(msf / 75) % 60];
+      header[2] = lut_BCD_8[(msf % 75)];
+      header[3] = 0x01;
+
+      /* data track sector read is controlled by CDC */
+      cdd.lba += cdc_decoder_update(header);
+    }
+    else if (cdd.index < cdd.toc.last)
+    {
+      uint8 header[4] = { 0, };
+
+      /* check against audio track start index */
+      if (cdd.lba >= cdd.toc.tracks[cdd.index].start)
+      {
+        /* audio track playing */
+        Pico_mcd->regs[0x36>>1].byte.h = 0x00;
+      }
+
+      /* audio blocks are still sent to CDC as well as CD DAC/Fader */
+      cdc_decoder_update(header);
+      /* next audio block is automatically read */
+      cdd.lba++;
+    }
+    else
+    {
+      /* end of disc */
+      cdd.status = CD_END;
+      return;
+    }
+
+    /* check end of current track */
+    if (cdd.lba >= cdd.toc.tracks[cdd.index].end)
+    {
+#ifdef USE_LIBTREMOR
+#ifdef DISABLE_MANY_OGG_OPEN_FILES
+      /* close previous track VORBIS file structure to save memory */
+      if (cdd.toc.tracks[cdd.index].vf.datasource)
+      {
+        ogg_free(cdd.index);
+      }
+#endif
+#endif
+      /* play next track */
+      cdd.index++;
+
+      /* PAUSE between tracks */
+      Pico_mcd->regs[0x36>>1].byte.h = 0x01;
+
+      /* seek to next audio track start */
+#ifdef USE_LIBTREMOR
+      if (cdd.toc.tracks[cdd.index].vf.seekable)
+      {
+#ifdef DISABLE_MANY_OGG_OPEN_FILES
+        /* VORBIS file need to be opened first */
+        ov_open(cdd.toc.tracks[cdd.index].fd,&cdd.toc.tracks[cdd.index].vf,0,0);
+#endif
+        ov_pcm_seek(&cdd.toc.tracks[cdd.index].vf, -cdd.toc.tracks[cdd.index].offset);
+      }
+      else
+#endif 
+#if 0
+      if (cdd.toc.tracks[cdd.index].fd)
+      {
+        fseek(cdd.toc.tracks[cdd.index].fd, (cdd.toc.tracks[cdd.index].start * 2352) - cdd.toc.tracks[cdd.index].offset, SEEK_SET);
+      }
+#else
+      {
+        cdd_change_track(cdd.index, cdd.lba);
+      }
+#endif
+    }
+  }
+
+  /* scanning disc */
+  else if (cdd.status == CD_SCAN)
+  {
+    /* fast-forward or fast-rewind */
+    cdd.lba += cdd.scanOffset;
+
+    /* check current track limits */
+    if (cdd.lba >= cdd.toc.tracks[cdd.index].end)
+    {
+#ifdef USE_LIBTREMOR
+#ifdef DISABLE_MANY_OGG_OPEN_FILES
+      /* close previous track VORBIS file structure to save memory */
+      if (cdd.toc.tracks[cdd.index].vf.datasource)
+      {
+        ogg_free(cdd.index);
+      }
+#endif
+#endif
+      /* next track */
+      cdd.index++;
+
+      /* skip directly to track start position */
+      cdd.lba = cdd.toc.tracks[cdd.index].start;
+      
+      /* AUDIO track playing ? */
+      if (cdd.status == CD_PLAY)
+      {
+        Pico_mcd->regs[0x36>>1].byte.h = 0x00;
+      }
+    }
+    else if (cdd.lba < cdd.toc.tracks[cdd.index].start)
+    {
+#ifdef USE_LIBTREMOR
+#ifdef DISABLE_MANY_OGG_OPEN_FILES
+      /* close previous track VORBIS file structure to save memory */
+      if (cdd.toc.tracks[cdd.index].vf.datasource)
+      {
+        ogg_free(cdd.index);
+      }
+#endif
+#endif
+
+      /* previous track */
+      cdd.index--;
+
+      /* skip directly to track end position */
+      cdd.lba = cdd.toc.tracks[cdd.index].end;
+    }
+
+    /* check disc limits */
+    if (cdd.index < 0)
+    {
+      cdd.index = 0;
+      cdd.lba = 0;
+    }
+    else if (cdd.index >= cdd.toc.last)
+    {
+      /* no AUDIO track playing */
+      Pico_mcd->regs[0x36>>1].byte.h = 0x01;
+
+      /* end of disc */
+      cdd.index = cdd.toc.last;
+      cdd.lba = cdd.toc.end;
+      cdd.status = CD_END;
+      return;
+    }
+
+    /* seek to current block */
+    if (!cdd.index)
+    {
+      /* no AUDIO track playing */
+      Pico_mcd->regs[0x36>>1].byte.h = 0x01;
+
+      /* DATA track */
+      pm_seek(cdd.toc.tracks[0].fd, cdd.lba * cdd.sectorSize, SEEK_SET);
+    }
+#ifdef USE_LIBTREMOR
+    else if (cdd.toc.tracks[cdd.index].vf.seekable)
+    {
+#ifdef DISABLE_MANY_OGG_OPEN_FILES
+      /* check if a new track is being played */
+      if (!cdd.toc.tracks[cdd.index].vf.datasource)
+      {
+        /* VORBIS file need to be opened first */
+        ov_open(cdd.toc.tracks[cdd.index].fd,&cdd.toc.tracks[cdd.index].vf,0,0);
+      }
+#endif
+      /* VORBIS AUDIO track */
+      ov_pcm_seek(&cdd.toc.tracks[cdd.index].vf, (cdd.lba - cdd.toc.tracks[cdd.index].start) * 588 - cdd.toc.tracks[cdd.index].offset);
+    }
+#endif 
+#if 0
+    else if (cdd.toc.tracks[cdd.index].fd)
+    {
+      /* PCM AUDIO track */
+      fseek(cdd.toc.tracks[cdd.index].fd, (cdd.lba * 2352) - cdd.toc.tracks[cdd.index].offset, SEEK_SET);
+    }
+#else
+    else
+    {
+      cdd_change_track(cdd.index, cdd.lba);
+    }
+#endif
+  }
+}
+
+#define set_reg16(r, v) { \
+  uint16 _v = v; \
+  Pico_mcd->s68k_regs[(r)] = _v >> 8; \
+  Pico_mcd->s68k_regs[(r)+1] = _v; \
+}
+
+void cdd_process(void)
+{
+  /* Process CDD command */
+  switch (Pico_mcd->regs[0x42>>1].byte.h & 0x0f)
+  {
+    case 0x00:  /* Drive Status */
+    {
+      /* RS1-RS8 normally unchanged */
+      Pico_mcd->regs[0x38>>1].byte.h = cdd.status;
+
+      /* unless RS1 indicated invalid track infos */
+      if (Pico_mcd->regs[0x38>>1].byte.l == 0x0f)
+      {
+        /* and SEEK has ended */
+        if (cdd.status != CD_SEEK)
+        {
+          /* then return valid track infos, e.g current track number in RS2-RS3 (fixes Lunar - The Silver Star) */
+          Pico_mcd->regs[0x38>>1].byte.l = 0x02;
+          set_reg16(0x3a, (cdd.index < cdd.toc.last) ? lut_BCD_16[cdd.index + 1] : 0x0A0A);
+        }
+      }
+      break;
+    }
+
+    case 0x01:  /* Stop Drive */
+    {
+      /* update status */
+      cdd.status = cdd.loaded ? CD_STOP : NO_DISC;
+
+      /* no audio track playing */
+      Pico_mcd->regs[0x36>>1].byte.h = 0x01;
+
+      /* RS1-RS8 ignored, expects 0x0 ("no disc" ?) in RS0 once */
+      set_reg16(0x38, 0x0000);
+      set_reg16(0x3a, 0x0000);
+      set_reg16(0x3c, 0x0000);
+      set_reg16(0x3e, 0x0000);
+      set_reg16(0x40, 0x000f);
+      return;
+    }
+
+    case 0x02:  /* Read TOC */
+    {
+      /* Infos automatically retrieved by CDD processor from Q-Channel */
+      /* commands 0x00-0x02 (current block) and 0x03-0x05 (Lead-In) */
+      switch (Pico_mcd->regs[0x44>>1].byte.l)
+      {
+        case 0x00:  /* Current Absolute Time (MM:SS:FF) */
+        {
+          int lba = cdd.lba + 150;
+          set_reg16(0x38, cdd.status << 8);
+          set_reg16(0x3a, lut_BCD_16[(lba/75)/60]);
+          set_reg16(0x3c, lut_BCD_16[(lba/75)%60]);
+          set_reg16(0x3e, lut_BCD_16[(lba%75)]);
+          Pico_mcd->regs[0x40>>1].byte.h = cdd.index ? 0x00 : 0x04; /* Current block flags in RS8 (bit0 = mute status, bit1: pre-emphasis status, bit2: track type) */
+          break;
+        }
+
+        case 0x01:  /* Current Track Relative Time (MM:SS:FF) */
+        {
+          int lba = cdd.lba - cdd.toc.tracks[cdd.index].start;
+          set_reg16(0x38, (cdd.status << 8) | 0x01);
+          set_reg16(0x3a, lut_BCD_16[(lba/75)/60]);
+          set_reg16(0x3c, lut_BCD_16[(lba/75)%60]);
+          set_reg16(0x3e, lut_BCD_16[(lba%75)]);
+          Pico_mcd->regs[0x40>>1].byte.h = cdd.index ? 0x00 : 0x04; /* Current block flags in RS8 (bit0 = mute status, bit1: pre-emphasis status, bit2: track type) */
+          break;
+        }
+
+        case 0x02:  /* Current Track Number */
+        {
+          set_reg16(0x38, (cdd.status << 8) | 0x02);
+          set_reg16(0x3a, (cdd.index < cdd.toc.last) ? lut_BCD_16[cdd.index + 1] : 0x0A0A);
+          set_reg16(0x3c, 0x0000);
+          set_reg16(0x3e, 0x0000); /* Disk Control Code (?) in RS6 */
+          Pico_mcd->regs[0x40>>1].byte.h = 0x00;
+          break;
+        }
+
+        case 0x03:  /* Total length (MM:SS:FF) */
+        {
+          int lba = cdd.toc.end + 150;
+          set_reg16(0x38, (cdd.status << 8) | 0x03);
+          set_reg16(0x3a, lut_BCD_16[(lba/75)/60]);
+          set_reg16(0x3c, lut_BCD_16[(lba/75)%60]);
+          set_reg16(0x3e, lut_BCD_16[(lba%75)]);
+          Pico_mcd->regs[0x40>>1].byte.h = 0x00;
+          break;
+        }
+
+        case 0x04:  /* First & Last Track Numbers */
+        {
+          set_reg16(0x38, (cdd.status << 8) | 0x04);
+          set_reg16(0x3a, 0x0001);
+          set_reg16(0x3c, lut_BCD_16[cdd.toc.last]);
+          set_reg16(0x3e, 0x0000); /* Drive Version (?) in RS6-RS7 */
+          Pico_mcd->regs[0x40>>1].byte.h = 0x00;  /* Lead-In flags in RS8 (bit0 = mute status, bit1: pre-emphasis status, bit2: track type) */
+          break;
+        }
+
+        case 0x05:  /* Track Start Time (MM:SS:FF) */
+        {
+          int track = Pico_mcd->regs[0x46>>1].byte.h * 10 + Pico_mcd->regs[0x46>>1].byte.l;
+          int lba = cdd.toc.tracks[track-1].start + 150;
+          set_reg16(0x38, (cdd.status << 8) | 0x05);
+          set_reg16(0x3a, lut_BCD_16[(lba/75)/60]);
+          set_reg16(0x3c, lut_BCD_16[(lba/75)%60]);
+          set_reg16(0x3e, lut_BCD_16[(lba%75)]);
+          Pico_mcd->regs[0x40>>1].byte.h = track % 10;  /* Track Number (low digit) */
+          if (track == 1)
+          {
+            /* RS6 bit 3 is set for the first (DATA) track */
+            Pico_mcd->regs[0x3e>>1].byte.h |= 0x08;
+          }
+          break;
+        }
+
+        default:
+        {
+#ifdef LOG_ERROR
+          error("Unknown CDD Command %02X (%X)\n", Pico_mcd->regs[0x44>>1].byte.l, s68k.pc);
+#endif
+          return;
+        }
+      }
+      break;
+    }
+
+    case 0x03:  /* Play  */
+    {
+      /* reset track index */
+      int index = 0;
+
+      /* new LBA position */
+      int lba = ((Pico_mcd->regs[0x44>>1].byte.h * 10 + Pico_mcd->regs[0x44>>1].byte.l) * 60 + 
+                 (Pico_mcd->regs[0x46>>1].byte.h * 10 + Pico_mcd->regs[0x46>>1].byte.l)) * 75 +
+                 (Pico_mcd->regs[0x48>>1].byte.h * 10 + Pico_mcd->regs[0x48>>1].byte.l) - 150;
+
+      /* CD drive latency */
+      if (!cdd.latency)
+      {
+        /* Fixes a few games hanging during intro because they expect data to be read with some delay */
+        /* Radical Rex needs at least one interrupt delay */
+        /* Wolf Team games (Anet Futatabi, Cobra Command, Road Avenger & Time Gal) need at least 6 interrupts delay  */
+        /* Space Adventure Cobra (2nd morgue scene) needs at least 13 interrupts delay (incl. seek time, so 6 is OK) */
+        /* Jeopardy & ESPN Sunday Night NFL are picky about this as well: 10 interrupts delay (+ seek time) seems OK */
+        cdd.latency = 10;
+      }
+
+      /* CD drive seek time */
+      /* max. seek time = 1.5 s = 1.5 x 75 = 112.5 CDD interrupts (rounded to 120) for 270000 sectors max on disc. */
+      /* Note: This is only a rough approximation since, on real hardware, seek time is much likely not linear and */
+      /* latency much larger than above value, but this model works fine for Sonic CD (track 26 playback needs to  */
+      /* be enough delayed to start in sync with intro sequence, as compared with real hardware recording).        */
+      if (lba > cdd.lba)
+      {
+        cdd.latency += (((lba - cdd.lba) * 120) / 270000);
+      }
+      else 
+      {
+        cdd.latency += (((cdd.lba - lba) * 120) / 270000);
+      }
+
+      /* update current LBA */
+      cdd.lba = lba;
+
+      /* get track index */
+      while ((cdd.toc.tracks[index].end <= lba) && (index < cdd.toc.last)) index++;
+
+#ifdef USE_LIBTREMOR
+#ifdef DISABLE_MANY_OGG_OPEN_FILES
+      /* check if track index has changed */
+      if (index != cdd.index)
+      {
+        /* close previous track VORBIS file structure to save memory */
+        if (cdd.toc.tracks[cdd.index].vf.datasource)
+        {
+          ogg_free(cdd.index);
+        }
+
+        /* open current track VORBIS file */
+        if (cdd.toc.tracks[index].vf.seekable)
+        {
+          ov_open(cdd.toc.tracks[index].fd,&cdd.toc.tracks[index].vf,0,0);
+        }
+      }
+#endif
+#endif
+
+      /* update current track index */
+      cdd.index = index;
+
+      /* stay within track limits when seeking files */
+      if (lba < cdd.toc.tracks[index].start) 
+      {
+        lba = cdd.toc.tracks[index].start;
+      }
+      
+      /* seek to current block */
+      if (!index)
+      {
+        /* DATA track */
+        pm_seek(cdd.toc.tracks[0].fd, lba * cdd.sectorSize, SEEK_SET);
+      }
+#ifdef USE_LIBTREMOR
+      else if (cdd.toc.tracks[index].vf.seekable)
+      {
+        /* VORBIS AUDIO track */
+        ov_pcm_seek(&cdd.toc.tracks[index].vf, (lba - cdd.toc.tracks[index].start) * 588 - cdd.toc.tracks[index].offset);
+      }
+#endif
+#if 0
+      else if (cdd.toc.tracks[index].fd)
+      {
+        /* PCM AUDIO track */
+        fseek(cdd.toc.tracks[index].fd, (lba * 2352) - cdd.toc.tracks[index].offset, SEEK_SET);
+      }
+#else
+      else
+      {
+        cdd_change_track(index, lba);
+      }
+#endif
+
+      /* no audio track playing (yet) */
+      Pico_mcd->regs[0x36>>1].byte.h = 0x01;
+
+      /* update status */
+      cdd.status = CD_PLAY;
+
+      /* return track index in RS2-RS3 */
+      set_reg16(0x38, (CD_PLAY << 8) | 0x02);
+      set_reg16(0x3a, (cdd.index < cdd.toc.last) ? lut_BCD_16[index + 1] : 0x0A0A);
+      set_reg16(0x3c, 0x0000);
+      set_reg16(0x3e, 0x0000);
+      Pico_mcd->regs[0x40>>1].byte.h = 0x00;
+      break;
+    }
+
+    case 0x04:  /* Seek */
+    {
+      /* reset track index */
+      int index = 0;
+
+      /* new LBA position */
+      int lba = ((Pico_mcd->regs[0x44>>1].byte.h * 10 + Pico_mcd->regs[0x44>>1].byte.l) * 60 + 
+                 (Pico_mcd->regs[0x46>>1].byte.h * 10 + Pico_mcd->regs[0x46>>1].byte.l)) * 75 +
+                 (Pico_mcd->regs[0x48>>1].byte.h * 10 + Pico_mcd->regs[0x48>>1].byte.l) - 150;
+
+      /* CD drive seek time  */
+      /* We are using similar linear model as above, although still not exactly accurate, */
+      /* it works fine for Switch/Panic! intro (Switch needs at least 30 interrupts while */
+      /* seeking from 00:05:63 to 24:03:19, Panic! when seeking from 00:05:60 to 24:06:07) */
+      if (lba > cdd.lba)
+      {
+        cdd.latency = ((lba - cdd.lba) * 120) / 270000;
+      }
+      else
+      {
+        cdd.latency = ((cdd.lba - lba) * 120) / 270000;
+      }
+
+      /* update current LBA */
+      cdd.lba = lba;
+
+      /* get current track index */
+      while ((cdd.toc.tracks[index].end <= lba) && (index < cdd.toc.last)) index++;
+
+#ifdef USE_LIBTREMOR
+#ifdef DISABLE_MANY_OGG_OPEN_FILES
+      /* check if track index has changed */
+      if (index != cdd.index)
+      {
+        /* close previous track VORBIS file structure to save memory */
+        if (cdd.toc.tracks[cdd.index].vf.datasource)
+        {
+          ogg_free(cdd.index);
+        }
+
+        /* open current track VORBIS file */
+        if (cdd.toc.tracks[index].vf.seekable)
+        {
+          ov_open(cdd.toc.tracks[index].fd,&cdd.toc.tracks[index].vf,0,0);
+        }
+      }
+#endif
+#endif
+
+      /* update current track index */
+      cdd.index = index;
+
+      /* stay within track limits */
+      if (lba < cdd.toc.tracks[index].start) 
+      {
+        lba = cdd.toc.tracks[index].start;
+      }
+      
+      /* seek to current block */
+      if (!index)
+      {
+        /* DATA track */
+        pm_seek(cdd.toc.tracks[0].fd, lba * cdd.sectorSize, SEEK_SET);
+      }
+#ifdef USE_LIBTREMOR
+      else if (cdd.toc.tracks[index].vf.seekable)
+      {
+        /* VORBIS AUDIO track */
+        ov_pcm_seek(&cdd.toc.tracks[index].vf, (lba - cdd.toc.tracks[index].start) * 588 - cdd.toc.tracks[index].offset);
+      }
+#endif
+#if 0
+      else if (cdd.toc.tracks[index].fd)
+      {
+        /* PCM AUDIO track */
+        fseek(cdd.toc.tracks[index].fd, (lba * 2352) - cdd.toc.tracks[index].offset, SEEK_SET);
+      }
+#endif
+
+      /* no audio track playing */
+      Pico_mcd->regs[0x36>>1].byte.h = 0x01;
+
+      /* update status */
+      cdd.status = CD_SEEK;
+
+      /* 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) */
+      set_reg16(0x38, (CD_SEEK << 8) | 0x0f);
+      set_reg16(0x3a, 0x0000);
+      set_reg16(0x3c, 0x0000);
+      set_reg16(0x3e, 0x0000);
+      set_reg16(0x40, ~(CD_SEEK + 0xf) & 0x0f);
+      return;
+    }
+
+    case 0x06:  /* Pause */
+    {
+      /* no audio track playing */
+      Pico_mcd->regs[0x36>>1].byte.h = 0x01;
+
+      /* update status (RS1-RS8 unchanged) */
+      cdd.status = Pico_mcd->regs[0x38>>1].byte.h = CD_READY;
+      break;
+    }
+
+    case 0x07:  /* Resume */
+    {
+      /* update status (RS1-RS8 unchanged) */
+      cdd.status = Pico_mcd->regs[0x38>>1].byte.h = CD_PLAY;
+      break;
+    }
+
+    case 0x08:  /* Forward Scan */
+    {
+      /* reset scanning direction / speed */
+      cdd.scanOffset = CD_SCAN_SPEED;
+
+      /* update status (RS1-RS8 unchanged) */
+      cdd.status = Pico_mcd->regs[0x38>>1].byte.h = CD_SCAN;
+      break;
+    }
+
+    case 0x09:  /* Rewind Scan */
+    {
+      /* reset scanning direction / speed */
+      cdd.scanOffset = -CD_SCAN_SPEED;
+
+      /* update status (RS1-RS8 unchanged) */
+      cdd.status = Pico_mcd->regs[0x38>>1].byte.h = CD_SCAN;
+      break;
+    }
+
+
+    case 0x0a:  /* N-Track Jump Control ? (usually sent before CD_SEEK or CD_PLAY commands) */
+    {
+      /* TC3 corresponds to seek direction (00=forward, FF=reverse) */
+      /* TC4-TC7 are related to seek length (4x4 bits i.e parameter values are between -65535 and +65535) */
+      /* Maybe related to number of auto-sequenced track jumps/moves for CD DSP (cf. CXD2500BQ datasheet) */
+      /* also see US Patent nr. 5222054 for a detailled description of seeking operation using Track Jump */
+
+      /* no audio track playing */
+      Pico_mcd->regs[0x36>>1].byte.h = 0x01;
+
+      /* update status (RS1-RS8 unchanged) */
+      cdd.status = Pico_mcd->regs[0x38>>1].byte.h = CD_READY;
+      break;
+    }
+
+    case 0x0c:  /* Close Tray */
+    {
+      /* no audio track playing */
+      Pico_mcd->regs[0x36>>1].byte.h = 0x01;
+
+      /* update status */
+      cdd.status = cdd.loaded ? CD_STOP : NO_DISC;
+
+      /* RS1-RS8 ignored, expects 0x0 ("no disc" ?) in RS0 once */
+      set_reg16(0x38, 0x0000);
+      set_reg16(0x3a, 0x0000);
+      set_reg16(0x3c, 0x0000);
+      set_reg16(0x3e, 0x0000);
+      set_reg16(0x40, 0x000f);
+
+      if (PicoMCDcloseTray)
+        PicoMCDcloseTray();
+      return;
+    }
+
+    case 0x0d:  /* Open Tray */
+    {
+      /* no audio track playing */
+      Pico_mcd->regs[0x36>>1].byte.h = 0x01;
+
+      /* update status (RS1-RS8 ignored) */
+      cdd.status = CD_OPEN;
+      set_reg16(0x38, CD_OPEN << 8);
+      set_reg16(0x3a, 0x0000);
+      set_reg16(0x3c, 0x0000);
+      set_reg16(0x3e, 0x0000);
+      set_reg16(0x40, ~CD_OPEN & 0x0f);
+
+      if (PicoMCDopenTray)
+        PicoMCDopenTray();
+      return;
+    }
+
+    default:  /* Unknown command */
+#ifdef LOG_CDD
+      error("Unknown CDD Command !!!\n");
+#endif
+      Pico_mcd->regs[0x38>>1].byte.h = cdd.status;
+      break;
+  }
+
+  /* only compute checksum when necessary */
+  Pico_mcd->regs[0x40>>1].byte.l =
+    ~(Pico_mcd->regs[0x38>>1].byte.h + Pico_mcd->regs[0x38>>1].byte.l +
+    Pico_mcd->regs[0x3a>>1].byte.h + Pico_mcd->regs[0x3a>>1].byte.l +
+    Pico_mcd->regs[0x3c>>1].byte.h + Pico_mcd->regs[0x3c>>1].byte.l +
+    Pico_mcd->regs[0x3e>>1].byte.h + Pico_mcd->regs[0x3e>>1].byte.l +
+    Pico_mcd->regs[0x40>>1].byte.h) & 0x0f;
+}
+
+// vim:shiftwidth=2:ts=2:expandtab
diff --git a/pico/cd/cdd.h b/pico/cd/cdd.h
new file mode 100644 (file)
index 0000000..4789cdb
--- /dev/null
@@ -0,0 +1,98 @@
+/***************************************************************************************
+ *  Genesis Plus
+ *  CD drive processor & CD-DA fader
+ *
+ *  Copyright (C) 2012-2013  Eke-Eke (Genesis Plus GX)
+ *
+ *  Redistribution and use of this code or any derivative works are permitted
+ *  provided that the following conditions are met:
+ *
+ *   - Redistributions may not be sold, nor may they be used in a commercial
+ *     product or activity.
+ *
+ *   - Redistributions that are modified from the original source must include the
+ *     complete source code, including the source code for all components used by a
+ *     binary built from the modified sources. However, as a special exception, the
+ *     source code distributed need not include anything that is normally distributed
+ *     (in either source or binary form) with the major components (compiler, kernel,
+ *     and so on) of the operating system on which the executable runs, unless that
+ *     component itself accompanies the executable.
+ *
+ *   - Redistributions must reproduce the above copyright notice, this list of
+ *     conditions and the following disclaimer in the documentation and/or other
+ *     materials provided with the distribution.
+ *
+ *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ *  POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************************/
+#ifndef _HW_CDD_
+#define _HW_CDD_
+
+#ifdef USE_LIBTREMOR
+#include "tremor/ivorbisfile.h"
+#endif
+
+/* CDD status */
+#define NO_DISC  0x00
+#define CD_PLAY  0x01
+#define CD_SEEK  0x02
+#define CD_SCAN  0x03
+#define CD_READY 0x04
+#define CD_OPEN  0x05 /* similar to 0x0E ? */
+#define CD_STOP  0x09
+#define CD_END   0x0C
+
+/* CD blocks scanning speed */
+#define CD_SCAN_SPEED 30
+
+#define CD_MAX_TRACKS 100
+
+/* CD track */
+typedef struct
+{
+  void *fd;
+#ifdef USE_LIBTREMOR
+  OggVorbis_File vf;
+#endif
+  int offset;
+  int start;
+  int end;
+} track_t; 
+
+/* CD TOC */
+typedef struct
+{
+  int end;
+  int last;
+  track_t tracks[CD_MAX_TRACKS];
+} toc_t; 
+
+/* CDD hardware */
+typedef struct
+{
+  uint32 cycles;
+  uint32 latency;
+  int loaded;
+  int index;
+  int lba;
+  int scanOffset;
+  int volume;
+  uint8 status;
+  uint16 sectorSize;
+  toc_t toc;
+  int16 audio[2];
+} cdd_t; 
+
+extern cdd_t cdd;
+
+#endif
index a038ccf..78c6b0f 100644 (file)
@@ -242,6 +242,8 @@ file_ok:
                                                data->tracks[count].type = CT_MP3;
                                        else if (strcasecmp(ext, "wav") == 0)
                                                data->tracks[count].type = CT_WAV;
+                                       else if (strcasecmp(ext, "bin") == 0)
+                                               data->tracks[count].type = CT_BIN;
                                        else {
                                                elprintf(EL_STATUS, "unhandled audio format: \"%s\"",
                                                        data->tracks[count].fname);
index 3355361..cad03e9 100644 (file)
@@ -22,13 +22,10 @@ void (*PicoMCDcloseTray)(void) = NULL;
 PICO_INTERNAL void PicoInitMCD(void)
 {
   SekInitS68k();
-  Init_CD_Driver();
-  gfx_init();
 }
 
 PICO_INTERNAL void PicoExitMCD(void)
 {
-  End_CD_Driver();
 }
 
 PICO_INTERNAL void PicoPowerMCD(void)
@@ -45,9 +42,11 @@ PICO_INTERNAL void PicoPowerMCD(void)
   memset(Pico_mcd->s68k_regs, 0, sizeof(Pico_mcd->s68k_regs));
   memset(&Pico_mcd->pcm, 0, sizeof(Pico_mcd->pcm));
   memset(&Pico_mcd->m, 0, sizeof(Pico_mcd->m));
+  Pico_mcd->s68k_regs[0x38+9] = 0x0f;  // default checksum
 
   cdc_init();
-  Reset_CD();
+  cdd_reset();
+  gfx_init();
 
   // cold reset state (tested)
   Pico_mcd->m.state_flags = PCD_ST_S68K_RST;
@@ -62,7 +61,7 @@ void pcd_soft_reset(void)
 
   Pico_mcd->m.s68k_pend_ints = 0;
   cdc_reset();
-  CDD_Reset();
+  cdd_reset();
 #ifdef _ASM_CD_MEMORY_C
   //PicoMemResetCDdecode(1); // don't have to call this in 2M mode
 #endif
@@ -135,7 +134,20 @@ unsigned int pcd_cycles_m68k_to_s68k(unsigned int c)
 static void pcd_cdc_event(unsigned int now)
 {
   // 75Hz CDC update
-  Check_CD_Command();
+  cdd_update();
+
+  /* check if a new CDD command has been processed */
+  if (!(Pico_mcd->s68k_regs[0x4b] & 0xf0))
+  {
+    /* reset CDD command wait flag */
+    Pico_mcd->s68k_regs[0x4b] = 0xf0;
+
+    if (Pico_mcd->s68k_regs[0x33] & PCDS_IEN4) {
+      elprintf(EL_INTS|EL_CD, "s68k: cdd irq 4");
+      SekInterruptS68k(4);
+    }
+  }
+
   pcd_event_schedule(now, PCD_EVENT_CDC, 12500000/75);
 }
 
index d3a2927..7d838fc 100644 (file)
@@ -407,8 +407,11 @@ void s68k_reg_write8(u32 a, u32 d)
       elprintf(EL_CDREGS|EL_CD, "s68k irq mask: %02x", d);\r
       d &= 0x7e;\r
       if ((d ^ Pico_mcd->s68k_regs[0x33]) & d & PCDS_IEN4) {\r
-        if (Pico_mcd->s68k_regs[0x37] & 4)\r
-          CDD_Export_Status();\r
+        // XXX: emulate pending irq instead?\r
+        if (Pico_mcd->s68k_regs[0x37] & 4) {\r
+          elprintf(EL_INTS, "cdd export irq 4 (unmask)");\r
+          SekInterruptS68k(4);\r
+        }\r
       }\r
       break;\r
     case 0x34: // fader\r
@@ -418,15 +421,21 @@ void s68k_reg_write8(u32 a, u32 d)
       return; // d/m bit is unsetable\r
     case 0x37: {\r
       u32 d_old = Pico_mcd->s68k_regs[0x37];\r
-      Pico_mcd->s68k_regs[0x37] = d&7;\r
+      Pico_mcd->s68k_regs[0x37] = d & 7;\r
       if ((d&4) && !(d_old&4)) {\r
-        CDD_Export_Status();\r
+        // ??\r
+        pcd_event_schedule_s68k(PCD_EVENT_CDC, 12500000/75);\r
+\r
+        if (Pico_mcd->s68k_regs[0x33] & PCDS_IEN4) {\r
+          elprintf(EL_INTS, "cdd export irq 4");\r
+          SekInterruptS68k(4);\r
+        }\r
       }\r
       return;\r
     }\r
     case 0x4b:\r
       Pico_mcd->s68k_regs[a] = (u8) d;\r
-      CDD_Import_Command();\r
+      cdd_process();\r
       return;\r
     case 0x58:\r
       return;\r
index 904693f..3ba4532 100644 (file)
@@ -198,7 +198,7 @@ enum media_type_e PicoLoadMedia(const char *filename,
 {
   const char *rom_fname = filename;
   enum media_type_e media_type;
-  cd_img_type cd_img_type = CIT_NOT_CD;
+  enum cd_img_type cd_img_type = CIT_NOT_CD;
   unsigned char *rom_data = NULL;
   unsigned int rom_size = 0;
   pm_file *rom = NULL;
@@ -210,7 +210,7 @@ enum media_type_e PicoLoadMedia(const char *filename,
     goto out;
 
   if ((PicoAHW & PAHW_MCD) && Pico_mcd != NULL)
-    Stop_CD();
+    cdd_unload();
   PicoCartUnload();
   PicoAHW = 0;
   PicoQuirks = 0;
@@ -291,7 +291,7 @@ enum media_type_e PicoLoadMedia(const char *filename,
 
   // insert CD if it was detected
   if (cd_img_type != CIT_NOT_CD) {
-    ret = Insert_CD(filename, cd_img_type);
+    ret = cdd_load(filename, cd_img_type);
     if (ret != 0) {
       PicoCartUnload();
       media_type = PM_BAD_CD;
index 41ba7fb..d541672 100644 (file)
@@ -102,7 +102,6 @@ void PicoGetInternal(pint_t which, pint_ret_t *ret);
 // cd/mcd.c\r
 extern void (*PicoMCDopenTray)(void);\r
 extern void (*PicoMCDcloseTray)(void);\r
-extern int PicoCDBuffers;\r
 \r
 // pico.c\r
 #define XPCM_BUFFER_SIZE (320+160)\r
@@ -128,14 +127,9 @@ void *PicoTmpStateSave(void);
 void  PicoTmpStateRestore(void *data);\r
 extern void (*PicoStateProgressCB)(const char *str);\r
 \r
-// cd/buffering.c\r
-void PicoCDBufferInit(void);\r
-void PicoCDBufferFree(void);\r
-void PicoCDBufferFlush(void);\r
-\r
-// cd/cd_sys.c\r
-int Insert_CD(const char *cdimg_name, int type);\r
-int Stop_CD(void); // unloads CD, returns 1 if there was cd loaded\r
+// cd/cdd.c\r
+int cdd_load(const char *filename, int type);\r
+int cdd_unload(void);\r
 \r
 // Cart.c\r
 typedef enum\r
@@ -244,6 +238,15 @@ enum media_type_e {
   PM_MARK3,\r
   PM_CD,\r
 };\r
+\r
+enum cd_img_type\r
+{\r
+  CIT_NOT_CD = 0,\r
+  CIT_ISO,\r
+  CIT_BIN,\r
+  CIT_CUE\r
+};\r
+\r
 enum media_type_e PicoLoadMedia(const char *filename,\r
   const char *carthw_cfg_fname,\r
   const char *(*get_bios_filename)(int *region, const char *cd_fname),\r
index d4d6d7d..76c4812 100644 (file)
@@ -374,9 +374,6 @@ struct PicoSRAM
 };\r
 \r
 // MCD\r
-#include "cd/cd_sys.h"\r
-#include "cd/LC89510.h"\r
-\r
 #define PCM_MIXBUF_LEN ((12500000 / 384) / 50 + 1)\r
 \r
 struct mcd_pcm\r
@@ -448,9 +445,8 @@ typedef struct
   unsigned char bram[0x2000];                  // 110200: 8K\r
   struct mcd_misc m;                           // 112200: misc\r
   struct mcd_pcm pcm;                          // 112240:\r
-  _scd_toc TOC;                                        // not to be saved\r
-  CDD  cdd;\r
-  _scd scd;\r
+  void *cdda_stream;\r
+  int cdda_type;\r
   int pcm_mixbuf[PCM_MIXBUF_LEN * 2];\r
   int pcm_mixpos;\r
   char pcm_mixbuf_dirty;\r
@@ -628,6 +624,19 @@ void cdc_reg_w(unsigned char data);
 unsigned char  cdc_reg_r(void);\r
 unsigned short cdc_host_r(void);\r
 \r
+// cd/cdd.c\r
+void cdd_reset(void);\r
+int cdd_context_save(unsigned char *state);\r
+int cdd_context_load(unsigned char *state);\r
+int cdd_context_load_old(unsigned char *state);\r
+void cdd_read_data(unsigned char *dst);\r
+void cdd_read_audio(unsigned int samples);\r
+void cdd_update(void);\r
+void cdd_process(void);\r
+\r
+// cd/cd_image.c\r
+int load_cd_image(const char *cd_img_name, int *type);\r
+\r
 // cd/gfx.c\r
 void gfx_init(void);\r
 void gfx_start(unsigned int base);\r
@@ -727,13 +736,14 @@ PICO_INTERNAL int  SekInterruptS68k(int irq);
 void SekInterruptClearS68k(int irq);\r
 \r
 // sound/sound.c\r
-PICO_INTERNAL void cdda_start_play();\r
 extern short cdda_out_buffer[2*1152];\r
 extern int PsndLen_exc_cnt;\r
 extern int PsndLen_exc_add;\r
 extern int timer_a_next_oflow, timer_a_step; // in z80 cycles\r
 extern int timer_b_next_oflow, timer_b_step;\r
 \r
+void cdda_start_play(int lba_base, int lba_offset, int lb_len);\r
+\r
 void ym2612_sync_timers(int z80_cycles, int mode_old, int mode_new);\r
 void ym2612_pack_state(void);\r
 void ym2612_unpack_state(void);\r
@@ -786,9 +796,6 @@ PICO_INTERNAL void z80_exit(void);
 PICO_INTERNAL_ASM void wram_2M_to_1M(unsigned char *m);\r
 PICO_INTERNAL_ASM void wram_1M_to_2M(unsigned char *m);\r
 \r
-// cd/buffering.c\r
-PICO_INTERNAL void PicoCDBufferRead(void *dest, int lba);\r
-\r
 // sound/sound.c\r
 PICO_INTERNAL void PsndReset(void);\r
 PICO_INTERNAL void PsndDoDAC(int line_to);\r
index b12afc3..69c1be0 100644 (file)
@@ -132,8 +132,6 @@ void PsndRerate(int preserve_state)
     // feed it back it's own registers, just like after loading state\r
     memcpy(YM2612GetRegs(), state, 0x204);\r
     ym2612_unpack_state();\r
-    if ((PicoAHW & PAHW_MCD) && !(Pico_mcd->s68k_regs[0x36] & 1) && (Pico_mcd->scd.Status_CDC & 1))\r
-      cdda_start_play();\r
   }\r
 \r
   if (preserve_state) memcpy(state, sn76496_regs, 28*4); // remember old state\r
@@ -191,23 +189,19 @@ PICO_INTERNAL void PsndDoDAC(int line_to)
 }\r
 \r
 // cdda\r
-static pm_file *cdda_stream = NULL;\r
-\r
 static void cdda_raw_update(int *buffer, int length)\r
 {\r
   int ret, cdda_bytes, mult = 1;\r
-  if (cdda_stream == NULL)\r
-    return;\r
 \r
   cdda_bytes = length*4;\r
   if (PsndRate <= 22050 + 100) mult = 2;\r
   if (PsndRate <  22050 - 100) mult = 4;\r
   cdda_bytes *= mult;\r
 \r
-  ret = pm_read(cdda_out_buffer, cdda_bytes, cdda_stream);\r
+  ret = pm_read(cdda_out_buffer, cdda_bytes, Pico_mcd->cdda_stream);\r
   if (ret < cdda_bytes) {\r
     memset((char *)cdda_out_buffer + ret, 0, cdda_bytes - ret);\r
-    cdda_stream = NULL;\r
+    Pico_mcd->cdda_stream = NULL;\r
     return;\r
   }\r
 \r
@@ -219,51 +213,24 @@ static void cdda_raw_update(int *buffer, int length)
   }\r
 }\r
 \r
-PICO_INTERNAL void cdda_start_play(void)\r
+void cdda_start_play(int lba_base, int lba_offset, int lb_len)\r
 {\r
-  int lba_offset, index, lba_length, i;\r
-\r
-  elprintf(EL_STATUS, "cdda play track #%i", Pico_mcd->scd.Cur_Track);\r
-\r
-  index = Pico_mcd->scd.Cur_Track - 1;\r
-\r
-  lba_offset = Pico_mcd->scd.Cur_LBA - Track_to_LBA(index + 1);\r
-  if (lba_offset < 0) lba_offset = 0;\r
-  lba_offset += Pico_mcd->TOC.Tracks[index].Offset;\r
-\r
-  // find the actual file for this track\r
-  for (i = index; i > 0; i--)\r
-    if (Pico_mcd->TOC.Tracks[i].F != NULL) break;\r
-\r
-  if (Pico_mcd->TOC.Tracks[i].F == NULL) {\r
-    elprintf(EL_STATUS|EL_ANOMALY, "no track?!");\r
-    return;\r
-  }\r
-\r
-  if (Pico_mcd->TOC.Tracks[i].ftype == CT_MP3)\r
+  if (Pico_mcd->cdda_type == CT_MP3)\r
   {\r
     int pos1024 = 0;\r
 \r
-    lba_length = Pico_mcd->TOC.Tracks[i].Length;\r
-    for (i++; i < Pico_mcd->TOC.Last_Track; i++) {\r
-      if (Pico_mcd->TOC.Tracks[i].F != NULL) break;\r
-      lba_length += Pico_mcd->TOC.Tracks[i].Length;\r
-    }\r
-\r
     if (lba_offset)\r
-      pos1024 = lba_offset * 1024 / lba_length;\r
+      pos1024 = lba_offset * 1024 / lb_len;\r
 \r
-    mp3_start_play(Pico_mcd->TOC.Tracks[index].F, pos1024);\r
+    mp3_start_play(Pico_mcd->cdda_stream, pos1024);\r
     return;\r
   }\r
 \r
-  cdda_stream = Pico_mcd->TOC.Tracks[i].F;\r
-  PicoCDBufferFlush(); // buffering relies on fp not being touched\r
-  pm_seek(cdda_stream, lba_offset * 2352, SEEK_SET);\r
-  if (Pico_mcd->TOC.Tracks[i].ftype == CT_WAV)\r
+  pm_seek(Pico_mcd->cdda_stream, (lba_base + lba_offset) * 2352, SEEK_SET);\r
+  if (Pico_mcd->cdda_type == CT_WAV)\r
   {\r
     // skip headers, assume it's 44kHz stereo uncompressed\r
-    pm_seek(cdda_stream, 44, SEEK_CUR);\r
+    pm_seek(Pico_mcd->cdda_stream, 44, SEEK_CUR);\r
   }\r
 }\r
 \r
@@ -330,13 +297,12 @@ static int PsndRender(int offset, int length)
 \r
   // CD: CDDA audio\r
   // CD mode, cdda enabled, not data track, CDC is reading\r
-  if ((PicoAHW & PAHW_MCD) && (PicoOpt & POPT_EN_MCD_CDDA) &&\r
-               !(Pico_mcd->s68k_regs[0x36] & 1) && (Pico_mcd->scd.Status_CDC & 1))\r
+  if ((PicoAHW & PAHW_MCD) && (PicoOpt & POPT_EN_MCD_CDDA)\r
+      && Pico_mcd->cdda_stream != NULL\r
+      && !(Pico_mcd->s68k_regs[0x36] & 1))\r
   {\r
     // note: only 44, 22 and 11 kHz supported, with forced stereo\r
-    int index = Pico_mcd->scd.Cur_Track - 1;\r
-\r
-    if (Pico_mcd->TOC.Tracks[index].ftype == CT_MP3)\r
+    if (Pico_mcd->cdda_type == CT_MP3)\r
       mp3_update(buf32, length, stereo);\r
     else\r
       cdda_raw_update(buf32, length);\r
index 94cefad..089957e 100644 (file)
@@ -149,8 +149,8 @@ typedef enum {
   CHUNK_GA_REGS,\r
   CHUNK_PCM,\r
   CHUNK_CDC,     // old\r
-  CHUNK_CDD,     // 20\r
-  CHUNK_SCD,\r
+  CHUNK_CDD,     // 20 old\r
+  CHUNK_SCD,     // old\r
   CHUNK_RC,      // old\r
   CHUNK_MISC_CD,\r
   //\r
@@ -177,6 +177,7 @@ typedef enum {
   CHUNK_CD_EVT = 50,\r
   CHUNK_CD_GFX,\r
   CHUNK_CD_CDC,\r
+  CHUNK_CD_CDD,\r
   //\r
   CHUNK_DEFAULT_COUNT,\r
   CHUNK_CARTHW_ = CHUNK_CARTHW,  // 64 (defined in PicoInt)\r
@@ -317,8 +318,6 @@ static int state_save(void *file)
     CHECKED_WRITE_BUFF(CHUNK_BRAM,     Pico_mcd->bram);\r
     CHECKED_WRITE_BUFF(CHUNK_GA_REGS,  Pico_mcd->s68k_regs); // GA regs, not CPU regs\r
     CHECKED_WRITE_BUFF(CHUNK_PCM,      Pico_mcd->pcm);\r
-    CHECKED_WRITE_BUFF(CHUNK_CDD,      Pico_mcd->cdd);\r
-    CHECKED_WRITE_BUFF(CHUNK_SCD,      Pico_mcd->scd);\r
     CHECKED_WRITE_BUFF(CHUNK_MISC_CD,  Pico_mcd->m);\r
     memset(buff, 0, 0x40);\r
     memcpy(buff, pcd_event_times, sizeof(pcd_event_times));\r
@@ -328,6 +327,8 @@ static int state_save(void *file)
     CHECKED_WRITE(CHUNK_CD_GFX, len, buf2);\r
     len = cdc_context_save(buf2);\r
     CHECKED_WRITE(CHUNK_CD_CDC, len, buf2);\r
+    len = cdd_context_save(buf2);\r
+    CHECKED_WRITE(CHUNK_CD_CDD, len, buf2);\r
 \r
     if (Pico_mcd->s68k_regs[3] & 4) // convert back\r
       wram_2M_to_1M(Pico_mcd->word_ram2M);\r
@@ -498,8 +499,6 @@ static int state_load(void *file)
       case CHUNK_BRAM:     CHECKED_READ_BUFF(Pico_mcd->bram); break;\r
       case CHUNK_GA_REGS:  CHECKED_READ_BUFF(Pico_mcd->s68k_regs); break;\r
       case CHUNK_PCM:      CHECKED_READ_BUFF(Pico_mcd->pcm); break;\r
-      case CHUNK_CDD:      CHECKED_READ_BUFF(Pico_mcd->cdd); break;\r
-      case CHUNK_SCD:      CHECKED_READ_BUFF(Pico_mcd->scd); break;\r
       case CHUNK_MISC_CD:  CHECKED_READ_BUFF(Pico_mcd->m); break;\r
 \r
       case CHUNK_CD_EVT:\r
@@ -517,12 +516,22 @@ static int state_load(void *file)
         len_check = cdc_context_load(buf);\r
         break;\r
 \r
+      case CHUNK_CD_CDD:\r
+        CHECKED_READ_LIM(buf);\r
+        len_check = cdd_context_load(buf);\r
+        break;\r
+\r
       // old, to be removed:\r
       case CHUNK_CDC:\r
         CHECKED_READ_LIM(buf);\r
         cdc_context_load_old(buf);\r
         break;\r
 \r
+      case CHUNK_SCD:\r
+        CHECKED_READ_LIM(buf);\r
+        cdd_context_load_old(buf);\r
+        break;\r
+\r
       // 32x stuff\r
 #ifndef NO_32X\r
       case CHUNK_MSH2:\r
@@ -596,9 +605,6 @@ readend:
   {\r
     SekCycleAimS68k = SekCycleCntS68k;\r
     pcd_state_loaded();\r
-\r
-    if (!(Pico_mcd->s68k_regs[0x36] & 1) && (Pico_mcd->scd.Status_CDC & 1))\r
-      cdda_start_play();\r
   }\r
 \r
   retval = 0;\r
index 175bcc1..d2f7e96 100644 (file)
@@ -520,9 +520,6 @@ Homepage: http://www.mame.net/
 \r
 Eke\r
 CD graphics processor and CD controller implementation (from Genesis Plus GX)\r
-\r
-Stephane Dallongeville\r
-Gens, MD/Mega CD/32X emulator. Some Sega CD code is based on this emu.\r
 #ifdef PSP\r
 \r
 people @ ps2dev.org forums / PSPSDK crew\r
@@ -537,6 +534,7 @@ Additional thanks
 * Charles MacDonald (http://cgfm2.emuviews.com/) for old but still very useful\r
   info about genesis hardware.\r
 * Steve Snake for all that he has done for Genesis emulation scene.\r
+* Stephane Dallongeville for writing Gens and making it open source.\r
 * Tasco Deluxe for his reverse engineering work on SVP and some mappers.\r
 * Bart Trzynadlowski for his SSFII and 68000 docs.\r
 * Haze for his research (http://haze.mameworld.info).\r
index c651bca..fb59ecf 100644 (file)
@@ -93,9 +93,9 @@ DEFINES += NO_SMS
 endif
 # CD
 SRCS_COMMON += $(R)pico/cd/mcd.c $(R)pico/cd/memory.c $(R)pico/cd/sek.c \
-       $(R)pico/cd/cdc.c $(R)pico/cd/cd_sys.c $(R)pico/cd/cd_file.c \
+       $(R)pico/cd/cdc.c $(R)pico/cd/cdd.c $(R)pico/cd/cd_image.c \
        $(R)pico/cd/cue.c $(R)pico/cd/gfx.c $(R)pico/cd/gfx_dma.c \
-       $(R)pico/cd/misc.c $(R)pico/cd/pcm.c $(R)pico/cd/buffering.c
+       $(R)pico/cd/misc.c $(R)pico/cd/pcm.c
 # 32X
 ifneq "$(no_32x)" "1"
 SRCS_COMMON += $(R)pico/32x/32x.c $(R)pico/32x/memory.c $(R)pico/32x/draw.c \
index 324c993..97369cb 100644 (file)
@@ -308,11 +308,6 @@ static int custom_read(menu_entry *me, const char *var, const char *val)
                                return 0;
                        return 1;
 
-               case MA_CDOPT_READAHEAD:
-                       if (strcasecmp(var, "ReadAhead buffer") != 0) return 0;
-                       PicoCDBuffers = atoi(val) / 2;
-                       return 1;
-
                case MA_32XOPT_MSH2_CYCLES:
                        currentConfig.msh2_khz = atoi(val);
                        Pico32xSetClocks(currentConfig.msh2_khz * 1000, 0);
index c66c637..18f63f2 100644 (file)
@@ -530,19 +530,20 @@ out:
 \r
 int emu_swap_cd(const char *fname)\r
 {\r
-       cd_img_type cd_type;\r
+       enum cd_img_type cd_type;\r
        int ret = -1;\r
 \r
        cd_type = PicoCdCheck(fname, NULL);\r
        if (cd_type != CIT_NOT_CD)\r
-               ret = Insert_CD(fname, cd_type);\r
+               ret = cdd_load(fname, cd_type);\r
        if (ret != 0) {\r
                menu_update_msg("Load failed, invalid CD image?");\r
                return 0;\r
        }\r
 \r
        strncpy(rom_fname_loaded, fname, sizeof(rom_fname_loaded)-1);\r
-       rom_fname_loaded[sizeof(rom_fname_loaded)-1] = 0;\r
+       rom_fname_loaded[sizeof(rom_fname_loaded) - 1] = 0;\r
+\r
        return 1;\r
 }\r
 \r
@@ -606,7 +607,6 @@ void emu_set_defconfig(void)
        PsndRate = currentConfig.s_PsndRate;\r
        PicoRegionOverride = currentConfig.s_PicoRegion;\r
        PicoAutoRgnOrder = currentConfig.s_PicoAutoRgnOrder;\r
-       PicoCDBuffers = currentConfig.s_PicoCDBuffers;\r
 }\r
 \r
 int emu_read_config(const char *rom_fname, int no_defaults)\r
@@ -1336,10 +1336,6 @@ void emu_loop(void)
 \r
        PicoLoopPrepare();\r
 \r
-       // prepare CD buffer\r
-       if (PicoAHW & PAHW_MCD)\r
-               PicoCDBufferInit();\r
-\r
        plat_video_loop_prepare();\r
        emu_loop_prep();\r
        pemu_sound_start();\r
@@ -1501,10 +1497,4 @@ void emu_loop(void)
 \r
        pemu_loop_end();\r
        emu_sound_stop();\r
-\r
-       // pemu_loop_end() might want to do 1 frame for bg image,\r
-       // so free CD buffer here\r
-       if (PicoAHW & PAHW_MCD)\r
-               PicoCDBufferFree();\r
 }\r
-\r
index 372fad9..0f04bc4 100644 (file)
@@ -395,31 +395,6 @@ static int menu_loop_keyconfig(int id, int keys)
 
 // ------------ SCD options menu ------------
 
-static const char *mgn_cdopt_ra(int id, int *offs)
-{
-       *offs = -5;
-       if (PicoCDBuffers <= 0)
-               return "     OFF";
-       sprintf(static_buff, "%5iK", PicoCDBuffers * 2);
-       return static_buff;
-}
-
-static int mh_cdopt_ra(int id, int keys)
-{
-       if (keys & PBTN_LEFT) {
-               PicoCDBuffers >>= 1;
-               if (PicoCDBuffers < 2)
-                       PicoCDBuffers = 0;
-       } else {
-               if (PicoCDBuffers <= 0)
-                       PicoCDBuffers = 1;
-               PicoCDBuffers <<= 1;
-               if (PicoCDBuffers > 8*1024)
-                       PicoCDBuffers = 8*1024; // 16M
-       }
-       return 0;
-}
-
 static const char h_cdleds[] = "Show power/CD LEDs of emulated console";
 static const char h_cdda[]   = "Play audio tracks from mp3s/wavs/bins";
 static const char h_cdpcm[]  = "Emulate PCM audio chip for effects/voices/music";
@@ -435,7 +410,6 @@ static menu_entry e_menu_cd_options[] =
        mee_onoff_h("CD LEDs",              MA_CDOPT_LEDS,          currentConfig.EmuOpt, EOPT_EN_CD_LEDS, h_cdleds),
        mee_onoff_h("CDDA audio",           MA_CDOPT_CDDA,          PicoOpt, POPT_EN_MCD_CDDA, h_cdda),
        mee_onoff_h("PCM audio",            MA_CDOPT_PCM,           PicoOpt, POPT_EN_MCD_PCM, h_cdpcm),
-       mee_cust   ("ReadAhead buffer",     MA_CDOPT_READAHEAD,     mh_cdopt_ra, mgn_cdopt_ra),
        mee_onoff_h("SaveRAM cart",         MA_CDOPT_SAVERAM,       PicoOpt, POPT_EN_MCD_RAMCART, h_srcart),
        mee_onoff_h("Scale/Rot. fx (slow)", MA_CDOPT_SCALEROT_CHIP, PicoOpt, POPT_EN_MCD_GFX, h_scfx),
        mee_end,
@@ -1045,7 +1019,7 @@ static int main_menu_handler(int id, int keys)
                break;
        case MA_MAIN_CHANGE_CD:
                if (PicoAHW & PAHW_MCD) {
-                       if (!Stop_CD())
+                       if (!cdd_unload())
                                menu_loop_tray();
                        return 1;
                }
index f59cf67..ee15d9c 100644 (file)
@@ -500,7 +500,7 @@ static unsigned int disk_get_image_index(void)
 
 static bool disk_set_image_index(unsigned int index)
 {
-       cd_img_type cd_type;
+       enum cd_img_type cd_type;
        int ret;
 
        if (index >= sizeof(disks) / sizeof(disks[0]))
@@ -521,7 +521,7 @@ static bool disk_set_image_index(unsigned int index)
        ret = -1;
        cd_type = PicoCdCheck(disks[index].fname, NULL);
        if (cd_type != CIT_NOT_CD)
-               ret = Insert_CD(disks[index].fname, cd_type);
+               ret = cdd_load(disks[index].fname, cd_type);
        if (ret != 0) {
                lprintf("Load failed, invalid CD image?\n");
                return 0;
@@ -882,7 +882,6 @@ void retro_init(void)
 #endif
        PsndRate = 44100;
        PicoAutoRgnOrder = 0x184; // US, EU, JP
-       PicoCDBuffers = 0;
 
        vout_width = 320;
        vout_height = 240;