diff --git a/HISTORY.txt b/HISTORY.txt index fc40578..01008bf 100644 --- a/HISTORY.txt +++ b/HISTORY.txt @@ -43,6 +43,7 @@ Genesis Plus GX 1.7.5 (xx/xx/xxxx) (Eke-Eke) --------------- * added support for some new unlicensed games with copy protection (Thunderbolt II, Tom Clown, Chaoji Puke / Super Poker) * added support for Everdrive extended SSF mapper +* added (very basic) emulation of Flashkit MD hardware * improved console region auto-detection for a few PAL-only games (The Smurfs Travel the World & Williams Arcade's Greatest Hits) * improved I2C EEPROM boards emulation accuracy * improved SVP memory handlers accuracy (fixes Virtua Racing debug mode) @@ -105,6 +106,7 @@ Genesis Plus GX 1.7.5 (xx/xx/xxxx) (Eke-Eke) * improved FIFO timings accuracy (fixes "Overdrive" Demo) * improved H-Counter accuracy in H32 mode * improved VDP status timing accuracy +* improved DMA timing accuracy during blanking (verified on real hardware by Mask of Destiny) * improved accuracy of Master System color palette brightness range (verified against real hardware) * fixed misaligned buffer writes in Mode 4 when -DALIGN_LONG option is used * fixed alpha channel for 15-bit (RGB555) and 32-bit (RGB888) color support diff --git a/builds/genesis_plus_gx_libretro.dll b/builds/genesis_plus_gx_libretro.dll index f622bab..842d654 100644 Binary files a/builds/genesis_plus_gx_libretro.dll and b/builds/genesis_plus_gx_libretro.dll differ diff --git a/builds/genplus_cube.dol b/builds/genplus_cube.dol index 3183f28..de8919f 100644 Binary files a/builds/genplus_cube.dol and b/builds/genplus_cube.dol differ diff --git a/builds/genplus_wii.dol b/builds/genplus_wii.dol index 3c9b354..ecacd8f 100644 Binary files a/builds/genplus_wii.dol and b/builds/genplus_wii.dol differ diff --git a/core/cart_hw/md_cart.c b/core/cart_hw/md_cart.c index 8842c10..aac79a1 100644 --- a/core/cart_hw/md_cart.c +++ b/core/cart_hw/md_cart.c @@ -2,7 +2,7 @@ * Genesis Plus * Mega Drive cartridge hardware support * - * Copyright (C) 2007-2016 Eke-Eke (Genesis Plus GX) + * Copyright (C) 2007-2017 Eke-Eke (Genesis Plus GX) * * Many cartridge protections were initially documented by Haze * (http://haze.mameworld.info/) @@ -65,6 +65,8 @@ static void mapper_sf004_w(uint32 address, uint32 data); static uint32 mapper_sf004_r(uint32 address); static void mapper_t5740_w(uint32 address, uint32 data); static uint32 mapper_t5740_r(uint32 address); +static void mapper_flashkit_w(uint32 address, uint32 data); +static uint32 mapper_flashkit_r(uint32 address); static uint32 mapper_smw_64_r(uint32 address); static void mapper_smw_64_w(uint32 address, uint32 data); static void mapper_realtec_w(uint32 address, uint32 data); @@ -628,6 +630,13 @@ void md_cart_init(void) zbank_memory_map[i].write = zbank_unused_w; } } + else if (strstr(rominfo.ROMType,"GM") && strstr(rominfo.product,"00000000-42")) + { + /* Flashkit MD mapper */ + m68k.memory_map[0x00].write8 = mapper_flashkit_w; + m68k.memory_map[0x00].write16 = mapper_flashkit_w; + zbank_memory_map[0x00].write = mapper_flashkit_w; + } else if ((*(uint16 *)(cart.rom + 0x08) == 0x6000) && (*(uint16 *)(cart.rom + 0x0a) == 0x01f6) && (rominfo.realchecksum == 0xf894)) { /* Super Mario World 64 (unlicensed) mapper */ @@ -1267,6 +1276,44 @@ static uint32 mapper_t5740_r(uint32 address) return READ_BYTE(cart.rom, address); } +/* + FlashKit MD mapper (very limited M29W320xx Flash memory support -- enough for unlicensed games using device signature as protection) +*/ +static void mapper_flashkit_w(uint32 address, uint32 data) +{ + /* Increment Bus Write counter */ + cart.hw.regs[0]++; + + /* Wait for 3 consecutive bus writes */ + if (cart.hw.regs[0] == 3) + { + /* assume 'Auto Select' command */ + m68k.memory_map[0x0].read16 = mapper_flashkit_r; + } + else if (cart.hw.regs[0] == 4) + { + /* assume 'Read/Reset' command */ + m68k.memory_map[0x0].read16 = NULL; + + /* reset Bus Write counter */ + cart.hw.regs[0] = 0; + } +} + +static uint32 mapper_flashkit_r(uint32 address) +{ + /* hard-coded device signature */ + switch (address & 0x06) + { + case 0x00: /* Manufacturer Code (STMicroelectronics) */ + return 0x0020; + case 0x02: /* Device Code (M29W320EB) */ + return 0x2257; + default: /* not supported */ + return 0xffff; + } +} + /* Super Mario World 64 (unlicensed) mapper */ diff --git a/core/cart_hw/md_cart.h b/core/cart_hw/md_cart.h index efa0c72..9627868 100644 --- a/core/cart_hw/md_cart.h +++ b/core/cart_hw/md_cart.h @@ -2,7 +2,7 @@ * Genesis Plus * Mega Drive cartridge hardware support * - * Copyright (C) 2007-2016 Eke-Eke (Genesis Plus GX) + * Copyright (C) 2007-2017 Eke-Eke (Genesis Plus GX) * * Most cartridge protections were initially documented by Haze * (http://haze.mameworld.info/) diff --git a/core/cd_hw/cdd.c b/core/cd_hw/cdd.c index d20aa87..6c53b07 100644 --- a/core/cd_hw/cdd.c +++ b/core/cd_hw/cdd.c @@ -2,7 +2,7 @@ * Genesis Plus * CD drive processor & CD-DA fader * - * Copyright (C) 2012-2016 Eke-Eke (Genesis Plus GX) + * Copyright (C) 2012-2017 Eke-Eke (Genesis Plus GX) * * Redistribution and use of this code or any derivative works are permitted * provided that the following conditions are met: @@ -157,6 +157,19 @@ static const char extensions[SUPPORTED_EXT][16] = }; #if defined(USE_LIBTREMOR) || defined(USE_LIBVORBIS) + +static int seek64_wrap(void *f,ogg_int64_t off,int whence){ + return cdStreamSeek(f,off,whence); +} + +static ov_callbacks cb = +{ + (size_t (*)(void *, size_t, size_t, void *)) cdStreamRead, + (int (*)(void *, ogg_int64_t, int)) seek64_wrap, + (int (*)(void *)) cdStreamClose, + (long (*)(void *)) cdStreamTell +}; + #ifdef DISABLE_MANY_OGG_OPEN_FILES static void ogg_free(int i) { @@ -170,9 +183,10 @@ static void ogg_free(int i) cdd.toc.tracks[i].vf.seekable = 1; /* reset file reading position */ - fseek(cdd.toc.tracks[i].fd, 0, SEEK_SET); + cdStreamSeek(cdd.toc.tracks[i].fd, 0, SEEK_SET); } #endif + #endif void cdd_init(int samplerate) @@ -255,21 +269,21 @@ int cdd_context_load(uint8 *state) if (cdd.toc.sub) { /* 96 bytes per sector */ - fseek(cdd.toc.sub, lba * 96, SEEK_SET); + cdStreamSeek(cdd.toc.sub, lba * 96, SEEK_SET); } /* seek to current track position */ if (cdd.toc.tracks[cdd.index].type) { /* DATA track */ - fseek(cdd.toc.tracks[cdd.index].fd, lba * cdd.sectorSize, SEEK_SET); + cdStreamSeek(cdd.toc.tracks[cdd.index].fd, lba * cdd.sectorSize, SEEK_SET); } #if defined(USE_LIBTREMOR) || defined(USE_LIBVORBIS) 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); + ov_open_callbacks(cdd.toc.tracks[cdd.index].fd,&cdd.toc.tracks[cdd.index].vf,0,0,cb); #endif /* VORBIS AUDIO track */ ov_pcm_seek(&cdd.toc.tracks[cdd.index].vf, (lba * 588) - cdd.toc.tracks[cdd.index].offset); @@ -278,7 +292,7 @@ int cdd_context_load(uint8 *state) 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); + cdStreamSeek(cdd.toc.tracks[cdd.index].fd, (lba * 2352) - cdd.toc.tracks[cdd.index].offset, SEEK_SET); } return bufferptr; @@ -289,7 +303,7 @@ int cdd_load(char *filename, char *header) char fname[256+10]; char line[128]; char *ptr, *lptr; - FILE *fd; + cdStream *fd; /* assume CD image file by default */ int isCDfile = 1; @@ -298,7 +312,7 @@ int cdd_load(char *filename, char *header) cdd_unload(); /* open file */ - fd = fopen(filename, "rb"); + fd = cdStreamOpen(filename); if (!fd) return (-1); /* save a copy of base filename */ @@ -310,7 +324,7 @@ int cdd_load(char *filename, char *header) int len; /* read first 16 bytes */ - fread(header, 0x10, 1, fd); + cdStreamRead(header, 0x10, 1, fd); /* look for valid CD image identifier */ if (!memcmp("SEGADISCSYSTEM", header, 14)) @@ -321,7 +335,7 @@ int cdd_load(char *filename, char *header) else { /* read next 16 bytes */ - fread(header, 0x10, 1, fd); + cdStreamRead(header, 0x10, 1, fd); /* look for valid CD image identifier */ if (!memcmp("SEGADISCSYSTEM", header, 14)) @@ -335,7 +349,7 @@ int cdd_load(char *filename, char *header) if (cdd.sectorSize) { /* read CD image header + security code */ - fread(header + 0x10, 0x200, 1, fd); + cdStreamRead(header + 0x10, 0x200, 1, fd); /* initialize first track file descriptor */ cdd.toc.tracks[0].fd = fd; @@ -344,8 +358,8 @@ int cdd_load(char *filename, char *header) cdd.toc.tracks[0].type = TYPE_CDROM; /* DATA track end LBA (based on DATA file length) */ - fseek(fd, 0, SEEK_END); - cdd.toc.tracks[0].end = ftell(fd) / cdd.sectorSize; + cdStreamSeek(fd, 0, SEEK_END); + cdd.toc.tracks[0].end = cdStreamTell(fd) / cdd.sectorSize; /* DATA track length should be at least 2s (BIOS requirement) */ if (cdd.toc.tracks[0].end < 150) @@ -354,7 +368,7 @@ int cdd_load(char *filename, char *header) } /* DATA track start LBA (logical block 0) */ - fseek(fd, 0, SEEK_SET); + cdStreamSeek(fd, 0, SEEK_SET); cdd.toc.tracks[0].start = 0; /* initialize TOC */ @@ -367,14 +381,14 @@ int cdd_load(char *filename, char *header) isCDfile = 0; /* close file */ - fclose(fd); + cdStreamClose(fd); } /* automatically try to mount CD associated CUE file */ len = strlen(fname); while ((len && (fname[len] != '.')) || (len > 251)) len--; strcpy(&fname[len], ".cue"); - fd = fopen(fname, "rb"); + fd = cdStreamOpen(fname); } /* parse CUE file */ @@ -386,7 +400,7 @@ int cdd_load(char *filename, char *header) if (cdd.toc.last) { /* skip first track */ - while (fgets(line, 128, fd)) + while (cdStreamGets(line, 128, fd)) { if (strstr(line, "INDEX 01") && !strstr(line, "INDEX 1")) break; @@ -394,7 +408,7 @@ int cdd_load(char *filename, char *header) } /* read lines until end of file */ - while (fgets(line, 128, fd)) + while (cdStreamGets(line, 128, fd)) { /* skip any SPACE characters */ lptr = line; @@ -431,7 +445,7 @@ int cdd_load(char *filename, char *header) *ptr = 0; /* open current track file descriptor */ - cdd.toc.tracks[cdd.toc.last].fd = fopen(fname, "rb"); + cdd.toc.tracks[cdd.toc.last].fd = cdStreamOpen(fname); if (!cdd.toc.tracks[cdd.toc.last].fd) { /* error opening file */ @@ -449,32 +463,32 @@ int cdd_load(char *filename, char *header) { /* read file header */ unsigned char head[28]; - fseek(cdd.toc.tracks[cdd.toc.last].fd, 8, SEEK_SET); - fread(head, 28, 1, cdd.toc.tracks[cdd.toc.last].fd); - fseek(cdd.toc.tracks[cdd.toc.last].fd, 0, SEEK_SET); + cdStreamSeek(cdd.toc.tracks[cdd.toc.last].fd, 8, SEEK_SET); + cdStreamRead(head, 28, 1, cdd.toc.tracks[cdd.toc.last].fd); + cdStreamSeek(cdd.toc.tracks[cdd.toc.last].fd, 0, SEEK_SET); /* autodetect WAVE file header (44.1KHz 16-bit stereo format only) */ if (!memcmp(head, waveHeader, 28)) { /* look for 'data' chunk id */ int dataOffset = 0; - fseek(cdd.toc.tracks[cdd.toc.last].fd, 36, SEEK_SET); - while (fread(head, 4, 1, cdd.toc.tracks[cdd.toc.last].fd)) + cdStreamSeek(cdd.toc.tracks[cdd.toc.last].fd, 36, SEEK_SET); + while (cdStreamRead(head, 4, 1, cdd.toc.tracks[cdd.toc.last].fd)) { if (!memcmp(head, "data", 4)) { - dataOffset = ftell(cdd.toc.tracks[cdd.toc.last].fd) + 4; - fseek(cdd.toc.tracks[cdd.toc.last].fd, 0, SEEK_SET); + dataOffset = cdStreamTell(cdd.toc.tracks[cdd.toc.last].fd) + 4; + cdStreamSeek(cdd.toc.tracks[cdd.toc.last].fd, 0, SEEK_SET); break; } - fseek(cdd.toc.tracks[cdd.toc.last].fd, -2, SEEK_CUR); + cdStreamSeek(cdd.toc.tracks[cdd.toc.last].fd, -2, SEEK_CUR); } /* check if 'data' chunk has not been found */ if (!dataOffset) { /* invalid WAVE file */ - fclose(cdd.toc.tracks[cdd.toc.last].fd); + cdStreamClose(cdd.toc.tracks[cdd.toc.last].fd); cdd.toc.tracks[cdd.toc.last].fd = 0; break; } @@ -483,7 +497,7 @@ int cdd_load(char *filename, char *header) cdd.toc.tracks[cdd.toc.last].offset -= dataOffset; } #if defined(USE_LIBTREMOR) || defined(USE_LIBVORBIS) - else if (!ov_open(cdd.toc.tracks[cdd.toc.last].fd,&cdd.toc.tracks[cdd.toc.last].vf,0,0)) + else if (!ov_open_callbacks(cdd.toc.tracks[cdd.toc.last].fd,&cdd.toc.tracks[cdd.toc.last].vf,0,0,cb)) { /* retrieve stream infos */ vorbis_info *info = ov_info(&cdd.toc.tracks[cdd.toc.last].vf,-1); @@ -499,7 +513,7 @@ int cdd_load(char *filename, char *header) else { /* unsupported audio file */ - fclose(cdd.toc.tracks[cdd.toc.last].fd); + cdStreamClose(cdd.toc.tracks[cdd.toc.last].fd); cdd.toc.tracks[cdd.toc.last].fd = 0; break; } @@ -515,7 +529,7 @@ int cdd_load(char *filename, char *header) /* close any opened file */ if (cdd.toc.tracks[cdd.toc.last].fd) { - fclose(cdd.toc.tracks[cdd.toc.last].fd); + cdStreamClose(cdd.toc.tracks[cdd.toc.last].fd); cdd.toc.tracks[cdd.toc.last].fd = 0; } @@ -538,7 +552,7 @@ int cdd_load(char *filename, char *header) cdd.sectorSize = 2352; /* skip 16-byte header */ - fseek(cdd.toc.tracks[0].fd, 0x10, SEEK_SET); + cdStreamSeek(cdd.toc.tracks[0].fd, 0x10, SEEK_SET); } if (cdd.sectorSize) @@ -547,8 +561,8 @@ int cdd_load(char *filename, char *header) cdd.toc.tracks[0].type = TYPE_CDROM; /* read CD image header + security code */ - fread(header, 0x210, 1, cdd.toc.tracks[0].fd); - fseek(cdd.toc.tracks[0].fd, 0, SEEK_SET); + cdStreamRead(header, 0x210, 1, cdd.toc.tracks[0].fd); + cdStreamSeek(cdd.toc.tracks[0].fd, 0, SEEK_SET); } } else @@ -638,18 +652,18 @@ int cdd_load(char *filename, char *header) #endif { /* current track end time */ - fseek(cdd.toc.tracks[cdd.toc.last].fd, 0, SEEK_END); + cdStreamSeek(cdd.toc.tracks[cdd.toc.last].fd, 0, SEEK_END); if (cdd.toc.tracks[cdd.toc.last].type) { /* DATA track length */ - cdd.toc.tracks[cdd.toc.last].end = cdd.toc.tracks[cdd.toc.last].start + ((ftell(cdd.toc.tracks[cdd.toc.last].fd) + cdd.sectorSize - 1) / cdd.sectorSize); + cdd.toc.tracks[cdd.toc.last].end = cdd.toc.tracks[cdd.toc.last].start + ((cdStreamTell(cdd.toc.tracks[cdd.toc.last].fd) + cdd.sectorSize - 1) / cdd.sectorSize); } else { /* AUDIO track length */ - cdd.toc.tracks[cdd.toc.last].end = cdd.toc.tracks[cdd.toc.last].start + ((ftell(cdd.toc.tracks[cdd.toc.last].fd) + 2351) / 2352); + cdd.toc.tracks[cdd.toc.last].end = cdd.toc.tracks[cdd.toc.last].start + ((cdStreamTell(cdd.toc.tracks[cdd.toc.last].fd) + 2351) / 2352); } - fseek(cdd.toc.tracks[cdd.toc.last].fd, 0, SEEK_SET); + cdStreamSeek(cdd.toc.tracks[cdd.toc.last].fd, 0, SEEK_SET); } /* adjust track start time (based on current file start time + index absolute time) */ @@ -687,11 +701,11 @@ int cdd_load(char *filename, char *header) #endif if (cdd.toc.tracks[cdd.toc.last].fd) { - fclose(cdd.toc.tracks[cdd.toc.last].fd); + cdStreamClose(cdd.toc.tracks[cdd.toc.last].fd); } /* close CUE file */ - fclose(fd); + cdStreamClose(fd); } else { @@ -705,7 +719,7 @@ int cdd_load(char *filename, char *header) { /* auto-detect wrong initial track index */ sprintf(ptr, extensions[i], cdd.toc.last); - fd = fopen(fname, "rb"); + fd = cdStreamOpen(fname); if (fd) { offset = 0; @@ -713,7 +727,7 @@ int cdd_load(char *filename, char *header) } sprintf(ptr, extensions[i], cdd.toc.last + 1); - fd = fopen(fname, "rb"); + fd = cdStreamOpen(fname); if (fd) break; } @@ -722,31 +736,31 @@ int cdd_load(char *filename, char *header) { /* read file HEADER */ unsigned char head[28]; - fseek(fd, 8, SEEK_SET); - fread(head, 28, 1, fd); - fseek(fd, 0, SEEK_SET); + cdStreamSeek(fd, 8, SEEK_SET); + cdStreamRead(head, 28, 1, fd); + cdStreamSeek(fd, 0, SEEK_SET); /* check if this is a valid WAVE file (44.1KHz 16-bit stereo format only) */ if (!memcmp(head, waveHeader, 28)) { /* look for 'data' chunk id */ int dataOffset = 0; - fseek(fd, 36, SEEK_SET); - while (fread(head, 4, 1, fd)) + cdStreamSeek(fd, 36, SEEK_SET); + while (cdStreamRead(head, 4, 1, fd)) { if (!memcmp(head, "data", 4)) { - dataOffset = ftell(fd) + 4; + dataOffset = cdStreamTell(fd) + 4; break; } - fseek(fd, -2, SEEK_CUR); + cdStreamSeek(fd, -2, SEEK_CUR); } /* check if 'data' chunk has not been found */ if (!dataOffset) { /* invalid WAVE file */ - fclose(fd); + cdStreamClose(fd); break; } @@ -760,16 +774,16 @@ int cdd_load(char *filename, char *header) cdd.toc.tracks[cdd.toc.last].start += 150; /* current track end time */ - fseek(fd, 0, SEEK_END); - cdd.toc.tracks[cdd.toc.last].end = cdd.toc.tracks[cdd.toc.last].start + ((ftell(fd) - dataOffset + 2351) / 2352); + cdStreamSeek(fd, 0, SEEK_END); + cdd.toc.tracks[cdd.toc.last].end = cdd.toc.tracks[cdd.toc.last].start + ((cdStreamTell(fd) - dataOffset + 2351) / 2352); /* initialize file read offset for current track */ cdd.toc.tracks[cdd.toc.last].offset = cdd.toc.tracks[cdd.toc.last].start * 2352; /* auto-detect PAUSE within audio files */ - fseek(fd, 100 * 2352, SEEK_SET); - fread(head, 4, 1, fd); - fseek(fd, 0, SEEK_SET); + cdStreamSeek(fd, 100 * 2352, SEEK_SET); + cdStreamRead(head, 4, 1, fd); + cdStreamSeek(fd, 0, SEEK_SET); if (*(int32 *)head == 0) { /* assume 2s PAUSE is included at the beginning of the file */ @@ -787,7 +801,7 @@ int cdd_load(char *filename, char *header) cdd.toc.last++; } #if defined(USE_LIBTREMOR) || defined(USE_LIBVORBIS) - else if (!ov_open(fd,&cdd.toc.tracks[cdd.toc.last].vf,0,0)) + else if (!ov_open_callbacks(fd,&cdd.toc.tracks[cdd.toc.last].vf,0,0,cb)) { /* retrieve stream infos */ vorbis_info *info = ov_info(&cdd.toc.tracks[cdd.toc.last].vf,-1); @@ -852,7 +866,7 @@ int cdd_load(char *filename, char *header) else { /* unsupported audio file format */ - fclose(fd); + cdStreamClose(fd); break; } @@ -861,7 +875,7 @@ int cdd_load(char *filename, char *header) /* try to open next audio track file */ sprintf(ptr, extensions[i], cdd.toc.last + offset); - fd = fopen(fname, "rb"); + fd = cdStreamOpen(fname); } } @@ -976,7 +990,7 @@ int cdd_load(char *filename, char *header) /* Automatically try to open associated subcode data file */ strncpy(&fname[strlen(fname) - 4], ".sub", 4); - cdd.toc.sub = fopen(fname, "rb"); + cdd.toc.sub = cdStreamOpen(fname); /* return 1 if loaded file is CD image file */ return (isCDfile); @@ -1014,13 +1028,13 @@ void cdd_unload(void) else { /* close file */ - fclose(cdd.toc.tracks[i].fd); + cdStreamClose(cdd.toc.tracks[i].fd); } } } /* close any opened subcode file */ - if (cdd.toc.sub) fclose(cdd.toc.sub); + if (cdd.toc.sub) cdStreamClose(cdd.toc.sub); /* CD unloaded */ cdd.loaded = 0; @@ -1042,16 +1056,16 @@ void cdd_read_data(uint8 *dst) if (cdd.sectorSize == 2048) { /* Mode 1 COOKED data (ISO) */ - fseek(cdd.toc.tracks[0].fd, cdd.lba * 2048, SEEK_SET); + cdStreamSeek(cdd.toc.tracks[0].fd, cdd.lba * 2048, SEEK_SET); } else { /* Mode 1 RAW data (skip 16-byte header) */ - fseek(cdd.toc.tracks[0].fd, cdd.lba * 2352 + 16, SEEK_SET); + cdStreamSeek(cdd.toc.tracks[0].fd, cdd.lba * 2352 + 16, SEEK_SET); } /* read sector data (Mode 1 = 2048 bytes) */ - fread(dst, 2048, 1, cdd.toc.tracks[0].fd); + cdStreamRead(dst, 2048, 1, cdd.toc.tracks[0].fd); } } @@ -1139,7 +1153,7 @@ void cdd_read_audio(unsigned int samples) #else uint8 *ptr = cdc.ram; #endif - fread(cdc.ram, 1, samples * 4, cdd.toc.tracks[cdd.index].fd); + cdStreamRead(cdc.ram, 1, samples * 4, cdd.toc.tracks[cdd.index].fd); /* process 16-bit (little-endian) stereo samples */ for (i=0; i>1].byte.l + 0x100) >> 1; /* read interleaved subcode data from .sub file (12 x 8-bit of P subchannel first, then Q subchannel, etc) */ - fread(subc, 1, 96, cdd.toc.sub); + cdStreamRead(subc, 1, 96, cdd.toc.sub); /* convert back to raw subcode format (96 bytes with 8 x P-W subchannel bits per byte) */ for (i=0; i<96; i+=2) @@ -1345,7 +1359,7 @@ void cdd_update(void) { #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); + ov_open_callbacks(cdd.toc.tracks[cdd.index].fd,&cdd.toc.tracks[cdd.index].vf,0,0,cb); #endif ov_pcm_seek(&cdd.toc.tracks[cdd.index].vf, (cdd.toc.tracks[cdd.index].start * 588) - cdd.toc.tracks[cdd.index].offset); } @@ -1353,7 +1367,7 @@ void cdd_update(void) #endif 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); + cdStreamSeek(cdd.toc.tracks[cdd.index].fd, (cdd.toc.tracks[cdd.index].start * 2352) - cdd.toc.tracks[cdd.index].offset, SEEK_SET); } } } @@ -1431,14 +1445,14 @@ void cdd_update(void) /* seek to current subcode position */ if (cdd.toc.sub) { - fseek(cdd.toc.sub, cdd.lba * 96, SEEK_SET); + cdStreamSeek(cdd.toc.sub, cdd.lba * 96, SEEK_SET); } /* seek to current track position */ if (cdd.toc.tracks[cdd.index].type) { /* DATA track */ - fseek(cdd.toc.tracks[0].fd, cdd.lba * cdd.sectorSize, SEEK_SET); + cdStreamSeek(cdd.toc.tracks[0].fd, cdd.lba * cdd.sectorSize, SEEK_SET); } #if defined(USE_LIBTREMOR) || defined(USE_LIBVORBIS) else if (cdd.toc.tracks[cdd.index].vf.seekable) @@ -1448,7 +1462,7 @@ void cdd_update(void) 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); + ov_open_callbacks(cdd.toc.tracks[cdd.index].fd,&cdd.toc.tracks[cdd.index].vf,0,0,cb); } #endif /* VORBIS AUDIO track */ @@ -1458,7 +1472,7 @@ void cdd_update(void) 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); + cdStreamSeek(cdd.toc.tracks[cdd.index].fd, (cdd.lba * 2352) - cdd.toc.tracks[cdd.index].offset, SEEK_SET); } } } @@ -1641,7 +1655,7 @@ void cdd_process(void) /* 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); + ov_open_callbacks(cdd.toc.tracks[index].fd,&cdd.toc.tracks[index].vf,0,0,cb); } } #endif @@ -1659,14 +1673,14 @@ void cdd_process(void) /* seek to current subcode position */ if (cdd.toc.sub) { - fseek(cdd.toc.sub, lba * 96, SEEK_SET); + cdStreamSeek(cdd.toc.sub, lba * 96, SEEK_SET); } /* seek to current track position */ if (cdd.toc.tracks[index].type) { /* DATA track */ - fseek(cdd.toc.tracks[0].fd, lba * cdd.sectorSize, SEEK_SET); + cdStreamSeek(cdd.toc.tracks[0].fd, lba * cdd.sectorSize, SEEK_SET); } #if defined(USE_LIBTREMOR) || defined(USE_LIBVORBIS) else if (cdd.toc.tracks[index].vf.seekable) @@ -1678,7 +1692,7 @@ void cdd_process(void) 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); + cdStreamSeek(cdd.toc.tracks[index].fd, (lba * 2352) - cdd.toc.tracks[index].offset, SEEK_SET); } /* no audio track playing (yet) */ @@ -1739,7 +1753,7 @@ void cdd_process(void) /* 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); + ov_open_callbacks(cdd.toc.tracks[index].fd,&cdd.toc.tracks[index].vf,0,0,cb); } } #endif @@ -1758,7 +1772,7 @@ void cdd_process(void) if (cdd.toc.tracks[index].type) { /* DATA track */ - fseek(cdd.toc.tracks[0].fd, lba * cdd.sectorSize, SEEK_SET); + cdStreamSeek(cdd.toc.tracks[0].fd, lba * cdd.sectorSize, SEEK_SET); } #if defined(USE_LIBTREMOR) || defined(USE_LIBVORBIS) else if (cdd.toc.tracks[index].vf.seekable) @@ -1770,13 +1784,13 @@ void cdd_process(void) 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); + cdStreamSeek(cdd.toc.tracks[index].fd, (lba * 2352) - cdd.toc.tracks[index].offset, SEEK_SET); } /* seek to current subcode position */ if (cdd.toc.sub) { - fseek(cdd.toc.sub, lba * 96, SEEK_SET); + cdStreamSeek(cdd.toc.sub, lba * 96, SEEK_SET); } /* no audio track playing */ diff --git a/core/cd_hw/cdd.h b/core/cd_hw/cdd.h index 59d998c..bd09677 100644 --- a/core/cd_hw/cdd.h +++ b/core/cd_hw/cdd.h @@ -2,7 +2,7 @@ * Genesis Plus * CD drive processor & CD-DA fader * - * Copyright (C) 2012-2016 Eke-Eke (Genesis Plus GX) + * Copyright (C) 2012-2017 Eke-Eke (Genesis Plus GX) * * Redistribution and use of this code or any derivative works are permitted * provided that the following conditions are met: @@ -64,7 +64,7 @@ /* CD track */ typedef struct { - FILE *fd; + cdStream *fd; #if defined(USE_LIBTREMOR) || defined(USE_LIBVORBIS) OggVorbis_File vf; #endif @@ -80,7 +80,7 @@ typedef struct int end; int last; track_t tracks[CD_MAX_TRACKS]; - FILE *sub; + cdStream *sub; } toc_t; /* CDD hardware */ diff --git a/core/m68k/m68kcpu.h b/core/m68k/m68kcpu.h index b390438..de394b5 100644 --- a/core/m68k/m68kcpu.h +++ b/core/m68k/m68kcpu.h @@ -529,16 +529,6 @@ #define m68k_read_pcrelative_16(address) m68k_read_immediate_16(address) #define m68k_read_pcrelative_32(address) m68k_read_immediate_32(address) -/* Read from the current address space */ -#define m68ki_read_8(A) m68ki_read_8_fc (A, FLAG_S | m68ki_get_address_space()) -#define m68ki_read_16(A) m68ki_read_16_fc(A, FLAG_S | m68ki_get_address_space()) -#define m68ki_read_32(A) m68ki_read_32_fc(A, FLAG_S | m68ki_get_address_space()) - -/* Write to the current data space */ -#define m68ki_write_8(A, V) m68ki_write_8_fc (A, FLAG_S | FUNCTION_CODE_USER_DATA, V) -#define m68ki_write_16(A, V) m68ki_write_16_fc(A, FLAG_S | FUNCTION_CODE_USER_DATA, V) -#define m68ki_write_32(A, V) m68ki_write_32_fc(A, FLAG_S | FUNCTION_CODE_USER_DATA, V) - /* map read immediate 8 to read immediate 16 */ #define m68ki_read_imm_8() MASK_OUT_ABOVE_8(m68ki_read_imm_16()) @@ -547,17 +537,6 @@ #define m68ki_read_pcrel_16(A) m68k_read_pcrelative_16(A) #define m68ki_read_pcrel_32(A) m68k_read_pcrelative_32(A) -/* Read from the program space */ -#define m68ki_read_program_8(A) m68ki_read_8_fc(A, FLAG_S | FUNCTION_CODE_USER_PROGRAM) -#define m68ki_read_program_16(A) m68ki_read_16_fc(A, FLAG_S | FUNCTION_CODE_USER_PROGRAM) -#define m68ki_read_program_32(A) m68ki_read_32_fc(A, FLAG_S | FUNCTION_CODE_USER_PROGRAM) - -/* Read from the data space */ -#define m68ki_read_data_8(A) m68ki_read_8_fc(A, FLAG_S | FUNCTION_CODE_USER_DATA) -#define m68ki_read_data_16(A) m68ki_read_16_fc(A, FLAG_S | FUNCTION_CODE_USER_DATA) -#define m68ki_read_data_32(A) m68ki_read_32_fc(A, FLAG_S | FUNCTION_CODE_USER_DATA) - - /* ======================================================================== */ /* =============================== PROTOTYPES ============================= */ @@ -684,15 +663,15 @@ static const uint16 m68ki_exception_cycle_table[256] = INLINE uint m68ki_read_imm_16(void); INLINE uint m68ki_read_imm_32(void); -/* Read data with specific function code */ -INLINE uint m68ki_read_8_fc (uint address, uint fc); -INLINE uint m68ki_read_16_fc (uint address, uint fc); -INLINE uint m68ki_read_32_fc (uint address, uint fc); +/* Read from the current address space */ +INLINE uint m68ki_read_8(uint address); +INLINE uint m68ki_read_16(uint address); +INLINE uint m68ki_read_32(uint address); -/* Write data with specific function code */ -INLINE void m68ki_write_8_fc (uint address, uint fc, uint value); -INLINE void m68ki_write_16_fc(uint address, uint fc, uint value); -INLINE void m68ki_write_32_fc(uint address, uint fc, uint value); +/* Write to the current data space */ +INLINE void m68ki_write_8(uint address, uint value); +INLINE void m68ki_write_16(uint address, uint value); +INLINE void m68ki_write_32(uint address, uint value); /* Indexed and PC-relative ea fetching */ INLINE uint m68ki_get_ea_pcdi(void); @@ -864,69 +843,69 @@ INLINE uint m68ki_read_imm_32(void) * These functions will also check for address error and set the function * code if they are enabled in m68kconf.h. */ -INLINE uint m68ki_read_8_fc(uint address, uint fc) +INLINE uint m68ki_read_8(uint address) { cpu_memory_map *temp = &m68ki_cpu.memory_map[((address)>>16)&0xff];; - m68ki_set_fc(fc) /* auto-disable (see m68kcpu.h) */ + m68ki_set_fc(FLAG_S | m68ki_get_address_space()) /* auto-disable (see m68kcpu.h) */ if (temp->read8) return (*temp->read8)(ADDRESS_68K(address)); else return READ_BYTE(temp->base, (address) & 0xffff); } -INLINE uint m68ki_read_16_fc(uint address, uint fc) +INLINE uint m68ki_read_16(uint address) { cpu_memory_map *temp; - m68ki_set_fc(fc) /* auto-disable (see m68kcpu.h) */ - m68ki_check_address_error(address, MODE_READ, fc) /* auto-disable (see m68kcpu.h) */ + m68ki_set_fc(FLAG_S | m68ki_get_address_space()) /* auto-disable (see m68kcpu.h) */ + m68ki_check_address_error(address, MODE_READ, FLAG_S | m68ki_get_address_space()) /* auto-disable (see m68kcpu.h) */ temp = &m68ki_cpu.memory_map[((address)>>16)&0xff]; if (temp->read16) return (*temp->read16)(ADDRESS_68K(address)); else return *(uint16 *)(temp->base + ((address) & 0xffff)); } -INLINE uint m68ki_read_32_fc(uint address, uint fc) +INLINE uint m68ki_read_32(uint address) { cpu_memory_map *temp; - m68ki_set_fc(fc) /* auto-disable (see m68kcpu.h) */ - m68ki_check_address_error(address, MODE_READ, fc) /* auto-disable (see m68kcpu.h) */ + m68ki_set_fc(FLAG_S | m68ki_get_address_space()) /* auto-disable (see m68kcpu.h) */ + m68ki_check_address_error(address, MODE_READ, FLAG_S | m68ki_get_address_space()) /* auto-disable (see m68kcpu.h) */ temp = &m68ki_cpu.memory_map[((address)>>16)&0xff]; if (temp->read16) return ((*temp->read16)(ADDRESS_68K(address)) << 16) | ((*temp->read16)(ADDRESS_68K(address + 2))); else return m68k_read_immediate_32(address); } -INLINE void m68ki_write_8_fc(uint address, uint fc, uint value) +INLINE void m68ki_write_8(uint address, uint value) { cpu_memory_map *temp; - m68ki_set_fc(fc) /* auto-disable (see m68kcpu.h) */ + m68ki_set_fc(FLAG_S | FUNCTION_CODE_USER_DATA) /* auto-disable (see m68kcpu.h) */ temp = &m68ki_cpu.memory_map[((address)>>16)&0xff]; if (temp->write8) (*temp->write8)(ADDRESS_68K(address),value); else WRITE_BYTE(temp->base, (address) & 0xffff, value); } -INLINE void m68ki_write_16_fc(uint address, uint fc, uint value) +INLINE void m68ki_write_16(uint address, uint value) { cpu_memory_map *temp; - m68ki_set_fc(fc) /* auto-disable (see m68kcpu.h) */ - m68ki_check_address_error(address, MODE_WRITE, fc); /* auto-disable (see m68kcpu.h) */ + m68ki_set_fc(FLAG_S | FUNCTION_CODE_USER_DATA) /* auto-disable (see m68kcpu.h) */ + m68ki_check_address_error(address, MODE_WRITE, FLAG_S | FUNCTION_CODE_USER_DATA); /* auto-disable (see m68kcpu.h) */ temp = &m68ki_cpu.memory_map[((address)>>16)&0xff]; if (temp->write16) (*temp->write16)(ADDRESS_68K(address),value); else *(uint16 *)(temp->base + ((address) & 0xffff)) = value; } -INLINE void m68ki_write_32_fc(uint address, uint fc, uint value) +INLINE void m68ki_write_32(uint address, uint value) { cpu_memory_map *temp; - m68ki_set_fc(fc) /* auto-disable (see m68kcpu.h) */ - m68ki_check_address_error(address, MODE_WRITE, fc) /* auto-disable (see m68kcpu.h) */ + m68ki_set_fc(FLAG_S | FUNCTION_CODE_USER_DATA) /* auto-disable (see m68kcpu.h) */ + m68ki_check_address_error(address, MODE_WRITE, FLAG_S | FUNCTION_CODE_USER_DATA) /* auto-disable (see m68kcpu.h) */ temp = &m68ki_cpu.memory_map[((address)>>16)&0xff]; if (temp->write16) (*temp->write16)(ADDRESS_68K(address),value>>16); @@ -1070,36 +1049,30 @@ INLINE uint OPER_PCIX_32(void) {uint ea = EA_PCIX_32(); return m68ki_read_pcre /* ---------------------------- Stack Functions --------------------------- */ /* Push/pull data from the stack */ -/* Optimized access assuming stack is always located in ROM/RAM [EkeEke] */ INLINE void m68ki_push_16(uint value) { REG_SP = MASK_OUT_ABOVE_32(REG_SP - 2); - /*m68ki_write_16(REG_SP, value);*/ - *(uint16 *)(m68ki_cpu.memory_map[(REG_SP>>16)&0xff].base + (REG_SP & 0xffff)) = value; + m68ki_write_16(REG_SP, value); } INLINE void m68ki_push_32(uint value) { REG_SP = MASK_OUT_ABOVE_32(REG_SP - 4); - /*m68ki_write_32(REG_SP, value);*/ - *(uint16 *)(m68ki_cpu.memory_map[(REG_SP>>16)&0xff].base + (REG_SP & 0xffff)) = value >> 16; - *(uint16 *)(m68ki_cpu.memory_map[((REG_SP + 2)>>16)&0xff].base + ((REG_SP + 2) & 0xffff)) = value & 0xffff; + m68ki_write_32(REG_SP, value); } INLINE uint m68ki_pull_16(void) { uint sp = REG_SP; REG_SP = MASK_OUT_ABOVE_32(REG_SP + 2); - return m68k_read_immediate_16(sp); - /*return m68ki_read_16(sp);*/ + return m68ki_read_16(sp); } INLINE uint m68ki_pull_32(void) { uint sp = REG_SP; REG_SP = MASK_OUT_ABOVE_32(REG_SP + 4); - return m68k_read_immediate_32(sp); - /*return m68ki_read_32(sp);*/ + return m68ki_read_32(sp); } @@ -1117,7 +1090,8 @@ INLINE void m68ki_jump(uint new_pc) INLINE void m68ki_jump_vector(uint vector) { - REG_PC = m68ki_read_data_32(vector<<2); + m68ki_use_data_space() /* auto-disable (see m68kcpu.h) */ + REG_PC = m68ki_read_32(vector<<2); } @@ -1385,11 +1359,12 @@ INLINE void m68ki_exception_interrupt(uint int_level) m68ki_int_ack(int_level); /* Get the new PC */ - new_pc = m68ki_read_data_32(vector<<2); + m68ki_use_data_space() /* auto-disable (see m68kcpu.h) */ + new_pc = m68ki_read_32(vector<<2); /* If vector is uninitialized, call the uninitialized interrupt vector */ if(new_pc == 0) - new_pc = m68ki_read_data_32((EXCEPTION_UNINITIALIZED_INTERRUPT<<2)); + new_pc = m68ki_read_32((EXCEPTION_UNINITIALIZED_INTERRUPT<<2)); /* Generate a stack frame */ m68ki_stack_frame_3word(REG_PC, sr); diff --git a/core/macros.h b/core/macros.h index 6f8969f..9b4223c 100644 --- a/core/macros.h +++ b/core/macros.h @@ -39,7 +39,7 @@ /* Set to your compiler's static inline keyword to enable it, or * set it to blank to disable it. - * If you define INLINE in the makefile, it will override this value. + * If you define INLINE in makefile or osd.h, it will override this value. * NOTE: not enabling inline functions will SEVERELY slow down emulation. */ #ifndef INLINE @@ -53,4 +53,18 @@ #define ALIGNED_(x) __attribute__ ((aligned(x))) #endif +/* Default CD image file access (read-only) functions */ +/* If you need to override default stdio.h functions with custom filesystem API, + redefine following macros in platform specific include file (osd.h) or Makefile +*/ +#ifndef cdStream +#define cdStream FILE +#define cdStreamOpen(fname) fopen(fname, "rb") +#define cdStreamClose fclose +#define cdStreamRead fread +#define cdStreamSeek fseek +#define cdStreamTell ftell +#define cdStreamGets fgets +#endif + #endif /* _MACROS_H_ */ diff --git a/core/shared.h b/core/shared.h index 959f289..3ab1a33 100644 --- a/core/shared.h +++ b/core/shared.h @@ -7,8 +7,8 @@ #include #include "types.h" -#include "macros.h" #include "osd.h" +#include "macros.h" #include "loadrom.h" #include "m68k.h" #include "z80.h" diff --git a/core/vdp_ctrl.c b/core/vdp_ctrl.c index 2af4265..146e94b 100644 --- a/core/vdp_ctrl.c +++ b/core/vdp_ctrl.c @@ -5,7 +5,7 @@ * Support for SG-1000 (TMS99xx & 315-5066), Master System (315-5124 & 315-5246), Game Gear & Mega Drive VDP * * Copyright (C) 1998-2003 Charles Mac Donald (original code) - * Copyright (C) 2007-2016 Eke-Eke (Genesis Plus GX) + * Copyright (C) 2007-2017 Eke-Eke (Genesis Plus GX) * * Redistribution and use of this code or any derivative works are permitted * provided that the following conditions are met: @@ -161,7 +161,7 @@ static const uint8 dma_timing[2][2] = { /* H32, H40 */ {16 , 18}, /* active display */ - {167, 205} /* blank display */ + {166, 204} /* blank display */ }; /* DMA processing functions (set by VDP register 23 high nibble) */ @@ -560,19 +560,16 @@ void vdp_dma_update(unsigned int cycles) /* DMA transfer rate (bytes per line) - According to the manual, here's a table that describes the transfer - rates of each of the three DMA types: - DMA Mode Width Display Transfer Count ----------------------------------------------------- 68K > VDP 32-cell Active 16 - Blanking 167 - 40-cell Active 18 - Blanking 205 - VRAM Fill 32-cell Active 15 Blanking 166 - 40-cell Active 17 + 40-cell Active 18 Blanking 204 + VRAM Fill 32-cell Active 15 + Blanking 165 + 40-cell Active 17 + Blanking 203 VRAM Copy 32-cell Active 8 Blanking 83 40-cell Active 9 @@ -897,7 +894,10 @@ void vdp_z80_ctrl_w(unsigned int data) { case 2: { - /* DMA Fill will be triggered by next write to DATA port */ + /* DMA Fill */ + dma_type = 2; + + /* DMA is pending until next DATA port write */ dmafill = 1; /* Set DMA Busy flag */ @@ -2039,7 +2039,7 @@ static void vdp_reg_w(unsigned int r, unsigned int d, unsigned int cycles) static void vdp_fifo_update(unsigned int cycles) { - int slots, count = 0; + int num, slots, count = 0; const int *fifo_timing; @@ -2075,13 +2075,13 @@ static void vdp_fifo_update(unsigned int cycles) count++; } - /* number of processed FIFO entries since last access */ - slots = (slots + count - fifo_slots) >> fifo_byte_access; + /* number of processed FIFO entries since last access (byte access needs two slots to process one FIFO word) */ + num = (slots + count - fifo_slots) >> fifo_byte_access; - if (slots > 0) + if (num > 0) { /* process FIFO entries */ - fifo_write_cnt -= slots; + fifo_write_cnt -= num; /* Clear FIFO full flag */ status &= 0xFEFF; @@ -2093,14 +2093,19 @@ static void vdp_fifo_update(unsigned int cycles) /* Set FIFO empty flag */ status |= 0x200; - } - /* Update FIFO access slot counter */ - fifo_slots += (slots << fifo_byte_access); + /* Reinitialize FIFO access slot counter */ + fifo_slots = slots + count; + } + else + { + /* Update FIFO access slot counter */ + fifo_slots += (num << fifo_byte_access); + } } /* next FIFO update cycle */ - fifo_cycles = mcycles_vdp + fifo_timing[count | fifo_byte_access]; + fifo_cycles = mcycles_vdp + fifo_timing[fifo_slots - slots + fifo_byte_access]; } diff --git a/core/vdp_ctrl.h b/core/vdp_ctrl.h index 0920a40..2615381 100644 --- a/core/vdp_ctrl.h +++ b/core/vdp_ctrl.h @@ -5,7 +5,7 @@ * Support for SG-1000 (TMS99xx & 315-5066), Master System (315-5124 & 315-5246), Game Gear & Mega Drive VDP * * Copyright (C) 1998-2003 Charles Mac Donald (original code) - * Copyright (C) 2007-2016 Eke-Eke (Genesis Plus GX) + * Copyright (C) 2007-2017 Eke-Eke (Genesis Plus GX) * * Redistribution and use of this code or any derivative works are permitted * provided that the following conditions are met: