From 4f36224598ead9da6cb8d5b7467d872953950713 Mon Sep 17 00:00:00 2001 From: FIX94 Date: Tue, 14 Feb 2017 08:15:20 +0100 Subject: [PATCH] -added fds support, make sure to have your fds files in the same folder as the fds bios named disksys.rom to use it -added new keyboard command "B" to switch disk sides in fds titles that need it --- README.md | 2 + cpu.c | 9 +- main.c | 149 +++++++++++++++++++++++- mapper.c | 35 ++++++ mapper.h | 1 + mapper/fds.c | 306 +++++++++++++++++++++++++++++++++++++++++++++++++ mapper_h/fds.h | 20 ++++ mem.c | 2 +- 8 files changed, 520 insertions(+), 4 deletions(-) create mode 100644 mapper/fds.c create mode 100644 mapper_h/fds.h diff --git a/README.md b/README.md index c20a965..ebc6bd9 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,7 @@ NTSC and PAL .nes ROMs are supported right now, it also creates .sav files if th Supported Mappers: 0,1,2,3,4,7,9,10,11,13,15,36,37,38,44,46,47,66,71,79,87,99,101,113,133,140,144,145,146,147,148,149,185,240 and 242. To start a game, simply drag and drop its .nes file into it or call it via command line with the .nes file as argument. If you are starting a PAL NES title then make sure it has (E) in the name to be started in PAL mode. +You can also play FDS titles if you have the FDS BIOS named disksys.rom in the same folder as your .fds files. You can also listen to .nsf files by dragging them in, changing tracks works by pressing left/right. Controls right now are keyboard only and do the following: @@ -16,6 +17,7 @@ S is select Arrow Keys is DPad Keys 1-9 integer-scale the window to number P is Pause +B is Disk Switching (for FDS) O is Enable/Disable vertical Overscan That is all I can say about it right now, who knows if I will write some more on it. \ No newline at end of file diff --git a/cpu.c b/cpu.c index d806238..1053224 100644 --- a/cpu.c +++ b/cpu.c @@ -30,6 +30,8 @@ static bool interrupt; bool dmc_interrupt; bool mmc5_dmc_interrupt; bool apu_interrupt; +bool fds_interrupt; +bool fds_transfer_interrupt; uint32_t cpu_oam_dma; extern bool nesPause; @@ -40,6 +42,8 @@ void cpuInit() dmc_interrupt = false; mmc5_dmc_interrupt = false; apu_interrupt = false; + fds_interrupt = false; + fds_transfer_interrupt = false; cpu_oam_dma = 0; p = (P_FLAG_IRQ_DISABLE | P_FLAG_S1 | P_FLAG_S2); a = 0; @@ -415,6 +419,8 @@ bool cpuCycle() #endif if(interrupt) interrupt = false; + if(fds_transfer_interrupt) + fds_transfer_interrupt = false; waitCycles+=5; } uint16_t instrPtr = pc; @@ -1906,7 +1912,8 @@ bool cpuCycle() } //update interrupt values ppu_nmi_handler_req = ppuNMI(); - cpu_interrupt_req = (interrupt || ((mapper_interrupt || dmc_interrupt || apu_interrupt || mmc5_dmc_interrupt) && !(p & P_FLAG_IRQ_DISABLE))); + cpu_interrupt_req = (interrupt || ((mapper_interrupt || dmc_interrupt || apu_interrupt || + fds_interrupt || fds_transfer_interrupt || mmc5_dmc_interrupt) && !(p & P_FLAG_IRQ_DISABLE))); //if(instrPtr > 0xa980 && instrPtr < 0xa9C0) printf("%d %d %d %04x %04x\n",a,x,y,instrPtr,memGet8(instrPtr)|(memGet8(instrPtr+1)<<8)); return true; } diff --git a/main.c b/main.c index 1e57e0e..6ae906c 100644 --- a/main.c +++ b/main.c @@ -28,11 +28,12 @@ #define DEBUG_KEY 0 #define DEBUG_LOAD_INFO 1 -static const char *VERSION_STRING = "fixNES Alpha v0.5.4"; +static const char *VERSION_STRING = "fixNES Alpha v0.5.5"; static void nesEmuDisplayFrame(void); static void nesEmuMainLoop(void); static void nesEmuDeinit(void); +static void nesEmuFdsSetup(uint8_t *src, uint8_t *dst); static void nesEmuHandleKeyDown(unsigned char key, int x, int y); static void nesEmuHandleKeyUp(unsigned char key, int x, int y); @@ -54,6 +55,7 @@ bool nesEmuNSFPlayback = false; static bool inPause = false; static bool inOverscanToggle = false; static bool inResize = false; +static bool inDiskSwitch = false; #if WINDOWS_BUILD #include @@ -72,6 +74,7 @@ static DWORD emuTotalElapsed = 0; static const int visibleImg = VISIBLE_DOTS*VISIBLE_LINES*4; static int scaleFactor = 2; static bool emuSaveEnabled = false; +static bool emuFdsHasSideB = false; static int emuApuClockCycles; static int emuApuClock; static int mainLoopRuns; @@ -178,6 +181,101 @@ int main(int argc, char** argv) } nesEmuNSFPlayback = true; } + else if(argc >= 2 && (strstr(argv[1],".fds") != NULL || strstr(argv[1],".FDS") != NULL + || strstr(argv[1],".qd") != NULL || strstr(argv[1],".QD") != NULL)) + { + emuSaveName = strdup(argv[1]); + memcpy(emuSaveName+strlen(emuSaveName)-3,"sav",3); + bool saveValid = false; + FILE *save = fopen(emuSaveName, "rb"); + if(save) + { + fseek(save,0,SEEK_END); + size_t saveSize = ftell(save); + if(saveSize == 0x10000 || saveSize == 0x20000) + { + emuNesROM = malloc(saveSize); + rewind(save); + fread(emuNesROM,1,saveSize,save); + saveValid = true; + if(saveSize == 0x20000) + emuFdsHasSideB = true; + } + else + printf("Save file ignored\n"); + fclose(save); + } + if(!saveValid) + { + FILE *nesF = fopen(argv[1],"rb"); + if(!nesF) return EXIT_SUCCESS; + fseek(nesF,0,SEEK_END); + size_t fsize = ftell(nesF); + rewind(nesF); + uint8_t *nesFread = malloc(fsize); + fread(nesFread,1,fsize,nesF); + fclose(nesF); + uint8_t *fds_src; + uint32_t fds_src_len; + if(nesFread[0] == 0x46 && nesFread[1] == 0x44 && nesFread[2] == 0x53) + { + fds_src = nesFread+0x10; + fds_src_len = fsize-0x10; + } + else + { + fds_src = nesFread; + fds_src_len = fsize; + } + bool fds_no_crc = (fds_src[0x38] == 0x02 && fds_src[0x3A] == 0x03 && fds_src[0x3A] != 0x02 && fds_src[0x3E] != 0x03); + if(fds_no_crc) + { + if(fds_src_len == 0x1FFB8) + { + emuFdsHasSideB = true; + emuNesROM = malloc(0x20000); + memset(emuNesROM, 0, 0x20000); + nesEmuFdsSetup(fds_src, emuNesROM); //setup individually + nesEmuFdsSetup(fds_src+0xFFDC, emuNesROM+0x10000); + } + else if(fds_src_len == 0xFFDC) + { + emuNesROM = malloc(0x10000); + memset(emuNesROM, 0, 0x10000); + nesEmuFdsSetup(fds_src, emuNesROM); + } + } + else + { + if(fds_src_len == 0x20000) + { + emuFdsHasSideB = true; + emuNesROM = malloc(0x20000); + memcpy(emuNesROM, fds_src, 0x20000); + } + else if(fds_src_len == 0x10000) + { + emuNesROM = malloc(0x10000); + memcpy(emuNesROM, fds_src, 0x10000); + } + } + free(nesFread); + } + emuPrgRAMsize = 0x8000; + emuPrgRAM = malloc(emuPrgRAMsize); + cpuInit(); + ppuInit(); + memInit(); + apuInit(); + inputInit(); + if(!mapperInitFDS(emuNesROM, emuFdsHasSideB, emuPrgRAM, emuPrgRAMsize)) + { + printf("FDS init failed!\n"); + free(emuNesROM); + emuNesROM = NULL; + return EXIT_SUCCESS; + } + } if(emuNesROM == NULL) return EXIT_SUCCESS; #if WINDOWS_BUILD @@ -236,7 +334,21 @@ static void nesEmuDeinit(void) audioDeinit(); apuDeinit(); if(emuNesROM != NULL) + { + if(fdsEnabled) + { + FILE *save = fopen(emuSaveName, "wb"); + if(save) + { + if(emuFdsHasSideB) + fwrite(emuNesROM,1,0x20000,save); + else + fwrite(emuNesROM,1,0x10000,save); + fclose(save); + } + } free(emuNesROM); + } emuNesROM = NULL; if(emuPrgRAM != NULL) { @@ -344,7 +456,7 @@ void nesEmuResetApuClock(void) { emuApuClock = 0; } - +extern bool fdsSwitch; static void nesEmuHandleKeyDown(unsigned char key, int x, int y) { (void)x; @@ -397,6 +509,14 @@ static void nesEmuHandleKeyDown(unsigned char key, int x, int y) memDumpMainMem(); exit(EXIT_SUCCESS); break; + case 'b': + case 'B': + if(!inDiskSwitch) + { + fdsSwitch = true; + inDiskSwitch = true; + } + break; case 'p': case 'P': if(!inPause) @@ -528,6 +648,10 @@ static void nesEmuHandleKeyUp(unsigned char key, int x, int y) #endif inValReads[BUTTON_START]=0; break; + case 'b': + case 'B': + inDiskSwitch = false; + break; case 'p': case 'P': #if DEBUG_KEY @@ -670,3 +794,24 @@ static void nesEmuDisplayFrame() glutSwapBuffers(); } + +static void nesEmuFdsSetup(uint8_t *src, uint8_t *dst) +{ + memcpy(dst, src, 0x38); + memcpy(dst+0x3A, src+0x38, 2); + uint16_t cDiskPos = 0x3E; + uint16_t cROMPos = 0x3A; + do + { + if(src[cROMPos] != 0x03) + break; + memcpy(dst+cDiskPos, src+cROMPos, 0x10); + uint16_t copySize = (*(uint16_t*)(src+cROMPos+0xD))+1; + cDiskPos+=0x12; + cROMPos+=0x10; + memcpy(dst+cDiskPos, src+cROMPos, copySize); + cDiskPos+=copySize+2; + cROMPos+=copySize; + } while(cROMPos < 0xFFDC && cDiskPos < 0xFFFF); + printf("%04x -> %04x\n", cROMPos, cDiskPos); +} diff --git a/mapper.c b/mapper.c index 73bf44c..1db8b81 100644 --- a/mapper.c +++ b/mapper.c @@ -11,6 +11,7 @@ #include "mapper.h" #include "mapperList.h" #include "mapper_h/nsf.h" +#include "mapper_h/fds.h" get8FuncT mapperGet8; set8FuncT mapperSet8; @@ -45,3 +46,37 @@ bool mapperInitNSF(uint8_t *nsfBIN, uint32_t nsfBINsize, uint8_t *prgRAM, uint32 mapperCycle = nsfcycle; return true; } + +static uint8_t fdsBIOS[0x2000]; +bool mapperInitFDS(uint8_t *fdsFile, bool fdsSideB, uint8_t *prgRAM, uint32_t prgRAMsize) +{ + if(fdsFile == NULL) + { + printf("No FDS loaded!\n"); + return false; + } + FILE *f = fopen("disksys.rom","rb"); + if(f == NULL) + { + printf("disksys.rom not found!\n"); + return false; + } + fseek(f,0,SEEK_END); + size_t fsize = ftell(f); + rewind(f); + if(fsize != 0x2000) + { + printf("disksys.rom has a wrong size, is %i bytes, should be 8192 bytes!\n", fsize); + fclose(f); + return false; + } + fread(fdsBIOS, 1, 0x2000, f); + fclose(f); + fdsinit(fdsBIOS, fsize, fdsFile, fdsSideB, prgRAM, prgRAMsize); + mapperGet8 = fdsget8; + mapperSet8 = fdsset8; + mapperChrGet8 = fdschrGet8; + mapperChrSet8 = fdschrSet8; + mapperCycle = fdscycle; + return true; +} diff --git a/mapper.h b/mapper.h index 7da881f..1685d99 100644 --- a/mapper.h +++ b/mapper.h @@ -18,6 +18,7 @@ typedef void (*cycleFuncT)(); bool mapperInit(uint8_t mapper, uint8_t *prgROM, uint32_t prgROMsize, uint8_t *prgRAM, uint32_t prgRAMsize, uint8_t *chrROM, uint32_t chrROMsize); bool mapperInitNSF(uint8_t *nsfBIN, uint32_t nsfBINsize, uint8_t *prgRAM, uint32_t prgRAMsize); +bool mapperInitFDS(uint8_t *fdsFile, bool fdsSideB, uint8_t *prgRAM, uint32_t prgRAMsize); extern get8FuncT mapperGet8; extern set8FuncT mapperSet8; diff --git a/mapper/fds.c b/mapper/fds.c new file mode 100644 index 0000000..e99cd86 --- /dev/null +++ b/mapper/fds.c @@ -0,0 +1,306 @@ +/* + * Copyright (C) 2017 FIX94 + * + * This software may be modified and distributed under the terms + * of the MIT license. See the LICENSE file for details. + */ + +#include +#include +#include +#include "../ppu.h" +#include "../cpu.h" +#include "../input.h" +#include "../mem.h" +#include "../audio_fds.h" + +bool fdsSwitch; + +static uint8_t *fds_BIOS; +static uint8_t *fds_File; +static uint8_t *fds_prgRAM; +static uint32_t fds_BIOSsize; +static uint32_t fds_FileLoc; +static uint32_t fds_prgRAMsize; +static uint8_t fds_chrRAM[0x2000]; +static bool fds_irq_enable; +static bool fds_transfer_irq_enable; +static bool fds_disk_ready; +static bool fds_transfer_done; +static bool fds_data_read; +static bool fds_cur_data_read; +static bool fds_has_disk_sideB; +static bool fds_disk_sideB; +static bool fds_crc_check; +static bool fds_disk_start; +static bool fds_disk_active; +static uint8_t fds_transfer_val; +static uint8_t fds_switch_delay; +static uint16_t fds_irq_timer; +static uint16_t fds_cur_irq_timer; +static uint16_t fds_transfer_timer; +static uint16_t fds_disk_position; +static uint32_t fds_disk_ready_timer; + +extern bool fds_interrupt; +extern bool fds_transfer_interrupt; + +static void fdsLoadDisk(bool req_side_b) +{ + if(req_side_b) + fds_FileLoc = 0x10000; + else + fds_FileLoc = 0; + fds_disk_sideB = req_side_b; + fds_disk_ready = false; + //give it 1 second to get ready + fds_disk_ready_timer = 1789773; +} + + +void fdsinit(uint8_t *fdsBIOS, uint32_t fdsBIOSsize, uint8_t *fdsFile, bool fdsSideB, uint8_t *prgRAMin, uint32_t prgRAMsizeIn) +{ + fds_BIOS = fdsBIOS; + fds_BIOSsize = fdsBIOSsize; + fds_File = fdsFile; + fds_FileLoc = 0; + fds_has_disk_sideB = fdsSideB; + fdsLoadDisk(false); + fdsSwitch = false; + //give it another 6 seconds to get ready + fds_disk_ready_timer += 10738638; + fds_prgRAM = prgRAMin; + fds_prgRAMsize = prgRAMsizeIn; + fds_irq_enable = false; + fds_transfer_irq_enable = false; + fds_transfer_done = false; + fds_data_read = true; + fds_disk_active = false; + fds_crc_check = false; + fds_disk_start = true; + fds_cur_data_read = false; + fds_transfer_val = 0; + fds_switch_delay = 0; + fds_irq_timer = 0; + fds_cur_irq_timer = 0; + fds_transfer_timer = 0; + fds_disk_position = 0; + fdsAudioInit(); + memset(fds_chrRAM, 0, 0x2000); + printf("FDS Inited\n"); +} + +uint8_t fdsget8(uint16_t addr) +{ + //printf("fdsget8 %04x\n", addr); + if(addr < 0x6000) + { + /* FDS Disk Regs */ + if(addr == 0x4030) + { + uint8_t ret = (fds_interrupt&1) | ((fds_transfer_done&1)<<1) | (((!fds_disk_active)&1)<<6) | 0x80; + fds_transfer_done = false; + fds_interrupt = false; + return ret; + } + else if(addr == 0x4031) + { + //printf("Returning %02x\n", fds_transfer_val); + return fds_transfer_val; + } + else if(addr == 0x4032) + { + return (((!fds_disk_ready)&1) | ((!fds_disk_active)&1)<<1) | 0x40; + } + else if(addr == 0x4033) + return 0x80; + /* FDS Audio Regs */ + if(addr >= 0x4040 && addr <= 0x407F) + return fdsAudioGetWave(addr&0x3F); + else if(addr == 0x4090 || addr == 0x4092) + return fdsAudioGet8(addr&3); + return 0; + } + else //if addr >= 0x6000 + { + if(addr < 0xE000) + return fds_prgRAM[addr-0x6000]; + return fds_BIOS[addr&0x1FFF]; + } +} + +void fdsset8(uint16_t addr, uint8_t val) +{ + //printf("fdsset8 %04x %02x\n", addr, val); + /* FDS Disk Regs */ + if(addr == 0x4020) + fds_irq_timer = ((fds_irq_timer&~0xFF)|val); + else if(addr == 0x4021) + fds_irq_timer = ((fds_irq_timer&0xFF)|(val<<8)); + else if(addr == 0x4022) + { + fds_irq_enable = ((val&2) != 0); + if(fds_irq_enable) + fds_cur_irq_timer = fds_irq_timer; + else + fds_cur_irq_timer = 0; + } + else if(addr == 0x4024) + { + //fds_transfer_interrupt = false; + fds_transfer_done = false; + if(!fds_data_read) + { + //printf("Writing %02x\n", val); + fds_transfer_val = val; + } + else + { + //printf("Writing nothing\n"); + } + } + else if(addr == 0x4025) + { + if(val&2) + { + //printf("Resetting disc position\n"); + fds_disk_position = 0; + fds_disk_start = true; + fds_crc_check = false; + fds_disk_active = false; + fds_transfer_timer = 0; + } + else + { + fds_disk_active = true; + if((val&4) == 0) + { + if(fds_data_read != false) + { + //printf("Write mode\n"); + fds_data_read = false; + fds_switch_delay = 2; + } + } + else + { + if(fds_data_read != true) + { + //printf("Read mode\n"); + fds_data_read = true; + } + } + if(val&0x40) + { + if(fds_transfer_timer == 0) + fds_transfer_timer = 145; + } + else + fds_transfer_timer = 0; + } + if((val&8) == 0) + { + //printf("Vertical mode\n"); + ppuScreenMode = PPU_MODE_VERTICAL; + } + else + { + //printf("Horizontal mode\n"); + ppuScreenMode = PPU_MODE_HORIZONTAL; + } + if(val&0x10 && !fds_data_read) + { + if(fds_crc_check != true) + { + //printf("In CRC Write check\n"); + fds_disk_position+=2; + } + fds_crc_check = true; + } + else + { + if(fds_crc_check != false) + { + //printf("Finished CRC Write check\n"); + fds_transfer_val = fds_File[fds_FileLoc+fds_disk_position]; + } + fds_crc_check = false; + } + if(val&0x80) + fds_transfer_irq_enable = true; + else + { + fds_transfer_irq_enable = false; + //fds_transfer_interrupt = false; + } + } + /* FDS Audio Regs */ + if(addr >= 0x4040 && addr <= 0x407F) + fdsAudioSetWave(addr&0x3F, val); + else if(addr >= 0x4080 && addr <= 0x408A) + fdsAudioSet8(addr&0x1F, val); + /* FDS RAM */ + if(addr >= 0x6000 && addr < 0xE000) + fds_prgRAM[addr-0x6000] = val; +} + +uint8_t fdschrGet8(uint16_t addr) +{ + return fds_chrRAM[addr&0x1FFF]; +} + +void fdschrSet8(uint16_t addr, uint8_t val) +{ + fds_chrRAM[addr&0x1FFF] = val; +} + +void fdscycle() +{ + fdsAudioClockTimers(); + if(fds_cur_irq_timer == 1) + { + if(fds_irq_enable) + fds_interrupt = true; + fds_cur_irq_timer = 0; + } + else if(fds_cur_irq_timer > 1) + fds_cur_irq_timer--; + if(fds_disk_ready_timer == 1) + { + fds_disk_ready = true; + fds_disk_ready_timer = 0; + } + else if(fds_disk_ready_timer > 1) + fds_disk_ready_timer--; + + if(fdsSwitch) + { + if(fds_has_disk_sideB) + fdsLoadDisk(!fds_disk_sideB); + fdsSwitch = false; + } + if(!fds_disk_active || fds_crc_check) + return; + + if(fds_transfer_timer == 1) + { + if(fds_switch_delay == 0) + { + if(!fds_disk_start) + fds_disk_position++; + //printf("Transfer done, giving pos %04x\n", fds_disk_position); + if(fds_data_read) + fds_transfer_val = fds_File[fds_FileLoc+fds_disk_position]; + else + fds_File[fds_FileLoc+fds_disk_position] = fds_transfer_val; + } + else if(fds_switch_delay > 0) + fds_switch_delay--; + fds_transfer_done = true; + fds_transfer_timer = 145; + fds_transfer_interrupt = true; + fds_disk_start = false; + } + else if(fds_transfer_timer > 1) + fds_transfer_timer--; +} diff --git a/mapper_h/fds.h b/mapper_h/fds.h new file mode 100644 index 0000000..acea0c9 --- /dev/null +++ b/mapper_h/fds.h @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2017 FIX94 + * + * This software may be modified and distributed under the terms + * of the MIT license. See the LICENSE file for details. + */ + +#ifndef fds_h_ +#define fds_h_ + +void fdsinit(uint8_t *fdsBIOS, uint32_t fdsBIOSsize, + uint8_t *fdsFile, bool fdsSideB, + uint8_t *prgRAMin, uint32_t prgRAMsizeIn); +uint8_t fdsget8(uint16_t addr); +void fdsset8(uint16_t addr, uint8_t val); +uint8_t fdschrGet8(uint16_t addr); +void fdschrSet8(uint16_t addr, uint8_t val); +void fdscycle(); + +#endif diff --git a/mem.c b/mem.c index cc0ba58..fadd437 100644 --- a/mem.c +++ b/mem.c @@ -28,7 +28,7 @@ uint8_t memGet8(uint16_t addr) { uint8_t val = memLastVal; //printf("memGet8 %04x\n", addr); - if(addr >= 0x4100) + if(addr >= 0x4020) val = mapperGet8(addr); else if(addr >= 0x4000) {