From d2e3d0fbd2f26039c4597bc308ca044f7a4b6f0a Mon Sep 17 00:00:00 2001 From: sorgelig Date: Sun, 19 Apr 2020 14:58:44 +0800 Subject: [PATCH] pcecd: initial support. --- Makefile | 1 + MiSTer.vcxproj | 4 + MiSTer.vcxproj.filters | 12 + cd.h | 31 ++ menu.cpp | 6 +- osd.cpp | 1 + support.h | 3 + support/megacd/cdd.cpp | 2 +- support/megacd/megacd.cpp | 2 +- support/megacd/megacd.h | 26 +- support/pcecd/pcecd.cpp | 136 ++++++ support/pcecd/pcecd.h | 104 +++++ support/pcecd/pcecdd.cpp | 872 ++++++++++++++++++++++++++++++++++++++ user_io.cpp | 10 + user_io.h | 1 + 15 files changed, 1183 insertions(+), 28 deletions(-) create mode 100644 cd.h create mode 100644 support/pcecd/pcecd.cpp create mode 100644 support/pcecd/pcecd.h create mode 100644 support/pcecd/pcecdd.cpp diff --git a/Makefile b/Makefile index c3f3700..5c3ca8f 100644 --- a/Makefile +++ b/Makefile @@ -36,6 +36,7 @@ CPP_SRC = $(wildcard *.cpp) \ $(wildcard ./support/neogeo/*.cpp) \ $(wildcard ./support/arcade/*.cpp) \ $(wildcard ./support/megacd/*.cpp) \ + $(wildcard ./support/pcecd/*.cpp) \ $(wildcard ./support/c64/*.cpp) \ lib/lodepng/lodepng.cpp diff --git a/MiSTer.vcxproj b/MiSTer.vcxproj index af1f2e3..390f559 100644 --- a/MiSTer.vcxproj +++ b/MiSTer.vcxproj @@ -86,6 +86,8 @@ + + @@ -98,6 +100,7 @@ + @@ -142,6 +145,7 @@ + diff --git a/MiSTer.vcxproj.filters b/MiSTer.vcxproj.filters index 42962d0..457d032 100644 --- a/MiSTer.vcxproj.filters +++ b/MiSTer.vcxproj.filters @@ -184,6 +184,12 @@ Source Files\support + + Source Files\support + + + Source Files\support + @@ -348,5 +354,11 @@ Header Files\support + + Header Files + + + Header Files\support + \ No newline at end of file diff --git a/cd.h b/cd.h new file mode 100644 index 0000000..be8fcd3 --- /dev/null +++ b/cd.h @@ -0,0 +1,31 @@ +#ifndef CD_H +#define CD_H + +typedef struct +{ + fileTYPE f; + int offset; + int start; + int end; + int type; +} track_t; + +typedef struct +{ + int end; + int last; + track_t tracks[100]; +// fileTYPE sub; +} toc_t; + +typedef struct +{ + uint8_t m; + uint8_t s; + uint8_t f; +} msf_t; + + +typedef int (*SendDataFunc) (uint8_t* buf, int len, uint8_t index); + +#endif \ No newline at end of file diff --git a/menu.cpp b/menu.cpp index 62397ff..b430edc 100644 --- a/menu.cpp +++ b/menu.cpp @@ -1758,6 +1758,10 @@ void HandleUI(void) } mcd_set_image(ioctl_index, SelectedPath); } + else if (is_pce()) + { + pcecd_set_image(ioctl_index, SelectedPath); + } else { user_io_set_index(user_io_ext_idx(SelectedPath, fs_pFileExt) << 6 | (menusub + 1)); @@ -3545,7 +3549,7 @@ void HandleUI(void) char type = flist_SelectedItem()->de.d_type; memcpy(name, flist_SelectedItem()->de.d_name, sizeof(name)); - if ((fs_Options & SCANO_UMOUNT) && is_megacd() && type == DT_DIR && strcmp(flist_SelectedItem()->de.d_name, "..")) + if ((fs_Options & SCANO_UMOUNT) && (is_megacd() || is_pce()) && type == DT_DIR && strcmp(flist_SelectedItem()->de.d_name, "..")) { int len = strlen(SelectedPath); strcat(SelectedPath, "/"); diff --git a/osd.cpp b/osd.cpp index e9f6578..e97d538 100644 --- a/osd.cpp +++ b/osd.cpp @@ -704,6 +704,7 @@ void OsdUpdate() spi_write(osdbuf + i * 256, 256, 0); DisableOsd(); if (is_megacd()) mcd_poll(); + if (is_pce()) pcecd_poll(); } } diff --git a/support.h b/support.h index 4339367..d6507d4 100644 --- a/support.h +++ b/support.h @@ -30,3 +30,6 @@ // C64 support #include "support/c64/c64.h" + +// PCECD support +#include "support/pcecd/pcecd.h" diff --git a/support/megacd/cdd.cpp b/support/megacd/cdd.cpp index 61e2488..ad01eff 100644 --- a/support/megacd/cdd.cpp +++ b/support/megacd/cdd.cpp @@ -642,7 +642,7 @@ void cdd_t::CommandExec() { /* DATA track */ FileSeek(&this->toc.tracks[0].f, lba_ * this->sectorSize, SEEK_SET); } - else if (cdd.toc.tracks[index].f.opened()) + else if (this->toc.tracks[index].f.opened()) { /* PCM AUDIO track */ FileSeek(&this->toc.tracks[index].f, (lba_ * 2352) - this->toc.tracks[index].offset, SEEK_SET); diff --git a/support/megacd/megacd.cpp b/support/megacd/megacd.cpp index 6270e84..45aced8 100644 --- a/support/megacd/megacd.cpp +++ b/support/megacd/megacd.cpp @@ -12,7 +12,7 @@ #define SAVE_IO_INDEX 5 // fake download to trigger save loading -int loaded = 0, unloaded = 0, need_reset=0; +static int loaded = 0, unloaded = 0, need_reset=0; static uint8_t has_command = 0; void mcd_poll() diff --git a/support/megacd/megacd.h b/support/megacd/megacd.h index f41f8f2..5e12f19 100644 --- a/support/megacd/megacd.h +++ b/support/megacd/megacd.h @@ -35,31 +35,7 @@ #define CD_COMM_TRAY_CLOSE 0x0C #define CD_COMM_TRAY_OPEN 0x0D -typedef struct -{ - fileTYPE f; - int offset; - int start; - int end; - int type; -} track_t; - -typedef struct -{ - int end; - int last; - track_t tracks[100]; -// fileTYPE sub; -} toc_t; - -typedef struct -{ - uint8_t m; - uint8_t s; - uint8_t f; -} msf_t; - -typedef int (*SendDataFunc) (uint8_t* buf, int len, uint8_t index); +#include "../../cd.h" class cdd_t { diff --git a/support/pcecd/pcecd.cpp b/support/pcecd/pcecd.cpp new file mode 100644 index 0000000..0df4987 --- /dev/null +++ b/support/pcecd/pcecd.cpp @@ -0,0 +1,136 @@ + +#include +#include +#include +#include + +#include "../../file_io.h" +#include "../../user_io.h" +#include "../../spi.h" +#include "../../hardware.h" +#include "pcecd.h" + + +static int /*loaded = 0, unloaded = 0,*/ need_reset=0; +static uint8_t has_command = 0; + +void pcecd_poll() +{ + static uint32_t poll_timer = 0; + static uint8_t last_req = 255; + static uint8_t adj = 0; + + if (!poll_timer || CheckTimer(poll_timer)) + { + poll_timer = GetTimer(13 + (!adj ? 1 : 0)); + if (++adj >= 3) adj = 0; + + if (pcecdd.has_status) { + uint16_t s; + pcecdd.GetStatus((uint8_t*)&s); + + spi_uio_cmd_cont(UIO_CD_SET); + spi_w(s); + DisableIO(); + + pcecdd.has_status = 0; + + printf("\x1b[32mPCECD: Send status = %02X, message = %02X\n\x1b[0m", s&0xFF, s >> 8); + } + + pcecdd.Update(); + } + + + uint8_t req = spi_uio_cmd_cont(UIO_CD_GET); + if (req != last_req) + { + last_req = req; + + uint16_t data_in[6]; + data_in[0] = spi_w(0); + data_in[1] = spi_w(0); + data_in[2] = spi_w(0); + data_in[3] = spi_w(0); + data_in[4] = spi_w(0); + data_in[5] = spi_w(0); + DisableIO(); + + if (need_reset) { + need_reset = 0; + pcecdd.Reset(); + } + + if (!((uint8_t*)data_in)[11]) { + pcecdd.SetCommand((uint8_t*)data_in); + pcecdd.CommandExec(); + has_command = 1; + } + else { + pcecdd.can_read_next = true; + } + + + //printf("\x1b[32mMCD: Get command, command = %04X%04X%04X, has_command = %u\n\x1b[0m", data_in[2], data_in[1], data_in[0], has_command); + } + else + DisableIO(); +} + +void pcecd_reset() { + need_reset = 1; +} + +static void notify_mount(int load) +{ + spi_uio_cmd16(UIO_SET_SDINFO, load); + spi_uio_cmd8(UIO_SET_SDSTAT, 1); + + if (!load) + { + user_io_8bit_set_status(UIO_STATUS_RESET, UIO_STATUS_RESET); + usleep(100000); + user_io_8bit_set_status(0, UIO_STATUS_RESET); + } +} + +void pcecd_set_image(int num, const char *filename) +{ + (void)num; + + pcecdd.Unload(); + pcecdd.status = CD_STAT_OPEN; + + if (strlen(filename)) { + static char path[1024]; + + if (pcecdd.Load(filename) > 0) { + pcecdd.status = pcecdd.loaded ? CD_STAT_STOP : CD_STAT_NO_DISC; + pcecdd.latency = 10; + pcecdd.SendData = pcecd_send_data; + + // load CD BIOS + sprintf(path, "%s/cd.rom", user_io_get_core_path()); + user_io_file_tx(path, 0); + notify_mount(1); + } + else { + notify_mount(0); + pcecdd.status = CD_STAT_NO_DISC; + } + } + else + { + pcecdd.Unload(); + notify_mount(0); + pcecdd.status = CD_STAT_NO_DISC; + } +} + +int pcecd_send_data(uint8_t* buf, int len, uint8_t index) { + user_io_set_index(index); + user_io_set_download(1); + user_io_file_tx_write(buf, len); + user_io_set_download(0); + return 1; +} diff --git a/support/pcecd/pcecd.h b/support/pcecd/pcecd.h new file mode 100644 index 0000000..08326af --- /dev/null +++ b/support/pcecd/pcecd.h @@ -0,0 +1,104 @@ +#ifndef PCECD_H +#define PCECD_H + + +// CDD status +#define CD_STAT_STOP 0x00 +#define CD_STAT_PLAY 0x01 +#define CD_STAT_SEEK 0x02 +#define CD_STAT_SCAN 0x03 +#define CD_STAT_PAUSE 0x04 +#define CD_STAT_OPEN 0x05 +#define CD_STAT_NO_VALID_CHK 0x06 +#define CD_STAT_NO_VALID_CMD 0x07 +#define CD_STAT_ERROR 0x08 +#define CD_STAT_TOC 0x09 +#define CD_STAT_TRACK_MOVE 0x0A +#define CD_STAT_NO_DISC 0x0B +#define CD_STAT_END 0x0C +#define CD_STAT_TRAY 0x0E +#define CD_STAT_TEST 0x0F + +// CDD command +#define PCECD_COMM_TESTUNIT 0x00 +#define PCECD_COMM_REQUESTSENSE 0x03 +#define PCECD_COMM_READ6 0x08 +#define PCECD_COMM_SAPSP 0xD8 +#define PCECD_COMM_SAPEP 0xD9 +#define PCECD_COMM_PAUSE 0xDA +#define PCECD_COMM_READSUBQ 0xDD +#define PCECD_COMM_GETDIRINFO 0xDE + +#define PCECD_STATE_IDLE 0 +#define PCECD_STATE_READ 1 +#define PCECD_STATE_PLAY 2 +#define PCECD_STATE_PAUSE 3 + + +#include "../../cd.h" + + +class pcecdd_t +{ +public: + uint32_t latency; + uint8_t status; + uint8_t isData; + int loaded; + SendDataFunc SendData; + int has_status; + bool can_read_next; + + pcecdd_t(); + int Load(const char *filename); + void Unload(); + void Reset(); + void Update(); + void CommandExec(); + int GetStatus(uint8_t* buf); + int SetCommand(uint8_t* buf); + +private: + toc_t toc; + int index; + int lba; + int cnt; + uint16_t sectorSize; + int scanOffset; + int audioLength; + int audioOffset; + uint8_t state; + int CDDAStart; + int CDDAEnd; + + uint8_t stat[2]; + uint8_t comm[12]; + + uint8_t sec_buf[2352 + 2]; + + int LoadCUE(const char* filename); + int SectorSend(uint8_t* header); + void ReadData(uint8_t *buf); + int ReadCDDA(uint8_t *buf); + void ReadSubcode(uint16_t* buf); + void LBAToMSF(int lba, msf_t* msf); + void MSFToLBA(int* lba, msf_t* msf); + void MSFToLBA(int* lba, uint8_t m, uint8_t s, uint8_t f); + int GetTrackByLBA(int lba, toc_t* toc); +}; + +#define BCD(v) ((uint8_t)((((v)/10) << 4) | ((v)%10))) +#define U8(v) ((uint8_t)(((((v)&0xF0) >> 4) * 10) + ((v)&0x0F))) + +#define CD_SCAN_SPEED 30 + +//pcecdd.cpp +extern pcecdd_t pcecdd; + + +void pcecd_poll(); +void pcecd_set_image(int num, const char *filename); +int pcecd_send_data(uint8_t* buf, int len, uint8_t index); +void pcecd_reset(); + +#endif diff --git a/support/pcecd/pcecdd.cpp b/support/pcecd/pcecdd.cpp new file mode 100644 index 0000000..a564b4a --- /dev/null +++ b/support/pcecd/pcecdd.cpp @@ -0,0 +1,872 @@ + +#include +#include +#include +#include + +#include "../../file_io.h" + +#include "pcecd.h" + +#define PCECD_DATA_IO_INDEX 2 + +pcecdd_t pcecdd; + +pcecdd_t::pcecdd_t() { + latency = 10; + loaded = 0; + index = 0; + lba = 0; + scanOffset = 0; + isData = 1; + status = CD_STAT_NO_DISC; + audioLength = 0; + audioOffset = 0; + SendData = NULL; + has_status = 0; + CDDAStart = 0; + CDDAEnd = 0; + state = PCECD_STATE_IDLE; + + stat[0] = 0xB; + stat[1] = 0x0; +} + +static int sgets(char *out, int sz, char **in) +{ + *out = 0; + do + { + char *instr = *in; + int cnt = 0; + + while (*instr && *instr != 10) + { + if (*instr == 13) + { + instr++; + continue; + } + + if (cnt < sz - 1) + { + out[cnt++] = *instr; + out[cnt] = 0; + } + + instr++; + } + + if(*instr == 10) instr++; + *in = instr; + } + while (!*out && **in); + + return *out; +} + +int pcecdd_t::LoadCUE(const char* filename) { + static char fname[1024 + 10]; + static char line[128]; + char *ptr, *lptr; + static char toc[100 * 1024]; + + strcpy(fname, filename); + + memset(toc, 0, sizeof(toc)); + if (!FileLoad(fname, toc, sizeof(toc) - 1)) return 1; + + printf("\x1b[32mPCECD: Open CUE: %s\n\x1b[0m", fname); + + int mm, ss, bb, pregap = 0; + + char *buf = toc; + while (sgets(line, sizeof(line), &buf)) + { + lptr = line; + while (*lptr == 0x20) lptr++; + + /* decode FILE commands */ + if (!(memcmp(lptr, "FILE", 4))) + { + ptr = fname + strlen(fname) - 1; + while ((ptr - fname) && (*ptr != '/') && (*ptr != '\\')) ptr--; + if (ptr - fname) ptr++; + + lptr += 4; + while (*lptr == 0x20) lptr++; + + if (*lptr == '\"') + { + lptr++; + while ((*lptr != '\"') && (lptr <= (line + 128)) && (ptr < (fname + 1023))) + *ptr++ = *lptr++; + } + else + { + while ((*lptr != 0x20) && (lptr <= (line + 128)) && (ptr < (fname + 1023))) + *ptr++ = *lptr++; + } + *ptr = 0; + + if(!FileOpen(&this->toc.tracks[this->toc.last].f, fname)) return -1; + + printf("\x1b[32mPCECD: Open track file: %s\n\x1b[0m", fname); + + pregap = 0; + + this->toc.tracks[this->toc.last].offset = 0; + + if (!strstr(lptr, "BINARY") && !strstr(lptr, "MOTOROLA") && !strstr(lptr, "WAVE")) + { + FileClose(&this->toc.tracks[this->toc.last].f); + printf("\x1b[32mPCECD: unsupported file: %s\n\x1b[0m", fname); + + return -1; + } + } + + /* decode TRACK commands */ + else if ((sscanf(lptr, "TRACK %02d %*s", &bb)) || (sscanf(lptr, "TRACK %d %*s", &bb))) + { + if (bb != (this->toc.last + 1)) + { + FileClose(&this->toc.tracks[this->toc.last].f); + printf("\x1b[32mPCECD: missing tracks: %s\n\x1b[0m", fname); + break; + } + + //if (!this->toc.last) + { + if (strstr(lptr, "MODE1/2048")) + { + this->sectorSize = 2048; + this->toc.tracks[this->toc.last].type = 1; + } + else if (strstr(lptr, "MODE1/2352")) + { + this->sectorSize = 2352; + this->toc.tracks[this->toc.last].type = 1; + + FileSeek(&this->toc.tracks[this->toc.last].f, 0x10, SEEK_SET); + } + else if (strstr(lptr, "AUDIO")) + { + this->sectorSize = 2352; + this->toc.tracks[this->toc.last].type = 0; + + FileSeek(&this->toc.tracks[this->toc.last].f, 0, SEEK_SET); + } + + /*if (this->sectorSize) + { + this->toc.tracks[0].type = 1; + + FileReadAdv(&this->toc.tracks[0].f, header, 0x210); + FileSeek(&this->toc.tracks[0].f, 0, SEEK_SET); + }*/ + } + + if (this->toc.last) + { + if (!this->toc.tracks[this->toc.last].f.opened()) + { + this->toc.tracks[this->toc.last - 1].end = 0; + } + } + } + + /* decode PREGAP commands */ + else if (sscanf(lptr, "PREGAP %02d:%02d:%02d", &mm, &ss, &bb) == 3) + { + pregap += bb + ss * 75 + mm * 60 * 75; + } + + /* decode INDEX commands */ + else if ((sscanf(lptr, "INDEX 00 %02d:%02d:%02d", &mm, &ss, &bb) == 3) || + (sscanf(lptr, "INDEX 0 %02d:%02d:%02d", &mm, &ss, &bb) == 3)) + { + if (this->toc.last && !this->toc.tracks[this->toc.last - 1].end) + { + this->toc.tracks[this->toc.last - 1].end = bb + ss * 75 + mm * 60 * 75 + pregap; + } + } + else if ((sscanf(lptr, "INDEX 01 %02d:%02d:%02d", &mm, &ss, &bb) == 3) || + (sscanf(lptr, "INDEX 1 %02d:%02d:%02d", &mm, &ss, &bb) == 3)) + { + this->toc.tracks[this->toc.last].offset += pregap * 2352; + + if (!this->toc.tracks[this->toc.last].f.opened()) + { + FileOpen(&this->toc.tracks[this->toc.last].f, fname); + this->toc.tracks[this->toc.last].start = bb + ss * 75 + mm * 60 * 75 + pregap; + if (this->toc.last && !this->toc.tracks[this->toc.last - 1].end) + { + this->toc.tracks[this->toc.last - 1].end = this->toc.tracks[this->toc.last].start; + } + } + else + { + FileSeek(&this->toc.tracks[this->toc.last].f, 0, SEEK_SET); + + this->toc.tracks[this->toc.last].start = this->toc.end + pregap; + this->toc.tracks[this->toc.last].offset += this->toc.end * 2352; + + int sectorSize = 2352; + if (this->toc.tracks[this->toc.last].type) sectorSize = this->sectorSize; + this->toc.tracks[this->toc.last].end = this->toc.tracks[this->toc.last].start + ((this->toc.tracks[this->toc.last].f.size + sectorSize - 1) / sectorSize); + + this->toc.tracks[this->toc.last].start += (bb + ss * 75 + mm * 60 * 75); + this->toc.end = this->toc.tracks[this->toc.last].end; + } + + this->toc.last++; + if (this->toc.last == 99) break; + } + } + + if (this->toc.last && !this->toc.tracks[this->toc.last - 1].end) + { + this->toc.end += pregap; + this->toc.tracks[this->toc.last - 1].end = this->toc.end; + } + + for (int i = 0; i < this->toc.last; i++) + { + printf("\x1b[32mPCECD: Track = %u, start = %u, end = %u, offset = %u, type = %u\n\x1b[0m", i, this->toc.tracks[i].start, this->toc.tracks[i].end, this->toc.tracks[i].offset, this->toc.tracks[i].type); + } + + FileClose(&this->toc.tracks[this->toc.last].f); + return 0; +} + +int pcecdd_t::Load(const char *filename) +{ + //char fname[1024 + 10]; + static char header[1024]; + fileTYPE *fd_img; + + Unload(); + + if (LoadCUE(filename)) { + return (-1); + } + + fd_img = &this->toc.tracks[0].f; + + FileSeek(fd_img, 0, SEEK_SET); + FileReadAdv(fd_img, header, 0x10); + + if (!memcmp("SEGADISCSYSTEM", header, 14)) + { + this->sectorSize = 2048; + } + else + { + FileReadAdv(fd_img, header, 0x10); + if (!memcmp("SEGADISCSYSTEM", header, 14)) + { + this->sectorSize = 2352; + } + } + + if (this->sectorSize) + { + FileReadAdv(fd_img, header + 0x10, 0x200); + FileSeek(fd_img, 0, SEEK_SET); + } + else + { + FileClose(fd_img); + return (-1); + } + + printf("\x1b[32mPCECD: Sector size = %u, Track 0 end = %u\n\x1b[0m", this->sectorSize, this->toc.tracks[0].end); + + if (this->toc.last) + { + this->toc.tracks[this->toc.last].start = this->toc.end; + this->loaded = 1; + + //memcpy(&fname[strlen(fname) - 4], ".sub", 4); + //this->toc.sub = fopen(getFullPath(fname), "r"); + + printf("\x1b[32mPCECD: CD mounted , last track = %u\n\x1b[0m", this->toc.last); + + return 1; + } + + return 0; +} + +void pcecdd_t::Unload() +{ + if (this->loaded) + { + for (int i = 0; i < this->toc.last; i++) + { + FileClose(&this->toc.tracks[i].f); + } + + //if (this->toc.sub) fclose(this->toc.sub); + + this->loaded = 0; + } + + memset(&this->toc, 0x00, sizeof(this->toc)); + this->sectorSize = 0; +} + +void pcecdd_t::Reset() { + latency = 10; + index = 0; + lba = 0; + scanOffset = 0; + isData = 1; + status = loaded ? CD_STAT_STOP : CD_STAT_NO_DISC; + audioLength = 0; + audioOffset = 0; + has_status = 0; + CDDAStart = 0; + CDDAEnd = 0; + state = PCECD_STATE_IDLE; + + stat[0] = 0xB; + stat[1] = 0x0; +} + +void pcecdd_t::Update() { + /*if (this->status == CD_STAT_STOP || this->status == CD_STAT_TRAY || this->status == CD_STAT_OPEN) + { + if (this->latency > 0) + { + this->latency--; + return; + } + this->status = this->loaded ? CD_STAT_TOC : CD_STAT_NO_DISC; + } + else if (this->status == CD_STAT_SEEK) + { + if (this->latency > 0) + { + this->latency--; + return; + } + this->status = CD_STAT_PAUSE; + } + else*/ if (this->state == PCECD_STATE_READ) + { + if (this->latency > 0) + { + this->latency--; + return; + } + + if (this->index >= this->toc.last) + { + this->state = PCECD_STATE_IDLE; + return; + } + + if (!this->can_read_next) + return; + + this->can_read_next = false; + + //if (this->toc.sub) mcd_sub_send(); + + if (this->toc.tracks[this->index].type) + { + // CD-ROM (Mode 1) + sec_buf[0] = 0x00; + sec_buf[1] = 0x08 | 0x80; + ReadData(sec_buf + 2); + + if (SendData) + SendData(sec_buf, 2048 + 2, PCECD_DATA_IO_INDEX); + + printf("\x1b[32mPCECD: Data sector send = %i\n\x1b[0m", this->lba); + } + else + { + if (this->lba >= this->toc.tracks[this->index].start) + { + this->isData = 0x00; + } + + //SectorSend(0); + } + + this->cnt--; + + if (!this->cnt) { + stat[0] = 0; + stat[1] = 0; + has_status = 1; + + this->state = PCECD_STATE_IDLE; + } + else { + + } + + this->lba++; + if (this->lba >= this->toc.tracks[this->index].end) + { + this->index++; + + this->isData = 0x01; + + if (this->toc.tracks[this->index].f.opened()) + { + FileSeek(&this->toc.tracks[this->index].f, (this->toc.tracks[this->index].start * 2352) - this->toc.tracks[this->index].offset, SEEK_SET); + } + } + } + else if (this->state == PCECD_STATE_PLAY) { + if (this->latency > 0) + { + this->latency--; + return; + } + + if (this->index >= this->toc.last) + { + this->state = PCECD_STATE_IDLE; + return; + } + + if (this->toc.tracks[this->index].type) + return; + + FileSeek(&this->toc.tracks[index].f, (this->lba * 2352) - this->toc.tracks[index].offset, SEEK_SET); + + sec_buf[0] = 0x30; + sec_buf[1] = 0x09; + ReadCDDA(sec_buf + 2); + + if (SendData) + SendData(sec_buf, 2352 + 2, PCECD_DATA_IO_INDEX); + + //printf("\x1b[32mPCECD: Audio sector send = %i, track = %i, offset = %i\n\x1b[0m", this->lba, this->index, (this->lba * 2352) - this->toc.tracks[index].offset); + + this->lba++; + if (this->lba > this->CDDAEnd) + { + this->state = PCECD_STATE_IDLE; + } + + } + //else if (this->status == CD_STAT_SCAN) + //{ + // this->lba += this->scanOffset; + + // if (this->lba >= this->toc.tracks[this->index].end) + // { + // this->index++; + // if (this->index < this->toc.last) + // { + // this->lba = this->toc.tracks[this->index].start; + // } + // else + // { + // this->lba = this->toc.end; + // this->status = CD_STAT_END; + // this->isData = 0x01; + // return; + // } + // } + // else if (this->lba < this->toc.tracks[this->index].start) + // { + // if (this->index > 0) + // { + // this->index--; + // this->lba = this->toc.tracks[this->index].end; + // } + // else + // { + // this->lba = 0; + // } + // } + + // this->isData = this->toc.tracks[this->index].type; + + // //if (this->toc.sub) fseek(this->toc.sub, this->lba * 96, SEEK_SET); + + // if (this->toc.tracks[this->index].type) + // { + // // DATA track + // FileSeek(&this->toc.tracks[0].f, this->lba * this->sectorSize, SEEK_SET); + // } + // else if (this->toc.tracks[this->index].f.opened()) + // { + // // AUDIO track + // FileSeek(&this->toc.tracks[this->index].f, (this->lba * 2352) - this->toc.tracks[this->index].offset, SEEK_SET); + // } + //} +} + +void pcecdd_t::CommandExec() { + msf_t msf; + int lba_ = 0; + uint8_t buf[16]; + + memset(buf, 0, 16); + + switch (comm[0]) { + case PCECD_COMM_TESTUNIT: + stat[0] = 0; + stat[1] = 0; + has_status = 1; + printf("\x1b[32mPCECD: Command TESTUNIT\n\x1b[0m"); + break; + + case PCECD_COMM_GETDIRINFO: { + int len = 0; + switch (comm[1]) { + case 0: + default: + buf[0] = 2; + buf[1] = 0 | 0x80; + buf[2] = 1; + buf[3] = BCD(this->toc.last); + len = 2 + 2; + break; + + case 1: + lba_ = this->toc.end + 150; + LBAToMSF(lba_, &msf); + + buf[0] = 4; + buf[1] = 0 | 0x80; + buf[2] = BCD(msf.m); + buf[3] = BCD(msf.s); + buf[4] = BCD(msf.f); + buf[5] = 0; + len = 4 + 2; + break; + + case 2: + int track = U8(comm[2]); + lba_ = this->toc.tracks[track - 1].start + 150; + LBAToMSF(lba_, &msf); + + buf[0] = 4; + buf[1] = 0 | 0x80; + buf[2] = BCD(msf.m); + buf[3] = BCD(msf.s); + buf[4] = BCD(msf.f); + buf[5] = this->toc.tracks[track - 1].type << 2; + len = 4 + 2; + break; + } + + stat[0] = 0; + stat[1] = 0; + has_status = 1; + + printf("\x1b[32mPCECD: Command GETDIRINFO, [1] = %02X, [2] = %02X\n\x1b[0m", comm[1], comm[2]); + + if (SendData && len) + SendData(buf, len, PCECD_DATA_IO_INDEX); + + printf("\x1b[32mPCECD: Send data, len = %u, [2] = %02X, [3] = %02X, [4] = %02X, [5] = %02X\n\x1b[0m", len, buf[2], buf[3], buf[4], buf[5]); + } + break; + + case PCECD_COMM_READ6: { + lba_ = ((comm[1] << 16) | (comm[2] << 8) | comm[3]) & 0x1FFFFF; + int cnt_ = comm[4]; + + this->lba = lba_; + this->cnt = cnt_; + + int index = GetTrackByLBA(lba_, &this->toc); + + this->index = index; + if (lba_ < this->toc.tracks[index].start) + { + lba_ = this->toc.tracks[index].start; + } + + if (this->toc.tracks[index].type) + { + FileSeek(&this->toc.tracks[0].f, lba_ * this->sectorSize, SEEK_SET); + } + else if (this->toc.tracks[index].f.opened()) + { + FileSeek(&this->toc.tracks[index].f, (lba_ * 2352) - this->toc.tracks[index].offset, SEEK_SET); + } + + this->audioOffset = 0; + + //if (this->toc.sub) fseek(this->toc.sub, lba_ * 96, SEEK_SET); + + //this->isData = 1; + this->can_read_next = true; + this->state = PCECD_STATE_READ; + + printf("\x1b[32mPCECD: Command READ6, lba = %u, cnt = %u\n\x1b[0m", this->lba, this->cnt); + } + break; + + case PCECD_COMM_SAPSP: { + int lba_ = 0; + switch (comm[9] & 0xc0) + { + default: + case 0x00: + lba_ = (comm[3] << 16) | (comm[4] << 8) | comm[5]; + break; + + case 0x40: + MSFToLBA(&lba_, U8(comm[2]), U8(comm[3]), U8(comm[4])); + break; + + case 0x80: + { + int track = U8(comm[2]); + + if (!track) + track = 1; + else if (track > toc.last) + track = toc.last; + lba_ = this->toc.tracks[track - 1].start; + } + break; + } + + this->CDDAStart = lba_; + this->lba = lba_; + int index = GetTrackByLBA(lba_, &this->toc); + + this->index = index; + /*if (lba_ < this->toc.tracks[index].start) + { + lba_ = this->toc.tracks[index].start; + }*/ + + this->CDDAEnd = this->toc.tracks[index].end; + + //this->isData = 0; + this->state = PCECD_STATE_PLAY; + + FileSeek(&this->toc.tracks[index].f, (this->lba * 2352) - this->toc.tracks[index].offset, SEEK_SET); + + sec_buf[0] = 0x30; + sec_buf[1] = 0x09; + ReadCDDA(sec_buf + 2); + + if (SendData) + SendData(sec_buf, 2352 + 2, PCECD_DATA_IO_INDEX); + + this->lba++; + + stat[0] = 0; + stat[1] = 0; + has_status = 1; + } + printf("\x1b[32mPCECD: Command SAPSP, start = %i, [9] = %02X\n\x1b[0m", this->CDDAStart, comm[9]); + break; + + case PCECD_COMM_SAPEP: { + int lba_ = 0; + switch (comm[9] & 0xc0) + { + default: + case 0x00: + lba_ = (comm[3] << 16) | (comm[4] << 8) | comm[5]; + break; + + case 0x40: + MSFToLBA(&lba_, U8(comm[2]), U8(comm[3]), U8(comm[4])); + break; + + case 0x80: + { + int track = U8(comm[2]); + + if (!track) + track = 1; + else if (track > toc.last) + track = toc.last; + lba_ = this->toc.tracks[track - 1].start + 150; + } + break; + } + + this->CDDAEnd = lba_; + + stat[0] = 0; + stat[1] = 0; + has_status = 1; + } + printf("\x1b[32mPCECD: Command SAPEP, end = %i, [9] = %02X\n\x1b[0m", this->CDDAEnd, comm[9]); + break; + + case PCECD_COMM_PAUSE: { + this->state = PCECD_STATE_PAUSE; + + stat[0] = 0; + stat[1] = 0; + has_status = 1; + } + printf("\x1b[32mPCECD: Command PAUSE, current lba = %i\n\x1b[0m", this->lba); + break; + + case PCECD_COMM_READSUBQ: { + int lba_rel = this->toc.tracks[this->index].start - this->toc.tracks[this->index].offset + 150; + lba_ = this->toc.tracks[this->index].start + 150; + + buf[0] = 0x0A; + buf[1] = 0 | 0x80; + buf[2] = this->state == PCECD_STATE_PLAY ? 0 : 3; + buf[3] = 0; + buf[4] = this->index + 1; + buf[5] = this->index; + + LBAToMSF(lba_rel, &msf); + buf[6] = BCD(msf.m); + buf[7] = BCD(msf.s); + buf[8] = BCD(msf.f); + + LBAToMSF(lba_, &msf); + buf[9] = BCD(msf.m); + buf[10] = BCD(msf.s); + buf[11] = BCD(msf.f); + + stat[0] = 0; + stat[1] = 0; + has_status = 1; + + printf("\x1b[32mPCECD: Command READSUBQ, [1] = %02X, track = %i, index = %i, lba_rel = %i, lba_abs = %i\n\x1b[0m", comm[1], this->index + 1, this->index, lba_rel, lba_); + + if (SendData) + SendData(buf, 10 + 2, PCECD_DATA_IO_INDEX); + } + break; + + default: + //stat[0] = this->status; + + printf("\x1b[32mPCECD: Command undefined, [0] = %02X, [1] = %02X, [2] = %02X, [3] = %02X, [4] = %02X, [5] = %02X\n\x1b[0m", comm[0], comm[1], comm[2], comm[3], comm[4], comm[5]); + break; + } + + /*if (buf[0] || buf[1]) { + int len = ((int)buf[1] * 256) + buf[0] + 2; + if (SendData) + SendData(buf, len, PCECD_DATA_IO_INDEX); + + printf("\x1b[32mPCECD: Send data, len = %u, [2] = %02X, [3] = %02X, [4] = %02X, [5] = %02X\n\x1b[0m", len, buf[2], buf[3], buf[4], buf[5]); + }*/ +} + +int pcecdd_t::GetStatus(uint8_t* buf) { + memcpy(buf, stat, 2); + return 0; +} + +int pcecdd_t::SetCommand(uint8_t* buf) { + memcpy(comm, buf, 12); + return 0; +} + +void pcecdd_t::LBAToMSF(int lba, msf_t* msf) { + msf->m = (lba / 75) / 60; + msf->s = (lba / 75) % 60; + msf->f = (lba % 75); +} + +void pcecdd_t::MSFToLBA(int* lba, uint8_t m, uint8_t s, uint8_t f) { + *lba = f + s * 75 + m * 60 * 75; +} + +void pcecdd_t::MSFToLBA(int* lba, msf_t* msf) { + *lba = msf->f + msf->s * 75 + msf->m * 60 * 75; +} + +int pcecdd_t::GetTrackByLBA(int lba, toc_t* toc) { + int index = 0; + while ((toc->tracks[index].end <= lba) && (index < toc->last)) index++; + return index; +} + +void pcecdd_t::ReadData(uint8_t *buf) +{ + if (this->toc.tracks[this->index].type && (this->lba >= 0)) + { + if (this->sectorSize == 2048) + { + FileSeek(&this->toc.tracks[0].f, this->lba * 2048, SEEK_SET); + } + else + { + FileSeek(&this->toc.tracks[0].f, this->lba * 2352 + 16, SEEK_SET); + } + + FileReadAdv(&this->toc.tracks[0].f, buf, 2048); + } +} + +int pcecdd_t::ReadCDDA(uint8_t *buf) +{ + this->audioLength = 2352;// 2352 + 2352 - this->audioOffset; + this->audioOffset = 0;// 2352; + + if (this->toc.tracks[this->index].f.opened()) + { + FileReadAdv(&this->toc.tracks[this->index].f, buf, this->audioLength); + } + + return this->audioLength; +} + +void pcecdd_t::ReadSubcode(uint16_t* buf) +{ + (void)buf; + /* + uint8_t subc[96]; + int i, j, n; + + fread(subc, 96, 1, this->toc.sub); + + for (i = 0, n = 0; i < 96; i += 2, n++) + { + int code = 0; + for (j = 0; j < 8; j++) + { + int bits = (subc[(j * 12) + (i / 8)] >> (6 - (i & 6))) & 3; + code |= ((bits & 1) << (7 - j)); + code |= ((bits >> 1) << (15 - j)); + } + + buf[n] = code; + } + */ +} + +int pcecdd_t::SectorSend(uint8_t* header) +{ + uint8_t buf[2352 + 2352]; + int len = 2352; + + if (header) { + memcpy(buf + 12, header, 4); + ReadData(buf + 16); + } + else { + len = ReadCDDA(buf); + } + + if (SendData) + return SendData(buf, len, PCECD_DATA_IO_INDEX); + + return 0; +} + + + + + + diff --git a/user_io.cpp b/user_io.cpp index c616db4..8420612 100644 --- a/user_io.cpp +++ b/user_io.cpp @@ -239,6 +239,13 @@ char is_megacd() return (is_megacd_type == 1); } +static int is_pce_type = 0; +char is_pce() +{ + if (!is_pce_type) is_pce_type = strcasecmp(core_name, "TGFX16") ? 2 : 1; + return (is_pce_type == 1); +} + static int is_archie_type = 0; char is_archie() { @@ -294,6 +301,7 @@ static void user_io_read_core_name() is_neogeo_type = 0; is_minimig_type = 0; is_megacd_type = 0; + is_pce_type = 0; is_archie_type = 0; is_gba_type = 0; is_c64_type = 0; @@ -1985,6 +1993,7 @@ void user_io_send_buttons(char force) if (is_archie()) fpga_load_rbf(name[0] ? name : "Archie.rbf"); if (is_minimig()) minimig_reset(); if (is_megacd()) mcd_reset(); + if (is_pce()) pcecd_reset(); } key_map = map; @@ -2647,6 +2656,7 @@ void user_io_poll() } if (is_megacd()) mcd_poll(); + if (is_pce()) pcecd_poll(); process_ss(0); } diff --git a/user_io.h b/user_io.h index 07bc2ae..0ccb795 100644 --- a/user_io.h +++ b/user_io.h @@ -263,6 +263,7 @@ char is_x86(); char is_snes(); char is_neogeo(); char is_megacd(); +char is_pce(); char is_archie(); char is_gba(); char is_c64();