Compare commits

...

466 Commits

Author SHA1 Message Date
thor2016 2b8f6e7627
Merge pull request #776 from awjackson/mapper92
Reimplement mapper 92 correctly
2025-01-19 15:03:14 -05:00
thor2016 eb5ca2e6d6
Merge pull request #778 from awjackson/mapper97
More mapper fixes
2025-01-19 15:02:12 -05:00
Alex W. Jackson 4008488b80 Mapper fixes: Fix 97, remove deprecated 101 and 151, add names to various mappers 2025-01-14 07:16:18 -05:00
Alex W. Jackson f15fb4f37c Implement mapper 92 correctly (it's not an address latching mapper but a mapper 72 variant) 2025-01-12 22:38:01 -05:00
thor2016 71ba361794
Merge pull request #774 from chenrui333/revert-766-fix-x265-4.0
chore: scope the patch for x265 4.0 build
2025-01-03 13:22:27 -05:00
Rui Chen 3bf931e5ca
chore: scope the patch for x265 4.0 build
upstream has reverted the x265_encoder_encode api change in 78e5b703b1 per 4.1 release, thus the patch is no longer needed, hence reverting for now. (previous 4.0 API change commit, c69c113960)

Signed-off-by: Rui Chen <rui@chenrui.dev>
2024-12-28 22:12:52 -05:00
thor2016 fe65681012
Merge pull request #772 from brad0/arm64_build
Use proper symbol name checking for arm64
2024-12-08 09:23:39 -05:00
Brad Smith f803006608 Use proper symbol name checking for arm64
The proper symbol for checking for 64-bit ARM is __aarch64__
2024-12-08 07:49:34 -05:00
harry e315b06ff3 Updated MacOSX auto build environment to ventura OS. 2024-11-24 04:22:51 -05:00
harry 214773faae Added tas editor lua null checks for Qt GUI. 2024-11-24 04:16:27 -05:00
thor2016 0ba9ffe3a4
Merge pull request #755 from parasyte/fix/cdlogger-invalidation
Fix PRG reads and writes in CD Logger
2024-11-24 03:49:19 -05:00
thor2016 6dc277a27c
Merge pull request #756 from parasyte/fix/debugger-overflow
Fix "OVERFLOW" byte not being shown at address $FFFF.
2024-11-24 03:47:20 -05:00
thor2016 3c8e0a0dcb
Merge pull request #754 from parasyte/fix/attribution
Fix attribution
2024-11-24 03:45:48 -05:00
thor2016 4a2d980f9d
Merge pull request #765 from negativeExponent/patch-2
MMC5: Fix initial values for chr banks and nametables
2024-11-24 03:41:08 -05:00
thor2016 940c895de5
Merge pull request #767 from negativeExponent/add_m451_m471
Add mappers 451 and 471
2024-11-24 03:39:46 -05:00
thor2016 3f599cb3e6
Merge pull request #758 from silverslither/master
Enable TAS Editor Lua functions on QT
2024-11-24 03:38:45 -05:00
thor2016 cd057bb13f
Merge pull request #766 from chenrui333/fix-x265-4.0
chore: update AviRecord to comply with updated x265 API
2024-11-24 03:35:45 -05:00
Rui Chen a6fcb73b11
chore: update AviRecord to comply with updated x265 API
Some patch ref: https://code.videolan.org/videolan/vlc/-/merge_requests/6167
upstream commit: c69c113960

Signed-off-by: Rui Chen <rui@chenrui.dev>
2024-11-23 17:17:48 -05:00
negative fb0b178c1d
Add mappers 451 and 471
As requested.
Fix https://github.com/TASEmulators/fceux/issues/761
2024-10-31 11:07:19 +08:00
negativeExponent 4441f3cbdf
MMC5: Fix initial values for chr banks and nametables
At least 1 game expect chr bank and nametables to be initialized at zero (fix Deathloop 256)
2024-10-28 15:32:24 +08:00
Jay Oster 65f4a482d5 Do not treat jump destinations as data accesses
The two JMP instructions have address modes that imply a data access
occurs. All branch instructions and JSR have `optype` 0, so they don't
have this problem.
2024-09-13 12:46:48 -07:00
silverslither daa2f817a9 enabled taseditor lua functions for QT 2024-09-13 13:02:38 -04:00
Jay Oster 5886b9e157 Fix "OVERFLOW" byte not being shown at address $FFFF. 2024-09-13 00:59:01 -07:00
Jay Oster 9da80206f8 Fix PRG writes in CD Logger
This code was added for FDS RAM, but it breaks PRG writes with normal
cartridge-based memory controllers.

The bug inappropriately resets (clears) the access mode bits previously
recorded when an MMIO register is written in PRG address space. For
instance, if an instruction is executed at $8000 and then some code
later writes to $8000, the instruction execution would have been
forgotten.
2024-09-12 15:25:00 -07:00
Jay Oster 0f6c5b2936 Fix attribution
This change de-duplicates Xodnizel's identity in some "About" windows.

Closes #753
2024-08-19 13:04:40 -07:00
thor2016 f980ec2bc7
Merge pull request #732 from awjackson/fix_731
Make X24C02 only enter read/write state if I2C address matches; fixes #731
2024-06-09 14:22:20 -04:00
harry e6efd7f694 Fix for gcc misleading indentation in lua-engine.cpp. 2024-06-09 14:10:15 -04:00
harry eecb2e77b6 Replace strncpy usage in favor of Strlcpy to get rid of compiler warnings. 2024-06-09 14:07:41 -04:00
harry ecbfca1084 Minor gcc/clang compiler warning fix. 2024-06-09 09:34:08 -04:00
thor2016 c919de08b2
Merge pull request #735 from awjackson/fixbuild
Fix Linux build
2024-05-29 07:35:46 -04:00
Alex W. Jackson d94157e125 Fix Linux build 2024-05-28 19:56:07 -04:00
Alexey Cluster 14df08d804 Take NES 2.0 header WRAM size into account for MMC3 2024-05-28 14:03:27 +04:00
harry ffb28e1131 Changed Qt Avi recording to use atomic buffer indices to ensure both threads are aware of changes when they happen. 2024-05-11 07:09:42 -04:00
harry 283aea91db For Qt netplay, reset client frame rate adjustment to normal on disconnect. 2024-05-11 06:16:12 -04:00
Alex W. Jackson 38bb5b1f51 Make X24C02 only enter read/write state if I2C address matches; fixes SD Gundam Gaiden 2 2024-05-07 17:32:15 -04:00
harry c4dd4f5153 Updated client netplay rom requests to only send extracted archive files as well. 2024-05-05 06:29:47 -04:00
harry 0ea2670ae0 For Qt GUI, store archive file index so that a hard reload knows how to refind the ROM inside the archive. For netplay, don't send entire zip archives. Instead just send the single extracted ROM of interest. 2024-05-05 05:57:11 -04:00
harry 4b36de6ec9 Build fix. 2024-05-04 23:08:34 -04:00
harry 4e57ca40ae For Qt GUI, create a temp directory per every boot of application that can be used to store temporary files for things such as netplay roms. This folder is deleted at application exit. 2024-05-04 22:04:29 -04:00
thor2016 151c951d63
Merge pull request #730 from TheRealQuantam/indy-fix
"(z),Y" addressing incorrectly shown as "(z,Y)" in debugger
2024-04-18 21:29:12 -04:00
TheRealQuantam 1028732d84 Remember that Qt and Win versions have different disassembly code 2024-04-16 18:40:09 -07:00
TheRealQuantam fa6e4411dd "(z),Y" addressing incorrectly shown as "(z,Y)" in debugger 2024-04-16 18:15:22 -07:00
harry 84b823ffa7 Added more netplay status data to host status dialog. 2024-04-13 15:57:09 -04:00
harry 94975d7dbe Fix code so that FCEUGI fully constructs properly and is not clobbered after the construction by a memset. Also, some minor code cleanup in related areas. 2024-04-12 08:14:20 -04:00
harry c97e2c9ad3 For Qt Netplay, added code to sync cheats between server and clients. 2024-04-11 06:58:43 -04:00
harry 6e698433aa Added netplay debug mode for interface debug logging. 2024-04-08 07:07:08 -04:00
harry 9036dd07bd Added logic to allow netplay host to control pause state of clients. 2024-04-07 21:21:18 -04:00
harry e7d234136c Netplay sync state fixes. 2024-04-07 20:22:32 -04:00
harry 9f8310bbe1 Minor cleanup of netplay main menu. 2024-04-07 15:11:27 -04:00
harry e032d65811 For Qt netplay, changed client message dialogs to be non-blocking. This prevents re-entrant event loops. 2024-04-07 14:53:06 -04:00
thor2016 e751431099
Merge pull request #726 from negativeExponent/patch-1
unrom512.cpp: Expand support for PRG ROM size upto 4M
2024-04-06 10:07:36 -04:00
thor2016 3e1a8ec486
Merge pull request #728 from liyansong2018/master
Fix Path Traversal #727 in Netplay server
2024-04-06 10:05:08 -04:00
liyansong2018 48b48e7c13 Fix Path Traversal in Netplay server 2024-04-06 10:40:29 +08:00
harry f71b912afb Qt netplay fixes for processing input packet data. Don't attempt spawn dialog windows when in read loop, it will cause event loop re-entrancy issues. 2024-04-04 06:43:10 -04:00
harry 10418f551a Added framework for Qt netplay client status dialog. 2024-04-03 04:55:07 -04:00
harry 2fe563181e Added ROM unload handling logic for netplay. 2024-03-26 20:58:21 -04:00
harry 25cab8195f Bug fix for Qt win64 netplay, make sure rom files are opened in binary mode. 2024-03-26 20:20:01 -04:00
harry f50b70b87e Reduce netplay max tcp transmission size to 8k for ROM transfers. 2024-03-24 22:08:15 -04:00
harry 84654b1c06 Set low delay tcp option for netplay. 2024-03-24 21:34:07 -04:00
harry 6e22998336 Increased netplay tcp OS level send/receive buffer sizes. 2024-03-24 21:29:41 -04:00
harry a63f5e6051 Netplay modified data read code to allow smaller buffered data to arrive in pieces rather than waiting for full data set. 2024-03-24 20:49:17 -04:00
harry 450870ef77 Build fix for constexpr vars that conflicted with some win macros. 2024-03-24 16:29:13 -04:00
harry bed9b10380 Added netplay ROM comparison logic. 2024-03-24 15:42:10 -04:00
negativeExponent 79c533ffdc
unrom512.cpp: Expand support for PRG ROM size upto 4M
at least 1 cart in Mapper30 has 2MB. current implementation only allows carts of upto 512K
2024-03-24 10:27:52 +08:00
harry cc61b7b5ab Added app version check between netplay host and clients to ensure interface compatibility. 2024-03-23 19:01:33 -04:00
harry cc234ae04b Added on state loaded callback function to core so that driver code can be notified of a new state being loaded. In Qt driver, emit a signal on state loads that objects can connect to. For a resync of all netplay clients when server detects a new state load. 2024-03-23 07:32:25 -04:00
harry 2ff6084935 Qt netplay host game UI dialog improvements. 2024-03-21 22:29:15 -04:00
harry 5a0898ccbe For Qt GUI, added netplay client state load request functionality. 2024-03-21 22:06:40 -04:00
harry 55654f7191 For Qt GUI, changed instruction tracing to be enabled/disabled by registering callback functions. This increases efficiency when tracing is disabled. 2024-03-18 06:02:30 -04:00
thor2016 5eeeb2219f
Merge pull request #721 from vampirecat35/master
Update StringBuilder.h
2024-03-05 08:36:48 -05:00
Andy Vandijck 1926729680
Update StringBuilder.h
Fix nullptr_t to std::nullptr_t
2024-03-05 11:12:34 +01:00
harry 72d1a8edf2 Added netplay client frame throttling functionality to keep it in step with server. 2024-03-04 06:47:09 -05:00
harry 798c5a1d9c For NetPlay, added ability for client to request a ROM to load. 2024-03-03 20:30:35 -05:00
harry ee814f99e5 Added NetPlay server force resync and drop player UI functionality. 2024-03-03 13:09:28 -05:00
harry 75e9627aa8 Added framework for a net play host status dialog window. 2024-02-28 07:18:19 -05:00
harry d212b894a7 Added ROM loaded and NES reset signals to allow for net play to reconfigure accordingly during those events. 2024-02-26 07:02:59 -05:00
harry 145fc1614f Added a simple ping message to Qt netplay in an effort to measure round trip message delay. 2024-02-26 06:05:01 -05:00
harry 015f6a0acd Added client pause flag to status message for net play. 2024-02-25 16:22:18 -05:00
harry 6832eaa964 Added custom string class that mirrors the C++ std::string API but also allows for fixed size buffers on the stack. This new class also has various C style functions (like sprintf) built into it. 2024-02-25 16:08:35 -05:00
harry 0123e1fbf8 Added sync checking and network byte ordering code for Qt net play. 2024-02-25 08:40:36 -05:00
harry 8d93015a56 Put win64 auto build back to Qt5 until the Qt6 build issue can be solved. 2024-02-24 18:19:34 -05:00
harry 245a8701e0 More attempted to fix Qt6 win build. 2024-02-24 17:37:00 -05:00
harry 9d08ff453a Another win64 Qt6 build fix 2024-02-24 17:01:43 -05:00
harry ce0dd16abd QHelp build for Mac OSX 2024-02-24 14:03:14 -05:00
harry c14dd99efc Build fix for Qt win platforms when UNICODE defaults to wide chars. 2024-02-24 14:00:31 -05:00
harry f63ac15aa2 Help pages build fixes for Qt6. 2024-02-24 13:56:06 -05:00
harry de549f0eb9 Build fix for const qualifier not being respected. 2024-02-24 13:28:36 -05:00
harry 5f3ce5896a Compile fix for <QtPlatformHeaders/QWindowsWindowFunctions> header not existing in Windows Qt 6. Set Qt win64 auto build to build against Qt 6. 2024-02-24 10:35:09 -05:00
harry e2ac013cbb Run cppcheck static analyzer against code base. Fixed a few warnings. 2024-02-24 08:46:06 -05:00
harry c324a82526 More cleanup of sprintf usage in favor of snprintf. This is to resolve deprecation warnings on Mac OSX 2024-02-24 07:27:20 -05:00
thor2016 db8fd407ab
Merge pull request #718 from TheRealQuantam/tracefix4
Non-SDL/Qt Windows Trace Logging Optimizations
2024-02-24 07:10:36 -05:00
TheRealQuantam 0605967820 Non-SDL/Qt Windows optimizations 2024-02-24 00:11:56 -08:00
harry 548635a2f2 Resolved vsprintf deprecation compiler warning, swap out for vsnprintf 2024-02-23 22:56:27 -05:00
harry 37574f9bef More cleanup of sprintf usage in favor of snprintf. This is to resolve deprecation warnings on Mac OSX 2024-02-23 22:38:40 -05:00
harry 7b79d9db4c Partial cleanup of sprintf usage in favor of snprintf. This is to resolve deprecation warnings on Mac OSX 2024-02-23 20:53:01 -05:00
harry 80f17c664b Resolved a couple gcc compiler warnings in trace logger. 2024-02-23 09:09:08 -05:00
thor2016 b25f56fe12
Merge pull request #686 from negativeExponent/vrc5_128k
Fix 128K CHR-ROM variants for VRC5
2024-02-23 07:34:17 -05:00
thor2016 3d5a062799
Merge pull request #714 from TheRealQuantam/tracefix2
Trace logging optimizations and bug fixes
2024-02-23 07:33:55 -05:00
TheRealQuantam 2d468d7926 Dummy commit to re-validate PR 2024-02-22 00:19:51 -08:00
TheRealQuantam 56980510b7 Trace logging optimizations and bug fixes 2024-02-21 21:00:05 -08:00
harry 780a445468 Added global module import function to Qt GUI JS engine. 2024-02-21 06:59:43 -05:00
harry f04e8a5ea4 NetPlay config and GUI improvements. 2024-02-20 06:56:26 -05:00
harry 0e4c122623 Added a clear recent ROM list menu item to Qt GUI. 2024-02-20 05:11:58 -05:00
harry 36614540fd Minor config improvements. Modified Qt recent ROM menu to drop file entries that no longer exist on disk. 2024-02-20 04:54:07 -05:00
harry cb45321433 More Qt netplay updates. 2024-02-19 15:53:11 -05:00
harry 84c2591d3f Added initial framework for netplay on Qt GUI. Still much TODO here. 2024-02-19 11:57:12 -05:00
harry 2f2279f5ff Added more functions to JS File object. 2024-02-18 21:10:24 -05:00
thor2016 72b297980b
Merge pull request #709 from andyvand/master
Fix strings
2024-02-18 16:08:56 -05:00
harry c62f62b497 Added option on how to handle new gamepad device detection. Can now choose to do nothing, prompt user, or auto reconfigure of button mappings when a new device is detected. 2024-02-18 16:04:00 -05:00
Andy Vandijck 3cf7615aeb
Merge pull request #3 from TASEmulators/master
For Qt GUI, poll SDL events immediately after initializing the joysti…
2024-02-18 17:25:49 +01:00
harry 9ed1dd481b For Qt GUI, poll SDL events immediately after initializing the joystick subsystem to process all input device add events. Added gamepad init logging. 2024-02-18 10:37:26 -05:00
Andy Vandijck 2e18434959 Fix Linux build
Fix Linux build
2024-02-18 15:52:24 +01:00
Andy Vandijck 897849111c Fix Linux build
Fix Linux build
2024-02-18 15:51:11 +01:00
Andy Vandijck b8fce760dd Fix Linux
Fix Linux build
2024-02-18 15:49:36 +01:00
Andy Vandijck 1227e9ebc0 Fix Linux build
Fix Linux build
2024-02-18 15:45:48 +01:00
Andy Vandijck b8ebb122cd Remove .orig file
Remove left overs from patch
2024-02-18 15:14:51 +01:00
Andy Vandijck 2d632dfeeb Change toUtf8() to toLocal8Bit()
Change strings
2024-02-18 14:52:19 +01:00
Andy Vandijck 6e33b530c0
Merge pull request #2 from TASEmulators/master
Improvements
2024-02-18 09:15:04 +01:00
harry 9cd7b620dd Minor JS File object fixes. 2024-02-17 21:01:24 -05:00
harry 460bf597d5 Added initial framework for a JS File object. 2024-02-17 20:52:09 -05:00
harry b5ae9012ce Include missing headers to fix build. 2024-02-17 19:20:04 -05:00
Andy Vandijck ef5df90e69
Update CMakeLists.txt 2024-02-17 20:11:10 +01:00
Andy Vandijck 56b24556df
Merge pull request #1 from TASEmulators/master
Add improvements
2024-02-17 20:08:20 +01:00
Andy Vandijck cde83851ba Fix build for newer targets
Fix build
2024-02-17 19:21:47 +01:00
thor2016 3f81906926
Merge pull request #708 from andyvand/master
Fix timestamp arm64
2024-02-17 10:26:20 -05:00
harry 7b9829eda9 Changed JS log file save function so that it doesn't truncate the current temp file. 2024-02-17 08:42:12 -05:00
harry a929eda845 Added JS log file functionality. 2024-02-17 07:54:00 -05:00
Andy Vandijck 6332900833 Fix timestamp arm64
Fix timestamp arm64
2024-02-17 11:22:03 +01:00
harry ab46158f05 Added movie js function remaps 2024-02-17 04:23:11 -05:00
harry df12fa2a85 Added more movie JS interface functions. Hooked up lua joypad.getimmediate functionality for Qt GUI. 2024-02-16 22:52:04 -05:00
harry aaa519d29c Added initial framework for movie JS API. Still TODO implement rest of movie functions. 2024-02-16 07:12:25 -05:00
harry af9b53ba75 Added joypad button override functionality to JS API. 2024-02-15 22:04:11 -05:00
harry f85f93c5bd JS joypad API improvements. 2024-02-14 06:28:26 -05:00
harry 446763b232 Added JS joypad object functionality. 2024-02-11 14:56:58 -05:00
harry 6248b0ee64 Added ability to pass command line arguments to JS scripts. 2024-02-11 10:43:40 -05:00
harry 20a9c151be JS logging improvements. 2024-02-11 10:25:47 -05:00
harry 2229d32720 Added a QJSEngine wrapper class to maintain link to script instance and dialog window with new script objects. 2024-02-10 23:00:07 -05:00
thor2016 290c4ccd96
Merge pull request #706 from negativeExponent/patch-1
QT: Fix volume adjustment for APU
2024-02-10 08:49:11 -05:00
negativeExponent 8d0fe851bf
QT: Fix volume adjustment for APU
Volume adjustments for the apu channel has a range of 0-256. With a value of 256, this acts as a bypass (toggle) and skips the computation entirely when set. This fixes issues when the original signal is too low already that passing it through volume controls will attunuate the signal instead and silence it.

The main volume does not behave the same way and 256 is not a toggle, so left it as-is.

@thor2016 feel free to make it better if necessary, maybe a toggle instead of a 256 max value or something.
2024-02-09 10:19:47 +08:00
harry 8ebb560d1c Added emulator save state JS interface. 2024-02-06 22:44:08 -05:00
harry 2f2482e950 Minor null check fix. 2024-02-05 18:34:03 -05:00
harry 401110bae8 Added ppu interface functions to JS engine. 2024-02-05 18:29:25 -05:00
harry a5071f10f0 Implemented ROM JS interface object. 2024-02-05 06:43:27 -05:00
harry 61da515f11 Finished remaining JS interface functions for JS emu object. 2024-02-05 05:56:40 -05:00
harry 1fc813803e Added JS script monitoring thread to prevent bad scripts from hanging the gui. 2024-02-04 22:09:59 -05:00
thor2016 5495c7eddc
Merge pull request #699 from TheRealQuantam/luafixes2
Multiple Lua Implementation Fixes
2024-02-04 09:07:23 -05:00
harry 4fa0d0651a Added vsync timer logic to Qt OpenGL video driver. 2024-01-31 07:08:08 -05:00
harry 01358407fd For Qt GUI, changed onFrameFinished callback to only update video buffer. Don't do any input processing as this will mess up when running turbo mode. Added a draw timer to SDL video renderer to better align is scheduling with the next vsync. 2024-01-31 06:49:54 -05:00
harry d363d04dbb For Qt GUI, add video buffer mutex to ensure clean transfer between emulation and GUI threads. Use common FCEU::mutex wrapper for cleaner code. 2024-01-31 05:28:41 -05:00
thor2016 cb0edc5a21
Merge pull request #695 from negativeExponent/mapper413
Mapper413
2024-01-31 04:29:21 -05:00
TheRealQuantam f702b5b989 Retriggering checks 2024-01-30 14:25:06 -08:00
harry 19abb0b249 Fix for build break, QJSEngine::setObjectOwnership does not exist in Qt5. Only in version 6. 2024-01-30 06:50:40 -05:00
TheRealQuantam c56b234b85 Multiple Lua support fixes:
- Do not crash when a Lua script calls rom.gethash when no ROM is loaded
- Do NOT assume the error message from lua_pcall will always be in stack slot 1, as sometimes it won't be
2024-01-30 02:41:42 -08:00
TheRealQuantam c7330d4543 Revert bad fix for not terminating script on initial error 2024-01-30 01:41:13 -08:00
harry 6b96016047 JS scripting in work. 2024-01-29 23:17:15 -05:00
harry 813d4c0c4b Added nullptr check in the event QStyle factory fails. 2024-01-29 20:19:36 -05:00
TheRealQuantam 5ff4edbdad Multiple Lua support fixes:
- Move call to info_onstop from FCEU_LuaStop to FCEU_LuaOnStop so it will always get called
- Do NOT assume the error message from lua_pcall will always be in stack slot 1, as sometimes it won't be
- After calling HandleCallbackError ensure L still exists before calling lua_settop
2024-01-28 19:01:49 -08:00
negative 5631e488f4
fix indents 2024-01-29 07:57:43 +08:00
harry a85f348e50 For Qt GUI, edit frame throttling logic when using turbo mode or really fast emulation speed to not be so wasteful when emulation is paused. Don't make sense to waste CPU resources spinning on nothing. Fixes #681. 2024-01-28 08:15:00 -05:00
harry c50c1d570c Change linear filter checkbox text to not include OpenGL. This function not specific to OpenGL and works for all supported video drivers. 2024-01-27 19:35:01 -05:00
harry b03c9c9c8b Removed const qualifiers to fix Qt build. Different versions of Qt QJSValue don't allow the call method to called from a const object. 2024-01-27 01:04:48 -05:00
harry fe0496a6cf Bug fix for issue in new LUA memory hook scheme where the callbacks get unregistered from the x6502 while still running. Fixes #693 2024-01-27 00:39:23 -05:00
harry a02ae8d3e0 Added memory hooks to JS engine. 2024-01-26 22:57:54 -05:00
thor2016 4f604b7708
Merge pull request #690 from negativeExponent/fix_ntsc_clip
Clip Left/Right Sides option now taken into account when using NTSC s…
2024-01-26 22:04:15 -05:00
harry 23cf99afe5 Added source listing to gdb debug output. 2024-01-26 22:00:20 -05:00
harry 3e8978c2aa Added debug script to aid in getting crash callstacks from users. 2024-01-26 20:33:40 -05:00
negative 82a99060e5
Use macro and minor offset adjustment 2024-01-25 18:10:48 +08:00
negative 8e935a05a6
Clip Left/Right Sides option now taken into account when using NTSC scaler 2024-01-24 14:52:45 +08:00
harry 2fce5ffe74 Added memory access functions for JS script interface. 2024-01-19 16:54:56 -05:00
harry 7a0be296fa Added logic to realtime update js global variable viewer. 2024-01-17 07:14:10 -05:00
harry 1dde9e7e75 Minor fixes for JS global variable viewer. 2024-01-16 22:04:00 -05:00
harry dc2d3c26aa Added global JS property tree to allow exploring of engine data. 2024-01-16 21:48:13 -05:00
harry 9a9f9541d6 Build fix for systems without Qt QML installed. 2024-01-15 20:09:25 -05:00
harry 198cdafbf8 Qt JS script engine interface in work. 2024-01-15 14:17:13 -05:00
harry 8e7e5e8c05 Minor refactor of script memory hook interface so that both lua and js script can coexist nicely. Script engines now register themselves with the CPU module for their functions to be called. 2024-01-15 09:31:53 -05:00
harry f90a269386 Build fix for Qt6. 2024-01-15 05:57:24 -05:00
harry e51a748a05 Qt JS engine in work. 2024-01-15 05:34:13 -05:00
harry ecda95ed70 Qt JS engine in work. 2024-01-15 04:33:27 -05:00
harry 3436e221de For Qt GUI, added initial framework for use of the Qt built-in ECMAScript (javascript based) engine. This scripting capability will allow users to load their own custom UI windows (created using Qt Creator tool) in the GUI. This is intended to serve as a the Qt GUI's functional replacement for building GUI elements using IUP in LUA scripts. This is a work in progress. 2024-01-14 08:58:10 -05:00
negative d742620d72
Fix 128K CHR-ROM variants for VRC5 2024-01-13 09:30:42 +08:00
negative aace08d0b6
Add mapper 413 support 2024-01-07 22:03:33 +08:00
negative 647c08e1e6
Add support for misc rom area 2024-01-07 21:59:25 +08:00
harry b53d087fca Changed Qt Win64 1px fullscreen window border to be a configuration option. Doesn't seem to be necessary for all users and maybe not at all anymore. We will see if the QOpenGLWidget issue resurfaces with this setting off. Fixes #514 2023-12-12 21:27:55 -05:00
Alexey Cluster e806a5a25a
Merge pull request #676 from negativeExponent/master
Fix handling of roms with  prg size below 16K
2023-12-09 22:46:54 +04:00
negative 1bd7e2f5b9
Fix handling of roms with prg size below 16K
Fix https://github.com/TASEmulators/fceux/issues/675
2023-12-08 18:39:15 +08:00
harry 72b949efcd For Qt GUI, added hot keys for certain emulation speed presets. Presets are: 1/4x, 1/2x, Normal 1x, 2x, 4x, 8x, and 16x. These hot keys can be mapped to gamepads using advanced key bindings. 2023-11-30 21:09:52 -05:00
harry 8600679636 Comment out warning message about debug file not being able to be opened for reading. It is normal for the file to not exist so it seems silly to warn about not being able to open it. 2023-11-24 09:02:50 -05:00
harry 2909846446 Upgrade appveyor macos build environment to monterey. Also auto build macos app with Qt6. 2023-11-17 21:57:16 -05:00
Alexey 'Cluster' Avdyukhin 5a5faa7372 More mapper 45 fixes 2023-10-26 23:33:49 +04:00
Alexey 'Cluster' Avdyukhin 764e1ebd76 Mapper 45 fixes 2023-10-26 23:19:38 +04:00
Alexey 'Cluster' Avdyukhin 33aca22af2 Issue #654 fix 2023-10-02 23:38:44 +04:00
Alexey 'Cluster' Avdyukhin e0138e5bfd Mapper 134 fix 2023-10-02 22:57:04 +04:00
Alexey 'Cluster' Avdyukhin 1ffa4d7f0c Mapper 134 CHR and PRG masks 2023-10-02 22:42:48 +04:00
harry d2ee6351c0 Added feature macro __FCEU_X86_TSC_ENABLE to enable usage of the X86 TSC. 2023-09-07 19:12:44 -04:00
zeromus 396096223e fix build errors from rdtsc (fixes #663) 2023-09-07 18:56:48 -04:00
harry d86c81e26e Fixed memory leak bug where FCEU_LoadGameSave and FCEU_SaveGameSave functions were not closing out their file handles. 2023-08-30 17:47:16 -04:00
harry 5252188010 Updated web pages and download links for 2.6.6 release. 2023-08-28 06:56:26 -04:00
harry 34eb7601c4 Fixed pkgconfig libarchive path for MacOSX build. 2023-08-26 13:04:21 -04:00
harry 79147dd9e7 Updated help docs for upcoming 2.6.6 release. 2023-08-24 21:26:26 -04:00
Alexey 'Cluster' Avdyukhin 3981ffc8a2
Merge pull request #655 from negativeExponent/patch-2
MMC5: Fix PRG in 32K bank switching
2023-08-22 23:21:14 +04:00
harry 35218bd313 Added initial web press release notes for version 2.6.6 2023-08-19 21:32:21 -04:00
harry 1adbb9c91b Fix for windows appveyor pipeline. Use strawberry perl to run build script. 2023-07-17 21:45:01 -04:00
100thCoin 4c28daf4a8 Write instructions now update the databus
This corrects open bus execution following write instructions.
2023-07-14 14:28:21 -07:00
harry dda4443ae9 Minor tscValid function correction. 2023-06-26 22:40:49 -04:00
negativeExponent 3f1e080672
Fix PRG in 32K bank mode
PRG register $5117 value is used for the entire $8000-$FFFF CPU range in 32K mode.

See https://www.nesdev.org/wiki/MMC5#PRG_mode_($5100) in PRG bankswitching
2023-06-27 09:03:46 +08:00
harry 99bb679ac5 Integrated suggested changes for issue #649 2023-06-18 18:11:03 -04:00
harry 530fec6aff Cleanup a few hard coded constants in timeStamp.h 2023-05-28 11:14:01 -04:00
harry 43cd7ef60a Updated Qt driver FCEUD_GetTime and FCEUD_GetTimeFreq functions to allow for a higher timing resolution. 2023-05-21 18:41:24 -04:00
harry 70aa850c15 Build fix for win64 Qt GUI. 2023-05-21 16:56:52 -04:00
harry 1a3170fd68 Changed Qt GUI frame throttling to use new time stamp record for computing timing. This fixes an issue where frame timing starts to lose precision when application time gets to float large values by performing calcultions using integer math 2023-05-21 16:44:20 -04:00
harry 6fb899e9a1 Another win32 build fix. 2023-05-19 22:37:13 -04:00
harry 2d896c10bc Build fix for win32. 2023-05-19 22:35:22 -04:00
harry e597f6a4a3 Moved time stamp functions to its own file. Use new common time stamp functions in Qt GUI timing. 2023-05-19 22:31:01 -04:00
harry a20f6f559b Compiler warning fix for potential uninitialized var. 2023-05-15 21:29:42 -04:00
harry be38e34a06 For Qt GUI, added code to save/restore window geometry for ROM selection from archive dialog. 2023-05-15 21:11:19 -04:00
harry 584593816f Remove debug symbol save call from load symbols function so that live file edits are not overwriten. Added a save debug symbols debugger menu action so that this can be explicitly performed. Fixes issue #642. 2023-05-15 20:42:17 -04:00
harry 7573f1b7dc Added profiler per thread logging. 2023-05-13 20:26:56 -04:00
harry 58b87387eb Cleanup of Qt GUI video driver viewport loading/unloading. Use QObject::deleteLater for a cleaner shutdown of a viewport. 2023-05-11 08:05:14 -04:00
harry 52c53dfe5b Removed commented out code Qt GUI video interface code. 2023-05-10 21:30:27 -04:00
harry b125d48db5 For Qt GUI add code that forces video alpha bits to 255 for all pixels. Some video drivers aren't ignoring the alpha bits as they should so make sure they as always set to be safe. 2023-05-10 20:58:19 -04:00
harry 3208c01b38 Hooked up bi-linear filter for new QPainter video driver. 2023-05-10 00:25:07 -04:00
harry 13b52f5c8e A few corrections to the QPainter Video driver. 2023-05-09 23:01:53 -04:00
harry 3d6cf7a730 Added a third video driver option for Qt GUI that uses a QPainter object to render QImages to the viewport. Consolidated video driver interface into a base class so generic object pointer can be used throughout the code to control the viewport. 2023-05-09 22:57:05 -04:00
harry a9f4176f2b Minor profiler update 2023-05-09 22:53:40 -04:00
harry d0d822447d Preparing to merge debug profiler in to main dev line. 2023-05-09 18:28:49 -04:00
harry 157b8531a2 Added TSC timing to suppliment lower resolution time measurements. 2023-05-09 08:26:28 -04:00
harry 9a0578dba9 Merge branch 'master' of github.com:TASEmulators/fceux 2023-05-09 05:59:32 -04:00
Alexey 'Cluster' Avdyukhin 3d1062c9fe Removed debug code from mapper 342 2023-05-08 19:42:58 +04:00
harry 5847c0c364 Initial add of execution profiling debug code. This code is only included in the build if the __FCEU_PROFILER_ENABLE__ macro is set. 2023-05-08 07:50:26 -04:00
Alexey 'Cluster' Avdyukhin 62b72b6141 Minor comments fixes 2023-05-08 15:17:53 +04:00
Alexey 'Cluster' Avdyukhin e95e1d1095 Mapper 342 fixes 2023-05-08 13:46:43 +04:00
harry f660f132af Added GNU profiler instrumentation build option to Qt GUI. 2023-05-07 07:37:48 -04:00
thor2016 94f2696a83
Merge pull request #626 from bbbradsmith/ppu_internal_memory_init
Memory initialization settings for PPU internal memory
2023-05-04 20:58:47 -04:00
thor2016 2265f3effe
Merge pull request #643 from fmahnke/mem-reg-read
Implement LUA function memory.registerread
2023-05-04 20:55:07 -04:00
Fritz Mahnke 150372eeca Remove some code that was ported to FCEUX from gens, but isn't used. 2023-05-04 14:50:11 -07:00
Fritz Mahnke 17e04a9b74 Implement LUA function memory.registerread. 2023-05-04 14:50:11 -07:00
Alexey 'Cluster' Avdyukhin f8b8e93eaf Mapper 342 memory optimization 2023-05-02 14:35:08 +04:00
harry 201cb50d89 Updated README and macOSX build from source instructions to include optional dependency libarchive. 2023-04-30 09:16:59 -04:00
Alexey 'Cluster' Avdyukhin 8b37ad91e5 Commit 8857f99d rollback 2023-04-28 17:33:05 +04:00
Alexey 'Cluster' Avdyukhin d72d9daebb Merge branch 'master' of github.com:TASEmulators/fceux 2023-04-28 15:02:22 +04:00
Alexey 'Cluster' Avdyukhin 8857f99dd0 Using 8KB of CHR RAM memory for UNROM-512 by default (required by some games), use NES 2.0 to override 2023-04-28 15:02:04 +04:00
harry f4c88411b0 Added libarchive to Qt GUI macOS build. 2023-04-25 21:21:40 -04:00
harry e1e88b7298 Added libarchive to Qt win64 build. 2023-04-25 04:14:30 -04:00
harry 99bc0fa17f Add nullptr check to ensure that libarchive version strings are valid before printing. They will be null when a particular format or filter is not supported. 2023-04-24 23:14:43 -04:00
harry 02baa1dfaa Added libarchive to linux build pipeline. 2023-04-24 23:11:20 -04:00
harry b7bc8a29f0 Added libarchive version info to Qt GUI about window. 2023-04-24 23:08:05 -04:00
harry 45b0ea6f8d Added cross-platform libarchive interface to allow Qt GUI to use 7zip ROM archives. Code is setup to allow for libarchive to be an optional dependency and will fallback to regular minizip if unavailable. 2023-04-24 22:49:30 -04:00
harry 084b2b9ccc Added snap by number of frames (instead of by time) option for Qt state recorder. 2023-04-22 15:56:31 -04:00
thor2016 0942d160ca
Merge pull request #636 from fmahnke/cheat-fix
Fixes for updating the cheats list.
2023-04-20 21:18:55 -04:00
Fritz Mahnke dbb688ec41 Fixes for updating the cheats list.
Update the cheats list after adding a new cheat from the Game Genie window. With
this change, the new cheat is shown immediately in the cheats window, if it's
open.

Fix an issue where the cheats list isn't always immediately updated after a
change. For example, clicking Add while an item is already selected might not
show the item until some other user action is taken. This change updates the
cheats list QTreeWidget viewport explicitly after making changes to its items.
This causes changes to be shown immediately.

Remove unused GuiCheatsDialog_t::actvCheatRedraw member.
2023-04-20 13:11:27 -04:00
thor2016 7666f1f7aa
Merge pull request #635 from fmahnke/ppu-viewer-fix
Don't divide by 0 when PPU/sprite viewer windows are small.
2023-04-20 06:23:36 -04:00
Fritz Mahnke 783aa5f38c Don't divide by 0 when PPU/sprite viewer windows are small.
Some of the views are proportional to window dimensions. This caused division by
0 where window dimensions round down to 0. This change avoids that, instead
setting those views' sizes to 0 in these cases.
2023-04-19 01:41:44 -04:00
thor2016 50d4d58276
Merge pull request #634 from fmahnke/no-scroll-pc
Don't always scroll to PC when updating debug window assembly view.
2023-04-17 21:26:54 -04:00
thor2016 b3d2a5f230
Merge pull request #633 from fmahnke/null-fix
Don't index into empty QString in HexEditor.
2023-04-17 21:26:34 -04:00
harry da7c7761a2 Added breakpoint editor address validity checking to Qt GUI. 2023-04-17 21:21:59 -04:00
Fritz Mahnke 39bb749f5d Don't always scroll to PC when updating debug window assembly view.
Change ConsoleDebugger::updateWindowData and updateAllDebuggerWindows to support
two different types of updates: UPDATE_ALL and UPDATE_NO_SCROLL. The new
"no scroll" type lets callers request the assembly view be updated without
scrolling the view to the PC line.

Change the hex editor and trace logger calls to updateAllDebuggerWindows to use
the no scroll update. The user may use these functions with the current
disassembly position in mind and not want to lose it.
2023-04-17 17:41:24 -07:00
thor2016 46054d190c
Merge pull request #632 from fmahnke/focus-fix2
Remove redundant setFocus call, which actually removes focus.
2023-04-17 19:49:18 -04:00
Fritz Mahnke f885abb71b Don't index into empty QString in HexEditor.
QKeyEvent::text may return an empty string in some environments for some keys,
such as modifier keys. This can cause a cause a crash. Add a check for the
hex editor to skip the editing code, which assumes the keyboard event is a
printable character and depends on a non-empty keyboard event text.
2023-04-17 08:28:37 -07:00
Fritz Mahnke 46ad7bbd38 Remove redundant setFocus call, which actually removes focus.
Under i3wm 4.21.1/Qt 6.4.1, the existing code actually removes keyboard focus
from the newly-activated window. Removing the call to setFocus in these cases
fixes the problem. The call to activateWindow is enough to put keyboard focus on
it.

The documentation for activateWindow implies the same.
2023-04-17 08:13:09 -07:00
thor2016 771bccd820
Merge pull request #631 from negativeExponent/m227_chrr_protect_fix
Mapper 227: Fix CHR-RAM protect check
2023-04-17 07:16:43 -04:00
negative c4ce3ac3fd Mapper 227: Fix CHR-RAM protect check 2023-04-17 17:53:42 +08:00
harry 8649a38ef9 Removed old commented out method in Qt debugger. 2023-04-16 21:41:49 -04:00
harry 259c5754ee Code cleanup of conddebug.cpp. Make functions that are not externally used static. Changed condition to have a constructor/destructor and allocate via std new/delete. Fixed a small memory leak. For Qt GUI, refactored debugger breakpoint editor window so that it has its own class to allow for more detailed error checking methods to be added. 2023-04-16 21:38:50 -04:00
harry 5adbc1fcf2 Minor initialization fix for state recorder. 2023-04-15 15:53:17 -04:00
thor2016 c5182aacce
Merge pull request #629 from thesamesam/gcc13
Fix build with GCC 13
2023-04-10 06:59:19 -04:00
Sam James 6ad3837eeb
Fix build with GCC 13
GCC 13 (as usual for new compiler releases) shuffles around some internal includes and so etc is no longer transitively included:
```
In file included from /var/tmp/portage/games-emulation/fceux-2.6.5/work/fceux-2.6.5/src/drivers/Qt/AboutWindow.cpp:33:
/usr/include/x264.h:40:4: warning: #warning You must include stdint.h or inttypes.h before x264.h [-Wcpp]
   40 | #  warning You must include stdint.h or inttypes.h before x264.h
      |    ^~~~~~~
/usr/include/x264.h:127:5: error: uint8_t does not name a type
  127 |     uint8_t *p_payload;
      |     ^~~~~~~
```

See https://gnu.org/software/gcc/gcc-13/porting_to.html.

Bug: https://bugs.gentoo.org/900611
2023-04-10 05:20:23 +01:00
harry 4cb6d97183 Added state recorder config dialogs to Qt GUI that prompt user to apply selected settings and to restart recorder for changes to take effect. 2023-04-03 21:42:24 -04:00
harry 47f795b04b For Qt GUI, added state recorder status display to config window. 2023-04-02 07:39:00 -04:00
harry b4efaa91d8 Changed memory_savestate and compressed_buf buffers in state.cpp to be static file scope. No reason to export these to the linker with global scope. 2023-04-02 06:01:37 -04:00
harry 55bcb3d41a Added a load prev and next state functions for state recorder. 2023-04-01 21:17:34 -04:00
harry 99aefa563a Fix for state recorder load state function. Set EMUFILE_MEMORY read position back to beginning of memory block before calling FCEUSS_LoadFP. 2023-04-01 19:39:37 -04:00
harry e95c0fe86b For Qt GUI, hooked up state recorder pause on load options. 2023-04-01 18:22:54 -04:00
harry 86c6d3e56c Qt GUI state recorder config window updates. Added estimated state save CPU time display. Pause on load time widgets in work. 2023-03-31 06:55:59 -04:00
harry 3e9398f973 Added a timed pause state for use by the state history loader. When the user backs up to a previous state, give the option of temporarily pausing to give the user time to visually process the state before resuming game play. When in this state, an unpause count down can also be optionally shown on the upper left of the video display. Also, setting pause during this state down will cancel the count down and put the emulation into full pause. TODO add GUI config hooks to control video overlay and duration config options. 2023-03-31 05:34:32 -04:00
harry b6a8b46de0 For Qt GUI, added feature that allows save state files to be loaded via window drag n drop from a file dialog. 2023-03-26 17:05:19 -04:00
Brad Smith 46654ed585
ignore 7z_64.dll in output folder 2023-03-26 15:48:26 -04:00
bbbradsmith 4774a773a8 Apply memory initialization settings to nametable, palettes, and sprites. 2023-03-26 15:40:30 -04:00
harry 4b8528588d Added code to save/load state recorder config parameters for Qt gui. 2023-03-12 20:46:45 -04:00
harry bb76573112 State recorder config setup in work. 2023-03-11 20:45:13 -05:00
harry f87d746350 State recorder config dialog in work for Qt GUI. 2023-03-11 15:54:44 -05:00
harry bc6164260d State recorder in work. 2023-03-11 07:47:58 -05:00
harry 326d09d546 Merge branch 'master' of github.com:TASEmulators/fceux 2023-03-11 07:18:11 -05:00
thor2016 88c01cba6c
Merge pull request #624 from negativeExponent/master
Add mapper 174, update mapper 78, fix mapper 205
2023-03-10 21:20:37 -05:00
negative 0aa49a5627 Mapper 205: Fix for split-rom variant (UNIF) 2023-03-06 14:42:25 +08:00
negative 012fbca2d8 Move mapper 205 to mapper 361/366, add proper mapper 205
- Current mapper 205 implementation moved to describe mappers 361 and 366
instead.
- Then add mapper new mapper 205.
These mapper changes should now reflect
what is described in mapper's wiki article
2023-03-06 14:03:18 +08:00
negative 43bdd96d7e Add mapper 174 2023-03-06 13:24:20 +08:00
negative 6babc7fdaf Mapper 78: Add submapper support 2023-03-06 13:13:06 +08:00
harry d7c23fa92e FCEU state recorder in work. 2023-03-04 16:34:21 -05:00
thor2016 c0eee08ce5
Merge pull request #622 from negativeExponent/patch-1
Mapper 354: Add CHR-RAM protect
2023-03-03 20:50:54 -05:00
negativeExponent 9cf87738bf
Mapper 354: Add CHR-RAM protect
Fix https://github.com/TASEmulators/fceux/issues/621#issuecomment-1449284275
2023-03-01 11:42:28 +08:00
harry 5bdbf628a0 For Qt GUI, set palupdate flag after force grayscale or use custom palette settings changeto ensure that PAL 3x filter updates appropriately. Fixes issue #618 2023-02-21 18:56:06 -05:00
harry da05b56cba Added checkbox to Qt debugger menu to control trace logger auto start function on debugger open. Also added code to stop the trace logger on debugger close if it was the debugger who started it in the first place. 2023-02-20 18:36:07 -05:00
harry 25cdc5ade1 Ensure proper initialized returns for emufile read functions. 2023-02-20 12:53:55 -05:00
harry 6f2c0a84f9 Refactor save game RAM code so that the mappers call a function to register their buffers instead of writing directly to the cartinfo variables. Added optional reset callback function that can registered and will be called when FCEU_ClearGameSave runs. This is for memory that needs to be reset to non-zero values. 2023-02-20 11:21:04 -05:00
harry b199bb9787 Update version.h so iterim git is not confused with latest release. 2023-02-19 21:02:06 -05:00
harry dfd5e13b8f Minor cleanup of unrom512 flash state save/load init. Removed debug pragma message. 2023-02-19 20:58:03 -05:00
harry 20b982854d Commented out unrom512 flash save RAM hooks until movie FCEU_ClearGameSave issue can be fixed. 2023-02-19 20:34:04 -05:00
harry 92b021171f Fixed compiler endianness detection. Unified to use common macros in endian.h 2023-02-19 20:07:50 -05:00
harry d5fd976ccf Added button icons for ok/cancel buttons on Qt select from zip archive window. 2023-02-19 15:39:04 -05:00
harry 56c0d30f83 Fix crash in Qt CDL when cdloggerVideoDataSize is zero. 2023-02-19 15:22:34 -05:00
harry 6b73e91c38 Ensure a few static variables are initialized properly. 2023-02-18 16:24:28 -05:00
harry e9f97f520a Change size input for allocation functions to size_t type instead of uint32. 2023-02-18 16:23:28 -05:00
harry 903e035a95 For Qt GUI added code to warn user that symbol table will be wiped when importing ld65 dbg files. Added code to clear and redraw debugger window data after importing new symbols. 2023-02-14 20:33:46 -05:00
harry 791ff7478d Commented out debug print. 2023-02-13 18:56:14 -05:00
harry 53cf1eaf2a Added a macro for NES header size to avoid having magic number 16 all over code. Fixed ld65 bank calculation to account for header. 2023-02-13 18:53:53 -05:00
harry b33b27c25b First semi-successful ld65 debug symbol import 2023-02-12 22:21:05 -05:00
harry e0aa5a71fa ld65 debug database loader in work. 2023-02-12 14:47:00 -05:00
harry 0beac5d725 ld65 debug file parser in work. 2023-02-12 12:54:20 -05:00
harry 07617997f4 Added hooks to Qt GUI for importing of ld65 debug symbol files. 2023-02-12 09:09:17 -05:00
harry c1e7465fe5 Laying out framework for ld65 debug symbol loader feature. 2023-02-12 08:30:14 -05:00
harry 18f09c8e76 Fix for UBSAN left shift of negative number error in SexyFilter2 2023-02-09 20:06:18 -05:00
harry 66f35e1074 Fixed 2.6.5 release source download link labels. 2023-02-08 20:29:20 -05:00
harry 785327db33 Updated web page download links for 2.6.5 release. 2023-02-08 20:25:05 -05:00
zeromus ea6ed69b87 add missing StateRestore on mapper 354 2023-02-08 17:47:15 -05:00
harry ed192bec5c Updated 2.6.5 web page press release. 2023-02-08 04:43:30 -05:00
harry cb0301b12d Added a flag to control whether duplicate debug symbol names are allowed. Default value to true. 2023-02-08 04:38:06 -05:00
harry cd5253babe Updated and regenerated help docs with new debugger.getsymboloffset lua info. 2023-02-07 21:31:04 -05:00
harry 66e2576595 Fixed string over-read in win port by added a exit condition for loop in ASM debugger logic. 2023-02-06 21:26:40 -05:00
harry 410810ac18 Fix for win port editing core debug symbol table entries. 2023-02-06 20:49:09 -05:00
harry 47530d614c Added code to check for duplicate debug symbol names when editing the name of an existing symbol. 2023-02-05 20:44:36 -05:00
harry 130d1dcd45 Changed symbolic debug table error printf statements to use FCEU_printf so that messages are logged in message viewer for user to read. 2023-02-05 08:20:28 -05:00
harry e4749425ba Added code to remap symbolic debug name in lookup table if editted via gui. 2023-02-05 03:57:23 -05:00
harry 98008bcd4d Fixed memory leak in Qt GUI when adding a new symbolic debug fails. Added error messaging to inform user why it failed. 2023-02-04 21:00:29 -05:00
harry fb75b34b1d Added smarts to Qt debugger context menu to show add/edit for symbols and bookmarks on whether they already exist or not. 2023-02-04 20:14:47 -05:00
harry b3386027bd Fixed ASAN error in debug symbol delete. 2023-02-04 15:40:52 -05:00
harry 575b019659 Changed core symbol table to have private data that can be accessed via methods. The goal is to control access to this data to prevent table lookups getting messed up when symbols are editted via the gui. 2023-02-04 15:15:31 -05:00
harry fa7da51ccd Patch new core debug symbol table into win port. 2023-02-04 07:25:39 -05:00
thor2016 5bdbdd61b1
Merge pull request #608 from tsone/lua_improve_getsymboloffset
Renamed Lua debugger.getsymboladdress() -> getsymboloffset()
2023-02-03 20:46:11 -05:00
tsone ef1f7ec39a Renamed Lua debugger.getsymboladdress -> getsymboloffset and added the function documentation. 2023-02-01 16:00:28 +01:00
harry 2d81c9c7b2 Added frame advance delay config parameter to Qt GUI and set delay default to 40 frames to match win port timing. Also, reset frameAdvance_Delay_count to zero before setting frameAdvanceRequested flag to avoid possible race condition where emulation thread can miss seeing zero count and not temporarily pause when it should. 2023-02-01 01:06:48 -05:00
harry b602de6ce0 Removed old common config code from Qt build. The Qt port only uses the newer C++ style common config system. 2023-01-31 23:02:21 -05:00
harry d32ab0ad51 Added a mutex to the debug symbol table access functions to ensure that access to symbol maps is thread safe. Since a map change will invalidate any iterators operating on the map, it is important to ensure that access to the map is locked when a thread is iterating or operating on the map. 2023-01-31 22:14:49 -05:00
harry 5cec622e58 Disabled integer loss of data conversion compiler warnings (4267,4244) for win64 builds. All warnings are converting between 32 and 64 bit types and is doubtful to an issue. 2023-01-31 01:56:04 -05:00
harry 4a54f43246 Updated state.cpp so that .luasav file paths use std::string so that they aren't limited in size. 2023-01-31 00:27:01 -05:00
harry 5ed3463c01 Cleaned up -Wunused-result compiler warnings in lua-engine.cpp 2023-01-31 00:03:16 -05:00
harry be9ad4ccf2 Fix small memory leak that occurred when loading a ROM with auto-resume enabled and now resume save file currently exists. Created fceuScopedPtr class type to help prevent memory leaks on temporary memory allocations in functions with early outs. 2023-01-30 23:10:03 -05:00
harry d4c2a7e2d9 Fix for Qt ram watch window save file symbol type parameter sometimes being undefined. 2023-01-30 22:13:28 -05:00
harry 6a2e384469 Fix for Qt Ram Watch window save files to allow for max path. 2023-01-30 21:41:03 -05:00
zeromus 8ea0a3e7e3 fix msvc building 2023-01-30 18:04:34 -05:00
tsone d5a3cecea0 Moved debug symbol table (.nl file) related code to own file and added symbol name -> address lookup. Example uses in Lua and Debugger breakpoint. 2023-01-30 17:00:10 -06:00
harry d061ba2bfa Fixes for -Wformat compiler warnings when using custom printf style functions. 2023-01-30 09:24:49 -05:00
harry 3266a20970 Changed printf attribute check to look for gcc and clang compilers specifically. 2023-01-29 20:46:16 -05:00
harry f815c849c2 Added FCEU printf format specifier macros to enable compiler checking of format strings for custom printf style functions. 2023-01-29 19:38:30 -05:00
harry 0a19794cec Fixed a few warnings for -Wunused-result with fread usage. 2023-01-29 12:32:47 -05:00
harry 4944faf618 Cleaned up -Wunused-result warnings for usage of fgets. fgets from stdin should really never fail so just added nullptr return handling to silence warning. 2023-01-29 11:42:32 -05:00
harry 421c7b35e7 Resolved strncpy -Wstringop-truncation warning in Qt NES header editor. 2023-01-29 11:28:58 -05:00
harry 727e403917 A couple more int compare sign warning fixes. 2023-01-28 22:51:33 -05:00
harry 5a98a7fc0d Re-enable int comparison sign mismatch compiler warnings. 2023-01-28 20:28:51 -05:00
harry 7c3c3caf93 More int comparison sign mismatch compiler warning fixes. 2023-01-28 20:24:17 -05:00
harry 213f4e2579 More fixes for int compare sign mismatch warnings in Qt TAS Editor. 2023-01-28 16:24:04 -05:00
harry 7910da7805 More int comparison sign mismatch compiler warning fixes. 2023-01-28 16:03:05 -05:00
harry 7a40075f3e Build fix for ssize_t not being available in windows. 2023-01-28 15:05:58 -05:00
harry c075cdca4f More int comparison sign mismatch compiler warning fixes. 2023-01-28 14:05:21 -05:00
harry 4434974350 Cleaned up int comparison sign mismatches in Qt TasEditor markers. 2023-01-28 13:49:09 -05:00
harry d530bab2e7 Resolved gcc -Wsign-compare compiler warnings in state.cpp. 2023-01-28 09:11:42 -05:00
harry 5b9385b2c8 Resolved int comparison compiler warning. 2023-01-28 09:09:58 -05:00
harry a45aa73a4a Fix for int conversion compiler warning. 2023-01-28 08:04:05 -05:00
harry 5582df13d7 A few signed/unsigned int comparison mismatch compiler warning fixes. 2023-01-28 07:54:31 -05:00
harry c2dc8cd25b A few more int conversion compiler warning fixes. 2023-01-28 07:49:24 -05:00
harry 2d158a8298 Updated a few types to size_t to match std. 2023-01-27 21:01:51 -05:00
harry a81632b7e1 Changed compiler attribute checking to play nice with older compilers. 2023-01-27 20:38:47 -05:00
harry d4d4001d32 Added a guard to not double define __WIN_DRIVER__ macro. 2023-01-27 08:14:58 -05:00
harry 85dfcef243 One more compiler warning fix for size_t to long conversion. 2023-01-27 08:06:28 -05:00
harry a9562cd655 Cleaned up a few compiler warnings caused by last commit. 2023-01-26 08:03:18 -05:00
harry 5e9e80eddc Change EMUFILE fseek,ftell, and other related functions to use types that follow the C standard (long int for position offsets and size_t for sizes). This allows for larger max file sizes on unix platforms and cleaner code that better maps to the C standard. 2023-01-25 21:46:30 -05:00
harry b338d4a037 Fix for UBSAN error: left shift of negative value 2023-01-25 20:36:32 -05:00
harry 01821d89b5 Fix for Qt GUI Avi codec save settings to support max file path. 2023-01-23 22:26:56 -05:00
harry 41878d95ef Added Qt empty scan code to Qt Key map for Mac OS platform. QKeyEvent::nativeScanCode() does not return valid codes on Mac OS, so this backup conversion method will not work on that platform. 2023-01-23 21:40:59 -05:00
harry 53288c0a75 Cleaned up native scan code to Qt key conversion code for windows. Use known key definitions instead of hardcoded values when possible. 2023-01-23 21:20:19 -05:00
harry f4a9fa6898 Comment out debug print statements for Qt keyscan code. 2023-01-22 21:51:29 -05:00
harry 39aafe7a88 Cleaned up native scan code to Qt key conversion code for linux. Use known key definitions instead of hardcoded values when possible. 2023-01-22 21:15:56 -05:00
Alexey 'Cluster' Avdyukhin 9a74d64b2c Fix for #510, for Windows 2023-01-22 21:32:13 +04:00
Alexey 'Cluster' Avdyukhin 99dc99831c Fix for #510 2023-01-22 20:43:30 +04:00
harry a4a799feef Changed Qt GUI TAS editor recent menu to show file name separated by some space and then full path to file. This is so that the file name can still be read when the full path is ridiculusly long. 2023-01-22 10:00:00 -05:00
harry 6d622cc787 Fix for Qt GUI TAS editor to support max file path for fm3 files. 2023-01-22 09:55:20 -05:00
harry 93c0e13572 Fix for Qt GUI wave file recording to support max file path length. 2023-01-22 09:45:22 -05:00
harry 44a5c58e44 Added realloc error checking in convert_fcm function to fix cppcheck warning. 2023-01-21 12:32:52 -05:00
harry b9385118bd Further protect against overlapping string copy by checking if pointers are different... just to be sure it is safe. 2023-01-21 12:11:41 -05:00
harry 26f623f5ea Fix crash in Qt GUI for movie player file path parser. 2023-01-21 11:59:56 -05:00
harry 821e82a069 Fix indentation and add braces to silence empty while loop body compiler warning. 2023-01-21 11:41:55 -05:00
harry aad52488ac Bug fix for ASAN error overlapping strcpy source and destination caused curMovieFilename being passed to openRecordingMovie which copies over itself. Changed type from char array to std::string whose assign function will allocate new memory to copy to before deleting the old string buffer. 2023-01-21 09:59:50 -05:00
harry 2b468be264 Changed temp save/load state file path variables to be std::string. 2023-01-20 23:53:29 -05:00
harry 2f7b4abab2 Reset std::strings lastSavestateMade and lastLoadstateMade using clear method. 2023-01-20 23:42:05 -05:00
harry 47435295ff Fixed if conditionals using lastSavestateMade address that always evaluates to true. Changed lastSavestateMade and lastLoadstateMade to std::string instead of char buffer, ensures proper initialization at startup and allows for unix max path. 2023-01-20 22:37:17 -05:00
harry f0a4e8bd11 Added a proper contructor to CHEATF_SUBFAST struct to fix clang compiler initializer warning. 2023-01-20 22:02:32 -05:00
harry 8fc3ea8ba2 Added FCEU_UNUSED and FCEU_MAYBE_UNUSED macros to help silence certain unused variable and function warnings. Used FCEU_MAYBE_UNUSED to silence unused static function warnings (until it can be deemed that these functions will never be needed). Also, cleaned up a few other unused variable warnings. 2023-01-20 21:50:26 -05:00
harry 5f44e8f374 For Qt GUI, fixed http references to https://fceux.com to avoid redirection. 2023-01-19 06:45:15 -05:00
harry 243eb1d3fd Added 2.6.5 release notes to chm file and regenerated web html. 2023-01-18 21:28:05 -05:00
harry 4b9430e8b1 Added recent mapper 225 and 255 update to release notes. 2023-01-18 21:03:02 -05:00
zeromus ebf0c2c737 update 225 from fceumm to get 255 support too. 2023-01-18 11:05:43 -06:00
harry db6d5bed8c Initial cut at web press release page for upcoming 2.6.5 release. 2023-01-17 21:00:43 -05:00
Alexey 'Cluster' Avdyukhin b40cb9bcf1 Added separator to the menu (win) 2023-01-17 16:55:00 +04:00
harry 5c1c71be67 For Qt GUI, added feature that allows for lua script loading via file drag and drop operations. 2023-01-17 07:02:03 -05:00
harry dd77569621 More large filepath parsing updates for Qt GUI. 2023-01-16 21:11:09 -05:00
harry 1adffbdf00 Modified Qt GUI recent ROM menu items to show the ROM base name following by a tab space and then the full path. This allows for the ROM file name to be in view in the event that the full path is excessively long. 2023-01-16 20:57:26 -05:00
harry 38089b62c0 Fix for Qt GUI compiler warnings in iNesHeaderEditor for potential stack buffer overflows on snprintf usage. 2023-01-16 20:34:00 -05:00
harry f589dfed05 Merge branch 'master' of github.com:TASEmulators/fceux 2023-01-16 20:21:16 -05:00
harry 42039004b5 Fix for Qt GUI symbolic debug filename widget size exploding when the ROM file path is large. 2023-01-16 20:21:10 -05:00
zeromus 3501ab9a40 add mapper 354 from fceu-mm 2023-01-16 10:34:13 -06:00
harry 50a7bb70c8 Changed Qt symbolic debugger file save function to use std::string for filepath. 2023-01-16 09:50:38 -05:00
harry ba47f169ca Fixed stack buffer overflow in Qt GUI loading a ROM with a large filepath from file dialog. 2023-01-16 09:44:32 -05:00
harry 3564f61849 Changed Qt GUI NL filename utility functions to operate on std::string arguments instead of char buffers to better allow for large file paths. 2023-01-16 09:35:22 -05:00
harry 097c8dc79d Increase configSys file parsing line buffer to be able to handle 4096 characters. This allows for unix max file path accomodation. 2023-01-16 09:33:55 -05:00
harry 5760a26863 Add include cart.h to ines.h for CartInfo definition. 2023-01-16 09:09:59 -05:00
harry 4c9a0ad7cf Increased array size of LoadedRomFName buffer to allow for max unix filepath length. Remove duplicate extern definitions in cpp and instead include ines.h header which contains official extern definition. 2023-01-16 08:42:33 -05:00
harry 600588910f Another build fix for Qt GUI. 2023-01-15 04:38:53 -05:00
harry 2be7794ab5 Build fix for Qt GUI. 2023-01-15 01:44:34 -05:00
harry 8a59bd3191 Qt GUI build fix for new ffmpeg macro that expands to a C++20 designated initializer that is not supported by earlier compiler standards. 2023-01-15 01:04:39 -05:00
harry 9a969edf99 Another Qt batch change to try to catch error. 2023-01-15 00:31:57 -05:00
harry ba73c0b2f8 Changed error check command for Qt auto build batch file. 2023-01-15 00:05:05 -05:00
harry 210069b78a Change temp stack variable that holds full ROM path from fixed char array to std::string. This will allow for larger file paths. 2023-01-14 22:43:45 -05:00
harry c837c8981c For QT GUI added logic to check for an FCEUX_CONFIG_DIR environment variable to specify the folder where fceux data resides. This allows users to specify there own data folder that doesn't have a .fceux hidden folder get auto created. 2023-01-14 18:34:03 -05:00
harry 90d03a6374 For Qt GUI, add libav version preprocessor guard to make sure that AV_OPT_TYPE_UINT64 definition exists before using it in source. Fixes issue #578 2023-01-13 01:18:58 -05:00
harry a3240e9c2e Qt GUI deprecation usage fixes for ffmpeg 5.1.x libavutil. Code is now compatible with new AVChannelLayout data structure. Used proper version macros so that code is still setup to be backwards compatible with ffmpeg 4.x 2023-01-13 00:45:44 -05:00
harry ff24dd7a68 For win64 Qt GUI build, disable annoying data type conversion/comparison warnings. 2023-01-12 21:33:05 -05:00
harry ec4d76707c Reset Qt GUI audio buffer samples to zero when killing SDL sound. 2023-01-11 21:57:51 -05:00
harry 37bf5c9bf2 Added logic to Qt GUI to protect against invalid audio sample rates or buffer sizes being fed from the command line to the sound system. Sound will use default values if inputs are deemed invalid. Fixes issue #603 2023-01-11 21:38:29 -05:00
harry cc1e6a8f8b Minor change to Qt GUI window focus audio mute logic. Ensure that it is always re-computed on a window active change event. 2023-01-11 21:08:55 -05:00
harry 739c01f051 Added Qt GUI sound mute function. This function is accessible either via hot key or checkbox on sound config window. Mute state is a config parameter and will persist between application boots. Fixes issue #591 2023-01-11 20:47:11 -05:00
harry e06d1cd506 Modified Qt GUI parseFilepath to output std::string types instead of char * buffers to remove file path length limitations. 2023-01-10 21:14:10 -05:00
harry 4dd8943724 Added negative index protections into GetCHRAddress to protect against a large unsigned number being passed and interpretted as a negative number. Caught by gcc UBSAN. 2023-01-10 17:42:45 -05:00
harry 293fc7b672 Upgrade mac OS build image to 'Big Sur' for appveyor builds. Homebrew has dropped pre-build support for Catalina. 2023-01-07 17:52:36 -05:00
Alexey 'Cluster' Avdyukhin d1368c8213 Debugger and hex editor fix for Vs. System ROMs 2023-01-07 19:46:10 +04:00
Alexey 'Cluster' Avdyukhin c9cdca11c4 Comments for mapper 342 2023-01-07 19:40:59 +04:00
Alexey 'Cluster' Avdyukhin e1c20e4928 Removed some warnings 2023-01-07 19:27:04 +04:00
harry 2c5c3a9fe4 Fix for compiler sprintf usage warning: too many arguments for format. 2023-01-07 02:52:55 -05:00
harry 4c71af3212 Fix for apparent logic error of self-comparison always evaluates to true. Resolves g++ compiler warning. 2023-01-07 02:51:34 -05:00
harry 6ae834a1df Changed interface to Qt GUI function getDirFromFile to pass reference to std::string so that returned string will not have string length limitations. Buffer size will grow as needed for the path and will not be allocated on the stack. 2023-01-07 01:47:45 -05:00
harry 4e54ea54ac Refactor Qt GUI function fceuExecutablePath to be more efficient. Since the path to the executable never changes during the lifetime of the process, save it off the first time this function is called for later use. Function interface changed to just pass back a pointer to the saved string. Saves on stack memory and is more efficient since it does not have to continually copy data onto the stack. 2023-01-07 01:19:29 -05:00
harry b3717c008b Refactor Qt GUI function getDirFromFile to use QFileInfo to get absolute directory path. Also, added a input buffer size argument to prevent string copy buffer overflows. Fixes issue #598. 2023-01-07 00:43:35 -05:00
harry 77b894df0e Changed Qt debugger data save file extension to be .fdb instead of .dbg so that it does not conflict/overwrite ld65 debug symbol files. Fixes issue #600. 2023-01-06 23:27:06 -05:00
Alexey 'Cluster' Avdyukhin 552be94c1a
Merge pull request #596 from Kagamiin/feature/vrc-irq-cycle-mode
Implementing cycle IRQ mode for Konami VRC mappers
2023-01-06 18:18:50 +04:00
Alexey 'Cluster' Avdyukhin 04e1b32675 Linux build fix 2023-01-06 18:04:45 +04:00
Alexey 'Cluster' Avdyukhin ac18eb3c37 Vs. System - unused DIP switches replaced with second coin and service buttons 2023-01-06 17:58:02 +04:00
Alexey 'Cluster' Avdyukhin 598a291daf Vs. System error messages and DIP switch visualization 2023-01-06 16:50:33 +04:00
Alexey 'Cluster' Avdyukhin 2c35a6dfae Allow to open HEX editor when emulation is not paused + minor fix 2023-01-06 16:37:47 +04:00
Alexey 'Cluster' Avdyukhin e6e17ded38 Linux build fix 2023-01-06 16:34:46 +04:00
Alexey 'Cluster' Avdyukhin 4c215246fe Minor GUI fix 2023-01-06 16:31:31 +04:00
Alexey 'Cluster' Avdyukhin d2aed113b8 More NES 2.0 header fields: Vs. System settings, expansion type 2023-01-06 16:03:34 +04:00
Alexey 'Cluster' Avdyukhin 88ad9ceca9 Mapper 342 update 2022-12-23 20:35:35 +04:00
Kagamiin~ 77b252bf50 Implementing cycle IRQ mode for Konami VRC mappers 2022-12-21 15:16:29 -03:00
Alexey 'Cluster' Avdyukhin a04df761a9 Mapper 470 2022-12-21 12:30:04 +04:00
Alexey 'Cluster' Avdyukhin f3675320d8 Fixed IPS loader to prevent double archive browser 2022-12-19 14:55:53 +04:00
Alexey 'Cluster' Avdyukhin f53c2470fc Submappers 268.8 and 268.9 2022-12-16 20:10:21 +04:00
Alexey 'Cluster' Avdyukhin 9ae27c7ded Mapper 268, submappers 6 and 7 2022-12-12 23:38:56 +04:00
Alexey 'Cluster' Avdyukhin 47c2ce5a38 Mapper 268, support for ROMs with 1 MiB CHR-ROM 2022-12-12 23:13:42 +04:00
Alexey 'Cluster' Avdyukhin 773eaa868c Mapper 268, submappers 8,9 merged into 2,3 and fixed (https://www.nesdev.org/wiki/Talk:NES_2.0_Mapper_268) + refactoring 2022-12-12 17:48:56 +04:00
Alexey 'Cluster' Avdyukhin 0fb86b9740 Fixed broken UNROM-512 emulation + some refactoring 2022-12-07 20:04:27 +04:00
Alexey 'Cluster' Avdyukhin 689d763f67 Windows build fix 2022-12-07 09:42:05 +04:00
Alexey 'Cluster' Avdyukhin 853b2718b7 Removed debug messages 2022-12-06 22:51:41 +04:00
Alexey 'Cluster' Avdyukhin b6bf83db7f Mapper 268, submappers 8,9 2022-12-06 17:59:26 +04:00
Alexey 'Cluster' Avdyukhin a70bc4c72c Mapper 268, submappers 4,5 2022-12-05 23:25:49 +04:00
Alexey 'Cluster' Avdyukhin 92c0417783 Mapper 268 refactoring 2022-12-05 23:15:09 +04:00
Alexey 'Cluster' Avdyukhin d6d5b44a35 Mapper 268, submappers 2,3 fix 2022-12-05 21:56:50 +04:00
Alexey 'Cluster' Avdyukhin 7a64e06b88 Mapper 268, submappers 1,2,3 2022-12-05 21:55:38 +04:00
Alexey 'Cluster' Avdyukhin 856a19352f Forgot to update CMakeLists.txt 2022-12-05 17:50:11 +04:00
Alexey 'Cluster' Avdyukhin 90aecc0543 COOLGIRL mapper (mapper 342) 2022-12-05 14:56:31 +04:00
Alexey 'Cluster' Avdyukhin 328e351255 Typo fix 2022-12-05 14:09:21 +04:00
Alexey 'Cluster' Avdyukhin d075c2b46a COOLBOY fixes and self-writable feature 2022-12-05 13:54:50 +04:00
harry 35c5fa36c1 Upgraded Qt/SDL win64 build dependencies to use SDL-2.24.1 and ffmpeg-5.1.2 2022-10-12 20:51:11 -04:00
harry 06c3473c29 Undo packaging of LUA DLLs for Qt Win64 GUI. Static lib seems to be more stable. 2022-10-10 22:04:48 -04:00
harry 83c529efb6 Package lua DLLs and auxlib.lua into Qt win64 zip for IUP functionality. 2022-10-10 09:54:52 -04:00
harry 900305b587 For Qt GUI, added option to use palette background color as video background color. This option can be accessed from via main menu -> option submenu. 2022-10-09 21:09:52 -04:00
harry 06467ce73a Fix for Qt GUI OpenGL blending parameters. 2022-10-09 20:11:54 -04:00
harry 1ad9a3d857 For Qt GUI, added logic to prevent controller buttons that are bound to the keyboard from being active when family keyboard is enabled. Controller buttons that are mapped to physical gamepad or joystick are unaffected. For issue #572. 2022-10-08 09:56:49 -04:00
mjbudd77 edae2d4f57 Updated download links for interim auto builds for new interim-build pre-release setup (uploaded from appveyor using github release deployment) 2022-10-01 17:33:17 -04:00
375 changed files with 30896 additions and 8772 deletions

5
.gitignore vendored
View File

@ -1,3 +1,4 @@
build
/vc/defaultconfig/scmrev.h
/vc/.vs
/vc/vc14_bin_Debug
@ -17,6 +18,7 @@
/output/auxlib.lua
/output/fceux.pdb
/output/7z.dll
/output/7z_64.dll
/output/fceux.exe
/output/fceux.exp
/output/fceux.lib
@ -27,6 +29,9 @@
/vc/fceux.zip
/vc/fceux64.zip
# macOS junk
.DS_Store
# linux build output
bin
src/fceux

5
README
View File

@ -5,9 +5,9 @@ Updated By mjbudd77
[NOTE: This only applies to Qt/SDL builds]
http://www.fceux.com
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

View File

@ -14,10 +14,9 @@ environment:
- job_name: Ubuntu
appveyor_build_worker_image: Ubuntu2004
#appveyor_build_worker_image: Ubuntu1804
- job_name: MacOS
appveyor_build_worker_image: macOS
appveyor_build_worker_image: macos-ventura
for:
@ -27,7 +26,7 @@ for:
- job_name: Windows 32
build_script:
- cmd: perl pipelines/build.pl win32
- cmd: pipelines/WinAppveyorBuild.bat win32
-
matrix:
@ -35,7 +34,7 @@ for:
- job_name: Windows 64
build_script:
- cmd: perl pipelines/build.pl win64
- cmd: pipelines/WinAppveyorBuild.bat win64
-
matrix:
@ -43,7 +42,7 @@ for:
- job_name: Win64 Qt
build_script:
- cmd: perl pipelines/build.pl win64-QtSDL
- cmd: pipelines/WinAppveyorBuild.bat win64-QtSDL
-
matrix:

Binary file not shown.

View File

@ -0,0 +1,11 @@
set PROJECT_ROOT=%~dp0..
set PERL=C:\Strawberry\perl\bin\perl.exe
set JOB=%1
echo %PERL%
echo %JOB%
%PERL% pipelines\build.pl %JOB%
if %ERRORLEVEL% NEQ 0 EXIT /B 1

View File

@ -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

View File

@ -9,7 +9,7 @@ env
SCRIPT_DIR=$( cd $(dirname $BASH_SOURCE[0]); pwd );
QT_MAJOR=5;
QT_MAJOR=6;
QT_PKGNAME=qt$QT_MAJOR;
FCEUX_VERSION_MAJOR=`perl $SCRIPT_DIR/../scripts/fceuVersion.pl -major`;
FCEUX_VERSION_MINOR=`perl $SCRIPT_DIR/../scripts/fceuVersion.pl -minor`;
@ -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/lib/pkgconfig:
ls -ltr $HOME/Qt;

View File

@ -3,7 +3,7 @@ set PROJECT_ROOT=%~dp0..
set CWD=%CD%
call "C:\Qt\5.15\msvc2019_64\bin\qtenv2.bat"
REM call "C:\Qt\6.0\msvc2019_64\bin\qtenv2.bat"
REM call "C:\Qt\6.5\msvc2019_64\bin\qtenv2.bat"
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvars64.bat"
cd /d %CWD%
@ -22,34 +22,46 @@ mkdir build
cd build
mkdir bin
curl -s -LO http://www.libsdl.org/release/SDL2-devel-2.0.20-VC.zip
curl -s -LO https://github.com/GyanD/codexffmpeg/releases/download/5.0/ffmpeg-5.0-full_build-shared.zip
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-2.0.20-VC.zip .
powershell -command "Expand-Archive" ffmpeg-5.0-full_build-shared.zip
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-2.0.20 SDL2
move ffmpeg-5.0-full_build-shared\ffmpeg-5.0-full_build-shared ffmpeg
rmdir ffmpeg-5.0-full_build-shared
del ffmpeg-5.0-full_build-shared.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 -DQT=5 -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
@if ERRORLEVEL 1 goto end
if %ERRORLEVEL% NEQ 0 EXIT /B 1
copy src\Release\fceux.exe bin\qfceux.exe
copy %PROJECT_ROOT%\src\auxlib.lua 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
@ -64,16 +76,16 @@ dir bin
REM Create Zip Archive
%PROJECT_ROOT%\vc\zip -X -9 -r %PROJECT_ROOT%\vc\%ZIP_FILENAME% bin
@if ERRORLEVEL 1 goto end
if %ERRORLEVEL% NEQ 0 EXIT /B 1
cd %PROJECT_ROOT%\output
%PROJECT_ROOT%\vc\zip -X -9 -u -r %PROJECT_ROOT%\vc\%ZIP_FILENAME% palettes luaScripts tools
@if ERRORLEVEL 1 goto end
if %ERRORLEVEL% NEQ 0 EXIT /B 1
mkdir doc
copy *.chm doc\.
%PROJECT_ROOT%\vc\zip -X -9 -u -r %PROJECT_ROOT%\vc\%ZIP_FILENAME% doc
@if ERRORLEVEL 1 goto end
if %ERRORLEVEL% NEQ 0 EXIT /B 1
cd %PROJECT_ROOT%

View File

@ -10,14 +10,14 @@ set DEPLOY_GROUP=master
IF DEFINED APPVEYOR_REPO_TAG_NAME set DEPLOY_GROUP=%APPVEYOR_REPO_TAG_NAME%
msbuild %PROJECT_ROOT%\vc\vc14_fceux.vcxproj /p:Configuration=%BUILD_CONFIG% /p:Platform="Win32"
@if ERRORLEVEL 1 goto end
if %ERRORLEVEL% NEQ 0 EXIT /B 1
cd %PROJECT_ROOT%\vc
REM Create Zip Archive
cd %PROJECT_ROOT%\output
..\vc\zip -X -9 -r ..\vc\%ZIP_FILENAME% fceux.exe fceux.chm taseditor.chm lua5.1.dll lua51.dll 7z.dll auxlib.lua palettes luaScripts tools
@if ERRORLEVEL 1 goto end
if %ERRORLEVEL% NEQ 0 EXIT /B 1
cd %PROJECT_ROOT%

View File

@ -10,7 +10,7 @@ set DEPLOY_GROUP=master
IF DEFINED APPVEYOR_REPO_TAG_NAME set DEPLOY_GROUP=%APPVEYOR_REPO_TAG_NAME%
msbuild %PROJECT_ROOT%\vc\vc14_fceux.vcxproj /p:Configuration=%BUILD_CONFIG% /p:Platform="x64"
@if ERRORLEVEL 1 goto end
if %ERRORLEVEL% NEQ 0 EXIT /B 1
cd %PROJECT_ROOT%\vc
@ -18,9 +18,9 @@ REM Create Zip Archive
cd %PROJECT_ROOT%\output
..\vc\zip -X -9 -j ..\vc\%ZIP_FILENAME% ..\vc\x64\%BUILD_CONFIG%\fceux64.exe ..\src\drivers\win\lua\x64\lua5.1.dll ..\src\drivers\win\lua\x64\lua51.dll ..\src\auxlib.lua ..\src\drivers\win\7z_64.dll
@if ERRORLEVEL 1 goto end
if %ERRORLEVEL% NEQ 0 EXIT /B 1
..\vc\zip -X -9 -u -r ..\vc\%ZIP_FILENAME% fceux.chm taseditor.chm palettes luaScripts tools
@if ERRORLEVEL 1 goto end
if %ERRORLEVEL% NEQ 0 EXIT /B 1
cd %PROJECT_ROOT%

View File

@ -5,11 +5,11 @@ An open source NES Emulator for Windows and Unix that features solid emulation a
## Builds and Releases
Interim builds:
* Win32: [fceux.zip](https://ci.appveyor.com/api/projects/zeromus/fceux/artifacts/fceux.zip?branch=master&job=Windows%2032)
* Win64: [fceux64.zip](https://ci.appveyor.com/api/projects/zeromus/fceux/artifacts/fceux64.zip?branch=master&job=Windows%2064)
* Win64 Qt/SDL: [qfceux64.zip](https://ci.appveyor.com/api/projects/zeromus/fceux/artifacts/qfceux64.zip?branch=master&job=Win64%20Qt)
* Ubuntu: [fceux-2.6.4-amd64.deb](https://ci.appveyor.com/api/projects/zeromus/fceux/artifacts/fceux-2.6.4-amd64.deb?branch=master&job=Ubuntu)
* MacOSX: [fceux-2.6.4-Darwin.dmg](https://ci.appveyor.com/api/projects/zeromus/fceux/artifacts/fceux-2.6.4-Darwin.dmg?branch=master&job=MacOS)
* Win32: [fceux-win32.zip](https://github.com/TASEmulators/fceux/releases/download/interim-build/fceux-win32.zip)
* Win64: [fceux-win64.zip](https://github.com/TASEmulators/fceux/releases/download/interim-build/fceux-win64.zip)
* Win64 Qt/SDL: [fceux-win64-QtSDL.zip](https://github.com/TASEmulators/fceux/releases/download/interim-build/fceux-win64-QtSDL.zip)
* Ubuntu: [fceux-ubuntu-x64.deb](https://github.com/TASEmulators/fceux/releases/download/interim-build/fceux-ubuntu-x64.deb)
* MacOSX: [fceux-Darwin.dmg](https://github.com/TASEmulators/fceux/releases/download/interim-build/fceux-Darwin.dmg)
* Status: [Appveyor](https://ci.appveyor.com/project/zeromus/fceux/)
But you might like mesen more: https://github.com/SourMesen/Mesen
@ -18,4 +18,4 @@ You should get releases from here: https://sourceforge.net/projects/fceultra/fil
That's because github forces us to use tags we don't have for releases.
2.6.4 is the most recent release but most people are using the autobuilds.
2.6.6 is the most recent release but most people are using the autobuilds.

25
scripts/linux_debug.pl Executable file
View File

@ -0,0 +1,25 @@
#!/usr/bin/perl
use strict;
my $i; my $findResult;
my $exe = "fceux";
$findResult = `find . -name fceux`;
if ( $findResult ne "")
{
$findResult =~ s/\n.*//;
$exe=$findResult;
}
print "Executable: $exe\n";
my $gdbCmdFile = "/tmp/gdbCmdFile";
open CMD_FILE, ">$gdbCmdFile" or die "Error: Could not open file: $gdbCmdFile\n";
print CMD_FILE "run\n";
print CMD_FILE "list\n";
print CMD_FILE "backtrace\n";
close(CMD_FILE);
system("gdb -x $gdbCmdFile $exe");

16
scripts/runCppCheck.sh Executable file
View File

@ -0,0 +1,16 @@
#!/bin/bash
PROJECT_ROOT=$( cd "$(dirname ${BASH_SOURCE[0]})"/.. && pwd )
echo $PROJECT_ROOT;
SRC_DIR=$PROJECT_ROOT/src
cd $SRC_DIR;
cppcheck --version
IGNORE_DIRS=" -i ./attic "
IGNORE_DIRS+="-i ./drivers/sdl "
#IGNORE_DIRS+="-i ./drivers/win "
cppcheck --force $IGNORE_DIRS .

View File

@ -10,28 +10,113 @@ if (${PUBLIC_RELEASE})
endif()
if ( ${QT6} )
set( QT 6 )
endif()
if (NOT DEFINED QT)
message( STATUS "Attempting to determine Qt Version...")
find_package( Qt6 COMPONENTS Core QUIET)
if (${Qt6Core_FOUND})
message( STATUS "Found Qt Version: ${Qt6Core_VERSION}")
set( QT 6 )
else()
find_package( Qt5 COMPONENTS Core QUIET)
if (${Qt5Core_FOUND})
message( STATUS "Found Qt Version: ${Qt5Core_VERSION}")
set( QT 5 )
endif()
endif()
endif()
if ( ${FCEU_PROFILER_ENABLE} )
message( STATUS "FCEU Profiler Enabled")
add_definitions( -D__FCEU_PROFILER_ENABLE__ )
endif()
if ( ${QT} EQUAL 6 )
message( STATUS "GUI Frontend: Qt6")
set( Qt Qt6 )
find_package( Qt6 REQUIRED COMPONENTS Widgets OpenGL OpenGLWidgets)
find_package( Qt6 REQUIRED COMPONENTS Network)
find_package( Qt6 COMPONENTS Help QUIET)
find_package( Qt6 COMPONENTS Qml)
find_package( Qt6 COMPONENTS UiTools)
add_definitions( ${Qt6Widgets_DEFINITIONS} ${Qt6Qml_DEFINITIONS} ${Qt6Network_DEFINITIONS} ${Qt6Help_DEFINITIONS} ${Qt6OpenGLWidgets_DEFINITIONS} )
# add_definitions(${Qt6UiTools_DEFINITIONS}) # Leave ${Qt6UiTools_DEFINITIONS} out as this is causing a build error
include_directories( ${Qt6Widgets_INCLUDE_DIRS} ${Qt6Qml_INCLUDE_DIRS} ${Qt6UiTools_INCLUDE_DIRS} ${Qt6Network_INCLUDE_DIRS} ${Qt6Help_INCLUDE_DIRS} ${Qt6OpenGLWidgets_INCLUDE_DIRS} )
if (${Qt6Help_FOUND})
message( STATUS "Qt6 Help Module Found")
if (${QHELP})
add_definitions( -D_USE_QHELP )
endif()
else()
message( STATUS "Qt6 Help Module Not Found")
endif()
if (${Qt6Network_FOUND})
message( STATUS "Qt6 Network Module Found")
add_definitions( -D__FCEU_QNETWORK_ENABLE__ )
else()
message( STATUS "Qt6 Network Module Not Found")
endif()
if (${Qt6Qml_FOUND})
message( STATUS "Qt6 Qml Module Found")
add_definitions( -D__FCEU_QSCRIPT_ENABLE__ )
else()
message( STATUS "Qt6 Qml Module Not Found")
endif()
if (${Qt6UiTools_FOUND})
message( STATUS "Qt6 UiTools Module Found")
add_definitions( -D__QT_UI_TOOLS__ )
else()
message( STATUS "Qt6 UiTools Module Not Found")
endif()
else()
message( STATUS "GUI Frontend: Qt5")
set( Qt Qt5 )
endif()
find_package( Qt5 REQUIRED COMPONENTS Widgets OpenGL)
find_package( Qt5 COMPONENTS Help QUIET)
find_package( Qt5 COMPONENTS Network)
find_package( Qt5 COMPONENTS Qml)
find_package( Qt5 COMPONENTS UiTools)
add_definitions( ${Qt5Widgets_DEFINITIONS} ${Qt5Qml_DEFINITIONS} ${Qt5UiTools_DEFINITIONS} ${Qt5Network_DEFINITIONS} ${Qt5Help_DEFINITIONS} )
include_directories( ${Qt5Widgets_INCLUDE_DIRS} ${Qt5Qml_INCLUDE_DIRS} ${Qt5UiTools_INCLUDE_DIRS} ${Qt5Network_INCLUDE_DIRS} ${Qt5Help_INCLUDE_DIRS} )
if ( ${QHELP} )
set(QtHelpModule Help)
add_definitions( -D_USE_QHELP )
endif()
if (${Qt5Help_FOUND})
message( STATUS "Qt5 Help Module Found")
if (${QHELP})
add_definitions( -D_USE_QHELP )
endif()
else()
message( STATUS "Qt5 Help Module Not Found")
endif()
if ( ${QT6} )
find_package( Qt6 REQUIRED COMPONENTS Widgets OpenGL OpenGLWidgets ${QtHelpModule})
add_definitions( ${Qt6Widgets_DEFINITIONS} ${Qt6Help_DEFINITIONS} ${Qt6OpenGLWidgets_DEFINITIONS} )
include_directories( ${Qt6Widgets_INCLUDE_DIRS} ${Qt6Help_INCLUDE_DIRS} ${Qt6OpenGLWidgets_INCLUDE_DIRS} )
else()
find_package( Qt5 REQUIRED COMPONENTS Widgets OpenGL ${QtHelpModule})
add_definitions( ${Qt5Widgets_DEFINITIONS} ${Qt5Help_DEFINITIONS} )
include_directories( ${Qt5Widgets_INCLUDE_DIRS} ${Qt5Help_INCLUDE_DIRS} )
endif()
if (${Qt5Network_FOUND})
message( STATUS "Qt5 Network Module Found")
add_definitions( -D__FCEU_NETWORK_ENABLE__ )
else()
message( STATUS "Qt5 Network Module Not Found")
endif()
if (${Qt5Qml_FOUND})
message( STATUS "Qt5 Qml Module Found")
add_definitions( -D__FCEU_QSCRIPT_ENABLE__ )
else()
message( STATUS "Qt5 Qml Module Not Found")
endif()
if (${Qt5UiTools_FOUND})
message( STATUS "Qt5 UiTools Module Found")
add_definitions( -D__QT_UI_TOOLS__ )
else()
message( STATUS "Qt5 UiTools Module Not Found")
endif()
endif()
if(WIN32)
find_package(OpenGL REQUIRED)
@ -41,10 +126,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 )
@ -76,7 +166,8 @@ else(WIN32)
find_package(OpenGL REQUIRED)
find_package(ZLIB REQUIRED)
add_definitions( -Wall -Wno-write-strings -Wno-sign-compare -Wno-parentheses -Wno-unused-local-typedefs -fPIC )
add_definitions( -Wall -Wno-write-strings -Wno-parentheses -Wno-unused-local-typedefs -fPIC )
#add_definitions( -Wno-sign-compare ) # Integer comparison sign mismatch warnings
add_definitions( -DFCEUDEF_DEBUGGER )
#if ( ${QT6} )
@ -90,6 +181,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 )
@ -107,6 +204,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} )
@ -260,14 +364,6 @@ endif()
include_directories( ${CMAKE_SOURCE_DIR}/src )
include_directories( ${CMAKE_SOURCE_DIR}/src/drivers )
if(APPLE)
add_definitions( -DPSS_STYLE=1 )
else(APPLE)
if(UNIX)
add_definitions( -DPSS_STYLE=1 )
endif(UNIX)
endif(APPLE)
set(SRC_CORE
${CMAKE_CURRENT_SOURCE_DIR}/asm.cpp
${CMAKE_CURRENT_SOURCE_DIR}/cart.cpp
@ -275,6 +371,7 @@ set(SRC_CORE
${CMAKE_CURRENT_SOURCE_DIR}/conddebug.cpp
${CMAKE_CURRENT_SOURCE_DIR}/config.cpp
${CMAKE_CURRENT_SOURCE_DIR}/debug.cpp
${CMAKE_CURRENT_SOURCE_DIR}/debugsymboltable.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drawing.cpp
${CMAKE_CURRENT_SOURCE_DIR}/fceu.cpp
${CMAKE_CURRENT_SOURCE_DIR}/fds.cpp
@ -283,11 +380,13 @@ set(SRC_CORE
${CMAKE_CURRENT_SOURCE_DIR}/filter.cpp
${CMAKE_CURRENT_SOURCE_DIR}/ines.cpp
${CMAKE_CURRENT_SOURCE_DIR}/input.cpp
${CMAKE_CURRENT_SOURCE_DIR}/ld65dbg.cpp
${CMAKE_CURRENT_SOURCE_DIR}/movie.cpp
${CMAKE_CURRENT_SOURCE_DIR}/netplay.cpp
${CMAKE_CURRENT_SOURCE_DIR}/nsf.cpp
${CMAKE_CURRENT_SOURCE_DIR}/oldmovie.cpp
${CMAKE_CURRENT_SOURCE_DIR}/palette.cpp
${CMAKE_CURRENT_SOURCE_DIR}/profiler.cpp
${CMAKE_CURRENT_SOURCE_DIR}/ppu.cpp
${CMAKE_CURRENT_SOURCE_DIR}/sound.cpp
${CMAKE_CURRENT_SOURCE_DIR}/state.cpp
@ -309,7 +408,6 @@ set(SRC_CORE
${CMAKE_CURRENT_SOURCE_DIR}/boards/120.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/121.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/12in1.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/151.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/156.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/158B.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/15.cpp
@ -346,7 +444,11 @@ set(SRC_CORE
${CMAKE_CURRENT_SOURCE_DIR}/boards/32.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/33.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/34.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/36.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/354.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/413.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/471.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/451.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/36.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/3d-block.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/40.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/411120-c.cpp
@ -396,6 +498,7 @@ set(SRC_CORE
${CMAKE_CURRENT_SOURCE_DIR}/boards/cheapocabra.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/cityfighter.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/coolboy.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/coolgirl.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/dance2000.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/datalatch.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/dream.cpp
@ -467,6 +570,7 @@ set(SRC_CORE
${CMAKE_CURRENT_SOURCE_DIR}/boards/vrc7.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/vrc7p.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/yoko.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/inx007t.cpp
${CMAKE_CURRENT_SOURCE_DIR}/input/arkanoid.cpp
${CMAKE_CURRENT_SOURCE_DIR}/input/bworld.cpp
${CMAKE_CURRENT_SOURCE_DIR}/input/cursor.cpp
@ -495,13 +599,14 @@ set(SRC_CORE
${CMAKE_CURRENT_SOURCE_DIR}/utils/guid.cpp
${CMAKE_CURRENT_SOURCE_DIR}/utils/md5.cpp
${CMAKE_CURRENT_SOURCE_DIR}/utils/memory.cpp
${CMAKE_CURRENT_SOURCE_DIR}/utils/mutex.cpp
${CMAKE_CURRENT_SOURCE_DIR}/utils/timeStamp.cpp
)
set(SRC_DRIVERS_COMMON
${CMAKE_CURRENT_SOURCE_DIR}/drivers/common/args.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/common/cheat.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/common/config.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/common/configSys.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/common/hq2x.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/common/hq3x.cpp
@ -518,6 +623,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
@ -543,7 +650,9 @@ 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/QtScriptManager.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/SplashScreen.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/TraceLogger.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/AboutWindow.cpp
@ -561,6 +670,7 @@ set(SRC_DRIVERS_SDL
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/sdl-joystick.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/sdl-throttle.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/unix-netplay.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/NetPlay.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/AviRecord.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/AviRiffViewer.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/avi/avi-utils.cpp
@ -627,14 +737,18 @@ 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}Qml_LIBRARIES}
${${Qt}UiTools_LIBRARIES}
${${Qt}Network_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}
)

View File

@ -3,6 +3,7 @@
#include "types.h"
#include "utils/xstring.h"
#include "utils/StringBuilder.h"
#include "debug.h"
#include "asm.h"
#include "x6502.h"
@ -256,8 +257,11 @@ int Assemble(unsigned char *output, int addr, char *str) {
///disassembles the opcodes in the buffer assuming the provided address. Uses GetMem() and 6502 current registers to query referenced values. returns a static string buffer.
char *Disassemble(int addr, uint8 *opcode) {
static char str[64]={0},chr[5]={0};
static char str[64]={0};
const char *chr;
char indReg;
uint16 tmp,tmp2;
StringBuilder sb(str);
//these may be replaced later with passed-in values to make a lighter-weight disassembly mode that may not query the referenced values
#define RX (X.X)
@ -286,7 +290,7 @@ char *Disassemble(int addr, uint8 *opcode) {
#ifdef BRK_3BYTE_HACK
case 0x00:
sprintf(str,"BRK %02X %02X", opcode[1], opcode[2]);
sb << "BRK " << sb_hex(opcode[1], 2) << ' ' << sb_hex(opcode[2], 2);
break;
#else
case 0x00: strcpy(str,"BRK"); break;
@ -323,207 +327,226 @@ char *Disassemble(int addr, uint8 *opcode) {
case 0xF8: strcpy(str,"SED"); break;
//(Indirect,X)
case 0x01: strcpy(chr,"ORA"); goto _indirectx;
case 0x21: strcpy(chr,"AND"); goto _indirectx;
case 0x41: strcpy(chr,"EOR"); goto _indirectx;
case 0x61: strcpy(chr,"ADC"); goto _indirectx;
case 0x81: strcpy(chr,"STA"); goto _indirectx;
case 0xA1: strcpy(chr,"LDA"); goto _indirectx;
case 0xC1: strcpy(chr,"CMP"); goto _indirectx;
case 0xE1: strcpy(chr,"SBC"); goto _indirectx;
case 0x01: chr = "ORA"; goto _indirectx;
case 0x21: chr = "AND"; goto _indirectx;
case 0x41: chr = "EOR"; goto _indirectx;
case 0x61: chr = "ADC"; goto _indirectx;
case 0x81: chr = "STA"; goto _indirectx;
case 0xA1: chr = "LDA"; goto _indirectx;
case 0xC1: chr = "CMP"; goto _indirectx;
case 0xE1: chr = "SBC"; goto _indirectx;
_indirectx:
indirectX(tmp);
sprintf(str,"%s ($%02X,X) @ $%04X = #$%02X", chr,opcode[1],tmp,GetMem(tmp));
sb << chr << " (" << sb_addr(opcode[1], 2) << ",X) @ " << sb_addr(tmp) << " = " << sb_lit(GetMem(tmp));
break;
//Zero Page
case 0x05: strcpy(chr,"ORA"); goto _zeropage;
case 0x06: strcpy(chr,"ASL"); goto _zeropage;
case 0x24: strcpy(chr,"BIT"); goto _zeropage;
case 0x25: strcpy(chr,"AND"); goto _zeropage;
case 0x26: strcpy(chr,"ROL"); goto _zeropage;
case 0x45: strcpy(chr,"EOR"); goto _zeropage;
case 0x46: strcpy(chr,"LSR"); goto _zeropage;
case 0x65: strcpy(chr,"ADC"); goto _zeropage;
case 0x66: strcpy(chr,"ROR"); goto _zeropage;
case 0x84: strcpy(chr,"STY"); goto _zeropage;
case 0x85: strcpy(chr,"STA"); goto _zeropage;
case 0x86: strcpy(chr,"STX"); goto _zeropage;
case 0xA4: strcpy(chr,"LDY"); goto _zeropage;
case 0xA5: strcpy(chr,"LDA"); goto _zeropage;
case 0xA6: strcpy(chr,"LDX"); goto _zeropage;
case 0xC4: strcpy(chr,"CPY"); goto _zeropage;
case 0xC5: strcpy(chr,"CMP"); goto _zeropage;
case 0xC6: strcpy(chr,"DEC"); goto _zeropage;
case 0xE4: strcpy(chr,"CPX"); goto _zeropage;
case 0xE5: strcpy(chr,"SBC"); goto _zeropage;
case 0xE6: strcpy(chr,"INC"); goto _zeropage;
case 0x05: chr = "ORA"; goto _zeropage;
case 0x06: chr = "ASL"; goto _zeropage;
case 0x24: chr = "BIT"; goto _zeropage;
case 0x25: chr = "AND"; goto _zeropage;
case 0x26: chr = "ROL"; goto _zeropage;
case 0x45: chr = "EOR"; goto _zeropage;
case 0x46: chr = "LSR"; goto _zeropage;
case 0x65: chr = "ADC"; goto _zeropage;
case 0x66: chr = "ROR"; goto _zeropage;
case 0x84: chr = "STY"; goto _zeropage;
case 0x85: chr = "STA"; goto _zeropage;
case 0x86: chr = "STX"; goto _zeropage;
case 0xA4: chr = "LDY"; goto _zeropage;
case 0xA5: chr = "LDA"; goto _zeropage;
case 0xA6: chr = "LDX"; goto _zeropage;
case 0xC4: chr = "CPY"; goto _zeropage;
case 0xC5: chr = "CMP"; goto _zeropage;
case 0xC6: chr = "DEC"; goto _zeropage;
case 0xE4: chr = "CPX"; goto _zeropage;
case 0xE5: chr = "SBC"; goto _zeropage;
case 0xE6: chr = "INC"; goto _zeropage;
_zeropage:
// ################################## Start of SP CODE ###########################
// Change width to %04X // don't!
sprintf(str,"%s $%02X = #$%02X", chr,opcode[1],GetMem(opcode[1]));
sb << chr << ' ' << sb_addr(opcode[1], 2) << " = " << sb_lit(GetMem(opcode[1]));
// ################################## End of SP CODE ###########################
break;
//#Immediate
case 0x09: strcpy(chr,"ORA"); goto _immediate;
case 0x29: strcpy(chr,"AND"); goto _immediate;
case 0x49: strcpy(chr,"EOR"); goto _immediate;
case 0x69: strcpy(chr,"ADC"); goto _immediate;
//case 0x89: strcpy(chr,"STA"); goto _immediate; //baka, no STA #imm!!
case 0xA0: strcpy(chr,"LDY"); goto _immediate;
case 0xA2: strcpy(chr,"LDX"); goto _immediate;
case 0xA9: strcpy(chr,"LDA"); goto _immediate;
case 0xC0: strcpy(chr,"CPY"); goto _immediate;
case 0xC9: strcpy(chr,"CMP"); goto _immediate;
case 0xE0: strcpy(chr,"CPX"); goto _immediate;
case 0xE9: strcpy(chr,"SBC"); goto _immediate;
case 0x09: chr = "ORA"; goto _immediate;
case 0x29: chr = "AND"; goto _immediate;
case 0x49: chr = "EOR"; goto _immediate;
case 0x69: chr = "ADC"; goto _immediate;
//case 0x89: chr = "STA"; goto _immediate; //baka, no STA #imm!!
case 0xA0: chr = "LDY"; goto _immediate;
case 0xA2: chr = "LDX"; goto _immediate;
case 0xA9: chr = "LDA"; goto _immediate;
case 0xC0: chr = "CPY"; goto _immediate;
case 0xC9: chr = "CMP"; goto _immediate;
case 0xE0: chr = "CPX"; goto _immediate;
case 0xE9: chr = "SBC"; goto _immediate;
_immediate:
sprintf(str,"%s #$%02X", chr,opcode[1]);
sb << chr << ' ' << sb_lit(opcode[1]);
break;
//Absolute
case 0x0D: strcpy(chr,"ORA"); goto _absolute;
case 0x0E: strcpy(chr,"ASL"); goto _absolute;
case 0x2C: strcpy(chr,"BIT"); goto _absolute;
case 0x2D: strcpy(chr,"AND"); goto _absolute;
case 0x2E: strcpy(chr,"ROL"); goto _absolute;
case 0x4D: strcpy(chr,"EOR"); goto _absolute;
case 0x4E: strcpy(chr,"LSR"); goto _absolute;
case 0x6D: strcpy(chr,"ADC"); goto _absolute;
case 0x6E: strcpy(chr,"ROR"); goto _absolute;
case 0x8C: strcpy(chr,"STY"); goto _absolute;
case 0x8D: strcpy(chr,"STA"); goto _absolute;
case 0x8E: strcpy(chr,"STX"); goto _absolute;
case 0xAC: strcpy(chr,"LDY"); goto _absolute;
case 0xAD: strcpy(chr,"LDA"); goto _absolute;
case 0xAE: strcpy(chr,"LDX"); goto _absolute;
case 0xCC: strcpy(chr,"CPY"); goto _absolute;
case 0xCD: strcpy(chr,"CMP"); goto _absolute;
case 0xCE: strcpy(chr,"DEC"); goto _absolute;
case 0xEC: strcpy(chr,"CPX"); goto _absolute;
case 0xED: strcpy(chr,"SBC"); goto _absolute;
case 0xEE: strcpy(chr,"INC"); goto _absolute;
case 0x0D: chr = "ORA"; goto _absolute;
case 0x0E: chr = "ASL"; goto _absolute;
case 0x2C: chr = "BIT"; goto _absolute;
case 0x2D: chr = "AND"; goto _absolute;
case 0x2E: chr = "ROL"; goto _absolute;
case 0x4D: chr = "EOR"; goto _absolute;
case 0x4E: chr = "LSR"; goto _absolute;
case 0x6D: chr = "ADC"; goto _absolute;
case 0x6E: chr = "ROR"; goto _absolute;
case 0x8C: chr = "STY"; goto _absolute;
case 0x8D: chr = "STA"; goto _absolute;
case 0x8E: chr = "STX"; goto _absolute;
case 0xAC: chr = "LDY"; goto _absolute;
case 0xAD: chr = "LDA"; goto _absolute;
case 0xAE: chr = "LDX"; goto _absolute;
case 0xCC: chr = "CPY"; goto _absolute;
case 0xCD: chr = "CMP"; goto _absolute;
case 0xCE: chr = "DEC"; goto _absolute;
case 0xEC: chr = "CPX"; goto _absolute;
case 0xED: chr = "SBC"; goto _absolute;
case 0xEE: chr = "INC"; goto _absolute;
_absolute:
absolute(tmp);
sprintf(str,"%s $%04X = #$%02X", chr,tmp,GetMem(tmp));
sb << chr << ' ' << sb_addr(tmp) << " = " << sb_lit(GetMem(tmp));
break;
//branches
case 0x10: strcpy(chr,"BPL"); goto _branch;
case 0x30: strcpy(chr,"BMI"); goto _branch;
case 0x50: strcpy(chr,"BVC"); goto _branch;
case 0x70: strcpy(chr,"BVS"); goto _branch;
case 0x90: strcpy(chr,"BCC"); goto _branch;
case 0xB0: strcpy(chr,"BCS"); goto _branch;
case 0xD0: strcpy(chr,"BNE"); goto _branch;
case 0xF0: strcpy(chr,"BEQ"); goto _branch;
case 0x10: chr = "BPL"; goto _branch;
case 0x30: chr = "BMI"; goto _branch;
case 0x50: chr = "BVC"; goto _branch;
case 0x70: chr = "BVS"; goto _branch;
case 0x90: chr = "BCC"; goto _branch;
case 0xB0: chr = "BCS"; goto _branch;
case 0xD0: chr = "BNE"; goto _branch;
case 0xF0: chr = "BEQ"; goto _branch;
_branch:
relative(tmp);
sprintf(str,"%s $%04X", chr,tmp);
sb << chr << ' ' << sb_addr(tmp);
break;
//(Indirect),Y
case 0x11: strcpy(chr,"ORA"); goto _indirecty;
case 0x31: strcpy(chr,"AND"); goto _indirecty;
case 0x51: strcpy(chr,"EOR"); goto _indirecty;
case 0x71: strcpy(chr,"ADC"); goto _indirecty;
case 0x91: strcpy(chr,"STA"); goto _indirecty;
case 0xB1: strcpy(chr,"LDA"); goto _indirecty;
case 0xD1: strcpy(chr,"CMP"); goto _indirecty;
case 0xF1: strcpy(chr,"SBC"); goto _indirecty;
case 0x11: chr = "ORA"; goto _indirecty;
case 0x31: chr = "AND"; goto _indirecty;
case 0x51: chr = "EOR"; goto _indirecty;
case 0x71: chr = "ADC"; goto _indirecty;
case 0x91: chr = "STA"; goto _indirecty;
case 0xB1: chr = "LDA"; goto _indirecty;
case 0xD1: chr = "CMP"; goto _indirecty;
case 0xF1: chr = "SBC"; goto _indirecty;
_indirecty:
indirectY(tmp);
sprintf(str,"%s ($%02X),Y @ $%04X = #$%02X", chr,opcode[1],tmp,GetMem(tmp));
sb << chr << " (" << sb_addr(opcode[1], 2) << "),Y @ " << sb_addr(tmp) << " = " << sb_lit(GetMem(tmp));
break;
//Zero Page,X
case 0x15: strcpy(chr,"ORA"); goto _zeropagex;
case 0x16: strcpy(chr,"ASL"); goto _zeropagex;
case 0x35: strcpy(chr,"AND"); goto _zeropagex;
case 0x36: strcpy(chr,"ROL"); goto _zeropagex;
case 0x55: strcpy(chr,"EOR"); goto _zeropagex;
case 0x56: strcpy(chr,"LSR"); goto _zeropagex;
case 0x75: strcpy(chr,"ADC"); goto _zeropagex;
case 0x76: strcpy(chr,"ROR"); goto _zeropagex;
case 0x94: strcpy(chr,"STY"); goto _zeropagex;
case 0x95: strcpy(chr,"STA"); goto _zeropagex;
case 0xB4: strcpy(chr,"LDY"); goto _zeropagex;
case 0xB5: strcpy(chr,"LDA"); goto _zeropagex;
case 0xD5: strcpy(chr,"CMP"); goto _zeropagex;
case 0xD6: strcpy(chr,"DEC"); goto _zeropagex;
case 0xF5: strcpy(chr,"SBC"); goto _zeropagex;
case 0xF6: strcpy(chr,"INC"); goto _zeropagex;
case 0x15: chr = "ORA"; goto _zeropagex;
case 0x16: chr = "ASL"; goto _zeropagex;
case 0x35: chr = "AND"; goto _zeropagex;
case 0x36: chr = "ROL"; goto _zeropagex;
case 0x55: chr = "EOR"; goto _zeropagex;
case 0x56: chr = "LSR"; goto _zeropagex;
case 0x75: chr = "ADC"; goto _zeropagex;
case 0x76: chr = "ROR"; goto _zeropagex;
case 0x94: chr = "STY"; goto _zeropagex;
case 0x95: chr = "STA"; goto _zeropagex;
case 0xB4: chr = "LDY"; goto _zeropagex;
case 0xB5: chr = "LDA"; goto _zeropagex;
case 0xD5: chr = "CMP"; goto _zeropagex;
case 0xD6: chr = "DEC"; goto _zeropagex;
case 0xF5: chr = "SBC"; goto _zeropagex;
case 0xF6: chr = "INC"; goto _zeropagex;
_zeropagex:
zpIndex(tmp,RX);
zpIndex(tmp, RX);
indReg = 'X';
_indexed:
// ################################## Start of SP CODE ###########################
// Change width to %04X // don't!
sprintf(str,"%s $%02X,X @ $%04X = #$%02X", chr,opcode[1],tmp,GetMem(tmp));
sb << chr << ' ' << sb_addr(opcode[1], 2) << ',' << indReg << " @ " << sb_addr(tmp) << " = " << sb_lit(GetMem(tmp));
// ################################## End of SP CODE ###########################
break;
//Absolute,Y
case 0x19: strcpy(chr,"ORA"); goto _absolutey;
case 0x39: strcpy(chr,"AND"); goto _absolutey;
case 0x59: strcpy(chr,"EOR"); goto _absolutey;
case 0x79: strcpy(chr,"ADC"); goto _absolutey;
case 0x99: strcpy(chr,"STA"); goto _absolutey;
case 0xB9: strcpy(chr,"LDA"); goto _absolutey;
case 0xBE: strcpy(chr,"LDX"); goto _absolutey;
case 0xD9: strcpy(chr,"CMP"); goto _absolutey;
case 0xF9: strcpy(chr,"SBC"); goto _absolutey;
case 0x19: chr = "ORA"; goto _absolutey;
case 0x39: chr = "AND"; goto _absolutey;
case 0x59: chr = "EOR"; goto _absolutey;
case 0x79: chr = "ADC"; goto _absolutey;
case 0x99: chr = "STA"; goto _absolutey;
case 0xB9: chr = "LDA"; goto _absolutey;
case 0xBE: chr = "LDX"; goto _absolutey;
case 0xD9: chr = "CMP"; goto _absolutey;
case 0xF9: chr = "SBC"; goto _absolutey;
_absolutey:
absolute(tmp);
tmp2=(tmp+RY);
sprintf(str,"%s $%04X,Y @ $%04X = #$%02X", chr,tmp,tmp2,GetMem(tmp2));
tmp2 = (tmp + RY);
indReg = 'Y';
_absindexed:
sb << chr << ' ' << sb_addr(tmp) << ',' << indReg << " @ " << sb_addr(tmp2) << " = " << sb_lit(GetMem(tmp2));
break;
//Absolute,X
case 0x1D: strcpy(chr,"ORA"); goto _absolutex;
case 0x1E: strcpy(chr,"ASL"); goto _absolutex;
case 0x3D: strcpy(chr,"AND"); goto _absolutex;
case 0x3E: strcpy(chr,"ROL"); goto _absolutex;
case 0x5D: strcpy(chr,"EOR"); goto _absolutex;
case 0x5E: strcpy(chr,"LSR"); goto _absolutex;
case 0x7D: strcpy(chr,"ADC"); goto _absolutex;
case 0x7E: strcpy(chr,"ROR"); goto _absolutex;
case 0x9D: strcpy(chr,"STA"); goto _absolutex;
case 0xBC: strcpy(chr,"LDY"); goto _absolutex;
case 0xBD: strcpy(chr,"LDA"); goto _absolutex;
case 0xDD: strcpy(chr,"CMP"); goto _absolutex;
case 0xDE: strcpy(chr,"DEC"); goto _absolutex;
case 0xFD: strcpy(chr,"SBC"); goto _absolutex;
case 0xFE: strcpy(chr,"INC"); goto _absolutex;
case 0x1D: chr = "ORA"; goto _absolutex;
case 0x1E: chr = "ASL"; goto _absolutex;
case 0x3D: chr = "AND"; goto _absolutex;
case 0x3E: chr = "ROL"; goto _absolutex;
case 0x5D: chr = "EOR"; goto _absolutex;
case 0x5E: chr = "LSR"; goto _absolutex;
case 0x7D: chr = "ADC"; goto _absolutex;
case 0x7E: chr = "ROR"; goto _absolutex;
case 0x9D: chr = "STA"; goto _absolutex;
case 0xBC: chr = "LDY"; goto _absolutex;
case 0xBD: chr = "LDA"; goto _absolutex;
case 0xDD: chr = "CMP"; goto _absolutex;
case 0xDE: chr = "DEC"; goto _absolutex;
case 0xFD: chr = "SBC"; goto _absolutex;
case 0xFE: chr = "INC"; goto _absolutex;
_absolutex:
absolute(tmp);
tmp2=(tmp+RX);
sprintf(str,"%s $%04X,X @ $%04X = #$%02X", chr,tmp,tmp2,GetMem(tmp2));
break;
tmp2 = (tmp + RX);
indReg = 'X';
goto _absindexed;
//jumps
case 0x20: strcpy(chr,"JSR"); goto _jump;
case 0x4C: strcpy(chr,"JMP"); goto _jump;
case 0x6C: absolute(tmp); sprintf(str,"JMP ($%04X) = $%04X", tmp,GetMem(tmp)|GetMem(tmp+1)<<8); break;
case 0x20: chr = "JSR"; goto _jump;
case 0x4C: chr = "JMP"; goto _jump;
_jump:
absolute(tmp);
sprintf(str,"%s $%04X", chr,tmp);
sb << chr << ' ' << sb_addr(tmp);
break;
case 0x6C:
absolute(tmp);
sb << "JMP (" << sb_addr(tmp);
sb << ") = " << sb_addr(GetMem(tmp) | GetMem(tmp + 1) << 8);
break;
//Zero Page,Y
case 0x96: strcpy(chr,"STX"); goto _zeropagey;
case 0xB6: strcpy(chr,"LDX"); goto _zeropagey;
case 0x96: chr = "STX"; goto _zeropagey;
case 0xB6: chr = "LDX"; goto _zeropagey;
_zeropagey:
zpIndex(tmp,RY);
// ################################## Start of SP CODE ###########################
// Change width to %04X // don't!
sprintf(str,"%s $%02X,Y @ $%04X = #$%02X", chr,opcode[1],tmp,GetMem(tmp));
// ################################## End of SP CODE ###########################
break;
zpIndex(tmp, RY);
indReg = 'Y';
goto _indexed;
//UNDEFINED
default: strcpy(str,"ERROR"); break;
default: strcpy(str, "ERROR"); break;
}
return str;
}

View File

@ -48,7 +48,7 @@ static void M121CW(uint32 A, uint8 V) {
if (PRGsize[0] == CHRsize[0]) { // A9713 multigame extension hack!
setchr1(A, V | ((EXPREGS[3] & 0x80) << 1));
} else {
if ((A & 0x1000) == ((MMC3_cmd & 0x80) << 5))
if ((A & 0x1000) == static_cast<uint32>((MMC3_cmd & 0x80) << 5))
setchr1(A, V | 0x100);
else
setchr1(A, V);

View File

@ -24,7 +24,7 @@
static uint16 latchea;
static uint8 latched;
static uint8 *WRAM = NULL;
static uint32 WRAMSIZE;
static uint32 WRAMSIZE=0;
static SFORMAT StateRegs[] =
{
{ &latchea, 2, "AREG" },
@ -108,8 +108,7 @@ void Mapper15_Init(CartInfo *info) {
WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE);
SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1);
if (info->battery) {
info->SaveGame[0] = WRAM;
info->SaveGameLen[0] = WRAMSIZE;
info->addSaveGameBuf( WRAM, WRAMSIZE );
}
AddExState(WRAM, WRAMSIZE, 0, "WRAM");
AddExState(&StateRegs, ~0, 0, 0);

View File

@ -27,7 +27,7 @@
static uint8 laststrobe, trigger;
static uint8 reg[8];
static uint8 *WRAM = NULL;
static uint32 WRAMSIZE;
static uint32 WRAMSIZE=0;
static writefunc pcmwrite;
@ -123,8 +123,7 @@ void Mapper164_Init(CartInfo *info) {
AddExState(WRAM, WRAMSIZE, 0, "WRAM");
if (info->battery) {
info->SaveGame[0] = WRAM;
info->SaveGameLen[0] = WRAMSIZE;
info->addSaveGameBuf( WRAM, WRAMSIZE );
}
GameStateRestore = StateRestore;
@ -172,8 +171,7 @@ void Mapper163_Init(CartInfo *info) {
AddExState(WRAM, WRAMSIZE, 0, "WRAM");
if (info->battery) {
info->SaveGame[0] = WRAM;
info->SaveGameLen[0] = WRAMSIZE;
info->addSaveGameBuf( WRAM, WRAMSIZE );
}
GameStateRestore = StateRestore;
AddExState(&StateRegs, ~0, 0, 0);
@ -223,8 +221,7 @@ void UNLFS304_Init(CartInfo *info) {
AddExState(WRAM, WRAMSIZE, 0, "WRAM");
if (info->battery) {
info->SaveGame[0] = WRAM;
info->SaveGameLen[0] = WRAMSIZE;
info->addSaveGameBuf( WRAM, WRAMSIZE );
}
GameStateRestore = StateRestore;

View File

@ -23,7 +23,7 @@
static uint8 reg;
static uint8 *WRAM = NULL;
static uint32 WRAMSIZE;
static uint32 WRAMSIZE=0;
static SFORMAT StateRegs[] =
{
@ -73,8 +73,7 @@ void Mapper177_Init(CartInfo *info) {
SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1);
AddExState(WRAM, WRAMSIZE, 0, "WRAM");
if (info->battery) {
info->SaveGame[0] = WRAM;
info->SaveGameLen[0] = WRAMSIZE;
info->addSaveGameBuf( WRAM, WRAMSIZE );
}
AddExState(&StateRegs, ~0, 0, 0);

View File

@ -27,7 +27,7 @@
static uint8 reg[4];
static uint8 *WRAM = NULL;
static uint32 WRAMSIZE;
static uint32 WRAMSIZE=0;
// Tennis with VR sensor, very simple behaviour
extern void GetMouseData(uint32 (&md)[3]);
@ -192,8 +192,7 @@ void Mapper178_Init(CartInfo *info) {
WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE);
SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1);
if (info->battery) {
info->SaveGame[0] = WRAM;
info->SaveGameLen[0] = WRAMSIZE;
info->addSaveGameBuf( WRAM, WRAMSIZE );
}
AddExState(WRAM, WRAMSIZE, 0, "WRAM");

View File

@ -16,6 +16,9 @@
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* The Moero!! Pro Yakyuu series have an ADPCM chip with internal ROM,
* used for voice samples (not dumped, so emulation isn't possible)
*/
#include "mapinc.h"
@ -24,7 +27,7 @@ static uint8 preg[4], creg[8];
static uint8 IRQa, mirr;
static int32 IRQCount, IRQLatch;
static uint8 *WRAM = NULL;
static uint32 WRAMSIZE;
static uint32 WRAMSIZE=0;
static SFORMAT StateRegs[] =
{
@ -125,8 +128,7 @@ void Mapper18_Init(CartInfo *info) {
SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1);
AddExState(WRAM, WRAMSIZE, 0, "WRAM");
if (info->battery) {
info->SaveGame[0] = WRAM;
info->SaveGameLen[0] = WRAMSIZE;
info->addSaveGameBuf( WRAM, WRAMSIZE );
}
AddExState(&StateRegs, ~0, 0, 0);

View File

@ -22,7 +22,7 @@
#include "mmc3.h"
static void M187CW(uint32 A, uint8 V) {
if ((A & 0x1000) == ((MMC3_cmd & 0x80) << 5))
if ((A & 0x1000) == static_cast<uint32>((MMC3_cmd & 0x80) << 5))
setchr1(A, V | 0x100);
else
setchr1(A, V);

View File

@ -1,30 +1,40 @@
/* FCE Ultra - NES/Famicom Emulator
*
* Copyright notice for this file:
* Copyright (C) 2011 CaH4e3
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
*
* Copyright notice for this file:
* Copyright (C) 2011 CaH4e3
* Copyright (C) 2019 Libretro Team
* Copyright (C) 2020
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* PCB-018 board, discrete multigame cart 110-in-1
*
* Mapper 225
* Mapper 255
*
*/
/* 2020-2-20 - merge mapper 255, re-implement extra RAM */
#include "mapinc.h"
static uint8 prot[4], prg, mode, chr, mirr;
static uint8 extraRAM[4], prg, mode, chr, mirr;
static SFORMAT StateRegs[] =
{
{ prot, 4, "PROT" },
{ extraRAM, 4, "PROT" },
{ &prg, 1, "PRG" },
{ &chr, 1, "CHR" },
{ &mode, 1, "MODE" },
@ -36,14 +46,15 @@ static void Sync(void) {
if (mode) {
setprg16(0x8000, prg);
setprg16(0xC000, prg);
} else
}
else
setprg32(0x8000, prg >> 1);
setchr8(chr);
setmirror(mirr ^ 1);
}
static DECLFW(M225Write) {
uint32 bank = (A >> 14) & 1;
uint8 bank = (A >> 14) & 1;
mirr = (A >> 13) & 1;
mode = (A >> 12) & 1;
chr = (A & 0x3f) | (bank << 6);
@ -52,35 +63,28 @@ static DECLFW(M225Write) {
}
static DECLFW(M225LoWrite) {
if (A & 0x800) {
prot[A & 0x03] = V;
}
/* e.g. 115-in-1 [p1][!] CRC32 0xb39d30b4 */
if (A & 0x800) extraRAM[A & 3] = V & 0x0F;
}
static DECLFR(M225LoRead) {
if (A & 0x800) {
return prot[A & 3] & 0x0F;
}
if (A & 0x800) return extraRAM[A & 3];
return X.DB;
}
static void M225Power(void) {
prg = 0;
chr = 0;
mode = 0;
mirr = 0;
Sync();
SetReadHandler(0x5000, 0x5FFF, M225LoRead);
SetWriteHandler(0x5000, 0x5FFF, M225LoWrite);
SetReadHandler(0x5000, 0x5fff, M225LoRead);
SetWriteHandler(0x5000, 0x5fff, M225LoWrite);
SetReadHandler(0x8000, 0xFFFF, CartBR);
SetWriteHandler(0x8000, 0xFFFF, M225Write);
}
static void M225Reset(void) {
prg = 0;
chr = 0;
mode = 0;
mirr = 0;
Sync();
}
@ -94,3 +98,7 @@ void Mapper225_Init(CartInfo *info) {
GameStateRestore = StateRestore;
AddExState(&StateRegs, ~0, 0, 0);
}
void Mapper255_Init(CartInfo *info) {
Mapper225_Init(info);
}

View File

@ -22,7 +22,7 @@
static uint8 regs[8];
static uint8 *WRAM = NULL;
static uint32 WRAMSIZE;
static uint32 WRAMSIZE = 0;
static SFORMAT StateRegs[] =
{
@ -79,8 +79,7 @@ void Mapper246_Init(CartInfo *info) {
AddExState(WRAM, WRAMSIZE, 0, "WRAM");
if (info->battery) {
info->SaveGame[0] = WRAM;
info->SaveGameLen[0] = WRAMSIZE;
info->addSaveGameBuf( WRAM, WRAMSIZE );
}
AddExState(&StateRegs, ~0, 0, 0);

View File

@ -23,9 +23,9 @@
static uint8 creg[8], preg[2];
static int32 IRQa, IRQCount, IRQClock, IRQLatch;
static uint8 *WRAM = NULL;
static uint32 WRAMSIZE;
static uint32 WRAMSIZE=0;
static uint8 *CHRRAM = NULL;
static uint32 CHRRAMSIZE;
static uint32 CHRRAMSIZE=0;
static SFORMAT StateRegs[] =
{
@ -127,8 +127,7 @@ void Mapper252_Init(CartInfo *info) {
SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1);
AddExState(WRAM, WRAMSIZE, 0, "WRAM");
if (info->battery) {
info->SaveGame[0] = WRAM;
info->SaveGameLen[0] = WRAMSIZE;
info->addSaveGameBuf( WRAM, WRAMSIZE );
}
GameStateRestore = StateRestore;
AddExState(&StateRegs, ~0, 0, 0);

View File

@ -23,9 +23,9 @@
static uint8 chrlo[8], chrhi[8], prg[2], mirr, vlock;
static int32 IRQa, IRQCount, IRQLatch, IRQClock;
static uint8 *WRAM = NULL;
static uint32 WRAMSIZE;
static uint32 WRAMSIZE=0;
static uint8 *CHRRAM = NULL;
static uint32 CHRRAMSIZE;
static uint32 CHRRAMSIZE=0;
static SFORMAT StateRegs[] =
{
@ -144,8 +144,7 @@ void Mapper253_Init(CartInfo *info) {
SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1);
AddExState(WRAM, WRAMSIZE, 0, "WRAM");
if (info->battery) {
info->SaveGame[0] = WRAM;
info->SaveGameLen[0] = WRAMSIZE;
info->addSaveGameBuf( WRAM, WRAMSIZE );
}
AddExState(&StateRegs, ~0, 0, 0);

98
src/boards/354.cpp Normal file
View File

@ -0,0 +1,98 @@
/* FCEUmm - NES/Famicom Emulator
*
* Copyright notice for this file:
* Copyright (C) 2022
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "mapinc.h"
static uint16 latchAddr;
static uint8 latchData;
static uint8 submapper;
static SFORMAT StateRegs[] =
{
{ &latchAddr, 2, "ADDR" },
{ &latchData, 1, "DATA" },
{ 0 }
};
static void Mapper354_Sync(void)
{
int prg = latchData & 0x3F | latchAddr << 2 & 0x40 | latchAddr >> 5 & 0x80;
switch (latchAddr & 7)
{
case 0: case 4:
setprg32(0x8000, prg >> 1);
break;
case 1:
setprg16(0x8000, prg);
setprg16(0xC000, prg | 7);
break;
case 2: case 6:
setprg8(0x8000, prg << 1 | latchData >> 7);
setprg8(0xA000, prg << 1 | latchData >> 7);
setprg8(0xC000, prg << 1 | latchData >> 7);
setprg8(0xE000, prg << 1 | latchData >> 7);
break;
case 3: case 7:
setprg16(0x8000, prg);
setprg16(0xC000, prg);
break;
case 5:
setprg8(0x6000, prg << 1 | latchData >> 7);
setprg32(0x8000, prg >> 1 | 3);
break;
}
SetupCartCHRMapping(0, CHRptr[0], CHRsize[0], (latchAddr & 8) ? 0 : 1);
setchr8(0);
setmirror(latchData & 0x40 ? MI_H : MI_V);
}
static DECLFW(Mapper354_WriteLatch)
{
latchData = V;
latchAddr = A & 0xFFFF;
Mapper354_Sync();
}
static void Mapper354_Reset(void)
{
latchAddr = latchData = 0;
Mapper354_Sync();
}
static void Mapper354_Power(void)
{
latchAddr = latchData = 0;
SetReadHandler(0x6000, 0xFFFF, CartBR);
SetWriteHandler(submapper == 1 ? 0xE000 : 0xF000, 0xFFFF, Mapper354_WriteLatch);
Mapper354_Sync();
}
static void StateRestore(int version) {
Mapper354_Sync();
}
void Mapper354_Init(CartInfo *info)
{
submapper = info->submapper;
info->Power = Mapper354_Power;
info->Reset = Mapper354_Reset;
GameStateRestore = StateRestore;
AddExState(StateRegs, ~0, 0, 0);
}

147
src/boards/413.cpp Normal file
View File

@ -0,0 +1,147 @@
/* FCEUmm - NES/Famicom Emulator
*
* Copyright notice for this file:
* Copyright (C) 2024
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "mapinc.h"
#include "../ines.h"
static uint8 reg[4];
static uint8 IRQCount;
static uint8 IRQReload;
static uint8 IRQa;
static uint8 serialControl;
static uint32 serialAddress;
static SFORMAT StateRegs[] = {
{ reg, 4, "REGS" },
{ &IRQCount, 1, "IRQC" },
{ &IRQReload, 1, "IRQR" },
{ &IRQa, 1, "IRQA" },
{ &serialAddress, 4, "ADDR" },
{ &serialControl, 1, "CTRL" },
{ 0 }
};
static void Sync(void) {
setprg4(0x5000, 0x01);
setprg8(0x6000, reg[0]);
setprg8(0x8000, reg[1]);
setprg8(0xA000, reg[2]);
setprg4(0xD000, 0x07);
setprg8(0xE000, 0x04);
setchr4(0x0000, reg[3]);
setchr4(0x1000, ~0x02);
}
static uint64 lreset;
static uint32 laddr;
static DECLFR(M413ReadPCM) {
uint8 ret = X.DB;
if ((A == laddr) && ((timestampbase + timestamp) < (lreset + 4))) {
return ret;
}
if (serialControl & 0x02) {
ret = MiscROM[serialAddress++ & (MiscROM_size - 1)];
} else {
ret = MiscROM[serialAddress & (MiscROM_size - 1)];
}
laddr = A;
lreset = timestampbase + timestamp;
return ret;
}
static DECLFW(M413Write) {
switch (A & 0xF000) {
case 0x8000:
IRQReload = V;
break;
case 0x9000:
IRQCount = 0;
break;
case 0xA000:
case 0xB000:
IRQa = (A & 0x1000) != 0;
if (!IRQa) {
X6502_IRQEnd(FCEU_IQEXT);
}
break;
case 0xC000:
serialAddress = (serialAddress << 1) | (V >> 7);
break;
case 0xD000:
serialControl = V;
break;
case 0xE000:
case 0xF000:
reg[V >> 6] = V & 0x3F;
Sync();
break;
}
}
static void M413Power(void) {
serialAddress = 0;
serialControl = 0;
IRQCount = 0;
IRQReload = 0;
IRQa = 0;
reg[0] = 0;
reg[1] = 0;
reg[2] = 0;
reg[3] = 0;
laddr = 0;
lreset = 0;
Sync();
SetReadHandler(0x4800, 0x4FFF, M413ReadPCM);
SetReadHandler(0x5000, 0x7FFF, CartBR);
SetReadHandler(0x8000, 0xBFFF, CartBR);
SetReadHandler(0xC000, 0xCFFF, M413ReadPCM);
SetReadHandler(0xD000, 0xFFFF, CartBR);
SetWriteHandler(0x8000, 0xFFFF, M413Write);
}
static void M413IRQHook(void) {
if (IRQCount == 0) {
IRQCount = IRQReload;
} else {
IRQCount--;
}
if ((IRQCount == 0) && IRQa) {
X6502_IRQBegin(FCEU_IQEXT);
}
}
static void StateRestore(int version) {
Sync();
}
void Mapper413_Init(CartInfo *info) {
info->Power = M413Power;
GameHBIRQHook = M413IRQHook;
GameStateRestore = StateRestore;
AddExState(&StateRegs, ~0, 0, 0);
}

216
src/boards/451.cpp Normal file
View File

@ -0,0 +1,216 @@
/* FCE Ultra - NES/Famicom Emulator
*
* Copyright notice for this file:
* Copyright (C) 2024 negativeExponent
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/* NES 2.0 Mapper 451 is used for the homebrew game Haratyler HP/MP. It is
* basically a homebrew TLROM-like circuit board that implements the MMC3
* register's in an unusual fashion, and saves the high score to flash ROM */
#include "mapinc.h"
#include "mmc3.h"
#include "../ines.h"
const int ROM_CHIP = 0x00;
const int CFI_CHIP = 0x10;
const int FLASH_CHIP = 0x11;
const int FLASH_SECTOR_SIZE = 64 * 1024;
const int magic_addr1 = 0x0555;
const int magic_addr2 = 0x02AA;
static uint8 flash_state, flash_id_mode;
static uint8 *flash_data;
static uint16 flash_buffer_a[10];
static uint8 flash_buffer_v[10];
static uint8 flash_id[2];
static DECLFW(M451FlashWrite)
{
if (flash_state < sizeof(flash_buffer_a) / sizeof(flash_buffer_a[0])) {
flash_buffer_a[flash_state] = (A & 0xFFF);
flash_buffer_v[flash_state] = V;
flash_state++;
// enter flash ID mode
if ((flash_state == 2) &&
(flash_buffer_a[0] == magic_addr1) && (flash_buffer_v[0] == 0xAA) &&
(flash_buffer_a[1] == magic_addr2) && (flash_buffer_v[1] == 0x55) &&
(flash_buffer_a[1] == magic_addr1) && (flash_buffer_v[1] == 0x90)) {
flash_id_mode = 0;
flash_state = 0;
}
// erase sector
if ((flash_state == 6) &&
(flash_buffer_a[0] == magic_addr1) && (flash_buffer_v[0] == 0xAA) &&
(flash_buffer_a[1] == magic_addr2) && (flash_buffer_v[1] == 0x55) &&
(flash_buffer_a[2] == magic_addr1) && (flash_buffer_v[2] == 0x80) &&
(flash_buffer_a[3] == magic_addr1) && (flash_buffer_v[3] == 0xAA) &&
(flash_buffer_a[4] == magic_addr2) && (flash_buffer_v[4] == 0x55) &&
(flash_buffer_v[5] == 0x30)) {
int offset = &Page[A >> 11][A] - flash_data;
int sector = offset / FLASH_SECTOR_SIZE;
for (int i = sector * FLASH_SECTOR_SIZE; i < (sector + 1) * FLASH_SECTOR_SIZE; i++)
flash_data[i % PRGsize[ROM_CHIP]] = 0xFF;
FCEU_printf("Flash sector #%d is erased (0x%08x - 0x%08x).\n", sector, offset, offset + FLASH_SECTOR_SIZE);
}
// erase chip
if ((flash_state == 6) &&
(flash_buffer_a[0] == magic_addr1) && (flash_buffer_v[0] == 0xAA) &&
(flash_buffer_a[1] == magic_addr2) && (flash_buffer_v[1] == 0x55) &&
(flash_buffer_a[2] == magic_addr1) && (flash_buffer_v[2] == 0x80) &&
(flash_buffer_a[3] == magic_addr1) && (flash_buffer_v[3] == 0xAA) &&
(flash_buffer_a[4] == magic_addr2) && (flash_buffer_v[4] == 0x55) &&
(flash_buffer_a[4] == magic_addr1) && (flash_buffer_v[4] == 0x10)) {
memset(flash_data, 0xFF, PRGsize[ROM_CHIP]);
FCEU_printf("Flash chip erased.\n");
flash_state = 0;
}
// write byte
if ((flash_state == 4) &&
(flash_buffer_a[0] == magic_addr1) && (flash_buffer_v[0] == 0xAA) &&
(flash_buffer_a[1] == magic_addr2) && (flash_buffer_v[1] == 0x55) &&
(flash_buffer_a[2] == magic_addr1) && (flash_buffer_v[2] == 0xA0)) {
int offset = &Page[A >> 11][A] - flash_data;
if (CartBR(A) != 0xFF) {
FCEU_PrintError("Error: can't write to 0x%08x, flash sector is not erased.\n", offset);
}
else {
CartBW(A, V);
}
flash_state = 0;
}
}
// not a command
if (((A & 0x00FF) != (magic_addr1 & 0x00FF)) && ((A & 0x00FF) != (magic_addr2 & 0x00FF))) {
flash_state = 0;
}
// reset
if (V == 0xF0) {
flash_state = 0;
flash_id_mode = 0;
}
FixMMC3PRG(MMC3_cmd);
}
static void M451FixPRG(uint32 A, uint8 V) {
setprg8r(FLASH_CHIP, 0x8000, 0);
setprg8r(FLASH_CHIP, 0xA000, 0x10 | ((EXPREGS[0] << 2) & 0x08) | (EXPREGS[0] & 0x01));
setprg8r(FLASH_CHIP, 0xC000, 0x20 | ((EXPREGS[0] << 2) & 0x08) | (EXPREGS[0] & 0x01));
setprg8r(FLASH_CHIP, 0xE000, 0x30);
}
static void M451FixCHR(uint32 A, uint8 V) {
setchr8(EXPREGS[0] & 0x01);
}
static DECLFR(M451Read) {
if (flash_state == 0x90) {
return flash_id[A & 1];
}
return CartBR(A);
}
static DECLFW(M451Write) {
M451FlashWrite(A, V);
switch (A & 0xE000) {
case 0xA000:
MMC3_CMDWrite(0xA000, A & 0x01);
break;
case 0xC000:
A &= 0xFF;
MMC3_IRQWrite(0xC000, A - 1);
MMC3_IRQWrite(0xC001, 0);
MMC3_IRQWrite(0xE000 + ((A == 0xFF) ? 0x00 : 0x01), 0x00);
break;
case 0xE000:
EXPREGS[0] = A & 0x03;
FixMMC3PRG(MMC3_cmd);
FixMMC3CHR(MMC3_cmd);
break;
}
}
static void M451Power(void) {
GenMMC3Power();
SetReadHandler(0x8000, 0xFFFF, M451Read);
SetWriteHandler(0x8000, 0xFFFF, M451Write);
}
static void StateRestore(int version) {
FixMMC3PRG(MMC3_cmd);
FixMMC3CHR(MMC3_cmd);
}
static void M451Close(void) {
if(flash_data)
FCEU_gfree(flash_data);
flash_data = NULL;
}
static void M451FlashReset(void)
{
if (flash_data)
{
size_t flash_size = PRGsize[ROM_CHIP];
// Copy ROM to flash data
for (size_t i = 0; i < flash_size; i++) {
flash_data[i] = PRGptr[ROM_CHIP][i];
}
}
}
void Mapper451_Init(CartInfo *info) {
GenMMC3_Init(info, 512, 16, 0, 0);
pwrap = M451FixPRG;
cwrap = M451FixCHR;
info->Power = M451Power;
info->Close = M451Close;
GameStateRestore = StateRestore;
flash_state = 0;
flash_id_mode = 0;
info->battery = 1;
// Allocate memory for flash
size_t flash_size = PRGsize[ROM_CHIP];
flash_data = (uint8*)FCEU_gmalloc(flash_size);
// Copy ROM to flash data
for (size_t i = 0; i < flash_size; i++) {
flash_data[i] = PRGptr[ROM_CHIP][i];
}
SetupCartPRGMapping(FLASH_CHIP, flash_data, flash_size, 1);
info->addSaveGameBuf( flash_data, flash_size, M451FlashReset );
flash_id[0] = 0x37;
flash_id[1] = 0x86;
SetupCartPRGMapping(CFI_CHIP, flash_id, sizeof(flash_id), 0);
AddExState(flash_data, flash_size, 0, "FLSH");
AddExState(&flash_state, sizeof(flash_state), 0, "FLST");
AddExState(&flash_id_mode, sizeof(flash_id_mode), 0, "FLMD");
AddExState(flash_buffer_a, sizeof(flash_buffer_a), 0, "FLBA");
AddExState(flash_buffer_v, sizeof(flash_buffer_v), 0, "FLBV");
}

View File

@ -1,59 +1,65 @@
/* FCE Ultra - NES/Famicom Emulator
*
* Copyright notice for this file:
* Copyright (C) 2012 CaH4e3
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "mapinc.h"
static uint8 regs[8];
static SFORMAT StateRegs[] =
{
{ regs, 8, "REGS" },
{ 0 }
};
static void Sync(void) {
setprg8(0x8000, regs[0]);
setprg8(0xA000, regs[2]);
setprg8(0xC000, regs[4]);
setprg8(0xE000, ~0);
setchr4(0x0000, regs[6]);
setchr4(0x1000, regs[7]);
}
static DECLFW(M151Write) {
regs[(A >> 12) & 7] = V;
Sync();
}
static void M151Power(void) {
Sync();
SetReadHandler(0x8000, 0xFFFF, CartBR);
SetWriteHandler(0x8000, 0xFFFF, M151Write);
}
static void StateRestore(int version) {
Sync();
}
void Mapper151_Init(CartInfo *info) {
info->Power = M151Power;
GameStateRestore = StateRestore;
AddExState(&StateRegs, ~0, 0, 0);
}
/* FCEUmm - NES/Famicom Emulator
*
* Copyright notice for this file:
* Copyright (C) 2024 negativeExponent
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/* NES 2.0 Mapper 471 denotes the Impact Soft IM1 circuit board, used for
* Haratyler (without HG or MP) and Haraforce. It is basically INES Mapper 201
* with the addition of a scanline IRQ.*/
#include "mapinc.h"
static uint32 latch;
static void Sync() {
setprg32(0x8000, latch);
setchr8(latch);
}
static DECLFW(Write) {
X6502_IRQEnd(FCEU_IQEXT);
latch = A;
Sync();
}
static void Reset() {
latch = 0;
Sync();
}
static void Power() {
SetReadHandler(0x8000, 0xFFFF, CartBR);
SetWriteHandler(0x8000, 0xFFFF, Write);
Reset();
}
static void StateRestore(int version) {
Sync();
}
static void HBHook() {
X6502_IRQBegin(FCEU_IQEXT);
}
void Mapper471_Init(CartInfo *info) {
info->Power = Power;
info->Reset = Reset;
GameHBIRQHook = HBHook;
GameStateRestore = StateRestore;
AddExState(&latch, sizeof(latch), 0, "LATC");
}

View File

@ -24,7 +24,7 @@ static uint8 chr_reg[4];
static uint8 kogame, prg_reg, nt1, nt2, mirr;
static uint8 *WRAM = NULL;
static uint32 WRAMSIZE, count;
static uint32 WRAMSIZE=0, count=0;
static SFORMAT StateRegs[] =
{
@ -156,8 +156,7 @@ void Mapper68_Init(CartInfo *info) {
WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE);
SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1);
if (info->battery) {
info->SaveGame[0] = WRAM;
info->SaveGameLen[0] = WRAMSIZE;
info->addSaveGameBuf( WRAM, WRAMSIZE );
}
AddExState(WRAM, WRAMSIZE, 0, "WRAM");
AddExState(&StateRegs, ~0, 0, 0);

View File

@ -25,7 +25,7 @@ static uint8 cmdreg, preg[4], creg[8], mirr;
static uint8 IRQa;
static int32 IRQCount;
static uint8 *WRAM = NULL;
static uint32 WRAMSIZE;
static uint32 WRAMSIZE=0;
static SFORMAT StateRegs[] =
{
@ -266,8 +266,7 @@ void Mapper69_Init(CartInfo *info) {
SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1);
AddExState(WRAM, WRAMSIZE, 0, "WRAM");
if (info->battery) {
info->SaveGame[0] = WRAM;
info->SaveGameLen[0] = WRAMSIZE;
info->addSaveGameBuf( WRAM, WRAMSIZE );
}
GameStateRestore = StateRestore;
Mapper69_ESI();

View File

@ -17,13 +17,14 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Moero!! Pro Tennis have ADPCM codec on-board, PROM isn't dumped, emulation isn't
* possible just now.
* Moero!! Pro Tennis and Moero!! Pro Yakyuu '88 Ketteiban have an ADPCM chip with
* internal ROM, used for voice samples (not dumped, so emulation isn't possible)
*/
#include "mapinc.h"
static uint8 preg, creg;
static void (*Sync)(void);
static SFORMAT StateRegs[] =
{
@ -32,13 +33,19 @@ static SFORMAT StateRegs[] =
{ 0 }
};
static void Sync(void) {
static void M72Sync(void) {
setprg16(0x8000, preg);
setprg16(0xC000, ~0);
setchr8(creg);
}
static DECLFW(M72Write) {
static void M92Sync(void) {
setprg16(0x8000, 0);
setprg16(0xC000, preg);
setchr8(creg);
}
static DECLFW(Write) {
if (V & 0x80)
preg = V & 0xF;
if (V & 0x40)
@ -46,10 +53,10 @@ static DECLFW(M72Write) {
Sync();
}
static void M72Power(void) {
static void Power(void) {
Sync();
SetReadHandler(0x8000, 0xFFFF, CartBR);
SetWriteHandler(0x6000, 0xFFFF, M72Write);
SetWriteHandler(0x8000, 0xFFFF, Write);
}
static void StateRestore(int version) {
@ -57,7 +64,16 @@ static void StateRestore(int version) {
}
void Mapper72_Init(CartInfo *info) {
info->Power = M72Power;
Sync = M72Sync;
info->Power = Power;
GameStateRestore = StateRestore;
AddExState(&StateRegs, ~0, 0, 0);
}
void Mapper92_Init(CartInfo *info) {
Sync = M92Sync;
info->Power = Power;
GameStateRestore = StateRestore;
AddExState(&StateRegs, ~0, 0, 0);

View File

@ -169,8 +169,7 @@ void Mapper80_Init(CartInfo *info) {
GameStateRestore = StateRestore;
if (info->battery) {
info->SaveGame[0] = wram;
info->SaveGameLen[0] = 256;
info->addSaveGameBuf( wram, sizeof(wram) );
}
AddExState(&StateRegs80, ~0, 0, 0);

View File

@ -25,7 +25,7 @@
static uint8 regs[9], ctrl;
static uint8 *WRAM = NULL;
static uint32 WRAMSIZE;
static uint32 WRAMSIZE=0;
static SFORMAT StateRegs[] =
{
@ -90,8 +90,7 @@ void Mapper82_Init(CartInfo *info) {
SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1);
AddExState(WRAM, WRAMSIZE, 0, "WRAM");
if (info->battery) {
info->SaveGame[0] = WRAM;
info->SaveGameLen[0] = WRAMSIZE;
info->addSaveGameBuf( WRAM, WRAMSIZE );
}
GameStateRestore = StateRestore;
AddExState(&StateRegs, ~0, 0, 0);

View File

@ -92,8 +92,7 @@ void MapperNNN_Init(CartInfo *info) {
SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1);
AddExState(WRAM, WRAMSIZE, 0, "WRAM");
if (info->battery) {
info->SaveGame[0] = WRAM;
info->SaveGameLen[0] = WRAMSIZE;
info->addSaveGameBuf( WRAM, WRAMSIZE );
}
*/
AddExState(&StateRegs, ~0, 0, 0);

View File

@ -26,7 +26,8 @@ static uint8 dipswitch;
static void (*WSync)(void);
static readfunc defread;
static uint8 *WRAM = NULL;
static uint32 WRAMSIZE;
static uint32 WRAMSIZE=0;
static uint8 hasBattery = 0;
static DECLFW(LatchWrite) {
latche = A;
@ -77,8 +78,7 @@ static void Latch_Init(CartInfo *info, void (*proc)(void), readfunc func, uint16
WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE);
SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1);
if (info->battery) {
info->SaveGame[0] = WRAM;
info->SaveGameLen[0] = WRAMSIZE;
info->addSaveGameBuf( WRAM, WRAMSIZE );
}
AddExState(WRAM, WRAMSIZE, 0, "WRAM");
}
@ -122,7 +122,7 @@ static void UNL43272Sync(void) {
if ((latche & 0x81) == 0x81) {
setprg32(0x8000, (latche & 0x38) >> 3);
} else
FCEU_printf("unrecognized command %04!\n", latche);
FCEU_printf("unrecognized command %04x!\n", latche);
setchr8(0);
setmirror(0);
}
@ -181,6 +181,7 @@ void Mapper59_Init(CartInfo *info) {
}
//------------------ Map 061 ---------------------------
static void M61Sync(void) {
if (((latche & 0x10) << 1) ^ (latche & 0x20)) {
setprg16(0x8000, ((latche & 0xF) << 1) | (((latche & 0x20) >> 4)));
@ -195,30 +196,21 @@ void Mapper61_Init(CartInfo *info) {
Latch_Init(info, M61Sync, NULL, 0x0000, 0x8000, 0xFFFF, 0);
}
//------------------ Map 092 ---------------------------
// Another two-in-one mapper, two Jaleco carts uses similar
// hardware, but with different wiring.
// Original code provided by LULU
// Additionally, PCB contains DSP extra sound chip, used for voice samples (unemulated)
//------------------ Map 174 ---------------------------
static void M92Sync(void) {
uint8 reg = latche & 0xF0;
setprg16(0x8000, 0);
if (latche >= 0x9000) {
switch (reg) {
case 0xD0: setprg16(0xc000, latche & 15); break;
case 0xE0: setchr8(latche & 15); break;
}
static void M174Sync(void) {
if (latche & 0x80) {
setprg32(0x8000, (latche >> 5) & 3);
} else {
switch (reg) {
case 0xB0: setprg16(0xc000, latche & 15); break;
case 0x70: setchr8(latche & 15); break;
}
setprg16(0x8000, (latche >> 4) & 7);
setprg16(0xC000, (latche >> 4) & 7);
}
setchr8((latche >> 1) & 7);
setmirror((latche & 1) ^ 1);
}
void Mapper92_Init(CartInfo *info) {
Latch_Init(info, M92Sync, NULL, 0x80B0, 0x8000, 0xFFFF, 0);
void Mapper174_Init(CartInfo *info) {
Latch_Init(info, M174Sync, NULL, 0, 0x8000, 0xFFFF, 0);
}
//------------------ Map 200 ---------------------------
@ -342,20 +334,17 @@ void Mapper217_Init(CartInfo *info) {
}
//------------------ Map 227 ---------------------------
static void M227Sync(void) {
uint32 S = latche & 1;
uint32 p = ((latche >> 2) & 0x1F) + ((latche & 0x100) >> 3);
uint32 L = (latche >> 9) & 1;
// ok, according to nesdev wiki (refrenced to the nesdev dumping thread) there is a CHR write protection bit7.
// however, this bit clearly determined a specific PRG layout for some game but does not meant to have additional
// functionality. as I see from the menu code, it disables the chr writing before run an actual game.
// this fix here makes happy both waixing rpgs and multigame menus at once. can't veryfy it on a hardware
// but if I find some i'll definitly do this.
if ((latche & 0xF000) == 0xF000)
SetupCartCHRMapping(0, CHRptr[0], 0x2000, 0);
// Only Waixing appear to have battery flag enabled, while multicarts don't.
// Multicarts needs CHR-RAM protect in NROM modes, so only apply CHR-RAM protect
// on non battery-enabled carts.
if (!hasBattery && (latche & 0x80) == 0x80)
/* CHR-RAM write protect hack, needed for some multicarts */
SetupCartCHRMapping(0, CHRptr[0], 0x2000, 0);
else
SetupCartCHRMapping(0, CHRptr[0], 0x2000, 1);
@ -393,6 +382,7 @@ static void M227Sync(void) {
void Mapper227_Init(CartInfo *info) {
Latch_Init(info, M227Sync, NULL, 0x0000, 0x8000, 0xFFFF, 1);
hasBattery = info->battery;
}
//------------------ Map 229 ---------------------------

View File

@ -29,7 +29,7 @@ static uint8 IRQa;
static int16 IRQCount, IRQLatch;
static uint8 *WRAM = NULL;
static uint32 WRAMSIZE;
static uint32 WRAMSIZE=0;
static SFORMAT StateRegs[] =
{
@ -178,9 +178,12 @@ static void x24c02_write(uint8 data) {
x24c02_addr <<= 1;
x24c02_addr |= sda;
} else {
if (sda) // READ COMMAND
if ((x24c02_addr & 0x78) != 0x50) { // WRONG DEVICE ADDRESS
x24c02_out = 1;
x24c02_state = X24C0X_STANDBY;
} else if (sda) // READ COMMAND
x24c02_state = X24C0X_READ;
else // WRITE COMMAND
else // WRITE COMMAND
x24c02_state = X24C0X_WORD;
}
x24c02_bitcount++;
@ -317,8 +320,7 @@ void Mapper16_Init(CartInfo *info) {
MapIRQHook = BandaiIRQHook;
info->battery = 1;
info->SaveGame[0] = x24c0x_data + 256;
info->SaveGameLen[0] = 256;
info->addSaveGameBuf( x24c0x_data + 256, 256 );
AddExState(x24c0x_data, 256, 0, "DATA");
AddExState(&x24c02StateRegs, ~0, 0, 0);
@ -333,8 +335,7 @@ void Mapper159_Init(CartInfo *info) {
MapIRQHook = BandaiIRQHook;
info->battery = 1;
info->SaveGame[0] = x24c0x_data;
info->SaveGameLen[0] = 128;
info->addSaveGameBuf( x24c0x_data, 128 );
AddExState(x24c0x_data, 128, 0, "DATA");
AddExState(&x24c01StateRegs, ~0, 0, 0);
@ -378,8 +379,7 @@ void Mapper153_Init(CartInfo *info) {
AddExState(WRAM, WRAMSIZE, 0, "WRAM");
if (info->battery) {
info->SaveGame[0] = WRAM;
info->SaveGameLen[0] = WRAMSIZE;
info->addSaveGameBuf( WRAM, WRAMSIZE );
}
GameStateRestore = StateRestore;
@ -599,8 +599,7 @@ void Mapper157_Init(CartInfo *info) {
GameInfo->cspecial = SIS_DATACH;
info->battery = 1;
info->SaveGame[0] = x24c0x_data;
info->SaveGameLen[0] = 512;
info->addSaveGameBuf( x24c0x_data, 512 );
AddExState(x24c0x_data, 512, 0, "DATA");
AddExState(&x24c01StateRegs, ~0, 0, 0);
AddExState(&x24c02StateRegs, ~0, 0, 0);

View File

@ -252,8 +252,7 @@ void Mapper111_Init(CartInfo *info) {
if (flash)
{
FLASHROM = (uint8*)FCEU_gmalloc(FLASHROMSIZE);
info->SaveGame[0] = FLASHROM;
info->SaveGameLen[0] = FLASHROMSIZE;
info->addSaveGameBuf( FLASHROM, FLASHROMSIZE );
AddExState(FLASHROM, FLASHROMSIZE, 0, "FROM");
AddExState(&FlashRegs, ~0, 0, 0);

View File

@ -21,7 +21,7 @@
*
* COOLBOY cartridges use registers at address $6xxx
* MINDKIDS cartridges use a solder pad labelled "5/6K" to select between $5000 and $6000
*
*
* $xxx0
* 7 bit 0
* ---- ----
@ -29,12 +29,11 @@
* |||| ||||
* |||| |+++-- PRG offset (PRG A19, A18, A17)
* |||| +----- Alternate CHR A17
* ||++------- PRG offset (PRG A24, A23)
* ||++------- PRG offset (PRG A24, A23), CHR offset (CHR A19, A18)
* |+--------- PRG mask (PRG A17 from 0: MMC3; 1: offset)
* +---------- CHR mask (CHR A17 from 0: MMC3; 1: alternate)
*
* $xxx1
*
* 7 bit 0
* ---- ----
* GHIJ KKLx
@ -55,15 +54,16 @@
* $xxx3
* 7 bit 0
* ---- ----
* NPxP QQRx
* || | |||
* || | +++--- PRG offset for GNROM mode (PRG A16, A15, A14)
* || +------- 1: GNROM mode; 0: MMC3 mode
* || | (1: PRG A16...13 from QQ, L, R, CPU A14, A13 + CHR A16...10 from MMMM, PPU A12...10;
* || | 0: PRG A16...13 from MMC3 + CHR A16...A10 from MMC3 )
* NPZP QQRx
* |||| |||
* |||| +++--- PRG offset for GNROM mode (PRG A16, A15, A14)
* |||+------- 1: GNROM mode; 0: MMC3 mode
* |||| (1: PRG A16...13 from QQ, L, R, CPU A14, A13 + CHR A16...10 from MMMM, PPU A12...10;
* |||| 0: PRG A16...13 from MMC3 + CHR A16...A10 from MMC3 )
* ||+-------- 1: Also enable PRG RAM in $5000-$5FFF
* |+-+------- Banking mode
* |+--------- "Weird MMC3 mode"
* +---------- Lockout (prevent further writes to these four registers, only works in MMC3 mode)
* +---------- Lockout (prevent further writes to all registers but the one at $xxx2, only works in MMC3 mode)
*
* Also some new cartridges from MINDKIDS have /WE and /OE pins connected to mapper,
* which allows you to rewrite flash memory without soldering.
@ -75,25 +75,90 @@
#include "mapinc.h"
#include "mmc3.h"
#include "../ines.h"
static void COOLBOYCW(uint32 A, uint8 V) {
uint32 mask = 0xFF ^ (EXPREGS[0] & 0x80);
if (EXPREGS[3] & 0x10) {
if (EXPREGS[3] & 0x40) { // Weird mode
const int ROM_CHIP = 0x00;
const int CFI_CHIP = 0x11;
const int FLASH_CHIP = 0x12;
const uint32 FLASH_SECTOR_SIZE = 128 * 1024;
extern uint8* WRAM;
static uint8* CFI = NULL;
static uint8* Flash = NULL;
static uint8 flash_save = 0;
static uint8 flash_state = 0;
static uint16 flash_buffer_a[10];
static uint8 flash_buffer_v[10];
static uint8 cfi_mode = 0;
static uint16 regs_base = 0;
static uint8 flag23 = 0;
static uint8 flag45 = 0;
static uint8 flag67 = 0;
static uint8 flag89 = 0;
// Macronix 256-mbit memory CFI data
const uint8 cfi_data[] =
{
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0x51, 0x52, 0x59, 0x02, 0x00, 0x40, 0x00, 0x00,
0x00, 0x00, 0x00, 0x27, 0x36, 0x00, 0x00, 0x03,
0x06, 0x09, 0x13, 0x03, 0x05, 0x03, 0x02, 0x19,
0x02, 0x00, 0x06, 0x00, 0x01, 0xFF, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF,
0x50, 0x52, 0x49, 0x31, 0x33, 0x14, 0x02, 0x01,
0x00, 0x08, 0x00, 0x00, 0x02, 0x95, 0xA5, 0x05,
0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
};
static void AA6023CW(uint32 A, uint8 V) {
if (flag89) {
/*
$xxx0
7 bit 0
---- ----
AB.C DEEE
|| | ||||
|| | |+++-- PRG offset (PRG A19, A18, A17)
|| | +----- Alternate CHR A17
|| +------- 1=Write-protect CHR-RAM
|+--------- PRG mask (PRG A17 from 0: MMC3; 1: offset)
+---------- CHR mask (CHR A17 from 0: MMC3; 1: alternate)
*/
if (EXPREGS[0] & 0b00010000)
SetupCartCHRMapping(0, VROM, CHRsize[0], 0); // write-protect CHR-RAM
else
SetupCartCHRMapping(0, VROM, CHRsize[0], 1); // allow CHR writes
}
uint32 mask = 0xFF ^ (EXPREGS[0] & 0b10000000);
if (EXPREGS[3] & 0b00010000) {
if (EXPREGS[3] & 0b01000000) { // Weird mode
int cbase = (MMC3_cmd & 0x80) << 5;
switch (cbase ^ A) { // Don't even try do understand
case 0x0400:
case 0x0C00: V &= 0x7F; break;
}
}
// Highest bit goes from MMC3 registers when EXPREGS[3]&0x80==0 or from EXPREGS[0]&0x08 otherwise
// Highest bit goes from MMC3 registers when EXPREGS[0]&0x80==0 or from EXPREGS[0]&0x08 otherwise
setchr1(A,
(V & 0x80 & mask) | ((((EXPREGS[0] & 0x08) << 4) & ~mask)) // 7th bit
(V & 0x80 & mask) | ((((EXPREGS[0] & 0b00001000) << 4) & ~mask)) // 7th bit
| ((EXPREGS[2] & 0x0F) << 3) // 6-3 bits
| ((A >> 10) & 7) // 2-0 bits
| ((EXPREGS[0] & 0b00110000) << 4) // There are some ROMs with 1 MiB CHR-ROM
);
} else {
if (EXPREGS[3] & 0x40) { // Weird mode, again
}
else {
if (EXPREGS[3] & 0b01000000) { // Weird mode, again
int cbase = (MMC3_cmd & 0x80) << 5;
switch (cbase ^ A) { // Don't even try do understand
case 0x0000: V = DRegBuf[0]; break;
@ -103,18 +168,81 @@ static void COOLBOYCW(uint32 A, uint8 V) {
}
}
// Simple MMC3 mode
// Highest bit goes from MMC3 registers when EXPREGS[3]&0x80==0 or from EXPREGS[0]&0x08 otherwise
setchr1(A, (V & mask) | (((EXPREGS[0] & 0x08) << 4) & ~mask));
// Highest bit goes from MMC3 registers when EXPREGS[0]&0x80==0 or from EXPREGS[0]&0x08 otherwise
setchr1(A,
(V & mask)
| (((EXPREGS[0] & 0x08) << 4) & ~mask)
| ((EXPREGS[0] & 0b00110000) << 4)); // There are some ROMs with 1 MiB CHR-ROM
}
}
static void COOLBOYPW(uint32 A, uint8 V) {
uint32 mask = ((0x3F | (EXPREGS[1] & 0x40) | ((EXPREGS[1] & 0x20) << 2)) ^ ((EXPREGS[0] & 0x40) >> 2)) ^ ((EXPREGS[1] & 0x80) >> 2);
uint32 base = ((EXPREGS[0] & 0x07) >> 0) | ((EXPREGS[1] & 0x10) >> 1) | ((EXPREGS[1] & 0x0C) << 2) | ((EXPREGS[0] & 0x30) << 2);
static void AA6023PW(uint32 A, uint8 V) {
uint8 CREGS[] = {EXPREGS[0], EXPREGS[1], EXPREGS[2], EXPREGS[3]};
// Submappers has scrambled bits
if (flag23) {
/*
$xxx1
7 bit 0
---- ----
GHIL JKKx
|||| |||
|||| +++--- PRG offset (in order: PRG A20, A21, A22)
|||+------- GNROM mode bank PRG size (0: 32 KiB bank, PRG A14=CPU A14; 1: 16 KiB bank, PRG A14=offset A14)
||+-------- PRG mask (PRG A20 from 0: offset; 1: MMC3)
|+--------- PRG mask (PRG A19 from 0: offset; 1: MMC3)
+---------- PRG mask (PRG A18 from 0: MMC3; 1: offset)
*/
CREGS[1] = (CREGS[1] & 0b11100101)
| ((CREGS[1] & 0b00001000) << 1) // PRG A20
| ((CREGS[1] & 0b00000010) << 2) // PRG A22
| ((((CREGS[1] ^ 0b00010000) & 0b00010000) >> 3)); // GNROM mode bank PRG size
}
if (flag45) {
/*
$xxx0
7 bit 0
---- ----
ABCC DEEE
|||| ||||
|||| |+++-- PRG offset (PRG A19, A18, A17)
|||| +----- Alternate CHR A17
||++------- PRG offset (PRG A21, A20)
|+--------- PRG mask (PRG A17 from 0: MMC3; 1: offset)
+---------- CHR mask (CHR A17 from 0: MMC3; 1: alternate)
$xxx1
7 bit 0
---- ----
GHIx xxLx
||| |
||| +--- GNROM mode bank PRG size (1: 32 KiB bank, PRG A14=CPU A14; 0: 16 KiB bank, PRG A14=offset A14)
||+-------- PRG mask (PRG A20 from 0: offset; 1: MMC3)
|+--------- PRG mask (PRG A19 from 0: offset; 1: MMC3)
+---------- PRG mask (PRG A18 from 0: MMC3; 1: offset)
*/
CREGS[1] = (CREGS[1] & 0b11100011)
| ((CREGS[0] & 0b00100000) >> 3) // PRG A21
| (CREGS[0] & 0b00010000); // PRG A20
CREGS[0] &= 0b11001111;
}
uint32 mask = ((0b00111111 | (CREGS[1] & 0b01000000) | ((CREGS[1] & 0b00100000) << 2)) ^ ((CREGS[0] & 0b01000000) >> 2)) ^ ((CREGS[1] & 0b10000000) >> 2);
uint32 base = ((CREGS[0] & 0b00000111) >> 0) | ((CREGS[1] & 0b00010000) >> 1) | ((CREGS[1] & 0b00001100) << 2) | ((CREGS[0] & 0b00110000) << 2);
if (flash_save && cfi_mode) {
setprg32r(CFI_CHIP, 0x8000, 0);
return;
}
int chip = !flash_save ? ROM_CHIP : FLASH_CHIP;
// There are ROMs with multiple PRG ROM chips
int chip_offset = 0;
if (flag67 && EXPREGS[0] & 0b00001000) {
chip_offset += ROM_size;
}
// Very weird mode
// Last banks are first in this mode, ignored when MMC3_cmd&0x40
if ((EXPREGS[3] & 0x40) && (V >= 0xFE) && !((MMC3_cmd & 0x40) != 0)) {
if ((CREGS[3] & 0b01000000) && (V >= 0xFE) && !((MMC3_cmd & 0x40) != 0)) {
switch (A & 0xE000) {
case 0xC000:
case 0xE000:
@ -123,91 +251,234 @@ static void COOLBOYPW(uint32 A, uint8 V) {
}
}
// Regular MMC3 mode, internal ROM size can be up to 2048kb!
if (!(EXPREGS[3] & 0x10))
setprg8(A, (((base << 4) & ~mask)) | (V & mask));
else { // NROM mode
if (!(CREGS[3] & 0x10)) {
// Regular MMC3 mode but can be extended to 2MiB
setprg8r(chip, A, ((((base << 4) & ~mask)) | (V & mask)) + chip_offset);
}
else {
// NROM mode
mask &= 0xF0;
uint8 emask;
if ((((EXPREGS[1] & 2) != 0))) // 32kb mode
emask = (EXPREGS[3] & 0x0C) | ((A & 0x4000) >> 13);
if (CREGS[1] & 0b00000010) // 32kb mode
emask = (CREGS[3] & 0b00001100) | ((A & 0x4000) >> 13);
else // 16kb mode
emask = EXPREGS[3] & 0x0E;
setprg8(A, ((base << 4) & ~mask) // 7-4 bits are from base (see below)
| (V & mask) // ... or from MM3 internal regs, depends on mask
| emask // 3-1 (or 3-2 when (EXPREGS[3]&0x0C is set) from EXPREGS[3]
| ((A & 0x2000) >> 13)); // 0th just as is
emask = CREGS[3] & 0b00001110;
setprg8r(chip, A, (
((base << 4) & ~mask) // 7-4 bits are from base
| (V & mask) // ... or from MM3 internal regs, depends on mask
| emask // 3-1 (or 3-2 when (EXPREGS[3]&0x0C is set) from EXPREGS[3]
| ((A & 0x2000) >> 13) // 0th just as is
) + chip_offset); // For multi-chip ROMs
}
}
static DECLFW(COOLBOYWrite) {
if(A001B & 0x80)
CartBW(A,V);
static DECLFW(AA6023WramWrite) {
if (A001B & 0x80)
CartBW(A, V);
}
static DECLFW(AA6023Write) {
if (A >= 0x6000) {
AA6023WramWrite(A, V);
}
// Deny any further writes when 7th bit is 1 AND 4th is 0
if ((EXPREGS[3] & 0x90) != 0x80) {
EXPREGS[A & 3] = V;
FixMMC3PRG(MMC3_cmd);
FixMMC3CHR(MMC3_cmd);
}
FixMMC3PRG(MMC3_cmd);
FixMMC3CHR(MMC3_cmd);
}
static void COOLBOYReset(void) {
static DECLFW(AA6023FlashWrite) {
if (A < 0xC000)
MMC3_CMDWrite(A, V);
else
MMC3_IRQWrite(A, V);
if (!flash_save) return;
if (flash_state < sizeof(flash_buffer_a) / sizeof(flash_buffer_a[0])) {
flash_buffer_a[flash_state] = A & 0xFFF;
flash_buffer_v[flash_state] = V;
flash_state++;
// enter CFI mode
if ((flash_state == 1) &&
(flash_buffer_a[0] == 0x0AAA) && (flash_buffer_v[0] == 0x98)) {
cfi_mode = 1;
flash_state = 0;
}
// erase sector
if ((flash_state == 6) &&
(flash_buffer_a[0] == 0x0AAA) && (flash_buffer_v[0] == 0xAA) &&
(flash_buffer_a[1] == 0x0555) && (flash_buffer_v[1] == 0x55) &&
(flash_buffer_a[2] == 0x0AAA) && (flash_buffer_v[2] == 0x80) &&
(flash_buffer_a[3] == 0x0AAA) && (flash_buffer_v[3] == 0xAA) &&
(flash_buffer_a[4] == 0x0555) && (flash_buffer_v[4] == 0x55) &&
(flash_buffer_v[5] == 0x30)) {
int offset = &Page[A >> 11][A] - Flash;
int sector = offset / FLASH_SECTOR_SIZE;
for (uint32 i = sector * FLASH_SECTOR_SIZE; i < (sector + 1) * FLASH_SECTOR_SIZE; i++)
Flash[i % PRGsize[ROM_CHIP]] = 0xFF;
FCEU_printf("Flash sector #%d is erased (0x%08x - 0x%08x).\n", sector, offset, offset + FLASH_SECTOR_SIZE);
flash_state = 0;
}
// erase chip, lol
if ((flash_state == 6) &&
(flash_buffer_a[0] == 0x0AAA) && (flash_buffer_v[0] == 0xAA) &&
(flash_buffer_a[1] == 0x0555) && (flash_buffer_v[1] == 0x55) &&
(flash_buffer_a[2] == 0x0AAA) && (flash_buffer_v[2] == 0x80) &&
(flash_buffer_a[3] == 0x0AAA) && (flash_buffer_v[3] == 0xAA) &&
(flash_buffer_a[4] == 0x0555) && (flash_buffer_v[4] == 0x55) &&
(flash_buffer_v[5] == 0x10)) {
memset(Flash, 0xFF, PRGsize[ROM_CHIP]);
FCEU_printf("Flash chip erased.\n");
flash_state = 0;
}
// write byte
if ((flash_state == 4) &&
(flash_buffer_a[0] == 0x0AAA) && (flash_buffer_v[0] == 0xAA) &&
(flash_buffer_a[1] == 0x0555) && (flash_buffer_v[1] == 0x55) &&
(flash_buffer_a[2] == 0x0AAA) && (flash_buffer_v[2] == 0xA0)) {
int offset = &Page[A >> 11][A] - Flash;
if (CartBR(A) != 0xFF) {
FCEU_PrintError("Error: can't write to 0x%08x, flash sector is not erased.\n", offset);
}
else {
CartBW(A, V);
}
flash_state = 0;
}
}
// not a command
if (((A & 0xFFF) != 0x0AAA) && ((A & 0xFFF) != 0x0555)) {
flash_state = 0;
}
// reset
if (V == 0xF0) {
flash_state = 0;
cfi_mode = 0;
}
FixMMC3PRG(MMC3_cmd);
}
static void AA6023Reset(void) {
MMC3RegReset();
EXPREGS[0] = EXPREGS[1] = EXPREGS[2] = EXPREGS[3] = 0;
flash_state = 0;
cfi_mode = 0;
FixMMC3PRG(MMC3_cmd);
FixMMC3CHR(MMC3_cmd);
}
static void COOLBOYPower(void) {
static void AA6023Power(void) {
GenMMC3Power();
EXPREGS[0] = EXPREGS[1] = EXPREGS[2] = EXPREGS[3] = 0;
FixMMC3PRG(MMC3_cmd);
FixMMC3CHR(MMC3_cmd);
SetWriteHandler(0x5000, 0x5fff, CartBW); // some games access random unmapped areas and crashes because of KT-008 PCB hack in MMC3 source lol
SetWriteHandler(0x6000, 0x6fff, COOLBOYWrite);
if (regs_base != 0x5000)
SetWriteHandler(0x5000, 0x5fff, CartBW); // some games access random unmapped areas and crashes because of KT-008 PCB hack in MMC3 source lol
SetWriteHandler(0x6000, 0x7fff, AA6023WramWrite);
SetWriteHandler(regs_base, regs_base + 0x0fff, AA6023Write);
SetWriteHandler(0x8000, 0xFFFF, AA6023FlashWrite);
SetReadHandler(0x8000, 0xFFFF, CartBR);
}
static void MINDKIDSPower(void) {
GenMMC3Power();
EXPREGS[0] = EXPREGS[1] = EXPREGS[2] = EXPREGS[3] = 0;
static void AA6023Restore(int version) {
FixMMC3PRG(MMC3_cmd);
FixMMC3CHR(MMC3_cmd);
SetWriteHandler(0x5000, 0x5fff, COOLBOYWrite);
}
static void AA6023Close(void) {
if (WRAM)
FCEU_gfree(WRAM);
if (Flash)
FCEU_gfree(Flash);
if (CFI)
FCEU_gfree(CFI);
WRAM = Flash = CFI = NULL;
}
void CommonInit(CartInfo* info, int submapper)
{
GenMMC3_Init(info, 2048, info->vram_size / 1024, !info->ines2 ? 8 : (info->wram_size + info->battery_wram_size) / 1024, info->battery);
pwrap = AA6023PW;
cwrap = AA6023CW;
switch (submapper)
{
case 2:
regs_base = 0x7000;
break;
case 0:
case 4:
case 6:
case 8:
regs_base = 0x6000;
break;
case 1:
case 3:
case 5:
case 7:
case 9:
regs_base = 0x5000;
break;
default:
FCEU_PrintError("Submapper #%d is not supported", submapper);
}
flag23 = (submapper == 2) || (submapper == 3);
flag45 = (submapper == 4) || (submapper == 5);
flag67 = (submapper == 6) || (submapper == 7);
flag89 = (submapper == 8) || (submapper == 9);
info->Power = AA6023Power;
info->Reset = AA6023Reset;
info->Close = AA6023Close;
GameStateRestore = AA6023Restore;
flash_save = info->battery;
if (flash_save) {
CFI = (uint8*)FCEU_gmalloc(sizeof(cfi_data) * 2);
for (size_t i = 0; i < sizeof(cfi_data); i++) {
CFI[i * 2] = CFI[i * 2 + 1] = cfi_data[i];
}
SetupCartPRGMapping(CFI_CHIP, CFI, sizeof(cfi_data) * 2, 0);
Flash = (uint8*)FCEU_gmalloc(PRGsize[ROM_CHIP]);
for (unsigned int i = 0; i < PRGsize[ROM_CHIP]; i++) {
Flash[i] = PRGptr[ROM_CHIP][i % PRGsize[ROM_CHIP]];
}
SetupCartPRGMapping(FLASH_CHIP, Flash, PRGsize[ROM_CHIP], 1);
info->addSaveGameBuf( Flash, PRGsize[ROM_CHIP] );
}
AddExState(EXPREGS, 4, 0, "EXPR");
if (flash_save)
{
AddExState(&flash_state, sizeof(flash_state), 0, "FLST");
AddExState(flash_buffer_a, sizeof(flash_buffer_a), 0, "FLBA");
AddExState(flash_buffer_v, sizeof(flash_buffer_v), 0, "FLBV");
AddExState(&cfi_mode, sizeof(cfi_mode), 0, "CFIM");
AddExState(Flash, PRGsize[ROM_CHIP], 0, "FLAS");
}
}
// Registers at $6xxx
void COOLBOY_Init(CartInfo *info) {
GenMMC3_Init(info, 2048, 256, 8, 1);
pwrap = COOLBOYPW;
cwrap = COOLBOYCW;
info->Power = COOLBOYPower;
info->Reset = COOLBOYReset;
AddExState(EXPREGS, 4, 0, "EXPR");
void COOLBOY_Init(CartInfo* info) {
CommonInit(info, 0);
}
// Registers at $5xxx
void MINDKIDS_Init(CartInfo *info) {
GenMMC3_Init(info, 2048, 256, 8, 1);
pwrap = COOLBOYPW;
cwrap = COOLBOYCW;
info->Power = MINDKIDSPower;
info->Reset = COOLBOYReset;
AddExState(EXPREGS, 4, 0, "EXPR");
void MINDKIDS_Init(CartInfo* info) {
CommonInit(info, 1);
}
// For NES 2.0 loader
void SMD132_SMD133_Init(CartInfo *info) {
switch (info->submapper)
{
case 0:
COOLBOY_Init(info);
break;
case 1:
MINDKIDS_Init(info);
break;
default:
FCEU_PrintError("Unknown submapper: #%d.", info->submapper);
break;
}
void AA6023_Init(CartInfo* info) {
CommonInit(info, info->submapper);
}

2352
src/boards/coolgirl.cpp Normal file

File diff suppressed because it is too large Load Diff

View File

@ -21,11 +21,12 @@
#include "mapinc.h"
#include "../ines.h"
static uint8 latche, latcheinit, bus_conflict;
static uint16 addrreg0, addrreg1;
static uint8 latche=0, latcheinit=0, bus_conflict=0;
static uint16 addrreg0=0, addrreg1=0;
static uint8 *WRAM = NULL;
static uint32 WRAMSIZE;
static void (*WSync)(void);
static uint32 WRAMSIZE=0;
static void (*WSync)(void) = nullptr;
static uint8 submapper;
static DECLFW(LatchWrite) {
// FCEU_printf("bs %04x %02x\n",A,V);
@ -68,6 +69,7 @@ static void Latch_Init(CartInfo *info, void (*proc)(void), uint8 init, uint16 ad
info->Power = LatchPower;
info->Close = LatchClose;
GameStateRestore = StateRestore;
submapper = info->submapper;
if(info->ines2)
if(info->battery_wram_size + info->wram_size > 0)
wram = 1;
@ -85,14 +87,12 @@ static void Latch_Init(CartInfo *info, void (*proc)(void), uint8 init, uint16 ad
//else if(!info->wram_size && info->battery_wram_size)
//{
// SetupCartPRGMapping(0x10, WRAM, info->battery_wram_size, 1);
// info->SaveGame[0] = WRAM;
// info->SaveGameLen[0] = info->battery_wram_size;
// info->addSaveGameBuf( WRAM, info->battery_wram_size );
//} else {
// //well, this is annoying
// SetupCartPRGMapping(0x10, WRAM, info->wram_size, 1);
// SetupCartPRGMapping(0x11, WRAM, info->battery_wram_size, 1); //? ? ? there probably isnt even a way to select this
// info->SaveGame[0] = WRAM + info->wram_size;
// info->SaveGameLen[0] = info->battery_wram_size;
// info->addSaveGameBuf( WRAM + info->wram_size, info->battery_wram_size );
//}
//this is more likely the only practical scenario
@ -104,8 +104,7 @@ static void Latch_Init(CartInfo *info, void (*proc)(void), uint8 init, uint16 ad
setprg8r(0x10, 0x6000, 0);
if(info->battery_wram_size)
{
info->SaveGame[0] = WRAM;
info->SaveGameLen[0] = 8192;
info->addSaveGameBuf( WRAM, 8192 );
}
}
else
@ -114,8 +113,7 @@ static void Latch_Init(CartInfo *info, void (*proc)(void), uint8 init, uint16 ad
WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE);
SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1);
if (info->battery) {
info->SaveGame[0] = WRAM;
info->SaveGameLen[0] = WRAMSIZE;
info->addSaveGameBuf( WRAM, WRAMSIZE );
}
AddExState(WRAM, WRAMSIZE, 0, "WRAM");
}
@ -158,8 +156,7 @@ void NROM_Init(CartInfo *info) {
WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE);
SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1);
if (info->battery) {
info->SaveGame[0] = WRAM;
info->SaveGameLen[0] = WRAMSIZE;
info->addSaveGameBuf( WRAM, WRAMSIZE );
}
AddExState(WRAM, WRAMSIZE, 0, "WRAM");
}
@ -300,7 +297,11 @@ static void M78Sync() {
setprg16(0x8000, (latche & 7));
setprg16(0xc000, ~0);
setchr8(latche >> 4);
setmirror(MI_0 + ((latche >> 3) & 1));
if (submapper == 3) {
setmirror((latche >> 3) & 1);
} else {
setmirror(MI_0 + ((latche >> 3) & 1));
}
}
void Mapper78_Init(CartInfo *info) {
@ -308,7 +309,8 @@ void Mapper78_Init(CartInfo *info) {
}
//------------------ Map 86 ---------------------------
// Moero!! Pro Yakyuu has an ADPCM chip with internal ROM,
// used for voice samples (not dumped, so emulation isn't possible)
static void M86Sync(void) {
setprg32(0x8000, (latche >> 4) & 3);
setchr8((latche & 3) | ((latche >> 4) & 4));
@ -369,31 +371,14 @@ void Mapper94_Init(CartInfo *info) {
//------------------ Map 97 ---------------------------
static void M97Sync(void) {
setchr8(0);
setprg16(0x8000, ~0);
setprg16(0xc000, latche & 15);
switch (latche >> 6) {
case 0: break;
case 1: setmirror(MI_H); break;
case 2: setmirror(MI_V); break;
case 3: break;
}
setchr8(((latche >> 1) & 1) | ((latche << 1) & 2));
setmirror((latche >> 7) & 1);
setchr8(0);
}
void Mapper97_Init(CartInfo *info) {
Latch_Init(info, M97Sync, ~0, 0x8000, 0xFFFF, 0, 0);
}
//------------------ Map 101 ---------------------------
static void M101Sync(void) {
setprg32(0x8000, 0);
setchr8(latche);
}
void Mapper101_Init(CartInfo *info) {
Latch_Init(info, M101Sync, ~0, 0x6000, 0x7FFF, 0, 0);
Latch_Init(info, M97Sync, ~0, 0x8000, 0xBFFF, 0, 0);
}
//------------------ Map 107 ---------------------------

View File

@ -70,8 +70,7 @@ void UNLEDU2000_Init(CartInfo *info) {
WRAM = (uint8*)FCEU_gmalloc(32768);
SetupCartPRGMapping(0x10, WRAM, 32768, 1);
if (info->battery) {
info->SaveGame[0] = WRAM;
info->SaveGameLen[0] = 32768;
info->addSaveGameBuf( WRAM, 32768 );
}
AddExState(WRAM, 32768, 0, "WRAM");
AddExState(StateRegs, ~0, 0, 0);

View File

@ -141,8 +141,7 @@ void Mapper6_Init(CartInfo *info) {
SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1);
AddExState(WRAM, WRAMSIZE, 0, "WRAM");
if (info->battery) {
info->SaveGame[0] = WRAM;
info->SaveGameLen[0] = WRAMSIZE;
info->addSaveGameBuf( WRAM, WRAMSIZE );
}
AddExState(&StateRegs, ~0, 0, 0);

View File

@ -28,17 +28,19 @@
static uint8 DRegs[4];
static uint8 Buffer, BufferShift;
static uint32 WRAMSIZE;
static uint32 WRAMSIZE=0;
static uint8 *WRAM = NULL;
static int kanji_pos, kanji_page, r40C0;
static int IRQa, IRQCount;
FCEU_MAYBE_UNUSED
static DECLFW(MBWRAM) {
if (!(DRegs[3] & 0x10))
Page[A >> 11][A] = V;
}
FCEU_MAYBE_UNUSED
static DECLFR(MAWRAM) {
if (DRegs[3] & 0x10)
return X.DB;
@ -254,8 +256,7 @@ void FNS_Init(CartInfo *info) {
SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1);
AddExState(WRAM, WRAMSIZE, 0, "WRAM");
info->SaveGame[0] = WRAM;
info->SaveGameLen[0] = WRAMSIZE;
info->addSaveGameBuf( WRAM, WRAMSIZE );
AddExState(DRegs, 4, 0, "DREG");
AddExState(&lreset, 8, 1, "LRST");

88
src/boards/inx007t.cpp Normal file
View File

@ -0,0 +1,88 @@
/* FCE Ultra - NES/Famicom Emulator
*
* Copyright notice for this file:
* Copyright (C) 2022 Cluster
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* NES 2.0 Mapper 470 denotes the INX_007T_V01 multicart circuit board,
* used for the Retro-Bit re-release of Battletoads and Double Dragon.
* It is basically AOROM with an additional outer bank register at $5000-$5FFF
* whose data selects the 256 KiB outer bank.
*
* $5000-$5FFF
* 7 bit 0
* ---- ----
* xxxx xxOO
* ||
* ++- Select outer 256 KB PRG ROM bank for CPU $8000-$FFFF
*
* $8000-$FFFF
* 7 bit 0
* ---- ----
* xxxM xPPP
* | |||
* | +++- Select inner 32 KB PRG ROM bank for CPU $8000-$FFFF
* +------ Select 1 KB VRAM page for all 4 nametables
*
*/
#include "mapinc.h"
static uint8 latch_out, latch_in;
static void INX_007T_Sync() {
setprg32(0x8000, (latch_in & 0b111) | (latch_out << 3));
setmirror(MI_0 + ((latch_in >> 4) & 1));
setchr8(0);
}
static void StateRestore(int version) {
INX_007T_Sync();
}
static DECLFW(INX_007T_WriteLow)
{
latch_out = V;
INX_007T_Sync();
}
static DECLFW(INX_007T_WriteHi)
{
latch_in = V;
INX_007T_Sync();
}
static void INX_007T_Power(void) {
latch_in = latch_out = 0;
INX_007T_Sync();
SetReadHandler(0x8000, 0xFFFF, CartBR);
SetWriteHandler(0x5000,0x5FFF, INX_007T_WriteLow);
SetWriteHandler(0x8000, 0xFFFF, INX_007T_WriteHi);
}
static void INX_007T_Reset(void) {
latch_in = latch_out = 0;
INX_007T_Sync();
}
void INX_007T_Init(CartInfo *info) {
info->Power = INX_007T_Power;
info->Reset = INX_007T_Reset;
GameStateRestore = StateRestore;
SetupCartMirroring(MI_0, 0, NULL);
AddExState(&latch_out, 1, 0, "LATO");
AddExState(&latch_in, 1, 0, "LATI");
}

View File

@ -306,8 +306,7 @@ static void GenMMC1Init(CartInfo *info, int prg, int chr, int wram, int bram) {
SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1);
AddExState(WRAM, WRAMSIZE, 0, "WRAM");
if (bram) {
info->SaveGame[0] = WRAM + NONBRAMSIZE;
info->SaveGameLen[0] = bram * 1024;
info->addSaveGameBuf( WRAM + NONBRAMSIZE, bram * 1024 );
}
}
if (!chr) {

View File

@ -25,7 +25,7 @@
static uint8 is10;
static uint8 creg[4], latch0, latch1, preg, mirr;
static uint8 *WRAM = NULL;
static uint32 WRAMSIZE;
static uint32 WRAMSIZE=0;
static SFORMAT StateRegs[] =
{
@ -130,8 +130,7 @@ void Mapper10_Init(CartInfo *info) {
SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1);
AddExState(WRAM, WRAMSIZE, 0, "WRAM");
if (info->battery) {
info->SaveGame[0] = WRAM;
info->SaveGameLen[0] = WRAMSIZE;
info->addSaveGameBuf( WRAM, WRAMSIZE );
}
GameStateRestore = StateRestore;
AddExState(&StateRegs, ~0, 0, 0);

View File

@ -324,8 +324,7 @@ void GenMMC3_Init(CartInfo *info, int prg, int chr, int wram, int battery) {
if (battery) {
mmc3opts |= 2;
info->SaveGame[0] = WRAM;
info->SaveGameLen[0] = WRAMSIZE;
info->addSaveGameBuf( WRAM, WRAMSIZE );
}
// KT-008 boards hack 2-in-1, TODO assign to new ines mapper, most dump of KT-boards on the net are mapper 4, so need database or goodnes fix support
@ -364,8 +363,10 @@ static void M4Power(void) {
void Mapper4_Init(CartInfo *info) {
int ws = 8;
if ((info->CRC32 == 0x93991433 || info->CRC32 == 0xaf65aa84)) {
FCEU_printf("Low-G-Man can not work normally in the iNES format.\nThis game has been recognized by its CRC32 value, and the appropriate changes will be made so it will run.\nIf you wish to hack this game, you should use the UNIF format for your hack.\n\n");
if (info->ines2) {
ws = (info->wram_size + info->battery_wram_size) / 1024;
} else if ((info->CRC32 == 0x93991433 || info->CRC32 == 0xaf65aa84)) {
FCEU_printf("Low-G-Man can not work normally in the iNES format.\nThis game has been recognized by its CRC32 value, and the appropriate changes will be made so it will run.\nIf you wish to hack this game, you should use the NES 2.0 format for your hack.\n\n");
ws = 0;
}
GenMMC3_Init(info, 512, 256, ws, info->battery);
@ -499,38 +500,38 @@ void Mapper44_Init(CartInfo *info) {
// ---------------------------- Mapper 45 -------------------------------
static void M45CW(uint32 A, uint8 V) {
if (!UNIFchrrama) {
uint32 NV = V;
if (EXPREGS[2] & 8)
NV &= (1 << ((EXPREGS[2] & 7) + 1)) - 1;
else
if (EXPREGS[2])
NV &= 0; // hack ;( don't know exactly how it should be
NV |= EXPREGS[0] | ((EXPREGS[2] & 0xF0) << 4);
setchr1(A, NV);
} else
// setchr8(0); // i don't know what cart need this, but a new one need other lol
setchr1(A, V);
uint32 NV = V;
const int mask = ((EXPREGS[2] & 0x0F) > 7)
? ((1 << (EXPREGS[2] & 0x0F) << 3) - 1)
: 0;
NV |= (EXPREGS[0] & mask) | ((EXPREGS[2] & 0xF0) << 4);
setchr1(A, NV);
}
static void M45PW(uint32 A, uint8 V) {
uint32 MV = V & ((EXPREGS[3] & 0x3F) ^ 0x3F);
MV |= EXPREGS[1];
if(UNIFchrrama)
MV |= ((EXPREGS[2] & 0x40) << 2);
uint32 MV = V;
const int mask = (EXPREGS[3] & 0x3F) ^ 0x3F;
MV |= (EXPREGS[1] & 0x3F & mask) | (EXPREGS[1] & 0xC0);
setprg8(A, MV);
// FCEU_printf("1:%02x 2:%02x 3:%02x A=%04x V=%03x\n",EXPREGS[1],EXPREGS[2],EXPREGS[3],A,MV);
}
static DECLFW(M45Write) {
if (EXPREGS[3] & 0x40) {
WRAM[A - 0x6000] = V;
return;
WRAM[A - 0x6000] = V;
if (!(A & 1))
{
if (EXPREGS[3] & 0x40) {
WRAM[A - 0x6000] = V;
return;
}
EXPREGS[EXPREGS[4]] = V;
EXPREGS[4] = (EXPREGS[4] + 1) & 3;
FixMMC3PRG(MMC3_cmd);
FixMMC3CHR(MMC3_cmd);
}
else {
// lock reset
EXPREGS[3] &= ~0x40;
}
EXPREGS[EXPREGS[4]] = V;
EXPREGS[4] = (EXPREGS[4] + 1) & 3;
FixMMC3PRG(MMC3_cmd);
FixMMC3CHR(MMC3_cmd);
}
static DECLFR(M45Read) {
@ -551,7 +552,7 @@ static void M45Reset(void) {
static void M45Power(void) {
GenMMC3Power();
EXPREGS[0] = EXPREGS[1] = EXPREGS[2] = EXPREGS[3] = EXPREGS[4] = EXPREGS[5] = 0;
SetWriteHandler(0x5000, 0x7FFF, M45Write);
SetWriteHandler(0x6000, 0x7FFF, M45Write);
SetReadHandler(0x5000, 0x5FFF, M45Read);
}
@ -861,32 +862,52 @@ void Mapper119_Init(CartInfo *info) {
// ---------------------------- Mapper 134 ------------------------------
static void M134PW(uint32 A, uint8 V) {
setprg8(A, (V & 0x1F) | ((EXPREGS[0] & 2) << 4));
if ((EXPREGS[1] & 0x88) == 0x80)
setprg32(A, (EXPREGS[0] & 0x10) | ((EXPREGS[1] & 2) << 2)); // NROM-256
else if ((EXPREGS[1] & 0x88) == 0x88)
setprg16(0x8000 | (A & 0x4000), ((EXPREGS[0] & 0x10) << 1) | ((V & 0x10) >> 1) | ((EXPREGS[1] & 3) << 3)); // NROM-128
else if (EXPREGS[1] & 4)
setprg8(A, ((EXPREGS[0] & 0x10) << 2) | (V & 0x0F) | ((EXPREGS[1] & 3) << 4)); // MMC3 128KB mask
else
setprg8(A, ((EXPREGS[0] & 0x10) << 2) | (V & 0x1F) | ((EXPREGS[1] & 2) << 4)); // MMC3 256KB mask
}
static void M134CW(uint32 A, uint8 V) {
setchr1(A, (V & 0xFF) | ((EXPREGS[0] & 0x20) << 3));
// CNROM mode. Unclear. Untested.
if (EXPREGS[0] & 0x08)
setchr8(EXPREGS[2]);
else if (EXPREGS[1] & 0x40)
setchr1(A, ((EXPREGS[0] & 0x20) << 4) | (V & 0x7F) | ((EXPREGS[1] & 0x30) << 3)); // 128KB mask
else
setchr1(A, ((EXPREGS[0] & 0x20) << 4) | (V & 0xFF) | ((EXPREGS[1] & 0x20) << 3)); // 256KB mask
}
static DECLFW(M134Write) {
EXPREGS[0] = V;
if (EXPREGS[0] & 0x80)
{
// locked (except $6002.0-1)
if ((A & 3) == 2)
EXPREGS[2] = (EXPREGS[2] & 0xFC) | (V & 3);
return;
}
EXPREGS[A & 3] = V;
FixMMC3CHR(MMC3_cmd);
FixMMC3PRG(MMC3_cmd);
}
static void M134Power(void) {
EXPREGS[0] = 0;
EXPREGS[0] = EXPREGS[1] = EXPREGS[2] = EXPREGS[3] = 0;
GenMMC3Power();
SetWriteHandler(0x6001, 0x6001, M134Write);
SetWriteHandler(0x6000, 0x7FFF, M134Write);
}
static void M134Reset(void) {
EXPREGS[0] = 0;
EXPREGS[0] = EXPREGS[1] = EXPREGS[2] = EXPREGS[3] = 0;
MMC3RegReset();
}
void Mapper134_Init(CartInfo *info) {
GenMMC3_Init(info, 256, 256, 0, 0);
GenMMC3_Init(info, 512, 512, 0, 0);
pwrap = M134PW;
cwrap = M134CW;
info->Power = M134Power;
@ -1137,20 +1158,73 @@ void Mapper198_Init(CartInfo *info) {
info->Power = M195Power;
}
// ---------------------------- Mapper 205 ------------------------------
// GN-45 BOARD
/* ---------------------------- Mapper 205 ------------------------------ */
/* UNIF boardname BMC-JC-016-2
https://wiki.nesdev.com/w/index.php/INES_Mapper_205 */
/* 2023-02 : Update reg write logic and add solder pad */
static void M205PW(uint32 A, uint8 V) {
// GN-30A - íà÷àëüíàÿ ìàñêà äîëæíà áûòü 1F + àïïàðàòíûé ïåðåêëþ÷àòåëü íà øèíå àäðåñà
setprg8(A, (V & 0x0f) | EXPREGS[0]);
uint8 bank = V & ((EXPREGS[0] & 0x02) ? 0x0F : 0x1F);
if (PRGsize[1]) { // split-rom variant
setprg8r((EXPREGS[0] & 3) ? (EXPREGS[0] - 1) : 0, A, bank);
} else {
setprg8(A, EXPREGS[0] << 4 | bank);
}
}
static void M205CW(uint32 A, uint8 V) {
// GN-30A - íà÷àëüíàÿ ìàñêà äîëæíà áûòü FF
uint8 bank = V & ((EXPREGS[0] & 0x02) ? 0x7F : 0xFF);
if (CHRsize[1]) { // split-rom variant
setchr1r((EXPREGS[0] & 3) ? (EXPREGS[0] - 1) : 0, A, bank);
} else {
setchr1(A, (EXPREGS[0] << 7) | bank);
}
}
static DECLFW(M205Write) {
EXPREGS[0] = V & 3;
if (V & 1) {
EXPREGS[0] |= EXPREGS[1];
}
CartBW(A, V);
FixMMC3PRG(MMC3_cmd);
FixMMC3CHR(MMC3_cmd);
}
static void M205Reset(void) {
EXPREGS[0] = 0;
EXPREGS[1] ^= 2; /* solder pad */
MMC3RegReset();
}
static void M205Power(void) {
EXPREGS[0] = EXPREGS[1] = 0;
GenMMC3Power();
SetWriteHandler(0x6000, 0x7FFF, M205Write);
}
void Mapper205_Init(CartInfo *info) {
GenMMC3_Init(info, 256, 128, 0, 0);
pwrap = M205PW;
cwrap = M205CW;
info->Power = M205Power;
info->Reset = M205Reset;
AddExState(EXPREGS, 2, 0, "EXPR");
}
/* --------------------------- GN-45 BOARD ------------------------------ */
/* Mapper 361 and 366, previously assigned as Mapper 205 */
static void GN45PW(uint32 A, uint8 V) {
setprg8(A, (V & 0x0f) | EXPREGS[0]);
}
static void GN45CW(uint32 A, uint8 V) {
setchr1(A, (V & 0x7F) | (EXPREGS[0] << 3));
}
static DECLFW(M205Write0) {
static DECLFW(GN45Write0) {
if (EXPREGS[2] == 0) {
EXPREGS[0] = A & 0x30;
EXPREGS[2] = A & 0x80;
@ -1160,7 +1234,7 @@ static DECLFW(M205Write0) {
CartBW(A, V);
}
static DECLFW(M205Write1) {
static DECLFW(GN45Write1) {
if (EXPREGS[2] == 0) {
EXPREGS[0] = V & 0x30;
FixMMC3PRG(MMC3_cmd);
@ -1169,23 +1243,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");
}
@ -1376,6 +1450,7 @@ static DECLFW(M406IRQWrite) {
MMC3_IRQWrite((A & 0xFFFE) | ((A & 2) >> 1), V);
}
FCEU_MAYBE_UNUSED
static DECLFW(M406Write) {
}

View File

@ -307,8 +307,7 @@ cartdata MMC5CartList[] =
#define MMC5_NOCARTS (sizeof(MMC5CartList) / sizeof(MMC5CartList[0]))
int DetectMMC5WRAMSize(uint32 crc32) {
int x;
for (x = 0; x < MMC5_NOCARTS; x++) {
for (size_t x = 0; x < MMC5_NOCARTS; x++) {
if (crc32 == MMC5CartList[x].crc32) {
if(MMC5CartList[x].size > 1)
FCEU_printf(" >8KB external WRAM present. Use UNIF if you hack the ROM image.\n");
@ -425,7 +424,7 @@ static void MMC5PRG(void) {
switch (mmc5psize & 3) {
case 0:
MMC5ROMWrProtect[0] = MMC5ROMWrProtect[1] = MMC5ROMWrProtect[2] = MMC5ROMWrProtect[3] = 1;
setprg32(0x8000, ((PRGBanks[1] & 0x7F) >> 2));
setprg32(0x8000, ((PRGBanks[3] & 0x7F) >> 2));
for (x = 0; x < 4; x++)
MMC5MemIn[1 + x] = 1;
break;
@ -904,14 +903,14 @@ static void GenMMC5Power(void) {
PRGBanks.fill(0xFF);
WRAMPage = 0;
CHRBanksA.fill(0xFF);
CHRBanksB.fill(0xFF);
CHRBanksA.fill(0);
CHRBanksB.fill(0);
WRAMMaskEnable.fill(0xFF);
mmc5ABMode = 0;
IRQScanline = 0;
IRQEnable = 0;
CHRMode = 0;
NTAMirroring = NTFill = ATFill = 0xFF;
NTAMirroring = NTFill = ATFill = 0;
MMC5IRQR = 0;
MMC5LineCounter = 0;
mmc5psize = mmc5vsize = 3;
@ -1022,22 +1021,23 @@ static void GenMMC5_Init(CartInfo *info, int wsize, int battery) {
MMC5battery = battery;
if (battery) {
info->SaveGame[0] = WRAM;
uint32 saveGameSize = 0;
if (info->ines2)
{
info->SaveGameLen[0] = info->battery_wram_size;
saveGameSize = info->battery_wram_size;
}
else
{
//this is more complex than it looks because it MUST BE, I guess. is there an assumption that only 8KB of 16KB is battery backed? That's NES mappers for you
//I added 64KB for the new 64KB homebrews
if (wsize <= 16)
info->SaveGameLen[0] = 8192;
saveGameSize = 8192;
else if(wsize == 64)
info->SaveGameLen[0] = 64*1024;
saveGameSize = 64*1024;
else
info->SaveGameLen[0] = 32768;
saveGameSize = 32768;
}
info->addSaveGameBuf( WRAM, saveGameSize );
}
MMC5HackVROMMask = CHRmask4[0];

View File

@ -429,10 +429,8 @@ void Mapper19_Init(CartInfo *info) {
AddExState(N106_StateRegs, ~0, 0, 0);
if (info->battery) {
info->SaveGame[0] = WRAM;
info->SaveGameLen[0] = 8192;
info->SaveGame[1] = IRAM;
info->SaveGameLen[1] = 128;
info->addSaveGameBuf( WRAM, 8192 );
info->addSaveGameBuf( IRAM, 128 );
}
}

View File

@ -320,8 +320,7 @@ void UNLOneBus_Init(CartInfo *info) {
SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1);
AddExState(WRAM, WRAMSIZE, 0, "WRAM");
if (info->battery) {
info->SaveGame[0] = WRAM;
info->SaveGameLen[0] = WRAMSIZE;
info->addSaveGameBuf( WRAM, WRAMSIZE );
}
}
}

View File

@ -54,8 +54,7 @@ void SA9602B_Init(CartInfo *info) {
GenMMC3_Init(info, 512, 0, 0, 0);
pwrap = SA9602BPW;
mmc3opts |= 2;
info->SaveGame[0] = UNIFchrrama;
info->SaveGameLen[0] = 32 * 1024;
info->addSaveGameBuf( UNIFchrrama, 32 * 1024 );
info->Power = SA9602BPower;
AddExState(EXPREGS, 2, 0, "EXPR");
}

View File

@ -24,7 +24,7 @@ static uint8 preg[8];
static uint8 IRQa;
static int16 IRQCount, IRQLatch;
static uint8 *WRAM = NULL;
static uint32 WRAMSIZE;
static uint32 WRAMSIZE=0;
/*
static uint8 *CHRRAM = NULL;
static uint32 CHRRAMSIZE;
@ -187,8 +187,7 @@ void UNLSB2000_Init(CartInfo *info) {
SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1);
AddExState(WRAM, WRAMSIZE, 0, "WRAM");
if (info->battery) {
info->SaveGame[0] = WRAM;
info->SaveGameLen[0] = WRAMSIZE;
info->addSaveGameBuf( WRAM, WRAMSIZE );
}
AddExState(&StateRegs, ~0, 0, 0);

View File

@ -21,7 +21,7 @@
#include "mapinc.h"
static uint8 *WRAM = NULL;
static uint32 WRAMSIZE;
static uint32 WRAMSIZE=0;
unsigned int *GetKeyboard(void); // FIXME: 10/28 - now implemented in SDL as well. should we rename this to a FCEUI_* function?
@ -90,8 +90,7 @@ void Transformer_Init(CartInfo *info) {
WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE);
SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1);
if (info->battery) {
info->SaveGame[0] = WRAM;
info->SaveGameLen[0] = WRAMSIZE;
info->addSaveGameBuf( WRAM, WRAMSIZE );
}
AddExState(WRAM, WRAMSIZE, 0, "WRAM");
}

View File

@ -1,7 +1,7 @@
/* FCE Ultra - NES/Famicom Emulator
*
* Copyright notice for this file:
* Copyright (C) 2014 CaitSith2
* Copyright (C) 2014 CaitSith2, 2022 Cluster
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -19,7 +19,7 @@
*/
/*
* Roms still using NES 1.0 format should be loaded as 32K CHR RAM.
* Roms still using NES 1.0 format should be loaded as 8K CHR RAM.
* Roms defined under NES 2.0 should use the VRAM size field, defining 7, 8 or 9, based on how much VRAM should be present.
* UNIF doesn't have this problem, because unique board names can define this information.
* The UNIF names are UNROM-512-8K, UNROM-512-16K and UNROM-512-32K
@ -28,6 +28,7 @@
* Known games to use this board are:
* Battle Kid 2: Mountain of Torment (512K PRG, 8K CHR RAM, Horizontal Mirroring, Flash disabled)
* Study Hall (128K PRG (in 512K flash chip), 8K CHR RAM, Horizontal Mirroring, Flash enabled)
* Nix: The Paradox Relic (512 PRG, 8K CHR RAM, Vertical Mirroring, Flash enabled)
* Although Xmas 2013 uses a different board, where LEDs can be controlled (with writes to the $8000-BFFF space),
* it otherwise functions identically.
*/
@ -35,211 +36,159 @@
#include "mapinc.h"
#include "../ines.h"
static uint8 latche, latcheinit, bus_conflict, chrram_mask, software_id=false;
const int ROM_CHIP = 0x00;
const int CFI_CHIP = 0x10;
const int FLASH_CHIP = 0x11;
const int FLASH_SECTOR_SIZE = 4 * 1024;
static uint8 flash_save, flash_state, flash_id_mode, latche, bus_conflict;
static uint16 latcha;
static uint8 *flashdata;
static uint32 *flash_write_count;
static uint8 *FlashPage[32];
//static uint32 *FlashWriteCountPage[32];
//static uint8 flashloaded = false;
static uint8 *flash_data;
static uint16 flash_buffer_a[10];
static uint8 flash_buffer_v[10];
static uint8 flash_id[2];
static uint8 flash_save=0, flash_state=0, flash_mode=0, flash_bank;
static void (*WLSync)(void);
static void (*WHSync)(void);
static INLINE void setfpageptr(int s, uint32 A, uint8 *p) {
uint32 AB = A >> 11;
int x;
if (p)
for (x = (s >> 1) - 1; x >= 0; x--) {
FlashPage[AB + x] = p - A;
}
static void UNROM512_Sync() {
int chip;
if (flash_save)
chip = !flash_id_mode ? FLASH_CHIP : CFI_CHIP;
else
for (x = (s >> 1) - 1; x >= 0; x--) {
FlashPage[AB + x] = 0;
}
}
void setfprg16(uint32 A, uint32 V) {
if (PRGsize[0] >= 16384) {
V &= PRGmask16[0];
setfpageptr(16, A, flashdata ? (&flashdata[V << 14]) : 0);
} else {
uint32 VA = V << 3;
int x;
for (x = 0; x < 8; x++)
setfpageptr(2, A + (x << 11), flashdata ? (&flashdata[((VA + x) & PRGmask2[0]) << 11]) : 0);
}
}
void inc_flash_write_count(uint8 bank, uint32 A)
{
flash_write_count[(bank*4) + ((A&0x3000)>>12)]++;
if(!flash_write_count[(bank*4) + ((A&0x3000)>>12)])
flash_write_count[(bank*4) + ((A&0x3000)>>12)]++;
}
uint32 GetFlashWriteCount(uint8 bank, uint32 A)
{
return flash_write_count[(bank*4) + ((A&0x3000)>>12)];
chip = ROM_CHIP;
setprg16r(chip, 0x8000, latche);
setprg16r(chip, 0xc000, ~0);
setchr8(latche >> 5);
setmirror(MI_0 + ((latche >> 7) & 1));
}
static void StateRestore(int version) {
WHSync();
UNROM512_Sync();
}
static DECLFW(UNROM512LLatchWrite)
static DECLFW(UNROM512FlashWrite)
{
latche = V;
latcha = A;
WLSync();
if (flash_state < sizeof(flash_buffer_a) / sizeof(flash_buffer_a[0])) {
flash_buffer_a[flash_state] = (A & 0x3FFF) | ((latche & 1) << 14);
flash_buffer_v[flash_state] = V;
flash_state++;
// enter flash ID mode
if ((flash_state == 2) &&
(flash_buffer_a[0] == 0x5555) && (flash_buffer_v[0] == 0xAA) &&
(flash_buffer_a[1] == 0x2AAA) && (flash_buffer_v[1] == 0x55) &&
(flash_buffer_a[1] == 0x5555) && (flash_buffer_v[1] == 0x90)) {
flash_id_mode = 0;
flash_state = 0;
}
// erase sector
if ((flash_state == 6) &&
(flash_buffer_a[0] == 0x5555) && (flash_buffer_v[0] == 0xAA) &&
(flash_buffer_a[1] == 0x2AAA) && (flash_buffer_v[1] == 0x55) &&
(flash_buffer_a[2] == 0x5555) && (flash_buffer_v[2] == 0x80) &&
(flash_buffer_a[3] == 0x5555) && (flash_buffer_v[3] == 0xAA) &&
(flash_buffer_a[4] == 0x2AAA) && (flash_buffer_v[4] == 0x55) &&
(flash_buffer_v[5] == 0x30)) {
int offset = &Page[A >> 11][A] - flash_data;
int sector = offset / FLASH_SECTOR_SIZE;
for (int i = sector * FLASH_SECTOR_SIZE; i < (sector + 1) * FLASH_SECTOR_SIZE; i++)
flash_data[i % PRGsize[ROM_CHIP]] = 0xFF;
FCEU_printf("Flash sector #%d is erased (0x%08x - 0x%08x).\n", sector, offset, offset + FLASH_SECTOR_SIZE);
}
// erase chip
if ((flash_state == 6) &&
(flash_buffer_a[0] == 0x5555) && (flash_buffer_v[0] == 0xAA) &&
(flash_buffer_a[1] == 0x2AAA) && (flash_buffer_v[1] == 0x55) &&
(flash_buffer_a[2] == 0x5555) && (flash_buffer_v[2] == 0x80) &&
(flash_buffer_a[3] == 0x5555) && (flash_buffer_v[3] == 0xAA) &&
(flash_buffer_a[4] == 0x2AAA) && (flash_buffer_v[4] == 0x55) &&
(flash_buffer_a[4] == 0x5555) && (flash_buffer_v[4] == 0x10)) {
memset(flash_data, 0xFF, PRGsize[ROM_CHIP]);
FCEU_printf("Flash chip erased.\n");
flash_state = 0;
}
// write byte
if ((flash_state == 4) &&
(flash_buffer_a[0] == 0x5555) && (flash_buffer_v[0] == 0xAA) &&
(flash_buffer_a[1] == 0x2AAA) && (flash_buffer_v[1] == 0x55) &&
(flash_buffer_a[2] == 0x5555) && (flash_buffer_v[2] == 0xA0)) {
int offset = &Page[A >> 11][A] - flash_data;
if (CartBR(A) != 0xFF) {
FCEU_PrintError("Error: can't write to 0x%08x, flash sector is not erased.\n", offset);
}
else {
CartBW(A, V);
}
flash_state = 0;
}
}
// not a command
if (((A & 0xFFF) != 0x0AAA) && ((A & 0xFFF) != 0x0555)) {
flash_state = 0;
}
// reset
if (V == 0xF0) {
flash_state = 0;
flash_id_mode = 0;
}
UNROM512_Sync();
}
static DECLFW(UNROM512HLatchWrite)
{
if (bus_conflict)
latche = (V == CartBR(A)) ? V : 0;
latche = V & CartBR(A);
else
latche = V;
latcha = A;
WHSync();
}
static DECLFR(UNROM512LatchRead)
{
uint8 flash_id[3]={0xB5,0xB6,0xB7};
if(software_id)
{
if(A&1)
return flash_id[ROM_size>>4];
else
return 0xBF;
}
if(flash_save)
{
if(A < 0xC000)
{
if(GetFlashWriteCount(flash_bank,A))
return FlashPage[A >> 11][A];
}
else
{
if(GetFlashWriteCount(ROM_size-1,A))
return FlashPage[A >> 11][A];
}
}
return Page[A >> 11][A];
UNROM512_Sync();
}
static void UNROM512LatchPower(void) {
latche = latcheinit;
WHSync();
SetReadHandler(0x8000, 0xFFFF, UNROM512LatchRead);
latche = 0;
UNROM512_Sync();
SetReadHandler(0x8000, 0xFFFF, CartBR);
if(!flash_save)
SetWriteHandler(0x8000, 0xFFFF, UNROM512HLatchWrite);
else
{
SetWriteHandler(0x8000,0xBFFF,UNROM512LLatchWrite);
SetWriteHandler(0x8000,0xBFFF,UNROM512FlashWrite);
SetWriteHandler(0xC000,0xFFFF,UNROM512HLatchWrite);
}
}
static void UNROM512LatchClose(void) {
if(flash_write_count)
FCEU_gfree(flash_write_count);
if(flashdata)
FCEU_gfree(flashdata);
flash_write_count = NULL;
flashdata = NULL;
if(flash_data)
FCEU_gfree(flash_data);
flash_data = NULL;
}
static void UNROM512LSync() {
int erase_a[5]={0x9555,0xAAAA,0x9555,0x9555,0xAAAA};
int erase_d[5]={0xAA,0x55,0x80,0xAA,0x55};
int erase_b[5]={1,0,1,1,0};
if(flash_mode==0)
{
if((latcha == erase_a[flash_state]) && (latche == erase_d[flash_state]) && (flash_bank == erase_b[flash_state]))
{
flash_state++;
if(flash_state == 5)
{
flash_mode=1;
}
}
else if ((flash_state==2)&&(latcha==0x9555)&&(latche==0xA0)&&(flash_bank==1))
{
flash_state++;
flash_mode=2;
}
else if ((flash_state==2)&&(latcha==0x9555)&&(latche==0x90)&&(flash_bank==1))
{
flash_state=0;
software_id=true;
}
else
{
if(latche==0xF0)
software_id=false;
flash_state=0;
}
}
else if(flash_mode==1) //Chip Erase or Sector Erase
{
if(latche==0x30)
{
inc_flash_write_count(flash_bank,latcha);
memset(&FlashPage[(latcha & 0xF000) >> 11][latcha & 0xF000],0xFF,0x1000);
}
else if (latche==0x10)
{
for(uint32 i=0;i<(ROM_size*4);i++)
inc_flash_write_count(i>>2,i<<12);
memset(flashdata,0xFF,ROM_size*0x4000); //Erasing the rom chip as instructed. Crash rate calulated to be 99.9% :)
}
flash_state=0;
flash_mode=0;
}
else if(flash_mode==2) //Byte Program
{
if(!GetFlashWriteCount(flash_bank,latcha))
{
inc_flash_write_count(flash_bank,latcha);
memcpy(&FlashPage[(latcha & 0xF000) >> 11][latcha & 0xF000],&Page[(latcha & 0xF000)>>11][latcha & 0xF000],0x1000);
}
FlashPage[latcha>>11][latcha]&=latche;
flash_state=0;
flash_mode=0;
}
}
static void UNROM512HSync()
static void UNROM512_FlashReset(void)
{
flash_bank=latche&(ROM_size-1);
setprg16(0x8000, flash_bank);
setprg16(0xc000, ~0);
setfprg16(0x8000, flash_bank);
setfprg16(0xC000, ~0);
setchr8r(0, (latche & chrram_mask) >> 5);
setmirror(MI_0+(latche>>7));
if (flash_data)
{
size_t flash_size = PRGsize[ROM_CHIP];
// Copy ROM to flash data
for (size_t i = 0; i < flash_size; i++) {
flash_data[i] = PRGptr[ROM_CHIP][i];
}
}
}
void UNROM512_Init(CartInfo *info) {
flash_state=0;
flash_bank=0;
flash_save=info->battery;
info->Power = UNROM512LatchPower;
info->Close = UNROM512LatchClose;
GameStateRestore = StateRestore;
if(info->vram_size == 8192)
chrram_mask = 0;
else if (info->vram_size == 16384)
chrram_mask = 0x20;
else
chrram_mask = 0x60;
flash_state = 0;
flash_id_mode = 0;
flash_save = info->battery;
bus_conflict = !info->battery; // Is it required by any game?
int mirror = (head.ROM_type & 1) | ((head.ROM_type & 8) >> 2);
switch (mirror)
@ -258,28 +207,29 @@ void UNROM512_Init(CartInfo *info) {
break;
}
bus_conflict = !info->battery;
latcheinit = 0;
WLSync = UNROM512LSync;
WHSync = UNROM512HSync;
info->Power = UNROM512LatchPower;
info->Close = UNROM512LatchClose;
GameStateRestore = StateRestore;
if(flash_save)
{
flashdata = (uint8*)FCEU_gmalloc(ROM_size*0x4000);
flash_write_count = (uint32*)FCEU_gmalloc(ROM_size*4*sizeof(uint32));
info->SaveGame[0] = (uint8*)flash_write_count;
info->SaveGame[1] = flashdata;
info->SaveGameLen[0] = ROM_size*4*sizeof(uint32);
info->SaveGameLen[1] = ROM_size*0x4000;
AddExState(flash_write_count,ROM_size*4*sizeof(uint32),0,"FLASH_WRITE_COUNT");
AddExState(flashdata,ROM_size*0x4000,0,"FLASH_DATA");
AddExState(&flash_state,1,0,"FLASH_STATE");
AddExState(&flash_mode,1,0,"FLASH_MODE");
AddExState(&flash_bank,1,0,"FLASH_BANK");
AddExState(&latcha,2,0,"LATA");
// Allocate memory for flash
size_t flash_size = PRGsize[ROM_CHIP];
flash_data = (uint8*)FCEU_gmalloc(flash_size);
// Copy ROM to flash data
for (size_t i = 0; i < flash_size; i++) {
flash_data[i] = PRGptr[ROM_CHIP][i];
}
SetupCartPRGMapping(FLASH_CHIP, flash_data, flash_size, 1);
info->addSaveGameBuf( flash_data, flash_size, UNROM512_FlashReset );
flash_id[0] = 0xBF;
flash_id[1] = 0xB5 + (ROM_size >> 4);
SetupCartPRGMapping(CFI_CHIP, flash_id, sizeof(flash_id), 0);
AddExState(flash_data, flash_size, 0, "FLSH");
AddExState(&flash_state, sizeof(flash_state), 0, "FLST");
AddExState(&flash_id_mode, sizeof(flash_id_mode), 0, "FLMD");
AddExState(flash_buffer_a, sizeof(flash_buffer_a), 0, "FLBA");
AddExState(flash_buffer_v, sizeof(flash_buffer_v), 0, "FLBV");
}
AddExState(&latche, 1, 0, "LATC");
AddExState(&bus_conflict, 1, 0, "BUSC");
AddExState(&latcha, sizeof(latcha), 0, "LATA");
AddExState(&latche, sizeof(latche), 0, "LATC");
AddExState(&bus_conflict, sizeof(bus_conflict), 0, "BUSC");
}

View File

@ -23,7 +23,7 @@
static bool isPirate;
static uint8 is22, reg1mask, reg2mask;
static uint16 IRQCount;
static uint8 IRQLatch, IRQa;
static uint8 IRQLatch, IRQa, IRQMode;
static uint8 prgreg[2], chrreg[8];
static uint16 chrhi[8];
static uint8 regcmd, irqcmd, mirr, big_bank;
@ -45,6 +45,7 @@ static SFORMAT StateRegs[] =
{ &IRQCount, 2, "IRQC" },
{ &IRQLatch, 1, "IRQL" },
{ &IRQa, 1, "IRQA" },
{ &IRQMode, 1, "IRQM" },
{ 0 }
};
@ -115,7 +116,7 @@ static DECLFW(VRC24Write) {
case 0x9003: regcmd = V; Sync(); break;
case 0xF000: X6502_IRQEnd(FCEU_IQEXT); IRQLatch &= 0xF0; IRQLatch |= V & 0xF; break;
case 0xF001: X6502_IRQEnd(FCEU_IQEXT); IRQLatch &= 0x0F; IRQLatch |= V << 4; break;
case 0xF002: X6502_IRQEnd(FCEU_IQEXT); acount = 0; IRQCount = IRQLatch; IRQa = V & 2; irqcmd = V & 1; break;
case 0xF002: X6502_IRQEnd(FCEU_IQEXT); acount = 0; IRQCount = IRQLatch; IRQMode = V & 4; IRQa = V & 2; irqcmd = V & 1; break;
case 0xF003: X6502_IRQEnd(FCEU_IQEXT); IRQa = irqcmd; break;
}
}
@ -136,16 +137,28 @@ static void VRC24Power(void) {
void VRC24IRQHook(int a) {
#define LCYCS 341
if (IRQa) {
acount += a * 3;
if (acount >= LCYCS) {
while (acount >= LCYCS) {
acount -= LCYCS;
if (IRQMode) {
acount += a;
while (acount > 0) {
acount--;
IRQCount++;
if (IRQCount & 0x100) {
X6502_IRQBegin(FCEU_IQEXT);
IRQCount = IRQLatch;
}
}
} else {
acount += a * 3;
if (acount >= LCYCS) {
while (acount >= LCYCS) {
acount -= LCYCS;
IRQCount++;
if (IRQCount & 0x100) {
X6502_IRQBegin(FCEU_IQEXT);
IRQCount = IRQLatch;
}
}
}
}
}
}
@ -172,8 +185,7 @@ static void VRC24_Init(CartInfo *info) {
AddExState(WRAM, WRAMSIZE, 0, "WRAM");
if(info->battery) {
info->SaveGame[0]=WRAM;
info->SaveGameLen[0]=WRAMSIZE;
info->addSaveGameBuf( WRAM, WRAMSIZE );
}
AddExState(&StateRegs, ~0, 0, 0);

View File

@ -254,11 +254,10 @@ void QTAi_Init(CartInfo *info) {
AddExState(WRAM, WRAMSIZE, 0, "WRAM");
if (info->battery) {
info->SaveGame[0] = WRAM;
// note, only extrnal cart's SRAM is battery backed, the the part on the main cartridge is just
// an additional work ram. so we may save only half here, but I forgot what part is saved lol, will
// find out later.
info->SaveGameLen[0] = WRAMSIZE;
info->addSaveGameBuf( WRAM, WRAMSIZE );
}
AddExState(&StateRegs, ~0, 0, 0);

View File

@ -25,10 +25,10 @@
static uint8 is26;
static uint8 prg[2], chr[8], mirr;
static uint8 IRQLatch, IRQa, IRQd;
static uint8 IRQLatch, IRQa, IRQd, IRQMode;
static int32 IRQCount, CycleCount;
static uint8 *WRAM = NULL;
static uint32 WRAMSIZE;
static uint32 WRAMSIZE=0;
static SFORMAT StateRegs[] =
{
@ -40,6 +40,7 @@ static SFORMAT StateRegs[] =
{ &IRQLatch, 1, "IRQL" },
{ &IRQCount, 4, "IRQC" },
{ &CycleCount, 4, "CYCC" },
{ &IRQMode, 1, "IRQM" },
{ 0 }
};
@ -109,6 +110,7 @@ static DECLFW(VRC6Write) {
case 0xE003: chr[7] = V; Sync(); break;
case 0xF000: IRQLatch = V; X6502_IRQEnd(FCEU_IQEXT); break;
case 0xF001:
IRQMode = V & 4;
IRQa = V & 2;
IRQd = V & 1;
if (V & 2)
@ -132,13 +134,25 @@ static void VRC6Power(void) {
static void VRC6IRQHook(int a) {
if (IRQa) {
CycleCount += a * 3;
while(CycleCount >= 341) {
CycleCount -= 341;
IRQCount++;
if (IRQCount == 0x100) {
IRQCount = IRQLatch;
X6502_IRQBegin(FCEU_IQEXT);
if (IRQMode) {
CycleCount += a;
while (CycleCount > 0) {
CycleCount--;
IRQCount++;
if (IRQCount & 0x100) {
X6502_IRQBegin(FCEU_IQEXT);
IRQCount = IRQLatch;
}
}
} else {
CycleCount += a * 3;
while(CycleCount >= 341) {
CycleCount -= 341;
IRQCount++;
if (IRQCount == 0x100) {
IRQCount = IRQLatch;
X6502_IRQBegin(FCEU_IQEXT);
}
}
}
}
@ -365,8 +379,7 @@ void Mapper26_Init(CartInfo *info) {
SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1);
AddExState(WRAM, WRAMSIZE, 0, "WRAM");
if (info->battery) {
info->SaveGame[0] = WRAM;
info->SaveGameLen[0] = WRAMSIZE;
info->addSaveGameBuf( WRAM, WRAMSIZE );
}
AddExState(&StateRegs, ~0, 0, 0);

View File

@ -21,10 +21,10 @@
#include "mapinc.h"
static uint8 vrc7idx, preg[3], creg[8], mirr;
static uint8 IRQLatch, IRQa, IRQd;
static uint8 IRQLatch, IRQa, IRQd, IRQMode;
static int32 IRQCount, CycleCount;
static uint8 *WRAM = NULL;
static uint32 WRAMSIZE;
static uint32 WRAMSIZE=0;
#include "emu2413.h"
@ -44,6 +44,7 @@ static SFORMAT StateRegs[] =
{ &IRQCount, 4, "IRQC" },
{ &CycleCount, 4, "CYCC" },
{ (void**)VRC7Sound_saveptr, sizeof(*VRC7Sound) | FCEUSTATE_INDIRECT, "VRC7" },
{ &IRQMode, 1, "IRQM" },
{0}
};
@ -134,6 +135,7 @@ static DECLFW(VRC7Write) {
case 0xE000: mirr = V & 3; Sync(); break;
case 0xE010: IRQLatch = V; X6502_IRQEnd(FCEU_IQEXT); break;
case 0xF000:
IRQMode = V & 4;
IRQa = V & 2;
IRQd = V & 1;
if (V & 2)
@ -165,13 +167,25 @@ static void VRC7Close(void)
static void VRC7IRQHook(int a) {
if (IRQa) {
CycleCount += a * 3;
while(CycleCount >= 341) {
CycleCount -= 341;
IRQCount++;
if (IRQCount == 0x100) {
IRQCount = IRQLatch;
X6502_IRQBegin(FCEU_IQEXT);
if (IRQMode) {
CycleCount += a;
while (CycleCount > 0) {
CycleCount--;
IRQCount++;
if (IRQCount & 0x100) {
X6502_IRQBegin(FCEU_IQEXT);
IRQCount = IRQLatch;
}
}
} else {
CycleCount += a * 3;
while(CycleCount >= 341) {
CycleCount -= 341;
IRQCount++;
if (IRQCount == 0x100) {
IRQCount = IRQLatch;
X6502_IRQBegin(FCEU_IQEXT);
}
}
}
}
@ -190,8 +204,7 @@ void Mapper85_Init(CartInfo *info) {
SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1);
AddExState(WRAM, WRAMSIZE, 0, "WRAM");
if (info->battery) {
info->SaveGame[0] = WRAM;
info->SaveGameLen[0] = WRAMSIZE;
info->addSaveGameBuf( WRAM, WRAMSIZE );
}
GameStateRestore = StateRestore;
VRC7_ESI();

View File

@ -536,19 +536,28 @@ void FCEU_GeniePower(void) {
}
void FCEU_SaveGameSave(CartInfo *LocalHWInfo) {
if (LocalHWInfo->battery && LocalHWInfo->SaveGame[0]) {
void FCEU_SaveGameSave(CartInfo *LocalHWInfo)
{
if (LocalHWInfo->battery && !LocalHWInfo->SaveGame.empty())
{
FILE *sp;
std::string soot = FCEU_MakeFName(FCEUMKF_SAV, 0, "sav");
if ((sp = FCEUD_UTF8fopen(soot, "wb")) == NULL) {
if ((sp = FCEUD_UTF8fopen(soot, "wb")) == NULL)
{
FCEU_PrintError("WRAM file \"%s\" cannot be written to.\n", soot.c_str());
} else {
for (int x = 0; x < 4; x++)
if (LocalHWInfo->SaveGame[x]) {
fwrite(LocalHWInfo->SaveGame[x], 1,
LocalHWInfo->SaveGameLen[x], sp);
}
else
{
for (size_t x = 0; x < LocalHWInfo->SaveGame.size(); x++)
{
if (LocalHWInfo->SaveGame[x].bufptr)
{
fwrite(LocalHWInfo->SaveGame[x].bufptr, 1,
LocalHWInfo->SaveGame[x].buflen, sp);
}
}
fclose(sp);
}
}
}
@ -556,25 +565,46 @@ void FCEU_SaveGameSave(CartInfo *LocalHWInfo) {
// hack, movie.cpp has to communicate with this function somehow
int disableBatteryLoading = 0;
void FCEU_LoadGameSave(CartInfo *LocalHWInfo) {
if (LocalHWInfo->battery && LocalHWInfo->SaveGame[0] && !disableBatteryLoading) {
void FCEU_LoadGameSave(CartInfo *LocalHWInfo)
{
if (LocalHWInfo->battery && !LocalHWInfo->SaveGame.empty() && !disableBatteryLoading)
{
FILE *sp;
std::string soot = FCEU_MakeFName(FCEUMKF_SAV, 0, "sav");
sp = FCEUD_UTF8fopen(soot, "rb");
if (sp != NULL) {
for (int x = 0; x < 4; x++)
if (LocalHWInfo->SaveGame[x])
fread(LocalHWInfo->SaveGame[x], 1, LocalHWInfo->SaveGameLen[x], sp);
if (sp != NULL)
{
for (size_t x = 0; x < LocalHWInfo->SaveGame.size(); x++)
{
if (LocalHWInfo->SaveGame[x].bufptr)
{
if ( fread(LocalHWInfo->SaveGame[x].bufptr, 1, LocalHWInfo->SaveGame[x].buflen, sp) != LocalHWInfo->SaveGame[x].buflen )
{
FCEU_printf("Warning save game data read came up short!\n");
}
}
}
fclose(sp);
}
}
}
//clears all save memory. call this if you want to pretend the saveram has been reset (it doesnt touch what is on disk though)
void FCEU_ClearGameSave(CartInfo *LocalHWInfo) {
if (LocalHWInfo->battery && LocalHWInfo->SaveGame[0]) {
for (int x = 0; x < 4; x++)
if (LocalHWInfo->SaveGame[x])
memset(LocalHWInfo->SaveGame[x], 0, LocalHWInfo->SaveGameLen[x]);
void FCEU_ClearGameSave(CartInfo *LocalHWInfo)
{
if (LocalHWInfo->battery && !LocalHWInfo->SaveGame.empty())
{
for (size_t x = 0; x < LocalHWInfo->SaveGame.size(); x++)
{
if (LocalHWInfo->SaveGame[x].bufptr)
{
memset(LocalHWInfo->SaveGame[x].bufptr, 0, LocalHWInfo->SaveGame[x].buflen);
}
if (LocalHWInfo->SaveGame[x].resetFunc)
{
LocalHWInfo->SaveGame[x].resetFunc();
}
}
}
}

View File

@ -1,20 +1,45 @@
#ifndef CART_H
#define CART_H
typedef struct {
#include <vector>
struct CartInfo
{
// Set by mapper/board code:
void (*Power)(void);
void (*Reset)(void);
void (*Close)(void);
uint8 *SaveGame[4]; // Pointers to memory to save/load.
uint32 SaveGameLen[4]; // How much memory to save/load.
struct SaveGame_t
{
uint8 *bufptr; // Pointer to memory to save/load.
uint32 buflen; // How much memory to save/load.
void (*resetFunc)(void); // Callback to reset save game memory
SaveGame_t(void)
: bufptr(nullptr), buflen(0), resetFunc(nullptr)
{
}
};
std::vector <SaveGame_t> SaveGame;
void addSaveGameBuf( uint8* bufptrIn, uint32 buflenIn, void (*resetFuncIn)(void) = nullptr )
{
SaveGame_t tmp;
tmp.bufptr = bufptrIn;
tmp.buflen = buflenIn;
tmp.resetFunc = resetFuncIn;
SaveGame.push_back( tmp );
}
// Set by iNES/UNIF loading code.
int mirror; // As set in the header or chunk.
// iNES/UNIF specific. Intended
// to help support games like "Karnov"
// that are not really MMC3 but are
// set to mapper 4.
// iNES/UNIF specific. Intended
// to help support games like "Karnov"
// that are not really MMC3 but are
// set to mapper 4.
int mirrorAs2Bits;
int battery; // Presence of an actual battery.
int ines2;
@ -27,7 +52,33 @@ typedef struct {
uint32 CRC32; // Should be set by the iNES/UNIF loading
// code, used by mapper/board code, maybe
// other code in the future.
} CartInfo;
CartInfo(void)
{
clear();
}
void clear(void)
{
Power = nullptr;
Reset = nullptr;
Close = nullptr;
SaveGame.clear();
mirror = 0;
mirrorAs2Bits = 0;
battery = 0;
ines2 = 0;
submapper = 0;
wram_size = 0;
battery_wram_size = 0;
vram_size = 0;
battery_vram_size = 0;
memset( MD5, 0, sizeof(MD5));
CRC32 = 0;
};
};
extern CartInfo *currCartInfo;

View File

@ -58,8 +58,17 @@ void FCEU_CheatAddRAM(int s, uint32 A, uint8 *p)
CheatRPtrs[AB+x]=p-A;
}
// Cheat change event callback. Called whenever cheat map is changed or recalculated.
static void (*cheatsChangeEventCB)(void*) = nullptr;
static void* cheatsChangeEventUserData = nullptr;
CHEATF_SUBFAST SubCheats[256] = { 0 };
void FCEU_SetCheatChangeEventCallback( void (*func)(void*), void* userData )
{
cheatsChangeEventCB = func;
cheatsChangeEventUserData = userData;
}
CHEATF_SUBFAST SubCheats[256];
uint32 numsubcheats = 0;
int globalCheatDisabled = 0;
int disableAutoLSCheats = 0;
@ -132,6 +141,11 @@ void RebuildSubCheats(void)
}
FrozenAddressCount = numsubcheats; //Update the frozen address list
// Notify the system of a change
if (cheatsChangeEventCB != nullptr)
{
cheatsChangeEventCB( cheatsChangeEventUserData );
}
}
void FCEU_PowerCheats()
@ -368,12 +382,15 @@ void FCEU_FlushGameCheats(FILE *override, int nosave)
}
int FCEUI_AddCheat(const char *name, uint32 addr, uint8 val, int compare, int type)
int FCEUI_AddCheat(const char *name, uint32 addr, uint8 val, int compare, int type, int status, bool rebuild)
{
AddCheatEntry(name, addr, val, compare, 1, type);
AddCheatEntry(name, addr, val, compare, status, type);
savecheats = 1;
RebuildSubCheats();
if (rebuild)
{
RebuildSubCheats();
}
return 1;
}
@ -644,7 +661,7 @@ int FCEUI_ToggleCheat(uint32 which)
int FCEUI_GlobalToggleCheat(int global_enabled)
{
int _numsubcheats = numsubcheats;
unsigned int _numsubcheats = numsubcheats;
globalCheatDisabled = !global_enabled;
RebuildSubCheats();
return _numsubcheats != numsubcheats;

View File

@ -33,12 +33,20 @@ extern int disableAutoLSCheats;
int FCEU_DisableAllCheats(void);
int FCEU_DeleteAllCheats(void);
typedef struct {
void FCEU_SetCheatChangeEventCallback( void (*func)(void*) = nullptr, void* userData = nullptr );
struct CHEATF_SUBFAST
{
uint16 addr;
uint8 val;
int compare;
readfunc PrevRead;
} CHEATF_SUBFAST;
CHEATF_SUBFAST(void)
{
addr = 0; val = 0; compare = 0; PrevRead = nullptr;
}
};
struct CHEATF {
struct CHEATF *next;

View File

@ -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;
}

View File

@ -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

View File

@ -11,12 +11,14 @@
#include <cstdio>
#include <cstdlib>
static char *aboutString = 0;
static std::string aboutString;
#ifndef FCEUX_BUILD_TIMESTAMP
#define FCEUX_BUILD_TIMESTAMP __TIME__ " " __DATE__
#endif
//#pragma message( "Compiling using C++ Std: " __FCEU_STRINGIZE(__cplusplus) )
// returns a string suitable for use in an aboutbox
const char *FCEUI_GetAboutString(void)
{
@ -26,7 +28,7 @@ const char *FCEUI_GetAboutString(void)
"zeromus, feos\n"
"\n"
"Current Contributors:\n"
"CaH4e3, rainwarrior, owomomo, punkrockguy318\n"
"CaH4e3, rainwarrior, owomomo, punkrockguy318, Cluster\n"
"\n"
"Past Contributors:\n"
"xhainingx, gocha, AnS, mjbudd77\n"
@ -55,14 +57,17 @@ const char *FCEUI_GetAboutString(void)
"\n"
FCEUX_BUILD_TIMESTAMP "\n";
if (aboutString) return aboutString;
if (aboutString.size() > 0) return aboutString.c_str();
const char *compilerString = FCEUD_GetCompilerString();
//allocate the string and concatenate the template with the compiler string
if (!(aboutString = (char*)FCEU_dmalloc(strlen(aboutTemplate) + strlen(compilerString) + 1)))
return NULL;
char cppVersion[128];
sprintf(aboutString,"%s%s",aboutTemplate,compilerString);
return aboutString;
snprintf( cppVersion, sizeof(cppVersion), "\nCompiled using C++ Language Standard: %li\n", __cplusplus);
aboutString.assign( aboutTemplate );
aboutString.append( compilerString );
aboutString.append( cppVersion );
return aboutString.c_str();
}

View File

@ -6,6 +6,7 @@
#include "cart.h"
#include "ines.h"
#include "debug.h"
#include "debugsymboltable.h"
#include "driver.h"
#include "ppu.h"
@ -18,10 +19,23 @@ 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)
struct TraceInstructionCallback
{
void (*func)(uint8 *opcode, int size) = nullptr;
TraceInstructionCallback* next = nullptr;
};
static TraceInstructionCallback* traceInstructionCB = nullptr;
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;
@ -29,18 +43,41 @@ 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
{
auto sym = debugSymbolTable.getSymbolAtAnyBank(offsetBuffer);
if (sym)
{
if (conversionOk)
{
*conversionOk = true;
}
return sym->offset() & 0xFFFF;
}
int type = GIT_CART;
if (GameInfo)
@ -48,21 +85,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);
}
}
@ -131,7 +173,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;
@ -145,8 +187,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
@ -161,7 +203,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;
@ -258,7 +300,7 @@ int getBank(int offs)
//Anything over FFFFF will kill it.
//GetNesFileAddress doesn't work well with Unif files
int addr = GetNesFileAddress(offs)-16;
int addr = GetNesFileAddress(offs)-NES_HEADER_SIZE;
if (GameInfo && GameInfo->type==GIT_NSF)
return addr != -1 ? addr / 0x1000 : -1;
@ -270,12 +312,12 @@ int GetNesFileAddress(int A){
if((A < 0x6000) || (A > 0xFFFF))return -1;
result = &Page[A>>11][A]-PRGptr[0];
if((result > (int)(PRGsize[0])) || (result < 0))return -1;
else return result+16; //16 bytes for the header remember
else return result+NES_HEADER_SIZE; //16 bytes for the header remember
}
int GetRomAddress(int A){
int i;
uint8 *p = GetNesPRGPointer(A-=16);
uint8 *p = GetNesPRGPointer(A-=NES_HEADER_SIZE);
for(i = 16;i < 32;i++){
if((&Page[i][i<<11] <= p) && (&Page[i][(i+1)<<11] > p))break;
}
@ -512,7 +554,7 @@ void LogCDData(uint8 *opcode, uint16 A, int size)
case 4: memop = 0x20; break;
}
if ((j = GetPRGAddress(A)) != -1)
if (((j = GetPRGAddress(A)) != -1) && (opcode[0] != 0x4C) && (opcode[0] != 0x6C))
{
if (opwrite[opcode[0]] == 0)
{
@ -527,7 +569,12 @@ void LogCDData(uint8 *opcode, uint16 A, int size)
newDataHit = true;
}
}
else
// Unclear why the write destination's access types gets reset for FDS...
// See:
// - https://github.com/TASEmulators/fceux/commit/a4fa6225a04b5ab8d3dfca3fc9abd7190bceec85
// - https://github.com/TASEmulators/fceux/commit/b10b6254c3d5c9519a85cb4382cdb22846d2e394
// - https://github.com/TASEmulators/fceux/commit/67942accc72149ae028d58f36419b64ea8651db9?diff=unified&w=1
else if(GameInfo && GameInfo->type == GIT_FDS)
{
if (cdloggerdata[j] & 1)
{
@ -642,7 +689,8 @@ uint16 StackNextIgnorePC = 0xFFFF;
///fires a breakpoint
static void breakpoint(uint8 *opcode, uint16 A, int size) {
int i, j, romAddrPC;
int i, romAddrPC;
unsigned int j;
uint8 brk_type;
uint8 stackop=0;
uint8 stackopstartaddr=0,stackopendaddr=0;
@ -783,7 +831,7 @@ static void breakpoint(uint8 *opcode, uint16 A, int size) {
{
if (watchpoint[i].flags & BT_R)
{
if ( (watchpoint[i].flags & WP_X) && (watchpoint[i].address == romAddrPC) )
if ( (watchpoint[i].flags & WP_X) && (watchpoint[i].address == static_cast<unsigned int>(romAddrPC)) )
{
BREAKHIT(i);
}
@ -814,7 +862,7 @@ static void breakpoint(uint8 *opcode, uint16 A, int size) {
// TXS and TSX only deal with the pointer.
if (watchpoint[i].flags & stackop)
{
for (j = (stackopstartaddr|0x0100); j <= (stackopendaddr|0x0100); j++)
for (j = (stackopstartaddr|0x0100); j <= (static_cast<unsigned int>(stackopendaddr)|0x0100); j++)
{
if (watchpoint[i].endaddress)
{
@ -840,7 +888,7 @@ static void breakpoint(uint8 *opcode, uint16 A, int size) {
// Pushes to stack
if (watchpoint[i].flags & WP_W)
{
for (j = (X.S|0x0100); j < (StackAddrBackup|0x0100); j++)
for (j = (X.S|0x0100); j < (static_cast<unsigned int>(StackAddrBackup)|0x0100); j++)
{
if (watchpoint[i].endaddress)
{
@ -858,7 +906,7 @@ static void breakpoint(uint8 *opcode, uint16 A, int size) {
// Pulls from stack
if (watchpoint[i].flags & WP_R)
{
for (j = (StackAddrBackup|0x0100); j < (X.S|0x0100); j++)
for (j = (StackAddrBackup|0x0100); j < (static_cast<unsigned int>(X.S)|0x0100); j++)
{
if (watchpoint[i].endaddress)
{
@ -954,5 +1002,82 @@ void DebugCycle()
if(debug_loggingCD)
LogCDData(opcode, A, size);
#ifdef __WIN_DRIVER__
FCEUD_TraceInstruction(opcode, size);
#else
// Use callback pointer that can be null checked, this saves on the overhead
// of calling a function for every instruction when we aren't tracing.
if (traceInstructionCB != nullptr)
{
auto* cb = traceInstructionCB;
while (cb != nullptr)
{
cb->func(opcode, size);
cb = cb->next;
}
}
#endif
}
void* FCEUI_TraceInstructionRegister( void (*func)(uint8*,int) )
{
TraceInstructionCallback* cb = nullptr;
if (traceInstructionCB == nullptr)
{
cb = traceInstructionCB = new TraceInstructionCallback();
cb->func = func;
}
else
{
cb = traceInstructionCB;
while (cb != nullptr)
{
if (cb->func == func)
{
// This function has already been registered, don't double add.
return nullptr;
}
if (cb->next == nullptr)
{
auto* newCB = new TraceInstructionCallback();
newCB->func = func;
cb->next = newCB;
return newCB;
}
cb = cb->next;
}
}
return cb;
}
bool FCEUI_TraceInstructionUnregisterHandle( void* handle )
{
TraceInstructionCallback* cb, *cb_prev, *cb_handle;
cb_handle = static_cast<TraceInstructionCallback*>(handle);
cb_prev = nullptr;
cb = traceInstructionCB;
while (cb != nullptr)
{
if (cb == cb_handle)
{ // Match we are going to remove from list and delete
if (cb_prev != nullptr)
{
cb_prev = cb->next;
}
else
{
traceInstructionCB = cb->next;
}
delete cb;
return true;
}
cb_prev = cb;
cb = cb->next;
}
return false;
}

View File

@ -172,7 +172,10 @@ 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);
void* FCEUI_TraceInstructionRegister( void (*func)(uint8*,int) );
bool FCEUI_TraceInstructionUnregisterHandle( void* handle );
#endif

1002
src/debugsymboltable.cpp Normal file

File diff suppressed because it is too large Load Diff

170
src/debugsymboltable.h Normal file
View File

@ -0,0 +1,170 @@
#ifndef _DEBUGSYMBOLTABLE_H_
#define _DEBUGSYMBOLTABLE_H_
#include <string>
#include <map>
#include "utils/mutex.h"
#include "ld65dbg.h"
class debugSymbolPage_t;
class debugSymbolTable_t;
class debugSymbol_t
{
public:
debugSymbol_t(void)
{
ofs = 0;
page = nullptr;
};
debugSymbol_t( int ofs, const char *name = nullptr, const char *comment = nullptr )
{
this->ofs = ofs;
if (name)
{
this->_name.assign(name);
}
if ( comment )
{
this->_comment.assign( comment );
}
page = nullptr;
}
const std::string &name(void)
{
return _name;
}
const std::string &comment(void)
{
return _comment;
}
void commentAssign( std::string str )
{
_comment.assign(str);
return;
}
void commentAssign( const char *str )
{
_comment.assign(str);
return;
}
int offset(void)
{
return ofs;
}
void setOffset( int o )
{
if (o != ofs)
{
ofs = o;
}
}
int updateName( const char *name, int arrayIndex = -1 );
void trimTrailingSpaces(void);
private:
int ofs;
std::string _name;
std::string _comment;
debugSymbolPage_t *page;
friend class debugSymbolPage_t;
friend class debugSymbolTable_t;
};
class debugSymbolPage_t
{
public:
debugSymbolPage_t(int page);
~debugSymbolPage_t(void);
int save(void);
void print(void);
int size(void){ return static_cast<int>(symMap.size()); }
int addSymbol( debugSymbol_t *sym );
int deleteSymbolAtOffset( int ofs );
int updateSymbol( debugSymbol_t *sym );
debugSymbol_t *getSymbolAtOffset( int ofs );
debugSymbol_t *getSymbol( const std::string &name );
int pageNum(void)
{
return _pageNum;
}
const char *pageName(void)
{
return _pageName;
}
private:
int _pageNum;
char _pageName[8];
std::map <int, debugSymbol_t*> symMap;
std::map <std::string, debugSymbol_t*> symNameMap;
friend class debugSymbolTable_t;
};
class debugSymbolTable_t
{
public:
debugSymbolTable_t(void);
~debugSymbolTable_t(void);
int loadFileNL( int addr );
int loadRegisterMap(void);
int loadGameSymbols(void);
int numPages(void){ return pageMap.size(); }
int numSymbols(void);
void save(void);
void clear(void);
void print(void);
debugSymbol_t *getSymbolAtBankOffset( int bank, int ofs );
debugSymbol_t *getSymbol( int bank, const std::string& name);
debugSymbol_t *getSymbolAtAnyBank( const std::string& name);
int addSymbolAtBankOffset( int bank, int ofs, debugSymbol_t *sym );
int addSymbolAtBankOffset(int bank, int ofs, const char* name, const char* comment = nullptr);
int deleteSymbolAtBankOffset( int bank, int ofs );
int updateSymbol( debugSymbol_t *sym );
const char *errorMessage(void);
int ld65LoadDebugFile( const char *dbgFilePath );
void ld65_SymbolLoad( ld65::sym *s );
private:
std::map <int, debugSymbolPage_t*> pageMap;
FCEU::mutex *cs;
};
extern debugSymbolTable_t debugSymbolTable;
#endif

View File

@ -346,7 +346,7 @@ void FCEU_DrawRecordingStatus(uint8* XBuf)
hasPlayRecIcon = true;
}
if(FCEUI_EmulationPaused())
if( EmulationPaused & (EMULATIONPAUSED_PAUSED | EMULATIONPAUSED_TIMER) )
drawstatus(XBuf-ClipSidesOffset,3,28,hasPlayRecIcon?-16:0);
}
}

View File

@ -23,7 +23,7 @@ ArchiveScanRecord FCEUD_ScanArchive(std::string fname);
const char *FCEUD_GetCompilerString();
//This makes me feel dirty for some reason.
void FCEU_printf(const char *format, ...);
void FCEU_printf( __FCEU_PRINTF_FORMAT const char *format, ...) __FCEU_PRINTF_ATTRIBUTE( 1, 2 );
#define FCEUI_printf FCEU_printf
//Video interface
@ -192,12 +192,12 @@ void TaseditorManualFunction(void);
int32 FCEUI_GetDesiredFPS(void);
void FCEUI_SaveSnapshot(void);
void FCEUI_SaveSnapshotAs(void);
void FCEU_DispMessage(const char *format, int disppos, ...);
void FCEU_DispMessage( __FCEU_PRINTF_FORMAT const char *format, int disppos, ...) __FCEU_PRINTF_ATTRIBUTE( 1, 3 );
#define FCEUI_DispMessage FCEU_DispMessage
int FCEUI_DecodePAR(const char *code, int *a, int *v, int *c, int *type);
int FCEUI_DecodeGG(const char *str, int *a, int *v, int *c);
int FCEUI_AddCheat(const char *name, uint32 addr, uint8 val, int compare, int type);
int FCEUI_AddCheat(const char *name, uint32 addr, uint8 val, int compare, int type, int status = 1, bool rebuild = true);
int FCEUI_DelCheat(uint32 which);
int FCEUI_ToggleCheat(uint32 which);
int FCEUI_GlobalToggleCheat(int global_enable);
@ -254,6 +254,8 @@ void FCEUI_VSUniToggleDIP(int w);
uint8 FCEUI_VSUniGetDIPs(void);
void FCEUI_VSUniSetDIP(int w, int state);
void FCEUI_VSUniCoin(void);
void FCEUI_VSUniCoin2(void);
void FCEUI_VSUniService(void);
void FCEUI_FDSInsert(void); //mbg merge 7/17/06 changed to void fn(void) to make it an EMUCMDFN
//int FCEUI_FDSEject(void);
@ -271,6 +273,10 @@ 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();
void FCEUI_SetNetPlayPause(bool value);
bool FCEUI_GetNetPlayPause();
//indicates whether input aids should be drawn (such as crosshairs, etc; usually in fullscreen mode)
bool FCEUD_ShouldDrawInputAids();
@ -361,7 +367,11 @@ bool FCEU_IsValidUI(EFCEUI ui);
#ifdef __cplusplus
extern "C"
{
#endif
FILE *FCEUI_UTF8fopen_C(const char *n, const char *m);
#ifdef __cplusplus
} // extern C
#endif
FILE *FCEUI_UTF8fopen_C(const char *n, const char *m);
#endif //__DRIVER_H_

View File

@ -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"
@ -69,7 +74,7 @@ static const char *Authors[] = {
"\t rainwarrior", "\t feos",
"Pre 2.0 Guys:",
"\t Bero", "\t Xodnizel", "\t Aaron Oneal", "\t Joe Nahmias",
"\t Paul Kuliniewicz", "\t Quietust", "\t Ben Parnell",
"\t Paul Kuliniewicz", "\t Quietust",
"\t Parasyte &amp; bbitmaster",
"\t blip & nitsuja",
"Included components:",
@ -125,7 +130,7 @@ AboutWindow::AboutWindow(QWidget *parent)
mainLayout->addLayout( hbox1 );
sprintf( stmp, "git URL: %s", fceu_get_git_url() );
snprintf( stmp, sizeof(stmp), "git URL: %s", fceu_get_git_url() );
hbox1 = new QHBoxLayout();
lbl = new QLabel( tr(stmp) );
@ -135,7 +140,7 @@ AboutWindow::AboutWindow(QWidget *parent)
mainLayout->addLayout( hbox1 );
sprintf( stmp, "git Revision: %s", fceu_get_git_rev() );
snprintf( stmp, sizeof(stmp), "git Revision: %s", fceu_get_git_rev() );
hbox1 = new QHBoxLayout();
lbl = new QLabel( tr(stmp) );
@ -147,7 +152,7 @@ AboutWindow::AboutWindow(QWidget *parent)
hbox1 = new QHBoxLayout();
lbl = new QLabel();
lbl->setText("<a href=\"http://fceux.com\">Website</a>");
lbl->setText("<a href=\"https://fceux.com\">Website</a>");
lbl->setTextInteractionFlags(Qt::TextBrowserInteraction);
lbl->setOpenExternalLinks(true);
@ -186,44 +191,61 @@ AboutWindow::AboutWindow(QWidget *parent)
credits->insertPlainText( "\nOpen Source Dependencies:\n" );
sprintf( stmp, " Compiled with Qt version %d.%d.%d\n", QT_VERSION_MAJOR, QT_VERSION_MINOR, QT_VERSION_PATCH );
snprintf( stmp, sizeof(stmp), " Compiled with Qt version %d.%d.%d\n", QT_VERSION_MAJOR, QT_VERSION_MINOR, QT_VERSION_PATCH );
credits->insertPlainText( stmp );
sprintf( stmp, " Compiled with SDL version %d.%d.%d\n", SDL_MAJOR_VERSION, SDL_MINOR_VERSION, SDL_PATCHLEVEL );
snprintf( stmp, sizeof(stmp), " Compiled with SDL version %d.%d.%d\n", SDL_MAJOR_VERSION, SDL_MINOR_VERSION, SDL_PATCHLEVEL );
credits->insertPlainText( stmp );
SDL_version v;
SDL_GetVersion(&v);
sprintf( stmp, " Linked with SDL version %d.%d.%d\n", v.major, v.minor, v.patch);
snprintf( stmp, sizeof(stmp), " Linked with SDL version %d.%d.%d\n", v.major, v.minor, v.patch);
credits->insertPlainText( stmp );
#ifdef ZLIB_VERSION
sprintf( stmp, " Compiled with zlib %s\n", ZLIB_VERSION );
snprintf( stmp, sizeof(stmp), " Compiled with zlib %s\n", ZLIB_VERSION );
credits->insertPlainText( stmp );
#endif
#ifdef _USE_LIBARCHIVE
snprintf( stmp, sizeof(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])
{
snprintf( stmp, sizeof(stmp), " %s %s\n", libArcName[i], libArcVersion[i]);
credits->insertPlainText( stmp );
}
i++;
}
#endif
#ifdef _S9XLUA_H
sprintf( stmp, " Compiled with %s\n", LUA_RELEASE );
snprintf( stmp, sizeof(stmp), " Compiled with %s\n", LUA_RELEASE );
credits->insertPlainText( stmp );
#endif
#ifdef _USE_LIBAV
sprintf( stmp, " Compiled with ffmpeg libraries:\n");
snprintf( stmp, sizeof(stmp), " Compiled with ffmpeg libraries:\n");
credits->insertPlainText( stmp );
sprintf( stmp, " libavutil %i.%i.%i\n", LIBAVUTIL_VERSION_MAJOR, LIBAVUTIL_VERSION_MINOR, LIBAVUTIL_VERSION_MICRO);
snprintf( stmp, sizeof(stmp), " libavutil %i.%i.%i\n", LIBAVUTIL_VERSION_MAJOR, LIBAVUTIL_VERSION_MINOR, LIBAVUTIL_VERSION_MICRO);
credits->insertPlainText( stmp );
sprintf( stmp, " libavformat %i.%i.%i\n", LIBAVFORMAT_VERSION_MAJOR, LIBAVFORMAT_VERSION_MINOR, LIBAVFORMAT_VERSION_MICRO);
snprintf( stmp, sizeof(stmp), " libavformat %i.%i.%i\n", LIBAVFORMAT_VERSION_MAJOR, LIBAVFORMAT_VERSION_MINOR, LIBAVFORMAT_VERSION_MICRO);
credits->insertPlainText( stmp );
sprintf( stmp, " libavcodec %i.%i.%i\n", LIBAVCODEC_VERSION_MAJOR, LIBAVCODEC_VERSION_MINOR, LIBAVCODEC_VERSION_MICRO);
snprintf( stmp, sizeof(stmp), " libavcodec %i.%i.%i\n", LIBAVCODEC_VERSION_MAJOR, LIBAVCODEC_VERSION_MINOR, LIBAVCODEC_VERSION_MICRO);
credits->insertPlainText( stmp );
sprintf( stmp, " libswscale %i.%i.%i\n", LIBSWSCALE_VERSION_MAJOR, LIBSWSCALE_VERSION_MINOR, LIBSWSCALE_VERSION_MICRO);
snprintf( stmp, sizeof(stmp), " libswscale %i.%i.%i\n", LIBSWSCALE_VERSION_MAJOR, LIBSWSCALE_VERSION_MINOR, LIBSWSCALE_VERSION_MICRO);
credits->insertPlainText( stmp );
sprintf( stmp, " libswresample %i.%i.%i\n", LIBSWRESAMPLE_VERSION_MAJOR, LIBSWRESAMPLE_VERSION_MINOR, LIBSWRESAMPLE_VERSION_MICRO);
snprintf( stmp, sizeof(stmp), " libswresample %i.%i.%i\n", LIBSWRESAMPLE_VERSION_MAJOR, LIBSWRESAMPLE_VERSION_MINOR, LIBSWRESAMPLE_VERSION_MICRO);
credits->insertPlainText( stmp );
#endif
#ifdef _USE_X264
sprintf( stmp, " Compiled with x264 version %s\n", X264_POINTVER );
snprintf( stmp, sizeof(stmp), " Compiled with x264 version %s\n", X264_POINTVER );
credits->insertPlainText( stmp );
#endif

View File

@ -26,6 +26,7 @@
#include <stdarg.h>
#include <string.h>
#include <string>
#include <atomic>
#ifdef WIN32
#include <windows.h>
@ -79,12 +80,12 @@ extern "C"
static gwavi_t *gwavi = NULL;
static bool recordEnable = false;
static bool recordAudio = true;
static int vbufHead = 0;
static int vbufTail = 0;
static int vbufSize = 0;
static int abufHead = 0;
static int abufTail = 0;
static int abufSize = 0;
static std::atomic<int> vbufHead(0);
static std::atomic<int> vbufTail(0);
static constexpr int vbufSize = 1024 * 1024 * 64;
static std::atomic<int> abufHead(0);
static std::atomic<int> abufTail(0);
static constexpr int abufSize = 256 * 1024;
static uint32_t *rawVideoBuf = NULL;
static int16_t *rawAudioBuf = NULL;
static int aviDriver = 0;
@ -460,7 +461,14 @@ static int encode_frame( unsigned char *inBuf, int width, int height )
pic->stride[1] = width/2;
pic->stride[2] = width/2;
#if defined(MAX_SCALABLE_LAYERS) && (X265_BUILD >= 210) && (X265_BUILD < 213)
/* Handle API changes for scalable layers output in x265 4.0 */
x265_picture *pics[MAX_SCALABLE_LAYERS] = {NULL};
pics[0] = pic;
ret = x265_encoder_encode( hdl, &nal, &i_nal, pic, pics );
#else
ret = x265_encoder_encode( hdl, &nal, &i_nal, pic, &pic_out );
#endif
if ( ret <= 0 )
{
@ -493,7 +501,14 @@ static int close(void)
/* Flush delayed frames */
while( hdl != NULL )
{
#if defined(MAX_SCALABLE_LAYERS) && (X265_BUILD >= 210) && (X265_BUILD < 213)
/* Handle API changes for scalable layers output in x265 4.0 */
x265_picture *pics[MAX_SCALABLE_LAYERS] = {NULL};
pics[0] = pic;
ret = x265_encoder_encode( hdl, &nal, &i_nal, pic, pics );
#else
ret = x265_encoder_encode( hdl, &nal, &i_nal, NULL, &pic_out );
#endif
if ( ret <= 0 )
{
@ -795,7 +810,7 @@ struct OutputStream
if ( writeError )
{
char msg[512];
sprintf( msg, "%s Stream Write Errors Detected.\nOutput may be incomplete or corrupt.\nSee log file '%s' for details\n",
snprintf( msg, sizeof(msg), "%s Stream Write Errors Detected.\nOutput may be incomplete or corrupt.\nSee log file '%s' for details\n",
isAudio ? "Audio" : "Video", AV_LOG_FILE_NAME);
FCEUD_PrintError(msg);
}
@ -853,14 +868,16 @@ static void log_callback( void *avcl, int level, const char *fmt, va_list vl)
int loadCodecConfig( int type, const char *codec_name, AVCodecContext *ctx)
{
int i,j;
char filename[512];
char filename[4096];
char line[512];
char section[256], id[256], val[256];
void *obj, *child;
FILE *fp;
const char *baseDir = FCEUI_GetBaseDirectory();
sprintf( filename, "%s/avi/%s.conf", baseDir, codec_name );
snprintf( filename, sizeof(filename), "%s/avi/%s.conf", baseDir, codec_name );
filename[sizeof(filename)-1] = 0;
fp = fopen( filename, "r");
@ -991,12 +1008,14 @@ int saveCodecConfig( int type, const char *codec_name, AVCodecContext *ctx)
void *obj, *child = NULL;
FILE *fp;
uint8_t *str;
char filename[512];
char filename[4096];
const AVOption *opt;
bool useOpt;
const char *baseDir = FCEUI_GetBaseDirectory();
sprintf( filename, "%s/avi/%s.conf", baseDir, codec_name );
snprintf( filename, sizeof(filename), "%s/avi/%s.conf", baseDir, codec_name );
filename[sizeof(filename)-1] = 0;
fp = fopen( filename, "w");
@ -1285,9 +1304,8 @@ static int initVideoStream( const char *codec_name, OutputStream *ost )
return 0;
}
static AVFrame *alloc_audio_frame(enum AVSampleFormat sample_fmt,
uint64_t channel_layout,
int sample_rate, int nb_samples)
static AVFrame *alloc_audio_frame(const AVCodecContext *c,
int nb_samples)
{
AVFrame *frame = av_frame_alloc();
int ret;
@ -1296,9 +1314,13 @@ static AVFrame *alloc_audio_frame(enum AVSampleFormat sample_fmt,
fprintf(stderr, "Error allocating an audio frame\n");
return NULL;
}
frame->format = sample_fmt;
frame->channel_layout = channel_layout;
frame->sample_rate = sample_rate;
frame->format = c->sample_fmt;
#if LIBAVUTIL_VERSION_INT < AV_VERSION_INT(57, 28, 100)
frame->channel_layout = c->channel_layout;
#else
av_channel_layout_copy(&frame->ch_layout, &c->ch_layout);
#endif
frame->sample_rate = c->sample_rate;
frame->nb_samples = nb_samples;
if (nb_samples)
@ -1313,6 +1335,48 @@ static AVFrame *alloc_audio_frame(enum AVSampleFormat sample_fmt,
return frame;
}
#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(57, 28, 100)
static int select_audio_channel_layout(const OutputStream *ost, const AVCodec *codec, AVChannelLayout *dst)
{
int best_nb_channels = 0;
const AVChannelLayout *p, *best_ch_layout;
#if __cplusplus >= 202002L
const AVChannelLayout defaultLayout = AV_CHANNEL_LAYOUT_MONO;
#else
AVChannelLayout defaultLayout;
av_channel_layout_from_mask( &defaultLayout, AV_CH_LAYOUT_MONO );
#endif
if (!codec->ch_layouts)
{
return av_channel_layout_copy(dst, &defaultLayout);
}
best_ch_layout = p = codec->ch_layouts;
while (p && p->nb_channels)
{
int nb_channels = p->nb_channels;
if ( ost->chanLayout > 0 )
{
if (ost->chanLayout == p->u.mask)
{
best_ch_layout = p;
best_nb_channels = nb_channels;
break;
}
}
if (nb_channels > best_nb_channels)
{
best_ch_layout = p;
best_nb_channels = nb_channels;
}
p++;
}
return av_channel_layout_copy(dst, best_ch_layout);
}
#endif
static int initAudioStream( const char *codec_name, OutputStream *ost )
{
int ret, nb_samples;
@ -1406,6 +1470,7 @@ static int initAudioStream( const char *codec_name, OutputStream *ost )
}
// Channel Layout Selection
#if LIBAVUTIL_VERSION_INT < AV_VERSION_INT(57, 28, 100)
if ( ost->chanLayout > 0 )
{
c->channel_layout = ost->chanLayout;
@ -1432,6 +1497,13 @@ static int initAudioStream( const char *codec_name, OutputStream *ost )
c->channel_layout = codec->channel_layouts ? codec->channel_layouts[0] : AV_CH_LAYOUT_STEREO;
}
c->channels = av_get_channel_layout_nb_channels(c->channel_layout);
#else
if (select_audio_channel_layout( ost, codec, &c->ch_layout) )
{
fprintf( avLogFp, "Error selecting the audio channel layout\n");
return -1;
}
#endif
c->bit_rate = 64000;
//ost->st->time_base = (AVRational){ 1, c->sample_rate };
ost->st->time_base.num = 1;
@ -1454,10 +1526,24 @@ static int initAudioStream( const char *codec_name, OutputStream *ost )
}
av_opt_set_sample_fmt(ost->swr_ctx, "in_sample_fmt", AV_SAMPLE_FMT_S16, 0);
av_opt_set_int(ost->swr_ctx, "in_sample_rate", audioSampleRate, 0);
#if LIBAVUTIL_VERSION_INT < AV_VERSION_INT(57, 28, 100)
av_opt_set_int(ost->swr_ctx, "in_channel_layout", AV_CH_LAYOUT_MONO, 0);
#else
#if __cplusplus >= 202002L
AVChannelLayout src_ch_layout = AV_CHANNEL_LAYOUT_MONO;
#else
AVChannelLayout src_ch_layout;
av_channel_layout_from_mask( &src_ch_layout, AV_CH_LAYOUT_MONO );
#endif
av_opt_set_chlayout(ost->swr_ctx, "in_chlayout", &src_ch_layout, 0);
#endif
av_opt_set_sample_fmt(ost->swr_ctx, "out_sample_fmt", c->sample_fmt, 0);
av_opt_set_int(ost->swr_ctx, "out_sample_rate", c->sample_rate, 0);
#if LIBAVUTIL_VERSION_INT < AV_VERSION_INT(57, 28, 100)
av_opt_set_int(ost->swr_ctx, "out_channel_layout", c->channel_layout, 0);
#else
av_opt_set_chlayout(ost->swr_ctx, "out_chlayout", &c->ch_layout, 0);
#endif
ret = swr_init(ost->swr_ctx);
if (ret < 0)
@ -1498,9 +1584,8 @@ static int initAudioStream( const char *codec_name, OutputStream *ost )
ost->frameSize = nb_samples;
ost->bytesPerSample = av_get_bytes_per_sample( c->sample_fmt );
ost->frame = alloc_audio_frame(c->sample_fmt, c->channel_layout, c->sample_rate, nb_samples);
ost->tmp_frame = alloc_audio_frame(c->sample_fmt, c->channel_layout, c->sample_rate, nb_samples);
//ost->tmp_frame = alloc_audio_frame(AV_SAMPLE_FMT_S16, AV_CH_LAYOUT_MONO, audioSampleRate, nb_samples);
ost->frame = alloc_audio_frame(c, nb_samples);
ost->tmp_frame = alloc_audio_frame(c, nb_samples);
//printf("Audio: FMT:%i ChanLayout:%li Rate:%i FrameSize:%i bytesPerSample:%i \n",
// c->sample_fmt, c->channel_layout, c->sample_rate, nb_samples, ost->bytesPerSample );
@ -1856,7 +1941,12 @@ static int encode_audio_frame( int16_t *audioOut, int numSamples)
ret = av_samples_copy( ost->frame->data, ost->tmp_frame->data,
ost->frame->nb_samples, srcOffset, copySize,
ost->frame->channels, ost->enc->sample_fmt );
#if LIBAVUTIL_VERSION_INT < AV_VERSION_INT(57, 28, 100)
ost->frame->channels,
#else
ost->frame->ch_layout.nb_channels,
#endif
ost->enc->sample_fmt );
if ( ret < 0 )
{
@ -2048,7 +2138,7 @@ int aviRecordLogOpen(void)
if ( avLogFp == NULL )
{
char msg[512];
sprintf( msg, "Error: Failed to open AV Recording log file for writing: %s\n", AV_LOG_FILE_NAME);
snprintf( msg, sizeof(msg), "Error: Failed to open AV Recording log file for writing: %s\n", AV_LOG_FILE_NAME);
FCEUD_PrintError(msg);
avLogFp = stdout;
}
@ -2063,7 +2153,7 @@ int aviRecordOpenFile( const char *filepath )
char fourcc[8];
gwavi_audio_t audioConfig;
double fps;
char fileName[1024];
std::string fileName;
char txt[512];
const char *romFile;
@ -2076,7 +2166,7 @@ int aviRecordOpenFile( const char *filepath )
if ( filepath != NULL )
{
strcpy( fileName, filepath );
fileName.assign( filepath );
}
else
{
@ -2095,21 +2185,21 @@ int aviRecordOpenFile( const char *filepath )
if ( lastPath.size() > 0 )
{
strcpy( fileName, lastPath.c_str() );
strcat( fileName, "/" );
fileName.assign( lastPath.c_str() );
fileName.append( "/" );
}
else if ( baseDir )
{
strcpy( fileName, baseDir );
strcat( fileName, "/avi/" );
fileName.assign( baseDir );
fileName.append( "/avi/" );
}
else
{
fileName[0] = 0;
fileName.clear();
}
strcat( fileName, base );
strcat( fileName, ".avi");
//printf("AVI Filepath:'%s'\n", fileName );
fileName.append( base );
fileName.append(".avi");
//printf("AVI Filepath:'%s'\n", fileName.c_str() );
}
else
{
@ -2117,9 +2207,9 @@ int aviRecordOpenFile( const char *filepath )
}
}
if ( fileName[0] != 0 )
if ( fileName.size() > 0 )
{
QFile file(fileName);
QFile file(fileName.c_str());
if ( file.exists() )
{
@ -2127,7 +2217,7 @@ int aviRecordOpenFile( const char *filepath )
std::string msg;
msg = "Pre-existing AVI file will be overwritten:\n\n" +
std::string(fileName) + "\n\nReplace file?";
fileName + "\n\nReplace file?";
ret = QMessageBox::warning( consoleWindow, QObject::tr("Overwrite Warning"),
QString::fromStdString(msg), QMessageBox::Yes | QMessageBox::No );
@ -2141,15 +2231,15 @@ int aviRecordOpenFile( const char *filepath )
date = QDate::currentDate();
avi_info.add_pair( "ICRD", date.toString(Qt::ISODate).toStdString().c_str() );
avi_info.add_pair( "ICRD", date.toString(Qt::ISODate).toLocal8Bit().constData() );
avi_info.add_pair( "ILNG", QLocale::languageToString( locale.language() ).toStdString().c_str() );
avi_info.add_pair( "ILNG", QLocale::languageToString( locale.language() ).toLocal8Bit().constData() );
avi_info.add_pair( "IARL", QLocale::countryToString( locale.country() ).toStdString().c_str() );
avi_info.add_pair( "IARL", QLocale::countryToString( locale.country() ).toLocal8Bit().constData() );
avi_info.add_pair( "IMED", QSysInfo::prettyProductName().toStdString().c_str() );
avi_info.add_pair( "IMED", QSysInfo::prettyProductName().toLocal8Bit().constData() );
sprintf( txt, "FCEUX %s", FCEU_VERSION_STRING );
snprintf( txt, sizeof(txt), "FCEUX %s", FCEU_VERSION_STRING );
avi_info.add_pair( "ITCH", txt );
romFile = getRomFile();
@ -2225,12 +2315,12 @@ int aviRecordOpenFile( const char *filepath )
#ifdef _USE_LIBAV
if ( aviDriver == AVI_DRIVER_LIBAV )
{
if ( LIBAV::initMedia( fileName ) )
if ( LIBAV::initMedia( fileName.c_str() ) )
{
char msg[512];
fprintf( avLogFp, "Error: Failed to open AVI file.\n");
recordEnable = false;
sprintf( msg, "Error: AV Recording Initialization Failed.\nSee %s for details...\n", AV_LOG_FILE_NAME);
snprintf( msg, sizeof(msg), "Error: AV Recording Initialization Failed.\nSee %s for details...\n", AV_LOG_FILE_NAME);
FCEUD_PrintError(msg);
return -1;
}
@ -2240,21 +2330,19 @@ int aviRecordOpenFile( const char *filepath )
{
gwavi = new gwavi_t();
if ( gwavi->open( fileName, nes_shm->video.ncol, nes_shm->video.nrow, fourcc, fps, recordAudio ? &audioConfig : NULL ) )
if ( gwavi->open( fileName.c_str(), nes_shm->video.ncol, nes_shm->video.nrow, fourcc, fps, recordAudio ? &audioConfig : NULL ) )
{
char msg[512];
fprintf( avLogFp, "Error: Failed to open AVI file.\n");
recordEnable = false;
sprintf( msg, "Error: AV Recording Initialization Failed.\nSee %s for details...\n", AV_LOG_FILE_NAME);
snprintf( msg, sizeof(msg), "Error: AV Recording Initialization Failed.\nSee %s for details...\n", AV_LOG_FILE_NAME);
FCEUD_PrintError(msg);
return -1;
}
}
vbufSize = 1024 * 1024 * 60;
rawVideoBuf = (uint32_t*)malloc( vbufSize * sizeof(uint32_t) );
abufSize = 96000;
rawAudioBuf = (int16_t*)malloc( abufSize * sizeof(uint16_t) );
vbufHead = 0;
@ -2273,10 +2361,6 @@ int aviRecordAddFrame( void )
return -1;
}
//if ( gwavi == NULL )
//{
// return -1;
//}
if ( FCEUI_EmulationPaused() )
{
return 0;
@ -2286,25 +2370,28 @@ int aviRecordAddFrame( void )
numPixels = nes_shm->video.ncol * nes_shm->video.nrow;
availSize = (vbufTail - vbufHead);
if ( availSize <= 0 )
head = vbufHead;
auto calcAvailSize = [&]()
{
availSize += vbufSize;
}
availSize = (vbufTail - head);
if ( availSize <= 0 )
{
availSize += vbufSize;
}
};
calcAvailSize();
while ( numPixels > availSize )
{
//printf("Video Unavail %i \n", availSize );
msleep(1);
availSize = (vbufTail - vbufHead);
if ( availSize <= 0 )
{
availSize += vbufSize;
}
calcAvailSize();
}
i = 0; head = vbufHead;
i = 0;
while ( i < numPixels )
{
@ -2333,12 +2420,17 @@ int aviRecordAddAudioFrame( int32_t *buf, int numSamples )
return -1;
}
// Get current buffer index values from atomic variables and store in stack variables
// Do loop processing with stack variables and then update atomics when finished
int head = abufHead;
for (int i=0; i<numSamples; i++)
{
rawAudioBuf[ abufHead ] = buf[i];
rawAudioBuf[ head ] = buf[i];
abufHead = (abufHead + 1) % abufSize;
head = (head + 1) % abufSize;
}
abufHead = head;
return 0;
}
@ -2362,8 +2454,10 @@ int aviRecordClose(void)
{
free(rawAudioBuf); rawAudioBuf = NULL;
}
vbufTail = abufTail = 0;
vbufSize = abufSize = 0;
vbufHead = 0;
abufHead = 0;
vbufTail = 0;
abufTail = 0;
return 0;
}
@ -2505,6 +2599,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)
@ -2524,6 +2619,8 @@ void AviRecordDiskThread_t::run(void)
char localRecordAudio = 0;
int avgAudioPerFrame, audioChunkSize, audioSamplesAvail=0;
int localVideoFormat;
int audioHead = 0;
int audioTail = 0;
fprintf( avLogFp, "AVI Record Disk Thread Start\n");
@ -2596,12 +2693,19 @@ void AviRecordDiskThread_t::run(void)
// Main Disk Record Loop
while ( !isInterruptionRequested() )
{
while ( (numPixelsReady < numPixels) && (vbufTail != vbufHead) )
{
videoOut[ numPixelsReady ] = rawVideoBuf[ vbufTail ]; numPixelsReady++;
vbufTail = (vbufTail + 1) % vbufSize;
// Get current buffer index values from atomic variables and store in stack variables
// Do loop processing with stack variables and then update atomics when finished
int vhead = vbufHead;
int vtail = vbufTail;
while ( (numPixelsReady < numPixels) && (vtail != vhead) )
{
videoOut[ numPixelsReady ] = rawVideoBuf[ vtail ]; numPixelsReady++;
vtail = (vtail + 1) % vbufSize;
}
vbufTail = vtail;
}
if ( numPixelsReady >= numPixels )
@ -2655,7 +2759,11 @@ void AviRecordDiskThread_t::run(void)
numPixelsReady = 0;
audioSamplesAvail = abufHead - abufTail;
// Get current buffer index values from atomic variables and store in stack variables
// Do loop processing with stack variables and then update atomics when finished
audioHead = abufHead;
audioTail = abufTail;
audioSamplesAvail = audioHead - audioTail;
if ( audioSamplesAvail < 0 )
{
@ -2667,17 +2775,18 @@ void AviRecordDiskThread_t::run(void)
{
numSamples = 0;
while ( abufHead != abufTail )
while ( audioHead != audioTail )
{
audioOut[ numSamples ] = rawAudioBuf[ abufTail ]; numSamples++;
audioOut[ numSamples ] = rawAudioBuf[ audioTail ]; numSamples++;
abufTail = (abufTail + 1) % abufSize;
audioTail = (audioTail + 1) % abufSize;
if ( numSamples >= audioChunkSize )
{
break;
}
}
abufTail = audioTail;
if ( numSamples > 0 )
{
@ -2703,8 +2812,11 @@ void AviRecordDiskThread_t::run(void)
}
}
audioHead = abufHead;
audioTail = abufTail;
// Write Leftover Audio Samples
audioSamplesAvail = abufHead - abufTail;
audioSamplesAvail = audioHead - audioTail;
if ( audioSamplesAvail < 0 )
{
@ -2717,12 +2829,13 @@ void AviRecordDiskThread_t::run(void)
//printf("Writing Last %i Audio Samples\n", audioSamplesAvail );
numSamples = 0;
while ( abufHead != abufTail )
while ( audioHead != audioTail )
{
audioOut[ numSamples ] = rawAudioBuf[ abufTail ]; numSamples++;
audioOut[ numSamples ] = rawAudioBuf[ audioTail ]; numSamples++;
abufTail = (abufTail + 1) % abufSize;
audioTail = (audioTail + 1) % abufSize;
}
abufTail = audioTail;
if ( numSamples > 0 )
{
@ -3060,7 +3173,7 @@ void LibavOptionsPage::initSampleRateSelect( const char *codec_name )
while ( c->supported_samplerates[i] != 0 )
{
sprintf( rateName, "%i", c->supported_samplerates[i] );
snprintf( rateName, sizeof(rateName), "%i", c->supported_samplerates[i] );
audioSampleRate->addItem( tr(rateName), c->supported_samplerates[i] );
@ -3093,6 +3206,7 @@ void LibavOptionsPage::initChannelLayoutSelect( const char *codec_name )
{
return;
}
#if LIBAVUTIL_VERSION_INT < AV_VERSION_INT(57, 28, 100)
if ( c->channel_layouts )
{
int i=0;
@ -3104,14 +3218,34 @@ void LibavOptionsPage::initChannelLayoutSelect( const char *codec_name )
audioChanLayout->addItem( tr(layoutDesc), (unsigned long long)c->channel_layouts[i] );
if ( LIBAV::audio_st.chanLayout == c->channel_layouts[i] )
if ( static_cast<uint64_t>(LIBAV::audio_st.chanLayout) == c->channel_layouts[i] )
{
audioChanLayout->setCurrentIndex( audioChanLayout->count() - 1 );
formatOk = true;
}
i++;
}
}
#else
const AVChannelLayout *p = c->ch_layouts;
while (p && p->nb_channels)
{
char layoutDesc[256];
av_channel_layout_describe(p, layoutDesc, sizeof(layoutDesc));
audioChanLayout->addItem( tr(layoutDesc), (unsigned long long)p->u.mask );
if ( LIBAV::audio_st.chanLayout == p->u.mask )
{
audioChanLayout->setCurrentIndex( audioChanLayout->count() - 1 );
formatOk = true;
}
p++;
}
#endif
if ( !formatOk )
{
LIBAV::audio_st.chanLayout = -1;
@ -3166,10 +3300,10 @@ void LibavOptionsPage::initCodecLists(void)
c = av_codec_iterate( &it );
}
initPixelFormatSelect( videoEncSel->currentText().toStdString().c_str() );
initSampleFormatSelect( audioEncSel->currentText().toStdString().c_str() );
initSampleRateSelect( audioEncSel->currentText().toStdString().c_str() );
initChannelLayoutSelect( audioEncSel->currentText().toStdString().c_str() );
initPixelFormatSelect( videoEncSel->currentText().toLocal8Bit().constData() );
initSampleFormatSelect( audioEncSel->currentText().toLocal8Bit().constData() );
initSampleRateSelect( audioEncSel->currentText().toLocal8Bit().constData() );
initChannelLayoutSelect( audioEncSel->currentText().toLocal8Bit().constData() );
videoEncSel->model()->sort(0, Qt::AscendingOrder);
audioEncSel->model()->sort(0, Qt::AscendingOrder);
@ -3184,7 +3318,7 @@ void LibavOptionsPage::videoCodecChanged(int idx)
{
const AVCodec *c;
LIBAV::video_st.selEnc = videoEncSel->currentText().toStdString().c_str();
LIBAV::video_st.selEnc = videoEncSel->currentText().toLocal8Bit().constData();
c = avcodec_find_encoder_by_name( LIBAV::video_st.selEnc.c_str() );
@ -3199,7 +3333,7 @@ void LibavOptionsPage::audioCodecChanged(int idx)
{
const AVCodec *c;
LIBAV::audio_st.selEnc = audioEncSel->currentText().toStdString().c_str();
LIBAV::audio_st.selEnc = audioEncSel->currentText().toLocal8Bit().constData();
c = avcodec_find_encoder_by_name( LIBAV::audio_st.selEnc.c_str() );
@ -3313,7 +3447,7 @@ void LibavEncOptItem::setValueText(void)
if ( units[x]->default_val.i64 & i )
{
char stmp2[128];
sprintf( stmp2, "%s", units[x]->name );
snprintf( stmp2, sizeof(stmp2), "%s", units[x]->name );
if (j>0)
{
strcat( stmp, ",");
@ -3335,7 +3469,9 @@ void LibavEncOptItem::setValueText(void)
break;
case AV_OPT_TYPE_INT:
case AV_OPT_TYPE_INT64:
#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(55, 58, 100)
case AV_OPT_TYPE_UINT64:
#endif
{
int64_t i;
@ -3346,7 +3482,7 @@ void LibavEncOptItem::setValueText(void)
if ( units[x]->default_val.i64 == i )
{
char stmp2[128];
sprintf( stmp2, " (%s)", units[x]->name );
snprintf( stmp2, sizeof(stmp2), " (%s)", units[x]->name );
strcat( stmp, stmp2 );
break;
}
@ -3382,12 +3518,12 @@ LibavEncOptWin::LibavEncOptWin(int type, QWidget *parent)
if ( type )
{
codec_name = LIBAV::audio_st.selEnc.c_str();
sprintf( title, "%s Audio Encoder Configuration", codec_name );
snprintf( title, sizeof(title), "%s Audio Encoder Configuration", codec_name );
}
else
{
codec_name = LIBAV::video_st.selEnc.c_str();
sprintf( title, "%s Video Encoder Configuration", codec_name );
snprintf( title, sizeof(title), "%s Video Encoder Configuration", codec_name );
}
setWindowTitle( title );
resize(512, 512);
@ -3707,7 +3843,9 @@ LibavEncOptInputWin::LibavEncOptInputWin( LibavEncOptItem *itemIn, QWidget *pare
{
case AV_OPT_TYPE_INT:
case AV_OPT_TYPE_INT64:
#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(55, 58, 100)
case AV_OPT_TYPE_UINT64:
#endif
{
int64_t val;
@ -3715,13 +3853,13 @@ LibavEncOptInputWin::LibavEncOptInputWin( LibavEncOptItem *itemIn, QWidget *pare
grid->addWidget( new QLabel( tr("Range:") ), 2, 0 );
sprintf( stmp, "[ %.0f, %.0f ]", opt->min, opt->max );
snprintf( stmp, sizeof(stmp), "[ %.0f, %.0f ]", opt->min, opt->max );
grid->addWidget( new QLabel( tr(stmp) ), 2, 1 );
grid->addWidget( new QLabel( tr("Default:") ), 3, 0 );
sprintf( stmp, "%lli", (long long)opt->default_val.i64 );
snprintf( stmp, sizeof(stmp), "%lli", (long long)opt->default_val.i64 );
grid->addWidget( new QLabel( tr(stmp) ), 3, 1 );
@ -3737,12 +3875,12 @@ LibavEncOptInputWin::LibavEncOptInputWin( LibavEncOptItem *itemIn, QWidget *pare
{
if ( item->units[i]->help )
{
sprintf( stmp, "%3lli: %s - %s", (long long)item->units[i]->default_val.i64,
snprintf( stmp, sizeof(stmp), "%3lli: %s - %s", (long long)item->units[i]->default_val.i64,
item->units[i]->name, item->units[i]->help );
}
else
{
sprintf( stmp, "%3lli: %s", (long long)item->units[i]->default_val.i64,
snprintf( stmp, sizeof(stmp), "%3lli: %s", (long long)item->units[i]->default_val.i64,
item->units[i]->name );
}
@ -3773,13 +3911,13 @@ LibavEncOptInputWin::LibavEncOptInputWin( LibavEncOptItem *itemIn, QWidget *pare
grid->addWidget( new QLabel( tr("Range:") ), 2, 0 );
sprintf( stmp, "[ %e, %e ]", opt->min, opt->max );
snprintf( stmp, sizeof(stmp), "[ %e, %e ]", opt->min, opt->max );
grid->addWidget( new QLabel( tr(stmp) ), 2, 1 );
grid->addWidget( new QLabel( tr("Default:") ), 3, 0 );
sprintf( stmp, "%f", opt->default_val.dbl );
snprintf( stmp, sizeof(stmp), "%f", opt->default_val.dbl );
grid->addWidget( new QLabel( tr(stmp) ), 3, 1 );
@ -3804,7 +3942,7 @@ LibavEncOptInputWin::LibavEncOptInputWin( LibavEncOptItem *itemIn, QWidget *pare
if ( opt->default_val.str )
{
sprintf( stmp, "%s", opt->default_val.str );
snprintf( stmp, sizeof(stmp), "%s", opt->default_val.str );
}
grid->addWidget( new QLabel( tr(stmp) ), 2, 1 );
@ -3828,7 +3966,7 @@ LibavEncOptInputWin::LibavEncOptInputWin( LibavEncOptItem *itemIn, QWidget *pare
grid->addWidget( new QLabel( tr("Default:") ), 2, 0 );
sprintf( stmp, "%i/%i", opt->default_val.q.num, opt->default_val.q.den );
snprintf( stmp, sizeof(stmp), "%i/%i", opt->default_val.q.num, opt->default_val.q.den );
grid->addWidget( new QLabel( tr(stmp) ), 2, 1 );
@ -3858,7 +3996,7 @@ LibavEncOptInputWin::LibavEncOptInputWin( LibavEncOptItem *itemIn, QWidget *pare
grid->addWidget( new QLabel( tr("Default:") ), 2, 0 );
sprintf( stmp, "%s", opt->default_val.i64 ? "true" : "false" );
snprintf( stmp, sizeof(stmp), "%s", opt->default_val.i64 ? "true" : "false" );
grid->addWidget( new QLabel( tr(stmp) ), 2, 1 );
@ -3882,7 +4020,7 @@ LibavEncOptInputWin::LibavEncOptInputWin( LibavEncOptItem *itemIn, QWidget *pare
grid->addWidget( new QLabel( tr("Default:") ), 2, 0 );
sprintf( stmp, "0x%08llX", (unsigned long long)opt->default_val.i64 );
snprintf( stmp, sizeof(stmp), "0x%08llX", (unsigned long long)opt->default_val.i64 );
grid->addWidget( new QLabel( tr(stmp) ), 2, 1 );
@ -3892,7 +4030,7 @@ LibavEncOptInputWin::LibavEncOptInputWin( LibavEncOptItem *itemIn, QWidget *pare
for (size_t i=0; i<item->units.size(); i++)
{
sprintf( stmp, "%s", item->units[i]->name );
snprintf( stmp, sizeof(stmp), "%s", item->units[i]->name );
c = new QCheckBox( tr(stmp) );
@ -3972,7 +4110,9 @@ void LibavEncOptInputWin::applyChanges(void)
{
case AV_OPT_TYPE_INT:
case AV_OPT_TYPE_INT64:
#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(55, 58, 100)
case AV_OPT_TYPE_UINT64:
#endif
{
if ( intEntry )
{
@ -3999,7 +4139,7 @@ void LibavEncOptInputWin::applyChanges(void)
{
if ( strEntry )
{
av_opt_set( item->obj, item->opt->name, strEntry->text().toStdString().c_str(), 0 );
av_opt_set( item->obj, item->opt->name, strEntry->text().toLocal8Bit().constData(), 0 );
}
}
break;
@ -4062,7 +4202,9 @@ void LibavEncOptInputWin::resetDefaultsCB(void)
{
case AV_OPT_TYPE_INT:
case AV_OPT_TYPE_INT64:
#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(55, 58, 100)
case AV_OPT_TYPE_UINT64:
#endif
{
if ( intEntry )
{

View File

@ -294,18 +294,18 @@ void AviRiffViewerDialog::openAviFileDialog(void)
{
return;
}
//qDebug() << "selected file path : " << filename.toUtf8();
//qDebug() << "selected file path : " << filename.toLocal8Bit();
printf( "AVI Debug movie %s\n", filename.toStdString().c_str() );
printf( "AVI Debug movie %s\n", filename.toLocal8Bit().constData() );
lastPath = QFileInfo(filename).absolutePath().toStdString();
lastPath = QFileInfo(filename).absolutePath().toLocal8Bit().constData();
if ( lastPath.size() > 0 )
{
g_config->setOption ("SDL.AviFilePath", lastPath);
}
openFile( filename.toStdString().c_str() );
openFile( filename.toLocal8Bit().constData() );
}
//----------------------------------------------------------------------------
int AviRiffViewerDialog::openFile( const char *filepath )
@ -475,112 +475,112 @@ int AviRiffViewerDialog::processChunk( AviRiffTreeItem *item )
avi->getChunkData( item->filePos(), data.buf, item->getSize()+8 );
sprintf( stmp, "%c%c%c%c", data.buf[0], data.buf[1], data.buf[2], data.buf[3] );
snprintf( stmp, sizeof(stmp), "%c%c%c%c", data.buf[0], data.buf[1], data.buf[2], data.buf[3] );
twi = new QTreeWidgetItem();
twi->setText( 0, tr("fcc") );
twi->setText( 2, tr(stmp) );
item->addChild(twi);
sprintf( stmp, "%u", data.readU32(4) );
snprintf( stmp, sizeof(stmp), "%u", data.readU32(4) );
twi = new QTreeWidgetItem();
twi->setText( 0, tr("cb") );
twi->setText( 2, tr(stmp) );
item->addChild(twi);
sprintf( stmp, "%u", data.readU32(8) );
snprintf( stmp, sizeof(stmp), "%u", data.readU32(8) );
twi = new QTreeWidgetItem();
twi->setText( 0, tr("dwMicroSecPerFrame") );
twi->setText( 2, tr(stmp) );
item->addChild(twi);
sprintf( stmp, "%u", data.readU32(12) );
snprintf( stmp, sizeof(stmp), "%u", data.readU32(12) );
twi = new QTreeWidgetItem();
twi->setText( 0, tr("dwMaxBytesPerSec") );
twi->setText( 2, tr(stmp) );
item->addChild(twi);
sprintf( stmp, "%u", data.readU32(16) );
snprintf( stmp, sizeof(stmp), "%u", data.readU32(16) );
twi = new QTreeWidgetItem();
twi->setText( 0, tr("dwPaddingGranularity") );
twi->setText( 2, tr(stmp) );
item->addChild(twi);
sprintf( stmp, "0x%X", data.readU32(20) );
snprintf( stmp, sizeof(stmp), "0x%X", data.readU32(20) );
twi = new QTreeWidgetItem();
twi->setText( 0, tr("dwFlags") );
twi->setText( 2, tr(stmp) );
item->addChild(twi);
sprintf( stmp, "%u", data.readU32(24) );
snprintf( stmp, sizeof(stmp), "%u", data.readU32(24) );
twi = new QTreeWidgetItem();
twi->setText( 0, tr("dwTotalFrames") );
twi->setText( 2, tr(stmp) );
item->addChild(twi);
sprintf( stmp, "%u", data.readU32(28) );
snprintf( stmp, sizeof(stmp), "%u", data.readU32(28) );
twi = new QTreeWidgetItem();
twi->setText( 0, tr("dwInitialFrames") );
twi->setText( 2, tr(stmp) );
item->addChild(twi);
sprintf( stmp, "%u", data.readU32(32) );
snprintf( stmp, sizeof(stmp), "%u", data.readU32(32) );
twi = new QTreeWidgetItem();
twi->setText( 0, tr("dwStreams") );
twi->setText( 2, tr(stmp) );
item->addChild(twi);
sprintf( stmp, "%u", data.readU32(36) );
snprintf( stmp, sizeof(stmp), "%u", data.readU32(36) );
twi = new QTreeWidgetItem();
twi->setText( 0, tr("dwSuggestedBufferSize") );
twi->setText( 2, tr(stmp) );
item->addChild(twi);
sprintf( stmp, "%u", data.readU32(40) );
snprintf( stmp, sizeof(stmp), "%u", data.readU32(40) );
twi = new QTreeWidgetItem();
twi->setText( 0, tr("dwWidth") );
twi->setText( 2, tr(stmp) );
item->addChild(twi);
sprintf( stmp, "%u", data.readU32(44) );
snprintf( stmp, sizeof(stmp), "%u", data.readU32(44) );
twi = new QTreeWidgetItem();
twi->setText( 0, tr("dwHeight") );
twi->setText( 2, tr(stmp) );
item->addChild(twi);
sprintf( stmp, "%u", data.readU32(48) );
snprintf( stmp, sizeof(stmp), "%u", data.readU32(48) );
twi = new QTreeWidgetItem();
twi->setText( 0, tr("dwScale") );
twi->setText( 2, tr(stmp) );
item->addChild(twi);
sprintf( stmp, "%u", data.readU32(52) );
snprintf( stmp, sizeof(stmp), "%u", data.readU32(52) );
twi = new QTreeWidgetItem();
twi->setText( 0, tr("dwRate") );
twi->setText( 2, tr(stmp) );
item->addChild(twi);
sprintf( stmp, "%u", data.readU32(56) );
snprintf( stmp, sizeof(stmp), "%u", data.readU32(56) );
twi = new QTreeWidgetItem();
twi->setText( 0, tr("dwStart") );
twi->setText( 2, tr(stmp) );
item->addChild(twi);
sprintf( stmp, "%u", data.readU32(60) );
snprintf( stmp, sizeof(stmp), "%u", data.readU32(60) );
twi = new QTreeWidgetItem();
twi->setText( 0, tr("dwLength") );
@ -593,21 +593,21 @@ int AviRiffViewerDialog::processChunk( AviRiffTreeItem *item )
avi->getChunkData( item->filePos(), data.buf, item->getSize()+8 );
sprintf( stmp, "%c%c%c%c", data.buf[0], data.buf[1], data.buf[2], data.buf[3] );
snprintf( stmp, sizeof(stmp), "%c%c%c%c", data.buf[0], data.buf[1], data.buf[2], data.buf[3] );
twi = new QTreeWidgetItem();
twi->setText( 0, tr("fcc") );
twi->setText( 2, tr(stmp) );
item->addChild(twi);
sprintf( stmp, "%u", data.readU32(4) );
snprintf( stmp, sizeof(stmp), "%u", data.readU32(4) );
twi = new QTreeWidgetItem();
twi->setText( 0, tr("cb") );
twi->setText( 2, tr(stmp) );
item->addChild(twi);
sprintf( stmp, "%c%c%c%c", data.buf[8], data.buf[9], data.buf[10], data.buf[11] );
snprintf( stmp, sizeof(stmp), "%c%c%c%c", data.buf[8], data.buf[9], data.buf[10], data.buf[11] );
strcpy( strhType, stmp );
twi = new QTreeWidgetItem();
@ -617,11 +617,11 @@ int AviRiffViewerDialog::processChunk( AviRiffTreeItem *item )
if ( isalnum(data.buf[12]) )
{
sprintf( stmp, "%c%c%c%c", data.buf[12], data.buf[13], data.buf[14], data.buf[15] );
snprintf( stmp, sizeof(stmp), "%c%c%c%c", data.buf[12], data.buf[13], data.buf[14], data.buf[15] );
}
else
{
sprintf( stmp, "0x%X", data.readU32(12) );
snprintf( stmp, sizeof(stmp), "0x%X", data.readU32(12) );
}
twi = new QTreeWidgetItem();
@ -629,42 +629,42 @@ int AviRiffViewerDialog::processChunk( AviRiffTreeItem *item )
twi->setText( 2, tr(stmp) );
item->addChild(twi);
sprintf( stmp, "0x%X", data.readU32(16) );
snprintf( stmp, sizeof(stmp), "0x%X", data.readU32(16) );
twi = new QTreeWidgetItem();
twi->setText( 0, tr("dwFlags") );
twi->setText( 2, tr(stmp) );
item->addChild(twi);
sprintf( stmp, "%u", data.readU16(20) );
snprintf( stmp, sizeof(stmp), "%u", data.readU16(20) );
twi = new QTreeWidgetItem();
twi->setText( 0, tr("wPriority") );
twi->setText( 2, tr(stmp) );
item->addChild(twi);
sprintf( stmp, "%u", data.readU16(22) );
snprintf( stmp, sizeof(stmp), "%u", data.readU16(22) );
twi = new QTreeWidgetItem();
twi->setText( 0, tr("wLanguage") );
twi->setText( 2, tr(stmp) );
item->addChild(twi);
sprintf( stmp, "%u", data.readU32(24) );
snprintf( stmp, sizeof(stmp), "%u", data.readU32(24) );
twi = new QTreeWidgetItem();
twi->setText( 0, tr("dwInitialFrames") );
twi->setText( 2, tr(stmp) );
item->addChild(twi);
sprintf( stmp, "%u", data.readU32(28) );
snprintf( stmp, sizeof(stmp), "%u", data.readU32(28) );
twi = new QTreeWidgetItem();
twi->setText( 0, tr("dwScale") );
twi->setText( 2, tr(stmp) );
item->addChild(twi);
sprintf( stmp, "%u", data.readU32(32) );
snprintf( stmp, sizeof(stmp), "%u", data.readU32(32) );
twi = new QTreeWidgetItem();
twi->setText( 0, tr("dwRate") );
@ -672,68 +672,68 @@ int AviRiffViewerDialog::processChunk( AviRiffTreeItem *item )
if ( strcmp( strhType, "vids" ) == 0 )
{
sprintf( stmp, "(%13.10f Hz)", (double)data.readU32(32) / (double)data.readU32(28) );
snprintf( stmp, sizeof(stmp), "(%13.10f Hz)", (double)data.readU32(32) / (double)data.readU32(28) );
twi->setText( 3, tr(stmp) );
}
item->addChild(twi);
sprintf( stmp, "%u", data.readU32(36) );
snprintf( stmp, sizeof(stmp), "%u", data.readU32(36) );
twi = new QTreeWidgetItem();
twi->setText( 0, tr("dwStart") );
twi->setText( 2, tr(stmp) );
item->addChild(twi);
sprintf( stmp, "%u", data.readU32(40) );
snprintf( stmp, sizeof(stmp), "%u", data.readU32(40) );
twi = new QTreeWidgetItem();
twi->setText( 0, tr("dwLength") );
twi->setText( 2, tr(stmp) );
item->addChild(twi);
sprintf( stmp, "%u", data.readU32(44) );
snprintf( stmp, sizeof(stmp), "%u", data.readU32(44) );
twi = new QTreeWidgetItem();
twi->setText( 0, tr("dwSuggestedBufferSize") );
twi->setText( 2, tr(stmp) );
item->addChild(twi);
sprintf( stmp, "%i", data.readI32(48) );
snprintf( stmp, sizeof(stmp), "%i", data.readI32(48) );
twi = new QTreeWidgetItem();
twi->setText( 0, tr("dwQuality") );
twi->setText( 2, tr(stmp) );
item->addChild(twi);
sprintf( stmp, "%u", data.readU32(52) );
snprintf( stmp, sizeof(stmp), "%u", data.readU32(52) );
twi = new QTreeWidgetItem();
twi->setText( 0, tr("dwSampleSize") );
twi->setText( 2, tr(stmp) );
item->addChild(twi);
sprintf( stmp, "%u", data.readU16(56) );
snprintf( stmp, sizeof(stmp), "%u", data.readU16(56) );
twi = new QTreeWidgetItem();
twi->setText( 0, tr("rcFrame.left") );
twi->setText( 2, tr(stmp) );
item->addChild(twi);
sprintf( stmp, "%u", data.readU16(58) );
snprintf( stmp, sizeof(stmp), "%u", data.readU16(58) );
twi = new QTreeWidgetItem();
twi->setText( 0, tr("rcFrame.top") );
twi->setText( 2, tr(stmp) );
item->addChild(twi);
sprintf( stmp, "%u", data.readU16(60) );
snprintf( stmp, sizeof(stmp), "%u", data.readU16(60) );
twi = new QTreeWidgetItem();
twi->setText( 0, tr("rcFrame.right") );
twi->setText( 2, tr(stmp) );
item->addChild(twi);
sprintf( stmp, "%u", data.readU16(62) );
snprintf( stmp, sizeof(stmp), "%u", data.readU16(62) );
twi = new QTreeWidgetItem();
twi->setText( 0, tr("rcFrame.bottom") );
@ -748,49 +748,49 @@ int AviRiffViewerDialog::processChunk( AviRiffTreeItem *item )
avi->getChunkData( item->filePos(), data.buf, item->getSize()+8 );
sprintf( stmp, "%c%c%c%c", data.buf[0], data.buf[1], data.buf[2], data.buf[3] );
snprintf( stmp, sizeof(stmp), "%c%c%c%c", data.buf[0], data.buf[1], data.buf[2], data.buf[3] );
twi = new QTreeWidgetItem();
twi->setText( 0, tr("fcc") );
twi->setText( 2, tr(stmp) );
item->addChild(twi);
sprintf( stmp, "%u", data.readU32(4) );
snprintf( stmp, sizeof(stmp), "%u", data.readU32(4) );
twi = new QTreeWidgetItem();
twi->setText( 0, tr("cb") );
twi->setText( 2, tr(stmp) );
item->addChild(twi);
sprintf( stmp, "%u", data.readU32(8) );
snprintf( stmp, sizeof(stmp), "%u", data.readU32(8) );
twi = new QTreeWidgetItem();
twi->setText( 0, tr("biSize") );
twi->setText( 2, tr(stmp) );
item->addChild(twi);
sprintf( stmp, "%i", data.readI32(12) );
snprintf( stmp, sizeof(stmp), "%i", data.readI32(12) );
twi = new QTreeWidgetItem();
twi->setText( 0, tr("biWidth") );
twi->setText( 2, tr(stmp) );
item->addChild(twi);
sprintf( stmp, "%i", data.readI32(16) );
snprintf( stmp, sizeof(stmp), "%i", data.readI32(16) );
twi = new QTreeWidgetItem();
twi->setText( 0, tr("biHeight") );
twi->setText( 2, tr(stmp) );
item->addChild(twi);
sprintf( stmp, "%u", data.readU16(20) );
snprintf( stmp, sizeof(stmp), "%u", data.readU16(20) );
twi = new QTreeWidgetItem();
twi->setText( 0, tr("biPlanes") );
twi->setText( 2, tr(stmp) );
item->addChild(twi);
sprintf( stmp, "%u", data.readU16(22) );
snprintf( stmp, sizeof(stmp), "%u", data.readU16(22) );
twi = new QTreeWidgetItem();
twi->setText( 0, tr("biBitCount") );
@ -799,11 +799,11 @@ int AviRiffViewerDialog::processChunk( AviRiffTreeItem *item )
if ( isalnum(data.buf[24]) )
{
sprintf( stmp, "%c%c%c%c", data.buf[24], data.buf[25], data.buf[26], data.buf[27] );
snprintf( stmp, sizeof(stmp), "%c%c%c%c", data.buf[24], data.buf[25], data.buf[26], data.buf[27] );
}
else
{
sprintf( stmp, "0x%X", data.readU32(24) );
snprintf( stmp, sizeof(stmp), "0x%X", data.readU32(24) );
}
twi = new QTreeWidgetItem();
@ -811,35 +811,35 @@ int AviRiffViewerDialog::processChunk( AviRiffTreeItem *item )
twi->setText( 2, tr(stmp) );
item->addChild(twi);
sprintf( stmp, "%u", data.readU32(28) );
snprintf( stmp, sizeof(stmp), "%u", data.readU32(28) );
twi = new QTreeWidgetItem();
twi->setText( 0, tr("biSizeImage") );
twi->setText( 2, tr(stmp) );
item->addChild(twi);
sprintf( stmp, "%i", data.readI32(32) );
snprintf( stmp, sizeof(stmp), "%i", data.readI32(32) );
twi = new QTreeWidgetItem();
twi->setText( 0, tr("biXPelsPerMeter") );
twi->setText( 2, tr(stmp) );
item->addChild(twi);
sprintf( stmp, "%i", data.readI32(36) );
snprintf( stmp, sizeof(stmp), "%i", data.readI32(36) );
twi = new QTreeWidgetItem();
twi->setText( 0, tr("biYPelsPerMeter") );
twi->setText( 2, tr(stmp) );
item->addChild(twi);
sprintf( stmp, "%u", data.readU32(40) );
snprintf( stmp, sizeof(stmp), "%u", data.readU32(40) );
twi = new QTreeWidgetItem();
twi->setText( 0, tr("biClrUsed") );
twi->setText( 2, tr(stmp) );
item->addChild(twi);
sprintf( stmp, "%u", data.readU32(44) );
snprintf( stmp, sizeof(stmp), "%u", data.readU32(44) );
twi = new QTreeWidgetItem();
twi->setText( 0, tr("biClrImportant") );
@ -854,56 +854,56 @@ int AviRiffViewerDialog::processChunk( AviRiffTreeItem *item )
avi->getChunkData( item->filePos(), data.buf, dataSize );
sprintf( stmp, "%c%c%c%c", data.buf[0], data.buf[1], data.buf[2], data.buf[3] );
snprintf( stmp, sizeof(stmp), "%c%c%c%c", data.buf[0], data.buf[1], data.buf[2], data.buf[3] );
twi = new QTreeWidgetItem();
twi->setText( 0, tr("fcc") );
twi->setText( 2, tr(stmp) );
item->addChild(twi);
sprintf( stmp, "%u", data.readU32(4) );
snprintf( stmp, sizeof(stmp), "%u", data.readU32(4) );
twi = new QTreeWidgetItem();
twi->setText( 0, tr("cb") );
twi->setText( 2, tr(stmp) );
item->addChild(twi);
sprintf( stmp, "%u", data.readU16(8) );
snprintf( stmp, sizeof(stmp), "%u", data.readU16(8) );
twi = new QTreeWidgetItem();
twi->setText( 0, tr("wFormatTag") );
twi->setText( 2, tr(stmp) );
item->addChild(twi);
sprintf( stmp, "%u", data.readU16(10) );
snprintf( stmp, sizeof(stmp), "%u", data.readU16(10) );
twi = new QTreeWidgetItem();
twi->setText( 0, tr("nChannels") );
twi->setText( 2, tr(stmp) );
item->addChild(twi);
sprintf( stmp, "%u", data.readU32(12) );
snprintf( stmp, sizeof(stmp), "%u", data.readU32(12) );
twi = new QTreeWidgetItem();
twi->setText( 0, tr("nSamplesPerSec") );
twi->setText( 2, tr(stmp) );
item->addChild(twi);
sprintf( stmp, "%u", data.readU32(16) );
snprintf( stmp, sizeof(stmp), "%u", data.readU32(16) );
twi = new QTreeWidgetItem();
twi->setText( 0, tr("nAvgBytesPerSec") );
twi->setText( 2, tr(stmp) );
item->addChild(twi);
sprintf( stmp, "%u", data.readU16(20) );
snprintf( stmp, sizeof(stmp), "%u", data.readU16(20) );
twi = new QTreeWidgetItem();
twi->setText( 0, tr("nBlockAlign") );
twi->setText( 2, tr(stmp) );
item->addChild(twi);
sprintf( stmp, "%u", data.readU16(22) );
snprintf( stmp, sizeof(stmp), "%u", data.readU16(22) );
twi = new QTreeWidgetItem();
twi->setText( 0, tr("nBitsPerSample") );
@ -929,25 +929,25 @@ int AviRiffViewerDialog::processChunk( AviRiffTreeItem *item )
avi->getChunkData( item->filePos(), data.buf, item->getSize()+8 );
sprintf( stmp, "%c%c%c%c", data.buf[0], data.buf[1], data.buf[2], data.buf[3] );
snprintf( stmp, sizeof(stmp), "%c%c%c%c", data.buf[0], data.buf[1], data.buf[2], data.buf[3] );
twi = new QTreeWidgetItem();
twi->setText( 0, tr("fcc") );
twi->setText( 2, tr(stmp) );
item->addChild(twi);
sprintf( stmp, "%u", data.readU32(4) );
snprintf( stmp, sizeof(stmp), "%u", data.readU32(4) );
twi = new QTreeWidgetItem();
twi->setText( 0, tr("cb") );
twi->setText( 2, tr(stmp) );
item->addChild(twi);
sprintf( stmp, "%u", data.readU32(8) );
snprintf( stmp, sizeof(stmp), "%u", data.readU32(8) );
for (i=0; i<item->getSize(); i++)
for (i=0; i < static_cast<int>(item->getSize()); i++)
{
if ( i >= ( sizeof(stmp)-1 ) )
if ( i >= (static_cast<int>(sizeof(stmp))-1 ) )
{
i = sizeof(stmp)-1; break;
}
@ -991,7 +991,7 @@ AviRiffTreeItem::AviRiffTreeItem(int typeIn, long long int fposIn, const char *f
strcpy( fourcc, fourccIn );
//sprintf( stmp, "0x%08llX", fposIn );
//snprintf( stmp, sizeof(stmp), "0x%08llX", fposIn );
switch ( type )
{
@ -1013,16 +1013,16 @@ AviRiffTreeItem::AviRiffTreeItem(int typeIn, long long int fposIn, const char *f
if ( showSizeHex )
{
sprintf( stmp, "0x%08lX", (unsigned long)size );
snprintf( stmp, sizeof(stmp), "0x%08lX", (unsigned long)size );
}
else
{
sprintf( stmp, "%zu", size );
snprintf( stmp, sizeof(stmp), "%zu", size );
}
setText( 2, QString(stmp) );
sprintf( stmp, "0x%08llX", fposIn );
snprintf( stmp, sizeof(stmp), "0x%08llX", fposIn );
setText( 3, QString(stmp) );
}

View File

@ -54,7 +54,6 @@ void openCheatDialog(QWidget *parent)
{
win->activateWindow();
win->raise();
win->setFocus();
return;
}
win = new GuiCheatsDialog_t(parent);
@ -518,9 +517,9 @@ int GuiCheatsDialog_t::addSearchResult(uint32_t a, uint8_t last, uint8_t current
item = new QTreeWidgetItem();
sprintf(addrStr, "$%04X", a);
sprintf(lastStr, "%02X", last);
sprintf(curStr, "%02X", current);
snprintf(addrStr, sizeof(addrStr), "$%04X", a);
snprintf(lastStr, sizeof(lastStr), "%02X", last);
snprintf(curStr, sizeof(curStr), "%02X", current);
//item->setFont( 0, font );
//item->setFont( 1, font );
@ -592,9 +591,9 @@ void GuiCheatsDialog_t::knownValueCallback(void)
//printf("Cheat Search Known!\n");
FCEU_WRAPPER_LOCK();
//printf("'%s'\n", knownValEntry->displayText().toStdString().c_str() );
//printf("'%s'\n", knownValEntry->displayText().toLocal8Bit().constData() );
value = strtol(knownValEntry->displayText().toStdString().c_str(), NULL, 16);
value = strtol(knownValEntry->displayText().toLocal8Bit().constData(), NULL, 16);
FCEUI_CheatSearchEnd(FCEU_SEARCH_NEWVAL_KNOWN, value, 0);
@ -625,7 +624,7 @@ void GuiCheatsDialog_t::notEqualValueCallback(void)
if (checked)
{
value = strtol(neValEntry->displayText().toStdString().c_str(), NULL, 16);
value = strtol(neValEntry->displayText().toLocal8Bit().constData(), NULL, 16);
FCEUI_CheatSearchEnd(FCEU_SEARCH_PUERLY_RELATIVE_CHANGE, 0, value);
}
@ -649,7 +648,7 @@ void GuiCheatsDialog_t::greaterThanValueCallback(void)
if (checked)
{
value = strtol(grValEntry->displayText().toStdString().c_str(), NULL, 16);
value = strtol(grValEntry->displayText().toLocal8Bit().constData(), NULL, 16);
FCEUI_CheatSearchEnd(FCEU_SEARCH_NEWVAL_GT_KNOWN, 0, value);
}
@ -673,7 +672,7 @@ void GuiCheatsDialog_t::lessThanValueCallback(void)
if (checked)
{
value = strtol(ltValEntry->displayText().toStdString().c_str(), NULL, 16);
value = strtol(ltValEntry->displayText().toLocal8Bit().constData(), NULL, 16);
FCEUI_CheatSearchEnd(FCEU_SEARCH_NEWVAL_LT_KNOWN, 0, value);
}
@ -694,25 +693,21 @@ int GuiCheatsDialog_t::activeCheatListCB(const char *name, uint32 a, uint8 v, in
if (c >= 0)
{
sprintf(codeStr, "$%04X?%02X:%02X", a, c, v);
snprintf(codeStr, sizeof(codeStr), "$%04X?%02X:%02X", a, c, v);
}
else
{
sprintf(codeStr, "$%04X:%02X ", a, v);
snprintf(codeStr, sizeof(codeStr), "$%04X:%02X ", a, v);
}
item = actvCheatList->topLevelItem(actvCheatIdx);
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)
@ -755,7 +750,7 @@ void GuiCheatsDialog_t::openCheatFile(void)
int ret, useNativeFileDialogVal;
QString filename;
std::string last;
char dir[512];
std::string dir;
QFileDialog dialog(this, tr("Open Cheat File"));
dialog.setFileMode(QFileDialog::ExistingFile);
@ -770,7 +765,7 @@ void GuiCheatsDialog_t::openCheatFile(void)
getDirFromFile(last.c_str(), dir);
dialog.setDirectory(tr(dir));
dialog.setDirectory(tr(dir.c_str()));
// Check config option to use native file dialog or not
g_config->getOption("SDL.UseNativeFileDialog", &useNativeFileDialogVal);
@ -794,13 +789,13 @@ void GuiCheatsDialog_t::openCheatFile(void)
{
return;
}
qDebug() << "selected file path : " << filename.toUtf8();
qDebug() << "selected file path : " << filename.toLocal8Bit();
g_config->setOption("SDL.LastOpenFile", filename.toStdString().c_str());
g_config->setOption("SDL.LastOpenFile", filename.toLocal8Bit().constData());
FCEU_WRAPPER_LOCK();
fp = fopen(filename.toStdString().c_str(), "r");
fp = fopen(filename.toLocal8Bit().constData(), "r");
if (fp != NULL)
{
@ -819,7 +814,7 @@ void GuiCheatsDialog_t::saveCheatFile(void)
FILE *fp;
int ret, useNativeFileDialogVal;
QString filename;
char dir[512];
char dir[4096];
QFileDialog dialog(this, tr("Save Cheat File"));
dialog.setFileMode(QFileDialog::AnyFile);
@ -839,7 +834,7 @@ void GuiCheatsDialog_t::saveCheatFile(void)
dialog.selectFile(dir);
}
sprintf(dir, "%s/cheats", FCEUI_GetBaseDirectory());
snprintf(dir, sizeof(dir), "%s/cheats", FCEUI_GetBaseDirectory());
dialog.setDirectory(tr(dir));
@ -865,13 +860,13 @@ void GuiCheatsDialog_t::saveCheatFile(void)
{
return;
}
qDebug() << "selected file path : " << filename.toUtf8();
qDebug() << "selected file path : " << filename.toLocal8Bit();
//g_config->setOption ("SDL.LastOpenFile", filename.toStdString().c_str() );
//g_config->setOption ("SDL.LastOpenFile", filename.toLocal8Bit().constData() );
FCEU_WRAPPER_LOCK();
fp = FCEUD_UTF8fopen(filename.toStdString().c_str(), "wb");
fp = FCEUD_UTF8fopen(filename.toLocal8Bit().constData(), "wb");
if (fp != NULL)
{
@ -893,11 +888,11 @@ void GuiCheatsDialog_t::addActvCheat(void)
int t = 1;
std::string name, cmpStr;
a = strtoul(cheatAddrEntry->displayText().toStdString().c_str(), NULL, 16);
a = strtoul(cheatAddrEntry->displayText().toLocal8Bit().constData(), NULL, 16);
v = strtoul(cheatValEntry->displayText().toStdString().c_str(), NULL, 16);
v = strtoul(cheatValEntry->displayText().toLocal8Bit().constData(), NULL, 16);
cmpStr = cheatCmpEntry->displayText().toStdString();
cmpStr = cheatCmpEntry->displayText().toLocal8Bit().constData();
if (isxdigit(cmpStr[0]))
{
@ -908,7 +903,7 @@ void GuiCheatsDialog_t::addActvCheat(void)
c = -1;
}
name = cheatNameEntry->text().toStdString();
name = cheatNameEntry->text().toLocal8Bit().constData();
t = typeEntry->currentData().toInt();
@ -970,11 +965,11 @@ void GuiCheatsDialog_t::updateCheatParameters(void)
}
//printf("Row: %i \n", row );
a = strtoul(cheatAddrEntry->displayText().toStdString().c_str(), NULL, 16);
a = strtoul(cheatAddrEntry->displayText().toLocal8Bit().constData(), NULL, 16);
v = strtoul(cheatValEntry->displayText().toStdString().c_str(), NULL, 16);
v = strtoul(cheatValEntry->displayText().toLocal8Bit().constData(), NULL, 16);
cmpStr = cheatCmpEntry->displayText().toStdString();
cmpStr = cheatCmpEntry->displayText().toLocal8Bit().constData();
//printf("CMP: '%s' \n", cmpStr.c_str() );
@ -988,7 +983,7 @@ void GuiCheatsDialog_t::updateCheatParameters(void)
}
//printf("CMP: '%i' 0x%X\n", c, c );
name = cheatNameEntry->text().toStdString();
name = cheatNameEntry->text().toLocal8Bit().constData();
//printf("Name: %s \n", name.c_str() );
@ -1030,15 +1025,15 @@ void GuiCheatsDialog_t::actvCheatItemClicked(QTreeWidgetItem *item, int column)
FCEUI_ToggleCheat(row);
}
}
sprintf(stmp, "%04X", a);
snprintf(stmp, sizeof(stmp), "%04X", a);
cheatAddrEntry->setText(tr(stmp));
sprintf(stmp, "%02X", v);
snprintf(stmp, sizeof(stmp), "%02X", v);
cheatValEntry->setText(tr(stmp));
if (c >= 0)
{
sprintf(stmp, "%02X", c);
snprintf(stmp, sizeof(stmp), "%02X", c);
cheatCmpEntry->setText(tr(stmp));
}
else

View File

@ -72,7 +72,6 @@ protected:
int fontCharWidth;
int actvCheatIdx;
bool actvCheatRedraw;
bool pauseWhileActive;
bool wasPausedByCheats;

View File

@ -51,7 +51,7 @@ static int autoResumeCDL = false;
static bool autoSaveArmedCDL = false;
static char loadedcdfile[512] = {0};
static int getDefaultCDLFile(char *filepath);
static int getDefaultCDLFile(std::string &filepath);
static CodeDataLoggerDialog_t *cdlWin = NULL;
//----------------------------------------------------
@ -63,7 +63,6 @@ int openCDLWindow( QWidget *parent )
{
cdlWin->activateWindow();
cdlWin->raise();
cdlWin->setFocus();
}
else
{
@ -280,9 +279,9 @@ CodeDataLoggerDialog_t::CodeDataLoggerDialog_t(QWidget *parent)
if (autoLoadCDL)
{
char nameo[2048];
std::string nameo;
getDefaultCDLFile(nameo);
LoadCDLog(nameo);
LoadCDLog(nameo.c_str());
}
restoreGeometry(settings.value("cdLogger/geometry").toByteArray());
@ -365,22 +364,22 @@ void CodeDataLoggerDialog_t::updatePeriodic(void)
if (cdloggerdataSize > 0)
{
sprintf(str, "0x%06x %.2f%%", codecount, (fcodecount / fromsize) * 100);
snprintf(str, sizeof(str), "0x%06x %.2f%%", codecount, (fcodecount / fromsize) * 100);
prgLoggedCodeLabel->setText(tr(str));
sprintf(str, "0x%06x %.2f%%", datacount, (fdatacount / fromsize) * 100);
snprintf(str, sizeof(str), "0x%06x %.2f%%", datacount, (fdatacount / fromsize) * 100);
prgLoggedDataLabel->setText(tr(str));
sprintf(str, "0x%06x %.2f%%", undefinedcount, (fundefinedcount / fromsize) * 100);
snprintf(str, sizeof(str), "0x%06x %.2f%%", undefinedcount, (fundefinedcount / fromsize) * 100);
prgUnloggedLabel->setText(tr(str));
sprintf(str, "0x%06x %.2f%%", rendercount, (frendercount / fvromsize) * 100);
snprintf(str, sizeof(str), "0x%06x %.2f%%", rendercount, (frendercount / fvromsize) * 100);
chrLoggedCodeLabel->setText(tr(str));
sprintf(str, "0x%06x %.2f%%", vromreadcount, (fvromreadcount / fvromsize) * 100);
snprintf(str, sizeof(str), "0x%06x %.2f%%", vromreadcount, (fvromreadcount / fvromsize) * 100);
chrLoggedDataLabel->setText(tr(str));
sprintf(str, "0x%06x %.2f%%", undefinedvromcount, (fundefinedvromcount / fvromsize) * 100);
snprintf(str, sizeof(str), "0x%06x %.2f%%", undefinedvromcount, (fundefinedvromcount / fvromsize) * 100);
chrUnloggedLabel->setText(tr(str));
}
else
@ -393,7 +392,7 @@ void CodeDataLoggerDialog_t::updatePeriodic(void)
chrUnloggedLabel->setText(tr("------"));
}
sprintf(str, "CDL File: %s", loadedcdfile);
snprintf(str, sizeof(str), "CDL File: %s", loadedcdfile);
cdlFileLabel->setText(tr(str));
}
@ -444,15 +443,15 @@ void CodeDataLoggerDialog_t::saveCdlFileAs(void)
if (romFile != NULL)
{
char dir[512], base[256];
std::string dir, base;
parseFilepath(romFile, dir, base);
parseFilepath(romFile, &dir, &base);
strcat(base, ".cdl");
base.append(".cdl");
dialog.setDirectory(tr(dir));
dialog.setDirectory(tr(dir.c_str()));
dialog.selectFile(tr(base));
dialog.selectFile(tr(base.c_str()));
}
// Check config option to use native file dialog or not
@ -477,10 +476,10 @@ void CodeDataLoggerDialog_t::saveCdlFileAs(void)
{
return;
}
//qDebug() << "selected file path : " << filename.toUtf8();
//qDebug() << "selected file path : " << filename.toLocal8Bit();
FCEU_WRAPPER_LOCK();
strcpy(loadedcdfile, filename.toStdString().c_str());
strcpy(loadedcdfile, filename.toLocal8Bit().constData());
SaveCDLogFile();
FCEU_WRAPPER_UNLOCK();
}
@ -489,7 +488,7 @@ void CodeDataLoggerDialog_t::loadCdlFile(void)
{
int ret, useNativeFileDialogVal;
QString filename;
char dir[512];
std::string dir;
const char *romFile;
QFileDialog dialog(this, tr("Load CDL File"));
@ -507,7 +506,7 @@ void CodeDataLoggerDialog_t::loadCdlFile(void)
{
getDirFromFile(romFile, dir);
dialog.setDirectory(tr(dir));
dialog.setDirectory(tr(dir.c_str()));
}
// Check config option to use native file dialog or not
@ -532,10 +531,10 @@ void CodeDataLoggerDialog_t::loadCdlFile(void)
{
return;
}
//qDebug() << "selected file path : " << filename.toUtf8();
//qDebug() << "selected file path : " << filename.toLocal8Bit();
FCEU_WRAPPER_LOCK();
LoadCDLog(filename.toStdString().c_str());
LoadCDLog(filename.toLocal8Bit().constData());
FCEU_WRAPPER_UNLOCK();
return;
@ -587,11 +586,11 @@ void CodeDataLoggerDialog_t::SaveStrippedROM(int invert)
if (romFile != NULL)
{
char dir[512], base[256];
std::string dir;
parseFilepath(romFile, dir, base);
parseFilepath(romFile, &dir);
dialog.setDirectory(tr(dir));
dialog.setDirectory(tr(dir.c_str()));
}
// Check config option to use native file dialog or not
@ -616,9 +615,9 @@ void CodeDataLoggerDialog_t::SaveStrippedROM(int invert)
{
return;
}
//qDebug() << "selected file path : " << filename.toUtf8();
//qDebug() << "selected file path : " << filename.toLocal8Bit();
FILE *fp = fopen(filename.toStdString().c_str(), "wb");
FILE *fp = fopen(filename.toLocal8Bit().constData(), "wb");
if (!fp)
{
FCEUD_PrintError("Error opening target stripped rom file!");
@ -725,12 +724,12 @@ void CodeDataLoggerDialog_t::SaveUnusedROMClicked(void)
SaveStrippedROM(1);
}
//----------------------------------------------------
static int getDefaultCDLFile(char *filepath)
static int getDefaultCDLFile(std::string &filepath)
{
const char *romFile;
char dir[512], baseFile[256];
std::string dir, baseFile;
filepath[0] = 0;
filepath.clear();
romFile = getRomFile();
@ -739,15 +738,18 @@ static int getDefaultCDLFile(char *filepath)
return -1;
}
parseFilepath(romFile, dir, baseFile);
parseFilepath(romFile, &dir, &baseFile);
if (dir[0] == 0)
if (dir.size() == 0)
{
sprintf(filepath, "%s.cdl", baseFile);
filepath.assign(baseFile);
filepath.append(".cdl");
}
else
{
sprintf(filepath, "%s/%s.cdl", dir, baseFile);
filepath.assign(dir);
filepath.append(baseFile);
filepath.append(".cdl");
}
//printf("%s\n", filepath );
@ -787,7 +789,14 @@ void InitCDLog(void)
if (!CHRram[0] || (CHRptr[0] == PRGptr[0]))
{ // Some kind of workaround for my OneBus VRAM hack, will remove it if I find another solution for that
cdloggerVideoDataSize = CHRsize[0];
cdloggervdata = (unsigned char *)malloc(cdloggerVideoDataSize);
if (cdloggerVideoDataSize > 0)
{
cdloggervdata = (unsigned char *)malloc(cdloggerVideoDataSize);
}
else
{
cdloggervdata = nullptr;
}
}
else
{
@ -829,7 +838,10 @@ void ResetCDLog(void)
if (GameInfo->type != GIT_NSF)
{
undefinedvromcount = 8192;
memset(cdloggervdata, 0, 8192);
if (cdloggervdata != NULL)
{
memset(cdloggervdata, 0, 8192);
}
}
}
FCEU_WRAPPER_UNLOCK();
@ -938,11 +950,11 @@ void CDLoggerROMChanged(void)
return;
// try to load respective CDL file
char nameo[1024];
std::string nameo;
getDefaultCDLFile(nameo);
FILE *FP;
FP = fopen(nameo, "rb");
FP = fopen(nameo.c_str(), "rb");
if (FP != NULL)
{
// .cdl file with this ROM name exists
@ -951,7 +963,7 @@ void CDLoggerROMChanged(void)
//{
// DoCDLogger();
//}
if (LoadCDLog(nameo))
if (LoadCDLog(nameo.c_str()))
{
StartCDLogging();
}
@ -967,9 +979,9 @@ void SaveCDLogFile(void)
{
if (loadedcdfile[0] == 0)
{
char nameo[1024];
std::string nameo;
getDefaultCDLFile(nameo);
RenameCDLog(nameo);
RenameCDLog(nameo.c_str());
}
FILE *FP;

View File

@ -73,7 +73,7 @@ void ColorMenuItem::setImageColor( QColor c )
lastColor = c;
b = parentWidget()->palette().color(QPalette::WindowText);
b = qobject_cast<QWidget*>(parent())->palette().color(QPalette::WindowText);
i=0;
@ -119,9 +119,9 @@ void ColorMenuItem::pickerClosed(int ret)
colorText = colorPtr->name();
//printf("Saving '%s' = Color string '%s'\n", confName.c_str(), colorText.toStdString().c_str() );
//printf("Saving '%s' = Color string '%s'\n", confName.c_str(), colorText.toLocal8Bit().constData() );
g_config->setOption( confName, colorText.toStdString().c_str() );
g_config->setOption( confName, colorText.toLocal8Bit().constData() );
g_config->save();
}
@ -140,7 +140,7 @@ void ColorMenuItem::openColorPicker(void)
qs = title;
qs.replace( "&", "", Qt::CaseInsensitive); // get rid of & accelerator characters
picker = new ColorMenuPickerDialog_t( colorPtr, qs.toStdString().c_str(), parentWidget() );
picker = new ColorMenuPickerDialog_t( colorPtr, qs.toLocal8Bit().constData(), qobject_cast<QWidget*>(parent()) );
picker->show();
@ -167,7 +167,7 @@ ColorMenuPickerDialog_t::ColorMenuPickerDialog_t( QColor *c, const char *titleTe
style = this->style();
sprintf( stmp, "Pick Color for %s", titleText);
snprintf( stmp, sizeof(stmp), "Pick Color for %s", titleText);
setWindowTitle( stmp );

File diff suppressed because it is too large Load Diff

View File

@ -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,9 @@ class ConsoleDebugger : public QDialog
ColorMenuItem *pcColorAct;
int selBmAddrVal;
bool windowUpdateReq;
enum QAsmView::UpdateType windowUpdateReq;
bool startedTraceLogger;
private:
void setRegsFromEntry(void);
@ -557,6 +606,7 @@ class ConsoleDebugger : public QDialog
void asmViewCtxMenuRunToCursor(void);
void moveTab( QWidget *w, int row, int column);
private slots:
void ld65ImportDebug(void);
void updatePeriodic(void);
void hbarChanged(int value);
void vbarChanged(int value);
@ -582,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);
@ -589,6 +640,7 @@ class ConsoleDebugger : public QDialog
void registerNameEnableCB(bool value);
void autoOpenDebugCB( bool value );
void debFileAutoLoadCB( bool value );
void autoStartTraceLoggerOnOpen(bool value);
void breakOnBadOpcodeCB(bool value);
void breakOnNewCodeCB(bool value);
void breakOnNewDataCB(bool value);
@ -622,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;

View File

@ -54,16 +54,21 @@ ConsoleSndConfDialog_t::ConsoleSndConfDialog_t(QWidget *parent)
// Enable Sound Select
enaChkbox = new QCheckBox(tr("Enable Sound"));
// Speaker Mute Select
muteChkbox = new QCheckBox(tr("Mute Speaker Output"));
// Enable Low Pass Filter Select
enaLowPass = new QCheckBox(tr("Enable Low Pass Filter"));
setCheckBoxFromProperty(enaChkbox, "SDL.Sound");
setCheckBoxFromProperty(muteChkbox, "SDL.Sound.Mute");
setCheckBoxFromProperty(enaLowPass, "SDL.Sound.LowPass");
connect(enaChkbox, SIGNAL(stateChanged(int)), this, SLOT(enaSoundStateChange(int)));
connect(muteChkbox, SIGNAL(stateChanged(int)), this, SLOT(enaSpeakerMuteChange(int)));
connect(enaLowPass, SIGNAL(stateChanged(int)), this, SLOT(enaSoundLowPassChange(int)));
vbox1->addWidget(enaChkbox);
vbox1->addWidget(muteChkbox);
vbox1->addWidget(enaLowPass);
// Audio Quality Select
@ -184,10 +189,10 @@ ConsoleSndConfDialog_t::ConsoleSndConfDialog_t(QWidget *parent)
frame = new QGroupBox(tr("Triangle"));
vbox2 = new QVBoxLayout();
triLbl = new QLabel("255");
triLbl = new QLabel("256");
vslider = new QSlider(Qt::Vertical);
vslider->setMinimum(0);
vslider->setMaximum(255);
vslider->setMaximum(256);
setSliderFromProperty(vslider, triLbl, "SDL.Sound.TriangleVolume");
vbox2->addWidget(triLbl);
@ -199,10 +204,10 @@ ConsoleSndConfDialog_t::ConsoleSndConfDialog_t(QWidget *parent)
frame = new QGroupBox(tr("Square1"));
vbox2 = new QVBoxLayout();
sqr1Lbl = new QLabel("255");
sqr1Lbl = new QLabel("256");
vslider = new QSlider(Qt::Vertical);
vslider->setMinimum(0);
vslider->setMaximum(255);
vslider->setMaximum(256);
setSliderFromProperty(vslider, sqr1Lbl, "SDL.Sound.Square1Volume");
vbox2->addWidget(sqr1Lbl);
@ -214,10 +219,10 @@ ConsoleSndConfDialog_t::ConsoleSndConfDialog_t(QWidget *parent)
frame = new QGroupBox(tr("Square2"));
vbox2 = new QVBoxLayout();
sqr2Lbl = new QLabel("255");
sqr2Lbl = new QLabel("256");
sqr2Slider = new QSlider(Qt::Vertical);
sqr2Slider->setMinimum(0);
sqr2Slider->setMaximum(255);
sqr2Slider->setMaximum(256);
setSliderFromProperty(sqr2Slider, sqr2Lbl, "SDL.Sound.Square2Volume");
vbox2->addWidget(sqr2Lbl);
@ -229,10 +234,10 @@ ConsoleSndConfDialog_t::ConsoleSndConfDialog_t(QWidget *parent)
frame = new QGroupBox(tr("Noise"));
vbox2 = new QVBoxLayout();
nseLbl = new QLabel("255");
nseLbl = new QLabel("256");
nseSlider = new QSlider(Qt::Vertical);
nseSlider->setMinimum(0);
nseSlider->setMaximum(255);
nseSlider->setMaximum(256);
setSliderFromProperty(nseSlider, nseLbl, "SDL.Sound.NoiseVolume");
vbox2->addWidget(nseLbl);
@ -244,10 +249,10 @@ ConsoleSndConfDialog_t::ConsoleSndConfDialog_t(QWidget *parent)
frame = new QGroupBox(tr("PCM"));
vbox2 = new QVBoxLayout();
pcmLbl = new QLabel("255");
pcmLbl = new QLabel("256");
pcmSlider = new QSlider(Qt::Vertical);
pcmSlider->setMinimum(0);
pcmSlider->setMaximum(255);
pcmSlider->setMaximum(256);
setSliderFromProperty(pcmSlider, pcmLbl, "SDL.Sound.PCMVolume");
vbox2->addWidget(pcmLbl);
@ -327,9 +332,14 @@ void ConsoleSndConfDialog_t::periodicUpdate(void)
bufUsage->setValue( (int)(percBufUse) );
sprintf( stmp, "Sink Starve Count: %u", nes_shm->sndBuf.starveCounter );
snprintf( stmp, sizeof(stmp), "Sink Starve Count: %u", nes_shm->sndBuf.starveCounter );
starveLbl->setText( tr(stmp) );
if ( FCEUD_SoundIsMuted() != muteChkbox->isChecked() )
{
muteChkbox->setChecked( FCEUD_SoundIsMuted() );
}
}
//----------------------------------------------------
void ConsoleSndConfDialog_t::setSliderEnables(void)
@ -386,7 +396,7 @@ void ConsoleSndConfDialog_t::setSliderFromProperty(QSlider *slider, QLabel *lbl,
char stmp[32];
g_config->getOption(property, &pval);
slider->setValue(pval);
sprintf(stmp, "%i", pval);
snprintf(stmp, sizeof(stmp), "%i", pval);
lbl->setText(stmp);
}
//----------------------------------------------------
@ -394,7 +404,7 @@ void ConsoleSndConfDialog_t::bufSizeChanged(int value)
{
char stmp[32];
sprintf(stmp, "%i", value);
snprintf(stmp, sizeof(stmp), "%i", value);
bufSizeLabel->setText(stmp);
@ -412,7 +422,7 @@ void ConsoleSndConfDialog_t::volumeChanged(int value)
{
char stmp[32];
sprintf(stmp, "%i", value);
snprintf(stmp, sizeof(stmp), "%i", value);
volLbl->setText(stmp);
@ -429,7 +439,7 @@ void ConsoleSndConfDialog_t::triangleChanged(int value)
{
char stmp[32];
sprintf(stmp, "%i", value);
snprintf(stmp, sizeof(stmp), "%i", value);
triLbl->setText(stmp);
@ -446,7 +456,7 @@ void ConsoleSndConfDialog_t::square1Changed(int value)
{
char stmp[32];
sprintf(stmp, "%i", value);
snprintf(stmp, sizeof(stmp), "%i", value);
sqr1Lbl->setText(stmp);
@ -463,7 +473,7 @@ void ConsoleSndConfDialog_t::square2Changed(int value)
{
char stmp[32];
sprintf(stmp, "%i", value);
snprintf(stmp, sizeof(stmp), "%i", value);
sqr2Lbl->setText(stmp);
@ -480,7 +490,7 @@ void ConsoleSndConfDialog_t::noiseChanged(int value)
{
char stmp[32];
sprintf(stmp, "%i", value);
snprintf(stmp, sizeof(stmp), "%i", value);
nseLbl->setText(stmp);
@ -497,7 +507,7 @@ void ConsoleSndConfDialog_t::pcmChanged(int value)
{
char stmp[32];
sprintf(stmp, "%i", value);
snprintf(stmp, sizeof(stmp), "%i", value);
pcmLbl->setText(stmp);
@ -536,6 +546,11 @@ void ConsoleSndConfDialog_t::enaSoundStateChange(int value)
}
}
//----------------------------------------------------
void ConsoleSndConfDialog_t::enaSpeakerMuteChange(int value)
{
FCEUD_MuteSoundOutput( value ? true : false );
}
//----------------------------------------------------
void ConsoleSndConfDialog_t::enaSoundLowPassChange(int value)
{
if (value)

View File

@ -31,6 +31,7 @@ protected:
int sndQuality;
QCheckBox *enaChkbox;
QCheckBox *muteChkbox;
QCheckBox *enaLowPass;
QCheckBox *swapDutyChkbox;
QCheckBox *useGlobalFocus;
@ -68,6 +69,7 @@ private slots:
void noiseChanged(int value);
void pcmChanged(int value);
void enaSoundStateChange(int value);
void enaSpeakerMuteChange(int value);
void enaSoundLowPassChange(int value);
void swapDutyCallback(int value);
void useGlobalFocusChanged(int value);

View File

@ -21,10 +21,12 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <string>
#include <QWindow>
#include <QScreen>
#include <QToolTip>
#include <QFileInfo>
#include <QApplication>
#if WIN32
@ -46,32 +48,27 @@
#include "Qt/fceuWrapper.h"
#include "Qt/ConsoleUtilities.h"
static std::string fceuExecPath;
//---------------------------------------------------------------------------
int getDirFromFile( const char *path, char *dir )
int getDirFromFile( const char *path, std::string &dir )
{
int i, lastSlash = -1, lastPeriod = -1;
dir.clear();
i=0;
while ( path[i] != 0 )
if (path[0] != 0)
{
if ( path[i] == '/' )
{
lastSlash = i;
}
else if ( path[i] == '.' )
{
lastPeriod = i;
}
dir[i] = path[i]; i++;
}
dir[i] = 0;
QFileInfo fi;
if ( lastPeriod >= 0 )
{
if ( lastPeriod > lastSlash )
fi.setFile( QString(path) );
if (fi.exists())
{
dir[lastSlash] = 0;
dir = fi.canonicalPath().toLocal8Bit().constData();
}
else
{
dir = fi.absolutePath().toLocal8Bit().constData();
}
//printf("Dir: '%s'\n", dir.c_str());
}
return 0;
@ -79,7 +76,7 @@ int getDirFromFile( const char *path, char *dir )
//---------------------------------------------------------------------------
const char *getRomFile( void )
{
static char filePath[2048];
static std::string filePath;
if ( GameInfo )
{
@ -88,32 +85,32 @@ const char *getRomFile( void )
if ( GameInfo->archiveFilename != NULL )
{
char dir[1024], base[512], suffix[64];
std::string dir, base, suffix;
parseFilepath( GameInfo->archiveFilename, dir, base, suffix );
parseFilepath( GameInfo->archiveFilename, &dir, &base, &suffix );
filePath[0] = 0;
filePath.clear();
if ( dir[0] != 0 )
if ( dir.size() != 0 )
{
strcat( filePath, dir );
filePath.append( dir );
}
parseFilepath( GameInfo->filename, dir, base, suffix );
parseFilepath( GameInfo->filename, &dir, &base, &suffix );
strcat( filePath, base );
strcat( filePath, suffix );
filePath.append( base );
filePath.append( suffix );
//printf("ArchivePath: '%s' \n", filePath );
//printf("ArchivePath: '%s' \n", filePath.c_str() );
return filePath;
return filePath.c_str();
}
else
{
return GameInfo->filename;
}
}
return NULL;
return nullptr;
}
//---------------------------------------------------------------------------
// Return file base name stripping out preceding path and trailing suffix.
@ -163,19 +160,25 @@ int getFileBaseName( const char *filepath, char *base, char *suffix )
return end;
}
//---------------------------------------------------------------------------
int parseFilepath( const char *filepath, char *dir, char *base, char *suffix )
int parseFilepath( const char *filepath, std::string *dir, std::string *base, std::string *suffix )
{
int i=0,j=0,end=0;
if ( suffix != NULL )
if (dir)
{
suffix[0] = 0;
dir->clear();
}
if (base)
{
base->clear();
}
if (suffix)
{
suffix->clear();
}
size_t i=0,j=0;
if ( filepath == NULL )
{
if ( dir ) dir[0] = 0;
if ( base ) base[0] = 0;
if ( suffix) suffix[0] = 0;
return 0;
}
i=0; j=0;
@ -187,57 +190,55 @@ int parseFilepath( const char *filepath, char *dir, char *base, char *suffix )
}
if ( dir )
{
dir[i] = filepath[i];
dir->push_back(filepath[i]);
}
i++;
}
if ( dir )
if (dir)
{
dir[j] = 0;
if (j > 0)
{
dir->erase(j);
}
}
i = j;
if ( base == NULL )
{
return end;
}
j=0;
while ( filepath[i] != 0 )
{
base[j] = filepath[i]; i++; j++;
}
base[j] = 0; end=j;
if ( suffix )
{
suffix[0] = 0;
}
while ( j > 1 )
{
j--;
if ( base[j] == '.' )
if (filepath[i] == '.')
{
if ( suffix )
j = i;
}
if (base)
{
base->push_back(filepath[i]);
}
i++;
}
if (filepath[j] == '.')
{
if ( suffix )
{
suffix->assign( &filepath[j] );
}
if (base)
{
i = base->find_last_of('.');
if ( i != std::string::npos )
{
strcpy( suffix, &base[j] );
base->erase(i);
}
end=j; base[j] = 0;
break;
}
}
return end;
return 0;
}
//---------------------------------------------------------------------------
// Returns the path of fceux.exe as a string.
int fceuExecutablePath( char *outputPath, int outputSize )
static int _fceuExecutablePath( std::string &outputPath )
{
if ( (outputPath == NULL) || (outputSize <= 0) )
{
return -1;
}
outputPath[0] = 0;
outputPath.clear();
#ifdef WIN32
char fullPath[2048];
@ -248,8 +249,7 @@ int fceuExecutablePath( char *outputPath, int outputSize )
GetModuleFileNameA(NULL, fullPath, 2048);
_splitpath(fullPath, driveLetter, directory, NULL, NULL);
snprintf(finalPath, sizeof(finalPath), "%s%s", driveLetter, directory);
strncpy( outputPath, finalPath, outputSize );
outputPath[outputSize-1] = 0;
outputPath.assign( finalPath );
return 0;
#elif __linux__ || __unix__
@ -267,8 +267,7 @@ int fceuExecutablePath( char *outputPath, int outputSize )
if ( dir )
{
//printf("DIR Path: '%s' \n", dir );
strncpy( outputPath, dir, outputSize );
outputPath[outputSize-1] = 0;
outputPath.assign( dir );
return 0;
}
}
@ -288,8 +287,7 @@ int fceuExecutablePath( char *outputPath, int outputSize )
if ( dir )
{
//printf("DIR Path: '%s' \n", dir );
strncpy( outputPath, dir, outputSize );
outputPath[outputSize-1] = 0;
outputPath.assign( dir );
return 0;
}
}
@ -297,6 +295,15 @@ int fceuExecutablePath( char *outputPath, int outputSize )
return -1;
}
//---------------------------------------------------------------------------
const char *fceuExecutablePath(void)
{
if (fceuExecPath.size() == 0)
{
_fceuExecutablePath( fceuExecPath );
}
return fceuExecPath.c_str();
}
//---------------------------------------------------------------------------
int fceuLoadConfigColor( const char *confName, QColor *color )
{
std::string colorString;
@ -528,13 +535,13 @@ void fceuDecIntValidtor::setMinMax( long long int min, long long int max)
QValidator::State fceuDecIntValidtor::validate(QString &input, int &pos) const
{
long long int i, v;
//printf("Validate: %i '%s'\n", input.size(), input.toStdString().c_str() );
//printf("Validate: %i '%s'\n", input.size(), input.toLocal8Bit().constData() );
if ( input.size() == 0 )
{
return QValidator::Acceptable;
}
std::string s = input.toStdString();
std::string s = input.toLocal8Bit().constData();
i=0;
if (s[i] == '-')
@ -595,14 +602,14 @@ void fceuHexIntValidtor::setMinMax( long long int min, long long int max)
QValidator::State fceuHexIntValidtor::validate(QString &input, int &pos) const
{
long long int i, v;
//printf("Validate: %i '%s'\n", input.size(), input.toStdString().c_str() );
//printf("Validate: %i '%s'\n", input.size(), input.toLocal8Bit().constData() );
if ( input.size() == 0 )
{
return QValidator::Acceptable;
}
input = input.toUpper();
std::string s = input.toStdString();
std::string s = input.toLocal8Bit().constData();
i=0;
if (s[i] == '-')
@ -1332,7 +1339,7 @@ QString fceuGetOpcodeToolTip( uint8_t *opcode, int size )
for (int i=0; i<size; i++)
{
sprintf(stmp, "$%02X ", opcode[i] );
snprintf(stmp, sizeof(stmp), "$%02X ", opcode[i] );
text.append( stmp );
}
@ -1340,7 +1347,7 @@ QString fceuGetOpcodeToolTip( uint8_t *opcode, int size )
text.append( addrMode );
text.append( "\nCycle Count:\t\t" );
sprintf( stmp, "%i", X6502_GetOpcodeCycles( opcode[0] ) );
snprintf( stmp, sizeof(stmp), "%i", X6502_GetOpcodeCycles( opcode[0] ) );
text.append( stmp );
text.append( "\n" );
@ -1375,4 +1382,37 @@ QString fceuGetOpcodeToolTip( uint8_t *opcode, int size )
return QString::fromStdString( text );
}
//----------------------------------------------------
void setCheckBoxFromProperty( QCheckBox *cbx, const char *property )
{
int pval;
g_config->getOption (property, &pval);
cbx->setCheckState( pval ? Qt::Checked : Qt::Unchecked );
}
//----------------------------------------------------
void setComboBoxFromProperty( QComboBox *cbx, const char *property )
{
int i, pval;
g_config->getOption (property, &pval);
for (i=0; i<cbx->count(); i++)
{
if ( pval == cbx->itemData(i).toInt() )
{
cbx->setCurrentIndex(i); break;
}
}
}
//---------------------------------------------------------------------------
void setComboBoxFromValue( QComboBox *cbx, int pval )
{
for (int i=0; i<cbx->count(); i++)
{
if ( pval == cbx->itemData(i).toInt() )
{
cbx->setCurrentIndex(i); break;
}
}
}
//---------------------------------------------------------------------------

View File

@ -2,22 +2,25 @@
#pragma once
#include <string>
#include <QColor>
#include <QTimer>
#include <QValidator>
#include <QDialog>
#include <QHelpEvent>
#include <QComboBox>
#include <QCheckBox>
int getDirFromFile( const char *path, char *dir );
int getDirFromFile( const char *path, std::string &dir );
const char *getRomFile( void );
int getFileBaseName( const char *filepath, char *base, char *suffix = NULL );
int getFileBaseName( const char *filepath, char *base, char *suffix = nullptr );
int parseFilepath( const char *filepath, char *dir, char *base, char *suffix = NULL );
int parseFilepath( const char *filepath, std::string *dir, std::string *base = nullptr, std::string *suffix = nullptr );
int fceuExecutablePath( char *outputPath, int outputSize );
const char *fceuExecutablePath(void);
int fceuLoadConfigColor( const char *confName, QColor *color );
@ -91,3 +94,8 @@ class QCheckBoxRO : public QCheckBox
QString fceuGetOpcodeToolTip( uint8_t *opcode, int size );
QDialog *fceuCustomToolTipShow( const QPoint &globalPos, QDialog *popup );
//----------------------------------------------------
void setCheckBoxFromProperty( QCheckBox *cbx, const char *property );
void setComboBoxFromProperty( QComboBox *cbx, const char *property );
void setComboBoxFromValue( QComboBox *cbx, int pval );

View File

@ -35,6 +35,10 @@
#include "Qt/ConsoleVideoConf.h"
#include "Qt/nes_shm.h"
#if defined(WIN32) && (QT_VERSION_MAJOR < 6)
#include <QtPlatformHeaders/QWindowsWindowFunctions>
#endif
extern int input_display;
extern int frame_display;
extern int rerecord_display;
@ -85,8 +89,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();
@ -118,8 +123,8 @@ ConsoleVideoConfDialog_t::ConsoleVideoConfDialog_t(QWidget *parent)
vbox1->addLayout( hbox1 );
// Enable OpenGL Linear Filter Checkbox
gl_LF_chkBox = new QCheckBox( tr("Enable OpenGL Linear Filter") );
// Enable Linear Filter Checkbox
gl_LF_chkBox = new QCheckBox( tr("Enable Linear Filter") );
setCheckBoxFromProperty( gl_LF_chkBox , "SDL.OpenGLip");
@ -127,6 +132,18 @@ ConsoleVideoConfDialog_t::ConsoleVideoConfDialog_t(QWidget *parent)
vbox1->addWidget( gl_LF_chkBox );
#if defined(WIN32) && (QT_VERSION_MAJOR < 6)
// 1px full screen border - hack fix for QOpenGLWidget fullscreen issues
winFullScreenBorderCbx = new QCheckBox( tr("Fullscreen Border (1px)") );
winFullScreenBorderCbx->setToolTip(tr("Hack fix for QOpenGLWidget fullscreen issue. May not be needed."));
setCheckBoxFromProperty( winFullScreenBorderCbx , "SDL.winFullScreenBorder");
connect(winFullScreenBorderCbx, SIGNAL(stateChanged(int)), this, SLOT(winFullScreenBorderChanged(int)) );
vbox1->addWidget(winFullScreenBorderCbx);
#endif
// Region Select
lbl = new QLabel( tr("Region:") );
@ -232,15 +249,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 +317,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() );
}
}
@ -511,7 +518,7 @@ ConsoleVideoConfDialog_t::ConsoleVideoConfDialog_t(QWidget *parent)
scrRateReadout->setFont( font );
scrRateReadout->setReadOnly(true);
scrRateReadout->setAlignment(Qt::AlignCenter);
sprintf( stmp, "%.3f", consoleWindow->getRefreshRate() );
snprintf( stmp, sizeof(stmp), "%.3f", consoleWindow->getRefreshRate() );
scrRateReadout->setText( tr(stmp) );
hbox->addWidget( new QLabel( tr("Refresh Rate (Hz):") ) );
@ -594,20 +601,16 @@ 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() );
snprintf( stmp, sizeof(stmp), "%i x %i ", w.width(), w.height() );
winSizeReadout->setText( tr(stmp) );
sprintf( stmp, "%i x %i ", v.width(), v.height() );
snprintf( stmp, sizeof(stmp), "%i x %i ", v.width(), v.height() );
vpSizeReadout->setText( tr(stmp) );
}
@ -722,21 +725,31 @@ void ConsoleVideoConfDialog_t::openGL_linearFilterChanged( int value )
{
bool opt = (value != Qt::Unchecked);
g_config->setOption("SDL.OpenGLip", opt );
g_config->save ();
g_config->save();
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 );
}
}
}
//----------------------------------------------------
#if defined(WIN32) && (QT_VERSION_MAJOR < 6)
void ConsoleVideoConfDialog_t::winFullScreenBorderChanged(int value)
{
bool opt = (value != Qt::Unchecked);
// This function is needed to fix the issue referenced below. It adds a 1-pixel border
// around the fullscreen window due to some limitation in windows.
// https://doc.qt.io/qt-5/windows-issues.html#fullscreen-opengl-based-windows
QWindowsWindowFunctions::setHasBorderInFullScreen( consoleWindow->windowHandle(), opt);
g_config->setOption("SDL.winFullScreenBorder", opt );
g_config->save();
}
#endif
//----------------------------------------------------
void ConsoleVideoConfDialog_t::autoScaleChanged( int value )
{
bool opt = (value != Qt::Unchecked);
@ -745,13 +758,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 +841,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 +1103,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 +1171,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() )

View File

@ -55,6 +55,9 @@ class ConsoleVideoConfDialog_t : public QDialog
QCheckBox *showFrameCount_cbx;
QCheckBox *showLagCount_cbx;
QCheckBox *showRerecordCount_cbx;
#if defined(WIN32) && (QT_VERSION_MAJOR < 6)
QCheckBox *winFullScreenBorderCbx;
#endif
QDoubleSpinBox *xScaleBox;
QDoubleSpinBox *yScaleBox;
QLabel *aspectSelectLabel;
@ -111,6 +114,9 @@ class ConsoleVideoConfDialog_t : public QDialog
void ntscEndScanLineChanged(int value);
void palStartScanLineChanged(int value);
void palEndScanLineChanged(int value);
#if defined(WIN32) && (QT_VERSION_MAJOR < 6)
void winFullScreenBorderChanged(int value);
#endif
};

View File

@ -86,13 +86,19 @@ ConsoleViewGL_t::ConsoleViewGL_t(QWidget *parent)
setFocusPolicy(Qt::StrongFocus);
//setAttribute(Qt::WA_OpaquePaintEvent);
drawTimer = new QTimer(this);
drawTimer->setInterval(14);
drawTimer->setSingleShot(true);
drawTimer->setTimerType(Qt::PreciseTimer);
connect(drawTimer, &QTimer::timeout, this, &ConsoleViewGL_t::onDrawSignal);
localBufSize = (4 * GL_NES_WIDTH) * (4 * GL_NES_HEIGHT) * sizeof(uint32_t);
localBuf = (uint32_t*)malloc( localBufSize );
if ( localBuf )
{
memset( localBuf, 0, localBufSize );
memset32( localBuf, alphaMask, localBufSize );
}
vsyncEnabled = true;
@ -136,6 +142,10 @@ ConsoleViewGL_t::ConsoleViewGL_t(QWidget *parent)
ConsoleViewGL_t::~ConsoleViewGL_t(void)
{
//printf("Destroying GL Viewport\n");
drawTimer->stop();
delete drawTimer;
if ( localBuf )
{
free( localBuf ); localBuf = NULL;
@ -502,7 +512,7 @@ void ConsoleViewGL_t::transfer2LocalBuffer(void)
}
else
{
memcpy( localBuf, src, cpSize );
copyPixels32( dest, src, cpSize, alphaMask);
}
}
@ -564,6 +574,22 @@ void ConsoleViewGL_t::getNormalizedCursorPos( double &x, double &y )
void ConsoleViewGL_t::renderFinished(void)
{
videoBufferSwapMark();
// Schedule draw timing inline with vsync
drawTimer->start();
}
void ConsoleViewGL_t::queueRedraw(void)
{
if (!drawTimer->isActive())
{
update();
}
}
void ConsoleViewGL_t::onDrawSignal(void)
{
update();
}
void ConsoleViewGL_t::paintGL(void)
@ -671,7 +697,7 @@ void ConsoleViewGL_t::paintGL(void)
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_BLEND);
glBlendFunc(GL_ONE, GL_ONE);
glBlendFunc(GL_ONE, GL_ZERO);
//glBlendFunc(GL_ONE_MINUS_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
if ( textureType == GL_TEXTURE_RECTANGLE )

View File

@ -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);
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);
@ -79,6 +90,7 @@ class ConsoleViewGL_t : public QOpenGLWidget, protected QOpenGLFunctions
unsigned int textureType;
unsigned int mouseButtonMask;
QColor *bgColor;
QTimer *drawTimer;
uint32_t *localBuf;
uint32_t localBufSize;
@ -86,5 +98,6 @@ class ConsoleViewGL_t : public QOpenGLWidget, protected QOpenGLFunctions
private slots:
void cleanupGL(void);
void renderFinished(void);
void onDrawSignal();
};

View File

@ -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++;
}
}
//----------------------------------------------------------

View File

@ -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:
};

View File

@ -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++;
}

View File

@ -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:
};

View File

@ -82,6 +82,11 @@ ConsoleViewSDL_t::ConsoleViewSDL_t(QWidget *parent)
vsyncEnabled = false;
mouseButtonMask = 0;
drawTimer = new QTimer(this);
drawTimer->setInterval(14);
drawTimer->setSingleShot(true);
drawTimer->setTimerType(Qt::PreciseTimer);
connect(drawTimer, &QTimer::timeout, this, &ConsoleViewSDL_t::onDrawSignal);
localBufSize = (4 * GL_NES_WIDTH) * (4 * GL_NES_HEIGHT) * sizeof(uint32_t);
@ -89,7 +94,7 @@ ConsoleViewSDL_t::ConsoleViewSDL_t(QWidget *parent)
if ( localBuf )
{
memset( localBuf, 0, localBufSize );
memset32( localBuf, alphaMask, localBufSize );
}
forceAspect = true;
@ -122,6 +127,10 @@ ConsoleViewSDL_t::ConsoleViewSDL_t(QWidget *parent)
ConsoleViewSDL_t::~ConsoleViewSDL_t(void)
{
//printf("Destroying SDL Viewport\n");
drawTimer->stop();
delete drawTimer;
if ( localBuf )
{
free( localBuf ); localBuf = NULL;
@ -240,7 +249,7 @@ void ConsoleViewSDL_t::transfer2LocalBuffer(void)
}
else
{
memcpy( localBuf, src, cpSize );
copyPixels32( dest, src, cpSize, alphaMask);
}
}
@ -583,6 +592,19 @@ void ConsoleViewSDL_t::getNormalizedCursorPos( double &x, double &y )
//printf("Normalized Cursor (%f,%f) \n", x, y );
}
void ConsoleViewSDL_t::queueRedraw(void)
{
if (!drawTimer->isActive())
{
render();
}
}
void ConsoleViewSDL_t::onDrawSignal(void)
{
render();
}
void ConsoleViewSDL_t::render(void)
{
int nesWidth = GL_NES_WIDTH;
@ -705,5 +727,8 @@ void ConsoleViewSDL_t::render(void)
videoBufferSwapMark();
// Schedule draw timing inline with vsync
drawTimer->start();
nes_shm->render_count++;
}

View File

@ -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);
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);
@ -73,6 +83,7 @@ class ConsoleViewSDL_t : public QWidget
bool forceAspect;
bool autoScaleEna;
QColor *bgColor;
QTimer *drawTimer;
uint32_t *localBuf;
uint32_t localBufSize;
@ -85,5 +96,6 @@ class ConsoleViewSDL_t : public QWidget
//SDL_Rect sdlViewport;
private slots:
void onDrawSignal();
};

File diff suppressed because it is too large Load Diff

View File

@ -23,12 +23,16 @@
#include <QCursor>
#include <QMutex>
#include <QColor>
#include <QTemporaryDir>
#if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
#include <QRecursiveMutex>
#endif
#include "utils/mutex.h"
#include "Qt/ColorMenu.h"
#include "Qt/ConsoleViewerGL.h"
#include "Qt/ConsoleViewerSDL.h"
#include "Qt/ConsoleViewerQWidget.h"
#include "Qt/GamePadConf.h"
#include "Qt/AviRecord.h"
@ -125,16 +129,15 @@ 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 );
#if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
QRecursiveMutex *mutex;
#else
QMutex *mutex;
#endif
FCEU::mutex emulatorMutex;
FCEU::mutex videoBufferMutex;
int videoInit(void);
void videoReset(void);
@ -154,6 +157,7 @@ class consoleWin_t : public QMainWindow
#endif
int loadVideoDriver( int driverId, bool force = false );
int unloadVideoDriver(void);
double getRefreshRate(void){ return refreshRate; }
@ -175,12 +179,14 @@ class consoleWin_t : public QMainWindow
void setContextMenuEnable(bool enable);
void setSoundUseGlobalFocus(bool enable);
void OpenHelpWindow(std::string subpage = "");
void OpenHelpWindow(QString subpage = QString());
int getPeriodicInterval(void);
QColor *getVideoBgColorPtr(void){ return &videoBgColor; }
QString getTempDir();
protected:
consoleMenuBar *menubar;
@ -190,6 +196,7 @@ class consoleWin_t : public QMainWindow
QMenu *toolsMenu;
QMenu *debugMenu;
QMenu *movieMenu;
QMenu *netPlayMenu;
QMenu *helpMenu;
QMenu *recentRomMenu;
@ -201,6 +208,7 @@ class consoleWin_t : public QMainWindow
QAction *quickLoadAct;
QAction *quickSaveAct;
QAction *loadLuaAct;
QAction *loadJsAct;
QAction *scrShotAct;
QAction *quitAct;
QAction *inputConfig;
@ -210,6 +218,7 @@ class consoleWin_t : public QMainWindow
QAction *hotkeyConfig;
QAction *paletteConfig;
QAction *guiConfig;
QAction *stateRecordConfig;
QAction *timingConfig;
QAction *movieConfig;
QAction *autoResume;
@ -254,11 +263,18 @@ class consoleWin_t : public QMainWindow
QAction *recAsWavAct;
QAction *stopWavAct;
QAction *tasEditorAct;
QAction *netPlayHostAct;
QAction *netPlayJoinAct;
QAction *netPlayDiscAct;
QAction *netPlayHostStatAct;
QAction *netPlayClientStatAct;
//QAction *aviHudAct;
//QAction *aviMsgAct;
QTimer *gameTimer;
QColor videoBgColor;
ColorMenuItem *bgColorMenuItem;
QTemporaryDir *tempDir;
std::string errorMsg;
bool errorMsgValid;
@ -272,6 +288,7 @@ class consoleWin_t : public QMainWindow
bool contextMenuEnable;
bool soundUseGlobalFocus;
bool autoHideMenuFullscreen;
bool redrawVideoRequest;
std::list <std::string*> romList;
std::vector <autoFireMenuAction*> afActList;
@ -307,10 +324,19 @@ class consoleWin_t : public QMainWindow
void changeState(int slot);
void saveState(int slot);
void loadState(int slot);
void transferVideoBuffer(void);
void transferVideoBuffer(bool allowRedraw);
void syncAutoFirePatternMenu(void);
std::string findHelpFile(void);
QString findHelpFile(void);
public:
signals:
void romLoaded(void);
void romUnload(void);
void stateLoaded(void);
void nesResetOccurred(void);
void pauseToggled(bool state);
void cheatsChanged(void);
public slots:
void openDebugWindow(void);
@ -320,6 +346,7 @@ class consoleWin_t : public QMainWindow
void toggleMenuVis(void);
void recordMovie(void);
void winResizeIx(int iScale);
void onNetPlayChange(void);
private slots:
void closeApp(void);
void openROMFile(void);
@ -342,7 +369,12 @@ class consoleWin_t : public QMainWindow
void openPaletteConfWin(void);
void openGuiConfWin(void);
void openTimingConfWin(void);
void openStateRecorderConfWin(void);
void openPaletteEditorWin(void);
void openNetPlayHostWindow(void);
void openNetPlayJoinWindow(void);
void openNetPlayStatusWindow(void);
void closeNetPlaySession(void);
void openAviRiffViewer(void);
void openTimingStatWin(void);
void openMovieOptWin(void);
@ -364,6 +396,7 @@ class consoleWin_t : public QMainWindow
void incrementState(void);
void decrementState(void);
void loadLua(void);
void loadJs(void);
void takeScreenShot(void);
void prepareScreenShot(void);
void powerConsoleCB(void);
@ -373,6 +406,7 @@ class consoleWin_t : public QMainWindow
void toggleGameGenie(bool checked);
void loadGameGenieROM(void);
void loadMostRecentROM(void);
void clearRecentRomMenu(void);
void setRegionNTSC(void);
void setRegionPAL(void);
void setRegionDendy(void);
@ -403,6 +437,7 @@ class consoleWin_t : public QMainWindow
void stopMovie(void);
void playMovieFromBeginning(void);
void setCustomAutoFire(void);
void muteSoundVolume(void);
void incrSoundVolume(void);
void decrSoundVolume(void);
void toggleLagCounterDisplay(void);
@ -436,6 +471,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*);
@ -453,8 +490,10 @@ class consoleWin_t : public QMainWindow
void winActiveChanged(void);
void emuFrameFinish(void);
void toggleMenuAutoHide(bool);
void toggleUseBgPaletteForVideo(bool);
void videoBgColorChanged( QColor &c );
void loadRomRequestCB( QString s );
void videoDriverDestroyed( QObject *obj );
};

View File

@ -126,7 +126,6 @@ int openFamilyKeyboardDialog(QWidget *parent)
{
fkbWin->activateWindow();
fkbWin->raise();
fkbWin->setFocus();
}
else
{
@ -248,7 +247,7 @@ void FamilyKeyboardWidget::updateHardwareStatus(void)
//*********************************************************************************
int FamilyKeyboardWidget::getKeyAtPoint( QPoint p )
{
for (int i=0; i<NUM_KEYS; i++)
for (int i=0; i < static_cast<int>(NUM_KEYS); i++)
{
if ( key[i].rect.contains(p) )
{
@ -617,11 +616,11 @@ FKBConfigDialog::FKBConfigDialog(QWidget *parent)
if ( strcmp( keyNames[j], keyNames[j+1] ) == 0 )
{
sprintf( stmp, " %s ", keyNames[j] );
snprintf( stmp, sizeof(stmp), " %s ", keyNames[j] );
}
else
{
sprintf( stmp, " %s - %s ", keyNames[j], keyNames[j+1] );
snprintf( stmp, sizeof(stmp), " %s - %s ", keyNames[j], keyNames[j+1] );
}
item->setText(0, tr(stmp) );
@ -859,9 +858,9 @@ void FKBConfigDialog::openFontDialog(void)
keyboard->setFont( selFont );
keyboard->update();
//printf("Font Changed to: '%s'\n", font.toString().toStdString().c_str() );
//printf("Font Changed to: '%s'\n", font.toString().toLocal8Bit().constData() );
g_config->setOption("SDL.FamilyKeyboardFont", selFont.toString().toStdString().c_str() );
g_config->setOption("SDL.FamilyKeyboardFont", selFont.toString().toLocal8Bit().constData() );
QTimer::singleShot( 100, this, SLOT(keyTreeResizeDone(void)) );
}
@ -1029,7 +1028,7 @@ void FKBConfigDialog::keyTreeItemActivated(QTreeWidgetItem *item, int column)
//----------------------------------------------------------------------------
int FKBConfigDialog::getButtonIndexFromName( const char *buttonName )
{
for (int j=0; j<FamilyKeyboardWidget::NUM_KEYS; j++)
for (int j=0; j < static_cast<int>(FamilyKeyboardWidget::NUM_KEYS); j++)
{
if ( strcmp( buttonName, FamilyKeyBoardNames[j] ) == 0 )
{
@ -1190,9 +1189,9 @@ void FKBConfigDialog::mappingLoad(void)
{
return;
}
//qDebug() << "selected file path : " << filename.toUtf8();
//qDebug() << "selected file path : " << filename.toLocal8Bit();
mappingLoad( filename.toStdString().c_str() );
mappingLoad( filename.toLocal8Bit().constData() );
return;
}
@ -1332,26 +1331,26 @@ void FKBConfigDialog::mappingSave(void)
}
stmp[k] = 0;
//sprintf(stmp, "k%s", SDL_GetKeyName(bmap[c][i].ButtonNum));
//snprintf(stmp, sizeof(stmp), "k%s", SDL_GetKeyName(bmap[c][i].ButtonNum));
}
else
{
if (fkbmap[i].ButtonNum & 0x2000)
{
/* Hat "button" */
sprintf(stmp, "h%i.%i",
snprintf(stmp, sizeof(stmp), "h%i.%i",
(fkbmap[i].ButtonNum >> 8) & 0x1F, fkbmap[i].ButtonNum & 0xFF);
}
else if (fkbmap[i].ButtonNum & 0x8000)
{
/* Axis "button" */
sprintf(stmp, "%ca%i",
snprintf(stmp, sizeof(stmp), "%ca%i",
(fkbmap[i].ButtonNum & 0x4000) ? '-' : '+', fkbmap[i].ButtonNum & 0x3FFF);
}
else
{
/* Button */
sprintf(stmp, "b%i", fkbmap[i].ButtonNum);
snprintf(stmp, sizeof(stmp), "b%i", fkbmap[i].ButtonNum);
}
}
fprintf( fp, "%s=%s\n", FamilyKeyBoardNames[i], stmp );
@ -1433,7 +1432,7 @@ void FKBConfigDialog::mappingSaveAs(void)
return;
}
saveFileName = filename.toStdString();
saveFileName = filename.toLocal8Bit().constData();
mappingSave();
}
@ -1463,7 +1462,7 @@ FKBKeyMapDialog::FKBKeyMapDialog( int idx, QWidget *parent )
setLayout( mainLayout );
sprintf( stmp, "Press a key to set new physical mapping for the '%s' Key", keyNames[idx*2] );
snprintf( stmp, sizeof(stmp), "Press a key to set new physical mapping for the '%s' Key", keyNames[idx*2] );
msgLbl = new QLabel( tr(stmp) );

View File

@ -89,6 +89,7 @@ FrameTimingDialog_t::FrameTimingDialog_t(QWidget *parent)
frameTimeIdlePct = new QTreeWidgetItem();
frameLateCount = new QTreeWidgetItem();
videoTimeAbs = new QTreeWidgetItem();
emuSignalDelay = new QTreeWidgetItem();
tree->addTopLevelItem(frameTimeAbs);
tree->addTopLevelItem(frameTimeDel);
@ -97,6 +98,7 @@ FrameTimingDialog_t::FrameTimingDialog_t(QWidget *parent)
tree->addTopLevelItem(frameTimeWorkPct);
tree->addTopLevelItem(frameTimeIdlePct);
tree->addTopLevelItem(videoTimeAbs);
tree->addTopLevelItem(emuSignalDelay);
tree->addTopLevelItem(frameLateCount);
frameTimeAbs->setFlags(Qt::ItemIsEnabled | Qt::ItemNeverHasChildren);
@ -109,6 +111,7 @@ FrameTimingDialog_t::FrameTimingDialog_t(QWidget *parent)
frameTimeWorkPct->setText(0, tr("Frame Work %"));
frameTimeIdlePct->setText(0, tr("Frame Idle %"));
frameLateCount->setText(0, tr("Frame Late Count"));
emuSignalDelay->setText(0, tr("EMU Signal Delay ms"));
videoTimeAbs->setText(0, tr("Video Period ms"));
frameTimeAbs->setTextAlignment(0, Qt::AlignLeft);
@ -119,6 +122,7 @@ FrameTimingDialog_t::FrameTimingDialog_t(QWidget *parent)
frameTimeIdlePct->setTextAlignment(0, Qt::AlignLeft);
frameLateCount->setTextAlignment(0, Qt::AlignLeft);
videoTimeAbs->setTextAlignment(0, Qt::AlignLeft);
emuSignalDelay->setTextAlignment(0, Qt::AlignLeft);
for (int i = 0; i < 4; i++)
{
@ -130,6 +134,7 @@ FrameTimingDialog_t::FrameTimingDialog_t(QWidget *parent)
frameTimeIdlePct->setTextAlignment(i + 1, Qt::AlignCenter);
frameLateCount->setTextAlignment(i + 1, Qt::AlignCenter);
videoTimeAbs->setTextAlignment(i + 1, Qt::AlignCenter);
emuSignalDelay->setTextAlignment(i + 1, Qt::AlignCenter);
}
hbox = new QHBoxLayout();
@ -204,98 +209,111 @@ void FrameTimingDialog_t::updateTimingStats(void)
getFrameTimingStats(&stats);
// Absolute
sprintf(stmp, "%.3f", stats.frameTimeAbs.tgt * 1e3);
snprintf(stmp, sizeof(stmp), "%.3f", stats.frameTimeAbs.tgt * 1e3);
frameTimeAbs->setText(1, tr(stmp));
sprintf(stmp, "%.3f", stats.frameTimeAbs.cur * 1e3);
snprintf(stmp, sizeof(stmp), "%.3f", stats.frameTimeAbs.cur * 1e3);
frameTimeAbs->setText(2, tr(stmp));
sprintf(stmp, "%.3f", stats.frameTimeAbs.min * 1e3);
snprintf(stmp, sizeof(stmp), "%.3f", stats.frameTimeAbs.min * 1e3);
frameTimeAbs->setText(3, tr(stmp));
sprintf(stmp, "%.3f", stats.frameTimeAbs.max * 1e3);
snprintf(stmp, sizeof(stmp), "%.3f", stats.frameTimeAbs.max * 1e3);
frameTimeAbs->setText(4, tr(stmp));
// Delta
sprintf(stmp, "%.3f", stats.frameTimeDel.tgt * 1e3);
snprintf(stmp, sizeof(stmp), "%.3f", stats.frameTimeDel.tgt * 1e3);
frameTimeDel->setText(1, tr(stmp));
sprintf(stmp, "%.3f", stats.frameTimeDel.cur * 1e3);
snprintf(stmp, sizeof(stmp), "%.3f", stats.frameTimeDel.cur * 1e3);
frameTimeDel->setText(2, tr(stmp));
sprintf(stmp, "%.3f", stats.frameTimeDel.min * 1e3);
snprintf(stmp, sizeof(stmp), "%.3f", stats.frameTimeDel.min * 1e3);
frameTimeDel->setText(3, tr(stmp));
sprintf(stmp, "%.3f", stats.frameTimeDel.max * 1e3);
snprintf(stmp, sizeof(stmp), "%.3f", stats.frameTimeDel.max * 1e3);
frameTimeDel->setText(4, tr(stmp));
// Work
sprintf(stmp, "lt %.3f", stats.frameTimeWork.tgt * 1e3);
snprintf(stmp, sizeof(stmp), "lt %.3f", stats.frameTimeWork.tgt * 1e3);
frameTimeWork->setText(1, tr(stmp));
sprintf(stmp, "%.3f", stats.frameTimeWork.cur * 1e3);
snprintf(stmp, sizeof(stmp), "%.3f", stats.frameTimeWork.cur * 1e3);
frameTimeWork->setText(2, tr(stmp));
sprintf(stmp, "%.3f", stats.frameTimeWork.min * 1e3);
snprintf(stmp, sizeof(stmp), "%.3f", stats.frameTimeWork.min * 1e3);
frameTimeWork->setText(3, tr(stmp));
sprintf(stmp, "%.3f", stats.frameTimeWork.max * 1e3);
snprintf(stmp, sizeof(stmp), "%.3f", stats.frameTimeWork.max * 1e3);
frameTimeWork->setText(4, tr(stmp));
// Idle
sprintf(stmp, "gt %.3f", stats.frameTimeIdle.tgt * 1e3);
snprintf(stmp, sizeof(stmp), "gt %.3f", stats.frameTimeIdle.tgt * 1e3);
frameTimeIdle->setText(1, tr(stmp));
sprintf(stmp, "%.3f", stats.frameTimeIdle.cur * 1e3);
snprintf(stmp, sizeof(stmp), "%.3f", stats.frameTimeIdle.cur * 1e3);
frameTimeIdle->setText(2, tr(stmp));
sprintf(stmp, "%.3f", stats.frameTimeIdle.min * 1e3);
snprintf(stmp, sizeof(stmp), "%.3f", stats.frameTimeIdle.min * 1e3);
frameTimeIdle->setText(3, tr(stmp));
sprintf(stmp, "%.3f", stats.frameTimeIdle.max * 1e3);
snprintf(stmp, sizeof(stmp), "%.3f", stats.frameTimeIdle.max * 1e3);
frameTimeIdle->setText(4, tr(stmp));
// Work %
sprintf(stmp, "lt %.1f", 100.0 * stats.frameTimeWork.tgt / stats.frameTimeAbs.tgt);
snprintf(stmp, sizeof(stmp), "lt %.1f", 100.0 * stats.frameTimeWork.tgt / stats.frameTimeAbs.tgt);
frameTimeWorkPct->setText(1, tr(stmp));
sprintf(stmp, "%.1f", 100.0 * stats.frameTimeWork.cur / stats.frameTimeAbs.tgt);
snprintf(stmp, sizeof(stmp), "%.1f", 100.0 * stats.frameTimeWork.cur / stats.frameTimeAbs.tgt);
frameTimeWorkPct->setText(2, tr(stmp));
sprintf(stmp, "%.1f", 100.0 * stats.frameTimeWork.min / stats.frameTimeAbs.tgt);
snprintf(stmp, sizeof(stmp), "%.1f", 100.0 * stats.frameTimeWork.min / stats.frameTimeAbs.tgt);
frameTimeWorkPct->setText(3, tr(stmp));
sprintf(stmp, "%.1f", 100.0 * stats.frameTimeWork.max / stats.frameTimeAbs.tgt);
snprintf(stmp, sizeof(stmp), "%.1f", 100.0 * stats.frameTimeWork.max / stats.frameTimeAbs.tgt);
frameTimeWorkPct->setText(4, tr(stmp));
// Idle %
sprintf(stmp, "gt %.1f", 100.0 * stats.frameTimeIdle.tgt / stats.frameTimeAbs.tgt);
snprintf(stmp, sizeof(stmp), "gt %.1f", 100.0 * stats.frameTimeIdle.tgt / stats.frameTimeAbs.tgt);
frameTimeIdlePct->setText(1, tr(stmp));
sprintf(stmp, "%.1f", 100.0 * stats.frameTimeIdle.cur / stats.frameTimeAbs.tgt);
snprintf(stmp, sizeof(stmp), "%.1f", 100.0 * stats.frameTimeIdle.cur / stats.frameTimeAbs.tgt);
frameTimeIdlePct->setText(2, tr(stmp));
sprintf(stmp, "%.1f", 100.0 * stats.frameTimeIdle.min / stats.frameTimeAbs.tgt);
snprintf(stmp, sizeof(stmp), "%.1f", 100.0 * stats.frameTimeIdle.min / stats.frameTimeAbs.tgt);
frameTimeIdlePct->setText(3, tr(stmp));
sprintf(stmp, "%.1f", 100.0 * stats.frameTimeIdle.max / stats.frameTimeAbs.tgt);
snprintf(stmp, sizeof(stmp), "%.1f", 100.0 * stats.frameTimeIdle.max / stats.frameTimeAbs.tgt);
frameTimeIdlePct->setText(4, tr(stmp));
// Video
sprintf(stmp, "%.3f", stats.videoTimeDel.tgt * 1e3);
snprintf(stmp, sizeof(stmp), "%.3f", stats.videoTimeDel.tgt * 1e3);
videoTimeAbs->setText(1, tr(stmp));
sprintf(stmp, "%.3f", stats.videoTimeDel.cur * 1e3);
snprintf(stmp, sizeof(stmp), "%.3f", stats.videoTimeDel.cur * 1e3);
videoTimeAbs->setText(2, tr(stmp));
sprintf(stmp, "%.3f", stats.videoTimeDel.min * 1e3);
snprintf(stmp, sizeof(stmp), "%.3f", stats.videoTimeDel.min * 1e3);
videoTimeAbs->setText(3, tr(stmp));
sprintf(stmp, "%.3f", stats.videoTimeDel.max * 1e3);
snprintf(stmp, sizeof(stmp), "%.3f", stats.videoTimeDel.max * 1e3);
videoTimeAbs->setText(4, tr(stmp));
// Emulator to GUI Thread Signal Delay
snprintf(stmp, sizeof(stmp), "%.3f", stats.emuSignalDelay.tgt * 1e3);
emuSignalDelay->setText(1, tr(stmp));
snprintf(stmp, sizeof(stmp), "%.3f", stats.emuSignalDelay.cur * 1e3);
emuSignalDelay->setText(2, tr(stmp));
snprintf(stmp, sizeof(stmp), "%.3f", stats.emuSignalDelay.min * 1e3);
emuSignalDelay->setText(3, tr(stmp));
snprintf(stmp, sizeof(stmp), "%.3f", stats.emuSignalDelay.max * 1e3);
emuSignalDelay->setText(4, tr(stmp));
// Late Count
sprintf(stmp, "%u", stats.lateCount);
snprintf(stmp, sizeof(stmp), "%u", stats.lateCount);
frameLateCount->setText(1, tr("0"));
frameLateCount->setText(2, tr(stmp));

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