diff --git a/waterbox/gpgx/Genesis-Plus-GX b/waterbox/gpgx/Genesis-Plus-GX index 499dd30a13..ca03348aad 160000 --- a/waterbox/gpgx/Genesis-Plus-GX +++ b/waterbox/gpgx/Genesis-Plus-GX @@ -1 +1 @@ -Subproject commit 499dd30a13c400b154e22bfc50522b2a309afbc2 +Subproject commit ca03348aadbe1951eca04d2d7b65fbcf0d8d30c1 diff --git a/waterbox/gpgx/Makefile b/waterbox/gpgx/Makefile index ecf4af58a8..fff5c30db5 100644 --- a/waterbox/gpgx/Makefile +++ b/waterbox/gpgx/Makefile @@ -23,6 +23,7 @@ CCFLAGS := -Iutil \ -DUSE_32BPP_RENDERING \ -DHOOK_CPU \ -DINLINE=static\ __inline__ \ + -DcdStream=cdStream \ -fcommon LDFLAGS := @@ -80,7 +81,7 @@ SRCS = $(GPGX_DIR)/core/sound/sound.c \ $(GPGX_DIR)/core/cart_hw/megasd.c \ $(GPGX_DIR)/core/debug/cpuhook.c \ $(GPGX_DIR)/core/loadrom.c \ - cinterface/cddImpl.c \ + cinterface/cdStreamImpl.c \ cinterface/cinterface.c \ util/scrc32.c diff --git a/waterbox/gpgx/cinterface/callbacks.h b/waterbox/gpgx/cinterface/callbacks.h index 9234e9ab0c..4ee2e5ee78 100644 --- a/waterbox/gpgx/cinterface/callbacks.h +++ b/waterbox/gpgx/cinterface/callbacks.h @@ -12,7 +12,7 @@ extern ECL_ENTRY void (*biz_readcb)(unsigned addr); extern ECL_ENTRY void (*biz_writecb)(unsigned addr); extern CDCallback biz_cdcb; -extern ECL_ENTRY void (*cdd_readcallback)(int lba, void *dest, int audio); +extern ECL_ENTRY void (*cdd_readcallback)(int lba, void *dest, int subcode); enum eCDLog_AddrType { diff --git a/waterbox/gpgx/cinterface/cdStreamImpl.c b/waterbox/gpgx/cinterface/cdStreamImpl.c new file mode 100644 index 0000000000..10e408f041 --- /dev/null +++ b/waterbox/gpgx/cinterface/cdStreamImpl.c @@ -0,0 +1,202 @@ +#include +#include + +#include "callbacks.h" + +#define SECTOR_DATA_SIZE 2352 +#define SECTOR_SUBCODE_SIZE 96 + +ECL_INVISIBLE toc_t hotswap_toc; +int8 cd_index = 0; + +struct cdStream_t +{ + int sector_size; + int num_sectors; + int64_t current_sector; + int64_t current_offset; + int64_t end_offset; + uint8_t* cache_buffer; + uint8_t* sectors_cached; +}; + +static cdStream cd_streams[128]; +static cdStream subcode_streams[128]; +ECL_INVISIBLE static int cache_is_allocated[256]; + +#define ALLOC_CACHE(stream) do \ +{ \ + if (UNLIKELY(!cache_is_allocated[(uint8)cd_index + stream->sector_size == SECTOR_SUBCODE_SIZE ? 128 : 0])) \ + { \ + stream->cache_buffer = alloc_invisible(stream->end_offset); \ + stream->sectors_cached = alloc_invisible(stream->num_sectors); \ + memset(stream->sectors_cached, 0, stream->num_sectors); \ + cache_is_allocated[(uint8)cd_index + stream->sector_size == SECTOR_SUBCODE_SIZE ? 128 : 0] = 1; \ + } \ +} while (0); + +static void cdStreamInit(cdStream* stream, int is_subcode) +{ + stream->sector_size = is_subcode ? SECTOR_SUBCODE_SIZE : SECTOR_DATA_SIZE; + stream->num_sectors = cdd.toc.end; // should only be called with current CD + stream->current_sector = 0; + stream->current_offset = 0; + stream->end_offset = stream->sector_size * (int64_t)stream->num_sectors; + ALLOC_CACHE(stream); +} + +cdStream* cdStreamOpen(const char* fname) +{ + // This shouldn't happen + if (cd_index < 0) + { + return NULL; + } + + char* fext = strrchr(fname, '.'); + if (!fext) + { + if (!strcmp(fname, "PRIMARY_CD")) + { + if (load_archive("PRIMARY_CD", (unsigned char*)&cdd.toc, sizeof(toc_t), NULL)) + { + cd_index = 0; + cdStreamInit(&cd_streams[0], 0); + return &cd_streams[0]; + } + } + else if (!strcmp(fname, "HOTSWAP_CD")) + { + memcpy(&cdd.toc, &hotswap_toc, sizeof(toc_t)); + cdStreamInit(&cd_streams[cd_index], 0); + return &cd_streams[cd_index]; + } + } + else if (!strcmp(fext, ".iso")) + { + // an .iso will attempt to be loaded for the "secondary" CD + if (load_archive("SECONDARY_CD", (unsigned char*)&cdd.toc, sizeof(toc_t), NULL)) + { + cd_index = 0; + cdStreamInit(&cd_streams[0], 0); + return &cd_streams[0]; + } + } + else if (!strcmp(fext, ".sub")) + { + // separate stream for subcode + cdStreamInit(&subcode_streams[cd_index], 1); + return &subcode_streams[cd_index]; + } + + return NULL; +} + +void cdStreamClose(cdStream* stream) +{ + // nothing to do +} + +static uint8_t* cdStreamGetSector(cdStream* restrict stream, unsigned* offset) +{ + if (stream->current_sector >= stream->num_sectors) + { + static uint8_t empty_sector[SECTOR_DATA_SIZE]; + *offset = 0; + return empty_sector; + } + + *offset = stream->current_offset - (stream->current_sector * stream->sector_size); + uint8_t* sector_cache = &stream->cache_buffer[stream->current_offset - *offset]; + + if (!stream->sectors_cached[stream->current_sector]) + { + cdd_readcallback(stream->current_sector, sector_cache, stream->sector_size == SECTOR_SUBCODE_SIZE); + stream->sectors_cached[stream->current_sector] = 1; + } + + return sector_cache; +} + +size_t cdStreamRead(void* restrict buffer, size_t size, size_t count, cdStream* restrict stream) +{ + ALLOC_CACHE(stream); + + size_t bytes_to_read = size * count; // in practice, this shouldn't ever overflow + + // we'll 0 fill the bytes past EOF, although we'll still report the bytes actually read + size_t ret = bytes_to_read; + if (stream->current_offset + ret > stream->end_offset) + { + ret = stream->end_offset - stream->current_offset; + } + + while (bytes_to_read > 0) + { + unsigned offset; + uint8_t* sector = cdStreamGetSector(stream, &offset); + + unsigned bytes_to_copy = stream->sector_size - offset; + if (bytes_to_copy > bytes_to_read) + { + bytes_to_copy = bytes_to_read; + } + + memcpy(buffer, sector + offset, bytes_to_copy); + bytes_to_read -= bytes_to_copy; + + stream->current_offset += bytes_to_copy; + if (bytes_to_copy + offset >= stream->sector_size) + { + stream->current_sector++; + } + + if (UNLIKELY(stream->current_offset >= stream->end_offset)) + { + stream->current_offset = stream->end_offset; + stream->current_sector = stream->num_sectors; + } + } + + return ret; +} + +int cdStreamSeek(cdStream* stream, int64_t offset, int origin) +{ + switch (origin) + { + case SEEK_SET: + stream->current_offset = offset; + break; + case SEEK_CUR: + stream->current_offset += offset; + break; + case SEEK_END: + stream->current_offset = stream->end_offset + offset; + break; + } + + if (stream->current_offset < 0) + { + stream->current_offset = 0; + } + + if (stream->current_offset > stream->end_offset) + { + stream->current_offset = stream->end_offset; + } + + stream->current_sector = stream->current_offset / stream->sector_size; + return 0; +} + +int64_t cdStreamTell(cdStream* stream) +{ + return stream->current_offset; +} + +char* cdStreamGets(char* restrict str, int count, cdStream* restrict stream) +{ + // This is only used for GPGX's .cue file parsing, which is not used in our case + return NULL; +} diff --git a/waterbox/gpgx/cinterface/cddImpl.c b/waterbox/gpgx/cinterface/cddImpl.c deleted file mode 100644 index 6a4c6c1527..0000000000 --- a/waterbox/gpgx/cinterface/cddImpl.c +++ /dev/null @@ -1,524 +0,0 @@ -#include "shared.h" -#include "megasd.h" -#include - -static int sampleLba = 0; -static int sampleOffset = 0; -static int tocLba = 0; - -void cdd_reset(void) -{ - /* reset drive access latency */ - cdd.latency = 0; - - /* reset track index */ - cdd.index = 0; - - /* reset logical block address */ - cdd.lba = 0; - - /* reset logical block address for audio*/ - sampleLba = 0; - sampleOffset = 0; - - /* reset logical block address for Toc*/ - tocLba = 0; - - /* reset status */ - cdd.status = cdd.loaded ? CD_TOC : NO_DISC; - - /* reset CD-DA fader (full volume) */ - cdd.fader[0] = cdd.fader[1] = 0x400; - - /* clear CD-DA output */ - cdd.audio[0] = cdd.audio[1] = 0; -} - -typedef struct -{ - toc_t toc; -} frontendcd_t; - -int cdd_load(const char *key, char *header) -{ - frontendcd_t fecd; - char data[2048]; - int startoffs; - - int bytes = sizeof(frontendcd_t); - if (load_archive(key, (unsigned char *)&fecd, bytes, NULL) != bytes) - return 0; - - // look for valid header - cdd_readcallback(0, data, 0); - if (memcmp("SEGADISCSYSTEM", data, 14) == 0) - startoffs = 0; - else if (memcmp("SEGADISCSYSTEM", data + 16, 14) == 0) - startoffs = 16; - else - return 0; - // copy security block - memcpy(header, data + startoffs, 0x210); - - // copy disk information - memcpy(&cdd.toc, &fecd.toc, sizeof(toc_t)); - - /* Valid CD-ROM Mode 1 track found ? */ - if (cdd.toc.tracks[0].type == TYPE_MODE1) - { - /* 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); - } - else if (strstr(header + 0x180,"T-06201-01") != NULL) - { - /* Sewer Shark (USA) (REV1) */ - /* no audio track */ - } - 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)); - } - } - } - - cdd.loaded = 1; - return 1; -} - -void cdd_unload(void) -{ - cdd.loaded = 0; - cdd_readcallback = NULL; - - /* reset TOC */ - memset(&cdd.toc, 0x00, sizeof(cdd.toc)); -} - -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_PAUSE; - } - - /* 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 */ - cdc_decoder_update(*(uint32 *)(header)); - cdd.lba++; - } - else if (cdd.index < cdd.toc.last) - { - /* check against audio track start index */ - if (cdd.lba >= cdd.toc.tracks[cdd.index].start) - { - /* audio track playing */ - // if it wasn't before, set the audio start position - if (scd.regs[0x36>>1].byte.h) - { - sampleLba = cdd.lba + 1; - sampleOffset = 0; - } - scd.regs[0x36>>1].byte.h = 0x00; - } - - /* audio blocks are still sent to CDC as well as CD DAC/Fader */ - cdc_decoder_update(0); - - /* 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) - { - /* play next track */ - cdd.index++; - - /* PAUSE between tracks */ - scd.regs[0x36>>1].byte.h = 0x01; - } - } - - /* scanning disc */ - else if (cdd.status == CD_SCAN) - { - /* fast-forward or fast-rewind */ - cdd.lba += cdd.scanOffset; - sampleLba += cdd.scanOffset; - - /* check current track limits */ - if (cdd.lba >= cdd.toc.tracks[cdd.index].end) - { - /* 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) - { - scd.regs[0x36>>1].byte.h = 0x00; - // set audio start point - sampleLba = cdd.lba; - sampleOffset = 0; - } - } - else if (cdd.lba < cdd.toc.tracks[cdd.index].start) - { - /* 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 */ - scd.regs[0x36>>1].byte.h = 0x01; - - /* end of disc */ - cdd.index = cdd.toc.last; - cdd.lba = cdd.toc.end; - cdd.status = CD_END; - return; - } - } -} - - -void cdd_read_data(uint8 *dst, uint8 *subheader) -{ - /* only allow reading (first) CD-ROM track sectors */ - if (cdd.toc.tracks[cdd.index].type && (cdd.lba >= 0)) - { - /* check sector size */ - if (cdd.sectorSize == 2048) - { - /* read Mode 1 user data (2048 bytes) */ - cdd_readcallback(cdd.lba, dst, 0); - // cdStreamSeek(trackStream[0], cdd.lba * 2048, SEEK_SET); - // cdStreamRead(dst, 2048, 1, trackStream[0]); - } - else - { - /* check if sub-header is required (Mode 2 sector only) */ - if (!subheader) - { - /* skip block sync pattern (12 bytes) + block header (4 bytes) then read Mode 1 user data (2048 bytes) */ - cdd_readcallback(cdd.lba, dst, 0); - // cdStreamSeek(trackStream[0], (cdd.lba * 2352) + 12 + 4, SEEK_SET); - // cdStreamRead(dst, 2048, 1, trackStream[0]); - } - else - { - /* skip block sync pattern (12 bytes) + block header (4 bytes) + Mode 2 sub-header (first 4 bytes) then read Mode 2 sub-header (last 4 bytes) */ - - - uint8_t buffer[2352]; - cdd_readcallback(cdd.lba, buffer, 0); - - // cdStreamSeek(trackStream[0], (cdd.lba * 2352) + 12 + 4 + 4, SEEK_SET); - size_t pos = 12 + 4 + 4; - - // cdStreamRead(subheader, 4, 1, trackStream[0]); - memcpy(subheader, &buffer[pos], 4); pos += 4; - - /* read Mode 2 user data (max 2328 bytes) */ - // cdStreamRead(dst, 2328, 1, trackStream[0]); - memcpy(dst, &buffer[pos], 2328); - } - } - } -} - -void cdd_seek_audio(int index, int lba) -{ - cdd.index = index; - sampleLba = lba; -// /* seek to track position */ -// if (trackStream[index]) -// { -// /* PCM AUDIO track */ -// cdStreamSeek(trackStream[index], (lba * 2352) - trackOffset[index], SEEK_SET); -// } -} - -void cdd_read_audio(unsigned int samples) -{ - /* previous audio outputs */ - int prev_l = cdd.audio[0]; - int prev_r = cdd.audio[1]; - - /* audio track playing ? */ - if (!scd.regs[0x36>>1].byte.h) - { - int i, mul, l, r; - - /* current CD-DA fader volume */ - int curVol = cdd.fader[0]; - - /* CD-DA fader volume setup (0-1024) */ - int endVol = cdd.fader[1]; - - /* read samples from current block */ - { -#ifdef LSB_FIRST - int16 *ptr = (int16 *) (cdc.ram); -#else - uint8 *ptr = cdc.ram; -#endif - { - char scratch[2352]; - // copy the end of current sector - int nsampreq = samples; - unsigned char *dest = cdc.ram; - cdd_readcallback(sampleLba, scratch, 1); - memcpy(cdc.ram, scratch + sampleOffset * 4, 2352 - sampleOffset * 4); - sampleLba++; - nsampreq -= 588 - sampleOffset; - dest += 2352 - sampleOffset * 4; - sampleOffset = 0; - // fill full sectors - while (nsampreq >= 588) - { - cdd_readcallback(sampleLba, scratch, 1); - memcpy(dest, scratch, 2352); - sampleLba++; - nsampreq -= 588; - dest += 2352; - } - // do last partial sector - if (nsampreq > 0) - { - cdd_readcallback(sampleLba, scratch, 1); - memcpy(dest, scratch, nsampreq * 4); - sampleOffset = nsampreq; - dest += nsampreq * 4; - nsampreq = 0; - } - //printf("samples: %i\n", samples); - //memset(cdc.ram, 0, samples * 4); - //fread(cdc.ram, 1, samples * 4, cdd.toc.tracks[cdd.index].fd); - } - - /* process 16-bit (little-endian) stereo samples */ - for (i=0; i endVol) - { - /* fade-out */ - curVol--; - } - else if (!curVol) - { - /* audio will remain muted until next setup */ - break; - } - } - } - - /* save current CD-DA fader volume */ - cdd.fader[0] = curVol; - - /* save last audio output for next frame */ - cdd.audio[0] = prev_l; - cdd.audio[1] = prev_r; - } - else - { - /* no audio output */ - if (prev_l | prev_r) - { - /* update blip buffer */ - blip_add_delta_fast(snd.blips[2], 0, -prev_l, -prev_r); - - /* save audio output for next frame */ - cdd.audio[0] = 0; - cdd.audio[1] = 0; - } - } - - /* end of blip buffer timeframe */ - blip_end_frame(snd.blips[2], samples); -} - -void cdd_seek_toc(int lba) -{ - tocLba = lba; -// if (tocStream == NULL) return; -// cdStreamSeek(tocStream, cdd.lba * 96, SEEK_SET); -} - -void cdd_read_toc(uint8 *dst, size_t size) -{ - if (size > 2352) { fprintf(stderr, "Excessive size requested (%lu) on cdd_read_toc()\n", size); exit(1); } - uint8_t buffer[2352]; - cdd_readcallback(tocLba, buffer, 0); - memcpy(dst, buffer, size); -// if (tocStream == NULL) return; -// cdStreamRead(dst, 1, size, tocStream); -} \ No newline at end of file diff --git a/waterbox/gpgx/cinterface/cinterface.c b/waterbox/gpgx/cinterface/cinterface.c index f216cc8893..aeb9873d6a 100644 --- a/waterbox/gpgx/cinterface/cinterface.c +++ b/waterbox/gpgx/cinterface/cinterface.c @@ -4,10 +4,6 @@ #include #include "callbacks.h" -#ifdef _MSC_VER -#define snprintf _snprintf -#endif - #include #include #include @@ -35,6 +31,8 @@ char romextension[4]; static int16 soundbuffer[4096]; static int nsamples; +int cinterface_force_sram; + int cinterface_render_bga = 1; int cinterface_render_bgb = 1; int cinterface_render_bgw = 1; @@ -60,7 +58,7 @@ ECL_ENTRY void (*biz_execcb)(unsigned addr); ECL_ENTRY void (*biz_readcb)(unsigned addr); ECL_ENTRY void (*biz_writecb)(unsigned addr); CDCallback biz_cdcb = NULL; -ECL_ENTRY void (*cdd_readcallback)(int lba, void *dest, int audio); +ECL_ENTRY void (*cdd_readcallback)(int lba, void *dest, int subcode); uint8 *tempsram; static void update_viewport(void) @@ -138,7 +136,7 @@ GPGX_EX void gpgx_set_input_callback(ECL_ENTRY void (*fecb)(void)) input_callback_cb = fecb; } -GPGX_EX void gpgx_set_cdd_callback(ECL_ENTRY void (*cddcb)(int lba, void *dest, int audio)) +GPGX_EX void gpgx_set_cdd_callback(ECL_ENTRY void (*cddcb)(int lba, void *dest, int subcode)) { cdd_readcallback = cddcb; } @@ -190,11 +188,27 @@ GPGX_EX void gpgx_advance(void) nsamples = audio_update(soundbuffer); } -GPGX_EX void gpgx_swap_disc(const toc_t* toc) +extern toc_t hotswap_toc; +extern int8 cd_index; + +GPGX_EX void gpgx_swap_disc(const toc_t* toc, int8 index) { if (system_hw == SYSTEM_MCD) { - cdd_hotswap(toc); + if (toc) + { + char header[0x210]; + cd_index = index; + memcpy(&hotswap_toc, toc, sizeof(toc_t)); + cdd_load("HOTSWAP_CD", header); + } + else + { + cd_index = -1; + cdd_unload(); + } + + cdd_reset(); } } @@ -216,7 +230,7 @@ typedef struct } vdpview_t; -extern uint8 ALIGNED_(4) bg_pattern_cache[0x80000]; +extern uint8 bg_pattern_cache[0x80000]; uint32_t pixel[0x100]; GPGX_EX void gpgx_get_vdp_view(vdpview_t *view) @@ -235,10 +249,36 @@ GPGX_EX void gpgx_get_vdp_view(vdpview_t *view) view->ntw.baseaddr = ntwb; } +extern int eeprom_i2c_get_size(void); + // internal: computes sram size (no brams) -int saveramsize(void) +static int saveramsize(void) { - return sram_get_actual_size(); + // the variables in SRAM_T are all part of "configuration", so we don't have to save those. + // the only thing that needs to be saved is the SRAM itself and the SEEPROM struct (if applicable) + + if (!sram.on) + return 0; + switch (sram.custom) + { + case 0: // plain bus access saveram + break; + case 1: // i2c + return eeprom_i2c_get_size(); + case 2: // spi + return sizeof(sram.sram); // it doesn't appear to mask anything internally + case 3: // 93c + return 128; // limited to 128 bytes (note: SMS only) + default: + return sizeof(sram.sram); // ??? + } + // figure size for plain bus access saverams + { + int startaddr = sram.start / 8192; + int endaddr = sram.end / 8192 + 1; + int size = (endaddr - startaddr) * 8192; + return size; + } } GPGX_EX void gpgx_clear_sram(void) @@ -345,17 +385,70 @@ GPGX_EX int gpgx_put_sram(const uint8 *data, int size) GPGX_EX void gpgx_poke_cram(int addr, uint8 val) { - write_cram_byte(addr, val); + uint16 *p; + uint16 data; + int index; + + p = (uint16 *)&cram[addr & 0x7E]; + data = *p; + data = ((data & 0x1C0) << 3) | ((data & 0x038) << 2) | ((data & 0x007) << 1); + + if (addr & 1) + { + data &= 0xFF00; + data |= val; + } + else + { + data &= 0x00FF; + data |= val << 8; + } + + data = ((data & 0xE00) >> 3) | ((data & 0x0E0) >> 2) | ((data & 0x00E) >> 1); + + if (*p != data) + { + index = (addr >> 1) & 0x3F; + *p = data; + + if (index & 0x0F) + { + color_update_m5(index, data); + } + + if (index == border) + { + color_update_m5(0x00, data); + } + } } GPGX_EX void gpgx_poke_vram(int addr, uint8 val) { - write_vram_byte(addr, val); + uint8 *p; + addr &= 0xFFFF; + p = &vram[addr]; + if (*p != val) + { + int name; + *p = val; + // copy of MARK_BG_DIRTY(addr) (to avoid putting this code in vdp_ctrl.c) + name = (addr >> 5) & 0x7FF; + if (bg_name_dirty[name] == 0) + { + bg_name_list[bg_list_index++] = name; + } + bg_name_dirty[name] |= (1 << ((addr >> 2) & 7)); + } } GPGX_EX void gpgx_flush_vram(void) { - flush_vram_cache(); + if (bg_list_index) + { + update_bg_pattern_cache(bg_list_index); + bg_list_index = 0; + } } GPGX_EX const char* gpgx_get_memdom(int which, void **area, int *size) @@ -615,9 +708,9 @@ GPGX_EX int gpgx_init(const char* feromextension, ECL_ENTRY int (*feload_archive_cb)(const char *filename, unsigned char *buffer, int maxsize), struct InitSettings *settings) { - _debug_puts("Initializing GPGX native..."); + fprintf(stderr, "Initializing GPGX native...\n"); - force_sram = settings->ForceSram; + cinterface_force_sram = settings->ForceSram; memset(&bitmap, 0, sizeof(bitmap)); @@ -632,10 +725,6 @@ GPGX_EX int gpgx_init(const char* feromextension, bitmap.data = alloc_plain(2 * 1024 * 1024); tempsram = alloc_plain(24 * 1024); - // cd_hw/cd_cart.h - - ext.cd_hw.cartridge.area = alloc_plain(SCD_CARTRIDGE_AREA_SIZE); - // Initializing ram deepfreeze list #ifdef USE_RAM_DEEPFREEZE deepfreeze_list_size = 0; @@ -749,8 +838,15 @@ GPGX_EX int gpgx_init(const char* feromextension, config.input[i].padtype = settings->SixButton ? DEVICE_PAD6B : DEVICE_PAD3B; } - if (!load_rom("PRIMARY_ROM", "PRIMARY_CD", "SECONDARY_CD")) - return 0; + // first try to load our main CD + if (!load_rom("PRIMARY_CD")) + { + // otherwise, try to load our ROM + if (!load_rom("PRIMARY_ROM")) + { + return 0; + } + } audio_init(44100, 0); system_init(); @@ -827,7 +923,12 @@ GPGX_EX void gpgx_set_sprite_limit_enabled(int enabled) GPGX_EX void gpgx_invalidate_pattern_cache(void) { - vdp_invalidate_full_cache(); + bg_list_index = (reg[1] & 0x04) ? 0x800 : 0x200; + for (int i = 0; i < bg_list_index; i++) + { + bg_name_list[i] = i; + bg_name_dirty[i] = 0xFF; + } } typedef struct diff --git a/waterbox/gpgx/util/cdStream.h b/waterbox/gpgx/util/cdStream.h new file mode 100644 index 0000000000..b07c7ae124 --- /dev/null +++ b/waterbox/gpgx/util/cdStream.h @@ -0,0 +1,17 @@ +#ifndef CD_STREAM_H +#define CD_STREAM_H + +#include +#include + +struct cdStream_t; +typedef struct cdStream_t cdStream; + +extern cdStream *cdStreamOpen(const char *fname); +extern void cdStreamClose(cdStream *stream); +extern size_t cdStreamRead(void *restrict buffer, size_t size, size_t count, cdStream *restrict stream); +extern int cdStreamSeek(cdStream *stream, int64_t offset, int origin); +extern int64_t cdStreamTell(cdStream *stream); +extern char *cdStreamGets(char *restrict str, int count, cdStream *restrict stream); + +#endif diff --git a/waterbox/gpgx/util/osd.h b/waterbox/gpgx/util/osd.h index 9ccdfe8473..d915ea28f8 100644 --- a/waterbox/gpgx/util/osd.h +++ b/waterbox/gpgx/util/osd.h @@ -1,15 +1,12 @@ #pragma once -#ifdef _MSC_VER -#include -typedef unsigned char bool; -#define strncasecmp _strnicmp -#endif - #include #include #include +#include "scrc32.h" +#include "cdStream.h" + #define MAX_INPUTS 8 #define MAX_KEYS 8 #define MAXPATHLEN 1024 @@ -93,7 +90,5 @@ extern char MS_BIOS_US[256]; extern char MS_BIOS_EU[256]; extern char MS_BIOS_JP[256]; -void osd_input_update(void); -int load_archive(const char *filename, unsigned char *buffer, int maxsize, char *extension); -void real_input_callback(void); - +extern void osd_input_update(void); +extern int load_archive(const char *filename, unsigned char *buffer, int maxsize, char *extension);