From f2c6ba0c431b8ddaa2ff804e9d266d498c0fe8da Mon Sep 17 00:00:00 2001 From: ShutOstrich <132171977+ShutOstrich@users.noreply.github.com> Date: Sun, 27 Aug 2023 23:45:26 +0200 Subject: [PATCH 1/2] Disable all messages --- src/fceu.cpp | 3 +-- src/video.cpp | 3 ++- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/fceu.cpp b/src/fceu.cpp index b20ad48..49f5c75 100644 --- a/src/fceu.cpp +++ b/src/fceu.cpp @@ -892,8 +892,7 @@ void ResetNES(void) { extern uint8 *XBackBuf; memset(XBackBuf, 0, 256 * 256); - // OpenEmu - //FCEU_DispMessage("Reset", 0); + FCEU_DispMessage("Reset", 0); } diff --git a/src/video.cpp b/src/video.cpp index 7d7744d..ddad754 100644 --- a/src/video.cpp +++ b/src/video.cpp @@ -72,7 +72,8 @@ static u8 *xbsave=NULL; GUIMESSAGE guiMessage; GUIMESSAGE subtitleMessage; -bool vidGuiMsgEna = true; +// OpenEmu +bool vidGuiMsgEna = false; //for input display extern int input_display; From 23bc10038632877eff8f8caacdb402f8e50151de Mon Sep 17 00:00:00 2001 From: ShutOstrich <132171977+ShutOstrich@users.noreply.github.com> Date: Sun, 27 Aug 2023 23:45:32 +0200 Subject: [PATCH 2/2] Update to FCEUX 2.6.6 --- FCEU.xcodeproj/project.pbxproj | 14 ++ Info.plist | 2 +- src/CMakeLists.txt | 33 ++- src/boards/15.cpp | 5 +- src/boards/164.cpp | 11 +- src/boards/177.cpp | 5 +- src/boards/178.cpp | 5 +- src/boards/18.cpp | 5 +- src/boards/246.cpp | 5 +- src/boards/252.cpp | 7 +- src/boards/253.cpp | 7 +- src/boards/354.cpp | 1 + src/boards/68.cpp | 5 +- src/boards/69.cpp | 5 +- src/boards/80.cpp | 3 +- src/boards/82.cpp | 5 +- src/boards/__dummy_mapper.cpp | 3 +- src/boards/addrlatch.cpp | 39 ++- src/boards/bandai.cpp | 14 +- src/boards/cheapocabra.cpp | 3 +- src/boards/coolboy.cpp | 3 +- src/boards/coolgirl.cpp | 161 ++++++------- src/boards/datalatch.cpp | 31 +-- src/boards/edu2000.cpp | 3 +- src/boards/ffe.cpp | 3 +- src/boards/fns.cpp | 5 +- src/boards/mmc1.cpp | 3 +- src/boards/mmc2and4.cpp | 5 +- src/boards/mmc3.cpp | 88 +++++-- src/boards/mmc5.cpp | 13 +- src/boards/n106.cpp | 6 +- src/boards/onebus.cpp | 3 +- src/boards/sa-9602b.cpp | 3 +- src/boards/sb-2000.cpp | 5 +- src/boards/transformer.cpp | 5 +- src/boards/unrom512.cpp | 36 ++- src/boards/vrc2and4.cpp | 3 +- src/boards/vrc5.cpp | 3 +- src/boards/vrc6.cpp | 5 +- src/boards/vrc7.cpp | 5 +- src/cart.cpp | 56 +++-- src/cart.h | 67 +++++- src/conddebug.cpp | 112 ++++----- src/conddebug.h | 21 +- src/debug.cpp | 64 +++-- src/debug.h | 2 +- src/debugsymboltable.cpp | 95 +++++++- src/debugsymboltable.h | 12 +- src/drawing.cpp | 2 +- src/driver.h | 2 + src/emufile.cpp | 8 +- src/emufile.h | 4 +- src/fceu.cpp | 57 ++++- src/fceu.h | 6 +- src/fceulua.h | 3 - src/filter.cpp | 2 +- src/fir/Makefile | 15 ++ src/ines.cpp | 8 +- src/ines.h | 2 + src/ld65dbg.cpp | 419 +++++++++++++++++++++++++++++++++ src/ld65dbg.h | 139 +++++++++++ src/lua-engine.cpp | 49 +--- src/movie.cpp | 19 +- src/ppu.cpp | 15 +- src/profiler.cpp | 367 +++++++++++++++++++++++++++++ src/profiler.h | 167 +++++++++++++ src/state.cpp | 396 ++++++++++++++++++++++++++++++- src/state.h | 54 +++++ src/types.h | 40 +++- src/unif.cpp | 5 +- src/utils/endian.cpp | 15 +- src/utils/endian.h | 8 + src/utils/memory.cpp | 8 +- src/utils/memory.h | 6 +- src/utils/mutex.cpp | 9 + src/utils/mutex.h | 2 + src/utils/timeStamp.cpp | 117 +++++++++ src/utils/timeStamp.h | 384 ++++++++++++++++++++++++++++++ src/version.h | 4 +- src/video.cpp | 35 +++ src/x6502.cpp | 21 +- 81 files changed, 2914 insertions(+), 469 deletions(-) create mode 100644 src/fir/Makefile create mode 100644 src/ld65dbg.cpp create mode 100644 src/ld65dbg.h create mode 100644 src/profiler.cpp create mode 100644 src/profiler.h create mode 100644 src/utils/timeStamp.cpp create mode 100644 src/utils/timeStamp.h diff --git a/FCEU.xcodeproj/project.pbxproj b/FCEU.xcodeproj/project.pbxproj index 1ada4cb..26e6674 100644 --- a/FCEU.xcodeproj/project.pbxproj +++ b/FCEU.xcodeproj/project.pbxproj @@ -72,6 +72,7 @@ 8F28FD5229FD3E7D008FC4A9 /* inx007t.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8F28FD4F29FD3E7D008FC4A9 /* inx007t.cpp */; }; 8F28FD5529FD3EA4008FC4A9 /* debugsymboltable.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8F28FD5329FD3EA4008FC4A9 /* debugsymboltable.cpp */; }; 8F28FD5829FD3EB8008FC4A9 /* mutex.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8F28FD5629FD3EB8008FC4A9 /* mutex.cpp */; }; + 8F5A69CF2A9BF26400B405DB /* ld65dbg.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8F5A69CB2A9BF26400B405DB /* ld65dbg.cpp */; }; 945942D014E4F2DC0015D2AA /* FCEUX.icns in Resources */ = {isa = PBXBuildFile; fileRef = 945942CF14E4F2DC0015D2AA /* FCEUX.icns */; }; 949BBA741A9EF079007B49CC /* 01-222.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 949BB7521A9EED55007B49CC /* 01-222.cpp */; }; 949BBA751A9EF079007B49CC /* 09-034a.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 949BB7531A9EED55007B49CC /* 09-034a.cpp */; }; @@ -346,6 +347,12 @@ 8F28FD5429FD3EA4008FC4A9 /* debugsymboltable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = debugsymboltable.h; sourceTree = ""; }; 8F28FD5629FD3EB8008FC4A9 /* mutex.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = mutex.cpp; sourceTree = ""; }; 8F28FD5729FD3EB8008FC4A9 /* mutex.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mutex.h; sourceTree = ""; }; + 8F5A69C72A9BF26400B405DB /* timeStamp.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = timeStamp.cpp; sourceTree = ""; }; + 8F5A69C82A9BF26400B405DB /* profiler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = profiler.h; sourceTree = ""; }; + 8F5A69C92A9BF26400B405DB /* profiler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = profiler.cpp; sourceTree = ""; }; + 8F5A69CA2A9BF26400B405DB /* timeStamp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = timeStamp.h; sourceTree = ""; }; + 8F5A69CB2A9BF26400B405DB /* ld65dbg.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ld65dbg.cpp; sourceTree = ""; }; + 8F5A69CC2A9BF26400B405DB /* ld65dbg.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ld65dbg.h; sourceTree = ""; }; 945942CE14E4EF180015D2AA /* OENESSystemResponderClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OENESSystemResponderClient.h; path = ../OpenEmu/SystemPlugins/NES/OENESSystemResponderClient.h; sourceTree = ""; }; 945942CF14E4F2DC0015D2AA /* FCEUX.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = FCEUX.icns; sourceTree = ""; }; 949BB74E1A9EED55007B49CC /* asm.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = asm.cpp; sourceTree = ""; }; @@ -816,6 +823,8 @@ 949BB9A11A9EED59007B49CC /* input */, 949BB9B61A9EED59007B49CC /* input.cpp */, 949BB9B71A9EED59007B49CC /* input.h */, + 8F5A69CB2A9BF26400B405DB /* ld65dbg.cpp */, + 8F5A69CC2A9BF26400B405DB /* ld65dbg.h */, 949BB9F71A9EED5A007B49CC /* lua-engine.cpp */, 949BB9F81A9EED5A007B49CC /* movie.cpp */, 949BB9F91A9EED5A007B49CC /* movie.h */, @@ -832,6 +841,8 @@ 949BBA0B1A9EED5A007B49CC /* ppu.cpp */, 949BBA0C1A9EED5A007B49CC /* ppu.h */, 949BBA0D1A9EED5A007B49CC /* pputile.inc */, + 8F5A69C92A9BF26400B405DB /* profiler.cpp */, + 8F5A69C82A9BF26400B405DB /* profiler.h */, 949BBA0F1A9EED5A007B49CC /* sound.cpp */, 949BBA101A9EED5A007B49CC /* sound.h */, 949BBA111A9EED5A007B49CC /* state.cpp */, @@ -1185,6 +1196,8 @@ 949BBA291A9EED5B007B49CC /* memory.h */, 8F28FD5629FD3EB8008FC4A9 /* mutex.cpp */, 8F28FD5729FD3EB8008FC4A9 /* mutex.h */, + 8F5A69C72A9BF26400B405DB /* timeStamp.cpp */, + 8F5A69CA2A9BF26400B405DB /* timeStamp.h */, 949BBA2B1A9EED5B007B49CC /* unzip.cpp */, 949BBA2C1A9EED5B007B49CC /* unzip.h */, 949BBA2D1A9EED5B007B49CC /* valuearray.h */, @@ -1463,6 +1476,7 @@ 949BBAF61A9EF07A007B49CC /* sa-9602b.cpp in Sources */, 870D6EA61D4C1F82001E8FC6 /* BMW8544.cpp in Sources */, 870D6EB41D4C20B3001E8FC6 /* inlnsf.cpp in Sources */, + 8F5A69CF2A9BF26400B405DB /* ld65dbg.cpp in Sources */, 949BBAF71A9EF07A007B49CC /* sachen.cpp in Sources */, 949BBAF81A9EF07A007B49CC /* sc-127.cpp in Sources */, 870D6EB31D4C20B3001E8FC6 /* hp898f.cpp in Sources */, diff --git a/Info.plist b/Info.plist index 8133adf..612961f 100644 --- a/Info.plist +++ b/Info.plist @@ -17,7 +17,7 @@ CFBundleSignature ???? CFBundleVersion - 2.6.5 + 2.6.6 NSPrincipalClass OEGameCoreController OEGameCoreClass diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c14a045..0437eaf 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -22,6 +22,12 @@ if ( ${QHELP} ) add_definitions( -D_USE_QHELP ) endif() +if ( ${FCEU_PROFILER_ENABLE} ) + message( STATUS "FCEU Profiler Enabled") + add_definitions( -D__FCEU_PROFILER_ENABLE__ ) +endif() + + if ( ${QT6} ) find_package( Qt6 REQUIRED COMPONENTS Widgets OpenGL OpenGLWidgets ${QtHelpModule}) add_definitions( ${Qt6Widgets_DEFINITIONS} ${Qt6Help_DEFINITIONS} ${Qt6OpenGLWidgets_DEFINITIONS} ) @@ -41,12 +47,15 @@ if(WIN32) add_definitions( -DMSVC -D_CRT_SECURE_NO_WARNINGS ) add_definitions( -D__SDL__ -D__QT_DRIVER__ -DQT_DEPRECATED_WARNINGS ) add_definitions( -DFCEUDEF_DEBUGGER ) + add_definitions( -D_USE_LIBARCHIVE ) add_definitions( /wd4267 /wd4244 ) #add_definitions( /wd4018 ) # Integer comparison sign mismatch warnings include_directories( ${SDL_INSTALL_PREFIX}/SDL2/include ) + include_directories( ${LIBARCHIVE_INSTALL_PREFIX}/libarchive/include ) include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/drivers/win/zlib ) set( OPENGL_LDFLAGS OpenGL::GL ) set( SDL2_LDFLAGS ${SDL_INSTALL_PREFIX}/SDL2/lib/x64/SDL2.lib ) + set( LIBARCHIVE_LDFLAGS ${LIBARCHIVE_INSTALL_PREFIX}/libarchive/lib/archive.lib ) set( SYS_LIBS wsock32 ws2_32 vfw32 Htmlhelp ) set(APP_ICON_RESOURCES_WINDOWS ${CMAKE_SOURCE_DIR}/icons/fceux.rc ) @@ -93,6 +102,12 @@ else(WIN32) #endif() add_definitions( -D__QT_DRIVER__ -DQT_DEPRECATED_WARNINGS ) + if ( ${GPROF_ENABLE} ) + add_definitions( -pg ) + set( GPROF_LDFLAGS -pg ) + message( STATUS "GNU Profiling Enabled" ) + endif() + if ( ${ASAN_ENABLE} ) add_definitions( -fsanitize=address -fsanitize=bounds-strict ) add_definitions( -fsanitize=undefined -fno-sanitize=vptr ) @@ -110,6 +125,13 @@ else(WIN32) add_definitions( -D_SYSTEM_MINIZIP ${MINIZIP_CFLAGS} ) endif() + pkg_check_modules( LIBARCHIVE libarchive) + + if ( ${LIBARCHIVE_FOUND} ) + message( STATUS "Using System Libarchive Library ${LIBARCHIVE_VERSION}" ) + add_definitions( -D_USE_LIBARCHIVE ${LIBARCHIVE_CFLAGS} ) + endif() + pkg_check_modules( X264 x264) if ( ${X264_FOUND} ) @@ -287,11 +309,13 @@ set(SRC_CORE ${CMAKE_CURRENT_SOURCE_DIR}/filter.cpp ${CMAKE_CURRENT_SOURCE_DIR}/ines.cpp ${CMAKE_CURRENT_SOURCE_DIR}/input.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/ld65dbg.cpp ${CMAKE_CURRENT_SOURCE_DIR}/movie.cpp ${CMAKE_CURRENT_SOURCE_DIR}/netplay.cpp ${CMAKE_CURRENT_SOURCE_DIR}/nsf.cpp ${CMAKE_CURRENT_SOURCE_DIR}/oldmovie.cpp ${CMAKE_CURRENT_SOURCE_DIR}/palette.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/profiler.cpp ${CMAKE_CURRENT_SOURCE_DIR}/ppu.cpp ${CMAKE_CURRENT_SOURCE_DIR}/sound.cpp ${CMAKE_CURRENT_SOURCE_DIR}/state.cpp @@ -503,6 +527,7 @@ set(SRC_CORE ${CMAKE_CURRENT_SOURCE_DIR}/utils/md5.cpp ${CMAKE_CURRENT_SOURCE_DIR}/utils/memory.cpp ${CMAKE_CURRENT_SOURCE_DIR}/utils/mutex.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/utils/timeStamp.cpp ) @@ -525,6 +550,8 @@ set(SRC_DRIVERS_SDL ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/ConsoleWindow.cpp ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/ConsoleViewerGL.cpp ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/ConsoleViewerSDL.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/ConsoleViewerQWidget.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/ConsoleViewerInterface.cpp ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/InputConf.cpp ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/GamePadConf.cpp ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/FamilyKeyboard.cpp @@ -550,6 +577,7 @@ set(SRC_DRIVERS_SDL ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/ConsoleUtilities.cpp ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/ConsoleVideoConf.cpp ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/ConsoleSoundConf.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/StateRecorderConf.cpp ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/iNesHeaderEditor.cpp ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/SplashScreen.cpp ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/TraceLogger.cpp @@ -634,14 +662,15 @@ add_executable( ${APP_NAME} ${SOURCES} ../resources.qrc ${CMAKE_CURRENT_BINARY_DIR}/fceux_git_info.cpp) endif() -target_link_libraries( ${APP_NAME} ${ASAN_LDFLAGS} +target_link_libraries( ${APP_NAME} + ${ASAN_LDFLAGS} ${GPROF_LDFLAGS} ${${Qt}Widgets_LIBRARIES} ${${Qt}Help_LIBRARIES} ${${Qt}OpenGL_LIBRARIES} ${${Qt}OpenGLWidgets_LIBRARIES} ${OPENGL_LDFLAGS} ${SDL2_LDFLAGS} - ${MINIZIP_LDFLAGS} ${ZLIB_LIBRARIES} + ${MINIZIP_LDFLAGS} ${ZLIB_LIBRARIES} ${LIBARCHIVE_LDFLAGS} ${LUA_LDFLAGS} ${X264_LDFLAGS} ${X265_LDFLAGS} ${LIBAV_LDFLAGS} ${SYS_LIBS} ) diff --git a/src/boards/15.cpp b/src/boards/15.cpp index 01f55cd..2558fdc 100644 --- a/src/boards/15.cpp +++ b/src/boards/15.cpp @@ -24,7 +24,7 @@ static uint16 latchea; static uint8 latched; static uint8 *WRAM = NULL; -static uint32 WRAMSIZE; +static uint32 WRAMSIZE=0; static SFORMAT StateRegs[] = { { &latchea, 2, "AREG" }, @@ -108,8 +108,7 @@ void Mapper15_Init(CartInfo *info) { WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE); SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); if (info->battery) { - info->SaveGame[0] = WRAM; - info->SaveGameLen[0] = WRAMSIZE; + info->addSaveGameBuf( WRAM, WRAMSIZE ); } AddExState(WRAM, WRAMSIZE, 0, "WRAM"); AddExState(&StateRegs, ~0, 0, 0); diff --git a/src/boards/164.cpp b/src/boards/164.cpp index 6eb963b..c4344d0 100644 --- a/src/boards/164.cpp +++ b/src/boards/164.cpp @@ -27,7 +27,7 @@ static uint8 laststrobe, trigger; static uint8 reg[8]; static uint8 *WRAM = NULL; -static uint32 WRAMSIZE; +static uint32 WRAMSIZE=0; static writefunc pcmwrite; @@ -123,8 +123,7 @@ void Mapper164_Init(CartInfo *info) { AddExState(WRAM, WRAMSIZE, 0, "WRAM"); if (info->battery) { - info->SaveGame[0] = WRAM; - info->SaveGameLen[0] = WRAMSIZE; + info->addSaveGameBuf( WRAM, WRAMSIZE ); } GameStateRestore = StateRestore; @@ -172,8 +171,7 @@ void Mapper163_Init(CartInfo *info) { AddExState(WRAM, WRAMSIZE, 0, "WRAM"); if (info->battery) { - info->SaveGame[0] = WRAM; - info->SaveGameLen[0] = WRAMSIZE; + info->addSaveGameBuf( WRAM, WRAMSIZE ); } GameStateRestore = StateRestore; AddExState(&StateRegs, ~0, 0, 0); @@ -223,8 +221,7 @@ void UNLFS304_Init(CartInfo *info) { AddExState(WRAM, WRAMSIZE, 0, "WRAM"); if (info->battery) { - info->SaveGame[0] = WRAM; - info->SaveGameLen[0] = WRAMSIZE; + info->addSaveGameBuf( WRAM, WRAMSIZE ); } GameStateRestore = StateRestore; diff --git a/src/boards/177.cpp b/src/boards/177.cpp index 0416060..9525939 100644 --- a/src/boards/177.cpp +++ b/src/boards/177.cpp @@ -23,7 +23,7 @@ static uint8 reg; static uint8 *WRAM = NULL; -static uint32 WRAMSIZE; +static uint32 WRAMSIZE=0; static SFORMAT StateRegs[] = { @@ -73,8 +73,7 @@ void Mapper177_Init(CartInfo *info) { SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); AddExState(WRAM, WRAMSIZE, 0, "WRAM"); if (info->battery) { - info->SaveGame[0] = WRAM; - info->SaveGameLen[0] = WRAMSIZE; + info->addSaveGameBuf( WRAM, WRAMSIZE ); } AddExState(&StateRegs, ~0, 0, 0); diff --git a/src/boards/178.cpp b/src/boards/178.cpp index d577329..5dc7709 100644 --- a/src/boards/178.cpp +++ b/src/boards/178.cpp @@ -27,7 +27,7 @@ static uint8 reg[4]; static uint8 *WRAM = NULL; -static uint32 WRAMSIZE; +static uint32 WRAMSIZE=0; // Tennis with VR sensor, very simple behaviour extern void GetMouseData(uint32 (&md)[3]); @@ -192,8 +192,7 @@ void Mapper178_Init(CartInfo *info) { WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE); SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); if (info->battery) { - info->SaveGame[0] = WRAM; - info->SaveGameLen[0] = WRAMSIZE; + info->addSaveGameBuf( WRAM, WRAMSIZE ); } AddExState(WRAM, WRAMSIZE, 0, "WRAM"); diff --git a/src/boards/18.cpp b/src/boards/18.cpp index a9ac4b6..bbf65f6 100644 --- a/src/boards/18.cpp +++ b/src/boards/18.cpp @@ -24,7 +24,7 @@ static uint8 preg[4], creg[8]; static uint8 IRQa, mirr; static int32 IRQCount, IRQLatch; static uint8 *WRAM = NULL; -static uint32 WRAMSIZE; +static uint32 WRAMSIZE=0; static SFORMAT StateRegs[] = { @@ -125,8 +125,7 @@ void Mapper18_Init(CartInfo *info) { SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); AddExState(WRAM, WRAMSIZE, 0, "WRAM"); if (info->battery) { - info->SaveGame[0] = WRAM; - info->SaveGameLen[0] = WRAMSIZE; + info->addSaveGameBuf( WRAM, WRAMSIZE ); } AddExState(&StateRegs, ~0, 0, 0); diff --git a/src/boards/246.cpp b/src/boards/246.cpp index ec069de..3e00f04 100644 --- a/src/boards/246.cpp +++ b/src/boards/246.cpp @@ -22,7 +22,7 @@ static uint8 regs[8]; static uint8 *WRAM = NULL; -static uint32 WRAMSIZE; +static uint32 WRAMSIZE = 0; static SFORMAT StateRegs[] = { @@ -79,8 +79,7 @@ void Mapper246_Init(CartInfo *info) { AddExState(WRAM, WRAMSIZE, 0, "WRAM"); if (info->battery) { - info->SaveGame[0] = WRAM; - info->SaveGameLen[0] = WRAMSIZE; + info->addSaveGameBuf( WRAM, WRAMSIZE ); } AddExState(&StateRegs, ~0, 0, 0); diff --git a/src/boards/252.cpp b/src/boards/252.cpp index 9962e08..51de2e9 100644 --- a/src/boards/252.cpp +++ b/src/boards/252.cpp @@ -23,9 +23,9 @@ static uint8 creg[8], preg[2]; static int32 IRQa, IRQCount, IRQClock, IRQLatch; static uint8 *WRAM = NULL; -static uint32 WRAMSIZE; +static uint32 WRAMSIZE=0; static uint8 *CHRRAM = NULL; -static uint32 CHRRAMSIZE; +static uint32 CHRRAMSIZE=0; static SFORMAT StateRegs[] = { @@ -127,8 +127,7 @@ void Mapper252_Init(CartInfo *info) { SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); AddExState(WRAM, WRAMSIZE, 0, "WRAM"); if (info->battery) { - info->SaveGame[0] = WRAM; - info->SaveGameLen[0] = WRAMSIZE; + info->addSaveGameBuf( WRAM, WRAMSIZE ); } GameStateRestore = StateRestore; AddExState(&StateRegs, ~0, 0, 0); diff --git a/src/boards/253.cpp b/src/boards/253.cpp index 3ed9bfe..04bbb09 100644 --- a/src/boards/253.cpp +++ b/src/boards/253.cpp @@ -23,9 +23,9 @@ static uint8 chrlo[8], chrhi[8], prg[2], mirr, vlock; static int32 IRQa, IRQCount, IRQLatch, IRQClock; static uint8 *WRAM = NULL; -static uint32 WRAMSIZE; +static uint32 WRAMSIZE=0; static uint8 *CHRRAM = NULL; -static uint32 CHRRAMSIZE; +static uint32 CHRRAMSIZE=0; static SFORMAT StateRegs[] = { @@ -144,8 +144,7 @@ void Mapper253_Init(CartInfo *info) { SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); AddExState(WRAM, WRAMSIZE, 0, "WRAM"); if (info->battery) { - info->SaveGame[0] = WRAM; - info->SaveGameLen[0] = WRAMSIZE; + info->addSaveGameBuf( WRAM, WRAMSIZE ); } AddExState(&StateRegs, ~0, 0, 0); diff --git a/src/boards/354.cpp b/src/boards/354.cpp index a0ef343..10de718 100644 --- a/src/boards/354.cpp +++ b/src/boards/354.cpp @@ -58,6 +58,7 @@ static void Mapper354_Sync(void) setprg32(0x8000, prg >> 1 | 3); break; } + SetupCartCHRMapping(0, CHRptr[0], CHRsize[0], (latchAddr & 8) ? 0 : 1); setchr8(0); setmirror(latchData & 0x40 ? MI_H : MI_V); } diff --git a/src/boards/68.cpp b/src/boards/68.cpp index 710f443..32adeb6 100644 --- a/src/boards/68.cpp +++ b/src/boards/68.cpp @@ -24,7 +24,7 @@ static uint8 chr_reg[4]; static uint8 kogame, prg_reg, nt1, nt2, mirr; static uint8 *WRAM = NULL; -static uint32 WRAMSIZE, count; +static uint32 WRAMSIZE=0, count=0; static SFORMAT StateRegs[] = { @@ -156,8 +156,7 @@ void Mapper68_Init(CartInfo *info) { WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE); SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); if (info->battery) { - info->SaveGame[0] = WRAM; - info->SaveGameLen[0] = WRAMSIZE; + info->addSaveGameBuf( WRAM, WRAMSIZE ); } AddExState(WRAM, WRAMSIZE, 0, "WRAM"); AddExState(&StateRegs, ~0, 0, 0); diff --git a/src/boards/69.cpp b/src/boards/69.cpp index bc25621..9975abf 100644 --- a/src/boards/69.cpp +++ b/src/boards/69.cpp @@ -25,7 +25,7 @@ static uint8 cmdreg, preg[4], creg[8], mirr; static uint8 IRQa; static int32 IRQCount; static uint8 *WRAM = NULL; -static uint32 WRAMSIZE; +static uint32 WRAMSIZE=0; static SFORMAT StateRegs[] = { @@ -266,8 +266,7 @@ void Mapper69_Init(CartInfo *info) { SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); AddExState(WRAM, WRAMSIZE, 0, "WRAM"); if (info->battery) { - info->SaveGame[0] = WRAM; - info->SaveGameLen[0] = WRAMSIZE; + info->addSaveGameBuf( WRAM, WRAMSIZE ); } GameStateRestore = StateRestore; Mapper69_ESI(); diff --git a/src/boards/80.cpp b/src/boards/80.cpp index b99132c..5480aec 100644 --- a/src/boards/80.cpp +++ b/src/boards/80.cpp @@ -169,8 +169,7 @@ void Mapper80_Init(CartInfo *info) { GameStateRestore = StateRestore; if (info->battery) { - info->SaveGame[0] = wram; - info->SaveGameLen[0] = 256; + info->addSaveGameBuf( wram, sizeof(wram) ); } AddExState(&StateRegs80, ~0, 0, 0); diff --git a/src/boards/82.cpp b/src/boards/82.cpp index a1a68b6..01e4f7a 100644 --- a/src/boards/82.cpp +++ b/src/boards/82.cpp @@ -25,7 +25,7 @@ static uint8 regs[9], ctrl; static uint8 *WRAM = NULL; -static uint32 WRAMSIZE; +static uint32 WRAMSIZE=0; static SFORMAT StateRegs[] = { @@ -90,8 +90,7 @@ void Mapper82_Init(CartInfo *info) { SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); AddExState(WRAM, WRAMSIZE, 0, "WRAM"); if (info->battery) { - info->SaveGame[0] = WRAM; - info->SaveGameLen[0] = WRAMSIZE; + info->addSaveGameBuf( WRAM, WRAMSIZE ); } GameStateRestore = StateRestore; AddExState(&StateRegs, ~0, 0, 0); diff --git a/src/boards/__dummy_mapper.cpp b/src/boards/__dummy_mapper.cpp index 505f916..17cdba5 100644 --- a/src/boards/__dummy_mapper.cpp +++ b/src/boards/__dummy_mapper.cpp @@ -92,8 +92,7 @@ void MapperNNN_Init(CartInfo *info) { SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); AddExState(WRAM, WRAMSIZE, 0, "WRAM"); if (info->battery) { - info->SaveGame[0] = WRAM; - info->SaveGameLen[0] = WRAMSIZE; + info->addSaveGameBuf( WRAM, WRAMSIZE ); } */ AddExState(&StateRegs, ~0, 0, 0); diff --git a/src/boards/addrlatch.cpp b/src/boards/addrlatch.cpp index 67ae7d5..500231d 100644 --- a/src/boards/addrlatch.cpp +++ b/src/boards/addrlatch.cpp @@ -26,7 +26,8 @@ static uint8 dipswitch; static void (*WSync)(void); static readfunc defread; static uint8 *WRAM = NULL; -static uint32 WRAMSIZE; +static uint32 WRAMSIZE=0; +static uint8 hasBattery = 0; static DECLFW(LatchWrite) { latche = A; @@ -77,8 +78,7 @@ static void Latch_Init(CartInfo *info, void (*proc)(void), readfunc func, uint16 WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE); SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); if (info->battery) { - info->SaveGame[0] = WRAM; - info->SaveGameLen[0] = WRAMSIZE; + info->addSaveGameBuf( WRAM, WRAMSIZE ); } AddExState(WRAM, WRAMSIZE, 0, "WRAM"); } @@ -221,6 +221,23 @@ void Mapper92_Init(CartInfo *info) { Latch_Init(info, M92Sync, NULL, 0x80B0, 0x8000, 0xFFFF, 0); } +//------------------ Map 174 --------------------------- + +static void M174Sync(void) { + if (latche & 0x80) { + setprg32(0x8000, (latche >> 5) & 3); + } else { + setprg16(0x8000, (latche >> 4) & 7); + setprg16(0xC000, (latche >> 4) & 7); + } + setchr8((latche >> 1) & 7); + setmirror((latche & 1) ^ 1); +} + +void Mapper174_Init(CartInfo *info) { + Latch_Init(info, M174Sync, NULL, 0, 0x8000, 0xFFFF, 0); +} + //------------------ Map 200 --------------------------- static void M200Sync(void) { @@ -342,20 +359,17 @@ void Mapper217_Init(CartInfo *info) { } //------------------ Map 227 --------------------------- - static void M227Sync(void) { uint32 S = latche & 1; uint32 p = ((latche >> 2) & 0x1F) + ((latche & 0x100) >> 3); uint32 L = (latche >> 9) & 1; -// ok, according to nesdev wiki (refrenced to the nesdev dumping thread) there is a CHR write protection bit7. -// however, this bit clearly determined a specific PRG layout for some game but does not meant to have additional -// functionality. as I see from the menu code, it disables the chr writing before run an actual game. -// this fix here makes happy both waixing rpgs and multigame menus at once. can't veryfy it on a hardware -// but if I find some i'll definitly do this. - - if ((latche & 0xF000) == 0xF000) - SetupCartCHRMapping(0, CHRptr[0], 0x2000, 0); +// Only Waixing appear to have battery flag enabled, while multicarts don't. +// Multicarts needs CHR-RAM protect in NROM modes, so only apply CHR-RAM protect +// on non battery-enabled carts. + if (!hasBattery && (latche & 0x80) == 0x80) + /* CHR-RAM write protect hack, needed for some multicarts */ + SetupCartCHRMapping(0, CHRptr[0], 0x2000, 0); else SetupCartCHRMapping(0, CHRptr[0], 0x2000, 1); @@ -393,6 +407,7 @@ static void M227Sync(void) { void Mapper227_Init(CartInfo *info) { Latch_Init(info, M227Sync, NULL, 0x0000, 0x8000, 0xFFFF, 1); + hasBattery = info->battery; } //------------------ Map 229 --------------------------- diff --git a/src/boards/bandai.cpp b/src/boards/bandai.cpp index d6670f5..e908a3a 100644 --- a/src/boards/bandai.cpp +++ b/src/boards/bandai.cpp @@ -29,7 +29,7 @@ static uint8 IRQa; static int16 IRQCount, IRQLatch; static uint8 *WRAM = NULL; -static uint32 WRAMSIZE; +static uint32 WRAMSIZE=0; static SFORMAT StateRegs[] = { @@ -317,8 +317,7 @@ void Mapper16_Init(CartInfo *info) { MapIRQHook = BandaiIRQHook; info->battery = 1; - info->SaveGame[0] = x24c0x_data + 256; - info->SaveGameLen[0] = 256; + info->addSaveGameBuf( x24c0x_data + 256, 256 ); AddExState(x24c0x_data, 256, 0, "DATA"); AddExState(&x24c02StateRegs, ~0, 0, 0); @@ -333,8 +332,7 @@ void Mapper159_Init(CartInfo *info) { MapIRQHook = BandaiIRQHook; info->battery = 1; - info->SaveGame[0] = x24c0x_data; - info->SaveGameLen[0] = 128; + info->addSaveGameBuf( x24c0x_data, 128 ); AddExState(x24c0x_data, 128, 0, "DATA"); AddExState(&x24c01StateRegs, ~0, 0, 0); @@ -378,8 +376,7 @@ void Mapper153_Init(CartInfo *info) { AddExState(WRAM, WRAMSIZE, 0, "WRAM"); if (info->battery) { - info->SaveGame[0] = WRAM; - info->SaveGameLen[0] = WRAMSIZE; + info->addSaveGameBuf( WRAM, WRAMSIZE ); } GameStateRestore = StateRestore; @@ -599,8 +596,7 @@ void Mapper157_Init(CartInfo *info) { GameInfo->cspecial = SIS_DATACH; info->battery = 1; - info->SaveGame[0] = x24c0x_data; - info->SaveGameLen[0] = 512; + info->addSaveGameBuf( x24c0x_data, 512 ); AddExState(x24c0x_data, 512, 0, "DATA"); AddExState(&x24c01StateRegs, ~0, 0, 0); AddExState(&x24c02StateRegs, ~0, 0, 0); diff --git a/src/boards/cheapocabra.cpp b/src/boards/cheapocabra.cpp index 3183781..5548301 100644 --- a/src/boards/cheapocabra.cpp +++ b/src/boards/cheapocabra.cpp @@ -252,8 +252,7 @@ void Mapper111_Init(CartInfo *info) { if (flash) { FLASHROM = (uint8*)FCEU_gmalloc(FLASHROMSIZE); - info->SaveGame[0] = FLASHROM; - info->SaveGameLen[0] = FLASHROMSIZE; + info->addSaveGameBuf( FLASHROM, FLASHROMSIZE ); AddExState(FLASHROM, FLASHROMSIZE, 0, "FROM"); AddExState(&FlashRegs, ~0, 0, 0); diff --git a/src/boards/coolboy.cpp b/src/boards/coolboy.cpp index 48e218b..13a1e61 100644 --- a/src/boards/coolboy.cpp +++ b/src/boards/coolboy.cpp @@ -454,8 +454,7 @@ void CommonInit(CartInfo* info, int submapper) Flash[i] = PRGptr[ROM_CHIP][i % PRGsize[ROM_CHIP]]; } SetupCartPRGMapping(FLASH_CHIP, Flash, PRGsize[ROM_CHIP], 1); - info->SaveGame[1] = Flash; - info->SaveGameLen[1] = PRGsize[ROM_CHIP]; + info->addSaveGameBuf( Flash, PRGsize[ROM_CHIP] ); } AddExState(EXPREGS, 4, 0, "EXPR"); diff --git a/src/boards/coolgirl.cpp b/src/boards/coolgirl.cpp index 95dcf82..3e24994 100644 --- a/src/boards/coolgirl.cpp +++ b/src/boards/coolgirl.cpp @@ -16,11 +16,11 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -* -* Very complicated homebrew multicart mapper with. -* The code is so obscured and weird because it's ported from Verilog CPLD source code: +* +* Very complicated homebrew multicart mapper with. +* The code is so obscured and weird because it's ported from Verilog CPLD source code: * https://github.com/ClusterM/coolgirl-famicom-multicart/blob/master/CoolGirl_mappers.vh -* +* * Range: $5000-$5FFF * * Mask: $5007 @@ -103,14 +103,12 @@ const uint32 FLASH_SECTOR_SIZE = 128 * 1024; const int ROM_CHIP = 0x00; const int WRAM_CHIP = 0x10; const int FLASH_CHIP = 0x11; -const int CHR_RAM_CHIP = 0x12; const int CFI_CHIP = 0x13; +static int CHR_SIZE = 0; static uint32 WRAM_SIZE = 0; -static uint8 *WRAM = NULL; -static uint32 CHR_RAM_SIZE = 0; -static uint8 *CHR_RAM; -static uint8 *SAVE_FLASH = NULL; +static uint8* WRAM = NULL; +static uint8* SAVE_FLASH = NULL; static uint8* CFI; static uint8 sram_enabled = 0; @@ -388,75 +386,75 @@ static void COOLGIRL_Sync_CHR(void) { int chr_shift_left = 0; // enable or disable writes to CHR RAM, setup CHR mask - SetupCartCHRMapping(CHR_RAM_CHIP, CHR_RAM, ((((~(chr_mask >> 13) & 0x3F) + 1) * 0x2000 - 1) & (CHR_RAM_SIZE - 1)) + 1, can_write_chr); + SetupCartCHRMapping(0, UNIFchrrama, ((((~(chr_mask >> 13) & 0x3F) + 1) * 0x2000 - 1) & (CHR_SIZE - 1)) + 1, can_write_chr); switch (chr_mode & 7) { default: case 0: - setchr8r(0x12, chr_bank_a >> 3 >> chr_shift_right << chr_shift_left); + setchr8(chr_bank_a >> 3 >> chr_shift_right << chr_shift_left); break; case 1: - setchr4r(0x12, 0x0000, mapper_163_latch >> chr_shift_right << chr_shift_left); - setchr4r(0x12, 0x1000, mapper_163_latch >> chr_shift_right << chr_shift_left); + setchr4(0x0000, mapper_163_latch >> chr_shift_right << chr_shift_left); + setchr4(0x1000, mapper_163_latch >> chr_shift_right << chr_shift_left); break; case 2: - setchr2r(0x12, 0x0000, chr_bank_a >> 1 >> chr_shift_right << chr_shift_left); + setchr2(0x0000, chr_bank_a >> 1 >> chr_shift_right << chr_shift_left); TKSMIR[0] = TKSMIR[1] = chr_bank_a; - setchr2r(0x12, 0x0800, chr_bank_c >> 1 >> chr_shift_right << chr_shift_left); + setchr2(0x0800, chr_bank_c >> 1 >> chr_shift_right << chr_shift_left); TKSMIR[2] = TKSMIR[3] = chr_bank_c; - setchr1r(0x12, 0x1000, chr_bank_e >> chr_shift_right << chr_shift_left); + setchr1(0x1000, chr_bank_e >> chr_shift_right << chr_shift_left); TKSMIR[4] = chr_bank_e; - setchr1r(0x12, 0x1400, chr_bank_f >> chr_shift_right << chr_shift_left); + setchr1(0x1400, chr_bank_f >> chr_shift_right << chr_shift_left); TKSMIR[5] = chr_bank_f; - setchr1r(0x12, 0x1800, chr_bank_g >> chr_shift_right << chr_shift_left); + setchr1(0x1800, chr_bank_g >> chr_shift_right << chr_shift_left); TKSMIR[6] = chr_bank_g; - setchr1r(0x12, 0x1C00, chr_bank_h >> chr_shift_right << chr_shift_left); + setchr1(0x1C00, chr_bank_h >> chr_shift_right << chr_shift_left); TKSMIR[7] = chr_bank_h; break; case 3: - setchr1r(0x12, 0x0000, chr_bank_e >> chr_shift_right << chr_shift_left); + setchr1(0x0000, chr_bank_e >> chr_shift_right << chr_shift_left); TKSMIR[0] = chr_bank_e; - setchr1r(0x12, 0x0400, chr_bank_f >> chr_shift_right << chr_shift_left); + setchr1(0x0400, chr_bank_f >> chr_shift_right << chr_shift_left); TKSMIR[1] = chr_bank_f; - setchr1r(0x12, 0x0800, chr_bank_g >> chr_shift_right << chr_shift_left); + setchr1(0x0800, chr_bank_g >> chr_shift_right << chr_shift_left); TKSMIR[2] = chr_bank_g; - setchr1r(0x12, 0x0C00, chr_bank_h >> chr_shift_right << chr_shift_left); + setchr1(0x0C00, chr_bank_h >> chr_shift_right << chr_shift_left); TKSMIR[3] = chr_bank_h; - setchr2r(0x12, 0x1000, chr_bank_a >> 1 >> chr_shift_right << chr_shift_left); + setchr2(0x1000, chr_bank_a >> 1 >> chr_shift_right << chr_shift_left); TKSMIR[4] = TKSMIR[5] = chr_bank_a; - setchr2r(0x12, 0x1800, chr_bank_c >> 1 >> chr_shift_right << chr_shift_left); + setchr2(0x1800, chr_bank_c >> 1 >> chr_shift_right << chr_shift_left); TKSMIR[6] = TKSMIR[7] = chr_bank_c; break; case 4: - setchr4r(0x12, 0x0000, chr_bank_a >> 2 >> chr_shift_right << chr_shift_left); - setchr4r(0x12, 0x1000, chr_bank_e >> 2 >> chr_shift_right << chr_shift_left); + setchr4(0x0000, chr_bank_a >> 2 >> chr_shift_right << chr_shift_left); + setchr4(0x1000, chr_bank_e >> 2 >> chr_shift_right << chr_shift_left); break; case 5: if (!ppu_latch0) - setchr4r(0x12, 0x0000, chr_bank_a >> 2 >> chr_shift_right << chr_shift_left); + setchr4(0x0000, chr_bank_a >> 2 >> chr_shift_right << chr_shift_left); else - setchr4r(0x12, 0x0000, chr_bank_b >> 2 >> chr_shift_right << chr_shift_left); + setchr4(0x0000, chr_bank_b >> 2 >> chr_shift_right << chr_shift_left); if (!ppu_latch1) - setchr4r(0x12, 0x1000, chr_bank_e >> 2 >> chr_shift_right << chr_shift_left); + setchr4(0x1000, chr_bank_e >> 2 >> chr_shift_right << chr_shift_left); else - setchr4r(0x12, 0x1000, chr_bank_f >> 2 >> chr_shift_right << chr_shift_left); + setchr4(0x1000, chr_bank_f >> 2 >> chr_shift_right << chr_shift_left); break; case 6: - setchr2r(0x12, 0x0000, chr_bank_a >> 1 >> chr_shift_right << chr_shift_left); - setchr2r(0x12, 0x0800, chr_bank_c >> 1 >> chr_shift_right << chr_shift_left); - setchr2r(0x12, 0x1000, chr_bank_e >> 1 >> chr_shift_right << chr_shift_left); - setchr2r(0x12, 0x1800, chr_bank_g >> 1 >> chr_shift_right << chr_shift_left); + setchr2(0x0000, chr_bank_a >> 1 >> chr_shift_right << chr_shift_left); + setchr2(0x0800, chr_bank_c >> 1 >> chr_shift_right << chr_shift_left); + setchr2(0x1000, chr_bank_e >> 1 >> chr_shift_right << chr_shift_left); + setchr2(0x1800, chr_bank_g >> 1 >> chr_shift_right << chr_shift_left); break; case 7: - setchr1r(0x12, 0x0000, chr_bank_a >> chr_shift_right << chr_shift_left); - setchr1r(0x12, 0x0400, chr_bank_b >> chr_shift_right << chr_shift_left); - setchr1r(0x12, 0x0800, chr_bank_c >> chr_shift_right << chr_shift_left); - setchr1r(0x12, 0x0C00, chr_bank_d >> chr_shift_right << chr_shift_left); - setchr1r(0x12, 0x1000, chr_bank_e >> chr_shift_right << chr_shift_left); - setchr1r(0x12, 0x1400, chr_bank_f >> chr_shift_right << chr_shift_left); - setchr1r(0x12, 0x1800, chr_bank_g >> chr_shift_right << chr_shift_left); - setchr1r(0x12, 0x1C00, chr_bank_h >> chr_shift_right << chr_shift_left); + setchr1(0x0000, chr_bank_a >> chr_shift_right << chr_shift_left); + setchr1(0x0400, chr_bank_b >> chr_shift_right << chr_shift_left); + setchr1(0x0800, chr_bank_c >> chr_shift_right << chr_shift_left); + setchr1(0x0C00, chr_bank_d >> chr_shift_right << chr_shift_left); + setchr1(0x1000, chr_bank_e >> chr_shift_right << chr_shift_left); + setchr1(0x1400, chr_bank_f >> chr_shift_right << chr_shift_left); + setchr1(0x1800, chr_bank_g >> chr_shift_right << chr_shift_left); + setchr1(0x1C00, chr_bank_h >> chr_shift_right << chr_shift_left); break; } } @@ -468,10 +466,10 @@ static void COOLGIRL_Sync_Mirroring(void) { setmirror((mirroring < 2) ? (mirroring ^ 1) : mirroring); } else { // four screen mode - vnapage[0] = CHR_RAM + 0x3F000; - vnapage[1] = CHR_RAM + 0x3F400; - vnapage[2] = CHR_RAM + 0x3F800; - vnapage[3] = CHR_RAM + 0x3FC00; + vnapage[0] = UNIFchrrama + 0x3F000; + vnapage[1] = UNIFchrrama + 0x3F400; + vnapage[2] = UNIFchrrama + 0x3F800; + vnapage[3] = UNIFchrrama + 0x3FC00; } } @@ -509,9 +507,8 @@ static DECLFW(COOLGIRL_Flash_Write) { uint32 sector_address = sector * FLASH_SECTOR_SIZE; for (uint32 i = sector_address; i < sector_address + FLASH_SECTOR_SIZE; i++) SAVE_FLASH[i % SAVE_FLASH_SIZE] = 0xFF; - FCEU_printf("Flash sector #%d is erased: 0x%08x - 0x%08x.\n", sector, sector_address, sector_address + FLASH_SECTOR_SIZE - 1); flash_state = 0; - } + } // write byte if ((flash_state == 4) && @@ -557,7 +554,6 @@ static DECLFW(COOLGIRL_WRITE) { if (A >= 0x5000 && A < 0x6000 && !lockout) { - //FCEU_printf("Write: %02x => %04x\n", V, A); switch (A & 7) { case 0: @@ -573,7 +569,6 @@ static DECLFW(COOLGIRL_WRITE) { // {chr_mask[18], prg_mask[20:14]} = cpu_data_in[7:0]; SET_BITS(chr_mask, "18", V, "7"); SET_BITS(prg_mask, "20:14", V, "6:0"); - //FCEU_printf("REG_prg_mask: %02x\n", REG_prg_mask); break; case 3: // {prg_mode[2:0], chr_bank_a[7:3]} = cpu_data_in[7:0]; @@ -886,7 +881,7 @@ static DECLFW(COOLGIRL_WRITE) { if (mapper == 0b000100) { // prg_bank_a[5:1] = cpu_data_in[4:0]; - SET_BITS(chr_bank_a, "5:1", V, "4:0"); + SET_BITS(prg_bank_a, "5:1", V, "4:0"); // mirroring = { 1'b0, ~cpu_data_in[7]}; mirroring = get_bits(V, "7") ^ 1; } @@ -1176,7 +1171,6 @@ static DECLFW(COOLGIRL_WRITE) { // Mapper #1 - MMC1 /* - r0 - load register flag0 - 16KB of SRAM (SOROM) */ if (mapper == 0b010000) @@ -1230,7 +1224,7 @@ static DECLFW(COOLGIRL_WRITE) { SET_BITS(chr_bank_e, "6:2", mmc1_load_register, "5:1"); break; case 0b11: // 2'b11 - // prg_bank_a[4:1] = r0[4:1]; + // prg_bank_a[4:1] = mmc1_load_register[4:1]; SET_BITS(prg_bank_a, "4:1", mmc1_load_register, "4:1"); // sram_enabled = ~mmc1_load_register[5]; sram_enabled = get_bits(mmc1_load_register, "5") ^ 1; @@ -1397,9 +1391,6 @@ static DECLFW(COOLGIRL_WRITE) { } // Mapper #112 - /* - r0[2:0] - internal register - */ if (mapper == 0b010101) { switch (get_bits(A, "14:13")) @@ -1464,6 +1455,7 @@ static DECLFW(COOLGIRL_WRITE) { case 0b1100: // 4'b1100: if (flags[0]) mirroring = {1'b0, cpu_data_in[6]}; // $E000, mirroring, for mapper #48 if (flags & 1) // 48 mirroring = get_bits(V, "6"); // mirroring = cpu_data_in[6]; + break; case 0b1000: // 4'b1000: irq_scanline_latch = ~cpu_data_in; // $C000, IRQ latch mmc3_irq_latch = set_bits(mmc3_irq_latch, "7:0", get_bits(V, "7:0") ^ 0b11111111); break; @@ -1813,7 +1805,7 @@ static DECLFW(COOLGIRL_WRITE) { SET_BITS(chr_bank_c, "8:1", V, "7:0"); break; // 3'b001: chr_bank_c[8:1] <= cpu_data_in[7:0]; case 0b110: SET_BITS(chr_bank_e, "8:1", V, "7:0"); break; // 3'b110: chr_bank_e[8:1] <= cpu_data_in[7:0]; - case 0b111: + case 0b111: SET_BITS(chr_bank_g, "8:1", V, "7:0"); break; // 3'b111: chr_bank_g[8:1] <= cpu_data_in[7:0]; } } @@ -1963,32 +1955,19 @@ static void COOLGIRL_CpuCounter(int a) { // Mapper #23 - VRC4 if (vrc4_irq_control & 2) // if (ENABLE_MAPPER_021_022_023_025 & ENABLE_VRC4_INTERRUPTS & (vrc4_irq_control[1])) { - // Cycle mode without prescaler is not used by any games? It's missed in fceux source code. - if (vrc4_irq_control & 4) // if (vrc4_irq_control[2]) // cycle mode + vrc4_irq_prescaler++; // vrc4_irq_prescaler = vrc4_irq_prescaler + 1'b1; // count prescaler + // if ((vrc4_irq_prescaler_counter[1] == 0 && vrc4_irq_prescaler == 114) + // || (vrc4_irq_prescaler_counter[1] == 1 && vrc4_irq_prescaler == 113)) // 114, 114, 113 + if ((!(vrc4_irq_prescaler_counter & 2) && vrc4_irq_prescaler == 114) || ((vrc4_irq_prescaler_counter & 2) && vrc4_irq_prescaler == 113)) { - FCEU_PrintError("Cycle IRQ mode is not supported, please report to Cluster"); - vrc4_irq_value++; // {carry, vrc4_irq_value[7:0]} = vrc4_irq_value[7:0] + 1'b1; // just count IRQ value - if (vrc4_irq_value == 0) // if (carry) + vrc4_irq_prescaler = 0; // vrc4_irq_prescaler = 0; + vrc4_irq_prescaler_counter++; // vrc4_irq_prescaler_counter = vrc4_irq_prescaler_counter + 1'b1; + if (vrc4_irq_prescaler_counter == 0b11) vrc4_irq_prescaler_counter = 0; // if (vrc4_irq_prescaler_counter == 2'b11) vrc4_irq_prescaler_counter = 2'b00; + vrc4_irq_value++; // {carry, vrc4_irq_value[7:0]} = vrc4_irq_value[7:0] + 1'b1; + if (vrc4_irq_value == 0) // f (carry) { - X6502_IRQBegin(FCEU_IQEXT); // vrc4_irq_out = 1; - vrc4_irq_value = vrc4_irq_latch; // vrc4_irq_value[7:0] = vrc4_irq_latch[7:0]; - } - } - else { - vrc4_irq_prescaler++; // vrc4_irq_prescaler = vrc4_irq_prescaler + 1'b1; // count prescaler - // if ((vrc4_irq_prescaler_counter[1] == 0 && vrc4_irq_prescaler == 114) - // || (vrc4_irq_prescaler_counter[1] == 1 && vrc4_irq_prescaler == 113)) // 114, 114, 113 - if ((!(vrc4_irq_prescaler_counter & 2) && vrc4_irq_prescaler == 114) || ((vrc4_irq_prescaler_counter & 2) && vrc4_irq_prescaler == 113)) - { - vrc4_irq_prescaler = 0; // vrc4_irq_prescaler = 0; - vrc4_irq_prescaler_counter++; // vrc4_irq_prescaler_counter = vrc4_irq_prescaler_counter + 1'b1; - if (vrc4_irq_prescaler_counter == 0b11) vrc4_irq_prescaler_counter = 0; // if (vrc4_irq_prescaler_counter == 2'b11) vrc4_irq_prescaler_counter = 2'b00; - vrc4_irq_value++; // {carry, vrc4_irq_value[7:0]} = vrc4_irq_value[7:0] + 1'b1; - if (vrc4_irq_value == 0) // f (carry) - { - X6502_IRQBegin(FCEU_IQEXT); - vrc4_irq_value = vrc4_irq_latch; // irq_cpu_value[7:0] = vrc4_irq_latch[7:0]; - } + X6502_IRQBegin(FCEU_IQEXT); + vrc4_irq_value = vrc4_irq_latch; // irq_cpu_value[7:0] = vrc4_irq_latch[7:0]; } } } @@ -2238,15 +2217,13 @@ static void COOLGIRL_Power(void) { } static void COOLGIRL_Close(void) { - if (CHR_RAM) - FCEU_gfree(CHR_RAM); if (WRAM) FCEU_gfree(WRAM); if (SAVE_FLASH) FCEU_gfree(SAVE_FLASH); if (CFI) FCEU_gfree(CFI); - CHR_RAM = WRAM = SAVE_FLASH = CFI = NULL; + WRAM = SAVE_FLASH = CFI = NULL; } static void COOLGIRL_Restore(int version) { @@ -2256,12 +2233,8 @@ static void COOLGIRL_Restore(int version) { #define ExState(var, varname) AddExState(&var, sizeof(var), 0, varname) -void COOLGIRL_Init(CartInfo *info) { - CHR_RAM_SIZE = info->ines2 ? (info->vram_size + info->battery_vram_size) : (512 * 1024); - CHR_RAM = (uint8*)FCEU_gmalloc(CHR_RAM_SIZE); - memset(CHR_RAM, 0, CHR_RAM_SIZE); - SetupCartCHRMapping(CHR_RAM_CHIP, CHR_RAM, CHR_RAM_SIZE, 0); - AddExState(CHR_RAM, sizeof(CHR_RAM_SIZE), 0, "CHR_"); +void COOLGIRL_Init(CartInfo* info) { + CHR_SIZE = info->vram_size ? info->vram_size /* NES 2.0 */ : 256 * 1024 /* UNIF, fixed */; WRAM_SIZE = info->ines2 ? (info->wram_size + info->battery_wram_size) : (32 * 1024); if (WRAM_SIZE > 0) { @@ -2271,8 +2244,7 @@ void COOLGIRL_Init(CartInfo *info) { AddExState(WRAM, 32 * 1024, 0, "SRAM"); if (info->battery) { - info->SaveGame[0] = WRAM; - info->SaveGameLen[0] = 32 * 1024; + info->addSaveGameBuf(WRAM, 32 * 1024); } } @@ -2281,8 +2253,7 @@ void COOLGIRL_Init(CartInfo *info) { SAVE_FLASH = (uint8*)FCEU_gmalloc(SAVE_FLASH_SIZE); SetupCartPRGMapping(FLASH_CHIP, SAVE_FLASH, SAVE_FLASH_SIZE, 1); AddExState(SAVE_FLASH, SAVE_FLASH_SIZE, 0, "SAVF"); - info->SaveGame[1] = SAVE_FLASH; - info->SaveGameLen[1] = SAVE_FLASH_SIZE; + info->addSaveGameBuf(SAVE_FLASH, SAVE_FLASH_SIZE); } CFI = (uint8*)FCEU_gmalloc(sizeof(cfi_data) * 2); diff --git a/src/boards/datalatch.cpp b/src/boards/datalatch.cpp index 69803a9..624b579 100644 --- a/src/boards/datalatch.cpp +++ b/src/boards/datalatch.cpp @@ -21,11 +21,12 @@ #include "mapinc.h" #include "../ines.h" -static uint8 latche, latcheinit, bus_conflict; -static uint16 addrreg0, addrreg1; +static uint8 latche=0, latcheinit=0, bus_conflict=0; +static uint16 addrreg0=0, addrreg1=0; static uint8 *WRAM = NULL; -static uint32 WRAMSIZE; -static void (*WSync)(void); +static uint32 WRAMSIZE=0; +static void (*WSync)(void) = nullptr; +static uint8 submapper; static DECLFW(LatchWrite) { // FCEU_printf("bs %04x %02x\n",A,V); @@ -68,6 +69,7 @@ static void Latch_Init(CartInfo *info, void (*proc)(void), uint8 init, uint16 ad info->Power = LatchPower; info->Close = LatchClose; GameStateRestore = StateRestore; + submapper = info->submapper; if(info->ines2) if(info->battery_wram_size + info->wram_size > 0) wram = 1; @@ -85,14 +87,12 @@ static void Latch_Init(CartInfo *info, void (*proc)(void), uint8 init, uint16 ad //else if(!info->wram_size && info->battery_wram_size) //{ // SetupCartPRGMapping(0x10, WRAM, info->battery_wram_size, 1); - // info->SaveGame[0] = WRAM; - // info->SaveGameLen[0] = info->battery_wram_size; + // info->addSaveGameBuf( WRAM, info->battery_wram_size ); //} else { // //well, this is annoying // SetupCartPRGMapping(0x10, WRAM, info->wram_size, 1); // SetupCartPRGMapping(0x11, WRAM, info->battery_wram_size, 1); //? ? ? there probably isnt even a way to select this - // info->SaveGame[0] = WRAM + info->wram_size; - // info->SaveGameLen[0] = info->battery_wram_size; + // info->addSaveGameBuf( WRAM + info->wram_size, info->battery_wram_size ); //} //this is more likely the only practical scenario @@ -104,8 +104,7 @@ static void Latch_Init(CartInfo *info, void (*proc)(void), uint8 init, uint16 ad setprg8r(0x10, 0x6000, 0); if(info->battery_wram_size) { - info->SaveGame[0] = WRAM; - info->SaveGameLen[0] = 8192; + info->addSaveGameBuf( WRAM, 8192 ); } } else @@ -114,8 +113,7 @@ static void Latch_Init(CartInfo *info, void (*proc)(void), uint8 init, uint16 ad WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE); SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); if (info->battery) { - info->SaveGame[0] = WRAM; - info->SaveGameLen[0] = WRAMSIZE; + info->addSaveGameBuf( WRAM, WRAMSIZE ); } AddExState(WRAM, WRAMSIZE, 0, "WRAM"); } @@ -158,8 +156,7 @@ void NROM_Init(CartInfo *info) { WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE); SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); if (info->battery) { - info->SaveGame[0] = WRAM; - info->SaveGameLen[0] = WRAMSIZE; + info->addSaveGameBuf( WRAM, WRAMSIZE ); } AddExState(WRAM, WRAMSIZE, 0, "WRAM"); } @@ -300,7 +297,11 @@ static void M78Sync() { setprg16(0x8000, (latche & 7)); setprg16(0xc000, ~0); setchr8(latche >> 4); - setmirror(MI_0 + ((latche >> 3) & 1)); + if (submapper == 3) { + setmirror((latche >> 3) & 1); + } else { + setmirror(MI_0 + ((latche >> 3) & 1)); + } } void Mapper78_Init(CartInfo *info) { diff --git a/src/boards/edu2000.cpp b/src/boards/edu2000.cpp index 36f1ad1..7c1270e 100644 --- a/src/boards/edu2000.cpp +++ b/src/boards/edu2000.cpp @@ -70,8 +70,7 @@ void UNLEDU2000_Init(CartInfo *info) { WRAM = (uint8*)FCEU_gmalloc(32768); SetupCartPRGMapping(0x10, WRAM, 32768, 1); if (info->battery) { - info->SaveGame[0] = WRAM; - info->SaveGameLen[0] = 32768; + info->addSaveGameBuf( WRAM, 32768 ); } AddExState(WRAM, 32768, 0, "WRAM"); AddExState(StateRegs, ~0, 0, 0); diff --git a/src/boards/ffe.cpp b/src/boards/ffe.cpp index 51e591e..674f0d2 100644 --- a/src/boards/ffe.cpp +++ b/src/boards/ffe.cpp @@ -141,8 +141,7 @@ void Mapper6_Init(CartInfo *info) { SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); AddExState(WRAM, WRAMSIZE, 0, "WRAM"); if (info->battery) { - info->SaveGame[0] = WRAM; - info->SaveGameLen[0] = WRAMSIZE; + info->addSaveGameBuf( WRAM, WRAMSIZE ); } AddExState(&StateRegs, ~0, 0, 0); diff --git a/src/boards/fns.cpp b/src/boards/fns.cpp index 5bb4a4e..8b5c75e 100644 --- a/src/boards/fns.cpp +++ b/src/boards/fns.cpp @@ -28,7 +28,7 @@ static uint8 DRegs[4]; static uint8 Buffer, BufferShift; -static uint32 WRAMSIZE; +static uint32 WRAMSIZE=0; static uint8 *WRAM = NULL; static int kanji_pos, kanji_page, r40C0; @@ -256,8 +256,7 @@ void FNS_Init(CartInfo *info) { SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); AddExState(WRAM, WRAMSIZE, 0, "WRAM"); - info->SaveGame[0] = WRAM; - info->SaveGameLen[0] = WRAMSIZE; + info->addSaveGameBuf( WRAM, WRAMSIZE ); AddExState(DRegs, 4, 0, "DREG"); AddExState(&lreset, 8, 1, "LRST"); diff --git a/src/boards/mmc1.cpp b/src/boards/mmc1.cpp index bfe07a7..2265aa7 100644 --- a/src/boards/mmc1.cpp +++ b/src/boards/mmc1.cpp @@ -306,8 +306,7 @@ static void GenMMC1Init(CartInfo *info, int prg, int chr, int wram, int bram) { SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); AddExState(WRAM, WRAMSIZE, 0, "WRAM"); if (bram) { - info->SaveGame[0] = WRAM + NONBRAMSIZE; - info->SaveGameLen[0] = bram * 1024; + info->addSaveGameBuf( WRAM + NONBRAMSIZE, bram * 1024 ); } } if (!chr) { diff --git a/src/boards/mmc2and4.cpp b/src/boards/mmc2and4.cpp index 5d9d73d..3bde6f7 100644 --- a/src/boards/mmc2and4.cpp +++ b/src/boards/mmc2and4.cpp @@ -25,7 +25,7 @@ static uint8 is10; static uint8 creg[4], latch0, latch1, preg, mirr; static uint8 *WRAM = NULL; -static uint32 WRAMSIZE; +static uint32 WRAMSIZE=0; static SFORMAT StateRegs[] = { @@ -130,8 +130,7 @@ void Mapper10_Init(CartInfo *info) { SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); AddExState(WRAM, WRAMSIZE, 0, "WRAM"); if (info->battery) { - info->SaveGame[0] = WRAM; - info->SaveGameLen[0] = WRAMSIZE; + info->addSaveGameBuf( WRAM, WRAMSIZE ); } GameStateRestore = StateRestore; AddExState(&StateRegs, ~0, 0, 0); diff --git a/src/boards/mmc3.cpp b/src/boards/mmc3.cpp index 635d61e..e7e229c 100644 --- a/src/boards/mmc3.cpp +++ b/src/boards/mmc3.cpp @@ -324,8 +324,7 @@ void GenMMC3_Init(CartInfo *info, int prg, int chr, int wram, int battery) { if (battery) { mmc3opts |= 2; - info->SaveGame[0] = WRAM; - info->SaveGameLen[0] = WRAMSIZE; + info->addSaveGameBuf( WRAM, WRAMSIZE ); } // KT-008 boards hack 2-in-1, TODO assign to new ines mapper, most dump of KT-boards on the net are mapper 4, so need database or goodnes fix support @@ -1137,20 +1136,73 @@ void Mapper198_Init(CartInfo *info) { info->Power = M195Power; } -// ---------------------------- Mapper 205 ------------------------------ -// GN-45 BOARD +/* ---------------------------- Mapper 205 ------------------------------ */ +/* UNIF boardname BMC-JC-016-2 +https://wiki.nesdev.com/w/index.php/INES_Mapper_205 */ + +/* 2023-02 : Update reg write logic and add solder pad */ static void M205PW(uint32 A, uint8 V) { -// GN-30A - начальная маска должна быть 1F + аппаратный переключатель на шине адреса - setprg8(A, (V & 0x0f) | EXPREGS[0]); + uint8 bank = V & ((EXPREGS[0] & 0x02) ? 0x0F : 0x1F); + if (PRGsize[1]) { // split-rom variant + setprg8r((EXPREGS[0] & 3) ? (EXPREGS[0] - 1) : 0, A, bank); + } else { + setprg8(A, EXPREGS[0] << 4 | bank); + } } static void M205CW(uint32 A, uint8 V) { -// GN-30A - начальная маска должна быть FF + uint8 bank = V & ((EXPREGS[0] & 0x02) ? 0x7F : 0xFF); + if (CHRsize[1]) { // split-rom variant + setchr1r((EXPREGS[0] & 3) ? (EXPREGS[0] - 1) : 0, A, bank); + } else { + setchr1(A, (EXPREGS[0] << 7) | bank); + } +} + +static DECLFW(M205Write) { + EXPREGS[0] = V & 3; + if (V & 1) { + EXPREGS[0] |= EXPREGS[1]; + } + CartBW(A, V); + FixMMC3PRG(MMC3_cmd); + FixMMC3CHR(MMC3_cmd); +} + +static void M205Reset(void) { + EXPREGS[0] = 0; + EXPREGS[1] ^= 2; /* solder pad */ + MMC3RegReset(); +} + +static void M205Power(void) { + EXPREGS[0] = EXPREGS[1] = 0; + GenMMC3Power(); + SetWriteHandler(0x6000, 0x7FFF, M205Write); +} + +void Mapper205_Init(CartInfo *info) { + GenMMC3_Init(info, 256, 128, 0, 0); + pwrap = M205PW; + cwrap = M205CW; + info->Power = M205Power; + info->Reset = M205Reset; + AddExState(EXPREGS, 2, 0, "EXPR"); +} + +/* --------------------------- GN-45 BOARD ------------------------------ */ + +/* Mapper 361 and 366, previously assigned as Mapper 205 */ +static void GN45PW(uint32 A, uint8 V) { + setprg8(A, (V & 0x0f) | EXPREGS[0]); +} + +static void GN45CW(uint32 A, uint8 V) { setchr1(A, (V & 0x7F) | (EXPREGS[0] << 3)); } -static DECLFW(M205Write0) { +static DECLFW(GN45Write0) { if (EXPREGS[2] == 0) { EXPREGS[0] = A & 0x30; EXPREGS[2] = A & 0x80; @@ -1160,7 +1212,7 @@ static DECLFW(M205Write0) { CartBW(A, V); } -static DECLFW(M205Write1) { +static DECLFW(GN45Write1) { if (EXPREGS[2] == 0) { EXPREGS[0] = V & 0x30; FixMMC3PRG(MMC3_cmd); @@ -1169,23 +1221,23 @@ static DECLFW(M205Write1) { CartBW(A, V); } -static void M205Reset(void) { +static void GN45Reset(void) { EXPREGS[0] = EXPREGS[2] = 0; MMC3RegReset(); } -static void M205Power(void) { +static void GN45Power(void) { GenMMC3Power(); - SetWriteHandler(0x6000, 0x6fff, M205Write0); - SetWriteHandler(0x7000, 0x7fff, M205Write1); // OK-411 boards, the same logic, but data latched, 2-in-1 frankenstein + SetWriteHandler(0x6000, 0x6fff, GN45Write0); + SetWriteHandler(0x7000, 0x7fff, GN45Write1); /* OK-411 boards, the same logic, but data latched, 2-in-1 frankenstein */ } -void Mapper205_Init(CartInfo *info) { +void GN45_Init(CartInfo *info) { GenMMC3_Init(info, 128, 128, 8, 0); - pwrap = M205PW; - cwrap = M205CW; - info->Power = M205Power; - info->Reset = M205Reset; + pwrap = GN45PW; + cwrap = GN45CW; + info->Power = GN45Power; + info->Reset = GN45Reset; AddExState(EXPREGS, 1, 0, "EXPR"); } diff --git a/src/boards/mmc5.cpp b/src/boards/mmc5.cpp index 3513273..82095f0 100644 --- a/src/boards/mmc5.cpp +++ b/src/boards/mmc5.cpp @@ -424,7 +424,7 @@ static void MMC5PRG(void) { switch (mmc5psize & 3) { case 0: MMC5ROMWrProtect[0] = MMC5ROMWrProtect[1] = MMC5ROMWrProtect[2] = MMC5ROMWrProtect[3] = 1; - setprg32(0x8000, ((PRGBanks[1] & 0x7F) >> 2)); + setprg32(0x8000, ((PRGBanks[3] & 0x7F) >> 2)); for (x = 0; x < 4; x++) MMC5MemIn[1 + x] = 1; break; @@ -1021,22 +1021,23 @@ static void GenMMC5_Init(CartInfo *info, int wsize, int battery) { MMC5battery = battery; if (battery) { - info->SaveGame[0] = WRAM; + uint32 saveGameSize = 0; if (info->ines2) { - info->SaveGameLen[0] = info->battery_wram_size; + saveGameSize = info->battery_wram_size; } else { //this is more complex than it looks because it MUST BE, I guess. is there an assumption that only 8KB of 16KB is battery backed? That's NES mappers for you //I added 64KB for the new 64KB homebrews if (wsize <= 16) - info->SaveGameLen[0] = 8192; + saveGameSize = 8192; else if(wsize == 64) - info->SaveGameLen[0] = 64*1024; + saveGameSize = 64*1024; else - info->SaveGameLen[0] = 32768; + saveGameSize = 32768; } + info->addSaveGameBuf( WRAM, saveGameSize ); } MMC5HackVROMMask = CHRmask4[0]; diff --git a/src/boards/n106.cpp b/src/boards/n106.cpp index cbbbc79..59399e1 100644 --- a/src/boards/n106.cpp +++ b/src/boards/n106.cpp @@ -429,10 +429,8 @@ void Mapper19_Init(CartInfo *info) { AddExState(N106_StateRegs, ~0, 0, 0); if (info->battery) { - info->SaveGame[0] = WRAM; - info->SaveGameLen[0] = 8192; - info->SaveGame[1] = IRAM; - info->SaveGameLen[1] = 128; + info->addSaveGameBuf( WRAM, 8192 ); + info->addSaveGameBuf( IRAM, 128 ); } } diff --git a/src/boards/onebus.cpp b/src/boards/onebus.cpp index 4336b77..4391394 100644 --- a/src/boards/onebus.cpp +++ b/src/boards/onebus.cpp @@ -320,8 +320,7 @@ void UNLOneBus_Init(CartInfo *info) { SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); AddExState(WRAM, WRAMSIZE, 0, "WRAM"); if (info->battery) { - info->SaveGame[0] = WRAM; - info->SaveGameLen[0] = WRAMSIZE; + info->addSaveGameBuf( WRAM, WRAMSIZE ); } } } diff --git a/src/boards/sa-9602b.cpp b/src/boards/sa-9602b.cpp index a6a19bb..409e5dd 100644 --- a/src/boards/sa-9602b.cpp +++ b/src/boards/sa-9602b.cpp @@ -54,8 +54,7 @@ void SA9602B_Init(CartInfo *info) { GenMMC3_Init(info, 512, 0, 0, 0); pwrap = SA9602BPW; mmc3opts |= 2; - info->SaveGame[0] = UNIFchrrama; - info->SaveGameLen[0] = 32 * 1024; + info->addSaveGameBuf( UNIFchrrama, 32 * 1024 ); info->Power = SA9602BPower; AddExState(EXPREGS, 2, 0, "EXPR"); } diff --git a/src/boards/sb-2000.cpp b/src/boards/sb-2000.cpp index c2ea454..cf3ad0e 100644 --- a/src/boards/sb-2000.cpp +++ b/src/boards/sb-2000.cpp @@ -24,7 +24,7 @@ static uint8 preg[8]; static uint8 IRQa; static int16 IRQCount, IRQLatch; static uint8 *WRAM = NULL; -static uint32 WRAMSIZE; +static uint32 WRAMSIZE=0; /* static uint8 *CHRRAM = NULL; static uint32 CHRRAMSIZE; @@ -187,8 +187,7 @@ void UNLSB2000_Init(CartInfo *info) { SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); AddExState(WRAM, WRAMSIZE, 0, "WRAM"); if (info->battery) { - info->SaveGame[0] = WRAM; - info->SaveGameLen[0] = WRAMSIZE; + info->addSaveGameBuf( WRAM, WRAMSIZE ); } AddExState(&StateRegs, ~0, 0, 0); diff --git a/src/boards/transformer.cpp b/src/boards/transformer.cpp index b125255..642afbf 100644 --- a/src/boards/transformer.cpp +++ b/src/boards/transformer.cpp @@ -21,7 +21,7 @@ #include "mapinc.h" static uint8 *WRAM = NULL; -static uint32 WRAMSIZE; +static uint32 WRAMSIZE=0; unsigned int *GetKeyboard(void); // FIXME: 10/28 - now implemented in SDL as well. should we rename this to a FCEUI_* function? @@ -90,8 +90,7 @@ void Transformer_Init(CartInfo *info) { WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE); SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); if (info->battery) { - info->SaveGame[0] = WRAM; - info->SaveGameLen[0] = WRAMSIZE; + info->addSaveGameBuf( WRAM, WRAMSIZE ); } AddExState(WRAM, WRAMSIZE, 0, "WRAM"); } diff --git a/src/boards/unrom512.cpp b/src/boards/unrom512.cpp index ab316d8..f2599f3 100644 --- a/src/boards/unrom512.cpp +++ b/src/boards/unrom512.cpp @@ -168,6 +168,18 @@ static void UNROM512LatchClose(void) { flash_data = NULL; } +static void UNROM512_FlashReset(void) +{ + if (flash_data) + { + size_t flash_size = PRGsize[ROM_CHIP]; + // Copy ROM to flash data + for (size_t i = 0; i < flash_size; i++) { + flash_data[i] = PRGptr[ROM_CHIP][i]; + } + } +} + void UNROM512_Init(CartInfo *info) { info->Power = UNROM512LatchPower; info->Close = UNROM512LatchClose; @@ -198,26 +210,26 @@ void UNROM512_Init(CartInfo *info) { if(flash_save) { // Allocate memory for flash - flash_data = (uint8*)FCEU_gmalloc(PRGsize[ROM_CHIP]); + size_t flash_size = PRGsize[ROM_CHIP]; + flash_data = (uint8*)FCEU_gmalloc(flash_size); // Copy ROM to flash data - for (unsigned int i = 0; i < PRGsize[ROM_CHIP]; i++) { - flash_data[i] = PRGptr[ROM_CHIP][i % PRGsize[ROM_CHIP]]; + for (size_t i = 0; i < flash_size; i++) { + flash_data[i] = PRGptr[ROM_CHIP][i]; } - SetupCartPRGMapping(FLASH_CHIP, flash_data, PRGsize[ROM_CHIP], 1); - info->SaveGame[0] = flash_data; - info->SaveGameLen[0] = PRGsize[ROM_CHIP]; + SetupCartPRGMapping(FLASH_CHIP, flash_data, flash_size, 1); + info->addSaveGameBuf( flash_data, flash_size, UNROM512_FlashReset ); flash_id[0] = 0xBF; flash_id[1] = 0xB5 + (ROM_size >> 4); SetupCartPRGMapping(CFI_CHIP, flash_id, sizeof(flash_id), 0); - AddExState(flash_data, PRGsize[ROM_CHIP], 0, "FLSH"); - AddExState(&flash_state, 1, 0, "FLST"); - AddExState(&flash_id_mode, 1, 0, "FLMD"); + AddExState(flash_data, flash_size, 0, "FLSH"); + AddExState(&flash_state, sizeof(flash_state), 0, "FLST"); + AddExState(&flash_id_mode, sizeof(flash_id_mode), 0, "FLMD"); AddExState(flash_buffer_a, sizeof(flash_buffer_a), 0, "FLBA"); AddExState(flash_buffer_v, sizeof(flash_buffer_v), 0, "FLBV"); } - AddExState(&latcha, 2, 0, "LATA"); - AddExState(&latche, 1, 0, "LATC"); - AddExState(&bus_conflict, 1, 0, "BUSC"); + AddExState(&latcha, sizeof(latcha), 0, "LATA"); + AddExState(&latche, sizeof(latche), 0, "LATC"); + AddExState(&bus_conflict, sizeof(bus_conflict), 0, "BUSC"); } diff --git a/src/boards/vrc2and4.cpp b/src/boards/vrc2and4.cpp index 3b7974b..564c51b 100644 --- a/src/boards/vrc2and4.cpp +++ b/src/boards/vrc2and4.cpp @@ -185,8 +185,7 @@ static void VRC24_Init(CartInfo *info) { AddExState(WRAM, WRAMSIZE, 0, "WRAM"); if(info->battery) { - info->SaveGame[0]=WRAM; - info->SaveGameLen[0]=WRAMSIZE; + info->addSaveGameBuf( WRAM, WRAMSIZE ); } AddExState(&StateRegs, ~0, 0, 0); diff --git a/src/boards/vrc5.cpp b/src/boards/vrc5.cpp index 07de801..0c9e362 100644 --- a/src/boards/vrc5.cpp +++ b/src/boards/vrc5.cpp @@ -254,11 +254,10 @@ void QTAi_Init(CartInfo *info) { AddExState(WRAM, WRAMSIZE, 0, "WRAM"); if (info->battery) { - info->SaveGame[0] = WRAM; // note, only extrnal cart's SRAM is battery backed, the the part on the main cartridge is just // an additional work ram. so we may save only half here, but I forgot what part is saved lol, will // find out later. - info->SaveGameLen[0] = WRAMSIZE; + info->addSaveGameBuf( WRAM, WRAMSIZE ); } AddExState(&StateRegs, ~0, 0, 0); diff --git a/src/boards/vrc6.cpp b/src/boards/vrc6.cpp index 51f58eb..030f74c 100644 --- a/src/boards/vrc6.cpp +++ b/src/boards/vrc6.cpp @@ -28,7 +28,7 @@ static uint8 prg[2], chr[8], mirr; static uint8 IRQLatch, IRQa, IRQd, IRQMode; static int32 IRQCount, CycleCount; static uint8 *WRAM = NULL; -static uint32 WRAMSIZE; +static uint32 WRAMSIZE=0; static SFORMAT StateRegs[] = { @@ -379,8 +379,7 @@ void Mapper26_Init(CartInfo *info) { SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); AddExState(WRAM, WRAMSIZE, 0, "WRAM"); if (info->battery) { - info->SaveGame[0] = WRAM; - info->SaveGameLen[0] = WRAMSIZE; + info->addSaveGameBuf( WRAM, WRAMSIZE ); } AddExState(&StateRegs, ~0, 0, 0); diff --git a/src/boards/vrc7.cpp b/src/boards/vrc7.cpp index 38e5d83..a37d76f 100644 --- a/src/boards/vrc7.cpp +++ b/src/boards/vrc7.cpp @@ -24,7 +24,7 @@ static uint8 vrc7idx, preg[3], creg[8], mirr; static uint8 IRQLatch, IRQa, IRQd, IRQMode; static int32 IRQCount, CycleCount; static uint8 *WRAM = NULL; -static uint32 WRAMSIZE; +static uint32 WRAMSIZE=0; #include "emu2413.h" @@ -204,8 +204,7 @@ void Mapper85_Init(CartInfo *info) { SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); AddExState(WRAM, WRAMSIZE, 0, "WRAM"); if (info->battery) { - info->SaveGame[0] = WRAM; - info->SaveGameLen[0] = WRAMSIZE; + info->addSaveGameBuf( WRAM, WRAMSIZE ); } GameStateRestore = StateRestore; VRC7_ESI(); diff --git a/src/cart.cpp b/src/cart.cpp index 55741b7..fd82932 100644 --- a/src/cart.cpp +++ b/src/cart.cpp @@ -536,19 +536,27 @@ void FCEU_GeniePower(void) { } -void FCEU_SaveGameSave(CartInfo *LocalHWInfo) { - if (LocalHWInfo->battery && LocalHWInfo->SaveGame[0]) { +void FCEU_SaveGameSave(CartInfo *LocalHWInfo) +{ + if (LocalHWInfo->battery && !LocalHWInfo->SaveGame.empty()) + { FILE *sp; std::string soot = FCEU_MakeFName(FCEUMKF_SAV, 0, "sav"); - if ((sp = FCEUD_UTF8fopen(soot, "wb")) == NULL) { + if ((sp = FCEUD_UTF8fopen(soot, "wb")) == NULL) + { FCEU_PrintError("WRAM file \"%s\" cannot be written to.\n", soot.c_str()); - } else { - for (int x = 0; x < 4; x++) - if (LocalHWInfo->SaveGame[x]) { - fwrite(LocalHWInfo->SaveGame[x], 1, - LocalHWInfo->SaveGameLen[x], sp); + } + else + { + for (size_t x = 0; x < LocalHWInfo->SaveGame.size(); x++) + { + if (LocalHWInfo->SaveGame[x].bufptr) + { + fwrite(LocalHWInfo->SaveGame[x].bufptr, 1, + LocalHWInfo->SaveGame[x].buflen, sp); } + } } } } @@ -556,19 +564,21 @@ void FCEU_SaveGameSave(CartInfo *LocalHWInfo) { // hack, movie.cpp has to communicate with this function somehow int disableBatteryLoading = 0; -void FCEU_LoadGameSave(CartInfo *LocalHWInfo) { - if (LocalHWInfo->battery && LocalHWInfo->SaveGame[0] && !disableBatteryLoading) { +void FCEU_LoadGameSave(CartInfo *LocalHWInfo) +{ + if (LocalHWInfo->battery && !LocalHWInfo->SaveGame.empty() && !disableBatteryLoading) + { FILE *sp; std::string soot = FCEU_MakeFName(FCEUMKF_SAV, 0, "sav"); sp = FCEUD_UTF8fopen(soot, "rb"); if (sp != NULL) { - for (int x = 0; x < 4; x++) + for (size_t x = 0; x < LocalHWInfo->SaveGame.size(); x++) { - if (LocalHWInfo->SaveGame[x]) + if (LocalHWInfo->SaveGame[x].bufptr) { - if ( fread(LocalHWInfo->SaveGame[x], 1, LocalHWInfo->SaveGameLen[x], sp) != static_cast(LocalHWInfo->SaveGameLen[x]) ) + if ( fread(LocalHWInfo->SaveGame[x].bufptr, 1, LocalHWInfo->SaveGame[x].buflen, sp) != LocalHWInfo->SaveGame[x].buflen ) { FCEU_printf("Warning save game data read came up short!\n"); } @@ -579,10 +589,20 @@ void FCEU_LoadGameSave(CartInfo *LocalHWInfo) { } //clears all save memory. call this if you want to pretend the saveram has been reset (it doesnt touch what is on disk though) -void FCEU_ClearGameSave(CartInfo *LocalHWInfo) { - if (LocalHWInfo->battery && LocalHWInfo->SaveGame[0]) { - for (int x = 0; x < 4; x++) - if (LocalHWInfo->SaveGame[x]) - memset(LocalHWInfo->SaveGame[x], 0, LocalHWInfo->SaveGameLen[x]); +void FCEU_ClearGameSave(CartInfo *LocalHWInfo) +{ + if (LocalHWInfo->battery && !LocalHWInfo->SaveGame.empty()) + { + for (size_t x = 0; x < LocalHWInfo->SaveGame.size(); x++) + { + if (LocalHWInfo->SaveGame[x].bufptr) + { + memset(LocalHWInfo->SaveGame[x].bufptr, 0, LocalHWInfo->SaveGame[x].buflen); + } + if (LocalHWInfo->SaveGame[x].resetFunc) + { + LocalHWInfo->SaveGame[x].resetFunc(); + } + } } } diff --git a/src/cart.h b/src/cart.h index ecc6794..0b58133 100644 --- a/src/cart.h +++ b/src/cart.h @@ -1,20 +1,45 @@ #ifndef CART_H #define CART_H -typedef struct { +#include + +struct CartInfo +{ // Set by mapper/board code: void (*Power)(void); void (*Reset)(void); void (*Close)(void); - uint8 *SaveGame[4]; // Pointers to memory to save/load. - uint32 SaveGameLen[4]; // How much memory to save/load. + + struct SaveGame_t + { + uint8 *bufptr; // Pointer to memory to save/load. + uint32 buflen; // How much memory to save/load. + void (*resetFunc)(void); // Callback to reset save game memory + + SaveGame_t(void) + : bufptr(nullptr), buflen(0), resetFunc(nullptr) + { + } + }; + std::vector SaveGame; + + void addSaveGameBuf( uint8* bufptrIn, uint32 buflenIn, void (*resetFuncIn)(void) = nullptr ) + { + SaveGame_t tmp; + + tmp.bufptr = bufptrIn; + tmp.buflen = buflenIn; + tmp.resetFunc = resetFuncIn; + + SaveGame.push_back( tmp ); + } // Set by iNES/UNIF loading code. int mirror; // As set in the header or chunk. - // iNES/UNIF specific. Intended - // to help support games like "Karnov" - // that are not really MMC3 but are - // set to mapper 4. + // iNES/UNIF specific. Intended + // to help support games like "Karnov" + // that are not really MMC3 but are + // set to mapper 4. int mirrorAs2Bits; int battery; // Presence of an actual battery. int ines2; @@ -27,7 +52,33 @@ typedef struct { uint32 CRC32; // Should be set by the iNES/UNIF loading // code, used by mapper/board code, maybe // other code in the future. -} CartInfo; + + CartInfo(void) + { + clear(); + } + + void clear(void) + { + Power = nullptr; + Reset = nullptr; + Close = nullptr; + + SaveGame.clear(); + + mirror = 0; + mirrorAs2Bits = 0; + battery = 0; + ines2 = 0; + submapper = 0; + wram_size = 0; + battery_wram_size = 0; + vram_size = 0; + battery_vram_size = 0; + memset( MD5, 0, sizeof(MD5)); + CRC32 = 0; + }; +}; extern CartInfo *currCartInfo; diff --git a/src/conddebug.cpp b/src/conddebug.cpp index 3775d2b..c8efa39 100644 --- a/src/conddebug.cpp +++ b/src/conddebug.cpp @@ -52,17 +52,17 @@ #include uint16 debugLastAddress = 0; // used by 'T' and 'R' conditions -uint8 debugLastOpcode; // used to evaluate 'W' condition +uint8 debugLastOpcode = 0; // used to evaluate 'W' condition // Next non-whitespace character in string -char next; +static char next = 0; -int ishex(char c) +static int ishex(char c) { return isdigit(c) || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'); } -void scan(const char** str) +static void scan(const char** str) { do { @@ -71,40 +71,37 @@ void scan(const char** str) } while (isspace(next)); } -// Frees a condition and all of it's sub conditions -void freeTree(Condition* c) -{ - if (c->lhs) freeTree(c->lhs); - if (c->rhs) freeTree(c->rhs); - - free(c); -} - // Generic function to handle all infix operators but the last one in the precedence hierarchy. : '(' E ')' -Condition* InfixOperator(const char** str, Condition(*nextPart(const char**)), int(*operators)(const char**)) +static Condition* InfixOperator(const char** str, Condition(*nextPart(const char**)), int(*operators)(const char**)) { Condition* t = nextPart(str); Condition* t1; Condition* mid; int op; + if (t == nullptr) + { + return nullptr; + } while ((op = operators(str))) { scan(str); t1 = nextPart(str); - if (t1 == 0) + if (t1 == nullptr) { - if(t) - freeTree(t); + delete t; return 0; } - mid = (Condition*)FCEU_dmalloc(sizeof(Condition)); - if (!mid) - return NULL; - memset(mid, 0, sizeof(Condition)); + mid = new Condition(); + if (mid == nullptr) + { + delete t; + delete t1; + return nullptr; + } mid->lhs = t; mid->rhs = t1; @@ -117,7 +114,7 @@ Condition* InfixOperator(const char** str, Condition(*nextPart(const char**)), i } // Generic handler for two-character operators -int TwoCharOperator(const char** str, char c1, char c2, int op) +static int TwoCharOperator(const char** str, char c1, char c2, int op) { if (next == c1 && **str == c2) { @@ -131,43 +128,43 @@ int TwoCharOperator(const char** str, char c1, char c2, int op) } // Determines if a character is a flag -int isFlag(char c) +static int isFlag(char c) { return c == 'N' || c == 'I' || c == 'C' || c == 'V' || c == 'Z' || c == 'B' || c == 'U' || c == 'D'; } // Determines if a character is a register -int isRegister(char c) +static int isRegister(char c) { return c == 'A' || c == 'X' || c == 'Y' || c == 'P' || c == 'S'; } // Determines if a character is for PC bank -int isPCBank(char c) +static int isPCBank(char c) { return c == 'K'; } // Determines if a character is for Data bank -int isDataBank(char c) +static int isDataBank(char c) { return c == 'T'; } // Determines if a character is for value read -int isValueRead(char c) +static int isValueRead(char c) { return c == 'R'; } // Determines if a character is for value write -int isValueWrite(char c) +static int isValueWrite(char c) { return c == 'W'; } // Reads a hexadecimal number from str -int getNumber(unsigned int* number, const char** str) +static int getNumber(unsigned int* number, const char** str) { // char buffer[5]; @@ -185,10 +182,10 @@ int getNumber(unsigned int* number, const char** str) return 1; } -Condition* Connect(const char** str); +static Condition* Connect(const char** str); // Handles the following part of the grammar: '(' E ')' -Condition* Parentheses(const char** str, Condition* c, char openPar, char closePar) +static Condition* Parentheses(const char** str, Condition* c, char openPar, char closePar) { if (next == openPar) { @@ -216,7 +213,7 @@ Condition* Parentheses(const char** str, Condition* c, char openPar, char closeP * Check for primitives * Flags, Registers, Numbers, Addresses and parentheses */ -Condition* Primitive(const char** str, Condition* c) +static Condition* Primitive(const char** str, Condition* c) { if (isFlag(next)) /* Flags */ { @@ -394,24 +391,22 @@ Condition* Primitive(const char** str, Condition* c) } /* Handle * and / operators */ -Condition* Term(const char** str) +static Condition* Term(const char** str) { Condition* t; Condition* t1; Condition* mid; - t = (Condition*)FCEU_dmalloc(sizeof(Condition)); + t = new Condition(); - if (!t) + if (t == nullptr) { return NULL; } - memset(t, 0, sizeof(Condition)); - if (!Primitive(str, t)) { - freeTree(t); + delete t; return 0; } @@ -421,22 +416,25 @@ Condition* Term(const char** str) scan(str); - if (!(t1 = (Condition*)FCEU_dmalloc(sizeof(Condition)))) - return NULL; - - memset(t1, 0, sizeof(Condition)); + if ((t1 = new Condition()) == nullptr) + { + delete t; + return nullptr; + } if (!Primitive(str, t1)) { - freeTree(t); - freeTree(t1); + delete t; + delete t1; return 0; } - if (!(mid = (Condition*)FCEU_dmalloc(sizeof(Condition)))) - return NULL; - - memset(mid, 0, sizeof(Condition)); + if ((mid = new Condition()) == nullptr) + { + delete t; + delete t1; + return nullptr; + } mid->lhs = t; mid->rhs = t1; @@ -449,7 +447,7 @@ Condition* Term(const char** str) } /* Check for + and - operators */ -int SumOperators(const char** str) +static int SumOperators(const char** str) { switch (next) { @@ -460,13 +458,13 @@ int SumOperators(const char** str) } /* Handle + and - operators */ -Condition* Sum(const char** str) +static Condition* Sum(const char** str) { return InfixOperator(str, Term, SumOperators); } /* Check for <=, =>, ==, !=, > and < operators */ -int CompareOperators(const char** str) +static int CompareOperators(const char** str) { int val = TwoCharOperator(str, '=', '=', OP_EQ); if (val) return val; @@ -490,13 +488,13 @@ int CompareOperators(const char** str) } /* Handle <=, =>, ==, !=, > and < operators */ -Condition* Compare(const char** str) +static Condition* Compare(const char** str) { return InfixOperator(str, Sum, CompareOperators); } /* Check for || or && operators */ -int ConnectOperators(const char** str) +static int ConnectOperators(const char** str) { int val = TwoCharOperator(str, '|', '|', OP_OR); if(val) return val; @@ -508,7 +506,7 @@ int ConnectOperators(const char** str) } /* Handle || and && operators */ -Condition* Connect(const char** str) +static Condition* Connect(const char** str) { return InfixOperator(str, Compare, ConnectOperators); } @@ -521,6 +519,10 @@ Condition* generateCondition(const char* str) scan(&str); c = Connect(&str); - if (!c || next != 0) return 0; + if (!c || next != 0) + { + if (c) delete c; + return 0; + } else return c; } diff --git a/src/conddebug.h b/src/conddebug.h index 24af528..168eb4a 100644 --- a/src/conddebug.h +++ b/src/conddebug.h @@ -61,9 +61,28 @@ struct Condition unsigned int type2; unsigned int value2; + + Condition(void) + { + op = 0; + lhs = rhs = nullptr; + type1 = value1 = 0; + type2 = value2 = 0; + }; + + ~Condition(void) + { + if (lhs) + { + delete lhs; + } + if (rhs) + { + delete rhs; + } + } }; -void freeTree(Condition* c); Condition* generateCondition(const char* str); #endif diff --git a/src/debug.cpp b/src/debug.cpp index 2863631..fad9c6f 100644 --- a/src/debug.cpp +++ b/src/debug.cpp @@ -19,10 +19,15 @@ unsigned int debuggerPageSize = 14; int vblankScanLines = 0; //Used to calculate scanlines 240-261 (vblank) int vblankPixel = 0; //Used to calculate the pixels in vblank -int offsetStringToInt(unsigned int type, const char* offsetBuffer) +int offsetStringToInt(unsigned int type, const char* offsetBuffer, bool *conversionOk) { int offset = -1; + if (conversionOk) + { + *conversionOk = false; + } + if (sscanf(offsetBuffer,"%7X",(unsigned int *)&offset) == EOF) { return -1; @@ -30,14 +35,26 @@ int offsetStringToInt(unsigned int type, const char* offsetBuffer) if (type & BT_P) { + if (conversionOk) + { + *conversionOk = (offset >= 0) && (offset < 0x4000); + } return offset & 0x3FFF; } else if (type & BT_S) { + if (conversionOk) + { + *conversionOk = (offset >= 0) && (offset < 0x100); + } return offset & 0x00FF; } else if (type & BT_R) { + if (conversionOk) + { + *conversionOk = (offset >= 0); + } return offset; } else // BT_C @@ -46,6 +63,10 @@ int offsetStringToInt(unsigned int type, const char* offsetBuffer) if (sym) { + if (conversionOk) + { + *conversionOk = true; + } return sym->offset() & 0xFFFF; } @@ -56,21 +77,26 @@ int offsetStringToInt(unsigned int type, const char* offsetBuffer) type = GameInfo->type; } if (type == GIT_NSF) { //NSF Breakpoint keywords - if (strcmp(offsetBuffer,"LOAD") == 0) return (NSFHeader.LoadAddressLow | (NSFHeader.LoadAddressHigh<<8)); - if (strcmp(offsetBuffer,"INIT") == 0) return (NSFHeader.InitAddressLow | (NSFHeader.InitAddressHigh<<8)); - if (strcmp(offsetBuffer,"PLAY") == 0) return (NSFHeader.PlayAddressLow | (NSFHeader.PlayAddressHigh<<8)); + if (strcmp(offsetBuffer,"LOAD") == 0) offset = (NSFHeader.LoadAddressLow | (NSFHeader.LoadAddressHigh<<8)); + else if (strcmp(offsetBuffer,"INIT") == 0) offset = (NSFHeader.InitAddressLow | (NSFHeader.InitAddressHigh<<8)); + else if (strcmp(offsetBuffer,"PLAY") == 0) offset = (NSFHeader.PlayAddressLow | (NSFHeader.PlayAddressHigh<<8)); } else if (type == GIT_FDS) { //FDS Breakpoint keywords - if (strcmp(offsetBuffer,"NMI1") == 0) return (GetMem(0xDFF6) | (GetMem(0xDFF7)<<8)); - if (strcmp(offsetBuffer,"NMI2") == 0) return (GetMem(0xDFF8) | (GetMem(0xDFF9)<<8)); - if (strcmp(offsetBuffer,"NMI3") == 0) return (GetMem(0xDFFA) | (GetMem(0xDFFB)<<8)); - if (strcmp(offsetBuffer,"RST") == 0) return (GetMem(0xDFFC) | (GetMem(0xDFFD)<<8)); - if ((strcmp(offsetBuffer,"IRQ") == 0) || (strcmp(offsetBuffer,"BRK") == 0)) return (GetMem(0xDFFE) | (GetMem(0xDFFF)<<8)); + if (strcmp(offsetBuffer,"NMI1") == 0) offset = (GetMem(0xDFF6) | (GetMem(0xDFF7)<<8)); + else if (strcmp(offsetBuffer,"NMI2") == 0) offset = (GetMem(0xDFF8) | (GetMem(0xDFF9)<<8)); + else if (strcmp(offsetBuffer,"NMI3") == 0) offset = (GetMem(0xDFFA) | (GetMem(0xDFFB)<<8)); + else if (strcmp(offsetBuffer,"RST") == 0) offset = (GetMem(0xDFFC) | (GetMem(0xDFFD)<<8)); + else if ((strcmp(offsetBuffer,"IRQ") == 0) || (strcmp(offsetBuffer,"BRK") == 0)) offset = (GetMem(0xDFFE) | (GetMem(0xDFFF)<<8)); } else { //NES Breakpoint keywords - if ((strcmp(offsetBuffer,"NMI") == 0) || (strcmp(offsetBuffer,"VBL") == 0)) return (GetMem(0xFFFA) | (GetMem(0xFFFB)<<8)); - if (strcmp(offsetBuffer,"RST") == 0) return (GetMem(0xFFFC) | (GetMem(0xFFFD)<<8)); - if ((strcmp(offsetBuffer,"IRQ") == 0) || (strcmp(offsetBuffer,"BRK") == 0)) return (GetMem(0xFFFE) | (GetMem(0xFFFF)<<8)); + if ((strcmp(offsetBuffer,"NMI") == 0) || (strcmp(offsetBuffer,"VBL") == 0)) offset = (GetMem(0xFFFA) | (GetMem(0xFFFB)<<8)); + else if (strcmp(offsetBuffer,"RST") == 0) offset = (GetMem(0xFFFC) | (GetMem(0xFFFD)<<8)); + else if ((strcmp(offsetBuffer,"IRQ") == 0) || (strcmp(offsetBuffer,"BRK") == 0)) offset = (GetMem(0xFFFE) | (GetMem(0xFFFF)<<8)); + } + + if (conversionOk) + { + *conversionOk = (offset >= 0) && (offset < 0x10000); } } @@ -139,7 +165,7 @@ int checkCondition(const char* condition, int num) // Remove the old breakpoint condition before adding a new condition. if (watchpoint[num].cond) { - freeTree(watchpoint[num].cond); + delete watchpoint[num].cond; free(watchpoint[num].condText); watchpoint[num].cond = 0; watchpoint[num].condText = 0; @@ -153,8 +179,8 @@ int checkCondition(const char* condition, int num) { watchpoint[num].cond = c; watchpoint[num].condText = (char*)malloc(strlen(condition) + 1); - if (!watchpoint[num].condText) - return 0; + if (!watchpoint[num].condText) + return 0; strcpy(watchpoint[num].condText, condition); } else @@ -169,7 +195,7 @@ int checkCondition(const char* condition, int num) // Remove the old breakpoint condition if (watchpoint[num].cond) { - freeTree(watchpoint[num].cond); + delete watchpoint[num].cond; free(watchpoint[num].condText); watchpoint[num].cond = 0; watchpoint[num].condText = 0; @@ -266,7 +292,7 @@ int getBank(int offs) //Anything over FFFFF will kill it. //GetNesFileAddress doesn't work well with Unif files - int addr = GetNesFileAddress(offs)-16; + int addr = GetNesFileAddress(offs)-NES_HEADER_SIZE; if (GameInfo && GameInfo->type==GIT_NSF) return addr != -1 ? addr / 0x1000 : -1; @@ -278,12 +304,12 @@ int GetNesFileAddress(int A){ if((A < 0x6000) || (A > 0xFFFF))return -1; result = &Page[A>>11][A]-PRGptr[0]; if((result > (int)(PRGsize[0])) || (result < 0))return -1; - else return result+16; //16 bytes for the header remember + else return result+NES_HEADER_SIZE; //16 bytes for the header remember } int GetRomAddress(int A){ int i; - uint8 *p = GetNesPRGPointer(A-=16); + uint8 *p = GetNesPRGPointer(A-=NES_HEADER_SIZE); for(i = 16;i < 32;i++){ if((&Page[i][i<<11] <= p) && (&Page[i][(i+1)<<11] > p))break; } diff --git a/src/debug.h b/src/debug.h index e1d8b57..708c12e 100644 --- a/src/debug.h +++ b/src/debug.h @@ -172,7 +172,7 @@ DebuggerState &FCEUI_Debugger(); //#define WRITE_BREAKPOINT 16 //#define EXECUTE_BREAKPOINT 32 -int offsetStringToInt(unsigned int type, const char* offsetBuffer); +int offsetStringToInt(unsigned int type, const char* offsetBuffer, bool *conversionOk = nullptr); unsigned int NewBreak(const char* name, int start, int end, unsigned int type, const char* condition, unsigned int num, bool enable); #endif diff --git a/src/debugsymboltable.cpp b/src/debugsymboltable.cpp index 78d6535..a8f92b7 100644 --- a/src/debugsymboltable.cpp +++ b/src/debugsymboltable.cpp @@ -7,6 +7,7 @@ #include "debug.h" #include "fceu.h" #include "cart.h" +#include "ld65dbg.h" #ifdef __QT_DRIVER__ #include "Qt/ConsoleUtilities.h" @@ -385,6 +386,18 @@ void debugSymbolTable_t::clear(void) pageMap.clear(); } //-------------------------------------------------------------- +int debugSymbolTable_t::numSymbols(void) +{ + int n = 0; + FCEU::autoScopedLock alock(cs); + + for (auto it=pageMap.begin(); it!=pageMap.end(); it++) + { + n += it->second->size(); + } + return n; +} +//-------------------------------------------------------------- static int generateNLFilenameForBank(int bank, std::string &NLfilename) { int i; @@ -743,12 +756,11 @@ int debugSymbolTable_t::loadGameSymbols(void) { int nPages, pageSize, romSize = 0x10000; - this->save(); this->clear(); if ( GameInfo != nullptr ) { - romSize = 16 + CHRsize[0] + PRGsize[0]; + romSize = NES_HEADER_SIZE + CHRsize[0] + PRGsize[0]; } loadFileNL( -1 ); @@ -773,6 +785,7 @@ int debugSymbolTable_t::loadGameSymbols(void) return 0; } +//-------------------------------------------------------------- int debugSymbolTable_t::addSymbolAtBankOffset(int bank, int ofs, const char *name, const char *comment) { int result = -1; @@ -909,3 +922,81 @@ const char *debugSymbolTable_t::errorMessage(void) return dbgSymTblErrMsg; } //-------------------------------------------------------------- +static void ld65_iterate_cb( void *userData, ld65::sym *s ) +{ + debugSymbolTable_t *tbl = static_cast(userData); + + if (tbl) + { + tbl->ld65_SymbolLoad(s); + } +} +//-------------------------------------------------------------- +void debugSymbolTable_t::ld65_SymbolLoad( ld65::sym *s ) +{ + int bank = -1; + debugSymbol_t *sym; + debugSymbolPage_t *page; + ld65::scope *scope = s->getScope(); + ld65::segment *seg = s->getSegment(); + + if ( s->type() == ld65::sym::LABEL ) + { + //printf("Symbol Label Load: name:\"%s\" val:%i 0x%x\n", s->name(), s->value(), s->value() ); + if (seg) + { + int romAddr = seg->ofs() - NES_HEADER_SIZE; + + bank = romAddr >= 0 ? romAddr / (1<name(), romAddr, bank ); + } + //printf("\n"); + + auto pageIt = pageMap.find(bank); + + if (pageIt == pageMap.end() ) + { + page = new debugSymbolPage_t(bank); + + pageMap[bank] = page; + } + else + { + page = pageIt->second; + } + std::string name; + + if (scope) + { + scope->getFullName(name); + } + name.append(s->name()); + + //printf("Creating Symbol: %s\n", name.c_str() ); + + sym = new debugSymbol_t( s->value(), name.c_str() ); + + if ( page->addSymbol( sym ) ) + { + //printf("Failed to load sym: id:%i name:'%s' bank:%i \n", s->id(), s->name(), bank ); + delete sym; + } + } +} +//-------------------------------------------------------------- +int debugSymbolTable_t::ld65LoadDebugFile( const char *dbgFilePath ) +{ + ld65::database db; + + if ( db.dbgFileLoad( dbgFilePath ) ) + { + return -1; + } + FCEU::autoScopedLock alock(cs); + + db.iterateSymbols( this, ld65_iterate_cb ); + + return 0; +} +//-------------------------------------------------------------- diff --git a/src/debugsymboltable.h b/src/debugsymboltable.h index caf0dc5..8e07049 100644 --- a/src/debugsymboltable.h +++ b/src/debugsymboltable.h @@ -5,6 +5,7 @@ #include #include "utils/mutex.h" +#include "ld65dbg.h" class debugSymbolPage_t; class debugSymbolTable_t; @@ -91,7 +92,7 @@ class debugSymbolPage_t int save(void); void print(void); - int size(void){ return symMap.size(); } + int size(void){ return static_cast(symMap.size()); } int addSymbol( debugSymbol_t *sym ); @@ -130,8 +131,10 @@ class debugSymbolTable_t ~debugSymbolTable_t(void); int loadFileNL( int addr ); + int loadRegisterMap(void); int loadGameSymbols(void); int numPages(void){ return pageMap.size(); } + int numSymbols(void); void save(void); void clear(void); @@ -153,12 +156,13 @@ class debugSymbolTable_t const char *errorMessage(void); + int ld65LoadDebugFile( const char *dbgFilePath ); + + void ld65_SymbolLoad( ld65::sym *s ); + private: std::map pageMap; FCEU::mutex *cs; - - int loadRegisterMap(void); - }; extern debugSymbolTable_t debugSymbolTable; diff --git a/src/drawing.cpp b/src/drawing.cpp index 7597c06..1129b3c 100644 --- a/src/drawing.cpp +++ b/src/drawing.cpp @@ -346,7 +346,7 @@ void FCEU_DrawRecordingStatus(uint8* XBuf) hasPlayRecIcon = true; } - if(FCEUI_EmulationPaused()) + if( EmulationPaused & (EMULATIONPAUSED_PAUSED | EMULATIONPAUSED_TIMER) ) drawstatus(XBuf-ClipSidesOffset,3,28,hasPlayRecIcon?-16:0); } } diff --git a/src/driver.h b/src/driver.h index 9dde9c6..efc1cd7 100644 --- a/src/driver.h +++ b/src/driver.h @@ -273,6 +273,8 @@ void FCEUI_ClearEmulationFrameStepped(); void FCEUI_SetEmulationPaused(int val); ///toggles the paused bit (bit0) for EmulationPaused. caused FCEUD_DebugUpdate() to fire if the emulation pauses void FCEUI_ToggleEmulationPause(); +void FCEUI_PauseForDuration(int secs); +int FCEUI_PauseFramesRemaining(); //indicates whether input aids should be drawn (such as crosshairs, etc; usually in fullscreen mode) bool FCEUD_ShouldDrawInputAids(); diff --git a/src/emufile.cpp b/src/emufile.cpp index a4edb7e..0af17d7 100644 --- a/src/emufile.cpp +++ b/src/emufile.cpp @@ -191,7 +191,7 @@ size_t EMUFILE::read32le(u32* Bufo) u32 EMUFILE::read32le() { - u32 ret; + u32 ret=0; read32le(&ret); return ret; } @@ -230,7 +230,7 @@ size_t EMUFILE::read16le(u16* Bufo) u16 EMUFILE::read16le() { - u16 ret; + u16 ret=0; read16le(&ret); return ret; } @@ -269,14 +269,14 @@ void EMUFILE::writedouble(double val) double EMUFILE::readdouble() { - double temp; + double temp=0.0; readdouble(&temp); return temp; } size_t EMUFILE::readdouble(double* val) { - u64 temp; + u64 temp=0; size_t ret = read64le(&temp); *val = u64_to_double(temp); return ret; diff --git a/src/emufile.h b/src/emufile.h index 0bd65c3..623f6c2 100644 --- a/src/emufile.h +++ b/src/emufile.h @@ -179,10 +179,10 @@ class EMUFILE_MEMORY : public EMUFILE { va_start(argptr, format); vsprintf(tempbuf,format,argptr); - fwrite(tempbuf,amt); + fwrite(tempbuf,amt); delete[] tempbuf; - va_end(argptr); + va_end(argptr); return amt; }; diff --git a/src/fceu.cpp b/src/fceu.cpp index 49f5c75..37d61a5 100644 --- a/src/fceu.cpp +++ b/src/fceu.cpp @@ -36,6 +36,7 @@ #include "unif.h" #include "cheat.h" #include "palette.h" +#include "profiler.h" #include "state.h" #include "movie.h" #include "video.h" @@ -116,6 +117,7 @@ bool movieSubtitles = true; //Toggle for displaying movie subtitles bool DebuggerWasUpdated = false; //To prevent the debugger from updating things without being updated. bool AutoResumePlay = false; char romNameWhenClosingEmulator[2048] = {0}; +static unsigned int pauseTimer = 0; FCEUGI::FCEUGI() @@ -208,6 +210,8 @@ static void FCEU_CloseGame(void) GameInterface(GI_CLOSE); + FCEU_StateRecorderStop(); + FCEUI_StopMovie(); ResetExState(0, 0); @@ -592,6 +596,12 @@ FCEUGI *FCEUI_LoadGameVirtual(const char *name, int OverwriteVidMode, bool silen } FCEU_fclose(fp); + + if ( FCEU_StateRecorderIsEnabled() ) + { + FCEU_StateRecorderStart(); + } + return GameInfo; } @@ -725,6 +735,7 @@ extern unsigned int frameAdvHoldTimer; ///Skip may be passed in, if FRAMESKIP is #defined, to cause this to emulate more than one frame void FCEUI_Emulate(uint8 **pXBuf, int32 **SoundBuf, int32 *SoundBufSize, int skip) { + FCEU_PROFILE_FUNC(prof, "Emulate Single Frame"); //skip initiates frame skip if 1, or frame skip and sound skip if 2 FCEU_MAYBE_UNUSED int r; int ssize; @@ -756,6 +767,22 @@ void FCEUI_Emulate(uint8 **pXBuf, int32 **SoundBuf, int32 *SoundBufSize, int ski #endif } + if (EmulationPaused & EMULATIONPAUSED_TIMER) + { + if (pauseTimer > 0) + { + pauseTimer--; + } + else + { + EmulationPaused &= ~EMULATIONPAUSED_TIMER; + } + if (EmulationPaused & EMULATIONPAUSED_PAUSED) + { + EmulationPaused &= ~EMULATIONPAUSED_TIMER; + } + } + if (EmulationPaused & EMULATIONPAUSED_FA) { // the user is holding Frame Advance key @@ -779,7 +806,7 @@ void FCEUI_Emulate(uint8 **pXBuf, int32 **SoundBuf, int32 *SoundBufSize, int ski RefreshThrottleFPS(); } #endif - if (EmulationPaused & EMULATIONPAUSED_PAUSED) + if (EmulationPaused & (EMULATIONPAUSED_PAUSED | EMULATIONPAUSED_TIMER) ) { // emulator is paused memcpy(XBuf, XBackBuf, 256*256); @@ -793,6 +820,7 @@ void FCEUI_Emulate(uint8 **pXBuf, int32 **SoundBuf, int32 *SoundBufSize, int ski AutoFire(); UpdateAutosave(); + FCEU_StateRecorderUpdate(); #ifdef _S9XLUA_H FCEU_LuaFrameBoundary(); @@ -1254,6 +1282,33 @@ void FCEUI_FrameAdvance(void) { frameAdvanceRequested = true; } +void FCEUI_PauseForDuration(int secs) +{ + int framesPerSec; + + // If already paused, do nothing + if (EmulationPaused & EMULATIONPAUSED_PAUSED) + { + return; + } + + if (PAL || dendy) + { + framesPerSec = 50; + } + else + { + framesPerSec = 60; + } + pauseTimer = framesPerSec * secs; + EmulationPaused |= EMULATIONPAUSED_TIMER; +} + +int FCEUI_PauseFramesRemaining(void) +{ + return (EmulationPaused & EMULATIONPAUSED_TIMER) ? pauseTimer : 0; +} + static int AutosaveCounter = 0; void UpdateAutosave(void) { diff --git a/src/fceu.h b/src/fceu.h index 9d75921..b35bf4a 100644 --- a/src/fceu.h +++ b/src/fceu.h @@ -181,8 +181,10 @@ extern uint8 vsdip; #define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0])) -#define EMULATIONPAUSED_PAUSED 1 -#define EMULATIONPAUSED_FA 2 +#define EMULATIONPAUSED_PAUSED 0x01 +#define EMULATIONPAUSED_TIMER 0x02 +#define EMULATIONPAUSED_FA 0x04 #define FRAMEADVANCE_DELAY_DEFAULT 10 +#define NES_HEADER_SIZE 16 diff --git a/src/fceulua.h b/src/fceulua.h index 08b8a87..2a82d2d 100644 --- a/src/fceulua.h +++ b/src/fceulua.h @@ -21,9 +21,6 @@ enum LuaMemHookType LUAMEMHOOK_WRITE, LUAMEMHOOK_READ, LUAMEMHOOK_EXEC, - LUAMEMHOOK_WRITE_SUB, - LUAMEMHOOK_READ_SUB, - LUAMEMHOOK_EXEC_SUB, LUAMEMHOOK_COUNT }; diff --git a/src/filter.cpp b/src/filter.cpp index d1e13ac..650f8c4 100644 --- a/src/filter.cpp +++ b/src/filter.cpp @@ -37,7 +37,7 @@ void SexyFilter2(int32 *in, int32 count) while(count--) { int64 dropcurrent; - dropcurrent=((*in<<16)-acc)>>3; + dropcurrent=( int32(uint32(*in)<<16)-acc)>>3; acc+=dropcurrent; *in=acc>>16; diff --git a/src/fir/Makefile b/src/fir/Makefile new file mode 100644 index 0000000..a74f918 --- /dev/null +++ b/src/fir/Makefile @@ -0,0 +1,15 @@ +CC = gcc +%.h: %.coef + cat $< | ./toh > $@ || true + +all: floogie c44100ntsc.h c48000ntsc.h c96000ntsc.h c44100pal.h c48000pal.h c96000pal.h + +#c44100ntsc.h: c44100ntsc.coef +#c48000ntsc.h: c48000ntsc.coef +#c96000ntsc.h: c96000ntsc.coef +#c44100pal.h: c44100pal.coef +#c48000pal.h: c48000pal.coef +#c96000pal.h: c96000pal.coef + +floogie: toh.o + gcc -o toh toh.o diff --git a/src/ines.cpp b/src/ines.cpp index c2824a3..9bf183f 100644 --- a/src/ines.cpp +++ b/src/ines.cpp @@ -689,7 +689,7 @@ BMAPPINGLocal bmap[] = { {"", 171, Mapper171_Init}, {"", 172, Mapper172_Init}, {"", 173, Mapper173_Init}, -// {"", 174, Mapper174_Init}, + {"NTDec 5-in-1", 174, Mapper174_Init}, {"", 175, Mapper175_Init}, {"BMCFK23C", 176, BMCFK23C_Init}, // zero 26-may-2012 - well, i have some WXN junk games that use 176 for instance ????. i dont know what game uses this BMCFK23C as mapper 176. we'll have to make a note when we find it. {"", 177, Mapper177_Init}, @@ -720,7 +720,7 @@ BMAPPINGLocal bmap[] = { {"", 202, Mapper202_Init}, {"", 203, Mapper203_Init}, {"", 204, Mapper204_Init}, - {"", 205, Mapper205_Init}, + {"JC-016-2", 205, Mapper205_Init}, {"NAMCOT 108 Rev. C", 206, Mapper206_Init}, // Deprecated, Used to be "DEIROM" whatever it means, but actually simple version of MMC3 {"TAITO X1-005 Rev. B", 207, Mapper207_Init}, {"", 208, Mapper208_Init}, @@ -788,6 +788,8 @@ BMAPPINGLocal bmap[] = { {"HP10xx/H20xx Boards", 260, BMCHPxx_Init}, {"810544-CA-1", 261, BMC810544CA1_Init}, {"AA6023/AA6023B", 268, AA6023_Init}, + {"OK-411", 361, GN45_Init}, + {"GN-45", 366, GN45_Init}, {"COOLGIRL", 342, COOLGIRL_Init }, {"FAM250/81-01-39-C/SCHI-24", 354, Mapper354_Init }, @@ -810,7 +812,7 @@ int iNESLoad(const char *name, FCEUFILE *fp, int OverwriteVidMode) { head.cleanup(); - memset(&iNESCart, 0, sizeof(iNESCart)); + iNESCart.clear(); iNES2 = ((head.ROM_type2 & 0x0C) == 0x08); if(iNES2) diff --git a/src/ines.h b/src/ines.h index f1b0d23..6c95863 100644 --- a/src/ines.h +++ b/src/ines.h @@ -208,6 +208,7 @@ void Mapper170_Init(CartInfo *); void Mapper171_Init(CartInfo *); void Mapper172_Init(CartInfo *); void Mapper173_Init(CartInfo *); +void Mapper174_Init(CartInfo *); void Mapper175_Init(CartInfo *); void Mapper177_Init(CartInfo *); void Mapper178_Init(CartInfo *); @@ -279,6 +280,7 @@ void Mapper354_Init(CartInfo *); void Mapper406_Init(CartInfo *); void INX_007T_Init(CartInfo* info); +void GN45_Init(CartInfo *info); /* previously mapper 205 */ typedef struct { const char *name; diff --git a/src/ld65dbg.cpp b/src/ld65dbg.cpp new file mode 100644 index 0000000..7e93417 --- /dev/null +++ b/src/ld65dbg.cpp @@ -0,0 +1,419 @@ +// ld65dbg.cpp +#include +#include +#include +#include + +#include "types.h" +#include "ld65dbg.h" + + +namespace ld65 +{ + //--------------------------------------------------------------------------------------------------- + segment::segment( int id, const char *name, int startAddr, int size, int ofs, unsigned char type ) + : _name(name ? name : ""), _id(id), _startAddr(startAddr), _size(size), _ofs(ofs), _type(type) + { + } + //--------------------------------------------------------------------------------------------------- + scope::scope(int id, const char *name, int size, int parentID) + : _name(name ? name : ""), _id(id), _parentID(parentID), _size(size), _parent(nullptr) + { + } + //--------------------------------------------------------------------------------------------------- + void scope::getFullName(std::string &out) + { + if ( _parent ) + { + _parent->getFullName(out); + } + if (!_name.empty()) + { + out.append(_name); + out.append("::"); + } + } + //--------------------------------------------------------------------------------------------------- + sym::sym(int id, const char *name, int size, int value, int type) + : _name(name ? name : ""), _id(id), _size(size), _value(value), _type(type), _scope(nullptr), _segment(nullptr) + { + } + //--------------------------------------------------------------------------------------------------- + database::database(void) + { + } + //--------------------------------------------------------------------------------------------------- + database::~database(void) + { + for (auto itSym = symMap.begin(); itSym != symMap.end(); itSym++) + { + delete itSym->second; + } + for (auto itScope = scopeMap.begin(); itScope != scopeMap.end(); itScope++) + { + delete itScope->second; + } + for (auto itSeg = segmentMap.begin(); itSeg != segmentMap.end(); itSeg++) + { + delete itSeg->second; + } + } + //--------------------------------------------------------------------------------------------------- + database::dbgLine::dbgLine(size_t bufferSize) + { + buf = NULL; + bufSize = 0; + readPtr = 0; + + allocBuffer( bufferSize ); + } + //--------------------------------------------------------------------------------------------------- + database::dbgLine::~dbgLine(void) + { + if (buf) + { + ::free(buf); buf = NULL; + } + bufSize = 0; + readPtr = 0; + } + //--------------------------------------------------------------------------------------------------- + void database::dbgLine::allocBuffer(size_t bufferSize) + { + if (buf) + { + ::free(buf); buf = NULL; + } + bufSize = 0; + readPtr = 0; + + buf = static_cast( ::malloc( bufferSize ) ); + + if (buf == NULL) + { + bufSize = 0; + } + else + { + buf[0] = 0; + bufSize = bufferSize; + } + readPtr = 0; + } + //--------------------------------------------------------------------------------------------------- + const char *database::dbgLine::readFromFile( FILE *fp ) + { + readPtr = 0; + + return fgets(buf, bufSize, fp); + } + //--------------------------------------------------------------------------------------------------- + int database::dbgLine::readToken( char *tk, size_t tkSize ) + { + int charsRead = 0; + size_t i,j; + + i=readPtr; j=0; + if ( buf[i] != 0 ) + { + while (isspace(buf[i])) i++; + + if ( isalpha(buf[i]) || (buf[i] == '_') ) + { + while ( isalnum(buf[i]) || (buf[i] == '_') ) + { + if (j < tkSize) + { + tk[j] = buf[i]; j++; + } + i++; + } + } + else if (buf[i] != 0) + { + if (j < tkSize) + { + tk[j] = buf[i]; j++; + } + i++; + } + } + charsRead = j; + readPtr = i; + + if (j < tkSize) + { + tk[j] = 0; + } + else + { + tk[tkSize-1] = 0; + } + return charsRead; + } + //--------------------------------------------------------------------------------------------------- + int database::dbgLine::readKeyValuePair( char *keyValueBuffer, size_t keyValueBufferSize ) + { + int charsRead = 0; + size_t i,j; + bool isStringLiteral = false; + + i=readPtr; j=0; + if ( buf[i] != 0 ) + { + while (isspace(buf[i])) i++; + + if ( isalpha(buf[i]) || (buf[i] == '_') ) + { + while ( isalnum(buf[i]) || (buf[i] == '_') ) + { + if (j < keyValueBufferSize) + { + keyValueBuffer[j] = buf[i]; j++; + } + i++; + } + } + else if (buf[i] != 0) + { + if (j < keyValueBufferSize) + { + keyValueBuffer[j] = buf[i]; j++; + } + i++; + } + + while (isspace(buf[i])) i++; + } + + if ( buf[i] == '=' ) + { + if (j < keyValueBufferSize) + { + keyValueBuffer[j] = buf[i]; j++; + } + i++; + + while (isspace(buf[i])) i++; + + while ( buf[i] != 0 ) + { + if ( !isStringLiteral && buf[i] == ',' ) + { + break; + } + else if ( buf[i] == '\"' ) + { + isStringLiteral = !isStringLiteral; + } + else + { + if (j < keyValueBufferSize) + { + if (!isspace(buf[i])) + { + keyValueBuffer[j] = buf[i]; j++; + } + } + } + i++; + } + if (buf[i] == ',') + { + i++; + } + } + charsRead = j; + readPtr = i; + + if (j < keyValueBufferSize) + { + keyValueBuffer[j] = 0; + } + else + { + keyValueBuffer[keyValueBufferSize-1] = 0; + } + return charsRead; + } + //--------------------------------------------------------------------------------------------------- + int database::dbgLine::splitKeyValuePair( char *keyValueBuffer, char **keyPtr, char **valuePtr ) + { + size_t i=0; + + if (keyPtr != nullptr) + { + *keyPtr = keyValueBuffer; + } + while (keyValueBuffer[i] != 0) + { + if (keyValueBuffer[i] == '=') + { + keyValueBuffer[i] = 0; i++; break; + } + i++; + } + if (valuePtr != nullptr) + { + *valuePtr = &keyValueBuffer[i]; + } + return 0; + } + //--------------------------------------------------------------------------------------------------- + int database::dbgFileLoad( const char *dbgFilePath ) + { + static constexpr size_t lineSize = 4096; + FILE *fp; + dbgLine line( lineSize ); + char lineType[64]; + fceuScopedPtr keyValueBuffer( new char[ lineSize ], FCEU_ALLOC_TYPE_NEW_ARRAY ); + + fp = ::fopen( dbgFilePath, "r"); + + if (fp == NULL) + { + return -1; + } + + while ( line.readFromFile(fp) != NULL ) + { + //printf("%s", line.getLine()); + + if ( line.readToken( lineType, sizeof(lineType) ) ) + { + int id = -1, size = 0, startAddr = 0, ofs = -1, parentID = -1, scopeID = -1, segmentID = -1; + int value = 0; + unsigned char segType = segment::READ; + char name[256]; + char type[32]; + + name[0] = 0; + type[0] = 0; + + while ( line.readKeyValuePair( keyValueBuffer.get(), lineSize) ) + { + char *key, *val; + + line.splitKeyValuePair( keyValueBuffer.get(), &key, &val ); + + //printf(" Key '%s' -> Value '%s' \n", key, val ); + + if ( strcmp( key, "id") == 0 ) + { + id = strtol( val, nullptr, 0 ); + } + else if ( strcmp( key, "name") == 0 ) + { + strncpy( name, val, sizeof(name)); + } + else if ( strcmp( key, "size") == 0 ) + { + size = strtol( val, nullptr, 0 ); + } + else if ( strcmp( key, "val") == 0 ) + { + value = strtol( val, nullptr, 0 ); + } + else if ( strcmp( key, "scope") == 0 ) + { + scopeID = strtol( val, nullptr, 0 ); + } + else if ( strcmp( key, "parent") == 0 ) + { + parentID = strtol( val, nullptr, 0 ); + } + else if ( strcmp( key, "seg") == 0 ) + { + segmentID = strtol( val, nullptr, 0 ); + } + else if ( strcmp( key, "ooffs") == 0 ) + { + ofs = strtol( val, nullptr, 0 ); + } + else if ( strcmp( key, "type") == 0 ) + { + strncpy( type, val, sizeof(type)); + } + } + + if ( strcmp( lineType, "seg" ) == 0 ) + { + if ( id >= 0 ) + { + segment *s = new segment( id, name, startAddr, size, ofs, segType ); + + segmentMap[id] = s; + } + } + else if ( strcmp( lineType, "scope" ) == 0 ) + { + if ( id >= 0 ) + { + scope *s = new scope( id, name, size, parentID ); + + scopeMap[id] = s; + + auto it = scopeMap.find( parentID ); + + if ( it != scopeMap.end() ) + { + //printf("Found Parent:%i for %i\n", parentID, id ); + s->_parent = it->second; + } + } + } + else if ( strcmp( lineType, "sym") == 0 ) + { + if ( id >= 0 ) + { + int symType = sym::IMPORT; + + if ( strcmp( type, "lab") == 0) + { + symType = sym::LABEL; + } + else if ( strcmp( type, "equ") == 0) + { + symType = sym::EQU; + } + + sym *s = new sym( id, name, size, value, symType ); + + auto it = scopeMap.find( scopeID ); + + if ( it != scopeMap.end() ) + { + //printf("Found Scope:%i for %s\n", scopeID, name ); + s->_scope = it->second; + } + + auto itSeg = segmentMap.find( segmentID ); + + if ( itSeg != segmentMap.end() ) + { + //printf("Found Segment:%i for %s\n", segmentID, name ); + s->_segment = itSeg->second; + } + symMap[id] = s; + } + } + } + } + ::fclose(fp); + + return 0; + } + //--------------------------------------------------------------------------------------------------- + int database::iterateSymbols( void *userData, void (*cb)( void *userData, sym *s ) ) + { + int numSyms = 0; + + for (auto it = symMap.begin(); it != symMap.end(); it++) + { + cb( userData, it->second ); + numSyms++; + } + return numSyms; + } + //--------------------------------------------------------------------------------------------------- +} diff --git a/src/ld65dbg.h b/src/ld65dbg.h new file mode 100644 index 0000000..fe6078c --- /dev/null +++ b/src/ld65dbg.h @@ -0,0 +1,139 @@ +// ld65dbg.h +// +#pragma once +#include +#include +#include + +namespace ld65 +{ + class database; + + class segment + { + public: + static constexpr unsigned char READ = 0x01; + static constexpr unsigned char WRITE = 0x02; + + segment( int id, const char *name = nullptr, int startAddr = 0, int size = 0, int ofs = -1, unsigned char type = READ ); + + const char *name(void){ return _name.c_str(); }; + + int addr(void){ return _startAddr; }; + + int ofs(void){ return _ofs; }; + + private: + std::string _name; // Segment Name + int _id; // Debug ID + int _startAddr; // Start Address CPU + int _size; // Memory region size + int _ofs; // ROM Offset + unsigned char _type; // ro or rw + + + friend class database; + }; + + class scope + { + public: + scope( int id, const char *name = nullptr, int size = 0, int parentID = -1); + + const char *name(void){ return _name.c_str(); }; + + scope *getParent(void){ return _parent; }; + + void getFullName( std::string &out ); + + private: + std::string _name; // Scope Name + int _id; // Debug ID + int _parentID; // Parent ID + int _size; + + scope *_parent; + + + friend class database; + }; + + class sym + { + public: + enum + { + IMPORT = 0, + LABEL, + EQU + }; + + sym( int id, const char *name = nullptr, int size = 0, int value = 0, int type = IMPORT); + + int id(void){ return _id; }; + + const char *name(void){ return _name.c_str(); }; + + int size(void){ return _size; }; + + int value(void){ return _value; }; + + int type(void){ return _type; }; + + scope *getScope(void){ return _scope; }; + + segment *getSegment(void){ return _segment; }; + + private: + std::string _name; // Scope Name + int _id; // Debug ID + int _size; + int _value; + int _type; + + scope *_scope; + segment *_segment; + + friend class database; + }; + + class database + { + public: + database(void); + ~database(void); + + int dbgFileLoad( const char *dbgFilePath ); + + int iterateSymbols( void *userData, void (*cb)( void *userData, sym *s ) ); + + private: + std::map scopeMap; + std::map segmentMap; + std::map symMap; + + class dbgLine + { + public: + dbgLine(size_t bufferSize = 1024); + ~dbgLine(void); + + const char *readFromFile( FILE *fp ); + + const char *getLine(void){ return buf; }; + + int readToken( char *tk, size_t tkSize ); + + int readKeyValuePair( char *keyValueBuffer, size_t keyValueBufferSize ); + + static int splitKeyValuePair( char *keyValueBuffer, char **keyPtr, char **valuePtr ); + + private: + void allocBuffer(size_t bufferSize); + + size_t readPtr; + size_t bufSize; + char *buf; + }; + }; +}; diff --git a/src/lua-engine.cpp b/src/lua-engine.cpp index 6aa16a5..6ca7a4b 100644 --- a/src/lua-engine.cpp +++ b/src/lua-engine.cpp @@ -26,7 +26,6 @@ #include "debug.h" #include "debugsymboltable.h" #include "sound.h" -#include "drawing.h" #include "state.h" #include "movie.h" #include "driver.h" @@ -319,10 +318,6 @@ static const char* luaMemHookTypeStrings [] = "MEMHOOK_WRITE", "MEMHOOK_READ", "MEMHOOK_EXEC", - - "MEMHOOK_WRITE_SUB", - "MEMHOOK_READ_SUB", - "MEMHOOK_EXEC_SUB", }; //make sure we have the right number of strings @@ -2431,53 +2426,17 @@ static int memory_registerHook(lua_State* L, LuaMemHookType hookType, int defaul return 0; } -LuaMemHookType MatchHookTypeToCPU(lua_State* L, LuaMemHookType hookType) -{ - int cpuID = 0; - - int cpunameIndex = 0; - if(lua_type(L,2) == LUA_TSTRING) - cpunameIndex = 2; - else if(lua_type(L,3) == LUA_TSTRING) - cpunameIndex = 3; - - if(cpunameIndex) - { - const char* cpuName = lua_tostring(L, cpunameIndex); - if(!stricmp(cpuName, "sub")) - cpuID = 1; - lua_remove(L, cpunameIndex); - } - - switch(cpuID) - { - case 0: - return hookType; - - case 1: - switch(hookType) - { - case LUAMEMHOOK_WRITE: return LUAMEMHOOK_WRITE_SUB; - case LUAMEMHOOK_READ: return LUAMEMHOOK_READ_SUB; - case LUAMEMHOOK_EXEC: return LUAMEMHOOK_EXEC_SUB; - default: return hookType; - } - } - return hookType; -} - static int memory_registerwrite(lua_State *L) { - return memory_registerHook(L, MatchHookTypeToCPU(L,LUAMEMHOOK_WRITE), 1); + return memory_registerHook(L, LUAMEMHOOK_WRITE, 1); } -FCEU_MAYBE_UNUSED static int memory_registerread(lua_State *L) { - return memory_registerHook(L, MatchHookTypeToCPU(L,LUAMEMHOOK_READ), 1); + return memory_registerHook(L, LUAMEMHOOK_READ, 1); } static int memory_registerexec(lua_State *L) { - return memory_registerHook(L, MatchHookTypeToCPU(L,LUAMEMHOOK_EXEC), 1); + return memory_registerHook(L, LUAMEMHOOK_EXEC, 1); } //adelikat: table pulled from GENS. credz nitsuja! @@ -6137,7 +6096,7 @@ static const struct luaL_reg memorylib [] = { // memory hooks {"registerwrite", memory_registerwrite}, - //{"registerread", memory_registerread}, TODO + {"registerread", memory_registerread}, {"registerexec", memory_registerexec}, // alternate names {"register", memory_registerwrite}, diff --git a/src/movie.cpp b/src/movie.cpp index e4721bd..f3d422d 100644 --- a/src/movie.cpp +++ b/src/movie.cpp @@ -984,23 +984,23 @@ bool MovieData::loadSaveramFrom(std::vector* buf) return false; } - for(int i=0;i<4;i++) + for (size_t i=0;iSaveGame.size();i++) { int len = ms.read32le(); - if(!currCartInfo->SaveGame[i] && len!=0) + if( (currCartInfo->SaveGame[i].bufptr == nullptr) && (len!=0) ) { FCEU_PrintError("movie battery load mismatch 2"); return false; } - if(currCartInfo->SaveGameLen[i] != static_cast(len)) + if(currCartInfo->SaveGame[i].buflen != static_cast(len)) { FCEU_PrintError("movie battery load mismatch 3"); return false; } - ms.fread(currCartInfo->SaveGame[i], len); + ms.fread(currCartInfo->SaveGame[i].bufptr, len); } return true; @@ -1011,16 +1011,15 @@ void MovieData::dumpSaveramTo(std::vector* buf, int compressionLevel) EMUFILE_MEMORY ms(buf); ms.write32le(currCartInfo->battery?1:0); - for(int i=0;i<4;i++) + for(size_t i=0;iSaveGame.size();i++) { - if(!currCartInfo->SaveGame[i]) + if (!currCartInfo->SaveGame[i].bufptr) { ms.write32le((u32)0); continue; } - - ms.write32le(currCartInfo->SaveGameLen[i]); - ms.fwrite(currCartInfo->SaveGame[i], currCartInfo->SaveGameLen[i]); + ms.write32le( static_cast(currCartInfo->SaveGame[i].buflen) ); + ms.fwrite(currCartInfo->SaveGame[i].bufptr, currCartInfo->SaveGame[i].buflen); } } @@ -1429,7 +1428,7 @@ int CheckTimelines(MovieData& stateMovie, MovieData& currMovie) } -static bool load_successful; +static bool load_successful = false; bool FCEUMOV_ReadState(EMUFILE* is, uint32 size) { diff --git a/src/ppu.cpp b/src/ppu.cpp index aa7502e..ce84a9d 100644 --- a/src/ppu.cpp +++ b/src/ppu.cpp @@ -1734,10 +1734,17 @@ void FCEUPPU_Reset(void) { void FCEUPPU_Power(void) { int x; - memset(NTARAM, 0x00, 0x800); - memset(PALRAM, 0x00, 0x20); - memset(UPALRAM, 0x00, 0x03); - memset(SPRAM, 0x00, 0x100); + // initialize PPU memory regions according to settings + FCEU_MemoryRand(NTARAM, 0x800, true); + FCEU_MemoryRand(PALRAM, 0x20, true); + FCEU_MemoryRand(SPRAM, 0x100, true); + // palettes can only store values up to $3F, and PALRAM X4/X8/XC are mirrors of X0 for rendering purposes (UPALRAM is used for $2007 readback) + for (x = 0; x < 0x20; ++x) PALRAM[x] &= 0x3F; + UPALRAM[0] = PALRAM[0x04]; + UPALRAM[1] = PALRAM[0x08]; + UPALRAM[2] = PALRAM[0x0C]; + PALRAM[0x0C] = PALRAM[0x08] = PALRAM[0x04] = PALRAM[0x00]; + PALRAM[0x1C] = PALRAM[0x18] = PALRAM[0x14] = PALRAM[0x10]; FCEUPPU_Reset(); for (x = 0x2000; x < 0x4000; x += 8) { diff --git a/src/profiler.cpp b/src/profiler.cpp new file mode 100644 index 0000000..077605c --- /dev/null +++ b/src/profiler.cpp @@ -0,0 +1,367 @@ +/* FCE Ultra - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2002 Xodnizel + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +// profiler.cpp +// +#ifdef __FCEU_PROFILER_ENABLE__ + +#include + +#ifdef __QT_DRIVER__ +#include +#endif + +#include "utils/mutex.h" +#include "fceu.h" +#include "profiler.h" + +namespace FCEU +{ +static thread_local profileExecVector execList; +static thread_local profilerFuncMap threadProfileMap; + +FILE *profilerManager::pLog = nullptr; + +static profilerManager pMgr; + +//------------------------------------------------------------------------- +//---- Function Profile Record +//------------------------------------------------------------------------- +funcProfileRecord::funcProfileRecord(const char *fileNameStringLiteral, + const int fileLineNumber, + const char *funcNameStringLiteral, + const char *commentStringLiteral) + + : fileLineNum(fileLineNumber), fileName(fileNameStringLiteral), + funcName(funcNameStringLiteral), comment(commentStringLiteral) +{ + min.fromSeconds(9); + max.zero(); + sum.zero(); + numCalls = 0; + recursionCount = 0; + + threadProfileMap.addRecord( fileNameStringLiteral, fileLineNumber, + funcNameStringLiteral, commentStringLiteral, this); +} +//------------------------------------------------------------------------- +void funcProfileRecord::reset(void) +{ + min.fromSeconds(9); + max.zero(); + sum.zero(); + numCalls = 0; +} +//------------------------------------------------------------------------- +double funcProfileRecord::average(void) +{ + double avg = 0.0; + + if (numCalls) + { + avg = sum.toSeconds() / static_cast(numCalls); + } + return avg; +} +//------------------------------------------------------------------------- +//---- Profile Scoped Function Class +//------------------------------------------------------------------------- +profileFuncScoped::profileFuncScoped( funcProfileRecord *recordIn ) +{ + rec = recordIn; + + if (rec) + { + threadProfileMap.pushStack(rec); + start.readNew(); + rec->numCalls++; + rec->recursionCount++; + } +} +//------------------------------------------------------------------------- +profileFuncScoped::~profileFuncScoped(void) +{ + if (rec) + { + timeStampRecord ts, dt; + ts.readNew(); + dt = ts - start; + + rec->last = dt; + rec->sum += dt; + if (dt < rec->min) rec->min = dt; + if (dt > rec->max) rec->max = dt; + + rec->recursionCount--; + + execList._vec.push_back(*rec); + + threadProfileMap.popStack(rec); + } +} +//------------------------------------------------------------------------- +//---- Profile Execution Vector +//------------------------------------------------------------------------- +profileExecVector::profileExecVector(void) +{ + _vec.reserve( 10000 ); + + char threadName[128]; + char fileName[256]; + + strcpy( threadName, "MainThread"); + +#ifdef __QT_DRIVER__ + QThread *thread = QThread::currentThread(); + + if (thread) + { + //printf("Thread: %s\n", thread->objectName().toStdString().c_str()); + strcpy( threadName, thread->objectName().toStdString().c_str()); + } +#endif + sprintf( fileName, "fceux-profile-%s.log", threadName); + + logFp = ::fopen(fileName, "w"); + + if (logFp == nullptr) + { + printf("Error: Failed to create profiler logfile: %s\n", fileName); + } +} +//------------------------------------------------------------------------- +profileExecVector::~profileExecVector(void) +{ + if (logFp) + { + ::fclose(logFp); + } +} +//------------------------------------------------------------------------- +void profileExecVector::update(void) +{ + size_t n = _vec.size(); + + for (size_t i=0; isecond; + // } + // _map.clear(); + //} +} +//------------------------------------------------------------------------- +void profilerFuncMap::pushStack(funcProfileRecord *rec) +{ + stack.push_back(rec); +} +//------------------------------------------------------------------------- +void profilerFuncMap::popStack(funcProfileRecord *rec) +{ + stack.pop_back(); +} +//------------------------------------------------------------------------- +int profilerFuncMap::addRecord(const char *fileNameStringLiteral, + const int fileLineNumber, + const char *funcNameStringLiteral, + const char *commentStringLiteral, + funcProfileRecord *rec ) +{ + autoScopedLock aLock(_mapMtx); + char lineString[64]; + + sprintf( lineString, ":%i", fileLineNumber); + + std::string fname(fileNameStringLiteral); + + fname.append( lineString ); + + _map[fname] = rec; + + return 0; +} +//------------------------------------------------------------------------- +funcProfileRecord *profilerFuncMap::findRecord(const char *fileNameStringLiteral, + const int fileLineNumber, + const char *funcNameStringLiteral, + const char *commentStringLiteral, + bool create) +{ + autoScopedLock aLock(_mapMtx); + char lineString[64]; + funcProfileRecord *rec = nullptr; + + sprintf( lineString, ":%i", fileLineNumber); + + std::string fname(fileNameStringLiteral); + + fname.append( lineString ); + + auto it = _map.find(fname); + + if (it != _map.end()) + { + rec = it->second; + } + else if (create) + { + fprintf( pMgr.pLog, "Creating Function Profile Record: %s %s\n", fname.c_str(), funcNameStringLiteral); + + rec = new funcProfileRecord( fileNameStringLiteral, fileLineNumber, + funcNameStringLiteral, commentStringLiteral); + + _map[fname] = rec; + } + return rec; +} +//------------------------------------------------------------------------- +funcProfileRecord *profilerFuncMap::iterateBegin(void) +{ + autoScopedLock aLock(_mapMtx); + funcProfileRecord *rec = nullptr; + + _map_it = _map.begin(); + + if (_map_it != _map.end()) + { + rec = _map_it->second; + } + return rec; +} +//------------------------------------------------------------------------- +funcProfileRecord *profilerFuncMap::iterateNext(void) +{ + autoScopedLock aLock(_mapMtx); + funcProfileRecord *rec = nullptr; + + if (_map_it != _map.end()) + { + _map_it++; + } + if (_map_it != _map.end()) + { + rec = _map_it->second; + } + return rec; +} +//------------------------------------------------------------------------- +//----- profilerManager class +//------------------------------------------------------------------------- +profilerManager* profilerManager::instance = nullptr; + +profilerManager* profilerManager::getInstance(void) +{ + return instance; +} +//------------------------------------------------------------------------- +profilerManager::profilerManager(void) +{ + //printf("profilerManager Constructor\n"); + if (pLog == nullptr) + { + pLog = stdout; + } + + if (instance == nullptr) + { + instance = this; + } +} + +profilerManager::~profilerManager(void) +{ + //printf("profilerManager Destructor\n"); + { + autoScopedLock aLock(threadListMtx); + threadList.clear(); + } + + if (pLog && (pLog != stdout)) + { + fclose(pLog); pLog = nullptr; + } + if (instance == this) + { + instance = nullptr; + } +} + +int profilerManager::addThreadProfiler( profilerFuncMap *m ) +{ + autoScopedLock aLock(threadListMtx); + threadList.push_back(m); + return 0; +} + +int profilerManager::removeThreadProfiler( profilerFuncMap *m, bool shouldDestroy ) +{ + int result = -1; + autoScopedLock aLock(threadListMtx); + + for (auto it = threadList.begin(); it != threadList.end(); it++) + { + if (*it == m ) + { + threadList.erase(it); + if (shouldDestroy) + { + delete m; + } + result = 0; + break; + } + } + return result; +} +//------------------------------------------------------------------------- +} // namespace FCEU + +//------------------------------------------------------------------------- +int FCEU_profiler_log_thread_activity(void) +{ + FCEU::execList.update(); + return 0; +} +#endif // __FCEU_PROFILER_ENABLE__ diff --git a/src/profiler.h b/src/profiler.h new file mode 100644 index 0000000..61b9f5a --- /dev/null +++ b/src/profiler.h @@ -0,0 +1,167 @@ +/* FCE Ultra - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2002 Xodnizel + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +// profiler.h + +#pragma once + +/* + * This module is intended for debug use only. This allows for high precision timing of function + * execution. This functionality is not included in the build unless __FCEU_PROFILER_ENABLE__ + * is defined. To check timing on a particular function, add FCEU_PROFILE_FUNC macro to the top + * of the function body in the following manner. + * FCEU_PROFILE_FUNC(prof, "String Literal comment, whatever I want it to say") + * When __FCEU_PROFILER_ENABLE__ is not defined, the FCEU_PROFILE_FUNC macro evaluates to nothing + * so it won't break the regular build by having it used in code. + */ +#ifdef __FCEU_PROFILER_ENABLE__ + +#include +#include +#include +#include +#include +#include + + +#if defined(__linux__) || defined(__APPLE__) || defined(__unix__) +#include +#endif + +#include "utils/mutex.h" +#include "utils/timeStamp.h" + +namespace FCEU +{ + struct funcProfileRecord + { + const int fileLineNum; + const char *fileName; + const char *funcName; + const char *comment; + + timeStampRecord min; + timeStampRecord max; + timeStampRecord sum; + timeStampRecord last; + unsigned int numCalls; + unsigned int recursionCount; + + funcProfileRecord(const char *fileNameStringLiteral, + const int fileLineNumber, + const char *funcNameStringLiteral, + const char *commentStringLiteral); + + void reset(void); + + double average(void); + }; + + struct profileFuncScoped + { + funcProfileRecord *rec; + timeStampRecord start; + + profileFuncScoped( funcProfileRecord *recordIn ); + + ~profileFuncScoped(void); + }; + + struct profileExecVector + { + profileExecVector(void); + ~profileExecVector(void); + + void update(void); + + std::vector _vec; + + FILE *logFp; + }; + + class profilerFuncMap + { + public: + profilerFuncMap(); + ~profilerFuncMap(); + + int addRecord(const char *fileNameStringLiteral, + const int fileLineNumber, + const char *funcNameStringLiteral, + const char *commentStringLiteral, + funcProfileRecord *rec ); + + funcProfileRecord *findRecord(const char *fileNameStringLiteral, + const int fileLineNumber, + const char *funcNameStringLiteral, + const char *commentStringLiteral, + bool create = false); + + funcProfileRecord *iterateBegin(void); + funcProfileRecord *iterateNext(void); + + void pushStack(funcProfileRecord *rec); + void popStack(funcProfileRecord *rec); + private: + mutex _mapMtx; + std::map _map; + std::map::iterator _map_it; + + std::vector stack; + }; + + class profilerManager + { + public: + profilerManager(void); + ~profilerManager(void); + + int addThreadProfiler( profilerFuncMap *m ); + int removeThreadProfiler( profilerFuncMap *m, bool shouldDestroy = false ); + + static FILE *pLog; + + static profilerManager *getInstance(); + private: + + mutex threadListMtx; + std::list threadList; + static profilerManager *instance; + }; +} + +#if defined(__PRETTY_FUNCTION__) +#define __FCEU_PROFILE_FUNC_NAME__ __PRETTY_FUNCTION__ +#else +#define __FCEU_PROFILE_FUNC_NAME__ __func__ +#endif + +#define FCEU_PROFILE_FUNC(id, comment) \ + static thread_local FCEU::funcProfileRecord id( __FILE__, __LINE__, __FCEU_PROFILE_FUNC_NAME__, comment ); \ + FCEU::profileFuncScoped id ## _unique_scope( &id ) + + +int FCEU_profiler_log_thread_activity(void); + +#else // __FCEU_PROFILER_ENABLE__ not defined + +#define FCEU_PROFILE_FUNC(id, comment) + +#endif // __FCEU_PROFILER_ENABLE__ + diff --git a/src/state.cpp b/src/state.cpp index 27eff79..622168a 100644 --- a/src/state.cpp +++ b/src/state.cpp @@ -84,9 +84,9 @@ bool backupSavestates = true; bool compressSavestates = true; //By default FCEUX compresses savestates when a movie is inactive. // a temp memory stream. We'll be dumping some data here and then compress -EMUFILE_MEMORY memory_savestate; +static EMUFILE_MEMORY memory_savestate; // temporary buffer for compressed data of a savestate -std::vector compressed_buf; +static std::vector compressed_buf; #define SFMDATA_SIZE (128) static SFORMAT SFMDATA[SFMDATA_SIZE]; @@ -152,7 +152,7 @@ static int SubWrite(EMUFILE* os, SFORMAT *sf) os->fwrite(sf->desc,4); write32le(sf->s&(~FCEUSTATE_FLAGS),os); -#ifndef LSB_FIRST +#ifdef FCEU_BIG_ENDIAN if(sf->s&RLSB) FlipByteOrder((uint8*)sf->v,sf->s&(~FCEUSTATE_FLAGS)); #endif @@ -163,7 +163,7 @@ static int SubWrite(EMUFILE* os, SFORMAT *sf) os->fwrite((char*)sf->v,sf->s&(~FCEUSTATE_FLAGS)); //Now restore the original byte order. -#ifndef LSB_FIRST +#ifdef FCEU_BIG_ENDIAN if(sf->s&RLSB) FlipByteOrder((uint8*)sf->v,sf->s&(~FCEUSTATE_FLAGS)); #endif @@ -231,7 +231,7 @@ static bool ReadStateChunk(EMUFILE* is, SFORMAT *sf, int size) else is->fread((char *)tmp->v,tmp->s&(~FCEUSTATE_FLAGS)); -#ifndef LSB_FIRST +#ifdef FCEU_BIG_ENDIAN if(tmp->s&RLSB) FlipByteOrder((uint8*)tmp->v,tmp->s&(~FCEUSTATE_FLAGS)); #endif @@ -1179,3 +1179,389 @@ void RedoLoadState() redoLS = false; //Flag that RedoLoadState can not be run again undoLS = true; //Flag that LoadBackup can be run again } + +//----------------------------------------------------------------------------------------------------- +//----------------------------------------------------------------------------------------------------- +//----------- Save State History ---------------- +//----------------------------------------------------------------------------------------------------- +//----------------------------------------------------------------------------------------------------- +static StateRecorderConfigData stateRecorderConfig; + +class StateRecorder +{ + public: + StateRecorder(void) + { + loadConfig( stateRecorderConfig ); + + for (int i=0; i config.historyDurationMinutes) + { + config.historyDurationMinutes = config.timeBetweenSnapsMinutes; + } + + if (config.timingMode) + { + const double fhistMin = config.historyDurationMinutes; + const double fsnapMin = config.timeBetweenSnapsMinutes; + const double fnumSnaps = fhistMin / fsnapMin; + + ringBufSize = static_cast( fnumSnaps + 0.5f ); + + int32_t fps = FCEUI_GetDesiredFPS(); // Do >> 24 to get in Hz + + double hz = ( ((double)fps) / 16777216.0 ); + + double framesPerSnapf = hz * fsnapMin * 60.0; + + framesPerSnap = static_cast( framesPerSnapf + 0.50 ); + } + else + { + const double fhistMin = config.historyDurationMinutes; + int32_t fps = FCEUI_GetDesiredFPS(); // Do >> 24 to get in Hz + double hz = ( ((double)fps) / 16777216.0 ); + + const double fsnapMin = static_cast(config.framesBetweenSnaps) / (hz * 60.0); + const double fnumSnaps = fhistMin / fsnapMin; + + ringBufSize = static_cast( fnumSnaps + 0.5f ); + framesPerSnap = config.framesBetweenSnaps; + } + + printf("ringBufSize:%i framesPerSnap:%i\n", ringBufSize, framesPerSnap ); + + compressionLevel = config.compressionLevel; + loadPauseTime = config.loadPauseTimeSeconds; + pauseOnLoad = config.pauseOnLoad; + } + + void update(void) + { + bool isPaused = EmulationPaused ? true : false; + + unsigned int curFrame = static_cast(currFrameCounter); + + if (!isPaused && loadIndexReset) + { + ringHead = (lastState + 1) % ringBufSize; + + frameCounter = curFrame; + + loadIndexReset = false; + } + + if (!isPaused && (curFrame > frameCounter) ) + { + frameCounter = curFrame; + + if ( (frameCounter % framesPerSnap) == 0 ) + { + EMUFILE_MEMORY *em = ringBuf[ ringHead ]; + + em->set_len(0); + + FCEUSS_SaveMS( em, compressionLevel ); + + //printf("Frame:%u Save:%i Size:%zu Total:%zukB \n", frameCounter, ringHead, em->size(), dataSize() / 1024 ); + + lastState = ringHead; + + ringHead = (ringHead + 1) % ringBufSize; + + if (ringStart == ringHead) + { + ringStart = (ringHead + 1) % ringBufSize; + } + } + } + } + + int loadStateRelativeToEnd( int numSnapsFromLatest ) + { + if (numSnapsFromLatest < 0) + { + numSnapsFromLatest = 0; + } + numSnapsFromLatest = numSnapsFromLatest % ringBufSize; + + int snapIdx = ringHead - numSnapsFromLatest - 1; + + loadStateByIndex(snapIdx); + + return 0; + } + + int loadStateByIndex( int snapIdx ) + { + if (snapIdx < 0) + { + snapIdx = snapIdx + ringBufSize; + } + snapIdx = snapIdx % ringBufSize; + + EMUFILE_MEMORY *em = ringBuf[ snapIdx ]; + + em->fseek(SEEK_SET, 0); + + FCEUSS_LoadFP( em, SSLOADPARAM_NOBACKUP ); + + frameCounter = lastLoadFrame = static_cast(currFrameCounter); + + lastState = snapIdx; + loadIndexReset = true; + + if (pauseOnLoad == StateRecorderConfigData::TEMPORARY_PAUSE) + { + if (loadPauseTime > 0) + { // Temporary pause after loading new state for user to have time to process + FCEUI_PauseForDuration(loadPauseTime); + } + } + else if (pauseOnLoad == StateRecorderConfigData::FULL_PAUSE) + { + FCEUI_SetEmulationPaused( EMULATIONPAUSED_PAUSED ); + } + return 0; + } + + int loadPrevState(void) + { + int snapIdx = lastState; + + if ( lastState == ringHead ) + { // No States to Load + return -1; + } + if ( lastState != ringStart ) + { + if ( (lastLoadFrame+30) > frameCounter) + { + snapIdx--; + + if (snapIdx < 0) + { + snapIdx += ringBufSize; + } + } + } + return loadStateByIndex( snapIdx ); + } + + int loadNextState(void) + { + int snapIdx = lastState; + int nextIdx = (lastState + 1) % ringBufSize; + + if ( nextIdx != ringHead ) + { + snapIdx = nextIdx; + } + return loadStateByIndex( snapIdx ); + } + + int getHeadIndex(void) + { + return ringHead; + } + + int getStartIndex(void) + { + return ringStart; + } + + int numSnapsSaved(void) + { + int numSnaps = ringHead - ringStart; + + if (numSnaps < 0) + { + numSnaps = numSnaps + static_cast( ringBuf.size() ); + } + return numSnaps; + } + + size_t dataSize(void) + { + return ringBuf.size() * ringBuf[0]->size(); + } + + size_t ringBufferSize(void) + { + return ringBuf.size(); + } + static bool enabled; + static int lastState; + private: + + void doSnap(void) + { + + } + + std::vector ringBuf; + int ringHead; + int ringTail; + int ringStart; + int ringBufSize; + int compressionLevel; + int loadPauseTime; + StateRecorderConfigData::PauseType pauseOnLoad; + unsigned int frameCounter; + unsigned int framesPerSnap; + unsigned int lastLoadFrame; + bool loadIndexReset; + +}; + +static StateRecorder *stateRecorder = nullptr; +bool StateRecorder::enabled = false; +int StateRecorder::lastState = 0; + +int FCEU_StateRecorderStart(void) +{ + if (stateRecorder == nullptr) + { + stateRecorder = new StateRecorder(); + } + return stateRecorder == nullptr; +} + +int FCEU_StateRecorderStop(void) +{ + if (stateRecorder != nullptr) + { + delete stateRecorder; stateRecorder = nullptr; + } + return stateRecorder != nullptr; +} + +int FCEU_StateRecorderUpdate(void) +{ + if (stateRecorder != nullptr) + { + stateRecorder->update(); + } + return 0; +} + +bool FCEU_StateRecorderIsEnabled(void) +{ + return StateRecorder::enabled; +} + +void FCEU_StateRecorderSetEnabled(bool enabled) +{ + StateRecorder::enabled = enabled; +} + +bool FCEU_StateRecorderRunning(void) +{ + return stateRecorder != nullptr; +} + +int FCEU_StateRecorderGetMaxSnaps(void) +{ + int size = 0; + + if (stateRecorder != nullptr) + { + size = stateRecorder->ringBufferSize(); + } + return size; +} + +int FCEU_StateRecorderGetNumSnapsSaved(void) +{ + int n = 0; + + if (stateRecorder != nullptr) + { + n = stateRecorder->numSnapsSaved(); + } + return n; +} + +int FCEU_StateRecorderLoadState(int snapIndex) +{ + int ret = -1; + + if (stateRecorder != nullptr) + { + ret = stateRecorder->loadStateByIndex(snapIndex); + } + return ret; +} + +int FCEU_StateRecorderGetStateIndex(void) +{ + return StateRecorder::lastState; +} + +int FCEU_StateRecorderLoadPrevState(void) +{ + int ret = -1; + + if (stateRecorder != nullptr) + { + ret = stateRecorder->loadPrevState(); + } + return ret; +} + +int FCEU_StateRecorderLoadNextState(void) +{ + int ret = -1; + + if (stateRecorder != nullptr) + { + ret = stateRecorder->loadNextState(); + } + return ret; +} + +const StateRecorderConfigData& FCEU_StateRecorderGetConfigData(void) +{ + return stateRecorderConfig; +} +int FCEU_StateRecorderSetConfigData(const StateRecorderConfigData &newConfig) +{ + stateRecorderConfig = newConfig; + + if (stateRecorder != nullptr) + { + stateRecorder->loadConfig( stateRecorderConfig ); + } + return 0; +} diff --git a/src/state.h b/src/state.h index 4157dc9..705d7e8 100644 --- a/src/state.h +++ b/src/state.h @@ -17,6 +17,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#pragma once #include enum ENUM_SSLOADPARAMS @@ -78,3 +79,56 @@ extern bool backupSavestates; //Whether or not to make backups, true by defaul bool CheckBackupSaveStateExist(); //Checks if backupsavestate exists extern bool compressSavestates; //Whether or not to compress non-movie savestates (by default, yes) + +struct StateRecorderConfigData +{ + float historyDurationMinutes; + float timeBetweenSnapsMinutes; + int framesBetweenSnaps; + int compressionLevel; + int loadPauseTimeSeconds; + + enum TimingType + { + FRAMES = 0, + TIME, + } timingMode; + + enum PauseType + { + NO_PAUSE = 0, + TEMPORARY_PAUSE, + FULL_PAUSE, + } pauseOnLoad; + + StateRecorderConfigData(void) + { + framesBetweenSnaps = 60; + historyDurationMinutes = 15.0f; + timeBetweenSnapsMinutes = 3.0f / 60.0f; + compressionLevel = 0; + loadPauseTimeSeconds = 3; + pauseOnLoad = TEMPORARY_PAUSE; + timingMode = FRAMES; + } + + bool compare( const StateRecorderConfigData &other ) + { + return memcmp( this, &other, sizeof(StateRecorderConfigData) ) == 0; + } +}; + +int FCEU_StateRecorderStart(void); +int FCEU_StateRecorderStop(void); +int FCEU_StateRecorderUpdate(void); +bool FCEU_StateRecorderRunning(void); +bool FCEU_StateRecorderIsEnabled(void); +void FCEU_StateRecorderSetEnabled(bool enabled); +int FCEU_StateRecorderGetMaxSnaps(void); +int FCEU_StateRecorderGetNumSnapsSaved(void); +int FCEU_StateRecorderGetStateIndex(void); +int FCEU_StateRecorderLoadState(int snapIndex); +int FCEU_StateRecorderLoadPrevState(void); +int FCEU_StateRecorderLoadNextState(void); +int FCEU_StateRecorderSetConfigData(const StateRecorderConfigData &newConfig); +const StateRecorderConfigData& FCEU_StateRecorderGetConfigData(void); diff --git a/src/types.h b/src/types.h index f82d89d..61ab0bf 100644 --- a/src/types.h +++ b/src/types.h @@ -22,6 +22,9 @@ #ifndef __FCEU_TYPES #define __FCEU_TYPES +#include +#include + //enables a hack designed for debugging dragon warrior 3 which treats BRK as a 3-byte opcode //#define BRK_3BYTE_HACK @@ -182,24 +185,28 @@ typedef uint8 (*readfunc)(uint32 A); // Scoped pointer ensures that memory pointed to by this object gets cleaned up // and deallocated when this object goes out of scope. Helps prevent memory leaks // on temporary memory allocations in functions with early outs. +enum fceuAllocType +{ + FCEU_ALLOC_TYPE_NEW = 0, + FCEU_ALLOC_TYPE_NEW_ARRAY, + FCEU_ALLOC_TYPE_MALLOC +}; + template class fceuScopedPtr { public: - fceuScopedPtr( T *ptrIn = nullptr ) + fceuScopedPtr( T *ptrIn = nullptr, enum fceuAllocType allocType = FCEU_ALLOC_TYPE_NEW ) { //printf("Scoped Pointer Constructor <%s>: %p\n", typeid(T).name(), ptrIn ); ptr = ptrIn; + _allocType = allocType; } ~fceuScopedPtr(void) { //printf("Scoped Pointer Destructor <%s>: %p\n", typeid(T).name(), ptr ); - if (ptr) - { - delete ptr; - ptr = nullptr; - } + Delete(); } T* operator= (T *ptrIn) @@ -217,13 +224,32 @@ class fceuScopedPtr { if (ptr) { - delete ptr; + switch (_allocType) + { + case FCEU_ALLOC_TYPE_MALLOC: + { + ::free(ptr); + } + break; + case FCEU_ALLOC_TYPE_NEW_ARRAY: + { + delete [] ptr; + } + break; + default: + case FCEU_ALLOC_TYPE_NEW: + { + delete ptr; + } + break; + } ptr = nullptr; } } private: T *ptr; + enum fceuAllocType _allocType; }; diff --git a/src/unif.cpp b/src/unif.cpp index be20535..e47a8c5 100644 --- a/src/unif.cpp +++ b/src/unif.cpp @@ -104,7 +104,7 @@ static void ResetUNIF(void) { vramo = 0; boardname = 0; mirrortodo = 0; - memset(&UNIFCart, 0, sizeof(UNIFCart)); + UNIFCart.clear(); UNIFchrrama = 0; } @@ -475,7 +475,8 @@ static BMAPPING bmap[] = { { "FNS", FNS_Init, BMCFLAG_16KCHRR }, { "BS-400R", BS400R_Init, 0 }, { "BS-4040R", BS4040R_Init, 0 }, - { "COOLGIRL", COOLGIRL_Init, 0 }, + { "COOLGIRL", COOLGIRL_Init, BMCFLAG_256KCHRR }, + { "JC-016-2", Mapper205_Init, 0 }, { 0, 0, 0 } }; diff --git a/src/utils/endian.cpp b/src/utils/endian.cpp index 56704d4..477f84b 100644 --- a/src/utils/endian.cpp +++ b/src/utils/endian.cpp @@ -28,8 +28,11 @@ #include "endian.h" #include "../emufile.h" -//OMG ! configure this correctly +#ifdef FCEU_BIG_ENDIAN +#define LOCAL_BE +#else #define LOCAL_LE +#endif /* little endian to local endianess convert macros */ #ifdef LOCAL_BE /* local arch is big endian */ @@ -121,7 +124,7 @@ int read32le(uint32 *Bufo, FILE *fp) uint32 buf; if(fread(&buf,1,4,fp)<4) return 0; -#ifdef LSB_FIRST +#ifdef FCEU_LITTLE_ENDIAN *(uint32*)Bufo=buf; #else *(uint32*)Bufo=((buf&0xFF)<<24)|((buf&0xFF00)<<8)|((buf&0xFF0000)>>8)|((buf&0xFF000000)>>24); @@ -134,7 +137,7 @@ int read16le(uint16 *Bufo, std::istream *is) uint16 buf; if(is->read((char*)&buf,2).gcount() != 2) return 0; -#ifdef LSB_FIRST +#ifdef FCEU_LITTLE_ENDIAN *Bufo=buf; #else *Bufo = FCEU_de16lsb((uint8*)&buf); @@ -148,7 +151,7 @@ int read64le(uint64 *Bufo, std::istream *is) uint64 buf; if(is->read((char*)&buf,8).gcount() != 8) return 0; -#ifdef LSB_FIRST +#ifdef FCEU_LITTLE_ENDIAN *Bufo=buf; #else *Bufo = FCEU_de64lsb((uint8*)&buf); @@ -162,7 +165,7 @@ int read32le(uint32 *Bufo, std::istream *is) uint32 buf; if(is->read((char*)&buf,4).gcount() != 4) return 0; -#ifdef LSB_FIRST +#ifdef FCEU_LITTLE_ENDIAN *(uint32*)Bufo=buf; #else *(uint32*)Bufo=((buf&0xFF)<<24)|((buf&0xFF00)<<8)|((buf&0xFF0000)>>8)|((buf&0xFF000000)>>24); @@ -173,7 +176,7 @@ int read32le(uint32 *Bufo, std::istream *is) ///reads a little endian 16bit value from the specified file int read16le(char *d, FILE *fp) { -#ifdef LSB_FIRST +#ifdef FCEU_LITTLE_ENDIAN return((fread(d,1,2,fp)<2)?0:2); #else int ret; diff --git a/src/utils/endian.h b/src/utils/endian.h index 5bdbcde..3cbbe42 100644 --- a/src/utils/endian.h +++ b/src/utils/endian.h @@ -107,5 +107,13 @@ int writele(T *Bufo, EMUFILE*os) } } +#ifdef __BIG_ENDIAN__ +# define FCEU_BIG_ENDIAN +#elif defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) +# define FCEU_BIG_ENDIAN +#else +# define FCEU_LITTLE_ENDIAN +#endif + #endif //__FCEU_ENDIAN diff --git a/src/utils/memory.cpp b/src/utils/memory.cpp index a702311..f7e22c4 100644 --- a/src/utils/memory.cpp +++ b/src/utils/memory.cpp @@ -53,7 +53,7 @@ void FCEU_afree(void* ptr) #endif } -static void *_FCEU_malloc(uint32 size) +static void *_FCEU_malloc(size_t size) { void* ret = malloc(size); @@ -68,7 +68,7 @@ static void _FCEU_free(void* ptr) free(ptr); } -void *FCEU_gmalloc(uint32 size) +void *FCEU_gmalloc(size_t size) { void *ret = _FCEU_malloc(size); @@ -78,7 +78,7 @@ void *FCEU_gmalloc(uint32 size) return ret; } -void *FCEU_malloc(uint32 size) +void *FCEU_malloc(size_t size) { void *ret = _FCEU_malloc(size); memset(ret, 0, size); @@ -95,7 +95,7 @@ void FCEU_free(void *ptr) _FCEU_free(ptr); } -void *FCEU_dmalloc(uint32 size) +void *FCEU_dmalloc(size_t size) { return FCEU_malloc(size); } diff --git a/src/utils/memory.h b/src/utils/memory.h index 4fd97d9..d0ee446 100644 --- a/src/utils/memory.h +++ b/src/utils/memory.h @@ -25,11 +25,11 @@ #define FCEU_dwmemset(d,c,n) {int _x; for(_x=n-4;_x>=0;_x-=4) *(uint32 *)&(d)[_x]=c;} //returns a buffer initialized to 0 -void *FCEU_malloc(uint32 size); +void *FCEU_malloc(size_t size); //returns a buffer, with jumbled initial contents //used by boards for WRAM etc, initialized to 0 (default) or other via RAMInitOption -void *FCEU_gmalloc(uint32 size); +void *FCEU_gmalloc(size_t size); //free memory allocated with FCEU_gmalloc void FCEU_gfree(void *ptr); @@ -48,7 +48,7 @@ void FCEU_free(void *ptr); void* FCEU_realloc(void* ptr, size_t size); //don't use these. change them if you find them. -void *FCEU_dmalloc(uint32 size); +void *FCEU_dmalloc(size_t size); //don't use these. change them if you find them. void FCEU_dfree(void *ptr); diff --git a/src/utils/mutex.cpp b/src/utils/mutex.cpp index 0556ea0..60376a4 100644 --- a/src/utils/mutex.cpp +++ b/src/utils/mutex.cpp @@ -60,6 +60,15 @@ autoScopedLock::autoScopedLock( mutex *mtx ) } } +autoScopedLock::autoScopedLock( mutex &mtx ) +{ + m = &mtx; + if (m) + { + m->lock(); + } +} + autoScopedLock::~autoScopedLock(void) { if (m) diff --git a/src/utils/mutex.h b/src/utils/mutex.h index 721bf24..e7a2968 100644 --- a/src/utils/mutex.h +++ b/src/utils/mutex.h @@ -1,4 +1,5 @@ // mutex.h +#pragma once #ifdef __QT_DRIVER__ #include @@ -32,6 +33,7 @@ namespace FCEU { public: autoScopedLock( mutex *mtx ); + autoScopedLock( mutex &mtx ); ~autoScopedLock(void); private: diff --git a/src/utils/timeStamp.cpp b/src/utils/timeStamp.cpp new file mode 100644 index 0000000..f62d019 --- /dev/null +++ b/src/utils/timeStamp.cpp @@ -0,0 +1,117 @@ +// timeStamp.cpp +#include + +#include "timeStamp.h" + +#if defined(__linux__) || defined(__APPLE__) || defined(__unix__) +#include +#endif + +#if defined(WIN32) +#include +#endif + +//------------------------------------------------------------------------- +//---- Time Stamp Record +//------------------------------------------------------------------------- +#if defined(WIN32) +#include +#pragma intrinsic(__rdtsc) +#else +#include +#endif + +static uint64_t rdtsc() +{ + return __rdtsc(); +} + +namespace FCEU +{ + +uint64_t timeStampRecord::_tscFreq = 0; +#if defined(WIN32) +uint64_t timeStampRecord::qpcFreq = 0; +#endif + +void timeStampRecord::readNew(void) +{ +#if defined(__linux__) || defined(__APPLE__) || defined(__unix__) + clock_gettime( CLOCK_REALTIME, &ts ); +#else + QueryPerformanceCounter((LARGE_INTEGER*)&ts); +#endif + tsc = rdtsc(); +} +#if defined(WIN32) +void timeStampRecord::qpcCalibrate(void) +{ + if (QueryPerformanceFrequency((LARGE_INTEGER*)&timeStampRecord::qpcFreq) == 0) + { + printf("QueryPerformanceFrequency FAILED!\n"); + } +} +#endif + +class timeStampModule +{ + public: + timeStampModule(void) + { + printf("timeStampModuleInit\n"); + #if defined(WIN32) + timeStampRecord::qpcCalibrate(); + #endif + } +}; + +static timeStampModule module; + +bool timeStampModuleInitialized(void) +{ +#if defined(WIN32) + bool initialized = timeStampRecord::countFreq() != 0; +#else + bool initialized = true; +#endif + return initialized; +} + +void timeStampRecord::tscCalibrate(int numSamples) +{ + timeStampRecord t1, t2, td; + uint64_t td_sum = 0; + double td_avg; + +#if defined(WIN32) + if (QueryPerformanceFrequency((LARGE_INTEGER*)&timeStampRecord::qpcFreq) == 0) + { + printf("QueryPerformanceFrequency FAILED!\n"); + } +#endif + printf("Running TSC Calibration: %i sec...\n", numSamples); + + for (int i=0; i(td_sum); + + timeStampRecord::_tscFreq = static_cast( td_avg / td.toSeconds() ); + + printf("%i Calibration: %f sec TSC:%llu TSC Freq: %f MHz\n", i, td.toSeconds(), + static_cast(td.tsc), static_cast(timeStampRecord::_tscFreq) * 1.0e-6 ); + } +} + +} // namespace FCEU diff --git a/src/utils/timeStamp.h b/src/utils/timeStamp.h new file mode 100644 index 0000000..c4ba96f --- /dev/null +++ b/src/utils/timeStamp.h @@ -0,0 +1,384 @@ +// timeStamp.h +#pragma once + +#include + +#if defined(__linux__) || defined(__APPLE__) || defined(__unix__) +#include +#endif + +namespace FCEU +{ + class timeStampRecord + { + public: + static constexpr uint64_t ONE_SEC_TO_MILLI = 1000; + +#if defined(__linux__) || defined(__APPLE__) || defined(__unix__) + static constexpr long int ONE_SEC_TO_NANO = 1000000000; + static constexpr long int MILLI_TO_NANO = 1000000; + + timeStampRecord(void) + { + ts.tv_sec = 0; + ts.tv_nsec = 0; + tsc = 0; + } + + timeStampRecord& operator = (const timeStampRecord& in) + { + ts = in.ts; + tsc = in.tsc; + return *this; + } + + timeStampRecord& operator += (const timeStampRecord& op) + { + ts.tv_sec += op.ts.tv_sec; + ts.tv_nsec += op.ts.tv_nsec; + + if (ts.tv_nsec >= ONE_SEC_TO_NANO) + { + ts.tv_nsec -= ONE_SEC_TO_NANO; + ts.tv_sec++; + } + tsc += op.tsc; + return *this; + } + + timeStampRecord operator + (const timeStampRecord& op) + { + timeStampRecord res; + + res.ts.tv_sec = ts.tv_sec + op.ts.tv_sec; + res.ts.tv_nsec = ts.tv_nsec + op.ts.tv_nsec; + + if (res.ts.tv_nsec >= ONE_SEC_TO_NANO) + { + res.ts.tv_nsec -= ONE_SEC_TO_NANO; + res.ts.tv_sec++; + } + res.tsc = tsc + op.tsc; + return res; + } + + timeStampRecord operator - (const timeStampRecord& op) + { + timeStampRecord res; + + res.ts.tv_sec = ts.tv_sec - op.ts.tv_sec; + res.ts.tv_nsec = ts.tv_nsec - op.ts.tv_nsec; + + if (res.ts.tv_nsec < 0) + { + res.ts.tv_nsec += ONE_SEC_TO_NANO; + res.ts.tv_sec--; + } + res.tsc = tsc - op.tsc; + + return res; + } + + timeStampRecord operator * (const unsigned int multiplier) + { + timeStampRecord res; + + res.ts.tv_sec = ts.tv_sec * multiplier; + res.ts.tv_nsec = ts.tv_nsec * multiplier; + + if (res.ts.tv_nsec >= ONE_SEC_TO_NANO) + { + res.ts.tv_nsec -= ONE_SEC_TO_NANO; + res.ts.tv_sec++; + } + res.tsc = tsc * multiplier; + + return res; + } + + timeStampRecord operator / (const unsigned int divisor) + { + timeStampRecord res; + + res.ts.tv_sec = ts.tv_sec / divisor; + res.ts.tv_nsec = ts.tv_nsec / divisor; + res.tsc = tsc / divisor; + + return res; + } + + bool operator > (const timeStampRecord& op) + { + bool res; + if (ts.tv_sec == op.ts.tv_sec) + { + res = (ts.tv_nsec > op.ts.tv_nsec); + } + else + { + res = (ts.tv_sec > op.ts.tv_sec); + } + return res; + } + bool operator >= (const timeStampRecord& op) + { + bool res; + if (ts.tv_sec == op.ts.tv_sec) + { + res = (ts.tv_nsec >= op.ts.tv_nsec); + } + else + { + res = (ts.tv_sec >= op.ts.tv_sec); + } + return res; + } + + bool operator < (const timeStampRecord& op) + { + bool res; + if (ts.tv_sec == op.ts.tv_sec) + { + res = (ts.tv_nsec < op.ts.tv_nsec); + } + else + { + res = (ts.tv_sec < op.ts.tv_sec); + } + return res; + } + bool operator <= (const timeStampRecord& op) + { + bool res; + if (ts.tv_sec == op.ts.tv_sec) + { + res = (ts.tv_nsec <= op.ts.tv_nsec); + } + else + { + res = (ts.tv_sec <= op.ts.tv_sec); + } + return res; + } + + void zero(void) + { + ts.tv_sec = 0; + ts.tv_nsec = 0; + tsc = 0; + } + + bool isZero(void) + { + return (ts.tv_sec == 0) && (ts.tv_nsec == 0); + } + + void fromSeconds(unsigned int sec) + { + ts.tv_sec = sec; + ts.tv_nsec = 0; + tsc = 0; + } + + void fromSeconds(double sec) + { + double ns; + ts.tv_sec = static_cast(sec); + ns = (sec - static_cast(ts.tv_sec)) * 1.0e9; + ts.tv_nsec = static_cast(ns); + tsc = 0; + } + + double toSeconds(void) + { + double sec = static_cast(ts.tv_sec) + ( static_cast(ts.tv_nsec) * 1.0e-9 ); + return sec; + } + + void fromMilliSeconds(uint64_t ms) + { + ts.tv_sec = ms / ONE_SEC_TO_MILLI; + ts.tv_nsec = (ms * MILLI_TO_NANO) - (ts.tv_sec * ONE_SEC_TO_NANO); + } + + uint64_t toMilliSeconds(void) + { + uint64_t ms = (ts.tv_sec * ONE_SEC_TO_MILLI) + (ts.tv_nsec / MILLI_TO_NANO ); + return ms; + } + + uint64_t toCounts(void) + { + return (ts.tv_sec * ONE_SEC_TO_NANO) + ts.tv_nsec; + } + + static uint64_t countFreq(void) + { + return ONE_SEC_TO_NANO; + } + + struct timespec toTimeSpec(void) + { + return ts; + } +#else // WIN32 + + timeStampRecord(void) + { + ts = 0; + tsc = 0; + } + + timeStampRecord& operator = (const timeStampRecord& in) + { + ts = in.ts; + tsc = in.tsc; + return *this; + } + + timeStampRecord& operator += (const timeStampRecord& op) + { + ts += op.ts; + tsc += op.tsc; + return *this; + } + + timeStampRecord operator + (const timeStampRecord& op) + { + timeStampRecord res; + + res.ts = ts + op.ts; + res.tsc = tsc + op.tsc; + return res; + } + + timeStampRecord operator - (const timeStampRecord& op) + { + timeStampRecord res; + + res.ts = ts - op.ts; + res.tsc = tsc - op.tsc; + + return res; + } + + timeStampRecord operator * (const unsigned int multiplier) + { + timeStampRecord res; + + res.ts = ts * multiplier; + res.tsc = tsc * multiplier; + + return res; + } + + timeStampRecord operator / (const unsigned int divisor) + { + timeStampRecord res; + + res.ts = ts / divisor; + res.tsc = tsc / divisor; + + return res; + } + + bool operator > (const timeStampRecord& op) + { + return ts > op.ts; + } + bool operator >= (const timeStampRecord& op) + { + return ts >= op.ts; + } + + bool operator < (const timeStampRecord& op) + { + return ts < op.ts; + } + bool operator <= (const timeStampRecord& op) + { + return ts <= op.ts; + } + + void zero(void) + { + ts = 0; + tsc = 0; + } + + bool isZero(void) + { + return (ts == 0); + } + + + void fromSeconds(unsigned int sec) + { + ts = sec * qpcFreq; + tsc = 0; + } + + void fromSeconds(double sec) + { + ts = static_cast(sec * static_cast(qpcFreq)); + tsc = 0; + } + + double toSeconds(void) + { + double sec = static_cast(ts) / static_cast(qpcFreq); + return sec; + } + + void fromMilliSeconds(uint64_t ms) + { + ts = (ms * qpcFreq) / ONE_SEC_TO_MILLI; + } + + uint64_t toMilliSeconds(void) + { + uint64_t ms = (ts * ONE_SEC_TO_MILLI) / qpcFreq; + return ms; + } + + uint64_t toCounts(void) + { + return ts; + } + + static uint64_t countFreq(void) + { + return qpcFreq; + } + + static void qpcCalibrate(void); +#endif + + uint64_t getTSC(void){ return tsc; }; + + static uint64_t tscFreq(void) + { + return _tscFreq; + } + static bool tscValid(void){ return _tscFreq != 0; }; + + // Call this function to calibrate the estimated TSC frequency + static void tscCalibrate(int numSamples = 0); + + void readNew(void); + + private: +#if defined(__linux__) || defined(__APPLE__) || defined(__unix__) + struct timespec ts; +#else // Win32 + uint64_t ts; + static uint64_t qpcFreq; +#endif + uint64_t tsc; + static uint64_t _tscFreq; + }; + + bool timeStampModuleInitialized(void); + +} // namespace FCEU + diff --git a/src/version.h b/src/version.h index 01c9daa..c810c1f 100644 --- a/src/version.h +++ b/src/version.h @@ -62,14 +62,14 @@ #define FCEU_VERSION_MAJOR 2 #define FCEU_VERSION_MINOR 6 -#define FCEU_VERSION_PATCH 5 +#define FCEU_VERSION_PATCH 6 #define FCEU_VERSION_NUMERIC ( (FCEU_VERSION_MAJOR*10000) + (FCEU_VERSION_MINOR*100) + (FCEU_VERSION_PATCH) ) #define FCEU_VERSION_MAJOR_DECODE(x) ( (x / 10000) ) #define FCEU_VERSION_MINOR_DECODE(x) ( (x / 100) % 100 ) #define FCEU_VERSION_PATCH_DECODE(x) (x % 100) -#define FCEU_VERSION_STRING "2.6.5" FCEU_SUBVERSION_STRING FCEU_FEATURE_STRING FCEU_COMPILER +#define FCEU_VERSION_STRING "2.6.6" FCEU_SUBVERSION_STRING FCEU_FEATURE_STRING FCEU_COMPILER #define FCEU_NAME_AND_VERSION FCEU_NAME " " FCEU_VERSION_STRING #endif diff --git a/src/video.cpp b/src/video.cpp index ddad754..8baa577 100644 --- a/src/video.cpp +++ b/src/video.cpp @@ -88,6 +88,8 @@ std::string AsSnapshotName =""; //adelikat:this will set the snapshot name whe void FCEUI_SetSnapshotAsName(std::string name) { AsSnapshotName = name; } std::string FCEUI_GetSnapshotAsName() { return AsSnapshotName; } +static void FCEU_DrawPauseCountDown(uint8 *XBuf); + void FCEU_KillVirtualVideo(void) { if ( XBuf ) @@ -255,6 +257,7 @@ void FCEU_PutImage(void) FCEU_DrawLagCounter(XBuf); FCEU_DrawNTSCControlBars(XBuf); FCEU_DrawRecordingStatus(XBuf); + FCEU_DrawPauseCountDown(XBuf); ShowFPS(); } @@ -772,3 +775,35 @@ void ShowFPS(void) DrawTextTrans(XBuf + ((256 - ClipSidesOffset) - 40) + (FSettings.FirstSLine + 4) * 256, 256, (uint8*)fpsmsg, 0xA0); } + +bool showPauseCountDown = true; + +static void FCEU_DrawPauseCountDown(uint8 *XBuf) +{ + if (EmulationPaused & EMULATIONPAUSED_TIMER) + { + int pauseFramesLeft = FCEUI_PauseFramesRemaining(); + + if (showPauseCountDown && (pauseFramesLeft > 0) ) + { + char text[32]; + int framesPerSec; + + if (PAL || dendy) + { + framesPerSec = 50; + } + else + { + framesPerSec = 60; + } + + sprintf(text, "Unpausing in %d...", (pauseFramesLeft / framesPerSec) + 1); + + if (text[0]) + { + DrawTextTrans(XBuf + ClipSidesOffset + (FSettings.FirstSLine) * 256, 256, (uint8*)text, 0xA0); + } + } + } +} diff --git a/src/x6502.cpp b/src/x6502.cpp index 1948cd4..85c5936 100644 --- a/src/x6502.cpp +++ b/src/x6502.cpp @@ -47,7 +47,11 @@ void (*MapIRQHook)(int a); //normal memory read static INLINE uint8 RdMem(unsigned int A) { - return(_DB=ARead[A](A)); + _DB=ARead[A](A); + #ifdef _S9XLUA_H + CallRegisteredLuaMemHook(A, 1, _DB, LUAMEMHOOK_READ); + #endif + return(_DB); } //normal memory write @@ -57,13 +61,18 @@ static INLINE void WrMem(unsigned int A, uint8 V) #ifdef _S9XLUA_H CallRegisteredLuaMemHook(A, 1, V, LUAMEMHOOK_WRITE); #endif + _DB = V; } static INLINE uint8 RdRAM(unsigned int A) { + _DB=ARead[A](A); + #ifdef _S9XLUA_H + CallRegisteredLuaMemHook(A, 1, _DB, LUAMEMHOOK_READ); + #endif //bbit edited: this was changed so cheat substituion would work - return(_DB=ARead[A](A)); // return(_DB=RAM[A]); + return(_DB); } static INLINE void WrRAM(unsigned int A, uint8 V) @@ -72,12 +81,17 @@ static INLINE void WrRAM(unsigned int A, uint8 V) #ifdef _S9XLUA_H CallRegisteredLuaMemHook(A, 1, V, LUAMEMHOOK_WRITE); #endif + _DB = V; } uint8 X6502_DMR(uint32 A) { ADDCYC(1); - return(X.DB=ARead[A](A)); + _DB=ARead[A](A); + #ifdef _S9XLUA_H + CallRegisteredLuaMemHook(A, 1, _DB, LUAMEMHOOK_READ); + #endif + return(_DB); } void X6502_DMW(uint32 A, uint8 V) @@ -87,6 +101,7 @@ void X6502_DMW(uint32 A, uint8 V) #ifdef _S9XLUA_H CallRegisteredLuaMemHook(A, 1, V, LUAMEMHOOK_WRITE); #endif + _DB = V; } #define PUSH(V) \