Merge branch 'master' of github.com:Akerasoft/fceux
This commit is contained in:
commit
26b2438365
|
@ -17,6 +17,7 @@
|
|||
/output/auxlib.lua
|
||||
/output/fceux.pdb
|
||||
/output/7z.dll
|
||||
/output/7z_64.dll
|
||||
/output/fceux.exe
|
||||
/output/fceux.exp
|
||||
/output/fceux.lib
|
||||
|
|
3
README
3
README
|
@ -7,7 +7,7 @@ Updated By mjbudd77
|
|||
|
||||
https://fceux.com
|
||||
|
||||
Last Modified: March 24, 2022
|
||||
Last Modified: April 30, 2023
|
||||
|
||||
Table of Contents
|
||||
-----------------
|
||||
|
@ -32,6 +32,7 @@ Table of Contents
|
|||
* libx265 (optional) - H.265 video encoder for avi recording (recommended)
|
||||
* ffmpeg libraries (optional) - for avi recording (recommended)
|
||||
* - ffmpeg libraries used: libavcodec libavformat libavutil libswresample libswscale
|
||||
* libarchive (optional) - for 7zip archive support (test with version 3.4.0)
|
||||
* minizip
|
||||
* zlib
|
||||
* openGL
|
||||
|
|
|
@ -61,6 +61,13 @@ echo '****************************************'
|
|||
sudo apt-get --assume-yes install libminizip-dev
|
||||
pkg-config --cflags --libs minizip
|
||||
|
||||
# Install libarchive-dev
|
||||
echo '****************************************'
|
||||
echo 'Install Dependency libarchive-dev'
|
||||
echo '****************************************'
|
||||
sudo apt-get --assume-yes install libarchive-dev
|
||||
pkg-config --cflags --libs libarchive
|
||||
|
||||
# GTK+-2 is no longer needed
|
||||
#sudo apt-get install libgtk2.0-dev
|
||||
|
||||
|
|
|
@ -70,6 +70,12 @@ echo 'Install Dependency minizip'
|
|||
echo '****************************************'
|
||||
brew install minizip
|
||||
|
||||
echo '****************************************'
|
||||
echo 'Install Optional Dependency libarchive'
|
||||
echo '****************************************'
|
||||
brew install libarchive
|
||||
LIBARCHIVE_PATH=`brew --prefix libarchive`;
|
||||
|
||||
echo '****************************************'
|
||||
echo 'Install Optional Dependency x264'
|
||||
echo '****************************************'
|
||||
|
@ -87,7 +93,7 @@ brew install ffmpeg
|
|||
|
||||
#brew install zlib # Already installed in appveyor macOS
|
||||
|
||||
export PKG_CONFIG_PATH=$PKG_CONFIG_PATH:/usr/local/lib/pkgconfig:
|
||||
export PKG_CONFIG_PATH=$PKG_CONFIG_PATH:/usr/local/lib/pkgconfig:$LIBARCHIVE_PATH:
|
||||
|
||||
ls -ltr $HOME/Qt;
|
||||
|
||||
|
|
|
@ -24,28 +24,33 @@ mkdir bin
|
|||
|
||||
set SDL_VERSION=2.24.1
|
||||
set FFMPEG_VERSION=5.1.2
|
||||
set LIBARCHIVE_VERSION=3.6.2
|
||||
|
||||
curl -s -LO https://github.com/libsdl-org/SDL/releases/download/release-%SDL_VERSION%/SDL2-devel-%SDL_VERSION%-VC.zip
|
||||
curl -s -LO https://github.com/GyanD/codexffmpeg/releases/download/%FFMPEG_VERSION%/ffmpeg-%FFMPEG_VERSION%-full_build-shared.zip
|
||||
curl -s -LO https://www.libarchive.org/downloads/libarchive-v%LIBARCHIVE_VERSION%-amd64.zip
|
||||
|
||||
REM rmdir /q /s SDL2
|
||||
|
||||
powershell -command "Expand-Archive" SDL2-devel-%SDL_VERSION%-VC.zip .
|
||||
powershell -command "Expand-Archive" ffmpeg-%FFMPEG_VERSION%-full_build-shared.zip
|
||||
powershell -command "Expand-Archive" libarchive-v%LIBARCHIVE_VERSION%-amd64.zip
|
||||
|
||||
rename SDL2-%SDL_VERSION% SDL2
|
||||
move ffmpeg-%FFMPEG_VERSION%-full_build-shared\ffmpeg-%FFMPEG_VERSION%-full_build-shared ffmpeg
|
||||
rmdir ffmpeg-%FFMPEG_VERSION%-full_build-shared
|
||||
del ffmpeg-%FFMPEG_VERSION%-full_build-shared.zip
|
||||
move libarchive-v%LIBARCHIVE_VERSION%-amd64\libarchive libarchive
|
||||
|
||||
set SDL_INSTALL_PREFIX=%CD%
|
||||
set FFMPEG_INSTALL_PREFIX=%CD%
|
||||
set LIBARCHIVE_INSTALL_PREFIX=%CD%
|
||||
set PUBLIC_RELEASE=0
|
||||
IF DEFINED FCEU_RELEASE_VERSION (set PUBLIC_RELEASE=1)
|
||||
|
||||
REM cmake -h
|
||||
REM cmake -G "NMake Makefiles" -DCMAKE_BUILD_TYPE=Release -DSDL_INSTALL_PREFIX=%SDL_INSTALL_PREFIX% ..
|
||||
cmake -DQT6=0 -DPUBLIC_RELEASE=%PUBLIC_RELEASE% -DSDL_INSTALL_PREFIX=%SDL_INSTALL_PREFIX% -DUSE_LIBAV=1 -DFFMPEG_INSTALL_PREFIX=%FFMPEG_INSTALL_PREFIX% -G"Visual Studio 16" -T"v142" ..
|
||||
cmake -DQT6=0 -DPUBLIC_RELEASE=%PUBLIC_RELEASE% -DSDL_INSTALL_PREFIX=%SDL_INSTALL_PREFIX% -DLIBARCHIVE_INSTALL_PREFIX=%LIBARCHIVE_INSTALL_PREFIX% -DUSE_LIBAV=1 -DFFMPEG_INSTALL_PREFIX=%FFMPEG_INSTALL_PREFIX% -G"Visual Studio 16" -T"v142" ..
|
||||
|
||||
REM nmake
|
||||
msbuild /m fceux.sln /p:Configuration=Release
|
||||
|
@ -53,9 +58,10 @@ if %ERRORLEVEL% NEQ 0 EXIT /B 1
|
|||
|
||||
copy src\Release\fceux.exe bin\qfceux.exe
|
||||
copy %PROJECT_ROOT%\src\auxlib.lua bin\.
|
||||
REM copy %PROJECT_ROOT%\src\drivers\win\lua\x64\lua51.dll bin\.
|
||||
REM copy %PROJECT_ROOT%\src\drivers\win\lua\x64\lua5.1.dll bin\.
|
||||
copy %PROJECT_ROOT%\src\drivers\win\lua\x64\lua51.dll bin\.
|
||||
copy %PROJECT_ROOT%\src\drivers\win\lua\x64\lua5.1.dll bin\.
|
||||
copy %SDL_INSTALL_PREFIX%\SDL2\lib\x64\SDL2.dll bin\.
|
||||
copy %LIBARCHIVE_INSTALL_PREFIX%\libarchive\bin\archive.dll bin\.
|
||||
copy %FFMPEG_INSTALL_PREFIX%\ffmpeg\bin\*.dll bin\.
|
||||
|
||||
windeployqt --no-compiler-runtime bin\qfceux.exe
|
||||
|
|
|
@ -22,6 +22,12 @@ if ( ${QHELP} )
|
|||
add_definitions( -D_USE_QHELP )
|
||||
endif()
|
||||
|
||||
if ( ${FCEU_PROFILER_ENABLE} )
|
||||
message( STATUS "FCEU Profiler Enabled")
|
||||
add_definitions( -D__FCEU_PROFILER_ENABLE__ )
|
||||
endif()
|
||||
|
||||
|
||||
if ( ${QT6} )
|
||||
find_package( Qt6 REQUIRED COMPONENTS Widgets OpenGL OpenGLWidgets ${QtHelpModule})
|
||||
add_definitions( ${Qt6Widgets_DEFINITIONS} ${Qt6Help_DEFINITIONS} ${Qt6OpenGLWidgets_DEFINITIONS} )
|
||||
|
@ -41,12 +47,15 @@ if(WIN32)
|
|||
add_definitions( -DMSVC -D_CRT_SECURE_NO_WARNINGS )
|
||||
add_definitions( -D__SDL__ -D__QT_DRIVER__ -DQT_DEPRECATED_WARNINGS )
|
||||
add_definitions( -DFCEUDEF_DEBUGGER )
|
||||
add_definitions( -D_USE_LIBARCHIVE )
|
||||
add_definitions( /wd4267 /wd4244 )
|
||||
#add_definitions( /wd4018 ) # Integer comparison sign mismatch warnings
|
||||
include_directories( ${SDL_INSTALL_PREFIX}/SDL2/include )
|
||||
include_directories( ${LIBARCHIVE_INSTALL_PREFIX}/libarchive/include )
|
||||
include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/drivers/win/zlib )
|
||||
set( OPENGL_LDFLAGS OpenGL::GL )
|
||||
set( SDL2_LDFLAGS ${SDL_INSTALL_PREFIX}/SDL2/lib/x64/SDL2.lib )
|
||||
set( LIBARCHIVE_LDFLAGS ${LIBARCHIVE_INSTALL_PREFIX}/libarchive/lib/archive.lib )
|
||||
set( SYS_LIBS wsock32 ws2_32 vfw32 Htmlhelp )
|
||||
set(APP_ICON_RESOURCES_WINDOWS ${CMAKE_SOURCE_DIR}/icons/fceux.rc )
|
||||
|
||||
|
@ -93,6 +102,12 @@ else(WIN32)
|
|||
#endif()
|
||||
add_definitions( -D__QT_DRIVER__ -DQT_DEPRECATED_WARNINGS )
|
||||
|
||||
if ( ${GPROF_ENABLE} )
|
||||
add_definitions( -pg )
|
||||
set( GPROF_LDFLAGS -pg )
|
||||
message( STATUS "GNU Profiling Enabled" )
|
||||
endif()
|
||||
|
||||
if ( ${ASAN_ENABLE} )
|
||||
add_definitions( -fsanitize=address -fsanitize=bounds-strict )
|
||||
add_definitions( -fsanitize=undefined -fno-sanitize=vptr )
|
||||
|
@ -110,6 +125,13 @@ else(WIN32)
|
|||
add_definitions( -D_SYSTEM_MINIZIP ${MINIZIP_CFLAGS} )
|
||||
endif()
|
||||
|
||||
pkg_check_modules( LIBARCHIVE libarchive)
|
||||
|
||||
if ( ${LIBARCHIVE_FOUND} )
|
||||
message( STATUS "Using System Libarchive Library ${LIBARCHIVE_VERSION}" )
|
||||
add_definitions( -D_USE_LIBARCHIVE ${LIBARCHIVE_CFLAGS} )
|
||||
endif()
|
||||
|
||||
pkg_check_modules( X264 x264)
|
||||
|
||||
if ( ${X264_FOUND} )
|
||||
|
@ -293,6 +315,7 @@ set(SRC_CORE
|
|||
${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
|
||||
|
@ -504,6 +527,7 @@ set(SRC_CORE
|
|||
${CMAKE_CURRENT_SOURCE_DIR}/utils/md5.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/utils/memory.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/utils/mutex.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/utils/timeStamp.cpp
|
||||
)
|
||||
|
||||
|
||||
|
@ -526,6 +550,8 @@ set(SRC_DRIVERS_SDL
|
|||
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/ConsoleWindow.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/ConsoleViewerGL.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/ConsoleViewerSDL.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/ConsoleViewerQWidget.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/ConsoleViewerInterface.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/InputConf.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/GamePadConf.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/FamilyKeyboard.cpp
|
||||
|
@ -551,6 +577,7 @@ set(SRC_DRIVERS_SDL
|
|||
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/ConsoleUtilities.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/ConsoleVideoConf.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/ConsoleSoundConf.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/StateRecorderConf.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/iNesHeaderEditor.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/SplashScreen.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/TraceLogger.cpp
|
||||
|
@ -635,14 +662,15 @@ add_executable( ${APP_NAME} ${SOURCES} ../resources.qrc
|
|||
${CMAKE_CURRENT_BINARY_DIR}/fceux_git_info.cpp)
|
||||
endif()
|
||||
|
||||
target_link_libraries( ${APP_NAME} ${ASAN_LDFLAGS}
|
||||
target_link_libraries( ${APP_NAME}
|
||||
${ASAN_LDFLAGS} ${GPROF_LDFLAGS}
|
||||
${${Qt}Widgets_LIBRARIES}
|
||||
${${Qt}Help_LIBRARIES}
|
||||
${${Qt}OpenGL_LIBRARIES}
|
||||
${${Qt}OpenGLWidgets_LIBRARIES}
|
||||
${OPENGL_LDFLAGS}
|
||||
${SDL2_LDFLAGS}
|
||||
${MINIZIP_LDFLAGS} ${ZLIB_LIBRARIES}
|
||||
${MINIZIP_LDFLAGS} ${ZLIB_LIBRARIES} ${LIBARCHIVE_LDFLAGS}
|
||||
${LUA_LDFLAGS} ${X264_LDFLAGS} ${X265_LDFLAGS} ${LIBAV_LDFLAGS}
|
||||
${SYS_LIBS}
|
||||
)
|
||||
|
|
|
@ -27,6 +27,7 @@ static void (*WSync)(void);
|
|||
static readfunc defread;
|
||||
static uint8 *WRAM = NULL;
|
||||
static uint32 WRAMSIZE=0;
|
||||
static uint8 hasBattery = 0;
|
||||
|
||||
static DECLFW(LatchWrite) {
|
||||
latche = A;
|
||||
|
@ -220,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) {
|
||||
|
@ -341,20 +359,17 @@ void Mapper217_Init(CartInfo *info) {
|
|||
}
|
||||
|
||||
//------------------ Map 227 ---------------------------
|
||||
|
||||
static void M227Sync(void) {
|
||||
uint32 S = latche & 1;
|
||||
uint32 p = ((latche >> 2) & 0x1F) + ((latche & 0x100) >> 3);
|
||||
uint32 L = (latche >> 9) & 1;
|
||||
|
||||
// ok, according to nesdev wiki (refrenced to the nesdev dumping thread) there is a CHR write protection bit7.
|
||||
// however, this bit clearly determined a specific PRG layout for some game but does not meant to have additional
|
||||
// functionality. as I see from the menu code, it disables the chr writing before run an actual game.
|
||||
// this fix here makes happy both waixing rpgs and multigame menus at once. can't veryfy it on a hardware
|
||||
// but if I find some i'll definitly do this.
|
||||
|
||||
if ((latche & 0xF000) == 0xF000)
|
||||
SetupCartCHRMapping(0, CHRptr[0], 0x2000, 0);
|
||||
// Only Waixing appear to have battery flag enabled, while multicarts don't.
|
||||
// Multicarts needs CHR-RAM protect in NROM modes, so only apply CHR-RAM protect
|
||||
// on non battery-enabled carts.
|
||||
if (!hasBattery && (latche & 0x80) == 0x80)
|
||||
/* CHR-RAM write protect hack, needed for some multicarts */
|
||||
SetupCartCHRMapping(0, CHRptr[0], 0x2000, 0);
|
||||
else
|
||||
SetupCartCHRMapping(0, CHRptr[0], 0x2000, 1);
|
||||
|
||||
|
@ -392,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 ---------------------------
|
||||
|
|
|
@ -16,11 +16,11 @@
|
|||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Very complicated homebrew multicart mapper with.
|
||||
* The code is so obscured and weird because it's ported from Verilog CPLD source code:
|
||||
*
|
||||
* Very complicated homebrew multicart mapper with.
|
||||
* The code is so obscured and weird because it's ported from Verilog CPLD source code:
|
||||
* https://github.com/ClusterM/coolgirl-famicom-multicart/blob/master/CoolGirl_mappers.vh
|
||||
*
|
||||
*
|
||||
* Range: $5000-$5FFF
|
||||
*
|
||||
* Mask: $5007
|
||||
|
@ -103,14 +103,12 @@ const uint32 FLASH_SECTOR_SIZE = 128 * 1024;
|
|||
const int ROM_CHIP = 0x00;
|
||||
const int WRAM_CHIP = 0x10;
|
||||
const int FLASH_CHIP = 0x11;
|
||||
const int CHR_RAM_CHIP = 0x12;
|
||||
const int CFI_CHIP = 0x13;
|
||||
|
||||
static int CHR_SIZE = 0;
|
||||
static uint32 WRAM_SIZE = 0;
|
||||
static uint8 *WRAM = NULL;
|
||||
static uint32 CHR_RAM_SIZE = 0;
|
||||
static uint8 *CHR_RAM;
|
||||
static uint8 *SAVE_FLASH = NULL;
|
||||
static uint8* WRAM = NULL;
|
||||
static uint8* SAVE_FLASH = NULL;
|
||||
static uint8* CFI;
|
||||
|
||||
static uint8 sram_enabled = 0;
|
||||
|
@ -388,75 +386,75 @@ static void COOLGIRL_Sync_CHR(void) {
|
|||
int chr_shift_left = 0;
|
||||
|
||||
// enable or disable writes to CHR RAM, setup CHR mask
|
||||
SetupCartCHRMapping(CHR_RAM_CHIP, CHR_RAM, ((((~(chr_mask >> 13) & 0x3F) + 1) * 0x2000 - 1) & (CHR_RAM_SIZE - 1)) + 1, can_write_chr);
|
||||
SetupCartCHRMapping(0, UNIFchrrama, ((((~(chr_mask >> 13) & 0x3F) + 1) * 0x2000 - 1) & (CHR_SIZE - 1)) + 1, can_write_chr);
|
||||
|
||||
switch (chr_mode & 7)
|
||||
{
|
||||
default:
|
||||
case 0:
|
||||
setchr8r(0x12, chr_bank_a >> 3 >> chr_shift_right << chr_shift_left);
|
||||
setchr8(chr_bank_a >> 3 >> chr_shift_right << chr_shift_left);
|
||||
break;
|
||||
case 1:
|
||||
setchr4r(0x12, 0x0000, mapper_163_latch >> chr_shift_right << chr_shift_left);
|
||||
setchr4r(0x12, 0x1000, mapper_163_latch >> chr_shift_right << chr_shift_left);
|
||||
setchr4(0x0000, mapper_163_latch >> chr_shift_right << chr_shift_left);
|
||||
setchr4(0x1000, mapper_163_latch >> chr_shift_right << chr_shift_left);
|
||||
break;
|
||||
case 2:
|
||||
setchr2r(0x12, 0x0000, chr_bank_a >> 1 >> chr_shift_right << chr_shift_left);
|
||||
setchr2(0x0000, chr_bank_a >> 1 >> chr_shift_right << chr_shift_left);
|
||||
TKSMIR[0] = TKSMIR[1] = chr_bank_a;
|
||||
setchr2r(0x12, 0x0800, chr_bank_c >> 1 >> chr_shift_right << chr_shift_left);
|
||||
setchr2(0x0800, chr_bank_c >> 1 >> chr_shift_right << chr_shift_left);
|
||||
TKSMIR[2] = TKSMIR[3] = chr_bank_c;
|
||||
setchr1r(0x12, 0x1000, chr_bank_e >> chr_shift_right << chr_shift_left);
|
||||
setchr1(0x1000, chr_bank_e >> chr_shift_right << chr_shift_left);
|
||||
TKSMIR[4] = chr_bank_e;
|
||||
setchr1r(0x12, 0x1400, chr_bank_f >> chr_shift_right << chr_shift_left);
|
||||
setchr1(0x1400, chr_bank_f >> chr_shift_right << chr_shift_left);
|
||||
TKSMIR[5] = chr_bank_f;
|
||||
setchr1r(0x12, 0x1800, chr_bank_g >> chr_shift_right << chr_shift_left);
|
||||
setchr1(0x1800, chr_bank_g >> chr_shift_right << chr_shift_left);
|
||||
TKSMIR[6] = chr_bank_g;
|
||||
setchr1r(0x12, 0x1C00, chr_bank_h >> chr_shift_right << chr_shift_left);
|
||||
setchr1(0x1C00, chr_bank_h >> chr_shift_right << chr_shift_left);
|
||||
TKSMIR[7] = chr_bank_h;
|
||||
break;
|
||||
case 3:
|
||||
setchr1r(0x12, 0x0000, chr_bank_e >> chr_shift_right << chr_shift_left);
|
||||
setchr1(0x0000, chr_bank_e >> chr_shift_right << chr_shift_left);
|
||||
TKSMIR[0] = chr_bank_e;
|
||||
setchr1r(0x12, 0x0400, chr_bank_f >> chr_shift_right << chr_shift_left);
|
||||
setchr1(0x0400, chr_bank_f >> chr_shift_right << chr_shift_left);
|
||||
TKSMIR[1] = chr_bank_f;
|
||||
setchr1r(0x12, 0x0800, chr_bank_g >> chr_shift_right << chr_shift_left);
|
||||
setchr1(0x0800, chr_bank_g >> chr_shift_right << chr_shift_left);
|
||||
TKSMIR[2] = chr_bank_g;
|
||||
setchr1r(0x12, 0x0C00, chr_bank_h >> chr_shift_right << chr_shift_left);
|
||||
setchr1(0x0C00, chr_bank_h >> chr_shift_right << chr_shift_left);
|
||||
TKSMIR[3] = chr_bank_h;
|
||||
setchr2r(0x12, 0x1000, chr_bank_a >> 1 >> chr_shift_right << chr_shift_left);
|
||||
setchr2(0x1000, chr_bank_a >> 1 >> chr_shift_right << chr_shift_left);
|
||||
TKSMIR[4] = TKSMIR[5] = chr_bank_a;
|
||||
setchr2r(0x12, 0x1800, chr_bank_c >> 1 >> chr_shift_right << chr_shift_left);
|
||||
setchr2(0x1800, chr_bank_c >> 1 >> chr_shift_right << chr_shift_left);
|
||||
TKSMIR[6] = TKSMIR[7] = chr_bank_c;
|
||||
break;
|
||||
case 4:
|
||||
setchr4r(0x12, 0x0000, chr_bank_a >> 2 >> chr_shift_right << chr_shift_left);
|
||||
setchr4r(0x12, 0x1000, chr_bank_e >> 2 >> chr_shift_right << chr_shift_left);
|
||||
setchr4(0x0000, chr_bank_a >> 2 >> chr_shift_right << chr_shift_left);
|
||||
setchr4(0x1000, chr_bank_e >> 2 >> chr_shift_right << chr_shift_left);
|
||||
break;
|
||||
case 5:
|
||||
if (!ppu_latch0)
|
||||
setchr4r(0x12, 0x0000, chr_bank_a >> 2 >> chr_shift_right << chr_shift_left);
|
||||
setchr4(0x0000, chr_bank_a >> 2 >> chr_shift_right << chr_shift_left);
|
||||
else
|
||||
setchr4r(0x12, 0x0000, chr_bank_b >> 2 >> chr_shift_right << chr_shift_left);
|
||||
setchr4(0x0000, chr_bank_b >> 2 >> chr_shift_right << chr_shift_left);
|
||||
if (!ppu_latch1)
|
||||
setchr4r(0x12, 0x1000, chr_bank_e >> 2 >> chr_shift_right << chr_shift_left);
|
||||
setchr4(0x1000, chr_bank_e >> 2 >> chr_shift_right << chr_shift_left);
|
||||
else
|
||||
setchr4r(0x12, 0x1000, chr_bank_f >> 2 >> chr_shift_right << chr_shift_left);
|
||||
setchr4(0x1000, chr_bank_f >> 2 >> chr_shift_right << chr_shift_left);
|
||||
break;
|
||||
case 6:
|
||||
setchr2r(0x12, 0x0000, chr_bank_a >> 1 >> chr_shift_right << chr_shift_left);
|
||||
setchr2r(0x12, 0x0800, chr_bank_c >> 1 >> chr_shift_right << chr_shift_left);
|
||||
setchr2r(0x12, 0x1000, chr_bank_e >> 1 >> chr_shift_right << chr_shift_left);
|
||||
setchr2r(0x12, 0x1800, chr_bank_g >> 1 >> chr_shift_right << chr_shift_left);
|
||||
setchr2(0x0000, chr_bank_a >> 1 >> chr_shift_right << chr_shift_left);
|
||||
setchr2(0x0800, chr_bank_c >> 1 >> chr_shift_right << chr_shift_left);
|
||||
setchr2(0x1000, chr_bank_e >> 1 >> chr_shift_right << chr_shift_left);
|
||||
setchr2(0x1800, chr_bank_g >> 1 >> chr_shift_right << chr_shift_left);
|
||||
break;
|
||||
case 7:
|
||||
setchr1r(0x12, 0x0000, chr_bank_a >> chr_shift_right << chr_shift_left);
|
||||
setchr1r(0x12, 0x0400, chr_bank_b >> chr_shift_right << chr_shift_left);
|
||||
setchr1r(0x12, 0x0800, chr_bank_c >> chr_shift_right << chr_shift_left);
|
||||
setchr1r(0x12, 0x0C00, chr_bank_d >> chr_shift_right << chr_shift_left);
|
||||
setchr1r(0x12, 0x1000, chr_bank_e >> chr_shift_right << chr_shift_left);
|
||||
setchr1r(0x12, 0x1400, chr_bank_f >> chr_shift_right << chr_shift_left);
|
||||
setchr1r(0x12, 0x1800, chr_bank_g >> chr_shift_right << chr_shift_left);
|
||||
setchr1r(0x12, 0x1C00, chr_bank_h >> chr_shift_right << chr_shift_left);
|
||||
setchr1(0x0000, chr_bank_a >> chr_shift_right << chr_shift_left);
|
||||
setchr1(0x0400, chr_bank_b >> chr_shift_right << chr_shift_left);
|
||||
setchr1(0x0800, chr_bank_c >> chr_shift_right << chr_shift_left);
|
||||
setchr1(0x0C00, chr_bank_d >> chr_shift_right << chr_shift_left);
|
||||
setchr1(0x1000, chr_bank_e >> chr_shift_right << chr_shift_left);
|
||||
setchr1(0x1400, chr_bank_f >> chr_shift_right << chr_shift_left);
|
||||
setchr1(0x1800, chr_bank_g >> chr_shift_right << chr_shift_left);
|
||||
setchr1(0x1C00, chr_bank_h >> chr_shift_right << chr_shift_left);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -468,10 +466,10 @@ static void COOLGIRL_Sync_Mirroring(void) {
|
|||
setmirror((mirroring < 2) ? (mirroring ^ 1) : mirroring);
|
||||
}
|
||||
else { // four screen mode
|
||||
vnapage[0] = CHR_RAM + 0x3F000;
|
||||
vnapage[1] = CHR_RAM + 0x3F400;
|
||||
vnapage[2] = CHR_RAM + 0x3F800;
|
||||
vnapage[3] = CHR_RAM + 0x3FC00;
|
||||
vnapage[0] = UNIFchrrama + 0x3F000;
|
||||
vnapage[1] = UNIFchrrama + 0x3F400;
|
||||
vnapage[2] = UNIFchrrama + 0x3F800;
|
||||
vnapage[3] = UNIFchrrama + 0x3FC00;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -509,9 +507,8 @@ static DECLFW(COOLGIRL_Flash_Write) {
|
|||
uint32 sector_address = sector * FLASH_SECTOR_SIZE;
|
||||
for (uint32 i = sector_address; i < sector_address + FLASH_SECTOR_SIZE; i++)
|
||||
SAVE_FLASH[i % SAVE_FLASH_SIZE] = 0xFF;
|
||||
FCEU_printf("Flash sector #%d is erased: 0x%08x - 0x%08x.\n", sector, sector_address, sector_address + FLASH_SECTOR_SIZE - 1);
|
||||
flash_state = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// write byte
|
||||
if ((flash_state == 4) &&
|
||||
|
@ -557,7 +554,6 @@ static DECLFW(COOLGIRL_WRITE) {
|
|||
|
||||
if (A >= 0x5000 && A < 0x6000 && !lockout)
|
||||
{
|
||||
//FCEU_printf("Write: %02x => %04x\n", V, A);
|
||||
switch (A & 7)
|
||||
{
|
||||
case 0:
|
||||
|
@ -573,7 +569,6 @@ static DECLFW(COOLGIRL_WRITE) {
|
|||
// {chr_mask[18], prg_mask[20:14]} = cpu_data_in[7:0];
|
||||
SET_BITS(chr_mask, "18", V, "7");
|
||||
SET_BITS(prg_mask, "20:14", V, "6:0");
|
||||
//FCEU_printf("REG_prg_mask: %02x\n", REG_prg_mask);
|
||||
break;
|
||||
case 3:
|
||||
// {prg_mode[2:0], chr_bank_a[7:3]} = cpu_data_in[7:0];
|
||||
|
@ -886,7 +881,7 @@ static DECLFW(COOLGIRL_WRITE) {
|
|||
if (mapper == 0b000100)
|
||||
{
|
||||
// prg_bank_a[5:1] = cpu_data_in[4:0];
|
||||
SET_BITS(chr_bank_a, "5:1", V, "4:0");
|
||||
SET_BITS(prg_bank_a, "5:1", V, "4:0");
|
||||
// mirroring = { 1'b0, ~cpu_data_in[7]};
|
||||
mirroring = get_bits(V, "7") ^ 1;
|
||||
}
|
||||
|
@ -1176,7 +1171,6 @@ static DECLFW(COOLGIRL_WRITE) {
|
|||
|
||||
// Mapper #1 - MMC1
|
||||
/*
|
||||
r0 - load register
|
||||
flag0 - 16KB of SRAM (SOROM)
|
||||
*/
|
||||
if (mapper == 0b010000)
|
||||
|
@ -1230,7 +1224,7 @@ static DECLFW(COOLGIRL_WRITE) {
|
|||
SET_BITS(chr_bank_e, "6:2", mmc1_load_register, "5:1");
|
||||
break;
|
||||
case 0b11: // 2'b11
|
||||
// prg_bank_a[4:1] = r0[4:1];
|
||||
// prg_bank_a[4:1] = mmc1_load_register[4:1];
|
||||
SET_BITS(prg_bank_a, "4:1", mmc1_load_register, "4:1");
|
||||
// sram_enabled = ~mmc1_load_register[5];
|
||||
sram_enabled = get_bits(mmc1_load_register, "5") ^ 1;
|
||||
|
@ -1397,9 +1391,6 @@ static DECLFW(COOLGIRL_WRITE) {
|
|||
}
|
||||
|
||||
// Mapper #112
|
||||
/*
|
||||
r0[2:0] - internal register
|
||||
*/
|
||||
if (mapper == 0b010101)
|
||||
{
|
||||
switch (get_bits(A, "14:13"))
|
||||
|
@ -1464,6 +1455,7 @@ static DECLFW(COOLGIRL_WRITE) {
|
|||
case 0b1100: // 4'b1100: if (flags[0]) mirroring = {1'b0, cpu_data_in[6]}; // $E000, mirroring, for mapper #48
|
||||
if (flags & 1) // 48
|
||||
mirroring = get_bits(V, "6"); // mirroring = cpu_data_in[6];
|
||||
break;
|
||||
case 0b1000: // 4'b1000: irq_scanline_latch = ~cpu_data_in; // $C000, IRQ latch
|
||||
mmc3_irq_latch = set_bits(mmc3_irq_latch, "7:0", get_bits(V, "7:0") ^ 0b11111111);
|
||||
break;
|
||||
|
@ -1813,7 +1805,7 @@ static DECLFW(COOLGIRL_WRITE) {
|
|||
SET_BITS(chr_bank_c, "8:1", V, "7:0"); break; // 3'b001: chr_bank_c[8:1] <= cpu_data_in[7:0];
|
||||
case 0b110:
|
||||
SET_BITS(chr_bank_e, "8:1", V, "7:0"); break; // 3'b110: chr_bank_e[8:1] <= cpu_data_in[7:0];
|
||||
case 0b111:
|
||||
case 0b111:
|
||||
SET_BITS(chr_bank_g, "8:1", V, "7:0"); break; // 3'b111: chr_bank_g[8:1] <= cpu_data_in[7:0];
|
||||
}
|
||||
}
|
||||
|
@ -1963,32 +1955,19 @@ static void COOLGIRL_CpuCounter(int a) {
|
|||
// Mapper #23 - VRC4
|
||||
if (vrc4_irq_control & 2) // if (ENABLE_MAPPER_021_022_023_025 & ENABLE_VRC4_INTERRUPTS & (vrc4_irq_control[1]))
|
||||
{
|
||||
// Cycle mode without prescaler is not used by any games? It's missed in fceux source code.
|
||||
if (vrc4_irq_control & 4) // if (vrc4_irq_control[2]) // cycle mode
|
||||
vrc4_irq_prescaler++; // vrc4_irq_prescaler = vrc4_irq_prescaler + 1'b1; // count prescaler
|
||||
// if ((vrc4_irq_prescaler_counter[1] == 0 && vrc4_irq_prescaler == 114)
|
||||
// || (vrc4_irq_prescaler_counter[1] == 1 && vrc4_irq_prescaler == 113)) // 114, 114, 113
|
||||
if ((!(vrc4_irq_prescaler_counter & 2) && vrc4_irq_prescaler == 114) || ((vrc4_irq_prescaler_counter & 2) && vrc4_irq_prescaler == 113))
|
||||
{
|
||||
FCEU_PrintError("Cycle IRQ mode is not supported, please report to Cluster");
|
||||
vrc4_irq_value++; // {carry, vrc4_irq_value[7:0]} = vrc4_irq_value[7:0] + 1'b1; // just count IRQ value
|
||||
if (vrc4_irq_value == 0) // if (carry)
|
||||
vrc4_irq_prescaler = 0; // vrc4_irq_prescaler = 0;
|
||||
vrc4_irq_prescaler_counter++; // vrc4_irq_prescaler_counter = vrc4_irq_prescaler_counter + 1'b1;
|
||||
if (vrc4_irq_prescaler_counter == 0b11) vrc4_irq_prescaler_counter = 0; // if (vrc4_irq_prescaler_counter == 2'b11) vrc4_irq_prescaler_counter = 2'b00;
|
||||
vrc4_irq_value++; // {carry, vrc4_irq_value[7:0]} = vrc4_irq_value[7:0] + 1'b1;
|
||||
if (vrc4_irq_value == 0) // f (carry)
|
||||
{
|
||||
X6502_IRQBegin(FCEU_IQEXT); // vrc4_irq_out = 1;
|
||||
vrc4_irq_value = vrc4_irq_latch; // vrc4_irq_value[7:0] = vrc4_irq_latch[7:0];
|
||||
}
|
||||
}
|
||||
else {
|
||||
vrc4_irq_prescaler++; // vrc4_irq_prescaler = vrc4_irq_prescaler + 1'b1; // count prescaler
|
||||
// if ((vrc4_irq_prescaler_counter[1] == 0 && vrc4_irq_prescaler == 114)
|
||||
// || (vrc4_irq_prescaler_counter[1] == 1 && vrc4_irq_prescaler == 113)) // 114, 114, 113
|
||||
if ((!(vrc4_irq_prescaler_counter & 2) && vrc4_irq_prescaler == 114) || ((vrc4_irq_prescaler_counter & 2) && vrc4_irq_prescaler == 113))
|
||||
{
|
||||
vrc4_irq_prescaler = 0; // vrc4_irq_prescaler = 0;
|
||||
vrc4_irq_prescaler_counter++; // vrc4_irq_prescaler_counter = vrc4_irq_prescaler_counter + 1'b1;
|
||||
if (vrc4_irq_prescaler_counter == 0b11) vrc4_irq_prescaler_counter = 0; // if (vrc4_irq_prescaler_counter == 2'b11) vrc4_irq_prescaler_counter = 2'b00;
|
||||
vrc4_irq_value++; // {carry, vrc4_irq_value[7:0]} = vrc4_irq_value[7:0] + 1'b1;
|
||||
if (vrc4_irq_value == 0) // f (carry)
|
||||
{
|
||||
X6502_IRQBegin(FCEU_IQEXT);
|
||||
vrc4_irq_value = vrc4_irq_latch; // irq_cpu_value[7:0] = vrc4_irq_latch[7:0];
|
||||
}
|
||||
X6502_IRQBegin(FCEU_IQEXT);
|
||||
vrc4_irq_value = vrc4_irq_latch; // irq_cpu_value[7:0] = vrc4_irq_latch[7:0];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2238,15 +2217,13 @@ static void COOLGIRL_Power(void) {
|
|||
}
|
||||
|
||||
static void COOLGIRL_Close(void) {
|
||||
if (CHR_RAM)
|
||||
FCEU_gfree(CHR_RAM);
|
||||
if (WRAM)
|
||||
FCEU_gfree(WRAM);
|
||||
if (SAVE_FLASH)
|
||||
FCEU_gfree(SAVE_FLASH);
|
||||
if (CFI)
|
||||
FCEU_gfree(CFI);
|
||||
CHR_RAM = WRAM = SAVE_FLASH = CFI = NULL;
|
||||
WRAM = SAVE_FLASH = CFI = NULL;
|
||||
}
|
||||
|
||||
static void COOLGIRL_Restore(int version) {
|
||||
|
@ -2256,12 +2233,8 @@ static void COOLGIRL_Restore(int version) {
|
|||
|
||||
#define ExState(var, varname) AddExState(&var, sizeof(var), 0, varname)
|
||||
|
||||
void COOLGIRL_Init(CartInfo *info) {
|
||||
CHR_RAM_SIZE = info->ines2 ? (info->vram_size + info->battery_vram_size) : (512 * 1024);
|
||||
CHR_RAM = (uint8*)FCEU_gmalloc(CHR_RAM_SIZE);
|
||||
memset(CHR_RAM, 0, CHR_RAM_SIZE);
|
||||
SetupCartCHRMapping(CHR_RAM_CHIP, CHR_RAM, CHR_RAM_SIZE, 0);
|
||||
AddExState(CHR_RAM, sizeof(CHR_RAM_SIZE), 0, "CHR_");
|
||||
void COOLGIRL_Init(CartInfo* info) {
|
||||
CHR_SIZE = info->vram_size ? info->vram_size /* NES 2.0 */ : 256 * 1024 /* UNIF, fixed */;
|
||||
|
||||
WRAM_SIZE = info->ines2 ? (info->wram_size + info->battery_wram_size) : (32 * 1024);
|
||||
if (WRAM_SIZE > 0) {
|
||||
|
@ -2271,7 +2244,7 @@ void COOLGIRL_Init(CartInfo *info) {
|
|||
AddExState(WRAM, 32 * 1024, 0, "SRAM");
|
||||
if (info->battery)
|
||||
{
|
||||
info->addSaveGameBuf( WRAM, 32 * 1024);
|
||||
info->addSaveGameBuf(WRAM, 32 * 1024);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2280,7 +2253,7 @@ void COOLGIRL_Init(CartInfo *info) {
|
|||
SAVE_FLASH = (uint8*)FCEU_gmalloc(SAVE_FLASH_SIZE);
|
||||
SetupCartPRGMapping(FLASH_CHIP, SAVE_FLASH, SAVE_FLASH_SIZE, 1);
|
||||
AddExState(SAVE_FLASH, SAVE_FLASH_SIZE, 0, "SAVF");
|
||||
info->addSaveGameBuf( SAVE_FLASH, SAVE_FLASH_SIZE );
|
||||
info->addSaveGameBuf(SAVE_FLASH, SAVE_FLASH_SIZE);
|
||||
}
|
||||
|
||||
CFI = (uint8*)FCEU_gmalloc(sizeof(cfi_data) * 2);
|
||||
|
|
|
@ -26,6 +26,7 @@ static uint16 addrreg0=0, addrreg1=0;
|
|||
static uint8 *WRAM = NULL;
|
||||
static uint32 WRAMSIZE=0;
|
||||
static void (*WSync)(void) = nullptr;
|
||||
static uint8 submapper;
|
||||
|
||||
static DECLFW(LatchWrite) {
|
||||
// FCEU_printf("bs %04x %02x\n",A,V);
|
||||
|
@ -68,6 +69,7 @@ static void Latch_Init(CartInfo *info, void (*proc)(void), uint8 init, uint16 ad
|
|||
info->Power = LatchPower;
|
||||
info->Close = LatchClose;
|
||||
GameStateRestore = StateRestore;
|
||||
submapper = info->submapper;
|
||||
if(info->ines2)
|
||||
if(info->battery_wram_size + info->wram_size > 0)
|
||||
wram = 1;
|
||||
|
@ -295,7 +297,11 @@ static void M78Sync() {
|
|||
setprg16(0x8000, (latche & 7));
|
||||
setprg16(0xc000, ~0);
|
||||
setchr8(latche >> 4);
|
||||
setmirror(MI_0 + ((latche >> 3) & 1));
|
||||
if (submapper == 3) {
|
||||
setmirror((latche >> 3) & 1);
|
||||
} else {
|
||||
setmirror(MI_0 + ((latche >> 3) & 1));
|
||||
}
|
||||
}
|
||||
|
||||
void Mapper78_Init(CartInfo *info) {
|
||||
|
|
|
@ -1136,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;
|
||||
|
@ -1159,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);
|
||||
|
@ -1168,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");
|
||||
}
|
||||
|
||||
|
|
|
@ -52,17 +52,17 @@
|
|||
#include <cctype>
|
||||
|
||||
uint16 debugLastAddress = 0; // used by 'T' and 'R' conditions
|
||||
uint8 debugLastOpcode; // used to evaluate 'W' condition
|
||||
uint8 debugLastOpcode = 0; // used to evaluate 'W' condition
|
||||
|
||||
// Next non-whitespace character in string
|
||||
char next;
|
||||
static char next = 0;
|
||||
|
||||
int ishex(char c)
|
||||
static int ishex(char c)
|
||||
{
|
||||
return isdigit(c) || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F');
|
||||
}
|
||||
|
||||
void scan(const char** str)
|
||||
static void scan(const char** str)
|
||||
{
|
||||
do
|
||||
{
|
||||
|
@ -71,40 +71,37 @@ void scan(const char** str)
|
|||
} while (isspace(next));
|
||||
}
|
||||
|
||||
// Frees a condition and all of it's sub conditions
|
||||
void freeTree(Condition* c)
|
||||
{
|
||||
if (c->lhs) freeTree(c->lhs);
|
||||
if (c->rhs) freeTree(c->rhs);
|
||||
|
||||
free(c);
|
||||
}
|
||||
|
||||
// Generic function to handle all infix operators but the last one in the precedence hierarchy. : '(' E ')'
|
||||
Condition* InfixOperator(const char** str, Condition(*nextPart(const char**)), int(*operators)(const char**))
|
||||
static Condition* InfixOperator(const char** str, Condition(*nextPart(const char**)), int(*operators)(const char**))
|
||||
{
|
||||
Condition* t = nextPart(str);
|
||||
Condition* t1;
|
||||
Condition* mid;
|
||||
int op;
|
||||
|
||||
if (t == nullptr)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
while ((op = operators(str)))
|
||||
{
|
||||
scan(str);
|
||||
|
||||
t1 = nextPart(str);
|
||||
|
||||
if (t1 == 0)
|
||||
if (t1 == nullptr)
|
||||
{
|
||||
if(t)
|
||||
freeTree(t);
|
||||
delete t;
|
||||
return 0;
|
||||
}
|
||||
|
||||
mid = (Condition*)FCEU_dmalloc(sizeof(Condition));
|
||||
if (!mid)
|
||||
return NULL;
|
||||
memset(mid, 0, sizeof(Condition));
|
||||
mid = new Condition();
|
||||
if (mid == nullptr)
|
||||
{
|
||||
delete t;
|
||||
delete t1;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
mid->lhs = t;
|
||||
mid->rhs = t1;
|
||||
|
@ -117,7 +114,7 @@ Condition* InfixOperator(const char** str, Condition(*nextPart(const char**)), i
|
|||
}
|
||||
|
||||
// Generic handler for two-character operators
|
||||
int TwoCharOperator(const char** str, char c1, char c2, int op)
|
||||
static int TwoCharOperator(const char** str, char c1, char c2, int op)
|
||||
{
|
||||
if (next == c1 && **str == c2)
|
||||
{
|
||||
|
@ -131,43 +128,43 @@ int TwoCharOperator(const char** str, char c1, char c2, int op)
|
|||
}
|
||||
|
||||
// Determines if a character is a flag
|
||||
int isFlag(char c)
|
||||
static int isFlag(char c)
|
||||
{
|
||||
return c == 'N' || c == 'I' || c == 'C' || c == 'V' || c == 'Z' || c == 'B' || c == 'U' || c == 'D';
|
||||
}
|
||||
|
||||
// Determines if a character is a register
|
||||
int isRegister(char c)
|
||||
static int isRegister(char c)
|
||||
{
|
||||
return c == 'A' || c == 'X' || c == 'Y' || c == 'P' || c == 'S';
|
||||
}
|
||||
|
||||
// Determines if a character is for PC bank
|
||||
int isPCBank(char c)
|
||||
static int isPCBank(char c)
|
||||
{
|
||||
return c == 'K';
|
||||
}
|
||||
|
||||
// Determines if a character is for Data bank
|
||||
int isDataBank(char c)
|
||||
static int isDataBank(char c)
|
||||
{
|
||||
return c == 'T';
|
||||
}
|
||||
|
||||
// Determines if a character is for value read
|
||||
int isValueRead(char c)
|
||||
static int isValueRead(char c)
|
||||
{
|
||||
return c == 'R';
|
||||
}
|
||||
|
||||
// Determines if a character is for value write
|
||||
int isValueWrite(char c)
|
||||
static int isValueWrite(char c)
|
||||
{
|
||||
return c == 'W';
|
||||
}
|
||||
|
||||
// Reads a hexadecimal number from str
|
||||
int getNumber(unsigned int* number, const char** str)
|
||||
static int getNumber(unsigned int* number, const char** str)
|
||||
{
|
||||
// char buffer[5];
|
||||
|
||||
|
@ -185,10 +182,10 @@ int getNumber(unsigned int* number, const char** str)
|
|||
return 1;
|
||||
}
|
||||
|
||||
Condition* Connect(const char** str);
|
||||
static Condition* Connect(const char** str);
|
||||
|
||||
// Handles the following part of the grammar: '(' E ')'
|
||||
Condition* Parentheses(const char** str, Condition* c, char openPar, char closePar)
|
||||
static Condition* Parentheses(const char** str, Condition* c, char openPar, char closePar)
|
||||
{
|
||||
if (next == openPar)
|
||||
{
|
||||
|
@ -216,7 +213,7 @@ Condition* Parentheses(const char** str, Condition* c, char openPar, char closeP
|
|||
* Check for primitives
|
||||
* Flags, Registers, Numbers, Addresses and parentheses
|
||||
*/
|
||||
Condition* Primitive(const char** str, Condition* c)
|
||||
static Condition* Primitive(const char** str, Condition* c)
|
||||
{
|
||||
if (isFlag(next)) /* Flags */
|
||||
{
|
||||
|
@ -394,24 +391,22 @@ Condition* Primitive(const char** str, Condition* c)
|
|||
}
|
||||
|
||||
/* Handle * and / operators */
|
||||
Condition* Term(const char** str)
|
||||
static Condition* Term(const char** str)
|
||||
{
|
||||
Condition* t;
|
||||
Condition* t1;
|
||||
Condition* mid;
|
||||
|
||||
t = (Condition*)FCEU_dmalloc(sizeof(Condition));
|
||||
t = new Condition();
|
||||
|
||||
if (!t)
|
||||
if (t == nullptr)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(t, 0, sizeof(Condition));
|
||||
|
||||
if (!Primitive(str, t))
|
||||
{
|
||||
freeTree(t);
|
||||
delete t;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -421,22 +416,25 @@ Condition* Term(const char** str)
|
|||
|
||||
scan(str);
|
||||
|
||||
if (!(t1 = (Condition*)FCEU_dmalloc(sizeof(Condition))))
|
||||
return NULL;
|
||||
|
||||
memset(t1, 0, sizeof(Condition));
|
||||
if ((t1 = new Condition()) == nullptr)
|
||||
{
|
||||
delete t;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!Primitive(str, t1))
|
||||
{
|
||||
freeTree(t);
|
||||
freeTree(t1);
|
||||
delete t;
|
||||
delete t1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(mid = (Condition*)FCEU_dmalloc(sizeof(Condition))))
|
||||
return NULL;
|
||||
|
||||
memset(mid, 0, sizeof(Condition));
|
||||
if ((mid = new Condition()) == nullptr)
|
||||
{
|
||||
delete t;
|
||||
delete t1;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
mid->lhs = t;
|
||||
mid->rhs = t1;
|
||||
|
@ -449,7 +447,7 @@ Condition* Term(const char** str)
|
|||
}
|
||||
|
||||
/* Check for + and - operators */
|
||||
int SumOperators(const char** str)
|
||||
static int SumOperators(const char** str)
|
||||
{
|
||||
switch (next)
|
||||
{
|
||||
|
@ -460,13 +458,13 @@ int SumOperators(const char** str)
|
|||
}
|
||||
|
||||
/* Handle + and - operators */
|
||||
Condition* Sum(const char** str)
|
||||
static Condition* Sum(const char** str)
|
||||
{
|
||||
return InfixOperator(str, Term, SumOperators);
|
||||
}
|
||||
|
||||
/* Check for <=, =>, ==, !=, > and < operators */
|
||||
int CompareOperators(const char** str)
|
||||
static int CompareOperators(const char** str)
|
||||
{
|
||||
int val = TwoCharOperator(str, '=', '=', OP_EQ);
|
||||
if (val) return val;
|
||||
|
@ -490,13 +488,13 @@ int CompareOperators(const char** str)
|
|||
}
|
||||
|
||||
/* Handle <=, =>, ==, !=, > and < operators */
|
||||
Condition* Compare(const char** str)
|
||||
static Condition* Compare(const char** str)
|
||||
{
|
||||
return InfixOperator(str, Sum, CompareOperators);
|
||||
}
|
||||
|
||||
/* Check for || or && operators */
|
||||
int ConnectOperators(const char** str)
|
||||
static int ConnectOperators(const char** str)
|
||||
{
|
||||
int val = TwoCharOperator(str, '|', '|', OP_OR);
|
||||
if(val) return val;
|
||||
|
@ -508,7 +506,7 @@ int ConnectOperators(const char** str)
|
|||
}
|
||||
|
||||
/* Handle || and && operators */
|
||||
Condition* Connect(const char** str)
|
||||
static Condition* Connect(const char** str)
|
||||
{
|
||||
return InfixOperator(str, Compare, ConnectOperators);
|
||||
}
|
||||
|
@ -521,6 +519,10 @@ Condition* generateCondition(const char* str)
|
|||
scan(&str);
|
||||
c = Connect(&str);
|
||||
|
||||
if (!c || next != 0) return 0;
|
||||
if (!c || next != 0)
|
||||
{
|
||||
if (c) delete c;
|
||||
return 0;
|
||||
}
|
||||
else return c;
|
||||
}
|
||||
|
|
|
@ -61,9 +61,28 @@ struct Condition
|
|||
|
||||
unsigned int type2;
|
||||
unsigned int value2;
|
||||
|
||||
Condition(void)
|
||||
{
|
||||
op = 0;
|
||||
lhs = rhs = nullptr;
|
||||
type1 = value1 = 0;
|
||||
type2 = value2 = 0;
|
||||
};
|
||||
|
||||
~Condition(void)
|
||||
{
|
||||
if (lhs)
|
||||
{
|
||||
delete lhs;
|
||||
}
|
||||
if (rhs)
|
||||
{
|
||||
delete rhs;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void freeTree(Condition* c);
|
||||
Condition* generateCondition(const char* str);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -19,10 +19,15 @@ unsigned int debuggerPageSize = 14;
|
|||
int vblankScanLines = 0; //Used to calculate scanlines 240-261 (vblank)
|
||||
int vblankPixel = 0; //Used to calculate the pixels in vblank
|
||||
|
||||
int offsetStringToInt(unsigned int type, const char* offsetBuffer)
|
||||
int offsetStringToInt(unsigned int type, const char* offsetBuffer, bool *conversionOk)
|
||||
{
|
||||
int offset = -1;
|
||||
|
||||
if (conversionOk)
|
||||
{
|
||||
*conversionOk = false;
|
||||
}
|
||||
|
||||
if (sscanf(offsetBuffer,"%7X",(unsigned int *)&offset) == EOF)
|
||||
{
|
||||
return -1;
|
||||
|
@ -30,14 +35,26 @@ int offsetStringToInt(unsigned int type, const char* offsetBuffer)
|
|||
|
||||
if (type & BT_P)
|
||||
{
|
||||
if (conversionOk)
|
||||
{
|
||||
*conversionOk = (offset >= 0) && (offset < 0x4000);
|
||||
}
|
||||
return offset & 0x3FFF;
|
||||
}
|
||||
else if (type & BT_S)
|
||||
{
|
||||
if (conversionOk)
|
||||
{
|
||||
*conversionOk = (offset >= 0) && (offset < 0x100);
|
||||
}
|
||||
return offset & 0x00FF;
|
||||
}
|
||||
else if (type & BT_R)
|
||||
{
|
||||
if (conversionOk)
|
||||
{
|
||||
*conversionOk = (offset >= 0);
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
else // BT_C
|
||||
|
@ -46,6 +63,10 @@ int offsetStringToInt(unsigned int type, const char* offsetBuffer)
|
|||
|
||||
if (sym)
|
||||
{
|
||||
if (conversionOk)
|
||||
{
|
||||
*conversionOk = true;
|
||||
}
|
||||
return sym->offset() & 0xFFFF;
|
||||
}
|
||||
|
||||
|
@ -56,21 +77,26 @@ int offsetStringToInt(unsigned int type, const char* offsetBuffer)
|
|||
type = GameInfo->type;
|
||||
}
|
||||
if (type == GIT_NSF) { //NSF Breakpoint keywords
|
||||
if (strcmp(offsetBuffer,"LOAD") == 0) return (NSFHeader.LoadAddressLow | (NSFHeader.LoadAddressHigh<<8));
|
||||
if (strcmp(offsetBuffer,"INIT") == 0) return (NSFHeader.InitAddressLow | (NSFHeader.InitAddressHigh<<8));
|
||||
if (strcmp(offsetBuffer,"PLAY") == 0) return (NSFHeader.PlayAddressLow | (NSFHeader.PlayAddressHigh<<8));
|
||||
if (strcmp(offsetBuffer,"LOAD") == 0) offset = (NSFHeader.LoadAddressLow | (NSFHeader.LoadAddressHigh<<8));
|
||||
else if (strcmp(offsetBuffer,"INIT") == 0) offset = (NSFHeader.InitAddressLow | (NSFHeader.InitAddressHigh<<8));
|
||||
else if (strcmp(offsetBuffer,"PLAY") == 0) offset = (NSFHeader.PlayAddressLow | (NSFHeader.PlayAddressHigh<<8));
|
||||
}
|
||||
else if (type == GIT_FDS) { //FDS Breakpoint keywords
|
||||
if (strcmp(offsetBuffer,"NMI1") == 0) return (GetMem(0xDFF6) | (GetMem(0xDFF7)<<8));
|
||||
if (strcmp(offsetBuffer,"NMI2") == 0) return (GetMem(0xDFF8) | (GetMem(0xDFF9)<<8));
|
||||
if (strcmp(offsetBuffer,"NMI3") == 0) return (GetMem(0xDFFA) | (GetMem(0xDFFB)<<8));
|
||||
if (strcmp(offsetBuffer,"RST") == 0) return (GetMem(0xDFFC) | (GetMem(0xDFFD)<<8));
|
||||
if ((strcmp(offsetBuffer,"IRQ") == 0) || (strcmp(offsetBuffer,"BRK") == 0)) return (GetMem(0xDFFE) | (GetMem(0xDFFF)<<8));
|
||||
if (strcmp(offsetBuffer,"NMI1") == 0) offset = (GetMem(0xDFF6) | (GetMem(0xDFF7)<<8));
|
||||
else if (strcmp(offsetBuffer,"NMI2") == 0) offset = (GetMem(0xDFF8) | (GetMem(0xDFF9)<<8));
|
||||
else if (strcmp(offsetBuffer,"NMI3") == 0) offset = (GetMem(0xDFFA) | (GetMem(0xDFFB)<<8));
|
||||
else if (strcmp(offsetBuffer,"RST") == 0) offset = (GetMem(0xDFFC) | (GetMem(0xDFFD)<<8));
|
||||
else if ((strcmp(offsetBuffer,"IRQ") == 0) || (strcmp(offsetBuffer,"BRK") == 0)) offset = (GetMem(0xDFFE) | (GetMem(0xDFFF)<<8));
|
||||
}
|
||||
else { //NES Breakpoint keywords
|
||||
if ((strcmp(offsetBuffer,"NMI") == 0) || (strcmp(offsetBuffer,"VBL") == 0)) return (GetMem(0xFFFA) | (GetMem(0xFFFB)<<8));
|
||||
if (strcmp(offsetBuffer,"RST") == 0) return (GetMem(0xFFFC) | (GetMem(0xFFFD)<<8));
|
||||
if ((strcmp(offsetBuffer,"IRQ") == 0) || (strcmp(offsetBuffer,"BRK") == 0)) return (GetMem(0xFFFE) | (GetMem(0xFFFF)<<8));
|
||||
if ((strcmp(offsetBuffer,"NMI") == 0) || (strcmp(offsetBuffer,"VBL") == 0)) offset = (GetMem(0xFFFA) | (GetMem(0xFFFB)<<8));
|
||||
else if (strcmp(offsetBuffer,"RST") == 0) offset = (GetMem(0xFFFC) | (GetMem(0xFFFD)<<8));
|
||||
else if ((strcmp(offsetBuffer,"IRQ") == 0) || (strcmp(offsetBuffer,"BRK") == 0)) offset = (GetMem(0xFFFE) | (GetMem(0xFFFF)<<8));
|
||||
}
|
||||
|
||||
if (conversionOk)
|
||||
{
|
||||
*conversionOk = (offset >= 0) && (offset < 0x10000);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -139,7 +165,7 @@ int checkCondition(const char* condition, int num)
|
|||
// Remove the old breakpoint condition before adding a new condition.
|
||||
if (watchpoint[num].cond)
|
||||
{
|
||||
freeTree(watchpoint[num].cond);
|
||||
delete watchpoint[num].cond;
|
||||
free(watchpoint[num].condText);
|
||||
watchpoint[num].cond = 0;
|
||||
watchpoint[num].condText = 0;
|
||||
|
@ -153,8 +179,8 @@ int checkCondition(const char* condition, int num)
|
|||
{
|
||||
watchpoint[num].cond = c;
|
||||
watchpoint[num].condText = (char*)malloc(strlen(condition) + 1);
|
||||
if (!watchpoint[num].condText)
|
||||
return 0;
|
||||
if (!watchpoint[num].condText)
|
||||
return 0;
|
||||
strcpy(watchpoint[num].condText, condition);
|
||||
}
|
||||
else
|
||||
|
@ -169,7 +195,7 @@ int checkCondition(const char* condition, int num)
|
|||
// Remove the old breakpoint condition
|
||||
if (watchpoint[num].cond)
|
||||
{
|
||||
freeTree(watchpoint[num].cond);
|
||||
delete watchpoint[num].cond;
|
||||
free(watchpoint[num].condText);
|
||||
watchpoint[num].cond = 0;
|
||||
watchpoint[num].condText = 0;
|
||||
|
|
|
@ -172,7 +172,7 @@ DebuggerState &FCEUI_Debugger();
|
|||
//#define WRITE_BREAKPOINT 16
|
||||
//#define EXECUTE_BREAKPOINT 32
|
||||
|
||||
int offsetStringToInt(unsigned int type, const char* offsetBuffer);
|
||||
int offsetStringToInt(unsigned int type, const char* offsetBuffer, bool *conversionOk = nullptr);
|
||||
unsigned int NewBreak(const char* name, int start, int end, unsigned int type, const char* condition, unsigned int num, bool enable);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -756,7 +756,6 @@ int debugSymbolTable_t::loadGameSymbols(void)
|
|||
{
|
||||
int nPages, pageSize, romSize = 0x10000;
|
||||
|
||||
this->save();
|
||||
this->clear();
|
||||
|
||||
if ( GameInfo != nullptr )
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -273,6 +273,8 @@ void FCEUI_ClearEmulationFrameStepped();
|
|||
void FCEUI_SetEmulationPaused(int val);
|
||||
///toggles the paused bit (bit0) for EmulationPaused. caused FCEUD_DebugUpdate() to fire if the emulation pauses
|
||||
void FCEUI_ToggleEmulationPause();
|
||||
void FCEUI_PauseForDuration(int secs);
|
||||
int FCEUI_PauseFramesRemaining();
|
||||
|
||||
//indicates whether input aids should be drawn (such as crosshairs, etc; usually in fullscreen mode)
|
||||
bool FCEUD_ShouldDrawInputAids();
|
||||
|
|
|
@ -30,9 +30,14 @@
|
|||
#endif
|
||||
|
||||
#ifdef _USE_X264
|
||||
#include <cstdint>
|
||||
#include "x264.h"
|
||||
#endif
|
||||
|
||||
#ifdef _USE_LIBARCHIVE
|
||||
#include <archive.h>
|
||||
#endif
|
||||
|
||||
#ifdef _USE_LIBAV
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
|
@ -201,6 +206,23 @@ AboutWindow::AboutWindow(QWidget *parent)
|
|||
sprintf( stmp, " Compiled with zlib %s\n", ZLIB_VERSION );
|
||||
credits->insertPlainText( stmp );
|
||||
#endif
|
||||
#ifdef _USE_LIBARCHIVE
|
||||
sprintf( stmp, " Compiled with libarchive %s\n", ARCHIVE_VERSION_ONLY_STRING );
|
||||
credits->insertPlainText( stmp );
|
||||
const char *libArcName[] = { "zlib", "liblzma", "bzlib", "liblz4", "libzstd", nullptr };
|
||||
const char *libArcVersion[] = { archive_zlib_version(), archive_liblzma_version(),
|
||||
archive_bzlib_version(), archive_liblz4_version(), archive_libzstd_version(), nullptr };
|
||||
i=0;
|
||||
while (libArcName[i])
|
||||
{
|
||||
if (libArcVersion[i])
|
||||
{
|
||||
sprintf( stmp, " %s %s\n", libArcName[i], libArcVersion[i]);
|
||||
credits->insertPlainText( stmp );
|
||||
}
|
||||
i++;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef _S9XLUA_H
|
||||
sprintf( stmp, " Compiled with %s\n", LUA_RELEASE );
|
||||
|
|
|
@ -2580,6 +2580,7 @@ int FCEUD_AviGetFormatOpts( std::vector <std::string> &formatList )
|
|||
AviRecordDiskThread_t::AviRecordDiskThread_t( QObject *parent )
|
||||
: QThread(parent)
|
||||
{
|
||||
setObjectName( QString("AviRecordDiskThread") );
|
||||
}
|
||||
//----------------------------------------------------
|
||||
AviRecordDiskThread_t::~AviRecordDiskThread_t(void)
|
||||
|
|
|
@ -54,7 +54,6 @@ void openCheatDialog(QWidget *parent)
|
|||
{
|
||||
win->activateWindow();
|
||||
win->raise();
|
||||
win->setFocus();
|
||||
return;
|
||||
}
|
||||
win = new GuiCheatsDialog_t(parent);
|
||||
|
@ -705,14 +704,10 @@ int GuiCheatsDialog_t::activeCheatListCB(const char *name, uint32 a, uint8 v, in
|
|||
|
||||
if (item == NULL)
|
||||
{
|
||||
item = new QTreeWidgetItem();
|
||||
|
||||
actvCheatList->addTopLevelItem(item);
|
||||
item = new QTreeWidgetItem(actvCheatList);
|
||||
}
|
||||
|
||||
//item->setFlags( Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsUserCheckable );
|
||||
item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | Qt::ItemNeverHasChildren);
|
||||
|
||||
item->setCheckState(0, s ? Qt::Checked : Qt::Unchecked);
|
||||
|
||||
item->setText(0, tr(codeStr));
|
||||
|
@ -738,8 +733,6 @@ void GuiCheatsDialog_t::showActiveCheatList(bool redraw)
|
|||
|
||||
enaCheats->setChecked(!globalCheatDisabled);
|
||||
|
||||
actvCheatRedraw = redraw;
|
||||
|
||||
if (redraw)
|
||||
{
|
||||
actvCheatList->clear();
|
||||
|
@ -747,6 +740,8 @@ void GuiCheatsDialog_t::showActiveCheatList(bool redraw)
|
|||
actvCheatIdx = 0;
|
||||
|
||||
FCEUI_ListCheats(::activeCheatListCB, (void *)this);
|
||||
|
||||
actvCheatList->viewport()->update();
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
void GuiCheatsDialog_t::openCheatFile(void)
|
||||
|
|
|
@ -72,7 +72,6 @@ protected:
|
|||
|
||||
int fontCharWidth;
|
||||
int actvCheatIdx;
|
||||
bool actvCheatRedraw;
|
||||
bool pauseWhileActive;
|
||||
bool wasPausedByCheats;
|
||||
|
||||
|
|
|
@ -63,7 +63,6 @@ int openCDLWindow( QWidget *parent )
|
|||
{
|
||||
cdlWin->activateWindow();
|
||||
cdlWin->raise();
|
||||
cdlWin->setFocus();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -172,7 +172,7 @@ ConsoleDebugger::ConsoleDebugger(QWidget *parent)
|
|||
|
||||
loadDisplayViews();
|
||||
|
||||
windowUpdateReq = true;
|
||||
windowUpdateReq = QAsmView::UPDATE_ALL;
|
||||
|
||||
dbgWin = this;
|
||||
|
||||
|
@ -373,7 +373,7 @@ void ConsoleDebugger::ld65ImportDebug(void)
|
|||
|
||||
debugSymbolTable.ld65LoadDebugFile( filename.toStdString().c_str() );
|
||||
|
||||
queueUpdate();
|
||||
queueUpdate(QAsmView::UPDATE_ALL);
|
||||
|
||||
return;
|
||||
}
|
||||
|
@ -879,6 +879,16 @@ QMenuBar *ConsoleDebugger::buildMenuBar(void)
|
|||
|
||||
symMenu->addAction(act);
|
||||
|
||||
// Symbols -> Save
|
||||
act = new QAction(tr("&Save"), this);
|
||||
//act->setShortcut(QKeySequence( tr("F7") ) );
|
||||
act->setStatusTip(tr("&Save"));
|
||||
//act->setCheckable(true);
|
||||
//act->setChecked( break_on_unlogged_data );
|
||||
connect( act, SIGNAL(triggered(void)), this, SLOT(saveSymbolsCB(void)) );
|
||||
|
||||
symMenu->addAction(act);
|
||||
|
||||
symMenu->addSeparator();
|
||||
|
||||
// Symbols -> Symbolic Debug
|
||||
|
@ -1834,28 +1844,26 @@ void ConsoleDebugger::selBmAddrChanged(const QString &txt)
|
|||
//printf("selBmAddrVal = %04X\n", selBmAddrVal );
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
void ConsoleDebugger::openBpEditWindow( int editIdx, watchpointinfo *wp, bool forceAccept )
|
||||
DebuggerBreakpointEditor::DebuggerBreakpointEditor(int editIndex, watchpointinfo *wpIn, QWidget *parent)
|
||||
: QDialog(parent)
|
||||
{
|
||||
int ret;
|
||||
QDialog dialog(this);
|
||||
editIdx = editIndex;
|
||||
wp = wpIn;
|
||||
|
||||
QHBoxLayout *hbox;
|
||||
QVBoxLayout *mainLayout, *vbox;
|
||||
QLabel *lbl;
|
||||
QLineEdit *addr1, *addr2, *cond, *name;
|
||||
QCheckBox *forbidChkBox, *rbp, *wbp, *xbp, *ebp;
|
||||
QGridLayout *grid;
|
||||
QFrame *frame;
|
||||
QGroupBox *gbox;
|
||||
QPushButton *okButton, *cancelButton;
|
||||
QRadioButton *cpu_radio, *ppu_radio, *oam_radio, *rom_radio;
|
||||
|
||||
if ( editIdx >= 0 )
|
||||
{
|
||||
dialog.setWindowTitle( tr("Edit Breakpoint") );
|
||||
setWindowTitle( tr("Edit Breakpoint") );
|
||||
}
|
||||
else
|
||||
{
|
||||
dialog.setWindowTitle( tr("Add Breakpoint") );
|
||||
setWindowTitle( tr("Add Breakpoint") );
|
||||
}
|
||||
|
||||
hbox = new QHBoxLayout();
|
||||
|
@ -1874,6 +1882,9 @@ void ConsoleDebugger::openBpEditWindow( int editIdx, watchpointinfo *wp, bool fo
|
|||
hbox->addWidget( lbl );
|
||||
hbox->addWidget( addr2 );
|
||||
|
||||
connect( addr1, SIGNAL(textChanged(const QString &)), this, SLOT(addressTextChanged(const QString &)));
|
||||
connect( addr2, SIGNAL(textChanged(const QString &)), this, SLOT(addressTextChanged(const QString &)));
|
||||
|
||||
forbidChkBox = new QCheckBox( tr("Forbid") );
|
||||
hbox->addWidget( forbidChkBox );
|
||||
|
||||
|
@ -1906,6 +1917,11 @@ void ConsoleDebugger::openBpEditWindow( int editIdx, watchpointinfo *wp, bool fo
|
|||
rom_radio = new QRadioButton( tr("ROM") );
|
||||
cpu_radio->setChecked(true);
|
||||
|
||||
connect( cpu_radio, SIGNAL(toggled(bool)), this, SLOT(typeChanged(bool)));
|
||||
connect( ppu_radio, SIGNAL(toggled(bool)), this, SLOT(typeChanged(bool)));
|
||||
connect( oam_radio, SIGNAL(toggled(bool)), this, SLOT(typeChanged(bool)));
|
||||
connect( rom_radio, SIGNAL(toggled(bool)), this, SLOT(typeChanged(bool)));
|
||||
|
||||
gbox->setLayout( hbox );
|
||||
hbox->addWidget( cpu_radio );
|
||||
hbox->addWidget( ppu_radio );
|
||||
|
@ -1917,6 +1933,9 @@ void ConsoleDebugger::openBpEditWindow( int editIdx, watchpointinfo *wp, bool fo
|
|||
mainLayout->addLayout( grid );
|
||||
lbl = new QLabel( tr("Condition") );
|
||||
cond = new QLineEdit();
|
||||
condValid = true;
|
||||
|
||||
connect( cond, SIGNAL(textChanged(const QString &)), this, SLOT(conditionTextChanged(const QString &)));
|
||||
|
||||
grid->addWidget( lbl, 0, 0 );
|
||||
grid->addWidget( cond, 0, 1 );
|
||||
|
@ -1928,15 +1947,17 @@ void ConsoleDebugger::openBpEditWindow( int editIdx, watchpointinfo *wp, bool fo
|
|||
grid->addWidget( name, 1, 1 );
|
||||
|
||||
hbox = new QHBoxLayout();
|
||||
msgLbl = new QLabel();
|
||||
okButton = new QPushButton( tr("OK") );
|
||||
cancelButton = new QPushButton( tr("Cancel") );
|
||||
|
||||
mainLayout->addLayout( hbox );
|
||||
hbox->addWidget( cancelButton );
|
||||
hbox->addWidget( okButton );
|
||||
hbox->addWidget( msgLbl, 5 );
|
||||
hbox->addWidget( cancelButton, 1 );
|
||||
hbox->addWidget( okButton, 1 );
|
||||
|
||||
connect( okButton, SIGNAL(clicked(void)), &dialog, SLOT(accept(void)) );
|
||||
connect( cancelButton, SIGNAL(clicked(void)), &dialog, SLOT(reject(void)) );
|
||||
connect( okButton, SIGNAL(clicked(void)), this, SLOT(accept(void)) );
|
||||
connect( cancelButton, SIGNAL(clicked(void)), this, SLOT(reject(void)) );
|
||||
|
||||
okButton->setIcon( style()->standardIcon( QStyle::SP_DialogOkButton ) );
|
||||
cancelButton->setIcon( style()->standardIcon( QStyle::SP_DialogCancelButton ) );
|
||||
|
@ -2036,99 +2057,270 @@ void ConsoleDebugger::openBpEditWindow( int editIdx, watchpointinfo *wp, bool fo
|
|||
ebp->setChecked(true);
|
||||
}
|
||||
|
||||
dialog.setLayout( mainLayout );
|
||||
setLayout( mainLayout );
|
||||
|
||||
connect( this , SIGNAL(finished(int)), this, SLOT(closeWindow(int)) );
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
DebuggerBreakpointEditor::~DebuggerBreakpointEditor(void)
|
||||
{
|
||||
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
void DebuggerBreakpointEditor::closeEvent(QCloseEvent *event)
|
||||
{
|
||||
//printf("Close Window Event\n");
|
||||
done(QDialog::Rejected);
|
||||
deleteLater();
|
||||
event->accept();
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
void DebuggerBreakpointEditor::closeWindow(int ret)
|
||||
{
|
||||
//printf("Close Window %i\n", ret);
|
||||
if ( ret == QDialog::Accepted )
|
||||
{
|
||||
loadBreakpoint();
|
||||
}
|
||||
deleteLater();
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
void DebuggerBreakpointEditor::checkDataValid(void)
|
||||
{
|
||||
int type = 0;
|
||||
bool startAddrValid = false;
|
||||
bool endAddrValid = false;
|
||||
bool allEntriesValid = false;
|
||||
int addrLowerBound = 0;
|
||||
int addrUpperBound = 0;
|
||||
int start_addr = 0, end_addr = 0;
|
||||
|
||||
if ( cpu_radio->isChecked() )
|
||||
{
|
||||
type |= BT_C;
|
||||
addrLowerBound = 0;
|
||||
addrUpperBound = 0x10000;
|
||||
}
|
||||
else if ( ppu_radio->isChecked() )
|
||||
{
|
||||
type |= BT_P;
|
||||
addrLowerBound = 0;
|
||||
addrUpperBound = 0x4000;
|
||||
}
|
||||
else if ( oam_radio->isChecked() )
|
||||
{
|
||||
type |= BT_S;
|
||||
addrLowerBound = 0;
|
||||
addrUpperBound = 0x100;
|
||||
}
|
||||
else if ( rom_radio->isChecked() )
|
||||
{
|
||||
type |= BT_R;
|
||||
addrLowerBound = 0;
|
||||
addrUpperBound = 0x10000;
|
||||
|
||||
if (GameInfo != nullptr)
|
||||
{
|
||||
addrUpperBound = 16+PRGsize[0]+CHRsize[0];
|
||||
}
|
||||
}
|
||||
|
||||
if ( addr1->text().size() > 0 )
|
||||
{
|
||||
bool convOk = false;
|
||||
|
||||
start_addr = offsetStringToInt( type, addr1->text().toStdString().c_str(), &convOk );
|
||||
|
||||
//printf("StartAddr:0x%04X Upper:0x%04X\n", start_addr, addrUpperBound);
|
||||
startAddrValid = convOk && (start_addr >= addrLowerBound) && (start_addr < addrUpperBound);
|
||||
}
|
||||
else
|
||||
{
|
||||
startAddrValid = false;
|
||||
}
|
||||
|
||||
if ( addr2->text().size() > 0 )
|
||||
{
|
||||
bool convOk = false;
|
||||
|
||||
end_addr = offsetStringToInt( type, addr2->text().toStdString().c_str(), &convOk );
|
||||
|
||||
endAddrValid = convOk && (end_addr >= addrLowerBound) &&
|
||||
(end_addr < addrUpperBound) && (start_addr < end_addr);
|
||||
}
|
||||
else
|
||||
{
|
||||
endAddrValid = true;
|
||||
}
|
||||
|
||||
allEntriesValid = startAddrValid && endAddrValid && condValid;
|
||||
|
||||
okButton->setEnabled( allEntriesValid );
|
||||
|
||||
if (allEntriesValid)
|
||||
{
|
||||
msgLbl->clear();
|
||||
}
|
||||
else if (!startAddrValid)
|
||||
{
|
||||
msgLbl->setText(tr("Start Address Invalid"));
|
||||
}
|
||||
else if (!endAddrValid)
|
||||
{
|
||||
msgLbl->setText(tr("End Address Invalid"));
|
||||
}
|
||||
else if (!condValid)
|
||||
{
|
||||
msgLbl->setText(tr("Condition Invalid"));
|
||||
}
|
||||
else
|
||||
{
|
||||
msgLbl->clear();
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
void DebuggerBreakpointEditor::typeChanged(bool checked)
|
||||
{
|
||||
if (checked)
|
||||
{
|
||||
checkDataValid();
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
void DebuggerBreakpointEditor::addressTextChanged(const QString &txt)
|
||||
{
|
||||
checkDataValid();
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
void DebuggerBreakpointEditor::conditionTextChanged(const QString &txt)
|
||||
{
|
||||
if ( txt.size() > 0 )
|
||||
{
|
||||
Condition *c = generateCondition( txt.toStdString().c_str() );
|
||||
|
||||
condValid = (c != nullptr);
|
||||
|
||||
if (c)
|
||||
{
|
||||
delete c; c = nullptr;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
condValid = true;
|
||||
}
|
||||
checkDataValid();
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
void DebuggerBreakpointEditor::loadBreakpoint(void)
|
||||
{
|
||||
int start_addr = -1, end_addr = -1, type = 0, enable = 1, slot;
|
||||
std::string s;
|
||||
|
||||
FCEU_WRAPPER_LOCK();
|
||||
|
||||
slot = (editIdx < 0) ? numWPs : editIdx;
|
||||
|
||||
if ( cpu_radio->isChecked() )
|
||||
{
|
||||
type |= BT_C;
|
||||
}
|
||||
else if ( ppu_radio->isChecked() )
|
||||
{
|
||||
type |= BT_P;
|
||||
}
|
||||
else if ( oam_radio->isChecked() )
|
||||
{
|
||||
type |= BT_S;
|
||||
}
|
||||
else if ( rom_radio->isChecked() )
|
||||
{
|
||||
type |= BT_R;
|
||||
}
|
||||
|
||||
s = addr1->text().toStdString();
|
||||
|
||||
if ( s.size() > 0 )
|
||||
{
|
||||
start_addr = offsetStringToInt( type, s.c_str() );
|
||||
}
|
||||
|
||||
s = addr2->text().toStdString();
|
||||
|
||||
if ( s.size() > 0 )
|
||||
{
|
||||
end_addr = offsetStringToInt( type, s.c_str() );
|
||||
}
|
||||
|
||||
if ( rbp->isChecked() )
|
||||
{
|
||||
type |= WP_R;
|
||||
}
|
||||
if ( wbp->isChecked() )
|
||||
{
|
||||
type |= WP_W;
|
||||
}
|
||||
if ( xbp->isChecked() )
|
||||
{
|
||||
type |= WP_X;
|
||||
}
|
||||
|
||||
if ( forbidChkBox->isChecked() )
|
||||
{
|
||||
type |= WP_F;
|
||||
}
|
||||
|
||||
enable = ebp->isChecked();
|
||||
|
||||
if ( (start_addr >= 0) && (numWPs < 64) )
|
||||
{
|
||||
unsigned int retval;
|
||||
std::string nameString, condString;
|
||||
|
||||
nameString = name->text().toStdString();
|
||||
condString = cond->text().toStdString();
|
||||
|
||||
retval = NewBreak( nameString.c_str(), start_addr, end_addr, type, condString.c_str(), slot, enable);
|
||||
|
||||
if ( (retval == 1) || (retval == 2) )
|
||||
{
|
||||
printf("Breakpoint Add Failed\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (editIdx < 0)
|
||||
{
|
||||
numWPs++;
|
||||
}
|
||||
|
||||
//bpListUpdate( false );
|
||||
}
|
||||
}
|
||||
FCEU_WRAPPER_UNLOCK();
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
//int editIndex, watchpointinfo *wp, bool forceAccept,
|
||||
//----------------------------------------------------------------------------
|
||||
void ConsoleDebugger::openBpEditWindow( int editIdx, watchpointinfo *wp, bool forceAccept )
|
||||
{
|
||||
int ret;
|
||||
|
||||
DebuggerBreakpointEditor *dialog = new DebuggerBreakpointEditor( editIdx, wp, this );
|
||||
|
||||
if ( forceAccept )
|
||||
{
|
||||
dialog->loadBreakpoint();
|
||||
dialog->deleteLater();
|
||||
ret = QDialog::Accepted;
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = dialog.exec();
|
||||
ret = dialog->exec();
|
||||
}
|
||||
|
||||
if ( ret == QDialog::Accepted )
|
||||
if (ret == QDialog::Accepted)
|
||||
{
|
||||
int start_addr = -1, end_addr = -1, type = 0, enable = 1, slot;
|
||||
std::string s;
|
||||
|
||||
slot = (editIdx < 0) ? numWPs : editIdx;
|
||||
|
||||
if ( cpu_radio->isChecked() )
|
||||
{
|
||||
type |= BT_C;
|
||||
}
|
||||
else if ( ppu_radio->isChecked() )
|
||||
{
|
||||
type |= BT_P;
|
||||
}
|
||||
else if ( oam_radio->isChecked() )
|
||||
{
|
||||
type |= BT_S;
|
||||
}
|
||||
else if ( rom_radio->isChecked() )
|
||||
{
|
||||
type |= BT_R;
|
||||
}
|
||||
|
||||
s = addr1->text().toStdString();
|
||||
|
||||
if ( s.size() > 0 )
|
||||
{
|
||||
start_addr = offsetStringToInt( type, s.c_str() );
|
||||
}
|
||||
|
||||
s = addr2->text().toStdString();
|
||||
|
||||
if ( s.size() > 0 )
|
||||
{
|
||||
end_addr = offsetStringToInt( type, s.c_str() );
|
||||
}
|
||||
|
||||
if ( rbp->isChecked() )
|
||||
{
|
||||
type |= WP_R;
|
||||
}
|
||||
if ( wbp->isChecked() )
|
||||
{
|
||||
type |= WP_W;
|
||||
}
|
||||
if ( xbp->isChecked() )
|
||||
{
|
||||
type |= WP_X;
|
||||
}
|
||||
|
||||
if ( forbidChkBox->isChecked() )
|
||||
{
|
||||
type |= WP_F;
|
||||
}
|
||||
|
||||
enable = ebp->isChecked();
|
||||
|
||||
if ( (start_addr >= 0) && (numWPs < 64) )
|
||||
{
|
||||
unsigned int retval;
|
||||
std::string nameString, condString;
|
||||
|
||||
nameString = name->text().toStdString();
|
||||
condString = cond->text().toStdString();
|
||||
|
||||
retval = NewBreak( nameString.c_str(), start_addr, end_addr, type, condString.c_str(), slot, enable);
|
||||
|
||||
if ( (retval == 1) || (retval == 2) )
|
||||
{
|
||||
printf("Breakpoint Add Failed\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (editIdx < 0)
|
||||
{
|
||||
numWPs++;
|
||||
}
|
||||
|
||||
bpListUpdate( false );
|
||||
}
|
||||
}
|
||||
bpListUpdate( false );
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
|
@ -2439,7 +2631,7 @@ static void DeleteBreak(int sel)
|
|||
|
||||
if (watchpoint[sel].cond)
|
||||
{
|
||||
freeTree(watchpoint[sel].cond);
|
||||
delete watchpoint[sel].cond;
|
||||
}
|
||||
if (watchpoint[sel].condText)
|
||||
{
|
||||
|
@ -2488,7 +2680,7 @@ void debuggerClearAllBreakpoints(void)
|
|||
{
|
||||
if (watchpoint[i].cond)
|
||||
{
|
||||
freeTree(watchpoint[i].cond);
|
||||
delete watchpoint[i].cond;
|
||||
}
|
||||
if (watchpoint[i].condText)
|
||||
{
|
||||
|
@ -2499,7 +2691,7 @@ void debuggerClearAllBreakpoints(void)
|
|||
free(watchpoint[i].desc);
|
||||
}
|
||||
|
||||
watchpoint[i].address = 0;
|
||||
watchpoint[i].address = 0;
|
||||
watchpoint[i].endaddress = 0;
|
||||
watchpoint[i].flags = 0;
|
||||
watchpoint[i].cond = 0;
|
||||
|
@ -2753,6 +2945,13 @@ void ConsoleDebugger::reloadSymbolsCB(void)
|
|||
FCEU_WRAPPER_UNLOCK();
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
void ConsoleDebugger::saveSymbolsCB(void)
|
||||
{
|
||||
FCEU_WRAPPER_LOCK();
|
||||
debugSymbolTable.save();
|
||||
FCEU_WRAPPER_UNLOCK();
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
void ConsoleDebugger::pcSetPlaceTop(void)
|
||||
{
|
||||
asmView->setPC_placement( 0 );
|
||||
|
@ -2898,7 +3097,7 @@ void ConsoleDebugger::debugStepBackCB(void)
|
|||
{
|
||||
FCEU_WRAPPER_LOCK();
|
||||
FCEUD_TraceLoggerBackUpInstruction();
|
||||
updateWindowData();
|
||||
updateWindowData(QAsmView::UPDATE_ALL);
|
||||
hexEditorUpdateMemoryValues(true);
|
||||
hexEditorRequestUpdateAll();
|
||||
lastBpIdx = BREAK_TYPE_STEP;
|
||||
|
@ -3093,8 +3292,7 @@ void ConsoleDebugger::seekPCCB (void)
|
|||
setRegsFromEntry();
|
||||
//updateAllDebugWindows();
|
||||
}
|
||||
windowUpdateReq = true;
|
||||
//asmView->scrollToPC();
|
||||
windowUpdateReq = QAsmView::UPDATE_ALL;
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
void ConsoleDebugger::openChangePcDialog(void)
|
||||
|
@ -3148,7 +3346,7 @@ void ConsoleDebugger::openChangePcDialog(void)
|
|||
{
|
||||
X.PC = sbox->value();
|
||||
|
||||
windowUpdateReq = true;
|
||||
windowUpdateReq = QAsmView::UPDATE_ALL;
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
|
@ -4142,20 +4340,25 @@ void ConsoleDebugger::updateRegisterView(void)
|
|||
ppuScrollY->setText( tr(stmp) );
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
void ConsoleDebugger::updateWindowData(void)
|
||||
void ConsoleDebugger::updateWindowData(enum QAsmView::UpdateType type)
|
||||
{
|
||||
asmView->updateAssemblyView();
|
||||
|
||||
asmView->scrollToPC();
|
||||
if (type == QAsmView::UPDATE_ALL)
|
||||
{
|
||||
asmView->updateAssemblyView();
|
||||
asmView->scrollToPC();
|
||||
updateRegisterView();
|
||||
} else if (type == QAsmView::UPDATE_NO_SCROLL)
|
||||
{
|
||||
asmView->updateAssemblyView();
|
||||
updateRegisterView();
|
||||
}
|
||||
|
||||
updateRegisterView();
|
||||
|
||||
windowUpdateReq = false;
|
||||
windowUpdateReq = QAsmView::UPDATE_NONE;
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
void ConsoleDebugger::queueUpdate(void)
|
||||
void ConsoleDebugger::queueUpdate(enum QAsmView::UpdateType type)
|
||||
{
|
||||
windowUpdateReq = true;
|
||||
windowUpdateReq = type;
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
void ConsoleDebugger::updatePeriodic(void)
|
||||
|
@ -4173,10 +4376,10 @@ void ConsoleDebugger::updatePeriodic(void)
|
|||
bpNotifyReq = false;
|
||||
}
|
||||
|
||||
if ( windowUpdateReq )
|
||||
if ( windowUpdateReq != QAsmView::UPDATE_NONE )
|
||||
{
|
||||
FCEU_WRAPPER_LOCK();
|
||||
updateWindowData();
|
||||
updateWindowData(windowUpdateReq);
|
||||
FCEU_WRAPPER_UNLOCK();
|
||||
}
|
||||
asmView->update();
|
||||
|
@ -4346,7 +4549,7 @@ void ConsoleDebugger::breakPointNotify( int bpNum )
|
|||
}
|
||||
}
|
||||
|
||||
windowUpdateReq = true;
|
||||
windowUpdateReq = QAsmView::UPDATE_ALL;
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
void ConsoleDebugger::hbarChanged(int value)
|
||||
|
@ -4461,7 +4664,6 @@ void debuggerWindowSetFocus(bool val)
|
|||
{
|
||||
dbgWin->activateWindow();
|
||||
dbgWin->raise();
|
||||
dbgWin->setFocus();
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
|
@ -4470,11 +4672,11 @@ bool debuggerWaitingAtBreakpoint(void)
|
|||
return waitingAtBp;
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
void updateAllDebuggerWindows( void )
|
||||
void updateAllDebuggerWindows( enum QAsmView::UpdateType type )
|
||||
{
|
||||
if ( dbgWin )
|
||||
{
|
||||
dbgWin->queueUpdate();
|
||||
dbgWin->queueUpdate(type);
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
|
|
|
@ -167,6 +167,8 @@ class QAsmView : public QWidget
|
|||
|
||||
QFont getFont(void){ return font; };
|
||||
|
||||
enum UpdateType { UPDATE_NONE, UPDATE_ALL, UPDATE_NO_SCROLL };
|
||||
|
||||
protected:
|
||||
bool event(QEvent *event) override;
|
||||
void paintEvent(QPaintEvent *event) override;
|
||||
|
@ -420,6 +422,51 @@ class DebugBreakOnDialog : public QDialog
|
|||
void resetDeltas(void);
|
||||
};
|
||||
|
||||
class DebuggerBreakpointEditor : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
DebuggerBreakpointEditor(int editIndex = -1, watchpointinfo *wpIn = nullptr, QWidget *parent = 0);
|
||||
~DebuggerBreakpointEditor(void);
|
||||
|
||||
void loadBreakpoint(void);
|
||||
|
||||
protected:
|
||||
void closeEvent(QCloseEvent *event) override;
|
||||
void checkDataValid(void);
|
||||
|
||||
private:
|
||||
int editIdx;
|
||||
watchpointinfo *wp;
|
||||
|
||||
QLineEdit *addr1;
|
||||
QLineEdit *addr2;
|
||||
QLineEdit *cond;
|
||||
QLineEdit *name;
|
||||
QCheckBox *forbidChkBox;
|
||||
QCheckBox *rbp;
|
||||
QCheckBox *wbp;
|
||||
QCheckBox *xbp;
|
||||
QCheckBox *ebp;
|
||||
QLabel *msgLbl;
|
||||
|
||||
QPushButton *okButton;
|
||||
QPushButton *cancelButton;
|
||||
QRadioButton *cpu_radio;
|
||||
QRadioButton *ppu_radio;
|
||||
QRadioButton *oam_radio;
|
||||
QRadioButton *rom_radio;
|
||||
|
||||
bool condValid;
|
||||
|
||||
private slots:
|
||||
void closeWindow(int ret);
|
||||
void typeChanged(bool checked);
|
||||
void addressTextChanged( const QString &text );
|
||||
void conditionTextChanged( const QString &text );
|
||||
};
|
||||
|
||||
class ConsoleDebugger : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
@ -428,7 +475,7 @@ class ConsoleDebugger : public QDialog
|
|||
ConsoleDebugger(QWidget *parent = 0);
|
||||
~ConsoleDebugger(void);
|
||||
|
||||
void updateWindowData(void);
|
||||
void updateWindowData(enum QAsmView::UpdateType type);
|
||||
void updateRegisterView(void);
|
||||
void updateTabVisibility(void);
|
||||
void breakPointNotify(int bpNum);
|
||||
|
@ -437,7 +484,7 @@ class ConsoleDebugger : public QDialog
|
|||
void setBookmarkSelectedAddress( int addr );
|
||||
int getBookmarkSelectedAddress(void){ return selBmAddrVal; };
|
||||
void edit_BM_name( int addr );
|
||||
void queueUpdate(void);
|
||||
void queueUpdate(enum QAsmView::UpdateType type);
|
||||
|
||||
QLabel *asmLineSelLbl;
|
||||
|
||||
|
@ -530,7 +577,8 @@ class ConsoleDebugger : public QDialog
|
|||
ColorMenuItem *pcColorAct;
|
||||
|
||||
int selBmAddrVal;
|
||||
bool windowUpdateReq;
|
||||
enum QAsmView::UpdateType windowUpdateReq;
|
||||
|
||||
bool startedTraceLogger;
|
||||
|
||||
private:
|
||||
|
@ -584,6 +632,7 @@ class ConsoleDebugger : public QDialog
|
|||
void resizeToMinimumSizeHint(void);
|
||||
void resetCountersCB (void);
|
||||
void reloadSymbolsCB(void);
|
||||
void saveSymbolsCB(void);
|
||||
void displayByteCodesCB(bool value);
|
||||
void displayTraceDataCB(bool value);
|
||||
void displayROMoffsetCB(bool value);
|
||||
|
@ -625,6 +674,6 @@ void saveGameDebugBreakpoints( bool force = false );
|
|||
void loadGameDebugBreakpoints(void);
|
||||
void debuggerClearAllBreakpoints(void);
|
||||
void debuggerClearAllBookmarks(void);
|
||||
void updateAllDebuggerWindows(void);
|
||||
void updateAllDebuggerWindows(enum QAsmView::UpdateType type);
|
||||
|
||||
extern debuggerBookmarkManager_t dbgBmMgr;
|
||||
|
|
|
@ -85,8 +85,9 @@ ConsoleVideoConfDialog_t::ConsoleVideoConfDialog_t(QWidget *parent)
|
|||
|
||||
driverSelect = new QComboBox();
|
||||
|
||||
driverSelect->addItem( tr("OpenGL"), 0 );
|
||||
driverSelect->addItem( tr("SDL"), 1 );
|
||||
driverSelect->addItem( tr("OpenGL"), ConsoleViewerBase::VIDEO_DRIVER_OPENGL );
|
||||
driverSelect->addItem( tr("SDL"), ConsoleViewerBase::VIDEO_DRIVER_SDL );
|
||||
driverSelect->addItem( tr("QPainter"), ConsoleViewerBase::VIDEO_DRIVER_QPAINTER );
|
||||
|
||||
hbox1 = new QHBoxLayout();
|
||||
|
||||
|
@ -232,15 +233,10 @@ ConsoleVideoConfDialog_t::ConsoleVideoConfDialog_t(QWidget *parent)
|
|||
|
||||
if ( consoleWindow )
|
||||
{
|
||||
if ( consoleWindow->viewport_GL )
|
||||
if ( consoleWindow->viewport_Interface )
|
||||
{
|
||||
autoScaleCbx->setChecked( consoleWindow->viewport_GL->getAutoScaleOpt() );
|
||||
aspectCbx->setChecked( consoleWindow->viewport_GL->getForceAspectOpt() );
|
||||
}
|
||||
else if ( consoleWindow->viewport_SDL )
|
||||
{
|
||||
autoScaleCbx->setChecked( consoleWindow->viewport_SDL->getAutoScaleOpt() );
|
||||
aspectCbx->setChecked( consoleWindow->viewport_SDL->getForceAspectOpt() );
|
||||
autoScaleCbx->setChecked( consoleWindow->viewport_Interface->getAutoScaleOpt() );
|
||||
aspectCbx->setChecked( consoleWindow->viewport_Interface->getForceAspectOpt() );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -305,15 +301,10 @@ ConsoleVideoConfDialog_t::ConsoleVideoConfDialog_t(QWidget *parent)
|
|||
|
||||
if ( consoleWindow )
|
||||
{
|
||||
if ( consoleWindow->viewport_GL )
|
||||
if ( consoleWindow->viewport_Interface )
|
||||
{
|
||||
xScaleBox->setValue( consoleWindow->viewport_GL->getScaleX() );
|
||||
yScaleBox->setValue( consoleWindow->viewport_GL->getScaleY() );
|
||||
}
|
||||
else if ( consoleWindow->viewport_SDL )
|
||||
{
|
||||
xScaleBox->setValue( consoleWindow->viewport_SDL->getScaleX() );
|
||||
yScaleBox->setValue( consoleWindow->viewport_SDL->getScaleY() );
|
||||
xScaleBox->setValue( consoleWindow->viewport_Interface->getScaleX() );
|
||||
yScaleBox->setValue( consoleWindow->viewport_Interface->getScaleY() );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -594,13 +585,9 @@ void ConsoleVideoConfDialog_t::updateReadouts(void)
|
|||
|
||||
w = consoleWindow->size();
|
||||
|
||||
if ( consoleWindow->viewport_GL )
|
||||
if ( consoleWindow->viewport_Interface )
|
||||
{
|
||||
v = consoleWindow->viewport_GL->size();
|
||||
}
|
||||
else if ( consoleWindow->viewport_SDL )
|
||||
{
|
||||
v = consoleWindow->viewport_SDL->size();
|
||||
v = consoleWindow->viewport_Interface->size();
|
||||
}
|
||||
|
||||
sprintf( stmp, "%i x %i ", w.width(), w.height() );
|
||||
|
@ -726,13 +713,9 @@ void ConsoleVideoConfDialog_t::openGL_linearFilterChanged( int value )
|
|||
|
||||
if ( consoleWindow != NULL )
|
||||
{
|
||||
if ( consoleWindow->viewport_GL )
|
||||
if ( consoleWindow->viewport_Interface )
|
||||
{
|
||||
consoleWindow->viewport_GL->setLinearFilterEnable( opt );
|
||||
}
|
||||
if ( consoleWindow->viewport_SDL )
|
||||
{
|
||||
consoleWindow->viewport_SDL->setLinearFilterEnable( opt );
|
||||
consoleWindow->viewport_Interface->setLinearFilterEnable( opt );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -745,13 +728,9 @@ void ConsoleVideoConfDialog_t::autoScaleChanged( int value )
|
|||
|
||||
if ( consoleWindow != NULL )
|
||||
{
|
||||
if ( consoleWindow->viewport_GL )
|
||||
if ( consoleWindow->viewport_Interface )
|
||||
{
|
||||
consoleWindow->viewport_GL->setAutoScaleOpt( opt );
|
||||
}
|
||||
if ( consoleWindow->viewport_SDL )
|
||||
{
|
||||
consoleWindow->viewport_SDL->setAutoScaleOpt( opt );
|
||||
consoleWindow->viewport_Interface->setAutoScaleOpt( opt );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -832,9 +811,9 @@ void ConsoleVideoConfDialog_t::vsync_changed( int value )
|
|||
//consoleWindow->viewport_GL->setVsyncEnable( opt );
|
||||
consoleWindow->loadVideoDriver( 0, true );
|
||||
}
|
||||
if ( consoleWindow->viewport_SDL )
|
||||
else if ( consoleWindow->viewport_Interface )
|
||||
{
|
||||
consoleWindow->viewport_SDL->setVsyncEnable( opt );
|
||||
consoleWindow->viewport_Interface->setVsyncEnable( opt );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1094,15 +1073,10 @@ QSize ConsoleVideoConfDialog_t::calcNewScreenSize(void)
|
|||
|
||||
w = consoleWindow->size();
|
||||
|
||||
if ( consoleWindow->viewport_GL )
|
||||
if ( consoleWindow->viewport_Interface )
|
||||
{
|
||||
v = consoleWindow->viewport_GL->size();
|
||||
aspectRatio = consoleWindow->viewport_GL->getAspectRatio();
|
||||
}
|
||||
else if ( consoleWindow->viewport_SDL )
|
||||
{
|
||||
v = consoleWindow->viewport_SDL->size();
|
||||
aspectRatio = consoleWindow->viewport_SDL->getAspectRatio();
|
||||
v = consoleWindow->viewport_Interface->size();
|
||||
aspectRatio = consoleWindow->viewport_Interface->getAspectRatio();
|
||||
}
|
||||
|
||||
dw = w.width() - v.width();
|
||||
|
@ -1167,21 +1141,13 @@ void ConsoleVideoConfDialog_t::applyChanges( void )
|
|||
g_config->setOption("SDL.WinSizeX", s.width() );
|
||||
g_config->setOption("SDL.WinSizeY", s.height() );
|
||||
|
||||
if ( consoleWindow->viewport_GL )
|
||||
if ( consoleWindow->viewport_Interface )
|
||||
{
|
||||
consoleWindow->viewport_GL->setLinearFilterEnable( gl_LF_chkBox->isChecked() );
|
||||
consoleWindow->viewport_GL->setForceAspectOpt( aspectCbx->isChecked() );
|
||||
consoleWindow->viewport_GL->setAutoScaleOpt( autoScaleCbx->isChecked() );
|
||||
consoleWindow->viewport_GL->setScaleXY( xscale, yscale );
|
||||
consoleWindow->viewport_GL->reset();
|
||||
}
|
||||
if ( consoleWindow->viewport_SDL )
|
||||
{
|
||||
consoleWindow->viewport_SDL->setLinearFilterEnable( gl_LF_chkBox->isChecked() );
|
||||
consoleWindow->viewport_SDL->setForceAspectOpt( aspectCbx->isChecked() );
|
||||
consoleWindow->viewport_SDL->setAutoScaleOpt( autoScaleCbx->isChecked() );
|
||||
consoleWindow->viewport_SDL->setScaleXY( xscale, yscale );
|
||||
consoleWindow->viewport_SDL->reset();
|
||||
consoleWindow->viewport_Interface->setLinearFilterEnable( gl_LF_chkBox->isChecked() );
|
||||
consoleWindow->viewport_Interface->setForceAspectOpt( aspectCbx->isChecked() );
|
||||
consoleWindow->viewport_Interface->setAutoScaleOpt( autoScaleCbx->isChecked() );
|
||||
consoleWindow->viewport_Interface->setScaleXY( xscale, yscale );
|
||||
consoleWindow->viewport_Interface->reset();
|
||||
}
|
||||
|
||||
if ( !consoleWindow->isFullScreen() && !consoleWindow->isMaximized() )
|
||||
|
|
|
@ -92,7 +92,7 @@ ConsoleViewGL_t::ConsoleViewGL_t(QWidget *parent)
|
|||
|
||||
if ( localBuf )
|
||||
{
|
||||
memset( localBuf, 0, localBufSize );
|
||||
memset32( localBuf, alphaMask, localBufSize );
|
||||
}
|
||||
|
||||
vsyncEnabled = true;
|
||||
|
@ -136,6 +136,8 @@ ConsoleViewGL_t::ConsoleViewGL_t(QWidget *parent)
|
|||
|
||||
ConsoleViewGL_t::~ConsoleViewGL_t(void)
|
||||
{
|
||||
//printf("Destroying GL Viewport\n");
|
||||
|
||||
if ( localBuf )
|
||||
{
|
||||
free( localBuf ); localBuf = NULL;
|
||||
|
@ -502,7 +504,7 @@ void ConsoleViewGL_t::transfer2LocalBuffer(void)
|
|||
}
|
||||
else
|
||||
{
|
||||
memcpy( localBuf, src, cpSize );
|
||||
copyPixels32( dest, src, cpSize, alphaMask);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -10,7 +10,9 @@
|
|||
#include <QOpenGLWidget>
|
||||
#include <QOpenGLFunctions>
|
||||
|
||||
class ConsoleViewGL_t : public QOpenGLWidget, protected QOpenGLFunctions
|
||||
#include "Qt/ConsoleViewerInterface.h"
|
||||
|
||||
class ConsoleViewGL_t : public QOpenGLWidget, protected QOpenGLFunctions, public ConsoleViewerBase
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
|
@ -20,6 +22,8 @@ class ConsoleViewGL_t : public QOpenGLWidget, protected QOpenGLFunctions
|
|||
|
||||
int init(void);
|
||||
void reset(void);
|
||||
void queueRedraw(void){ update(); };
|
||||
int driver(void){ return VIDEO_DRIVER_OPENGL; };
|
||||
|
||||
void transfer2LocalBuffer(void);
|
||||
|
||||
|
@ -41,6 +45,13 @@ class ConsoleViewGL_t : public QOpenGLWidget, protected QOpenGLFunctions
|
|||
|
||||
void screenChanged(QScreen *scr);
|
||||
void setBgColor( QColor &c );
|
||||
void setCursor(const QCursor &c){ QOpenGLWidget::setCursor(c); };
|
||||
void setCursor( Qt::CursorShape s ){ QOpenGLWidget::setCursor(s); };
|
||||
|
||||
QSize size(void){ return QOpenGLWidget::size(); };
|
||||
QCursor cursor(void){ return QOpenGLWidget::cursor(); };
|
||||
void setMinimumSize(const QSize &s){ return QOpenGLWidget::setMinimumSize(s); };
|
||||
void setMaximumSize(const QSize &s){ return QOpenGLWidget::setMaximumSize(s); };
|
||||
|
||||
protected:
|
||||
void initializeGL(void);
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
// ConsoleViewerInterface.cpp
|
||||
//
|
||||
#include "Qt/ConsoleViewerInterface.h"
|
||||
|
||||
//----------------------------------------------------------
|
||||
void ConsoleViewerBase::memset32( void *buf, uint32_t val, size_t size)
|
||||
{
|
||||
uint32_t *p = static_cast<uint32_t*>(buf);
|
||||
size_t n = size / sizeof(uint32_t);
|
||||
|
||||
for (size_t i=0; i<n; i++)
|
||||
{
|
||||
*p = val; p++;
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------
|
||||
void ConsoleViewerBase::copyPixels32( void *dest, void *src, size_t size, uint32_t alphaMask)
|
||||
{
|
||||
uint32_t *d = static_cast<uint32_t*>(dest);
|
||||
uint32_t *s = static_cast<uint32_t*>(src);
|
||||
size_t n = size / sizeof(uint32_t);
|
||||
|
||||
for (size_t i=0; i<n; i++)
|
||||
{
|
||||
*d = *s | alphaMask; d++; s++;
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------
|
|
@ -0,0 +1,56 @@
|
|||
// ConsoleViewerInterface.h
|
||||
//
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
|
||||
#include <QColor>
|
||||
#include <QCursor>
|
||||
#include <QSize>
|
||||
|
||||
class ConsoleViewerBase
|
||||
{
|
||||
public:
|
||||
enum VideoDriver
|
||||
{
|
||||
VIDEO_DRIVER_OPENGL = 0,
|
||||
VIDEO_DRIVER_SDL,
|
||||
VIDEO_DRIVER_QPAINTER
|
||||
};
|
||||
virtual int init(void) = 0;
|
||||
virtual void reset(void) = 0;
|
||||
virtual void queueRedraw(void) = 0;
|
||||
virtual int driver(void) = 0;
|
||||
|
||||
virtual void transfer2LocalBuffer(void) = 0;
|
||||
|
||||
virtual void setVsyncEnable( bool ena ) = 0;
|
||||
virtual void setLinearFilterEnable( bool ena ) = 0;
|
||||
|
||||
virtual bool getForceAspectOpt(void) = 0;
|
||||
virtual void setForceAspectOpt( bool val ) = 0;
|
||||
virtual bool getAutoScaleOpt(void) = 0;
|
||||
virtual void setAutoScaleOpt( bool val ) = 0;
|
||||
virtual double getScaleX(void) = 0;
|
||||
virtual double getScaleY(void) = 0;
|
||||
virtual void setScaleXY( double xs, double ys ) = 0;
|
||||
virtual void getNormalizedCursorPos( double &x, double &y ) = 0;
|
||||
virtual bool getMouseButtonState( unsigned int btn ) = 0;
|
||||
virtual void setAspectXY( double x, double y ) = 0;
|
||||
virtual void getAspectXY( double &x, double &y ) = 0;
|
||||
virtual double getAspectRatio(void) = 0;
|
||||
|
||||
virtual void setCursor(const QCursor &c) = 0;
|
||||
virtual void setCursor( Qt::CursorShape s ) = 0;
|
||||
virtual void setBgColor( QColor &c ) = 0;
|
||||
|
||||
virtual QSize size(void) = 0;
|
||||
virtual QCursor cursor(void) = 0;
|
||||
virtual void setMinimumSize(const QSize &) = 0;
|
||||
virtual void setMaximumSize(const QSize &) = 0;
|
||||
|
||||
static void memset32( void *buf, uint32_t val, size_t size);
|
||||
static void copyPixels32( void *dest, void *src, size_t size, uint32_t alphaMask);
|
||||
|
||||
static constexpr uint32_t alphaMask = 0xff000000;
|
||||
protected:
|
||||
};
|
|
@ -0,0 +1,505 @@
|
|||
/* FCE Ultra - NES/Famicom Emulator
|
||||
*
|
||||
* Copyright notice for this file:
|
||||
* Copyright (C) 2020 mjbudd77
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
// GameViewer.cpp
|
||||
//
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
//#include <unistd.h>
|
||||
|
||||
#include "../../profiler.h"
|
||||
#include "Qt/nes_shm.h"
|
||||
#include "Qt/throttle.h"
|
||||
#include "Qt/fceuWrapper.h"
|
||||
#include "Qt/ConsoleViewerQWidget.h"
|
||||
#include "Qt/ConsoleUtilities.h"
|
||||
#include "Qt/ConsoleWindow.h"
|
||||
|
||||
extern unsigned int gui_draw_area_width;
|
||||
extern unsigned int gui_draw_area_height;
|
||||
|
||||
ConsoleViewQWidget_t::ConsoleViewQWidget_t(QWidget *parent)
|
||||
: QWidget( parent )
|
||||
{
|
||||
consoleWin_t *win = qobject_cast <consoleWin_t*>(parent);
|
||||
|
||||
printf("Initializing QPainter Video Driver\n");
|
||||
|
||||
QPalette pal = palette();
|
||||
|
||||
pal.setColor(QPalette::Window, Qt::black);
|
||||
setAutoFillBackground(true);
|
||||
setPalette(pal);
|
||||
|
||||
bgColor = nullptr;
|
||||
|
||||
if ( win )
|
||||
{
|
||||
bgColor = win->getVideoBgColorPtr();
|
||||
bgColor->setRgb( 0, 0, 0 );
|
||||
}
|
||||
|
||||
setMinimumWidth( 256 );
|
||||
setMinimumHeight( 224 );
|
||||
setFocusPolicy(Qt::StrongFocus);
|
||||
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||
|
||||
view_width = GL_NES_WIDTH;
|
||||
view_height = GL_NES_HEIGHT;
|
||||
|
||||
sx = sy = 0;
|
||||
rw = view_width;
|
||||
rh = view_height;
|
||||
sdlRendW = 0;
|
||||
sdlRendH = 0;
|
||||
xscale = 2.0;
|
||||
yscale = 2.0;
|
||||
|
||||
devPixRatio = 1.0f;
|
||||
aspectRatio = 1.0f;
|
||||
aspectX = 1.0f;
|
||||
aspectY = 1.0f;
|
||||
|
||||
vsyncEnabled = false;
|
||||
mouseButtonMask = 0;
|
||||
|
||||
localBufSize = (4 * GL_NES_WIDTH) * (4 * GL_NES_HEIGHT) * sizeof(uint32_t);
|
||||
|
||||
localBuf = (uint32_t*)malloc( localBufSize );
|
||||
|
||||
if ( localBuf )
|
||||
{
|
||||
memset32( localBuf, alphaMask, localBufSize );
|
||||
}
|
||||
|
||||
forceAspect = true;
|
||||
autoScaleEna = true;
|
||||
linearFilter = false;
|
||||
|
||||
if ( g_config )
|
||||
{
|
||||
int opt;
|
||||
g_config->getOption("SDL.OpenGLip", &opt );
|
||||
|
||||
linearFilter = (opt) ? true : false;
|
||||
|
||||
g_config->getOption ("SDL.AutoScale", &opt);
|
||||
|
||||
autoScaleEna = (opt) ? true : false;
|
||||
|
||||
g_config->getOption("SDL.XScale", &xscale);
|
||||
g_config->getOption("SDL.YScale", &yscale);
|
||||
|
||||
g_config->getOption ("SDL.ForceAspect", &forceAspect);
|
||||
|
||||
if ( bgColor )
|
||||
{
|
||||
fceuLoadConfigColor( "SDL.VideoBgColor", bgColor );
|
||||
}
|
||||
g_config->getOption ("SDL.VideoVsync", &vsyncEnabled);
|
||||
}
|
||||
}
|
||||
|
||||
ConsoleViewQWidget_t::~ConsoleViewQWidget_t(void)
|
||||
{
|
||||
//printf("Destroying QPainter Viewport\n");
|
||||
|
||||
if ( localBuf )
|
||||
{
|
||||
free( localBuf ); localBuf = nullptr;
|
||||
}
|
||||
cleanup();
|
||||
}
|
||||
|
||||
void ConsoleViewQWidget_t::setBgColor( QColor &c )
|
||||
{
|
||||
if ( bgColor )
|
||||
{
|
||||
*bgColor = c;
|
||||
}
|
||||
}
|
||||
|
||||
void ConsoleViewQWidget_t::setVsyncEnable( bool ena )
|
||||
{
|
||||
if ( vsyncEnabled != ena )
|
||||
{
|
||||
vsyncEnabled = ena;
|
||||
|
||||
reset();
|
||||
}
|
||||
}
|
||||
|
||||
void ConsoleViewQWidget_t::setLinearFilterEnable( bool ena )
|
||||
{
|
||||
if ( ena != linearFilter )
|
||||
{
|
||||
linearFilter = ena;
|
||||
|
||||
reset();
|
||||
}
|
||||
}
|
||||
|
||||
void ConsoleViewQWidget_t::setScaleXY( double xs, double ys )
|
||||
{
|
||||
xscale = xs;
|
||||
yscale = ys;
|
||||
|
||||
if ( forceAspect )
|
||||
{
|
||||
if ( xscale < yscale )
|
||||
{
|
||||
yscale = xscale;
|
||||
}
|
||||
else
|
||||
{
|
||||
xscale = yscale;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ConsoleViewQWidget_t::setAspectXY( double x, double y )
|
||||
{
|
||||
aspectX = x;
|
||||
aspectY = y;
|
||||
|
||||
aspectRatio = aspectY / aspectX;
|
||||
}
|
||||
|
||||
void ConsoleViewQWidget_t::getAspectXY( double &x, double &y )
|
||||
{
|
||||
x = aspectX;
|
||||
y = aspectY;
|
||||
}
|
||||
|
||||
double ConsoleViewQWidget_t::getAspectRatio(void)
|
||||
{
|
||||
return aspectRatio;
|
||||
}
|
||||
|
||||
void ConsoleViewQWidget_t::transfer2LocalBuffer(void)
|
||||
{
|
||||
int i=0, hq = 0, bufIdx;
|
||||
int numPixels = nes_shm->video.ncol * nes_shm->video.nrow;
|
||||
unsigned int cpSize = numPixels * 4;
|
||||
uint8_t *src, *dest;
|
||||
|
||||
bufIdx = nes_shm->pixBufIdx-1;
|
||||
|
||||
if ( bufIdx < 0 )
|
||||
{
|
||||
bufIdx = NES_VIDEO_BUFLEN-1;
|
||||
}
|
||||
if ( cpSize > localBufSize )
|
||||
{
|
||||
cpSize = localBufSize;
|
||||
}
|
||||
src = (uint8_t*)nes_shm->pixbuf[bufIdx];
|
||||
dest = (uint8_t*)localBuf;
|
||||
|
||||
hq = (nes_shm->video.preScaler == 1) || (nes_shm->video.preScaler == 4); // hq2x and hq3x
|
||||
|
||||
if ( hq )
|
||||
{
|
||||
for (i=0; i<numPixels; i++)
|
||||
{
|
||||
dest[3] = 0xFF;
|
||||
dest[1] = src[1];
|
||||
dest[2] = src[2];
|
||||
dest[0] = src[0];
|
||||
|
||||
src += 4; dest += 4;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//memcpy( localBuf, src, cpSize );
|
||||
copyPixels32( dest, src, cpSize, alphaMask);
|
||||
}
|
||||
}
|
||||
|
||||
int ConsoleViewQWidget_t::init(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ConsoleViewQWidget_t::cleanup(void)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void ConsoleViewQWidget_t::reset(void)
|
||||
{
|
||||
cleanup();
|
||||
if ( init() == 0 )
|
||||
{
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
cleanup();
|
||||
}
|
||||
}
|
||||
|
||||
void ConsoleViewQWidget_t::setCursor(const QCursor &c)
|
||||
{
|
||||
QWidget::setCursor(c);
|
||||
}
|
||||
|
||||
void ConsoleViewQWidget_t::setCursor( Qt::CursorShape s )
|
||||
{
|
||||
QWidget::setCursor(s);
|
||||
}
|
||||
|
||||
void ConsoleViewQWidget_t::showEvent(QShowEvent *event)
|
||||
{
|
||||
//printf("SDL Show: %i x %i \n", width(), height() );
|
||||
|
||||
//view_width = width();
|
||||
//view_height = height();
|
||||
|
||||
//gui_draw_area_width = view_width;
|
||||
//gui_draw_area_height = view_height;
|
||||
|
||||
//reset();
|
||||
}
|
||||
|
||||
void ConsoleViewQWidget_t::resizeEvent(QResizeEvent *event)
|
||||
{
|
||||
QSize s;
|
||||
|
||||
s = event->size();
|
||||
view_width = s.width();
|
||||
view_height = s.height();
|
||||
printf("QWidget Resize: %i x %i \n", view_width, view_height);
|
||||
|
||||
gui_draw_area_width = view_width;
|
||||
gui_draw_area_height = view_height;
|
||||
|
||||
reset();
|
||||
}
|
||||
|
||||
void ConsoleViewQWidget_t::mousePressEvent(QMouseEvent * event)
|
||||
{
|
||||
//printf("Mouse Button Press: (%i,%i) %x %x\n",
|
||||
// event->pos().x(), event->pos().y(), event->button(), event->buttons() );
|
||||
|
||||
mouseButtonMask = event->buttons();
|
||||
}
|
||||
|
||||
void ConsoleViewQWidget_t::mouseReleaseEvent(QMouseEvent * event)
|
||||
{
|
||||
//printf("Mouse Button Release: (%i,%i) %x %x\n",
|
||||
// event->pos().x(), event->pos().y(), event->button(), event->buttons() );
|
||||
|
||||
mouseButtonMask = event->buttons();
|
||||
}
|
||||
|
||||
bool ConsoleViewQWidget_t::getMouseButtonState( unsigned int btn )
|
||||
{
|
||||
bool isPressed = false;
|
||||
|
||||
if ( mouseButtonMask & btn )
|
||||
{
|
||||
isPressed = true;
|
||||
}
|
||||
else
|
||||
{ // Check SDL mouse state just in case SDL is intercepting
|
||||
// mouse events from window system causing Qt not to see them.
|
||||
int x, y;
|
||||
uint32_t b;
|
||||
b = SDL_GetMouseState( &x, &y);
|
||||
|
||||
if ( btn & Qt::LeftButton )
|
||||
{
|
||||
if ( b & SDL_BUTTON(SDL_BUTTON_LEFT) )
|
||||
{
|
||||
isPressed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if ( btn & Qt::RightButton )
|
||||
{
|
||||
if ( b & SDL_BUTTON(SDL_BUTTON_RIGHT) )
|
||||
{
|
||||
isPressed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if ( btn & Qt::MiddleButton )
|
||||
{
|
||||
if ( b & SDL_BUTTON(SDL_BUTTON_MIDDLE) )
|
||||
{
|
||||
isPressed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return isPressed;
|
||||
}
|
||||
|
||||
void ConsoleViewQWidget_t::getNormalizedCursorPos( double &x, double &y )
|
||||
{
|
||||
QPoint cursor;
|
||||
|
||||
cursor = QCursor::pos();
|
||||
|
||||
//printf("Global Cursor (%i,%i) \n", cursor.x(), cursor.y() );
|
||||
|
||||
cursor = mapFromGlobal( cursor );
|
||||
|
||||
//printf("Window Cursor (%i,%i) \n", cursor.x(), cursor.y() );
|
||||
|
||||
x = (double)(cursor.x() - sx) / (double)rw;
|
||||
y = (double)(cursor.y() - sy) / (double)rh;
|
||||
|
||||
if ( x < 0.0 )
|
||||
{
|
||||
x = 0.0;
|
||||
}
|
||||
else if ( x > 1.0 )
|
||||
{
|
||||
x = 1.0;
|
||||
}
|
||||
if ( y < 0.0 )
|
||||
{
|
||||
y = 0.0;
|
||||
}
|
||||
else if ( y > 1.0 )
|
||||
{
|
||||
y = 1.0;
|
||||
}
|
||||
//printf("Normalized Cursor (%f,%f) \n", x, y );
|
||||
}
|
||||
|
||||
void ConsoleViewQWidget_t::paintEvent(QPaintEvent *event)
|
||||
{
|
||||
QPainter painter(this);
|
||||
int nesWidth = GL_NES_WIDTH;
|
||||
int nesHeight = GL_NES_HEIGHT;
|
||||
float ixScale = 1.0;
|
||||
float iyScale = 1.0;
|
||||
|
||||
if ( nes_shm != nullptr )
|
||||
{
|
||||
nesWidth = nes_shm->video.ncol;
|
||||
nesHeight = nes_shm->video.nrow;
|
||||
ixScale = (float)nes_shm->video.xscale;
|
||||
iyScale = (float)nes_shm->video.yscale;
|
||||
}
|
||||
//printf(" %i x %i \n", nesWidth, nesHeight );
|
||||
float xscaleTmp = (float)view_width / (float)nesWidth;
|
||||
float yscaleTmp = (float)view_height / (float)nesHeight;
|
||||
|
||||
xscaleTmp *= ixScale;
|
||||
yscaleTmp *= iyScale;
|
||||
|
||||
if ( forceAspect )
|
||||
{
|
||||
if ( xscaleTmp < yscaleTmp )
|
||||
{
|
||||
yscaleTmp = xscaleTmp;
|
||||
}
|
||||
else
|
||||
{
|
||||
xscaleTmp = yscaleTmp;
|
||||
}
|
||||
}
|
||||
|
||||
if ( autoScaleEna )
|
||||
{
|
||||
xscale = xscaleTmp;
|
||||
yscale = yscaleTmp;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( xscaleTmp > xscale )
|
||||
{
|
||||
xscaleTmp = xscale;
|
||||
}
|
||||
if ( yscaleTmp > yscale )
|
||||
{
|
||||
yscaleTmp = yscale;
|
||||
}
|
||||
}
|
||||
|
||||
rw=(int)(nesWidth*xscaleTmp/ixScale);
|
||||
rh=(int)(nesHeight*yscaleTmp/iyScale);
|
||||
|
||||
if ( forceAspect )
|
||||
{
|
||||
int iw, ih, ax, ay;
|
||||
|
||||
ax = (int)(aspectX+0.50);
|
||||
ay = (int)(aspectY+0.50);
|
||||
|
||||
iw = rw * ay;
|
||||
ih = rh * ax;
|
||||
|
||||
if ( iw > ih )
|
||||
{
|
||||
rh = (rw * ay) / ax;
|
||||
}
|
||||
else
|
||||
{
|
||||
rw = (rh * ax) / ay;
|
||||
}
|
||||
|
||||
if ( rw > view_width )
|
||||
{
|
||||
rw = view_width;
|
||||
rh = (rw * ay) / ax;
|
||||
}
|
||||
|
||||
if ( rh > view_height )
|
||||
{
|
||||
rh = view_height;
|
||||
rw = (rh * ax) / ay;
|
||||
}
|
||||
}
|
||||
|
||||
if ( rw > view_width ) rw = view_width;
|
||||
if ( rh > view_height) rh = view_height;
|
||||
|
||||
sx=(view_width-rw)/2;
|
||||
sy=(view_height-rh)/2;
|
||||
|
||||
if ( bgColor )
|
||||
{
|
||||
painter.fillRect( 0, 0, view_width, view_height, *bgColor );
|
||||
}
|
||||
else
|
||||
{
|
||||
painter.fillRect( 0, 0, view_width, view_height, Qt::black );
|
||||
}
|
||||
painter.setRenderHint( QPainter::SmoothPixmapTransform, linearFilter );
|
||||
|
||||
int rowPitch = nesWidth * sizeof(uint32_t);
|
||||
|
||||
QImage tmpImage( (const uchar*)localBuf, nesWidth, nesHeight, rowPitch, QImage::Format_ARGB32);
|
||||
|
||||
//SDL_Rect source = {0, 0, nesWidth, nesHeight };
|
||||
QRect dest( sx, sy, rw, rh );
|
||||
|
||||
painter.drawImage( dest, tmpImage );
|
||||
|
||||
videoBufferSwapMark();
|
||||
|
||||
nes_shm->render_count++;
|
||||
}
|
|
@ -0,0 +1,92 @@
|
|||
// ConsoleViewerQWidget.h
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QWidget>
|
||||
#include <QColor>
|
||||
#include <QCursor>
|
||||
#include <QImage>
|
||||
#include <QPaintEvent>
|
||||
#include <QResizeEvent>
|
||||
|
||||
#include "Qt/ConsoleViewerInterface.h"
|
||||
|
||||
class ConsoleViewQWidget_t : public QWidget, public ConsoleViewerBase
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ConsoleViewQWidget_t(QWidget *parent = 0);
|
||||
~ConsoleViewQWidget_t(void);
|
||||
|
||||
int init(void);
|
||||
void reset(void);
|
||||
void cleanup(void);
|
||||
void queueRedraw(void){ update(); };
|
||||
int driver(void){ return VIDEO_DRIVER_QPAINTER; };
|
||||
|
||||
void transfer2LocalBuffer(void);
|
||||
|
||||
void setVsyncEnable( bool ena );
|
||||
void setLinearFilterEnable( bool ena );
|
||||
|
||||
bool getForceAspectOpt(void){ return forceAspect; };
|
||||
void setForceAspectOpt( bool val ){ forceAspect = val; return; };
|
||||
bool getAutoScaleOpt(void){ return autoScaleEna; };
|
||||
void setAutoScaleOpt( bool val ){ autoScaleEna = val; return; };
|
||||
double getScaleX(void){ return xscale; };
|
||||
double getScaleY(void){ return yscale; };
|
||||
void setScaleXY( double xs, double ys );
|
||||
void getNormalizedCursorPos( double &x, double &y );
|
||||
bool getMouseButtonState( unsigned int btn );
|
||||
void setAspectXY( double x, double y );
|
||||
void getAspectXY( double &x, double &y );
|
||||
double getAspectRatio(void);
|
||||
|
||||
void setCursor(const QCursor &c);
|
||||
void setCursor( Qt::CursorShape s );
|
||||
void setBgColor( QColor &c );
|
||||
|
||||
QSize size(void){ return QWidget::size(); };
|
||||
QCursor cursor(void){ return QWidget::cursor(); };
|
||||
void setMinimumSize(const QSize &s){ return QWidget::setMinimumSize(s); };
|
||||
void setMaximumSize(const QSize &s){ return QWidget::setMaximumSize(s); };
|
||||
|
||||
protected:
|
||||
|
||||
void paintEvent(QPaintEvent *event);
|
||||
void showEvent(QShowEvent *event);
|
||||
void resizeEvent(QResizeEvent *event);
|
||||
void mousePressEvent(QMouseEvent * event);
|
||||
void mouseReleaseEvent(QMouseEvent * event);
|
||||
|
||||
int view_width;
|
||||
int view_height;
|
||||
|
||||
double devPixRatio;
|
||||
double aspectRatio;
|
||||
double aspectX;
|
||||
double aspectY;
|
||||
double xscale;
|
||||
double yscale;
|
||||
int rw;
|
||||
int rh;
|
||||
int sx;
|
||||
int sy;
|
||||
int sdlRendW;
|
||||
int sdlRendH;
|
||||
|
||||
bool vsyncEnabled;
|
||||
bool linearFilter;
|
||||
bool forceAspect;
|
||||
bool autoScaleEna;
|
||||
QColor *bgColor;
|
||||
|
||||
uint32_t *localBuf;
|
||||
uint32_t localBufSize;
|
||||
unsigned int mouseButtonMask;
|
||||
|
||||
private slots:
|
||||
};
|
||||
|
|
@ -89,7 +89,7 @@ ConsoleViewSDL_t::ConsoleViewSDL_t(QWidget *parent)
|
|||
|
||||
if ( localBuf )
|
||||
{
|
||||
memset( localBuf, 0, localBufSize );
|
||||
memset32( localBuf, alphaMask, localBufSize );
|
||||
}
|
||||
|
||||
forceAspect = true;
|
||||
|
@ -122,6 +122,8 @@ ConsoleViewSDL_t::ConsoleViewSDL_t(QWidget *parent)
|
|||
|
||||
ConsoleViewSDL_t::~ConsoleViewSDL_t(void)
|
||||
{
|
||||
//printf("Destroying SDL Viewport\n");
|
||||
|
||||
if ( localBuf )
|
||||
{
|
||||
free( localBuf ); localBuf = NULL;
|
||||
|
@ -240,7 +242,7 @@ void ConsoleViewSDL_t::transfer2LocalBuffer(void)
|
|||
}
|
||||
else
|
||||
{
|
||||
memcpy( localBuf, src, cpSize );
|
||||
copyPixels32( dest, src, cpSize, alphaMask);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -10,7 +10,9 @@
|
|||
#include <QResizeEvent>
|
||||
#include <SDL.h>
|
||||
|
||||
class ConsoleViewSDL_t : public QWidget
|
||||
#include "Qt/ConsoleViewerInterface.h"
|
||||
|
||||
class ConsoleViewSDL_t : public QWidget, public ConsoleViewerBase
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
|
@ -22,6 +24,8 @@ class ConsoleViewSDL_t : public QWidget
|
|||
void reset(void);
|
||||
void cleanup(void);
|
||||
void render(void);
|
||||
void queueRedraw(void){ render(); };
|
||||
int driver(void){ return VIDEO_DRIVER_SDL; };
|
||||
|
||||
void transfer2LocalBuffer(void);
|
||||
|
||||
|
@ -44,6 +48,12 @@ class ConsoleViewSDL_t : public QWidget
|
|||
void setCursor(const QCursor &c);
|
||||
void setCursor( Qt::CursorShape s );
|
||||
void setBgColor( QColor &c );
|
||||
|
||||
QSize size(void){ return QWidget::size(); };
|
||||
QCursor cursor(void){ return QWidget::cursor(); };
|
||||
void setMinimumSize(const QSize &s){ return QWidget::setMinimumSize(s); };
|
||||
void setMaximumSize(const QSize &s){ return QWidget::setMaximumSize(s); };
|
||||
|
||||
protected:
|
||||
|
||||
//void paintEvent(QPaintEvent *event);
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
#include <QPixmap>
|
||||
#include <QWindow>
|
||||
#include <QScreen>
|
||||
#include <QSettings>
|
||||
#include <QHeaderView>
|
||||
#include <QFileInfo>
|
||||
#include <QFileDialog>
|
||||
|
@ -53,8 +54,11 @@
|
|||
#include "../../input.h"
|
||||
#include "../../movie.h"
|
||||
#include "../../wave.h"
|
||||
#include "../../state.h"
|
||||
#include "../../profiler.h"
|
||||
#include "../../version.h"
|
||||
#include "common/os_utils.h"
|
||||
#include "utils/timeStamp.h"
|
||||
|
||||
#ifdef _S9XLUA_H
|
||||
#include "../../fceulua.h"
|
||||
|
@ -78,6 +82,7 @@
|
|||
#include "Qt/MoviePlay.h"
|
||||
#include "Qt/MovieRecord.h"
|
||||
#include "Qt/MovieOptions.h"
|
||||
#include "Qt/StateRecorderConf.h"
|
||||
#include "Qt/TimingConf.h"
|
||||
#include "Qt/FrameTimingStats.h"
|
||||
#include "Qt/LuaControl.h"
|
||||
|
@ -110,7 +115,7 @@ consoleWin_t::consoleWin_t(QWidget *parent)
|
|||
: QMainWindow( parent )
|
||||
{
|
||||
int opt, xWinPos = -1, yWinPos = -1, xWinSize = 256, yWinSize = 240;
|
||||
int use_SDL_video = false;
|
||||
int videoDriver = 0;
|
||||
int setFullScreen = false;
|
||||
|
||||
//QString libpath = QLibraryInfo::location(QLibraryInfo::PluginsPath);
|
||||
|
@ -122,6 +127,13 @@ consoleWin_t::consoleWin_t(QWidget *parent)
|
|||
|
||||
printf("Running on Platform: %s\n", QGuiApplication::platformName().toStdString().c_str() );
|
||||
|
||||
QThread *thread = QThread::currentThread();
|
||||
|
||||
if (thread)
|
||||
{
|
||||
thread->setObjectName( QString("MainThread") );
|
||||
}
|
||||
|
||||
QApplication::setStyle( new fceuStyle() );
|
||||
|
||||
initHotKeys();
|
||||
|
@ -129,8 +141,10 @@ consoleWin_t::consoleWin_t(QWidget *parent)
|
|||
firstResize = true;
|
||||
closeRequested = false;
|
||||
errorMsgValid = false;
|
||||
viewport_GL = NULL;
|
||||
viewport_SDL = NULL;
|
||||
viewport_GL = NULL;
|
||||
viewport_SDL = NULL;
|
||||
viewport_QWidget = NULL;
|
||||
viewport_Interface = NULL;
|
||||
|
||||
contextMenuEnable = false;
|
||||
soundUseGlobalFocus = false;
|
||||
|
@ -145,21 +159,9 @@ consoleWin_t::consoleWin_t(QWidget *parent)
|
|||
g_config->getOption( "SDL.AutoHideMenuFullsreen", &autoHideMenuFullscreen );
|
||||
g_config->getOption( "SDL.ContextMenuEnable", &contextMenuEnable );
|
||||
g_config->getOption( "SDL.Sound.UseGlobalFocus", &soundUseGlobalFocus );
|
||||
g_config->getOption ("SDL.VideoDriver", &use_SDL_video);
|
||||
g_config->getOption ("SDL.VideoDriver", &videoDriver);
|
||||
|
||||
if ( use_SDL_video )
|
||||
{
|
||||
viewport_SDL = new ConsoleViewSDL_t(this);
|
||||
|
||||
setCentralWidget(viewport_SDL);
|
||||
}
|
||||
else
|
||||
{
|
||||
viewport_GL = new ConsoleViewGL_t(this);
|
||||
|
||||
setCentralWidget(viewport_GL);
|
||||
}
|
||||
setViewportAspect();
|
||||
loadVideoDriver( videoDriver );
|
||||
|
||||
setWindowTitle( tr(FCEU_NAME_AND_VERSION) );
|
||||
setWindowIcon(QIcon(":fceux1.png"));
|
||||
|
@ -225,13 +227,9 @@ consoleWin_t::consoleWin_t(QWidget *parent)
|
|||
// the window is resized appropriately. On the first resize event,
|
||||
// we will set the minimum viewport size back to 1x values that the
|
||||
// window can be shrunk by dragging lower corner.
|
||||
if ( viewport_GL != NULL )
|
||||
if ( viewport_Interface != NULL )
|
||||
{
|
||||
viewport_GL->setMinimumSize( reqSize );
|
||||
}
|
||||
else if ( viewport_SDL != NULL )
|
||||
{
|
||||
viewport_SDL->setMinimumSize( reqSize );
|
||||
viewport_Interface->setMinimumSize( reqSize );
|
||||
}
|
||||
//this->resize( reqSize );
|
||||
}
|
||||
|
@ -274,17 +272,6 @@ consoleWin_t::~consoleWin_t(void)
|
|||
if ( !isFullScreen() && !isMaximized() )
|
||||
{
|
||||
// Scaling is only saved when applying video settings
|
||||
//if ( viewport_GL != NULL )
|
||||
//{
|
||||
// g_config->setOption( "SDL.XScale", viewport_GL->getScaleX() );
|
||||
// g_config->setOption( "SDL.YScale", viewport_GL->getScaleY() );
|
||||
//}
|
||||
//else if ( viewport_SDL != NULL )
|
||||
//{
|
||||
// g_config->setOption( "SDL.XScale", viewport_SDL->getScaleX() );
|
||||
// g_config->setOption( "SDL.YScale", viewport_SDL->getScaleY() );
|
||||
//}
|
||||
|
||||
g_config->setOption( "SDL.WinPosX" , pos().x() );
|
||||
g_config->setOption( "SDL.WinPosY" , pos().y() );
|
||||
g_config->setOption( "SDL.WinSizeX", w.width() );
|
||||
|
@ -325,14 +312,8 @@ consoleWin_t::~consoleWin_t(void)
|
|||
//fceuWrapperClose();
|
||||
//FCEU_WRAPPER_UNLOCK();
|
||||
|
||||
if ( viewport_GL != NULL )
|
||||
{
|
||||
delete viewport_GL; viewport_GL = NULL;
|
||||
}
|
||||
if ( viewport_SDL != NULL )
|
||||
{
|
||||
delete viewport_SDL; viewport_SDL = NULL;
|
||||
}
|
||||
unloadVideoDriver();
|
||||
|
||||
delete mutex;
|
||||
|
||||
// LoadGame() checks for an IP and if it finds one begins a network session
|
||||
|
@ -365,26 +346,18 @@ int consoleWin_t::videoInit(void)
|
|||
{
|
||||
int ret = 0;
|
||||
|
||||
if ( viewport_SDL )
|
||||
if (viewport_Interface)
|
||||
{
|
||||
ret = viewport_SDL->init();
|
||||
}
|
||||
else if ( viewport_GL )
|
||||
{
|
||||
ret = viewport_GL->init();
|
||||
ret = viewport_Interface->init();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void consoleWin_t::videoReset(void)
|
||||
{
|
||||
if ( viewport_SDL )
|
||||
if (viewport_Interface)
|
||||
{
|
||||
viewport_SDL->reset();
|
||||
}
|
||||
else if ( viewport_GL )
|
||||
{
|
||||
viewport_GL->reset();
|
||||
viewport_Interface->reset();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -487,21 +460,13 @@ QSize consoleWin_t::calcRequiredSize(void)
|
|||
|
||||
w = size();
|
||||
|
||||
if ( viewport_GL )
|
||||
if ( viewport_Interface )
|
||||
{
|
||||
v = viewport_GL->size();
|
||||
forceAspect = viewport_GL->getForceAspectOpt();
|
||||
aspectRatio = viewport_GL->getAspectRatio();
|
||||
xscale = viewport_GL->getScaleX();
|
||||
yscale = viewport_GL->getScaleY();
|
||||
}
|
||||
else if ( viewport_SDL )
|
||||
{
|
||||
v = viewport_SDL->size();
|
||||
forceAspect = viewport_SDL->getForceAspectOpt();
|
||||
aspectRatio = viewport_SDL->getAspectRatio();
|
||||
xscale = viewport_SDL->getScaleX();
|
||||
yscale = viewport_SDL->getScaleY();
|
||||
v = viewport_Interface->size();
|
||||
forceAspect = viewport_Interface->getForceAspectOpt();
|
||||
aspectRatio = viewport_Interface->getAspectRatio();
|
||||
xscale = viewport_Interface->getScaleX();
|
||||
yscale = viewport_Interface->getScaleY();
|
||||
}
|
||||
|
||||
dw = 0;
|
||||
|
@ -572,13 +537,9 @@ void consoleWin_t::setViewportAspect(void)
|
|||
break;
|
||||
}
|
||||
|
||||
if ( viewport_GL )
|
||||
if (viewport_Interface)
|
||||
{
|
||||
viewport_GL->setAspectXY( x, y );
|
||||
}
|
||||
else if ( viewport_SDL )
|
||||
{
|
||||
viewport_SDL->setAspectXY( x, y );
|
||||
viewport_Interface->setAspectXY( x, y );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -648,25 +609,17 @@ void consoleWin_t::loadCursor(void)
|
|||
|
||||
void consoleWin_t::setViewerCursor( QCursor s )
|
||||
{
|
||||
if ( viewport_GL )
|
||||
if (viewport_Interface)
|
||||
{
|
||||
viewport_GL->setCursor(s);
|
||||
}
|
||||
else if ( viewport_SDL )
|
||||
{
|
||||
viewport_SDL->setCursor(s);
|
||||
viewport_Interface->setCursor(s);
|
||||
}
|
||||
}
|
||||
|
||||
void consoleWin_t::setViewerCursor( Qt::CursorShape s )
|
||||
{
|
||||
if ( viewport_GL )
|
||||
if (viewport_Interface)
|
||||
{
|
||||
viewport_GL->setCursor(s);
|
||||
}
|
||||
else if ( viewport_SDL )
|
||||
{
|
||||
viewport_SDL->setCursor(s);
|
||||
viewport_Interface->setCursor(s);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -674,13 +627,9 @@ Qt::CursorShape consoleWin_t::getViewerCursor(void)
|
|||
{
|
||||
Qt::CursorShape s = Qt::ArrowCursor;
|
||||
|
||||
if ( viewport_GL )
|
||||
if (viewport_Interface)
|
||||
{
|
||||
s = viewport_GL->cursor().shape();
|
||||
}
|
||||
else if ( viewport_SDL )
|
||||
{
|
||||
s = viewport_SDL->cursor().shape();
|
||||
s = viewport_Interface->cursor().shape();
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
@ -692,14 +641,11 @@ void consoleWin_t::resizeEvent(QResizeEvent *event)
|
|||
// We are assuming that window has been exposed and all sizing of menu is finished
|
||||
// Restore minimum sizes to 1x values after first resize event so that
|
||||
// window is still able to be shrunk by dragging lower corners.
|
||||
if ( viewport_GL != NULL )
|
||||
if (viewport_Interface)
|
||||
{
|
||||
viewport_GL->setMinimumSize( QSize( 256, 224 ) );
|
||||
}
|
||||
else if ( viewport_SDL != NULL )
|
||||
{
|
||||
viewport_SDL->setMinimumSize( QSize( 256, 224 ) );
|
||||
viewport_Interface->setMinimumSize( QSize( 256, 224 ) );
|
||||
}
|
||||
|
||||
firstResize = false;
|
||||
}
|
||||
//printf("%i x %i \n", event->size().width(), event->size().height() );
|
||||
|
@ -784,9 +730,21 @@ void consoleWin_t::dropEvent(QDropEvent *event)
|
|||
QFileInfo fi( filename );
|
||||
QString suffix = fi.suffix();
|
||||
|
||||
bool isStateSaveFile = (suffix.size() == 3) &&
|
||||
(suffix[0] == 'f') && (suffix[1] == 'c') &&
|
||||
( (suffix[2] == 's') || suffix[2].isDigit() );
|
||||
|
||||
//printf("DragNDrop Suffix: %s\n", suffix.toStdString().c_str() );
|
||||
|
||||
if ( suffix.compare("lua", Qt::CaseInsensitive) == 0 )
|
||||
if (isStateSaveFile)
|
||||
{
|
||||
FCEU_WRAPPER_LOCK();
|
||||
FCEUI_LoadState( filename.toStdString().c_str() );
|
||||
FCEU_WRAPPER_UNLOCK();
|
||||
|
||||
event->accept();
|
||||
}
|
||||
else if ( suffix.compare("lua", Qt::CaseInsensitive) == 0 )
|
||||
{
|
||||
int luaLoadSuccess;
|
||||
|
||||
|
@ -920,6 +878,9 @@ void consoleWin_t::initHotKeys(void)
|
|||
connect( Hotkeys[ HK_LOAD_STATE_7 ].getShortcut(), SIGNAL(activated()), this, SLOT(loadState7(void)) );
|
||||
connect( Hotkeys[ HK_LOAD_STATE_8 ].getShortcut(), SIGNAL(activated()), this, SLOT(loadState8(void)) );
|
||||
connect( Hotkeys[ HK_LOAD_STATE_9 ].getShortcut(), SIGNAL(activated()), this, SLOT(loadState9(void)) );
|
||||
|
||||
connect( Hotkeys[ HK_LOAD_PREV_STATE ].getShortcut(), SIGNAL(activated()), this, SLOT(loadPrevState(void)) );
|
||||
connect( Hotkeys[ HK_LOAD_NEXT_STATE ].getShortcut(), SIGNAL(activated()), this, SLOT(loadNextState(void)) );
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
void consoleWin_t::createMainMenu(void)
|
||||
|
@ -1214,6 +1175,15 @@ void consoleWin_t::createMainMenu(void)
|
|||
|
||||
optMenu->addAction(timingConfig);
|
||||
|
||||
// Options -> State Recorder Config
|
||||
stateRecordConfig = new QAction(tr("&State Recorder Config"), this);
|
||||
//stateRecordConfig->setShortcut( QKeySequence(tr("Ctrl+C")));
|
||||
stateRecordConfig->setStatusTip(tr("State Recorder Configure"));
|
||||
stateRecordConfig->setIcon( QIcon(":icons/media-record.png") );
|
||||
connect(stateRecordConfig, SIGNAL(triggered()), this, SLOT(openStateRecorderConfWin(void)) );
|
||||
|
||||
optMenu->addAction(stateRecordConfig);
|
||||
|
||||
// Options -> Movie Options
|
||||
movieConfig = new QAction(tr("&Movie Options"), this);
|
||||
//movieConfig->setShortcut( QKeySequence(tr("Ctrl+C")));
|
||||
|
@ -1982,85 +1952,164 @@ void consoleWin_t::createMainMenu(void)
|
|||
#endif
|
||||
};
|
||||
//---------------------------------------------------------------------------
|
||||
//---------------------------------------------------------------------------
|
||||
int consoleWin_t::unloadVideoDriver(void)
|
||||
{
|
||||
viewport_Interface = NULL;
|
||||
|
||||
if (viewport_GL != NULL)
|
||||
{
|
||||
if ( viewport_GL == centralWidget() )
|
||||
{
|
||||
takeCentralWidget();
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Error: Central Widget Failed!\n");
|
||||
}
|
||||
viewport_GL->deleteLater();
|
||||
|
||||
viewport_GL = NULL;
|
||||
}
|
||||
|
||||
if (viewport_SDL != NULL)
|
||||
{
|
||||
if ( viewport_SDL == centralWidget() )
|
||||
{
|
||||
takeCentralWidget();
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Error: Central Widget Failed!\n");
|
||||
}
|
||||
viewport_SDL->deleteLater();
|
||||
|
||||
viewport_SDL = NULL;
|
||||
}
|
||||
|
||||
if (viewport_QWidget != NULL)
|
||||
{
|
||||
if ( viewport_QWidget == centralWidget() )
|
||||
{
|
||||
takeCentralWidget();
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Error: Central Widget Failed!\n");
|
||||
}
|
||||
viewport_QWidget->deleteLater();
|
||||
|
||||
viewport_QWidget = NULL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
void consoleWin_t::videoDriverDestroyed(QObject* obj)
|
||||
{
|
||||
if (viewport_GL == obj)
|
||||
{
|
||||
//printf("GL Video Driver Destroyed\n");
|
||||
|
||||
if (viewport_Interface == static_cast<ConsoleViewerBase*>(viewport_GL))
|
||||
{
|
||||
viewport_Interface = NULL;
|
||||
}
|
||||
viewport_GL = NULL;
|
||||
}
|
||||
|
||||
if (viewport_SDL == obj)
|
||||
{
|
||||
//printf("SDL Video Driver Destroyedi\n");
|
||||
|
||||
if (viewport_Interface == static_cast<ConsoleViewerBase*>(viewport_SDL))
|
||||
{
|
||||
viewport_Interface = NULL;
|
||||
}
|
||||
viewport_SDL = NULL;
|
||||
}
|
||||
|
||||
if (viewport_QWidget == obj)
|
||||
{
|
||||
//printf("QPainter Video Driver Destroyed\n");
|
||||
|
||||
if (viewport_Interface == static_cast<ConsoleViewerBase*>(viewport_QWidget))
|
||||
{
|
||||
viewport_Interface = NULL;
|
||||
}
|
||||
viewport_QWidget = NULL;
|
||||
}
|
||||
printf("Video Driver Destroyed: %p\n", obj);
|
||||
//printf("viewport_GL: %p\n", viewport_GL);
|
||||
//printf("viewport_SDL: %p\n", viewport_SDL);
|
||||
//printf("viewport_Qt: %p\n", viewport_QWidget);
|
||||
//printf("viewport_Interface: %p\n", viewport_Interface);
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
int consoleWin_t::loadVideoDriver( int driverId, bool force )
|
||||
{
|
||||
if ( driverId )
|
||||
{ // SDL Driver
|
||||
if ( viewport_SDL != NULL )
|
||||
if (viewport_Interface)
|
||||
{
|
||||
if (viewport_Interface->driver() == driverId)
|
||||
{ // Already Loaded
|
||||
if ( force )
|
||||
if (force)
|
||||
{
|
||||
if ( viewport_SDL == centralWidget() )
|
||||
{
|
||||
takeCentralWidget();
|
||||
}
|
||||
delete viewport_SDL;
|
||||
|
||||
viewport_SDL = NULL;
|
||||
unloadVideoDriver();
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if ( viewport_GL != NULL )
|
||||
{
|
||||
if ( viewport_GL == centralWidget() )
|
||||
{
|
||||
takeCentralWidget();
|
||||
}
|
||||
delete viewport_GL;
|
||||
|
||||
viewport_GL = NULL;
|
||||
}
|
||||
|
||||
viewport_SDL = new ConsoleViewSDL_t(this);
|
||||
|
||||
setCentralWidget(viewport_SDL);
|
||||
|
||||
setViewportAspect();
|
||||
|
||||
viewport_SDL->init();
|
||||
|
||||
}
|
||||
else
|
||||
{ // OpenGL Driver
|
||||
if ( viewport_GL != NULL )
|
||||
{ // Already Loaded
|
||||
if ( force )
|
||||
{
|
||||
if ( viewport_GL == centralWidget() )
|
||||
{
|
||||
takeCentralWidget();
|
||||
}
|
||||
delete viewport_GL;
|
||||
|
||||
viewport_GL = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if ( viewport_SDL != NULL )
|
||||
switch ( driverId )
|
||||
{
|
||||
case ConsoleViewerBase::VIDEO_DRIVER_SDL:
|
||||
{
|
||||
if ( viewport_SDL == centralWidget() )
|
||||
{
|
||||
takeCentralWidget();
|
||||
}
|
||||
delete viewport_SDL;
|
||||
viewport_SDL = new ConsoleViewSDL_t(this);
|
||||
|
||||
viewport_SDL = NULL;
|
||||
viewport_Interface = static_cast<ConsoleViewerBase*>(viewport_SDL);
|
||||
|
||||
setCentralWidget(viewport_SDL);
|
||||
|
||||
setViewportAspect();
|
||||
|
||||
viewport_SDL->init();
|
||||
|
||||
connect( viewport_SDL, SIGNAL(destroyed(QObject*)), this, SLOT(videoDriverDestroyed(QObject*)) );
|
||||
}
|
||||
viewport_GL = new ConsoleViewGL_t(this);
|
||||
break;
|
||||
case ConsoleViewerBase::VIDEO_DRIVER_OPENGL:
|
||||
{
|
||||
viewport_GL = new ConsoleViewGL_t(this);
|
||||
|
||||
setCentralWidget(viewport_GL);
|
||||
viewport_Interface = static_cast<ConsoleViewerBase*>(viewport_GL);
|
||||
|
||||
setViewportAspect();
|
||||
setCentralWidget(viewport_GL);
|
||||
|
||||
viewport_GL->init();
|
||||
setViewportAspect();
|
||||
|
||||
viewport_GL->init();
|
||||
|
||||
connect( viewport_GL, SIGNAL(destroyed(QObject*)), this, SLOT(videoDriverDestroyed(QObject*)) );
|
||||
}
|
||||
break;
|
||||
default:
|
||||
case ConsoleViewerBase::VIDEO_DRIVER_QPAINTER:
|
||||
{
|
||||
viewport_QWidget = new ConsoleViewQWidget_t(this);
|
||||
|
||||
viewport_Interface = static_cast<ConsoleViewerBase*>(viewport_QWidget);
|
||||
|
||||
setCentralWidget(viewport_QWidget);
|
||||
|
||||
setViewportAspect();
|
||||
|
||||
viewport_QWidget->init();
|
||||
|
||||
connect( viewport_QWidget, SIGNAL(destroyed(QObject*)), this, SLOT(videoDriverDestroyed(QObject*)) );
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// Reload Viewport Cursor Type and Visibility
|
||||
|
@ -2256,15 +2305,10 @@ void consoleWin_t::videoBgColorChanged( QColor &c )
|
|||
{
|
||||
//printf("Color Changed\n");
|
||||
|
||||
if ( viewport_GL )
|
||||
if ( viewport_Interface )
|
||||
{
|
||||
viewport_GL->setBgColor(c);
|
||||
viewport_GL->update();
|
||||
}
|
||||
else if ( viewport_SDL )
|
||||
{
|
||||
viewport_SDL->setBgColor(c);
|
||||
viewport_SDL->render();
|
||||
viewport_Interface->setBgColor(c);
|
||||
viewport_Interface->queueRedraw();
|
||||
}
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
|
@ -2282,6 +2326,7 @@ int consoleWin_t::showListSelectDialog( const char *title, std::vector <std::st
|
|||
QPushButton *okButton, *cancelButton;
|
||||
QTreeWidget *tree;
|
||||
QTreeWidgetItem *item;
|
||||
QSettings settings;
|
||||
|
||||
dialog.setWindowTitle( tr(title) );
|
||||
|
||||
|
@ -2329,8 +2374,15 @@ int consoleWin_t::showListSelectDialog( const char *title, std::vector <std::st
|
|||
|
||||
dialog.setLayout( mainLayout );
|
||||
|
||||
// Restore Window Geometry
|
||||
dialog.restoreGeometry(settings.value("ArchiveViewer/geometry").toByteArray());
|
||||
|
||||
// Run Dialog Execution Loop
|
||||
ret = dialog.exec();
|
||||
|
||||
// Save Window Geometry
|
||||
settings.setValue("ArchiveViewer/geometry", dialog.saveGeometry());
|
||||
|
||||
if ( ret == QDialog::Accepted )
|
||||
{
|
||||
idx = 0;
|
||||
|
@ -2362,7 +2414,7 @@ void consoleWin_t::openROMFile(void)
|
|||
QDir d;
|
||||
|
||||
const QStringList filters(
|
||||
{ "All Useable files (*.nes *.NES *.nsf *.NSF *.fds *.FDS *.unf *.UNF *.unif *.UNIF *.zip *.ZIP)",
|
||||
{ "All Useable files (*.nes *.NES *.nsf *.NSF *.fds *.FDS *.unf *.UNF *.unif *.UNIF *.zip *.ZIP, *.7z *.7zip)",
|
||||
"NES files (*.nes *.NES)",
|
||||
"NSF files (*.nsf *.NSF)",
|
||||
"UNF files (*.unf *.UNF *.unif *.UNIF)",
|
||||
|
@ -2729,6 +2781,20 @@ void consoleWin_t::loadState7(void){ loadState(7); }
|
|||
void consoleWin_t::loadState8(void){ loadState(8); }
|
||||
void consoleWin_t::loadState9(void){ loadState(9); }
|
||||
|
||||
void consoleWin_t::loadPrevState(void)
|
||||
{
|
||||
FCEU_WRAPPER_LOCK();
|
||||
FCEU_StateRecorderLoadPrevState();
|
||||
FCEU_WRAPPER_UNLOCK();
|
||||
}
|
||||
|
||||
void consoleWin_t::loadNextState(void)
|
||||
{
|
||||
FCEU_WRAPPER_LOCK();
|
||||
FCEU_StateRecorderLoadNextState();
|
||||
FCEU_WRAPPER_UNLOCK();
|
||||
}
|
||||
|
||||
void consoleWin_t::quickSave(void)
|
||||
{
|
||||
FCEU_WRAPPER_LOCK();
|
||||
|
@ -2858,6 +2924,10 @@ void consoleWin_t::takeScreenShot(void)
|
|||
{
|
||||
image = screen->grabWindow( viewport_SDL->winId() );
|
||||
}
|
||||
else if ( viewport_QWidget )
|
||||
{
|
||||
image = screen->grabWindow( viewport_QWidget->winId() );
|
||||
}
|
||||
|
||||
for (u = 0; u < 99999; ++u)
|
||||
{
|
||||
|
@ -3173,17 +3243,11 @@ void consoleWin_t::winResizeIx(int iscale)
|
|||
|
||||
w = size();
|
||||
|
||||
if ( viewport_GL )
|
||||
if ( viewport_Interface )
|
||||
{
|
||||
v = viewport_GL->size();
|
||||
aspectRatio = viewport_GL->getAspectRatio();
|
||||
forceAspect = viewport_GL->getForceAspectOpt();
|
||||
}
|
||||
else if ( viewport_SDL )
|
||||
{
|
||||
v = viewport_SDL->size();
|
||||
aspectRatio = viewport_SDL->getAspectRatio();
|
||||
forceAspect = viewport_SDL->getForceAspectOpt();
|
||||
v = viewport_Interface->size();
|
||||
aspectRatio = viewport_Interface->getAspectRatio();
|
||||
forceAspect = viewport_Interface->getForceAspectOpt();
|
||||
}
|
||||
|
||||
dw = w.width() - v.width();
|
||||
|
@ -3846,6 +3910,15 @@ void consoleWin_t::toggleTurboMode(void)
|
|||
NoWaiting ^= 1;
|
||||
}
|
||||
|
||||
void consoleWin_t::openStateRecorderConfWin(void)
|
||||
{
|
||||
StateRecorderDialog_t *win;
|
||||
|
||||
win = new StateRecorderDialog_t(this);
|
||||
|
||||
win->show();
|
||||
}
|
||||
|
||||
void consoleWin_t::openMovie(void)
|
||||
{
|
||||
MoviePlayDialog_t *win;
|
||||
|
@ -4435,19 +4508,15 @@ int consoleWin_t::getPeriodicInterval(void)
|
|||
|
||||
void consoleWin_t::transferVideoBuffer(void)
|
||||
{
|
||||
FCEU_PROFILE_FUNC(prof, "VideoXfer");
|
||||
if ( nes_shm->blitUpdated )
|
||||
{
|
||||
nes_shm->blitUpdated = 0;
|
||||
|
||||
if ( viewport_SDL )
|
||||
if (viewport_Interface)
|
||||
{
|
||||
viewport_SDL->transfer2LocalBuffer();
|
||||
viewport_SDL->render();
|
||||
}
|
||||
else if ( viewport_GL )
|
||||
{
|
||||
viewport_GL->transfer2LocalBuffer();
|
||||
viewport_GL->update();
|
||||
viewport_Interface->transfer2LocalBuffer();
|
||||
viewport_Interface->queueRedraw();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4476,6 +4545,7 @@ void consoleWin_t::emuFrameFinish(void)
|
|||
|
||||
void consoleWin_t::updatePeriodic(void)
|
||||
{
|
||||
FCEU_PROFILE_FUNC(prof, "updatePeriodic");
|
||||
static bool eventProcessingInProg = false;
|
||||
|
||||
if ( eventProcessingInProg )
|
||||
|
@ -4551,6 +4621,9 @@ void consoleWin_t::updatePeriodic(void)
|
|||
|
||||
updateCounter++;
|
||||
|
||||
#ifdef __FCEU_PROFILER_ENABLE__
|
||||
FCEU_profiler_log_thread_activity();
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -4561,6 +4634,7 @@ emulatorThread_t::emulatorThread_t( QObject *parent )
|
|||
pself = 0;
|
||||
#endif
|
||||
|
||||
setObjectName( QString("EmulationThread") );
|
||||
}
|
||||
|
||||
#if defined(__linux__)
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include "Qt/ColorMenu.h"
|
||||
#include "Qt/ConsoleViewerGL.h"
|
||||
#include "Qt/ConsoleViewerSDL.h"
|
||||
#include "Qt/ConsoleViewerQWidget.h"
|
||||
#include "Qt/GamePadConf.h"
|
||||
#include "Qt/AviRecord.h"
|
||||
|
||||
|
@ -126,8 +127,10 @@ class consoleWin_t : public QMainWindow
|
|||
consoleWin_t(QWidget *parent = 0);
|
||||
~consoleWin_t(void);
|
||||
|
||||
ConsoleViewGL_t *viewport_GL;
|
||||
ConsoleViewSDL_t *viewport_SDL;
|
||||
ConsoleViewGL_t *viewport_GL;
|
||||
ConsoleViewSDL_t *viewport_SDL;
|
||||
ConsoleViewQWidget_t *viewport_QWidget;
|
||||
ConsoleViewerBase *viewport_Interface;
|
||||
|
||||
void setCyclePeriodms( int ms );
|
||||
|
||||
|
@ -155,6 +158,7 @@ class consoleWin_t : public QMainWindow
|
|||
#endif
|
||||
|
||||
int loadVideoDriver( int driverId, bool force = false );
|
||||
int unloadVideoDriver(void);
|
||||
|
||||
double getRefreshRate(void){ return refreshRate; }
|
||||
|
||||
|
@ -211,6 +215,7 @@ class consoleWin_t : public QMainWindow
|
|||
QAction *hotkeyConfig;
|
||||
QAction *paletteConfig;
|
||||
QAction *guiConfig;
|
||||
QAction *stateRecordConfig;
|
||||
QAction *timingConfig;
|
||||
QAction *movieConfig;
|
||||
QAction *autoResume;
|
||||
|
@ -344,6 +349,7 @@ class consoleWin_t : public QMainWindow
|
|||
void openPaletteConfWin(void);
|
||||
void openGuiConfWin(void);
|
||||
void openTimingConfWin(void);
|
||||
void openStateRecorderConfWin(void);
|
||||
void openPaletteEditorWin(void);
|
||||
void openAviRiffViewer(void);
|
||||
void openTimingStatWin(void);
|
||||
|
@ -439,6 +445,8 @@ class consoleWin_t : public QMainWindow
|
|||
void loadState7(void);
|
||||
void loadState8(void);
|
||||
void loadState9(void);
|
||||
void loadPrevState(void);
|
||||
void loadNextState(void);
|
||||
void mainMenuOpen(void);
|
||||
void mainMenuClose(void);
|
||||
void warnAmbiguousShortcut( QShortcut*);
|
||||
|
@ -459,6 +467,7 @@ class consoleWin_t : public QMainWindow
|
|||
void toggleUseBgPaletteForVideo(bool);
|
||||
void videoBgColorChanged( QColor &c );
|
||||
void loadRomRequestCB( QString s );
|
||||
void videoDriverDestroyed( QObject *obj );
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -126,7 +126,6 @@ int openFamilyKeyboardDialog(QWidget *parent)
|
|||
{
|
||||
fkbWin->activateWindow();
|
||||
fkbWin->raise();
|
||||
fkbWin->setFocus();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -42,6 +42,7 @@
|
|||
#include "Qt/config.h"
|
||||
#include "Qt/keyscan.h"
|
||||
#include "Qt/fceuWrapper.h"
|
||||
#include "Qt/CheatsConf.h"
|
||||
#include "Qt/HexEditor.h"
|
||||
#include "Qt/GameGenie.h"
|
||||
|
||||
|
@ -278,6 +279,7 @@ void GameGenieDialog_t::addCheatClicked(void)
|
|||
|
||||
FCEU_WRAPPER_LOCK();
|
||||
FCEUI_AddCheat( name.c_str(), a, v, c, 1 );
|
||||
updateCheatDialog();
|
||||
FCEU_WRAPPER_UNLOCK();
|
||||
|
||||
}
|
||||
|
|
|
@ -989,6 +989,8 @@ static int readQPaletteFromFile( const char *path, QPalette *pal )
|
|||
|
||||
rTxtMatch = NULL;
|
||||
|
||||
r = QPalette::WindowText;
|
||||
|
||||
for (k=0; k<30; k++)
|
||||
{
|
||||
|
||||
|
|
|
@ -399,7 +399,7 @@ static int writeMem( int mode, unsigned int addr, int value )
|
|||
{
|
||||
if (debuggerWindowIsOpen())
|
||||
{
|
||||
updateAllDebuggerWindows();
|
||||
updateAllDebuggerWindows(QAsmView::UPDATE_NO_SCROLL);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1853,7 +1853,7 @@ void HexEditorDialog_t::openDebugSymbolEditWindow( int addr )
|
|||
|
||||
if ( ret == QDialog::Accepted )
|
||||
{
|
||||
updateAllDebuggerWindows();
|
||||
updateAllDebuggerWindows(QAsmView::UPDATE_NO_SCROLL);
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
|
@ -2777,7 +2777,13 @@ void QHexEdit::keyPressEvent(QKeyEvent *event)
|
|||
event->accept();
|
||||
}
|
||||
else
|
||||
{
|
||||
{ // Use the input text to modify the values in the editor area.
|
||||
|
||||
if (event->text().isEmpty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int key;
|
||||
if ( cursorPosX >= 32 )
|
||||
{ // Edit Area is ASCII
|
||||
|
@ -2830,6 +2836,7 @@ void QHexEdit::keyPressEvent(QKeyEvent *event)
|
|||
}
|
||||
else
|
||||
{ // Edit Area is Hex
|
||||
|
||||
key = int(event->text()[0].toUpper().toLatin1());
|
||||
|
||||
if ( ::isxdigit( key ) )
|
||||
|
@ -4222,7 +4229,6 @@ int hexEditorOpenFromDebugger( int mode, int addr )
|
|||
{
|
||||
win->activateWindow();
|
||||
win->raise();
|
||||
win->setFocus();
|
||||
}
|
||||
|
||||
win->editor->setMode( mode );
|
||||
|
|
|
@ -230,10 +230,14 @@ MsgLogViewDialog_t::MsgLogViewDialog_t(QWidget *parent)
|
|||
|
||||
updateTimer->start(500); // 2hz
|
||||
|
||||
FCEU_WRAPPER_LOCK();
|
||||
|
||||
msgLog.loadTextViewer(txtView);
|
||||
|
||||
totalLines = msgLog.getTotalLineCount();
|
||||
|
||||
FCEU_WRAPPER_UNLOCK();
|
||||
|
||||
txtView->moveCursor(QTextCursor::End);
|
||||
|
||||
restoreGeometry(settings.value("MsgLogWindow/geometry").toByteArray());
|
||||
|
|
|
@ -108,7 +108,6 @@ int openNameTableViewWindow( QWidget *parent )
|
|||
{
|
||||
nameTableViewWindow->activateWindow();
|
||||
nameTableViewWindow->raise();
|
||||
nameTableViewWindow->setFocus();
|
||||
return -1;
|
||||
}
|
||||
initNameTableViewer();
|
||||
|
|
|
@ -0,0 +1,674 @@
|
|||
/* FCE Ultra - NES/Famicom Emulator
|
||||
*
|
||||
* Copyright notice for this file:
|
||||
* Copyright (C) 2022 thor2016
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
// StateRecorderConf.cpp
|
||||
//
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <string>
|
||||
|
||||
#include <QCloseEvent>
|
||||
#include <QGridLayout>
|
||||
#include <QSettings>
|
||||
#include <QMessageBox>
|
||||
|
||||
#include "Qt/throttle.h"
|
||||
#include "Qt/fceuWrapper.h"
|
||||
#include "Qt/StateRecorderConf.h"
|
||||
|
||||
#include "../../fceu.h"
|
||||
#include "../../state.h"
|
||||
#include "../../driver.h"
|
||||
#include "../../emufile.h"
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
StateRecorderDialog_t::StateRecorderDialog_t(QWidget *parent)
|
||||
: QDialog(parent)
|
||||
{
|
||||
QVBoxLayout *mainLayout, *vbox1;
|
||||
QHBoxLayout *hbox, *hbox1;
|
||||
QGroupBox *frame, *frame1;
|
||||
QGridLayout *grid, *memStatsGrid, *sysStatusGrid;
|
||||
QSettings settings;
|
||||
int opt;
|
||||
|
||||
setWindowTitle("State Recorder Config");
|
||||
|
||||
mainLayout = new QVBoxLayout();
|
||||
grid = new QGridLayout();
|
||||
|
||||
recorderEnable = new QCheckBox(tr("Auto Start Recorder at ROM Load"));
|
||||
snapFrames = new QSpinBox();
|
||||
snapMinutes = new QSpinBox();
|
||||
snapSeconds = new QSpinBox();
|
||||
historyDuration = new QSpinBox();
|
||||
snapFrameSelBtn = new QRadioButton( tr("By Frames") );
|
||||
snapTimeSelBtn = new QRadioButton( tr("By Time") );
|
||||
|
||||
recorderEnable->setChecked( FCEU_StateRecorderIsEnabled() );
|
||||
|
||||
connect( recorderEnable, SIGNAL(stateChanged(int)), this, SLOT(enableChanged(int)) );
|
||||
|
||||
snapFrames->setMinimum(1);
|
||||
snapFrames->setMaximum(10000);
|
||||
snapSeconds->setMinimum(0);
|
||||
snapSeconds->setMaximum(60);
|
||||
snapMinutes->setMinimum(0);
|
||||
snapMinutes->setMaximum(60);
|
||||
historyDuration->setMinimum(1);
|
||||
historyDuration->setMaximum(180);
|
||||
|
||||
opt = 10;
|
||||
g_config->getOption("SDL.StateRecorderFramesBetweenSnaps", &opt);
|
||||
snapFrames->setValue(opt);
|
||||
|
||||
opt = 15;
|
||||
g_config->getOption("SDL.StateRecorderHistoryDurationMin", &opt );
|
||||
historyDuration->setValue(opt);
|
||||
|
||||
opt = 0;
|
||||
g_config->getOption("SDL.StateRecorderTimeBetweenSnapsMin", &opt);
|
||||
snapMinutes->setValue(opt);
|
||||
|
||||
opt = 3;
|
||||
g_config->getOption("SDL.StateRecorderTimeBetweenSnapsSec", &opt);
|
||||
snapSeconds->setValue(opt);
|
||||
|
||||
opt = 0;
|
||||
g_config->getOption("SDL.StateRecorderTimingMode", &opt);
|
||||
|
||||
snapFrameSelBtn->setChecked(opt == 0);
|
||||
snapTimeSelBtn->setChecked(opt == 1);
|
||||
snapUseTime = opt ? true : false;
|
||||
|
||||
connect( snapFrames , SIGNAL(valueChanged(int)), this, SLOT(spinBoxValueChanged(int)) );
|
||||
connect( snapSeconds, SIGNAL(valueChanged(int)), this, SLOT(spinBoxValueChanged(int)) );
|
||||
connect( snapMinutes, SIGNAL(valueChanged(int)), this, SLOT(spinBoxValueChanged(int)) );
|
||||
connect( historyDuration, SIGNAL(valueChanged(int)), this, SLOT(spinBoxValueChanged(int)) );
|
||||
|
||||
frame = new QGroupBox(tr("Retain History For:"));
|
||||
hbox = new QHBoxLayout();
|
||||
|
||||
hbox->addWidget( historyDuration);
|
||||
hbox->addWidget( new QLabel( tr("Minutes") ) );
|
||||
|
||||
frame->setLayout(hbox);
|
||||
|
||||
grid->addWidget( recorderEnable, 0, 0 );
|
||||
grid->addWidget( frame , 1, 0 );
|
||||
|
||||
frame = new QGroupBox(tr("Compression Level:"));
|
||||
hbox = new QHBoxLayout();
|
||||
|
||||
cmprLvlCbox = new QComboBox();
|
||||
cmprLvlCbox->addItem( tr("0 - None"), 0 );
|
||||
cmprLvlCbox->addItem( tr("1"), 1 );
|
||||
cmprLvlCbox->addItem( tr("2"), 2 );
|
||||
cmprLvlCbox->addItem( tr("3"), 3 );
|
||||
cmprLvlCbox->addItem( tr("4"), 4 );
|
||||
cmprLvlCbox->addItem( tr("5"), 5 );
|
||||
cmprLvlCbox->addItem( tr("6"), 6 );
|
||||
cmprLvlCbox->addItem( tr("7"), 7 );
|
||||
cmprLvlCbox->addItem( tr("8"), 8 );
|
||||
cmprLvlCbox->addItem( tr("9 - Max"), 9 );
|
||||
|
||||
opt = 0;
|
||||
g_config->getOption("SDL.StateRecorderCompressionLevel", &opt);
|
||||
cmprLvlCbox->setCurrentIndex(opt);
|
||||
|
||||
connect( cmprLvlCbox, SIGNAL(currentIndexChanged(int)), this, SLOT(compressionLevelChanged(int)) );
|
||||
|
||||
hbox->addWidget(cmprLvlCbox);
|
||||
|
||||
frame->setLayout(hbox);
|
||||
grid->addWidget( frame, 1, 1 );
|
||||
|
||||
frame1 = new QGroupBox(tr("Snapshot Timing Setting:"));
|
||||
hbox1 = new QHBoxLayout();
|
||||
frame1->setLayout(hbox1);
|
||||
grid->addWidget( frame1, 2, 0, 1, 2 );
|
||||
|
||||
g_config->getOption("SDL.StateRecorderTimingMode", &opt);
|
||||
|
||||
hbox1->addWidget( snapFrameSelBtn );
|
||||
hbox1->addWidget( snapTimeSelBtn );
|
||||
|
||||
snapFramesGroup = new QGroupBox(tr("Frames Between Snapshots:"));
|
||||
hbox1 = new QHBoxLayout();
|
||||
snapFramesGroup->setLayout(hbox1);
|
||||
snapFramesGroup->setEnabled(snapFrameSelBtn->isChecked());
|
||||
grid->addWidget( snapFramesGroup, 3, 0, 1, 2 );
|
||||
|
||||
hbox1->addWidget( snapFrames);
|
||||
hbox1->addWidget( new QLabel( tr("Range (1 - 10000)") ) );
|
||||
|
||||
snapTimeGroup = new QGroupBox(tr("Time Between Snapshots:"));
|
||||
hbox1 = new QHBoxLayout();
|
||||
snapTimeGroup->setLayout(hbox1);
|
||||
snapTimeGroup->setEnabled(snapTimeSelBtn->isChecked());
|
||||
grid->addWidget( snapTimeGroup, 4, 0, 1, 2 );
|
||||
|
||||
frame = new QGroupBox();
|
||||
hbox = new QHBoxLayout();
|
||||
|
||||
hbox1->addWidget(frame);
|
||||
hbox->addWidget( snapMinutes);
|
||||
hbox->addWidget( new QLabel( tr("Minutes") ) );
|
||||
|
||||
frame->setLayout(hbox);
|
||||
|
||||
frame = new QGroupBox();
|
||||
hbox = new QHBoxLayout();
|
||||
|
||||
hbox1->addWidget(frame);
|
||||
hbox->addWidget( snapSeconds);
|
||||
hbox->addWidget( new QLabel( tr("Seconds") ) );
|
||||
|
||||
frame->setLayout(hbox);
|
||||
|
||||
frame1 = new QGroupBox(tr("Pause on State Load:"));
|
||||
vbox1 = new QVBoxLayout();
|
||||
frame1->setLayout(vbox1);
|
||||
|
||||
g_config->getOption("SDL.StateRecorderPauseOnLoad", &opt);
|
||||
|
||||
pauseOnLoadCbox = new QComboBox();
|
||||
pauseOnLoadCbox->addItem( tr("No"), StateRecorderConfigData::NO_PAUSE );
|
||||
pauseOnLoadCbox->addItem( tr("Temporary"), StateRecorderConfigData::TEMPORARY_PAUSE );
|
||||
pauseOnLoadCbox->addItem( tr("Full"), StateRecorderConfigData::FULL_PAUSE );
|
||||
|
||||
pauseOnLoadCbox->setCurrentIndex( opt );
|
||||
|
||||
connect( pauseOnLoadCbox, SIGNAL(currentIndexChanged(int)), this, SLOT(pauseOnLoadChanged(int)) );
|
||||
|
||||
g_config->getOption("SDL.StateRecorderPauseDuration", &opt);
|
||||
|
||||
pauseDuration = new QSpinBox();
|
||||
pauseDuration->setMinimum(0);
|
||||
pauseDuration->setMaximum(60);
|
||||
pauseDuration->setValue(opt);
|
||||
|
||||
vbox1->addWidget(pauseOnLoadCbox);
|
||||
|
||||
frame = new QGroupBox( tr("Duration:") );
|
||||
hbox = new QHBoxLayout();
|
||||
|
||||
vbox1->addWidget(frame);
|
||||
hbox->addWidget( pauseDuration);
|
||||
hbox->addWidget( new QLabel( tr("Seconds") ) );
|
||||
|
||||
frame->setLayout(hbox);
|
||||
|
||||
grid->addWidget(frame1, 4, 3, 2, 1);
|
||||
|
||||
frame = new QGroupBox( tr("Memory Usage:") );
|
||||
memStatsGrid = new QGridLayout();
|
||||
|
||||
numSnapsLbl = new QLineEdit();
|
||||
snapMemSizeLbl = new QLineEdit();
|
||||
totalMemUsageLbl = new QLineEdit();
|
||||
saveTimeLbl = new QLineEdit();
|
||||
|
||||
numSnapsLbl->setReadOnly(true);
|
||||
snapMemSizeLbl->setReadOnly(true);
|
||||
totalMemUsageLbl->setReadOnly(true);
|
||||
saveTimeLbl->setReadOnly(true);
|
||||
|
||||
grid->addWidget(frame, 1, 3, 2, 2);
|
||||
frame->setLayout(memStatsGrid);
|
||||
memStatsGrid->addWidget( new QLabel( tr("Number of\nSnapshots:") ), 0, 0 );
|
||||
memStatsGrid->addWidget( numSnapsLbl, 0, 1 );
|
||||
|
||||
memStatsGrid->addWidget( new QLabel( tr("Snapshot Size:") ), 1, 0 );
|
||||
memStatsGrid->addWidget( snapMemSizeLbl, 1, 1 );
|
||||
|
||||
memStatsGrid->addWidget( new QLabel( tr("Total Size:") ), 2, 0 );
|
||||
memStatsGrid->addWidget( totalMemUsageLbl, 2, 1 );
|
||||
|
||||
frame = new QGroupBox( tr("CPU Usage:") );
|
||||
hbox = new QHBoxLayout();
|
||||
frame->setLayout(hbox);
|
||||
|
||||
hbox->addWidget(new QLabel(tr("Snapshot\nSave Time:")), 2);
|
||||
hbox->addWidget(saveTimeLbl, 2);
|
||||
|
||||
grid->addWidget(frame, 3, 3, 1, 1);
|
||||
|
||||
mainLayout->addLayout(grid);
|
||||
|
||||
frame1 = new QGroupBox(tr("Recorder Status"));
|
||||
sysStatusGrid = new QGridLayout();
|
||||
frame1->setLayout(sysStatusGrid);
|
||||
|
||||
frame = new QGroupBox();
|
||||
hbox = new QHBoxLayout();
|
||||
|
||||
sysStatusGrid->addWidget( frame, 0, 0, 1, 2);
|
||||
frame->setLayout(hbox);
|
||||
|
||||
recStatusLbl = new QLineEdit();
|
||||
recStatusLbl->setReadOnly(true);
|
||||
startStopButton = new QPushButton( tr("Start") );
|
||||
hbox->addWidget( new QLabel(tr("State:")), 1 );
|
||||
hbox->addWidget( recStatusLbl, 2 );
|
||||
hbox->addWidget( startStopButton, 1 );
|
||||
|
||||
updateStartStopBuffon();
|
||||
updateRecorderStatusLabel();
|
||||
|
||||
connect(startStopButton, SIGNAL(clicked(void)), this, SLOT(startStopClicked(void)));
|
||||
connect(snapFrameSelBtn, SIGNAL(clicked(void)), this, SLOT(snapFrameModeClicked(void)));
|
||||
connect(snapTimeSelBtn , SIGNAL(clicked(void)), this, SLOT(snapTimeModeClicked(void)));
|
||||
|
||||
frame = new QGroupBox();
|
||||
hbox = new QHBoxLayout();
|
||||
|
||||
sysStatusGrid->addWidget( frame, 0, 2, 1, 1);
|
||||
frame->setLayout(hbox);
|
||||
|
||||
recBufSizeLbl = new QLineEdit();
|
||||
recBufSizeLbl->setReadOnly(true);
|
||||
hbox->addWidget( new QLabel(tr("Buffer Size:")), 1 );
|
||||
hbox->addWidget( recBufSizeLbl, 1 );
|
||||
|
||||
frame = new QGroupBox( tr("Buffer Use:") );
|
||||
hbox = new QHBoxLayout();
|
||||
|
||||
sysStatusGrid->addWidget( frame, 1, 0, 1, 3);
|
||||
frame->setLayout(hbox);
|
||||
|
||||
bufUsage = new QProgressBar();
|
||||
bufUsage->setToolTip( tr("% use of history record buffer.") );
|
||||
bufUsage->setOrientation( Qt::Horizontal );
|
||||
bufUsage->setMinimum( 0 );
|
||||
bufUsage->setMaximum( 100 );
|
||||
bufUsage->setValue( 0 );
|
||||
|
||||
hbox->addWidget(bufUsage);
|
||||
|
||||
updateBufferSizeStatus();
|
||||
|
||||
mainLayout->addWidget(frame1);
|
||||
|
||||
hbox = new QHBoxLayout();
|
||||
mainLayout->addLayout(hbox);
|
||||
|
||||
closeButton = new QPushButton( tr("Close") );
|
||||
applyButton = new QPushButton( tr("Apply") );
|
||||
|
||||
closeButton->setIcon( style()->standardIcon( QStyle::SP_DialogCloseButton ) );
|
||||
applyButton->setIcon( style()->standardIcon( QStyle::SP_DialogApplyButton ) );
|
||||
|
||||
connect(closeButton, SIGNAL(clicked(void)), this, SLOT(closeWindow(void)));
|
||||
connect(applyButton, SIGNAL(clicked(void)), this, SLOT(applyChanges(void)));
|
||||
|
||||
hbox->addWidget(applyButton, 1);
|
||||
hbox->addStretch(8);
|
||||
hbox->addWidget(closeButton, 1);
|
||||
|
||||
setLayout(mainLayout);
|
||||
|
||||
restoreGeometry(settings.value("stateRecorderWindow/geometry").toByteArray());
|
||||
|
||||
recalcMemoryUsage();
|
||||
|
||||
pauseOnLoadChanged( pauseOnLoadCbox->currentIndex() );
|
||||
|
||||
updateTimer = new QTimer(this);
|
||||
|
||||
connect(updateTimer, &QTimer::timeout, this, &StateRecorderDialog_t::updatePeriodic);
|
||||
|
||||
updateTimer->start(1000); // 1hz
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
StateRecorderDialog_t::~StateRecorderDialog_t(void)
|
||||
{
|
||||
//printf("Destroy State Recorder Config Window\n");
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
void StateRecorderDialog_t::closeEvent(QCloseEvent *event)
|
||||
{
|
||||
QSettings settings;
|
||||
settings.setValue("stateRecorderWindow/geometry", saveGeometry());
|
||||
|
||||
if (dataSavedCheck())
|
||||
{
|
||||
done(0);
|
||||
deleteLater();
|
||||
event->accept();
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
void StateRecorderDialog_t::closeWindow(void)
|
||||
{
|
||||
QSettings settings;
|
||||
settings.setValue("stateRecorderWindow/geometry", saveGeometry());
|
||||
|
||||
if (dataSavedCheck())
|
||||
{
|
||||
done(0);
|
||||
deleteLater();
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
void StateRecorderDialog_t::packConfig( StateRecorderConfigData &config )
|
||||
{
|
||||
config.timingMode = snapTimeSelBtn->isChecked() ?
|
||||
StateRecorderConfigData::TIME : StateRecorderConfigData::FRAMES;
|
||||
|
||||
config.framesBetweenSnaps = snapFrames->value();
|
||||
config.historyDurationMinutes = static_cast<float>( historyDuration->value() );
|
||||
config.timeBetweenSnapsMinutes = static_cast<float>( snapMinutes->value() ) +
|
||||
( static_cast<float>( snapSeconds->value() ) / 60.0f );
|
||||
config.compressionLevel = cmprLvlCbox->currentData().toInt();
|
||||
config.loadPauseTimeSeconds = pauseDuration->value();
|
||||
config.pauseOnLoad = static_cast<StateRecorderConfigData::PauseType>( pauseOnLoadCbox->currentData().toInt() );
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
bool StateRecorderDialog_t::dataSavedCheck(void)
|
||||
{
|
||||
bool okToClose = true;
|
||||
const StateRecorderConfigData &curConfig = FCEU_StateRecorderGetConfigData();
|
||||
|
||||
StateRecorderConfigData selConfig;
|
||||
|
||||
packConfig( selConfig );
|
||||
|
||||
if ( selConfig.compare( curConfig ) == false )
|
||||
{
|
||||
QMessageBox msgBox(QMessageBox::Question, tr("State Recorder"),
|
||||
tr("Setting selections have not yet been saved.\nDo you wish to save/apply the new settings?"),
|
||||
QMessageBox::No | QMessageBox::Yes, this);
|
||||
|
||||
msgBox.setDefaultButton( QMessageBox::Yes );
|
||||
|
||||
int ret = msgBox.exec();
|
||||
|
||||
if ( ret == QMessageBox::Yes )
|
||||
{
|
||||
applyChanges();
|
||||
}
|
||||
}
|
||||
return okToClose;
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
void StateRecorderDialog_t::applyChanges(void)
|
||||
{
|
||||
StateRecorderConfigData config;
|
||||
|
||||
packConfig( config );
|
||||
|
||||
FCEU_WRAPPER_LOCK();
|
||||
FCEU_StateRecorderSetEnabled( recorderEnable->isChecked() );
|
||||
FCEU_StateRecorderSetConfigData( config );
|
||||
if (FCEU_StateRecorderRunning())
|
||||
{
|
||||
QMessageBox msgBox(QMessageBox::Question, tr("State Recorder"),
|
||||
tr("New settings will not take effect until state recorder is restarted. Do you wish to restart?"),
|
||||
QMessageBox::No | QMessageBox::Yes, this);
|
||||
|
||||
msgBox.setDefaultButton( QMessageBox::Yes );
|
||||
|
||||
int ret = msgBox.exec();
|
||||
|
||||
if ( ret == QMessageBox::Yes )
|
||||
{
|
||||
FCEU_StateRecorderStop();
|
||||
FCEU_StateRecorderStart();
|
||||
updateStatusDisplay();
|
||||
}
|
||||
}
|
||||
FCEU_WRAPPER_UNLOCK();
|
||||
|
||||
g_config->setOption("SDL.StateRecorderHistoryDurationMin", historyDuration->value() );
|
||||
g_config->setOption("SDL.StateRecorderTimingMode", snapTimeSelBtn->isChecked() ? 1 : 0);
|
||||
g_config->setOption("SDL.StateRecorderFramesBetweenSnaps", snapFrames->value() );
|
||||
g_config->setOption("SDL.StateRecorderTimeBetweenSnapsMin", snapMinutes->value() );
|
||||
g_config->setOption("SDL.StateRecorderTimeBetweenSnapsSec", snapSeconds->value() );
|
||||
g_config->setOption("SDL.StateRecorderCompressionLevel", config.compressionLevel);
|
||||
g_config->setOption("SDL.StateRecorderPauseOnLoad", config.pauseOnLoad);
|
||||
g_config->setOption("SDL.StateRecorderPauseDuration", config.loadPauseTimeSeconds);
|
||||
g_config->setOption("SDL.StateRecorderEnable", recorderEnable->isChecked() );
|
||||
g_config->save();
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
void StateRecorderDialog_t::startStopClicked(void)
|
||||
{
|
||||
FCEU_WRAPPER_LOCK();
|
||||
bool isRunning = FCEU_StateRecorderRunning();
|
||||
|
||||
if (isRunning)
|
||||
{
|
||||
FCEU_StateRecorderStop();
|
||||
}
|
||||
else
|
||||
{
|
||||
FCEU_StateRecorderStart();
|
||||
}
|
||||
updateStatusDisplay();
|
||||
|
||||
FCEU_WRAPPER_UNLOCK();
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
void StateRecorderDialog_t::snapFrameModeClicked(void)
|
||||
{
|
||||
snapUseTime = false;
|
||||
snapTimeGroup->setEnabled(false);
|
||||
snapFramesGroup->setEnabled(true);
|
||||
|
||||
recalcMemoryUsage();
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
void StateRecorderDialog_t::snapTimeModeClicked(void)
|
||||
{
|
||||
snapUseTime = true;
|
||||
snapFramesGroup->setEnabled(false);
|
||||
snapTimeGroup->setEnabled(true);
|
||||
|
||||
recalcMemoryUsage();
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
void StateRecorderDialog_t::updateStartStopBuffon(void)
|
||||
{
|
||||
bool isRunning = FCEU_StateRecorderRunning();
|
||||
|
||||
if (isRunning)
|
||||
{
|
||||
startStopButton->setText( tr("Stop") );
|
||||
startStopButton->setIcon( style()->standardIcon( QStyle::SP_MediaStop ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
startStopButton->setText( tr("Start") );
|
||||
startStopButton->setIcon( QIcon(":icons/media-record.png") );
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
void StateRecorderDialog_t::updateBufferSizeStatus(void)
|
||||
{
|
||||
char stmp[64];
|
||||
|
||||
int numSnapsSaved = FCEU_StateRecorderGetNumSnapsSaved();
|
||||
int maxSnaps = FCEU_StateRecorderGetMaxSnaps();
|
||||
|
||||
snprintf( stmp, sizeof(stmp), "%i", maxSnaps );
|
||||
|
||||
recBufSizeLbl->setText( tr(stmp) );
|
||||
|
||||
if (maxSnaps > 0)
|
||||
{
|
||||
bufUsage->setMaximum( maxSnaps );
|
||||
}
|
||||
bufUsage->setValue( numSnapsSaved );
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
void StateRecorderDialog_t::updateRecorderStatusLabel(void)
|
||||
{
|
||||
bool isRunning = FCEU_StateRecorderRunning();
|
||||
|
||||
if (isRunning)
|
||||
{
|
||||
recStatusLbl->setText( tr("Recording") );
|
||||
}
|
||||
else
|
||||
{
|
||||
recStatusLbl->setText( tr("Off") );
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
void StateRecorderDialog_t::updateStatusDisplay(void)
|
||||
{
|
||||
updateStartStopBuffon();
|
||||
updateRecorderStatusLabel();
|
||||
updateBufferSizeStatus();
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
void StateRecorderDialog_t::updatePeriodic(void)
|
||||
{
|
||||
FCEU_WRAPPER_LOCK();
|
||||
updateStatusDisplay();
|
||||
FCEU_WRAPPER_UNLOCK();
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
void StateRecorderDialog_t::enableChanged(int val)
|
||||
{
|
||||
bool ena = val ? true : false;
|
||||
|
||||
FCEU_WRAPPER_LOCK();
|
||||
FCEU_StateRecorderSetEnabled( ena );
|
||||
FCEU_WRAPPER_UNLOCK();
|
||||
|
||||
g_config->setOption("SDL.StateRecorderEnable", ena );
|
||||
g_config->save();
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
void StateRecorderDialog_t::spinBoxValueChanged(int newValue)
|
||||
{
|
||||
recalcMemoryUsage();
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
void StateRecorderDialog_t::compressionLevelChanged(int newValue)
|
||||
{
|
||||
recalcMemoryUsage();
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
void StateRecorderDialog_t::pauseOnLoadChanged(int index)
|
||||
{
|
||||
StateRecorderConfigData::PauseType pauseOnLoad;
|
||||
|
||||
pauseOnLoad = static_cast<StateRecorderConfigData::PauseType>( pauseOnLoadCbox->currentData().toInt() );
|
||||
|
||||
pauseDuration->setEnabled( pauseOnLoad == StateRecorderConfigData::TEMPORARY_PAUSE );
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
void StateRecorderDialog_t::recalcMemoryUsage(void)
|
||||
{
|
||||
char stmp[64];
|
||||
|
||||
float fsnapMin = 1.0;
|
||||
float fhistMin = static_cast<float>( historyDuration->value() );
|
||||
|
||||
if (snapUseTime)
|
||||
{
|
||||
fsnapMin = static_cast<float>( snapMinutes->value() ) +
|
||||
( static_cast<float>( snapSeconds->value() ) / 60.0f );
|
||||
}
|
||||
else
|
||||
{
|
||||
int32_t fps = FCEUI_GetDesiredFPS(); // Do >> 24 to get in Hz
|
||||
double hz = ( ((double)fps) / 16777216.0 );
|
||||
|
||||
fsnapMin = static_cast<double>(snapFrames->value()) / (hz * 60.0);
|
||||
}
|
||||
|
||||
float fnumSnaps = fhistMin / fsnapMin;
|
||||
float fsnapSize = 10.0f * 1024.0f;
|
||||
float ftotalSize;
|
||||
constexpr float oneKiloByte = 1024.0f;
|
||||
constexpr float oneMegaByte = 1024.0f * 1024.0f;
|
||||
|
||||
int inumSnaps = static_cast<int>( fnumSnaps + 0.5f );
|
||||
|
||||
sprintf( stmp, "%i", inumSnaps );
|
||||
|
||||
numSnapsLbl->setText( tr(stmp) );
|
||||
|
||||
saveTimeMs = 0.0;
|
||||
|
||||
if (GameInfo)
|
||||
{
|
||||
constexpr int numIterations = 10;
|
||||
double ts_start, ts_end;
|
||||
|
||||
FCEU_WRAPPER_LOCK();
|
||||
|
||||
EMUFILE_MEMORY em;
|
||||
int compressionLevel = cmprLvlCbox->currentData().toInt();
|
||||
|
||||
ts_start = getHighPrecTimeStamp();
|
||||
|
||||
// Perform State Save multiple times to get a good average
|
||||
// on what the compression delays will be.
|
||||
for (int i=0; i<numIterations; i++)
|
||||
{
|
||||
em.set_len(0);
|
||||
FCEUSS_SaveMS( &em, compressionLevel );
|
||||
}
|
||||
ts_end = getHighPrecTimeStamp();
|
||||
|
||||
saveTimeMs = (ts_end - ts_start) * 1000.0 / static_cast<double>(numIterations);
|
||||
|
||||
fsnapSize = static_cast<float>( em.size() );
|
||||
|
||||
FCEU_WRAPPER_UNLOCK();
|
||||
}
|
||||
|
||||
if (fsnapSize >= oneKiloByte)
|
||||
{
|
||||
sprintf( stmp, "%.02f kB", fsnapSize / oneKiloByte );
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf( stmp, "%.0f B", fsnapSize );
|
||||
}
|
||||
|
||||
snapMemSizeLbl->setText( tr(stmp) );
|
||||
|
||||
ftotalSize = fsnapSize * static_cast<float>(inumSnaps);
|
||||
|
||||
if (ftotalSize >= oneMegaByte)
|
||||
{
|
||||
sprintf( stmp, "%.02f MB", ftotalSize / oneMegaByte );
|
||||
}
|
||||
else if (ftotalSize >= oneKiloByte)
|
||||
{
|
||||
sprintf( stmp, "%.02f kB", ftotalSize / oneKiloByte );
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf( stmp, "%.0f B", ftotalSize );
|
||||
}
|
||||
|
||||
totalMemUsageLbl->setText( tr(stmp) );
|
||||
|
||||
sprintf( stmp, "%.02f ms", saveTimeMs);
|
||||
saveTimeLbl->setText( tr(stmp) );
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
|
@ -0,0 +1,83 @@
|
|||
// StateRecorderConf.h
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QWidget>
|
||||
#include <QDialog>
|
||||
#include <QVBoxLayout>
|
||||
#include <QHBoxLayout>
|
||||
#include <QComboBox>
|
||||
#include <QCheckBox>
|
||||
#include <QSpinBox>
|
||||
#include <QComboBox>
|
||||
#include <QPushButton>
|
||||
#include <QRadioButton>
|
||||
#include <QProgressBar>
|
||||
#include <QLineEdit>
|
||||
#include <QLabel>
|
||||
#include <QFrame>
|
||||
#include <QGroupBox>
|
||||
#include <QTimer>
|
||||
|
||||
struct StateRecorderConfigData;
|
||||
|
||||
class StateRecorderDialog_t : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
StateRecorderDialog_t(QWidget *parent = 0);
|
||||
~StateRecorderDialog_t(void);
|
||||
|
||||
protected:
|
||||
void closeEvent(QCloseEvent *event);
|
||||
|
||||
QSpinBox *snapMinutes;
|
||||
QSpinBox *snapSeconds;
|
||||
QSpinBox *snapFrames;
|
||||
QSpinBox *historyDuration;
|
||||
QSpinBox *pauseDuration;
|
||||
QCheckBox *recorderEnable;
|
||||
QLineEdit *numSnapsLbl;
|
||||
QLineEdit *snapMemSizeLbl;
|
||||
QLineEdit *totalMemUsageLbl;
|
||||
QLineEdit *saveTimeLbl;
|
||||
QPushButton *applyButton;
|
||||
QPushButton *closeButton;
|
||||
QComboBox *cmprLvlCbox;
|
||||
QComboBox *pauseOnLoadCbox;
|
||||
QGroupBox *snapTimeGroup;
|
||||
QGroupBox *snapFramesGroup;
|
||||
QRadioButton *snapFrameSelBtn;
|
||||
QRadioButton *snapTimeSelBtn;
|
||||
QLineEdit *recStatusLbl;
|
||||
QLineEdit *recBufSizeLbl;
|
||||
QPushButton *startStopButton;
|
||||
QProgressBar *bufUsage;
|
||||
QTimer *updateTimer;
|
||||
|
||||
double saveTimeMs;
|
||||
bool snapUseTime;
|
||||
|
||||
bool dataSavedCheck(void);
|
||||
void recalcMemoryUsage(void);
|
||||
void updateStartStopBuffon(void);
|
||||
void updateRecorderStatusLabel(void);
|
||||
void updateBufferSizeStatus(void);
|
||||
void updateStatusDisplay(void);
|
||||
void packConfig( StateRecorderConfigData &config );
|
||||
|
||||
public slots:
|
||||
void closeWindow(void);
|
||||
private slots:
|
||||
void applyChanges(void);
|
||||
void updatePeriodic(void);
|
||||
void startStopClicked(void);
|
||||
void snapTimeModeClicked(void);
|
||||
void snapFrameModeClicked(void);
|
||||
void spinBoxValueChanged(int newValue);
|
||||
void enableChanged(int);
|
||||
void compressionLevelChanged(int newValue);
|
||||
void pauseOnLoadChanged(int index);
|
||||
};
|
|
@ -116,7 +116,6 @@ void tasWindowSetFocus(bool val)
|
|||
{
|
||||
tasWin->activateWindow();
|
||||
tasWin->raise();
|
||||
tasWin->setFocus();
|
||||
}
|
||||
}
|
||||
// this getter contains formula to decide whether to record or replay movie
|
||||
|
@ -2917,7 +2916,6 @@ void TasEditorWindow::openFindNoteWindow(void)
|
|||
{
|
||||
findWin->activateWindow();
|
||||
findWin->raise();
|
||||
findWin->setFocus();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -57,6 +57,7 @@
|
|||
|
||||
#include "common/os_utils.h"
|
||||
|
||||
#include "Qt/ConsoleDebugger.h"
|
||||
#include "Qt/ConsoleWindow.h"
|
||||
#include "Qt/ConsoleUtilities.h"
|
||||
#include "Qt/TraceLogger.h"
|
||||
|
@ -1211,7 +1212,6 @@ void openTraceLoggerWindow(QWidget *parent)
|
|||
{
|
||||
traceLogWindow->activateWindow();
|
||||
traceLogWindow->raise();
|
||||
traceLogWindow->setFocus();
|
||||
return;
|
||||
}
|
||||
//printf("Open Trace Logger Window\n");
|
||||
|
@ -2188,7 +2188,7 @@ void QTraceLogView::openBpEditWindow(int editIdx, watchpointinfo *wp, traceRecor
|
|||
numWPs++;
|
||||
}
|
||||
|
||||
updateAllDebuggerWindows();
|
||||
updateAllDebuggerWindows(QAsmView::UPDATE_NO_SCROLL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2233,7 +2233,7 @@ void QTraceLogView::openDebugSymbolEditWindow(int addr, int bank)
|
|||
|
||||
if (ret == QDialog::Accepted)
|
||||
{
|
||||
updateAllDebuggerWindows();
|
||||
updateAllDebuggerWindows(QAsmView::UPDATE_NO_SCROLL);
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
|
@ -2507,6 +2507,7 @@ void QTraceLogView::paintEvent(QPaintEvent *event)
|
|||
TraceLogDiskThread_t::TraceLogDiskThread_t( QObject *parent )
|
||||
: QThread(parent)
|
||||
{
|
||||
setObjectName( QString("TraceLogDiskThread") );
|
||||
}
|
||||
//----------------------------------------------------
|
||||
TraceLogDiskThread_t::~TraceLogDiskThread_t(void)
|
||||
|
|
|
@ -295,6 +295,12 @@ int getHotKeyConfig( int i, const char **nameOut, const char **keySeqOut, const
|
|||
case HK_SELECT_STATE_PREV:
|
||||
name = "SelectStatePrev"; keySeq = ""; title = "Select Previous State Slot"; group = "State";
|
||||
break;
|
||||
case HK_LOAD_PREV_STATE:
|
||||
name = "LoadPrevState"; keySeq = ""; title = "Load Previous Recorded State"; group = "State";
|
||||
break;
|
||||
case HK_LOAD_NEXT_STATE:
|
||||
name = "LoadNextState"; keySeq = ""; title = "Load Next Recorded State"; group = "State";
|
||||
break;
|
||||
case HK_VOLUME_MUTE:
|
||||
name = "VolumeMute"; keySeq = ""; title = "Sound Volume Mute"; group = "Sound";
|
||||
break;
|
||||
|
@ -748,6 +754,16 @@ InitConfig()
|
|||
config->addOption("loadstate", "SDL.AutoLoadState", INVALID_STATE);
|
||||
config->addOption("savestate", "SDL.AutoSaveState", INVALID_STATE);
|
||||
|
||||
config->addOption("SDL.StateRecorderEnable", false);
|
||||
config->addOption("SDL.StateRecorderHistoryDurationMin", 15);
|
||||
config->addOption("SDL.StateRecorderTimingMode", 0);
|
||||
config->addOption("SDL.StateRecorderFramesBetweenSnaps", 60);
|
||||
config->addOption("SDL.StateRecorderTimeBetweenSnapsMin", 0);
|
||||
config->addOption("SDL.StateRecorderTimeBetweenSnapsSec", 3);
|
||||
config->addOption("SDL.StateRecorderCompressionLevel", 0);
|
||||
config->addOption("SDL.StateRecorderPauseOnLoad", 1);
|
||||
config->addOption("SDL.StateRecorderPauseDuration", 3);
|
||||
|
||||
//TODO implement this
|
||||
config->addOption("periodicsaves", "SDL.PeriodicSaves", 0);
|
||||
|
||||
|
|
|
@ -34,6 +34,9 @@ enum HOTKEY {
|
|||
HK_SELECT_STATE_5, HK_SELECT_STATE_6, HK_SELECT_STATE_7, HK_SELECT_STATE_8, HK_SELECT_STATE_9,
|
||||
HK_SELECT_STATE_NEXT, HK_SELECT_STATE_PREV,
|
||||
|
||||
// State Recorder
|
||||
HK_LOAD_PREV_STATE, HK_LOAD_NEXT_STATE,
|
||||
|
||||
// GUI
|
||||
HK_FULLSCREEN, HK_MAIN_MENU_HIDE,
|
||||
|
||||
|
|
|
@ -52,6 +52,8 @@
|
|||
#include "../../fceu.h"
|
||||
#include "../../cheat.h"
|
||||
#include "../../movie.h"
|
||||
#include "../../state.h"
|
||||
#include "../../profiler.h"
|
||||
#include "../../version.h"
|
||||
|
||||
#ifdef _S9XLUA_H
|
||||
|
@ -60,6 +62,7 @@
|
|||
|
||||
#include "common/os_utils.h"
|
||||
#include "common/configSys.h"
|
||||
#include "utils/timeStamp.h"
|
||||
#include "../../oldmovie.h"
|
||||
#include "../../types.h"
|
||||
|
||||
|
@ -189,7 +192,23 @@ const char *FCEUD_GetCompilerString(void)
|
|||
uint64
|
||||
FCEUD_GetTime(void)
|
||||
{
|
||||
return SDL_GetTicks();
|
||||
uint64 t;
|
||||
|
||||
if (FCEU::timeStampModuleInitialized())
|
||||
{
|
||||
FCEU::timeStampRecord ts;
|
||||
|
||||
ts.readNew();
|
||||
|
||||
t = ts.toCounts();
|
||||
}
|
||||
else
|
||||
{
|
||||
t = (double)SDL_GetTicks();
|
||||
|
||||
t = t * 1e-3;
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -199,7 +218,13 @@ uint64
|
|||
FCEUD_GetTimeFreq(void)
|
||||
{
|
||||
// SDL_GetTicks() is in milliseconds
|
||||
return 1000;
|
||||
uint64 f = 1000;
|
||||
|
||||
if (FCEU::timeStampModuleInitialized())
|
||||
{
|
||||
f = FCEU::timeStampRecord::countFreq();
|
||||
}
|
||||
return f;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -972,6 +997,45 @@ int fceuWrapperInit( int argc, char *argv[] )
|
|||
// load the hotkeys from the config life
|
||||
setHotKeys();
|
||||
|
||||
// Initialize the State Recorder
|
||||
{
|
||||
bool srEnable = false;
|
||||
bool srUseTimeMode = false;
|
||||
int srHistDurMin = 15;
|
||||
int srFramesBtwSnaps = 60;
|
||||
int srTimeBtwSnapsMin = 0;
|
||||
int srTimeBtwSnapsSec = 3;
|
||||
int srCompressionLevel = 0;
|
||||
int pauseOnLoadTime = 3;
|
||||
int pauseOnLoad = StateRecorderConfigData::TEMPORARY_PAUSE;
|
||||
|
||||
g_config->getOption("SDL.StateRecorderEnable", &srEnable);
|
||||
g_config->getOption("SDL.StateRecorderTimingMode", &srUseTimeMode);
|
||||
g_config->getOption("SDL.StateRecorderHistoryDurationMin", &srHistDurMin);
|
||||
g_config->getOption("SDL.StateRecorderFramesBetweenSnaps", &srFramesBtwSnaps);
|
||||
g_config->getOption("SDL.StateRecorderTimeBetweenSnapsMin", &srTimeBtwSnapsMin);
|
||||
g_config->getOption("SDL.StateRecorderTimeBetweenSnapsSec", &srTimeBtwSnapsSec);
|
||||
g_config->getOption("SDL.StateRecorderCompressionLevel", &srCompressionLevel);
|
||||
g_config->getOption("SDL.StateRecorderPauseOnLoad", &pauseOnLoad);
|
||||
g_config->getOption("SDL.StateRecorderPauseDuration", &pauseOnLoadTime);
|
||||
|
||||
StateRecorderConfigData srConfig;
|
||||
|
||||
srConfig.historyDurationMinutes = srHistDurMin;
|
||||
srConfig.timingMode = srUseTimeMode ?
|
||||
StateRecorderConfigData::TIME : StateRecorderConfigData::FRAMES;
|
||||
srConfig.timeBetweenSnapsMinutes = static_cast<float>( srTimeBtwSnapsMin ) +
|
||||
( static_cast<float>( srTimeBtwSnapsSec ) / 60.0f );
|
||||
srConfig.framesBetweenSnaps = srFramesBtwSnaps;
|
||||
srConfig.compressionLevel = srCompressionLevel;
|
||||
srConfig.loadPauseTimeSeconds = pauseOnLoadTime;
|
||||
srConfig.pauseOnLoad = static_cast<StateRecorderConfigData::PauseType>(pauseOnLoad);
|
||||
|
||||
FCEU_StateRecorderSetEnabled( srEnable );
|
||||
FCEU_StateRecorderSetConfigData( srConfig );
|
||||
}
|
||||
|
||||
// Rom Load
|
||||
if (romIndex >= 0)
|
||||
{
|
||||
QFileInfo fi( argv[romIndex] );
|
||||
|
@ -1425,6 +1489,9 @@ int fceuWrapperUpdate( void )
|
|||
|
||||
emulatorHasMutex = 0;
|
||||
|
||||
#ifdef __FCEU_PROFILER_ENABLE__
|
||||
FCEU_profiler_log_thread_activity();
|
||||
#endif
|
||||
while ( SpeedThrottle() )
|
||||
{
|
||||
// Input device processing is in main thread
|
||||
|
@ -1438,25 +1505,27 @@ int fceuWrapperUpdate( void )
|
|||
|
||||
emulatorHasMutex = 0;
|
||||
|
||||
#ifdef __FCEU_PROFILER_ENABLE__
|
||||
FCEU_profiler_log_thread_activity();
|
||||
#endif
|
||||
msleep( 100 );
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
ArchiveScanRecord FCEUD_ScanArchive(std::string fname)
|
||||
static int minizip_ScanArchive( const char *filepath, ArchiveScanRecord &rec)
|
||||
{
|
||||
int idx=0, ret;
|
||||
unzFile zf;
|
||||
unz_file_info fi;
|
||||
char filename[512];
|
||||
ArchiveScanRecord rec;
|
||||
|
||||
zf = unzOpen( fname.c_str() );
|
||||
|
||||
zf = unzOpen( filepath );
|
||||
|
||||
if ( zf == NULL )
|
||||
{
|
||||
//printf("Error: Failed to open Zip File: '%s'\n", fname.c_str() );
|
||||
return rec;
|
||||
return -1;
|
||||
}
|
||||
rec.type = 0;
|
||||
|
||||
|
@ -1486,18 +1555,313 @@ ArchiveScanRecord FCEUD_ScanArchive(std::string fname)
|
|||
|
||||
unzClose( zf );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef _USE_LIBARCHIVE
|
||||
#include <archive.h>
|
||||
#include <archive_entry.h>
|
||||
|
||||
static int libarchive_ScanArchive( const char *filepath, ArchiveScanRecord &rec)
|
||||
{
|
||||
int r, idx=0;
|
||||
struct archive *a;
|
||||
struct archive_entry *entry;
|
||||
|
||||
a = archive_read_new();
|
||||
|
||||
if (a == nullptr)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Initialize decoders
|
||||
r = archive_read_support_filter_all(a);
|
||||
if (r)
|
||||
{
|
||||
archive_read_free(a);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Initialize formats
|
||||
r = archive_read_support_format_all(a);
|
||||
if (r)
|
||||
{
|
||||
archive_read_free(a);
|
||||
return -1;
|
||||
}
|
||||
|
||||
r = archive_read_open_filename(a, filepath, 10240);
|
||||
|
||||
if (r)
|
||||
{
|
||||
archive_read_free(a);
|
||||
return -1;
|
||||
}
|
||||
rec.type = 1;
|
||||
|
||||
while (1)
|
||||
{
|
||||
r = archive_read_next_header(a, &entry);
|
||||
if (r == ARCHIVE_EOF)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else if (r != ARCHIVE_OK)
|
||||
{
|
||||
printf("archive_read_next_header() %s\n", archive_error_string(a));
|
||||
break;
|
||||
}
|
||||
const char *filename = archive_entry_pathname(entry);
|
||||
|
||||
FCEUARCHIVEFILEINFO_ITEM item;
|
||||
item.name.assign( filename );
|
||||
item.size = archive_entry_size(entry);
|
||||
item.index = idx; idx++;
|
||||
|
||||
rec.files.push_back( item );
|
||||
}
|
||||
rec.numFilesInArchive = idx;
|
||||
|
||||
archive_read_free(a);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
ArchiveScanRecord FCEUD_ScanArchive(std::string fname)
|
||||
{
|
||||
int ret = -1;
|
||||
ArchiveScanRecord rec;
|
||||
|
||||
#ifdef _USE_LIBARCHIVE
|
||||
ret = libarchive_ScanArchive( fname.c_str(), rec );
|
||||
#endif
|
||||
|
||||
if (ret == -1)
|
||||
{
|
||||
minizip_ScanArchive( fname.c_str(), rec );
|
||||
}
|
||||
return rec;
|
||||
}
|
||||
|
||||
FCEUFILE* FCEUD_OpenArchive(ArchiveScanRecord& asr, std::string& fname, std::string* innerFilename, int* userCancel)
|
||||
static FCEUFILE* minizip_OpenArchive(ArchiveScanRecord& asr, std::string &fname, std::string *searchFile, int innerIndex )
|
||||
{
|
||||
int ret;
|
||||
FCEUFILE* fp = 0;
|
||||
int ret, idx=0;
|
||||
FCEUFILE* fp = nullptr;
|
||||
void *tmpMem = nullptr;
|
||||
unzFile zf;
|
||||
unz_file_info fi;
|
||||
char filename[512];
|
||||
char foundFile = 0;
|
||||
void *tmpMem = NULL;
|
||||
bool foundFile = false;
|
||||
|
||||
zf = unzOpen( fname.c_str() );
|
||||
|
||||
if ( zf == NULL )
|
||||
{
|
||||
//printf("Error: Failed to open Zip File: '%s'\n", fname.c_str() );
|
||||
return fp;
|
||||
}
|
||||
|
||||
//printf("Searching for %s in %s \n", searchFile.c_str(), fname.c_str() );
|
||||
|
||||
ret = unzGoToFirstFile( zf );
|
||||
|
||||
//printf("unzGoToFirstFile: %i \n", ret );
|
||||
|
||||
while ( ret == 0 )
|
||||
{
|
||||
unzGetCurrentFileInfo( zf, &fi, filename, sizeof(filename), NULL, 0, NULL, 0 );
|
||||
|
||||
//printf("Filename: %u '%s' \n", fi.uncompressed_size, filename );
|
||||
|
||||
if (searchFile)
|
||||
{
|
||||
if ( strcmp( searchFile->c_str(), filename ) == 0 )
|
||||
{
|
||||
//printf("Found Filename: %u '%s' \n", fi.uncompressed_size, filename );
|
||||
foundFile = true; break;
|
||||
}
|
||||
}
|
||||
else if ((innerIndex != -1) && (idx == innerIndex))
|
||||
{
|
||||
foundFile = true; break;
|
||||
}
|
||||
|
||||
ret = unzGoToNextFile( zf );
|
||||
|
||||
//printf("unzGoToNextFile: %i \n", ret );
|
||||
idx++;
|
||||
}
|
||||
|
||||
if ( !foundFile )
|
||||
{
|
||||
unzClose( zf );
|
||||
return fp;
|
||||
}
|
||||
|
||||
tmpMem = ::malloc( fi.uncompressed_size );
|
||||
|
||||
if ( tmpMem == NULL )
|
||||
{
|
||||
unzClose( zf );
|
||||
return fp;
|
||||
}
|
||||
//printf("Loading via minizip\n");
|
||||
|
||||
EMUFILE_MEMORY* ms = new EMUFILE_MEMORY(fi.uncompressed_size);
|
||||
|
||||
unzOpenCurrentFile( zf );
|
||||
unzReadCurrentFile( zf, tmpMem, fi.uncompressed_size );
|
||||
unzCloseCurrentFile( zf );
|
||||
|
||||
ms->fwrite( tmpMem, fi.uncompressed_size );
|
||||
|
||||
free( tmpMem );
|
||||
|
||||
//if we extracted the file correctly
|
||||
fp = new FCEUFILE();
|
||||
fp->archiveFilename = fname;
|
||||
fp->filename = filename;
|
||||
fp->fullFilename = fp->archiveFilename + "|" + fp->filename;
|
||||
fp->archiveIndex = idx;
|
||||
fp->mode = FCEUFILE::READ;
|
||||
fp->size = fi.uncompressed_size;
|
||||
fp->stream = ms;
|
||||
fp->archiveCount = (int)asr.numFilesInArchive;
|
||||
ms->fseek(0,SEEK_SET); //rewind so that the rom analyzer sees a freshly opened file
|
||||
|
||||
unzClose( zf );
|
||||
|
||||
return fp;
|
||||
}
|
||||
|
||||
#ifdef _USE_LIBARCHIVE
|
||||
static FCEUFILE* libarchive_OpenArchive( ArchiveScanRecord& asr, std::string& fname, std::string *searchFile, int innerIndex)
|
||||
{
|
||||
int r, idx=0;
|
||||
struct archive *a;
|
||||
struct archive_entry *entry;
|
||||
const char *filename = nullptr;
|
||||
bool foundFile = false;
|
||||
int fileSize = 0;
|
||||
FCEUFILE* fp = nullptr;
|
||||
|
||||
a = archive_read_new();
|
||||
|
||||
if (a == nullptr)
|
||||
{
|
||||
archive_read_free(a);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Initialize decoders
|
||||
r = archive_read_support_filter_all(a);
|
||||
if (r)
|
||||
{
|
||||
archive_read_free(a);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Initialize formats
|
||||
r = archive_read_support_format_all(a);
|
||||
if (r)
|
||||
{
|
||||
archive_read_free(a);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
r = archive_read_open_filename(a, fname.c_str(), 10240);
|
||||
|
||||
if (r)
|
||||
{
|
||||
archive_read_free(a);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
while (1)
|
||||
{
|
||||
r = archive_read_next_header(a, &entry);
|
||||
if (r == ARCHIVE_EOF)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else if (r != ARCHIVE_OK)
|
||||
{
|
||||
printf("archive_read_next_header() %s\n", archive_error_string(a));
|
||||
break;
|
||||
}
|
||||
filename = archive_entry_pathname(entry);
|
||||
fileSize = archive_entry_size(entry);
|
||||
|
||||
if (searchFile)
|
||||
{
|
||||
if (strcmp( filename, searchFile->c_str() ) == 0)
|
||||
{
|
||||
foundFile = true; break;
|
||||
}
|
||||
}
|
||||
else if ((innerIndex != -1) && (idx == innerIndex))
|
||||
{
|
||||
foundFile = true; break;
|
||||
}
|
||||
idx++;
|
||||
}
|
||||
|
||||
if (foundFile && (fileSize > 0))
|
||||
{
|
||||
const void *buff;
|
||||
size_t size, totalSize = 0;
|
||||
#if ARCHIVE_VERSION_NUMBER >= 3000000
|
||||
int64_t offset;
|
||||
#else
|
||||
off_t offset;
|
||||
#endif
|
||||
|
||||
//printf("Loading via libarchive\n");
|
||||
|
||||
EMUFILE_MEMORY* ms = new EMUFILE_MEMORY(fileSize);
|
||||
|
||||
while (1)
|
||||
{
|
||||
r = archive_read_data_block(a, &buff, &size, &offset);
|
||||
|
||||
if (r == ARCHIVE_EOF)
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (r != ARCHIVE_OK)
|
||||
{
|
||||
break;
|
||||
}
|
||||
//printf("Read: %p Size:%zu Offset:%llu\n", buff, size, (long long int)offset);
|
||||
ms->fwrite( buff, size );
|
||||
totalSize += size;
|
||||
}
|
||||
|
||||
//if we extracted the file correctly
|
||||
fp = new FCEUFILE();
|
||||
fp->archiveFilename = fname;
|
||||
fp->filename = filename;
|
||||
fp->fullFilename = fp->archiveFilename + "|" + fp->filename;
|
||||
fp->archiveIndex = idx;
|
||||
fp->mode = FCEUFILE::READ;
|
||||
fp->size = totalSize;
|
||||
fp->stream = ms;
|
||||
fp->archiveCount = (int)asr.numFilesInArchive;
|
||||
ms->fseek(0,SEEK_SET); //rewind so that the rom analyzer sees a freshly opened file
|
||||
}
|
||||
|
||||
archive_read_free(a);
|
||||
|
||||
return fp;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
FCEUFILE* FCEUD_OpenArchive(ArchiveScanRecord& asr, std::string& fname, std::string* innerFilename, int* userCancel)
|
||||
{
|
||||
FCEUFILE* fp = nullptr;
|
||||
std::string searchFile;
|
||||
|
||||
if ( innerFilename != NULL )
|
||||
|
@ -1547,75 +1911,14 @@ FCEUFILE* FCEUD_OpenArchive(ArchiveScanRecord& asr, std::string& fname, std::str
|
|||
}
|
||||
}
|
||||
|
||||
zf = unzOpen( fname.c_str() );
|
||||
#ifdef _USE_LIBARCHIVE
|
||||
fp = libarchive_OpenArchive(asr, fname, &searchFile, -1 );
|
||||
#endif
|
||||
|
||||
if ( zf == NULL )
|
||||
if (fp == nullptr)
|
||||
{
|
||||
//printf("Error: Failed to open Zip File: '%s'\n", fname.c_str() );
|
||||
return fp;
|
||||
fp = minizip_OpenArchive(asr, fname, &searchFile, -1 );
|
||||
}
|
||||
|
||||
//printf("Searching for %s in %s \n", searchFile.c_str(), fname.c_str() );
|
||||
|
||||
ret = unzGoToFirstFile( zf );
|
||||
|
||||
//printf("unzGoToFirstFile: %i \n", ret );
|
||||
|
||||
while ( ret == 0 )
|
||||
{
|
||||
unzGetCurrentFileInfo( zf, &fi, filename, sizeof(filename), NULL, 0, NULL, 0 );
|
||||
|
||||
//printf("Filename: %u '%s' \n", fi.uncompressed_size, filename );
|
||||
|
||||
if ( strcmp( searchFile.c_str(), filename ) == 0 )
|
||||
{
|
||||
//printf("Found Filename: %u '%s' \n", fi.uncompressed_size, filename );
|
||||
foundFile = 1; break;
|
||||
}
|
||||
|
||||
ret = unzGoToNextFile( zf );
|
||||
|
||||
//printf("unzGoToNextFile: %i \n", ret );
|
||||
}
|
||||
|
||||
if ( !foundFile )
|
||||
{
|
||||
unzClose( zf );
|
||||
return fp;
|
||||
}
|
||||
|
||||
tmpMem = ::malloc( fi.uncompressed_size );
|
||||
|
||||
if ( tmpMem == NULL )
|
||||
{
|
||||
unzClose( zf );
|
||||
return fp;
|
||||
}
|
||||
|
||||
EMUFILE_MEMORY* ms = new EMUFILE_MEMORY(fi.uncompressed_size);
|
||||
|
||||
unzOpenCurrentFile( zf );
|
||||
unzReadCurrentFile( zf, tmpMem, fi.uncompressed_size );
|
||||
unzCloseCurrentFile( zf );
|
||||
|
||||
ms->fwrite( tmpMem, fi.uncompressed_size );
|
||||
|
||||
free( tmpMem );
|
||||
|
||||
//if we extracted the file correctly
|
||||
fp = new FCEUFILE();
|
||||
fp->archiveFilename = fname;
|
||||
fp->filename = searchFile;
|
||||
fp->fullFilename = fp->archiveFilename + "|" + fp->filename;
|
||||
fp->archiveIndex = ret;
|
||||
fp->mode = FCEUFILE::READ;
|
||||
fp->size = fi.uncompressed_size;
|
||||
fp->stream = ms;
|
||||
fp->archiveCount = (int)asr.numFilesInArchive;
|
||||
ms->fseek(0,SEEK_SET); //rewind so that the rom analyzer sees a freshly opened file
|
||||
|
||||
unzClose( zf );
|
||||
|
||||
return fp;
|
||||
}
|
||||
|
||||
|
@ -1628,82 +1931,16 @@ FCEUFILE* FCEUD_OpenArchive(ArchiveScanRecord& asr, std::string& fname, std::str
|
|||
|
||||
FCEUFILE* FCEUD_OpenArchiveIndex(ArchiveScanRecord& asr, std::string &fname, int innerIndex, int* userCancel)
|
||||
{
|
||||
int ret, idx=0;
|
||||
FCEUFILE* fp = 0;
|
||||
unzFile zf;
|
||||
unz_file_info fi;
|
||||
char filename[512];
|
||||
char foundFile = 0;
|
||||
void *tmpMem = NULL;
|
||||
FCEUFILE* fp = nullptr;
|
||||
|
||||
zf = unzOpen( fname.c_str() );
|
||||
|
||||
if ( zf == NULL )
|
||||
#ifdef _USE_LIBARCHIVE
|
||||
fp = libarchive_OpenArchive( asr, fname, nullptr, innerIndex );
|
||||
#endif
|
||||
if (fp == nullptr)
|
||||
{
|
||||
//printf("Error: Failed to open Zip File: '%s'\n", fname.c_str() );
|
||||
return fp;
|
||||
fp = minizip_OpenArchive(asr, fname, nullptr, innerIndex);
|
||||
}
|
||||
|
||||
ret = unzGoToFirstFile( zf );
|
||||
|
||||
//printf("unzGoToFirstFile: %i \n", ret );
|
||||
|
||||
while ( ret == 0 )
|
||||
{
|
||||
unzGetCurrentFileInfo( zf, &fi, filename, sizeof(filename), NULL, 0, NULL, 0 );
|
||||
|
||||
//printf("Filename: %u '%s' \n", fi.uncompressed_size, filename );
|
||||
|
||||
if ( idx == innerIndex )
|
||||
{
|
||||
//printf("Found Filename: %u '%s' \n", fi.uncompressed_size, filename );
|
||||
foundFile = 1; break;
|
||||
}
|
||||
idx++;
|
||||
|
||||
ret = unzGoToNextFile( zf );
|
||||
|
||||
//printf("unzGoToNextFile: %i \n", ret );
|
||||
}
|
||||
|
||||
if ( !foundFile )
|
||||
{
|
||||
unzClose( zf );
|
||||
return fp;
|
||||
}
|
||||
|
||||
tmpMem = ::malloc( fi.uncompressed_size );
|
||||
|
||||
if ( tmpMem == NULL )
|
||||
{
|
||||
unzClose( zf );
|
||||
return fp;
|
||||
}
|
||||
|
||||
EMUFILE_MEMORY* ms = new EMUFILE_MEMORY(fi.uncompressed_size);
|
||||
|
||||
unzOpenCurrentFile( zf );
|
||||
unzReadCurrentFile( zf, tmpMem, fi.uncompressed_size );
|
||||
unzCloseCurrentFile( zf );
|
||||
|
||||
ms->fwrite( tmpMem, fi.uncompressed_size );
|
||||
|
||||
free( tmpMem );
|
||||
|
||||
//if we extracted the file correctly
|
||||
fp = new FCEUFILE();
|
||||
fp->archiveFilename = fname;
|
||||
fp->filename = filename;
|
||||
fp->fullFilename = fp->archiveFilename + "|" + fp->filename;
|
||||
fp->archiveIndex = ret;
|
||||
fp->mode = FCEUFILE::READ;
|
||||
fp->size = fi.uncompressed_size;
|
||||
fp->stream = ms;
|
||||
fp->archiveCount = (int)asr.numFilesInArchive;
|
||||
ms->fseek(0,SEEK_SET); //rewind so that the rom analyzer sees a freshly opened file
|
||||
|
||||
unzClose( zf );
|
||||
|
||||
return fp;
|
||||
}
|
||||
|
||||
|
|
|
@ -1230,28 +1230,15 @@ void GetMouseData(uint32 (&d)[3])
|
|||
|
||||
b = 0; // map mouse buttons
|
||||
|
||||
if (consoleWindow->viewport_SDL)
|
||||
if (consoleWindow->viewport_Interface)
|
||||
{
|
||||
consoleWindow->viewport_SDL->getNormalizedCursorPos(nx, ny);
|
||||
consoleWindow->viewport_Interface->getNormalizedCursorPos(nx, ny);
|
||||
|
||||
if (consoleWindow->viewport_SDL->getMouseButtonState(Qt::LeftButton))
|
||||
if (consoleWindow->viewport_Interface->getMouseButtonState(Qt::LeftButton))
|
||||
{
|
||||
b |= 0x01;
|
||||
}
|
||||
if (consoleWindow->viewport_SDL->getMouseButtonState(Qt::RightButton))
|
||||
{
|
||||
b |= 0x02;
|
||||
}
|
||||
}
|
||||
else if (consoleWindow->viewport_GL)
|
||||
{
|
||||
consoleWindow->viewport_GL->getNormalizedCursorPos(nx, ny);
|
||||
|
||||
if (consoleWindow->viewport_GL->getMouseButtonState(Qt::LeftButton))
|
||||
{
|
||||
b |= 0x01;
|
||||
}
|
||||
if (consoleWindow->viewport_GL->getMouseButtonState(Qt::RightButton))
|
||||
if (consoleWindow->viewport_Interface->getMouseButtonState(Qt::RightButton))
|
||||
{
|
||||
b |= 0x02;
|
||||
}
|
||||
|
|
|
@ -92,7 +92,6 @@ int openPPUViewWindow( QWidget *parent )
|
|||
{
|
||||
ppuViewWindow->activateWindow();
|
||||
ppuViewWindow->raise();
|
||||
ppuViewWindow->setFocus();
|
||||
return -1;
|
||||
}
|
||||
initPPUViewer();
|
||||
|
@ -110,7 +109,6 @@ int openOAMViewWindow( QWidget *parent )
|
|||
{
|
||||
spriteViewWindow->activateWindow();
|
||||
spriteViewWindow->raise();
|
||||
spriteViewWindow->setFocus();
|
||||
return -1;
|
||||
}
|
||||
initPPUViewer();
|
||||
|
@ -637,8 +635,8 @@ QPoint ppuPatternView_t::convPixToTile( QPoint p )
|
|||
w = pattern->w;
|
||||
h = pattern->h;
|
||||
|
||||
i = x / (w*8);
|
||||
j = y / (h*8);
|
||||
i = w == 0 ? 0 : x / (w*8);
|
||||
j = h == 0 ? 0 : y / (h*8);
|
||||
|
||||
if ( PPUView_sprite16Mode[ patternIndex ] )
|
||||
{
|
||||
|
@ -3338,8 +3336,8 @@ QPoint oamPatternView_t::convPixToTile( QPoint p )
|
|||
w = oamPattern.w;
|
||||
h = oamPattern.h;
|
||||
|
||||
i = x / (w*8);
|
||||
j = y / (h*16);
|
||||
i = w == 0 ? 0 : x / (w*8);
|
||||
j = h == 0 ? 0 : y / (h*16);
|
||||
|
||||
//printf("(x,y) = (%i,%i) w=%i h=%i $%X%X \n", x, y, w, h, jj, ii );
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
|
||||
#include "Qt/sdl.h"
|
||||
#include "Qt/throttle.h"
|
||||
#include "utils/timeStamp.h"
|
||||
|
||||
#if defined(__linux__) || defined(__APPLE__) || defined(__unix__)
|
||||
#include <time.h>
|
||||
|
@ -36,7 +37,8 @@ static const double Fastest = 32; // 32x speed (around 1920 fps on NTSC)
|
|||
static const double Normal = 1.0; // 1x speed (around 60 fps on NTSC)
|
||||
|
||||
static uint32 frameLateCounter = 0;
|
||||
static double Lasttime=0, Nexttime=0, Latetime=0;
|
||||
static FCEU::timeStampRecord Lasttime, Nexttime, Latetime;
|
||||
static FCEU::timeStampRecord DesiredFrameTime, HalfFrameTime, QuarterFrameTime, DoubleFrameTime;
|
||||
static double desired_frametime = (1.0 / 60.099823);
|
||||
static double desired_frameRate = (60.099823);
|
||||
static double baseframeRate = (60.099823);
|
||||
|
@ -60,21 +62,22 @@ extern bool turbo;
|
|||
|
||||
double getHighPrecTimeStamp(void)
|
||||
{
|
||||
#if defined(__linux__) || defined(__APPLE__) || defined(__unix__)
|
||||
struct timespec ts;
|
||||
double t;
|
||||
|
||||
clock_gettime( CLOCK_REALTIME, &ts );
|
||||
if (FCEU::timeStampModuleInitialized())
|
||||
{
|
||||
FCEU::timeStampRecord ts;
|
||||
|
||||
t = (double)ts.tv_sec + (double)(ts.tv_nsec * 1.0e-9);
|
||||
#else
|
||||
double t;
|
||||
ts.readNew();
|
||||
|
||||
t = (double)SDL_GetTicks();
|
||||
|
||||
t = t * 1e-3;
|
||||
#endif
|
||||
t = ts.toSeconds();
|
||||
}
|
||||
else
|
||||
{
|
||||
t = (double)SDL_GetTicks();
|
||||
|
||||
t = t * 1e-3;
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
|
@ -117,9 +120,9 @@ static void setTimer( double hz )
|
|||
|
||||
//printf("Timer Set: %li ns\n", ispec.it_value.tv_nsec );
|
||||
|
||||
Lasttime = getHighPrecTimeStamp();
|
||||
Nexttime = Lasttime + desired_frametime;
|
||||
Latetime = Nexttime + (desired_frametime*0.50);
|
||||
Lasttime.readNew();
|
||||
Nexttime = Lasttime + DesiredFrameTime;
|
||||
Latetime = Nexttime + HalfFrameTime;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -268,10 +271,17 @@ RefreshThrottleFPS(void)
|
|||
|
||||
if ( T < 0 ) T = 1;
|
||||
|
||||
DesiredFrameTime.fromSeconds( desired_frametime );
|
||||
HalfFrameTime = DesiredFrameTime / 2;
|
||||
QuarterFrameTime = DesiredFrameTime / 4;
|
||||
DoubleFrameTime = DesiredFrameTime * 2;
|
||||
|
||||
//printf("FrameTime: %f %f %f %f \n", DesiredFrameTime.toSeconds(),
|
||||
// HalfFrameTime.toSeconds(), QuarterFrameTime.toSeconds(), DoubleFrameTime.toSeconds() );
|
||||
//printf("FrameTime: %llu %llu %f %lf \n", fps, fps >> 24, hz, desired_frametime );
|
||||
|
||||
Lasttime=0;
|
||||
Nexttime=0;
|
||||
Lasttime.zero();
|
||||
Nexttime.zero();
|
||||
InFrame=0;
|
||||
|
||||
#ifdef __linux__
|
||||
|
@ -295,18 +305,17 @@ double getFrameRateAdjustmentRatio(void)
|
|||
return frmRateAdjRatio;
|
||||
}
|
||||
|
||||
int highPrecSleep( double timeSeconds )
|
||||
static int highPrecSleep( FCEU::timeStampRecord &ts )
|
||||
{
|
||||
int ret = 0;
|
||||
#if defined(__linux__) || defined(__APPLE__) || defined(__unix__)
|
||||
struct timespec req, rem;
|
||||
|
||||
req.tv_sec = (long)timeSeconds;
|
||||
req.tv_nsec = (long)((timeSeconds - (double)req.tv_sec) * 1e9);
|
||||
req = ts.toTimeSpec();
|
||||
|
||||
ret = nanosleep( &req, &rem );
|
||||
#else
|
||||
SDL_Delay( (long)(timeSeconds * 1e3) );
|
||||
SDL_Delay( ts.toMilliSeconds() );
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
@ -321,39 +330,37 @@ SpeedThrottle(void)
|
|||
{
|
||||
return 0; /* Done waiting */
|
||||
}
|
||||
double time_left;
|
||||
double cur_time, idleStart;
|
||||
double frame_time = desired_frametime;
|
||||
double halfFrame = 0.500 * frame_time;
|
||||
double quarterFrame = 0.250 * frame_time;
|
||||
FCEU::timeStampRecord cur_time, idleStart, time_left;
|
||||
|
||||
idleStart = cur_time = getHighPrecTimeStamp();
|
||||
cur_time.readNew();
|
||||
idleStart = cur_time;
|
||||
|
||||
if (Lasttime < 1.0)
|
||||
if (Lasttime.isZero())
|
||||
{
|
||||
//printf("Lasttime Reset\n");
|
||||
Lasttime = cur_time;
|
||||
Latetime = Lasttime + 2.0*frame_time;
|
||||
Latetime = Lasttime + DoubleFrameTime;
|
||||
}
|
||||
|
||||
if (!InFrame)
|
||||
{
|
||||
InFrame = 1;
|
||||
Nexttime = Lasttime + frame_time;
|
||||
Latetime = Nexttime + halfFrame;
|
||||
Nexttime = Lasttime + DesiredFrameTime;
|
||||
Latetime = Nexttime + HalfFrameTime;
|
||||
}
|
||||
|
||||
if (cur_time >= Nexttime)
|
||||
{
|
||||
time_left = 0;
|
||||
time_left.zero();
|
||||
}
|
||||
else
|
||||
{
|
||||
time_left = Nexttime - cur_time;
|
||||
}
|
||||
|
||||
if (time_left > 50)
|
||||
if (time_left.toMilliSeconds() > 50)
|
||||
{
|
||||
time_left = 50;
|
||||
time_left.fromMilliSeconds(50);
|
||||
/* In order to keep input responsive, don't wait too long at once */
|
||||
/* 50 ms wait gives us a 20 Hz responsetime which is nice. */
|
||||
}
|
||||
|
@ -379,7 +386,7 @@ SpeedThrottle(void)
|
|||
}
|
||||
}
|
||||
}
|
||||
else if ( time_left > 0 )
|
||||
else if ( !time_left.isZero() )
|
||||
{
|
||||
highPrecSleep( time_left );
|
||||
}
|
||||
|
@ -392,7 +399,7 @@ SpeedThrottle(void)
|
|||
}
|
||||
}
|
||||
#else
|
||||
if ( time_left > 0 )
|
||||
if ( !time_left.isZero() )
|
||||
{
|
||||
highPrecSleep( time_left );
|
||||
}
|
||||
|
@ -406,14 +413,15 @@ SpeedThrottle(void)
|
|||
}
|
||||
#endif
|
||||
|
||||
cur_time = getHighPrecTimeStamp();
|
||||
cur_time.readNew();
|
||||
|
||||
if ( cur_time >= (Nexttime - quarterFrame) )
|
||||
if ( cur_time >= (Nexttime - QuarterFrameTime) )
|
||||
{
|
||||
if ( keepFrameTimeStats )
|
||||
{
|
||||
FCEU::timeStampRecord diffTime = (cur_time - Lasttime);
|
||||
|
||||
frameDeltaCur = (cur_time - Lasttime);
|
||||
frameDeltaCur = diffTime.toSeconds();
|
||||
|
||||
if ( frameDeltaCur < frameDeltaMin )
|
||||
{
|
||||
|
@ -424,7 +432,9 @@ SpeedThrottle(void)
|
|||
frameDeltaMax = frameDeltaCur;
|
||||
}
|
||||
|
||||
frameIdleCur = (cur_time - idleStart);
|
||||
diffTime = (cur_time - idleStart);
|
||||
|
||||
frameIdleCur = diffTime.toSeconds();
|
||||
|
||||
if ( frameIdleCur < frameIdleMin )
|
||||
{
|
||||
|
@ -438,14 +448,14 @@ SpeedThrottle(void)
|
|||
//printf("Frame Sleep Time: %f Target Error: %f us\n", time_left * 1e6, (cur_time - Nexttime) * 1e6 );
|
||||
}
|
||||
Lasttime = Nexttime;
|
||||
Nexttime = Lasttime + frame_time;
|
||||
Latetime = Nexttime + halfFrame;
|
||||
Nexttime = Lasttime + DesiredFrameTime;
|
||||
Latetime = Nexttime + HalfFrameTime;
|
||||
|
||||
if ( cur_time >= Nexttime )
|
||||
{
|
||||
Lasttime = cur_time;
|
||||
Nexttime = Lasttime + frame_time;
|
||||
Latetime = Nexttime + halfFrame;
|
||||
Nexttime = Lasttime + DesiredFrameTime;
|
||||
Latetime = Nexttime + HalfFrameTime;
|
||||
}
|
||||
return 0; /* Done waiting */
|
||||
}
|
||||
|
|
|
@ -1235,7 +1235,7 @@ void DeleteBreak(int sel)
|
|||
if(sel<0) return;
|
||||
if(sel>=numWPs) return;
|
||||
if (watchpoint[sel].cond)
|
||||
freeTree(watchpoint[sel].cond);
|
||||
delete watchpoint[sel].cond;
|
||||
if (watchpoint[sel].condText)
|
||||
free(watchpoint[sel].condText);
|
||||
if (watchpoint[sel].desc)
|
||||
|
|
|
@ -179,10 +179,10 @@ public:
|
|||
va_start(argptr, format);
|
||||
vsprintf(tempbuf,format,argptr);
|
||||
|
||||
fwrite(tempbuf,amt);
|
||||
fwrite(tempbuf,amt);
|
||||
delete[] tempbuf;
|
||||
|
||||
va_end(argptr);
|
||||
va_end(argptr);
|
||||
return amt;
|
||||
};
|
||||
|
||||
|
|
57
src/fceu.cpp
57
src/fceu.cpp
|
@ -36,6 +36,7 @@
|
|||
#include "unif.h"
|
||||
#include "cheat.h"
|
||||
#include "palette.h"
|
||||
#include "profiler.h"
|
||||
#include "state.h"
|
||||
#include "movie.h"
|
||||
#include "video.h"
|
||||
|
@ -116,6 +117,7 @@ bool movieSubtitles = true; //Toggle for displaying movie subtitles
|
|||
bool DebuggerWasUpdated = false; //To prevent the debugger from updating things without being updated.
|
||||
bool AutoResumePlay = false;
|
||||
char romNameWhenClosingEmulator[2048] = {0};
|
||||
static unsigned int pauseTimer = 0;
|
||||
|
||||
|
||||
FCEUGI::FCEUGI()
|
||||
|
@ -208,6 +210,8 @@ static void FCEU_CloseGame(void)
|
|||
|
||||
GameInterface(GI_CLOSE);
|
||||
|
||||
FCEU_StateRecorderStop();
|
||||
|
||||
FCEUI_StopMovie();
|
||||
|
||||
ResetExState(0, 0);
|
||||
|
@ -592,6 +596,12 @@ FCEUGI *FCEUI_LoadGameVirtual(const char *name, int OverwriteVidMode, bool silen
|
|||
}
|
||||
|
||||
FCEU_fclose(fp);
|
||||
|
||||
if ( FCEU_StateRecorderIsEnabled() )
|
||||
{
|
||||
FCEU_StateRecorderStart();
|
||||
}
|
||||
|
||||
return GameInfo;
|
||||
}
|
||||
|
||||
|
@ -725,6 +735,7 @@ extern unsigned int frameAdvHoldTimer;
|
|||
|
||||
///Skip may be passed in, if FRAMESKIP is #defined, to cause this to emulate more than one frame
|
||||
void FCEUI_Emulate(uint8 **pXBuf, int32 **SoundBuf, int32 *SoundBufSize, int skip) {
|
||||
FCEU_PROFILE_FUNC(prof, "Emulate Single Frame");
|
||||
//skip initiates frame skip if 1, or frame skip and sound skip if 2
|
||||
FCEU_MAYBE_UNUSED int r;
|
||||
int ssize;
|
||||
|
@ -756,6 +767,22 @@ void FCEUI_Emulate(uint8 **pXBuf, int32 **SoundBuf, int32 *SoundBufSize, int ski
|
|||
#endif
|
||||
}
|
||||
|
||||
if (EmulationPaused & EMULATIONPAUSED_TIMER)
|
||||
{
|
||||
if (pauseTimer > 0)
|
||||
{
|
||||
pauseTimer--;
|
||||
}
|
||||
else
|
||||
{
|
||||
EmulationPaused &= ~EMULATIONPAUSED_TIMER;
|
||||
}
|
||||
if (EmulationPaused & EMULATIONPAUSED_PAUSED)
|
||||
{
|
||||
EmulationPaused &= ~EMULATIONPAUSED_TIMER;
|
||||
}
|
||||
}
|
||||
|
||||
if (EmulationPaused & EMULATIONPAUSED_FA)
|
||||
{
|
||||
// the user is holding Frame Advance key
|
||||
|
@ -779,7 +806,7 @@ void FCEUI_Emulate(uint8 **pXBuf, int32 **SoundBuf, int32 *SoundBufSize, int ski
|
|||
RefreshThrottleFPS();
|
||||
}
|
||||
#endif
|
||||
if (EmulationPaused & EMULATIONPAUSED_PAUSED)
|
||||
if (EmulationPaused & (EMULATIONPAUSED_PAUSED | EMULATIONPAUSED_TIMER) )
|
||||
{
|
||||
// emulator is paused
|
||||
memcpy(XBuf, XBackBuf, 256*256);
|
||||
|
@ -793,6 +820,7 @@ void FCEUI_Emulate(uint8 **pXBuf, int32 **SoundBuf, int32 *SoundBufSize, int ski
|
|||
|
||||
AutoFire();
|
||||
UpdateAutosave();
|
||||
FCEU_StateRecorderUpdate();
|
||||
|
||||
#ifdef _S9XLUA_H
|
||||
FCEU_LuaFrameBoundary();
|
||||
|
@ -1254,6 +1282,33 @@ void FCEUI_FrameAdvance(void) {
|
|||
frameAdvanceRequested = true;
|
||||
}
|
||||
|
||||
void FCEUI_PauseForDuration(int secs)
|
||||
{
|
||||
int framesPerSec;
|
||||
|
||||
// If already paused, do nothing
|
||||
if (EmulationPaused & EMULATIONPAUSED_PAUSED)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (PAL || dendy)
|
||||
{
|
||||
framesPerSec = 50;
|
||||
}
|
||||
else
|
||||
{
|
||||
framesPerSec = 60;
|
||||
}
|
||||
pauseTimer = framesPerSec * secs;
|
||||
EmulationPaused |= EMULATIONPAUSED_TIMER;
|
||||
}
|
||||
|
||||
int FCEUI_PauseFramesRemaining(void)
|
||||
{
|
||||
return (EmulationPaused & EMULATIONPAUSED_TIMER) ? pauseTimer : 0;
|
||||
}
|
||||
|
||||
static int AutosaveCounter = 0;
|
||||
|
||||
void UpdateAutosave(void) {
|
||||
|
|
|
@ -181,8 +181,9 @@ extern uint8 vsdip;
|
|||
|
||||
#define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0]))
|
||||
|
||||
#define EMULATIONPAUSED_PAUSED 1
|
||||
#define EMULATIONPAUSED_FA 2
|
||||
#define EMULATIONPAUSED_PAUSED 0x01
|
||||
#define EMULATIONPAUSED_TIMER 0x02
|
||||
#define EMULATIONPAUSED_FA 0x04
|
||||
|
||||
#define FRAMEADVANCE_DELAY_DEFAULT 10
|
||||
#define NES_HEADER_SIZE 16
|
||||
|
|
|
@ -21,9 +21,6 @@ enum LuaMemHookType
|
|||
LUAMEMHOOK_WRITE,
|
||||
LUAMEMHOOK_READ,
|
||||
LUAMEMHOOK_EXEC,
|
||||
LUAMEMHOOK_WRITE_SUB,
|
||||
LUAMEMHOOK_READ_SUB,
|
||||
LUAMEMHOOK_EXEC_SUB,
|
||||
|
||||
LUAMEMHOOK_COUNT
|
||||
};
|
||||
|
|
|
@ -689,7 +689,7 @@ BMAPPINGLocal bmap[] = {
|
|||
{"", 171, Mapper171_Init},
|
||||
{"", 172, Mapper172_Init},
|
||||
{"", 173, Mapper173_Init},
|
||||
// {"", 174, Mapper174_Init},
|
||||
{"NTDec 5-in-1", 174, Mapper174_Init},
|
||||
{"", 175, Mapper175_Init},
|
||||
{"BMCFK23C", 176, BMCFK23C_Init}, // zero 26-may-2012 - well, i have some WXN junk games that use 176 for instance ????. i dont know what game uses this BMCFK23C as mapper 176. we'll have to make a note when we find it.
|
||||
{"", 177, Mapper177_Init},
|
||||
|
@ -720,7 +720,7 @@ BMAPPINGLocal bmap[] = {
|
|||
{"", 202, Mapper202_Init},
|
||||
{"", 203, Mapper203_Init},
|
||||
{"", 204, Mapper204_Init},
|
||||
{"", 205, Mapper205_Init},
|
||||
{"JC-016-2", 205, Mapper205_Init},
|
||||
{"NAMCOT 108 Rev. C", 206, Mapper206_Init}, // Deprecated, Used to be "DEIROM" whatever it means, but actually simple version of MMC3
|
||||
{"TAITO X1-005 Rev. B", 207, Mapper207_Init},
|
||||
{"", 208, Mapper208_Init},
|
||||
|
@ -788,6 +788,8 @@ BMAPPINGLocal bmap[] = {
|
|||
{"HP10xx/H20xx Boards", 260, BMCHPxx_Init},
|
||||
{"810544-CA-1", 261, BMC810544CA1_Init},
|
||||
{"AA6023/AA6023B", 268, AA6023_Init},
|
||||
{"OK-411", 361, GN45_Init},
|
||||
{"GN-45", 366, GN45_Init},
|
||||
{"COOLGIRL", 342, COOLGIRL_Init },
|
||||
{"FAM250/81-01-39-C/SCHI-24", 354, Mapper354_Init },
|
||||
|
||||
|
|
|
@ -208,6 +208,7 @@ void Mapper170_Init(CartInfo *);
|
|||
void Mapper171_Init(CartInfo *);
|
||||
void Mapper172_Init(CartInfo *);
|
||||
void Mapper173_Init(CartInfo *);
|
||||
void Mapper174_Init(CartInfo *);
|
||||
void Mapper175_Init(CartInfo *);
|
||||
void Mapper177_Init(CartInfo *);
|
||||
void Mapper178_Init(CartInfo *);
|
||||
|
@ -280,6 +281,7 @@ void Mapper406_Init(CartInfo *);
|
|||
void Mapper474_Init(CartInfo*);
|
||||
|
||||
void INX_007T_Init(CartInfo* info);
|
||||
void GN45_Init(CartInfo *info); /* previously mapper 205 */
|
||||
|
||||
typedef struct {
|
||||
const char *name;
|
||||
|
|
|
@ -26,7 +26,6 @@
|
|||
#include "debug.h"
|
||||
#include "debugsymboltable.h"
|
||||
#include "sound.h"
|
||||
#include "drawing.h"
|
||||
#include "state.h"
|
||||
#include "movie.h"
|
||||
#include "driver.h"
|
||||
|
@ -319,10 +318,6 @@ static const char* luaMemHookTypeStrings [] =
|
|||
"MEMHOOK_WRITE",
|
||||
"MEMHOOK_READ",
|
||||
"MEMHOOK_EXEC",
|
||||
|
||||
"MEMHOOK_WRITE_SUB",
|
||||
"MEMHOOK_READ_SUB",
|
||||
"MEMHOOK_EXEC_SUB",
|
||||
};
|
||||
|
||||
//make sure we have the right number of strings
|
||||
|
@ -2431,53 +2426,17 @@ static int memory_registerHook(lua_State* L, LuaMemHookType hookType, int defaul
|
|||
return 0;
|
||||
}
|
||||
|
||||
LuaMemHookType MatchHookTypeToCPU(lua_State* L, LuaMemHookType hookType)
|
||||
{
|
||||
int cpuID = 0;
|
||||
|
||||
int cpunameIndex = 0;
|
||||
if(lua_type(L,2) == LUA_TSTRING)
|
||||
cpunameIndex = 2;
|
||||
else if(lua_type(L,3) == LUA_TSTRING)
|
||||
cpunameIndex = 3;
|
||||
|
||||
if(cpunameIndex)
|
||||
{
|
||||
const char* cpuName = lua_tostring(L, cpunameIndex);
|
||||
if(!stricmp(cpuName, "sub"))
|
||||
cpuID = 1;
|
||||
lua_remove(L, cpunameIndex);
|
||||
}
|
||||
|
||||
switch(cpuID)
|
||||
{
|
||||
case 0:
|
||||
return hookType;
|
||||
|
||||
case 1:
|
||||
switch(hookType)
|
||||
{
|
||||
case LUAMEMHOOK_WRITE: return LUAMEMHOOK_WRITE_SUB;
|
||||
case LUAMEMHOOK_READ: return LUAMEMHOOK_READ_SUB;
|
||||
case LUAMEMHOOK_EXEC: return LUAMEMHOOK_EXEC_SUB;
|
||||
default: return hookType;
|
||||
}
|
||||
}
|
||||
return hookType;
|
||||
}
|
||||
|
||||
static int memory_registerwrite(lua_State *L)
|
||||
{
|
||||
return memory_registerHook(L, MatchHookTypeToCPU(L,LUAMEMHOOK_WRITE), 1);
|
||||
return memory_registerHook(L, LUAMEMHOOK_WRITE, 1);
|
||||
}
|
||||
FCEU_MAYBE_UNUSED
|
||||
static int memory_registerread(lua_State *L)
|
||||
{
|
||||
return memory_registerHook(L, MatchHookTypeToCPU(L,LUAMEMHOOK_READ), 1);
|
||||
return memory_registerHook(L, LUAMEMHOOK_READ, 1);
|
||||
}
|
||||
static int memory_registerexec(lua_State *L)
|
||||
{
|
||||
return memory_registerHook(L, MatchHookTypeToCPU(L,LUAMEMHOOK_EXEC), 1);
|
||||
return memory_registerHook(L, LUAMEMHOOK_EXEC, 1);
|
||||
}
|
||||
|
||||
//adelikat: table pulled from GENS. credz nitsuja!
|
||||
|
@ -6137,7 +6096,7 @@ static const struct luaL_reg memorylib [] = {
|
|||
|
||||
// memory hooks
|
||||
{"registerwrite", memory_registerwrite},
|
||||
//{"registerread", memory_registerread}, TODO
|
||||
{"registerread", memory_registerread},
|
||||
{"registerexec", memory_registerexec},
|
||||
// alternate names
|
||||
{"register", memory_registerwrite},
|
||||
|
|
15
src/ppu.cpp
15
src/ppu.cpp
|
@ -1734,10 +1734,17 @@ void FCEUPPU_Reset(void) {
|
|||
void FCEUPPU_Power(void) {
|
||||
int x;
|
||||
|
||||
memset(NTARAM, 0x00, 0x800);
|
||||
memset(PALRAM, 0x00, 0x20);
|
||||
memset(UPALRAM, 0x00, 0x03);
|
||||
memset(SPRAM, 0x00, 0x100);
|
||||
// initialize PPU memory regions according to settings
|
||||
FCEU_MemoryRand(NTARAM, 0x800, true);
|
||||
FCEU_MemoryRand(PALRAM, 0x20, true);
|
||||
FCEU_MemoryRand(SPRAM, 0x100, true);
|
||||
// palettes can only store values up to $3F, and PALRAM X4/X8/XC are mirrors of X0 for rendering purposes (UPALRAM is used for $2007 readback)
|
||||
for (x = 0; x < 0x20; ++x) PALRAM[x] &= 0x3F;
|
||||
UPALRAM[0] = PALRAM[0x04];
|
||||
UPALRAM[1] = PALRAM[0x08];
|
||||
UPALRAM[2] = PALRAM[0x0C];
|
||||
PALRAM[0x0C] = PALRAM[0x08] = PALRAM[0x04] = PALRAM[0x00];
|
||||
PALRAM[0x1C] = PALRAM[0x18] = PALRAM[0x14] = PALRAM[0x10];
|
||||
FCEUPPU_Reset();
|
||||
|
||||
for (x = 0x2000; x < 0x4000; x += 8) {
|
||||
|
|
|
@ -0,0 +1,367 @@
|
|||
/* FCE Ultra - NES/Famicom Emulator
|
||||
*
|
||||
* Copyright notice for this file:
|
||||
* Copyright (C) 2002 Xodnizel
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
// profiler.cpp
|
||||
//
|
||||
#ifdef __FCEU_PROFILER_ENABLE__
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef __QT_DRIVER__
|
||||
#include <QThread>
|
||||
#endif
|
||||
|
||||
#include "utils/mutex.h"
|
||||
#include "fceu.h"
|
||||
#include "profiler.h"
|
||||
|
||||
namespace FCEU
|
||||
{
|
||||
static thread_local profileExecVector execList;
|
||||
static thread_local profilerFuncMap threadProfileMap;
|
||||
|
||||
FILE *profilerManager::pLog = nullptr;
|
||||
|
||||
static profilerManager pMgr;
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
//---- Function Profile Record
|
||||
//-------------------------------------------------------------------------
|
||||
funcProfileRecord::funcProfileRecord(const char *fileNameStringLiteral,
|
||||
const int fileLineNumber,
|
||||
const char *funcNameStringLiteral,
|
||||
const char *commentStringLiteral)
|
||||
|
||||
: fileLineNum(fileLineNumber), fileName(fileNameStringLiteral),
|
||||
funcName(funcNameStringLiteral), comment(commentStringLiteral)
|
||||
{
|
||||
min.fromSeconds(9);
|
||||
max.zero();
|
||||
sum.zero();
|
||||
numCalls = 0;
|
||||
recursionCount = 0;
|
||||
|
||||
threadProfileMap.addRecord( fileNameStringLiteral, fileLineNumber,
|
||||
funcNameStringLiteral, commentStringLiteral, this);
|
||||
}
|
||||
//-------------------------------------------------------------------------
|
||||
void funcProfileRecord::reset(void)
|
||||
{
|
||||
min.fromSeconds(9);
|
||||
max.zero();
|
||||
sum.zero();
|
||||
numCalls = 0;
|
||||
}
|
||||
//-------------------------------------------------------------------------
|
||||
double funcProfileRecord::average(void)
|
||||
{
|
||||
double avg = 0.0;
|
||||
|
||||
if (numCalls)
|
||||
{
|
||||
avg = sum.toSeconds() / static_cast<double>(numCalls);
|
||||
}
|
||||
return avg;
|
||||
}
|
||||
//-------------------------------------------------------------------------
|
||||
//---- Profile Scoped Function Class
|
||||
//-------------------------------------------------------------------------
|
||||
profileFuncScoped::profileFuncScoped( funcProfileRecord *recordIn )
|
||||
{
|
||||
rec = recordIn;
|
||||
|
||||
if (rec)
|
||||
{
|
||||
threadProfileMap.pushStack(rec);
|
||||
start.readNew();
|
||||
rec->numCalls++;
|
||||
rec->recursionCount++;
|
||||
}
|
||||
}
|
||||
//-------------------------------------------------------------------------
|
||||
profileFuncScoped::~profileFuncScoped(void)
|
||||
{
|
||||
if (rec)
|
||||
{
|
||||
timeStampRecord ts, dt;
|
||||
ts.readNew();
|
||||
dt = ts - start;
|
||||
|
||||
rec->last = dt;
|
||||
rec->sum += dt;
|
||||
if (dt < rec->min) rec->min = dt;
|
||||
if (dt > rec->max) rec->max = dt;
|
||||
|
||||
rec->recursionCount--;
|
||||
|
||||
execList._vec.push_back(*rec);
|
||||
|
||||
threadProfileMap.popStack(rec);
|
||||
}
|
||||
}
|
||||
//-------------------------------------------------------------------------
|
||||
//---- Profile Execution Vector
|
||||
//-------------------------------------------------------------------------
|
||||
profileExecVector::profileExecVector(void)
|
||||
{
|
||||
_vec.reserve( 10000 );
|
||||
|
||||
char threadName[128];
|
||||
char fileName[256];
|
||||
|
||||
strcpy( threadName, "MainThread");
|
||||
|
||||
#ifdef __QT_DRIVER__
|
||||
QThread *thread = QThread::currentThread();
|
||||
|
||||
if (thread)
|
||||
{
|
||||
//printf("Thread: %s\n", thread->objectName().toStdString().c_str());
|
||||
strcpy( threadName, thread->objectName().toStdString().c_str());
|
||||
}
|
||||
#endif
|
||||
sprintf( fileName, "fceux-profile-%s.log", threadName);
|
||||
|
||||
logFp = ::fopen(fileName, "w");
|
||||
|
||||
if (logFp == nullptr)
|
||||
{
|
||||
printf("Error: Failed to create profiler logfile: %s\n", fileName);
|
||||
}
|
||||
}
|
||||
//-------------------------------------------------------------------------
|
||||
profileExecVector::~profileExecVector(void)
|
||||
{
|
||||
if (logFp)
|
||||
{
|
||||
::fclose(logFp);
|
||||
}
|
||||
}
|
||||
//-------------------------------------------------------------------------
|
||||
void profileExecVector::update(void)
|
||||
{
|
||||
size_t n = _vec.size();
|
||||
|
||||
for (size_t i=0; i<n; i++)
|
||||
{
|
||||
funcProfileRecord &rec = _vec[i];
|
||||
|
||||
fprintf( logFp, "%s: %u %f %f %f %f\n", rec.funcName, rec.numCalls, rec.last.toSeconds(), rec.average(), rec.min.toSeconds(), rec.max.toSeconds());
|
||||
}
|
||||
_vec.clear();
|
||||
}
|
||||
//-------------------------------------------------------------------------
|
||||
//---- Profile Function Record Map
|
||||
//-------------------------------------------------------------------------
|
||||
profilerFuncMap::profilerFuncMap(void)
|
||||
{
|
||||
//printf("profilerFuncMap Constructor: %p\n", this);
|
||||
pMgr.addThreadProfiler(this);
|
||||
|
||||
_map_it = _map.begin();
|
||||
}
|
||||
//-------------------------------------------------------------------------
|
||||
profilerFuncMap::~profilerFuncMap(void)
|
||||
{
|
||||
//printf("profilerFuncMap Destructor: %p\n", this);
|
||||
pMgr.removeThreadProfiler(this);
|
||||
|
||||
//{
|
||||
// autoScopedLock aLock(_mapMtx);
|
||||
|
||||
// for (auto it = _map.begin(); it != _map.end(); it++)
|
||||
// {
|
||||
// delete it->second;
|
||||
// }
|
||||
// _map.clear();
|
||||
//}
|
||||
}
|
||||
//-------------------------------------------------------------------------
|
||||
void profilerFuncMap::pushStack(funcProfileRecord *rec)
|
||||
{
|
||||
stack.push_back(rec);
|
||||
}
|
||||
//-------------------------------------------------------------------------
|
||||
void profilerFuncMap::popStack(funcProfileRecord *rec)
|
||||
{
|
||||
stack.pop_back();
|
||||
}
|
||||
//-------------------------------------------------------------------------
|
||||
int profilerFuncMap::addRecord(const char *fileNameStringLiteral,
|
||||
const int fileLineNumber,
|
||||
const char *funcNameStringLiteral,
|
||||
const char *commentStringLiteral,
|
||||
funcProfileRecord *rec )
|
||||
{
|
||||
autoScopedLock aLock(_mapMtx);
|
||||
char lineString[64];
|
||||
|
||||
sprintf( lineString, ":%i", fileLineNumber);
|
||||
|
||||
std::string fname(fileNameStringLiteral);
|
||||
|
||||
fname.append( lineString );
|
||||
|
||||
_map[fname] = rec;
|
||||
|
||||
return 0;
|
||||
}
|
||||
//-------------------------------------------------------------------------
|
||||
funcProfileRecord *profilerFuncMap::findRecord(const char *fileNameStringLiteral,
|
||||
const int fileLineNumber,
|
||||
const char *funcNameStringLiteral,
|
||||
const char *commentStringLiteral,
|
||||
bool create)
|
||||
{
|
||||
autoScopedLock aLock(_mapMtx);
|
||||
char lineString[64];
|
||||
funcProfileRecord *rec = nullptr;
|
||||
|
||||
sprintf( lineString, ":%i", fileLineNumber);
|
||||
|
||||
std::string fname(fileNameStringLiteral);
|
||||
|
||||
fname.append( lineString );
|
||||
|
||||
auto it = _map.find(fname);
|
||||
|
||||
if (it != _map.end())
|
||||
{
|
||||
rec = it->second;
|
||||
}
|
||||
else if (create)
|
||||
{
|
||||
fprintf( pMgr.pLog, "Creating Function Profile Record: %s %s\n", fname.c_str(), funcNameStringLiteral);
|
||||
|
||||
rec = new funcProfileRecord( fileNameStringLiteral, fileLineNumber,
|
||||
funcNameStringLiteral, commentStringLiteral);
|
||||
|
||||
_map[fname] = rec;
|
||||
}
|
||||
return rec;
|
||||
}
|
||||
//-------------------------------------------------------------------------
|
||||
funcProfileRecord *profilerFuncMap::iterateBegin(void)
|
||||
{
|
||||
autoScopedLock aLock(_mapMtx);
|
||||
funcProfileRecord *rec = nullptr;
|
||||
|
||||
_map_it = _map.begin();
|
||||
|
||||
if (_map_it != _map.end())
|
||||
{
|
||||
rec = _map_it->second;
|
||||
}
|
||||
return rec;
|
||||
}
|
||||
//-------------------------------------------------------------------------
|
||||
funcProfileRecord *profilerFuncMap::iterateNext(void)
|
||||
{
|
||||
autoScopedLock aLock(_mapMtx);
|
||||
funcProfileRecord *rec = nullptr;
|
||||
|
||||
if (_map_it != _map.end())
|
||||
{
|
||||
_map_it++;
|
||||
}
|
||||
if (_map_it != _map.end())
|
||||
{
|
||||
rec = _map_it->second;
|
||||
}
|
||||
return rec;
|
||||
}
|
||||
//-------------------------------------------------------------------------
|
||||
//----- profilerManager class
|
||||
//-------------------------------------------------------------------------
|
||||
profilerManager* profilerManager::instance = nullptr;
|
||||
|
||||
profilerManager* profilerManager::getInstance(void)
|
||||
{
|
||||
return instance;
|
||||
}
|
||||
//-------------------------------------------------------------------------
|
||||
profilerManager::profilerManager(void)
|
||||
{
|
||||
//printf("profilerManager Constructor\n");
|
||||
if (pLog == nullptr)
|
||||
{
|
||||
pLog = stdout;
|
||||
}
|
||||
|
||||
if (instance == nullptr)
|
||||
{
|
||||
instance = this;
|
||||
}
|
||||
}
|
||||
|
||||
profilerManager::~profilerManager(void)
|
||||
{
|
||||
//printf("profilerManager Destructor\n");
|
||||
{
|
||||
autoScopedLock aLock(threadListMtx);
|
||||
threadList.clear();
|
||||
}
|
||||
|
||||
if (pLog && (pLog != stdout))
|
||||
{
|
||||
fclose(pLog); pLog = nullptr;
|
||||
}
|
||||
if (instance == this)
|
||||
{
|
||||
instance = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
int profilerManager::addThreadProfiler( profilerFuncMap *m )
|
||||
{
|
||||
autoScopedLock aLock(threadListMtx);
|
||||
threadList.push_back(m);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int profilerManager::removeThreadProfiler( profilerFuncMap *m, bool shouldDestroy )
|
||||
{
|
||||
int result = -1;
|
||||
autoScopedLock aLock(threadListMtx);
|
||||
|
||||
for (auto it = threadList.begin(); it != threadList.end(); it++)
|
||||
{
|
||||
if (*it == m )
|
||||
{
|
||||
threadList.erase(it);
|
||||
if (shouldDestroy)
|
||||
{
|
||||
delete m;
|
||||
}
|
||||
result = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
//-------------------------------------------------------------------------
|
||||
} // namespace FCEU
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
int FCEU_profiler_log_thread_activity(void)
|
||||
{
|
||||
FCEU::execList.update();
|
||||
return 0;
|
||||
}
|
||||
#endif // __FCEU_PROFILER_ENABLE__
|
|
@ -0,0 +1,167 @@
|
|||
/* FCE Ultra - NES/Famicom Emulator
|
||||
*
|
||||
* Copyright notice for this file:
|
||||
* Copyright (C) 2002 Xodnizel
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
// profiler.h
|
||||
|
||||
#pragma once
|
||||
|
||||
/*
|
||||
* This module is intended for debug use only. This allows for high precision timing of function
|
||||
* execution. This functionality is not included in the build unless __FCEU_PROFILER_ENABLE__
|
||||
* is defined. To check timing on a particular function, add FCEU_PROFILE_FUNC macro to the top
|
||||
* of the function body in the following manner.
|
||||
* FCEU_PROFILE_FUNC(prof, "String Literal comment, whatever I want it to say")
|
||||
* When __FCEU_PROFILER_ENABLE__ is not defined, the FCEU_PROFILE_FUNC macro evaluates to nothing
|
||||
* so it won't break the regular build by having it used in code.
|
||||
*/
|
||||
#ifdef __FCEU_PROFILER_ENABLE__
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <list>
|
||||
#include <map>
|
||||
|
||||
|
||||
#if defined(__linux__) || defined(__APPLE__) || defined(__unix__)
|
||||
#include <time.h>
|
||||
#endif
|
||||
|
||||
#include "utils/mutex.h"
|
||||
#include "utils/timeStamp.h"
|
||||
|
||||
namespace FCEU
|
||||
{
|
||||
struct funcProfileRecord
|
||||
{
|
||||
const int fileLineNum;
|
||||
const char *fileName;
|
||||
const char *funcName;
|
||||
const char *comment;
|
||||
|
||||
timeStampRecord min;
|
||||
timeStampRecord max;
|
||||
timeStampRecord sum;
|
||||
timeStampRecord last;
|
||||
unsigned int numCalls;
|
||||
unsigned int recursionCount;
|
||||
|
||||
funcProfileRecord(const char *fileNameStringLiteral,
|
||||
const int fileLineNumber,
|
||||
const char *funcNameStringLiteral,
|
||||
const char *commentStringLiteral);
|
||||
|
||||
void reset(void);
|
||||
|
||||
double average(void);
|
||||
};
|
||||
|
||||
struct profileFuncScoped
|
||||
{
|
||||
funcProfileRecord *rec;
|
||||
timeStampRecord start;
|
||||
|
||||
profileFuncScoped( funcProfileRecord *recordIn );
|
||||
|
||||
~profileFuncScoped(void);
|
||||
};
|
||||
|
||||
struct profileExecVector
|
||||
{
|
||||
profileExecVector(void);
|
||||
~profileExecVector(void);
|
||||
|
||||
void update(void);
|
||||
|
||||
std::vector <funcProfileRecord> _vec;
|
||||
|
||||
FILE *logFp;
|
||||
};
|
||||
|
||||
class profilerFuncMap
|
||||
{
|
||||
public:
|
||||
profilerFuncMap();
|
||||
~profilerFuncMap();
|
||||
|
||||
int addRecord(const char *fileNameStringLiteral,
|
||||
const int fileLineNumber,
|
||||
const char *funcNameStringLiteral,
|
||||
const char *commentStringLiteral,
|
||||
funcProfileRecord *rec );
|
||||
|
||||
funcProfileRecord *findRecord(const char *fileNameStringLiteral,
|
||||
const int fileLineNumber,
|
||||
const char *funcNameStringLiteral,
|
||||
const char *commentStringLiteral,
|
||||
bool create = false);
|
||||
|
||||
funcProfileRecord *iterateBegin(void);
|
||||
funcProfileRecord *iterateNext(void);
|
||||
|
||||
void pushStack(funcProfileRecord *rec);
|
||||
void popStack(funcProfileRecord *rec);
|
||||
private:
|
||||
mutex _mapMtx;
|
||||
std::map<std::string, funcProfileRecord*> _map;
|
||||
std::map<std::string, funcProfileRecord*>::iterator _map_it;
|
||||
|
||||
std::vector <funcProfileRecord*> stack;
|
||||
};
|
||||
|
||||
class profilerManager
|
||||
{
|
||||
public:
|
||||
profilerManager(void);
|
||||
~profilerManager(void);
|
||||
|
||||
int addThreadProfiler( profilerFuncMap *m );
|
||||
int removeThreadProfiler( profilerFuncMap *m, bool shouldDestroy = false );
|
||||
|
||||
static FILE *pLog;
|
||||
|
||||
static profilerManager *getInstance();
|
||||
private:
|
||||
|
||||
mutex threadListMtx;
|
||||
std::list <profilerFuncMap*> threadList;
|
||||
static profilerManager *instance;
|
||||
};
|
||||
}
|
||||
|
||||
#if defined(__PRETTY_FUNCTION__)
|
||||
#define __FCEU_PROFILE_FUNC_NAME__ __PRETTY_FUNCTION__
|
||||
#else
|
||||
#define __FCEU_PROFILE_FUNC_NAME__ __func__
|
||||
#endif
|
||||
|
||||
#define FCEU_PROFILE_FUNC(id, comment) \
|
||||
static thread_local FCEU::funcProfileRecord id( __FILE__, __LINE__, __FCEU_PROFILE_FUNC_NAME__, comment ); \
|
||||
FCEU::profileFuncScoped id ## _unique_scope( &id )
|
||||
|
||||
|
||||
int FCEU_profiler_log_thread_activity(void);
|
||||
|
||||
#else // __FCEU_PROFILER_ENABLE__ not defined
|
||||
|
||||
#define FCEU_PROFILE_FUNC(id, comment)
|
||||
|
||||
#endif // __FCEU_PROFILER_ENABLE__
|
||||
|
390
src/state.cpp
390
src/state.cpp
|
@ -84,9 +84,9 @@ bool backupSavestates = true;
|
|||
bool compressSavestates = true; //By default FCEUX compresses savestates when a movie is inactive.
|
||||
|
||||
// a temp memory stream. We'll be dumping some data here and then compress
|
||||
EMUFILE_MEMORY memory_savestate;
|
||||
static EMUFILE_MEMORY memory_savestate;
|
||||
// temporary buffer for compressed data of a savestate
|
||||
std::vector<uint8> compressed_buf;
|
||||
static std::vector<uint8> compressed_buf;
|
||||
|
||||
#define SFMDATA_SIZE (128)
|
||||
static SFORMAT SFMDATA[SFMDATA_SIZE];
|
||||
|
@ -1179,3 +1179,389 @@ void RedoLoadState()
|
|||
redoLS = false; //Flag that RedoLoadState can not be run again
|
||||
undoLS = true; //Flag that LoadBackup can be run again
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------------------------------
|
||||
//----------- Save State History ----------------
|
||||
//-----------------------------------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------------------------------
|
||||
static StateRecorderConfigData stateRecorderConfig;
|
||||
|
||||
class StateRecorder
|
||||
{
|
||||
public:
|
||||
StateRecorder(void)
|
||||
{
|
||||
loadConfig( stateRecorderConfig );
|
||||
|
||||
for (int i=0; i<ringBufSize; i++)
|
||||
{
|
||||
EMUFILE_MEMORY *em = new EMUFILE_MEMORY( 0x1000 );
|
||||
|
||||
ringBuf.push_back(em);
|
||||
}
|
||||
ringStart = ringHead = ringTail = 0;
|
||||
frameCounter = 0;
|
||||
lastState = ringHead;
|
||||
loadIndexReset = false;
|
||||
lastLoadFrame = 0;
|
||||
}
|
||||
|
||||
~StateRecorder(void)
|
||||
{
|
||||
for (size_t i=0; i<ringBuf.size(); i++)
|
||||
{
|
||||
delete ringBuf[i];
|
||||
}
|
||||
ringBuf.clear();
|
||||
}
|
||||
|
||||
void loadConfig( StateRecorderConfigData &config )
|
||||
{
|
||||
if (config.framesBetweenSnaps < 1)
|
||||
{
|
||||
config.framesBetweenSnaps = 1;
|
||||
}
|
||||
if (config.timeBetweenSnapsMinutes < 0.0)
|
||||
{
|
||||
config.timeBetweenSnapsMinutes = 3.0f / 60.0f;
|
||||
}
|
||||
if (config.timeBetweenSnapsMinutes > config.historyDurationMinutes)
|
||||
{
|
||||
config.historyDurationMinutes = config.timeBetweenSnapsMinutes;
|
||||
}
|
||||
|
||||
if (config.timingMode)
|
||||
{
|
||||
const double fhistMin = config.historyDurationMinutes;
|
||||
const double fsnapMin = config.timeBetweenSnapsMinutes;
|
||||
const double fnumSnaps = fhistMin / fsnapMin;
|
||||
|
||||
ringBufSize = static_cast<int>( fnumSnaps + 0.5f );
|
||||
|
||||
int32_t fps = FCEUI_GetDesiredFPS(); // Do >> 24 to get in Hz
|
||||
|
||||
double hz = ( ((double)fps) / 16777216.0 );
|
||||
|
||||
double framesPerSnapf = hz * fsnapMin * 60.0;
|
||||
|
||||
framesPerSnap = static_cast<unsigned int>( framesPerSnapf + 0.50 );
|
||||
}
|
||||
else
|
||||
{
|
||||
const double fhistMin = config.historyDurationMinutes;
|
||||
int32_t fps = FCEUI_GetDesiredFPS(); // Do >> 24 to get in Hz
|
||||
double hz = ( ((double)fps) / 16777216.0 );
|
||||
|
||||
const double fsnapMin = static_cast<double>(config.framesBetweenSnaps) / (hz * 60.0);
|
||||
const double fnumSnaps = fhistMin / fsnapMin;
|
||||
|
||||
ringBufSize = static_cast<int>( fnumSnaps + 0.5f );
|
||||
framesPerSnap = config.framesBetweenSnaps;
|
||||
}
|
||||
|
||||
printf("ringBufSize:%i framesPerSnap:%i\n", ringBufSize, framesPerSnap );
|
||||
|
||||
compressionLevel = config.compressionLevel;
|
||||
loadPauseTime = config.loadPauseTimeSeconds;
|
||||
pauseOnLoad = config.pauseOnLoad;
|
||||
}
|
||||
|
||||
void update(void)
|
||||
{
|
||||
bool isPaused = EmulationPaused ? true : false;
|
||||
|
||||
unsigned int curFrame = static_cast<unsigned int>(currFrameCounter);
|
||||
|
||||
if (!isPaused && loadIndexReset)
|
||||
{
|
||||
ringHead = (lastState + 1) % ringBufSize;
|
||||
|
||||
frameCounter = curFrame;
|
||||
|
||||
loadIndexReset = false;
|
||||
}
|
||||
|
||||
if (!isPaused && (curFrame > frameCounter) )
|
||||
{
|
||||
frameCounter = curFrame;
|
||||
|
||||
if ( (frameCounter % framesPerSnap) == 0 )
|
||||
{
|
||||
EMUFILE_MEMORY *em = ringBuf[ ringHead ];
|
||||
|
||||
em->set_len(0);
|
||||
|
||||
FCEUSS_SaveMS( em, compressionLevel );
|
||||
|
||||
//printf("Frame:%u Save:%i Size:%zu Total:%zukB \n", frameCounter, ringHead, em->size(), dataSize() / 1024 );
|
||||
|
||||
lastState = ringHead;
|
||||
|
||||
ringHead = (ringHead + 1) % ringBufSize;
|
||||
|
||||
if (ringStart == ringHead)
|
||||
{
|
||||
ringStart = (ringHead + 1) % ringBufSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int loadStateRelativeToEnd( int numSnapsFromLatest )
|
||||
{
|
||||
if (numSnapsFromLatest < 0)
|
||||
{
|
||||
numSnapsFromLatest = 0;
|
||||
}
|
||||
numSnapsFromLatest = numSnapsFromLatest % ringBufSize;
|
||||
|
||||
int snapIdx = ringHead - numSnapsFromLatest - 1;
|
||||
|
||||
loadStateByIndex(snapIdx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int loadStateByIndex( int snapIdx )
|
||||
{
|
||||
if (snapIdx < 0)
|
||||
{
|
||||
snapIdx = snapIdx + ringBufSize;
|
||||
}
|
||||
snapIdx = snapIdx % ringBufSize;
|
||||
|
||||
EMUFILE_MEMORY *em = ringBuf[ snapIdx ];
|
||||
|
||||
em->fseek(SEEK_SET, 0);
|
||||
|
||||
FCEUSS_LoadFP( em, SSLOADPARAM_NOBACKUP );
|
||||
|
||||
frameCounter = lastLoadFrame = static_cast<unsigned int>(currFrameCounter);
|
||||
|
||||
lastState = snapIdx;
|
||||
loadIndexReset = true;
|
||||
|
||||
if (pauseOnLoad == StateRecorderConfigData::TEMPORARY_PAUSE)
|
||||
{
|
||||
if (loadPauseTime > 0)
|
||||
{ // Temporary pause after loading new state for user to have time to process
|
||||
FCEUI_PauseForDuration(loadPauseTime);
|
||||
}
|
||||
}
|
||||
else if (pauseOnLoad == StateRecorderConfigData::FULL_PAUSE)
|
||||
{
|
||||
FCEUI_SetEmulationPaused( EMULATIONPAUSED_PAUSED );
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int loadPrevState(void)
|
||||
{
|
||||
int snapIdx = lastState;
|
||||
|
||||
if ( lastState == ringHead )
|
||||
{ // No States to Load
|
||||
return -1;
|
||||
}
|
||||
if ( lastState != ringStart )
|
||||
{
|
||||
if ( (lastLoadFrame+30) > frameCounter)
|
||||
{
|
||||
snapIdx--;
|
||||
|
||||
if (snapIdx < 0)
|
||||
{
|
||||
snapIdx += ringBufSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
return loadStateByIndex( snapIdx );
|
||||
}
|
||||
|
||||
int loadNextState(void)
|
||||
{
|
||||
int snapIdx = lastState;
|
||||
int nextIdx = (lastState + 1) % ringBufSize;
|
||||
|
||||
if ( nextIdx != ringHead )
|
||||
{
|
||||
snapIdx = nextIdx;
|
||||
}
|
||||
return loadStateByIndex( snapIdx );
|
||||
}
|
||||
|
||||
int getHeadIndex(void)
|
||||
{
|
||||
return ringHead;
|
||||
}
|
||||
|
||||
int getStartIndex(void)
|
||||
{
|
||||
return ringStart;
|
||||
}
|
||||
|
||||
int numSnapsSaved(void)
|
||||
{
|
||||
int numSnaps = ringHead - ringStart;
|
||||
|
||||
if (numSnaps < 0)
|
||||
{
|
||||
numSnaps = numSnaps + static_cast<int>( ringBuf.size() );
|
||||
}
|
||||
return numSnaps;
|
||||
}
|
||||
|
||||
size_t dataSize(void)
|
||||
{
|
||||
return ringBuf.size() * ringBuf[0]->size();
|
||||
}
|
||||
|
||||
size_t ringBufferSize(void)
|
||||
{
|
||||
return ringBuf.size();
|
||||
}
|
||||
static bool enabled;
|
||||
static int lastState;
|
||||
private:
|
||||
|
||||
void doSnap(void)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
std::vector <EMUFILE_MEMORY*> ringBuf;
|
||||
int ringHead;
|
||||
int ringTail;
|
||||
int ringStart;
|
||||
int ringBufSize;
|
||||
int compressionLevel;
|
||||
int loadPauseTime;
|
||||
StateRecorderConfigData::PauseType pauseOnLoad;
|
||||
unsigned int frameCounter;
|
||||
unsigned int framesPerSnap;
|
||||
unsigned int lastLoadFrame;
|
||||
bool loadIndexReset;
|
||||
|
||||
};
|
||||
|
||||
static StateRecorder *stateRecorder = nullptr;
|
||||
bool StateRecorder::enabled = false;
|
||||
int StateRecorder::lastState = 0;
|
||||
|
||||
int FCEU_StateRecorderStart(void)
|
||||
{
|
||||
if (stateRecorder == nullptr)
|
||||
{
|
||||
stateRecorder = new StateRecorder();
|
||||
}
|
||||
return stateRecorder == nullptr;
|
||||
}
|
||||
|
||||
int FCEU_StateRecorderStop(void)
|
||||
{
|
||||
if (stateRecorder != nullptr)
|
||||
{
|
||||
delete stateRecorder; stateRecorder = nullptr;
|
||||
}
|
||||
return stateRecorder != nullptr;
|
||||
}
|
||||
|
||||
int FCEU_StateRecorderUpdate(void)
|
||||
{
|
||||
if (stateRecorder != nullptr)
|
||||
{
|
||||
stateRecorder->update();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool FCEU_StateRecorderIsEnabled(void)
|
||||
{
|
||||
return StateRecorder::enabled;
|
||||
}
|
||||
|
||||
void FCEU_StateRecorderSetEnabled(bool enabled)
|
||||
{
|
||||
StateRecorder::enabled = enabled;
|
||||
}
|
||||
|
||||
bool FCEU_StateRecorderRunning(void)
|
||||
{
|
||||
return stateRecorder != nullptr;
|
||||
}
|
||||
|
||||
int FCEU_StateRecorderGetMaxSnaps(void)
|
||||
{
|
||||
int size = 0;
|
||||
|
||||
if (stateRecorder != nullptr)
|
||||
{
|
||||
size = stateRecorder->ringBufferSize();
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
int FCEU_StateRecorderGetNumSnapsSaved(void)
|
||||
{
|
||||
int n = 0;
|
||||
|
||||
if (stateRecorder != nullptr)
|
||||
{
|
||||
n = stateRecorder->numSnapsSaved();
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
int FCEU_StateRecorderLoadState(int snapIndex)
|
||||
{
|
||||
int ret = -1;
|
||||
|
||||
if (stateRecorder != nullptr)
|
||||
{
|
||||
ret = stateRecorder->loadStateByIndex(snapIndex);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int FCEU_StateRecorderGetStateIndex(void)
|
||||
{
|
||||
return StateRecorder::lastState;
|
||||
}
|
||||
|
||||
int FCEU_StateRecorderLoadPrevState(void)
|
||||
{
|
||||
int ret = -1;
|
||||
|
||||
if (stateRecorder != nullptr)
|
||||
{
|
||||
ret = stateRecorder->loadPrevState();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int FCEU_StateRecorderLoadNextState(void)
|
||||
{
|
||||
int ret = -1;
|
||||
|
||||
if (stateRecorder != nullptr)
|
||||
{
|
||||
ret = stateRecorder->loadNextState();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
const StateRecorderConfigData& FCEU_StateRecorderGetConfigData(void)
|
||||
{
|
||||
return stateRecorderConfig;
|
||||
}
|
||||
int FCEU_StateRecorderSetConfigData(const StateRecorderConfigData &newConfig)
|
||||
{
|
||||
stateRecorderConfig = newConfig;
|
||||
|
||||
if (stateRecorder != nullptr)
|
||||
{
|
||||
stateRecorder->loadConfig( stateRecorderConfig );
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
54
src/state.h
54
src/state.h
|
@ -17,6 +17,7 @@
|
|||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#pragma once
|
||||
#include <string>
|
||||
|
||||
enum ENUM_SSLOADPARAMS
|
||||
|
@ -78,3 +79,56 @@ extern bool backupSavestates; //Whether or not to make backups, true by defaul
|
|||
bool CheckBackupSaveStateExist(); //Checks if backupsavestate exists
|
||||
|
||||
extern bool compressSavestates; //Whether or not to compress non-movie savestates (by default, yes)
|
||||
|
||||
struct StateRecorderConfigData
|
||||
{
|
||||
float historyDurationMinutes;
|
||||
float timeBetweenSnapsMinutes;
|
||||
int framesBetweenSnaps;
|
||||
int compressionLevel;
|
||||
int loadPauseTimeSeconds;
|
||||
|
||||
enum TimingType
|
||||
{
|
||||
FRAMES = 0,
|
||||
TIME,
|
||||
} timingMode;
|
||||
|
||||
enum PauseType
|
||||
{
|
||||
NO_PAUSE = 0,
|
||||
TEMPORARY_PAUSE,
|
||||
FULL_PAUSE,
|
||||
} pauseOnLoad;
|
||||
|
||||
StateRecorderConfigData(void)
|
||||
{
|
||||
framesBetweenSnaps = 60;
|
||||
historyDurationMinutes = 15.0f;
|
||||
timeBetweenSnapsMinutes = 3.0f / 60.0f;
|
||||
compressionLevel = 0;
|
||||
loadPauseTimeSeconds = 3;
|
||||
pauseOnLoad = TEMPORARY_PAUSE;
|
||||
timingMode = FRAMES;
|
||||
}
|
||||
|
||||
bool compare( const StateRecorderConfigData &other )
|
||||
{
|
||||
return memcmp( this, &other, sizeof(StateRecorderConfigData) ) == 0;
|
||||
}
|
||||
};
|
||||
|
||||
int FCEU_StateRecorderStart(void);
|
||||
int FCEU_StateRecorderStop(void);
|
||||
int FCEU_StateRecorderUpdate(void);
|
||||
bool FCEU_StateRecorderRunning(void);
|
||||
bool FCEU_StateRecorderIsEnabled(void);
|
||||
void FCEU_StateRecorderSetEnabled(bool enabled);
|
||||
int FCEU_StateRecorderGetMaxSnaps(void);
|
||||
int FCEU_StateRecorderGetNumSnapsSaved(void);
|
||||
int FCEU_StateRecorderGetStateIndex(void);
|
||||
int FCEU_StateRecorderLoadState(int snapIndex);
|
||||
int FCEU_StateRecorderLoadPrevState(void);
|
||||
int FCEU_StateRecorderLoadNextState(void);
|
||||
int FCEU_StateRecorderSetConfigData(const StateRecorderConfigData &newConfig);
|
||||
const StateRecorderConfigData& FCEU_StateRecorderGetConfigData(void);
|
||||
|
|
|
@ -475,7 +475,8 @@ static BMAPPING bmap[] = {
|
|||
{ "FNS", FNS_Init, BMCFLAG_16KCHRR },
|
||||
{ "BS-400R", BS400R_Init, 0 },
|
||||
{ "BS-4040R", BS4040R_Init, 0 },
|
||||
{ "COOLGIRL", COOLGIRL_Init, 0 },
|
||||
{ "COOLGIRL", COOLGIRL_Init, BMCFLAG_256KCHRR },
|
||||
{ "JC-016-2", Mapper205_Init, 0 },
|
||||
|
||||
{ 0, 0, 0 }
|
||||
};
|
||||
|
|
|
@ -60,6 +60,15 @@ autoScopedLock::autoScopedLock( mutex *mtx )
|
|||
}
|
||||
}
|
||||
|
||||
autoScopedLock::autoScopedLock( mutex &mtx )
|
||||
{
|
||||
m = &mtx;
|
||||
if (m)
|
||||
{
|
||||
m->lock();
|
||||
}
|
||||
}
|
||||
|
||||
autoScopedLock::~autoScopedLock(void)
|
||||
{
|
||||
if (m)
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
// mutex.h
|
||||
#pragma once
|
||||
|
||||
#ifdef __QT_DRIVER__
|
||||
#include <QMutex>
|
||||
|
@ -32,6 +33,7 @@ namespace FCEU
|
|||
{
|
||||
public:
|
||||
autoScopedLock( mutex *mtx );
|
||||
autoScopedLock( mutex &mtx );
|
||||
~autoScopedLock(void);
|
||||
|
||||
private:
|
||||
|
|
|
@ -0,0 +1,117 @@
|
|||
// timeStamp.cpp
|
||||
#include <stdio.h>
|
||||
|
||||
#include "timeStamp.h"
|
||||
|
||||
#if defined(__linux__) || defined(__APPLE__) || defined(__unix__)
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#if defined(WIN32)
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
//---- Time Stamp Record
|
||||
//-------------------------------------------------------------------------
|
||||
#if defined(WIN32)
|
||||
#include <intrin.h>
|
||||
#pragma intrinsic(__rdtsc)
|
||||
#else
|
||||
#include <x86intrin.h>
|
||||
#endif
|
||||
|
||||
static uint64_t rdtsc()
|
||||
{
|
||||
return __rdtsc();
|
||||
}
|
||||
|
||||
namespace FCEU
|
||||
{
|
||||
|
||||
uint64_t timeStampRecord::_tscFreq = 0;
|
||||
#if defined(WIN32)
|
||||
uint64_t timeStampRecord::qpcFreq = 0;
|
||||
#endif
|
||||
|
||||
void timeStampRecord::readNew(void)
|
||||
{
|
||||
#if defined(__linux__) || defined(__APPLE__) || defined(__unix__)
|
||||
clock_gettime( CLOCK_REALTIME, &ts );
|
||||
#else
|
||||
QueryPerformanceCounter((LARGE_INTEGER*)&ts);
|
||||
#endif
|
||||
tsc = rdtsc();
|
||||
}
|
||||
#if defined(WIN32)
|
||||
void timeStampRecord::qpcCalibrate(void)
|
||||
{
|
||||
if (QueryPerformanceFrequency((LARGE_INTEGER*)&timeStampRecord::qpcFreq) == 0)
|
||||
{
|
||||
printf("QueryPerformanceFrequency FAILED!\n");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
class timeStampModule
|
||||
{
|
||||
public:
|
||||
timeStampModule(void)
|
||||
{
|
||||
printf("timeStampModuleInit\n");
|
||||
#if defined(WIN32)
|
||||
timeStampRecord::qpcCalibrate();
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
static timeStampModule module;
|
||||
|
||||
bool timeStampModuleInitialized(void)
|
||||
{
|
||||
#if defined(WIN32)
|
||||
bool initialized = timeStampRecord::countFreq() != 0;
|
||||
#else
|
||||
bool initialized = true;
|
||||
#endif
|
||||
return initialized;
|
||||
}
|
||||
|
||||
void timeStampRecord::tscCalibrate(int numSamples)
|
||||
{
|
||||
timeStampRecord t1, t2, td;
|
||||
uint64_t td_sum = 0;
|
||||
double td_avg;
|
||||
|
||||
#if defined(WIN32)
|
||||
if (QueryPerformanceFrequency((LARGE_INTEGER*)&timeStampRecord::qpcFreq) == 0)
|
||||
{
|
||||
printf("QueryPerformanceFrequency FAILED!\n");
|
||||
}
|
||||
#endif
|
||||
printf("Running TSC Calibration: %i sec...\n", numSamples);
|
||||
|
||||
for (int i=0; i<numSamples; i++)
|
||||
{
|
||||
t1.readNew();
|
||||
#if defined(WIN32)
|
||||
Sleep(1000);
|
||||
#else
|
||||
sleep(1);
|
||||
#endif
|
||||
t2.readNew();
|
||||
|
||||
td += t2 - t1;
|
||||
|
||||
td_sum = td.tsc;
|
||||
|
||||
td_avg = static_cast<double>(td_sum);
|
||||
|
||||
timeStampRecord::_tscFreq = static_cast<uint64_t>( td_avg / td.toSeconds() );
|
||||
|
||||
printf("%i Calibration: %f sec TSC:%llu TSC Freq: %f MHz\n", i, td.toSeconds(),
|
||||
static_cast<unsigned long long>(td.tsc), static_cast<double>(timeStampRecord::_tscFreq) * 1.0e-6 );
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace FCEU
|
|
@ -0,0 +1,384 @@
|
|||
// timeStamp.h
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#if defined(__linux__) || defined(__APPLE__) || defined(__unix__)
|
||||
#include <time.h>
|
||||
#endif
|
||||
|
||||
namespace FCEU
|
||||
{
|
||||
class timeStampRecord
|
||||
{
|
||||
public:
|
||||
static constexpr uint64_t ONE_SEC_TO_MILLI = 1000;
|
||||
|
||||
#if defined(__linux__) || defined(__APPLE__) || defined(__unix__)
|
||||
static constexpr long int ONE_SEC_TO_NANO = 1000000000;
|
||||
static constexpr long int MILLI_TO_NANO = 1000000;
|
||||
|
||||
timeStampRecord(void)
|
||||
{
|
||||
ts.tv_sec = 0;
|
||||
ts.tv_nsec = 0;
|
||||
tsc = 0;
|
||||
}
|
||||
|
||||
timeStampRecord& operator = (const timeStampRecord& in)
|
||||
{
|
||||
ts = in.ts;
|
||||
tsc = in.tsc;
|
||||
return *this;
|
||||
}
|
||||
|
||||
timeStampRecord& operator += (const timeStampRecord& op)
|
||||
{
|
||||
ts.tv_sec += op.ts.tv_sec;
|
||||
ts.tv_nsec += op.ts.tv_nsec;
|
||||
|
||||
if (ts.tv_nsec >= ONE_SEC_TO_NANO)
|
||||
{
|
||||
ts.tv_nsec -= ONE_SEC_TO_NANO;
|
||||
ts.tv_sec++;
|
||||
}
|
||||
tsc += op.tsc;
|
||||
return *this;
|
||||
}
|
||||
|
||||
timeStampRecord operator + (const timeStampRecord& op)
|
||||
{
|
||||
timeStampRecord res;
|
||||
|
||||
res.ts.tv_sec = ts.tv_sec + op.ts.tv_sec;
|
||||
res.ts.tv_nsec = ts.tv_nsec + op.ts.tv_nsec;
|
||||
|
||||
if (res.ts.tv_nsec >= ONE_SEC_TO_NANO)
|
||||
{
|
||||
res.ts.tv_nsec -= ONE_SEC_TO_NANO;
|
||||
res.ts.tv_sec++;
|
||||
}
|
||||
res.tsc = tsc + op.tsc;
|
||||
return res;
|
||||
}
|
||||
|
||||
timeStampRecord operator - (const timeStampRecord& op)
|
||||
{
|
||||
timeStampRecord res;
|
||||
|
||||
res.ts.tv_sec = ts.tv_sec - op.ts.tv_sec;
|
||||
res.ts.tv_nsec = ts.tv_nsec - op.ts.tv_nsec;
|
||||
|
||||
if (res.ts.tv_nsec < 0)
|
||||
{
|
||||
res.ts.tv_nsec += ONE_SEC_TO_NANO;
|
||||
res.ts.tv_sec--;
|
||||
}
|
||||
res.tsc = tsc - op.tsc;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
timeStampRecord operator * (const unsigned int multiplier)
|
||||
{
|
||||
timeStampRecord res;
|
||||
|
||||
res.ts.tv_sec = ts.tv_sec * multiplier;
|
||||
res.ts.tv_nsec = ts.tv_nsec * multiplier;
|
||||
|
||||
if (res.ts.tv_nsec >= ONE_SEC_TO_NANO)
|
||||
{
|
||||
res.ts.tv_nsec -= ONE_SEC_TO_NANO;
|
||||
res.ts.tv_sec++;
|
||||
}
|
||||
res.tsc = tsc * multiplier;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
timeStampRecord operator / (const unsigned int divisor)
|
||||
{
|
||||
timeStampRecord res;
|
||||
|
||||
res.ts.tv_sec = ts.tv_sec / divisor;
|
||||
res.ts.tv_nsec = ts.tv_nsec / divisor;
|
||||
res.tsc = tsc / divisor;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
bool operator > (const timeStampRecord& op)
|
||||
{
|
||||
bool res;
|
||||
if (ts.tv_sec == op.ts.tv_sec)
|
||||
{
|
||||
res = (ts.tv_nsec > op.ts.tv_nsec);
|
||||
}
|
||||
else
|
||||
{
|
||||
res = (ts.tv_sec > op.ts.tv_sec);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
bool operator >= (const timeStampRecord& op)
|
||||
{
|
||||
bool res;
|
||||
if (ts.tv_sec == op.ts.tv_sec)
|
||||
{
|
||||
res = (ts.tv_nsec >= op.ts.tv_nsec);
|
||||
}
|
||||
else
|
||||
{
|
||||
res = (ts.tv_sec >= op.ts.tv_sec);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
bool operator < (const timeStampRecord& op)
|
||||
{
|
||||
bool res;
|
||||
if (ts.tv_sec == op.ts.tv_sec)
|
||||
{
|
||||
res = (ts.tv_nsec < op.ts.tv_nsec);
|
||||
}
|
||||
else
|
||||
{
|
||||
res = (ts.tv_sec < op.ts.tv_sec);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
bool operator <= (const timeStampRecord& op)
|
||||
{
|
||||
bool res;
|
||||
if (ts.tv_sec == op.ts.tv_sec)
|
||||
{
|
||||
res = (ts.tv_nsec <= op.ts.tv_nsec);
|
||||
}
|
||||
else
|
||||
{
|
||||
res = (ts.tv_sec <= op.ts.tv_sec);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
void zero(void)
|
||||
{
|
||||
ts.tv_sec = 0;
|
||||
ts.tv_nsec = 0;
|
||||
tsc = 0;
|
||||
}
|
||||
|
||||
bool isZero(void)
|
||||
{
|
||||
return (ts.tv_sec == 0) && (ts.tv_nsec == 0);
|
||||
}
|
||||
|
||||
void fromSeconds(unsigned int sec)
|
||||
{
|
||||
ts.tv_sec = sec;
|
||||
ts.tv_nsec = 0;
|
||||
tsc = 0;
|
||||
}
|
||||
|
||||
void fromSeconds(double sec)
|
||||
{
|
||||
double ns;
|
||||
ts.tv_sec = static_cast<time_t>(sec);
|
||||
ns = (sec - static_cast<double>(ts.tv_sec)) * 1.0e9;
|
||||
ts.tv_nsec = static_cast<long>(ns);
|
||||
tsc = 0;
|
||||
}
|
||||
|
||||
double toSeconds(void)
|
||||
{
|
||||
double sec = static_cast<double>(ts.tv_sec) + ( static_cast<double>(ts.tv_nsec) * 1.0e-9 );
|
||||
return sec;
|
||||
}
|
||||
|
||||
void fromMilliSeconds(uint64_t ms)
|
||||
{
|
||||
ts.tv_sec = ms / ONE_SEC_TO_MILLI;
|
||||
ts.tv_nsec = (ms * MILLI_TO_NANO) - (ts.tv_sec * ONE_SEC_TO_NANO);
|
||||
}
|
||||
|
||||
uint64_t toMilliSeconds(void)
|
||||
{
|
||||
uint64_t ms = (ts.tv_sec * ONE_SEC_TO_MILLI) + (ts.tv_nsec / MILLI_TO_NANO );
|
||||
return ms;
|
||||
}
|
||||
|
||||
uint64_t toCounts(void)
|
||||
{
|
||||
return (ts.tv_sec * ONE_SEC_TO_NANO) + ts.tv_nsec;
|
||||
}
|
||||
|
||||
static uint64_t countFreq(void)
|
||||
{
|
||||
return ONE_SEC_TO_NANO;
|
||||
}
|
||||
|
||||
struct timespec toTimeSpec(void)
|
||||
{
|
||||
return ts;
|
||||
}
|
||||
#else // WIN32
|
||||
|
||||
timeStampRecord(void)
|
||||
{
|
||||
ts = 0;
|
||||
tsc = 0;
|
||||
}
|
||||
|
||||
timeStampRecord& operator = (const timeStampRecord& in)
|
||||
{
|
||||
ts = in.ts;
|
||||
tsc = in.tsc;
|
||||
return *this;
|
||||
}
|
||||
|
||||
timeStampRecord& operator += (const timeStampRecord& op)
|
||||
{
|
||||
ts += op.ts;
|
||||
tsc += op.tsc;
|
||||
return *this;
|
||||
}
|
||||
|
||||
timeStampRecord operator + (const timeStampRecord& op)
|
||||
{
|
||||
timeStampRecord res;
|
||||
|
||||
res.ts = ts + op.ts;
|
||||
res.tsc = tsc + op.tsc;
|
||||
return res;
|
||||
}
|
||||
|
||||
timeStampRecord operator - (const timeStampRecord& op)
|
||||
{
|
||||
timeStampRecord res;
|
||||
|
||||
res.ts = ts - op.ts;
|
||||
res.tsc = tsc - op.tsc;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
timeStampRecord operator * (const unsigned int multiplier)
|
||||
{
|
||||
timeStampRecord res;
|
||||
|
||||
res.ts = ts * multiplier;
|
||||
res.tsc = tsc * multiplier;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
timeStampRecord operator / (const unsigned int divisor)
|
||||
{
|
||||
timeStampRecord res;
|
||||
|
||||
res.ts = ts / divisor;
|
||||
res.tsc = tsc / divisor;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
bool operator > (const timeStampRecord& op)
|
||||
{
|
||||
return ts > op.ts;
|
||||
}
|
||||
bool operator >= (const timeStampRecord& op)
|
||||
{
|
||||
return ts >= op.ts;
|
||||
}
|
||||
|
||||
bool operator < (const timeStampRecord& op)
|
||||
{
|
||||
return ts < op.ts;
|
||||
}
|
||||
bool operator <= (const timeStampRecord& op)
|
||||
{
|
||||
return ts <= op.ts;
|
||||
}
|
||||
|
||||
void zero(void)
|
||||
{
|
||||
ts = 0;
|
||||
tsc = 0;
|
||||
}
|
||||
|
||||
bool isZero(void)
|
||||
{
|
||||
return (ts == 0);
|
||||
}
|
||||
|
||||
|
||||
void fromSeconds(unsigned int sec)
|
||||
{
|
||||
ts = sec * qpcFreq;
|
||||
tsc = 0;
|
||||
}
|
||||
|
||||
void fromSeconds(double sec)
|
||||
{
|
||||
ts = static_cast<uint64_t>(sec * static_cast<double>(qpcFreq));
|
||||
tsc = 0;
|
||||
}
|
||||
|
||||
double toSeconds(void)
|
||||
{
|
||||
double sec = static_cast<double>(ts) / static_cast<double>(qpcFreq);
|
||||
return sec;
|
||||
}
|
||||
|
||||
void fromMilliSeconds(uint64_t ms)
|
||||
{
|
||||
ts = (ms * qpcFreq) / ONE_SEC_TO_MILLI;
|
||||
}
|
||||
|
||||
uint64_t toMilliSeconds(void)
|
||||
{
|
||||
uint64_t ms = (ts * ONE_SEC_TO_MILLI) / qpcFreq;
|
||||
return ms;
|
||||
}
|
||||
|
||||
uint64_t toCounts(void)
|
||||
{
|
||||
return ts;
|
||||
}
|
||||
|
||||
static uint64_t countFreq(void)
|
||||
{
|
||||
return qpcFreq;
|
||||
}
|
||||
|
||||
static void qpcCalibrate(void);
|
||||
#endif
|
||||
|
||||
uint64_t getTSC(void){ return tsc; };
|
||||
|
||||
static uint64_t tscFreq(void)
|
||||
{
|
||||
return _tscFreq;
|
||||
}
|
||||
static bool tscValid(void){ return tscFreq != 0; };
|
||||
|
||||
// Call this function to calibrate the estimated TSC frequency
|
||||
static void tscCalibrate(int numSamples = 0);
|
||||
|
||||
void readNew(void);
|
||||
|
||||
private:
|
||||
#if defined(__linux__) || defined(__APPLE__) || defined(__unix__)
|
||||
struct timespec ts;
|
||||
#else // Win32
|
||||
uint64_t ts;
|
||||
static uint64_t qpcFreq;
|
||||
#endif
|
||||
uint64_t tsc;
|
||||
static uint64_t _tscFreq;
|
||||
};
|
||||
|
||||
bool timeStampModuleInitialized(void);
|
||||
|
||||
} // namespace FCEU
|
||||
|
|
@ -87,6 +87,8 @@ std::string AsSnapshotName =""; //adelikat:this will set the snapshot name whe
|
|||
void FCEUI_SetSnapshotAsName(std::string name) { AsSnapshotName = name; }
|
||||
std::string FCEUI_GetSnapshotAsName() { return AsSnapshotName; }
|
||||
|
||||
static void FCEU_DrawPauseCountDown(uint8 *XBuf);
|
||||
|
||||
void FCEU_KillVirtualVideo(void)
|
||||
{
|
||||
if ( XBuf )
|
||||
|
@ -254,6 +256,7 @@ void FCEU_PutImage(void)
|
|||
FCEU_DrawLagCounter(XBuf);
|
||||
FCEU_DrawNTSCControlBars(XBuf);
|
||||
FCEU_DrawRecordingStatus(XBuf);
|
||||
FCEU_DrawPauseCountDown(XBuf);
|
||||
ShowFPS();
|
||||
}
|
||||
|
||||
|
@ -771,3 +774,35 @@ void ShowFPS(void)
|
|||
|
||||
DrawTextTrans(XBuf + ((256 - ClipSidesOffset) - 40) + (FSettings.FirstSLine + 4) * 256, 256, (uint8*)fpsmsg, 0xA0);
|
||||
}
|
||||
|
||||
bool showPauseCountDown = true;
|
||||
|
||||
static void FCEU_DrawPauseCountDown(uint8 *XBuf)
|
||||
{
|
||||
if (EmulationPaused & EMULATIONPAUSED_TIMER)
|
||||
{
|
||||
int pauseFramesLeft = FCEUI_PauseFramesRemaining();
|
||||
|
||||
if (showPauseCountDown && (pauseFramesLeft > 0) )
|
||||
{
|
||||
char text[32];
|
||||
int framesPerSec;
|
||||
|
||||
if (PAL || dendy)
|
||||
{
|
||||
framesPerSec = 50;
|
||||
}
|
||||
else
|
||||
{
|
||||
framesPerSec = 60;
|
||||
}
|
||||
|
||||
sprintf(text, "Unpausing in %d...", (pauseFramesLeft / framesPerSec) + 1);
|
||||
|
||||
if (text[0])
|
||||
{
|
||||
DrawTextTrans(XBuf + ClipSidesOffset + (FSettings.FirstSLine) * 256, 256, (uint8*)text, 0xA0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -47,7 +47,11 @@ void (*MapIRQHook)(int a);
|
|||
//normal memory read
|
||||
static INLINE uint8 RdMem(unsigned int A)
|
||||
{
|
||||
return(_DB=ARead[A](A));
|
||||
_DB=ARead[A](A);
|
||||
#ifdef _S9XLUA_H
|
||||
CallRegisteredLuaMemHook(A, 1, _DB, LUAMEMHOOK_READ);
|
||||
#endif
|
||||
return(_DB);
|
||||
}
|
||||
|
||||
//normal memory write
|
||||
|
@ -61,9 +65,13 @@ static INLINE void WrMem(unsigned int A, uint8 V)
|
|||
|
||||
static INLINE uint8 RdRAM(unsigned int A)
|
||||
{
|
||||
_DB=ARead[A](A);
|
||||
#ifdef _S9XLUA_H
|
||||
CallRegisteredLuaMemHook(A, 1, _DB, LUAMEMHOOK_READ);
|
||||
#endif
|
||||
//bbit edited: this was changed so cheat substituion would work
|
||||
return(_DB=ARead[A](A));
|
||||
// return(_DB=RAM[A]);
|
||||
return(_DB);
|
||||
}
|
||||
|
||||
static INLINE void WrRAM(unsigned int A, uint8 V)
|
||||
|
@ -77,7 +85,11 @@ static INLINE void WrRAM(unsigned int A, uint8 V)
|
|||
uint8 X6502_DMR(uint32 A)
|
||||
{
|
||||
ADDCYC(1);
|
||||
return(X.DB=ARead[A](A));
|
||||
_DB=ARead[A](A);
|
||||
#ifdef _S9XLUA_H
|
||||
CallRegisteredLuaMemHook(A, 1, _DB, LUAMEMHOOK_READ);
|
||||
#endif
|
||||
return(_DB);
|
||||
}
|
||||
|
||||
void X6502_DMW(uint32 A, uint8 V)
|
||||
|
|
|
@ -744,6 +744,7 @@ xcopy /y /d "$(ProjectDir)\..\src\drivers\win\7z_64.dll" "$(OutDir)"</Command>
|
|||
<ClCompile Include="..\src\utils\md5.cpp" />
|
||||
<ClCompile Include="..\src\utils\memory.cpp" />
|
||||
<ClCompile Include="..\src\utils\mutex.cpp" />
|
||||
<ClCompile Include="..\src\utils\timeStamp.cpp" />
|
||||
<ClCompile Include="..\src\utils\unzip.cpp" />
|
||||
<ClCompile Include="..\src\utils\xstring.cpp" />
|
||||
<ClCompile Include="..\src\lua\src\lapi.c">
|
||||
|
@ -1008,6 +1009,7 @@ xcopy /y /d "$(ProjectDir)\..\src\drivers\win\7z_64.dll" "$(OutDir)"</Command>
|
|||
<ClCompile Include="..\src\oldmovie.cpp" />
|
||||
<ClCompile Include="..\src\palette.cpp" />
|
||||
<ClCompile Include="..\src\ppu.cpp" />
|
||||
<ClCompile Include="..\src\profiler.cpp" />
|
||||
<ClCompile Include="..\src\sound.cpp" />
|
||||
<ClCompile Include="..\src\state.cpp" />
|
||||
<ClCompile Include="..\src\unif.cpp" />
|
||||
|
@ -1137,6 +1139,7 @@ xcopy /y /d "$(ProjectDir)\..\src\drivers\win\7z_64.dll" "$(OutDir)"</Command>
|
|||
<ClInclude Include="..\src\oldmovie.h" />
|
||||
<ClInclude Include="..\src\palette.h" />
|
||||
<ClInclude Include="..\src\ppu.h" />
|
||||
<ClInclude Include="..\src\profiler.h" />
|
||||
<ClInclude Include="..\src\sound.h" />
|
||||
<ClInclude Include="..\src\state.h" />
|
||||
<ClInclude Include="..\src\types-des.h" />
|
||||
|
@ -1151,6 +1154,7 @@ xcopy /y /d "$(ProjectDir)\..\src\drivers\win\7z_64.dll" "$(OutDir)"</Command>
|
|||
<ClInclude Include="..\src\utils\md5.h" />
|
||||
<ClInclude Include="..\src\utils\memory.h" />
|
||||
<ClInclude Include="..\src\utils\mutex.h" />
|
||||
<ClInclude Include="..\src\utils\timeStamp.h" />
|
||||
<ClInclude Include="..\src\utils\unzip.h" />
|
||||
<ClInclude Include="..\src\utils\valuearray.h" />
|
||||
<ClInclude Include="..\src\utils\xstring.h" />
|
||||
|
|
|
@ -81,6 +81,7 @@
|
|||
brew install qt5
|
||||
brew install sdl2
|
||||
brew install minizip
|
||||
brew install libarchive (optional dependency for 7zip archive support)
|
||||
brew install ffmpeg (optional dependency but recommended for AVI recording)
|
||||
brew install x264 (optional dependency but recommended for AVI recording)
|
||||
</pre>
|
||||
|
|
Loading…
Reference in New Issue