21 Commits

Author SHA1 Message Date
clobber 07de1ad746 Merge pull request #13 from ShutOstrich/master 2023-09-06 18:50:19 -06:00
ShutOstrich 23bc100386 Update to FCEUX 2.6.6 2023-08-27 23:45:32 +02:00
ShutOstrich f2c6ba0c43 Disable all messages 2023-08-27 23:45:26 +02:00
clobber 7e9cde361e Build fix
Now requires a minimum of C++11: Use of undeclared identifier 'nullptr'
2023-06-20 20:07:39 -06:00
clobber ee3ffeeacc Merge pull request #12 from ShutOstrich/master
Update to FCEUX 2.6.5
2023-04-29 20:40:56 -06:00
ShutOstrich 8a1427db5c Update to FCEUX 2.6.5 2023-04-30 00:37:54 +02:00
ShutOstrich 10724c5437 Disable "Reset" message 2023-04-30 00:32:10 +02:00
clobber 88b1044105 Fix -ringBufferAtIndex: deprecation warning. 2022-12-24 17:10:23 -07:00
clobber 1b76eae51e Update to FCEUX 2.6.3 2022-12-16 17:49:38 -07:00
clobber 4db4639569 Update to FCEUX 2.6.2 2022-12-16 17:34:24 -07:00
clobber 1e9dc7ee26 Update to FCEUX 2.6.1 2022-12-16 17:28:16 -07:00
clobber e62374c88d Update to FCEUX 2.6.0 2022-12-16 17:23:14 -07:00
clobber c4ea492891 Update to FCEUX 2.5.0 2022-12-16 16:58:06 -07:00
clobber 4b460d1cb8 Update to FCEUX 2.4.0 2022-12-16 16:44:41 -07:00
clobber 14cfd5c93c Update to FCEUX 2.3.0 2022-12-16 16:32:10 -07:00
C.W. Betts 14a65ab35d Minor Xcode maintenance.
Remove the ~attic directory.
2021-03-22 01:02:58 -06:00
C.W. Betts 46d186d251 Poke the plists: get the development language from Xcode build. 2020-10-01 01:51:37 -06:00
C.W. Betts b1a06da5ba Fix locations of the system plugin headers.
Minor Xcode maintenance.
2020-10-01 01:26:41 -06:00
C.W. Betts 7bd6e5ea8b Update language resources.
This quiets warnings in newer Xcode releases.

Also update framework locations.
2020-01-07 16:36:20 -07:00
clobber 9d79c1a4a5 Bump version for sparkle updater. Core is still 2.2.3 2018-12-08 23:22:48 -06:00
clobber c1271716eb Add support for Raw cheat formats 2018-12-08 23:22:32 -06:00
624 changed files with 16872 additions and 142030 deletions
Binary file not shown.
File diff suppressed because it is too large Load Diff
+24 -2
View File
@@ -233,7 +233,7 @@ static __weak FCEUGameCore *_current;
for (int i = 0; i < _soundSize; i++)
_soundBuffer[i] = (_soundBuffer[i] << 16) | (_soundBuffer[i] & 0xffff);
[[self ringBufferAtIndex:0] write:_soundBuffer maxLength:_soundSize << 2];
[[self audioBufferAtIndex:0] write:_soundBuffer maxLength:_soundSize << 2];
}
- (void)resetEmulation
@@ -479,8 +479,25 @@ const int NESMap[] = {JOY_UP, JOY_DOWN, JOY_LEFT, JOY_RIGHT, JOY_A, JOY_B, JOY_S
int address, value, compare;
int type = 1;
if (FCEUI_DecodeGG(cCode, &address, &value, &compare))
if (singleCode.length == 7 && [singleCode characterAtIndex:4] == ':')
{
address = (int)strtoul([singleCode substringToIndex:4].UTF8String, NULL, 16);
value = (int)strtoul([singleCode substringFromIndex:5].UTF8String, NULL, 16);
compare = -1;
FCEUI_AddCheat(cCode, address, value, compare, type);
}
else if (singleCode.length == 10 && [singleCode characterAtIndex:4] == '?' && [singleCode characterAtIndex:7] == ':')
{
address = (int)strtoul([singleCode substringToIndex:4].UTF8String, NULL, 16);
compare = (int)strtoul([singleCode substringWithRange:NSMakeRange(5, 2)].UTF8String, NULL, 16);
value = (int)strtoul([singleCode substringFromIndex:8].UTF8String, NULL, 16);
FCEUI_AddCheat(cCode, address, value, compare, type);
}
else if (FCEUI_DecodeGG(cCode, &address, &value, &compare))
FCEUI_AddCheat(cCode, address, value, compare, type);
// Does not work
// else if (FCEUI_DecodePAR(cCode, &address, &value, &compare, &type))
// FCEUI_AddCheat(cCode, address, value, compare, type);
}
}
}
@@ -778,7 +795,9 @@ const char *GetKeyboard(void) {return "";}
bool turbo = false;
bool swapDuty = 0; // some Famicom and NES clones had duty cycle bits swapped
int dendy = 0;
int eoptions = 0;
int closeFinishedMovie = 0;
int KillFCEUXonFrame = 0;
int FCEUD_ShowStatusIcon(void) {return 0;}
int FCEUD_SendData(void *data, uint32 len) {return 1;}
int FCEUD_RecvData(void *data, uint32 len) {return 1;}
@@ -806,6 +825,7 @@ EMUFILE_FILE *FCEUD_UTF8_fstream(const char *fn, const char *m)
}
void FCEUD_NetplayText(uint8 *text) {};
void FCEUD_NetworkClose(void) {}
void FCEUD_FlushTrace(void) {}
void FCEUD_VideoChanged (void) {}
bool FCEUD_ShouldDrawInputAids() {return false;}
bool FCEUD_PauseAfterPlayback() {return false;}
@@ -815,6 +835,8 @@ bool FCEUI_AviIsRecording(void) {return false;}
bool FCEUI_AviDisableMovieMessages() {return true;}
FCEUFILE *FCEUD_OpenArchiveIndex(ArchiveScanRecord &asr, std::string &fname, int innerIndex) {return 0;}
FCEUFILE *FCEUD_OpenArchive(ArchiveScanRecord &asr, std::string &fname, std::string *innerFilename) {return 0;}
FCEUFILE *FCEUD_OpenArchiveIndex(ArchiveScanRecord &asr, std::string &fname, int innerIndex, int *userCancel) {return 0;}
FCEUFILE *FCEUD_OpenArchive(ArchiveScanRecord &asr, std::string &fname, std::string *innerFilename, int *userCancel) {return 0;}
ArchiveScanRecord FCEUD_ScanArchive(std::string fname) { return ArchiveScanRecord(); }
void GetMouseData(uint32 (&md)[3]) {}
void FCEUD_PrintError(const char *s)
+3 -3
View File
@@ -3,7 +3,7 @@
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>${EXECUTABLE_NAME}</string>
<key>CFBundleIconFile</key>
@@ -17,7 +17,7 @@
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>2.2.3.1</string>
<string>2.6.6</string>
<key>NSPrincipalClass</key>
<string>OEGameCoreController</string>
<key>OEGameCoreClass</key>
@@ -41,7 +41,7 @@
<key>OEGameCorePlayerCount</key>
<string>4</string>
<key>OEProjectURL</key>
<string>http://sourceforge.net/projects/fceultra/</string>
<string>https://github.com/TASEmulators/fceux</string>
<key>OESystemIdentifiers</key>
<array>
<string>openemu.system.nes</string>
+2
View File
@@ -0,0 +1,2 @@
/* Localized versions of Info.plist keys */
+731
View File
@@ -0,0 +1,731 @@
include(GNUInstallDirs)
set( APP_NAME fceux)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_AUTOUIC ON)
if (${PUBLIC_RELEASE})
add_definitions( -DPUBLIC_RELEASE=1 )
endif()
if ( ${QT6} )
message( STATUS "GUI Frontend: Qt6")
set( Qt Qt6 )
else()
message( STATUS "GUI Frontend: Qt5")
set( Qt Qt5 )
endif()
if ( ${QHELP} )
set(QtHelpModule Help)
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} )
include_directories( ${Qt6Widgets_INCLUDE_DIRS} ${Qt6Help_INCLUDE_DIRS} ${Qt6OpenGLWidgets_INCLUDE_DIRS} )
else()
find_package( Qt5 REQUIRED COMPONENTS Widgets OpenGL ${QtHelpModule})
add_definitions( ${Qt5Widgets_DEFINITIONS} ${Qt5Help_DEFINITIONS} )
include_directories( ${Qt5Widgets_INCLUDE_DIRS} ${Qt5Help_INCLUDE_DIRS} )
endif()
if(WIN32)
find_package(OpenGL REQUIRED)
#find_package(Qt5 COMPONENTS Widgets OpenGL REQUIRED)
#add_definitions( ${Qt5Widgets_DEFINITIONS} )
#include_directories( ${Qt5Widgets_INCLUDE_DIRS} )
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 )
if ( ${USE_LIBAV} )
add_definitions( -D_USE_LIBAV ${LIBAV_CFLAGS} )
include_directories( ${FFMPEG_INSTALL_PREFIX}/ffmpeg/include )
set( LIBAV_LDFLAGS ${FFMPEG_INSTALL_PREFIX}/ffmpeg/lib/avcodec.lib
${FFMPEG_INSTALL_PREFIX}/ffmpeg/lib/avformat.lib
${FFMPEG_INSTALL_PREFIX}/ffmpeg/lib/avutil.lib
${FFMPEG_INSTALL_PREFIX}/ffmpeg/lib/swscale.lib
${FFMPEG_INSTALL_PREFIX}/ffmpeg/lib/swresample.lib )
endif()
else(WIN32)
# Non Windows System
# UNIX (Linux or Mac OSX)
if ( ${GLVND} )
message( STATUS "OpenGL preference: GLVND")
set (OpenGL_GL_PREFERENCE GLVND)
else()
message( STATUS "OpenGL preference: LEGACY")
set (OpenGL_GL_PREFERENCE LEGACY)
endif()
# Use the built-in cmake find_package functions to find dependencies
# Use package PkgConfig to detect headers/library what find_package cannot find.
find_package(PkgConfig REQUIRED)
find_package(OpenGL REQUIRED)
find_package(ZLIB REQUIRED)
add_definitions( -Wall -Wno-write-strings -Wno-parentheses -Wno-unused-local-typedefs -fPIC )
#add_definitions( -Wno-sign-compare ) # Integer comparison sign mismatch warnings
add_definitions( -DFCEUDEF_DEBUGGER )
#if ( ${QT6} )
# find_package( Qt6 COMPONENTS Widgets OpenGL OpenGLWidgets REQUIRED)
# add_definitions( ${Qt6Widgets_DEFINITIONS} ${Qt6OpenGLWidgets_DEFINITIONS} )
# include_directories( ${Qt6Widgets_INCLUDE_DIRS} ${QtOpenGLWidgets_INCLUDE_DIRS} )
#else()
# find_package( Qt5 COMPONENTS Widgets OpenGL REQUIRED)
# add_definitions( ${Qt5Widgets_DEFINITIONS} )
# include_directories( ${Qt5Widgets_INCLUDE_DIRS} )
#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 )
set( ASAN_LDFLAGS -lasan -lubsan)
message( STATUS "Address Sanitizer Enabled" )
else()
message( STATUS "Address Sanitizer Disabled" )
endif()
# Check for libminizip
pkg_check_modules( MINIZIP REQUIRED minizip)
if ( ${MINIZIP_FOUND} )
message( STATUS "Using System minizip ${MINIZIP_VERSION}" )
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} )
message( STATUS "Using System X264 Encoder Library ${X264_VERSION}" )
add_definitions( -D_USE_X264 ${X264_CFLAGS} )
endif()
pkg_check_modules( X265 x265)
if ( ${X265_FOUND} )
message( STATUS "Using System X265 Encoder Library ${X265_VERSION}" )
add_definitions( -D_USE_X265 ${X265_CFLAGS} )
endif()
pkg_check_modules( LIBAV libavcodec libavformat libavutil libswresample libswscale)
if ( ${LIBAV_FOUND} )
message( STATUS "Using System Libav Library ${LIBAV_VERSION}" )
add_definitions( -D_USE_LIBAV ${LIBAV_CFLAGS} )
endif()
#find_package(X11)
pkg_check_modules( X11 x11)
if ( ${X11_FOUND} )
message( STATUS "Has X11 Library ${X11_VERSION}" )
add_definitions( -D_HAS_X11 )
include_directories( ${X11_INCLUDE_DIR} )
endif()
pkg_check_modules( XKB xkbcommon)
if ( ${XKB_FOUND} )
message( STATUS "Has XKB Library ${XKB_VERSION}" )
add_definitions( -D_HAS_XKB ${XKB_CFLAGS} )
endif()
#pkg_check_modules( GL gl) # Use built in find package instead for OpenGL
# Check for OpenGL
if ( ${OPENGL_FOUND} )
include_directories( ${OPENGL_INCLUDE_DIR} )
endif()
# Check for SDL2
pkg_check_modules( SDL2 REQUIRED sdl2)
if ( ${SDL2_FOUND} )
add_definitions( ${SDL2_CFLAGS} -D__SDL__ )
endif()
# Check for LUA
pkg_search_module( LUA lua5.1 lua-5.1 )
add_definitions( -DHAVE_ASPRINTF ) # What system wouldn't have this?
add_definitions( -DLUA_USE_LINUX ) # This needs to be set when link LUA internally for linux and macosx
if(APPLE)
set( OPENGL_LDFLAGS "-framework OpenGL" )
else()
set( OPENGL_LDFLAGS ${OPENGL_LIBRARIES} )
# OpenBSD refuses to implement the POSIX realtime interface and
# refuses to provide a stub library for -ldl
if(${CMAKE_SYSTEM_NAME} STREQUAL "OpenBSD")
set( SYS_LIBS -lpthread)
else()
set( SYS_LIBS -lrt -lpthread -ldl)
endif()
endif()
endif(WIN32)
if ( ${LUA_FOUND} )
# Use System LUA
message( STATUS "Using System Lua ${LUA_VERSION}" )
add_definitions( -D_S9XLUA_H ${LUA_CFLAGS} )
set( LUA_ENGINE_SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/lua-engine.cpp )
else ()
# Use Internal LUA
message( STATUS "Using Internal Lua" )
add_definitions( -D_S9XLUA_H -I${CMAKE_CURRENT_SOURCE_DIR}/lua/src )
set( LUA_ENGINE_SOURCE
${CMAKE_CURRENT_SOURCE_DIR}/lua/src/lapi.c
${CMAKE_CURRENT_SOURCE_DIR}/lua/src/lauxlib.c
${CMAKE_CURRENT_SOURCE_DIR}/lua/src/lbaselib.c
${CMAKE_CURRENT_SOURCE_DIR}/lua/src/lcode.c
${CMAKE_CURRENT_SOURCE_DIR}/lua/src/ldblib.c
${CMAKE_CURRENT_SOURCE_DIR}/lua/src/ldebug.c
${CMAKE_CURRENT_SOURCE_DIR}/lua/src/ldo.c
${CMAKE_CURRENT_SOURCE_DIR}/lua/src/ldump.c
${CMAKE_CURRENT_SOURCE_DIR}/lua/src/lfunc.c
${CMAKE_CURRENT_SOURCE_DIR}/lua/src/lgc.c
${CMAKE_CURRENT_SOURCE_DIR}/lua/src/linit.c
${CMAKE_CURRENT_SOURCE_DIR}/lua/src/liolib.c
${CMAKE_CURRENT_SOURCE_DIR}/lua/src/llex.c
${CMAKE_CURRENT_SOURCE_DIR}/lua/src/lmathlib.c
${CMAKE_CURRENT_SOURCE_DIR}/lua/src/lmem.c
${CMAKE_CURRENT_SOURCE_DIR}/lua/src/loadlib.c
${CMAKE_CURRENT_SOURCE_DIR}/lua/src/lobject.c
${CMAKE_CURRENT_SOURCE_DIR}/lua/src/lopcodes.c
${CMAKE_CURRENT_SOURCE_DIR}/lua/src/loslib.c
${CMAKE_CURRENT_SOURCE_DIR}/lua/src/lparser.c
${CMAKE_CURRENT_SOURCE_DIR}/lua/src/lstate.c
${CMAKE_CURRENT_SOURCE_DIR}/lua/src/lstring.c
${CMAKE_CURRENT_SOURCE_DIR}/lua/src/lstrlib.c
${CMAKE_CURRENT_SOURCE_DIR}/lua/src/ltable.c
${CMAKE_CURRENT_SOURCE_DIR}/lua/src/ltablib.c
${CMAKE_CURRENT_SOURCE_DIR}/lua/src/ltm.c
${CMAKE_CURRENT_SOURCE_DIR}/lua/src/lundump.c
${CMAKE_CURRENT_SOURCE_DIR}/lua/src/lvm.c
${CMAKE_CURRENT_SOURCE_DIR}/lua/src/lzio.c
${CMAKE_CURRENT_SOURCE_DIR}/lua/src/print.c
${CMAKE_CURRENT_SOURCE_DIR}/lua-engine.cpp
)
endif()
if ( ${ZLIB_FOUND} )
message( STATUS "Using System zlib ${ZLIB_VERSION_STRING}" )
#add_definitions( ${ZLIB_CFLAGS} )
include_directories( ${ZLIB_INCLUDE_DIRS} )
else()
message( STATUS "Using Internal zlib" )
set( ZLIB_SOURCE
${CMAKE_CURRENT_SOURCE_DIR}/drivers/win/zlib/adler32.c
${CMAKE_CURRENT_SOURCE_DIR}/drivers/win/zlib/compress.c
${CMAKE_CURRENT_SOURCE_DIR}/drivers/win/zlib/crc32.c
${CMAKE_CURRENT_SOURCE_DIR}/drivers/win/zlib/deflate.c
${CMAKE_CURRENT_SOURCE_DIR}/drivers/win/zlib/gzio.c
${CMAKE_CURRENT_SOURCE_DIR}/drivers/win/zlib/infblock.c
${CMAKE_CURRENT_SOURCE_DIR}/drivers/win/zlib/infcodes.c
${CMAKE_CURRENT_SOURCE_DIR}/drivers/win/zlib/inffast.c
${CMAKE_CURRENT_SOURCE_DIR}/drivers/win/zlib/inflate.c
${CMAKE_CURRENT_SOURCE_DIR}/drivers/win/zlib/inftrees.c
${CMAKE_CURRENT_SOURCE_DIR}/drivers/win/zlib/infutil.c
${CMAKE_CURRENT_SOURCE_DIR}/drivers/win/zlib/trees.c
${CMAKE_CURRENT_SOURCE_DIR}/drivers/win/zlib/uncompr.c
${CMAKE_CURRENT_SOURCE_DIR}/drivers/win/zlib/unzip.c
${CMAKE_CURRENT_SOURCE_DIR}/drivers/win/zlib/zutil.c
)
endif()
include_directories( ${CMAKE_SOURCE_DIR}/src )
include_directories( ${CMAKE_SOURCE_DIR}/src/drivers )
if(APPLE)
add_definitions( -DPSS_STYLE=1 )
else(APPLE)
if(UNIX)
add_definitions( -DPSS_STYLE=1 )
endif(UNIX)
endif(APPLE)
set(SRC_CORE
${CMAKE_CURRENT_SOURCE_DIR}/asm.cpp
${CMAKE_CURRENT_SOURCE_DIR}/cart.cpp
${CMAKE_CURRENT_SOURCE_DIR}/cheat.cpp
${CMAKE_CURRENT_SOURCE_DIR}/conddebug.cpp
${CMAKE_CURRENT_SOURCE_DIR}/config.cpp
${CMAKE_CURRENT_SOURCE_DIR}/debug.cpp
${CMAKE_CURRENT_SOURCE_DIR}/debugsymboltable.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drawing.cpp
${CMAKE_CURRENT_SOURCE_DIR}/fceu.cpp
${CMAKE_CURRENT_SOURCE_DIR}/fds.cpp
${CMAKE_CURRENT_SOURCE_DIR}/file.cpp
${CMAKE_CURRENT_SOURCE_DIR}/emufile.cpp
${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
${CMAKE_CURRENT_SOURCE_DIR}/unif.cpp
${CMAKE_CURRENT_SOURCE_DIR}/video.cpp
${CMAKE_CURRENT_SOURCE_DIR}/vsuni.cpp
${CMAKE_CURRENT_SOURCE_DIR}/wave.cpp
${CMAKE_CURRENT_SOURCE_DIR}/x6502.cpp
${LUA_ENGINE_SOURCE}
${ZLIB_SOURCE}
${CMAKE_CURRENT_SOURCE_DIR}/boards/01-222.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/09-034a.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/103.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/106.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/108.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/112.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/116.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/117.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/120.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/121.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/12in1.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/151.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/156.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/158B.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/15.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/164.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/168.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/170.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/175.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/176.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/177.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/178.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/183.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/185.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/186.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/187.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/189.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/18.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/190.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/193.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/199.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/206.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/208.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/222.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/225.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/228.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/230.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/232.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/234.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/235.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/244.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/246.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/252.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/253.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/28.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/32.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/33.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/34.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/354.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/36.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/3d-block.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/40.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/411120-c.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/41.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/42.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/43.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/46.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/50.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/51.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/57.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/603-5052.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/62.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/65.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/67.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/68.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/69.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/71.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/72.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/77.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/79.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/80013-B.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/80.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/8157.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/8237.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/82.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/830118C.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/88.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/8in1.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/90.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/91.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/96.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/99.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/a9746.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/ac-08.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/addrlatch.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/ax5705.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/bandai.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/bb.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/bmc13in1jy110.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/bmc42in1r.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/bmc64in1nr.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/bmc70in1.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/BMW8544.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/bonza.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/bs-5.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/bs4xxxr.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/cheapocabra.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/cityfighter.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/coolboy.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/coolgirl.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/dance2000.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/datalatch.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/dream.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/__dummy_mapper.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/edu2000.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/eh8813a.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/emu2413.c
${CMAKE_CURRENT_SOURCE_DIR}/boards/et-100.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/et-4320.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/F-15.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/famicombox.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/ffe.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/fk23c.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/fns.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/ghostbusters63in1.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/gs-2004.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/gs-2013.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/h2288.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/hp10xx_hp20xx.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/hp898f.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/inlnsf.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/karaoke.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/kof97.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/ks7010.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/ks7012.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/ks7013.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/ks7016.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/ks7017.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/ks7030.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/ks7031.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/ks7032.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/ks7037.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/ks7057.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/le05.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/lh32.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/lh53.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/malee.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/mihunche.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/mmc1.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/mmc2and4.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/mmc3.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/mmc5.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/n106.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/n625092.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/novel.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/onebus.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/pec-586.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/rt-01.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/sa-9602b.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/sachen.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/sb-2000.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/sc-127.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/sheroes.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/sl1632.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/subor.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/super24.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/supervision.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/t-227-1.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/t-262.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/tengen.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/tf-1201.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/transformer.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/unrom512.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/vrc1.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/vrc2and4.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/vrc3.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/vrc5.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/vrc6.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/vrc7.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/vrc7p.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/yoko.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/inx007t.cpp
${CMAKE_CURRENT_SOURCE_DIR}/input/arkanoid.cpp
${CMAKE_CURRENT_SOURCE_DIR}/input/bworld.cpp
${CMAKE_CURRENT_SOURCE_DIR}/input/cursor.cpp
${CMAKE_CURRENT_SOURCE_DIR}/input/fkb.cpp
${CMAKE_CURRENT_SOURCE_DIR}/input/fns.cpp
${CMAKE_CURRENT_SOURCE_DIR}/input/ftrainer.cpp
${CMAKE_CURRENT_SOURCE_DIR}/input/hypershot.cpp
${CMAKE_CURRENT_SOURCE_DIR}/input/mahjong.cpp
${CMAKE_CURRENT_SOURCE_DIR}/input/mouse.cpp
${CMAKE_CURRENT_SOURCE_DIR}/input/oekakids.cpp
${CMAKE_CURRENT_SOURCE_DIR}/input/pec586kb.cpp
${CMAKE_CURRENT_SOURCE_DIR}/input/powerpad.cpp
${CMAKE_CURRENT_SOURCE_DIR}/input/quiz.cpp
${CMAKE_CURRENT_SOURCE_DIR}/input/shadow.cpp
${CMAKE_CURRENT_SOURCE_DIR}/input/snesmouse.cpp
${CMAKE_CURRENT_SOURCE_DIR}/input/suborkb.cpp
${CMAKE_CURRENT_SOURCE_DIR}/input/toprider.cpp
${CMAKE_CURRENT_SOURCE_DIR}/input/virtualboy.cpp
${CMAKE_CURRENT_SOURCE_DIR}/input/lcdcompzapper.cpp
${CMAKE_CURRENT_SOURCE_DIR}/input/zapper.cpp
${CMAKE_CURRENT_SOURCE_DIR}/utils/backward.cpp
${CMAKE_CURRENT_SOURCE_DIR}/utils/xstring.cpp
${CMAKE_CURRENT_SOURCE_DIR}/utils/crc32.cpp
${CMAKE_CURRENT_SOURCE_DIR}/utils/endian.cpp
${CMAKE_CURRENT_SOURCE_DIR}/utils/general.cpp
${CMAKE_CURRENT_SOURCE_DIR}/utils/guid.cpp
${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
)
set(SRC_DRIVERS_COMMON
${CMAKE_CURRENT_SOURCE_DIR}/drivers/common/args.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/common/cheat.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/common/configSys.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/common/hq2x.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/common/hq3x.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/common/scale2x.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/common/scale3x.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/common/scalebit.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/common/vidblit.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/common/os_utils.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/common/nes_ntsc.c
)
set(SRC_DRIVERS_SDL
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/main.cpp
${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
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/HotKeyConf.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/TimingConf.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/FrameTimingStats.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/PaletteConf.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/PaletteEditor.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/ColorMenu.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/GuiConf.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/HelpPages.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/MoviePlay.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/MovieRecord.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/MovieOptions.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/LuaControl.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/CheatsConf.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/GameGenie.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/HexEditor.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/MsgLogViewer.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/CodeDataLogger.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/SymbolicDebug.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/ConsoleDebugger.cpp
${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
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/AboutWindow.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/fceuWrapper.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/ppuViewer.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/NameTableViewer.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/RamWatch.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/RamSearch.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/config.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/input.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/nes_shm.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/keyscan.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/sdl-sound.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/sdl-video.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/sdl-joystick.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/sdl-throttle.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/unix-netplay.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/AviRecord.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/AviRiffViewer.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/avi/avi-utils.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/avi/fileio.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/avi/gwavi.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/TasEditor/TasEditorWindow.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/TasEditor/taseditor_project.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/TasEditor/taseditor_config.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/TasEditor/taseditor_lua.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/TasEditor/markers_manager.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/TasEditor/greenzone.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/TasEditor/selection.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/TasEditor/playback.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/TasEditor/recorder.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/TasEditor/history.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/TasEditor/splicer.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/TasEditor/inputlog.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/TasEditor/laglog.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/TasEditor/branches.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/TasEditor/bookmarks.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/TasEditor/bookmark.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/TasEditor/snapshot.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/TasEditor/markers.cpp
)
set(SOURCES ${SRC_CORE} ${SRC_DRIVERS_COMMON} ${SRC_DRIVERS_SDL})
# Put build timestamp into BUILD_TS environment variable and from there into
# the FCEUX_BUILD_TIMESTAMP preprocessor definition.
# Note: with CMake >= 3.8.0, this will respect SOURCE_DATE_EPOCH. For more info,
# see <https://reproducible-builds.org/docs/source-date-epoch/>.
string(TIMESTAMP BUILD_TS "%H:%M:%S %b %d %Y" UTC)
add_definitions( -DFCEUX_BUILD_TIMESTAMP=\"${BUILD_TS}\" )
if (WIN32)
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/fceux_git_info.cpp
COMMAND ${CMAKE_SOURCE_DIR}/scripts/genGitHdr.bat ${CMAKE_CURRENT_BINARY_DIR}
VERBATIM )
else()
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/fceux_git_info.cpp
COMMAND ${CMAKE_SOURCE_DIR}/scripts/genGitHdr.sh ${CMAKE_CURRENT_BINARY_DIR}
VERBATIM )
endif()
set_property(SOURCE ${CMAKE_CURRENT_BINARY_DIR}/fceux_git_info.cpp PROPERTY SKIP_AUTOGEN ON)
if (APPLE)
set(MACOSX_BUNDLE_ICON_FILE fceux.icns)
set(APP_ICON ${CMAKE_SOURCE_DIR}/fceux.icns )
set_source_files_properties( ${APP_ICON} PROPERTIES MACOSX_PACKAGE_LOCATION "Resources" )
add_executable( ${APP_NAME} MACOSX_BUNDLE ${APP_ICON} ${SOURCES} ../resources.qrc
${CMAKE_CURRENT_BINARY_DIR}/fceux_git_info.cpp)
elseif (WIN32)
add_executable( ${APP_NAME} ${SOURCES} ../resources.qrc
${CMAKE_CURRENT_BINARY_DIR}/fceux_git_info.cpp
${APP_ICON_RESOURCES_WINDOWS} )
else()
add_executable( ${APP_NAME} ${SOURCES} ../resources.qrc
${CMAKE_CURRENT_BINARY_DIR}/fceux_git_info.cpp)
endif()
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} ${LIBARCHIVE_LDFLAGS}
${LUA_LDFLAGS} ${X264_LDFLAGS} ${X265_LDFLAGS} ${LIBAV_LDFLAGS}
${SYS_LIBS}
)
if (WIN32)
# target_link_libraries( ${APP_NAME} wsock32 ws2_32 )
set_target_properties(${APP_NAME} PROPERTIES WIN32_EXECUTABLE TRUE)
endif()
if (APPLE)
install( TARGETS ${APP_NAME}
BUNDLE DESTINATION . COMPONENT Runtime
RUNTIME DESTINATION bin COMPONENT Runtime )
# Use \$ to defer expansion until install script is called; CPack will call it with its own CMAKE_INSTALL_PREFIX
set(APP \${CMAKE_INSTALL_PREFIX}/${APP_NAME}.app)
install( DIRECTORY ${CMAKE_SOURCE_DIR}/output/.
DESTINATION ${APP_NAME}.app/Contents/Resources COMPONENT Extra )
set(CPACK_PACKAGE_ICON ${CMAKE_SOURCE_DIR}/fceux.icns )
set(CPACK_GENERATOR "DragNDrop")
include(CPACK)
# macdeployqt tool that comes with Qt: https://doc.qt.io/qt-5/macos-deployment.html#macdeploy
# Compared to fixup_bundle, correctly finds and installs Qt-specific resources as well as non-Qt dependencies
find_program(MACDEPLOYQT macdeployqt)
if(NOT MACDEPLOYQT)
message(FATAL_ERROR "Could not find macdeployqt executable")
endif()
find_package(Perl REQUIRED)
install( CODE "
message(STATUS \"Deploying and fixing up dependencies in app: ${APP}\")
execute_process(COMMAND \"${MACDEPLOYQT}\" \"${APP}\" -verbose=1)
execute_process(COMMAND \"${PERL_EXECUTABLE}\"
\"${CMAKE_SOURCE_DIR}/scripts/macOSX_BundleFix.pl\"
\"${CMAKE_BINARY_DIR}/_CPack_Packages\")
"
COMPONENT Runtime
)
else(APPLE)
install( TARGETS ${APP_NAME}
RUNTIME DESTINATION bin )
install( FILES ${CMAKE_CURRENT_SOURCE_DIR}/auxlib.lua DESTINATION share/fceux/luaScripts )
install( DIRECTORY ${CMAKE_SOURCE_DIR}/output/. DESTINATION share/fceux )
install( FILES ${CMAKE_SOURCE_DIR}/fceux1.png DESTINATION share/pixmaps )
install( FILES ${CMAKE_SOURCE_DIR}/fceux.desktop DESTINATION share/applications )
install( FILES ${CMAKE_SOURCE_DIR}/documentation/fceux.6 DESTINATION ${CMAKE_INSTALL_MANDIR}/man6 )
install( FILES ${CMAKE_SOURCE_DIR}/documentation/fceux-net-server.6 DESTINATION ${CMAKE_INSTALL_MANDIR}/man6 )
endif(APPLE)
-42
View File
@@ -1,42 +0,0 @@
import glob
file_list = glob.glob('*.cpp')
file_list.remove('lua-engine.cpp') # use logic below for this
subdirs = Split("""
boards
drivers/common
fir
input
utils
""")
#palettes
Import('env')
Export('env')
if env['LUA']:
file_list.append('lua-engine.cpp')
if env['SYSTEM_LUA'] == 0:
subdirs.append('lua')
if env['CREATE_AVI']:
subdirs.append('drivers/videolog')
for dir in subdirs:
subdir_files = SConscript('%s/SConscript' % dir)
file_list.append(subdir_files)
if env['PLATFORM'] == 'win32':
platform_files = SConscript('drivers/win/SConscript')
else:
platform_files = SConscript('drivers/sdl/SConscript')
file_list.append(platform_files)
print env['LINKFLAGS']
if env['PLATFORM'] == 'win32':
fceux = env.Program('fceux.exe', file_list)
else:
fceux = env.Program('fceux', file_list)
Return('fceux')
+7 -7
View File
@@ -16,7 +16,7 @@ int Assemble(unsigned char *output, int addr, char *str) {
output[0] = output[1] = output[2] = 0;
char astr[128],ins[4];
int len = strlen(str);
if ((!len) || (len > 0x127)) return 1;
if ((!len) || (len > 127)) return 1;
strcpy(astr,str);
str_ucase(astr);
@@ -272,7 +272,7 @@ char *Disassemble(int addr, uint8 *opcode) {
(a) = opcode[1] | opcode[2]<<8; \
}
#define zpIndex(a,i) { \
(a) = opcode[1]+(i); \
(a) = (opcode[1]+(i))&0xFF; \
}
#define indirectX(a) { \
(a) = (opcode[1]+RX)&0xFF; \
@@ -360,8 +360,8 @@ char *Disassemble(int addr, uint8 *opcode) {
case 0xE6: strcpy(chr,"INC"); goto _zeropage;
_zeropage:
// ################################## Start of SP CODE ###########################
// Change width to %04X
sprintf(str,"%s $%04X = #$%02X", chr,opcode[1],GetMem(opcode[1]));
// Change width to %04X // don't!
sprintf(str,"%s $%02X = #$%02X", chr,opcode[1],GetMem(opcode[1]));
// ################################## End of SP CODE ###########################
break;
@@ -457,7 +457,7 @@ char *Disassemble(int addr, uint8 *opcode) {
_zeropagex:
zpIndex(tmp,RX);
// ################################## Start of SP CODE ###########################
// Change width to %04X
// Change width to %04X // don't!
sprintf(str,"%s $%02X,X @ $%04X = #$%02X", chr,opcode[1],tmp,GetMem(tmp));
// ################################## End of SP CODE ###########################
break;
@@ -515,8 +515,8 @@ char *Disassemble(int addr, uint8 *opcode) {
_zeropagey:
zpIndex(tmp,RY);
// ################################## Start of SP CODE ###########################
// Change width to %04X
sprintf(str,"%s $%04X,Y @ $%04X = #$%02X", chr,opcode[1],tmp,GetMem(tmp));
// Change width to %04X // don't!
sprintf(str,"%s $%02X,Y @ $%04X = #$%02X", chr,opcode[1],tmp,GetMem(tmp));
// ################################## End of SP CODE ###########################
break;
+2
View File
@@ -19,6 +19,7 @@
*
* TXC mappers, originally much complex banksitching
*
* P/N PRG MAP, UNIF Name
* 01-22111-000 (05-00002-010) (132, 22211) - MGC-001 Qi Wang
* 01-22110-000 (52S ) - MGC-002 2-in-1 Gun
* 01-22111-100 (02-00002-010) (173 ) - MGC-008 Mahjong Block
@@ -27,6 +28,7 @@
* 01-22000-400 (05-00002-010) (036 ) - MGC-015 Policeman
* 01-22017-000 (05-PT017-080) (189 ) - MGC-017 Thunder Warrior
* 01-11160-000 (04-02310-000) ( , 11160) - MGC-023 6-in-1
* 01-22026-000 (05-04010-090) ( ) - MGC-026 4-in-1
* 01-22270-000 (05-00002-010) (132, 22211) - MGC-xxx Creatom
* 01-22200-400 (------------) (079 ) - ET.03 F-15 City War
* (172 ) - 1991 Du Ma Racing
+89 -89
View File
@@ -1,90 +1,90 @@
/* FCE Ultra - NES/Famicom Emulator
*
* Copyright notice for this file:
* Copyright (C) 2005 CaH4e3
*
* 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
*
* NTDEC, ASDER games
*
*/
#include "mapinc.h"
static uint8 reg[8];
static uint8 mirror, cmd, bank;
static uint8 *WRAM = NULL;
static SFORMAT StateRegs[] =
{
{ &cmd, 1, "CMD" },
{ &mirror, 1, "MIRR" },
{ &bank, 1, "BANK" },
{ reg, 8, "REGS" },
{ 0 }
};
static void Sync(void) {
setmirror(mirror ^ 1);
setprg8(0x8000, reg[0]);
setprg8(0xA000, reg[1]);
setchr2(0x0000, (reg[2] >> 1));
setchr2(0x0800, (reg[3] >> 1));
setchr1(0x1000, ((bank & 0x10) << 4) | reg[4]);
setchr1(0x1400, ((bank & 0x20) << 3) | reg[5]);
setchr1(0x1800, ((bank & 0x40) << 2) | reg[6]);
setchr1(0x1C00, ((bank & 0x80) << 1) | reg[7]);
}
static DECLFW(M112Write) {
switch (A) {
case 0xe000: mirror = V & 1; Sync();; break;
case 0x8000: cmd = V & 7; break;
case 0xa000: reg[cmd] = V; Sync(); break;
case 0xc000: bank = V; Sync(); break;
}
}
static void M112Close(void) {
if (WRAM)
FCEU_gfree(WRAM);
WRAM = NULL;
}
static void M112Power(void) {
bank = 0;
setprg16(0xC000, ~0);
setprg8r(0x10, 0x6000, 0);
SetReadHandler(0x8000, 0xFFFF, CartBR);
SetWriteHandler(0x8000, 0xFFFF, M112Write);
SetWriteHandler(0x4020, 0x5FFF, M112Write);
SetReadHandler(0x6000, 0x7FFF, CartBR);
SetWriteHandler(0x6000, 0x7FFF, CartBW);
/* FCE Ultra - NES/Famicom Emulator
*
* Copyright notice for this file:
* Copyright (C) 2005 CaH4e3
*
* 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
*
* NTDEC, ASDER games
*
*/
#include "mapinc.h"
static uint8 reg[8];
static uint8 mirror, cmd, bank;
static uint8 *WRAM = NULL;
static SFORMAT StateRegs[] =
{
{ &cmd, 1, "CMD" },
{ &mirror, 1, "MIRR" },
{ &bank, 1, "BANK" },
{ reg, 8, "REGS" },
{ 0 }
};
static void Sync(void) {
setmirror(mirror ^ 1);
setprg8(0x8000, reg[0]);
setprg8(0xA000, reg[1]);
setchr2(0x0000, (reg[2] >> 1));
setchr2(0x0800, (reg[3] >> 1));
setchr1(0x1000, ((bank & 0x10) << 4) | reg[4]);
setchr1(0x1400, ((bank & 0x20) << 3) | reg[5]);
setchr1(0x1800, ((bank & 0x40) << 2) | reg[6]);
setchr1(0x1C00, ((bank & 0x80) << 1) | reg[7]);
}
static DECLFW(M112Write) {
switch (A) {
case 0xe000: mirror = V & 1; Sync();; break;
case 0x8000: cmd = V & 7; break;
case 0xa000: reg[cmd] = V; Sync(); break;
case 0xc000: bank = V; Sync(); break;
}
}
static void M112Close(void) {
if (WRAM)
FCEU_gfree(WRAM);
WRAM = NULL;
}
static void M112Power(void) {
bank = 0;
setprg16(0xC000, ~0);
setprg8r(0x10, 0x6000, 0);
SetReadHandler(0x8000, 0xFFFF, CartBR);
SetWriteHandler(0x8000, 0xFFFF, M112Write);
SetWriteHandler(0x4020, 0x5FFF, M112Write);
SetReadHandler(0x6000, 0x7FFF, CartBR);
SetWriteHandler(0x6000, 0x7FFF, CartBW);
FCEU_CheatAddRAM(8, 0x6000, WRAM);
}
static void StateRestore(int version) {
Sync();
}
void Mapper112_Init(CartInfo *info) {
info->Power = M112Power;
info->Close = M112Close;
GameStateRestore = StateRestore;
WRAM = (uint8*)FCEU_gmalloc(8192);
SetupCartPRGMapping(0x10, WRAM, 8192, 1);
AddExState(WRAM, 8192, 0, "WRAM");
AddExState(&StateRegs, ~0, 0, 0);
}
}
static void StateRestore(int version) {
Sync();
}
void Mapper112_Init(CartInfo *info) {
info->Power = M112Power;
info->Close = M112Close;
GameStateRestore = StateRestore;
WRAM = (uint8*)FCEU_gmalloc(8192);
SetupCartPRGMapping(0x10, WRAM, 8192, 1);
AddExState(WRAM, 8192, 0, "WRAM");
AddExState(&StateRegs, ~0, 0, 0);
}
+1 -1
View File
@@ -48,7 +48,7 @@ static void M121CW(uint32 A, uint8 V) {
if (PRGsize[0] == CHRsize[0]) { // A9713 multigame extension hack!
setchr1(A, V | ((EXPREGS[3] & 0x80) << 1));
} else {
if ((A & 0x1000) == ((MMC3_cmd & 0x80) << 5))
if ((A & 0x1000) == static_cast<uint32>((MMC3_cmd & 0x80) << 5))
setchr1(A, V | 0x100);
else
setchr1(A, V);
+20 -14
View File
@@ -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" },
@@ -35,31 +35,39 @@ static SFORMAT StateRegs[] =
static void Sync(void) {
int i;
setmirror(((latched >> 6) & 1) ^ 1);
switch (latchea) {
case 0x8000:
switch (latchea & 3) {
case 0:
for (i = 0; i < 4; i++)
setprg8(0x8000 + (i << 13), (((latched & 0x7F) << 1) + i) ^ (latched >> 7));
setprg8(0x8000 + (i << 13), ((latched & 0x3F) << 1) + i);
break;
case 0x8002:
case 2:
for (i = 0; i < 4; i++)
setprg8(0x8000 + (i << 13), ((latched & 0x7F) << 1) + (latched >> 7));
setprg8(0x8000 + (i << 13), ((latched & 0x3F) << 1) + (latched >> 7));
break;
case 0x8001:
case 0x8003:
case 1:
case 3:
for (i = 0; i < 4; i++) {
unsigned int b;
b = latched & 0x7F;
b = latched & 0x3F;
if (i >= 2 && !(latchea & 0x2))
b = 0x7F;
setprg8(0x8000 + (i << 13), (i & 1) + ((b << 1) ^ (latched >> 7)));
b = b | 0x07;
setprg8(0x8000 + (i << 13), (i & 1) + (b << 1));
}
break;
}
setchr8(0);
}
static DECLFW(M15Write) {
latchea = A;
latched = V;
// cah4e3 02.10.19 once again, there may be either two similar mapper 15 exist. the one for 110in1 or 168in1 carts with complex multi game features.
// and another implified version for subor/waixing chinese originals and hacks with no different modes, working only in mode 0 and which does not
// expect there is any CHR write protection. protecting CHR writes only for mode 3 fixes the problem, all roms may be run on the same source again.
if((latchea & 3) == 3)
SetupCartCHRMapping(0, CHRptr[0], 0x2000, 0);
else
SetupCartCHRMapping(0, CHRptr[0], 0x2000, 1);
Sync();
}
@@ -70,7 +78,6 @@ static void StateRestore(int version) {
static void M15Power(void) {
latchea = 0x8000;
latched = 0;
setchr8(0);
setprg8r(0x10, 0x6000, 0);
SetReadHandler(0x6000, 0x7FFF, CartBR);
SetWriteHandler(0x6000, 0x7FFF, CartBW);
@@ -101,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);
+226 -229
View File
@@ -1,232 +1,229 @@
/* FCE Ultra - NES/Famicom Emulator
*
* Copyright notice for this file:
* Copyright (C) 2002 Xodnizel 2006 CaH4e3
*
* 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
*
* It seems that 162/163/164 mappers are the same mapper with just different
* mapper modes enabled or disabled in software or hardware, need more nanjing
* carts
*/
#include "mapinc.h"
static uint8 laststrobe, trigger;
static uint8 reg[8];
static uint8 *WRAM = NULL;
static uint32 WRAMSIZE;
static writefunc pcmwrite;
static void (*WSync)(void);
static SFORMAT StateRegs[] =
{
{ &laststrobe, 1, "STB" },
{ &trigger, 1, "TRG" },
{ reg, 8, "REGS" },
{ 0 }
};
static void Sync(void) {
setprg8r(0x10, 0x6000, 0);
setprg32(0x8000, (reg[0] << 4) | (reg[1] & 0xF));
setchr8(0);
}
static void StateRestore(int version) {
WSync();
}
static DECLFR(ReadLow) {
switch (A & 0x7700) {
case 0x5100: return reg[2] | reg[0] | reg[1] | reg[3] ^ 0xff; break;
case 0x5500:
if (trigger)
return reg[2] | reg[1]; // Lei Dian Huang Bi Ka Qiu Chuan Shuo (NJ046) may broke other games
else
return 0;
}
return 4;
}
static void M163HB(void) {
if (reg[1] & 0x80) {
if (scanline == 239) {
setchr4(0x0000, 0);
setchr4(0x1000, 0);
} else if (scanline == 127) {
setchr4(0x0000, 1);
setchr4(0x1000, 1);
}
/*
if(scanline>=127) // Hu Lu Jin Gang (NJ039) (Ch) [!] don't like it
{
setchr4(0x0000,1);
setchr4(0x1000,1);
}
else
{
setchr4(0x0000,0);
setchr4(0x1000,0);
}
*/
}
}
static DECLFW(Write) {
switch (A & 0x7300) {
case 0x5100: reg[0] = V; WSync(); break;
case 0x5000: reg[1] = V; WSync(); break;
case 0x5300: reg[2] = V; break;
case 0x5200: reg[3] = V; WSync(); break;
}
}
static void Power(void) {
memset(reg, 0, 8);
reg[1] = 0xFF;
SetWriteHandler(0x5000, 0x5FFF, Write);
SetReadHandler(0x6000, 0xFFFF, CartBR);
SetWriteHandler(0x6000, 0x7FFF, CartBW);
/* FCE Ultra - NES/Famicom Emulator
*
* Copyright notice for this file:
* Copyright (C) 2002 Xodnizel 2006 CaH4e3
*
* 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
*
* It seems that 162/163/164 mappers are the same mapper with just different
* mapper modes enabled or disabled in software or hardware, need more nanjing
* carts
*/
#include "mapinc.h"
static uint8 laststrobe, trigger;
static uint8 reg[8];
static uint8 *WRAM = NULL;
static uint32 WRAMSIZE=0;
static writefunc pcmwrite;
static void (*WSync)(void);
static SFORMAT StateRegs[] =
{
{ &laststrobe, 1, "STB" },
{ &trigger, 1, "TRG" },
{ reg, 8, "REGS" },
{ 0 }
};
static void Sync(void) {
setprg8r(0x10, 0x6000, 0);
setprg32(0x8000, (reg[0] << 4) | (reg[1] & 0xF));
setchr8(0);
}
static void StateRestore(int version) {
WSync();
}
static DECLFR(ReadLow) {
switch (A & 0x7700) {
case 0x5100: return reg[2] | reg[0] | reg[1] | reg[3] ^ 0xff; break;
case 0x5500:
if (trigger)
return reg[2] | reg[1]; // Lei Dian Huang Bi Ka Qiu Chuan Shuo (NJ046) may broke other games
else
return 0;
}
return 4;
}
static void M163HB(void) {
if (reg[1] & 0x80) {
if (scanline == 239) {
setchr4(0x0000, 0);
setchr4(0x1000, 0);
} else if (scanline == 127) {
setchr4(0x0000, 1);
setchr4(0x1000, 1);
}
/*
if(scanline>=127) // Hu Lu Jin Gang (NJ039) (Ch) [!] don't like it
{
setchr4(0x0000,1);
setchr4(0x1000,1);
}
else
{
setchr4(0x0000,0);
setchr4(0x1000,0);
}
*/
}
}
static DECLFW(Write) {
switch (A & 0x7300) {
case 0x5100: reg[0] = V; WSync(); break;
case 0x5000: reg[1] = V; WSync(); break;
case 0x5300: reg[2] = V; break;
case 0x5200: reg[3] = V; WSync(); break;
}
}
static void Power(void) {
memset(reg, 0, 8);
reg[1] = 0xFF;
SetWriteHandler(0x5000, 0x5FFF, Write);
SetReadHandler(0x6000, 0xFFFF, CartBR);
SetWriteHandler(0x6000, 0x7FFF, CartBW);
FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM);
WSync();
}
static void Close(void) {
if (WRAM)
FCEU_gfree(WRAM);
WRAM = NULL;
}
void Mapper164_Init(CartInfo *info) {
info->Power = Power;
info->Close = Close;
WSync = Sync;
WRAMSIZE = 8192;
WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE);
SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1);
AddExState(WRAM, WRAMSIZE, 0, "WRAM");
if (info->battery) {
info->SaveGame[0] = WRAM;
info->SaveGameLen[0] = WRAMSIZE;
}
GameStateRestore = StateRestore;
AddExState(&StateRegs, ~0, 0, 0);
}
static DECLFW(Write2) {
if (A == 0x5101) {
if (laststrobe && !V) {
trigger ^= 1;
}
laststrobe = V;
} else if (A == 0x5100 && V == 6) //damn thoose protected games
setprg32(0x8000, 3);
else
switch (A & 0x7300) {
case 0x5200: reg[0] = V; WSync(); break;
case 0x5000: reg[1] = V; WSync(); if (!(reg[1] & 0x80) && (scanline < 128)) setchr8(0); /* setchr8(0); */ break;
case 0x5300: reg[2] = V; break;
case 0x5100: reg[3] = V; WSync(); break;
}
}
static void Power2(void) {
memset(reg, 0, 8);
laststrobe = 1;
pcmwrite = GetWriteHandler(0x4011);
SetReadHandler(0x5000, 0x5FFF, ReadLow);
SetWriteHandler(0x5000, 0x5FFF, Write2);
SetReadHandler(0x6000, 0xFFFF, CartBR);
SetWriteHandler(0x6000, 0x7FFF, CartBW);
WSync();
}
static void Close(void) {
if (WRAM)
FCEU_gfree(WRAM);
WRAM = NULL;
}
void Mapper164_Init(CartInfo *info) {
info->Power = Power;
info->Close = Close;
WSync = Sync;
WRAMSIZE = 8192;
WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE);
SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1);
AddExState(WRAM, WRAMSIZE, 0, "WRAM");
if (info->battery) {
info->addSaveGameBuf( WRAM, WRAMSIZE );
}
GameStateRestore = StateRestore;
AddExState(&StateRegs, ~0, 0, 0);
}
static DECLFW(Write2) {
if (A == 0x5101) {
if (laststrobe && !V) {
trigger ^= 1;
}
laststrobe = V;
} else if (A == 0x5100 && V == 6) //damn thoose protected games
setprg32(0x8000, 3);
else
switch (A & 0x7300) {
case 0x5200: reg[0] = V; WSync(); break;
case 0x5000: reg[1] = V; WSync(); if (!(reg[1] & 0x80) && (scanline < 128)) setchr8(0); /* setchr8(0); */ break;
case 0x5300: reg[2] = V; break;
case 0x5100: reg[3] = V; WSync(); break;
}
}
static void Power2(void) {
memset(reg, 0, 8);
laststrobe = 1;
pcmwrite = GetWriteHandler(0x4011);
SetReadHandler(0x5000, 0x5FFF, ReadLow);
SetWriteHandler(0x5000, 0x5FFF, Write2);
SetReadHandler(0x6000, 0xFFFF, CartBR);
SetWriteHandler(0x6000, 0x7FFF, CartBW);
FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM);
WSync();
}
void Mapper163_Init(CartInfo *info) {
info->Power = Power2;
info->Close = Close;
WSync = Sync;
GameHBIRQHook = M163HB;
WRAMSIZE = 8192;
WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE);
SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1);
AddExState(WRAM, WRAMSIZE, 0, "WRAM");
if (info->battery) {
info->SaveGame[0] = WRAM;
info->SaveGameLen[0] = WRAMSIZE;
}
GameStateRestore = StateRestore;
AddExState(&StateRegs, ~0, 0, 0);
}
static void Sync3(void) {
setchr8(0);
setprg8r(0x10, 0x6000, 0);
switch (reg[3] & 7) {
case 0:
case 2: setprg32(0x8000, (reg[0] & 0xc) | (reg[1] & 2) | ((reg[2] & 0xf) << 4)); break;
case 1:
case 3: setprg32(0x8000, (reg[0] & 0xc) | (reg[2] & 0xf) << 4); break;
case 4:
case 6: setprg32(0x8000, (reg[0] & 0xe) | ((reg[1] >> 1) & 1) | ((reg[2] & 0xf) << 4)); break;
case 5:
case 7: setprg32(0x8000, (reg[0] & 0xf) | ((reg[2] & 0xf) << 4)); break;
}
}
static DECLFW(Write3) {
// FCEU_printf("bs %04x %02x\n",A,V);
reg[(A >> 8) & 3] = V;
WSync();
}
static void Power3(void) {
reg[0] = 3;
reg[1] = 0;
reg[2] = 0;
reg[3] = 7;
SetWriteHandler(0x5000, 0x5FFF, Write3);
SetReadHandler(0x6000, 0xFFFF, CartBR);
SetWriteHandler(0x6000, 0x7FFF, CartBW);
WSync();
}
void Mapper163_Init(CartInfo *info) {
info->Power = Power2;
info->Close = Close;
WSync = Sync;
GameHBIRQHook = M163HB;
WRAMSIZE = 8192;
WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE);
SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1);
AddExState(WRAM, WRAMSIZE, 0, "WRAM");
if (info->battery) {
info->addSaveGameBuf( WRAM, WRAMSIZE );
}
GameStateRestore = StateRestore;
AddExState(&StateRegs, ~0, 0, 0);
}
static void Sync3(void) {
setchr8(0);
setprg8r(0x10, 0x6000, 0);
switch (reg[3] & 7) {
case 0:
case 2: setprg32(0x8000, (reg[0] & 0xc) | (reg[1] & 2) | ((reg[2] & 0xf) << 4)); break;
case 1:
case 3: setprg32(0x8000, (reg[0] & 0xc) | (reg[2] & 0xf) << 4); break;
case 4:
case 6: setprg32(0x8000, (reg[0] & 0xe) | ((reg[1] >> 1) & 1) | ((reg[2] & 0xf) << 4)); break;
case 5:
case 7: setprg32(0x8000, (reg[0] & 0xf) | ((reg[2] & 0xf) << 4)); break;
}
}
static DECLFW(Write3) {
// FCEU_printf("bs %04x %02x\n",A,V);
reg[(A >> 8) & 3] = V;
WSync();
}
static void Power3(void) {
reg[0] = 3;
reg[1] = 0;
reg[2] = 0;
reg[3] = 7;
SetWriteHandler(0x5000, 0x5FFF, Write3);
SetReadHandler(0x6000, 0xFFFF, CartBR);
SetWriteHandler(0x6000, 0x7FFF, CartBW);
FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM);
WSync();
}
void UNLFS304_Init(CartInfo *info) {
info->Power = Power3;
info->Close = Close;
WSync = Sync3;
WRAMSIZE = 8192;
WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE);
SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1);
AddExState(WRAM, WRAMSIZE, 0, "WRAM");
if (info->battery) {
info->SaveGame[0] = WRAM;
info->SaveGameLen[0] = WRAMSIZE;
}
GameStateRestore = StateRestore;
AddExState(&StateRegs, ~0, 0, 0);
}
WSync();
}
void UNLFS304_Init(CartInfo *info) {
info->Power = Power3;
info->Close = Close;
WSync = Sync3;
WRAMSIZE = 8192;
WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE);
SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1);
AddExState(WRAM, WRAMSIZE, 0, "WRAM");
if (info->battery) {
info->addSaveGameBuf( WRAM, WRAMSIZE );
}
GameStateRestore = StateRestore;
AddExState(&StateRegs, ~0, 0, 0);
}
+2 -3
View File
@@ -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);
+4 -5
View File
@@ -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]);
@@ -37,8 +37,8 @@ static int32 SensorDelay;
// highly experimental, not actually working, just curious if it hapen to work with some other decoder
// SND Registers
static uint8 pcm_enable = 0;
static int16 pcm_latch = 0x3F6, pcm_clock = 0x3F6;
static writefunc pcmwrite;
//static int16 pcm_latch = 0x3F6, pcm_clock = 0x3F6;
//static writefunc pcmwrite;
static SFORMAT StateRegs[] =
{
@@ -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");
+2 -3
View File
@@ -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);
+27
View File
@@ -18,6 +18,33 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Family Study Box by Fukutake Shoten
*
* REG[0] R dddddddd / W ww---sss
* ddd - TAPE DATA BYTE (ready when IRQ occurs)
* sss - BRAM hi-bank
* ww - PRAM bank
* REG[1] R 0123---- / W ----PPPP
* 0 - ?
* 1 - ?
* 2 - ?
* 3 - ?
* PPPP- PROM bank
* REG[2] R -?--R--- / W A-BC-DEF
* 4 - ?
* R - sb4x power supply status (active low)
* A - ?
* B - ?
* C - ?
* D - ?
* E - ?
* F - ?
*
* BRAM0 4400-4FFF, 3K bank 0 (32K SWRAM) [hardwired]
* BRAMB 5000-5FFF, 4K banks 1-7 (32K SWRAM) [REG[0] W -----sss]
* PRAMB 6000-7FFF, 8K banks 1-3 (32K PRAM) [REG[0] W ww------]
* PROMB 8000-BFFF, 16K banks 1-15 (256K PROM)[REG[1] W ----PPPP]
* PROM0 C000-FFFF, 16K bank 0 (256K PROM) [hardwired]
*
*/
#include "mapinc.h"
+1 -1
View File
@@ -22,7 +22,7 @@
#include "mmc3.h"
static void M187CW(uint32 A, uint8 V) {
if ((A & 0x1000) == ((MMC3_cmd & 0x80) << 5))
if ((A & 0x1000) == static_cast<uint32>((MMC3_cmd & 0x80) << 5))
setchr1(A, V | 0x100);
else
setchr1(A, V);
+85
View File
@@ -0,0 +1,85 @@
/* FCE Ultra - NES/Famicom Emulator
*
* Copyright (C) 2017 FCEUX Team
*
* 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
*
* Magic Kid GooGoo
*/
#include "mapinc.h"
static uint8 prgr, chrr[4];
static uint8 *WRAM = NULL;
static void Mapper190_Sync(void) {
setprg8r(0x10, 0x6000, 0);
setprg16(0x8000, prgr);
setprg16(0xC000, 0);
setchr2(0x0000, chrr[0]);
setchr2(0x0800, chrr[1]);
setchr2(0x1000, chrr[2]);
setchr2(0x1800, chrr[3]);
}
static DECLFW(Mapper190_Write89) { prgr = V&7; Mapper190_Sync(); }
static DECLFW(Mapper190_WriteCD) { prgr = 8|(V&7); Mapper190_Sync(); }
static DECLFW(Mapper190_WriteAB) {
int bank = A&3;
chrr[bank] = V&63;
Mapper190_Sync();
}
static void Mapper190_Power(void) {
FCEU_CheatAddRAM(0x2000 >> 10, 0x6000, WRAM);
SetReadHandler(0x6000, 0xFFFF, CartBR);
SetWriteHandler(0x6000, 0x7FFF, CartBW);
SetWriteHandler(0x8000, 0x9FFF, Mapper190_Write89);
SetWriteHandler(0xA000, 0xBFFF, Mapper190_WriteAB);
SetWriteHandler(0xC000, 0xDFFF, Mapper190_WriteCD);
Mapper190_Sync();
setmirror(MI_V);
}
static void Mapper190_Close(void) {
FCEU_gfree(WRAM);
WRAM = NULL;
}
static void Mapper190_Restore(int) {
Mapper190_Sync();
}
void Mapper190_Init(CartInfo *info) {
info->Power = Mapper190_Power;
info->Close = Mapper190_Close;
GameStateRestore = Mapper190_Restore;
WRAM = (uint8*)FCEU_gmalloc(0x2000);
SetupCartPRGMapping(0x10, WRAM, 0x2000, 1);
chrr[0] = chrr[1] = chrr[2] = chrr[3] = prgr = 0;
AddExState(&prgr, 1, 0, "PRGR");
AddExState(chrr, 4, 0, "CHRR");
AddExState(WRAM, 0x2000, 0, "WRAM");
}
+43 -25
View File
@@ -1,30 +1,40 @@
/* FCE Ultra - NES/Famicom Emulator
*
* Copyright notice for this file:
* Copyright (C) 2011 CaH4e3
*
* 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
*/
*
* Copyright notice for this file:
* Copyright (C) 2011 CaH4e3
* Copyright (C) 2019 Libretro Team
* Copyright (C) 2020
*
* 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
*
* PCB-018 board, discrete multigame cart 110-in-1
*
* Mapper 225
* Mapper 255
*
*/
/* 2020-2-20 - merge mapper 255, re-implement extra RAM */
#include "mapinc.h"
static uint8 prot[4], prg, mode, chr, mirr;
static uint8 extraRAM[4], prg, mode, chr, mirr;
static SFORMAT StateRegs[] =
{
{ prot, 4, "PROT" },
{ extraRAM, 4, "PROT" },
{ &prg, 1, "PRG" },
{ &chr, 1, "CHR" },
{ &mode, 1, "MODE" },
@@ -36,14 +46,15 @@ static void Sync(void) {
if (mode) {
setprg16(0x8000, prg);
setprg16(0xC000, prg);
} else
}
else
setprg32(0x8000, prg >> 1);
setchr8(chr);
setmirror(mirr ^ 1);
}
static DECLFW(M225Write) {
uint32 bank = (A >> 14) & 1;
uint8 bank = (A >> 14) & 1;
mirr = (A >> 13) & 1;
mode = (A >> 12) & 1;
chr = (A & 0x3f) | (bank << 6);
@@ -52,18 +63,21 @@ static DECLFW(M225Write) {
}
static DECLFW(M225LoWrite) {
/* e.g. 115-in-1 [p1][!] CRC32 0xb39d30b4 */
if (A & 0x800) extraRAM[A & 3] = V & 0x0F;
}
static DECLFR(M225LoRead) {
return 0;
if (A & 0x800) return extraRAM[A & 3];
return X.DB;
}
static void M225Power(void) {
prg = 0;
mode = 0;
Sync();
SetReadHandler(0x5000, 0x5FFF, M225LoRead);
SetWriteHandler(0x5000, 0x5FFF, M225LoWrite);
SetReadHandler(0x5000, 0x5fff, M225LoRead);
SetWriteHandler(0x5000, 0x5fff, M225LoWrite);
SetReadHandler(0x8000, 0xFFFF, CartBR);
SetWriteHandler(0x8000, 0xFFFF, M225Write);
}
@@ -84,3 +98,7 @@ void Mapper225_Init(CartInfo *info) {
GameStateRestore = StateRestore;
AddExState(&StateRegs, ~0, 0, 0);
}
void Mapper255_Init(CartInfo *info) {
Mapper225_Init(info);
}
+58 -11
View File
@@ -19,36 +19,79 @@
*/
#include "mapinc.h"
#include "ines.h"
static uint16 cmdreg = 0;
static uint8 openbus = 0;
// For carts with extra 128K prg rom (Contra)
static uint8 unrom = 0;
static uint8 unromData = 0;
static uint32 PRGROMSize = 0;
static uint16 cmdreg;
static SFORMAT StateRegs[] =
{
{ &cmdreg, 2, "CREG" },
{ &openbus, 1, "OB" },
{ &unrom, 1, "UROM" },
{ &unromData, 1, "UDTA" },
{ 0 }
};
static void Sync(void) {
if (cmdreg & 0x400)
setmirror(MI_0);
else
setmirror(((cmdreg >> 13) & 1) ^ 1);
if (cmdreg & 0x800) {
setprg16(0x8000, ((cmdreg & 0x300) >> 3) | ((cmdreg & 0x1F) << 1) | ((cmdreg >> 12) & 1));
setprg16(0xC000, ((cmdreg & 0x300) >> 3) | ((cmdreg & 0x1F) << 1) | ((cmdreg >> 12) & 1));
} else
setprg32(0x8000, ((cmdreg & 0x300) >> 4) | (cmdreg & 0x1F));
if (unrom) {
int PRGPageCount = PRGROMSize / (16 * 1024);
setprg16(0x8000, PRGPageCount & 0xC0 | (unromData & 7));
setprg16(0xC000, PRGPageCount & 0xC0 | 7);
setmirror(MI_V);
} else {
uint8 bank = ((cmdreg & 0x300) >> 3) | (cmdreg & 0x1F);
if (bank >= (PRGROMSize / (32 * 1024))) {
openbus = 1;
} else {
if (cmdreg & 0x400)
setmirror(MI_0);
else
setmirror(((cmdreg >> 13) & 1) ^ 1);
if (cmdreg & 0x800) {
setprg16(0x8000, (bank << 1) | ((cmdreg >> 12) & 1));
setprg16(0xC000, (bank << 1) | ((cmdreg >> 12) & 1));
} else
setprg32(0x8000, bank);
}
}
}
static DECLFR(M235Read) {
if (openbus) {
openbus = 0;
return X.DB;
}
return CartBR(A);
}
static DECLFW(M235Write) {
cmdreg = A;
unromData = V;
Sync();
}
static void M235Reset(void) {
cmdreg = 0;
unromData = 0;
if (PRGROMSize & 0x20000)
unrom = (unrom + 1) & 1;
Sync();
}
static void M235Power(void) {
setchr8(0);
SetWriteHandler(0x8000, 0xFFFF, M235Write);
SetReadHandler(0x8000, 0xFFFF, CartBR);
SetReadHandler(0x8000, 0xFFFF, M235Read);
cmdreg = 0;
unromData = 0;
unrom = 0;
Sync();
}
@@ -57,7 +100,11 @@ static void M235Restore(int version) {
}
void Mapper235_Init(CartInfo *info) {
info->Reset = M235Reset;
info->Power = M235Power;
GameStateRestore = M235Restore;
AddExState(&StateRegs, ~0, 0, 0);
// needs raw, non-pow2 PRGROM size for comparison
PRGROMSize = head.ROM_size * 16384;
}
+2 -3
View File
@@ -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);
+3 -4
View File
@@ -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);
+3 -4
View File
@@ -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);
+6 -5
View File
@@ -1,5 +1,5 @@
/*
Copyright (C) 2012 FCEUX team
Copyright (C) 2012-2017 FCEUX team
This file is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -53,8 +53,8 @@ void Mirror(uint8 value)
static void Sync()
{
int prglo;
int prghi;
int prglo = 0;
int prghi = 0;
int outb = outer << 1;
//this can probably be rolled up, but i have no motivation to do so
@@ -127,20 +127,21 @@ static void Sync()
static DECLFW(WriteEXP)
{
uint32 addr = A;
//uint32 addr = A;
uint8 value = V;
reg = value & 0x81;
}
static DECLFW(WritePRG)
{
uint32 addr = A;
//uint32 addr = A;
uint8 value = V;
switch (reg)
{
case 0x00:
chr = value & 3;
Mirror(value);
Sync();
break;
case 0x01:
prg = value & 15;
+98
View File
@@ -0,0 +1,98 @@
/* FCEUmm - NES/Famicom Emulator
*
* Copyright notice for this file:
* Copyright (C) 2022
*
* 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
*/
#include "mapinc.h"
static uint16 latchAddr;
static uint8 latchData;
static uint8 submapper;
static SFORMAT StateRegs[] =
{
{ &latchAddr, 2, "ADDR" },
{ &latchData, 1, "DATA" },
{ 0 }
};
static void Mapper354_Sync(void)
{
int prg = latchData & 0x3F | latchAddr << 2 & 0x40 | latchAddr >> 5 & 0x80;
switch (latchAddr & 7)
{
case 0: case 4:
setprg32(0x8000, prg >> 1);
break;
case 1:
setprg16(0x8000, prg);
setprg16(0xC000, prg | 7);
break;
case 2: case 6:
setprg8(0x8000, prg << 1 | latchData >> 7);
setprg8(0xA000, prg << 1 | latchData >> 7);
setprg8(0xC000, prg << 1 | latchData >> 7);
setprg8(0xE000, prg << 1 | latchData >> 7);
break;
case 3: case 7:
setprg16(0x8000, prg);
setprg16(0xC000, prg);
break;
case 5:
setprg8(0x6000, prg << 1 | latchData >> 7);
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);
}
static DECLFW(Mapper354_WriteLatch)
{
latchData = V;
latchAddr = A & 0xFFFF;
Mapper354_Sync();
}
static void Mapper354_Reset(void)
{
latchAddr = latchData = 0;
Mapper354_Sync();
}
static void Mapper354_Power(void)
{
latchAddr = latchData = 0;
SetReadHandler(0x6000, 0xFFFF, CartBR);
SetWriteHandler(submapper == 1 ? 0xE000 : 0xF000, 0xFFFF, Mapper354_WriteLatch);
Mapper354_Sync();
}
static void StateRestore(int version) {
Mapper354_Sync();
}
void Mapper354_Init(CartInfo *info)
{
submapper = info->submapper;
info->Power = Mapper354_Power;
info->Reset = Mapper354_Reset;
GameStateRestore = StateRestore;
AddExState(StateRegs, ~0, 0, 0);
}
+7 -1
View File
@@ -22,11 +22,12 @@
#include "mapinc.h"
static uint8 latche;
static uint8 latche, mirr;
static SFORMAT StateRegs[] =
{
{ &latche, 1, "LATC" },
{ &mirr, 1, "MIRR" },
{ 0 }
};
@@ -36,6 +37,11 @@ static void Sync(void) {
}
static DECLFW(M36Write) {
switch((A>>12)&7) { // need to 4-in-1 MGC-26 BMC, doesnt break other games though
case 0: mirr = MI_V; setmirror(mirr); break;
case 4: mirr = MI_H; setmirror(mirr); break;
}
latche = V;
Sync();
}
+2 -3
View File
@@ -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);
+2 -3
View File
@@ -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();
+5
View File
@@ -21,6 +21,7 @@
#include "mapinc.h"
static uint8 preg, mirr;
static int hardmirr;
static SFORMAT StateRegs[] =
{
@@ -35,6 +36,8 @@ static void Sync(void) {
setchr8(0);
if(mirr)
setmirror(mirr);
else
setmirror(hardmirr); // restore hardwired mirroring
}
static DECLFW(M71Write) {
@@ -46,6 +49,7 @@ static DECLFW(M71Write) {
}
static void M71Power(void) {
preg = 0;
mirr = 0;
Sync();
SetReadHandler(0x8000, 0xFFFF, CartBR);
@@ -57,6 +61,7 @@ static void StateRestore(int version) {
}
void Mapper71_Init(CartInfo *info) {
hardmirr = info->mirror;
info->Power = M71Power;
GameStateRestore = StateRestore;
+1 -2
View File
@@ -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);
+76
View File
@@ -0,0 +1,76 @@
/* FCE Ultra - NES/Famicom Emulator
*
* Copyright notice for this file:
* Copyright (C) 2017 CaH4e3
*
* 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
*/
#include "mapinc.h"
static uint8 bios_prg, rom_prg, rom_mode, mirror;
static SFORMAT StateRegs[] =
{
{ &bios_prg, 1, "BREG" },
{ &rom_prg, 1, "RREG" },
{ &rom_mode, 1, "RMODE" },
{ 0 }
};
static void Sync(void) {
setchr8(0);
if(rom_mode&2) {
setprg16r(0,0x8000,(bios_prg&0xF)|(rom_prg&0x70));
} else {
setprg16r(1,0x8000,bios_prg&3);
}
setprg16r(0,0xC000,rom_prg&0x7F);
setmirror(((bios_prg>>4)&1)^1);
}
static DECLFW(BMC80013BWrite) {
uint8 reg = (A>>13)&3;
if(reg == 0) {
bios_prg = V;
} else {
rom_prg = V;
rom_mode = reg;
}
Sync();
}
static void BMC80013BPower(void) {
bios_prg=rom_prg=rom_mode=mirror=0;
Sync();
SetReadHandler(0x8000, 0xFFFF, CartBR);
SetWriteHandler(0x8000, 0xFFFF, BMC80013BWrite);
}
static void BMC80013BReset(void) {
bios_prg=rom_prg=rom_mode=mirror=0;
Sync();
}
static void StateRestore(int version) {
Sync();
}
void BMC80013B_Init(CartInfo *info) {
info->Reset = BMC80013BReset;
info->Power = BMC80013BPower;
GameStateRestore = StateRestore;
AddExState(&StateRegs, ~0, 0, 0);
}
+2 -3
View File
@@ -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);
+1 -2
View File
@@ -19,7 +19,6 @@
*
* Super Game (Sugar Softec) protected mapper
* Pocahontas 2 (Unl) [U][!], etc.
* TODO: 9in1 LION KING HANGS!
*/
#include "mapinc.h"
@@ -139,7 +138,7 @@ static DECLFW(UNL8237Write) {
}
static DECLFW(UNL8237ExWrite) {
switch (A) {
switch (A & 0xF007) {
case 0x5000: EXPREGS[0] = V; FixMMC3PRG(MMC3_cmd); break;
case 0x5001: EXPREGS[1] = V; FixMMC3PRG(MMC3_cmd); FixMMC3CHR(MMC3_cmd); break;
case 0x5007: EXPREGS[2] = V; break;
-6
View File
@@ -1,6 +0,0 @@
import glob
source_list = glob.glob('*.cpp')+glob.glob('*.c')
for x in range(len(source_list)):
source_list[x] = 'boards/' + source_list[x]
Return('source_list')
+1 -2
View File
@@ -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);
+40 -13
View File
@@ -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");
}
@@ -122,7 +122,7 @@ static void UNL43272Sync(void) {
if ((latche & 0x81) == 0x81) {
setprg32(0x8000, (latche & 0x38) >> 3);
} else
FCEU_printf("unrecognized command %04!\n", latche);
FCEU_printf("unrecognized command %04x!\n", latche);
setchr8(0);
setmirror(0);
}
@@ -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) {
@@ -237,13 +254,8 @@ void Mapper200_Init(CartInfo *info) {
//------------------ Map 201 ---------------------------
static void M201Sync(void) {
if (latche & 8) {
setprg32(0x8000, latche & 3);
setchr8(latche & 3);
} else {
setprg32(0x8000, 0);
setchr8(0);
}
setprg32(0x8000, latche & 3);
setchr8(latche & 3);
}
void Mapper201_Init(CartInfo *info) {
@@ -309,8 +321,14 @@ void Mapper212_Init(CartInfo *info) {
//------------------ Map 213 ---------------------------
static void M213Sync(void) {
setprg32(0x8000, (latche >> 1) & 3);
if(latche & 0x40) {
setprg16(0x8000, (latche & 7));
setprg16(0xC000, (latche & 7));
} else {
setprg32(0x8000, (latche >> 1) & 3);
}
setchr8((latche >> 3) & 7);
setmirror(((latche & 1)^((latche >> 6) & 1)) ^ 1);
}
void Mapper213_Init(CartInfo *info) {
@@ -341,12 +359,20 @@ 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;
// 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);
if ((latche >> 7) & 1) {
if (S) {
setprg32(0x8000, p >> 1);
@@ -381,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 ---------------------------
+276 -134
View File
@@ -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[] =
{
@@ -48,120 +48,205 @@ static SFORMAT StateRegs[] =
#define X24C0X_READ 3
#define X24C0X_WRITE 4
static uint8 x24c0x_data[256], x24c0x_state;
static uint8 x24c0x_addr, x24c0x_word, x24c0x_latch, x24c0x_bitcount;
static uint8 x24c0x_sda, x24c0x_scl, x24c0x_out, x24c0x_oe;
static uint8 x24c0x_data[512];
static SFORMAT x24c0xStateRegs[] =
static uint8 x24c01_state;
static uint8 x24c01_addr, x24c01_word, x24c01_latch, x24c01_bitcount;
static uint8 x24c01_sda, x24c01_scl, x24c01_out;
static uint8 x24c02_state;
static uint8 x24c02_addr, x24c02_word, x24c02_latch, x24c02_bitcount;
static uint8 x24c02_sda, x24c02_scl, x24c02_out;
static SFORMAT x24c01StateRegs[] =
{
{ &x24c0x_addr, 1, "ADDR" },
{ &x24c0x_word, 1, "WORD" },
{ &x24c0x_latch, 1, "LATC" },
{ &x24c0x_bitcount, 1, "BITC" },
{ &x24c0x_sda, 1, "SDA" },
{ &x24c0x_scl, 1, "SCL" },
{ &x24c0x_out, 1, "OUT" },
{ &x24c0x_oe, 1, "OE" },
{ &x24c0x_state, 1, "STAT" },
{ &x24c01_addr, 1, "ADDR" },
{ &x24c01_word, 1, "WORD" },
{ &x24c01_latch, 1, "LATC" },
{ &x24c01_bitcount, 1, "BITC" },
{ &x24c01_sda, 1, "SDA" },
{ &x24c01_scl, 1, "SCL" },
{ &x24c01_out, 1, "OUT" },
{ &x24c01_state, 1, "STAT" },
{ 0 }
};
static void x24c0x_init() {
x24c0x_addr = x24c0x_word = x24c0x_latch = x24c0x_bitcount = x24c0x_sda = x24c0x_scl = x24c0x_oe = 0;
x24c0x_state = X24C0X_STANDBY;
static SFORMAT x24c02StateRegs[] =
{
{ &x24c02_addr, 1, "ADDR" },
{ &x24c02_word, 1, "WORD" },
{ &x24c02_latch, 1, "LATC" },
{ &x24c02_bitcount, 1, "BITC" },
{ &x24c02_sda, 1, "SDA" },
{ &x24c02_scl, 1, "SCL" },
{ &x24c02_out, 1, "OUT" },
{ &x24c02_state, 1, "STAT" },
{ 0 }
};
static void x24c01_init() {
x24c01_addr = x24c01_word = x24c01_latch = x24c01_bitcount = x24c01_sda = x24c01_scl = 0;
x24c01_state = X24C0X_STANDBY;
}
static void x24c0x_write(uint8 data) {
uint8 sda = (data >> 6) & 1;
uint8 scl = (data >> 5) & 1;
x24c0x_oe = (data >> 7);
static void x24c02_init() {
x24c02_addr = x24c02_word = x24c02_latch = x24c02_bitcount = x24c02_sda = x24c02_scl = 0;
x24c02_state = X24C0X_STANDBY;
}
if(x24c0x_scl && scl) {
if(x24c0x_sda && !sda) { // START
x24c0x_state = X24C0X_ADDRESS;
x24c0x_bitcount = 0;
x24c0x_addr = 0;
} else if(!x24c0x_sda && sda) { //STOP
x24c0x_state = X24C0X_STANDBY;
static void x24c01_write(uint8 data) {
uint8 scl = (data >> 5) & 1;
uint8 sda = (data >> 6) & 1;
if(x24c01_scl && scl) {
if(x24c01_sda && !sda) { // START
x24c01_state = X24C0X_ADDRESS;
x24c01_bitcount = 0;
x24c01_addr = 0;
} else if(!x24c01_sda && sda) { //STOP
x24c01_state = X24C0X_STANDBY;
}
} else if(!x24c0x_scl && scl) { // RISING EDGE
switch(x24c0x_state) {
} else if(!x24c01_scl && scl) { // RISING EDGE
switch(x24c01_state) {
case X24C0X_ADDRESS:
if(x24c0x_bitcount < 7) {
x24c0x_addr <<= 1;
x24c0x_addr |= sda;
if(x24c01_bitcount < 7) {
x24c01_addr <<= 1;
x24c01_addr |= sda;
} else {
if(!x24c02) // X24C01 mode
x24c0x_word = x24c0x_addr;
if(sda) { // READ COMMAND
x24c0x_state = X24C0X_READ;
} else { // WRITE COMMAND
if(x24c02) // X24C02 mode
x24c0x_state = X24C0X_WORD;
else
x24c0x_state = X24C0X_WRITE;
}
x24c01_word = x24c01_addr;
if(sda) // READ COMMAND
x24c01_state = X24C0X_READ;
else // WRITE COMMAND
x24c01_state = X24C0X_WRITE;
}
x24c0x_bitcount++;
break;
case X24C0X_WORD:
if(x24c0x_bitcount == 8) { // ACK
x24c0x_word = 0;
x24c0x_out = 0;
} else { // WORD ADDRESS INPUT
x24c0x_word <<= 1;
x24c0x_word |= sda;
if(x24c0x_bitcount == 16) { // END OF ADDRESS INPUT
x24c0x_bitcount = 7;
x24c0x_state = X24C0X_WRITE;
}
}
x24c0x_bitcount++;
x24c01_bitcount++;
break;
case X24C0X_READ:
if (x24c0x_bitcount == 8) { // ACK
x24c0x_out = 0;
x24c0x_latch = x24c0x_data[x24c0x_word];
x24c0x_bitcount = 0;
} else { // REAL OUTPUT
x24c0x_out = x24c0x_latch >> 7;
x24c0x_latch <<= 1;
x24c0x_bitcount++;
if(x24c0x_bitcount == 8) {
x24c0x_word++;
x24c0x_word &= 0xff;
if (x24c01_bitcount == 8) { // ACK
x24c01_out = 0;
x24c01_latch = x24c0x_data[x24c01_word];
x24c01_bitcount = 0;
} else { // REAL OUTPUT
x24c01_out = x24c01_latch >> 7;
x24c01_latch <<= 1;
x24c01_bitcount++;
if(x24c01_bitcount == 8) {
x24c01_word++;
x24c01_word &= 0xff;
}
}
break;
case X24C0X_WRITE:
if (x24c0x_bitcount == 8) { // ACK
x24c0x_out = 0;
x24c0x_latch = 0;
x24c0x_bitcount = 0;
} else { // REAL INPUT
x24c0x_latch <<= 1;
x24c0x_latch |= sda;
x24c0x_bitcount++;
if(x24c0x_bitcount == 8) {
x24c0x_data[x24c0x_word] = x24c0x_latch;
x24c0x_word++;
x24c0x_word &= 0xff;
if (x24c01_bitcount == 8) { // ACK
x24c01_out = 0;
x24c01_latch = 0;
x24c01_bitcount = 0;
} else { // REAL INPUT
x24c01_latch <<= 1;
x24c01_latch |= sda;
x24c01_bitcount++;
if(x24c01_bitcount == 8) {
x24c0x_data[x24c01_word] = x24c01_latch;
x24c01_word++;
x24c01_word &= 0xff;
}
}
break;
}
}
x24c0x_sda = sda;
x24c0x_scl = scl;
x24c01_sda = sda;
x24c01_scl = scl;
}
static uint8 x24c0x_read() {
return x24c0x_out << 4;
static void x24c02_write(uint8 data) {
uint8 scl = (data >> 5) & 1;
uint8 sda = (data >> 6) & 1;
if (x24c02_scl && scl) {
if (x24c02_sda && !sda) { // START
x24c02_state = X24C0X_ADDRESS;
x24c02_bitcount = 0;
x24c02_addr = 0;
} else if (!x24c02_sda && sda) { //STOP
x24c02_state = X24C0X_STANDBY;
}
} else if (!x24c02_scl && scl) { // RISING EDGE
switch (x24c02_state) {
case X24C0X_ADDRESS:
if (x24c02_bitcount < 7) {
x24c02_addr <<= 1;
x24c02_addr |= sda;
} else {
if (sda) // READ COMMAND
x24c02_state = X24C0X_READ;
else // WRITE COMMAND
x24c02_state = X24C0X_WORD;
}
x24c02_bitcount++;
break;
case X24C0X_WORD:
if (x24c02_bitcount == 8) { // ACK
x24c02_word = 0;
x24c02_out = 0;
} else { // WORD ADDRESS INPUT
x24c02_word <<= 1;
x24c02_word |= sda;
if (x24c02_bitcount == 16) {// END OF ADDRESS INPUT
x24c02_bitcount = 7;
x24c02_state = X24C0X_WRITE;
}
}
x24c02_bitcount++;
break;
case X24C0X_READ:
if (x24c02_bitcount == 8) { // ACK
x24c02_out = 0;
x24c02_latch = x24c0x_data[x24c02_word|0x100];
x24c02_bitcount = 0;
} else { // REAL OUTPUT
x24c02_out = x24c02_latch >> 7;
x24c02_latch <<= 1;
x24c02_bitcount++;
if (x24c02_bitcount == 8) {
x24c02_word++;
x24c02_word &= 0xff;
}
}
break;
case X24C0X_WRITE:
if (x24c02_bitcount == 8) { // ACK
x24c02_out = 0;
x24c02_latch = 0;
x24c02_bitcount = 0;
} else { // REAL INPUT
x24c02_latch <<= 1;
x24c02_latch |= sda;
x24c02_bitcount++;
if (x24c02_bitcount == 8) {
x24c0x_data[x24c02_word|0x100] = x24c02_latch;
x24c02_word++;
x24c02_word &= 0xff;
}
}
break;
}
}
x24c02_sda = sda;
x24c02_scl = scl;
}
//
static void SyncMirror(void) {
switch (reg[9] & 3) {
case 0: setmirror(MI_V); break;
case 1: setmirror(MI_H); break;
case 2: setmirror(MI_0); break;
case 3: setmirror(MI_1); break;
}
}
static void Sync(void) {
if (is153) {
int base = (reg[0] & 1) << 4;
@@ -174,12 +259,7 @@ static void Sync(void) {
setprg16(0x8000, reg[8]);
setprg16(0xC000, ~0);
}
switch (reg[9] & 3) {
case 0: setmirror(MI_V); break;
case 1: setmirror(MI_H); break;
case 2: setmirror(MI_0); break;
case 3: setmirror(MI_1); break;
}
SyncMirror();
}
static DECLFW(BandaiWrite) {
@@ -192,12 +272,15 @@ static DECLFW(BandaiWrite) {
case 0x0A: X6502_IRQEnd(FCEU_IQEXT); IRQa = V & 1; IRQCount = IRQLatch; break;
case 0x0B: IRQLatch &= 0xFF00; IRQLatch |= V; break;
case 0x0C: IRQLatch &= 0xFF; IRQLatch |= V << 8; break;
case 0x0D: x24c0x_write(V); break;
case 0x0D: if(x24c02) x24c02_write(V); else x24c01_write(V); break;
}
}
static DECLFR(BandaiRead) {
return (X.DB & 0xEF) | x24c0x_read();
if(x24c02)
return (X.DB & 0xEF) | (x24c02_out << 4);
else
return (X.DB & 0xEF) | (x24c01_out << 4);
}
static void BandaiIRQHook(int a) {
@@ -213,7 +296,10 @@ static void BandaiIRQHook(int a) {
static void BandaiPower(void) {
IRQa = 0;
x24c0x_init();
if(x24c02)
x24c02_init();
else
x24c01_init();
Sync();
SetReadHandler(0x6000, 0x7FFF, BandaiRead);
SetReadHandler(0x8000, 0xFFFF, CartBR);
@@ -231,12 +317,11 @@ void Mapper16_Init(CartInfo *info) {
MapIRQHook = BandaiIRQHook;
info->battery = 1;
info->SaveGame[0] = x24c0x_data;
info->SaveGameLen[0] = 256;
info->addSaveGameBuf( x24c0x_data + 256, 256 );
AddExState(x24c0x_data, 256, 0, "DATA");
AddExState(&x24c02StateRegs, ~0, 0, 0);
GameStateRestore = StateRestore;
AddExState(&x24c0xStateRegs, ~0, 0, 0);
AddExState(&StateRegs, ~0, 0, 0);
}
@@ -247,12 +332,11 @@ 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);
GameStateRestore = StateRestore;
AddExState(&x24c0xStateRegs, ~0, 0, 0);
AddExState(&StateRegs, ~0, 0, 0);
}
@@ -292,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;
@@ -307,7 +390,9 @@ static int BarcodeReadPos;
static int BarcodeCycleCount;
static uint32 BarcodeOut;
int FCEUI_DatachSet(const uint8 *rcode) {
// #define INTERL2OF5
int FCEUI_DatachSet(uint8 *rcode) {
int prefix_parity_type[10][6] = {
{ 0, 0, 0, 0, 0, 0 }, { 0, 0, 1, 0, 1, 1 }, { 0, 0, 1, 1, 0, 1 }, { 0, 0, 1, 1, 1, 0 },
{ 0, 1, 0, 0, 1, 1 }, { 0, 1, 1, 0, 0, 1 }, { 0, 1, 1, 1, 0, 0 }, { 0, 1, 0, 1, 0, 1 },
@@ -330,6 +415,7 @@ int FCEUI_DatachSet(const uint8 *rcode) {
};
uint8 code[13 + 1];
uint32 tmp_p = 0;
uint32 csum = 0;
int i, j;
int len;
@@ -341,18 +427,46 @@ int FCEUI_DatachSet(const uint8 *rcode) {
}
if (len != 13 && len != 12 && len != 8 && len != 7) return(0);
#define BS(x) BarcodeData[tmp_p] = x; tmp_p++
#define BS(x) BarcodeData[tmp_p] = x; tmp_p++
for (j = 0; j < 32; j++) {
for (j = 0; j < 32; j++) { // delay before sending a code
BS(0x00);
}
/* Left guard bars */
#ifdef INTERL2OF5
BS(1); BS(1); BS(0); BS(0); // 1
BS(1); BS(1); BS(0); BS(0); // 1
BS(1); BS(1); BS(0); BS(0); // 1
BS(1); BS(1); BS(0); BS(0); // 1
BS(1); BS(1); BS(0); BS(0); // 1
BS(1); BS(0); BS(0); // 0
BS(1); BS(0); BS(0); // 0
BS(1); BS(0); BS(0); // 0
BS(1); BS(0); BS(0); // 0
BS(1); BS(0); BS(0); // 0
BS(1); BS(0); BS(0); // 0
BS(1); BS(0); BS(0); // 0
BS(1); BS(0); BS(0); // 0
BS(1); BS(0); BS(0); // 0
BS(1); BS(0); BS(0); // 0
BS(1); BS(0); BS(0); // 0
BS(1); BS(0); BS(0); // 0
BS(1); BS(0); BS(0); // 0
BS(1); BS(0); BS(0); // 0
BS(1); BS(0); BS(0); // 0
BS(1); BS(0); BS(0); // 0
BS(1); BS(0); BS(0); // 0
BS(1); BS(0); BS(0); // 0
BS(1); BS(0); BS(0); // 0
BS(1); BS(0); BS(0); // 0
BS(1); BS(0); BS(0); // 0 cs
BS(1); BS(1); BS(0); BS(0); // 1
#else
// Left guard bars
BS(1); BS(0); BS(1);
if (len == 13 || len == 12) {
uint32 csum;
for (i = 0; i < 6; i++)
if (prefix_parity_type[code[0]][i]) {
for (j = 0; j < 7; j++) {
@@ -362,53 +476,53 @@ int FCEUI_DatachSet(const uint8 *rcode) {
for (j = 0; j < 7; j++) {
BS(data_left_odd[code[i + 1]][j]);
}
/* Center guard bars */
// Center guard bars
BS(0); BS(1); BS(0); BS(1); BS(0);
for (i = 7; i < 12; i++)
for (j = 0; j < 7; j++) {
BS(data_right[code[i]][j]);
}
csum = 0;
for (i = 0; i < 12; i++) csum += code[i] * ((i & 1) ? 3 : 1);
csum = (10 - (csum % 10)) % 10;
// Calc and write down the control code if not assigned, instead, send code as is
// Battle Rush uses modified type of codes with different control code calculation
if (len == 12) {
for (i = 0; i < 12; i++)
csum += code[i] * ((i & 1) ? 3 : 1);
csum = (10 - (csum % 10)) % 10;
rcode[12] = csum + 0x30; // update check code to the input string as well
rcode[13] = 0;
code[12] = csum;
}
for (j = 0; j < 7; j++) {
BS(data_right[csum][j]);
BS(data_right[code[12]][j]);
}
} else if (len == 8 || len == 7) {
uint32 csum = 0;
for (i = 0; i < 7; i++) csum += (i & 1) ? code[i] : (code[i] * 3);
csum = (10 - (csum % 10)) % 10;
for (i = 0; i < 4; i++)
for (j = 0; j < 7; j++) {
BS(data_left_odd[code[i]][j]);
}
/* Center guard bars */
// Center guard bars
BS(0); BS(1); BS(0); BS(1); BS(0);
for (i = 4; i < 7; i++)
for (j = 0; j < 7; j++) {
BS(data_right[code[i]][j]);
}
csum = 0;
for (i = 0; i < 7; i++)
csum += (i & 1) ? code[i] : (code[i] * 3);
csum = (10 - (csum % 10)) % 10;
rcode[7] = csum + 0x30; // update check code to the input string as well
rcode[8] = 0;
for (j = 0; j < 7; j++) {
BS(data_right[csum][j]);
}
}
/* Right guard bars */
// Right guard bars
BS(1); BS(0); BS(1);
#endif
for (j = 0; j < 32; j++) {
BS(0x00);
}
BS(0xFF);
#undef BS
@@ -419,6 +533,26 @@ int FCEUI_DatachSet(const uint8 *rcode) {
return(1);
}
static void BarcodeSync(void) {
setchr8(0);
setprg16(0x8000, (reg[8] & 0x0F));
setprg16(0xC000, 0x0F);
SyncMirror();
}
static DECLFW(BarcodeWrite) {
A &= 0x0F;
switch (A) {
case 0x00: reg[0] = (V & 8) << 2; x24c01_write(reg[0xD] | reg[0]); break; // extra EEPROM x24C01 used in Battle Rush mini-cart
case 0x08:
case 0x09: reg[A] = V; BarcodeSync(); break;
case 0x0A: X6502_IRQEnd(FCEU_IQEXT); IRQa = V & 1; IRQCount = IRQLatch; break;
case 0x0B: IRQLatch &= 0xFF00; IRQLatch |= V; break;
case 0x0C: IRQLatch &= 0xFF; IRQLatch |= V << 8; break;
case 0x0D: reg[0xD] = V & (~0x20); x24c01_write(reg[0xD] | reg[0]); x24c02_write(V); break;
}
}
static void BarcodeIRQHook(int a) {
BandaiIRQHook(a);
@@ -436,7 +570,7 @@ static void BarcodeIRQHook(int a) {
}
static DECLFR(BarcodeRead) {
return BarcodeOut;
return (X.DB & 0xE7) | ((x24c02_out | x24c01_out) << 4) | BarcodeOut;
}
static void M157Power(void) {
@@ -446,20 +580,28 @@ static void M157Power(void) {
BarcodeOut = 0;
BarcodeCycleCount = 0;
Sync();
x24c01_init();
x24c02_init();
BarcodeSync();
SetWriteHandler(0x6000, 0xFFFF, BandaiWrite);
SetReadHandler(0x6000, 0x7FFF, BarcodeRead);
SetReadHandler(0x8000, 0xFFFF, CartBR);
SetWriteHandler(0x8000, 0xFFFF, BarcodeWrite);
}
void Mapper157_Init(CartInfo *info) {
is153 = 1;
x24c02 = 1;
info->Power = M157Power;
MapIRQHook = BarcodeIRQHook;
GameInfo->cspecial = SIS_DATACH;
info->battery = 1;
info->addSaveGameBuf( x24c0x_data, 512 );
AddExState(x24c0x_data, 512, 0, "DATA");
AddExState(&x24c01StateRegs, ~0, 0, 0);
AddExState(&x24c02StateRegs, ~0, 0, 0);
GameStateRestore = StateRestore;
GameStateRestore = StateRestore;
AddExState(&StateRegs, ~0, 0, 0);
}
+6 -6
View File
@@ -84,12 +84,12 @@ byte_8C29: .BYTE 0,$76, 0, 0, 8
byte_8CC6: .BYTE 0,$78, 0, 0,$12
*/
static uint8 sim0reset[0x1F] = {
0x3B, 0xE9, 0x00, 0xFF, 0xC1, 0x10, 0x31, 0xFE,
0x55, 0xC8, 0x10, 0x20, 0x55, 0x47, 0x4F, 0x53,
0x56, 0x53, 0x43, 0xAD, 0x10, 0x10, 0x10, 0x10,
0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10
};
//static uint8 sim0reset[0x1F] = {
// 0x3B, 0xE9, 0x00, 0xFF, 0xC1, 0x10, 0x31, 0xFE,
// 0x55, 0xC8, 0x10, 0x20, 0x55, 0x47, 0x4F, 0x53,
// 0x56, 0x53, 0x43, 0xAD, 0x10, 0x10, 0x10, 0x10,
// 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10
//};
static void Sync(void) {
setprg32(0x8000, prg_reg);
+164
View File
@@ -0,0 +1,164 @@
/* FCE Ultra - NES/Famicom Emulator
*
* Copyright notice for this file:
* Copyright (C) 2020 CaH4e3
*
* 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
*
* Double Dragon 310000-in-1 (4040R)
* 700000-in-1 (BS-400R)(Unl)
*/
#include "mapinc.h"
#include "mmc3.h"
static uint8 pointer;
static uint8 offset;
static uint8 *WRAM = NULL;
static uint32 WRAMSIZE;
static int getPRGBankBS4XXXR(int bank)
{
if (((~bank) & 1) && (pointer & 0x40))
bank ^= 2;
return (bank & 2) ? (0xFE | (bank & 1)) : EXPREGS[4 | (bank & 1)];
}
static void BS4XXXRPW(uint32 A, uint8 V) {
if ((EXPREGS[3] >> 4) & 0x01)
{
int AND = ((EXPREGS[0] >> 1) & 1) ? 0x0F : 0x0F;
int OR = (EXPREGS[0] & 7) << 4;
int bank0 = getPRGBankBS4XXXR(0);
int bank1 = getPRGBankBS4XXXR(1);
if (!((EXPREGS[3] >> 1) & 1)) //16K Mode
{
setprg8(0x8000, ((bank0) & AND) | OR);
setprg8(0xA000, ((bank1) & AND) | OR);
setprg8(0xC000, ((bank0) & AND) | OR);
setprg8(0xE000, ((bank1) & AND) | OR);
}
else // 32K Mode
{
setprg8(0x8000, ((bank0) & AND) | OR);
setprg8(0xA000, ((bank1) & AND) | OR);
setprg8(0xC000, ((bank0 | 2) & AND) | OR);
setprg8(0xE000, ((bank1 | 2) & AND) | OR);
}
}
else // MMC3 Mode
{
int prgAND = ((EXPREGS[0] >> offset) & 1) ? 0x0F : 0x1F;
int prgOR = (EXPREGS[0] & 7) << 4;
setprg8(A, (V & prgAND) | (prgOR));
}
setprg8r(0x10, 0x6000, 0);
}
static void BS4XXXRCW(uint32 A, uint8 V) {
if ((EXPREGS[3] >> 4) & 1)
{
int AND = ((EXPREGS[0] >> 1) & 1) ? 0x0F : 0x0F;
int bank = EXPREGS[2] & AND;
int chrOR = ((EXPREGS[0] >> 3) & 7) << 4;
setchr8((bank) | (chrOR));
}
else
{
int chrAND = ((EXPREGS[0] >> 1) & 1) ? 0xFF : 0xFF;
int chrOR = ((EXPREGS[0] >> 3) & 7) << 7;
setchr1(A, (V & chrAND) | (chrOR));
}
}
static DECLFW(BS4XXXRHiWrite) {
// FCEU_printf("w: %04x-%02x\n",A,V)
if (A==0x8000)
{
pointer = MMC3_cmd ^ V;
}
else if (A == 0x8001)
{
if((MMC3_cmd & 7) > 5)
EXPREGS[4|(MMC3_cmd & 1)] = V;
}
MMC3_CMDWrite(A, V);
}
static DECLFW(BS4XXXRLoWrite) {
// FCEU_printf("w: %04x-%02x\n", A, V);
if (A & 0x800)
{
if (!(EXPREGS[3] & 0x80)) {
EXPREGS[A & 0x03] = V;
FixMMC3PRG(MMC3_cmd);
FixMMC3CHR(MMC3_cmd);
}
else if (EXPREGS[3] & 0x10)
{
EXPREGS[A & 0x03] = V;
FixMMC3PRG(MMC3_cmd);
FixMMC3CHR(MMC3_cmd);
}
else
WRAM[A - 0x6000] = V;
}
else
WRAM[A - 0x6000] = V;
}
static void BSXXXXRPower(void) {
EXPREGS[0] = EXPREGS[1] = EXPREGS[2] = EXPREGS[3] = EXPREGS[4] = EXPREGS[5] = 0;
GenMMC3Power();
SetReadHandler(0x6000, 0x7FFF, CartBR);
SetWriteHandler(0x6000, 0x7FFF, BS4XXXRLoWrite);
SetWriteHandler(0x8000, 0x9FFF, BS4XXXRHiWrite);
FixMMC3PRG(MMC3_cmd);
FixMMC3CHR(MMC3_cmd);
}
static void BS4XXXRClose(void) {
if (WRAM)
FCEU_gfree(WRAM);
WRAM = NULL;
}
void BSXXXXR_Init(CartInfo *info) {
GenMMC3_Init(info, 512, 256, 8, 0);
cwrap = BS4XXXRCW;
pwrap = BS4XXXRPW;
info->Power = BSXXXXRPower;
info->Close = BS4XXXRClose;
WRAMSIZE = 8192;
WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE);
SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1);
AddExState(WRAM, WRAMSIZE, 0, "WRAM");
AddExState(EXPREGS, 8, 0, "EXPR");
}
void BS400R_Init(CartInfo *info) {
offset = 1;
BSXXXXR_Init(info);
}
void BS4040R_Init(CartInfo *info) {
offset = 6;
BSXXXXR_Init(info);
}
+269
View File
@@ -0,0 +1,269 @@
/* 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
*/
// mapper 111 - Cheapocabra board by Memblers
// http://forums.nesdev.com/viewtopic.php?p=146039
//
// 512k PRG-ROM in 32k pages (flashable if battery backed is specified)
// 32k CHR-RAM used as:
// 2 x 8k pattern pages
// 2 x 8k nametable pages
//
// Notes:
// - CHR-RAM for nametables maps to $3000-3FFF as well, but FCEUX internally mirrors to 4k?
#include "mapinc.h"
#include "../ines.h"
static uint8 reg;
static uint8 *CHRRAM = NULL;
const uint32 CHRRAMSIZE = 1024 * 32;
static bool flash = false;
static uint8 flash_mode;
static uint8 flash_sequence;
static uint8 flash_id;
static uint8 *FLASHROM = NULL;
const uint32 FLASHROMSIZE = 1024 * 512;
static SFORMAT StateRegs[] =
{
{ &reg, 1, "REG" },
{ 0 }
};
static SFORMAT FlashRegs[] =
{
{ &flash_mode, 1, "FMOD" },
{ &flash_sequence, 1, "FSEQ" },
{ &flash_id, 1, "FMID" },
{ 0 }
};
static void Sync(void) {
// bit 7 controls green LED
// bit 6 controls red LED
int nt = (reg & 0x20) ? 8192 : 0; // bit 5 controls 8k nametable page
int chr = (reg & 0x10) ? 1 : 0; // bit 4 selects 8k CHR page
int prg = (reg & 0x0F); // bits 0-3 select 32k PRG page
nt += (16 * 1024);
for (int n=0; n<4; ++n)
{
setntamem(CHRRAM + nt + (1024 * n),1,n);
}
setchr8r(0x10, chr);
uint32 prg_chip = flash ? 0x10 : 0;
setprg32r(prg_chip,0x8000,prg);
}
static DECLFW(M111Write) {
if ((A >= 0x5000 && A <= 0x5FFF) || (A >= 0x7000 && A <= 0x7FFF))
{
reg = V;
Sync();
}
}
static DECLFR(M111FlashID)
{
// Software ID mode is undefined by the datasheet for all but the lowest 2 addressable bytes,
// but some tests of the chip currently being used found it repeats in 512-byte patterns.
// http://forums.nesdev.com/viewtopic.php?p=178728#p178728
uint32 aid = A & 0x1FF;
switch (aid)
{
case 0: return 0xBF;
case 1: return 0xB7;
default: return 0xFF;
}
}
void M111FlashIDEnter()
{
if (flash_id) return;
flash_id = 1;
SetReadHandler(0x8000,0xFFFF,M111FlashID);
}
void M111FlashIDExit()
{
if (!flash_id) return;
flash_id = 0;
SetReadHandler(0x8000,0xFFFF,CartBR);
}
static DECLFW(M111Flash) {
if (A < 0x8000 || A > 0xFFFF) return;
uint32 flash_addr = ((reg & 0x0F) << 15) | (A & 0x7FFF);
uint32 command_addr = flash_addr & 0x7FFF;
enum
{
FLASH_MODE_READY = 0,
FLASH_MODE_COMMAND,
FLASH_MODE_BYTE_WRITE,
FLASH_MODE_ERASE,
};
switch (flash_mode)
{
default:
case FLASH_MODE_READY:
if (command_addr == 0x5555 && V == 0xAA)
{
flash_mode = FLASH_MODE_COMMAND;
flash_sequence = 0;
}
else if (V == 0xF0)
{
M111FlashIDExit();
}
break;
case FLASH_MODE_COMMAND:
if (flash_sequence == 0)
{
if (command_addr == 0x2AAA && V == 0x55)
flash_sequence = 1;
else
flash_mode = FLASH_MODE_READY;
}
else if (flash_sequence == 1)
{
if (command_addr == 0x5555)
{
flash_sequence = 0;
switch (V)
{
default: flash_mode = FLASH_MODE_READY; break;
case 0xA0: flash_mode = FLASH_MODE_BYTE_WRITE; break;
case 0x80: flash_mode = FLASH_MODE_ERASE; break;
case 0x90: M111FlashIDEnter(); flash_mode = FLASH_MODE_READY; break;
case 0xF0: M111FlashIDExit(); flash_mode = FLASH_MODE_READY; break;
}
}
else
flash_mode = FLASH_MODE_READY;
}
else
flash_mode = FLASH_MODE_READY; // should be unreachable
break;
case FLASH_MODE_BYTE_WRITE:
FLASHROM[flash_addr] &= V;
flash_mode = FLASH_MODE_READY;
break;
case FLASH_MODE_ERASE:
if (flash_sequence == 0)
{
if (command_addr == 0x5555 && V == 0xAA)
flash_sequence = 1;
else
flash_mode = FLASH_MODE_READY;
}
else if (flash_sequence == 1)
{
if (command_addr == 0x2AAA && V == 0x55)
flash_sequence = 2;
else
flash_mode = FLASH_MODE_READY;
}
else if (flash_sequence == 2)
{
if (command_addr == 0x5555 && V == 0x10) // erase chip
{
memset(FLASHROM, 0xFF, FLASHROMSIZE);
}
else if (V == 0x30) // erase 4k sector
{
uint32 sector = flash_addr & 0x7F000;
memset(FLASHROM + sector, 0xFF, 1024 * 4);
}
flash_mode = FLASH_MODE_READY;
}
else
flash_mode = FLASH_MODE_READY; // should be unreachable
break;
}
}
static void M111Power(void) {
reg = 0xFF;
Sync();
SetReadHandler(0x8000, 0xffff, CartBR);
SetWriteHandler(0x5000, 0x5fff, M111Write);
SetWriteHandler(0x7000, 0x7fff, M111Write);
if (flash)
{
flash_mode = 0;
flash_sequence = 0;
flash_id = false;
SetWriteHandler(0x8000, 0xFFFF, M111Flash);
}
}
static void M111Close(void) {
if (CHRRAM)
FCEU_gfree(CHRRAM);
CHRRAM = NULL;
if (FLASHROM)
FCEU_gfree(FLASHROM);
FLASHROM = NULL;
}
static void StateRestore(int version) {
Sync();
}
void Mapper111_Init(CartInfo *info) {
info->Power = M111Power;
info->Close = M111Close;
CHRRAM = (uint8*)FCEU_gmalloc(CHRRAMSIZE);
SetupCartCHRMapping(0x10, CHRRAM, CHRRAMSIZE, 1);
GameStateRestore = StateRestore;
AddExState(&StateRegs, ~0, 0, 0);
AddExState(CHRRAM, CHRRAMSIZE, 0, "CRAM");
flash = (info->battery != 0);
if (flash)
{
FLASHROM = (uint8*)FCEU_gmalloc(FLASHROMSIZE);
info->addSaveGameBuf( FLASHROM, FLASHROMSIZE );
AddExState(FLASHROM, FLASHROMSIZE, 0, "FROM");
AddExState(&FlashRegs, ~0, 0, 0);
// copy PRG ROM into FLASHROM, use it instead of PRG ROM
const uint32 PRGSIZE = ROM_size * 16 * 1024;
for (uint32 w=0, r=0; w<FLASHROMSIZE; ++w)
{
FLASHROM[w] = ROM[r];
++r;
if (r >= PRGSIZE) r = 0;
}
SetupCartPRGMapping(0x10, FLASHROM, FLASHROMSIZE, 0);
}
}
+409 -71
View File
@@ -1,7 +1,7 @@
/* FCE Ultra - NES/Famicom Emulator
*
* Copyright notice for this file:
* Copyright (C) 2015 CaH4e3, ClusteR
* Copyright (C) 2018 CaH4e3, Cluster
*
* 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
@@ -17,38 +17,148 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* CoolBoy 400-in-1 FK23C-mimic mapper 16Mb/32Mb PROM + 128K/256K CHR RAM, optional SRAM, optional NTRAM
* only MMC3 mode
* SMD132 and SMD133 ASICs, MMC3 clones that can address up to 32 MiB of PRG-ROM, 256 KiB of CHR-RAM, and 8 KiB of WRAM.
*
* 6000 (xx76x210) | 0xC0
* 6001 (xxx354x)
* 6002 = 0
* 6003 = 0
* COOLBOY cartridges use registers at address $6xxx
* MINDKIDS cartridges use a solder pad labelled "5/6K" to select between $5000 and $6000
*
* $xxx0
* 7 bit 0
* ---- ----
* ABCC DEEE
* |||| ||||
* |||| |+++-- PRG offset (PRG A19, A18, A17)
* |||| +----- Alternate CHR A17
* ||++------- PRG offset (PRG A24, A23), CHR offset (CHR A19, A18)
* |+--------- PRG mask (PRG A17 from 0: MMC3; 1: offset)
* +---------- CHR mask (CHR A17 from 0: MMC3; 1: alternate)
*
* $xxx1
* 7 bit 0
* ---- ----
* GHIJ KKLx
* |||| |||
* |||| ||+--- GNROM mode bank PRG size (1: 32 KiB bank, PRG A14=CPU A14; 0: 16 KiB bank, PRG A14=offset A14)
* |||+-++---- PRG offset (in order: PRG A20, A22, A21)
* ||+-------- PRG mask (PRG A20 from 0: offset; 1: MMC3)
* |+--------- PRG mask (PRG A19 from 0: offset; 1: MMC3)
* +---------- PRG mask (PRG A18 from 0: MMC3; 1: offset)
*
* $xxx2
* 7 bit 0
* ---- ----
* xxxx MMMM
* ||||
* ++++-- CHR offset for GNROM mode (CHR A16, A15, A14, A13)
*
* $xxx3
* 7 bit 0
* ---- ----
* NPZP QQRx
* |||| |||
* |||| +++--- PRG offset for GNROM mode (PRG A16, A15, A14)
* |||+------- 1: GNROM mode; 0: MMC3 mode
* |||| (1: PRG A16...13 from QQ, L, R, CPU A14, A13 + CHR A16...10 from MMMM, PPU A12...10;
* |||| 0: PRG A16...13 from MMC3 + CHR A16...A10 from MMC3 )
* ||+-------- 1: Also enable PRG RAM in $5000-$5FFF
* |+-+------- Banking mode
* |+--------- "Weird MMC3 mode"
* +---------- Lockout (prevent further writes to all registers but the one at $xxx2, only works in MMC3 mode)
*
* Also some new cartridges from MINDKIDS have /WE and /OE pins connected to mapper,
* which allows you to rewrite flash memory without soldering.
* This also allows console to write data to the cartridge.
* This behavior is not emulated.
* No cart has been discovered so far that makes use of this feature, but this can be used for homebrew.
*
* hardware tested logic, don't try to understand lol
*/
#include "mapinc.h"
#include "mmc3.h"
#include "../ines.h"
static void COOLBOYCW(uint32 A, uint8 V) {
uint32 mask = 0xFF ^ (EXPREGS[0] & 0x80);
if (EXPREGS[3] & 0x10) {
if (EXPREGS[3] & 0x40) { // Weird mode
const int ROM_CHIP = 0x00;
const int CFI_CHIP = 0x11;
const int FLASH_CHIP = 0x12;
const uint32 FLASH_SECTOR_SIZE = 128 * 1024;
extern uint8* WRAM;
static uint8* CFI = NULL;
static uint8* Flash = NULL;
static uint8 flash_save = 0;
static uint8 flash_state = 0;
static uint16 flash_buffer_a[10];
static uint8 flash_buffer_v[10];
static uint8 cfi_mode = 0;
static uint16 regs_base = 0;
static uint8 flag23 = 0;
static uint8 flag45 = 0;
static uint8 flag67 = 0;
static uint8 flag89 = 0;
// Macronix 256-mbit memory CFI data
const uint8 cfi_data[] =
{
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0x51, 0x52, 0x59, 0x02, 0x00, 0x40, 0x00, 0x00,
0x00, 0x00, 0x00, 0x27, 0x36, 0x00, 0x00, 0x03,
0x06, 0x09, 0x13, 0x03, 0x05, 0x03, 0x02, 0x19,
0x02, 0x00, 0x06, 0x00, 0x01, 0xFF, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF,
0x50, 0x52, 0x49, 0x31, 0x33, 0x14, 0x02, 0x01,
0x00, 0x08, 0x00, 0x00, 0x02, 0x95, 0xA5, 0x05,
0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
};
static void AA6023CW(uint32 A, uint8 V) {
if (flag89) {
/*
$xxx0
7 bit 0
---- ----
AB.C DEEE
|| | ||||
|| | |+++-- PRG offset (PRG A19, A18, A17)
|| | +----- Alternate CHR A17
|| +------- 1=Write-protect CHR-RAM
|+--------- PRG mask (PRG A17 from 0: MMC3; 1: offset)
+---------- CHR mask (CHR A17 from 0: MMC3; 1: alternate)
*/
if (EXPREGS[0] & 0b00010000)
SetupCartCHRMapping(0, VROM, CHRsize[0], 0); // write-protect CHR-RAM
else
SetupCartCHRMapping(0, VROM, CHRsize[0], 1); // allow CHR writes
}
uint32 mask = 0xFF ^ (EXPREGS[0] & 0b10000000);
if (EXPREGS[3] & 0b00010000) {
if (EXPREGS[3] & 0b01000000) { // Weird mode
int cbase = (MMC3_cmd & 0x80) << 5;
switch (cbase ^ A) { // Don't even try do understand
case 0x0400:
case 0x0C00: V &= 0x7F; break;
}
}
// Highest bit goes from MMC3 registers when EXPREGS[3]&0x80==0 or from EXPREGS[0]&0x08 otherwise
// Highest bit goes from MMC3 registers when EXPREGS[0]&0x80==0 or from EXPREGS[0]&0x08 otherwise
setchr1(A,
(V & 0x80 & mask) | ((((EXPREGS[0] & 0x08) << 4) & ~mask)) // 7th bit
(V & 0x80 & mask) | ((((EXPREGS[0] & 0b00001000) << 4) & ~mask)) // 7th bit
| ((EXPREGS[2] & 0x0F) << 3) // 6-3 bits
| ((A >> 10) & 7) // 2-0 bits
| ((EXPREGS[0] & 0b00110000) << 4) // There are some ROMs with 1 MiB CHR-ROM
);
} else {
if (EXPREGS[3] & 0x40) { // Weird mode, again
}
else {
if (EXPREGS[3] & 0b01000000) { // Weird mode, again
int cbase = (MMC3_cmd & 0x80) << 5;
switch (cbase ^ A) { // Don't even try do understand
case 0x0000: V = DRegBuf[0]; break;
@@ -58,89 +168,317 @@ static void COOLBOYCW(uint32 A, uint8 V) {
}
}
// Simple MMC3 mode
// Highest bit goes from MMC3 registers when EXPREGS[3]&0x80==0 or from EXPREGS[0]&0x08 otherwise
setchr1(A, (V & mask) | (((EXPREGS[0] & 0x08) << 4) & ~mask));
// Highest bit goes from MMC3 registers when EXPREGS[0]&0x80==0 or from EXPREGS[0]&0x08 otherwise
setchr1(A,
(V & mask)
| (((EXPREGS[0] & 0x08) << 4) & ~mask)
| ((EXPREGS[0] & 0b00110000) << 4)); // There are some ROMs with 1 MiB CHR-ROM
}
}
static void COOLBOYPW(uint32 A, uint8 V) {
uint32 mask = ((0x3F | (EXPREGS[1] & 0x40) | ((EXPREGS[1] & 0x20) << 2)) ^ ((EXPREGS[0] & 0x40) >> 2)) ^ ((EXPREGS[1] & 0x80) >> 2);
uint32 base = ((EXPREGS[0] & 0x07) >> 0) | ((EXPREGS[1] & 0x10) >> 1) | ((EXPREGS[1] & 0x0C) << 2) | ((EXPREGS[0] & 0x30) << 2);
static void AA6023PW(uint32 A, uint8 V) {
uint8 CREGS[] = {EXPREGS[0], EXPREGS[1], EXPREGS[2], EXPREGS[3]};
// Submappers has scrambled bits
if (flag23) {
/*
$xxx1
7 bit 0
---- ----
GHIL JKKx
|||| |||
|||| +++--- PRG offset (in order: PRG A20, A21, A22)
|||+------- GNROM mode bank PRG size (0: 32 KiB bank, PRG A14=CPU A14; 1: 16 KiB bank, PRG A14=offset A14)
||+-------- PRG mask (PRG A20 from 0: offset; 1: MMC3)
|+--------- PRG mask (PRG A19 from 0: offset; 1: MMC3)
+---------- PRG mask (PRG A18 from 0: MMC3; 1: offset)
*/
CREGS[1] = (CREGS[1] & 0b11100101)
| ((CREGS[1] & 0b00001000) << 1) // PRG A20
| ((CREGS[1] & 0b00000010) << 2) // PRG A22
| ((((CREGS[1] ^ 0b00010000) & 0b00010000) >> 3)); // GNROM mode bank PRG size
}
if (flag45) {
/*
$xxx0
7 bit 0
---- ----
ABCC DEEE
|||| ||||
|||| |+++-- PRG offset (PRG A19, A18, A17)
|||| +----- Alternate CHR A17
||++------- PRG offset (PRG A21, A20)
|+--------- PRG mask (PRG A17 from 0: MMC3; 1: offset)
+---------- CHR mask (CHR A17 from 0: MMC3; 1: alternate)
$xxx1
7 bit 0
---- ----
GHIx xxLx
||| |
||| +--- GNROM mode bank PRG size (1: 32 KiB bank, PRG A14=CPU A14; 0: 16 KiB bank, PRG A14=offset A14)
||+-------- PRG mask (PRG A20 from 0: offset; 1: MMC3)
|+--------- PRG mask (PRG A19 from 0: offset; 1: MMC3)
+---------- PRG mask (PRG A18 from 0: MMC3; 1: offset)
*/
CREGS[1] = (CREGS[1] & 0b11100011)
| ((CREGS[0] & 0b00100000) >> 3) // PRG A21
| (CREGS[0] & 0b00010000); // PRG A20
CREGS[0] &= 0b11001111;
}
uint32 mask = ((0b00111111 | (CREGS[1] & 0b01000000) | ((CREGS[1] & 0b00100000) << 2)) ^ ((CREGS[0] & 0b01000000) >> 2)) ^ ((CREGS[1] & 0b10000000) >> 2);
uint32 base = ((CREGS[0] & 0b00000111) >> 0) | ((CREGS[1] & 0b00010000) >> 1) | ((CREGS[1] & 0b00001100) << 2) | ((CREGS[0] & 0b00110000) << 2);
if (flash_save && cfi_mode) {
setprg32r(CFI_CHIP, 0x8000, 0);
return;
}
int chip = !flash_save ? ROM_CHIP : FLASH_CHIP;
// There are ROMs with multiple PRG ROM chips
int chip_offset = 0;
if (flag67 && EXPREGS[0] & 0b00001000) {
chip_offset += ROM_size;
}
// Very weird mode
// Last banks are first in this mode, ignored when MMC3_cmd&0x40
if ((EXPREGS[3] & 0x40) && (V >= 0xFE) && !((MMC3_cmd & 0x40) != 0)) {
if ((CREGS[3] & 0b01000000) && (V >= 0xFE) && !((MMC3_cmd & 0x40) != 0)) {
switch (A & 0xE000) {
case 0xA000:
if ((MMC3_cmd & 0x40)) V = 0;
break;
case 0xC000:
if (!(MMC3_cmd & 0x40)) V = 0;
break;
case 0xE000:
V = 0;
break;
}
}
// Regular MMC3 mode, internal ROM size can be up to 2048kb!
if (!(EXPREGS[3] & 0x10))
setprg8(A, (((base << 4) & ~mask)) | (V & mask));
else { // NROM mode
if (!(CREGS[3] & 0x10)) {
// Regular MMC3 mode but can be extended to 2MiB
setprg8r(chip, A, ((((base << 4) & ~mask)) | (V & mask)) + chip_offset);
}
else {
// NROM mode
mask &= 0xF0;
uint8 emask;
if ((((EXPREGS[1] & 2) != 0))) // 32kb mode
emask = (EXPREGS[3] & 0x0C) | ((A & 0x4000) >> 13);
if (CREGS[1] & 0b00000010) // 32kb mode
emask = (CREGS[3] & 0b00001100) | ((A & 0x4000) >> 13);
else // 16kb mode
emask = EXPREGS[3] & 0x0E;
setprg8(A, ((base << 4) & ~mask) // 7-4 bits are from base (see below)
| (V & mask) // ... or from MM3 internal regs, depends on mask
| emask // 3-1 (or 3-2 when (EXPREGS[3]&0x0C is set) from EXPREGS[3]
| ((A & 0x2000) >> 13)); // 0th just as is
emask = CREGS[3] & 0b00001110;
setprg8r(chip, A, (
((base << 4) & ~mask) // 7-4 bits are from base
| (V & mask) // ... or from MM3 internal regs, depends on mask
| emask // 3-1 (or 3-2 when (EXPREGS[3]&0x0C is set) from EXPREGS[3]
| ((A & 0x2000) >> 13) // 0th just as is
) + chip_offset); // For multi-chip ROMs
}
}
static DECLFW(COOLBOYWrite) {
if(A001B & 0x80)
CartBW(A,V);
static DECLFW(AA6023WramWrite) {
if (A001B & 0x80)
CartBW(A, V);
}
static DECLFW(AA6023Write) {
if (A >= 0x6000) {
AA6023WramWrite(A, V);
}
// Deny any further writes when 7th bit is 1 AND 4th is 0
if ((EXPREGS[3] & 0x90) != 0x80) {
EXPREGS[A & 3] = V;
FixMMC3PRG(MMC3_cmd);
FixMMC3CHR(MMC3_cmd);
}
FixMMC3PRG(MMC3_cmd);
FixMMC3CHR(MMC3_cmd);
}
static DECLFW(AA6023FlashWrite) {
if (A < 0xC000)
MMC3_CMDWrite(A, V);
else
MMC3_IRQWrite(A, V);
if (!flash_save) return;
if (flash_state < sizeof(flash_buffer_a) / sizeof(flash_buffer_a[0])) {
flash_buffer_a[flash_state] = A & 0xFFF;
flash_buffer_v[flash_state] = V;
flash_state++;
// enter CFI mode
if ((flash_state == 1) &&
(flash_buffer_a[0] == 0x0AAA) && (flash_buffer_v[0] == 0x98)) {
cfi_mode = 1;
flash_state = 0;
}
// erase sector
if ((flash_state == 6) &&
(flash_buffer_a[0] == 0x0AAA) && (flash_buffer_v[0] == 0xAA) &&
(flash_buffer_a[1] == 0x0555) && (flash_buffer_v[1] == 0x55) &&
(flash_buffer_a[2] == 0x0AAA) && (flash_buffer_v[2] == 0x80) &&
(flash_buffer_a[3] == 0x0AAA) && (flash_buffer_v[3] == 0xAA) &&
(flash_buffer_a[4] == 0x0555) && (flash_buffer_v[4] == 0x55) &&
(flash_buffer_v[5] == 0x30)) {
int offset = &Page[A >> 11][A] - Flash;
int sector = offset / FLASH_SECTOR_SIZE;
for (uint32 i = sector * FLASH_SECTOR_SIZE; i < (sector + 1) * FLASH_SECTOR_SIZE; i++)
Flash[i % PRGsize[ROM_CHIP]] = 0xFF;
FCEU_printf("Flash sector #%d is erased (0x%08x - 0x%08x).\n", sector, offset, offset + FLASH_SECTOR_SIZE);
flash_state = 0;
}
// erase chip, lol
if ((flash_state == 6) &&
(flash_buffer_a[0] == 0x0AAA) && (flash_buffer_v[0] == 0xAA) &&
(flash_buffer_a[1] == 0x0555) && (flash_buffer_v[1] == 0x55) &&
(flash_buffer_a[2] == 0x0AAA) && (flash_buffer_v[2] == 0x80) &&
(flash_buffer_a[3] == 0x0AAA) && (flash_buffer_v[3] == 0xAA) &&
(flash_buffer_a[4] == 0x0555) && (flash_buffer_v[4] == 0x55) &&
(flash_buffer_v[5] == 0x10)) {
memset(Flash, 0xFF, PRGsize[ROM_CHIP]);
FCEU_printf("Flash chip erased.\n");
flash_state = 0;
}
// write byte
if ((flash_state == 4) &&
(flash_buffer_a[0] == 0x0AAA) && (flash_buffer_v[0] == 0xAA) &&
(flash_buffer_a[1] == 0x0555) && (flash_buffer_v[1] == 0x55) &&
(flash_buffer_a[2] == 0x0AAA) && (flash_buffer_v[2] == 0xA0)) {
int offset = &Page[A >> 11][A] - Flash;
if (CartBR(A) != 0xFF) {
FCEU_PrintError("Error: can't write to 0x%08x, flash sector is not erased.\n", offset);
}
else {
CartBW(A, V);
}
flash_state = 0;
}
}
// not a command
if (((A & 0xFFF) != 0x0AAA) && ((A & 0xFFF) != 0x0555)) {
flash_state = 0;
}
// reset
if (V == 0xF0) {
flash_state = 0;
cfi_mode = 0;
}
FixMMC3PRG(MMC3_cmd);
}
static void AA6023Reset(void) {
MMC3RegReset();
EXPREGS[0] = EXPREGS[1] = EXPREGS[2] = EXPREGS[3] = 0;
flash_state = 0;
cfi_mode = 0;
FixMMC3PRG(MMC3_cmd);
FixMMC3CHR(MMC3_cmd);
}
static void AA6023Power(void) {
GenMMC3Power();
EXPREGS[0] = EXPREGS[1] = EXPREGS[2] = EXPREGS[3] = 0;
FixMMC3PRG(MMC3_cmd);
FixMMC3CHR(MMC3_cmd);
if (regs_base != 0x5000)
SetWriteHandler(0x5000, 0x5fff, CartBW); // some games access random unmapped areas and crashes because of KT-008 PCB hack in MMC3 source lol
SetWriteHandler(0x6000, 0x7fff, AA6023WramWrite);
SetWriteHandler(regs_base, regs_base + 0x0fff, AA6023Write);
SetWriteHandler(0x8000, 0xFFFF, AA6023FlashWrite);
SetReadHandler(0x8000, 0xFFFF, CartBR);
}
static void AA6023Restore(int version) {
FixMMC3PRG(MMC3_cmd);
FixMMC3CHR(MMC3_cmd);
}
static void AA6023Close(void) {
if (WRAM)
FCEU_gfree(WRAM);
if (Flash)
FCEU_gfree(Flash);
if (CFI)
FCEU_gfree(CFI);
WRAM = Flash = CFI = NULL;
}
void CommonInit(CartInfo* info, int submapper)
{
GenMMC3_Init(info, 2048, info->vram_size / 1024, !info->ines2 ? 8 : (info->wram_size + info->battery_wram_size) / 1024, info->battery);
pwrap = AA6023PW;
cwrap = AA6023CW;
switch (submapper)
{
case 2:
regs_base = 0x7000;
break;
case 0:
case 4:
case 6:
case 8:
regs_base = 0x6000;
break;
case 1:
case 3:
case 5:
case 7:
case 9:
regs_base = 0x5000;
break;
default:
FCEU_PrintError("Submapper #%d is not supported", submapper);
}
flag23 = (submapper == 2) || (submapper == 3);
flag45 = (submapper == 4) || (submapper == 5);
flag67 = (submapper == 6) || (submapper == 7);
flag89 = (submapper == 8) || (submapper == 9);
info->Power = AA6023Power;
info->Reset = AA6023Reset;
info->Close = AA6023Close;
GameStateRestore = AA6023Restore;
flash_save = info->battery;
if (flash_save) {
CFI = (uint8*)FCEU_gmalloc(sizeof(cfi_data) * 2);
for (size_t i = 0; i < sizeof(cfi_data); i++) {
CFI[i * 2] = CFI[i * 2 + 1] = cfi_data[i];
}
SetupCartPRGMapping(CFI_CHIP, CFI, sizeof(cfi_data) * 2, 0);
Flash = (uint8*)FCEU_gmalloc(PRGsize[ROM_CHIP]);
for (unsigned int i = 0; i < PRGsize[ROM_CHIP]; i++) {
Flash[i] = PRGptr[ROM_CHIP][i % PRGsize[ROM_CHIP]];
}
SetupCartPRGMapping(FLASH_CHIP, Flash, PRGsize[ROM_CHIP], 1);
info->addSaveGameBuf( Flash, PRGsize[ROM_CHIP] );
}
AddExState(EXPREGS, 4, 0, "EXPR");
if (flash_save)
{
AddExState(&flash_state, sizeof(flash_state), 0, "FLST");
AddExState(flash_buffer_a, sizeof(flash_buffer_a), 0, "FLBA");
AddExState(flash_buffer_v, sizeof(flash_buffer_v), 0, "FLBV");
AddExState(&cfi_mode, sizeof(cfi_mode), 0, "CFIM");
AddExState(Flash, PRGsize[ROM_CHIP], 0, "FLAS");
}
}
static void COOLBOYReset(void) {
MMC3RegReset();
EXPREGS[0] = EXPREGS[1] = EXPREGS[2] = EXPREGS[3] = 0;
// EXPREGS[0] = 0;
// EXPREGS[1] = 0x60;
// EXPREGS[2] = 0;
// EXPREGS[3] = 0;
FixMMC3PRG(MMC3_cmd);
FixMMC3CHR(MMC3_cmd);
// Registers at $6xxx
void COOLBOY_Init(CartInfo* info) {
CommonInit(info, 0);
}
static void COOLBOYPower(void) {
GenMMC3Power();
EXPREGS[0] = EXPREGS[1] = EXPREGS[2] = EXPREGS[3] = 0;
// EXPREGS[0] = 0;
// EXPREGS[1] = 0x60;
// EXPREGS[2] = 0;
// EXPREGS[3] = 0;
FixMMC3PRG(MMC3_cmd);
FixMMC3CHR(MMC3_cmd);
SetWriteHandler(0x5000, 0x5fff, CartBW); // some games access random unmapped areas and crashes because of KT-008 PCB hack in MMC3 source lol
SetWriteHandler(0x6000, 0x7fff, COOLBOYWrite);
// Registers at $5xxx
void MINDKIDS_Init(CartInfo* info) {
CommonInit(info, 1);
}
void COOLBOY_Init(CartInfo *info) {
GenMMC3_Init(info, 512, 256, 8, 0);
pwrap = COOLBOYPW;
cwrap = COOLBOYCW;
info->Power = COOLBOYPower;
info->Reset = COOLBOYReset;
AddExState(EXPREGS, 4, 0, "EXPR");
}
// For NES 2.0 loader
void AA6023_Init(CartInfo* info) {
CommonInit(info, info->submapper);
}
File diff suppressed because it is too large Load Diff
+574 -498
View File
File diff suppressed because it is too large Load Diff
+1 -2
View File
@@ -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);
+18 -18
View File
@@ -53,22 +53,22 @@
#include "emu2413.h"
static const unsigned char default_inst[15][8] = {
/* VRC7 instruments, January 17, 2004 update -Xodnizel */
{ 0x03, 0x21, 0x04, 0x06, 0x8D, 0xF2, 0x42, 0x17 },
{ 0x13, 0x41, 0x05, 0x0E, 0x99, 0x96, 0x63, 0x12 },
{ 0x31, 0x11, 0x10, 0x0A, 0xF0, 0x9C, 0x32, 0x02 },
{ 0x21, 0x61, 0x1D, 0x07, 0x9F, 0x64, 0x20, 0x27 },
{ 0x22, 0x21, 0x1E, 0x06, 0xF0, 0x76, 0x08, 0x28 },
{ 0x02, 0x01, 0x06, 0x00, 0xF0, 0xF2, 0x03, 0x95 },
{ 0x21, 0x61, 0x1C, 0x07, 0x82, 0x81, 0x16, 0x07 },
{ 0x23, 0x21, 0x1A, 0x17, 0xEF, 0x82, 0x25, 0x15 },
{ 0x25, 0x11, 0x1F, 0x00, 0x86, 0x41, 0x20, 0x11 },
{ 0x85, 0x01, 0x1F, 0x0F, 0xE4, 0xA2, 0x11, 0x12 },
{ 0x07, 0xC1, 0x2B, 0x45, 0xB4, 0xF1, 0x24, 0xF4 },
{ 0x61, 0x23, 0x11, 0x06, 0x96, 0x96, 0x13, 0x16 },
{ 0x01, 0x02, 0xD3, 0x05, 0x82, 0xA2, 0x31, 0x51 },
{ 0x61, 0x22, 0x0D, 0x02, 0xC3, 0x7F, 0x24, 0x05 },
{ 0x21, 0x62, 0x0E, 0x00, 0xA1, 0xA0, 0x44, 0x17 },
/* VRC7 instruments, March 15, 2019 dumped by Nuke.YKT */
{ 0x03, 0x21, 0x05, 0x06, 0xE8, 0x81, 0x42, 0x27 },
{ 0x13, 0x41, 0x14, 0x0D, 0xD8, 0xF6, 0x23, 0x12 },
{ 0x11, 0x11, 0x08, 0x08, 0xFA, 0xB2, 0x20, 0x12 },
{ 0x31, 0x61, 0x0C, 0x07, 0xA8, 0x64, 0x61, 0x27 },
{ 0x32, 0x21, 0x1E, 0x06, 0xE1, 0x76, 0x01, 0x28 },
{ 0x02, 0x01, 0x06, 0x00, 0xA3, 0xE2, 0xF4, 0xF4 },
{ 0x21, 0x61, 0x1D, 0x07, 0x82, 0x81, 0x11, 0x07 },
{ 0x23, 0x21, 0x22, 0x17, 0xA2, 0x72, 0x01, 0x17 },
{ 0x35, 0x11, 0x25, 0x00, 0x40, 0x73, 0x72, 0x01 },
{ 0xB5, 0x01, 0x0F, 0x0F, 0xA8, 0xA5, 0x51, 0x02 },
{ 0x17, 0xC1, 0x24, 0x07, 0xF8, 0xF8, 0x22, 0x12 },
{ 0x71, 0x23, 0x11, 0x06, 0x65, 0x74, 0x18, 0x16 },
{ 0x01, 0x02, 0xD3, 0x05, 0xC9, 0x95, 0x03, 0x02 },
{ 0x61, 0x63, 0x0C, 0x00, 0x94, 0xC0, 0x33, 0xF6 },
{ 0x21, 0x72, 0x0D, 0x00, 0xC1, 0xD5, 0x56, 0x06 },
};
/* Size of Sintable ( 8 -- 18 can be used. 9 recommended.)*/
@@ -604,8 +604,8 @@ void OPLL_reset(OPLL * opll) {
for (i = 0; i < 0x40; i++)
OPLL_writeReg(opll, i, 0);
opll->realstep = (uint32)((1 << 31) / rate);
opll->opllstep = (uint32)((1 << 31) / (clk / 72));
opll->realstep = (uint32)((1u << 31) / rate);
opll->opllstep = (uint32)((1u << 31) / (clk / 72));
opll->oplltime = 0;
}
+1 -1
View File
@@ -70,7 +70,7 @@ static void SSSNROMPower(void) {
regs[0] = regs[1] = regs[2] = regs[3] = regs[4] = regs[5] = regs[6] = 0;
regs[7] = 0xff;
Sync();
memset(WRAM, 0x00, WRAMSIZE);
FCEU_MemoryRand(WRAM, WRAMSIZE, true);
// SetWriteHandler(0x0000,0x1FFF,SSSNROMRamWrite);
SetReadHandler(0x0800, 0x1FFF, CartBR);
SetWriteHandler(0x0800, 0x1FFF, CartBW);
+1 -2
View File
@@ -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);
+130 -131
View File
@@ -30,26 +30,22 @@ static uint32 CHRRAMSize;
static void BMCFK23CCW(uint32 A, uint8 V)
{
if(EXPREGS[0]&0x40)
setchr8(EXPREGS[2]|unromchr);
else if(EXPREGS[0]&0x20) {
setchr1r(0x10, A, V);
}
else
{
uint16 base=(EXPREGS[2]&0x7F)<<3;
if(EXPREGS[3]&2)
{
int cbase=(MMC3_cmd&0x80)<<5;
setchr1(A,V|base);
setchr1(0x0000^cbase,DRegBuf[0]|base);
setchr1(0x0400^cbase,EXPREGS[6]|base);
setchr1(0x0800^cbase,DRegBuf[1]|base);
setchr1(0x0c00^cbase,EXPREGS[7]|base);
}
else
setchr1(A,V|base);
}
if(EXPREGS[0]&0x40)
setchr8(EXPREGS[2]|unromchr);
else if(EXPREGS[0]&0x20) {
setchr1r(0x10, A, V);
} else {
uint16 base=(EXPREGS[2]&0x7F)<<3;
if(EXPREGS[3]&2) {
int cbase=(MMC3_cmd&0x80)<<5;
setchr1(A,V|base);
setchr1(0x0000^cbase,DRegBuf[0]|base);
setchr1(0x0400^cbase,EXPREGS[6]|base);
setchr1(0x0800^cbase,DRegBuf[1]|base);
setchr1(0x0c00^cbase,EXPREGS[7]|base);
} else
setchr1(A,V|base);
}
}
//some games are wired differently, and this will need to be changed.
@@ -86,110 +82,110 @@ static int prg_mask;
//PRG wrapper
static void BMCFK23CPW(uint32 A, uint8 V)
{
uint32 bank = (EXPREGS[1] & 0x1F);
uint32 hiblock = ((EXPREGS[0] & 8) << 4)|((EXPREGS[0] & 0x80) << 1)|(UNIFchrrama?((EXPREGS[2] & 0x40)<<3):0);
uint32 block = (EXPREGS[1] & 0x60) | hiblock;
uint32 extra = (EXPREGS[3] & 2);
//uint32 bank = (EXPREGS[1] & 0x1F);
//uint32 hiblock = ((EXPREGS[0] & 8) << 4)|((EXPREGS[0] & 0x80) << 1)|(UNIFchrrama?((EXPREGS[2] & 0x40)<<3):0);
//uint32 block = (EXPREGS[1] & 0x60) | hiblock;
//uint32 extra = (EXPREGS[3] & 2);
// FCEU_printf("0:%04X:%02X\n",A,V);
if((EXPREGS[0]&7)==4)
setprg32(0x8000,EXPREGS[1]>>1);
else if ((EXPREGS[0]&7)==3)
{
setprg16(0x8000,EXPREGS[1]);
setprg16(0xC000,EXPREGS[1]);
}
else
{
if(EXPREGS[0]&3)
{
if((EXPREGS[0]&7)==4)
setprg32(0x8000,EXPREGS[1]>>1);
else if ((EXPREGS[0]&7)==3) {
setprg16(0x8000,EXPREGS[1]);
setprg16(0xC000,EXPREGS[1]);
} else {
if(EXPREGS[0]&3) {
uint32 blocksize = (6)-(EXPREGS[0]&3);
uint32 mask = (1<<blocksize)-1;
V &= mask;
//V &= 63; //? is this a good idea?
V |= (EXPREGS[1]<<1);
setprg8(A,V);
// FCEU_printf("1:%04X:%02X\n",A,V);
setprg8(A,V);
} else {
setprg8(A,V & prg_mask);
// FCEU_printf("2:%04X:%02X\n",A,V);
}
else
setprg8(A,V & prg_mask);
if(EXPREGS[3]&2)
{
setprg8(0xC000,EXPREGS[4]);
setprg8(0xE000,EXPREGS[5]);
}
}
if(EXPREGS[3]&2) {
setprg8(0xC000,EXPREGS[4]);
setprg8(0xE000,EXPREGS[5]);
}
}
setprg8r(0x10,0x6000,A001B&3);
}
//PRG handler ($8000-$FFFF)
static DECLFW(BMCFK23CHiWrite)
{
if(EXPREGS[0]&0x40)
{
// FCEU_printf("K4:(exp0=%02x)\n",EXPREGS[0]);
// FCEU_printf("W0:%04X:%02X (exp0=%02x)\n",A,V,EXPREGS[0]);
if((EXPREGS[0]&0x60)==0x40) {
// FCEU_printf("W2:%04X:%02X (exp0=%02x)\n",A,V,EXPREGS[0]);
if(EXPREGS[0]&0x30)
unromchr=0;
else
{
else {
unromchr=V&3;
FixMMC3CHR(MMC3_cmd);
}
}
else
{
if((A==0x8001)&&(EXPREGS[3]&2&&MMC3_cmd&8))
{
} else {
if((A==0x8001)&&(EXPREGS[3]&2)&&(MMC3_cmd&8)) {
// FCEU_printf("W3:%04X:%02X (exp0=%02x)\n",A,V,EXPREGS[0]);
EXPREGS[4|(MMC3_cmd&3)]=V;
FixMMC3PRG(MMC3_cmd);
FixMMC3CHR(MMC3_cmd);
}
else
if(A<0xC000) {
if(UNIFchrrama) { // hacky... strange behaviour, must be bit scramble due to pcb layot restrictions
// check if it not interfer with other dumps
if((A==0x8000)&&(V==0x46))
V=0x47;
else if((A==0x8000)&&(V==0x47))
V=0x46;
}
MMC3_CMDWrite(A,V);
FixMMC3PRG(MMC3_cmd);
}
else
MMC3_IRQWrite(A,V);
}
} else
if(A<0xC000) {
if(UNIFchrrama) { // hacky... strange behaviour, must be bit scramble due to pcb layot restrictions
// check if it not interfer with other dumps
if((A==0x8000)&&(V==0x46))
V=0x47;
else if((A==0x8000)&&(V==0x47))
V=0x46;
}
// FCEU_printf("W1:%04X:%02X\n",A,V);
MMC3_CMDWrite(A,V);
FixMMC3PRG(MMC3_cmd);
} else {
MMC3_IRQWrite(A,V);
// FCEU_printf("W4:%04X:%02X (exp0=%02x)\n",A,V,EXPREGS[0]);
}
}
}
//EXP handler ($5000-$5FFF)
static DECLFW(BMCFK23CWrite)
{
if(A&(1<<(dipswitch+4)))
{
if(A&(1<<(dipswitch+4))) {
//printf("+ ");
EXPREGS[A&3]=V;
EXPREGS[A&3]=V;
bool remap = false;
// BUT WHY is there any rom that need it actually?
// bool remap = false;
// FCEU_printf("K3:(exp0=%02x)\n",EXPREGS[0]);
// FCEU_printf("WH0:%04X:%02X\n",A,V);
//sometimes writing to reg0 causes remappings to occur. we think the 2 signifies this.
//sometimes writing to reg0 causes remappings to occur. we think the 2 signifies this.
//if not, 0x24 is a value that is known to work
//however, the low 4 bits are known to control the mapping mode, so 0x20 is more likely to be the immediate remap flag
remap |= ((EXPREGS[0]&0xF0)==0x20);
// remap |= ((EXPREGS[0]&0xF0)==0x20);
//this is an actual mapping reg. i think reg0 controls what happens when reg1 is written. anyway, we have to immediately remap these
remap |= (A&3)==1;
// remap |= (A&3)==1;
//this too.
remap |= (A&3)==2;
// remap |= (A&3)==2;
if(remap)
{
// if(remap) {
// FCEU_printf("WH1:%04X:%02X\n",A,V);
FixMMC3PRG(MMC3_cmd);
FixMMC3CHR(MMC3_cmd);
}
}
// }
}
if(is_BMCFK23CA)
{
if(is_BMCFK23CA) {
if(EXPREGS[3]&2)
EXPREGS[0] &= ~7; // hacky hacky! if someone wants extra banking, then for sure doesn't want mode 4 for it! (allow to run A version boards on normal mapper)
// FCEU_printf("EXTRA!\n",A);
EXPREGS[0] &= ~7; // hacky hacky! if someone wants extra banking, then for sure doesn't want mode 4 for it! (allow to run A version boards on normal mapper)
}
//printf("%04X = $%02X\n",A,V);
@@ -199,62 +195,65 @@ static DECLFW(BMCFK23CWrite)
static void BMCFK23CReset(void)
{
//NOT NECESSARY ANYMORE
// BUT WHY?
//this little hack makes sure that we try all the dip switch settings eventually, if we reset enough
// dipswitch++;
// dipswitch&=7;
//printf("BMCFK23C dipswitch set to %d\n",dipswitch);
dipswitch++;
dipswitch&=7;
printf("BMCFK23C dipswitch set to %u\n",dipswitch);
EXPREGS[0]=EXPREGS[1]=EXPREGS[2]=EXPREGS[3]=0;
EXPREGS[4]=EXPREGS[5]=EXPREGS[6]=EXPREGS[7]=0xFF;
MMC3RegReset();
FixMMC3PRG(MMC3_cmd);
FixMMC3CHR(MMC3_cmd);
EXPREGS[0]=EXPREGS[1]=EXPREGS[2]=EXPREGS[3]=0;
EXPREGS[4]=EXPREGS[5]=EXPREGS[6]=EXPREGS[7]=0xFF;
// FCEU_printf("K0:(exp0=%02x)\n",EXPREGS[0]);
MMC3RegReset();
FixMMC3PRG(MMC3_cmd);
FixMMC3CHR(MMC3_cmd);
}
static void BMCFK23CPower(void)
{
GenMMC3Power();
dipswitch = 0;
GenMMC3Power();
EXPREGS[0]=EXPREGS[1]=EXPREGS[2]=EXPREGS[3]=0;
EXPREGS[4]=EXPREGS[5]=EXPREGS[6]=EXPREGS[7]=0xFF;
GenMMC3Power();
SetWriteHandler(0x5000,0x5fff,BMCFK23CWrite);
SetWriteHandler(0x8000,0xFFFF,BMCFK23CHiWrite);
FixMMC3PRG(MMC3_cmd);
FixMMC3CHR(MMC3_cmd);
EXPREGS[0]=EXPREGS[1]=EXPREGS[2]=EXPREGS[3]=0;
EXPREGS[4]=EXPREGS[5]=EXPREGS[6]=EXPREGS[7]=0xFF;
// FCEU_printf("K1:(exp0=%02x)\n",EXPREGS[0]);
FixMMC3PRG(MMC3_cmd);
FixMMC3CHR(MMC3_cmd);
SetWriteHandler(0x5000,0x5fff,BMCFK23CWrite);
SetWriteHandler(0x8000,0xFFFF,BMCFK23CHiWrite);
}
static void BMCFK23CAPower(void)
{
GenMMC3Power();
dipswitch = 0;
EXPREGS[0]=EXPREGS[1]=EXPREGS[2]=EXPREGS[3]=0;
EXPREGS[4]=EXPREGS[5]=EXPREGS[6]=EXPREGS[7]=0xFF;
SetWriteHandler(0x5000,0x5fff,BMCFK23CWrite);
SetWriteHandler(0x8000,0xFFFF,BMCFK23CHiWrite);
FixMMC3PRG(MMC3_cmd);
FixMMC3CHR(MMC3_cmd);
GenMMC3Power();
dipswitch = 0;
EXPREGS[0]=EXPREGS[1]=EXPREGS[2]=EXPREGS[3]=0;
EXPREGS[4]=EXPREGS[5]=EXPREGS[6]=EXPREGS[7]=0xFF;
// FCEU_printf("K2:(exp0=%02x)\n",EXPREGS[0]);
FixMMC3PRG(MMC3_cmd);
FixMMC3CHR(MMC3_cmd);
SetWriteHandler(0x5000,0x5fff,BMCFK23CWrite);
SetWriteHandler(0x8000,0xFFFF,BMCFK23CHiWrite);
}
static void BMCFK23CAClose(void)
{
if(CHRRAM)
FCEU_gfree(CHRRAM);
CHRRAM=NULL;
if(CHRRAM)
FCEU_gfree(CHRRAM);
CHRRAM=NULL;
}
void BMCFK23C_Init(CartInfo *info)
{
is_BMCFK23CA = false;
GenMMC3_Init(info, 512, 256, 8, 0);
cwrap=BMCFK23CCW;
pwrap=BMCFK23CPW;
info->Power=BMCFK23CPower;
info->Reset=BMCFK23CReset;
AddExState(EXPREGS, 8, 0, "EXPR");
AddExState(&unromchr, 1, 0, "UCHR");
AddExState(&dipswitch, 1, 0, "DPSW");
GenMMC3_Init(info, 512, 256, 8, 0);
cwrap=BMCFK23CCW;
pwrap=BMCFK23CPW;
info->Power=BMCFK23CPower;
info->Reset=BMCFK23CReset;
AddExState(EXPREGS, 8, 0, "EXPR");
AddExState(&unromchr, 1, 0, "UCHR");
AddExState(&dipswitch, 1, 0, "DPSW");
prg_bonus = 1;
if(MasterRomInfoParams.find("bonus") != MasterRomInfoParams.end())
@@ -267,21 +266,21 @@ void BMCFK23CA_Init(CartInfo *info)
{
is_BMCFK23CA = true;
GenMMC3_Init(info, 512, 256, 8, 0);
cwrap=BMCFK23CCW;
pwrap=BMCFK23CPW;
info->Power=BMCFK23CAPower;
info->Reset=BMCFK23CReset;
info->Close=BMCFK23CAClose;
GenMMC3_Init(info, 512, 256, 8, 0);
cwrap=BMCFK23CCW;
pwrap=BMCFK23CPW;
info->Power=BMCFK23CAPower;
info->Reset=BMCFK23CReset;
info->Close=BMCFK23CAClose;
CHRRAMSize=8192;
CHRRAM=(uint8*)FCEU_gmalloc(CHRRAMSize);
SetupCartCHRMapping(0x10, CHRRAM, CHRRAMSize, 1);
AddExState(CHRRAM, CHRRAMSize, 0, "CRAM");
CHRRAM=(uint8*)FCEU_gmalloc(CHRRAMSize);
SetupCartCHRMapping(0x10, CHRRAM, CHRRAMSize, 1);
AddExState(CHRRAM, CHRRAMSize, 0, "CRAM");
AddExState(EXPREGS, 8, 0, "EXPR");
AddExState(&unromchr, 1, 0, "UCHR");
AddExState(&dipswitch, 1, 0, "DPSW");
AddExState(EXPREGS, 8, 0, "EXPR");
AddExState(&unromchr, 1, 0, "UCHR");
AddExState(&dipswitch, 1, 0, "DPSW");
prg_bonus = 1;
if(MasterRomInfoParams.find("bonus") != MasterRomInfoParams.end())
+265
View File
@@ -0,0 +1,265 @@
/* FCE Ultra - NES/Famicom Emulator
*
* Copyright notice for this file:
* Copyright (C) 1998 BERO
* Copyright (C) 2002 Xodnizel
* Copyright (C) 2020 CaH4e3
*
* 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
*
* Famicom Network System Base Unit + MMC1 cartridge board
*
*/
#include "mapinc.h"
static uint8 DRegs[4];
static uint8 Buffer, BufferShift;
static uint32 WRAMSIZE=0;
static uint8 *WRAM = NULL;
static int kanji_pos, kanji_page, r40C0;
static int IRQa, IRQCount;
FCEU_MAYBE_UNUSED
static DECLFW(MBWRAM) {
if (!(DRegs[3] & 0x10))
Page[A >> 11][A] = V;
}
FCEU_MAYBE_UNUSED
static DECLFR(MAWRAM) {
if (DRegs[3] & 0x10)
return X.DB;
return(Page[A >> 11][A]);
}
static void MMC1CHR(void) {
setchr8((r40C0 >> 3) & 1);
}
static void MMC1PRG(void) {
uint8 offs_16banks = DRegs[1] & 0x10;
uint8 prg_reg = DRegs[3] & 0xF;
setprg8r(0x10, 0x6000, DRegs[1] & 3);
switch (DRegs[0] & 0xC) {
case 0xC:
setprg16(0x8000, (prg_reg + offs_16banks));
setprg16(0xC000, 0xF + offs_16banks);
break;
case 0x8:
setprg16(0xC000, (prg_reg + offs_16banks));
setprg16(0x8000, offs_16banks);
break;
case 0x0:
case 0x4:
setprg16(0x8000, ((prg_reg & ~1) + offs_16banks));
setprg16(0xc000, ((prg_reg & ~1) + offs_16banks + 1));
break;
}
}
static void MMC1MIRROR(void) {
switch (DRegs[0] & 3) {
case 2: setmirror(MI_V); break;
case 3: setmirror(MI_H); break;
case 0: setmirror(MI_0); break;
case 1: setmirror(MI_1); break;
}
}
static uint64 lreset;
static DECLFW(MMC1_write) {
int n = (A >> 13) - 4;
if ((timestampbase + timestamp) < (lreset + 2))
return;
if (V & 0x80) {
DRegs[0] |= 0xC;
BufferShift = Buffer = 0;
MMC1PRG();
lreset = timestampbase + timestamp;
return;
}
Buffer |= (V & 1) << (BufferShift++);
if (BufferShift == 5) {
FCEU_printf("MMC1 REG%d:%02x (PC %04x)\n", n, Buffer, X.PC);
DRegs[n] = Buffer;
BufferShift = Buffer = 0;
switch (n) {
case 0: MMC1MIRROR();
case 1:
case 2:
case 3: MMC1PRG(); break;
}
}
}
static void MMC1_Restore(int version) {
MMC1MIRROR();
MMC1CHR();
MMC1PRG();
lreset = 0;
}
static void MMC1CMReset(void) {
int i;
for (i = 0; i < 4; i++)
DRegs[i] = 0;
Buffer = BufferShift = 0;
DRegs[0] = 0x1F;
DRegs[1] = 0;
DRegs[2] = 0;
DRegs[3] = 0;
MMC1MIRROR();
MMC1CHR();
MMC1PRG();
}
static DECLFW(FNC_cmd_write) {
switch (A) {
case 0x40A6: {
IRQCount = (IRQCount & 0xFF00) | V;
break;
}
case 0x40A7: {
IRQCount = (IRQCount & 0x00FF) | (V << 8);
break;
}
case 0x40A8: {
IRQa = V;
break;
}
case 0x40B0: {
kanji_page = V & 1;
break;
}
case 0x40C0: {
FCEU_printf("FNS W %04x:%02x (PC %04x)\n", A, V, X.PC);
r40C0 = V;
MMC1CHR();
break;
}
default:
FCEU_printf("FNS W %04x:%02x (PC %04x)\n", A, V, X.PC);
}
}
static DECLFR(FNC_stat_read) {
switch (A) {
case 0x40A2: {
int ret = (IRQa >> 1);
X6502_IRQEnd(FCEU_IQEXT);
IRQa = 0;
return ret;
}
case 0x40AC: { // NMI/IRQ state reset (lookalike)
return 0;
}
case 0x40B0: {
kanji_pos = 0;
return 0;
}
case 0x40C0: {
FCEU_printf("FNS R %04x (PC %04x)\n", A, X.PC);
int ret = r40C0;
r40C0 &= 0;
return ret;
}
default: {
FCEU_printf("FNS R %04x (PC %04x)\n", A, X.PC);
return 0xff;
}
}
}
static DECLFR(FNC_cart_i2c_read) {
FCEU_printf("I2C R %04x (PC %04x)\n", A, X.PC);
return 0;
}
static DECLFR(FNC_kanji_read) {
int32 ofs = ((A & 0xFFF) << 5) + kanji_pos;
kanji_pos++;
kanji_pos &= 0x1F;
// if (PRGptr[1] != NULL) // iNES debug
return PRGptr[1][ofs];
// else
// return CHRptr[0][ofs];
}
void NFC_IRQ(int a) {
if (IRQa) {
IRQCount -= a;
if (IRQCount <= 0)
X6502_IRQBegin(FCEU_IQEXT);
}
}
static void FNS_Power(void) {
lreset = 0;
SetWriteHandler(0x8000, 0xFFFF, MMC1_write);
SetReadHandler(0x8000, 0xFFFF, CartBR);
kanji_page = 0;
kanji_pos = 0;
r40C0 = 0xC0;
SetWriteHandler(0x4080, 0x40FF, FNC_cmd_write);
SetReadHandler(0x4080, 0x40FF, FNC_stat_read);
SetReadHandler(0x5000, 0x5FFF, FNC_kanji_read);
SetReadHandler(0x6000, 0x6000, FNC_cart_i2c_read);
SetReadHandler(0x6001, 0x7FFF, CartBR);
SetWriteHandler(0x6000, 0x7FFF, CartBW);
FCEU_CheatAddRAM(8, 0x6000, WRAM);
MMC1CMReset();
}
static void FNS_Close(void) {
if (WRAM)
FCEU_gfree(WRAM);
WRAM = NULL;
}
void FNS_Init(CartInfo *info) {
info->Close = FNS_Close;
info->Power = FNS_Power;
GameStateRestore = MMC1_Restore;
MapIRQHook = NFC_IRQ;
WRAMSIZE = (8 + 32) * 1024;
WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE);
SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1);
AddExState(WRAM, WRAMSIZE, 0, "WRAM");
info->addSaveGameBuf( WRAM, WRAMSIZE );
AddExState(DRegs, 4, 0, "DREG");
AddExState(&lreset, 8, 1, "LRST");
AddExState(&Buffer, 1, 1, "BFFR");
AddExState(&BufferShift, 1, 1, "BFRS");
}
+177
View File
@@ -0,0 +1,177 @@
/* FCE Ultra - NES/Famicom Emulator
*
* Copyright notice for this file:
* Copyright (C) 2017 CaH4e3
*
* 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
*
* HP10xx/HP20xx - a simplified version of FK23C mapper with pretty strict and better
* organized banking behaviour. It seems that some 176 mapper assigned game may be
* actually this kind of board instead but in common they aren't compatible at all,
* the games on the regular FK23C boards couldn't run on this mapper and vice versa...
*
*/
#include "mapinc.h"
#include "mmc3.h"
#include "../ines.h"
static uint8 unromchr, lock;
static uint32 dipswitch;
static void BMCHPxxCW(uint32 A, uint8 V)
{
if(EXPREGS[0]&4) { // custom banking
switch(EXPREGS[0]&3) {
case 0:
case 1:
setchr8(EXPREGS[2]&0x3F);
// FCEU_printf("\tCHR8 %02X\n",EXPREGS[2]&0x3F);
break;
case 2:
setchr8((EXPREGS[2]&0x3E)|(unromchr&1));
// FCEU_printf("\tCHR8 %02X\n",(EXPREGS[2]&0x3E)|(unromchr&1));
break;
case 3:
setchr8((EXPREGS[2]&0x3C)|(unromchr&3));
// FCEU_printf("\tCHR8 %02X\n",(EXPREGS[2]&0x3C)|(unromchr&3));
break;
}
} else { // mmc3 banking
int base, mask;
if(EXPREGS[0]&1) { // 128K mode
base=EXPREGS[2]&0x30;
mask=0x7F;
} else { // 256K mode
base=EXPREGS[2]&0x20;
mask=0xFF;
}
// FCEU_printf("\tCHR1 %04x:%02X\n",A,(V&mask)|(base<<3));
setchr1(A,(V&mask)|(base<<3));
}
}
//PRG wrapper
static void BMCHPxxPW(uint32 A, uint8 V)
{
if(EXPREGS[0]&4) { // custom banking
if((EXPREGS[0]&0xF)==4) { // 16K mode
// FCEU_printf("\tPRG16 %02X\n",EXPREGS[1]&0x1F);
setprg16(0x8000,EXPREGS[1]&0x1F);
setprg16(0xC000,EXPREGS[1]&0x1F);
} else { // 32K modes
// FCEU_printf("\tPRG32 %02X\n",(EXPREGS[1]&0x1F)>>1);
setprg32(0x8000,(EXPREGS[1]&0x1F)>>1);
}
} else { // mmc3 banking
int base, mask;
if(EXPREGS[0]&2) { // 128K mode
base=EXPREGS[1]&0x18;
mask=0x0F;
} else { // 256K mode
base=EXPREGS[1]&0x10;
mask=0x1F;
}
// FCEU_printf("\tPRG8 %02X\n",(V&mask)|(base<<1));
setprg8(A,(V&mask)|(base<<1));
setprg8r(0x10,0x6000,A001B&3);
}
}
//MIRROR wrapper
static void BMCHPxxMW(uint8 V) {
if(EXPREGS[0]&4) { // custom banking
// FCEU_printf("CUSTOM MIRR: %d\n",(unromchr>>2)&1);
setmirror(((unromchr>>2)&1)^1);
} else { // mmc3 banking
// FCEU_printf("MMC3 MIRR: %d\n",(V&1)^1);
A000B = V;
setmirror((A000B & 1) ^ 1);
}
}
//PRG handler ($8000-$FFFF)
static DECLFW(BMCHPxxHiWrite)
{
// FCEU_printf("HI WRITE %04X:%02X\n",A,V);
if(EXPREGS[0]&4) { // custom banking
// FCEU_printf("CUSTOM\n");
unromchr=V;
FixMMC3CHR(MMC3_cmd);
} else { // mmc3 banking
// FCEU_printf("MMC3\n");
if(A<0xC000) {
MMC3_CMDWrite(A,V);
FixMMC3PRG(MMC3_cmd);
FixMMC3CHR(MMC3_cmd);
} else {
MMC3_IRQWrite(A,V);
}
}
}
//EXP handler ($5000-$5FFF)
static DECLFW(BMCHPxxWrite)
{
if(!lock) {
// FCEU_printf("LO WRITE %04X:%02X\n",A,V);
EXPREGS[A&3]=V;
lock=V&0x80;
FixMMC3PRG(MMC3_cmd);
FixMMC3CHR(MMC3_cmd);
}
}
static DECLFR(BMCHPxxRead) {
return dipswitch;
}
static void BMCHPxxReset(void)
{
dipswitch++;
dipswitch&=0xF;
lock=0;
// FCEU_printf("BMCHPxx dipswitch set to %d\n",dipswitch);
EXPREGS[0]=EXPREGS[1]=EXPREGS[2]=EXPREGS[3]=0;
MMC3RegReset();
FixMMC3PRG(MMC3_cmd);
FixMMC3CHR(MMC3_cmd);
}
static void BMCHPxxPower(void)
{
GenMMC3Power();
dipswitch=lock=0;
EXPREGS[0]=EXPREGS[1]=EXPREGS[2]=EXPREGS[3]=0;
FixMMC3PRG(MMC3_cmd);
FixMMC3CHR(MMC3_cmd);
SetReadHandler(0x5000,0x5fff,BMCHPxxRead);
SetWriteHandler(0x5000,0x5fff,BMCHPxxWrite);
SetWriteHandler(0x8000,0xffff,BMCHPxxHiWrite);
}
void BMCHPxx_Init(CartInfo *info)
{
GenMMC3_Init(info, 256, 256, 8, 0);
cwrap=BMCHPxxCW;
pwrap=BMCHPxxPW;
mwrap=BMCHPxxMW;
info->Power=BMCHPxxPower;
info->Reset=BMCHPxxReset;
AddExState(EXPREGS, 8, 0, "EXPR");
AddExState(&unromchr, 1, 0, "UCHR");
AddExState(&dipswitch, 1, 0, "DPSW");
AddExState(&lock, 1, 0, "LOCK");
}
+88
View File
@@ -0,0 +1,88 @@
/* FCE Ultra - NES/Famicom Emulator
*
* Copyright notice for this file:
* Copyright (C) 2022 Cluster
*
* 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
*
* NES 2.0 Mapper 470 denotes the INX_007T_V01 multicart circuit board,
* used for the Retro-Bit re-release of Battletoads and Double Dragon.
* It is basically AOROM with an additional outer bank register at $5000-$5FFF
* whose data selects the 256 KiB outer bank.
*
* $5000-$5FFF
* 7 bit 0
* ---- ----
* xxxx xxOO
* ||
* ++- Select outer 256 KB PRG ROM bank for CPU $8000-$FFFF
*
* $8000-$FFFF
* 7 bit 0
* ---- ----
* xxxM xPPP
* | |||
* | +++- Select inner 32 KB PRG ROM bank for CPU $8000-$FFFF
* +------ Select 1 KB VRAM page for all 4 nametables
*
*/
#include "mapinc.h"
static uint8 latch_out, latch_in;
static void INX_007T_Sync() {
setprg32(0x8000, (latch_in & 0b111) | (latch_out << 3));
setmirror(MI_0 + ((latch_in >> 4) & 1));
setchr8(0);
}
static void StateRestore(int version) {
INX_007T_Sync();
}
static DECLFW(INX_007T_WriteLow)
{
latch_out = V;
INX_007T_Sync();
}
static DECLFW(INX_007T_WriteHi)
{
latch_in = V;
INX_007T_Sync();
}
static void INX_007T_Power(void) {
latch_in = latch_out = 0;
INX_007T_Sync();
SetReadHandler(0x8000, 0xFFFF, CartBR);
SetWriteHandler(0x5000,0x5FFF, INX_007T_WriteLow);
SetWriteHandler(0x8000, 0xFFFF, INX_007T_WriteHi);
}
static void INX_007T_Reset(void) {
latch_in = latch_out = 0;
INX_007T_Sync();
}
void INX_007T_Init(CartInfo *info) {
info->Power = INX_007T_Power;
info->Reset = INX_007T_Reset;
GameStateRestore = StateRestore;
SetupCartMirroring(MI_0, 0, NULL);
AddExState(&latch_out, 1, 0, "LATO");
AddExState(&latch_in, 1, 0, "LATI");
}
+1
View File
@@ -35,6 +35,7 @@ static void MALEEPower(void) {
void MALEE_Init(CartInfo *info) {
info->Power = MALEEPower;
FCEU_MemoryRand(WRAM,sizeof(WRAM),true);
SetupCartPRGMapping(0x10, WRAM, 2048, 1);
AddExState(WRAM, 2048, 0, "WRAM");
}
+58 -48
View File
@@ -22,12 +22,13 @@
#include "mapinc.h"
static void GenMMC1Power(void);
static void GenMMC1Init(CartInfo *info, int prg, int chr, int wram, int battery);
static void GenMMC1Init(CartInfo *info, int prg, int chr, int wram, int bram);
static uint8 DRegs[4];
static uint8 Buffer, BufferShift;
static int mmc1opts;
static uint32 WRAMSIZE;
static uint32 NONBRAMSIZE; // size of non-battery-backed portion of WRAM
static void (*MMC1CHRHook4)(uint32 A, uint8 V);
static void (*MMC1PRGHook16)(uint32 A, uint8 V);
@@ -48,9 +49,9 @@ static DECLFR(MAWRAM) {
}
static void MMC1CHR(void) {
if (mmc1opts & 4) {
if (DRegs[0] & 0x10)
setprg8r(0x10, 0x6000, (DRegs[1] >> 4) & 1);
if (WRAMSIZE > 0x2000) {
if (WRAMSIZE > 0x4000)
setprg8r(0x10, 0x6000, (DRegs[1] >> 2) & 3);
else
setprg8r(0x10, 0x6000, (DRegs[1] >> 3) & 1);
}
@@ -179,20 +180,39 @@ static void MMC1CMReset(void) {
MMC1PRG();
}
static int DetectMMC1WRAMSize(uint32 crc32) {
switch (crc32) {
static int DetectMMC1WRAMSize(CartInfo *info, int *bs) {
int ws = 8;
switch (info->CRC32) {
case 0xc6182024: // Romance of the 3 Kingdoms
case 0xabbf7217: // "" "" (J) (PRG0)
case 0xccf35c02: // "" "" (J) (PRG1)
case 0x2225c20f: // Genghis Khan
case 0xfb69743a: // "" "" (J)
case 0x4642dda6: // Nobunaga's Ambition
case 0x29449ba9: // "" "" (J)
case 0x2b11e0b0: // "" "" (J)
case 0xb8747abf: // Best Play Pro Yakyuu Special (J)
case 0xc9556b36: // Final Fantasy I & II (J) [!]
FCEU_printf(" >8KB external WRAM present. Use UNIF if you hack the ROM image.\n");
return(16);
case 0x3f7ad415: // "" "" (J) (PRG0)
case 0x2b11e0b0: // "" "" (J) (PRG1)
*bs = 8;
ws = 16;
break;
default: return(8);
case 0xb8747abf: // Best Play Pro Yakyuu Special (J) (PRG0)
case 0xc3de7c69: // "" "" (J) (PRG1)
case 0xc9556b36: // Final Fantasy I & II (J) [!]
*bs = 32;
ws = 32;
break;
default:
if(info->ines2) {
ws = (info->wram_size + info->battery_wram_size) / 1024;
*bs = info->battery_wram_size / 1024;
// we only support sizes between 8K and 32K
if (ws > 0 && ws < 8) ws = 8;
if (ws > 32) ws = 32;
if (*bs > ws) *bs = ws;
}
}
if (ws > 8)
FCEU_printf(" >8KB external WRAM present. Use NES 2.0 if you hack the ROM image.\n");
return ws;
}
static uint32 NWCIRQCount;
@@ -244,17 +264,16 @@ void Mapper105_Init(CartInfo *info) {
static void GenMMC1Power(void) {
lreset = 0;
if (mmc1opts & 1) {
FCEU_CheatAddRAM(8, 0x6000, WRAM);
if (mmc1opts & 4)
FCEU_dwmemset(WRAM, 0, 8192)
else if (!(mmc1opts & 2))
FCEU_dwmemset(WRAM, 0, 8192); // wtf?
}
SetWriteHandler(0x8000, 0xFFFF, MMC1_write);
SetReadHandler(0x8000, 0xFFFF, CartBR);
if (mmc1opts & 1) {
if (WRAMSIZE) {
FCEU_CheatAddRAM(8, 0x6000, WRAM);
// clear non-battery-backed portion of WRAM
if (NONBRAMSIZE)
FCEU_MemoryRand(WRAM, NONBRAMSIZE, true);
SetReadHandler(0x6000, 0x7FFF, MAWRAM);
SetWriteHandler(0x6000, 0x7FFF, MBWRAM);
setprg8r(0x10, 0x6000, 0);
@@ -271,31 +290,23 @@ static void GenMMC1Close(void) {
CHRRAM = WRAM = NULL;
}
static void GenMMC1Init(CartInfo *info, int prg, int chr, int wram, int battery) {
static void GenMMC1Init(CartInfo *info, int prg, int chr, int wram, int bram) {
is155 = 0;
info->Close = GenMMC1Close;
MMC1PRGHook16 = MMC1CHRHook4 = 0;
mmc1opts = 0;
WRAMSIZE = wram * 1024;
NONBRAMSIZE = (wram - bram) * 1024;
PRGmask16[0] &= (prg >> 14) - 1;
CHRmask4[0] &= (chr >> 12) - 1;
CHRmask8[0] &= (chr >> 13) - 1;
if (wram) {
WRAM = (uint8*)FCEU_gmalloc(wram * 1024);
//mbg 17-jun-08 - this shouldve been cleared to re-initialize save ram
//ch4 10-dec-08 - nope, this souldn't
//mbg 29-mar-09 - no time to debate this, we need to keep from breaking some old stuff.
//we really need to make up a policy for how compatibility and accuracy can be resolved.
memset(WRAM, 0, wram * 1024);
mmc1opts |= 1;
if (wram > 8) mmc1opts |= 4;
SetupCartPRGMapping(0x10, WRAM, wram * 1024, 1);
AddExState(WRAM, wram * 1024, 0, "WRAM");
if (battery) {
mmc1opts |= 2;
info->SaveGame[0] = WRAM + ((mmc1opts & 4) ? 8192 : 0);
info->SaveGameLen[0] = 8192;
if (WRAMSIZE) {
WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE);
SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1);
AddExState(WRAM, WRAMSIZE, 0, "WRAM");
if (bram) {
info->addSaveGameBuf( WRAM + NONBRAMSIZE, bram * 1024 );
}
}
if (!chr) {
@@ -313,13 +324,14 @@ static void GenMMC1Init(CartInfo *info, int prg, int chr, int wram, int battery)
}
void Mapper1_Init(CartInfo *info) {
int ws = DetectMMC1WRAMSize(info->CRC32);
GenMMC1Init(info, 512, 256, ws, info->battery);
int bs = info->battery ? 8 : 0;
int ws = DetectMMC1WRAMSize(info, &bs);
GenMMC1Init(info, 512, 256, ws, bs);
}
/* Same as mapper 1, without respect for WRAM enable bit. */
void Mapper155_Init(CartInfo *info) {
GenMMC1Init(info, 512, 256, 8, info->battery);
GenMMC1Init(info, 512, 256, 8, info->battery ? 8 : 0);
is155 = 1;
}
@@ -331,7 +343,7 @@ void Mapper171_Init(CartInfo *info) {
}
void SAROM_Init(CartInfo *info) {
GenMMC1Init(info, 128, 64, 8, info->battery);
GenMMC1Init(info, 128, 64, 8, info->battery ? 8 : 0);
}
void SBROM_Init(CartInfo *info) {
@@ -351,7 +363,7 @@ void SGROM_Init(CartInfo *info) {
}
void SKROM_Init(CartInfo *info) {
GenMMC1Init(info, 256, 64, 8, info->battery);
GenMMC1Init(info, 256, 64, 8, info->battery ? 8 : 0);
}
void SLROM_Init(CartInfo *info) {
@@ -383,11 +395,9 @@ void SHROM_Init(CartInfo *info) {
/* */
void SNROM_Init(CartInfo *info) {
GenMMC1Init(info, 256, 0, 8, info->battery);
GenMMC1Init(info, 256, 0, 8, info->battery ? 8 : 0);
}
void SOROM_Init(CartInfo *info) {
GenMMC1Init(info, 256, 0, 16, info->battery);
GenMMC1Init(info, 256, 0, 16, info->battery ? 8 : 0);
}
+2 -3
View File
@@ -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);
+111 -21
View File
@@ -113,6 +113,9 @@ void MMC3RegReset(void) {
DRegBuf[6] = 0;
DRegBuf[7] = 1;
// 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
kt_extra = 0;
FixMMC3PRG(0);
FixMMC3CHR(0);
}
@@ -187,7 +190,14 @@ DECLFW(MMC3_IRQWrite) {
DECLFW(KT008HackWrite) {
// FCEU_printf("%04x:%04x\n",A,V);
switch (A & 3) {
case 0: kt_extra = V; FixMMC3PRG(MMC3_cmd); break;
case 0: {
if (V == 0x27) // FF Xn hack! one more mapper in one
kt_extra = 0;
else
kt_extra = V;
FixMMC3PRG(MMC3_cmd);
break;
}
case 1: break; // unk
case 2: break; // unk
case 3: break; // unk
@@ -279,11 +289,11 @@ void GenMMC3Power(void) {
setprg8r(0x10, 0x6000, 0);
}
if (!(mmc3opts & 2))
FCEU_dwmemset(WRAM, 0, WRAMSIZE);
FCEU_MemoryRand(WRAM, WRAMSIZE, true);
}
MMC3RegReset();
if (CHRRAM)
FCEU_dwmemset(CHRRAM, 0, CHRRAMSIZE);
FCEU_MemoryRand(CHRRAM, CHRRAMSIZE, true);
}
static void GenMMC3Close(void) {
@@ -314,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
@@ -1127,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;
@@ -1150,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);
@@ -1159,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");
}
@@ -1353,3 +1415,31 @@ void TQROM_Init(CartInfo *info) {
void HKROM_Init(CartInfo *info) {
GenMMC3_Init(info, 512, 512, 1, info->battery);
}
// -------------------------------- iNES 2.0 ----------------------------
// ---------------------------- Mapper 406 ------------------------------
static DECLFW(M406CMDWrite) {
MMC3_CMDWrite((A & 0xFFFE) | ((A & 2) >> 1), V);
}
static DECLFW(M406IRQWrite) {
MMC3_IRQWrite((A & 0xFFFE) | ((A & 2) >> 1), V);
}
FCEU_MAYBE_UNUSED
static DECLFW(M406Write) {
}
static void M406_Power(void) {
GenMMC3Power();
// TODO : FLASH
SetWriteHandler(0x8000, 0xBFFF, M406CMDWrite);
SetWriteHandler(0xC000, 0xFFFF, M406IRQWrite);
}
void Mapper406_Init(CartInfo *info) {
GenMMC3_Init(info, 512, 256, 0, 0);
info->Power = M406_Power;
}
+249 -66
View File
@@ -22,6 +22,15 @@
#include "mapinc.h"
#include <array>
#define ABANKS MMC5SPRVPage
#define BBANKS MMC5BGVPage
#define SpriteON (PPU[1] & 0x10) //Show Sprite
#define ScreenON (PPU[1] & 0x08) //Show screen
#define PPUON (PPU[1] & 0x18) //PPU should operate
#define Sprite16 (PPU[0] & 0x20) //Sprites 8x16/8x8
static void (*sfun)(int P);
static void (*psfun)(void);
@@ -74,10 +83,11 @@ static INLINE void MMC5BGVROM_BANK8(uint32 V) {
}
}
static uint8 PRGBanks[4];
static std::array<uint8,4> PRGBanks;
static uint8 WRAMPage;
static uint16 CHRBanksA[8], CHRBanksB[4];
static uint8 WRAMMaskEnable[2];
static std::array<uint16,8> CHRBanksA;
static std::array<uint16,4> CHRBanksB;
static std::array<uint8,2> WRAMMaskEnable;
uint8 mmc5ABMode; /* A=0, B=1 */
static uint8 IRQScanline, IRQEnable;
@@ -86,18 +96,20 @@ static uint8 CHRMode, NTAMirroring, NTFill, ATFill;
static uint8 MMC5IRQR;
static uint8 MMC5LineCounter;
static uint8 mmc5psize, mmc5vsize;
static uint8 mul[2];
static std::array<uint8,2> mul;
static uint32 WRAMSIZE = 0;
static uint8 *WRAM = NULL;
static uint8 *MMC5fill = NULL;
static uint8 *ExRAM = NULL;
static uint8 MMC5battery = 0;
static uint8 MMC5WRAMsize; //configuration, not state
static uint8 MMC5WRAMIndex[8]; //configuration, not state
const int MMC5WRAMMAX = 1<<7; // 7 bits in register interface (real MMC5 has only 4 pins, however)
static uint8 MMC5WRAMsize=0; //configuration, not state
static uint8 MMC5WRAMIndex[MMC5WRAMMAX]; //configuration, not state
static uint8 MMC5ROMWrProtect[4];
static uint8 MMC5MemIn[5];
static std::array<uint8,4> MMC5ROMWrProtect;
static std::array<uint8,5> MMC5MemIn;
static void MMC5CHRA(void);
static void MMC5CHRB(void);
@@ -107,26 +119,50 @@ typedef struct __cartdata {
uint8 size;
} cartdata;
#define Sprite16 (PPU[0]& 0x20) //Sprites 8x16/8x8
//#define MMC5SPRVRAMADR(V) &MMC5SPRVPage[(V)>>10][(V)]
static inline uint8 * MMC5BGVRAMADR(uint32 A) {
#define MMC5SPRVRAMADR(V) &MMC5SPRVPage[(V) >> 10][(V)]
uint8* MMC5BGVRAMADR(uint32 A)
{
if(newppu)
{
if(Sprite16)
{
bool isPattern = PPUON != 0;
if (ppuphase == PPUPHASE_OBJ && isPattern)
return &ABANKS[(A) >> 10][(A)];
if (ppuphase == PPUPHASE_BG && isPattern)
return &BBANKS[(A) >> 10][(A)];
else if(mmc5ABMode == 0)
return &ABANKS[(A) >> 10][(A)];
else
return &BBANKS[(A) >> 10][(A)];
}
else return &ABANKS[(A) >> 10][(A)];;
}
if (!Sprite16) {
if (mmc5ABMode == 0)
return &MMC5SPRVPage[(A) >> 10][(A)];
return &ABANKS[(A) >> 10][(A)];
else
return &MMC5BGVPage[(A) >> 10][(A)];
} else return &MMC5BGVPage[(A) >> 10][(A)];
return &BBANKS[(A) >> 10][(A)];
} else return &BBANKS[(A) >> 10][(A)];
}
static void mmc5_PPUWrite(uint32 A, uint8 V) {
uint32 tmp = A;
extern uint8 PALRAM[0x20];
extern uint8 UPALRAM[0x03];
if (tmp >= 0x3F00) {
// hmmm....
if (!(tmp & 0xf))
PALRAM[0x00] = PALRAM[0x04] = PALRAM[0x08] = PALRAM[0x0C] = V & 0x3F;
else if (tmp & 3) PALRAM[(tmp & 0x1f)] = V & 0x3f;
if (!(tmp & 3)) {
if (!(tmp & 0xC)) {
PALRAM[0x00] = PALRAM[0x04] = PALRAM[0x08] = PALRAM[0x0C] = V & 0x3F;
PALRAM[0x10] = PALRAM[0x14] = PALRAM[0x18] = PALRAM[0x1C] = V & 0x3F;
}
else
UPALRAM[((tmp & 0xC) >> 2) - 1] = V & 0x3F;
} else
PALRAM[tmp & 0x1F] = V & 0x3F;
} else if (tmp < 0x2000) {
if (PPUCHRRAM & (1 << (tmp >> 10)))
VPage[tmp >> 10][tmp] = V;
@@ -136,16 +172,105 @@ static void mmc5_PPUWrite(uint32 A, uint8 V) {
}
}
uint8 FASTCALL mmc5_PPURead(uint32 A) {
if (A < 0x2000) {
if (ppuphase == PPUPHASE_BG
//zero 03-aug-2014 - added this to fix Uchuu Keibitai SDF. The game reads NT entries from CHR rom while PPU is disabled.
//obviously we have enormous numbers of bugs springing from our terrible emulation of ppu-disabled states, but this does the job for fixing this one
&& (PPU[1] & 0x10)
)
return *MMC5BGVRAMADR(A);
else return MMC5SPRVPage[(A) >> 10][(A)];
} else {
extern uint32 NTRefreshAddr;
uint8 FASTCALL mmc5_PPURead(uint32 A)
{
bool split = false;
if(newppu)
{
if((MMC5HackSPMode&0x80) && !(MMC5HackCHRMode&2))
{
int target = MMC5HackSPMode&0x1f;
int side = MMC5HackSPMode&0x40;
int ht = NTRefreshAddr&31;
if(side==0)
{
if(ht<target) split = true;
}
else
{
if(ht>=target) split = true;
}
}
}
if (A < 0x2000)
{
if(Sprite16)
{
bool isPattern = !!PPUON;
if (ppuphase == PPUPHASE_OBJ && isPattern)
return ABANKS[(A) >> 10][(A)];
if (ppuphase == PPUPHASE_BG && isPattern)
{
if(split)
return MMC5HackVROMPTR[MMC5HackSPPage*0x1000 + (A&0xFFF)];
//uhhh call through to this more sophisticated function, only if it's really needed?
//we should probably reuse it completely, if we can
if (MMC5HackCHRMode == 1)
return *FCEUPPU_GetCHR(A,NTRefreshAddr);
return BBANKS[(A) >> 10][(A)];
}
else if(mmc5ABMode == 0)
return ABANKS[(A) >> 10][(A)];
else
return BBANKS[(A) >> 10][(A)];
}
else
{
if (ppuphase == PPUPHASE_BG && ScreenON)
{
if(split)
return MMC5HackVROMPTR[MMC5HackSPPage*0x1000 + (A&0xFFF)];
//uhhh call through to this more sophisticated function, only if it's really needed?
//we should probably reuse it completely, if we can
if (MMC5HackCHRMode == 1)
return *FCEUPPU_GetCHR(A,NTRefreshAddr);
}
return ABANKS[(A) >> 10][(A)];
}
}
else
{
if(split)
{
static const int kHack = -1; //dunno if theres science to this or if it just fixes SDF (cant be bothered to think about it)
int linetile = (newppu_get_scanline()+kHack)/8 + MMC5HackSPScroll;
//REF NT: return 0x2000 | (v << 0xB) | (h << 0xA) | (vt << 5) | ht;
//REF AT: return 0x2000 | (v << 0xB) | (h << 0xA) | 0x3C0 | ((vt & 0x1C) << 1) | ((ht & 0x1C) >> 2);
if((A&0x3FF)>=0x3C0)
{
A &= ~(0x1C<<1); //mask off VT
A |= (linetile&0x1C)<<1; //mask on adjusted VT
return ExRAM[A & 0x3FF];
}
else
{
A &= ~((0x1F<<5) | (1<<0xB)); //mask off VT and V
A |= (linetile&31)<<5; //mask on adjusted VT (V doesnt make any sense, I think)
return ExRAM[A & 0x3FF];
}
}
if (MMC5HackCHRMode == 1)
{
if((A&0x3FF)>=0x3C0)
{
uint8 byte = ExRAM[NTRefreshAddr & 0x3ff];
//get attribute part and paste it 4x across the byte
byte >>= 6;
byte *= 0x55;
return byte;
}
}
return vnapage[(A >> 10) & 0x3][A & 0x3FF];
}
}
@@ -182,8 +307,7 @@ cartdata MMC5CartList[] =
#define MMC5_NOCARTS (sizeof(MMC5CartList) / sizeof(MMC5CartList[0]))
int DetectMMC5WRAMSize(uint32 crc32) {
int x;
for (x = 0; x < MMC5_NOCARTS; x++) {
for (size_t x = 0; x < MMC5_NOCARTS; x++) {
if (crc32 == MMC5CartList[x].crc32) {
if(MMC5CartList[x].size > 1)
FCEU_printf(" >8KB external WRAM present. Use UNIF if you hack the ROM image.\n");
@@ -194,6 +318,8 @@ int DetectMMC5WRAMSize(uint32 crc32) {
}
static void BuildWRAMSizeTable(void) {
bool other = false; // non-standard configuration
// fill first 8 entries
int x;
for (x = 0; x < 8; x++) {
switch (MMC5WRAMsize) {
@@ -201,9 +327,22 @@ static void BuildWRAMSizeTable(void) {
case 1: MMC5WRAMIndex[x] = (x > 3) ? 255 : 0; break; //0,0,0,0,X,X,X,X
case 2: MMC5WRAMIndex[x] = (x & 4) >> 2; break; //0,0,0,0,1,1,1,1
case 4: MMC5WRAMIndex[x] = (x > 3) ? 255 : (x & 3); break; //0,1,2,3,X,X,X,X
case 8: MMC5WRAMIndex[x] = x; break; //0,1,2,3,4,5,6,7
case 8: MMC5WRAMIndex[x] = x; break; //0,1,2,3,4,5,6,7
default: MMC5WRAMIndex[x] = x; other = true; break; //0,1,2...
}
}
// extend to fill complete table
if (other)
{
for (x = 0; x < MMC5WRAMMAX && x < MMC5WRAMsize; ++x) MMC5WRAMIndex[x] = x; // linear mapping
for (x = MMC5WRAMsize; x < MMC5WRAMMAX; ++x) MMC5WRAMIndex[x] = MMC5WRAMIndex[x-MMC5WRAMsize]; // repeat to fill table
// theoretically the table fill should decompose into powers of two for possible mismatched SRAM combos,
// but I don't want to complicate the code with unnecessary hypotheticals
}
else
{
for (x = 8; x < MMC5WRAMMAX; ++x) MMC5WRAMIndex[x] = MMC5WRAMIndex[x & 7]; // fill table, repeating groups of 8
}
}
static void MMC5CHRA(void) {
@@ -271,7 +410,7 @@ static void MMC5CHRB(void) {
}
static void MMC5WRAM(uint32 A, uint32 V) {
V = MMC5WRAMIndex[V & 7];
V = MMC5WRAMIndex[V & (MMC5WRAMMAX-1)];
if (V != 255) {
setprg8r(0x10, A, V);
FCEU_CheatAddRAM(8, 0x6000, (WRAM + ((V * 8192) & (WRAMSIZE - 1))));
@@ -285,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;
@@ -296,8 +435,8 @@ static void MMC5PRG(void) {
MMC5MemIn[1] = MMC5MemIn[2] = 1;
} else {
MMC5ROMWrProtect[0] = MMC5ROMWrProtect[1] = 0;
MMC5WRAM(0x8000, PRGBanks[1] & 7 & 0xFE);
MMC5WRAM(0xA000, (PRGBanks[1] & 7 & 0xFE) + 1);
MMC5WRAM(0x8000, PRGBanks[1] & (MMC5WRAMMAX-1) & 0xFE);
MMC5WRAM(0xA000, (PRGBanks[1] & (MMC5WRAMMAX-1) & 0xFE) + 1);
}
MMC5MemIn[3] = MMC5MemIn[4] = 1;
MMC5ROMWrProtect[2] = MMC5ROMWrProtect[3] = 1;
@@ -310,8 +449,8 @@ static void MMC5PRG(void) {
setprg16(0x8000, (PRGBanks[1] & 0x7F) >> 1);
} else {
MMC5ROMWrProtect[0] = MMC5ROMWrProtect[1] = 0;
MMC5WRAM(0x8000, PRGBanks[1] & 7 & 0xFE);
MMC5WRAM(0xA000, (PRGBanks[1] & 7 & 0xFE) + 1);
MMC5WRAM(0x8000, PRGBanks[1] & (MMC5WRAMMAX-1) & 0xFE);
MMC5WRAM(0xA000, (PRGBanks[1] & (MMC5WRAMMAX-1) & 0xFE) + 1);
}
if (PRGBanks[2] & 0x80) {
MMC5ROMWrProtect[2] = 1;
@@ -319,7 +458,7 @@ static void MMC5PRG(void) {
setprg8(0xC000, PRGBanks[2] & 0x7F);
} else {
MMC5ROMWrProtect[2] = 0;
MMC5WRAM(0xC000, PRGBanks[2] & 7);
MMC5WRAM(0xC000, PRGBanks[2] & (MMC5WRAMMAX-1));
}
MMC5MemIn[4] = 1;
MMC5ROMWrProtect[3] = 1;
@@ -333,7 +472,7 @@ static void MMC5PRG(void) {
MMC5MemIn[1 + x] = 1;
} else {
MMC5ROMWrProtect[x] = 0;
MMC5WRAM(0x8000 + (x << 13), PRGBanks[x] & 7);
MMC5WRAM(0x8000 + (x << 13), PRGBanks[x] & (MMC5WRAMMAX-1));
}
MMC5MemIn[4] = 1;
MMC5ROMWrProtect[3] = 1;
@@ -396,7 +535,7 @@ static DECLFW(Mapper5_write) {
break;
case 0x5113:
WRAMPage = V;
MMC5WRAM(0x6000, V & 7);
MMC5WRAM(0x6000, V & (MMC5WRAMMAX-1));
break;
case 0x5114:
case 0x5115:
@@ -492,7 +631,7 @@ void MMC5Synco(void) {
case 3: PPUNTARAM &= ~(1 << x); vnapage[x] = MMC5fill; break;
}
}
MMC5WRAM(0x6000, WRAMPage & 7);
MMC5WRAM(0x6000, WRAMPage & (MMC5WRAMMAX-1));
if (!mmc5ABMode) {
MMC5CHRB();
MMC5CHRA();
@@ -755,22 +894,42 @@ void NSFMMC5_Close(void) {
if (WRAM)
FCEU_gfree(WRAM);
WRAM = NULL;
MMC5WRAMsize = 0;
FCEU_gfree(ExRAM);
ExRAM = NULL;
}
static void GenMMC5Reset(void) {
int x;
static void GenMMC5Power(void) {
for (x = 0; x < 4; x++) PRGBanks[x] = ~0;
for (x = 0; x < 8; x++) CHRBanksA[x] = ~0;
for (x = 0; x < 4; x++) CHRBanksB[x] = ~0;
WRAMMaskEnable[0] = WRAMMaskEnable[1] = ~0;
mmc5psize = mmc5vsize = 3;
PRGBanks.fill(0xFF);
WRAMPage = 0;
CHRBanksA.fill(0xFF);
CHRBanksB.fill(0xFF);
WRAMMaskEnable.fill(0xFF);
mmc5ABMode = 0;
IRQScanline = 0;
IRQEnable = 0;
CHRMode = 0;
NTAMirroring = NTFill = ATFill = 0xFF;
MMC5IRQR = 0;
MMC5LineCounter = 0;
mmc5psize = mmc5vsize = 3;
mul.fill(0);
MMC5ROMWrProtect.fill(0);
MMC5MemIn.fill(0);
// MMC5fill is and 8-bit tile index, and a 2-bit attribute implented as a mirrored nametable
u8 nval = MMC5fill[0x000];
u8 aval = MMC5fill[0x3C0] & 3; aval = aval | (aval << 2) | (aval << 4) | (aval << 6);
FCEU_dwmemset(MMC5fill + 0x000, nval | (nval<<8) | (nval<<16) | (nval<<24), 0x3C0);
FCEU_dwmemset(MMC5fill + 0x3C0, aval | (aval<<8) | (aval<<16) | (aval<<24), 0x040);
if(MMC5battery == 0) {
FCEU_MemoryRand(WRAM, MMC5WRAMsize * 8 * 1024);
FCEU_MemoryRand(MMC5fill,1024);
FCEU_MemoryRand(ExRAM,1024);
}
MMC5Synco();
@@ -793,11 +952,11 @@ static void GenMMC5Reset(void) {
}
static SFORMAT MMC5_StateRegs[] = {
{ PRGBanks, 4, "PRGB" },
{ CHRBanksA, 16, "CHRA" },
{ CHRBanksB, 8, "CHRB" },
{ &PRGBanks, 4, "PRGB" },
{ &CHRBanksA, 16, "CHRA" },
{ &CHRBanksB, 8, "CHRB" },
{ &WRAMPage, 1, "WRMP" },
{ WRAMMaskEnable, 2, "WRME" },
{ &WRAMMaskEnable, 2, "WRME" },
{ &mmc5ABMode, 1, "ABMD" },
{ &IRQScanline, 1, "IRQS" },
{ &IRQEnable, 1, "IRQE" },
@@ -811,9 +970,9 @@ static SFORMAT MMC5_StateRegs[] = {
{ &MMC5LineCounter, 1, "LCTR" },
{ &mmc5psize, 1, "PSIZ" },
{ &mmc5vsize, 1, "VSIZ" },
{ mul, 2, "MUL2" },
{ MMC5ROMWrProtect, 4, "WRPR" },
{ MMC5MemIn, 5, "MEMI" },
{ &mul, 2, "MUL2" },
{ &MMC5ROMWrProtect, 4, "WRPR" },
{ &MMC5MemIn, 5, "MEMI" },
{ &MMC5Sound.wl[0], 2 | FCEUSTATE_RLSB, "SDW0" },
{ &MMC5Sound.wl[1], 2 | FCEUSTATE_RLSB, "SDW1" },
@@ -836,13 +995,17 @@ static SFORMAT MMC5_StateRegs[] = {
static void GenMMC5_Init(CartInfo *info, int wsize, int battery) {
if (wsize) {
WRAM = (uint8*)FCEU_gmalloc(wsize * 1024);
WRAM = (uint8*)FCEU_malloc(wsize * 1024);
FCEU_MemoryRand(WRAM, wsize * 1024);
SetupCartPRGMapping(0x10, WRAM, wsize * 1024, 1);
AddExState(WRAM, wsize * 1024, 0, "WRAM");
}
MMC5fill = (uint8*)FCEU_gmalloc(1024);
ExRAM = (uint8*)FCEU_gmalloc(1024);
MMC5fill = (uint8*)FCEU_malloc(1024);
ExRAM = (uint8*)FCEU_malloc(1024);
FCEU_MemoryRand(MMC5fill,1024);
FCEU_MemoryRand(ExRAM,1024);
AddExState(ExRAM, 1024, 0, "ERAM");
AddExState(&MMC5HackSPMode, 1, 0, "SPLM");
@@ -854,14 +1017,27 @@ static void GenMMC5_Init(CartInfo *info, int wsize, int battery) {
MMC5WRAMsize = wsize / 8;
BuildWRAMSizeTable();
GameStateRestore = MMC5_StateRestore;
info->Power = GenMMC5Reset;
info->Power = GenMMC5Power;
MMC5battery = battery;
if (battery) {
info->SaveGame[0] = WRAM;
if (wsize <= 16)
info->SaveGameLen[0] = 8192;
uint32 saveGameSize = 0;
if (info->ines2)
{
saveGameSize = info->battery_wram_size;
}
else
info->SaveGameLen[0] = 32768;
{
//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)
saveGameSize = 8192;
else if(wsize == 64)
saveGameSize = 64*1024;
else
saveGameSize = 32768;
}
info->addSaveGameBuf( WRAM, saveGameSize );
}
MMC5HackVROMMask = CHRmask4[0];
@@ -877,7 +1053,14 @@ static void GenMMC5_Init(CartInfo *info, int wsize, int battery) {
}
void Mapper5_Init(CartInfo *info) {
WRAMSIZE = DetectMMC5WRAMSize(info->CRC32);
if (info->ines2)
{
WRAMSIZE = (info->wram_size + info->battery_wram_size) / 1024;
}
else
{
WRAMSIZE = DetectMMC5WRAMSize(info->CRC32);
}
GenMMC5_Init(info, WRAMSIZE, info->battery);
}
+30 -8
View File
@@ -57,9 +57,23 @@ static SFORMAT N106_StateRegs[] = {
{ PRG, 3, "PRG" },
{ CHR, 8, "CHR" },
{ NTAPage, 4, "NTA" },
{ &gorfus, 1, "GORF" },
{ &dopol, 1, "DOPO" },
{ &gorko, 1, "GORK" },
{ 0 }
};
static void SyncMirror()
{
switch(gorko) {
case 0: setmirror(MI_0); break;
case 1: setmirror(MI_V); break;
case 2: setmirror(MI_H); break;
case 3: setmirror(MI_0); break;
}
}
static void SyncPRG(void) {
setprg8(0x8000, PRG[0]);
setprg8(0xa000, PRG[1]);
@@ -143,7 +157,10 @@ static void FixCache(int a, int V) {
case 0x02: FreqCache[w] &= ~0x0000FF00; FreqCache[w] |= V << 8; break;
case 0x04:
FreqCache[w] &= ~0x00030000; FreqCache[w] |= (V & 3) << 16;
LengthCache[w] = (8 - ((V >> 2) & 7)) << 2;
// something wrong here http://www.romhacking.net/forum/index.php?topic=21907.msg306903#msg306903
// LengthCache[w] = (8 - ((V >> 2) & 7)) << 2;
// fix be like in https://github.com/SourMesen/Mesen/blob/cda0a0bdcb5525480784f4b8c71de6fc7273b570/Core/Namco163Audio.h#L61
LengthCache[w] = 256 - (V & 0xFC);
break;
case 0x07: EnvCache[w] = (double)(V & 0xF) * 576716; break;
}
@@ -179,8 +196,11 @@ static DECLFW(Mapper19_write) {
X6502_IRQEnd(FCEU_IQEXT);
break;
case 0xE000:
gorko = V & 0xC0;
PRG[0] = V & 0x3F;
if(is210) {
gorko = V>>6;
SyncMirror();
}
SyncPRG();
break;
case 0xE800:
@@ -331,6 +351,7 @@ static void DoNamcoSound(int32 *Wave, int Count) {
static void Mapper19_StateRestore(int version) {
SyncPRG();
SyncMirror();
FixNTAR();
FixCRR();
int x;
@@ -382,8 +403,8 @@ static void N106_Power(void) {
FixCRR();
if (!battery) {
FCEU_dwmemset(WRAM, 0, 8192);
FCEU_dwmemset(IRAM, 0, 128);
FCEU_MemoryRand(WRAM, sizeof(WRAM), true);
FCEU_MemoryRand(IRAM, sizeof(IRAM), true);
}
for (x = 0x40; x < 0x80; x++)
FixCache(x, IRAM[x]);
@@ -401,15 +422,15 @@ void Mapper19_Init(CartInfo *info) {
if (FSettings.SndRate)
Mapper19_ESI();
FCEU_MemoryRand(WRAM, sizeof(WRAM), true);
FCEU_MemoryRand(IRAM, sizeof(IRAM), true);
AddExState(WRAM, 8192, 0, "WRAM");
AddExState(IRAM, 128, 0, "IRAM");
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 );
}
}
@@ -422,6 +443,7 @@ void Mapper210_Init(CartInfo *info) {
is210 = 1;
GameStateRestore = Mapper210_StateRestore;
info->Power = N106_Power;
FCEU_MemoryRand(WRAM, sizeof(WRAM), true);
AddExState(WRAM, 8192, 0, "WRAM");
AddExState(N106_StateRegs, ~0, 0, 0);
}
+29
View File
@@ -47,6 +47,9 @@ static int16 pcm_addr, pcm_size, pcm_latch, pcm_clock = 0xE1;
static writefunc defapuwrite[64];
static readfunc defapuread[64];
static uint32 WRAMSIZE;
static uint8 *WRAM = NULL;
static SFORMAT StateRegs[] =
{
{ cpu410x, 16, "REGC" },
@@ -265,6 +268,13 @@ static void UNLOneBusPower(void) {
SetWriteHandler(0x4100, 0x410f, UNLOneBusWriteCPU410X);
SetWriteHandler(0x8000, 0xffff, UNLOneBusWriteMMC3);
if (WRAMSIZE) {
FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM);
SetWriteHandler(0x6000, 0x6000 + ((WRAMSIZE - 1) & 0x1fff), CartBW);
SetReadHandler(0x6000, 0x6000 + ((WRAMSIZE - 1) & 0x1fff), CartBR);
setprg8r(0x10, 0x6000, 0);
}
Sync();
}
@@ -282,9 +292,16 @@ static void StateRestore(int version) {
Sync();
}
void UNLOneBusClose(void) {
if (WRAM)
FCEU_gfree(WRAM);
WRAM = NULL;
}
void UNLOneBus_Init(CartInfo *info) {
info->Power = UNLOneBusPower;
info->Reset = UNLOneBusReset;
info->Close = UNLOneBusClose;
if (((*(uint32*)&(info->MD5)) == 0x305fcdc3) || // PowerJoy Supermax Carts
((*(uint32*)&(info->MD5)) == 0x6abfce8e))
@@ -294,4 +311,16 @@ void UNLOneBus_Init(CartInfo *info) {
MapIRQHook = UNLOneBusCpuHook;
GameStateRestore = StateRestore;
AddExState(&StateRegs, ~0, 0, 0);
WRAMSIZE = 8 * 1024;
if (info->ines2)
WRAMSIZE = info->wram_size + info->battery_wram_size;
if (WRAMSIZE) {
WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE);
SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1);
AddExState(WRAM, WRAMSIZE, 0, "WRAM");
if (info->battery) {
info->addSaveGameBuf( WRAM, WRAMSIZE );
}
}
}
+3
View File
@@ -16,6 +16,9 @@
* 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
*
* PEC-586 FC based computer series by DUNDA
*
*/
#include "mapinc.h"
+3 -1
View File
@@ -26,6 +26,8 @@
#include "mapinc.h"
extern u64 xoroshiro128plus_next(); // deterministic random
static DECLFR(UNLRT01Read) {
// u16 i, prot_areas[2][2] = {
// { 0x8E80, 0x8EFF },
@@ -33,7 +35,7 @@ static DECLFR(UNLRT01Read) {
// };
if(((A >= 0xCE80) && (A < 0xCF00)) ||
((A >= 0xFE80) && (A < 0xFF00))) {
return 0xF2 | (rand() & 0x0D);
return 0xF2 | (xoroshiro128plus_next() & 0x0D);
} else
return CartBR(A);
}
+1 -2
View File
@@ -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");
}
+2 -3
View File
@@ -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);
+2 -3
View File
@@ -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");
}
+160 -194
View File
@@ -1,7 +1,7 @@
/* FCE Ultra - NES/Famicom Emulator
*
* Copyright notice for this file:
* Copyright (C) 2014 CaitSith2
* Copyright (C) 2014 CaitSith2, 2022 Cluster
*
* 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
@@ -19,7 +19,7 @@
*/
/*
* Roms still using NES 1.0 format should be loaded as 32K CHR RAM.
* Roms still using NES 1.0 format should be loaded as 8K CHR RAM.
* Roms defined under NES 2.0 should use the VRAM size field, defining 7, 8 or 9, based on how much VRAM should be present.
* UNIF doesn't have this problem, because unique board names can define this information.
* The UNIF names are UNROM-512-8K, UNROM-512-16K and UNROM-512-32K
@@ -28,6 +28,7 @@
* Known games to use this board are:
* Battle Kid 2: Mountain of Torment (512K PRG, 8K CHR RAM, Horizontal Mirroring, Flash disabled)
* Study Hall (128K PRG (in 512K flash chip), 8K CHR RAM, Horizontal Mirroring, Flash enabled)
* Nix: The Paradox Relic (512 PRG, 8K CHR RAM, Vertical Mirroring, Flash enabled)
* Although Xmas 2013 uses a different board, where LEDs can be controlled (with writes to the $8000-BFFF space),
* it otherwise functions identically.
*/
@@ -35,235 +36,200 @@
#include "mapinc.h"
#include "../ines.h"
static uint8 latche, latcheinit, bus_conflict, chrram_mask, software_id=false;
const int ROM_CHIP = 0x00;
const int CFI_CHIP = 0x10;
const int FLASH_CHIP = 0x11;
const int FLASH_SECTOR_SIZE = 4 * 1024;
static uint8 flash_save, flash_state, flash_id_mode, latche, bus_conflict;
static uint16 latcha;
static uint8 *flashdata;
static uint32 *flash_write_count;
static uint8 *FlashPage[32];
static uint32 *FlashWriteCountPage[32];
static uint8 flashloaded = false;
static uint8 *flash_data;
static uint16 flash_buffer_a[10];
static uint8 flash_buffer_v[10];
static uint8 flash_id[2];
static uint8 flash_save=0, flash_state=0, flash_mode=0, flash_bank;
static void (*WLSync)(void);
static void (*WHSync)(void);
static INLINE void setfpageptr(int s, uint32 A, uint8 *p) {
uint32 AB = A >> 11;
int x;
if (p)
for (x = (s >> 1) - 1; x >= 0; x--) {
FlashPage[AB + x] = p - A;
}
else
for (x = (s >> 1) - 1; x >= 0; x--) {
FlashPage[AB + x] = 0;
}
}
void setfprg16(uint32 A, uint32 V) {
if (PRGsize[0] >= 16384) {
V &= PRGmask16[0];
setfpageptr(16, A, flashdata ? (&flashdata[V << 14]) : 0);
} else {
uint32 VA = V << 3;
int x;
for (x = 0; x < 8; x++)
setfpageptr(2, A + (x << 11), flashdata ? (&flashdata[((VA + x) & PRGmask2[0]) << 11]) : 0);
}
}
void inc_flash_write_count(uint8 bank, uint32 A)
{
flash_write_count[(bank*4) + ((A&0x3000)>>12)]++;
if(!flash_write_count[(bank*4) + ((A&0x3000)>>12)])
flash_write_count[(bank*4) + ((A&0x3000)>>12)]++;
}
uint32 GetFlashWriteCount(uint8 bank, uint32 A)
{
return flash_write_count[(bank*4) + ((A&0x3000)>>12)];
static void UNROM512_Sync() {
int chip;
if (flash_save)
chip = !flash_id_mode ? FLASH_CHIP : CFI_CHIP;
else
chip = ROM_CHIP;
setprg16r(chip, 0x8000, latche & 0b11111);
setprg16r(chip, 0xc000, ~0);
setchr8((latche >> 5) & 0b11);
setmirror(MI_0 + ((latche >> 7) & 1));
}
static void StateRestore(int version) {
WHSync();
UNROM512_Sync();
}
static DECLFW(UNROM512LLatchWrite)
static DECLFW(UNROM512FlashWrite)
{
latche = V;
latcha = A;
WLSync();
if (flash_state < sizeof(flash_buffer_a) / sizeof(flash_buffer_a[0])) {
flash_buffer_a[flash_state] = (A & 0x3FFF) | ((latche & 1) << 14);
flash_buffer_v[flash_state] = V;
flash_state++;
// enter flash ID mode
if ((flash_state == 2) &&
(flash_buffer_a[0] == 0x5555) && (flash_buffer_v[0] == 0xAA) &&
(flash_buffer_a[1] == 0x2AAA) && (flash_buffer_v[1] == 0x55) &&
(flash_buffer_a[1] == 0x5555) && (flash_buffer_v[1] == 0x90)) {
flash_id_mode = 0;
flash_state = 0;
}
// erase sector
if ((flash_state == 6) &&
(flash_buffer_a[0] == 0x5555) && (flash_buffer_v[0] == 0xAA) &&
(flash_buffer_a[1] == 0x2AAA) && (flash_buffer_v[1] == 0x55) &&
(flash_buffer_a[2] == 0x5555) && (flash_buffer_v[2] == 0x80) &&
(flash_buffer_a[3] == 0x5555) && (flash_buffer_v[3] == 0xAA) &&
(flash_buffer_a[4] == 0x2AAA) && (flash_buffer_v[4] == 0x55) &&
(flash_buffer_v[5] == 0x30)) {
int offset = &Page[A >> 11][A] - flash_data;
int sector = offset / FLASH_SECTOR_SIZE;
for (int i = sector * FLASH_SECTOR_SIZE; i < (sector + 1) * FLASH_SECTOR_SIZE; i++)
flash_data[i % PRGsize[ROM_CHIP]] = 0xFF;
FCEU_printf("Flash sector #%d is erased (0x%08x - 0x%08x).\n", sector, offset, offset + FLASH_SECTOR_SIZE);
}
// erase chip
if ((flash_state == 6) &&
(flash_buffer_a[0] == 0x5555) && (flash_buffer_v[0] == 0xAA) &&
(flash_buffer_a[1] == 0x2AAA) && (flash_buffer_v[1] == 0x55) &&
(flash_buffer_a[2] == 0x5555) && (flash_buffer_v[2] == 0x80) &&
(flash_buffer_a[3] == 0x5555) && (flash_buffer_v[3] == 0xAA) &&
(flash_buffer_a[4] == 0x2AAA) && (flash_buffer_v[4] == 0x55) &&
(flash_buffer_a[4] == 0x5555) && (flash_buffer_v[4] == 0x10)) {
memset(flash_data, 0xFF, PRGsize[ROM_CHIP]);
FCEU_printf("Flash chip erased.\n");
flash_state = 0;
}
// write byte
if ((flash_state == 4) &&
(flash_buffer_a[0] == 0x5555) && (flash_buffer_v[0] == 0xAA) &&
(flash_buffer_a[1] == 0x2AAA) && (flash_buffer_v[1] == 0x55) &&
(flash_buffer_a[2] == 0x5555) && (flash_buffer_v[2] == 0xA0)) {
int offset = &Page[A >> 11][A] - flash_data;
if (CartBR(A) != 0xFF) {
FCEU_PrintError("Error: can't write to 0x%08x, flash sector is not erased.\n", offset);
}
else {
CartBW(A, V);
}
flash_state = 0;
}
}
// not a command
if (((A & 0xFFF) != 0x0AAA) && ((A & 0xFFF) != 0x0555)) {
flash_state = 0;
}
// reset
if (V == 0xF0) {
flash_state = 0;
flash_id_mode = 0;
}
UNROM512_Sync();
}
static DECLFW(UNROM512HLatchWrite)
{
if (bus_conflict)
latche = (V == CartBR(A)) ? V : 0;
latche = V & CartBR(A);
else
latche = V;
latcha = A;
WHSync();
}
static DECLFR(UNROM512LatchRead)
{
uint8 flash_id[3]={0xB5,0xB6,0xB7};
if(software_id)
{
if(A&1)
return flash_id[ROM_size>>4];
else
return 0xBF;
}
if(flash_save)
{
if(A < 0xC000)
{
if(GetFlashWriteCount(flash_bank,A))
return FlashPage[A >> 11][A];
}
else
{
if(GetFlashWriteCount(ROM_size-1,A))
return FlashPage[A >> 11][A];
}
}
return Page[A >> 11][A];
UNROM512_Sync();
}
static void UNROM512LatchPower(void) {
latche = latcheinit;
WHSync();
SetReadHandler(0x8000, 0xFFFF, UNROM512LatchRead);
latche = 0;
UNROM512_Sync();
SetReadHandler(0x8000, 0xFFFF, CartBR);
if(!flash_save)
SetWriteHandler(0x8000, 0xFFFF, UNROM512HLatchWrite);
else
{
SetWriteHandler(0x8000,0xBFFF,UNROM512LLatchWrite);
SetWriteHandler(0x8000,0xBFFF,UNROM512FlashWrite);
SetWriteHandler(0xC000,0xFFFF,UNROM512HLatchWrite);
}
}
static void UNROM512LatchClose(void) {
if(flash_write_count)
FCEU_gfree(flash_write_count);
if(flashdata)
FCEU_gfree(flashdata);
flash_write_count = NULL;
flashdata = NULL;
if(flash_data)
FCEU_gfree(flash_data);
flash_data = NULL;
}
static void UNROM512LSync() {
int erase_a[5]={0x9555,0xAAAA,0x9555,0x9555,0xAAAA};
int erase_d[5]={0xAA,0x55,0x80,0xAA,0x55};
int erase_b[5]={1,0,1,1,0};
if(flash_mode==0)
{
if((latcha == erase_a[flash_state]) && (latche == erase_d[flash_state]) && (flash_bank == erase_b[flash_state]))
{
flash_state++;
if(flash_state == 5)
{
flash_mode=1;
}
}
else if ((flash_state==2)&&(latcha==0x9555)&&(latche==0xA0)&&(flash_bank==1))
{
flash_state++;
flash_mode=2;
}
else if ((flash_state==2)&&(latcha==0x9555)&&(latche==0x90)&&(flash_bank==1))
{
flash_state=0;
software_id=true;
}
else
{
if(latche==0xF0)
software_id=false;
flash_state=0;
}
}
else if(flash_mode==1) //Chip Erase or Sector Erase
{
if(latche==0x30)
{
inc_flash_write_count(flash_bank,latcha);
memset(&FlashPage[(latcha & 0xF000) >> 11][latcha & 0xF000],0xFF,0x1000);
}
else if (latche==0x10)
{
for(uint32 i=0;i<(ROM_size*4);i++)
inc_flash_write_count(i>>2,i<<12);
memset(flashdata,0xFF,ROM_size*0x4000); //Erasing the rom chip as instructed. Crash rate calulated to be 99.9% :)
}
flash_state=0;
flash_mode=0;
}
else if(flash_mode==2) //Byte Program
{
if(!GetFlashWriteCount(flash_bank,latcha))
{
inc_flash_write_count(flash_bank,latcha);
memcpy(&FlashPage[(latcha & 0xF000) >> 11][latcha & 0xF000],&Page[(latcha & 0xF000)>>11][latcha & 0xF000],0x1000);
}
FlashPage[latcha>>11][latcha]&=latche;
flash_state=0;
flash_mode=0;
}
}
static void UNROM512HSync()
static void UNROM512_FlashReset(void)
{
flash_bank=latche&(ROM_size-1);
setprg16(0x8000, flash_bank);
setprg16(0xc000, ~0);
setfprg16(0x8000, flash_bank);
setfprg16(0xC000, ~0);
setchr8r(0, (latche & chrram_mask) >> 5);
setmirror(MI_0+(latche>>7));
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) {
flash_state=0;
flash_bank=0;
flash_save=info->battery;
if(info->vram_size == 8192)
chrram_mask = 0;
else if (info->vram_size == 16384)
chrram_mask = 0x20;
else
chrram_mask = 0x60;
SetupCartMirroring(info->mirror,(info->mirror>=MI_0)?0:1,0);
bus_conflict = !info->battery;
latcheinit = 0;
WLSync = UNROM512LSync;
WHSync = UNROM512HSync;
info->Power = UNROM512LatchPower;
info->Close = UNROM512LatchClose;
GameStateRestore = StateRestore;
flash_state = 0;
flash_id_mode = 0;
flash_save = info->battery;
bus_conflict = !info->battery; // Is it required by any game?
int mirror = (head.ROM_type & 1) | ((head.ROM_type & 8) >> 2);
switch (mirror)
{
case 0: // hard horizontal, internal
SetupCartMirroring(MI_H, 1, NULL);
break;
case 1: // hard vertical, internal
SetupCartMirroring(MI_V, 1, NULL);
break;
case 2: // switchable 1-screen, internal (flags: 4-screen + horizontal)
SetupCartMirroring(MI_0, 0, NULL);
break;
case 3: // hard four screen, last 8k of 32k RAM (flags: 4-screen + vertical)
SetupCartMirroring( 4, 1, VROM + (info->vram_size - 8192));
break;
}
if(flash_save)
{
flashdata = (uint8*)FCEU_gmalloc(ROM_size*0x4000);
flash_write_count = (uint32*)FCEU_gmalloc(ROM_size*4*sizeof(uint32));
info->SaveGame[0] = (uint8*)flash_write_count;
info->SaveGame[1] = flashdata;
info->SaveGameLen[0] = ROM_size*4*sizeof(uint32);
info->SaveGameLen[1] = ROM_size*0x4000;
AddExState(flash_write_count,ROM_size*4*sizeof(uint32),0,"FLASH_WRITE_COUNT");
AddExState(flashdata,ROM_size*0x4000,0,"FLASH_DATA");
AddExState(&flash_state,1,0,"FLASH_STATE");
AddExState(&flash_mode,1,0,"FLASH_MODE");
AddExState(&flash_bank,1,0,"FLASH_BANK");
AddExState(&latcha,2,0,"LATA");
// Allocate memory for flash
size_t flash_size = PRGsize[ROM_CHIP];
flash_data = (uint8*)FCEU_gmalloc(flash_size);
// Copy ROM to flash data
for (size_t i = 0; i < flash_size; i++) {
flash_data[i] = PRGptr[ROM_CHIP][i];
}
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, 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(&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");
}
+69 -100
View File
@@ -20,14 +20,14 @@
#include "mapinc.h"
static uint8 isPirate, is22;
static bool isPirate;
static uint8 is22, reg1mask, reg2mask;
static uint16 IRQCount;
static uint8 IRQLatch, IRQa;
static uint8 IRQLatch, IRQa, IRQMode;
static uint8 prgreg[2], chrreg[8];
static uint16 chrhi[8];
static uint8 regcmd, irqcmd, mirr, big_bank;
static uint16 acount = 0;
static uint16 weirdo = 0;
static uint8 *WRAM = NULL;
static uint32 WRAMSIZE;
@@ -37,6 +37,7 @@ static SFORMAT StateRegs[] =
{ prgreg, 2, "PREG" },
{ chrreg, 8, "CREG" },
{ chrhi, 16, "CRGH" },
{ &acount, 2, "ACNT" },
{ &regcmd, 1, "CMDR" },
{ &irqcmd, 1, "CMDI" },
{ &mirr, 1, "MIRR" },
@@ -44,6 +45,7 @@ static SFORMAT StateRegs[] =
{ &IRQCount, 2, "IRQC" },
{ &IRQLatch, 1, "IRQL" },
{ &IRQa, 1, "IRQA" },
{ &IRQMode, 1, "IRQM" },
{ 0 }
};
@@ -61,15 +63,8 @@ static void Sync(void) {
setchr8(0);
else{
uint8 i;
if(!weirdo)
for (i = 0; i < 8; i++)
setchr1(i << 10, (chrhi[i] | chrreg[i]) >> is22);
else {
setchr1(0x0000, 0xFC);
setchr1(0x0400, 0xFD);
setchr1(0x0800, 0xFF);
weirdo--;
}
for (i = 0; i < 8; i++)
setchr1(i << 10, (chrhi[i] | chrreg[i]) >> is22);
}
switch (mirr & 0x3) {
case 0: setmirror(MI_V); break;
@@ -80,7 +75,7 @@ static void Sync(void) {
}
static DECLFW(VRC24Write) {
A &= 0xF003;
A = A & 0xF000 | !!(A & reg2mask) << 1 | !!(A & reg1mask);
if ((A >= 0xB000) && (A <= 0xE003)) {
if (UNIFchrrama)
big_bank = (V & 8) << 2; // my personally many-in-one feature ;) just for support pirate cart 2-in-1
@@ -121,81 +116,49 @@ static DECLFW(VRC24Write) {
case 0x9003: regcmd = V; Sync(); break;
case 0xF000: X6502_IRQEnd(FCEU_IQEXT); IRQLatch &= 0xF0; IRQLatch |= V & 0xF; break;
case 0xF001: X6502_IRQEnd(FCEU_IQEXT); IRQLatch &= 0x0F; IRQLatch |= V << 4; break;
case 0xF002: X6502_IRQEnd(FCEU_IQEXT); acount = 0; IRQCount = IRQLatch; IRQa = V & 2; irqcmd = V & 1; break;
case 0xF002: X6502_IRQEnd(FCEU_IQEXT); acount = 0; IRQCount = IRQLatch; IRQMode = V & 4; IRQa = V & 2; irqcmd = V & 1; break;
case 0xF003: X6502_IRQEnd(FCEU_IQEXT); IRQa = irqcmd; break;
}
}
static DECLFW(M21Write) {
A = (A & 0xF000) | ((A >> 1) & 0x3); // Ganbare Goemon Gaiden 2 - Tenka no Zaihou (J) [!] isn't mapper 21 actually,
// it's mapper 23 by wirings
VRC24Write(A, V);
}
static DECLFW(M22Write) {
if (A == 0xC007) { // Ganbare Goemon Gaiden does strange things!!! at the end credits
weirdo = 8; // quick dirty hack, seems there is no other games with such PCB, so
// we never know if it will not work for something else lol
static void VRC24Power(void) {
big_bank = 0x20;
Sync();
if (WRAM) {
setprg8r(0x10, 0x6000, 0);
SetReadHandler(0x6000, 0x7FFF, CartBR);
SetWriteHandler(0x6000, 0x7FFF, CartBW);
FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM);
}
A |= ((A >> 2) & 0x3); // It's just swapped lines from 21 mapper
//
VRC24Write((A & 0xF000) | ((A >> 1) & 1) | ((A << 1) & 2), V);
}
static DECLFW(M23Write) {
A |= ((A >> 2) & 0x3) | ((A >> 4) & 0x3) | ((A >> 6) & 0x3);// actually there is many-in-one mapper source, some pirate or
// licensed games use various address bits for registers
VRC24Write(A, V);
}
static void M21Power(void) {
Sync();
SetReadHandler(0x8000, 0xFFFF, CartBR);
SetWriteHandler(0x8000, 0xFFFF, M21Write);
}
static void M22Power(void) {
Sync();
SetReadHandler(0x8000, 0xFFFF, CartBR);
SetWriteHandler(0x8000, 0xFFFF, M22Write);
}
static void M23Power(void) {
big_bank = 0x20;
Sync();
setprg8r(0x10, 0x6000, 0); // Only two Goemon games are have battery backed RAM, three more shooters
// (Parodius Da!, Gradius 2 and Crisis Force uses 2k or SRAM at 6000-67FF only
SetReadHandler(0x6000, 0x7FFF, CartBR);
SetWriteHandler(0x6000, 0x7FFF, CartBW);
SetReadHandler(0x8000, 0xFFFF, CartBR);
SetWriteHandler(0x8000, 0xFFFF, M23Write);
FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM);
}
static void M25Power(void) {
big_bank = 0x20;
Sync();
setprg8r(0x10, 0x6000, 0);
SetReadHandler(0x6000, 0x7FFF, CartBR);
SetWriteHandler(0x6000, 0x7FFF, CartBW);
SetReadHandler(0x8000, 0xFFFF, CartBR);
SetWriteHandler(0x8000, 0xFFFF, M22Write);
FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM);
SetWriteHandler(0x8000, 0xFFFF, VRC24Write);
}
void VRC24IRQHook(int a) {
#define LCYCS 341
if (IRQa) {
acount += a * 3;
if (acount >= LCYCS) {
while (acount >= LCYCS) {
acount -= LCYCS;
if (IRQMode) {
acount += a;
while (acount > 0) {
acount--;
IRQCount++;
if (IRQCount & 0x100) {
X6502_IRQBegin(FCEU_IQEXT);
IRQCount = IRQLatch;
}
}
} else {
acount += a * 3;
if (acount >= LCYCS) {
while (acount >= LCYCS) {
acount -= LCYCS;
IRQCount++;
if (IRQCount & 0x100) {
X6502_IRQBegin(FCEU_IQEXT);
IRQCount = IRQLatch;
}
}
}
}
}
}
@@ -210,26 +173,8 @@ static void VRC24Close(void) {
WRAM = NULL;
}
void Mapper21_Init(CartInfo *info) {
isPirate = 0;
is22 = 0;
info->Power = M21Power;
MapIRQHook = VRC24IRQHook;
GameStateRestore = StateRestore;
AddExState(&StateRegs, ~0, 0, 0);
}
void Mapper22_Init(CartInfo *info) {
isPirate = 0;
is22 = 1;
info->Power = M22Power;
GameStateRestore = StateRestore;
AddExState(&StateRegs, ~0, 0, 0);
}
void VRC24_Init(CartInfo *info) {
static void VRC24_Init(CartInfo *info) {
info->Power = VRC24Power;
info->Close = VRC24Close;
MapIRQHook = VRC24IRQHook;
GameStateRestore = StateRestore;
@@ -240,30 +185,54 @@ 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);
}
void Mapper23_Init(CartInfo *info) {
isPirate = 0;
void Mapper21_Init(CartInfo *info) {
isPirate = false;
is22 = 0;
info->Power = M23Power;
reg1mask = 0x42;
reg2mask = 0x84;
VRC24_Init(info);
}
void Mapper22_Init(CartInfo *info) {
isPirate = false;
is22 = 1;
reg1mask = 2;
reg2mask = 1;
// no IRQ (all mapper 22 games are VRC2)
// no WRAM
info->Power = VRC24Power;
GameStateRestore = StateRestore;
AddExState(&StateRegs, ~0, 0, 0);
}
void Mapper23_Init(CartInfo *info) {
isPirate = false;
is22 = 0;
reg1mask = 0x15;
reg2mask = 0x2a;
VRC24_Init(info);
}
void Mapper25_Init(CartInfo *info) {
isPirate = 0;
isPirate = false;
is22 = 0;
info->Power = M25Power;
reg1mask = 0xa;
reg2mask = 0x5;
VRC24_Init(info);
}
void UNLT230_Init(CartInfo *info) {
isPirate = 1;
isPirate = true;
is22 = 0;
info->Power = M23Power;
reg1mask = 0x15;
reg2mask = 0x2a;
VRC24_Init(info);
}
+159 -121
View File
@@ -1,7 +1,7 @@
/* FCE Ultra - NES/Famicom Emulator
*
* Copyright notice for this file:
* Copyright (C) 2005 CaH4e3
* Copyright (C) 2005-2019 CaH4e3
*
* 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
@@ -17,25 +17,118 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* VRC-5 (CAI Shogakko no Sansu)
* VRC-V (CAI Shogakko no Sansu)
*
*/
#include "mapinc.h"
static uint8 QTAINTRAM[2048];
static writefunc old2007wrap;
//#define CAI_DEBUG
// main tiles RAM is 8K in size, but unless other non-CHR ROM type carts,
// this one accesses the $0000 and $1000 pages based on extra NT RAM on board
// which is similar to MMC5 but much simpler because there are no additional
// bankings here.
// extra NT RAM handling is in PPU code now.
static uint16 CHRSIZE = 8192;
static uint16 WRAMSIZE = 8192 + 4096;
// there are two separate WRAMs 8K each, on main system cartridge (not battery
// backed), and one on the daughter cart (with battery). both are accessed
// via the same registers with additional selector flags.
static uint16 WRAMSIZE = 8192 + 8192;
static uint8 *CHRRAM = NULL;
static uint8 *WRAM = NULL;
static uint8 IRQa, K4IRQ;
static uint32 IRQLatch, IRQCount;
// some kind of 16-bit text encoding (actually 14-bit) used in game resources
// may be converted by the hardware into the tile indexes for internal CHR ROM
// not sure whey they made it hardware, because most of calculations are just
// bit shifting. the main purpose of this table is to calculate actual CHR ROM
// bank for every character. there is a some kind of regularity, so this table
// may be calculated in software easily.
// table read out from hardware registers as is
///*
static uint8 conv_tbl[4][8] = {
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x40, 0x10, 0x28, 0x00, 0x18, 0x30 },
{ 0x00, 0x00, 0x48, 0x18, 0x30, 0x08, 0x20, 0x38 },
{ 0x00, 0x00, 0x80, 0x20, 0x38, 0x10, 0x28, 0xB0 }
};
//*/
/*
static uint8 conv_tbl[64][4] = {
{ 0x40, 0x40, 0x40, 0x40 }, // 00 | A - 40 41 42 43 44 45 46 47
{ 0x41, 0x41, 0x41, 0x41 }, // 02 | B - 48 49 4A 4B 4C 4D 4E 4F
{ 0x42, 0x42, 0x42, 0x42 }, // 04 | C - 50 51 52 53 54 55 56 57
{ 0x43, 0x43, 0x43, 0x43 }, // 06 | D - 58 59 5A 5B 5C 5D 5E 5F
{ 0x44, 0x44, 0x44, 0x44 }, // 08 | E - 60 61 62 63 64 65 66 67
{ 0x45, 0x45, 0x45, 0x45 }, // 0A | F - 68 69 6A 6B 6C 6D 6E 6F
{ 0x46, 0x46, 0x46, 0x46 }, // 0C | G - 70 71 72 73 74 75 76 77
{ 0x47, 0x47, 0x47, 0x47 }, // 0E | H - 78 79 7A 7B 7C 7D 7E 7F
{ 0x40, 0x40, 0x40, 0x40 }, // 10 |
{ 0x41, 0x41, 0x41, 0x41 }, // 12 +----------------------------
{ 0x42, 0x42, 0x42, 0x42 }, // 14 | A A A A
{ 0x43, 0x43, 0x43, 0x43 }, // 16 | A A A A
{ 0x44, 0x44, 0x44, 0x44 }, // 18 | A A' B' A"
{ 0x45, 0x45, 0x45, 0x45 }, // 1A | A C D E
{ 0x46, 0x46, 0x46, 0x46 }, // 1C | A F G H
{ 0x47, 0x47, 0x47, 0x47 }, // 1E | A A B C
{ 0x40, 0x40, 0x48, 0x44 }, // 20 | A D E F
{ 0x41, 0x41, 0x49, 0x45 }, // 22 | A G H G"
{ 0x42, 0x42, 0x4A, 0x46 }, // 24 +----------------------------
{ 0x43, 0x43, 0x4B, 0x47 }, // 26 | A' - 40 41 42 43 40 41 42 43
{ 0x44, 0x40, 0x48, 0x44 }, // 28 | A" - 44 45 46 47 44 45 46 47
{ 0x45, 0x41, 0x49, 0x45 }, // 2A | B' - 48 49 4A 4B 48 49 4A 4B
{ 0x46, 0x42, 0x4A, 0x46 }, // 2C | G" - 74 75 76 77 74 75 76 77
{ 0x47, 0x43, 0x4B, 0x47 }, // 2E
{ 0x40, 0x50, 0x58, 0x60 }, // 30
{ 0x41, 0x51, 0x59, 0x61 }, // 32
{ 0x42, 0x52, 0x5A, 0x62 }, // 34
{ 0x43, 0x53, 0x5B, 0x63 }, // 36
{ 0x44, 0x54, 0x5C, 0x64 }, // 38
{ 0x45, 0x55, 0x5D, 0x65 }, // 3A
{ 0x46, 0x56, 0x5E, 0x66 }, // 3C
{ 0x47, 0x57, 0x5F, 0x67 }, // 3E
{ 0x40, 0x68, 0x70, 0x78 }, // 40
{ 0x41, 0x69, 0x71, 0x79 }, // 42
{ 0x42, 0x6A, 0x72, 0x7A }, // 44
{ 0x43, 0x6B, 0x73, 0x7B }, // 46
{ 0x44, 0x6C, 0x74, 0x7C }, // 48
{ 0x45, 0x6D, 0x75, 0x7D }, // 4A
{ 0x46, 0x6E, 0x76, 0x7E }, // 4C
{ 0x47, 0x6F, 0x77, 0x7F }, // 4E
{ 0x40, 0x40, 0x48, 0x50 }, // 50
{ 0x41, 0x41, 0x49, 0x51 }, // 52
{ 0x42, 0x42, 0x4A, 0x52 }, // 54
{ 0x43, 0x43, 0x4B, 0x53 }, // 56
{ 0x44, 0x44, 0x4C, 0x54 }, // 58
{ 0x45, 0x45, 0x4D, 0x55 }, // 5A
{ 0x46, 0x46, 0x4E, 0x56 }, // 5C
{ 0x47, 0x47, 0x4F, 0x57 }, // 5E
{ 0x40, 0x58, 0x60, 0x68 }, // 60
{ 0x41, 0x59, 0x61, 0x69 }, // 62
{ 0x42, 0x5A, 0x62, 0x6A }, // 64
{ 0x43, 0x5B, 0x63, 0x6B }, // 66
{ 0x44, 0x5C, 0x64, 0x6C }, // 68
{ 0x45, 0x5D, 0x65, 0x6D }, // 6A
{ 0x46, 0x5E, 0x66, 0x6E }, // 6C
{ 0x47, 0x5F, 0x67, 0x6F }, // 6E
{ 0x40, 0x70, 0x78, 0x74 }, // 70
{ 0x41, 0x71, 0x79, 0x75 }, // 72
{ 0x42, 0x72, 0x7A, 0x76 }, // 74
{ 0x43, 0x73, 0x7B, 0x77 }, // 76
{ 0x44, 0x74, 0x7C, 0x74 }, // 78
{ 0x45, 0x75, 0x7D, 0x75 }, // 7A
{ 0x46, 0x76, 0x7E, 0x76 }, // 7C
{ 0x47, 0x77, 0x7F, 0x77 }, // 7E
};
*/
static uint8 regs[16];
//static uint8 test[8];
static SFORMAT StateRegs[] =
{
{ &IRQCount, 1, "IRQC" },
@@ -48,93 +141,68 @@ static SFORMAT StateRegs[] =
static void chrSync(void) {
setchr4r(0x10, 0x0000, regs[5] & 1);
setchr4r(0x10, 0x1000, 0);
// 30.06.19 CaH4e3 there is much more complicated behaviour with second banking register, you may actually
// view the content of the internal character CHR rom via this window, but it is useless because hardware
// does not use this area to access the internal ROM. not sure why they did this, but I see no need to
// emulate this behaviour carefully, unless I find something that I missed...
setchr4r(0x10, 0x1000, 1);
}
static void Sync(void) {
chrSync();
// if(regs[0xA]&0x10)
// {
/* setchr1r(0x10,0x0000,(((regs[5]&1))<<2)+0);
setchr1r(0x10,0x0400,(((regs[5]&1))<<2)+1);
setchr1r(0x10,0x0800,(((regs[5]&1))<<2)+2);
setchr1r(0x10,0x0c00,(((regs[5]&1))<<2)+3);
setchr1r(0x10,0x1000,0);
setchr1r(0x10,0x1400,1);
setchr1r(0x10,0x1800,2);
setchr1r(0x10,0x1c00,3);*/
/* setchr1r(0x10,0x0000,(((regs[5]&1))<<2)+0);
setchr1r(0x10,0x0400,(((regs[5]&1))<<2)+1);
setchr1r(0x10,0x0800,(((regs[5]&1))<<2)+2);
setchr1r(0x10,0x0c00,(((regs[5]&1))<<2)+3);
setchr1r(0x10,0x1000,(((regs[5]&1)^1)<<2)+4);
setchr1r(0x10,0x1400,(((regs[5]&1)^1)<<2)+5);
setchr1r(0x10,0x1800,(((regs[5]&1)^1)<<2)+6);
setchr1r(0x10,0x1c00,(((regs[5]&1)^1)<<2)+7);
*/
// }
// else
// {
/*
setchr1r(0x10,0x0000,(((regs[5]&1)^1)<<2)+0);
setchr1r(0x10,0x0400,(((regs[5]&1)^1)<<2)+1);
setchr1r(0x10,0x0800,(((regs[5]&1)^1)<<2)+2);
setchr1r(0x10,0x0c00,(((regs[5]&1)^1)<<2)+3);
setchr1r(0x10,0x1000,(((regs[5]&1))<<2)+4);
setchr1r(0x10,0x1400,(((regs[5]&1))<<2)+5);
setchr1r(0x10,0x1800,(((regs[5]&1))<<2)+6);
setchr1r(0x10,0x1c00,(((regs[5]&1))<<2)+7);
// }
//*/
/* setchr1r(1,0x0000,test[0]);
setchr1r(1,0x0400,test[1]);
setchr1r(1,0x0800,test[2]);
setchr1r(1,0x0c00,test[3]);
setchr1r(1,0x1000,test[4]);
setchr1r(1,0x1400,test[5]);
setchr1r(1,0x1800,test[6]);
setchr1r(1,0x1c00,test[7]);
*/
setprg4r(0x10, 0x6000, regs[0] & 1);
if (regs[2] >= 0x40)
setprg8r(1, 0x8000, (regs[2] - 0x40));
else
setprg8r(0, 0x8000, (regs[2] & 0x3F));
if (regs[3] >= 0x40)
setprg8r(1, 0xA000, (regs[3] - 0x40));
else
setprg8r(0, 0xA000, (regs[3] & 0x3F));
if (regs[4] >= 0x40)
setprg8r(1, 0xC000, (regs[4] - 0x40));
else
setprg8r(0, 0xC000, (regs[4] & 0x3F));
setprg8r(1, 0xE000, ~0);
setmirror(MI_V);
setprg4r(0x10, 0x6000, (regs[0] & 1) | (regs[0] >> 2)); // two 4K banks are identical, either internal or excernal
setprg4r(0x10, 0x7000, (regs[1] & 1) | (regs[1] >> 2)); // SRAMs may be mapped in any bank independently
if (PRGptr[1] == NULL) { // for iNES 2.0 version it even more hacky lol
setprg8(0x8000, (regs[2] & 0x3F) + ((regs[2] & 0x40) >> 2));
setprg8(0xA000, (regs[3] & 0x3F) + ((regs[3] & 0x40) >> 2));
setprg8(0xC000, (regs[4] & 0x3F) + ((regs[4] & 0x40) >> 2));
setprg8(0xE000, 0x10 + 0x3F);
} else {
setprg8r((regs[2] >> 6) & 1, 0x8000, (regs[2] & 0x3F));
setprg8r((regs[3] >> 6) & 1, 0xA000, (regs[3] & 0x3F));
setprg8r((regs[4] >> 6) & 1, 0xC000, (regs[4] & 0x3F));
setprg8r(1, 0xE000, ~0); // always sees the last bank of the external cart, so can't be booted without it.
}
setmirror(((regs[0xA]&2)>>1)^1);
}
/*static DECLFW(TestWrite)
{
test[A&7] = V;
Sync();
}*/
static DECLFW(M190Write) {
// FCEU_printf("write %04x:%04x %d, %d\n",A,V,scanline,timestamp);
regs[(A & 0x0F00) >> 8] = V;
static DECLFW(QTAiWrite) {
regs[(A & 0x0F00) >> 8] = V; // IRQ pretty the same as in other VRC mappers by Konami
switch (A) {
case 0xd600: IRQLatch &= 0xFF00; IRQLatch |= V; break;
case 0xd700: IRQLatch &= 0x00FF; IRQLatch |= V << 8; break;
case 0xd900: IRQCount = IRQLatch; IRQa = V & 2; K4IRQ = V & 1; X6502_IRQEnd(FCEU_IQEXT); break;
case 0xd800: IRQa = K4IRQ; X6502_IRQEnd(FCEU_IQEXT); break;
case 0xda00: qtaintramreg = regs[0xA] & 3; break; // register shadow to share it with ppu
}
Sync();
}
static DECLFR(M190Read) {
// FCEU_printf("read %04x:%04x %d, %d\n",A,regs[(A&0x0F00)>>8],scanline,timestamp);
return regs[(A & 0x0F00) >> 8] + regs[0x0B];
static DECLFR(QTAiRead) {
// uint8 res1 = conv_tbl[(regs[0xD] & 0x7F) >> 1][(regs[0xC] >> 5) & 3];
// uint8 res2 = ((regs[0xD] & 1) << 7) | ((regs[0xC] & 0x1F) << 2) | (regs[0xB] & 3);
uint8 tabl = conv_tbl[(regs[0xC] >> 5) & 3][(regs[0xD] & 0x7F) >> 4];
uint8 res1 = 0x40 | (tabl & 0x3F) | ((regs[0xD] >> 1) & 7) | ((regs[0xB] & 4) << 5);
uint8 res2 = ((regs[0xD] & 1) << 7) | ((regs[0xC] & 0x1F) << 2) | (regs[0xB] & 3);
if (tabl & 0x40)
res1 &= 0xFB;
else if (tabl & 0x80)
res1 |= 0x04;
if (A == 0xDD00) {
return res1;
} else if (A == 0xDC00) {
#ifdef CAI_DEBUG
FCEU_printf("%02x:%02x+%d -> %02x:%02x\n", regs[0xD], regs[0xC], regs[0xB], res1, res2);
#endif
return res2;
} else
return 0;
}
static void VRC5IRQ(int a) {
if (IRQa) {
IRQCount += a;
@@ -145,50 +213,17 @@ static void VRC5IRQ(int a) {
}
}
//static void Mapper190_PPU(uint32 A)
//{
// if(A<0x2000)
// setchr4r(0x10,0x1000,QTAINTRAM[A&0x1FFF]&1);
// else
// chrSync();
//}
static DECLFW(M1902007Wrap) {
if (A >= 0x2000) {
if (regs[0xA] & 1)
QTAINTRAM[A & 0x1FFF] = V;
else
old2007wrap(A, V);
}
}
static void M190Power(void) {
/* test[0]=0;
test[1]=1;
test[2]=2;
test[3]=3;
test[4]=4;
test[5]=5;
test[6]=6;
test[7]=7;
*/
setprg4r(0x10, 0x7000, 2);
old2007wrap = GetWriteHandler(0x2007);
SetWriteHandler(0x2007, 0x2007, M1902007Wrap);
static void QTAiPower(void) {
SetReadHandler(0x6000, 0xFFFF, CartBR);
// SetWriteHandler(0x5000,0x5007,TestWrite);
SetWriteHandler(0x6000, 0x7FFF, CartBW);
SetWriteHandler(0x8000, 0xFFFF, M190Write);
SetReadHandler(0xDC00, 0xDC00, M190Read);
SetReadHandler(0xDD00, 0xDD00, M190Read);
SetWriteHandler(0x8000, 0xFFFF, QTAiWrite);
SetReadHandler(0xDC00, 0xDC00, QTAiRead);
SetReadHandler(0xDD00, 0xDD00, QTAiRead);
FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM);
Sync();
}
static void M190Close(void) {
static void QTAiClose(void) {
if (CHRRAM)
FCEU_gfree(CHRRAM);
CHRRAM = NULL;
@@ -201,13 +236,14 @@ static void StateRestore(int version) {
Sync();
}
void Mapper190_Init(CartInfo *info) {
info->Power = M190Power;
info->Close = M190Close;
void QTAi_Init(CartInfo *info) {
QTAIHack = 1;
info->Power = QTAiPower;
info->Close = QTAiClose;
GameStateRestore = StateRestore;
MapIRQHook = VRC5IRQ;
// PPU_hook=Mapper190_PPU;
CHRRAM = (uint8*)FCEU_gmalloc(CHRSIZE);
SetupCartCHRMapping(0x10, CHRRAM, CHRSIZE, 1);
@@ -218,8 +254,10 @@ void Mapper190_Init(CartInfo *info) {
AddExState(WRAM, WRAMSIZE, 0, "WRAM");
if (info->battery) {
info->SaveGame[0] = WRAM;
info->SaveGameLen[0] = WRAMSIZE - 4096;
// 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->addSaveGameBuf( WRAM, WRAMSIZE );
}
AddExState(&StateRegs, ~0, 0, 0);
+24 -11
View File
@@ -25,10 +25,10 @@
static uint8 is26;
static uint8 prg[2], chr[8], mirr;
static uint8 IRQLatch, IRQa, IRQd;
static uint8 IRQLatch, IRQa, IRQd, IRQMode;
static int32 IRQCount, CycleCount;
static uint8 *WRAM = NULL;
static uint32 WRAMSIZE;
static uint32 WRAMSIZE=0;
static SFORMAT StateRegs[] =
{
@@ -40,6 +40,7 @@ static SFORMAT StateRegs[] =
{ &IRQLatch, 1, "IRQL" },
{ &IRQCount, 4, "IRQC" },
{ &CycleCount, 4, "CYCC" },
{ &IRQMode, 1, "IRQM" },
{ 0 }
};
@@ -109,6 +110,7 @@ static DECLFW(VRC6Write) {
case 0xE003: chr[7] = V; Sync(); break;
case 0xF000: IRQLatch = V; X6502_IRQEnd(FCEU_IQEXT); break;
case 0xF001:
IRQMode = V & 4;
IRQa = V & 2;
IRQd = V & 1;
if (V & 2)
@@ -132,13 +134,25 @@ static void VRC6Power(void) {
static void VRC6IRQHook(int a) {
if (IRQa) {
CycleCount += a * 3;
while(CycleCount >= 341) {
CycleCount -= 341;
IRQCount++;
if (IRQCount == 0x100) {
IRQCount = IRQLatch;
X6502_IRQBegin(FCEU_IQEXT);
if (IRQMode) {
CycleCount += a;
while (CycleCount > 0) {
CycleCount--;
IRQCount++;
if (IRQCount & 0x100) {
X6502_IRQBegin(FCEU_IQEXT);
IRQCount = IRQLatch;
}
}
} else {
CycleCount += a * 3;
while(CycleCount >= 341) {
CycleCount -= 341;
IRQCount++;
if (IRQCount == 0x100) {
IRQCount = IRQLatch;
X6502_IRQBegin(FCEU_IQEXT);
}
}
}
}
@@ -365,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);
+25 -12
View File
@@ -21,10 +21,10 @@
#include "mapinc.h"
static uint8 vrc7idx, preg[3], creg[8], mirr;
static uint8 IRQLatch, IRQa, IRQd;
static uint8 IRQLatch, IRQa, IRQd, IRQMode;
static int32 IRQCount, CycleCount;
static uint8 *WRAM = NULL;
static uint32 WRAMSIZE;
static uint32 WRAMSIZE=0;
#include "emu2413.h"
@@ -44,6 +44,7 @@ static SFORMAT StateRegs[] =
{ &IRQCount, 4, "IRQC" },
{ &CycleCount, 4, "CYCC" },
{ (void**)VRC7Sound_saveptr, sizeof(*VRC7Sound) | FCEUSTATE_INDIRECT, "VRC7" },
{ &IRQMode, 1, "IRQM" },
{0}
};
@@ -86,7 +87,7 @@ static void VRC7SKill(void) {
static void VRC7_ESI(void) {
GameExpSound.RChange = VRC7SC;
GameExpSound.Kill = VRC7SKill;
VRC7Sound = OPLL_new(3579545, FSettings.SndRate ? FSettings.SndRate : 44100);
VRC7Sound = OPLL_new(3579545, FSettings.SndRate ? FSettings.SndRate : 48000);
OPLL_reset(VRC7Sound);
OPLL_reset(VRC7Sound);
}
@@ -134,6 +135,7 @@ static DECLFW(VRC7Write) {
case 0xE000: mirr = V & 3; Sync(); break;
case 0xE010: IRQLatch = V; X6502_IRQEnd(FCEU_IQEXT); break;
case 0xF000:
IRQMode = V & 4;
IRQa = V & 2;
IRQd = V & 1;
if (V & 2)
@@ -165,13 +167,25 @@ static void VRC7Close(void)
static void VRC7IRQHook(int a) {
if (IRQa) {
CycleCount += a * 3;
while(CycleCount >= 341) {
CycleCount -= 341;
IRQCount++;
if (IRQCount == 0x100) {
IRQCount = IRQLatch;
X6502_IRQBegin(FCEU_IQEXT);
if (IRQMode) {
CycleCount += a;
while (CycleCount > 0) {
CycleCount--;
IRQCount++;
if (IRQCount & 0x100) {
X6502_IRQBegin(FCEU_IQEXT);
IRQCount = IRQLatch;
}
}
} else {
CycleCount += a * 3;
while(CycleCount >= 341) {
CycleCount -= 341;
IRQCount++;
if (IRQCount == 0x100) {
IRQCount = IRQLatch;
X6502_IRQBegin(FCEU_IQEXT);
}
}
}
}
@@ -190,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();
+54 -19
View File
@@ -76,6 +76,8 @@ uint8 geniech[3];
uint32 genieaddr[3];
CartInfo *currCartInfo;
static INLINE void setpageptr(int s, uint32 A, uint8 *p, int ram) {
uint32 AB = A >> 11;
int x;
@@ -130,6 +132,11 @@ void SetupCartCHRMapping(int chip, uint8 *p, uint32 size, int ram) {
CHRmask4[chip] = (size >> 12) - 1;
CHRmask8[chip] = (size >> 13) - 1;
if (CHRmask1[chip] >= (unsigned int)(-1)) CHRmask1[chip] = 0;
if (CHRmask2[chip] >= (unsigned int)(-1)) CHRmask2[chip] = 0;
if (CHRmask4[chip] >= (unsigned int)(-1)) CHRmask4[chip] = 0;
if (CHRmask8[chip] >= (unsigned int)(-1)) CHRmask8[chip] = 0;
CHRram[chip] = ram;
}
@@ -529,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);
}
}
}
}
}
@@ -549,25 +564,45 @@ 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++)
if (LocalHWInfo->SaveGame[x])
fread(LocalHWInfo->SaveGame[x], 1, LocalHWInfo->SaveGameLen[x], sp);
if (sp != NULL)
{
for (size_t x = 0; x < LocalHWInfo->SaveGame.size(); x++)
{
if (LocalHWInfo->SaveGame[x].bufptr)
{
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");
}
}
}
}
}
}
//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();
}
}
}
}
+67 -8
View File
@@ -1,17 +1,46 @@
typedef struct {
#ifndef CART_H
#define CART_H
#include <vector>
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_t> 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;
int submapper; // Submappers as defined by NES 2.0
@@ -23,7 +52,35 @@ 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;
void FCEU_SaveGameSave(CartInfo *LocalHWInfo);
void FCEU_LoadGameSave(CartInfo *LocalHWInfo);
@@ -98,3 +155,5 @@ void FCEU_GeniePower(void);
bool FCEU_OpenGenie(void);
void FCEU_CloseGenie(void);
void FCEU_KillGenie(void);
#endif
+286 -315
View File
@@ -39,8 +39,7 @@ using namespace std;
static uint8 *CheatRPtrs[64];
vector<uint16> FrozenAddresses; //List of addresses that are currently frozen
void UpdateFrozenList(void); //Function that populates the list of frozen addresses
unsigned int FrozenAddressCount=0; //Keeps up with the Frozen address count, necessary for using in other dialogs (such as hex editor)
unsigned int FrozenAddressCount = 0; //Keeps up with the Frozen address count, necessary for using in other dialogs (such as hex editor)
void FCEU_CheatResetRAM(void)
{
@@ -60,27 +59,13 @@ void FCEU_CheatAddRAM(int s, uint32 A, uint8 *p)
}
struct CHEATF {
struct CHEATF *next;
char *name;
uint16 addr;
uint8 val;
int compare; /* -1 for no compare. */
int type; /* 0 for replace, 1 for substitute(GG). */
int status;
};
typedef struct {
uint16 addr;
uint8 val;
int compare;
readfunc PrevRead;
} CHEATF_SUBFAST;
static CHEATF_SUBFAST SubCheats[256];
static int numsubcheats=0;
struct CHEATF *cheats=0,*cheatsl=0;
CHEATF_SUBFAST SubCheats[256];
uint32 numsubcheats = 0;
int globalCheatDisabled = 0;
int disableAutoLSCheats = 0;
bool disableShowGG = 0;
static _8BYTECHEATMAP* cheatMap = NULL;
struct CHEATF *cheats = 0, *cheatsl = 0;
#define CHEATC_NONE 0x8000
@@ -92,7 +77,7 @@ int savecheats = 0;
static DECLFR(SubCheatsRead)
{
CHEATF_SUBFAST *s=SubCheats;
CHEATF_SUBFAST *s = SubCheats;
int x=numsubcheats;
do
@@ -116,79 +101,91 @@ static DECLFR(SubCheatsRead)
void RebuildSubCheats(void)
{
int x;
struct CHEATF *c=cheats;
for(x=0;x<numsubcheats;x++)
SetReadHandler(SubCheats[x].addr,SubCheats[x].addr,SubCheats[x].PrevRead);
numsubcheats=0;
while(c)
uint32 x;
struct CHEATF *c = cheats;
for (x = 0; x < numsubcheats; x++)
{
if(c->type==1 && c->status)
SetReadHandler(SubCheats[x].addr, SubCheats[x].addr, SubCheats[x].PrevRead);
if (cheatMap)
FCEUI_SetCheatMapByte(SubCheats[x].addr, false);
}
numsubcheats = 0;
if (!globalCheatDisabled)
{
while(c)
{
if(GetReadHandler(c->addr)==SubCheatsRead)
if(c->type == 1 && c->status && GetReadHandler(c->addr) != SubCheatsRead)
{
/* Prevent a catastrophe by this check. */
//FCEU_DispMessage("oops",0);
}
else
{
SubCheats[numsubcheats].PrevRead=GetReadHandler(c->addr);
SubCheats[numsubcheats].addr=c->addr;
SubCheats[numsubcheats].val=c->val;
SubCheats[numsubcheats].compare=c->compare;
SetReadHandler(c->addr,c->addr,SubCheatsRead);
SubCheats[numsubcheats].PrevRead = GetReadHandler(c->addr);
SubCheats[numsubcheats].addr = c->addr;
SubCheats[numsubcheats].val = c->val;
SubCheats[numsubcheats].compare = c->compare;
SetReadHandler(c->addr, c->addr, SubCheatsRead);
if (cheatMap)
FCEUI_SetCheatMapByte(SubCheats[numsubcheats].addr, true);
numsubcheats++;
}
c = c->next;
}
c=c->next;
}
FrozenAddressCount = numsubcheats; //Update the frozen address list
UpdateFrozenList();
//FCEUI_DispMessage("Active Cheats: %d",0, FrozenAddresses.size()/*FrozenAddressCount*/); //Debug
}
void FCEU_PowerCheats()
{
numsubcheats=0; /* Quick hack to prevent setting of ancient read addresses. */
numsubcheats = 0; /* Quick hack to prevent setting of ancient read addresses. */
if (cheatMap)
FCEUI_RefreshCheatMap();
RebuildSubCheats();
}
static int AddCheatEntry(char *name, uint32 addr, uint8 val, int compare, int status, int type);
int FCEU_CalcCheatAffectedBytes(uint32 address, uint32 size) {
uint32 count = 0;
if (cheatMap)
for (uint32 i = 0; i < size; ++i)
if (FCEUI_FindCheatMapByte(address + i))
++count;
return count;
}
static void AddCheatEntry(const char *name, uint32 addr, uint8 val, int compare, int status, int type);
static void CheatMemErr(void)
{
FCEUD_PrintError("Error allocating memory for cheat data.");
}
/* This function doesn't allocate any memory for "name" */
static int AddCheatEntry(char *name, uint32 addr, uint8 val, int compare, int status, int type)
static void AddCheatEntry(const char *name, uint32 addr, uint8 val, int compare, int status, int type)
{
struct CHEATF *temp;
if(!(temp=(struct CHEATF *)FCEU_dmalloc(sizeof(struct CHEATF))))
{
CheatMemErr();
return(0);
}
temp->name=name;
temp->addr=addr;
temp->val=val;
temp->status=status;
temp->compare=compare;
temp->type=type;
temp->next=0;
CHEATF *temp = new CHEATF();
temp->name = name;
temp->addr = addr;
temp->val = val;
temp->status = status;
temp->compare = compare;
temp->type = type;
temp->next = nullptr;
if(cheats)
{
cheatsl->next=temp;
cheatsl=temp;
cheatsl->next = temp;
cheatsl = temp;
}
else
cheats=cheatsl=temp;
return(1);
cheats = cheatsl = temp;
}
void FCEU_LoadGameCheats(FILE *override)
/* The "override_existing" parameter is used only in cheat dialog import.
Since the default behaviour will reset numsubcheats to 0 everytime,
In game loading, this is absolutely right, but when importing in cheat window,
resetting numsubcheats to 0 will override existed cheat items to make them
invalid.
*/
void FCEU_LoadGameCheats(FILE *override, int override_existing)
{
FILE *fp;
unsigned int addr;
@@ -198,89 +195,120 @@ void FCEU_LoadGameCheats(FILE *override)
unsigned int compare;
int x;
char linebuf[2048];
char *namebuf;
int tc=0;
char linebuf[2048] = { 0 };
char namebuf[128] = { 0 };
int tc = 0;
char *fn;
numsubcheats=savecheats=0;
if (override_existing)
{
numsubcheats = 0;
if (cheatMap)
FCEUI_RefreshCheatMap();
}
if(override)
fp = override;
else
{
fn=strdup(FCEU_MakeFName(FCEUMKF_CHEAT,0,0).c_str());
fp=FCEUD_UTF8fopen(fn,"rb");
fn = strdup(FCEU_MakeFName(FCEUMKF_CHEAT, 0, 0).c_str());
fp = FCEUD_UTF8fopen(fn, "rb");
free(fn);
if(!fp) return;
if (!fp) {
return;
}
}
FCEU_DispMessage("Cheats file loaded.",0); //Tells user a cheats file was loaded.
while(fgets(linebuf,2048,fp) != nullptr)
while(fgets(linebuf, 2048, fp) != nullptr)
{
char *tbuf=linebuf;
int doc=0;
char *tbuf = linebuf;
int doc = 0;
addr=val=compare=status=type=0;
addr = val = compare = status = type = 0;
if(tbuf[0]=='S')
if(tbuf[0] == 'S')
{
tbuf++;
type=1;
type = 1;
}
else type=0;
else
type = 0;
if(tbuf[0]=='C')
if(tbuf[0] == 'C')
{
tbuf++;
doc=1;
doc = 1;
}
if(tbuf[0]==':')
if(tbuf[0] == ':')
{
tbuf++;
status=0;
status = 0;
}
else status=1;
else status = 1;
if(doc)
{
char *neo=&tbuf[4+2+2+1+1+1];
if(sscanf(tbuf,"%04x%*[:]%02x%*[:]%02x",&addr,&val,&compare)!=3)
char *neo = &tbuf[4+2+2+1+1+1];
if(sscanf(tbuf, "%04x%*[:]%02x%*[:]%02x", &addr, &val, &compare) != 3)
continue;
if (!(namebuf=(char *)FCEU_dmalloc(strlen(neo)+1)))
return;
strcpy(namebuf,neo);
strcpy(namebuf, neo);
}
else
{
char *neo=&tbuf[4+2+1+1];
if(sscanf(tbuf,"%04x%*[:]%02x",&addr,&val)!=2)
char *neo = &tbuf[4+2+1+1];
if(sscanf(tbuf, "%04x%*[:]%02x", &addr, &val) != 2)
continue;
if (!(namebuf=(char *)FCEU_dmalloc(strlen(neo)+1)))
return;
strcpy(namebuf,neo);
strcpy(namebuf, neo);
}
for(x=0;x<(int)strlen(namebuf);x++)
for(x = 0; x < (int)strlen(namebuf); x++)
{
if(namebuf[x]==10 || namebuf[x]==13)
if(namebuf[x] == 10 || namebuf[x] == 13)
{
namebuf[x]=0;
namebuf[x] = 0;
break;
}
else if(namebuf[x] > 0x00 && namebuf[x] < 0x20)
namebuf[x]=0x20;
namebuf[x] = 0x20;
}
AddCheatEntry(namebuf,addr,val,doc?compare:-1,status,type);
AddCheatEntry(namebuf, addr, val, doc ? compare : -1, status, type);
tc++;
}
RebuildSubCheats();
FCEU_DispMessage("Cheats file loaded.", 0); //Tells user a cheats file was loaded.
if(!override)
fclose(fp);
}
void FCEU_SaveGameCheats(FILE* fp, int release)
{
struct CHEATF *next = cheats;
while (next)
{
if (next->type)
fputc('S', fp);
if (next->compare >= 0)
fputc('C', fp);
if (!next->status)
fputc(':', fp);
if (next->compare >= 0)
fprintf(fp, "%04x:%02x:%02x:%s\n", next->addr, next->val, next->compare, next->name.c_str());
else
fprintf(fp, "%04x:%02x:%s\n", next->addr, next->val, next->name.c_str());
struct CHEATF *t = next;
next = next->next;
if (release) delete t;
}
}
void FCEU_FlushGameCheats(FILE *override, int nosave)
{
if(CheatComp)
@@ -297,8 +325,7 @@ void FCEU_FlushGameCheats(FILE *override, int nosave)
{
struct CHEATF *last=next;
next=next->next;
free(last->name);
free(last);
delete last;
if(!next) break;
}
cheats=cheatsl=0;
@@ -313,7 +340,6 @@ void FCEU_FlushGameCheats(FILE *override, int nosave)
if(cheats)
{
struct CHEATF *next=cheats;
FILE *fp;
if(override)
@@ -323,28 +349,7 @@ void FCEU_FlushGameCheats(FILE *override, int nosave)
if(fp)
{
for(;;)
{
struct CHEATF *t;
if(next->type)
fputc('S',fp);
if(next->compare>=0)
fputc('C',fp);
if(!next->status)
fputc(':',fp);
if(next->compare>=0)
fprintf(fp,"%04x:%02x:%02x:%s\n",next->addr,next->val,next->compare,next->name);
else
fprintf(fp,"%04x:%02x:%s\n",next->addr,next->val,next->name);
free(next->name);
t=next;
next=next->next;
free(t);
if(!next) break;
}
FCEU_SaveGameCheats(fp, 1);
if(!override)
fclose(fp);
}
@@ -365,23 +370,11 @@ void FCEU_FlushGameCheats(FILE *override, int nosave)
int FCEUI_AddCheat(const char *name, uint32 addr, uint8 val, int compare, int type)
{
char *t;
if(!(t=(char *)FCEU_dmalloc(strlen(name)+1)))
{
CheatMemErr();
return(0);
}
strcpy(t,name);
if(!AddCheatEntry(t,addr,val,compare,1,type))
{
free(t);
return(0);
}
savecheats=1;
AddCheatEntry(name, addr, val, compare, 1, type);
savecheats = 1;
RebuildSubCheats();
return(1);
return 1;
}
int FCEUI_DelCheat(uint32 which)
@@ -411,8 +404,7 @@ int FCEUI_DelCheat(uint32 which)
else
cheats=cheatsl=0; // No (more) cheats.
}
free(cur->name); // Now that all references to this cheat are removed,
free(cur); // free the memory.
delete cur; // free the memory.
break;
} // *END REMOVE THIS CHEAT*
@@ -447,18 +439,18 @@ void FCEU_ApplyPeriodicCheats(void)
}
void FCEUI_ListCheats(int (*callb)(char *name, uint32 a, uint8 v, int compare, int s, int type, void *data), void *data)
void FCEUI_ListCheats(int (*callb)(const char *name, uint32 a, uint8 v, int compare, int s, int type, void *data), void *data)
{
struct CHEATF *next=cheats;
while(next)
{
if(!callb(next->name,next->addr,next->val,next->compare,next->status,next->type,data)) break;
if(!callb(next->name.c_str(),next->addr,next->val,next->compare,next->status,next->type,data)) break;
next=next->next;
}
}
int FCEUI_GetCheat(uint32 which, char **name, uint32 *a, uint8 *v, int *compare, int *s, int *type)
int FCEUI_GetCheat(uint32 which, std::string *name, uint32 *a, uint8 *v, int *compare, int *s, int *type)
{
struct CHEATF *next=cheats;
uint32 x=0;
@@ -566,7 +558,7 @@ int FCEUI_DecodeGG(const char *str, int *a, int *v, int *c)
int FCEUI_DecodePAR(const char *str, int *a, int *v, int *c, int *type)
{
int boo[4];
unsigned int boo[4];
if(strlen(str)!=8) return(0);
sscanf(str,"%02x%02x%02x%02x",boo,boo+1,boo+2,boo+3);
@@ -596,45 +588,36 @@ int FCEUI_DecodePAR(const char *str, int *a, int *v, int *c, int *type)
/* name can be NULL if the name isn't going to be changed. */
/* same goes for a, v, and s(except the values of each one must be <0) */
int FCEUI_SetCheat(uint32 which, const char *name, int32 a, int32 v, int c, int s, int type)
int FCEUI_SetCheat(uint32 which, const std::string *name, int32 a, int32 v, int c, int s, int type)
{
struct CHEATF *next=cheats;
uint32 x=0;
struct CHEATF *next = cheats;
uint32 x = 0;
while(next)
{
if(x==which)
if(x == which)
{
if(name)
{
char *t;
if((t=(char *)realloc(next->name, strlen(name)+1)))
{
next->name=t;
strcpy(next->name,name);
}
else
return(0);
}
if(a>=0)
next->addr=a;
if(v>=0)
next->val=v;
if(s>=0)
next->status=s;
if(c>=-1)
next->compare=c;
next->type=type;
next->name = *name;
if(a >= 0)
next->addr = a;
if(v >= 0)
next->val = v;
if(s >= 0)
next->status = s;
if(c >= -1)
next->compare = c;
next->type = type;
savecheats=1;
savecheats = 1;
RebuildSubCheats();
return(1);
return 1;
}
next=next->next;
next = next->next;
x++;
}
return(0);
return 0;
}
/* Convenience function. */
@@ -659,6 +642,14 @@ int FCEUI_ToggleCheat(uint32 which)
return(-1);
}
int FCEUI_GlobalToggleCheat(int global_enabled)
{
unsigned int _numsubcheats = numsubcheats;
globalCheatDisabled = !global_enabled;
RebuildSubCheats();
return _numsubcheats != numsubcheats;
}
static int InitCheatComp(void)
{
uint32 x;
@@ -741,7 +732,7 @@ void FCEUI_CheatSearchGet(int (*callb)(uint32 a, uint8 last, uint8 current, void
void FCEUI_CheatSearchGetRange(uint32 first, uint32 last, int (*callb)(uint32 a, uint8 last, uint8 current))
{
uint32 x;
uint32 in=0;
uint32 in = 0;
if(!CheatComp)
{
@@ -750,14 +741,15 @@ void FCEUI_CheatSearchGetRange(uint32 first, uint32 last, int (*callb)(uint32 a,
return;
}
for(x=0;x<0x10000;x++)
if(!(CheatComp[x]&CHEATC_NOSHOW) && CheatRPtrs[x>>10])
for(x = 0; x < 0x10000; x++)
if(!(CheatComp[x] & CHEATC_NOSHOW) && CheatRPtrs[x >> 10])
{
if(in>=first)
if(!callb(x,CheatComp[x],CheatRPtrs[x>>10][x]))
if(in >= first)
if(!callb(x, CheatComp[x], CheatRPtrs[x >> 10][x]))
break;
in++;
if(in>last) return;
if(in > last)
return;
}
}
@@ -803,130 +795,56 @@ void FCEUI_CheatSearchEnd(int type, uint8 v1, uint8 v2)
}
}
if(!type) // Change to a specific value.
switch (type)
{
for(x=0;x<0x10000;x++)
if(!(CheatComp[x]&CHEATC_NOSHOW))
{
if(CheatComp[x]==v1 && CheatRPtrs[x>>10][x]==v2)
{
}
else
CheatComp[x]|=CHEATC_EXCLUDED;
}
default:
case FCEU_SEARCH_SPECIFIC_CHANGE: // Change to a specific value
for (x = 0; x < 0x10000; ++x)
if (!(CheatComp[x] & CHEATC_NOSHOW) && (CheatComp[x] != v1 || CheatRPtrs[x >> 10][x] != v2))
CheatComp[x] |= CHEATC_EXCLUDED;
break;
case FCEU_SEARCH_RELATIVE_CHANGE: // Search for relative change (between values).
for (x = 0; x < 0x10000; x++)
if (!(CheatComp[x] & CHEATC_NOSHOW) && (CheatComp[x] != v1 || CAbs(CheatComp[x] - CheatRPtrs[x >> 10][x]) != v2))
CheatComp[x] |= CHEATC_EXCLUDED;
break;
case FCEU_SEARCH_PUERLY_RELATIVE_CHANGE: // Purely relative change.
for (x = 0x000; x<0x10000; x++)
if (!(CheatComp[x] & CHEATC_NOSHOW) && CAbs(CheatComp[x] - CheatRPtrs[x >> 10][x]) != v2)
CheatComp[x] |= CHEATC_EXCLUDED;
break;
case FCEU_SEARCH_ANY_CHANGE: // Any change.
for (x = 0x000; x < 0x10000; x++)
if (!(CheatComp[x] & CHEATC_NOSHOW) && CheatComp[x] == CheatRPtrs[x >> 10][x])
CheatComp[x] |= CHEATC_EXCLUDED;
break;
case FCEU_SEARCH_NEWVAL_KNOWN: // new value = known
for (x = 0x000; x < 0x10000; x++)
if (!(CheatComp[x] & CHEATC_NOSHOW) && CheatRPtrs[x >> 10][x] != v1)
CheatComp[x] |= CHEATC_EXCLUDED;
break;
case FCEU_SEARCH_NEWVAL_GT: // new value greater than
for (x = 0x000; x < 0x10000; x++)
if (!(CheatComp[x] & CHEATC_NOSHOW) && CheatComp[x] >= CheatRPtrs[x >> 10][x])
CheatComp[x] |= CHEATC_EXCLUDED;
break;
case FCEU_SEARCH_NEWVAL_LT: // new value less than
for (x = 0x000; x < 0x10000; x++)
if (!(CheatComp[x] & CHEATC_NOSHOW) && CheatComp[x] <= CheatRPtrs[x >> 10][x])
CheatComp[x] |= CHEATC_EXCLUDED;
break;
case FCEU_SEARCH_NEWVAL_GT_KNOWN: // new value greater than by known value
for (x = 0x000; x < 0x10000; x++)
if (!(CheatComp[x] & CHEATC_NOSHOW) && CheatRPtrs[x >> 10][x] - CheatComp[x] != v2)
CheatComp[x] |= CHEATC_EXCLUDED;
break;
case FCEU_SEARCH_NEWVAL_LT_KNOWN: // new value less than by known value
for (x = 0x000; x < 0x10000; x++)
if (!(CheatComp[x] & CHEATC_NOSHOW) && (CheatComp[x] - CheatRPtrs[x >> 10][x]) != v2)
CheatComp[x] |= CHEATC_EXCLUDED;
break;
}
else if(type==1) // Search for relative change(between values).
{
for(x=0;x<0x10000;x++)
if(!(CheatComp[x]&CHEATC_NOSHOW))
{
if(CheatComp[x]==v1 && CAbs(CheatComp[x]-CheatRPtrs[x>>10][x])==v2)
{
}
else
CheatComp[x]|=CHEATC_EXCLUDED;
}
}
else if(type==2) // Purely relative change.
{
for(x=0x000;x<0x10000;x++)
if(!(CheatComp[x]&CHEATC_NOSHOW))
{
if(CAbs(CheatComp[x]-CheatRPtrs[x>>10][x])==v2)
{
}
else
CheatComp[x]|=CHEATC_EXCLUDED;
}
}
else if(type==3) // Any change.
{
for(x=0x000;x<0x10000;x++)
if(!(CheatComp[x]&CHEATC_NOSHOW))
{
if(CheatComp[x]!=CheatRPtrs[x>>10][x])
{
}
else
CheatComp[x]|=CHEATC_EXCLUDED;
}
}
else if(type==4) // new value = known
{
for(x=0x000;x<0x10000;x++)
if(!(CheatComp[x]&CHEATC_NOSHOW))
{
if(CheatRPtrs[x>>10][x]==v1)
{
}
else
CheatComp[x]|=CHEATC_EXCLUDED;
}
}
else if(type==5) // new value greater than
{
for(x=0x000;x<0x10000;x++)
if(!(CheatComp[x]&CHEATC_NOSHOW))
{
if(CheatComp[x]<CheatRPtrs[x>>10][x])
{
}
else
CheatComp[x]|=CHEATC_EXCLUDED;
}
}
else if(type==6) // new value less than
{
for(x=0x000;x<0x10000;x++)
if(!(CheatComp[x]&CHEATC_NOSHOW))
{
if(CheatComp[x]>CheatRPtrs[x>>10][x])
{
}
else
CheatComp[x]|=CHEATC_EXCLUDED;
}
}
else if(type==7) // new value greater than by known value
{
for(x=0x000;x<0x10000;x++)
if(!(CheatComp[x]&CHEATC_NOSHOW))
{
if((CheatRPtrs[x>>10][x]-CheatComp[x])==v2)
{
}
else
CheatComp[x]|=CHEATC_EXCLUDED;
}
}
else if(type==8) // new value less than by known value
{
for(x=0x000;x<0x10000;x++)
if(!(CheatComp[x]&CHEATC_NOSHOW))
{
if((CheatComp[x]-CheatRPtrs[x>>10][x])==v2)
{
}
else
CheatComp[x]|=CHEATC_EXCLUDED;
}
}
}
int FCEU_CheatGetByte(uint32 A)
@@ -949,18 +867,71 @@ void FCEU_CheatSetByte(uint32 A, uint8 V)
BWrite[A](A, V);
}
void UpdateFrozenList(void)
// disable all cheats
int FCEU_DisableAllCheats(void)
{
//The purpose of this function is to keep an up to date list of addresses that are currently frozen
//and make these accessible to other dialogs that deal with memory addresses such as
//memwatch, hex editor, ramfilter, etc.
int x;
FrozenAddresses.clear(); //Clear vector and repopulate
for(x=0;x<numsubcheats;x++)
int count = 0;
struct CHEATF *next = cheats;
while(next)
{
FrozenAddresses.push_back(SubCheats[x].addr);
//FCEU_printf("Address %d: %d \n",x,FrozenAddresses[x]); //Debug
if(next->status){
count++;
}
next->status = 0;
next = next->next;
}
savecheats = 1;
RebuildSubCheats();
return count;
}
// delete all cheats
int FCEU_DeleteAllCheats(void)
{
struct CHEATF *cur = cheats;
struct CHEATF *next = NULL;
while (cur)
{
next = cur->next;
delete cur;
cur = next;
}
cheats = cheatsl = 0;
savecheats = 1;
RebuildSubCheats();
return 0;
}
int FCEUI_FindCheatMapByte(uint16 address)
{
return cheatMap[address / 8] >> (address % 8) & 1;
}
void FCEUI_SetCheatMapByte(uint16 address, bool cheat)
{
cheat ? cheatMap[address / 8] |= (1 << address % 8) : cheatMap[address / 8] ^= (1 << address % 8);
}
void FCEUI_CreateCheatMap(void)
{
if (!cheatMap)
cheatMap = (unsigned char*)malloc(CHEATMAP_SIZE);
FCEUI_RefreshCheatMap();
}
void FCEUI_RefreshCheatMap(void)
{
memset(cheatMap, 0, CHEATMAP_SIZE);
for (uint32 i = 0; i < numsubcheats; ++i)
FCEUI_SetCheatMapByte(SubCheats[i].addr, true);
}
void FCEUI_ReleaseCheatMap(void)
{
if (cheatMap)
{
free(cheatMap);
cheatMap = NULL;
}
//FCEUI_DispMessage("FrozenCount: %d",0,FrozenAddressCount);//Debug
}
+66 -2
View File
@@ -1,12 +1,76 @@
#ifndef CHEAT_H
#define CHEAT_H
void FCEU_CheatResetRAM(void);
void FCEU_CheatAddRAM(int s, uint32 A, uint8 *p);
void FCEU_LoadGameCheats(FILE *override);
void FCEU_LoadGameCheats(FILE *override, int override_existing = 1);
void FCEU_FlushGameCheats(FILE *override, int nosave);
void FCEU_SaveGameCheats(FILE *fp, int release = 0);
int FCEUI_GlobalToggleCheat(int global_enabled);
void FCEU_ApplyPeriodicCheats(void);
void FCEU_PowerCheats(void);
int FCEU_CalcCheatAffectedBytes(uint32 address, uint32 size);
// Trying to find a more efficient way for determining if an address has a cheat
// each bit of 1 byte represents to 8 bytes in NES
typedef unsigned char _8BYTECHEATMAP;
#define CHEATMAP_SIZE 0x10000 / 8
extern int FCEUI_FindCheatMapByte(uint16 address);
extern void FCEUI_SetCheatMapByte(uint16 address, bool cheat);
extern void FCEUI_CreateCheatMap(void);
extern void FCEUI_RefreshCheatMap(void);
extern void FCEUI_ReleaseCheatMap(void);
extern unsigned int FrozenAddressCount;
int FCEU_CheatGetByte(uint32 A);
void FCEU_CheatSetByte(uint32 A, uint8 V);
extern int savecheats;
extern int savecheats;
extern int globalCheatDisabled;
extern int disableAutoLSCheats;
int FCEU_DisableAllCheats(void);
int FCEU_DeleteAllCheats(void);
struct CHEATF_SUBFAST
{
uint16 addr;
uint8 val;
int compare;
readfunc PrevRead;
CHEATF_SUBFAST(void)
{
addr = 0; val = 0; compare = 0; PrevRead = nullptr;
}
};
struct CHEATF {
struct CHEATF *next;
std::string name;
uint16 addr;
uint8 val;
int compare; /* -1 for no compare. */
int type; /* 0 for replace, 1 for substitute(GG). */
int status;
};
struct SEARCHPOSSIBLE {
uint16 addr;
uint8 previous;
uint8 current;
bool update;
};
#define FCEU_SEARCH_SPECIFIC_CHANGE 0
#define FCEU_SEARCH_RELATIVE_CHANGE 1
#define FCEU_SEARCH_PUERLY_RELATIVE_CHANGE 2
#define FCEU_SEARCH_ANY_CHANGE 3
#define FCEU_SEARCH_NEWVAL_KNOWN 4
#define FCEU_SEARCH_NEWVAL_GT 5
#define FCEU_SEARCH_NEWVAL_LT 6
#define FCEU_SEARCH_NEWVAL_GT_KNOWN 7
#define FCEU_SEARCH_NEWVAL_LT_KNOWN 8
#endif
+114 -61
View File
@@ -34,10 +34,11 @@
* Primitive -> Number | Address | Register | Flag | PC Bank | '(' Connect ')'
* Number -> '#' [1-9A-F]*
* Address -> '$' [1-9A-F]* | '$' '[' Connect ']'
* Register -> 'A' | 'X' | 'Y' | 'P'
* Flag -> 'N' | 'C' | 'Z' | 'I' | 'B' | 'V'
* Register -> 'A' | 'X' | 'Y' | 'P' | 'S'
* Flag -> 'N' | 'C' | 'Z' | 'I' | 'B' | 'V' | 'U' | 'D'
* PC Bank -> 'K'
* Data Bank -> 'T'
* Data Bank -> 'T'
* Value -> 'R' | 'W'
*/
#include "types.h"
@@ -50,17 +51,18 @@
#include <cassert>
#include <cctype>
// hack: this address is used by 'T' condition
uint16 addressOfTheLastAccessedData = 0;
// Next non-whitespace character in string
char next;
uint16 debugLastAddress = 0; // used by 'T' and 'R' conditions
uint8 debugLastOpcode = 0; // used to evaluate 'W' condition
int ishex(char c)
// Next non-whitespace character in string
static char next = 0;
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
{
@@ -69,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;
@@ -115,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)
{
@@ -129,31 +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';
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
static int isValueRead(char c)
{
return c == 'R';
}
// Determines if a character is for value write
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];
@@ -171,19 +182,19 @@ 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)
{
scan(str);
c->lhs = Connect(str);
if (!c) return 0;
c->lhs = Connect(str);
if (next == closePar)
{
scan(str);
@@ -202,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 */
{
@@ -272,6 +283,40 @@ Condition* Primitive(const char** str, Condition* c)
return c;
}
else if (isValueRead(next))
{
if (c->type1 == TYPE_NO)
{
c->type1 = TYPE_VALUE_READ;
c->value1 = next;
}
else
{
c->type2 = TYPE_VALUE_READ;
c->value2 = next;
}
scan(str);
return c;
}
else if (isValueWrite(next))
{
if (c->type1 == TYPE_NO)
{
c->type1 = TYPE_VALUE_WRITE;
c->value1 = next;
}
else
{
c->type2 = TYPE_VALUE_WRITE;
c->value2 = next;
}
scan(str);
return c;
}
else if (next == '#') /* Numbers */
{
unsigned int number = 0;
@@ -346,21 +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));
if (!t)
return NULL;
t = new Condition();
memset(t, 0, sizeof(Condition));
if (t == nullptr)
{
return NULL;
}
if (!Primitive(str, t))
{
freeTree(t);
delete t;
return 0;
}
@@ -370,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;
@@ -398,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)
{
@@ -409,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;
@@ -439,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;
@@ -457,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);
}
@@ -470,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;
}
+25 -2
View File
@@ -28,6 +28,8 @@
#define TYPE_ADDR 4
#define TYPE_PC_BANK 5
#define TYPE_DATA_BANK 6
#define TYPE_VALUE_READ 7
#define TYPE_VALUE_WRITE 8
#define OP_NO 0
#define OP_EQ 1
@@ -43,7 +45,9 @@
#define OP_OR 11
#define OP_AND 12
extern uint16 addressOfTheLastAccessedData;
extern uint16 debugLastAddress;
extern uint8 debugLastOpcode;
//mbg merge 7/18/06 turned into sane c++
struct Condition
{
@@ -57,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
+26 -12
View File
@@ -11,20 +11,27 @@
#include <cstdio>
#include <cstdlib>
static char *aboutString = 0;
static std::string aboutString;
#ifndef FCEUX_BUILD_TIMESTAMP
#define FCEUX_BUILD_TIMESTAMP __TIME__ " " __DATE__
#endif
//#pragma message( "Compiling using C++ Std: " __FCEU_STRINGIZE(__cplusplus) )
// returns a string suitable for use in an aboutbox
char *FCEUI_GetAboutString() {
const char *FCEUI_GetAboutString(void)
{
const char *aboutTemplate =
FCEU_NAME_AND_VERSION "\n\n"
"Administrators:\n"
"zeromus, punkrockguy318 (Lukas Sabota), feos\n"
"zeromus, feos\n"
"\n"
"Current Contributors:\n"
"CaH4e3, rainwarrior\n"
"CaH4e3, rainwarrior, owomomo, punkrockguy318, Cluster\n"
"\n"
"Past Contributors:\n"
"xhainingx, gocha, AnS\n"
"xhainingx, gocha, AnS, mjbudd77\n"
"\n"
"FCEUX 2.0:\n"
"mz, nitsujrehtona, SP, Ugly Joe,\n"
@@ -40,20 +47,27 @@ char *FCEUI_GetAboutString() {
"FCEU TAS - blip & nitsuja\n"
"FCEU TAS+ - Luke Gustafson\n"
"\n"
"Logo/icon:\n"
"Terwilf\n"
"\n"
"FCEUX is dedicated to the fallen heroes\n"
"of NES emulation. In Memoriam --\n"
"ugetab\n"
"\n"
__TIME__ " " __DATE__ "\n";
"\n"
FCEUX_BUILD_TIMESTAMP "\n";
if(aboutString) return aboutString;
if (aboutString.size() > 0) return aboutString.c_str();
const char *compilerString = FCEUD_GetCompilerString();
//allocate the string and concatenate the template with the compiler string
if (!(aboutString = (char*)FCEU_dmalloc(strlen(aboutTemplate) + strlen(compilerString) + 1)))
return NULL;
char cppVersion[128];
sprintf(aboutString,"%s%s",aboutTemplate,compilerString);
return aboutString;
snprintf( cppVersion, sizeof(cppVersion), "\nCompiled using C++ Language Standard: %li\n", __cplusplus);
aboutString.assign( aboutTemplate );
aboutString.append( compilerString );
aboutString.append( cppVersion );
return aboutString.c_str();
}
View File
+286 -117
View File
@@ -6,6 +6,7 @@
#include "cart.h"
#include "ines.h"
#include "debug.h"
#include "debugsymboltable.h"
#include "driver.h"
#include "ppu.h"
@@ -18,45 +19,88 @@ 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 (sscanf(offsetBuffer,"%4X",&offset) == EOF)
if (conversionOk)
{
*conversionOk = false;
}
if (sscanf(offsetBuffer,"%7X",(unsigned int *)&offset) == EOF)
{
return -1;
}
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
{
if (GameInfo->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));
auto sym = debugSymbolTable.getSymbolAtAnyBank(offsetBuffer);
if (sym)
{
if (conversionOk)
{
*conversionOk = true;
}
return sym->offset() & 0xFFFF;
}
else if (GameInfo->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));
int type = GIT_CART;
if (GameInfo)
{
type = GameInfo->type;
}
if (type == GIT_NSF) { //NSF Breakpoint keywords
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) 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);
}
}
return offset;
return offset & 0xFFFF;
}
// Returns the value of a given type or register
@@ -77,6 +121,7 @@ int getValue(int type)
case 'Z': return _P & Z_FLAG ? 1 : 0;
case 'C': return _P & C_FLAG ? 1 : 0;
case 'P': return _PC;
case 'S': return _S;
}
return 0;
@@ -120,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;
@@ -134,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
@@ -150,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;
@@ -193,6 +238,9 @@ unsigned int NewBreak(const char* name, int start, int end, unsigned int type, c
watchpoint[num].flags|=BT_S;
watchpoint[num].flags&=~WP_X; //disable execute flag!
}
if (type & BT_R) {
watchpoint[num].flags|=BT_R;
}
if (watchpoint[num].desc)
free(watchpoint[num].desc);
@@ -207,11 +255,27 @@ int GetPRGAddress(int A){
int result;
if(A > 0xFFFF)
return -1;
result = &Page[A>>11][A]-PRGptr[0];
if((result > (int)PRGsize[0]) || (result < 0))
return -1;
else
return result;
if (GameInfo->type == GIT_FDS) {
if (A < 0xE000) {
result = &Page[A >> 11][A] - PRGptr[1];
if ((result > (int)PRGsize[1]) || (result < 0))
return -1;
else
return result;
} else {
result = &Page[A >> 11][A] - PRGptr[0];
if ((result > (int)PRGsize[0]) || (result < 0))
return -1;
else
return result + PRGsize[1];
}
} else {
result = &Page[A >> 11][A] - PRGptr[0];
if ((result > (int)PRGsize[0]) || (result < 0))
return -1;
else
return result;
}
}
/**
@@ -228,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;
@@ -240,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;
}
@@ -309,6 +373,32 @@ uint8 GetPPUMem(uint8 A) {
//---------------------
uint8 evaluateWrite(uint8 opcode, uint16 address)
{
// predicts value written by this opcode
switch (opwrite[opcode])
{
default:
case 0: return 0; // no write
case 1: return _A; // STA, PHA
case 2: return _X; // STX
case 3: return _Y; // STY
case 4: return _P; // PHP
case 5: return GetMem(address) << 1; // ASL (SLO)
case 6: return GetMem(address) >> 1; // LSR (SRE)
case 7: return (GetMem(address) << 1) | (_P & 1); // ROL (RLA)
case 8: return (GetMem(address) >> 1) | ((_P & 1) << 7); // ROL (RRA)
case 9: return GetMem(address) + 1; // INC (ISC)
case 10: return GetMem(address) - 1; // DEC (DCP)
case 11: return _A & _X; // (SAX)
case 12: return _A&_X&(((address-_Y)>>8)+1); // (AHX)
case 13: return _Y&(((address-_X)>>8)+1); // (SHY)
case 14: return _X&(((address-_Y)>>8)+1); // (SHX)
case 15: return _S& (((address-_Y)>>8)+1); // (TAS)
}
return 0;
}
// Evaluates a condition
int evaluate(Condition* c)
{
@@ -334,7 +424,9 @@ int evaluate(Condition* c)
{
case TYPE_ADDR: value1 = GetMem(value1); break;
case TYPE_PC_BANK: value1 = getBank(_PC); break;
case TYPE_DATA_BANK: value1 = getBank(addressOfTheLastAccessedData); break;
case TYPE_DATA_BANK: value1 = getBank(debugLastAddress); break;
case TYPE_VALUE_READ: value1 = GetMem(debugLastAddress); break;
case TYPE_VALUE_WRITE: value1 = evaluateWrite(debugLastOpcode, debugLastAddress); break;
}
f = value1;
@@ -359,7 +451,9 @@ int evaluate(Condition* c)
{
case TYPE_ADDR: value2 = GetMem(value2); break;
case TYPE_PC_BANK: value2 = getBank(_PC); break;
case TYPE_DATA_BANK: value2 = getBank(addressOfTheLastAccessedData); break;
case TYPE_DATA_BANK: value2 = getBank(debugLastAddress); break;
case TYPE_VALUE_READ: value2 = GetMem(debugLastAddress); break;
case TYPE_VALUE_WRITE: value2 = evaluateWrite(debugLastOpcode, debugLastAddress); break;
}
switch (c->op)
@@ -371,7 +465,7 @@ int evaluate(Condition* c)
case OP_G: f = value1 > value2; break;
case OP_L: f = value1 < value2; break;
case OP_MULT: f = value1 * value2; break;
case OP_DIV: f = value1 / value2; break;
case OP_DIV: f = (value2==0) ? 0 : (value1 / value2); break;
case OP_PLUS: f = value1 + value2; break;
case OP_MINUS: f = value1 - value2; break;
case OP_OR: f = value1 || value2; break;
@@ -390,12 +484,12 @@ int condition(watchpointinfo* wp)
//---------------------
volatile int codecount, datacount, undefinedcount;
unsigned char *cdloggerdata;
volatile int codecount = 0, datacount = 0, undefinedcount = 0;
unsigned char *cdloggerdata = NULL;
unsigned int cdloggerdataSize = 0;
static int indirectnext;
static int indirectnext = 0;
int debug_loggingCD;
int debug_loggingCD = 0;
//called by the cpu to perform logging if CDLogging is enabled
void LogCDVectors(int which){
@@ -417,20 +511,29 @@ void LogCDVectors(int which){
}
}
void LogCDData(uint8 *opcode, uint16 A, int size) {
bool break_on_unlogged_code = false;
bool break_on_unlogged_data = false;
void LogCDData(uint8 *opcode, uint16 A, int size)
{
int i, j;
uint8 memop = 0;
bool newCodeHit = false, newDataHit = false;
if((j = GetPRGAddress(_PC)) != -1)
for (i = 0; i < size; i++) {
if(cdloggerdata[j+i] & 1)continue; //this has been logged so skip
if ((j = GetPRGAddress(_PC)) != -1)
{
for (i = 0; i < size; i++)
{
if (cdloggerdata[j+i] & 1) continue; //this has been logged so skip
cdloggerdata[j+i] |= 1;
cdloggerdata[j+i] |= ((_PC + i) >> 11) & 0x0c;
cdloggerdata[j+i] |= ((_PC & 0x8000) >> 8) ^ 0x80; // 19/07/14 used last reserved bit, if bit 7 is 1, then code is running from lowe area (6000)
if(indirectnext)cdloggerdata[j+i] |= 0x10;
if (indirectnext)cdloggerdata[j+i] |= 0x10;
codecount++;
if(!(cdloggerdata[j+i] & 2))undefinedcount--;
if (!(cdloggerdata[j+i] & 2))undefinedcount--;
newCodeHit = true;
}
}
//log instruction jumped to in an indirect jump
if(opcode[0] == 0x6c)
@@ -443,14 +546,43 @@ void LogCDData(uint8 *opcode, uint16 A, int size) {
case 4: memop = 0x20; break;
}
if((j = GetPRGAddress(A)) != -1) {
if(!(cdloggerdata[j] & 2)) {
cdloggerdata[j] |= 2;
cdloggerdata[j] |=(A>>11)&0x0c;
cdloggerdata[j] |= memop;
datacount++;
if(!(cdloggerdata[j] & 1))undefinedcount--;
if ((j = GetPRGAddress(A)) != -1)
{
if (opwrite[opcode[0]] == 0)
{
if (!(cdloggerdata[j] & 2))
{
cdloggerdata[j] |= 2;
cdloggerdata[j] |= (A >> 11) & 0x0c;
cdloggerdata[j] |= memop;
cdloggerdata[j] |= ((A & 0x8000) >> 8) ^ 0x80;
datacount++;
if (!(cdloggerdata[j] & 1))undefinedcount--;
newDataHit = true;
}
}
else
{
if (cdloggerdata[j] & 1)
{
codecount--;
}
if (cdloggerdata[j] & 2)
{
datacount--;
}
if ((cdloggerdata[j] & 3) != 0) undefinedcount++;
cdloggerdata[j] = 0;
}
}
if ( break_on_unlogged_code && newCodeHit )
{
BreakHit( BREAK_TYPE_UNLOGGED_CODE );
}
else if ( break_on_unlogged_data && newDataHit )
{
BreakHit( BREAK_TYPE_UNLOGGED_DATA );
}
}
@@ -502,61 +634,71 @@ void IncrementInstructionsCounters()
delta_instructions++;
}
void BreakHit(int bp_num, bool force)
{
if(!force)
bool CondForbidTest(int bp_num) {
if (bp_num >= 0 && !condition(&watchpoint[bp_num]))
{
//check to see whether we fall in any forbid zone
for (int i = 0; i < numWPs; i++)
{
watchpointinfo& wp = watchpoint[i];
if(!(wp.flags & WP_F) || !(wp.flags & WP_E))
continue;
return false; // condition rejected
}
if (condition(&wp))
{
if (wp.endaddress) {
if( (wp.address <= _PC) && (wp.endaddress >= _PC) )
return; //forbid
} else {
if(wp.address == _PC)
return; //forbid
}
//check to see whether we fall in any forbid zone
for (int i = 0; i < numWPs; i++)
{
watchpointinfo& wp = watchpoint[i];
if (!(wp.flags & WP_F) || !(wp.flags & WP_E))
continue;
if (condition(&wp))
{
if (wp.endaddress) {
if ((wp.address <= _PC) && (wp.endaddress >= _PC))
return false; // forbid
}
else {
if (wp.address == _PC)
return false; // forbid
}
}
}
FCEUI_SetEmulationPaused(EMULATIONPAUSED_PAUSED); //mbg merge 7/19/06 changed to use EmulationPaused()
#ifdef WIN32
FCEUD_DebugBreakpoint(bp_num);
#endif
return true;
}
uint8 StackAddrBackup = X.S;
void BreakHit(int bp_num)
{
FCEUI_SetEmulationPaused(EMULATIONPAUSED_PAUSED); //mbg merge 7/19/06 changed to use EmulationPaused()
//#ifdef WIN32
FCEUD_DebugBreakpoint(bp_num);
//#endif
}
int StackAddrBackup;
uint16 StackNextIgnorePC = 0xFFFF;
///fires a breakpoint
static void breakpoint(uint8 *opcode, uint16 A, int size) {
int i, j;
int i, romAddrPC;
unsigned int j;
uint8 brk_type;
uint8 stackop=0;
uint8 stackopstartaddr,stackopendaddr;
uint8 stackopstartaddr=0,stackopendaddr=0;
debugLastAddress = A;
debugLastOpcode = opcode[0];
if (break_asap)
{
break_asap = false;
BreakHit(BREAK_TYPE_LUA, true);
BreakHit(BREAK_TYPE_LUA);
}
if (break_on_cycles && ((timestampbase + (uint64)timestamp - total_cycles_base) > break_cycles_limit))
BreakHit(BREAK_TYPE_CYCLES_EXCEED, true);
BreakHit(BREAK_TYPE_CYCLES_EXCEED);
if (break_on_instructions && (total_instructions > break_instructions_limit))
BreakHit(BREAK_TYPE_INSTRUCTIONS_EXCEED, true);
BreakHit(BREAK_TYPE_INSTRUCTIONS_EXCEED);
//if the current instruction is bad, and we are breaking on bad opcodes, then hit the breakpoint
if(dbgstate.badopbreak && (size == 0))
BreakHit(BREAK_TYPE_BADOP, true);
BreakHit(BREAK_TYPE_BADOP);
//if we're stepping out, track the nest level
if (dbgstate.stepout) {
@@ -575,7 +717,7 @@ static void breakpoint(uint8 *opcode, uint16 A, int size) {
//if we're stepping, then we'll always want to break
if (dbgstate.step) {
dbgstate.step = false;
BreakHit(BREAK_TYPE_STEP, true);
BreakHit(BREAK_TYPE_STEP);
return;
}
@@ -587,7 +729,7 @@ static void breakpoint(uint8 *opcode, uint16 A, int size) {
if (diff<=0)
{
dbgstate.runline=false;
BreakHit(BREAK_TYPE_STEP, true);
BreakHit(BREAK_TYPE_STEP);
return;
}
}
@@ -596,33 +738,36 @@ static void breakpoint(uint8 *opcode, uint16 A, int size) {
if ((watchpoint[64].address == _PC) && (watchpoint[64].flags)) {
watchpoint[64].address = 0;
watchpoint[64].flags = 0;
BreakHit(BREAK_TYPE_STEP, true);
BreakHit(BREAK_TYPE_STEP);
return;
}
romAddrPC = GetNesFileAddress(_PC);
brk_type = opbrktype[opcode[0]] | WP_X;
switch (opcode[0]) {
//Push Ops
case 0x08: //Fall to next
case 0x48: stackopstartaddr=stackopendaddr=X.S-1; stackop=WP_W; StackAddrBackup = X.S; StackNextIgnorePC=_PC+1; break;
case 0x48: debugLastAddress=stackopstartaddr=stackopendaddr=X.S-1; stackop=WP_W; StackAddrBackup = X.S; StackNextIgnorePC=_PC+1; break;
//Pull Ops
case 0x28: //Fall to next
case 0x68: stackopstartaddr=stackopendaddr=X.S+1; stackop=WP_R; StackAddrBackup = X.S; StackNextIgnorePC=_PC+1; break;
case 0x68: debugLastAddress=stackopstartaddr=stackopendaddr=X.S+1; stackop=WP_R; StackAddrBackup = X.S; StackNextIgnorePC=_PC+1; break;
//JSR (Includes return address - 1)
case 0x20: stackopstartaddr=stackopendaddr=X.S-1; stackop=WP_W; StackAddrBackup = X.S; StackNextIgnorePC=(opcode[1]|opcode[2]<<8); break;
//RTI (Includes processor status, and exact return address)
case 0x40: stackopstartaddr=X.S+1; stackopendaddr=X.S+3; stackop=WP_R; StackAddrBackup = X.S; StackNextIgnorePC=(GetMem(X.S+2|0x0100)|GetMem(X.S+3|0x0100)<<8); break;
//RTS (Includes return address - 1)
case 0x60: stackopstartaddr=X.S+1; stackopendaddr=X.S+2; stackop=WP_R; StackAddrBackup = X.S; StackNextIgnorePC=(GetMem(stackopstartaddr|0x0100)|GetMem(stackopendaddr|0x0100)<<8)+1; break;
default: break;
}
#define BREAKHIT(x) { if (CondForbidTest(x)) { breakHit = (x); goto STOPCHECKING; } }
int breakHit = -1;
for (i = 0; i < numWPs; i++)
{
// ################################## Start of SP CODE ###########################
if ((watchpoint[i].flags & WP_E) && condition(&watchpoint[i]))
if ((watchpoint[i].flags & WP_E))
{
// ################################## End of SP CODE ###########################
if (watchpoint[i].flags & BT_P)
{
// PPU Mem breaks
@@ -632,11 +777,11 @@ static void breakpoint(uint8 *opcode, uint16 A, int size) {
if (watchpoint[i].endaddress)
{
if ((watchpoint[i].address <= PPUAddr) && (watchpoint[i].endaddress >= PPUAddr))
BreakHit(i);
BREAKHIT(i);
} else
{
if (watchpoint[i].address == PPUAddr)
BreakHit(i);
BREAKHIT(i);
}
}
} else if (watchpoint[i].flags & BT_S)
@@ -647,16 +792,16 @@ static void breakpoint(uint8 *opcode, uint16 A, int size) {
if (watchpoint[i].endaddress)
{
if ((watchpoint[i].address <= PPU[3]) && (watchpoint[i].endaddress >= PPU[3]))
BreakHit(i);
BREAKHIT(i);
} else
{
if (watchpoint[i].address == PPU[3])
BreakHit(i);
BREAKHIT(i);
}
} else if ((watchpoint[i].flags & WP_W) && (A == 0x4014))
{
// Sprite DMA! :P
BreakHit(i);
BREAKHIT(i);
}
} else
{
@@ -667,12 +812,32 @@ static void breakpoint(uint8 *opcode, uint16 A, int size) {
{
if (((watchpoint[i].flags & (WP_R | WP_W)) && (watchpoint[i].address <= A) && (watchpoint[i].endaddress >= A)) ||
((watchpoint[i].flags & WP_X) && (watchpoint[i].address <= _PC) && (watchpoint[i].endaddress >= _PC)))
BreakHit(i);
} else
BREAKHIT(i);
}
else
{
if (((watchpoint[i].flags & (WP_R | WP_W)) && (watchpoint[i].address == A)) ||
((watchpoint[i].flags & WP_X) && (watchpoint[i].address == _PC)))
BreakHit(i);
if (watchpoint[i].flags & BT_R)
{
if ( (watchpoint[i].flags & WP_X) && (watchpoint[i].address == static_cast<unsigned int>(romAddrPC)) )
{
BREAKHIT(i);
}
//else if ( (watchpoint[i].flags & WP_R) && (watchpoint[i].address == A) )
//{
// BREAKHIT(i);
//}
}
else
{
if ( (watchpoint[i].flags & (WP_R | WP_W)) && (watchpoint[i].address == A))
{
BREAKHIT(i);
}
else if ( (watchpoint[i].flags & WP_X) && (watchpoint[i].address == _PC) )
{
BREAKHIT(i);
}
}
}
} else
{
@@ -684,16 +849,16 @@ static void breakpoint(uint8 *opcode, uint16 A, int size) {
// TXS and TSX only deal with the pointer.
if (watchpoint[i].flags & stackop)
{
for (j = (stackopstartaddr|0x0100); j <= (stackopendaddr|0x0100); j++)
for (j = (stackopstartaddr|0x0100); j <= (static_cast<unsigned int>(stackopendaddr)|0x0100); j++)
{
if (watchpoint[i].endaddress)
{
if ((watchpoint[i].address <= j) && (watchpoint[i].endaddress >= j))
BreakHit(i);
BREAKHIT(i);
} else
{
if (watchpoint[i].address == j)
BreakHit(i);
BREAKHIT(i);
}
}
}
@@ -704,40 +869,40 @@ static void breakpoint(uint8 *opcode, uint16 A, int size) {
StackNextIgnorePC = 0xFFFF;
} else
{
if ((X.S < StackAddrBackup) && (stackop==0))
if (StackAddrBackup != -1 && (X.S < StackAddrBackup) && (stackop==0))
{
// Unannounced stack mem breaks
// Pushes to stack
if (watchpoint[i].flags & WP_W)
{
for (j = (X.S|0x0100); j < (StackAddrBackup|0x0100); j++)
for (j = (X.S|0x0100); j < (static_cast<unsigned int>(StackAddrBackup)|0x0100); j++)
{
if (watchpoint[i].endaddress)
{
if ((watchpoint[i].address <= j) && (watchpoint[i].endaddress >= j))
BreakHit(i);
BREAKHIT(i);
} else
{
if (watchpoint[i].address == j)
BreakHit(i);
BREAKHIT(i);
}
}
}
} else if ((StackAddrBackup < X.S) && (stackop==0))
} else if (StackAddrBackup != -1 && (StackAddrBackup < X.S) && (stackop==0))
{
// Pulls from stack
if (watchpoint[i].flags & WP_R)
{
for (j = (StackAddrBackup|0x0100); j < (X.S|0x0100); j++)
for (j = (StackAddrBackup|0x0100); j < (static_cast<unsigned int>(X.S)|0x0100); j++)
{
if (watchpoint[i].endaddress)
{
if ((watchpoint[i].address <= j) && (watchpoint[i].endaddress >= j))
BreakHit(i);
BREAKHIT(i);
} else
{
if (watchpoint[i].address == j)
BreakHit(i);
BREAKHIT(i);
}
}
}
@@ -746,13 +911,20 @@ static void breakpoint(uint8 *opcode, uint16 A, int size) {
}
}
// ################################## Start of SP CODE ###########################
}
// ################################## End of SP CODE ###########################
}
} //loop across all breakpoints
STOPCHECKING:
//Update the stack address with the current one, now that changes have registered.
//ZEROMUS THINKS IT MAKES MORE SENSE HERE
StackAddrBackup = X.S;
if(breakHit != -1)
BreakHit(i);
////Update the stack address with the current one, now that changes have registered.
//StackAddrBackup = X.S;
}
//bbit edited: this is the end of the inserted code
@@ -781,9 +953,12 @@ void DebugCycle()
size = opsize[opcode[0]];
switch (size)
{
default:
case 1: break;
case 2:
opcode[1] = GetMem(_PC + 1);
break;
case 0: // illegal instructions may have operands
case 3:
opcode[1] = GetMem(_PC + 1);
opcode[2] = GetMem(_PC + 2);
@@ -807,7 +982,6 @@ void DebugCycle()
case 7: A = (opcode[1] | (opcode[2] << 8)) + _X; break;
case 8: A = opcode[1] + _Y; break;
}
addressOfTheLastAccessedData = A;
if (numWPs || dbgstate.step || dbgstate.runline || dbgstate.stepout || watchpoint[64].flags || dbgstate.badopbreak || break_on_cycles || break_on_instructions || break_asap)
breakpoint(opcode, A, size);
@@ -815,10 +989,5 @@ void DebugCycle()
if(debug_loggingCD)
LogCDData(opcode, A, size);
#ifdef WIN32
//This needs to be windows only or else the linux build system will fail since logging is declared in a
//windows source file
FCEUD_TraceInstruction(opcode, size);
#endif
}
+14 -8
View File
@@ -15,12 +15,15 @@
#define BT_C 0x00 //break type, cpu mem
#define BT_P 0x20 //break type, ppu mem
#define BT_S 0x40 //break type, sprite mem
#define BT_R 0x80 //break type, rom mem
#define BREAK_TYPE_STEP -1
#define BREAK_TYPE_BADOP -2
#define BREAK_TYPE_CYCLES_EXCEED -3
#define BREAK_TYPE_INSTRUCTIONS_EXCEED -4
#define BREAK_TYPE_LUA -5
#define BREAK_TYPE_UNLOGGED_CODE -6
#define BREAK_TYPE_UNLOGGED_DATA -7
//opbrktype is used to grab the breakpoint type that each instruction will cause.
//WP_X is not used because ALL opcodes will have the execute bit set.
@@ -46,21 +49,20 @@ static const uint8 opbrktype[256] = {
typedef struct {
uint16 address;
uint16 endaddress;
uint8 flags;
// ################################## Start of SP CODE ###########################
uint32 address;
uint32 endaddress;
uint16 flags;
Condition* cond;
char* condText;
char* desc;
// ################################## End of SP CODE ###########################
} watchpointinfo;
//mbg merge 7/18/06 had to make this extern
extern watchpointinfo watchpoint[65]; //64 watchpoints, + 1 reserved for step over
extern unsigned int debuggerPageSize;
int getBank(int offs);
int GetNesFileAddress(int A);
int GetPRGAddress(int A);
@@ -95,9 +97,12 @@ static INLINE int FCEUI_GetLoggingCD() { return debug_loggingCD; }
extern int iaPC;
extern uint32 iapoffset; //mbg merge 7/18/06 changed from int
void DebugCycle();
void BreakHit(int bp_num, bool force = false);
bool CondForbidTest(int bp_num);
void BreakHit(int bp_num);
extern bool break_asap;
extern bool break_on_unlogged_code;
extern bool break_on_unlogged_data;
extern uint64 total_cycles_base;
extern uint64 delta_cycles_base;
extern bool break_on_cycles;
@@ -115,8 +120,9 @@ extern void IncrementInstructionsCounters();
//internal variables that debuggers will want access to
extern uint8 *vnapage[4],*VPage[8];
extern uint8 PPU[4],PALRAM[0x20],SPRAM[0x100],VRAMBuffer,PPUGenLatch,XOffset;
extern uint8 PPU[4],PALRAM[0x20],UPALRAM[3],SPRAM[0x100],VRAMBuffer,PPUGenLatch,XOffset;
extern uint32 FCEUPPU_PeekAddress();
extern uint8 READPAL_MOTHEROFALL(uint32 A);
extern int numWPs;
///encapsulates the operational state of the debugger core
@@ -166,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
File diff suppressed because it is too large Load Diff
+170
View File
@@ -0,0 +1,170 @@
#ifndef _DEBUGSYMBOLTABLE_H_
#define _DEBUGSYMBOLTABLE_H_
#include <string>
#include <map>
#include "utils/mutex.h"
#include "ld65dbg.h"
class debugSymbolPage_t;
class debugSymbolTable_t;
class debugSymbol_t
{
public:
debugSymbol_t(void)
{
ofs = 0;
page = nullptr;
};
debugSymbol_t( int ofs, const char *name = nullptr, const char *comment = nullptr )
{
this->ofs = ofs;
if (name)
{
this->_name.assign(name);
}
if ( comment )
{
this->_comment.assign( comment );
}
page = nullptr;
}
const std::string &name(void)
{
return _name;
}
const std::string &comment(void)
{
return _comment;
}
void commentAssign( std::string str )
{
_comment.assign(str);
return;
}
void commentAssign( const char *str )
{
_comment.assign(str);
return;
}
int offset(void)
{
return ofs;
}
void setOffset( int o )
{
if (o != ofs)
{
ofs = o;
}
}
int updateName( const char *name, int arrayIndex = -1 );
void trimTrailingSpaces(void);
private:
int ofs;
std::string _name;
std::string _comment;
debugSymbolPage_t *page;
friend class debugSymbolPage_t;
friend class debugSymbolTable_t;
};
class debugSymbolPage_t
{
public:
debugSymbolPage_t(int page);
~debugSymbolPage_t(void);
int save(void);
void print(void);
int size(void){ return static_cast<int>(symMap.size()); }
int addSymbol( debugSymbol_t *sym );
int deleteSymbolAtOffset( int ofs );
int updateSymbol( debugSymbol_t *sym );
debugSymbol_t *getSymbolAtOffset( int ofs );
debugSymbol_t *getSymbol( const std::string &name );
int pageNum(void)
{
return _pageNum;
}
const char *pageName(void)
{
return _pageName;
}
private:
int _pageNum;
char _pageName[8];
std::map <int, debugSymbol_t*> symMap;
std::map <std::string, debugSymbol_t*> symNameMap;
friend class debugSymbolTable_t;
};
class debugSymbolTable_t
{
public:
debugSymbolTable_t(void);
~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);
void print(void);
debugSymbol_t *getSymbolAtBankOffset( int bank, int ofs );
debugSymbol_t *getSymbol( int bank, const std::string& name);
debugSymbol_t *getSymbolAtAnyBank( const std::string& name);
int addSymbolAtBankOffset( int bank, int ofs, debugSymbol_t *sym );
int addSymbolAtBankOffset(int bank, int ofs, const char* name, const char* comment = nullptr);
int deleteSymbolAtBankOffset( int bank, int ofs );
int updateSymbol( debugSymbol_t *sym );
const char *errorMessage(void);
int ld65LoadDebugFile( const char *dbgFilePath );
void ld65_SymbolLoad( ld65::sym *s );
private:
std::map <int, debugSymbolPage_t*> pageMap;
FCEU::mutex *cs;
};
extern debugSymbolTable_t debugSymbolTable;
#endif
+5 -5
View File
@@ -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);
}
}
@@ -395,10 +395,10 @@ static int FixJoedChar(uint8 ch)
int c = ch - 32;
return (c < 0 || c > 98) ? 0 : c;
}
static int JoedCharWidth(uint8 ch)
{
return Font6x7[FixJoedChar(ch)*8];
}
//static int JoedCharWidth(uint8 ch)
//{
// return Font6x7[FixJoedChar(ch)*8];
//}
char target[64][256];
+28 -8
View File
@@ -14,14 +14,16 @@ inline FILE *FCEUD_UTF8fopen(const std::string &n, const char *mode) { return FC
EMUFILE_FILE* FCEUD_UTF8_fstream(const char *n, const char *m);
inline EMUFILE_FILE* FCEUD_UTF8_fstream(const std::string &n, const char *m) { return FCEUD_UTF8_fstream(n.c_str(),m); }
FCEUFILE* FCEUD_OpenArchiveIndex(ArchiveScanRecord& asr, std::string& fname, int innerIndex);
FCEUFILE* FCEUD_OpenArchiveIndex(ArchiveScanRecord& asr, std::string& fname, int innerIndex, int* userCancel);
FCEUFILE* FCEUD_OpenArchive(ArchiveScanRecord& asr, std::string& fname, std::string* innerFilename);
FCEUFILE* FCEUD_OpenArchive(ArchiveScanRecord& asr, std::string& fname, std::string* innerFilename, int* userCancel);
ArchiveScanRecord FCEUD_ScanArchive(std::string fname);
//mbg 7/23/06
const char *FCEUD_GetCompilerString();
//This makes me feel dirty for some reason.
void FCEU_printf(char *format, ...);
void FCEU_printf( __FCEU_PRINTF_FORMAT const char *format, ...) __FCEU_PRINTF_ATTRIBUTE( 1, 2 );
#define FCEUI_printf FCEU_printf
//Video interface
@@ -122,7 +124,8 @@ void FCEUI_SetVidSystem(int a);
//Set variables for NTSC(0) / PAL(1) / Dendy(2)
//Dendy has PAL framerate and resolution, but ~NTSC timings, and has 50 dummy scanlines to force 50 fps
void FCEUI_SetRegion(int region);
void FCEUI_SetRegion(int region, int notify = 1);
int FCEUI_GetRegion(void);
//Convenience function; returns currently emulated video system(0=NTSC, 1=PAL).
int FCEUI_GetCurrentVidSystem(int *slstart, int *slend);
@@ -140,7 +143,9 @@ void FCEUI_SetRenderedLines(int ntscf, int ntscl, int palf, int pall);
//Sets the base directory(save states, snapshots, etc. are saved in directories below this directory.
void FCEUI_SetBaseDirectory(std::string const & dir);
const char *FCEUI_GetBaseDirectory(void);
bool FCEUI_GetUserPaletteAvail(void);
void FCEUI_SetUserPalette(uint8 *pal, int nEntries);
//Sets up sound code to render sound at the specified rate, in samples
@@ -178,10 +183,16 @@ void FCEUD_MovieRecordTo(void);
void FCEUD_MovieReplayFrom(void);
void FCEUD_LuaRunFrom(void);
#ifdef _S9XLUA_H
// lua engine
void TaseditorAutoFunction(void);
void TaseditorManualFunction(void);
#endif
int32 FCEUI_GetDesiredFPS(void);
void FCEUI_SaveSnapshot(void);
void FCEUI_SaveSnapshotAs(void);
void FCEU_DispMessage(char *format, int disppos, ...);
void FCEU_DispMessage( __FCEU_PRINTF_FORMAT const char *format, int disppos, ...) __FCEU_PRINTF_ATTRIBUTE( 1, 3 );
#define FCEUI_DispMessage FCEU_DispMessage
int FCEUI_DecodePAR(const char *code, int *a, int *v, int *c, int *type);
@@ -189,16 +200,17 @@ int FCEUI_DecodeGG(const char *str, int *a, int *v, int *c);
int FCEUI_AddCheat(const char *name, uint32 addr, uint8 val, int compare, int type);
int FCEUI_DelCheat(uint32 which);
int FCEUI_ToggleCheat(uint32 which);
int FCEUI_GlobalToggleCheat(int global_enable);
int32 FCEUI_CheatSearchGetCount(void);
void FCEUI_CheatSearchGetRange(uint32 first, uint32 last, int (*callb)(uint32 a, uint8 last, uint8 current));
void FCEUI_CheatSearchGet(int (*callb)(uint32 a, uint8 last, uint8 current, void *data), void *data);
void FCEUI_CheatSearchBegin(void);
void FCEUI_CheatSearchEnd(int type, uint8 v1, uint8 v2);
void FCEUI_ListCheats(int (*callb)(char *name, uint32 a, uint8 v, int compare, int s, int type, void *data), void *data);
void FCEUI_ListCheats(int (*callb)(const char *name, uint32 a, uint8 v, int compare, int s, int type, void *data), void *data);
int FCEUI_GetCheat(uint32 which, char **name, uint32 *a, uint8 *v, int *compare, int *s, int *type);
int FCEUI_SetCheat(uint32 which, const char *name, int32 a, int32 v, int compare,int s, int type);
int FCEUI_GetCheat(uint32 which, std::string *name, uint32 *a, uint8 *v, int *compare, int *s, int *type);
int FCEUI_SetCheat(uint32 which, const std::string *name, int32 a, int32 v, int compare,int s, int type);
void FCEUI_CheatSearchShowExcluded(void);
void FCEUI_CheatSearchSetCurrentAsOriginal(void);
@@ -242,12 +254,14 @@ void FCEUI_VSUniToggleDIP(int w);
uint8 FCEUI_VSUniGetDIPs(void);
void FCEUI_VSUniSetDIP(int w, int state);
void FCEUI_VSUniCoin(void);
void FCEUI_VSUniCoin2(void);
void FCEUI_VSUniService(void);
void FCEUI_FDSInsert(void); //mbg merge 7/17/06 changed to void fn(void) to make it an EMUCMDFN
//int FCEUI_FDSEject(void);
void FCEUI_FDSSelect(void);
int FCEUI_DatachSet(const uint8 *rcode);
int FCEUI_DatachSet(uint8 *rcode);
///returns a flag indicating whether emulation is paused
int FCEUI_EmulationPaused();
@@ -259,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();
@@ -318,6 +334,9 @@ void FCEUD_DebugBreakpoint(int bp_num);
///the driver should log the current instruction, if it wants (we should move the code in the win driver that does this to the shared area)
void FCEUD_TraceInstruction(uint8 *opcode, int size);
///the driver should flush its trace log
void FCEUD_FlushTrace();
///the driver might should update its NTView (only used if debugging support is compiled in)
void FCEUD_UpdateNTView(int scanline, bool drawall);
@@ -337,7 +356,8 @@ enum EFCEUI
FCEUI_STOPMOVIE, FCEUI_RECORDMOVIE, FCEUI_PLAYMOVIE,
FCEUI_OPENGAME, FCEUI_CLOSEGAME,
FCEUI_TASEDITOR,
FCEUI_RESET, FCEUI_POWER, FCEUI_PLAYFROMBEGINNING, FCEUI_EJECT_DISK, FCEUI_SWITCH_DISK, FCEUI_INSERT_COIN
FCEUI_RESET, FCEUI_POWER, FCEUI_PLAYFROMBEGINNING, FCEUI_EJECT_DISK, FCEUI_SWITCH_DISK, FCEUI_INSERT_COIN, FCEUI_INPUT_BARCODE,
FCEUI_TOGGLERECORDINGMOVIE, FCEUI_TRUNCATEMOVIE, FCEUI_INSERT1FRAME, FCEUI_DELETE1FRAME
};
//checks whether an EFCEUI is valid right now
-6
View File
@@ -1,6 +0,0 @@
import glob
source_list = glob.glob('*.cpp') + glob.glob('*.c')
for x in range(len(source_list)):
source_list[x] = 'drivers/common/' + source_list[x]
Return('source_list')
+5 -5
View File
@@ -19,11 +19,11 @@
*/
/****************************************************************/
/* FCE Ultra */
/* */
/* This file contains code for parsing command-line */
/* options. */
/* */
/* FCE Ultra */
/* */
/* This file contains code for parsing command-line */
/* options. */
/* */
/****************************************************************/
#include <stdio.h>
+57 -25
View File
@@ -26,7 +26,11 @@
static void GetString(char *s, int max)
{
int x;
fgets(s,max,stdin);
if ( fgets(s,max,stdin) == nullptr )
{
s[0] = 0;
return;
}
for(x=0;x<max;x++)
if(s[x]=='\n')
@@ -41,7 +45,10 @@ static uint32 GetH16(unsigned int def)
{
char buf[32];
fgets(buf,ARRAY_SIZE(buf),stdin);
if ( fgets(buf,ARRAY_SIZE(buf),stdin) == nullptr )
{
return def;
}
if(buf[0]=='\n')
return(def);
if(buf[0]=='$')
@@ -56,7 +63,10 @@ static uint8 Get8(unsigned int def)
{
char buf[32];
fgets(buf,ARRAY_SIZE(buf),stdin);
if ( fgets(buf,ARRAY_SIZE(buf),stdin) == nullptr )
{
return def;
}
if(buf[0]=='\n')
return(def);
sscanf(buf,"%u",&def);
@@ -67,7 +77,10 @@ static int GetI(int def)
{
char buf[32];
fgets(buf,ARRAY_SIZE(buf),stdin);
if ( fgets(buf,ARRAY_SIZE(buf),stdin) == nullptr )
{
return def;
}
if(buf[0]=='\n')
return(def);
sscanf(buf,"%d",&def);
@@ -78,7 +91,10 @@ static int GetYN(int def)
{
char buf[32];
printf("(Y/N)[%s]: ",def?"Y":"N");
fgets(buf,ARRAY_SIZE(buf),stdin);
if ( fgets(buf,ARRAY_SIZE(buf),stdin) == nullptr )
{
return def;
}
if(buf[0]=='y' || buf[0]=='Y')
return(1);
if(buf[0]=='n' || buf[0]=='N')
@@ -114,7 +130,10 @@ int ListChoice(int hmm)
tryagain:
printf(" <'Enter' to continue, (S)top, or enter a number.> ");
fgets(buf,ARRAY_SIZE(buf),stdin);
if ( fgets(buf,ARRAY_SIZE(buf),stdin) == nullptr )
{
return -1;
}
if(buf[0]=='s' || buf[0]=='S') return(-1);
if(buf[0]=='\n') return(0);
if(!sscanf(buf,"%d",&num))
@@ -128,7 +147,10 @@ int ListChoice(int hmm)
tryagain2:
printf(" <'Enter' to make no selection or enter a number.> ");
fgets(buf,ARRAY_SIZE(buf),stdin);
if ( fgets(buf,ARRAY_SIZE(buf),stdin) == nullptr )
{
return -1;
}
if(buf[0]=='\n') return(0);
if(!sscanf(buf,"%d",&num))
return(0);
@@ -176,7 +198,7 @@ int AddToList(char *text, uint32 id)
**/
typedef struct MENU {
char *text;
const char *text;
void *action;
int type; // 0 for menu, 1 for function.
} MENU;
@@ -199,7 +221,8 @@ static void ToggleCheat(int num)
static void ModifyCheat(int num)
{
char *name;
std::string name;
std::string *pName;
char buf[256];
uint32 A;
uint8 V;
@@ -211,7 +234,7 @@ static void ModifyCheat(int num)
FCEUI_GetCheat(num, &name, &A, &V, &compare, &s, &type);
printf("Name [%s]: ",name);
printf("Name [%s]: ",name.c_str());
GetString(buf,256);
/* This obviously doesn't allow for cheats with no names. Bah. Who wants
@@ -219,14 +242,14 @@ static void ModifyCheat(int num)
*/
if(buf[0])
name=buf; // Change name when FCEUI_SetCheat() is called.
pName=&name; // Change name when FCEUI_SetCheat() is called.
else
name=0; // Don't change name when FCEUI_SetCheat() is called.
pName=nullptr; // Don't change name when FCEUI_SetCheat() is called.
printf("Address [$%04x]: ",(unsigned int)A);
A=GetH16(A);
printf("Value [%03d]: ",(unsigned int)V);
printf("Value [%03u]: ",(unsigned int)V);
V=Get8(V);
printf("Compare [%3d]: ",compare);
@@ -240,7 +263,7 @@ static void ModifyCheat(int num)
if(t=='Y' || t=='y') s=1;
else if(t=='N' || t=='n') s=0;
FCEUI_SetCheat(num,name,A,V,compare,s,type);
FCEUI_SetCheat(num,pName,A,V,compare,s,type);
}
@@ -302,9 +325,9 @@ static void AddCheatParam(uint32 A, uint8 V)
GetString(name,256);
printf("Address [$%04x]: ",(unsigned int)A);
A=GetH16(A);
printf("Value [%03d]: ",(unsigned int)V);
printf("Value [%03u]: ",(unsigned int)V);
V=Get8(V);
printf("Add cheat \"%s\" for address $%04x with value %03d?",name,(unsigned int)A,(unsigned int)V);
printf("Add cheat \"%s\" for address $%04x with value %03u?",name,(unsigned int)A,(unsigned int)V);
if(GetYN(0))
{
if(FCEUI_AddCheat(name,A,V,-1,0))
@@ -320,15 +343,15 @@ static void AddCheat(void)
}
static int lid;
static int clistcallb(char *name, uint32 a, uint8 v, int compare, int s, int type, void *data)
static int clistcallb(const char *name, uint32 a, uint8 v, int compare, int s, int type, void *data)
{
char tmp[512];
int ret;
if(compare>=0)
sprintf(tmp,"%s $%04x:%03d:%03d - %s",s?"*":" ",(unsigned int)a,(unsigned int)v,compare,name);
sprintf(tmp,"%s $%04x:%03u:%03d - %s",s?"*":" ",(unsigned int)a,(unsigned int)v,compare,name);
else
sprintf(tmp,"%s $%04x:%03d - %s",s?"*":" ",(unsigned int)a,(unsigned int)v,name);
sprintf(tmp,"%s $%04x:%03u - %s",s?"*":" ",(unsigned int)a,(unsigned int)v,name);
if(type==1)
tmp[2]='S';
ret=AddToList(tmp,lid);
@@ -348,7 +371,10 @@ static void ListCheats(void)
{
char tmp[32];
printf(" <(T)oggle status, (M)odify, or (D)elete this cheat.> ");
fgets(tmp,ARRAY_SIZE(tmp),stdin);
if ( fgets(tmp,ARRAY_SIZE(tmp),stdin) == nullptr )
{
tmp[0] = 0;
}
switch(tolower(tmp[0]))
{
case 't':ToggleCheat(which);
@@ -373,7 +399,7 @@ static void ResetSearch(void)
static int srescallb(uint32 a, uint8 last, uint8 current, void *data)
{
char tmp[14];
sprintf(tmp, "$%04x:%03d:%03d",(unsigned int)a,(unsigned int)last,(unsigned int)current);
sprintf(tmp, "$%04x:%03u:%03u",(unsigned int)a,(unsigned int)last,(unsigned int)current);
return(AddToList(tmp,a));
}
@@ -392,7 +418,7 @@ static void ShowRes(void)
}
}
static int ShowShortList(char *moe[], int n, int def)
static int ShowShortList(const char *moe[], int n, int def)
{
int x,c;
int baa; //mbg merge 7/17/06 made to normal int
@@ -405,7 +431,10 @@ static int ShowShortList(char *moe[], int n, int def)
clo:
printf("\nSelection [%d]> ",def+1);
fgets(tmp,ARRAY_SIZE(tmp),stdin);
if ( fgets(tmp,ARRAY_SIZE(tmp),stdin) == nullptr )
{
return def;
}
if(tmp[0]=='\n')
return def;
c=tolower(tmp[0]);
@@ -430,7 +459,7 @@ static void DoSearch(void)
{
static int v1=0,v2=0;
static int method=0;
char *m[9]={"O==V1 && C==V2",
const char *m[9]={"O==V1 && C==V2",
"O==V1 && |O-C|==V2",
"|O-C|==V2",
"O!=C",
@@ -504,7 +533,10 @@ static void DoMenu(MENU *men)
recommand:
printf("Command> ");
fgets(buf,ARRAY_SIZE(buf),stdin);
if ( fgets(buf,ARRAY_SIZE(buf),stdin) == nullptr )
{
return;
}
c=tolower(buf[0]);
if(c=='\n')
goto recommand;
+3 -1
View File
@@ -17,5 +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
*/
#ifndef COMMON_CHEAT_H
#define COMMON_CHEAT_H
void DoConsoleCheatConfig(void);
#endif
+7 -2
View File
@@ -125,7 +125,7 @@ static void cfg_Save(FILE *fp)
{
if(it->first.size()>30 || it->second.size()>30)
{
int zzz=9;
//int zzz=9;
}
fprintf(fp,"%s %s\n",it->first.c_str(),it->second.c_str());
}
@@ -145,6 +145,11 @@ static void GetValueR(FILE *fp, char *str, void *v, int c)
{
if(!c) // String, allocate some memory.
{
// Windows enforces a 32767 character limit for text boxes by default
// If a string exceeds this length, it's probably a corrupt file
if (s > 32768)
goto gogl;
if(!(*(char **)v=(char*)malloc(s)))
goto gogl;
@@ -208,7 +213,7 @@ void SaveParse(const CFGSTRUCT *cfgst, FILE *fp)
if(*(char **)cfgst[x].ptr)
{
// Only save it if there IS a string.
unsigned int len = strlen(*(char **)cfgst[x].ptr);
size_t len = strlen(*(char **)cfgst[x].ptr);
SetValueR(fp,cfgst[x].name,*(char **)cfgst[x].ptr, len + 1);
}
}
+7 -2
View File
@@ -23,16 +23,21 @@ void LoadFCEUConfig(const char *filename, CFGSTRUCT *cfgst);
// isn't really hurting much.
// Single piece of data(integer).
#define AC(x) { #x,&x,sizeof(x)}
#define NAC(w,x) { #w,&x,sizeof(x)}
#define AC(x) {#x,&x,sizeof(x)}
#define NAC(w,x) {#w,&x,sizeof(x)}
// VAC intruduced for backward compatibility with
// configuration files of previous versions
#define VAC(x,version) {#x "_V" #version,&x,sizeof(x)}
// Array.
#define ACA(x) {#x,x,sizeof(x)}
#define NACA(w,x) {#w,x,sizeof(x)}
#define VACA(x,version) {#x "_V" #version,x,sizeof(x)}
// String(pointer) with automatic memory allocation.
#define ACS(x) {#x,&x,0}
#define NACS(w,x) {#w,&x,0}
#define VACS(x,version) {#x "_V" #version,&x,0}
#define _DRIVERS_CONFIGH
#endif
+34 -11
View File
@@ -3,7 +3,10 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#ifndef WIN32
#include <dirent.h>
#endif
#include "../../types.h"
#include "configSys.h"
@@ -444,6 +447,23 @@ Config::getOption(const std::string &name,
return 0;
}
int
Config::getOption(const std::string &name,
bool *value) const
{
std::map<std::string, int>::const_iterator opt_i;
// confirm that the option exists
opt_i = _intOptMap.find(name);
if(opt_i == _intOptMap.end()) {
return -1;
}
// get the option
(*value) = opt_i->second ? true : false;
return 0;
}
int
Config::getOption(const std::string &name,
double *value) const
@@ -559,6 +579,7 @@ Config::parse(int argc,
return error;
}
#ifndef WIN32
// try to read cfg.d/*
std::string cfgd_dir_name = _dir + "/" + "cfg.d/";
DIR *d;
@@ -576,7 +597,7 @@ Config::parse(int argc,
// TODO 0 = good -1 = bad
std::string fname = cfgd_dir_name + dir->d_name;
printf("Loading auxilary configuration file at %s...\n", fname.c_str());
printf("Loading auxiliary configuration file at %s...\n", fname.c_str());
if (_loadFile(fname.c_str()) != 0)
{
printf("Failed to parse configuration at %s\n", fname.c_str());
@@ -585,7 +606,9 @@ Config::parse(int argc,
closedir(d);
}
#else
// FIXME TODO WIN32
#endif
// parse the arguments
return _parseArgs(argc, argv);
}
@@ -618,7 +641,7 @@ Config::_load()
int
Config::_loadFile(const char* fname)
{
signed int pos, eqPos;
size_t pos=0, eqPos=0;
std::fstream config;
std::map<std::string, int>::iterator int_i;
std::map<std::string, double>::iterator dbl_i;
@@ -633,7 +656,7 @@ Config::_loadFile(const char* fname)
configFile = fname;
}
std::string line, name, value;
char buf[1024];
char buf[4096];
// set the exception handling to catch i/o errors
config.exceptions(std::fstream::badbit);
@@ -648,7 +671,7 @@ Config::_loadFile(const char* fname)
while(!config.eof()) {
// read a line
config.getline(buf, 1024);
config.getline(buf, sizeof(buf));
line = buf;
// check line validity
@@ -681,7 +704,7 @@ Config::_loadFile(const char* fname)
// close the file
config.close();
} catch(std::fstream::failure e) {
} catch(std::fstream::failure &e) {
std::cerr << e.what() << std::endl;
return -1;
}
@@ -700,7 +723,7 @@ Config::save()
std::map<std::string, double>::iterator dbl_i;
std::map<std::string, std::string>::iterator str_i;
std::string configFile = _dir + "/" + cfgFile;
char buf[1024];
char buf[4096];
// set the exception handling to catch i/o errors
config.exceptions(std::ios::failbit | std::ios::badbit);
@@ -718,26 +741,26 @@ Config::save()
// write each configuration setting
for(int_i = _intOptMap.begin(); int_i != _intOptMap.end(); int_i++)
{
snprintf(buf, 1024, "%s = %d\n",
snprintf(buf, sizeof(buf), "%s = %d\n",
int_i->first.c_str(), int_i->second);
config.write(buf, strlen(buf));
}
for(dbl_i = _dblOptMap.begin(); dbl_i != _dblOptMap.end(); dbl_i++)
{
snprintf(buf, 1024, "%s = %f\n",
snprintf(buf, sizeof(buf), "%s = %f\n",
dbl_i->first.c_str(), dbl_i->second);
config.write(buf, strlen(buf));
}
for(str_i = _strOptMap.begin(); str_i != _strOptMap.end(); str_i++)
{
snprintf(buf, 1024, "%s = %s\n",
snprintf(buf, sizeof(buf), "%s = %s\n",
str_i->first.c_str(), str_i->second.c_str());
config.write(buf, strlen(buf));
}
// close the file
config.close();
} catch(std::fstream::failure e)
} catch(std::fstream::failure &e)
{
std::cerr << e.what() << std::endl;
return -1;
+1
View File
@@ -69,6 +69,7 @@ public:
int getOption(const std::string &, std::string *) const;
int getOption(const std::string &, const char **) const;
int getOption(const std::string &, int *) const;
int getOption(const std::string &, bool *) const;
int getOption(const std::string &, double *) const;
/**
+9 -6
View File
@@ -242,15 +242,16 @@ void nes_ntsc_init( nes_ntsc_t* ntsc, nes_ntsc_setup_t const* setup, int bpp )
#ifndef NES_NTSC_NO_BLITTERS
void nes_ntsc_blit( nes_ntsc_t const* ntsc, NES_NTSC_IN_T const* input, long in_row_width,
int burst_phase, int emphasis, int in_width, int in_height, void* rgb_out, long out_pitch )
void nes_ntsc_blit( nes_ntsc_t const* ntsc, NES_NTSC_IN_T const* input, NES_NTSC_IN_T const* inputD, long in_row_width,
int burst_phase, int in_width, int in_height, void* rgb_out, long out_pitch )
{
int chunk_count = (in_width - 1) / nes_ntsc_in_chunk;
for ( ; in_height; --in_height )
{
NES_NTSC_IN_T const* line_in = input;
NES_NTSC_BEGIN_ROW( ntsc, burst_phase, nes_ntsc_black, nes_ntsc_black, NES_NTSC_ADJ_IN( *line_in ) );
NES_NTSC_IN_T const* line_inD = inputD;
NES_NTSC_BEGIN_ROW( ntsc, burst_phase, nes_ntsc_black, nes_ntsc_black, NES_NTSC_ADJ_IN( *line_in, *line_inD ) );
nes_ntsc_out_t* restrict line_out = (nes_ntsc_out_t*) rgb_out;
int n;
++line_in;
@@ -259,20 +260,21 @@ void nes_ntsc_blit( nes_ntsc_t const* ntsc, NES_NTSC_IN_T const* input, long in_
{
/* order of input and output pixels must not be altered */
NES_NTSC_COLOR_IN( 0, NES_NTSC_ADJ_IN( line_in [0] ) );
NES_NTSC_COLOR_IN( 0, NES_NTSC_ADJ_IN( line_in [0], line_inD [0] ) );
NES_NTSC_RGB_OUT( 0, line_out [0], OutputDepth );
NES_NTSC_RGB_OUT( 1, line_out [1], OutputDepth );
NES_NTSC_COLOR_IN( 1, NES_NTSC_ADJ_IN( line_in [1] ) );
NES_NTSC_COLOR_IN( 1, NES_NTSC_ADJ_IN( line_in [1], line_inD [1] ) );
NES_NTSC_RGB_OUT( 2, line_out [2], OutputDepth );
NES_NTSC_RGB_OUT( 3, line_out [3], OutputDepth );
NES_NTSC_COLOR_IN( 2, NES_NTSC_ADJ_IN( line_in [2] ) );
NES_NTSC_COLOR_IN( 2, NES_NTSC_ADJ_IN( line_in [2], line_inD [2] ) );
NES_NTSC_RGB_OUT( 4, line_out [4], OutputDepth );
NES_NTSC_RGB_OUT( 5, line_out [5], OutputDepth );
NES_NTSC_RGB_OUT( 6, line_out [6], OutputDepth );
line_in += 3;
line_inD += 3;
line_out += rescale_out;
}
@@ -293,6 +295,7 @@ void nes_ntsc_blit( nes_ntsc_t const* ntsc, NES_NTSC_IN_T const* input, long in_
burst_phase = (burst_phase + 1) % nes_ntsc_burst_count;
input += in_row_width;
inputD += in_row_width;
}
}
+2 -2
View File
@@ -61,8 +61,8 @@ In_row_width is the number of pixels to get to the next input row. Emphasis is
the emphasis bits to bitwise-OR with all pixels in the input data. Out_pitch
is the number of *bytes* to get to the next output row. Output pixel format
is set by NES_NTSC_OUT_DEPTH (defaults to 16-bit RGB). */
void nes_ntsc_blit( nes_ntsc_t const* ntsc, NES_NTSC_IN_T const* nes_in,
long in_row_width, int burst_phase, int emphasis, int in_width,
void nes_ntsc_blit( nes_ntsc_t const* ntsc, NES_NTSC_IN_T const* nes_in, NES_NTSC_IN_T const* nes_inD,
long in_row_width, int burst_phase, int in_width,
int in_height, void* rgb_out, long out_pitch );
/* Number of output pixels written by blitter for given input width. Width might
+1 -1
View File
@@ -21,7 +21,7 @@ if you enable emphasis above. */
// CUSTOM: (XBuf uses bit 0x80, and has palettes above 0x3f for LUA)
/* Each raw pixel input value is passed through this. You might want to mask
the pixel index if you use the high bits as flags, etc. */
#define NES_NTSC_ADJ_IN( in ) ((in & 0x3f) | emphasis)
#define NES_NTSC_ADJ_IN( in, inD ) ((in & 0x3F) | (inD << 6))
/* For each pixel, this is the basic operation:
output_color = color_palette [NES_NTSC_ADJ_IN( NES_NTSC_IN_T )] */
+101
View File
@@ -0,0 +1,101 @@
// os_util.cpp
#include <stdio.h>
#include <stdlib.h>
#if defined(WIN32)
#include <windows.h>
#include <direct.h>
#include <io.h>
#else
#include <errno.h>
#include <unistd.h>
#include <sys/stat.h>
#endif
#include "common/os_utils.h"
//************************************************************
int fceu_mkdir( const char *path )
{
int retval;
#if defined(WIN32)
retval = _mkdir(path);
_chmod(path, 755);
#else
retval = mkdir(path, S_IRWXU);
if ( retval != 0 )
{
if ( errno == EEXIST )
{
//printf("Path Exists: '%s'\n", path);
retval = 0;
}
}
#endif
return retval;
}
//************************************************************
int fceu_mkpath( const char *path )
{
int i, retval = 0;
char p[512];
i=0;
while ( path[i] != 0 )
{
if ( path[i] == '/' )
{
if ( i > 0 )
{
p[i] = 0;
retval = fceu_mkdir( p );
if ( retval )
{
return retval;
}
}
}
p[i] = path[i]; i++;
}
p[i] = 0;
retval = fceu_mkdir( p );
return retval;
}
//************************************************************
bool fceu_file_exists( const char *filepath )
{
#ifdef WIN32
FILE *fp;
fp = ::fopen( filepath, "r" );
if ( fp != NULL )
{
::fclose(fp);
return true;
}
#else
struct stat sb;
if ( stat( filepath, &sb ) == 0 )
{
return true;
}
#endif
return false;
}
//************************************************************
int msleep( int ms )
{
int ret = 0;
#ifdef WIN32
Sleep(ms);
#else
ret = usleep(ms*1000);
#endif
return ret;
}
//************************************************************
+10
View File
@@ -0,0 +1,10 @@
// os_utils.h
//
int fceu_mkdir( const char *path );
int fceu_mkpath( const char *path );
bool fceu_file_exists( const char *filepath );
int msleep( int ms );
+78 -26
View File
@@ -65,9 +65,9 @@ static float *moire = NULL; // modulated signal
const float phasex = (float) 5/18*2;
const float phasey = (float) 1/ 6*2;
const float pi = 3.14f;
int palnotch = 90;
int palnotch = 100;
int palsaturation = 100;
int palsharpness = 50;
int palsharpness = 0;
int palcontrast = 100;
int palbrightness = 50;
bool palupdate = 1;
@@ -88,13 +88,13 @@ static int PAL_LUT(uint32 *buffer, int index, int x, int y)
static void CalculateShift(uint32 *CBM, int *cshiftr, int *cshiftl)
{
int a,x,z,y;
int a,x,z;
cshiftl[0]=cshiftl[1]=cshiftl[2]=-1;
for(a=0;a<3;a++)
{
for(x=0,y=-1,z=0;x<32;x++)
for(x=0,z=0;x<32;x++)
{
if(CBM[a]&(1<<x))
if(CBM[a]&(1u<<x))
{
if(cshiftl[a]==-1) cshiftl[a]=x;
z++;
@@ -107,8 +107,6 @@ static void CalculateShift(uint32 *CBM, int *cshiftr, int *cshiftl)
int InitBlitToHigh(int b, uint32 rmask, uint32 gmask, uint32 bmask, int efx, int specfilt, int specfilteropt)
{
//paldeemphswap = 0; // determine this in FCEUPPU_SetVideoSystem() instead
// -Video Modes Tag-
if(specfilt == 3) // NTSC 2x
{
@@ -208,6 +206,7 @@ int InitBlitToHigh(int b, uint32 rmask, uint32 gmask, uint32 bmask, int efx, int
palrgb = (uint32 *)FCEU_dmalloc((256+512)*PAL_PHASES*sizeof(uint32));
palrgb2 = (uint32 *)FCEU_dmalloc((256+512)*PAL_PHASES*sizeof(uint32));
moire = (float *)FCEU_dmalloc( PAL_PHASES*sizeof(float));
palupdate = 1;
}
silt = specfilt;
@@ -218,6 +217,11 @@ int InitBlitToHigh(int b, uint32 rmask, uint32 gmask, uint32 bmask, int efx, int
return(0);
//allocate adequate room for 32bpp palette
if ( palettetranslate )
{
free(palettetranslate);
palettetranslate=NULL;
}
palettetranslate=(uint32*)FCEU_dmalloc(256*4 + 512*4);
if(!palettetranslate)
@@ -234,18 +238,18 @@ void KillBlitToHigh(void)
{
if(palettetranslate)
{
free(palettetranslate);
FCEU_free(palettetranslate);
palettetranslate=NULL;
}
if(specbuf8bpp)
{
free(specbuf8bpp);
FCEU_free(specbuf8bpp);
specbuf8bpp = NULL;
}
if(specbuf32bpp)
{
free(specbuf32bpp);
FCEU_free(specbuf32bpp);
specbuf32bpp = NULL;
}
if(specbuf)
@@ -255,10 +259,11 @@ void KillBlitToHigh(void)
hq3x_Kill();
else
hq2x_Kill();
FCEU_free(specbuf);
specbuf=NULL;
}
if (nes_ntsc) {
free(nes_ntsc);
FCEU_free(nes_ntsc);
nes_ntsc = NULL;
}
if (ntscblit) {
@@ -461,7 +466,7 @@ void Blit8To8(uint8 *src, uint8 *dest, int xr, int yr, int pitch, int xscale, in
/* Todo: Make sure 24bpp code works right with big-endian cpus */
//takes a pointer to XBuf and applies fully modern deemph palettizing
u32 ModernDeemphColorMap(u8* src, u8* srcbuf, int xscale, int yscale)
template<int SCALE> static u32 _ModernDeemphColorMap(const u8* src, const u8* srcbuf)
{
u8 pixel = *src;
@@ -471,8 +476,8 @@ u32 ModernDeemphColorMap(u8* src, u8* srcbuf, int xscale, int yscale)
int ofs = src-srcbuf;
int xofs = ofs&255;
int yofs = ofs>>8;
if(xscale!=1) xofs /= xscale; //untested optimization
if(yscale!=1) yofs /= yscale; //untested optimization
xofs /= SCALE;
yofs /= SCALE;
ofs = xofs+yofs*256;
//find out which deemph bitplane value we're on
@@ -480,11 +485,47 @@ u32 ModernDeemphColorMap(u8* src, u8* srcbuf, int xscale, int yscale)
//if it was a deemph'd value, grab it from the deemph palette
if(deemph != 0)
color = palettetranslate[256+(pixel&0x3F)+deemph*64];
{
color = palettetranslate[256+(pixel&0x3F)+(deemph*64)];
}
return color;
}
u32 ModernDeemphColorMap(const u8* src, const u8* srcbuf, int scale)
{
if(scale == 1) return _ModernDeemphColorMap<1>(src,srcbuf);
else if(scale == 2) return _ModernDeemphColorMap<2>(src,srcbuf);
else if(scale == 3) return _ModernDeemphColorMap<3>(src,srcbuf);
else if(scale == 4) return _ModernDeemphColorMap<4>(src,srcbuf);
else if(scale == 5) return _ModernDeemphColorMap<5>(src,srcbuf);
else if(scale == 6) return _ModernDeemphColorMap<6>(src,srcbuf);
else if(scale == 7) return _ModernDeemphColorMap<7>(src,srcbuf);
else if(scale == 8) return _ModernDeemphColorMap<8>(src,srcbuf);
else if(scale == 9) return _ModernDeemphColorMap<9>(src,srcbuf);
else { FCEU_abort("unhandled ModernDeemphColorMap scale"); return 0; }
}
typedef u32 (*ModernDeemphColorMapFuncPtr)( const u8*, const u8* );
static ModernDeemphColorMapFuncPtr getModernDeemphColorMapFunc(int scale)
{
ModernDeemphColorMapFuncPtr ptr;
if(scale == 1) ptr = &_ModernDeemphColorMap<1>;
else if(scale == 2) ptr = &_ModernDeemphColorMap<2>;
else if(scale == 3) ptr = &_ModernDeemphColorMap<3>;
else if(scale == 4) ptr = &_ModernDeemphColorMap<4>;
else if(scale == 5) ptr = &_ModernDeemphColorMap<5>;
else if(scale == 6) ptr = &_ModernDeemphColorMap<6>;
else if(scale == 7) ptr = &_ModernDeemphColorMap<7>;
else if(scale == 8) ptr = &_ModernDeemphColorMap<8>;
else if(scale == 9) ptr = &_ModernDeemphColorMap<9>;
else { FCEU_abort("unhandled ModernDeemphColorMap scale"); ptr = nullptr; }
return ptr;
}
void Blit8ToHigh(uint8 *src, uint8 *dest, int xr, int yr, int pitch, int xscale, int yscale)
{
int x,y;
@@ -500,6 +541,7 @@ void Blit8ToHigh(uint8 *src, uint8 *dest, int xr, int yr, int pitch, int xscale,
{
int mult;
int base;
ModernDeemphColorMapFuncPtr ModernDeemphColorMapFunc = NULL;
// -Video Modes Tag-
if(silt == 2) mult = 2;
@@ -508,7 +550,12 @@ void Blit8ToHigh(uint8 *src, uint8 *dest, int xr, int yr, int pitch, int xscale,
Blit8To8(src, specbuf8bpp, xr, yr, 256*mult, xscale, yscale, 0, silt);
int mdcmxs = xscale*mult;
int mdcmys = yscale*mult;
if(mdcmxs != mdcmys)
abort();
ModernDeemphColorMapFunc = getModernDeemphColorMapFunc( mdcmxs );
xr *= mult;
yr *= mult;
xscale=yscale=1;
@@ -523,7 +570,7 @@ void Blit8ToHigh(uint8 *src, uint8 *dest, int xr, int yr, int pitch, int xscale,
{
for(x=xr;x;x--)
{
*(uint32 *)dest=ModernDeemphColorMap(src,specbuf8bpp,mdcmxs, mdcmys);
*(uint32 *)dest=ModernDeemphColorMapFunc(src,specbuf8bpp);
dest+=4;
src++;
}
@@ -536,7 +583,7 @@ void Blit8ToHigh(uint8 *src, uint8 *dest, int xr, int yr, int pitch, int xscale,
{
for(x=xr;x;x--)
{
uint32 tmp=ModernDeemphColorMap(src,specbuf8bpp,mdcmxs, mdcmys);
uint32 tmp=ModernDeemphColorMapFunc(src,specbuf8bpp);
*(uint8 *)dest=tmp;
*((uint8 *)dest+1)=tmp>>8;
*((uint8 *)dest+2)=tmp>>16;
@@ -576,7 +623,7 @@ void Blit8ToHigh(uint8 *src, uint8 *dest, int xr, int yr, int pitch, int xscale,
{
for(x=xr; x; x--)
{
*(uint32 *)dest = ModernDeemphColorMap(src,XBuf,1,1);
*(uint32 *)dest = _ModernDeemphColorMap<1>(src,XBuf);
dest += 4;
src++;
}
@@ -587,9 +634,11 @@ void Blit8ToHigh(uint8 *src, uint8 *dest, int xr, int yr, int pitch, int xscale,
{
uint32 *s = prescalebuf;
uint32 *d = (uint32 *)destbackup; // use 32-bit pointers ftw
int subpixel;
int subpixel,yend;
for (y=0; y<yr*yscale; y++)
yend = yr*yscale;
for (y=0; y<yend; y++)
{
int back = xr*(y%yscale>0); // bool as multiplier
for (x=0; x<xr; x++)
@@ -715,7 +764,7 @@ void Blit8ToHigh(uint8 *src, uint8 *dest, int xr, int yr, int pitch, int xscale,
newindex = (*src&63) | (deemph*64);
newindex += 256;
if(GameInfo->type==GIT_NSF)
if(GameInfo && GameInfo->type==GIT_NSF)
{
*d++ = palettetranslate[temp];
*d++ = palettetranslate[temp];
@@ -785,6 +834,7 @@ void Blit8ToHigh(uint8 *src, uint8 *dest, int xr, int yr, int pitch, int xscale,
lastindex = index;
}
}
src += (256-xr);
}
}
@@ -807,11 +857,13 @@ void Blit8ToHigh(uint8 *src, uint8 *dest, int xr, int yr, int pitch, int xscale,
switch(Bpp)
{
case 4:
if ( nes_ntsc && GameInfo->type!=GIT_NSF) {
if ( nes_ntsc && GameInfo && GameInfo->type!=GIT_NSF) {
int outxr = 301;
//if(xr == 282) outxr = 282; //hack for windows
burst_phase ^= 1;
nes_ntsc_blit( nes_ntsc, (unsigned char*)src, xr, burst_phase, (PPU[1] >> 5) << 6, xr, yr, ntscblit, (2*outxr) * Bpp );
u8* srcD = XDBuf + (src-XBuf); // get deemphasis buffer
nes_ntsc_blit( nes_ntsc, (unsigned char*)src, (unsigned char*)srcD, xr, burst_phase, xr, yr, ntscblit, (2*outxr) * Bpp );
const uint8 *in = ntscblit + (Bpp * xscale);
uint8 *out = dest;
@@ -912,7 +964,7 @@ void Blit8ToHigh(uint8 *src, uint8 *dest, int xr, int yr, int pitch, int xscale,
for(x=xr;x;x--)
{
//THE MAIN BLITTING CODEPATH (there may be others that are important)
*(uint32 *)dest = ModernDeemphColorMap(src,XBuf,1,1);
*(uint32 *)dest = _ModernDeemphColorMap<1>(src,XBuf);
dest+=4;
src++;
}
@@ -925,7 +977,7 @@ void Blit8ToHigh(uint8 *src, uint8 *dest, int xr, int yr, int pitch, int xscale,
{
for(x=xr;x;x--)
{
uint32 tmp = ModernDeemphColorMap(src,XBuf,1,1);
uint32 tmp = _ModernDeemphColorMap<1>(src,XBuf);
*(uint8 *)dest=tmp;
*((uint8 *)dest+1)=tmp>>8;
*((uint8 *)dest+2)=tmp>>16;
@@ -941,7 +993,7 @@ void Blit8ToHigh(uint8 *src, uint8 *dest, int xr, int yr, int pitch, int xscale,
{
for(x=xr;x;x--)
{
*(uint16 *)dest = ModernDeemphColorMap(src,XBuf,1,1);
*(uint16 *)dest = _ModernDeemphColorMap<1>(src,XBuf);
dest+=2;
src++;
}
+1 -1
View File
@@ -29,4 +29,4 @@ void Blit32to16(uint32 *src, uint16 *dest, int xr, int yr, int dpitch,
int shiftr[3], int shiftl[3]);
u32 ModernDeemphColorMap(u8* src, u8* srcbuf, int xscale, int yscale);
u32 ModernDeemphColorMap(const u8* src, const u8* srcbuf, int scale);
-28
View File
@@ -1,28 +0,0 @@
# Fix compliation error about 'XKeysymToString' by linking X11 explicitly
# Thanks Antonio Ospite!
Import('env')
config_string = 'pkg-config --cflags --libs x11'
env.ParseConfig(config_string)
Export('env')
source_list = Split(
"""
input.cpp
config.cpp
sdl.cpp
sdl-joystick.cpp
sdl-sound.cpp
sdl-throttle.cpp
sdl-video.cpp
unix-netplay.cpp
""")
Import('env')
if 'GL' in env['LIBS']:
source_list.append('sdl-opengl.cpp')
if env['GTK'] or env['GTK3']:
source_list.append('gui.cpp')
source_list = ['drivers/sdl/' + source for source in source_list]
Return('source_list')
-443
View File
@@ -1,443 +0,0 @@
#include "main.h"
#include "throttle.h"
#include "config.h"
#include "../common/cheat.h"
#include "input.h"
#include "dface.h"
#include "sdl.h"
#include "sdl-video.h"
#include "unix-netplay.h"
#ifdef WIN32
#include <windows.h>
#endif
#include <unistd.h>
#include <csignal>
#include <cstring>
#include <cerrno>
#include <cstdio>
#include <cstdlib>
#include <sys/time.h>
#include <sys/stat.h>
#include <sys/types.h>
/**
* Read a custom pallete from a file and load it into the core.
*/
int
LoadCPalette(const std::string &file)
{
uint8 tmpp[192];
FILE *fp;
if(!(fp = FCEUD_UTF8fopen(file.c_str(), "rb"))) {
char errorMsg[256];
strcpy(errorMsg, "Error loading custom palette from file: ");
strcat(errorMsg, file.c_str());
FCEUD_PrintError(errorMsg);
return 0;
}
size_t result = fread(tmpp, 1, 192, fp);
if(result != 192) {
char errorMsg[256];
strcpy(errorMsg, "Error loading custom palette from file: ");
strcat(errorMsg, file.c_str());
FCEUD_PrintError(errorMsg);
return 0;
}
FCEUI_SetUserPalette(tmpp, result/3);
fclose(fp);
return 1;
}
/**
* Creates the subdirectories used for saving snapshots, movies, game
* saves, etc. Hopefully obsolete with new configuration system.
*/
static void
CreateDirs(const std::string &dir)
{
char *subs[8]={"fcs","snaps","gameinfo","sav","cheats","movies","cfg.d"};
std::string subdir;
int x;
#if defined(WIN32) || defined(NEED_MINGW_HACKS)
mkdir(dir.c_str());
chmod(dir.c_str(), 755);
for(x = 0; x < 6; x++) {
subdir = dir + PSS + subs[x];
mkdir(subdir.c_str());
}
#else
mkdir(dir.c_str(), S_IRWXU);
for(x = 0; x < 6; x++) {
subdir = dir + PSS + subs[x];
mkdir(subdir.c_str(), S_IRWXU);
}
#endif
}
/**
* Attempts to locate FCEU's application directory. This will
* hopefully become obsolete once the new configuration system is in
* place.
*/
static void
GetBaseDirectory(std::string &dir)
{
char *home = getenv("HOME");
if(home) {
dir = std::string(home) + "/.fceux";
} else {
#ifdef WIN32
home = new char[MAX_PATH + 1];
GetModuleFileName(NULL, home, MAX_PATH + 1);
char *lastBS = strrchr(home,'\\');
if(lastBS) {
*lastBS = 0;
}
dir = std::string(home);
delete[] home;
#else
dir = "";
#endif
}
}
// returns a config structure with default options
// also creates config base directory (ie: /home/user/.fceux as well as subdirs
Config *
InitConfig()
{
std::string dir, prefix;
Config *config;
GetBaseDirectory(dir);
FCEUI_SetBaseDirectory(dir.c_str());
CreateDirs(dir);
config = new Config(dir);
// sound options
config->addOption('s', "sound", "SDL.Sound", 1);
config->addOption("volume", "SDL.Sound.Volume", 150);
config->addOption("trianglevol", "SDL.Sound.TriangleVolume", 256);
config->addOption("square1vol", "SDL.Sound.Square1Volume", 256);
config->addOption("square2vol", "SDL.Sound.Square2Volume", 256);
config->addOption("noisevol", "SDL.Sound.NoiseVolume", 256);
config->addOption("pcmvol", "SDL.Sound.PCMVolume", 256);
config->addOption("soundrate", "SDL.Sound.Rate", 44100);
config->addOption("soundq", "SDL.Sound.Quality", 1);
config->addOption("soundrecord", "SDL.Sound.RecordFile", "");
config->addOption("soundbufsize", "SDL.Sound.BufSize", 128);
config->addOption("lowpass", "SDL.Sound.LowPass", 0);
config->addOption('g', "gamegenie", "SDL.GameGenie", 0);
config->addOption("pal", "SDL.PAL", 0);
config->addOption("frameskip", "SDL.Frameskip", 0);
config->addOption("clipsides", "SDL.ClipSides", 0);
config->addOption("nospritelim", "SDL.DisableSpriteLimit", 1);
config->addOption("swapduty", "SDL.SwapDuty", 0);
// color control
config->addOption('p', "palette", "SDL.Palette", "");
config->addOption("tint", "SDL.Tint", 56);
config->addOption("hue", "SDL.Hue", 72);
config->addOption("ntsccolor", "SDL.NTSCpalette", 0);
// scanline settings
config->addOption("slstart", "SDL.ScanLineStart", 0);
config->addOption("slend", "SDL.ScanLineEnd", 239);
// video controls
config->addOption('f', "fullscreen", "SDL.Fullscreen", 0);
// set x/y res to 0 for automatic fullscreen resolution detection (no change)
config->addOption('x', "xres", "SDL.XResolution", 0);
config->addOption('y', "yres", "SDL.YResolution", 0);
config->addOption("SDL.LastXRes", 0);
config->addOption("SDL.LastYRes", 0);
config->addOption('b', "bpp", "SDL.BitsPerPixel", 32);
config->addOption("doublebuf", "SDL.DoubleBuffering", 0);
config->addOption("autoscale", "SDL.AutoScale", 1);
config->addOption("keepratio", "SDL.KeepRatio", 1);
config->addOption("xscale", "SDL.XScale", 1.0);
config->addOption("yscale", "SDL.YScale", 1.0);
config->addOption("xstretch", "SDL.XStretch", 0);
config->addOption("ystretch", "SDL.YStretch", 0);
config->addOption("noframe", "SDL.NoFrame", 0);
config->addOption("special", "SDL.SpecialFilter", 0);
config->addOption("showfps", "SDL.ShowFPS", 0);
config->addOption("togglemenu", "SDL.ToggleMenu", 0);
// OpenGL options
config->addOption("opengl", "SDL.OpenGL", 0);
config->addOption("openglip", "SDL.OpenGLip", 0);
config->addOption("SDL.SpecialFilter", 0);
config->addOption("SDL.SpecialFX", 0);
config->addOption("SDL.Vsync", 1);
// network play options - netplay is broken
config->addOption("server", "SDL.NetworkIsServer", 0);
config->addOption('n', "net", "SDL.NetworkIP", "");
config->addOption('u', "user", "SDL.NetworkUsername", "");
config->addOption('w', "pass", "SDL.NetworkPassword", "");
config->addOption('k', "netkey", "SDL.NetworkGameKey", "");
config->addOption("port", "SDL.NetworkPort", 4046);
config->addOption("players", "SDL.NetworkPlayers", 1);
// input configuration options
config->addOption("input1", "SDL.Input.0", "GamePad.0");
config->addOption("input2", "SDL.Input.1", "GamePad.1");
config->addOption("input3", "SDL.Input.2", "Gamepad.2");
config->addOption("input4", "SDL.Input.3", "Gamepad.3");
// allow for input configuration
config->addOption('i', "inputcfg", "SDL.InputCfg", InputCfg);
// display input
config->addOption("inputdisplay", "SDL.InputDisplay", 0);
// enable / disable opposite directionals (left + right or up + down simultaneously)
config->addOption("opposite-directionals", "SDL.Input.EnableOppositeDirectionals", 1);
// pause movie playback at frame x
config->addOption("pauseframe", "SDL.PauseFrame", 0);
config->addOption("recordhud", "SDL.RecordHUD", 1);
config->addOption("moviemsg", "SDL.MovieMsg", 1);
// overwrite the config file?
config->addOption("no-config", "SDL.NoConfig", 0);
config->addOption("autoresume", "SDL.AutoResume", 0);
// video playback
config->addOption("playmov", "SDL.Movie", "");
config->addOption("subtitles", "SDL.SubtitleDisplay", 1);
config->addOption("fourscore", "SDL.FourScore", 0);
config->addOption("nofscursor", "SDL.NoFullscreenCursor", 1);
#ifdef _S9XLUA_H
// load lua script
config->addOption("loadlua", "SDL.LuaScript", "");
#endif
#ifdef CREATE_AVI
config->addOption("videolog", "SDL.VideoLog", "");
config->addOption("mute", "SDL.MuteCapture", 0);
#endif
// auto load/save on gameload/close
config->addOption("loadstate", "SDL.AutoLoadState", INVALID_STATE);
config->addOption("savestate", "SDL.AutoSaveState", INVALID_STATE);
//TODO implement this
config->addOption("periodicsaves", "SDL.PeriodicSaves", 0);
#ifdef _GTK
char* home_dir = getenv("HOME");
// prefixed with _ because they are internal (not cli options)
config->addOption("_lastopenfile", "SDL.LastOpenFile", home_dir);
config->addOption("_laststatefrom", "SDL.LastLoadStateFrom", home_dir);
config->addOption("_lastopennsf", "SDL.LastOpenNSF", home_dir);
config->addOption("_lastsavestateas", "SDL.LastSaveStateAs", home_dir);
config->addOption("_lastloadlua", "SDL.LastLoadLua", "");
#endif
// fcm -> fm2 conversion
config->addOption("fcmconvert", "SDL.FCMConvert", "");
// fm2 -> srt conversion
config->addOption("ripsubs", "SDL.RipSubs", "");
// enable new PPU core
config->addOption("newppu", "SDL.NewPPU", 0);
// quit when a+b+select+start is pressed
config->addOption("4buttonexit", "SDL.ABStartSelectExit", 0);
// GamePad 0 - 3
for(unsigned int i = 0; i < GAMEPAD_NUM_DEVICES; i++) {
char buf[64];
snprintf(buf, 20, "SDL.Input.GamePad.%d.", i);
prefix = buf;
config->addOption(prefix + "DeviceType", DefaultGamePadDevice[i]);
config->addOption(prefix + "DeviceNum", 0);
for(unsigned int j = 0; j < GAMEPAD_NUM_BUTTONS; j++) {
config->addOption(prefix + GamePadNames[j], DefaultGamePad[i][j]);
}
}
// PowerPad 0 - 1
for(unsigned int i = 0; i < POWERPAD_NUM_DEVICES; i++) {
char buf[64];
snprintf(buf, 20, "SDL.Input.PowerPad.%d.", i);
prefix = buf;
config->addOption(prefix + "DeviceType", DefaultPowerPadDevice[i]);
config->addOption(prefix + "DeviceNum", 0);
for(unsigned int j = 0; j < POWERPAD_NUM_BUTTONS; j++) {
config->addOption(prefix +PowerPadNames[j], DefaultPowerPad[i][j]);
}
}
// QuizKing
prefix = "SDL.Input.QuizKing.";
config->addOption(prefix + "DeviceType", DefaultQuizKingDevice);
config->addOption(prefix + "DeviceNum", 0);
for(unsigned int j = 0; j < QUIZKING_NUM_BUTTONS; j++) {
config->addOption(prefix + QuizKingNames[j], DefaultQuizKing[j]);
}
// HyperShot
prefix = "SDL.Input.HyperShot.";
config->addOption(prefix + "DeviceType", DefaultHyperShotDevice);
config->addOption(prefix + "DeviceNum", 0);
for(unsigned int j = 0; j < HYPERSHOT_NUM_BUTTONS; j++) {
config->addOption(prefix + HyperShotNames[j], DefaultHyperShot[j]);
}
// Mahjong
prefix = "SDL.Input.Mahjong.";
config->addOption(prefix + "DeviceType", DefaultMahjongDevice);
config->addOption(prefix + "DeviceNum", 0);
for(unsigned int j = 0; j < MAHJONG_NUM_BUTTONS; j++) {
config->addOption(prefix + MahjongNames[j], DefaultMahjong[j]);
}
// TopRider
prefix = "SDL.Input.TopRider.";
config->addOption(prefix + "DeviceType", DefaultTopRiderDevice);
config->addOption(prefix + "DeviceNum", 0);
for(unsigned int j = 0; j < TOPRIDER_NUM_BUTTONS; j++) {
config->addOption(prefix + TopRiderNames[j], DefaultTopRider[j]);
}
// FTrainer
prefix = "SDL.Input.FTrainer.";
config->addOption(prefix + "DeviceType", DefaultFTrainerDevice);
config->addOption(prefix + "DeviceNum", 0);
for(unsigned int j = 0; j < FTRAINER_NUM_BUTTONS; j++) {
config->addOption(prefix + FTrainerNames[j], DefaultFTrainer[j]);
}
// FamilyKeyBoard
prefix = "SDL.Input.FamilyKeyBoard.";
config->addOption(prefix + "DeviceType", DefaultFamilyKeyBoardDevice);
config->addOption(prefix + "DeviceNum", 0);
for(unsigned int j = 0; j < FAMILYKEYBOARD_NUM_BUTTONS; j++) {
config->addOption(prefix + FamilyKeyBoardNames[j],
DefaultFamilyKeyBoard[j]);
}
// for FAMICOM microphone in pad 2 pad 1 didn't have it
// Takeshi no Chousenjou uses it for example.
prefix = "SDL.Input.FamicomPad2.";
config->addOption("rp2mic", prefix + "EnableMic", 0);
// TODO: use a better data structure to store the hotkeys or something
// improve this code overall in the future to make it
// easier to maintain
const int Hotkeys[HK_MAX] = {
SDLK_F1, // cheat menu
SDLK_F2, // bind state
SDLK_F3, // load lua
SDLK_F4, // toggleBG
SDLK_F5, // save state
SDLK_F6, // fds select
SDLK_F7, // load state
SDLK_F8, // fds eject
SDLK_F6, // VS insert coin
SDLK_F8, // VS toggle dipswitch
SDLK_PERIOD, // toggle frame display
SDLK_F10, // toggle subtitle
SDLK_F11, // reset
SDLK_F12, // screenshot
SDLK_PAUSE, // pause
SDLK_MINUS, // speed++
SDLK_EQUALS, // speed--
SDLK_BACKSLASH, //frame advnace
SDLK_TAB, // turbo
SDLK_COMMA, // toggle input display
SDLK_q, // toggle movie RW
SDLK_QUOTE, // toggle mute capture
0, // quit // edit 10/11/11 - don't map to escape, it causes ugly things to happen to sdl. can be manually appended to config
SDLK_DELETE, // frame advance lag skip
SDLK_SLASH, // lag counter display
SDLK_0, SDLK_1, SDLK_2, SDLK_3, SDLK_4, SDLK_5,
SDLK_6, SDLK_7, SDLK_8, SDLK_9,
SDLK_PAGEUP, // select state next
SDLK_PAGEDOWN}; // select state prev
prefix = "SDL.Hotkeys.";
for(int i=0; i < HK_MAX; i++)
config->addOption(prefix + HotkeyStrings[i], Hotkeys[i]);
// All mouse devices
config->addOption("SDL.OekaKids.0.DeviceType", "Mouse");
config->addOption("SDL.OekaKids.0.DeviceNum", 0);
config->addOption("SDL.Arkanoid.0.DeviceType", "Mouse");
config->addOption("SDL.Arkanoid.0.DeviceNum", 0);
config->addOption("SDL.Shadow.0.DeviceType", "Mouse");
config->addOption("SDL.Shadow.0.DeviceNum", 0);
config->addOption("SDL.Zapper.0.DeviceType", "Mouse");
config->addOption("SDL.Zapper.0.DeviceNum", 0);
return config;
}
void
UpdateEMUCore(Config *config)
{
int ntsccol, ntsctint, ntschue, flag, region, start, end;
std::string cpalette;
config->getOption("SDL.NTSCpalette", &ntsccol);
config->getOption("SDL.Tint", &ntsctint);
config->getOption("SDL.Hue", &ntschue);
FCEUI_SetNTSCTH(ntsccol, ntsctint, ntschue);
config->getOption("SDL.Palette", &cpalette);
if(cpalette.size()) {
LoadCPalette(cpalette);
}
config->getOption("SDL.PAL", &region);
FCEUI_SetRegion(region);
config->getOption("SDL.GameGenie", &flag);
FCEUI_SetGameGenie(flag ? 1 : 0);
config->getOption("SDL.Sound.LowPass", &flag);
FCEUI_SetLowPass(flag ? 1 : 0);
config->getOption("SDL.DisableSpriteLimit", &flag);
FCEUI_DisableSpriteLimitation(flag ? 1 : 0);
config->getOption("SDL.ScanLineStart", &start);
config->getOption("SDL.ScanLineEnd", &end);
#if DOING_SCANLINE_CHECKS
for(int i = 0; i < 2; x++) {
if(srendlinev[x]<0 || srendlinev[x]>239) srendlinev[x]=0;
if(erendlinev[x]<srendlinev[x] || erendlinev[x]>239) erendlinev[x]=239;
}
#endif
FCEUI_SetRenderedLines(start + 8, end - 8, start, end);
}

Some files were not shown because too many files have changed in this diff Show More