Merge branch 'master' into translations

This commit is contained in:
Vicki Pfau 2023-01-29 00:27:15 -08:00
commit e31e5525a2
216 changed files with 16000 additions and 7382 deletions

2
.gitignore vendored
View File

@ -10,10 +10,12 @@
*.a
*.dylib
*.dll
*.lib
*.exe
*.o
*.so
CMakeCache.txt
CMakeFiles
CMakeSettings.json
cmake_install.cmake
version.c

60
CHANGES
View File

@ -1,4 +1,50 @@
0.10.0: (Future)
0.11.0: (Future)
Features:
- New unlicensed GB mappers: NT (older types 1 and 2), Li Cheng, GGB-81
- Debugger: Add range watchpoints
Emulation fixes:
- GBA Memory: Make VRAM access stalls only apply to BG RAM
- GBA Video: Disable BG target 1 blending when OBJ blending (fixes mgba.io/i/2722)
Other fixes:
- Core: Allow sending thread requests to a crashed core (fixes mgba.io/i/2784)
- Qt: Fix crash when attempting to use OpenGL 2.1 to 3.1 (fixes mgba.io/i/2794)
- Qt: Disable sync while running scripts from main thread (fixes mgba.io/i/2738)
- Qt: Fix savestate preview sizes with different scales (fixes mgba.io/i/2560)
Misc:
- GB Serialize: Add missing savestate support for MBC6 and NT (newer)
- GBA: Improve detection of valid ELF ROMs
- Qt: Include wayland QPA in AppImage (fixes mgba.io/i/2796)
0.10.1: (2023-01-10)
Emulation fixes:
- GB Audio: Fix channels 1/2 not playing when resetting volume (fixes mgba.io/i/2614)
- GB Audio: Fix channel 3 volume being changed between samples (fixes mgba.io/i/1896)
- GB Audio: Fix up boot sequence
- GB Audio: Fix updating channels other than 2 when writing NR5x
- GB Memory: Actually, HDMAs should start when LCD is off (fixes mgba.io/i/2662)
- GB Serialize: Don't write BGP/OBP when loading SCGB state (fixes mgba.io/i/2694)
- GB SIO: Further fix bidirectional transfer starting
- GBA: Fix resetting key IRQ state (fixes mgba.io/i/2716)
- GBA BIOS: Include timing in degenerate ArcTan2 cases (fixes mgba.io/i/2763)
- GBA Video: Ignore disabled backgrounds as OBJ blend target (fixes mgba.io/i/2489)
Other fixes:
- GBA: Fix forceskip BIOS logic for multiboot ROMs (fixes mgba.io/i/2753)
- GBA Cheats: Fix issues detecting unencrypted cheats (fixes mgba.io/i/2724)
- Qt: Manually split filename to avoid overzealous splitting (fixes mgba.io/i/2681)
- Qt: Fix scanning specific e-Reader dotcodes (fixes mgba.io/i/2693)
- Qt: Don't re-enable sync if GBA link modes aren't the same (fixes mgba.io/i/2044)
- Qt: Improve handling of multiplayer syncing (fixes mgba.io/i/2720)
- Qt: Fix initializing update revision info
- Qt: Redo stable branch detection heuristic (fixes mgba.io/i/2679)
- Res: Fix species name location in Ruby/Sapphire revs 1/2 (fixes mgba.io/i/2685)
- VFS: Fix minizip write returning 0 on success instead of size
Misc:
- macOS: Add category to plist (closes mgba.io/i/2691)
- macOS: Fix modern build with libepoxy (fixes mgba.io/i/2700)
- Qt: Keep track of current palette preset name (fixes mgba.io/i/2680)
- Qt: Move OpenGL proxy onto its own thread (fixes mgba.io/i/2493)
0.10.0: (2022-10-11)
Features:
- Preliminary Lua scripting support
- Presets for Game Boy palettes
@ -6,7 +52,7 @@ Features:
- Tool for converting scanned pictures of e-Reader cards to raw dotcode data
- Options for muting when inactive, minimized, or for different players in multiplayer
- Cheat code support in homebrew ports
- Acclerometer and gyro support for controllers on PC
- Accelerometer and gyro support for controllers on PC
- Support for combo "Super Game Boy Color" SGB + GBC ROM hacks
- Improved support for HuC-3 mapper, including RTC
- Support for 64 kiB SRAM saves used in some bootlegs
@ -20,13 +66,13 @@ Emulation fixes:
- ARM7: Fix unsigned multiply timing
- GB: Copy logo from ROM if not running the BIOS intro (fixes mgba.io/i/2378)
- GB: Fix HALT breaking M-cycle alignment (fixes mgba.io/i/250)
- GB Audio: Fix channel 1/2 reseting edge cases (fixes mgba.io/i/1925)
- GB Audio: Fix channel 1/2 resetting edge cases (fixes mgba.io/i/1925)
- GB Audio: Properly apply per-model audio differences
- GB Audio: Revamp channel rendering
- GB Audio: Fix APU re-enable timing glitch
- GB I/O: Fix writing to WAVE RAM behavior (fixes mgba.io/i/1334)
- GB Memory: Add cursory cartridge open bus emulation (fixes mgba.io/i/2032)
- GB MBC: Fix edge case with Pocket Cam register accesses (fixes mgba.io/i/2557)
- GB Memory: Add cursory cartridge open bus emulation (fixes mgba.io/i/2032)
- GB Serialize: Fix loading MBC1 states that affect bank 0 (fixes mgba.io/i/2402)
- GB SIO: Fix bidirectional transfer starting (fixes mgba.io/i/2290)
- GB Video: Draw SGB border pieces that overlap GB graphics (fixes mgba.io/i/1339)
@ -130,7 +176,7 @@ Emulation fixes:
Other fixes:
- ARM Decoder: Fix decoding of lsl r0 (fixes mgba.io/i/2349)
- FFmpeg: Don't attempt to use YUV 4:2:0 for lossless videos (fixes mgba.io/i/2084)
- GB Video: Fix memory leak when reseting SGB games
- GB Video: Fix memory leak when resetting SGB games
- GBA: Fix out of bounds ROM accesses on patched ROMs smaller than 32 MiB
- GBA: Fix maximum tile ID in caching for 256-color modes
- GBA Video: Fix cache updating with proxy and GL renderers
@ -241,7 +287,7 @@ Emulation fixes:
- GBA BIOS: Implement dummy sound driver calls
- GBA BIOS: Improve HLE BIOS timing
- GBA BIOS: Fix reloading video registers after reset (fixes mgba.io/i/1808)
- GBA BIOS: Make HLE BIOS calls interruptable (fixes mgba.io/i/1711 and mgba.io/i/1823)
- GBA BIOS: Make HLE BIOS calls interruptible (fixes mgba.io/i/1711 and mgba.io/i/1823)
- GBA BIOS: Fix invalid decompression bounds checking
- GBA DMA: Linger last DMA on bus (fixes mgba.io/i/301 and mgba.io/i/1320)
- GBA DMA: Fix ordering and timing of overlapping DMAs
@ -257,7 +303,7 @@ Emulation fixes:
- GBA Serialize: Fix alignment check when loading states
- GBA SIO: Fix copying Normal mode transfer values
- GBA SIO: Fix Normal mode being totally broken (fixes mgba.io/i/1800)
- GBA SIO: Fix deseralizing SIO registers
- GBA SIO: Fix deserializing SIO registers
- GBA SIO: Fix hanging on starting a second multiplayer window (fixes mgba.io/i/854)
- GBA SIO: Fix Normal mode transfer start timing (fixes mgba.io/i/425)
- GBA Timers: Fix toggling timer cascading while timer is active (fixes mgba.io/i/2043)

View File

@ -34,7 +34,7 @@ if(NOT MSVC)
# mingw32 likes to complain about using the "wrong" format strings despite them actually working
set(WARNING_FLAGS "${WARNING_FLAGS} -Wno-format")
endif()
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${WARNING_FLAGS} -Werror=implicit-function-declaration")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${WARNING_FLAGS} -Werror=implicit-function-declaration -Werror=implicit-int")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${WARNING_FLAGS}")
else()
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_CRT_SECURE_NO_WARNINGS /wd4003 /wd4244 /wd4146 /wd4267 /Zc:preprocessor-")
@ -235,6 +235,7 @@ elseif(UNIX)
endif()
if(APPLE)
execute_process(COMMAND xcrun --show-sdk-version OUTPUT_VARIABLE MACOSX_SDK)
add_definitions(-D_DARWIN_C_SOURCE)
list(APPEND OS_LIB "-framework Foundation")
if(NOT CMAKE_SYSTEM_VERSION VERSION_LESS "10.0") # Darwin 10.x is Mac OS X 10.6
@ -413,7 +414,7 @@ endif()
if(BUILD_GL)
find_package(OpenGL QUIET)
if(NOT OPENGL_FOUND)
if(NOT OPENGL_FOUND OR (APPLE AND MACOSX_SDK VERSION_GREATER 10.14))
set(BUILD_GL OFF CACHE BOOL "OpenGL not found" FORCE)
elseif(UNIX AND NOT APPLE AND TARGET OpenGL::GL)
set(OPENGL_LIBRARY OpenGL::GL)
@ -430,6 +431,11 @@ if(NOT BUILD_GL AND NOT LIBMGBA_ONLY)
endif()
if(BUILD_GLES2 AND NOT BUILD_GL)
if(APPLE AND MACOSX_SDK VERSION_GREATER 10.14)
find_package(OpenGL QUIET)
set(OPENGLES2_INCLUDE_DIR ${OPENGL_INCLUDE_DIR})
set(OPENGLES2_LIBRARY ${OPENGL_LIBRARY})
endif()
find_path(OPENGLES2_INCLUDE_DIR NAMES GLES2/gl2.h)
find_library(OPENGLES2_LIBRARY NAMES GLESv2 GLESv2_CM)
if(NOT OPENGLES2_INCLUDE_DIR OR NOT OPENGLES2_LIBRARY)
@ -443,6 +449,11 @@ if(BUILD_GLES2)
endif()
if(BUILD_GLES3 AND NOT BUILD_GL)
if(APPLE AND MACOSX_SDK VERSION_GREATER 10.14)
find_package(OpenGL QUIET)
set(OPENGLES3_INCLUDE_DIR ${OPENGL_INCLUDE_DIR})
set(OPENGLES3_LIBRARY ${OPENGL_LIBRARY})
endif()
find_path(OPENGLES3_INCLUDE_DIR NAMES GLES3/gl3.h)
find_library(OPENGLES3_LIBRARY NAMES GLESv3 GLESv2)
if(NOT OPENGLES3_INCLUDE_DIR OR NOT OPENGLES3_LIBRARY)
@ -629,14 +640,15 @@ endif()
if(USE_LIBZIP)
if(TARGET libzip::zip)
list(APPEND DEPENDENCY_LIB libzip::zip)
set(ZIP_LIBRARIES libzip::zip)
elseif(TARGET zip)
list(APPEND DEPENDENCY_LIB zip)
set(ZIP_LIBRARIES zip)
else()
include_directories(AFTER ${LIBZIP_INCLUDE_DIRS})
link_directories(${LIBZIP_LIBRARY_DIRS})
list(APPEND DEPENDENCY_LIB ${LIBZIP_LIBRARIES})
set(ZIP_LIBRARIES ${LIBZIP_LIBRARIES})
endif()
list(APPEND DEPENDENCY_LIB ${ZIP_LIBRARIES})
list(APPEND FEATURES LIBZIP)
list(APPEND VFS_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/util/vfs/vfs-zip.c)
string(REGEX MATCH "^[0-9]+" LIBZIP_VERSION_MAJOR "${libzip_VERSION}")
@ -650,6 +662,7 @@ if(USE_LIBZIP)
elseif(USE_MINIZIP)
include_directories(AFTER ${MINIZIP_INCLUDE_DIRS})
link_directories(${MINIZIP_LIBRARY_DIRS})
set(ZIP_LIBRARIES ${MINIZIP_LIBRARIES})
list(APPEND DEPENDENCY_LIB ${MINIZIP_LIBRARIES})
list(APPEND FEATURES MINIZIP)
list(APPEND VFS_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/util/vfs/vfs-zip.c)
@ -705,8 +718,12 @@ if (USE_LZMA)
endif()
if(USE_EPOXY)
list(APPEND FEATURE_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/platform/opengl/gl.c ${CMAKE_CURRENT_SOURCE_DIR}/src/platform/opengl/gles2.c)
list(APPEND FEATURE_DEFINES BUILD_GL BUILD_GLES2 BUILD_GLES3)
if(NOT APPLE OR NOT MACOSX_SDK VERSION_GREATER 10.14)
list(APPEND FEATURE_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/platform/opengl/gl.c)
list(APPEND FEATURE_DEFINES BUILD_GL)
endif()
list(APPEND FEATURE_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/platform/opengl/gles2.c)
list(APPEND FEATURE_DEFINES BUILD_GLES2 BUILD_GLES3)
list(APPEND FEATURES EPOXY)
include_directories(AFTER ${EPOXY_INCLUDE_DIRS})
link_directories(${EPOXY_LIBRARY_DIRS})
@ -778,6 +795,7 @@ add_subdirectory(src/sm83)
add_subdirectory(src/util)
list(APPEND GUI_SRC ${EXTRA_GUI_SRC})
list(APPEND UTIL_BASE_SRC ${CMAKE_CURRENT_BINARY_DIR}/version.c)
list(APPEND UTIL_SRC ${CMAKE_CURRENT_BINARY_DIR}/version.c)
set(TEST_SRC ${CORE_TEST_SRC})
@ -968,12 +986,12 @@ if(BUILD_QT AND (WIN32 OR APPLE OR CMAKE_SYSTEM_NAME STREQUAL "Linux"))
endif()
if(BUILD_UPDATER)
add_executable(updater-stub WIN32 ${CORE_VFS_SRC} ${OS_SRC} ${UTIL_SRC} ${THIRD_PARTY_SRC}
add_executable(updater-stub WIN32 ${CORE_VFS_SRC} ${VFS_SRC} ${OS_SRC} ${UTIL_BASE_SRC} ${THIRD_PARTY_SRC}
${CMAKE_CURRENT_SOURCE_DIR}/src/core/config.c
${CMAKE_CURRENT_SOURCE_DIR}/src/feature/updater.c
${CMAKE_CURRENT_SOURCE_DIR}/src/feature/updater-main.c)
target_link_libraries(updater-stub ${OS_LIB} ${PLATFORM_LIBRARY})
set_target_properties(updater-stub PROPERTIES COMPILE_DEFINITIONS "${OS_DEFINES};${FUNCTION_DEFINES};BUILD_STATIC")
target_link_libraries(updater-stub ${ZLIB_LIBRARY} ${ZLIB_LIBRARY} ${ZIP_LIBRARIES} ${OS_LIB} ${PLATFORM_LIBRARY})
set_target_properties(updater-stub PROPERTIES COMPILE_DEFINITIONS "${OS_DEFINES};${FUNCTION_DEFINES};${FEATURE_DEFINES};BUILD_STATIC")
if(MSVC)
set_target_properties(updater-stub PROPERTIES LINK_FLAGS /ENTRY:mainCRTStartup)
else()

View File

@ -50,15 +50,15 @@ The following mappers are fully supported:
- MBC2
- MBC3
- MBC3+RTC
- MBC30
- MBC5
- MBC5+Rumble
- MBC7
- Wisdom Tree (unlicensed)
- NT "old type" 1 and 2 (unlicensed multicart)
- NT "new type" (unlicensed MBC5-like)
- Pokémon Jade/Diamond (unlicensed)
- BBD (unlicensed MBC5-like)
- Hitek (unlicensed MBC5-like)
- Sachen MMC1
- Sachen MMC1 (unlicensed)
The following mappers are partially supported:
@ -69,6 +69,10 @@ The following mappers are partially supported:
- HuC-1 (missing IR support)
- HuC-3 (missing IR support)
- Sachen MMC2 (missing alternate wiring support)
- BBD (missing logo switching)
- Hitek (missing logo switching)
- GGB-81 (missing logo switching)
- Li Cheng (missing logo switching)
### Planned features

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@ -0,0 +1,3 @@
[testinfo]
skip=10
frames=1

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

30
include/mgba-util/sfo.h Normal file
View File

@ -0,0 +1,30 @@
/* Copyright (c) 2013-2022 Jeffrey Pfau
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef SFO_H
#define SFO_H
#include <mgba-util/common.h>
CXX_GUARD_START
#include <mgba-util/table.h>
void SfoInit(struct Table* sfo);
static inline void SfoDeinit(struct Table* sfo) {
HashTableDeinit(sfo);
}
struct VFile;
bool SfoWrite(struct Table* sfo, struct VFile* vf);
bool SfoAddU32Value(struct Table* sfo, const char* name, uint32_t value);
bool SfoAddStrValue(struct Table* sfo, const char* name, const char* value);
bool SfoSetTitle(struct Table* sfo, const char* title);
CXX_GUARD_END
#endif

View File

@ -34,6 +34,16 @@ CXX_GUARD_START
size_t NAME ## Index(const struct NAME* vector, const TYPE* member); \
void NAME ## Copy(struct NAME* dest, const struct NAME* src);
#ifdef NDEBUG
#define VECTOR_BOUNDS_CHECK(NAME, V, L)
#else
#define VECTOR_BOUNDS_CHECK(NAME, V, L) \
if ((L) >= (V)->size) { \
fprintf(stderr, "Vector type %s invalid access of index %" PRIuPTR " into vector of size %" PRIuPTR "\n", #NAME, (L), (V)->size); \
abort(); \
}
#endif
#define DEFINE_VECTOR(NAME, TYPE) \
void NAME ## Init(struct NAME* vector, size_t capacity) { \
vector->size = 0; \
@ -50,9 +60,11 @@ CXX_GUARD_START
vector->size = 0; \
} \
TYPE* NAME ## GetPointer(struct NAME* vector, size_t location) { \
VECTOR_BOUNDS_CHECK(NAME, vector, location); \
return &vector->vector[location]; \
} \
TYPE const* NAME ## GetConstPointer(const struct NAME* vector, size_t location) { \
VECTOR_BOUNDS_CHECK(NAME, vector, location); \
return &vector->vector[location]; \
} \
TYPE* NAME ## Append(struct NAME* vector) { \
@ -78,10 +90,12 @@ CXX_GUARD_START
vector->vector = realloc(vector->vector, vector->capacity * sizeof(TYPE)); \
} \
void NAME ## Shift(struct NAME* vector, size_t location, size_t difference) { \
VECTOR_BOUNDS_CHECK(NAME, vector, location); \
memmove(&vector->vector[location], &vector->vector[location + difference], (vector->size - location - difference) * sizeof(TYPE)); \
vector->size -= difference; \
} \
void NAME ## Unshift(struct NAME* vector, size_t location, size_t difference) { \
VECTOR_BOUNDS_CHECK(NAME, vector, location); \
NAME ## Resize(vector, difference); \
memmove(&vector->vector[location + difference], &vector->vector[location], (vector->size - location - difference) * sizeof(TYPE)); \
} \
@ -97,8 +111,16 @@ CXX_GUARD_START
dest->size = src->size; \
} \
DECLARE_VECTOR(StringList, char*);
DECLARE_VECTOR(IntList, int);
DECLARE_VECTOR(SInt8List, int8_t);
DECLARE_VECTOR(SInt16List, int16_t);
DECLARE_VECTOR(SInt32List, int32_t);
DECLARE_VECTOR(SIntPtrList, intptr_t);
DECLARE_VECTOR(UInt8List, uint8_t);
DECLARE_VECTOR(UInt16List, uint16_t);
DECLARE_VECTOR(UInt32List, uint32_t);
DECLARE_VECTOR(UIntPtrList, uintptr_t);
DECLARE_VECTOR(StringList, char*);
CXX_GUARD_END

View File

@ -55,6 +55,7 @@ int mInputMapKeyBits(const struct mInputMap* map, uint32_t type, uint32_t bits,
void mInputBindKey(struct mInputMap*, uint32_t type, int key, int input);
int mInputQueryBinding(const struct mInputMap*, uint32_t type, int input);
void mInputUnbindKey(struct mInputMap*, uint32_t type, int input);
void mInputUnbindAllKeys(struct mInputMap*, uint32_t type);
int mInputMapAxis(const struct mInputMap*, uint32_t type, int axis, int value);
int mInputClearAxis(const struct mInputMap*, uint32_t type, int axis, int keys);
@ -69,6 +70,7 @@ void mInputBindHat(struct mInputMap*, uint32_t type, int id, const struct mInput
bool mInputQueryHat(const struct mInputMap*, uint32_t type, int id, struct mInputHatBindings* bindings);
void mInputUnbindHat(struct mInputMap*, uint32_t type, int id);
void mInputUnbindAllHats(struct mInputMap*, uint32_t type);
void mInputEnumerateHats(const struct mInputMap*, uint32_t type, void (handler(int hat, const struct mInputHatBindings* bindings, void* user)), void* user);
bool mInputMapLoad(struct mInputMap*, uint32_t type, const struct Configuration*);
void mInputMapSave(const struct mInputMap*, uint32_t type, struct Configuration*);

View File

@ -16,6 +16,7 @@ enum mStateExtdataTag {
EXTDATA_SAVEDATA = 2,
EXTDATA_CHEATS = 3,
EXTDATA_RTC = 4,
EXTDATA_SCREENSHOT_DIMENSIONS = 5,
EXTDATA_META_TIME = 0x101,
EXTDATA_META_CREATOR = 0x102,
EXTDATA_MAX

View File

@ -88,8 +88,9 @@ struct mBreakpoint {
struct mWatchpoint {
ssize_t id;
uint32_t address;
int segment;
uint32_t minAddress;
uint32_t maxAddress;
enum mWatchpointType type;
struct ParseTree* condition;
};

View File

@ -41,9 +41,13 @@ enum GBMemoryBankControllerType {
GB_MBC5_RUMBLE = 0x105,
GB_UNL_WISDOM_TREE = 0x200,
GB_UNL_PKJD = 0x203,
GB_UNL_NT_OLD_1 = 0x210,
GB_UNL_NT_OLD_2 = 0x211,
GB_UNL_NT_NEW = 0x212,
GB_UNL_BBD = 0x220, // Also used as a mask for MBCs that need special read behavior
GB_UNL_BBD = 0x220,
GB_UNL_HITEK = 0x221,
GB_UNL_LI_CHENG = 0x222,
GB_UNL_GGB81 = 0x223,
GB_UNL_SACHEN_MMC1 = 0x230,
GB_UNL_SACHEN_MMC2 = 0x231,
};

View File

@ -191,7 +191,6 @@ struct GBMBC1State {
};
struct GBMBC6State {
bool sramAccess;
bool flashBank0;
bool flashBank1;
};
@ -238,6 +237,13 @@ struct GBPKJDState {
uint8_t reg[2];
};
struct GBNTOldState {
bool swapped;
uint8_t baseBank;
uint8_t bankCount;
bool rumble;
};
struct GBNTNewState {
bool splitMode;
};
@ -263,6 +269,7 @@ union GBMBCState {
struct GBPocketCamState pocketCam;
struct GBTAMA5State tama5;
struct GBHuC3State huc3;
struct GBNTOldState ntOld;
struct GBNTNewState ntNew;
struct GBPKJDState pkjd;
struct GBBBDState bbd;

View File

@ -266,6 +266,10 @@ DECL_BITS(GBSerializedVideoFlags, Mode, 2, 2);
DECL_BIT(GBSerializedVideoFlags, NotModeEventScheduled, 4);
DECL_BIT(GBSerializedVideoFlags, NotFrameEventScheduled, 5);
DECL_BITFIELD(GBSerializedMBC6Flags, uint8_t);
DECL_BIT(GBSerializedMBC6Flags, FlashBank0, 0);
DECL_BIT(GBSerializedMBC6Flags, FlashBank1, 1);
DECL_BITFIELD(GBSerializedMBC7Flags, uint8_t);
DECL_BITS(GBSerializedMBC7Flags, Command, 0, 2);
DECL_BIT(GBSerializedMBC7Flags, Writable, 2);
@ -274,6 +278,10 @@ DECL_BITFIELD(GBSerializedSachenFlags, uint8_t);
DECL_BITS(GBSerializedSachenFlags, Transition, 0, 6);
DECL_BITS(GBSerializedSachenFlags, Locked, 6, 2);
DECL_BITFIELD(GBSerializedNTOldFlags, uint8_t);
DECL_BIT(GBSerializedNTOldFlags, Swapped, 0);
DECL_BIT(GBSerializedNTOldFlags, Rumble, 1);
DECL_BITFIELD(GBSerializedMemoryFlags, uint16_t);
DECL_BIT(GBSerializedMemoryFlags, SramAccess, 0);
DECL_BIT(GBSerializedMemoryFlags, RtcAccess, 1);
@ -392,6 +400,11 @@ struct GBSerializedState {
struct {
uint64_t lastLatch;
} rtc;
struct {
GBSerializedMBC6Flags flags;
uint8_t bank1;
uint8_t sramBank1;
} mbc6;
struct {
uint8_t state;
GBMBC7Field eeprom;
@ -416,6 +429,15 @@ struct GBSerializedState {
uint8_t value;
uint8_t mode;
} huc3;
struct {
GBSerializedNTOldFlags flags;
uint8_t baseBank;
uint8_t bankCount;
} ntOld;
struct {
uint8_t splitMode;
uint8_t bank1;
} ntNew;
struct {
uint8_t dataSwapMode;
uint8_t bankSwapMode;

View File

@ -154,6 +154,12 @@ void GBAHalt(struct GBA* gba);
void GBAStop(struct GBA* gba);
void GBADebug(struct GBA* gba, uint16_t value);
#ifdef USE_ELF
struct ELF;
bool GBAVerifyELFEntry(struct ELF* elf, uint32_t target);
#endif
#ifdef USE_DEBUGGERS
struct mDebugger;
void GBAAttachDebugger(struct GBA* gba, struct mDebugger* debugger);

View File

@ -21,60 +21,60 @@ CXX_GUARD_START
#include <mgba/internal/gba/cart/vfame.h>
enum GBAMemoryRegion {
REGION_BIOS = 0x0,
REGION_WORKING_RAM = 0x2,
REGION_WORKING_IRAM = 0x3,
REGION_IO = 0x4,
REGION_PALETTE_RAM = 0x5,
REGION_VRAM = 0x6,
REGION_OAM = 0x7,
REGION_CART0 = 0x8,
REGION_CART0_EX = 0x9,
REGION_CART1 = 0xA,
REGION_CART1_EX = 0xB,
REGION_CART2 = 0xC,
REGION_CART2_EX = 0xD,
REGION_CART_SRAM = 0xE,
REGION_CART_SRAM_MIRROR = 0xF
GBA_REGION_BIOS = 0x0,
GBA_REGION_EWRAM = 0x2,
GBA_REGION_IWRAM = 0x3,
GBA_REGION_IO = 0x4,
GBA_REGION_PALETTE_RAM = 0x5,
GBA_REGION_VRAM = 0x6,
GBA_REGION_OAM = 0x7,
GBA_REGION_ROM0 = 0x8,
GBA_REGION_ROM0_EX = 0x9,
GBA_REGION_ROM1 = 0xA,
GBA_REGION_ROM1_EX = 0xB,
GBA_REGION_ROM2 = 0xC,
GBA_REGION_ROM2_EX = 0xD,
GBA_REGION_SRAM = 0xE,
GBA_REGION_SRAM_MIRROR = 0xF
};
enum GBAMemoryBase {
BASE_BIOS = 0x00000000,
BASE_WORKING_RAM = 0x02000000,
BASE_WORKING_IRAM = 0x03000000,
BASE_IO = 0x04000000,
BASE_PALETTE_RAM = 0x05000000,
BASE_VRAM = 0x06000000,
BASE_OAM = 0x07000000,
BASE_CART0 = 0x08000000,
BASE_CART0_EX = 0x09000000,
BASE_CART1 = 0x0A000000,
BASE_CART1_EX = 0x0B000000,
BASE_CART2 = 0x0C000000,
BASE_CART2_EX = 0x0D000000,
BASE_CART_SRAM = 0x0E000000,
BASE_CART_SRAM_MIRROR = 0x0F000000
GBA_BASE_BIOS = 0x00000000,
GBA_BASE_EWRAM = 0x02000000,
GBA_BASE_IWRAM = 0x03000000,
GBA_BASE_IO = 0x04000000,
GBA_BASE_PALETTE_RAM = 0x05000000,
GBA_BASE_VRAM = 0x06000000,
GBA_BASE_OAM = 0x07000000,
GBA_BASE_ROM0 = 0x08000000,
GBA_BASE_ROM0_EX = 0x09000000,
GBA_BASE_ROM1 = 0x0A000000,
GBA_BASE_ROM1_EX = 0x0B000000,
GBA_BASE_ROM2 = 0x0C000000,
GBA_BASE_ROM2_EX = 0x0D000000,
GBA_BASE_SRAM = 0x0E000000,
GBA_BASE_SRAM_MIRROR = 0x0F000000
};
enum {
SIZE_BIOS = 0x00004000,
SIZE_WORKING_RAM = 0x00040000,
SIZE_WORKING_IRAM = 0x00008000,
SIZE_IO = 0x00000400,
SIZE_PALETTE_RAM = 0x00000400,
SIZE_VRAM = 0x00018000,
SIZE_OAM = 0x00000400,
SIZE_CART0 = 0x02000000,
SIZE_CART1 = 0x02000000,
SIZE_CART2 = 0x02000000,
SIZE_CART_SRAM = 0x00008000,
SIZE_CART_SRAM512 = 0x00010000,
SIZE_CART_FLASH512 = 0x00010000,
SIZE_CART_FLASH1M = 0x00020000,
SIZE_CART_EEPROM = 0x00002000,
SIZE_CART_EEPROM512 = 0x00000200,
GBA_SIZE_BIOS = 0x00004000,
GBA_SIZE_EWRAM = 0x00040000,
GBA_SIZE_IWRAM = 0x00008000,
GBA_SIZE_IO = 0x00000400,
GBA_SIZE_PALETTE_RAM = 0x00000400,
GBA_SIZE_VRAM = 0x00018000,
GBA_SIZE_OAM = 0x00000400,
GBA_SIZE_ROM0 = 0x02000000,
GBA_SIZE_ROM1 = 0x02000000,
GBA_SIZE_ROM2 = 0x02000000,
GBA_SIZE_SRAM = 0x00008000,
GBA_SIZE_SRAM512 = 0x00010000,
GBA_SIZE_FLASH512 = 0x00010000,
GBA_SIZE_FLASH1M = 0x00020000,
GBA_SIZE_EEPROM = 0x00002000,
GBA_SIZE_EEPROM512 = 0x00000200,
SIZE_AGB_PRINT = 0x10000
GBA_SIZE_AGB_PRINT = 0x10000
};
enum {

View File

@ -20,14 +20,12 @@ CXX_GUARD_START
#ifdef USE_EPOXY
#include <epoxy/gl.h>
#elif defined(BUILD_GL)
#ifdef __APPLE__
#elif defined(__APPLE__)
#include <OpenGL/gl3.h>
#else
#elif defined(BUILD_GL)
#define GL_GLEXT_PROTOTYPES
#include <GL/gl.h>
#include <GL/glext.h>
#endif
#else
#include <GLES3/gl3.h>
#endif

View File

@ -407,12 +407,12 @@ struct GBASerializedState {
uint32_t reserved[12];
uint16_t io[SIZE_IO >> 1];
uint16_t pram[SIZE_PALETTE_RAM >> 1];
uint16_t oam[SIZE_OAM >> 1];
uint16_t vram[SIZE_VRAM >> 1];
uint8_t iwram[SIZE_WORKING_IRAM];
uint8_t wram[SIZE_WORKING_RAM];
uint16_t io[GBA_SIZE_IO >> 1];
uint16_t pram[GBA_SIZE_PALETTE_RAM >> 1];
uint16_t oam[GBA_SIZE_OAM >> 1];
uint16_t vram[GBA_SIZE_VRAM >> 1];
uint8_t iwram[GBA_SIZE_IWRAM];
uint8_t wram[GBA_SIZE_EWRAM];
};
static_assert(sizeof(struct GBASerializedState) == 0x61000, "GBA savestate struct sized wrong");

View File

@ -6,6 +6,10 @@
#ifndef M_SCRIPT_SOCKET_H
#define M_SCRIPT_SOCKET_H
#include <mgba-util/common.h>
CXX_GUARD_START
enum mSocketErrorCode {
mSCRIPT_SOCKERR_UNKNOWN_ERROR = -1,
mSCRIPT_SOCKERR_OK = 0,
@ -22,4 +26,6 @@ enum mSocketErrorCode {
mSCRIPT_SOCKERR_UNSUPPORTED,
};
CXX_GUARD_END
#endif

View File

@ -0,0 +1,20 @@
/* Copyright (c) 2013-2023 Jeffrey Pfau
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef M_SCRIPT_TYPES_INTERNAL_H
#define M_SCRIPT_TYPES_INTERNAL_H
#include <mgba-util/common.h>
CXX_GUARD_START
struct Table;
void mScriptContextGetInputTypes(struct Table*);
void mScriptTypeAdd(struct Table*, const struct mScriptType* type);
CXX_GUARD_END
#endif

View File

@ -89,13 +89,14 @@ uint32_t mScriptContextSetWeakref(struct mScriptContext*, struct mScriptValue* v
struct mScriptValue* mScriptContextMakeWeakref(struct mScriptContext*, struct mScriptValue* value);
struct mScriptValue* mScriptContextAccessWeakref(struct mScriptContext*, struct mScriptValue* value);
void mScriptContextClearWeakref(struct mScriptContext*, uint32_t weakref);
void mScriptContextDisownWeakref(struct mScriptContext*, uint32_t weakref);
void mScriptContextAttachStdlib(struct mScriptContext* context);
void mScriptContextAttachSocket(struct mScriptContext* context);
void mScriptContextExportConstants(struct mScriptContext* context, const char* nspace, struct mScriptKVPair* constants);
void mScriptContextExportNamespace(struct mScriptContext* context, const char* nspace, struct mScriptKVPair* value);
void mScriptContextTriggerCallback(struct mScriptContext*, const char* callback);
void mScriptContextTriggerCallback(struct mScriptContext*, const char* callback, struct mScriptList* args);
uint32_t mScriptContextAddCallback(struct mScriptContext*, const char* callback, struct mScriptValue* value);
void mScriptContextRemoveCallback(struct mScriptContext*, uint32_t cbid);

271
include/mgba/script/input.h Normal file
View File

@ -0,0 +1,271 @@
/* Copyright (c) 2013-2022 Jeffrey Pfau
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef M_SCRIPT_INPUT_H
#define M_SCRIPT_INPUT_H
#include <mgba-util/common.h>
#include <mgba/script/context.h>
#include <mgba/script/macros.h>
CXX_GUARD_START
enum mScriptEventType {
mSCRIPT_EV_TYPE_NONE = 0,
mSCRIPT_EV_TYPE_KEY,
mSCRIPT_EV_TYPE_MOUSE_BUTTON,
mSCRIPT_EV_TYPE_MOUSE_MOVE,
mSCRIPT_EV_TYPE_MOUSE_WHEEL,
mSCRIPT_EV_TYPE_GAMEPAD_BUTTON,
mSCRIPT_EV_TYPE_GAMEPAD_HAT,
mSCRIPT_EV_TYPE_TRIGGER,
mSCRIPT_EV_TYPE_MAX
};
enum mScriptInputState {
mSCRIPT_INPUT_STATE_UP = 0,
mSCRIPT_INPUT_STATE_DOWN = 1,
mSCRIPT_INPUT_STATE_HELD = 2,
};
enum mScriptInputDirection {
mSCRIPT_INPUT_DIR_NONE = 0,
mSCRIPT_INPUT_DIR_NORTH = 1,
mSCRIPT_INPUT_DIR_EAST = 2,
mSCRIPT_INPUT_DIR_SOUTH = 4,
mSCRIPT_INPUT_DIR_WEST = 8,
mSCRIPT_INPUT_DIR_UP = mSCRIPT_INPUT_DIR_NORTH,
mSCRIPT_INPUT_DIR_RIGHT = mSCRIPT_INPUT_DIR_EAST,
mSCRIPT_INPUT_DIR_DOWN = mSCRIPT_INPUT_DIR_SOUTH,
mSCRIPT_INPUT_DIR_LEFT = mSCRIPT_INPUT_DIR_WEST,
mSCRIPT_INPUT_DIR_NORTHEAST = mSCRIPT_INPUT_DIR_NORTH | mSCRIPT_INPUT_DIR_EAST,
mSCRIPT_INPUT_DIR_NORTHWEST = mSCRIPT_INPUT_DIR_NORTH | mSCRIPT_INPUT_DIR_WEST,
mSCRIPT_INPUT_DIR_SOUTHEAST = mSCRIPT_INPUT_DIR_SOUTH | mSCRIPT_INPUT_DIR_EAST,
mSCRIPT_INPUT_DIR_SOUTHWEST = mSCRIPT_INPUT_DIR_SOUTH | mSCRIPT_INPUT_DIR_WEST,
};
enum mScriptKeyModifier {
mSCRIPT_KMOD_NONE = 0,
mSCRIPT_KMOD_LSHIFT = 0x1,
mSCRIPT_KMOD_RSHIFT = 0x2,
mSCRIPT_KMOD_SHIFT = 0x3,
mSCRIPT_KMOD_LCONTROL = 0x4,
mSCRIPT_KMOD_RCONTROL = 0x8,
mSCRIPT_KMOD_CONTROL = 0xC,
mSCRIPT_KMOD_LALT = 0x10,
mSCRIPT_KMOD_RALT = 0x20,
mSCRIPT_KMOD_ALT = 0x30,
mSCRIPT_KMOD_LSUPER = 0x40,
mSCRIPT_KMOD_RSUPER = 0x80,
mSCRIPT_KMOD_SUPER = 0xC0,
mSCRIPT_KMOD_CAPS_LOCK = 0x100,
mSCRIPT_KMOD_NUM_LOCK = 0x200,
mSCRIPT_KMOD_SCROLL_LOCK = 0x400,
};
#define mSCRIPT_KEYBASE 0x800000
enum mScriptKey {
mSCRIPT_KEY_NONE = 0,
mSCRIPT_KEY_BACKSPACE = 0x000008,
mSCRIPT_KEY_TAB = 0x000009,
mSCRIPT_KEY_ENTER = 0x00000A,
mSCRIPT_KEY_ESCAPE = 0x00001B,
mSCRIPT_KEY_DELETE = 0x00007F,
mSCRIPT_KEY_F1 = mSCRIPT_KEYBASE | 1,
mSCRIPT_KEY_F2,
mSCRIPT_KEY_F3,
mSCRIPT_KEY_F4,
mSCRIPT_KEY_F5,
mSCRIPT_KEY_F6,
mSCRIPT_KEY_F7,
mSCRIPT_KEY_F8,
mSCRIPT_KEY_F9,
mSCRIPT_KEY_F10,
mSCRIPT_KEY_F11,
mSCRIPT_KEY_F12,
mSCRIPT_KEY_F13,
mSCRIPT_KEY_F14,
mSCRIPT_KEY_F15,
mSCRIPT_KEY_F16,
mSCRIPT_KEY_F17,
mSCRIPT_KEY_F18,
mSCRIPT_KEY_F19,
mSCRIPT_KEY_F20,
mSCRIPT_KEY_F21,
mSCRIPT_KEY_F22,
mSCRIPT_KEY_F23,
mSCRIPT_KEY_F24,
mSCRIPT_KEY_UP = mSCRIPT_KEYBASE | 0x20,
mSCRIPT_KEY_RIGHT,
mSCRIPT_KEY_DOWN,
mSCRIPT_KEY_LEFT,
mSCRIPT_KEY_PAGE_UP,
mSCRIPT_KEY_PAGE_DOWN,
mSCRIPT_KEY_HOME,
mSCRIPT_KEY_END,
mSCRIPT_KEY_INSERT,
mSCRIPT_KEY_BREAK,
mSCRIPT_KEY_CLEAR,
mSCRIPT_KEY_PRINT_SCREEN,
mSCRIPT_KEY_SYSRQ,
mSCRIPT_KEY_MENU,
mSCRIPT_KEY_HELP,
mSCRIPT_KEY_LSHIFT = mSCRIPT_KEYBASE | 0x30,
mSCRIPT_KEY_RSHIFT,
mSCRIPT_KEY_SHIFT,
mSCRIPT_KEY_LCONTROL,
mSCRIPT_KEY_RCONTROL,
mSCRIPT_KEY_CONTROL,
mSCRIPT_KEY_LALT,
mSCRIPT_KEY_RALT,
mSCRIPT_KEY_ALT,
mSCRIPT_KEY_LSUPER,
mSCRIPT_KEY_RSUPER,
mSCRIPT_KEY_SUPER,
mSCRIPT_KEY_CAPS_LOCK,
mSCRIPT_KEY_NUM_LOCK,
mSCRIPT_KEY_SCROLL_LOCK,
mSCRIPT_KEY_KP_0 = mSCRIPT_KEYBASE | 0x40,
mSCRIPT_KEY_KP_1,
mSCRIPT_KEY_KP_2,
mSCRIPT_KEY_KP_3,
mSCRIPT_KEY_KP_4,
mSCRIPT_KEY_KP_5,
mSCRIPT_KEY_KP_6,
mSCRIPT_KEY_KP_7,
mSCRIPT_KEY_KP_8,
mSCRIPT_KEY_KP_9,
mSCRIPT_KEY_KP_PLUS,
mSCRIPT_KEY_KP_MINUS,
mSCRIPT_KEY_KP_MULTIPLY,
mSCRIPT_KEY_KP_DIVIDE,
mSCRIPT_KEY_KP_COMMA,
mSCRIPT_KEY_KP_POINT,
mSCRIPT_KEY_KP_ENTER,
};
enum mScriptMouseButton {
mSCRIPT_MOUSE_BUTTON_PRIMARY = 0,
mSCRIPT_MOUSE_BUTTON_SECONDARY = 1,
mSCRIPT_MOUSE_BUTTON_MIDDLE = 2,
};
struct mScriptEvent {
int32_t type;
int32_t reserved;
uint64_t seq;
};
struct mScriptKeyEvent {
struct mScriptEvent d;
uint8_t state;
uint16_t modifiers;
uint32_t key;
};
struct mScriptMouseButtonEvent {
struct mScriptEvent d;
uint8_t mouse;
uint8_t context;
uint8_t state;
uint8_t button;
};
struct mScriptMouseMoveEvent {
struct mScriptEvent d;
uint8_t mouse;
uint8_t context;
int32_t x;
int32_t y;
};
struct mScriptMouseWheelEvent {
struct mScriptEvent d;
uint8_t mouse;
int16_t x;
int16_t y;
};
struct mScriptGamepadButtonEvent {
struct mScriptEvent d;
uint8_t state;
uint8_t pad;
uint16_t button;
};
struct mScriptGamepadHatEvent {
struct mScriptEvent d;
uint8_t pad;
uint8_t hat;
uint8_t direction;
};
struct mScriptTriggerEvent {
struct mScriptEvent d;
uint8_t trigger;
bool state;
};
struct mScriptGamepad {
unsigned pad;
char visibleName[128];
char internalName[64];
struct mScriptList axes;
struct mScriptList buttons;
struct mScriptList hats;
};
mSCRIPT_DECLARE_STRUCT(mScriptEvent);
mSCRIPT_DECLARE_STRUCT(mScriptKeyEvent);
mSCRIPT_DECLARE_STRUCT(mScriptMouseButtonEvent);
mSCRIPT_DECLARE_STRUCT(mScriptMouseMoveEvent);
mSCRIPT_DECLARE_STRUCT(mScriptMouseWheelEvent);
mSCRIPT_DECLARE_STRUCT(mScriptGamepadButtonEvent);
mSCRIPT_DECLARE_STRUCT(mScriptGamepadHatEvent);
mSCRIPT_DECLARE_STRUCT(mScriptSensorEvent);
mSCRIPT_DECLARE_STRUCT(mScriptTriggerEvent);
mSCRIPT_DECLARE_STRUCT(mScriptGamepad);
void mScriptContextAttachInput(struct mScriptContext* context);
void mScriptContextFireEvent(struct mScriptContext*, struct mScriptEvent*);
int mScriptContextGamepadAttach(struct mScriptContext*, struct mScriptGamepad*);
bool mScriptContextGamepadDetach(struct mScriptContext*, int pad);
struct mScriptGamepad* mScriptContextGamepadLookup(struct mScriptContext*, int pad);
void mScriptGamepadInit(struct mScriptGamepad*);
void mScriptGamepadDeinit(struct mScriptGamepad*);
void mScriptGamepadSetAxisCount(struct mScriptGamepad*, unsigned);
void mScriptGamepadSetButtonCount(struct mScriptGamepad*, unsigned);
void mScriptGamepadSetHatCount(struct mScriptGamepad*, unsigned);
void mScriptGamepadSetAxis(struct mScriptGamepad*, unsigned, int16_t value);
void mScriptGamepadSetButton(struct mScriptGamepad*, unsigned, bool down);
void mScriptGamepadSetHat(struct mScriptGamepad*, unsigned, int direction);
int16_t mScriptGamepadGetAxis(struct mScriptGamepad*, unsigned);
bool mScriptGamepadGetButton(struct mScriptGamepad*, unsigned);
int mScriptGamepadGetHat(struct mScriptGamepad*, unsigned);
CXX_GUARD_END
#endif

View File

@ -76,6 +76,7 @@ CXX_GUARD_START
#define mSCRIPT_TYPE_FIELD_W(TYPE) opaque
#define mSCRIPT_TYPE_FIELD_CW(TYPE) opaque
#define mSCRIPT_TYPE_MS_VOID (&mSTVoid)
#define mSCRIPT_TYPE_MS_S8 (&mSTSInt8)
#define mSCRIPT_TYPE_MS_U8 (&mSTUInt8)
#define mSCRIPT_TYPE_MS_S16 (&mSTSInt16)
@ -97,7 +98,7 @@ CXX_GUARD_START
#define mSCRIPT_TYPE_MS_CS(STRUCT) (&mSTStructConst_ ## STRUCT)
#define mSCRIPT_TYPE_MS_S_METHOD(STRUCT, NAME) (&_mSTStructBindingType_ ## STRUCT ## _ ## NAME)
#define mSCRIPT_TYPE_MS_PS(STRUCT) (&mSTStructPtr_ ## STRUCT)
#define mSCRIPT_TYPE_MS_PCS(STRUCT) (&mSTStructConstPtr_ ## STRUCT)
#define mSCRIPT_TYPE_MS_PCS(STRUCT) (&mSTStructPtrConst_ ## STRUCT)
#define mSCRIPT_TYPE_MS_WSTR (&mSTStringWrapper)
#define mSCRIPT_TYPE_MS_WLIST (&mSTListWrapper)
#define mSCRIPT_TYPE_MS_W(TYPE) (&mSTWrapper_ ## TYPE)
@ -303,6 +304,8 @@ void mScriptValueWrap(struct mScriptValue* val, struct mScriptValue* out);
struct mScriptValue* mScriptValueUnwrap(struct mScriptValue* val);
const struct mScriptValue* mScriptValueUnwrapConst(const struct mScriptValue* val);
void mScriptValueFollowPointer(struct mScriptValue* ptr, struct mScriptValue* out);
struct mScriptValue* mScriptStringCreateEmpty(size_t size);
struct mScriptValue* mScriptStringCreateFromBytes(const void* string, size_t size);
struct mScriptValue* mScriptStringCreateFromUTF8(const char* string);

View File

@ -56,5 +56,7 @@
<string>Viewer</string>
</dict>
</array>
<key>LSApplicationCategoryType</key>
<string>public.app-category.games</string>
</dict>
</plist>

View File

@ -0,0 +1,33 @@
inputBuffer = console:createBuffer("Input")
function readPad()
inputBuffer:clear()
if not input.activeGamepad then
inputBuffer:print("No gamepad detected\n")
return
end
local gamepad = input.activeGamepad
local axes = gamepad.axes
local buttons = gamepad.buttons
local hats = gamepad.hats
inputBuffer:print(gamepad.visibleName .. "\n")
inputBuffer:print(string.format("%i buttons, %i axes, %i hats\n", #buttons, #axes, #hats))
local sbuttons = {}
for k, v in ipairs(buttons) do
if v then
sbuttons[k] = "down"
else
sbuttons[k] = " up"
end
end
inputBuffer:print(string.format("Buttons: %s\n", table.concat(sbuttons, ", ")))
inputBuffer:print(string.format("Axes: %s\n", table.concat(axes, ", ")))
inputBuffer:print(string.format("Hats: %s\n", table.concat(hats, ", ")))
end
callbacks:add("frame", readPad)

View File

@ -412,6 +412,13 @@ local gameRubyEn = Generation3En:new{
_speciesNameTable=0x1f716c,
}
local gameRubyEnR1 = Generation3En:new{
name="Ruby (USA)",
_party=0x3004360,
_partyCount=0x3004350,
_speciesNameTable=0x1f7184,
}
local gameSapphireEn = Generation3En:new{
name="Sapphire (USA)",
_party=0x3004360,
@ -419,6 +426,13 @@ local gameSapphireEn = Generation3En:new{
_speciesNameTable=0x1f70fc,
}
local gameSapphireEnR1 = Generation3En:new{
name="Sapphire (USA)",
_party=0x3004360,
_partyCount=0x3004350,
_speciesNameTable=0x1f7114,
}
local gameEmeraldEn = Generation3En:new{
name="Emerald (USA)",
_party=0x20244ec,
@ -471,6 +485,10 @@ gameCrc32 = {
[0x7d527d62] = gameYellowEn,
[0x84ee4776] = gameFireRedEnR1,
[0xdaffecec] = gameLeafGreenEnR1,
[0x61641576] = gameRubyEnR1, -- Rev 1
[0xaeac73e6] = gameRubyEnR1, -- Rev 2
[0xbafedae5] = gameSapphireEnR1, -- Rev 1
[0x9cc4410e] = gameSapphireEnR1, -- Rev 2
}
function printPartyStatus(game, buffer)

View File

@ -92,12 +92,13 @@ CREATE_MULTIPLE_WATCHPOINT_SHIM(storeMultiple, WATCHPOINT_WRITE)
CREATE_SHIM(setActiveRegion, void, (struct ARMCore* cpu, uint32_t address), address)
static bool _checkWatchpoints(struct ARMDebugger* debugger, uint32_t address, struct mDebuggerEntryInfo* info, enum mWatchpointType type, uint32_t newValue, int width) {
--width;
struct mWatchpoint* watchpoint;
size_t i;
uint32_t minAddress = address & ~(width - 1);
uint32_t maxAddress = minAddress + width;
for (i = 0; i < mWatchpointListSize(&debugger->watchpoints); ++i) {
watchpoint = mWatchpointListGetPointer(&debugger->watchpoints, i);
if (!((watchpoint->address ^ address) & ~width) && watchpoint->type & type) {
if (watchpoint->type & type && watchpoint->minAddress < maxAddress && minAddress < watchpoint->maxAddress) {
if (watchpoint->condition) {
int32_t value;
int segment;
@ -107,7 +108,7 @@ static bool _checkWatchpoints(struct ARMDebugger* debugger, uint32_t address, st
}
uint32_t oldValue;
switch (width + 1) {
switch (width) {
case 1:
oldValue = debugger->originalMemory.load8(debugger->cpu, address, 0);
break;

View File

@ -38,6 +38,11 @@ struct mInputAxisEnumerate {
void* user;
};
struct mInputHatEnumerate {
void (*handler)(int axis, const struct mInputHatBindings* bindings, void* user);
void* user;
};
static void _makeSectionName(const char* platform, char* sectionName, size_t len, uint32_t type) {
snprintf(sectionName, len, "%s.input.%c%c%c%c", platform, type >> 24, type >> 16, type >> 8, type);
sectionName[len - 1] = '\0';
@ -304,6 +309,12 @@ void _unbindAxis(uint32_t axis, void* dp, void* user) {
}
}
void _enumerateHat(uint32_t axis, void* dp, void* ep) {
struct mInputHatEnumerate* enumUser = ep;
const struct mInputHatBindings* description = dp;
enumUser->handler(axis, description, enumUser->user);
}
static bool _loadAll(struct mInputMap* map, uint32_t type, const char* sectionName, const struct Configuration* config) {
if (!ConfigurationHasSection(config, sectionName)) {
return false;
@ -415,6 +426,16 @@ void mInputUnbindKey(struct mInputMap* map, uint32_t type, int input) {
}
}
void mInputUnbindAllKeys(struct mInputMap* map, uint32_t type) {
struct mInputMapImpl* impl = _lookupMap(map, type);
if (impl) {
size_t i;
for (i = 0; i < map->info->nKeys; ++i) {
impl->map[i] = -1;
}
}
}
int mInputQueryBinding(const struct mInputMap* map, uint32_t type, int input) {
if (input < 0 || (size_t) input >= map->info->nKeys) {
return -1;
@ -578,6 +599,18 @@ void mInputUnbindAllHats(struct mInputMap* map, uint32_t type) {
}
}
void mInputEnumerateHats(const struct mInputMap* map, uint32_t type, void (handler(int hat, const struct mInputHatBindings* bindings, void* user)), void* user) {
const struct mInputMapImpl* impl = _lookupMapConst(map, type);
if (!impl) {
return;
}
struct mInputHatEnumerate enumUser = {
handler,
user
};
TableEnumerate(&impl->axes, _enumerateHat, &enumUser);
}
bool mInputMapLoad(struct mInputMap* map, uint32_t type, const struct Configuration* config) {
char sectionName[SECTION_NAME_MAX];
_makeSectionName(map->info->platformName, sectionName, SECTION_NAME_MAX, type);

View File

@ -651,7 +651,7 @@ static struct mScriptValue* _mScriptCoreAdapterGet(struct mScriptCoreAdapter* ad
static void _mScriptCoreAdapterReset(struct mScriptCoreAdapter* adapter) {
adapter->core->reset(adapter->core);
mScriptContextTriggerCallback(adapter->context, "reset");
mScriptContextTriggerCallback(adapter->context, "reset", NULL);
}
mSCRIPT_DECLARE_STRUCT(mScriptCoreAdapter);
@ -761,14 +761,16 @@ mSCRIPT_DEFINE_STRUCT_BINDING_DEFAULTS(mScriptConsole, createBuffer)
mSCRIPT_DEFINE_DEFAULTS_END;
static struct mScriptConsole* _ensureConsole(struct mScriptContext* context) {
struct mScriptValue* value = mScriptContextEnsureGlobal(context, "console", mSCRIPT_TYPE_MS_S(mScriptConsole));
struct mScriptConsole* console = value->value.opaque;
if (!console) {
console = calloc(1, sizeof(*console));
value->value.opaque = console;
value->flags = mSCRIPT_VALUE_FLAG_FREE_BUFFER;
mScriptContextSetDocstring(context, "console", "Singleton instance of struct::mScriptConsole");
struct mScriptValue* value = mScriptContextGetGlobal(context, "console");
if (value) {
return value->value.opaque;
}
struct mScriptConsole* console = calloc(1, sizeof(*console));
value = mScriptValueAlloc(mSCRIPT_TYPE_MS_S(mScriptConsole));
value->value.opaque = console;
value->flags = mSCRIPT_VALUE_FLAG_FREE_BUFFER;
mScriptContextSetGlobal(context, "console", value);
mScriptContextSetDocstring(context, "console", "Singleton instance of struct::mScriptConsole");
return console;
}

View File

@ -262,8 +262,18 @@ static void* _loadPNGState(struct mCore* core, struct VFile* vf, struct mStateEx
PNGReadClose(png, info, end);
return false;
}
unsigned width, height;
core->desiredVideoDimensions(core, &width, &height);
if (!PNGReadHeader(png, info)) {
PNGReadClose(png, info, end);
return false;
}
unsigned width = png_get_image_width(png, info);
unsigned height = png_get_image_height(png, info);
if (width > 0x4000 || height > 0x4000) {
// These images are ridiculously large...let's assume a DOS attempt and reject
PNGReadClose(png, info, end);
return false;
}
uint32_t* pixels = malloc(width * height * 4);
if (!pixels) {
PNGReadClose(png, info, end);
@ -278,8 +288,8 @@ static void* _loadPNGState(struct mCore* core, struct VFile* vf, struct mStateEx
.extdata = extdata
};
bool success = true;
PNGInstallChunkHandler(png, &bundle, _loadPNGChunkHandler, "gbAs gbAx");
bool success = PNGReadHeader(png, info);
success = success && PNGReadPixels(png, info, pixels, width, height, width);
success = success && PNGReadFooter(png, end);
PNGReadClose(png, info, end);
@ -295,6 +305,12 @@ static void* _loadPNGState(struct mCore* core, struct VFile* vf, struct mStateEx
.clean = free
};
mStateExtdataPut(extdata, EXTDATA_SCREENSHOT, &item);
uint16_t dims[2] = { width, height };
item.size = sizeof(dims);
item.data = malloc(item.size);
memcpy(item.data, dims, item.size);
mStateExtdataPut(extdata, EXTDATA_SCREENSHOT_DIMENSIONS, &item);
} else {
free(pixels);
}

View File

@ -12,10 +12,12 @@
#include <mgba/script/context.h>
#include <mgba/script/types.h>
#include "script/test.h"
#ifdef M_CORE_GBA
#include <mgba/internal/gba/memory.h>
#define TEST_PLATFORM mPLATFORM_GBA
#define RAM_BASE BASE_WORKING_IRAM
#define RAM_BASE GBA_BASE_IWRAM
#elif defined(M_CORE_GB)
#include <mgba/internal/gb/memory.h>
#define TEST_PLATFORM mPLATFORM_GB
@ -66,22 +68,6 @@ static const uint8_t _fakeGBROM[0x4000] = {
mCoreConfigDeinit(&core->config); \
core->deinit(core)
#define LOAD_PROGRAM(PROG) \
do { \
struct VFile* vf = VFileFromConstMemory(PROG, strlen(PROG)); \
assert_true(lua->load(lua, NULL, vf)); \
vf->close(vf); \
} while(0)
#define TEST_VALUE(TYPE, NAME, VALUE) \
do { \
struct mScriptValue val = mSCRIPT_MAKE(TYPE, VALUE); \
struct mScriptValue* global = lua->getGlobal(lua, NAME); \
assert_non_null(global); \
assert_true(global->type->equal(global, &val)); \
mScriptValueDeref(global); \
} while(0)
static void _mScriptTestLog(struct mLogger* log, int category, enum mLogLevel level, const char* format, va_list args) {
UNUSED(category);
struct mScriptTestLogger* logger = (struct mScriptTestLogger*) log;

View File

@ -58,8 +58,19 @@ static void _waitOnInterrupt(struct mCoreThreadInternal* threadContext) {
}
static void _pokeRequest(struct mCoreThreadInternal* threadContext) {
if (threadContext->state == mTHREAD_RUNNING || threadContext->state == mTHREAD_PAUSED) {
switch (threadContext->state) {
case mTHREAD_RUNNING:
case mTHREAD_PAUSED:
case mTHREAD_CRASHED:
threadContext->state = mTHREAD_REQUEST;
break;
case mTHREAD_INITIALIZED:
case mTHREAD_REQUEST:
case mTHREAD_INTERRUPTED:
case mTHREAD_INTERRUPTING:
case mTHREAD_EXITING:
case mTHREAD_SHUTDOWN:
break;
}
}
@ -194,7 +205,7 @@ void _script_ ## NAME(void* context) { \
if (!threadContext->scriptContext) { \
return; \
} \
mScriptContextTriggerCallback(threadContext->scriptContext, #NAME); \
mScriptContextTriggerCallback(threadContext->scriptContext, #NAME, NULL); \
}
ADD_CALLBACK(frame)
@ -283,7 +294,7 @@ static THREAD_ENTRY _mCoreThreadRun(void* context) {
}
}
if (scriptContext) {
mScriptContextTriggerCallback(scriptContext, "start");
mScriptContextTriggerCallback(scriptContext, "start", NULL);
}
#endif
@ -304,7 +315,7 @@ static THREAD_ENTRY _mCoreThreadRun(void* context) {
}
}
if (scriptContext) {
mScriptContextTriggerCallback(scriptContext, "reset");
mScriptContextTriggerCallback(scriptContext, "reset", NULL);
}
#endif
@ -404,7 +415,7 @@ static THREAD_ENTRY _mCoreThreadRun(void* context) {
}
#ifdef ENABLE_SCRIPTING
if (scriptContext) {
mScriptContextTriggerCallback(scriptContext, "reset");
mScriptContextTriggerCallback(scriptContext, "reset", NULL);
}
#endif
}
@ -428,7 +439,7 @@ static THREAD_ENTRY _mCoreThreadRun(void* context) {
}
#ifdef ENABLE_SCRIPTING
if (scriptContext) {
mScriptContextTriggerCallback(scriptContext, "shutdown");
mScriptContextTriggerCallback(scriptContext, "shutdown", NULL);
mScriptContextDetachCore(scriptContext);
}
#endif

View File

@ -60,6 +60,10 @@ static void _setReadWriteWatchpoint(struct CLIDebugger*, struct CLIDebugVector*)
static void _setReadWatchpoint(struct CLIDebugger*, struct CLIDebugVector*);
static void _setWriteWatchpoint(struct CLIDebugger*, struct CLIDebugVector*);
static void _setWriteChangedWatchpoint(struct CLIDebugger*, struct CLIDebugVector*);
static void _setReadWriteRangeWatchpoint(struct CLIDebugger*, struct CLIDebugVector*);
static void _setReadRangeWatchpoint(struct CLIDebugger*, struct CLIDebugVector*);
static void _setWriteRangeWatchpoint(struct CLIDebugger*, struct CLIDebugVector*);
static void _setWriteChangedRangeWatchpoint(struct CLIDebugger*, struct CLIDebugVector*);
static void _listWatchpoints(struct CLIDebugger*, struct CLIDebugVector*);
static void _trace(struct CLIDebugger*, struct CLIDebugVector*);
static void _writeByte(struct CLIDebugger*, struct CLIDebugVector*);
@ -114,6 +118,10 @@ static struct CLIDebuggerCommandSummary _debuggerCommands[] = {
{ "watch/c", _setWriteChangedWatchpoint, "Is", "Set a change watchpoint" },
{ "watch/r", _setReadWatchpoint, "Is", "Set a read watchpoint" },
{ "watch/w", _setWriteWatchpoint, "Is", "Set a write watchpoint" },
{ "watch-range", _setReadWriteRangeWatchpoint, "IIs", "Set a range watchpoint" },
{ "watch-range/c", _setWriteChangedRangeWatchpoint, "IIs", "Set a change range watchpoint" },
{ "watch-range/r", _setReadRangeWatchpoint, "IIs", "Set a read range watchpoint" },
{ "watch-range/w", _setWriteRangeWatchpoint, "IIs", "Set a write range watchpoint" },
{ "x/1", _dumpByte, "Ii", "Examine bytes at a specified offset" },
{ "x/2", _dumpHalfword, "Ii", "Examine halfwords at a specified offset" },
{ "x/4", _dumpWord, "Ii", "Examine words at a specified offset" },
@ -146,6 +154,14 @@ static struct CLIDebuggerCommandAlias _debuggerCommandAliases[] = {
{ "p/x", "print/x" },
{ "q", "quit" },
{ "w", "watch" },
{ "watchr", "watch-range" },
{ "wr", "watch-range" },
{ "watchr/c", "watch-range/c" },
{ "wr/c", "watch-range/c" },
{ "watchr/r", "watch-range/r" },
{ "wr/r", "watch-range/r" },
{ "watchr/w", "watch-range/w" },
{ "wr/w", "watch-range/w" },
{ ".", "source" },
{ 0, 0 }
};
@ -647,8 +663,9 @@ static void _setWatchpoint(struct CLIDebugger* debugger, struct CLIDebugVector*
return;
}
struct mWatchpoint watchpoint = {
.address = dv->intValue,
.segment = dv->segmentValue,
.minAddress = dv->intValue,
.maxAddress = dv->intValue + 1,
.type = type
};
if (dv->next && dv->next->type == CLIDV_CHAR_TYPE) {
@ -666,6 +683,48 @@ static void _setWatchpoint(struct CLIDebugger* debugger, struct CLIDebugVector*
}
}
static void _setRangeWatchpoint(struct CLIDebugger* debugger, struct CLIDebugVector* dv, enum mWatchpointType type) {
if (!dv || dv->type != CLIDV_INT_TYPE) {
debugger->backend->printf(debugger->backend, "%s\n", ERROR_MISSING_ARGS);
return;
}
if (!dv->next || dv->next->type != CLIDV_INT_TYPE) {
debugger->backend->printf(debugger->backend, "%s\n", ERROR_MISSING_ARGS);
return;
}
if (!debugger->d.platform->setWatchpoint) {
debugger->backend->printf(debugger->backend, "Watchpoints are not supported by this platform.\n");
return;
}
if (dv->intValue >= dv->next->intValue) {
debugger->backend->printf(debugger->backend, "Range watchpoint end is before start. Note that the end of the range is not included.\n");
return;
}
if (dv->segmentValue != dv->next->segmentValue) {
debugger->backend->printf(debugger->backend, "Range watchpoint does not start and end in the same segment.\n");
return;
}
struct mWatchpoint watchpoint = {
.segment = dv->segmentValue,
.minAddress = dv->intValue,
.maxAddress = dv->next->intValue,
.type = type
};
if (dv->next->next && dv->next->next->type == CLIDV_CHAR_TYPE) {
struct ParseTree* tree = _parseTree((const char*[]) { dv->next->next->charValue, NULL });
if (tree) {
watchpoint.condition = tree;
} else {
debugger->backend->printf(debugger->backend, "%s\n", ERROR_INVALID_ARGS);
return;
}
}
ssize_t id = debugger->d.platform->setWatchpoint(debugger->d.platform, &watchpoint);
if (id > 0) {
debugger->backend->printf(debugger->backend, INFO_WATCHPOINT_ADDED, id);
}
}
static void _setReadWriteWatchpoint(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
_setWatchpoint(debugger, dv, WATCHPOINT_RW);
}
@ -682,6 +741,22 @@ static void _setWriteChangedWatchpoint(struct CLIDebugger* debugger, struct CLID
_setWatchpoint(debugger, dv, WATCHPOINT_WRITE_CHANGE);
}
static void _setReadWriteRangeWatchpoint(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
_setRangeWatchpoint(debugger, dv, WATCHPOINT_RW);
}
static void _setReadRangeWatchpoint(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
_setRangeWatchpoint(debugger, dv, WATCHPOINT_READ);
}
static void _setWriteRangeWatchpoint(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
_setRangeWatchpoint(debugger, dv, WATCHPOINT_WRITE);
}
static void _setWriteChangedRangeWatchpoint(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
_setRangeWatchpoint(debugger, dv, WATCHPOINT_WRITE_CHANGE);
}
static void _clearBreakpoint(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
if (!dv || dv->type != CLIDV_INT_TYPE) {
debugger->backend->printf(debugger->backend, "%s\n", ERROR_MISSING_ARGS);
@ -717,9 +792,17 @@ static void _listWatchpoints(struct CLIDebugger* debugger, struct CLIDebugVector
for (i = 0; i < mWatchpointListSize(&watchpoints); ++i) {
struct mWatchpoint* watchpoint = mWatchpointListGetPointer(&watchpoints, i);
if (watchpoint->segment >= 0) {
debugger->backend->printf(debugger->backend, "%" PRIz "i: %02X:%X\n", watchpoint->id, watchpoint->segment, watchpoint->address);
if (watchpoint->maxAddress == watchpoint->minAddress + 1) {
debugger->backend->printf(debugger->backend, "%" PRIz "i: %02X:%X\n", watchpoint->id, watchpoint->segment, watchpoint->minAddress);
} else {
debugger->backend->printf(debugger->backend, "%" PRIz "i: %02X:%X-%X\n", watchpoint->id, watchpoint->segment, watchpoint->minAddress, watchpoint->maxAddress);
}
} else {
debugger->backend->printf(debugger->backend, "%" PRIz "i: 0x%X\n", watchpoint->id, watchpoint->address);
if (watchpoint->maxAddress == watchpoint->minAddress + 1) {
debugger->backend->printf(debugger->backend, "%" PRIz "i: 0x%X\n", watchpoint->id, watchpoint->minAddress);
} else {
debugger->backend->printf(debugger->backend, "%" PRIz "i: 0x%X-0x%X\n", watchpoint->id, watchpoint->minAddress, watchpoint->maxAddress);
}
}
}
mWatchpointListDeinit(&watchpoints);

View File

@ -532,7 +532,7 @@ static void _processQReadCommand(struct GDBStub* stub, const char* message) {
} else if (!strncmp("Xfer:memory-map:read::", message, 22)) {
if (strlen(stub->memoryMapXml) == 0) {
_generateMemoryMapXml(stub, stub->memoryMapXml);
}
}
_processQXferCommand(stub, message + 22, stub->memoryMapXml);
} else if (!strncmp("Supported:", message, 10)) {
_processQSupportedCommand(stub, message + 10);
@ -575,7 +575,8 @@ static void _setBreakpoint(struct GDBStub* stub, const char* message) {
.type = BREAKPOINT_HARDWARE
};
struct mWatchpoint watchpoint = {
.address = address
.minAddress = address,
.maxAddress = address + 1
};
switch (message[0]) {
@ -631,10 +632,11 @@ static void _clearBreakpoint(struct GDBStub* stub, const char* message) {
mWatchpointListInit(&watchpoints, 0);
stub->d.platform->listWatchpoints(stub->d.platform, &watchpoints);
for (index = 0; index < mWatchpointListSize(&watchpoints); ++index) {
if (mWatchpointListGetPointer(&watchpoints, index)->address != address) {
struct mWatchpoint* watchpoint = mWatchpointListGetPointer(&watchpoints, index);
if (address >= watchpoint->minAddress && address < watchpoint->maxAddress) {
continue;
}
stub->d.platform->clearBreakpoint(stub->d.platform, mWatchpointListGetPointer(&watchpoints, index)->id);
stub->d.platform->clearBreakpoint(stub->d.platform, watchpoint->id);
}
mWatchpointListDeinit(&watchpoints);
break;

View File

@ -11,8 +11,6 @@
DEFINE_VECTOR(LexVector, struct Token);
DEFINE_VECTOR(IntList, int32_t);
enum LexState {
LEX_ERROR = -1,
LEX_ROOT = 0,

View File

@ -19,6 +19,12 @@
#include <mgba-util/png-io.h>
#include <mgba-util/vfs.h>
#ifdef PSP2
#include <psp2/io/stat.h>
#elif defined(__3DS__)
#include <mgba-util/platform/3ds/3ds-vfs.h>
#endif
#include <sys/time.h>
mLOG_DECLARE_CATEGORY(GUI_RUNNER);
@ -117,34 +123,39 @@ static void _drawState(struct GUIBackground* background, void* id) {
struct mGUIBackground* gbaBackground = (struct mGUIBackground*) background;
unsigned stateId = ((uint32_t) id) >> 16;
if (gbaBackground->p->drawScreenshot) {
unsigned w, h;
gbaBackground->p->core->desiredVideoDimensions(gbaBackground->p->core, &w, &h);
size_t size = w * h * BYTES_PER_PIXEL;
if (size != gbaBackground->imageSize) {
mappedMemoryFree(gbaBackground->image, gbaBackground->imageSize);
gbaBackground->image = NULL;
}
if (gbaBackground->image && gbaBackground->screenshotId == (stateId | SCREENSHOT_VALID)) {
gbaBackground->p->drawScreenshot(gbaBackground->p, gbaBackground->image, w, h, true);
color_t* pixels = gbaBackground->image;
if (pixels && gbaBackground->screenshotId == (stateId | SCREENSHOT_VALID)) {
gbaBackground->p->drawScreenshot(gbaBackground->p, pixels, gbaBackground->w, gbaBackground->h, true);
return;
} else if (gbaBackground->screenshotId != (stateId | SCREENSHOT_INVALID)) {
struct VFile* vf = mCoreGetState(gbaBackground->p->core, stateId, false);
color_t* pixels = gbaBackground->image;
if (!pixels) {
pixels = anonymousMemoryMap(size);
gbaBackground->image = pixels;
gbaBackground->imageSize = size;
}
bool success = false;
if (vf && isPNG(vf) && pixels) {
unsigned w, h;
if (vf && isPNG(vf)) {
png_structp png = PNGReadOpen(vf, PNG_HEADER_BYTES);
png_infop info = png_create_info_struct(png);
png_infop end = png_create_info_struct(png);
if (png && info && end) {
success = PNGReadHeader(png, info);
success = success && PNGReadPixels(png, info, pixels, w, h, w);
success = success && PNGReadFooter(png, end);
success = png && info && end;
success = success && PNGReadHeader(png, info);
w = png_get_image_width(png, info);
h = png_get_image_height(png, info);
size_t size = w * h * BYTES_PER_PIXEL;
success = success && (w < 0x4000) && (h < 0x4000);
if (success) {
if (size != gbaBackground->imageSize) {
mappedMemoryFree(pixels, gbaBackground->imageSize);
pixels = anonymousMemoryMap(size);
gbaBackground->image = pixels;
gbaBackground->imageSize = size;
}
success = pixels;
}
success = success && PNGReadPixels(png, info, pixels, w, h, w);
if (success) {
gbaBackground->w = w;
gbaBackground->h = h;
}
success = success && PNGReadFooter(png, end);
PNGReadClose(png, info, end);
}
if (vf) {
@ -450,11 +461,7 @@ void mGUIRun(struct mGUIRunner* runner, const char* path) {
runner->setup(runner);
}
if (runner->config.port && runner->keySources) {
mLOG(GUI_RUNNER, DEBUG, "Loading key sources for %s...", runner->config.port);
size_t i;
for (i = 0; runner->keySources[i].id; ++i) {
mInputMapLoad(&runner->core->inputMap, runner->keySources[i].id, mCoreConfigGetInput(&runner->config));
}
mGUILoadInputMaps(runner);
}
mLOG(GUI_RUNNER, DEBUG, "Reseting...");
runner->core->reset(runner->core);
@ -745,11 +752,7 @@ void mGUIRun(struct mGUIRunner* runner, const char* path) {
void mGUIRunloop(struct mGUIRunner* runner) {
if (runner->keySources) {
mLOG(GUI_RUNNER, DEBUG, "Loading key sources for %s...", runner->config.port);
size_t i;
for (i = 0; runner->keySources[i].id; ++i) {
mInputMapLoad(&runner->params.keyMap, runner->keySources[i].id, mCoreConfigGetInput(&runner->config));
}
mGUILoadInputMaps(runner);
}
while (!runner->running || runner->running(runner)) {
char path[PATH_MAX];
@ -770,6 +773,52 @@ void mGUIRunloop(struct mGUIRunner* runner) {
}
}
void mGUILoadInputMaps(struct mGUIRunner* runner) {
mLOG(GUI_RUNNER, DEBUG, "Loading key sources for %s...", runner->config.port);
size_t i;
for (i = 0; runner->keySources[i].id; ++i) {
mInputMapLoad(&runner->params.keyMap, runner->keySources[i].id, mCoreConfigGetInput(&runner->config));
}
}
#if defined(__3DS__) || defined(PSP2)
bool mGUIGetRom(struct mGUIRunner* runner, char* out, size_t outLength) {
#ifdef PSP2
int fd = open("app0:/filename", O_RDONLY);
strcpy(out, "app0:/");
#elif defined(__3DS__)
int fd = open("romfs:/filename", O_RDONLY);
strcpy(out, "romfs:/");
#endif
if (fd < 0) {
return false;
}
size_t len = strlen(out);
ssize_t size = read(fd, out + len, outLength - len);
if (size > 0 && out[len + size - 1] == '\n') {
out[len + size - 1] = '\0';
}
close(fd);
if (size <= 0) {
return false;
}
char basedir[64];
mCoreConfigDirectory(basedir, sizeof(basedir));
strlcat(basedir, "/forwarders", sizeof(basedir));
#ifdef PSP2
sceIoMkdir(basedir, 0777);
#elif defined(__3DS__)
FSUSER_CreateDirectory(sdmcArchive, fsMakePath(PATH_ASCII, basedir), 0);
#endif
mCoreConfigSetValue(&runner->config, "savegamePath", basedir);
mCoreConfigSetValue(&runner->config, "savestatePath", basedir);
mCoreConfigSetValue(&runner->config, "screenshotPath", basedir);
mCoreConfigSetValue(&runner->config, "cheatsPath", basedir);
return true;
}
#endif
#ifndef DISABLE_THREADING
THREAD_ENTRY mGUIAutosaveThread(void* context) {
struct mGUIAutosaveContext* autosave = context;

View File

@ -33,6 +33,8 @@ struct mGUIBackground {
color_t* image;
size_t imageSize;
uint16_t w;
uint16_t h;
unsigned screenshotId;
};
@ -95,9 +97,14 @@ struct mGUIRunner {
void mGUIInit(struct mGUIRunner*, const char* port);
void mGUIDeinit(struct mGUIRunner*);
void mGUILoadInputMaps(struct mGUIRunner* runner);
void mGUIRun(struct mGUIRunner*, const char* path);
void mGUIRunloop(struct mGUIRunner*);
#if defined(__3DS__) || defined(PSP2)
bool mGUIGetRom(struct mGUIRunner* runner, char* out, size_t outLength);
#endif
#ifndef DISABLE_THREADING
THREAD_ENTRY mGUIAutosaveThread(void* context);
#endif

View File

@ -29,6 +29,8 @@
#define W_OK 02
#endif
FILE* logfile;
bool extractArchive(struct VDir* archive, const char* root, bool prefix) {
char path[PATH_MAX] = {0};
struct VDirEntry* vde;
@ -53,7 +55,7 @@ bool extractArchive(struct VDir* archive, const char* root, bool prefix) {
}
switch (vde->type(vde)) {
case VFS_DIRECTORY:
printf("mkdir %s\n", fname);
fprintf(logfile, "mkdir %s\n", fname);
if (mkdir(path, 0755) < 0 && errno != EEXIST) {
return false;
}
@ -70,7 +72,7 @@ bool extractArchive(struct VDir* archive, const char* root, bool prefix) {
}
break;
case VFS_FILE:
printf("extract %s\n", fname);
fprintf(logfile, "extract %s\n", fname);
vfIn = archive->openFile(archive, vde->name(vde), O_RDONLY);
errno = 0;
vfOut = VFileOpen(path, O_WRONLY | O_CREAT | O_TRUNC);
@ -111,13 +113,17 @@ int main(int argc, char* argv[]) {
const char* root;
int ok = 1;
mCoreConfigDirectory(bin, sizeof(bin));
strncat(bin, "/updater.log", sizeof(bin));
logfile = fopen(bin, "w");
mCoreConfigInit(&config, "updater");
if (!mCoreConfigLoad(&config)) {
puts("Failed to load config");
fputs("Failed to load config\n", logfile);
} else if (!mUpdateGetArchivePath(&config, updateArchive, sizeof(updateArchive)) || !(root = mUpdateGetRoot(&config))) {
puts("No pending update found");
fputs("No pending update found\n", logfile);
} else if (access(root, W_OK)) {
puts("Cannot write to update path");
fputs("Cannot write to update path\n", logfile);
} else {
#ifdef __APPLE__
char subdir[PATH_MAX];
@ -160,7 +166,6 @@ int main(int argc, char* argv[]) {
}
off_t diff = devend - devinfo - 1;
memcpy(devpath, &devinfo[1], diff);
puts(devpath);
break;
}
int retstat;
@ -177,11 +182,11 @@ int main(int argc, char* argv[]) {
archive = VDirOpenArchive(updateArchive);
}
if (archive) {
puts("Extracting update");
fputs("Extracting update\n", logfile);
if (extractArchive(archive, root, prefix)) {
ok = 0;
} else {
puts("An error occurred");
fputs("An error occurred\n", logfile);
}
archive->close(archive);
unlink(updateArchive);
@ -218,10 +223,10 @@ int main(int argc, char* argv[]) {
close(infd);
}
if (ok == 2) {
puts("Cannot move update over old file");
fputs("Cannot move update over old file\n", logfile);
}
} else {
puts("Cannot move update over old file");
fputs("Cannot move update over old file\n", logfile);
}
} else {
ok = 0;
@ -232,10 +237,10 @@ int main(int argc, char* argv[]) {
}
#endif
else {
puts("Cannot open update archive");
fputs("Cannot open update archive\n", logfile);
}
if (ok == 0) {
puts("Complete");
fputs("Complete", logfile);
const char* command = mUpdateGetCommand(&config);
strlcpy(bin, command, sizeof(bin));
mUpdateDeregister(&config);
@ -260,6 +265,7 @@ int main(int argc, char* argv[]) {
}
}
mCoreConfigDeinit(&config);
fclose(logfile);
if (ok == 0) {
#ifdef _WIN32
char qbin[PATH_MAX + 2] = {0};

View File

@ -78,14 +78,7 @@ static void _updateMatch(const char* key, const char* value, void* user) {
return;
}
const char* item = &key[dotLoc + 1];
struct Table* out = user;
struct mUpdate* update = HashTableLookup(out, match->channel);
if (!update) {
update = calloc(1, sizeof(*update));
HashTableInsert(out, match->channel, update);
}
_updateUpdate(update, item, value);
_updateUpdate(match->out, item, value);
}
bool mUpdaterInit(struct mUpdaterContext* context, const char* manifest) {

View File

@ -7,6 +7,12 @@ set(SOURCE_FILES
input.c
io.c
mbc.c
mbc/huc-3.c
mbc/licensed.c
mbc/mbc.c
mbc/pocket-cam.c
mbc/tama5.c
mbc/unlicensed.c
memory.c
overrides.c
serialize.c

View File

@ -269,6 +269,29 @@ void GBAudioWriteNR31(struct GBAudio* audio, uint8_t value) {
void GBAudioWriteNR32(struct GBAudio* audio, uint8_t value) {
GBAudioRun(audio, mTimingCurrentTime(audio->timing), 0x4);
audio->ch3.volume = GBAudioRegisterBankVolumeGetVolumeGB(value);
audio->ch3.sample = audio->ch3.wavedata8[audio->ch3.window >> 1];
if (!(audio->ch3.window & 1)) {
audio->ch3.sample >>= 4;
}
audio->ch3.sample &= 0xF;
int volume;
switch (audio->ch3.volume) {
case 0:
volume = 4;
break;
case 1:
volume = 0;
break;
case 2:
volume = 1;
break;
default:
case 3:
volume = 2;
break;
}
audio->ch3.sample >>= volume;
}
void GBAudioWriteNR33(struct GBAudio* audio, uint8_t value) {
@ -377,13 +400,13 @@ void GBAudioWriteNR44(struct GBAudio* audio, uint8_t value) {
}
void GBAudioWriteNR50(struct GBAudio* audio, uint8_t value) {
GBAudioRun(audio, mTimingCurrentTime(audio->timing), 0x2);
GBAudioRun(audio, mTimingCurrentTime(audio->timing), 0xF);
audio->volumeRight = GBRegisterNR50GetVolumeRight(value);
audio->volumeLeft = GBRegisterNR50GetVolumeLeft(value);
}
void GBAudioWriteNR51(struct GBAudio* audio, uint8_t value) {
GBAudioRun(audio, mTimingCurrentTime(audio->timing), 0x2);
GBAudioRun(audio, mTimingCurrentTime(audio->timing), 0xF);
audio->ch1Right = GBRegisterNR51GetCh1Right(value);
audio->ch2Right = GBRegisterNR51GetCh2Right(value);
audio->ch3Right = GBRegisterNR51GetCh3Right(value);
@ -476,11 +499,11 @@ void GBAudioRun(struct GBAudio* audio, int32_t timestamp, int channels) {
if (!audio->enable) {
return;
}
if (audio->p && channels != 0xF && timestamp - audio->lastSample > (int) (SAMPLE_INTERVAL * audio->timingFactor)) {
if (audio->p && channels != 0x1F && timestamp - audio->lastSample > (int) (SAMPLE_INTERVAL * audio->timingFactor)) {
GBAudioSample(audio, timestamp);
}
if (audio->playingCh1 && (channels & 0x1)) {
if (audio->playingCh1 && (channels & 0x1) && audio->ch1.envelope.dead != 2) {
int period = 4 * (2048 - audio->ch1.control.frequency) * audio->timingFactor;
int32_t diff = timestamp - audio->ch1.lastUpdate;
if (diff >= period) {
@ -490,7 +513,7 @@ void GBAudioRun(struct GBAudio* audio, int32_t timestamp, int channels) {
_updateSquareSample(&audio->ch1);
}
}
if (audio->playingCh2 && (channels & 0x2)) {
if (audio->playingCh2 && (channels & 0x2) && audio->ch2.envelope.dead != 2) {
int period = 4 * (2048 - audio->ch2.control.frequency) * audio->timingFactor;
int32_t diff = timestamp - audio->ch2.lastUpdate;
if (diff >= period) {
@ -756,7 +779,7 @@ void GBAudioSample(struct GBAudio* audio, int32_t timestamp) {
for (sample = audio->sampleIndex; timestamp >= interval && sample < GB_MAX_SAMPLES; ++sample, timestamp -= interval) {
int16_t sampleLeft = 0;
int16_t sampleRight = 0;
GBAudioRun(audio, sample * interval + audio->lastSample, 0xF);
GBAudioRun(audio, sample * interval + audio->lastSample, 0x1F);
GBAudioSamplePSG(audio, &sampleLeft, &sampleRight);
sampleLeft = (sampleLeft * audio->masterVolume * 6) >> 7;
sampleRight = (sampleRight * audio->masterVolume * 6) >> 7;
@ -863,7 +886,7 @@ bool _writeEnvelope(struct GBAudioEnvelope* envelope, uint8_t value, enum GBAudi
envelope->currentVolume &= 0xF;
}
_updateEnvelopeDead(envelope);
return (envelope->initialVolume || envelope->direction) && envelope->dead != 2;
return envelope->initialVolume || envelope->direction;
}
static void _updateSquareSample(struct GBAudioSquareChannel* ch) {

View File

@ -596,13 +596,13 @@ void GBReset(struct SM83Core* cpu) {
GBVideoReset(&gb->video);
GBTimerReset(&gb->timer);
GBIOReset(gb);
GBAudioReset(&gb->audio);
if (!gb->biosVf && gb->memory.rom) {
GBSkipBIOS(gb);
} else {
mTimingSchedule(&gb->timing, &gb->timer.event, 0);
}
GBAudioReset(&gb->audio);
GBSIOReset(&gb->sio);
cpu->memory.setActiveRegion(cpu, cpu->pc);
@ -744,6 +744,25 @@ void GBSkipBIOS(struct GB* gb) {
GBUnmapBIOS(gb);
}
GBIOWrite(gb, GB_REG_NR52, 0xF1);
GBIOWrite(gb, GB_REG_NR14, 0x3F);
GBIOWrite(gb, GB_REG_NR10, 0x80);
GBIOWrite(gb, GB_REG_NR11, 0xBF);
GBIOWrite(gb, GB_REG_NR12, 0xF3);
GBIOWrite(gb, GB_REG_NR13, 0xF3);
GBIOWrite(gb, GB_REG_NR24, 0x3F);
GBIOWrite(gb, GB_REG_NR21, 0x3F);
GBIOWrite(gb, GB_REG_NR22, 0x00);
GBIOWrite(gb, GB_REG_NR34, 0x3F);
GBIOWrite(gb, GB_REG_NR30, 0x7F);
GBIOWrite(gb, GB_REG_NR31, 0xFF);
GBIOWrite(gb, GB_REG_NR32, 0x9F);
GBIOWrite(gb, GB_REG_NR44, 0x3F);
GBIOWrite(gb, GB_REG_NR41, 0xFF);
GBIOWrite(gb, GB_REG_NR42, 0x00);
GBIOWrite(gb, GB_REG_NR43, 0x00);
GBIOWrite(gb, GB_REG_NR50, 0x77);
GBIOWrite(gb, GB_REG_NR51, 0xF3);
GBIOWrite(gb, GB_REG_LCDC, 0x91);
gb->memory.io[GB_REG_BANK] = 0x1;
GBVideoSkipBIOS(&gb->video);

View File

@ -162,36 +162,7 @@ void GBIOReset(struct GB* gb) {
GBIOWrite(gb, GB_REG_TMA, 0);
GBIOWrite(gb, GB_REG_TAC, 0);
GBIOWrite(gb, GB_REG_IF, 1);
gb->audio.playingCh1 = false;
gb->audio.playingCh2 = false;
gb->audio.playingCh3 = false;
gb->audio.playingCh4 = false;
GBIOWrite(gb, GB_REG_NR52, 0xF1);
GBIOWrite(gb, GB_REG_NR14, 0x3F);
GBIOWrite(gb, GB_REG_NR10, 0x80);
GBIOWrite(gb, GB_REG_NR11, 0xBF);
GBIOWrite(gb, GB_REG_NR12, 0xF3);
GBIOWrite(gb, GB_REG_NR13, 0xF3);
GBIOWrite(gb, GB_REG_NR24, 0x3F);
GBIOWrite(gb, GB_REG_NR21, 0x3F);
GBIOWrite(gb, GB_REG_NR22, 0x00);
GBIOWrite(gb, GB_REG_NR34, 0x3F);
GBIOWrite(gb, GB_REG_NR30, 0x7F);
GBIOWrite(gb, GB_REG_NR31, 0xFF);
GBIOWrite(gb, GB_REG_NR32, 0x9F);
GBIOWrite(gb, GB_REG_NR44, 0x3F);
GBIOWrite(gb, GB_REG_NR41, 0xFF);
GBIOWrite(gb, GB_REG_NR42, 0x00);
GBIOWrite(gb, GB_REG_NR43, 0x00);
GBIOWrite(gb, GB_REG_NR50, 0x77);
GBIOWrite(gb, GB_REG_NR51, 0xF3);
if (!gb->biosVf) {
GBIOWrite(gb, GB_REG_LCDC, 0x91);
gb->memory.io[GB_REG_BANK] = 1;
} else {
GBIOWrite(gb, GB_REG_LCDC, 0x00);
gb->memory.io[GB_REG_BANK] = 0xFF;
}
GBIOWrite(gb, GB_REG_LCDC, 0x00);
GBIOWrite(gb, GB_REG_SCY, 0x00);
GBIOWrite(gb, GB_REG_SCX, 0x00);
GBIOWrite(gb, GB_REG_LYC, 0x00);
@ -203,6 +174,7 @@ void GBIOReset(struct GB* gb) {
}
GBIOWrite(gb, GB_REG_WY, 0x00);
GBIOWrite(gb, GB_REG_WX, 0x00);
gb->memory.io[GB_REG_BANK] = 0xFF;
if (gb->model & GB_MODEL_CGB) {
GBIOWrite(gb, GB_REG_KEY0, 0);
GBIOWrite(gb, GB_REG_JOYP, 0xFF);
@ -754,7 +726,7 @@ void GBIODeserialize(struct GB* gb, const struct GBSerializedState* state) {
gb->video.renderer->writeVideoRegister(gb->video.renderer, GB_REG_SCX, state->io[GB_REG_SCX]);
gb->video.renderer->writeVideoRegister(gb->video.renderer, GB_REG_WY, state->io[GB_REG_WY]);
gb->video.renderer->writeVideoRegister(gb->video.renderer, GB_REG_WX, state->io[GB_REG_WX]);
if (gb->model & GB_MODEL_SGB) {
if (gb->model == GB_MODEL_SGB) {
gb->video.renderer->writeVideoRegister(gb->video.renderer, GB_REG_BGP, state->io[GB_REG_BGP]);
gb->video.renderer->writeVideoRegister(gb->video.renderer, GB_REG_OBP0, state->io[GB_REG_OBP0]);
gb->video.renderer->writeVideoRegister(gb->video.renderer, GB_REG_OBP1, state->io[GB_REG_OBP1]);

File diff suppressed because it is too large Load Diff

218
src/gb/mbc/huc-3.c Normal file
View File

@ -0,0 +1,218 @@
/* Copyright (c) 2013-2016 Jeffrey Pfau
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "gb/mbc/mbc-private.h"
#include <mgba/internal/gb/gb.h>
#include <mgba-util/vfs.h>
static void _latchHuC3Rtc(struct mRTCSource* rtc, uint8_t* huc3Regs, time_t* rtcLastLatch) {
time_t t;
if (rtc) {
if (rtc->sample) {
rtc->sample(rtc);
}
t = rtc->unixTime(rtc);
} else {
t = time(0);
}
t -= *rtcLastLatch;
t /= 60;
if (!t) {
return;
}
*rtcLastLatch += t * 60;
int minutes = huc3Regs[GBHUC3_RTC_MINUTES_HI] << 8;
minutes |= huc3Regs[GBHUC3_RTC_MINUTES_MI] << 4;
minutes |= huc3Regs[GBHUC3_RTC_MINUTES_LO];
minutes += t % 1440;
t /= 1440;
if (minutes >= 1440) {
minutes -= 1440;
++t;
} else if (minutes < 0) {
minutes += 1440;
--t;
}
huc3Regs[GBHUC3_RTC_MINUTES_LO] = minutes & 0xF;
huc3Regs[GBHUC3_RTC_MINUTES_MI] = (minutes >> 4) & 0xF;
huc3Regs[GBHUC3_RTC_MINUTES_HI] = (minutes >> 8) & 0xF;
int days = huc3Regs[GBHUC3_RTC_DAYS_LO];
days |= huc3Regs[GBHUC3_RTC_DAYS_MI] << 4;
days |= huc3Regs[GBHUC3_RTC_DAYS_HI] << 8;
days += t;
huc3Regs[GBHUC3_RTC_DAYS_LO] = days & 0xF;
huc3Regs[GBHUC3_RTC_DAYS_MI] = (days >> 4) & 0xF;
huc3Regs[GBHUC3_RTC_DAYS_HI] = (days >> 8) & 0xF;
}
static void _huc3Commit(struct GB* gb, struct GBHuC3State* state) {
size_t c;
switch (state->value & 0x70) {
case 0x10:
if ((state->index & 0xF8) == 0x10) {
_latchHuC3Rtc(gb->memory.rtc, state->registers, &gb->memory.rtcLastLatch);
}
state->value &= 0xF0;
state->value |= state->registers[state->index] & 0xF;
mLOG(GB_MBC, DEBUG, "HuC-3 read: %02X:%X", state->index, state->value & 0xF);
if (state->value & 0x10) {
++state->index;
}
break;
case 0x30:
mLOG(GB_MBC, DEBUG, "HuC-3 write: %02X:%X", state->index, state->value & 0xF);
state->registers[state->index] = state->value & 0xF;
if (state->value & 0x10) {
++state->index;
}
break;
case 0x40:
state->index &= 0xF0;
state->index |= (state->value) & 0xF;
mLOG(GB_MBC, DEBUG, "HuC-3 index (low): %02X", state->index);
break;
case 0x50:
state->index &= 0x0F;
state->index |= ((state->value) & 0xF) << 4;
mLOG(GB_MBC, DEBUG, "HuC-3 index (high): %02X", state->index);
break;
case 0x60:
switch (state->value & 0xF) {
case GBHUC3_CMD_LATCH:
_latchHuC3Rtc(gb->memory.rtc, state->registers, &gb->memory.rtcLastLatch);
memcpy(state->registers, &state->registers[GBHUC3_RTC_MINUTES_LO], 6);
mLOG(GB_MBC, DEBUG, "HuC-3 RTC latch");
break;
case GBHUC3_CMD_SET_RTC:
memcpy(&state->registers[GBHUC3_RTC_MINUTES_LO], state->registers, 6);
mLOG(GB_MBC, DEBUG, "HuC-3 set RTC");
break;
case GBHUC3_CMD_RO:
mLOG(GB_MBC, STUB, "HuC-3 unimplemented read-only mode");
break;
case GBHUC3_CMD_TONE:
if (state->registers[GBHUC3_SPEAKER_ENABLE] == 1) {
for (c = 0; c < mCoreCallbacksListSize(&gb->coreCallbacks); ++c) {
struct mCoreCallbacks* callbacks = mCoreCallbacksListGetPointer(&gb->coreCallbacks, c);
if (callbacks->alarm) {
callbacks->alarm(callbacks->context);
}
}
mLOG(GB_MBC, DEBUG, "HuC-3 tone %i", state->registers[GBHUC3_SPEAKER_TONE] & 3);
}
break;
default:
mLOG(GB_MBC, STUB, "HuC-3 unknown command: %X", state->value & 0xF);
break;
}
state->value = 0xE1;
break;
default:
mLOG(GB_MBC, STUB, "HuC-3 unknown mode commit: %02X:%02X", state->index, state->value);
break;
}
}
void _GBHuC3(struct GB* gb, uint16_t address, uint8_t value) {
struct GBMemory* memory = &gb->memory;
struct GBHuC3State* state = &memory->mbcState.huc3;
int bank = value & 0x7F;
if (address & 0x1FFF) {
mLOG(GB_MBC, STUB, "HuC-3 unknown value %04X:%02X", address, value);
}
switch (address >> 13) {
case 0x0:
switch (value) {
case 0xA:
memory->sramAccess = true;
GBMBCSwitchSramBank(gb, memory->sramCurrentBank);
break;
default:
memory->sramAccess = false;
break;
}
state->mode = value;
break;
case 0x1:
GBMBCSwitchBank(gb, bank);
break;
case 0x2:
GBMBCSwitchSramBank(gb, bank);
break;
case 0x5:
switch (state->mode) {
case GBHUC3_MODE_IN:
state->value = 0x80 | value;
break;
case GBHUC3_MODE_COMMIT:
_huc3Commit(gb, state);
break;
default:
mLOG(GB_MBC, STUB, "HuC-3 unknown mode write: %02X:%02X", state->mode, value);
}
break;
default:
// TODO
mLOG(GB_MBC, STUB, "HuC-3 unknown address: %04X:%02X", address, value);
break;
}
}
uint8_t _GBHuC3Read(struct GBMemory* memory, uint16_t address) {
struct GBHuC3State* state = &memory->mbcState.huc3;
switch (state->mode) {
case GBHUC3_MODE_SRAM_RO:
case GBHUC3_MODE_SRAM_RW:
return memory->sramBank[address & (GB_SIZE_EXTERNAL_RAM - 1)];
case GBHUC3_MODE_IN:
case GBHUC3_MODE_OUT:
return 0x80 | state->value;
default:
return 0xFF;
}
}
void GBMBCHuC3Read(struct GB* gb) {
struct GBMBCHuC3SaveBuffer buffer;
struct VFile* vf = gb->sramVf;
if (!vf) {
return;
}
vf->seek(vf, gb->sramSize, SEEK_SET);
if (vf->read(vf, &buffer, sizeof(buffer)) < (ssize_t) sizeof(buffer)) {
return;
}
size_t i;
for (i = 0; i < 0x80; ++i) {
gb->memory.mbcState.huc3.registers[i * 2] = buffer.regs[i] & 0xF;
gb->memory.mbcState.huc3.registers[i * 2 + 1] = buffer.regs[i] >> 4;
}
LOAD_64LE(gb->memory.rtcLastLatch, 0, &buffer.latchedUnix);
}
void GBMBCHuC3Write(struct GB* gb) {
struct VFile* vf = gb->sramVf;
if (!vf) {
return;
}
struct GBMBCHuC3SaveBuffer buffer;
size_t i;
for (i = 0; i < 0x80; ++i) {
buffer.regs[i] = gb->memory.mbcState.huc3.registers[i * 2] & 0xF;
buffer.regs[i] |= gb->memory.mbcState.huc3.registers[i * 2 + 1] << 4;
}
STORE_64LE(gb->memory.rtcLastLatch, 0, &buffer.latchedUnix);
_GBMBCAppendSaveSuffix(gb, &buffer, sizeof(buffer));
}

84
src/gb/mbc/licensed.c Normal file
View File

@ -0,0 +1,84 @@
/* Copyright (c) 2013-2016 Jeffrey Pfau
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "gb/mbc/mbc-private.h"
#include <mgba/internal/gb/gb.h>
void _GBMMM01(struct GB* gb, uint16_t address, uint8_t value) {
struct GBMemory* memory = &gb->memory;
if (!memory->mbcState.mmm01.locked) {
switch (address >> 13) {
case 0x0:
memory->mbcState.mmm01.locked = true;
GBMBCSwitchBank0(gb, memory->mbcState.mmm01.currentBank0);
break;
case 0x1:
memory->mbcState.mmm01.currentBank0 &= ~0x7F;
memory->mbcState.mmm01.currentBank0 |= value & 0x7F;
break;
case 0x2:
memory->mbcState.mmm01.currentBank0 &= ~0x180;
memory->mbcState.mmm01.currentBank0 |= (value & 0x30) << 3;
break;
default:
// TODO
mLOG(GB_MBC, STUB, "MMM01 unknown address: %04X:%02X", address, value);
break;
}
return;
}
switch (address >> 13) {
case 0x0:
switch (value) {
case 0xA:
memory->sramAccess = true;
GBMBCSwitchSramBank(gb, memory->sramCurrentBank);
break;
default:
memory->sramAccess = false;
break;
}
break;
case 0x1:
GBMBCSwitchBank(gb, value + memory->mbcState.mmm01.currentBank0);
break;
case 0x2:
GBMBCSwitchSramBank(gb, value);
break;
default:
// TODO
mLOG(GB_MBC, STUB, "MMM01 unknown address: %04X:%02X", address, value);
break;
}
}
void _GBHuC1(struct GB* gb, uint16_t address, uint8_t value) {
struct GBMemory* memory = &gb->memory;
int bank = value & 0x3F;
switch (address >> 13) {
case 0x0:
switch (value) {
case 0xE:
memory->sramAccess = false;
break;
default:
memory->sramAccess = true;
GBMBCSwitchSramBank(gb, memory->sramCurrentBank);
break;
}
break;
case 0x1:
GBMBCSwitchBank(gb, bank);
break;
case 0x2:
GBMBCSwitchSramBank(gb, value);
break;
default:
// TODO
mLOG(GB_MBC, STUB, "HuC-1 unknown address: %04X:%02X", address, value);
break;
}
}

63
src/gb/mbc/mbc-private.h Normal file
View File

@ -0,0 +1,63 @@
/* Copyright (c) 2013-2016 Jeffrey Pfau
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef GB_MBC_PRIVATE_H
#define GB_MBC_PRIVATE_H
#include <mgba/internal/gb/mbc.h>
CXX_GUARD_START
struct GB;
struct GBMemory;
struct mRTCSource;
void _GBMBC1(struct GB*, uint16_t address, uint8_t value);
void _GBMBC2(struct GB*, uint16_t address, uint8_t value);
void _GBMBC3(struct GB*, uint16_t address, uint8_t value);
void _GBMBC5(struct GB*, uint16_t address, uint8_t value);
void _GBMBC6(struct GB*, uint16_t address, uint8_t value);
void _GBMBC7(struct GB*, uint16_t address, uint8_t value);
void _GBMMM01(struct GB*, uint16_t address, uint8_t value);
void _GBPocketCam(struct GB* gb, uint16_t address, uint8_t value);
void _GBTAMA5(struct GB* gb, uint16_t address, uint8_t value);
void _GBHuC1(struct GB*, uint16_t address, uint8_t value);
void _GBHuC3(struct GB*, uint16_t address, uint8_t value);
void _GBWisdomTree(struct GB* gb, uint16_t address, uint8_t value);
void _GBPKJD(struct GB* gb, uint16_t address, uint8_t value);
void _GBNTOld1(struct GB* gb, uint16_t address, uint8_t value);
void _GBNTOld2(struct GB* gb, uint16_t address, uint8_t value);
void _GBNTNew(struct GB* gb, uint16_t address, uint8_t value);
void _GBBBD(struct GB* gb, uint16_t address, uint8_t value);
void _GBHitek(struct GB* gb, uint16_t address, uint8_t value);
void _GBLiCheng(struct GB* gb, uint16_t address, uint8_t value);
void _GBGGB81(struct GB* gb, uint16_t address, uint8_t value);
void _GBSachen(struct GB* gb, uint16_t address, uint8_t value);
uint8_t _GBMBC2Read(struct GBMemory*, uint16_t address);
uint8_t _GBMBC6Read(struct GBMemory*, uint16_t address);
uint8_t _GBMBC7Read(struct GBMemory*, uint16_t address);
void _GBMBC7Write(struct GBMemory* memory, uint16_t address, uint8_t value);
uint8_t _GBPocketCamRead(struct GBMemory*, uint16_t address);
uint8_t _GBTAMA5Read(struct GBMemory*, uint16_t address);
uint8_t _GBHuC3Read(struct GBMemory*, uint16_t address);
uint8_t _GBPKJDRead(struct GBMemory*, uint16_t address);
uint8_t _GBBBDRead(struct GBMemory*, uint16_t address);
uint8_t _GBHitekRead(struct GBMemory*, uint16_t address);
uint8_t _GBGGB81Read(struct GBMemory*, uint16_t address);
uint8_t _GBSachenMMC1Read(struct GBMemory*, uint16_t address);
uint8_t _GBSachenMMC2Read(struct GBMemory*, uint16_t address);
void _GBMBCLatchRTC(struct mRTCSource* rtc, uint8_t* rtcRegs, time_t* rtcLastLatch);
void _GBMBCAppendSaveSuffix(struct GB* gb, const void* buffer, size_t size);
CXX_GUARD_END
#endif

565
src/gb/mbc/mbc.c Normal file
View File

@ -0,0 +1,565 @@
/* Copyright (c) 2013-2016 Jeffrey Pfau
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "gb/mbc/mbc-private.h"
#include <mgba/core/interface.h>
#include <mgba/internal/defines.h>
#include <mgba/internal/gb/gb.h>
static void _GBMBC6MapChip(struct GB*, int half, uint8_t value);
void _GBMBCLatchRTC(struct mRTCSource* rtc, uint8_t* rtcRegs, time_t* rtcLastLatch) {
time_t t;
if (rtc) {
if (rtc->sample) {
rtc->sample(rtc);
}
t = rtc->unixTime(rtc);
} else {
t = time(0);
}
time_t currentLatch = t;
t -= *rtcLastLatch;
*rtcLastLatch = currentLatch;
int64_t diff;
diff = rtcRegs[0] + t % 60;
if (diff < 0) {
diff += 60;
t -= 60;
}
rtcRegs[0] = diff % 60;
t /= 60;
t += diff / 60;
diff = rtcRegs[1] + t % 60;
if (diff < 0) {
diff += 60;
t -= 60;
}
rtcRegs[1] = diff % 60;
t /= 60;
t += diff / 60;
diff = rtcRegs[2] + t % 24;
if (diff < 0) {
diff += 24;
t -= 24;
}
rtcRegs[2] = diff % 24;
t /= 24;
t += diff / 24;
diff = rtcRegs[3] + ((rtcRegs[4] & 1) << 8) + (t & 0x1FF);
rtcRegs[3] = diff;
rtcRegs[4] &= 0xFE;
rtcRegs[4] |= (diff >> 8) & 1;
if (diff & 0x200) {
rtcRegs[4] |= 0x80;
}
}
static void _GBMBC1Update(struct GB* gb) {
struct GBMBC1State* state = &gb->memory.mbcState.mbc1;
int bank = state->bankLo;
bank &= (1 << state->multicartStride) - 1;
bank |= state->bankHi << state->multicartStride;
if (state->mode) {
GBMBCSwitchBank0(gb, state->bankHi << state->multicartStride);
GBMBCSwitchSramBank(gb, state->bankHi & 3);
} else {
GBMBCSwitchBank0(gb, 0);
GBMBCSwitchSramBank(gb, 0);
}
if (!(state->bankLo & 0x1F)) {
++state->bankLo;
++bank;
}
GBMBCSwitchBank(gb, bank);
}
void _GBMBC1(struct GB* gb, uint16_t address, uint8_t value) {
struct GBMemory* memory = &gb->memory;
int bank = value & 0x1F;
switch (address >> 13) {
case 0x0:
switch (value & 0xF) {
case 0:
memory->sramAccess = false;
break;
case 0xA:
memory->sramAccess = true;
GBMBCSwitchSramBank(gb, memory->sramCurrentBank);
break;
default:
// TODO
mLOG(GB_MBC, STUB, "MBC1 unknown value %02X", value);
break;
}
break;
case 0x1:
memory->mbcState.mbc1.bankLo = bank;
_GBMBC1Update(gb);
break;
case 0x2:
bank &= 3;
memory->mbcState.mbc1.bankHi = bank;
_GBMBC1Update(gb);
break;
case 0x3:
memory->mbcState.mbc1.mode = value & 1;
_GBMBC1Update(gb);
break;
default:
// TODO
mLOG(GB_MBC, STUB, "MBC1 unknown address: %04X:%02X", address, value);
break;
}
}
void _GBMBC2(struct GB* gb, uint16_t address, uint8_t value) {
struct GBMemory* memory = &gb->memory;
int shift = (address & 1) * 4;
int bank = value & 0xF;
switch ((address & 0xC100) >> 8) {
case 0x0:
switch (value & 0x0F) {
case 0:
memory->sramAccess = false;
break;
case 0xA:
memory->sramAccess = true;
break;
default:
// TODO
mLOG(GB_MBC, STUB, "MBC2 unknown value %02X", value);
break;
}
break;
case 0x1:
if (!bank) {
++bank;
}
GBMBCSwitchBank(gb, bank);
break;
case 0x80:
case 0x81:
case 0x82:
case 0x83:
if (!memory->sramAccess) {
return;
}
address &= 0x1FF;
memory->sramBank[(address >> 1)] &= 0xF0 >> shift;
memory->sramBank[(address >> 1)] |= (value & 0xF) << shift;
gb->sramDirty |= mSAVEDATA_DIRT_NEW;
break;
default:
// TODO
mLOG(GB_MBC, STUB, "MBC2 unknown address: %04X:%02X", address, value);
break;
}
}
uint8_t _GBMBC2Read(struct GBMemory* memory, uint16_t address) {
if (!memory->sramAccess) {
return 0xFF;
}
address &= 0x1FF;
int shift = (address & 1) * 4;
return (memory->sramBank[(address >> 1)] >> shift) | 0xF0;
}
void _GBMBC3(struct GB* gb, uint16_t address, uint8_t value) {
struct GBMemory* memory = &gb->memory;
int bank = value;
switch (address >> 13) {
case 0x0:
switch (value & 0xF) {
case 0:
memory->sramAccess = false;
break;
case 0xA:
memory->sramAccess = true;
GBMBCSwitchSramBank(gb, memory->sramCurrentBank);
break;
default:
// TODO
mLOG(GB_MBC, STUB, "MBC3 unknown value %02X", value);
break;
}
break;
case 0x1:
if (gb->memory.romSize < GB_SIZE_CART_BANK0 * 0x80) {
bank &= 0x7F;
}
if (!bank) {
++bank;
}
GBMBCSwitchBank(gb, bank);
break;
case 0x2:
bank &= 0xF;
if (bank < 8) {
GBMBCSwitchSramBank(gb, value);
memory->rtcAccess = false;
} else if (bank <= 0xC) {
memory->activeRtcReg = bank - 8;
memory->rtcAccess = true;
}
break;
case 0x3:
if (memory->rtcLatched && value == 0) {
memory->rtcLatched = false;
} else if (!memory->rtcLatched && value == 1) {
_GBMBCLatchRTC(gb->memory.rtc, gb->memory.rtcRegs, &gb->memory.rtcLastLatch);
memory->rtcLatched = true;
}
break;
}
}
void _GBMBC5(struct GB* gb, uint16_t address, uint8_t value) {
struct GBMemory* memory = &gb->memory;
int bank;
switch (address >> 12) {
case 0x0:
case 0x1:
switch (value) {
case 0:
memory->sramAccess = false;
break;
case 0xA:
memory->sramAccess = true;
GBMBCSwitchSramBank(gb, memory->sramCurrentBank);
break;
default:
// TODO
mLOG(GB_MBC, STUB, "MBC5 unknown value %02X", value);
break;
}
break;
case 0x2:
bank = (memory->currentBank & 0x100) | value;
GBMBCSwitchBank(gb, bank);
break;
case 0x3:
bank = (memory->currentBank & 0xFF) | ((value & 1) << 8);
GBMBCSwitchBank(gb, bank);
break;
case 0x4:
case 0x5:
if (memory->mbcType == GB_MBC5_RUMBLE && memory->rumble) {
memory->rumble->setRumble(memory->rumble, (value >> 3) & 1);
value &= ~8;
}
GBMBCSwitchSramBank(gb, value & 0xF);
break;
default:
// TODO
mLOG(GB_MBC, STUB, "MBC5 unknown address: %04X:%02X", address, value);
break;
}
}
void _GBMBC6(struct GB* gb, uint16_t address, uint8_t value) {
struct GBMemory* memory = &gb->memory;
int bank = value;
switch (address >> 10) {
case 0:
switch (value) {
case 0:
memory->sramAccess = false;
break;
case 0xA:
memory->sramAccess = true;
break;
default:
// TODO
mLOG(GB_MBC, STUB, "MBC6 unknown value %02X", value);
break;
}
break;
case 0x1:
GBMBCSwitchSramHalfBank(gb, 0, bank);
break;
case 0x2:
GBMBCSwitchSramHalfBank(gb, 1, bank);
break;
case 0x3:
mLOG(GB_MBC, STUB, "MBC6 unimplemented flash OE write: %04X:%02X", address, value);
break;
case 0x4:
mLOG(GB_MBC, STUB, "MBC6 unimplemented flash WE write: %04X:%02X", address, value);
break;
case 0x8:
case 0x9:
GBMBCSwitchHalfBank(gb, 0, bank);
break;
case 0xA:
case 0xB:
_GBMBC6MapChip(gb, 0, value);
break;
case 0xC:
case 0xD:
GBMBCSwitchHalfBank(gb, 1, bank);
break;
case 0xE:
case 0xF:
_GBMBC6MapChip(gb, 1, value);
break;
case 0x28:
case 0x29:
case 0x2A:
case 0x2B:
if (memory->sramAccess) {
memory->sramBank[address & (GB_SIZE_EXTERNAL_RAM_HALFBANK - 1)] = value;
gb->sramDirty |= mSAVEDATA_DIRT_NEW;
}
break;
case 0x2C:
case 0x2D:
case 0x2E:
case 0x2F:
if (memory->sramAccess) {
memory->sramBank1[address & (GB_SIZE_EXTERNAL_RAM_HALFBANK - 1)] = value;
}
break;
default:
mLOG(GB_MBC, STUB, "MBC6 unknown address: %04X:%02X", address, value);
break;
}
}
uint8_t _GBMBC6Read(struct GBMemory* memory, uint16_t address) {
if (!memory->sramAccess) {
return 0xFF;
}
switch (address >> 12) {
case 0xA:
return memory->sramBank[address & (GB_SIZE_EXTERNAL_RAM_HALFBANK - 1)];
case 0xB:
return memory->sramBank1[address & (GB_SIZE_EXTERNAL_RAM_HALFBANK - 1)];
}
return 0xFF;
}
static void _GBMBC6MapChip(struct GB* gb, int half, uint8_t value) {
if (!half) {
gb->memory.mbcState.mbc6.flashBank0 = !!(value & 0x08);
GBMBCSwitchHalfBank(gb, half, gb->memory.currentBank);
} else {
gb->memory.mbcState.mbc6.flashBank1 = !!(value & 0x08);
GBMBCSwitchHalfBank(gb, half, gb->memory.currentBank1);
}
}
void _GBMBC7(struct GB* gb, uint16_t address, uint8_t value) {
int bank = value & 0x7F;
switch (address >> 13) {
case 0x0:
switch (value) {
default:
case 0:
gb->memory.mbcState.mbc7.access = 0;
break;
case 0xA:
gb->memory.mbcState.mbc7.access |= 1;
break;
}
break;
case 0x1:
GBMBCSwitchBank(gb, bank);
break;
case 0x2:
if (value == 0x40) {
gb->memory.mbcState.mbc7.access |= 2;
} else {
gb->memory.mbcState.mbc7.access &= ~2;
}
break;
case 0x5:
_GBMBC7Write(&gb->memory, address, value);
gb->sramDirty |= mSAVEDATA_DIRT_NEW;
break;
default:
// TODO
mLOG(GB_MBC, STUB, "MBC7 unknown address: %04X:%02X", address, value);
break;
}
}
uint8_t _GBMBC7Read(struct GBMemory* memory, uint16_t address) {
struct GBMBC7State* mbc7 = &memory->mbcState.mbc7;
if (mbc7->access != 3) {
return 0xFF;
}
switch (address & 0xF0) {
case 0x20:
if (memory->rotation && memory->rotation->readTiltX) {
int32_t x = -memory->rotation->readTiltX(memory->rotation);
x >>= 21;
x += 0x81D0;
return x;
}
return 0xFF;
case 0x30:
if (memory->rotation && memory->rotation->readTiltX) {
int32_t x = -memory->rotation->readTiltX(memory->rotation);
x >>= 21;
x += 0x81D0;
return x >> 8;
}
return 7;
case 0x40:
if (memory->rotation && memory->rotation->readTiltY) {
int32_t y = -memory->rotation->readTiltY(memory->rotation);
y >>= 21;
y += 0x81D0;
return y;
}
return 0xFF;
case 0x50:
if (memory->rotation && memory->rotation->readTiltY) {
int32_t y = -memory->rotation->readTiltY(memory->rotation);
y >>= 21;
y += 0x81D0;
return y >> 8;
}
return 7;
case 0x60:
return 0;
case 0x80:
return mbc7->eeprom;
default:
return 0xFF;
}
}
void _GBMBC7Write(struct GBMemory* memory, uint16_t address, uint8_t value) {
struct GBMBC7State* mbc7 = &memory->mbcState.mbc7;
if (mbc7->access != 3) {
return;
}
switch (address & 0xF0) {
case 0x00:
mbc7->latch = (value & 0x55) == 0x55;
return;
case 0x10:
mbc7->latch |= (value & 0xAA);
if (mbc7->latch == 0xAB && memory->rotation && memory->rotation->sample) {
memory->rotation->sample(memory->rotation);
}
mbc7->latch = 0;
return;
default:
mLOG(GB_MBC, STUB, "MBC7 unknown register: %04X:%02X", address, value);
return;
case 0x80:
break;
}
GBMBC7Field old = memory->mbcState.mbc7.eeprom;
value = GBMBC7FieldFillDO(value); // Hi-Z
if (!GBMBC7FieldIsCS(old) && GBMBC7FieldIsCS(value)) {
mbc7->state = GBMBC7_STATE_IDLE;
}
if (!GBMBC7FieldIsCLK(old) && GBMBC7FieldIsCLK(value)) {
if (mbc7->state == GBMBC7_STATE_READ_COMMAND || mbc7->state == GBMBC7_STATE_EEPROM_WRITE || mbc7->state == GBMBC7_STATE_EEPROM_WRAL) {
mbc7->sr <<= 1;
mbc7->sr |= GBMBC7FieldGetDI(value);
++mbc7->srBits;
}
switch (mbc7->state) {
case GBMBC7_STATE_IDLE:
if (GBMBC7FieldIsDI(value)) {
mbc7->state = GBMBC7_STATE_READ_COMMAND;
mbc7->srBits = 0;
mbc7->sr = 0;
}
break;
case GBMBC7_STATE_READ_COMMAND:
if (mbc7->srBits == 10) {
mbc7->state = 0x10 | (mbc7->sr >> 6);
if (mbc7->state & 0xC) {
mbc7->state &= ~0x3;
}
mbc7->srBits = 0;
mbc7->address = mbc7->sr & 0x7F;
}
break;
case GBMBC7_STATE_DO:
value = GBMBC7FieldSetDO(value, mbc7->sr >> 15);
mbc7->sr <<= 1;
--mbc7->srBits;
if (!mbc7->srBits) {
mbc7->state = GBMBC7_STATE_IDLE;
}
break;
default:
break;
}
switch (mbc7->state) {
case GBMBC7_STATE_EEPROM_EWEN:
mbc7->writable = true;
mbc7->state = GBMBC7_STATE_IDLE;
break;
case GBMBC7_STATE_EEPROM_EWDS:
mbc7->writable = false;
mbc7->state = GBMBC7_STATE_IDLE;
break;
case GBMBC7_STATE_EEPROM_WRITE:
if (mbc7->srBits == 16) {
if (mbc7->writable) {
memory->sram[mbc7->address * 2] = mbc7->sr >> 8;
memory->sram[mbc7->address * 2 + 1] = mbc7->sr;
}
mbc7->state = GBMBC7_STATE_IDLE;
}
break;
case GBMBC7_STATE_EEPROM_ERASE:
if (mbc7->writable) {
memory->sram[mbc7->address * 2] = 0xFF;
memory->sram[mbc7->address * 2 + 1] = 0xFF;
}
mbc7->state = GBMBC7_STATE_IDLE;
break;
case GBMBC7_STATE_EEPROM_READ:
mbc7->srBits = 16;
mbc7->sr = memory->sram[mbc7->address * 2] << 8;
mbc7->sr |= memory->sram[mbc7->address * 2 + 1];
mbc7->state = GBMBC7_STATE_DO;
value = GBMBC7FieldClearDO(value);
break;
case GBMBC7_STATE_EEPROM_WRAL:
if (mbc7->srBits == 16) {
if (mbc7->writable) {
int i;
for (i = 0; i < 128; ++i) {
memory->sram[i * 2] = mbc7->sr >> 8;
memory->sram[i * 2 + 1] = mbc7->sr;
}
}
mbc7->state = GBMBC7_STATE_IDLE;
}
break;
case GBMBC7_STATE_EEPROM_ERAL:
if (mbc7->writable) {
int i;
for (i = 0; i < 128; ++i) {
memory->sram[i * 2] = 0xFF;
memory->sram[i * 2 + 1] = 0xFF;
}
}
mbc7->state = GBMBC7_STATE_IDLE;
break;
default:
break;
}
} else if (GBMBC7FieldIsCS(value) && GBMBC7FieldIsCLK(old) && !GBMBC7FieldIsCLK(value)) {
value = GBMBC7FieldSetDO(value, GBMBC7FieldGetDO(old));
}
mbc7->eeprom = value;
}

149
src/gb/mbc/pocket-cam.c Normal file
View File

@ -0,0 +1,149 @@
/* Copyright (c) 2013-2016 Jeffrey Pfau
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "gb/mbc/mbc-private.h"
#include <mgba/internal/defines.h>
#include <mgba/internal/gb/gb.h>
static void _GBPocketCamCapture(struct GBMemory*);
void _GBPocketCam(struct GB* gb, uint16_t address, uint8_t value) {
struct GBMemory* memory = &gb->memory;
int bank = value & 0x3F;
switch (address >> 13) {
case 0x0:
switch (value) {
case 0:
memory->sramAccess = false;
break;
case 0xA:
memory->sramAccess = true;
GBMBCSwitchSramBank(gb, memory->sramCurrentBank);
break;
default:
// TODO
mLOG(GB_MBC, STUB, "Pocket Cam unknown value %02X", value);
break;
}
break;
case 0x1:
GBMBCSwitchBank(gb, bank);
break;
case 0x2:
if (value < 0x10) {
GBMBCSwitchSramBank(gb, value);
memory->mbcState.pocketCam.registersActive = false;
memory->directSramAccess = true;
} else {
memory->mbcState.pocketCam.registersActive = true;
memory->directSramAccess = false;
}
break;
case 0x5:
if (!memory->mbcState.pocketCam.registersActive) {
break;
}
address &= 0x7F;
if (address == 0 && value & 1) {
value &= 6; // TODO: Timing
gb->sramDirty |= mSAVEDATA_DIRT_NEW;
_GBPocketCamCapture(memory);
}
if (address < sizeof(memory->mbcState.pocketCam.registers)) {
memory->mbcState.pocketCam.registers[address] = value;
}
break;
default:
mLOG(GB_MBC, STUB, "Pocket Cam unknown address: %04X:%02X", address, value);
break;
}
}
uint8_t _GBPocketCamRead(struct GBMemory* memory, uint16_t address) {
if (memory->mbcState.pocketCam.registersActive) {
if ((address & 0x7F) == 0) {
return memory->mbcState.pocketCam.registers[0];
}
return 0;
}
return memory->sramBank[address & (GB_SIZE_EXTERNAL_RAM - 1)];
}
void _GBPocketCamCapture(struct GBMemory* memory) {
if (!memory->cam) {
return;
}
const void* image = NULL;
size_t stride;
enum mColorFormat format;
memory->cam->requestImage(memory->cam, &image, &stride, &format);
if (!image) {
return;
}
memset(&memory->sram[0x100], 0, GBCAM_HEIGHT * GBCAM_WIDTH / 4);
struct GBPocketCamState* pocketCam = &memory->mbcState.pocketCam;
size_t x, y;
for (y = 0; y < GBCAM_HEIGHT; ++y) {
for (x = 0; x < GBCAM_WIDTH; ++x) {
uint32_t gray;
uint32_t color;
switch (format) {
case mCOLOR_XBGR8:
case mCOLOR_XRGB8:
case mCOLOR_ARGB8:
case mCOLOR_ABGR8:
color = ((const uint32_t*) image)[y * stride + x];
gray = (color & 0xFF) + ((color >> 8) & 0xFF) + ((color >> 16) & 0xFF);
break;
case mCOLOR_BGRX8:
case mCOLOR_RGBX8:
case mCOLOR_RGBA8:
case mCOLOR_BGRA8:
color = ((const uint32_t*) image)[y * stride + x];
gray = ((color >> 8) & 0xFF) + ((color >> 16) & 0xFF) + ((color >> 24) & 0xFF);
break;
case mCOLOR_BGR5:
case mCOLOR_RGB5:
case mCOLOR_ARGB5:
case mCOLOR_ABGR5:
color = ((const uint16_t*) image)[y * stride + x];
gray = ((color << 3) & 0xF8) + ((color >> 2) & 0xF8) + ((color >> 7) & 0xF8);
break;
case mCOLOR_BGR565:
case mCOLOR_RGB565:
color = ((const uint16_t*) image)[y * stride + x];
gray = ((color << 3) & 0xF8) + ((color >> 3) & 0xFC) + ((color >> 8) & 0xF8);
break;
case mCOLOR_BGRA5:
case mCOLOR_RGBA5:
color = ((const uint16_t*) image)[y * stride + x];
gray = ((color << 2) & 0xF8) + ((color >> 3) & 0xF8) + ((color >> 8) & 0xF8);
break;
default:
mLOG(GB_MBC, WARN, "Unsupported pixel format: %X", format);
return;
}
uint16_t exposure = (pocketCam->registers[2] << 8) | (pocketCam->registers[3]);
gray = (gray + 1) * exposure / 0x300;
// TODO: Additional processing
int matrixEntry = 3 * ((x & 3) + 4 * (y & 3));
if (gray < pocketCam->registers[matrixEntry + 6]) {
gray = 0x101;
} else if (gray < pocketCam->registers[matrixEntry + 7]) {
gray = 0x100;
} else if (gray < pocketCam->registers[matrixEntry + 8]) {
gray = 0x001;
} else {
gray = 0;
}
int coord = (((x >> 3) & 0xF) * 8 + (y & 0x7)) * 2 + (y & ~0x7) * 0x20;
uint16_t existing;
LOAD_16LE(existing, coord + 0x100, memory->sram);
existing |= gray << (7 - (x & 7));
STORE_16LE(existing, coord + 0x100, memory->sram);
}
}
}

433
src/gb/mbc/tama5.c Normal file
View File

@ -0,0 +1,433 @@
/* Copyright (c) 2013-2016 Jeffrey Pfau
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "gb/mbc/mbc-private.h"
#include <mgba/internal/defines.h>
#include <mgba/internal/gb/gb.h>
#include <mgba-util/vfs.h>
static const uint8_t _tama6RTCMask[32] = {
//0 1 2 3 4 5 6 7 8 9 A B C D E F
0xF, 0x7, 0xF, 0x7, 0xF, 0x3, 0x7, 0xF, 0x3, 0xF, 0x1, 0xF, 0xF, 0x0, 0x0, 0x0,
0x0, 0x0, 0xF, 0x7, 0xF, 0x3, 0x7, 0xF, 0x3, 0x0, 0x1, 0x3, 0x0, 0x0, 0x0, 0x0,
};
static const int _daysToMonth[] = {
[ 1] = 0,
[ 2] = 31,
[ 3] = 31 + 28,
[ 4] = 31 + 28 + 31,
[ 5] = 31 + 28 + 31 + 30,
[ 6] = 31 + 28 + 31 + 30 + 31,
[ 7] = 31 + 28 + 31 + 30 + 31 + 30,
[ 8] = 31 + 28 + 31 + 30 + 31 + 30 + 31,
[ 9] = 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31,
[10] = 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30,
[11] = 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31,
[12] = 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30,
};
static int _tama6DMYToDayOfYear(int day, int month, int year) {
if (month < 1 || month > 12) {
return -1;
}
day += _daysToMonth[month];
if (month > 2 && (year & 3) == 0) {
++day;
}
return day;
}
static int _tama6DayOfYearToMonth(int day, int year) {
int month;
for (month = 1; month < 12; ++month) {
if (day <= _daysToMonth[month + 1]) {
return month;
}
if (month == 2 && (year & 3) == 0) {
if (day == 60) {
return 2;
}
--day;
}
}
return 12;
}
static int _tama6DayOfYearToDayOfMonth(int day, int year) {
int month;
for (month = 1; month < 12; ++month) {
if (day <= _daysToMonth[month + 1]) {
return day - _daysToMonth[month];
}
if (month == 2 && (year & 3) == 0) {
if (day == 60) {
return 29;
}
--day;
}
}
return day - _daysToMonth[12];
}
static void _latchTAMA6Rtc(struct mRTCSource* rtc, struct GBTAMA5State* tama5, time_t* rtcLastLatch) {
time_t t;
if (rtc) {
if (rtc->sample) {
rtc->sample(rtc);
}
t = rtc->unixTime(rtc);
} else {
t = time(0);
}
time_t currentLatch = t;
t -= *rtcLastLatch;
*rtcLastLatch = currentLatch;
if (!t || tama5->disabled) {
return;
}
uint8_t* timerRegs = tama5->rtcTimerPage;
bool is24hour = tama5->rtcAlarmPage[GBTAMA6_RTC_PA1_24_HOUR];
int64_t diff;
diff = timerRegs[GBTAMA6_RTC_PA0_SECOND_1] + timerRegs[GBTAMA6_RTC_PA0_SECOND_10] * 10 + t % 60;
if (diff < 0) {
diff += 60;
t -= 60;
}
timerRegs[GBTAMA6_RTC_PA0_SECOND_1] = diff % 10;
timerRegs[GBTAMA6_RTC_PA0_SECOND_10] = (diff % 60) / 10;
t /= 60;
t += diff / 60;
diff = timerRegs[GBTAMA6_RTC_PA0_MINUTE_1] + timerRegs[GBTAMA6_RTC_PA0_MINUTE_10] * 10 + t % 60;
if (diff < 0) {
diff += 60;
t -= 60;
}
timerRegs[GBTAMA6_RTC_PA0_MINUTE_1] = diff % 10;
timerRegs[GBTAMA6_RTC_PA0_MINUTE_10] = (diff % 60) / 10;
t /= 60;
t += diff / 60;
diff = timerRegs[GBTAMA6_RTC_PA0_HOUR_1];
if (is24hour) {
diff += timerRegs[GBTAMA6_RTC_PA0_HOUR_10] * 10;
} else {
int hour10 = timerRegs[GBTAMA6_RTC_PA0_HOUR_10];
diff += (hour10 & 1) * 10;
diff += (hour10 & 2) * 12;
}
diff += t % 24;
if (diff < 0) {
diff += 24;
t -= 24;
}
if (is24hour) {
timerRegs[GBTAMA6_RTC_PA0_HOUR_1] = (diff % 24) % 10;
timerRegs[GBTAMA6_RTC_PA0_HOUR_10] = (diff % 24) / 10;
} else {
timerRegs[GBTAMA6_RTC_PA0_HOUR_1] = (diff % 12) % 10;
timerRegs[GBTAMA6_RTC_PA0_HOUR_10] = (diff % 12) / 10 + (diff / 12) * 2;
}
t /= 24;
t += diff / 24;
int day = timerRegs[GBTAMA6_RTC_PA0_DAY_1] + timerRegs[GBTAMA6_RTC_PA0_DAY_10] * 10;
int month = timerRegs[GBTAMA6_RTC_PA0_MONTH_1] + timerRegs[GBTAMA6_RTC_PA0_MONTH_10] * 10;
int year = timerRegs[GBTAMA6_RTC_PA0_YEAR_1] + timerRegs[GBTAMA6_RTC_PA0_YEAR_10] * 10;
int leapYear = tama5->rtcAlarmPage[GBTAMA6_RTC_PA1_LEAP_YEAR];
int dayOfWeek = timerRegs[GBTAMA6_RTC_PA0_WEEK];
int dayInYear = _tama6DMYToDayOfYear(day, month, leapYear);
diff = dayInYear + t;
while (diff <= 0) {
// Previous year
if (leapYear & 3) {
diff += 365;
} else {
diff += 366;
}
--year;
--leapYear;
}
while (diff > (leapYear & 3 ? 365 : 366)) {
// Future year
if (year % 4) {
diff -= 365;
} else {
diff -= 366;
}
++year;
++leapYear;
}
dayOfWeek = (dayOfWeek + diff) % 7;
year %= 100;
leapYear &= 3;
day = _tama6DayOfYearToDayOfMonth(diff, leapYear);
month = _tama6DayOfYearToMonth(diff, leapYear);
timerRegs[GBTAMA6_RTC_PA0_WEEK] = dayOfWeek;
tama5->rtcAlarmPage[GBTAMA6_RTC_PA1_LEAP_YEAR] = leapYear;
timerRegs[GBTAMA6_RTC_PA0_DAY_1] = day % 10;
timerRegs[GBTAMA6_RTC_PA0_DAY_10] = day / 10;
timerRegs[GBTAMA6_RTC_PA0_MONTH_1] = month % 10;
timerRegs[GBTAMA6_RTC_PA0_MONTH_10] = month / 10;
timerRegs[GBTAMA6_RTC_PA0_YEAR_1] = year % 10;
timerRegs[GBTAMA6_RTC_PA0_YEAR_10] = year / 10;
}
void _GBTAMA5(struct GB* gb, uint16_t address, uint8_t value) {
struct GBMemory* memory = &gb->memory;
struct GBTAMA5State* tama5 = &memory->mbcState.tama5;
switch (address >> 13) {
case 0x5:
if (address & 1) {
tama5->reg = value;
} else {
value &= 0xF;
if (tama5->reg < GBTAMA5_MAX) {
mLOG(GB_MBC, DEBUG, "TAMA5 write: %02X:%X", tama5->reg, value);
tama5->registers[tama5->reg] = value;
uint8_t address = ((tama5->registers[GBTAMA5_ADDR_HI] << 4) & 0x10) | tama5->registers[GBTAMA5_ADDR_LO];
uint8_t out = (tama5->registers[GBTAMA5_WRITE_HI] << 4) | tama5->registers[GBTAMA5_WRITE_LO];
switch (tama5->reg) {
case GBTAMA5_BANK_LO:
case GBTAMA5_BANK_HI:
GBMBCSwitchBank(gb, tama5->registers[GBTAMA5_BANK_LO] | (tama5->registers[GBTAMA5_BANK_HI] << 4));
break;
case GBTAMA5_WRITE_LO:
case GBTAMA5_WRITE_HI:
case GBTAMA5_ADDR_HI:
break;
case GBTAMA5_ADDR_LO:
switch (tama5->registers[GBTAMA5_ADDR_HI] >> 1) {
case 0x0: // RAM write
memory->sram[address] = out;
gb->sramDirty |= mSAVEDATA_DIRT_NEW;
break;
case 0x1: // RAM read
break;
case 0x2: // Other commands
switch (address) {
case GBTAMA6_DISABLE_TIMER:
tama5->disabled = true;
tama5->rtcTimerPage[GBTAMA6_RTC_PAGE] &= 0x7;
tama5->rtcAlarmPage[GBTAMA6_RTC_PAGE] &= 0x7;
tama5->rtcFreePage0[GBTAMA6_RTC_PAGE] &= 0x7;
tama5->rtcFreePage1[GBTAMA6_RTC_PAGE] &= 0x7;
break;
case GBTAMA6_ENABLE_TIMER:
tama5->disabled = false;
tama5->rtcTimerPage[GBTAMA6_RTC_PA0_SECOND_1] = 0;
tama5->rtcTimerPage[GBTAMA6_RTC_PA0_SECOND_10] = 0;
tama5->rtcTimerPage[GBTAMA6_RTC_PAGE] |= 0x8;
tama5->rtcAlarmPage[GBTAMA6_RTC_PAGE] |= 0x8;
tama5->rtcFreePage0[GBTAMA6_RTC_PAGE] |= 0x8;
tama5->rtcFreePage1[GBTAMA6_RTC_PAGE] |= 0x8;
break;
case GBTAMA6_MINUTE_WRITE:
tama5->rtcTimerPage[GBTAMA6_RTC_PA0_MINUTE_1] = out & 0xF;
tama5->rtcTimerPage[GBTAMA6_RTC_PA0_MINUTE_10] = out >> 4;
break;
case GBTAMA6_HOUR_WRITE:
tama5->rtcTimerPage[GBTAMA6_RTC_PA0_HOUR_1] = out & 0xF;
tama5->rtcTimerPage[GBTAMA6_RTC_PA0_HOUR_10] = out >> 4;
break;
case GBTAMA6_DISABLE_ALARM:
tama5->rtcTimerPage[GBTAMA6_RTC_PAGE] &= 0xB;
tama5->rtcAlarmPage[GBTAMA6_RTC_PAGE] &= 0xB;
tama5->rtcFreePage0[GBTAMA6_RTC_PAGE] &= 0xB;
tama5->rtcFreePage1[GBTAMA6_RTC_PAGE] &= 0xB;
break;
case GBTAMA6_ENABLE_ALARM:
tama5->rtcTimerPage[GBTAMA6_RTC_PAGE] |= 0x4;
tama5->rtcAlarmPage[GBTAMA6_RTC_PAGE] |= 0x4;
tama5->rtcFreePage0[GBTAMA6_RTC_PAGE] |= 0x4;
tama5->rtcFreePage1[GBTAMA6_RTC_PAGE] |= 0x4;
break;
}
break;
case 0x4: // RTC access
address = tama5->registers[GBTAMA5_WRITE_LO];
if (address >= GBTAMA6_RTC_PAGE) {
break;
}
out = tama5->registers[GBTAMA5_WRITE_HI];
switch (tama5->registers[GBTAMA5_ADDR_LO]) {
case 0:
out &= _tama6RTCMask[address];
tama5->rtcTimerPage[address] = out;
break;
case 2:
out &= _tama6RTCMask[address | 0x10];
tama5->rtcAlarmPage[address] = out;
break;
case 4:
tama5->rtcFreePage0[address] = out;
break;
case 6:
tama5->rtcFreePage1[address] = out;
break;
}
break;
default:
mLOG(GB_MBC, STUB, "TAMA5 unknown address: %02X:%02X", address, out);
break;
}
break;
default:
mLOG(GB_MBC, STUB, "TAMA5 unknown write: %02X:%X", tama5->reg, value);
break;
}
} else {
mLOG(GB_MBC, STUB, "TAMA5 unknown write: %02X", tama5->reg);
}
}
break;
default:
mLOG(GB_MBC, STUB, "TAMA5 unknown address: %04X:%02X", address, value);
}
}
uint8_t _GBTAMA5Read(struct GBMemory* memory, uint16_t address) {
struct GBTAMA5State* tama5 = &memory->mbcState.tama5;
if ((address & 0x1FFF) > 1) {
mLOG(GB_MBC, STUB, "TAMA5 unknown address: %04X", address);
}
if (address & 1) {
return 0xFF;
} else {
uint8_t value = 0xF0;
uint8_t address = ((tama5->registers[GBTAMA5_ADDR_HI] << 4) & 0x10) | tama5->registers[GBTAMA5_ADDR_LO];
switch (tama5->reg) {
case GBTAMA5_ACTIVE:
return 0xF1;
case GBTAMA5_READ_LO:
case GBTAMA5_READ_HI:
switch (tama5->registers[GBTAMA5_ADDR_HI] >> 1) {
case 0x1:
value = memory->sram[address];
break;
case 0x2:
mLOG(GB_MBC, STUB, "TAMA5 unknown read %s: %02X", tama5->reg == GBTAMA5_READ_HI ? "hi" : "lo", address);
_latchTAMA6Rtc(memory->rtc, tama5, &memory->rtcLastLatch);
switch (address) {
case GBTAMA6_MINUTE_READ:
value = (tama5->rtcTimerPage[GBTAMA6_RTC_PA0_MINUTE_10] << 4) | tama5->rtcTimerPage[GBTAMA6_RTC_PA0_MINUTE_1];
break;
case GBTAMA6_HOUR_READ:
value = (tama5->rtcTimerPage[GBTAMA6_RTC_PA0_HOUR_10] << 4) | tama5->rtcTimerPage[GBTAMA6_RTC_PA0_HOUR_1];
break;
default:
value = address;
break;
}
break;
case 0x4:
if (tama5->reg == GBTAMA5_READ_HI) {
mLOG(GB_MBC, GAME_ERROR, "TAMA5 reading RTC incorrectly");
break;
}
_latchTAMA6Rtc(memory->rtc, tama5, &memory->rtcLastLatch);
address = tama5->registers[GBTAMA5_WRITE_LO];
if (address > GBTAMA6_RTC_PAGE) {
value = 0;
break;
}
switch (tama5->registers[GBTAMA5_ADDR_LO]) {
case 1:
value = tama5->rtcTimerPage[address];
break;
case 3:
value = tama5->rtcTimerPage[address];
break;
case 5:
value = tama5->rtcTimerPage[address];
break;
case 7:
value = tama5->rtcTimerPage[address];
break;
}
break;
default:
mLOG(GB_MBC, STUB, "TAMA5 unknown read %s: %02X", tama5->reg == GBTAMA5_READ_HI ? "hi" : "lo", address);
break;
}
if (tama5->reg == GBTAMA5_READ_HI) {
value >>= 4;
}
value |= 0xF0;
return value;
default:
mLOG(GB_MBC, STUB, "TAMA5 unknown read: %02X", tama5->reg);
return 0xF1;
}
}
}
void GBMBCTAMA5Read(struct GB* gb) {
struct GBMBCTAMA5SaveBuffer buffer;
struct VFile* vf = gb->sramVf;
if (!vf) {
return;
}
vf->seek(vf, gb->sramSize, SEEK_SET);
if (vf->read(vf, &buffer, sizeof(buffer)) < (ssize_t) sizeof(buffer)) {
gb->memory.mbcState.tama5.disabled = false;
return;
}
size_t i;
for (i = 0; i < 0x8; ++i) {
gb->memory.mbcState.tama5.rtcTimerPage[i * 2] = buffer.rtcTimerPage[i] & 0xF;
gb->memory.mbcState.tama5.rtcTimerPage[i * 2 + 1] = buffer.rtcTimerPage[i] >> 4;
gb->memory.mbcState.tama5.rtcAlarmPage[i * 2] = buffer.rtcAlarmPage[i] & 0xF;
gb->memory.mbcState.tama5.rtcAlarmPage[i * 2 + 1] = buffer.rtcAlarmPage[i] >> 4;
gb->memory.mbcState.tama5.rtcFreePage0[i * 2] = buffer.rtcFreePage0[i] & 0xF;
gb->memory.mbcState.tama5.rtcFreePage0[i * 2 + 1] = buffer.rtcFreePage0[i] >> 4;
gb->memory.mbcState.tama5.rtcFreePage1[i * 2] = buffer.rtcFreePage1[i] & 0xF;
gb->memory.mbcState.tama5.rtcFreePage1[i * 2 + 1] = buffer.rtcFreePage1[i] >> 4;
}
LOAD_64LE(gb->memory.rtcLastLatch, 0, &buffer.latchedUnix);
gb->memory.mbcState.tama5.disabled = !(gb->memory.mbcState.tama5.rtcTimerPage[GBTAMA6_RTC_PAGE] & 0x8);
gb->memory.mbcState.tama5.rtcTimerPage[GBTAMA6_RTC_PAGE] &= 0xC;
gb->memory.mbcState.tama5.rtcAlarmPage[GBTAMA6_RTC_PAGE] &= 0xC;
gb->memory.mbcState.tama5.rtcAlarmPage[GBTAMA6_RTC_PAGE] |= 1;
gb->memory.mbcState.tama5.rtcFreePage0[GBTAMA6_RTC_PAGE] &= 0xC;
gb->memory.mbcState.tama5.rtcFreePage0[GBTAMA6_RTC_PAGE] |= 2;
gb->memory.mbcState.tama5.rtcFreePage1[GBTAMA6_RTC_PAGE] &= 0xC;
gb->memory.mbcState.tama5.rtcFreePage1[GBTAMA6_RTC_PAGE] |= 3;
}
void GBMBCTAMA5Write(struct GB* gb) {
struct VFile* vf = gb->sramVf;
if (!vf) {
return;
}
struct GBMBCTAMA5SaveBuffer buffer = {0};
size_t i;
for (i = 0; i < 8; ++i) {
buffer.rtcTimerPage[i] = gb->memory.mbcState.tama5.rtcTimerPage[i * 2] & 0xF;
buffer.rtcTimerPage[i] |= gb->memory.mbcState.tama5.rtcTimerPage[i * 2 + 1] << 4;
buffer.rtcAlarmPage[i] = gb->memory.mbcState.tama5.rtcAlarmPage[i * 2] & 0xF;
buffer.rtcAlarmPage[i] |= gb->memory.mbcState.tama5.rtcAlarmPage[i * 2 + 1] << 4;
buffer.rtcFreePage0[i] = gb->memory.mbcState.tama5.rtcFreePage0[i * 2] & 0xF;
buffer.rtcFreePage0[i] |= gb->memory.mbcState.tama5.rtcFreePage0[i * 2 + 1] << 4;
buffer.rtcFreePage1[i] = gb->memory.mbcState.tama5.rtcFreePage1[i * 2] & 0xF;
buffer.rtcFreePage1[i] |= gb->memory.mbcState.tama5.rtcFreePage1[i * 2 + 1] << 4;
}
STORE_64LE(gb->memory.rtcLastLatch, 0, &buffer.latchedUnix);
_GBMBCAppendSaveSuffix(gb, &buffer, sizeof(buffer));
}

500
src/gb/mbc/unlicensed.c Normal file
View File

@ -0,0 +1,500 @@
/* Copyright (c) 2013-2016 Jeffrey Pfau
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "gb/mbc/mbc-private.h"
#include <mgba/internal/gb/gb.h>
void _GBWisdomTree(struct GB* gb, uint16_t address, uint8_t value) {
UNUSED(value);
int bank = address & 0x3F;
switch (address >> 14) {
case 0x0:
GBMBCSwitchBank0(gb, bank * 2);
GBMBCSwitchBank(gb, bank * 2 + 1);
break;
default:
// TODO
mLOG(GB_MBC, STUB, "Wisdom Tree unknown address: %04X:%02X", address, value);
break;
}
}
void _GBPKJD(struct GB* gb, uint16_t address, uint8_t value) {
struct GBMemory* memory = &gb->memory;
switch (address >> 13) {
case 0x2:
if (value < 8) {
memory->directSramAccess = true;
memory->activeRtcReg = 0;
} else if (value >= 0xD && value <= 0xF) {
memory->directSramAccess = false;
memory->rtcAccess = false;
memory->activeRtcReg = value - 8;
}
break;
case 0x5:
if (!memory->sramAccess) {
return;
}
switch (memory->activeRtcReg) {
case 0:
memory->sramBank[address & (GB_SIZE_EXTERNAL_RAM - 1)] = value;
break;
case 5:
case 6:
memory->mbcState.pkjd.reg[memory->activeRtcReg - 5] = value;
break;
case 7:
switch (value) {
case 0x11:
memory->mbcState.pkjd.reg[0]--;
break;
case 0x12:
memory->mbcState.pkjd.reg[1]--;
break;
case 0x41:
memory->mbcState.pkjd.reg[0] += memory->mbcState.pkjd.reg[1];
break;
case 0x42:
memory->mbcState.pkjd.reg[1] += memory->mbcState.pkjd.reg[0];
break;
case 0x51:
memory->mbcState.pkjd.reg[0]++;
break;
case 0x52:
memory->mbcState.pkjd.reg[1]--;
break;
}
break;
}
return;
}
_GBMBC3(gb, address, value);
}
uint8_t _GBPKJDRead(struct GBMemory* memory, uint16_t address) {
if (!memory->sramAccess) {
return 0xFF;
}
switch (memory->activeRtcReg) {
case 0:
return memory->sramBank[address & (GB_SIZE_EXTERNAL_RAM - 1)];
case 5:
case 6:
return memory->mbcState.pkjd.reg[memory->activeRtcReg - 5];
default:
return 0;
}
}
static uint8_t _reorderBits(uint8_t input, const uint8_t* reorder) {
uint8_t newbyte = 0;
int i;
for(i = 0; i < 8; ++i) {
int oldbit = reorder[i];
int newbit = i;
newbyte += ((input >> oldbit) & 1) << newbit;
}
return newbyte;
}
static const uint8_t _ntOld1Reorder[8] = {
0, 2, 1, 4, 3, 5, 6, 7
};
void _ntOldMulticart(struct GB* gb, uint16_t address, uint8_t value, const uint8_t reorder[8]) {
struct GBMemory* memory = &gb->memory;
struct GBNTOldState* mbcState = &memory->mbcState.ntOld;
int bank = value;
switch (address & 3) {
case 0:
mLOG(GB_MBC, STUB, "Unimplemented NT Old 1 address 0");
break;
case 1:
value &= 0x3F;
mbcState->baseBank = value * 2;
if (mbcState->baseBank) {
GBMBCSwitchBank0(gb, mbcState->baseBank);
GBMBCSwitchBank(gb, mbcState->baseBank + 1);
}
break;
case 2:
if ((value & 0xF0) == 0xE0) {
gb->sramSize = 0x2000;
GBResizeSram(gb, gb->sramSize);
}
switch (value & 0xF) {
case 0x00:
mbcState->bankCount = 32;
break;
case 0x08:
mbcState->bankCount = 16;
break;
case 0xC:
mbcState->bankCount = 8;
break;
case 0xE:
mbcState->bankCount = 4;
break;
case 0xF:
mbcState->bankCount = 2;
break;
default:
mbcState->bankCount = 32;
break;
}
break;
case 3:
mbcState->swapped = !!(value & 0x10);
bank = memory->currentBank;
if (mbcState->swapped) {
bank = _reorderBits(bank, reorder);
}
GBMBCSwitchBank(gb, bank);
break;
}
}
void _GBNTOld1(struct GB* gb, uint16_t address, uint8_t value) {
struct GBMemory* memory = &gb->memory;
struct GBNTOldState* mbcState = &memory->mbcState.ntOld;
int bank = value;
switch (address >> 12) {
case 0x0:
case 0x1:
_GBMBC3(gb, address, value);
break;
case 0x2:
case 0x3:
bank &= 0x1F;
if (!bank) {
bank = 1;
}
if (mbcState->swapped) {
bank = _reorderBits(bank, _ntOld1Reorder);
}
if (mbcState->bankCount) {
bank &= mbcState->bankCount - 1;
}
GBMBCSwitchBank(gb, bank + mbcState->baseBank);
break;
case 0x5:
_ntOldMulticart(gb, address, value, _ntOld1Reorder);
break;
}
}
static const uint8_t _ntOld2Reorder[8] = {
1, 2, 0, 3, 4, 5, 6, 7
};
void _GBNTOld2(struct GB* gb, uint16_t address, uint8_t value) {
struct GBMemory* memory = &gb->memory;
struct GBNTOldState* mbcState = &memory->mbcState.ntOld;
int bank = value;
switch (address >> 12) {
case 0x0:
case 0x1:
_GBMBC3(gb, address, value);
break;
case 0x2:
case 0x3:
if (!bank) {
bank = 1;
}
if (mbcState->swapped) {
bank = _reorderBits(bank, _ntOld2Reorder);
}
if (mbcState->bankCount) {
bank &= mbcState->bankCount - 1;
}
GBMBCSwitchBank(gb, bank + mbcState->baseBank);
break;
case 0x5:
_ntOldMulticart(gb, address, value, _ntOld2Reorder);
// Fall through
case 0x4:
if (address == 0x5001) {
mbcState->rumble = !!(value & 0x80);
}
if (mbcState->rumble) {
memory->rumble->setRumble(memory->rumble, !!(mbcState->swapped ? value & 0x08 : value & 0x02));
}
break;
}
}
void _GBNTNew(struct GB* gb, uint16_t address, uint8_t value) {
struct GBMemory* memory = &gb->memory;
if (address >> 8 == 0x14) {
memory->mbcState.ntNew.splitMode = true;
return;
}
if (memory->mbcState.ntNew.splitMode) {
int bank = value;
if (bank < 2) {
bank = 2;
}
switch (address >> 10) {
case 8:
GBMBCSwitchHalfBank(gb, 0, bank);
return;
case 9:
GBMBCSwitchHalfBank(gb, 1, bank);
return;
}
}
_GBMBC5(gb, address, value);
}
static const uint8_t _bbdDataReordering[8][8] = {
{ 0, 1, 2, 3, 4, 5, 6, 7 }, // 00 - Normal
{ 0, 1, 2, 3, 4, 5, 6, 7 }, // 01 - NOT KNOWN YET
{ 0, 1, 2, 3, 4, 5, 6, 7 }, // 02 - NOT KNOWN YET
{ 0, 1, 2, 3, 4, 5, 6, 7 }, // 03 - NOT KNOWN YET
{ 0, 5, 1, 3, 4, 2, 6, 7 }, // 04 - Garou
{ 0, 4, 2, 3, 1, 5, 6, 7 }, // 05 - Harry
{ 0, 1, 2, 3, 4, 5, 6, 7 }, // 06 - NOT KNOWN YET
{ 0, 1, 5, 3, 4, 2, 6, 7 }, // 07 - Digimon
};
static const uint8_t _bbdBankReordering[8][8] = {
{ 0, 1, 2, 3, 4, 5, 6, 7 }, // 00 - Normal
{ 0, 1, 2, 3, 4, 5, 6, 7 }, // 01 - NOT KNOWN YET
{ 0, 1, 2, 3, 4, 5, 6, 7 }, // 02 - NOT KNOWN YET
{ 3, 4, 2, 0, 1, 5, 6, 7 }, // 03 - 0,1 unconfirmed. Digimon/Garou
{ 0, 1, 2, 3, 4, 5, 6, 7 }, // 04 - NOT KNOWN YET
{ 1, 2, 3, 4, 0, 5, 6, 7 }, // 05 - 0,1 unconfirmed. Harry
{ 0, 1, 2, 3, 4, 5, 6, 7 }, // 06 - NOT KNOWN YET
{ 0, 1, 2, 3, 4, 5, 6, 7 }, // 07 - NOT KNOWN YET
};
void _GBBBD(struct GB* gb, uint16_t address, uint8_t value) {
struct GBMemory* memory = &gb->memory;
switch (address & 0xF0FF) {
case 0x2000:
value = _reorderBits(value, _bbdBankReordering[memory->mbcState.bbd.bankSwapMode]);
break;
case 0x2001:
memory->mbcState.bbd.dataSwapMode = value & 0x07;
if (!(memory->mbcState.bbd.dataSwapMode == 0x07 || memory->mbcState.bbd.dataSwapMode == 0x05 || memory->mbcState.bbd.dataSwapMode == 0x04 || memory->mbcState.bbd.dataSwapMode == 0x00)) {
mLOG(GB_MBC, STUB, "Bitswap mode unsupported: %X", memory->mbcState.bbd.dataSwapMode);
}
break;
case 0x2080:
memory->mbcState.bbd.bankSwapMode = value & 0x07;
if (!(memory->mbcState.bbd.bankSwapMode == 0x03 || memory->mbcState.bbd.bankSwapMode == 0x05 || memory->mbcState.bbd.bankSwapMode == 0x00)) {
mLOG(GB_MBC, STUB, "Bankswap mode unsupported: %X", memory->mbcState.bbd.dataSwapMode);
}
break;
}
_GBMBC5(gb, address, value);
}
uint8_t _GBBBDRead(struct GBMemory* memory, uint16_t address) {
switch (address >> 14) {
case 0:
default:
return memory->romBank[address & (GB_SIZE_CART_BANK0 - 1)];
case 1:
return _reorderBits(memory->romBank[address & (GB_SIZE_CART_BANK0 - 1)], _bbdDataReordering[memory->mbcState.bbd.dataSwapMode]);
}
}
static const uint8_t _hitekDataReordering[8][8] = {
{ 0, 1, 2, 3, 4, 5, 6, 7 },
{ 0, 6, 5, 3, 4, 1, 2, 7 },
{ 0, 5, 6, 3, 4, 2, 1, 7 },
{ 0, 6, 2, 3, 4, 5, 1, 7 },
{ 0, 6, 1, 3, 4, 5, 2, 7 },
{ 0, 1, 6, 3, 4, 5, 2, 7 },
{ 0, 2, 6, 3, 4, 1, 5, 7 },
{ 0, 6, 2, 3, 4, 1, 5, 7 },
};
static const uint8_t _hitekBankReordering[8][8] = {
{ 0, 1, 2, 3, 4, 5, 6, 7 },
{ 3, 2, 1, 0, 4, 5, 6, 7 },
{ 2, 1, 0, 3, 4, 5, 6, 7 },
{ 1, 0, 3, 2, 4, 5, 6, 7 },
{ 0, 3, 2, 1, 4, 5, 6, 7 },
{ 2, 3, 0, 1, 4, 5, 6, 7 },
{ 3, 0, 1, 2, 4, 5, 6, 7 },
{ 2, 0, 3, 1, 4, 5, 6, 7 },
};
void _GBHitek(struct GB* gb, uint16_t address, uint8_t value) {
struct GBMemory* memory = &gb->memory;
switch (address & 0xF0FF) {
case 0x2000:
value = _reorderBits(value, _hitekBankReordering[memory->mbcState.bbd.bankSwapMode]);
break;
case 0x2001:
memory->mbcState.bbd.dataSwapMode = value & 0x07;
break;
case 0x2080:
memory->mbcState.bbd.bankSwapMode = value & 0x07;
break;
case 0x300:
// See hhugboy src/memory/mbc/MbcUnlHitek.cpp for commentary on this return
return;
}
_GBMBC5(gb, address, value);
}
uint8_t _GBHitekRead(struct GBMemory* memory, uint16_t address) {
switch (address >> 14) {
case 0:
default:
return memory->romBank[address & (GB_SIZE_CART_BANK0 - 1)];
case 1:
return _reorderBits(memory->romBank[address & (GB_SIZE_CART_BANK0 - 1)], _hitekDataReordering[memory->mbcState.bbd.dataSwapMode]);
}
}
static const uint8_t _ggb81DataReordering[8][8] = {
{ 0, 1, 2, 3, 4, 5, 6, 7 },
{ 0, 2, 1, 3, 4, 6, 5, 7 },
{ 0, 6, 5, 3, 4, 2, 1, 7 },
{ 0, 5, 1, 3, 4, 2, 6, 7 },
{ 0, 5, 2, 3, 4, 1, 6, 7 },
{ 0, 2, 6, 3, 4, 5, 1, 7 },
{ 0, 1, 6, 3, 4, 2, 5, 7 },
{ 0, 2, 5, 3, 4, 6, 1, 7 },
};
void _GBGGB81(struct GB* gb, uint16_t address, uint8_t value) {
struct GBMemory* memory = &gb->memory;
switch (address & 0xF0FF) {
case 0x2001:
memory->mbcState.bbd.dataSwapMode = value & 0x07;
break;
}
_GBMBC5(gb, address, value);
}
uint8_t _GBGGB81Read(struct GBMemory* memory, uint16_t address) {
switch (address >> 14) {
case 0:
default:
return memory->romBank[address & (GB_SIZE_CART_BANK0 - 1)];
case 1:
return _reorderBits(memory->romBank[address & (GB_SIZE_CART_BANK0 - 1)], _ggb81DataReordering[memory->mbcState.bbd.dataSwapMode]);
}
}
void _GBLiCheng(struct GB* gb, uint16_t address, uint8_t value) {
if (address > 0x2100 && address < 0x3000) {
return;
}
_GBMBC5(gb, address, value);
}
void _GBSachen(struct GB* gb, uint16_t address, uint8_t value) {
struct GBSachenState* state = &gb->memory.mbcState.sachen;
uint8_t bank = value;
switch (address >> 13) {
case 0:
if ((state->unmaskedBank & 0x30) == 0x30) {
state->baseBank = bank;
GBMBCSwitchBank0(gb, state->baseBank & state->mask);
}
break;
case 1:
if (!bank) {
bank = 1;
}
state->unmaskedBank = bank;
bank = (bank & ~state->mask) | (state->baseBank & state->mask);
GBMBCSwitchBank(gb, bank);
break;
case 2:
if ((state->unmaskedBank & 0x30) == 0x30) {
state->mask = value;
bank = (state->unmaskedBank & ~state->mask) | (state->baseBank & state->mask);
GBMBCSwitchBank(gb, bank);
GBMBCSwitchBank0(gb, state->baseBank & state->mask);
}
break;
case 6:
if (gb->memory.mbcType == GB_UNL_SACHEN_MMC2 && state->locked == GB_SACHEN_LOCKED_DMG) {
state->locked = GB_SACHEN_LOCKED_CGB;
state->transition = 0;
}
break;
}
}
static uint16_t _unscrambleSachen(uint16_t address) {
uint16_t unscrambled = address & 0xFFAC;
unscrambled |= (address & 0x40) >> 6;
unscrambled |= (address & 0x10) >> 3;
unscrambled |= (address & 0x02) << 3;
unscrambled |= (address & 0x01) << 6;
return unscrambled;
}
uint8_t _GBSachenMMC1Read(struct GBMemory* memory, uint16_t address) {
struct GBSachenState* state = &memory->mbcState.sachen;
if (state->locked != GB_SACHEN_UNLOCKED && (address & 0xFF00) == 0x100) {
++state->transition;
if (state->transition == 0x31) {
state->locked = GB_SACHEN_UNLOCKED;
} else {
address |= 0x80;
}
}
if ((address & 0xFF00) == 0x0100) {
address = _unscrambleSachen(address);
}
if (address < GB_BASE_CART_BANK1) {
return memory->romBase[address];
} else if (address < GB_BASE_VRAM) {
return memory->romBank[address & (GB_SIZE_CART_BANK0 - 1)];
} else {
return 0xFF;
}
}
uint8_t _GBSachenMMC2Read(struct GBMemory* memory, uint16_t address) {
struct GBSachenState* state = &memory->mbcState.sachen;
if (address >= 0xC000 && state->locked == GB_SACHEN_LOCKED_DMG) {
state->transition = 0;
state->locked = GB_SACHEN_LOCKED_CGB;
}
if (state->locked != GB_SACHEN_UNLOCKED && (address & 0x8700) == 0x0100) {
++state->transition;
if (state->transition == 0x31) {
++state->locked;
state->transition = 0;
}
}
if ((address & 0xFF00) == 0x0100) {
if (state->locked == GB_SACHEN_LOCKED_CGB) {
address |= 0x80;
}
address = _unscrambleSachen(address);
}
if (address < GB_BASE_CART_BANK1) {
return memory->romBase[address];
} else if (address < GB_BASE_VRAM) {
return memory->romBank[address & (GB_SIZE_CART_BANK0 - 1)];
} else {
return 0xFF;
}
}

View File

@ -558,7 +558,7 @@ uint8_t GBMemoryWriteHDMA5(struct GB* gb, uint8_t value) {
gb->memory.hdmaDest |= 0x8000;
bool wasHdma = gb->memory.isHdma;
gb->memory.isHdma = value & 0x80;
if ((!wasHdma && !gb->memory.isHdma) || (GBRegisterLCDCIsEnable(gb->memory.io[GB_REG_LCDC]) && gb->video.mode == 0)) {
if ((!wasHdma && !gb->memory.isHdma) || gb->video.mode == 0) {
if (gb->memory.isHdma) {
gb->memory.hdmaRemaining = 0x10;
} else {
@ -566,8 +566,6 @@ uint8_t GBMemoryWriteHDMA5(struct GB* gb, uint8_t value) {
}
gb->cpuBlocked = true;
mTimingSchedule(&gb->timing, &gb->memory.hdmaEvent, 0);
} else if (gb->memory.isHdma && !GBRegisterLCDCIsEnable(gb->memory.io[GB_REG_LCDC])) {
return 0x80 | ((value + 1) & 0x7F);
}
return value & 0x7F;
}
@ -755,6 +753,12 @@ void GBMemorySerialize(const struct GB* gb, struct GBSerializedState* state) {
case GB_MBC3_RTC:
STORE_64LE(memory->rtcLastLatch, 0, &state->memory.rtc.lastLatch);
break;
case GB_MBC6:
state->memory.mbc6.flags = GBSerializedMBC6FlagsSetFlashBank0(0, memory->mbcState.mbc6.flashBank0);
state->memory.mbc6.flags = GBSerializedMBC6FlagsSetFlashBank1(state->memory.mbc6.flags, memory->mbcState.mbc6.flashBank1);
state->memory.mbc6.bank1 = memory->currentBank1;
state->memory.mbc6.sramBank1 = memory->currentSramBank1;
break;
case GB_MBC7:
state->memory.mbc7.state = memory->mbcState.mbc7.state;
state->memory.mbc7.eeprom = memory->mbcState.mbc7.eeprom;
@ -797,8 +801,20 @@ void GBMemorySerialize(const struct GB* gb, struct GBSerializedState* state) {
state->memory.mmm01.locked = memory->mbcState.mmm01.locked;
state->memory.mmm01.bank0 = memory->mbcState.mmm01.currentBank0;
break;
case GB_UNL_NT_OLD_1:
case GB_UNL_NT_OLD_2:
state->memory.ntOld.flags = GBSerializedNTOldFlagsSetSwapped(0, memory->mbcState.ntOld.swapped);
state->memory.ntOld.flags = GBSerializedNTOldFlagsSetRumble(state->memory.ntOld.flags, memory->mbcState.ntOld.rumble);
state->memory.ntOld.baseBank = memory->mbcState.ntOld.baseBank;
state->memory.ntOld.bankCount = memory->mbcState.ntOld.bankCount;
break;
case GB_UNL_NT_NEW:
state->memory.ntNew.splitMode = memory->mbcState.ntNew.splitMode;
state->memory.ntNew.bank1 = memory->currentBank1;
break;
case GB_UNL_BBD:
case GB_UNL_HITEK:
case GB_UNL_GGB81:
state->memory.bbd.dataSwapMode = memory->mbcState.bbd.dataSwapMode;
state->memory.bbd.bankSwapMode = memory->mbcState.bbd.bankSwapMode;
break;
@ -823,9 +839,11 @@ void GBMemoryDeserialize(struct GB* gb, const struct GBSerializedState* state) {
memory->wramCurrentBank = state->memory.wramCurrentBank;
memory->sramCurrentBank = state->memory.sramCurrentBank;
GBMBCSwitchBank(gb, memory->currentBank);
GBMemorySwitchWramBank(memory, memory->wramCurrentBank);
GBMBCSwitchSramBank(gb, memory->sramCurrentBank);
if (memory->mbcType != GB_MBC6 && memory->mbcType != GB_UNL_NT_NEW) {
GBMBCSwitchBank(gb, memory->currentBank);
GBMBCSwitchSramBank(gb, memory->sramCurrentBank);
}
LOAD_16LE(memory->dmaSource, 0, &state->memory.dmaSource);
LOAD_16LE(memory->dmaDest, 0, &state->memory.dmaDest);
@ -882,6 +900,16 @@ void GBMemoryDeserialize(struct GB* gb, const struct GBSerializedState* state) {
case GB_MBC3_RTC:
LOAD_64LE(memory->rtcLastLatch, 0, &state->memory.rtc.lastLatch);
break;
case GB_MBC6:
memory->mbcState.mbc6.flashBank0 = GBSerializedMBC6FlagsGetFlashBank0(state->memory.mbc6.flags);
memory->mbcState.mbc6.flashBank1 = GBSerializedMBC6FlagsGetFlashBank1(state->memory.mbc6.flags);
memory->currentBank1 = state->memory.mbc6.bank1;
memory->currentSramBank1 = state->memory.mbc6.sramBank1;
GBMBCSwitchHalfBank(gb, 0, memory->currentBank);
GBMBCSwitchHalfBank(gb, 1, memory->currentBank1);
GBMBCSwitchSramHalfBank(gb, 0, memory->sramCurrentBank);
GBMBCSwitchSramHalfBank(gb, 1, memory->currentSramBank1);
break;
case GB_MBC7:
memory->mbcState.mbc7.state = state->memory.mbc7.state;
memory->mbcState.mbc7.eeprom = state->memory.mbc7.eeprom;
@ -929,8 +957,27 @@ void GBMemoryDeserialize(struct GB* gb, const struct GBSerializedState* state) {
GBMBCSwitchBank0(gb, gb->memory.romSize / GB_SIZE_CART_BANK0 - 2);
}
break;
case GB_UNL_NT_OLD_1:
case GB_UNL_NT_OLD_2:
memory->mbcState.ntOld.swapped = GBSerializedNTOldFlagsGetSwapped(state->memory.ntOld.flags);
memory->mbcState.ntOld.rumble = GBSerializedNTOldFlagsGetRumble(state->memory.ntOld.flags);
memory->mbcState.ntOld.baseBank = state->memory.ntOld.baseBank;
memory->mbcState.ntOld.bankCount = state->memory.ntOld.bankCount;
GBMBCSwitchBank0(gb, memory->mbcState.ntOld.baseBank);
break;
case GB_UNL_NT_NEW:
memory->mbcState.ntNew.splitMode = state->memory.ntNew.splitMode;
memory->currentBank1 = state->memory.ntNew.bank1;
if (memory->mbcState.ntNew.splitMode) {
GBMBCSwitchHalfBank(gb, 0, memory->currentBank);
GBMBCSwitchHalfBank(gb, 1, memory->currentBank1);
} else {
GBMBCSwitchBank(gb, memory->currentBank);
}
break;
case GB_UNL_BBD:
case GB_UNL_HITEK:
case GB_UNL_GGB81:
memory->mbcState.bbd.dataSwapMode = state->memory.bbd.dataSwapMode & 0x7;
memory->mbcState.bbd.bankSwapMode = state->memory.bbd.bankSwapMode & 0x7;
break;

View File

@ -672,7 +672,19 @@ static const struct GBCartridgeOverride _overrides[] = {
{ 0x630ED957, GB_MODEL_AUTODETECT, GB_MBC3_RTC, { 0 } }, // Gold (non-debug)
{ 0x5AFF0038, GB_MODEL_AUTODETECT, GB_MBC3_RTC, { 0 } }, // Silver (debug)
{ 0xA61856BD, GB_MODEL_AUTODETECT, GB_MBC3_RTC, { 0 } }, // Silver (non-debug)
// Unlicensed bootlegs
{ 0x30F8F86C, GB_MODEL_AUTODETECT, GB_UNL_PKJD, { 0 } }, // Pokemon Jade Version (Telefang Speed bootleg)
{ 0xE1147E75, GB_MODEL_AUTODETECT, GB_UNL_NT_OLD_1, { 0 } }, // Rockman 8
{ 0xEFF88FAA, GB_MODEL_AUTODETECT, GB_UNL_NT_OLD_1, { 0 } }, // True Color 25 in 1 (NT-9920)
{ 0x811925D9, GB_MODEL_AUTODETECT, GB_UNL_NT_OLD_2, { 0 } }, // 23 in 1 (CR2011)
{ 0x62A8016A, GB_MODEL_AUTODETECT, GB_UNL_NT_OLD_2, { 0 } }, // 29 in 1 (CR2020)
{ 0x5758D6D9, GB_MODEL_AUTODETECT, GB_UNL_NT_OLD_2, { 0 } }, // Caise Gedou 24 in 1 Diannao Huamian Xuan Game (CY2060)
{ 0x62A8016A, GB_MODEL_AUTODETECT, GB_UNL_NT_OLD_2, { 0 } }, // Caise Gedou 29 in 1 Diannao Huamian Xuan Game (CY2061)
{ 0x80265A64, GB_MODEL_AUTODETECT, GB_UNL_NT_OLD_2, { 0 } }, // Rockman X4 (Megaman X4)
{ 0x805459DE, GB_MODEL_AUTODETECT, GB_UNL_NT_OLD_2, { 0 } }, // Sonic Adventure 8
{ 0x0B1B808A, GB_MODEL_AUTODETECT, GB_UNL_NT_OLD_2, { 0 } }, // Super Donkey Kong 5
{ 0x0B1B808A, GB_MODEL_AUTODETECT, GB_UNL_NT_OLD_2, { 0 } }, // Super Donkey Kong 5 (Alt)
{ 0x4650EB9A, GB_MODEL_AUTODETECT, GB_UNL_NT_OLD_2, { 0 } }, // Super Mario Special 3
{ 0xB289D95A, GB_MODEL_AUTODETECT, GB_UNL_NT_NEW, { 0 } }, // Capcom vs SNK - Millennium Fight 2001
{ 0x688D6713, GB_MODEL_AUTODETECT, GB_UNL_NT_NEW, { 0 } }, // Digimon 02 4
{ 0x8931A272, GB_MODEL_AUTODETECT, GB_UNL_NT_NEW, { 0 } }, // Digimon 2
@ -683,6 +695,7 @@ static const struct GBCartridgeOverride _overrides[] = {
{ 0xBC75D7B8, GB_MODEL_AUTODETECT, GB_UNL_NT_NEW, { 0 } }, // Pokemon - Mewtwo Strikes Back
{ 0xFF0B60CC, GB_MODEL_AUTODETECT, GB_UNL_NT_NEW, { 0 } }, // Shuma Baolong 02 4
{ 0x14A992A6, GB_MODEL_AUTODETECT, GB_UNL_NT_NEW, { 0 } }, // /Street Fighter Zero 4
{ 0x3EF5AFB2, GB_MODEL_AUTODETECT, GB_UNL_LI_CHENG, { 0 } }, // Pokemon Jade Version (Telefang Speed bootleg)
{ 0, 0, 0, { 0 } }
};

View File

@ -157,7 +157,7 @@ static int32_t _masterUpdate(struct GBSIOLockstepNode* node) {
}
}
// Tell the other GBs they can continue up to where we were
node->p->d.addCycles(&node->p->d, node->id, node->eventDiff);
node->p->d.addCycles(&node->p->d, 0, node->eventDiff);
#ifndef NDEBUG
node->phase = node->p->d.transferActive;
#endif
@ -169,26 +169,28 @@ static int32_t _masterUpdate(struct GBSIOLockstepNode* node) {
static uint32_t _slaveUpdate(struct GBSIOLockstepNode* node) {
enum mLockstepPhase transferActive;
int id;
ATOMIC_LOAD(transferActive, node->p->d.transferActive);
ATOMIC_LOAD(id, node->id);
bool signal = false;
switch (transferActive) {
case TRANSFER_IDLE:
node->p->d.addCycles(&node->p->d, node->id, LOCKSTEP_INCREMENT);
node->p->d.addCycles(&node->p->d, id, LOCKSTEP_INCREMENT);
break;
case TRANSFER_STARTING:
case TRANSFER_FINISHING:
break;
case TRANSFER_STARTED:
if (node->p->d.unusedCycles(&node->p->d, node->id) > node->eventDiff) {
if (node->p->d.unusedCycles(&node->p->d, id) > node->eventDiff) {
break;
}
node->transferFinished = false;
signal = true;
break;
case TRANSFER_FINISHED:
if (node->p->d.unusedCycles(&node->p->d, node->id) > node->eventDiff) {
if (node->p->d.unusedCycles(&node->p->d, id) > node->eventDiff) {
break;
}
_finishTransfer(node);
@ -199,7 +201,7 @@ static uint32_t _slaveUpdate(struct GBSIOLockstepNode* node) {
node->phase = node->p->d.transferActive;
#endif
if (signal) {
node->p->d.signal(&node->p->d, 1 << node->id);
node->p->d.signal(&node->p->d, 1 << id);
}
return 0;
}
@ -215,11 +217,13 @@ static void _GBSIOLockstepNodeProcessEvents(struct mTiming* timing, void* user,
int32_t cycles = 0;
node->nextEvent -= cyclesLate;
if (node->nextEvent <= 0) {
if (!node->id) {
int id;
ATOMIC_LOAD(id, node->id);
if (!id) {
cycles = _masterUpdate(node);
} else {
cycles = _slaveUpdate(node);
cycles += node->p->d.useCycles(&node->p->d, node->id, node->eventDiff);
cycles += node->p->d.useCycles(&node->p->d, id, node->eventDiff);
}
node->eventDiff = 0;
} else {
@ -240,7 +244,9 @@ static void _GBSIOLockstepNodeProcessEvents(struct mTiming* timing, void* user,
static void GBSIOLockstepNodeWriteSB(struct GBSIODriver* driver, uint8_t value) {
struct GBSIOLockstepNode* node = (struct GBSIOLockstepNode*) driver;
node->p->pendingSB[node->id] = value;
int id;
ATOMIC_LOAD(id, node->id);
node->p->pendingSB[id] = value;
}
static uint8_t GBSIOLockstepNodeWriteSC(struct GBSIODriver* driver, uint8_t value) {
@ -252,11 +258,17 @@ static uint8_t GBSIOLockstepNodeWriteSC(struct GBSIODriver* driver, uint8_t valu
mLockstepLock(&node->p->d);
bool claimed = false;
if (ATOMIC_CMPXCHG(node->p->masterClaimed, claimed, true)) {
if (node->id != 0) {
int id;
ATOMIC_LOAD(id, node->id);
if (id != 0) {
unsigned sb;
node->p->players[0]->id = 1;
node->p->players[1] = node->p->players[0];
node->p->players[0] = node->p->players[1];
node->id = 0;
node->p->players[1] = node->p->players[0];
node->p->players[0] = node;
sb = node->p->pendingSB[0];
node->p->pendingSB[0] = node->p->pendingSB[1];
node->p->pendingSB[1] = sb;
}
ATOMIC_STORE(node->p->d.transferActive, TRANSFER_STARTING);
ATOMIC_STORE(node->p->d.transferCycles, GBSIOCyclesPerTransfer[(value >> 1) & 1]);

View File

@ -118,10 +118,10 @@ void GBAAudioScheduleFifoDma(struct GBAAudio* audio, int number, struct GBADMA*
info->reg = GBADMARegisterSetDestControl(info->reg, GBA_DMA_FIXED);
info->reg = GBADMARegisterSetWidth(info->reg, 1);
switch (info->dest) {
case BASE_IO | REG_FIFO_A_LO:
case GBA_BASE_IO | REG_FIFO_A_LO:
audio->chA.dmaSource = number;
break;
case BASE_IO | REG_FIFO_B_LO:
case GBA_BASE_IO | REG_FIFO_B_LO:
audio->chB.dmaSource = number;
break;
default:

View File

@ -49,11 +49,11 @@ static void _SoftReset(struct GBA* gba) {
cpu->gprs[ARM_LR] = 0;
cpu->gprs[ARM_SP] = GBA_SP_BASE_SYSTEM;
int8_t flag = ((int8_t*) gba->memory.iwram)[0x7FFA];
memset(((int8_t*) gba->memory.iwram) + SIZE_WORKING_IRAM - 0x200, 0, 0x200);
memset(((int8_t*) gba->memory.iwram) + GBA_SIZE_IWRAM - 0x200, 0, 0x200);
if (flag) {
cpu->gprs[ARM_PC] = BASE_WORKING_RAM;
cpu->gprs[ARM_PC] = GBA_BASE_EWRAM;
} else {
cpu->gprs[ARM_PC] = BASE_CART0;
cpu->gprs[ARM_PC] = GBA_BASE_ROM0;
}
_ARMSetMode(cpu, MODE_ARM);
ARMWritePC(cpu);
@ -62,120 +62,120 @@ static void _SoftReset(struct GBA* gba) {
static void _RegisterRamReset(struct GBA* gba) {
uint32_t registers = gba->cpu->gprs[0];
struct ARMCore* cpu = gba->cpu;
cpu->memory.store16(cpu, BASE_IO | REG_DISPCNT, 0x0080, 0);
cpu->memory.store16(cpu, GBA_BASE_IO | REG_DISPCNT, 0x0080, 0);
if (registers & 0x01) {
memset(gba->memory.wram, 0, SIZE_WORKING_RAM);
memset(gba->memory.wram, 0, GBA_SIZE_EWRAM);
}
if (registers & 0x02) {
memset(gba->memory.iwram, 0, SIZE_WORKING_IRAM - 0x200);
memset(gba->memory.iwram, 0, GBA_SIZE_IWRAM - 0x200);
}
if (registers & 0x04) {
memset(gba->video.palette, 0, SIZE_PALETTE_RAM);
memset(gba->video.palette, 0, GBA_SIZE_PALETTE_RAM);
}
if (registers & 0x08) {
memset(gba->video.vram, 0, SIZE_VRAM);
memset(gba->video.vram, 0, GBA_SIZE_VRAM);
}
if (registers & 0x10) {
memset(gba->video.oam.raw, 0, SIZE_OAM);
memset(gba->video.oam.raw, 0, GBA_SIZE_OAM);
}
if (registers & 0x20) {
cpu->memory.store16(cpu, BASE_IO | REG_SIOCNT, 0x0000, 0);
cpu->memory.store16(cpu, BASE_IO | REG_RCNT, RCNT_INITIAL, 0);
cpu->memory.store16(cpu, BASE_IO | REG_SIOMLT_SEND, 0, 0);
cpu->memory.store16(cpu, BASE_IO | REG_JOYCNT, 0, 0);
cpu->memory.store32(cpu, BASE_IO | REG_JOY_RECV_LO, 0, 0);
cpu->memory.store32(cpu, BASE_IO | REG_JOY_TRANS_LO, 0, 0);
cpu->memory.store16(cpu, GBA_BASE_IO | REG_SIOCNT, 0x0000, 0);
cpu->memory.store16(cpu, GBA_BASE_IO | REG_RCNT, RCNT_INITIAL, 0);
cpu->memory.store16(cpu, GBA_BASE_IO | REG_SIOMLT_SEND, 0, 0);
cpu->memory.store16(cpu, GBA_BASE_IO | REG_JOYCNT, 0, 0);
cpu->memory.store32(cpu, GBA_BASE_IO | REG_JOY_RECV_LO, 0, 0);
cpu->memory.store32(cpu, GBA_BASE_IO | REG_JOY_TRANS_LO, 0, 0);
}
if (registers & 0x40) {
cpu->memory.store16(cpu, BASE_IO | REG_SOUND1CNT_LO, 0, 0);
cpu->memory.store16(cpu, BASE_IO | REG_SOUND1CNT_HI, 0, 0);
cpu->memory.store16(cpu, BASE_IO | REG_SOUND1CNT_X, 0, 0);
cpu->memory.store16(cpu, BASE_IO | REG_SOUND2CNT_LO, 0, 0);
cpu->memory.store16(cpu, BASE_IO | REG_SOUND2CNT_HI, 0, 0);
cpu->memory.store16(cpu, BASE_IO | REG_SOUND3CNT_LO, 0, 0);
cpu->memory.store16(cpu, BASE_IO | REG_SOUND3CNT_HI, 0, 0);
cpu->memory.store16(cpu, BASE_IO | REG_SOUND3CNT_X, 0, 0);
cpu->memory.store16(cpu, BASE_IO | REG_SOUND4CNT_LO, 0, 0);
cpu->memory.store16(cpu, BASE_IO | REG_SOUND4CNT_HI, 0, 0);
cpu->memory.store16(cpu, BASE_IO | REG_SOUNDCNT_LO, 0, 0);
cpu->memory.store16(cpu, BASE_IO | REG_SOUNDCNT_HI, 0, 0);
cpu->memory.store16(cpu, BASE_IO | REG_SOUNDCNT_X, 0, 0);
cpu->memory.store16(cpu, BASE_IO | REG_SOUNDBIAS, 0x200, 0);
cpu->memory.store16(cpu, GBA_BASE_IO | REG_SOUND1CNT_LO, 0, 0);
cpu->memory.store16(cpu, GBA_BASE_IO | REG_SOUND1CNT_HI, 0, 0);
cpu->memory.store16(cpu, GBA_BASE_IO | REG_SOUND1CNT_X, 0, 0);
cpu->memory.store16(cpu, GBA_BASE_IO | REG_SOUND2CNT_LO, 0, 0);
cpu->memory.store16(cpu, GBA_BASE_IO | REG_SOUND2CNT_HI, 0, 0);
cpu->memory.store16(cpu, GBA_BASE_IO | REG_SOUND3CNT_LO, 0, 0);
cpu->memory.store16(cpu, GBA_BASE_IO | REG_SOUND3CNT_HI, 0, 0);
cpu->memory.store16(cpu, GBA_BASE_IO | REG_SOUND3CNT_X, 0, 0);
cpu->memory.store16(cpu, GBA_BASE_IO | REG_SOUND4CNT_LO, 0, 0);
cpu->memory.store16(cpu, GBA_BASE_IO | REG_SOUND4CNT_HI, 0, 0);
cpu->memory.store16(cpu, GBA_BASE_IO | REG_SOUNDCNT_LO, 0, 0);
cpu->memory.store16(cpu, GBA_BASE_IO | REG_SOUNDCNT_HI, 0, 0);
cpu->memory.store16(cpu, GBA_BASE_IO | REG_SOUNDCNT_X, 0, 0);
cpu->memory.store16(cpu, GBA_BASE_IO | REG_SOUNDBIAS, 0x200, 0);
memset(gba->audio.psg.ch3.wavedata32, 0, sizeof(gba->audio.psg.ch3.wavedata32));
}
if (registers & 0x80) {
cpu->memory.store16(cpu, BASE_IO | REG_DISPSTAT, 0, 0);
cpu->memory.store16(cpu, BASE_IO | REG_VCOUNT, 0, 0);
cpu->memory.store16(cpu, BASE_IO | REG_BG0CNT, 0, 0);
cpu->memory.store16(cpu, BASE_IO | REG_BG1CNT, 0, 0);
cpu->memory.store16(cpu, BASE_IO | REG_BG2CNT, 0, 0);
cpu->memory.store16(cpu, BASE_IO | REG_BG3CNT, 0, 0);
cpu->memory.store16(cpu, BASE_IO | REG_BG0HOFS, 0, 0);
cpu->memory.store16(cpu, BASE_IO | REG_BG0VOFS, 0, 0);
cpu->memory.store16(cpu, BASE_IO | REG_BG1HOFS, 0, 0);
cpu->memory.store16(cpu, BASE_IO | REG_BG1VOFS, 0, 0);
cpu->memory.store16(cpu, BASE_IO | REG_BG2HOFS, 0, 0);
cpu->memory.store16(cpu, BASE_IO | REG_BG2VOFS, 0, 0);
cpu->memory.store16(cpu, BASE_IO | REG_BG3HOFS, 0, 0);
cpu->memory.store16(cpu, BASE_IO | REG_BG3VOFS, 0, 0);
cpu->memory.store16(cpu, BASE_IO | REG_BG2PA, 0x100, 0);
cpu->memory.store16(cpu, BASE_IO | REG_BG2PB, 0, 0);
cpu->memory.store16(cpu, BASE_IO | REG_BG2PC, 0, 0);
cpu->memory.store16(cpu, BASE_IO | REG_BG2PD, 0x100, 0);
cpu->memory.store32(cpu, BASE_IO | REG_BG2X_LO, 0, 0);
cpu->memory.store32(cpu, BASE_IO | REG_BG2Y_LO, 0, 0);
cpu->memory.store16(cpu, BASE_IO | REG_BG3PA, 0x100, 0);
cpu->memory.store16(cpu, BASE_IO | REG_BG3PB, 0, 0);
cpu->memory.store16(cpu, BASE_IO | REG_BG3PC, 0, 0);
cpu->memory.store16(cpu, BASE_IO | REG_BG3PD, 0x100, 0);
cpu->memory.store32(cpu, BASE_IO | REG_BG3X_LO, 0, 0);
cpu->memory.store32(cpu, BASE_IO | REG_BG3Y_LO, 0, 0);
cpu->memory.store16(cpu, BASE_IO | REG_WIN0H, 0, 0);
cpu->memory.store16(cpu, BASE_IO | REG_WIN1H, 0, 0);
cpu->memory.store16(cpu, BASE_IO | REG_WIN0V, 0, 0);
cpu->memory.store16(cpu, BASE_IO | REG_WIN1V, 0, 0);
cpu->memory.store16(cpu, BASE_IO | REG_WININ, 0, 0);
cpu->memory.store16(cpu, BASE_IO | REG_WINOUT, 0, 0);
cpu->memory.store16(cpu, BASE_IO | REG_MOSAIC, 0, 0);
cpu->memory.store16(cpu, BASE_IO | REG_BLDCNT, 0, 0);
cpu->memory.store16(cpu, BASE_IO | REG_BLDALPHA, 0, 0);
cpu->memory.store16(cpu, BASE_IO | REG_BLDY, 0, 0);
cpu->memory.store16(cpu, BASE_IO | REG_DMA0SAD_LO, 0, 0);
cpu->memory.store16(cpu, BASE_IO | REG_DMA0SAD_HI, 0, 0);
cpu->memory.store16(cpu, BASE_IO | REG_DMA0DAD_LO, 0, 0);
cpu->memory.store16(cpu, BASE_IO | REG_DMA0DAD_HI, 0, 0);
cpu->memory.store16(cpu, BASE_IO | REG_DMA0CNT_LO, 0, 0);
cpu->memory.store16(cpu, BASE_IO | REG_DMA0CNT_HI, 0, 0);
cpu->memory.store16(cpu, BASE_IO | REG_DMA1SAD_LO, 0, 0);
cpu->memory.store16(cpu, BASE_IO | REG_DMA1SAD_HI, 0, 0);
cpu->memory.store16(cpu, BASE_IO | REG_DMA1DAD_LO, 0, 0);
cpu->memory.store16(cpu, BASE_IO | REG_DMA1DAD_HI, 0, 0);
cpu->memory.store16(cpu, BASE_IO | REG_DMA1CNT_LO, 0, 0);
cpu->memory.store16(cpu, BASE_IO | REG_DMA1CNT_HI, 0, 0);
cpu->memory.store16(cpu, BASE_IO | REG_DMA2SAD_LO, 0, 0);
cpu->memory.store16(cpu, BASE_IO | REG_DMA2SAD_HI, 0, 0);
cpu->memory.store16(cpu, BASE_IO | REG_DMA2DAD_LO, 0, 0);
cpu->memory.store16(cpu, BASE_IO | REG_DMA2DAD_HI, 0, 0);
cpu->memory.store16(cpu, BASE_IO | REG_DMA2CNT_LO, 0, 0);
cpu->memory.store16(cpu, BASE_IO | REG_DMA2CNT_HI, 0, 0);
cpu->memory.store16(cpu, BASE_IO | REG_DMA3SAD_LO, 0, 0);
cpu->memory.store16(cpu, BASE_IO | REG_DMA3SAD_HI, 0, 0);
cpu->memory.store16(cpu, BASE_IO | REG_DMA3DAD_LO, 0, 0);
cpu->memory.store16(cpu, BASE_IO | REG_DMA3DAD_HI, 0, 0);
cpu->memory.store16(cpu, BASE_IO | REG_DMA3CNT_LO, 0, 0);
cpu->memory.store16(cpu, BASE_IO | REG_DMA3CNT_HI, 0, 0);
cpu->memory.store16(cpu, BASE_IO | REG_TM0CNT_LO, 0, 0);
cpu->memory.store16(cpu, BASE_IO | REG_TM0CNT_HI, 0, 0);
cpu->memory.store16(cpu, BASE_IO | REG_TM1CNT_LO, 0, 0);
cpu->memory.store16(cpu, BASE_IO | REG_TM1CNT_HI, 0, 0);
cpu->memory.store16(cpu, BASE_IO | REG_TM2CNT_LO, 0, 0);
cpu->memory.store16(cpu, BASE_IO | REG_TM2CNT_HI, 0, 0);
cpu->memory.store16(cpu, BASE_IO | REG_TM3CNT_LO, 0, 0);
cpu->memory.store16(cpu, BASE_IO | REG_TM3CNT_HI, 0, 0);
cpu->memory.store16(cpu, BASE_IO | REG_IE, 0, 0);
cpu->memory.store16(cpu, BASE_IO | REG_IF, 0xFFFF, 0);
cpu->memory.store16(cpu, BASE_IO | REG_WAITCNT, 0, 0);
cpu->memory.store16(cpu, BASE_IO | REG_IME, 0, 0);
cpu->memory.store16(cpu, GBA_BASE_IO | REG_DISPSTAT, 0, 0);
cpu->memory.store16(cpu, GBA_BASE_IO | REG_VCOUNT, 0, 0);
cpu->memory.store16(cpu, GBA_BASE_IO | REG_BG0CNT, 0, 0);
cpu->memory.store16(cpu, GBA_BASE_IO | REG_BG1CNT, 0, 0);
cpu->memory.store16(cpu, GBA_BASE_IO | REG_BG2CNT, 0, 0);
cpu->memory.store16(cpu, GBA_BASE_IO | REG_BG3CNT, 0, 0);
cpu->memory.store16(cpu, GBA_BASE_IO | REG_BG0HOFS, 0, 0);
cpu->memory.store16(cpu, GBA_BASE_IO | REG_BG0VOFS, 0, 0);
cpu->memory.store16(cpu, GBA_BASE_IO | REG_BG1HOFS, 0, 0);
cpu->memory.store16(cpu, GBA_BASE_IO | REG_BG1VOFS, 0, 0);
cpu->memory.store16(cpu, GBA_BASE_IO | REG_BG2HOFS, 0, 0);
cpu->memory.store16(cpu, GBA_BASE_IO | REG_BG2VOFS, 0, 0);
cpu->memory.store16(cpu, GBA_BASE_IO | REG_BG3HOFS, 0, 0);
cpu->memory.store16(cpu, GBA_BASE_IO | REG_BG3VOFS, 0, 0);
cpu->memory.store16(cpu, GBA_BASE_IO | REG_BG2PA, 0x100, 0);
cpu->memory.store16(cpu, GBA_BASE_IO | REG_BG2PB, 0, 0);
cpu->memory.store16(cpu, GBA_BASE_IO | REG_BG2PC, 0, 0);
cpu->memory.store16(cpu, GBA_BASE_IO | REG_BG2PD, 0x100, 0);
cpu->memory.store32(cpu, GBA_BASE_IO | REG_BG2X_LO, 0, 0);
cpu->memory.store32(cpu, GBA_BASE_IO | REG_BG2Y_LO, 0, 0);
cpu->memory.store16(cpu, GBA_BASE_IO | REG_BG3PA, 0x100, 0);
cpu->memory.store16(cpu, GBA_BASE_IO | REG_BG3PB, 0, 0);
cpu->memory.store16(cpu, GBA_BASE_IO | REG_BG3PC, 0, 0);
cpu->memory.store16(cpu, GBA_BASE_IO | REG_BG3PD, 0x100, 0);
cpu->memory.store32(cpu, GBA_BASE_IO | REG_BG3X_LO, 0, 0);
cpu->memory.store32(cpu, GBA_BASE_IO | REG_BG3Y_LO, 0, 0);
cpu->memory.store16(cpu, GBA_BASE_IO | REG_WIN0H, 0, 0);
cpu->memory.store16(cpu, GBA_BASE_IO | REG_WIN1H, 0, 0);
cpu->memory.store16(cpu, GBA_BASE_IO | REG_WIN0V, 0, 0);
cpu->memory.store16(cpu, GBA_BASE_IO | REG_WIN1V, 0, 0);
cpu->memory.store16(cpu, GBA_BASE_IO | REG_WININ, 0, 0);
cpu->memory.store16(cpu, GBA_BASE_IO | REG_WINOUT, 0, 0);
cpu->memory.store16(cpu, GBA_BASE_IO | REG_MOSAIC, 0, 0);
cpu->memory.store16(cpu, GBA_BASE_IO | REG_BLDCNT, 0, 0);
cpu->memory.store16(cpu, GBA_BASE_IO | REG_BLDALPHA, 0, 0);
cpu->memory.store16(cpu, GBA_BASE_IO | REG_BLDY, 0, 0);
cpu->memory.store16(cpu, GBA_BASE_IO | REG_DMA0SAD_LO, 0, 0);
cpu->memory.store16(cpu, GBA_BASE_IO | REG_DMA0SAD_HI, 0, 0);
cpu->memory.store16(cpu, GBA_BASE_IO | REG_DMA0DAD_LO, 0, 0);
cpu->memory.store16(cpu, GBA_BASE_IO | REG_DMA0DAD_HI, 0, 0);
cpu->memory.store16(cpu, GBA_BASE_IO | REG_DMA0CNT_LO, 0, 0);
cpu->memory.store16(cpu, GBA_BASE_IO | REG_DMA0CNT_HI, 0, 0);
cpu->memory.store16(cpu, GBA_BASE_IO | REG_DMA1SAD_LO, 0, 0);
cpu->memory.store16(cpu, GBA_BASE_IO | REG_DMA1SAD_HI, 0, 0);
cpu->memory.store16(cpu, GBA_BASE_IO | REG_DMA1DAD_LO, 0, 0);
cpu->memory.store16(cpu, GBA_BASE_IO | REG_DMA1DAD_HI, 0, 0);
cpu->memory.store16(cpu, GBA_BASE_IO | REG_DMA1CNT_LO, 0, 0);
cpu->memory.store16(cpu, GBA_BASE_IO | REG_DMA1CNT_HI, 0, 0);
cpu->memory.store16(cpu, GBA_BASE_IO | REG_DMA2SAD_LO, 0, 0);
cpu->memory.store16(cpu, GBA_BASE_IO | REG_DMA2SAD_HI, 0, 0);
cpu->memory.store16(cpu, GBA_BASE_IO | REG_DMA2DAD_LO, 0, 0);
cpu->memory.store16(cpu, GBA_BASE_IO | REG_DMA2DAD_HI, 0, 0);
cpu->memory.store16(cpu, GBA_BASE_IO | REG_DMA2CNT_LO, 0, 0);
cpu->memory.store16(cpu, GBA_BASE_IO | REG_DMA2CNT_HI, 0, 0);
cpu->memory.store16(cpu, GBA_BASE_IO | REG_DMA3SAD_LO, 0, 0);
cpu->memory.store16(cpu, GBA_BASE_IO | REG_DMA3SAD_HI, 0, 0);
cpu->memory.store16(cpu, GBA_BASE_IO | REG_DMA3DAD_LO, 0, 0);
cpu->memory.store16(cpu, GBA_BASE_IO | REG_DMA3DAD_HI, 0, 0);
cpu->memory.store16(cpu, GBA_BASE_IO | REG_DMA3CNT_LO, 0, 0);
cpu->memory.store16(cpu, GBA_BASE_IO | REG_DMA3CNT_HI, 0, 0);
cpu->memory.store16(cpu, GBA_BASE_IO | REG_TM0CNT_LO, 0, 0);
cpu->memory.store16(cpu, GBA_BASE_IO | REG_TM0CNT_HI, 0, 0);
cpu->memory.store16(cpu, GBA_BASE_IO | REG_TM1CNT_LO, 0, 0);
cpu->memory.store16(cpu, GBA_BASE_IO | REG_TM1CNT_HI, 0, 0);
cpu->memory.store16(cpu, GBA_BASE_IO | REG_TM2CNT_LO, 0, 0);
cpu->memory.store16(cpu, GBA_BASE_IO | REG_TM2CNT_HI, 0, 0);
cpu->memory.store16(cpu, GBA_BASE_IO | REG_TM3CNT_LO, 0, 0);
cpu->memory.store16(cpu, GBA_BASE_IO | REG_TM3CNT_HI, 0, 0);
cpu->memory.store16(cpu, GBA_BASE_IO | REG_IE, 0, 0);
cpu->memory.store16(cpu, GBA_BASE_IO | REG_IF, 0xFFFF, 0);
cpu->memory.store16(cpu, GBA_BASE_IO | REG_WAITCNT, 0, 0);
cpu->memory.store16(cpu, GBA_BASE_IO | REG_IME, 0, 0);
}
if (registers & 0x9C) {
gba->video.renderer->reset(gba->video.renderer);
@ -267,7 +267,7 @@ static void _MidiKey2Freq(struct GBA* gba) {
struct ARMCore* cpu = gba->cpu;
int oldRegion = gba->memory.activeRegion;
gba->memory.activeRegion = REGION_BIOS;
gba->memory.activeRegion = GBA_REGION_BIOS;
uint32_t key = cpu->memory.load32(cpu, cpu->gprs[0] + 4, 0);
gba->memory.activeRegion = oldRegion;
@ -336,12 +336,14 @@ static int16_t _ArcTan(int32_t i, int32_t* r1, int32_t* r3, uint32_t* cycles) {
static int16_t _ArcTan2(int32_t x, int32_t y, int32_t* r1, uint32_t* cycles) {
if (!y) {
*cycles = 11;
if (x >= 0) {
return 0;
}
return 0x8000;
}
if (!x) {
*cycles = 11;
if (y >= 0) {
return 0x4000;
}
@ -484,7 +486,7 @@ void GBASwi16(struct ARMCore* cpu, int immediate) {
break;
case GBA_SWI_CPU_SET:
case GBA_SWI_CPU_FAST_SET:
if (cpu->gprs[0] >> BASE_OFFSET < REGION_WORKING_RAM) {
if (cpu->gprs[0] >> BASE_OFFSET < GBA_REGION_EWRAM) {
mLOG(GBA_BIOS, GAME_ERROR, "Cannot CpuSet from BIOS");
break;
}
@ -499,7 +501,7 @@ void GBASwi16(struct ARMCore* cpu, int immediate) {
case GBA_SWI_GET_BIOS_CHECKSUM:
cpu->gprs[0] = GBA_BIOS_CHECKSUM;
cpu->gprs[1] = 1;
cpu->gprs[3] = SIZE_BIOS;
cpu->gprs[3] = GBA_SIZE_BIOS;
break;
case GBA_SWI_BG_AFFINE_SET:
_BgAffineSet(gba);
@ -508,7 +510,7 @@ void GBASwi16(struct ARMCore* cpu, int immediate) {
_ObjAffineSet(gba);
break;
case GBA_SWI_BIT_UNPACK:
if (cpu->gprs[0] < BASE_WORKING_RAM) {
if (cpu->gprs[0] < GBA_BASE_EWRAM) {
mLOG(GBA_BIOS, GAME_ERROR, "Bad BitUnPack source");
break;
}
@ -516,9 +518,9 @@ void GBASwi16(struct ARMCore* cpu, int immediate) {
default:
mLOG(GBA_BIOS, GAME_ERROR, "Bad BitUnPack destination");
// Fall through
case REGION_WORKING_RAM:
case REGION_WORKING_IRAM:
case REGION_VRAM:
case GBA_REGION_EWRAM:
case GBA_REGION_IWRAM:
case GBA_REGION_VRAM:
_unBitPack(gba);
break;
}
@ -533,9 +535,9 @@ void GBASwi16(struct ARMCore* cpu, int immediate) {
default:
mLOG(GBA_BIOS, GAME_ERROR, "Bad LZ77 destination");
// Fall through
case REGION_WORKING_RAM:
case REGION_WORKING_IRAM:
case REGION_VRAM:
case GBA_REGION_EWRAM:
case GBA_REGION_IWRAM:
case GBA_REGION_VRAM:
useStall = true;
_unLz77(gba, immediate == GBA_SWI_LZ77_UNCOMP_WRAM ? 1 : 2);
break;
@ -550,9 +552,9 @@ void GBASwi16(struct ARMCore* cpu, int immediate) {
default:
mLOG(GBA_BIOS, GAME_ERROR, "Bad Huffman destination");
// Fall through
case REGION_WORKING_RAM:
case REGION_WORKING_IRAM:
case REGION_VRAM:
case GBA_REGION_EWRAM:
case GBA_REGION_IWRAM:
case GBA_REGION_VRAM:
_unHuffman(gba);
break;
}
@ -567,9 +569,9 @@ void GBASwi16(struct ARMCore* cpu, int immediate) {
default:
mLOG(GBA_BIOS, GAME_ERROR, "Bad RL destination");
// Fall through
case REGION_WORKING_RAM:
case REGION_WORKING_IRAM:
case REGION_VRAM:
case GBA_REGION_EWRAM:
case GBA_REGION_IWRAM:
case GBA_REGION_VRAM:
_unRl(gba, immediate == GBA_SWI_RL_UNCOMP_WRAM ? 1 : 2);
break;
}
@ -585,9 +587,9 @@ void GBASwi16(struct ARMCore* cpu, int immediate) {
default:
mLOG(GBA_BIOS, GAME_ERROR, "Bad UnFilter destination");
// Fall through
case REGION_WORKING_RAM:
case REGION_WORKING_IRAM:
case REGION_VRAM:
case GBA_REGION_EWRAM:
case GBA_REGION_IWRAM:
case GBA_REGION_VRAM:
_unFilter(gba, immediate == GBA_SWI_DIFF_16BIT_UNFILTER ? 2 : 1, immediate == GBA_SWI_DIFF_8BIT_UNFILTER_WRAM ? 1 : 2);
break;
}

View File

@ -246,7 +246,7 @@ void GBAVFameSramWrite(struct GBAVFameCart* cart, uint32_t address, uint8_t valu
// if mode has been set - the address and value of the SRAM write will be modified
address = _modifySramAddress(cart->cartType, address, cart->sramMode);
value = _modifySramValue(cart->cartType, value, cart->sramMode);
address &= (SIZE_CART_SRAM - 1);
address &= (GBA_SIZE_SRAM - 1);
sramData[address] = value;
}

View File

@ -105,36 +105,36 @@ static bool GBACheatAddAutodetect(struct GBACheatSet* set, uint32_t op1, uint32_
char line[18] = "XXXXXXXX XXXXXXXX";
snprintf(line, sizeof(line), "%08X %08X", op1, op2);
int gsaP, rgsaP, parP, rparP;
int nextProbability;
int maxProbability = INT_MIN;
switch (set->gsaVersion) {
case 0:
// Try to detect GameShark version
GBACheatDecryptGameShark(&o1, &o2, GBACheatGameSharkSeeds);
gsaP = GBACheatGameSharkProbability(o1, o2);
nextProbability = GBACheatGameSharkProbability(o1, o2);
o1 = op1;
o2 = op2;
if (gsaP > maxProbability) {
maxProbability = gsaP;
if (nextProbability > maxProbability) {
maxProbability = nextProbability;
GBACheatSetGameSharkVersion(set, GBA_GS_GSAV1);
}
GBACheatDecryptGameShark(&o1, &o2, GBACheatProActionReplaySeeds);
parP = GBACheatProActionReplayProbability(o1, o2);
if (parP > maxProbability) {
maxProbability = parP;
nextProbability = GBACheatProActionReplayProbability(o1, o2);
if (nextProbability > maxProbability) {
maxProbability = nextProbability;
GBACheatSetGameSharkVersion(set, GBA_GS_PARV3);
}
rgsaP = GBACheatGameSharkProbability(op1, op1);
if (rgsaP > maxProbability) {
maxProbability = rgsaP;
nextProbability = GBACheatGameSharkProbability(op1, op2);
if (nextProbability > maxProbability) {
maxProbability = nextProbability;
GBACheatSetGameSharkVersion(set, GBA_GS_GSAV1_RAW);
}
rparP = GBACheatProActionReplayProbability(op1, op1);
if (rparP > maxProbability) {
maxProbability = rparP;
nextProbability = GBACheatProActionReplayProbability(op1, op2);
if (nextProbability > maxProbability) {
maxProbability = nextProbability;
GBACheatSetGameSharkVersion(set, GBA_GS_PARV3_RAW);
}
@ -323,49 +323,49 @@ static void GBACheatDumpDirectives(struct mCheatSet* set, struct StringList* dir
int GBACheatAddressIsReal(uint32_t address) {
switch (address >> BASE_OFFSET) {
case REGION_BIOS:
case GBA_REGION_BIOS:
return -0x80;
break;
case REGION_WORKING_RAM:
if ((address & OFFSET_MASK) > SIZE_WORKING_RAM) {
case GBA_REGION_EWRAM:
if ((address & OFFSET_MASK) > GBA_SIZE_EWRAM) {
return -0x40;
}
return 0x20;
case REGION_WORKING_IRAM:
if ((address & OFFSET_MASK) > SIZE_WORKING_IRAM) {
case GBA_REGION_IWRAM:
if ((address & OFFSET_MASK) > GBA_SIZE_IWRAM) {
return -0x40;
}
return 0x20;
case REGION_IO:
if ((address & OFFSET_MASK) > SIZE_IO) {
case GBA_REGION_IO:
if ((address & OFFSET_MASK) > GBA_SIZE_IO) {
return -0x80;
}
return 0x10;
case REGION_OAM:
if ((address & OFFSET_MASK) > SIZE_OAM) {
case GBA_REGION_OAM:
if ((address & OFFSET_MASK) > GBA_SIZE_OAM) {
return -0x80;
}
return -0x8;
case REGION_VRAM:
if ((address & OFFSET_MASK) > SIZE_VRAM) {
case GBA_REGION_VRAM:
if ((address & OFFSET_MASK) > GBA_SIZE_VRAM) {
return -0x80;
}
return -0x8;
case REGION_PALETTE_RAM:
if ((address & OFFSET_MASK) > SIZE_PALETTE_RAM) {
case GBA_REGION_PALETTE_RAM:
if ((address & OFFSET_MASK) > GBA_SIZE_PALETTE_RAM) {
return -0x80;
}
return -0x8;
case REGION_CART0:
case REGION_CART0_EX:
case REGION_CART1:
case REGION_CART1_EX:
case REGION_CART2:
case REGION_CART2_EX:
case GBA_REGION_ROM0:
case GBA_REGION_ROM0_EX:
case GBA_REGION_ROM1:
case GBA_REGION_ROM1_EX:
case GBA_REGION_ROM2:
case GBA_REGION_ROM2_EX:
return -0x8;
case REGION_CART_SRAM:
case REGION_CART_SRAM_MIRROR:
if ((address & OFFSET_MASK) > SIZE_CART_FLASH512) {
case GBA_REGION_SRAM:
case GBA_REGION_SRAM_MIRROR:
if ((address & OFFSET_MASK) > GBA_SIZE_FLASH512) {
return -0x80;
}
return -0x8;

View File

@ -215,7 +215,7 @@ bool GBACheatAddCodeBreaker(struct GBACheatSet* cheats, uint32_t op1, uint16_t o
return false;
}
cheats->hook = malloc(sizeof(*cheats->hook));
cheats->hook->address = BASE_CART0 | (op1 & (SIZE_CART0 - 1));
cheats->hook->address = GBA_BASE_ROM0 | (op1 & (GBA_SIZE_ROM0 - 1));
cheats->hook->mode = MODE_THUMB;
cheats->hook->refs = 1;
cheats->hook->reentries = 0;
@ -278,7 +278,7 @@ bool GBACheatAddCodeBreaker(struct GBACheatSet* cheats, uint32_t op1, uint16_t o
cheat = mCheatListAppend(&cheats->d.list);
cheat->type = CHEAT_IF_NAND;
cheat->width = 2;
cheat->address = BASE_IO | REG_KEYINPUT;
cheat->address = GBA_BASE_IO | REG_KEYINPUT;
cheat->operand = op2;
cheat->repeat = 1;
return true;

View File

@ -150,7 +150,7 @@ bool GBACheatAddGameSharkRaw(struct GBACheatSet* cheats, uint32_t op1, uint32_t
break;
case GSA_PATCH:
romPatch = mCheatPatchListAppend(&cheats->d.romPatches);
romPatch->address = BASE_CART0 | ((op1 & 0xFFFFFF) << 1);
romPatch->address = GBA_BASE_ROM0 | ((op1 & 0xFFFFFF) << 1);
romPatch->value = op2;
romPatch->applied = false;
romPatch->width = 2;
@ -207,7 +207,7 @@ bool GBACheatAddGameSharkRaw(struct GBACheatSet* cheats, uint32_t op1, uint32_t
return false;
}
cheats->hook = malloc(sizeof(*cheats->hook));
cheats->hook->address = BASE_CART0 | (op1 & (SIZE_CART0 - 1));
cheats->hook->address = GBA_BASE_ROM0 | (op1 & (GBA_SIZE_ROM0 - 1));
cheats->hook->mode = MODE_THUMB;
cheats->hook->refs = 1;
cheats->hook->reentries = 0;

View File

@ -233,7 +233,7 @@ static bool _addPAR3Special(struct GBACheatSet* cheats, uint32_t op2) {
}
if (romPatch >= 0) {
struct mCheatPatch* patch = mCheatPatchListAppend(&cheats->d.romPatches);
patch->address = BASE_CART0 | ((op2 & 0xFFFFFF) << 1);
patch->address = GBA_BASE_ROM0 | ((op2 & 0xFFFFFF) << 1);
patch->applied = false;
patch->check = false;
patch->width = 2;
@ -282,7 +282,7 @@ bool GBACheatAddProActionReplayRaw(struct GBACheatSet* cheats, uint32_t op1, uin
return false;
}
cheats->hook = malloc(sizeof(*cheats->hook));
cheats->hook->address = BASE_CART0 | (op1 & (SIZE_CART0 - 2));
cheats->hook->address = GBA_BASE_ROM0 | (op1 & (GBA_SIZE_ROM0 - 2));
cheats->hook->mode = MODE_THUMB;
cheats->hook->refs = 1;
cheats->hook->reentries = 0;
@ -320,7 +320,7 @@ bool GBACheatAddProActionReplayRaw(struct GBACheatSet* cheats, uint32_t op1, uin
case PAR3_BASE_OTHER:
width = ((op1 >> 24) & 1) + 1;
cheat->type = CHEAT_ASSIGN;
cheat->address = BASE_IO | (op1 & OFFSET_MASK);
cheat->address = GBA_BASE_IO | (op1 & OFFSET_MASK);
break;
}
if (op1 & 0x01000000 && (op1 & 0xFE000000) != 0xC6000000) {

View File

@ -57,76 +57,76 @@ static const struct mCoreChannelInfo _GBAAudioChannels[] = {
static const struct mCoreMemoryBlock _GBAMemoryBlocks[] = {
{ -1, "mem", "All", "All", 0, 0x10000000, 0x10000000, mCORE_MEMORY_VIRTUAL },
{ REGION_BIOS, "bios", "BIOS", "BIOS (16kiB)", BASE_BIOS, SIZE_BIOS, SIZE_BIOS, mCORE_MEMORY_READ | mCORE_MEMORY_MAPPED },
{ REGION_WORKING_RAM, "wram", "EWRAM", "Working RAM (256kiB)", BASE_WORKING_RAM, BASE_WORKING_RAM + SIZE_WORKING_RAM, SIZE_WORKING_RAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
{ REGION_WORKING_IRAM, "iwram", "IWRAM", "Internal Working RAM (32kiB)", BASE_WORKING_IRAM, BASE_WORKING_IRAM + SIZE_WORKING_IRAM, SIZE_WORKING_IRAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
{ REGION_IO, "io", "MMIO", "Memory-Mapped I/O", BASE_IO, BASE_IO + SIZE_IO, SIZE_IO, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
{ REGION_PALETTE_RAM, "palette", "Palette", "Palette RAM (1kiB)", BASE_PALETTE_RAM, BASE_PALETTE_RAM + SIZE_PALETTE_RAM, SIZE_PALETTE_RAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
{ REGION_VRAM, "vram", "VRAM", "Video RAM (96kiB)", BASE_VRAM, BASE_VRAM + SIZE_VRAM, SIZE_VRAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
{ REGION_OAM, "oam", "OAM", "OBJ Attribute Memory (1kiB)", BASE_OAM, BASE_OAM + SIZE_OAM, SIZE_OAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
{ REGION_CART0, "cart0", "ROM", "Game Pak (32MiB)", BASE_CART0, BASE_CART0 + SIZE_CART0, SIZE_CART0, mCORE_MEMORY_READ | mCORE_MEMORY_WORM | mCORE_MEMORY_MAPPED },
{ REGION_CART1, "cart1", "ROM WS1", "Game Pak (Waitstate 1)", BASE_CART1, BASE_CART1 + SIZE_CART1, SIZE_CART1, mCORE_MEMORY_READ | mCORE_MEMORY_WORM | mCORE_MEMORY_MAPPED },
{ REGION_CART2, "cart2", "ROM WS2", "Game Pak (Waitstate 2)", BASE_CART2, BASE_CART2 + SIZE_CART2, SIZE_CART2, mCORE_MEMORY_READ | mCORE_MEMORY_WORM | mCORE_MEMORY_MAPPED },
{ GBA_REGION_BIOS, "bios", "BIOS", "BIOS (16kiB)", GBA_BASE_BIOS, GBA_SIZE_BIOS, GBA_SIZE_BIOS, mCORE_MEMORY_READ | mCORE_MEMORY_MAPPED },
{ GBA_REGION_EWRAM, "wram", "EWRAM", "Working RAM (256kiB)", GBA_BASE_EWRAM, GBA_BASE_EWRAM + GBA_SIZE_EWRAM, GBA_SIZE_EWRAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
{ GBA_REGION_IWRAM, "iwram", "IWRAM", "Internal Working RAM (32kiB)", GBA_BASE_IWRAM, GBA_BASE_IWRAM + GBA_SIZE_IWRAM, GBA_SIZE_IWRAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
{ GBA_REGION_IO, "io", "MMIO", "Memory-Mapped I/O", GBA_BASE_IO, GBA_BASE_IO + GBA_SIZE_IO, GBA_SIZE_IO, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
{ GBA_REGION_PALETTE_RAM, "palette", "Palette", "Palette RAM (1kiB)", GBA_BASE_PALETTE_RAM, GBA_BASE_PALETTE_RAM + GBA_SIZE_PALETTE_RAM, GBA_SIZE_PALETTE_RAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
{ GBA_REGION_VRAM, "vram", "VRAM", "Video RAM (96kiB)", GBA_BASE_VRAM, GBA_BASE_VRAM + GBA_SIZE_VRAM, GBA_SIZE_VRAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
{ GBA_REGION_OAM, "oam", "OAM", "OBJ Attribute Memory (1kiB)", GBA_BASE_OAM, GBA_BASE_OAM + GBA_SIZE_OAM, GBA_SIZE_OAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
{ GBA_REGION_ROM0, "cart0", "ROM", "Game Pak (32MiB)", GBA_BASE_ROM0, GBA_BASE_ROM0 + GBA_SIZE_ROM0, GBA_SIZE_ROM0, mCORE_MEMORY_READ | mCORE_MEMORY_WORM | mCORE_MEMORY_MAPPED },
{ GBA_REGION_ROM1, "cart1", "ROM WS1", "Game Pak (Waitstate 1)", GBA_BASE_ROM1, GBA_BASE_ROM1 + GBA_SIZE_ROM1, GBA_SIZE_ROM1, mCORE_MEMORY_READ | mCORE_MEMORY_WORM | mCORE_MEMORY_MAPPED },
{ GBA_REGION_ROM2, "cart2", "ROM WS2", "Game Pak (Waitstate 2)", GBA_BASE_ROM2, GBA_BASE_ROM2 + GBA_SIZE_ROM2, GBA_SIZE_ROM2, mCORE_MEMORY_READ | mCORE_MEMORY_WORM | mCORE_MEMORY_MAPPED },
};
static const struct mCoreMemoryBlock _GBAMemoryBlocksSRAM[] = {
{ -1, "mem", "All", "All", 0, 0x10000000, 0x10000000, mCORE_MEMORY_VIRTUAL },
{ REGION_BIOS, "bios", "BIOS", "BIOS (16kiB)", BASE_BIOS, SIZE_BIOS, SIZE_BIOS, mCORE_MEMORY_READ | mCORE_MEMORY_MAPPED },
{ REGION_WORKING_RAM, "wram", "EWRAM", "Working RAM (256kiB)", BASE_WORKING_RAM, BASE_WORKING_RAM + SIZE_WORKING_RAM, SIZE_WORKING_RAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
{ REGION_WORKING_IRAM, "iwram", "IWRAM", "Internal Working RAM (32kiB)", BASE_WORKING_IRAM, BASE_WORKING_IRAM + SIZE_WORKING_IRAM, SIZE_WORKING_IRAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
{ REGION_IO, "io", "MMIO", "Memory-Mapped I/O", BASE_IO, BASE_IO + SIZE_IO, SIZE_IO, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
{ REGION_PALETTE_RAM, "palette", "Palette", "Palette RAM (1kiB)", BASE_PALETTE_RAM, BASE_PALETTE_RAM + SIZE_PALETTE_RAM, SIZE_PALETTE_RAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
{ REGION_VRAM, "vram", "VRAM", "Video RAM (96kiB)", BASE_VRAM, BASE_VRAM + SIZE_VRAM, SIZE_VRAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
{ REGION_OAM, "oam", "OAM", "OBJ Attribute Memory (1kiB)", BASE_OAM, BASE_OAM + SIZE_OAM, SIZE_OAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
{ REGION_CART0, "cart0", "ROM", "Game Pak (32MiB)", BASE_CART0, BASE_CART0 + SIZE_CART0, SIZE_CART0, mCORE_MEMORY_READ | mCORE_MEMORY_WORM | mCORE_MEMORY_MAPPED },
{ REGION_CART1, "cart1", "ROM WS1", "Game Pak (Waitstate 1)", BASE_CART1, BASE_CART1 + SIZE_CART1, SIZE_CART1, mCORE_MEMORY_READ | mCORE_MEMORY_WORM | mCORE_MEMORY_MAPPED },
{ REGION_CART2, "cart2", "ROM WS2", "Game Pak (Waitstate 2)", BASE_CART2, BASE_CART2 + SIZE_CART2, SIZE_CART2, mCORE_MEMORY_READ | mCORE_MEMORY_WORM | mCORE_MEMORY_MAPPED },
{ REGION_CART_SRAM, "sram", "SRAM", "Static RAM (64kiB)", BASE_CART_SRAM, BASE_CART_SRAM + SIZE_CART_SRAM, SIZE_CART_SRAM, true },
{ GBA_REGION_BIOS, "bios", "BIOS", "BIOS (16kiB)", GBA_BASE_BIOS, GBA_SIZE_BIOS, GBA_SIZE_BIOS, mCORE_MEMORY_READ | mCORE_MEMORY_MAPPED },
{ GBA_REGION_EWRAM, "wram", "EWRAM", "Working RAM (256kiB)", GBA_BASE_EWRAM, GBA_BASE_EWRAM + GBA_SIZE_EWRAM, GBA_SIZE_EWRAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
{ GBA_REGION_IWRAM, "iwram", "IWRAM", "Internal Working RAM (32kiB)", GBA_BASE_IWRAM, GBA_BASE_IWRAM + GBA_SIZE_IWRAM, GBA_SIZE_IWRAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
{ GBA_REGION_IO, "io", "MMIO", "Memory-Mapped I/O", GBA_BASE_IO, GBA_BASE_IO + GBA_SIZE_IO, GBA_SIZE_IO, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
{ GBA_REGION_PALETTE_RAM, "palette", "Palette", "Palette RAM (1kiB)", GBA_BASE_PALETTE_RAM, GBA_BASE_PALETTE_RAM + GBA_SIZE_PALETTE_RAM, GBA_SIZE_PALETTE_RAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
{ GBA_REGION_VRAM, "vram", "VRAM", "Video RAM (96kiB)", GBA_BASE_VRAM, GBA_BASE_VRAM + GBA_SIZE_VRAM, GBA_SIZE_VRAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
{ GBA_REGION_OAM, "oam", "OAM", "OBJ Attribute Memory (1kiB)", GBA_BASE_OAM, GBA_BASE_OAM + GBA_SIZE_OAM, GBA_SIZE_OAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
{ GBA_REGION_ROM0, "cart0", "ROM", "Game Pak (32MiB)", GBA_BASE_ROM0, GBA_BASE_ROM0 + GBA_SIZE_ROM0, GBA_SIZE_ROM0, mCORE_MEMORY_READ | mCORE_MEMORY_WORM | mCORE_MEMORY_MAPPED },
{ GBA_REGION_ROM1, "cart1", "ROM WS1", "Game Pak (Waitstate 1)", GBA_BASE_ROM1, GBA_BASE_ROM1 + GBA_SIZE_ROM1, GBA_SIZE_ROM1, mCORE_MEMORY_READ | mCORE_MEMORY_WORM | mCORE_MEMORY_MAPPED },
{ GBA_REGION_ROM2, "cart2", "ROM WS2", "Game Pak (Waitstate 2)", GBA_BASE_ROM2, GBA_BASE_ROM2 + GBA_SIZE_ROM2, GBA_SIZE_ROM2, mCORE_MEMORY_READ | mCORE_MEMORY_WORM | mCORE_MEMORY_MAPPED },
{ GBA_REGION_SRAM, "sram", "SRAM", "Static RAM (64kiB)", GBA_BASE_SRAM, GBA_BASE_SRAM + GBA_SIZE_SRAM, GBA_SIZE_SRAM, true },
};
static const struct mCoreMemoryBlock _GBAMemoryBlocksFlash512[] = {
{ -1, "mem", "All", "All", 0, 0x10000000, 0x10000000, mCORE_MEMORY_VIRTUAL },
{ REGION_BIOS, "bios", "BIOS", "BIOS (16kiB)", BASE_BIOS, SIZE_BIOS, SIZE_BIOS, mCORE_MEMORY_READ | mCORE_MEMORY_MAPPED },
{ REGION_WORKING_RAM, "wram", "EWRAM", "Working RAM (256kiB)", BASE_WORKING_RAM, BASE_WORKING_RAM + SIZE_WORKING_RAM, SIZE_WORKING_RAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
{ REGION_WORKING_IRAM, "iwram", "IWRAM", "Internal Working RAM (32kiB)", BASE_WORKING_IRAM, BASE_WORKING_IRAM + SIZE_WORKING_IRAM, SIZE_WORKING_IRAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
{ REGION_IO, "io", "MMIO", "Memory-Mapped I/O", BASE_IO, BASE_IO + SIZE_IO, SIZE_IO, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
{ REGION_PALETTE_RAM, "palette", "Palette", "Palette RAM (1kiB)", BASE_PALETTE_RAM, BASE_PALETTE_RAM + SIZE_PALETTE_RAM, SIZE_PALETTE_RAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
{ REGION_VRAM, "vram", "VRAM", "Video RAM (96kiB)", BASE_VRAM, BASE_VRAM + SIZE_VRAM, SIZE_VRAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
{ REGION_OAM, "oam", "OAM", "OBJ Attribute Memory (1kiB)", BASE_OAM, BASE_OAM + SIZE_OAM, SIZE_OAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
{ REGION_CART0, "cart0", "ROM", "Game Pak (32MiB)", BASE_CART0, BASE_CART0 + SIZE_CART0, SIZE_CART0, mCORE_MEMORY_READ | mCORE_MEMORY_WORM | mCORE_MEMORY_MAPPED },
{ REGION_CART1, "cart1", "ROM WS1", "Game Pak (Waitstate 1)", BASE_CART1, BASE_CART1 + SIZE_CART1, SIZE_CART1, mCORE_MEMORY_READ | mCORE_MEMORY_WORM | mCORE_MEMORY_MAPPED },
{ REGION_CART2, "cart2", "ROM WS2", "Game Pak (Waitstate 2)", BASE_CART2, BASE_CART2 + SIZE_CART2, SIZE_CART2, mCORE_MEMORY_READ | mCORE_MEMORY_WORM | mCORE_MEMORY_MAPPED },
{ REGION_CART_SRAM, "sram", "Flash", "Flash Memory (64kiB)", BASE_CART_SRAM, BASE_CART_SRAM + SIZE_CART_FLASH512, SIZE_CART_FLASH512, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
{ GBA_REGION_BIOS, "bios", "BIOS", "BIOS (16kiB)", GBA_BASE_BIOS, GBA_SIZE_BIOS, GBA_SIZE_BIOS, mCORE_MEMORY_READ | mCORE_MEMORY_MAPPED },
{ GBA_REGION_EWRAM, "wram", "EWRAM", "Working RAM (256kiB)", GBA_BASE_EWRAM, GBA_BASE_EWRAM + GBA_SIZE_EWRAM, GBA_SIZE_EWRAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
{ GBA_REGION_IWRAM, "iwram", "IWRAM", "Internal Working RAM (32kiB)", GBA_BASE_IWRAM, GBA_BASE_IWRAM + GBA_SIZE_IWRAM, GBA_SIZE_IWRAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
{ GBA_REGION_IO, "io", "MMIO", "Memory-Mapped I/O", GBA_BASE_IO, GBA_BASE_IO + GBA_SIZE_IO, GBA_SIZE_IO, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
{ GBA_REGION_PALETTE_RAM, "palette", "Palette", "Palette RAM (1kiB)", GBA_BASE_PALETTE_RAM, GBA_BASE_PALETTE_RAM + GBA_SIZE_PALETTE_RAM, GBA_SIZE_PALETTE_RAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
{ GBA_REGION_VRAM, "vram", "VRAM", "Video RAM (96kiB)", GBA_BASE_VRAM, GBA_BASE_VRAM + GBA_SIZE_VRAM, GBA_SIZE_VRAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
{ GBA_REGION_OAM, "oam", "OAM", "OBJ Attribute Memory (1kiB)", GBA_BASE_OAM, GBA_BASE_OAM + GBA_SIZE_OAM, GBA_SIZE_OAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
{ GBA_REGION_ROM0, "cart0", "ROM", "Game Pak (32MiB)", GBA_BASE_ROM0, GBA_BASE_ROM0 + GBA_SIZE_ROM0, GBA_SIZE_ROM0, mCORE_MEMORY_READ | mCORE_MEMORY_WORM | mCORE_MEMORY_MAPPED },
{ GBA_REGION_ROM1, "cart1", "ROM WS1", "Game Pak (Waitstate 1)", GBA_BASE_ROM1, GBA_BASE_ROM1 + GBA_SIZE_ROM1, GBA_SIZE_ROM1, mCORE_MEMORY_READ | mCORE_MEMORY_WORM | mCORE_MEMORY_MAPPED },
{ GBA_REGION_ROM2, "cart2", "ROM WS2", "Game Pak (Waitstate 2)", GBA_BASE_ROM2, GBA_BASE_ROM2 + GBA_SIZE_ROM2, GBA_SIZE_ROM2, mCORE_MEMORY_READ | mCORE_MEMORY_WORM | mCORE_MEMORY_MAPPED },
{ GBA_REGION_SRAM, "sram", "Flash", "Flash Memory (64kiB)", GBA_BASE_SRAM, GBA_BASE_SRAM + GBA_SIZE_FLASH512, GBA_SIZE_FLASH512, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
};
static const struct mCoreMemoryBlock _GBAMemoryBlocksFlash1M[] = {
{ -1, "mem", "All", "All", 0, 0x10000000, 0x10000000, mCORE_MEMORY_VIRTUAL },
{ REGION_BIOS, "bios", "BIOS", "BIOS (16kiB)", BASE_BIOS, SIZE_BIOS, SIZE_BIOS, mCORE_MEMORY_READ | mCORE_MEMORY_MAPPED },
{ REGION_WORKING_RAM, "wram", "EWRAM", "Working RAM (256kiB)", BASE_WORKING_RAM, BASE_WORKING_RAM + SIZE_WORKING_RAM, SIZE_WORKING_RAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
{ REGION_WORKING_IRAM, "iwram", "IWRAM", "Internal Working RAM (32kiB)", BASE_WORKING_IRAM, BASE_WORKING_IRAM + SIZE_WORKING_IRAM, SIZE_WORKING_IRAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
{ REGION_IO, "io", "MMIO", "Memory-Mapped I/O", BASE_IO, BASE_IO + SIZE_IO, SIZE_IO, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
{ REGION_PALETTE_RAM, "palette", "Palette", "Palette RAM (1kiB)", BASE_PALETTE_RAM, BASE_PALETTE_RAM + SIZE_PALETTE_RAM, SIZE_PALETTE_RAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
{ REGION_VRAM, "vram", "VRAM", "Video RAM (96kiB)", BASE_VRAM, BASE_VRAM + SIZE_VRAM, SIZE_VRAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
{ REGION_OAM, "oam", "OAM", "OBJ Attribute Memory (1kiB)", BASE_OAM, BASE_OAM + SIZE_OAM, SIZE_OAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
{ REGION_CART0, "cart0", "ROM", "Game Pak (32MiB)", BASE_CART0, BASE_CART0 + SIZE_CART0, SIZE_CART0, mCORE_MEMORY_READ | mCORE_MEMORY_WORM | mCORE_MEMORY_MAPPED },
{ REGION_CART1, "cart1", "ROM WS1", "Game Pak (Waitstate 1)", BASE_CART1, BASE_CART1 + SIZE_CART1, SIZE_CART1, mCORE_MEMORY_READ | mCORE_MEMORY_WORM | mCORE_MEMORY_MAPPED },
{ REGION_CART2, "cart2", "ROM WS2", "Game Pak (Waitstate 2)", BASE_CART2, BASE_CART2 + SIZE_CART2, SIZE_CART2, mCORE_MEMORY_READ | mCORE_MEMORY_WORM | mCORE_MEMORY_MAPPED },
{ REGION_CART_SRAM, "sram", "Flash", "Flash Memory (64kiB)", BASE_CART_SRAM, BASE_CART_SRAM + SIZE_CART_FLASH512, SIZE_CART_FLASH1M, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED, 1 },
{ GBA_REGION_BIOS, "bios", "BIOS", "BIOS (16kiB)", GBA_BASE_BIOS, GBA_SIZE_BIOS, GBA_SIZE_BIOS, mCORE_MEMORY_READ | mCORE_MEMORY_MAPPED },
{ GBA_REGION_EWRAM, "wram", "EWRAM", "Working RAM (256kiB)", GBA_BASE_EWRAM, GBA_BASE_EWRAM + GBA_SIZE_EWRAM, GBA_SIZE_EWRAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
{ GBA_REGION_IWRAM, "iwram", "IWRAM", "Internal Working RAM (32kiB)", GBA_BASE_IWRAM, GBA_BASE_IWRAM + GBA_SIZE_IWRAM, GBA_SIZE_IWRAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
{ GBA_REGION_IO, "io", "MMIO", "Memory-Mapped I/O", GBA_BASE_IO, GBA_BASE_IO + GBA_SIZE_IO, GBA_SIZE_IO, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
{ GBA_REGION_PALETTE_RAM, "palette", "Palette", "Palette RAM (1kiB)", GBA_BASE_PALETTE_RAM, GBA_BASE_PALETTE_RAM + GBA_SIZE_PALETTE_RAM, GBA_SIZE_PALETTE_RAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
{ GBA_REGION_VRAM, "vram", "VRAM", "Video RAM (96kiB)", GBA_BASE_VRAM, GBA_BASE_VRAM + GBA_SIZE_VRAM, GBA_SIZE_VRAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
{ GBA_REGION_OAM, "oam", "OAM", "OBJ Attribute Memory (1kiB)", GBA_BASE_OAM, GBA_BASE_OAM + GBA_SIZE_OAM, GBA_SIZE_OAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
{ GBA_REGION_ROM0, "cart0", "ROM", "Game Pak (32MiB)", GBA_BASE_ROM0, GBA_BASE_ROM0 + GBA_SIZE_ROM0, GBA_SIZE_ROM0, mCORE_MEMORY_READ | mCORE_MEMORY_WORM | mCORE_MEMORY_MAPPED },
{ GBA_REGION_ROM1, "cart1", "ROM WS1", "Game Pak (Waitstate 1)", GBA_BASE_ROM1, GBA_BASE_ROM1 + GBA_SIZE_ROM1, GBA_SIZE_ROM1, mCORE_MEMORY_READ | mCORE_MEMORY_WORM | mCORE_MEMORY_MAPPED },
{ GBA_REGION_ROM2, "cart2", "ROM WS2", "Game Pak (Waitstate 2)", GBA_BASE_ROM2, GBA_BASE_ROM2 + GBA_SIZE_ROM2, GBA_SIZE_ROM2, mCORE_MEMORY_READ | mCORE_MEMORY_WORM | mCORE_MEMORY_MAPPED },
{ GBA_REGION_SRAM, "sram", "Flash", "Flash Memory (64kiB)", GBA_BASE_SRAM, GBA_BASE_SRAM + GBA_SIZE_FLASH512, GBA_SIZE_FLASH1M, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED, 1 },
};
static const struct mCoreMemoryBlock _GBAMemoryBlocksEEPROM[] = {
{ -1, "mem", "All", "All", 0, 0x10000000, 0x10000000, mCORE_MEMORY_VIRTUAL },
{ REGION_BIOS, "bios", "BIOS", "BIOS (16kiB)", BASE_BIOS, SIZE_BIOS, SIZE_BIOS, mCORE_MEMORY_READ | mCORE_MEMORY_MAPPED },
{ REGION_WORKING_RAM, "wram", "EWRAM", "Working RAM (256kiB)", BASE_WORKING_RAM, BASE_WORKING_RAM + SIZE_WORKING_RAM, SIZE_WORKING_RAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
{ REGION_WORKING_IRAM, "iwram", "IWRAM", "Internal Working RAM (32kiB)", BASE_WORKING_IRAM, BASE_WORKING_IRAM + SIZE_WORKING_IRAM, SIZE_WORKING_IRAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
{ REGION_IO, "io", "MMIO", "Memory-Mapped I/O", BASE_IO, BASE_IO + SIZE_IO, SIZE_IO, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
{ REGION_PALETTE_RAM, "palette", "Palette", "Palette RAM (1kiB)", BASE_PALETTE_RAM, BASE_PALETTE_RAM + SIZE_PALETTE_RAM, SIZE_PALETTE_RAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
{ REGION_VRAM, "vram", "VRAM", "Video RAM (96kiB)", BASE_VRAM, BASE_VRAM + SIZE_VRAM, SIZE_VRAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
{ REGION_OAM, "oam", "OAM", "OBJ Attribute Memory (1kiB)", BASE_OAM, BASE_OAM + SIZE_OAM, SIZE_OAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
{ REGION_CART0, "cart0", "ROM", "Game Pak (32MiB)", BASE_CART0, BASE_CART0 + SIZE_CART0, SIZE_CART0, mCORE_MEMORY_READ | mCORE_MEMORY_WORM | mCORE_MEMORY_MAPPED },
{ REGION_CART1, "cart1", "ROM WS1", "Game Pak (Waitstate 1)", BASE_CART1, BASE_CART1 + SIZE_CART1, SIZE_CART1, mCORE_MEMORY_READ | mCORE_MEMORY_WORM | mCORE_MEMORY_MAPPED },
{ REGION_CART2, "cart2", "ROM WS2", "Game Pak (Waitstate 2)", BASE_CART2, BASE_CART2 + SIZE_CART2, SIZE_CART2, mCORE_MEMORY_READ | mCORE_MEMORY_WORM | mCORE_MEMORY_MAPPED },
{ REGION_CART_SRAM_MIRROR, "eeprom", "EEPROM", "EEPROM (8kiB)", 0, SIZE_CART_EEPROM, SIZE_CART_EEPROM, mCORE_MEMORY_RW },
{ GBA_REGION_BIOS, "bios", "BIOS", "BIOS (16kiB)", GBA_BASE_BIOS, GBA_SIZE_BIOS, GBA_SIZE_BIOS, mCORE_MEMORY_READ | mCORE_MEMORY_MAPPED },
{ GBA_REGION_EWRAM, "wram", "EWRAM", "Working RAM (256kiB)", GBA_BASE_EWRAM, GBA_BASE_EWRAM + GBA_SIZE_EWRAM, GBA_SIZE_EWRAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
{ GBA_REGION_IWRAM, "iwram", "IWRAM", "Internal Working RAM (32kiB)", GBA_BASE_IWRAM, GBA_BASE_IWRAM + GBA_SIZE_IWRAM, GBA_SIZE_IWRAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
{ GBA_REGION_IO, "io", "MMIO", "Memory-Mapped I/O", GBA_BASE_IO, GBA_BASE_IO + GBA_SIZE_IO, GBA_SIZE_IO, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
{ GBA_REGION_PALETTE_RAM, "palette", "Palette", "Palette RAM (1kiB)", GBA_BASE_PALETTE_RAM, GBA_BASE_PALETTE_RAM + GBA_SIZE_PALETTE_RAM, GBA_SIZE_PALETTE_RAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
{ GBA_REGION_VRAM, "vram", "VRAM", "Video RAM (96kiB)", GBA_BASE_VRAM, GBA_BASE_VRAM + GBA_SIZE_VRAM, GBA_SIZE_VRAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
{ GBA_REGION_OAM, "oam", "OAM", "OBJ Attribute Memory (1kiB)", GBA_BASE_OAM, GBA_BASE_OAM + GBA_SIZE_OAM, GBA_SIZE_OAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
{ GBA_REGION_ROM0, "cart0", "ROM", "Game Pak (32MiB)", GBA_BASE_ROM0, GBA_BASE_ROM0 + GBA_SIZE_ROM0, GBA_SIZE_ROM0, mCORE_MEMORY_READ | mCORE_MEMORY_WORM | mCORE_MEMORY_MAPPED },
{ GBA_REGION_ROM1, "cart1", "ROM WS1", "Game Pak (Waitstate 1)", GBA_BASE_ROM1, GBA_BASE_ROM1 + GBA_SIZE_ROM1, GBA_SIZE_ROM1, mCORE_MEMORY_READ | mCORE_MEMORY_WORM | mCORE_MEMORY_MAPPED },
{ GBA_REGION_ROM2, "cart2", "ROM WS2", "Game Pak (Waitstate 2)", GBA_BASE_ROM2, GBA_BASE_ROM2 + GBA_SIZE_ROM2, GBA_SIZE_ROM2, mCORE_MEMORY_READ | mCORE_MEMORY_WORM | mCORE_MEMORY_MAPPED },
{ GBA_REGION_SRAM_MIRROR, "eeprom", "EEPROM", "EEPROM (8kiB)", 0, GBA_SIZE_EEPROM, GBA_SIZE_EEPROM, mCORE_MEMORY_RW },
};
static const struct mCoreRegisterInfo _GBARegisters[] = {
@ -237,7 +237,7 @@ static bool _GBACoreInit(struct mCore* core) {
#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2
mDirectorySetInit(&core->dirs);
#endif
return true;
}
@ -512,7 +512,7 @@ static bool _GBACoreLoadROM(struct mCore* core, struct VFile* vf) {
#ifdef USE_ELF
struct ELF* elf = ELFOpen(vf);
if (elf) {
if (ELFEntry(elf) == BASE_CART0) {
if (GBAVerifyELFEntry(elf, GBA_BASE_ROM0)) {
GBALoadNull(core->board);
}
bool success = mCoreLoadELF(core, elf);
@ -700,8 +700,8 @@ static void _GBACoreReset(struct mCore* core) {
#endif
ARMReset(core->cpu);
bool forceSkip = gba->romVf && GBAIsMB(gba->romVf);
if (!(forceSkip || core->opts.skipBios) && (gba->romVf || gba->memory.rom) && gba->pristineRomSize >= 0xA0 && gba->biosVf) {
bool forceSkip = gba->mbVf || core->opts.skipBios;
if (!forceSkip && (gba->romVf || gba->memory.rom) && gba->pristineRomSize >= 0xA0 && gba->biosVf) {
uint32_t crc = doCrc32(&gba->memory.rom[1], 0x9C);
if (crc != LOGO_CRC32) {
mLOG(STATUS, WARN, "Invalid logo, skipping BIOS");
@ -709,7 +709,7 @@ static void _GBACoreReset(struct mCore* core) {
}
}
if (forceSkip || (core->opts.skipBios && (gba->romVf || gba->memory.rom))) {
if (forceSkip) {
GBASkipBIOS(core->board);
}
@ -907,36 +907,36 @@ void* _GBACoreGetMemoryBlock(struct mCore* core, size_t id, size_t* sizeOut) {
switch (id) {
default:
return NULL;
case REGION_BIOS:
*sizeOut = SIZE_BIOS;
case GBA_REGION_BIOS:
*sizeOut = GBA_SIZE_BIOS;
return gba->memory.bios;
case REGION_WORKING_RAM:
*sizeOut = SIZE_WORKING_RAM;
case GBA_REGION_EWRAM:
*sizeOut = GBA_SIZE_EWRAM;
return gba->memory.wram;
case REGION_WORKING_IRAM:
*sizeOut = SIZE_WORKING_IRAM;
case GBA_REGION_IWRAM:
*sizeOut = GBA_SIZE_IWRAM;
return gba->memory.iwram;
case REGION_PALETTE_RAM:
*sizeOut = SIZE_PALETTE_RAM;
case GBA_REGION_PALETTE_RAM:
*sizeOut = GBA_SIZE_PALETTE_RAM;
return gba->video.palette;
case REGION_VRAM:
*sizeOut = SIZE_VRAM;
case GBA_REGION_VRAM:
*sizeOut = GBA_SIZE_VRAM;
return gba->video.vram;
case REGION_OAM:
*sizeOut = SIZE_OAM;
case GBA_REGION_OAM:
*sizeOut = GBA_SIZE_OAM;
return gba->video.oam.raw;
case REGION_CART0:
case REGION_CART1:
case REGION_CART2:
case GBA_REGION_ROM0:
case GBA_REGION_ROM1:
case GBA_REGION_ROM2:
*sizeOut = gba->memory.romSize;
return gba->memory.rom;
case REGION_CART_SRAM:
case GBA_REGION_SRAM:
if (gba->memory.savedata.type == SAVEDATA_FLASH1M) {
*sizeOut = SIZE_CART_FLASH1M;
*sizeOut = GBA_SIZE_FLASH1M;
return gba->memory.savedata.currentBank;
}
// Fall through
case REGION_CART_SRAM_MIRROR:
case GBA_REGION_SRAM_MIRROR:
*sizeOut = GBASavedataSize(&gba->memory.savedata);
return gba->memory.savedata.data;
}
@ -1153,7 +1153,7 @@ static bool _GBACoreLookupIdentifier(struct mCore* core, const char* name, int32
for (i = 0; i < REG_MAX; i += 2) {
const char* reg = GBAIORegisterNames[i >> 1];
if (reg && strcasecmp(reg, name) == 0) {
*value = BASE_IO | i;
*value = GBA_BASE_IO | i;
return true;
}
}
@ -1321,7 +1321,7 @@ static void _GBACoreStartVideoLog(struct mCore* core, struct mVideoLogContext* c
struct GBASerializedState* state = mVideoLogContextInitialState(context, NULL);
state->id = 0;
state->cpu.gprs[ARM_PC] = BASE_WORKING_RAM;
state->cpu.gprs[ARM_PC] = GBA_BASE_EWRAM;
int channelId = mVideoLoggerAddChannel(context);
gbacore->vlProxy.logger = malloc(sizeof(struct mVideoLogger));
@ -1490,8 +1490,8 @@ static void _GBAVLPReset(struct mCore* core) {
// Make sure CPU loop never spins
GBAHalt(gba);
gba->cpu->memory.store16(gba->cpu, BASE_IO | REG_IME, 0, NULL);
gba->cpu->memory.store16(gba->cpu, BASE_IO | REG_IE, 0, NULL);
gba->cpu->memory.store16(gba->cpu, GBA_BASE_IO | REG_IME, 0, NULL);
gba->cpu->memory.store16(gba->cpu, GBA_BASE_IO | REG_IE, 0, NULL);
}
static bool _GBAVLPLoadROM(struct mCore* core, struct VFile* vf) {
@ -1510,13 +1510,13 @@ static bool _GBAVLPLoadState(struct mCore* core, const void* state) {
struct GBA* gba = (struct GBA*) core->board;
gba->timing.root = NULL;
gba->cpu->gprs[ARM_PC] = BASE_WORKING_RAM;
gba->cpu->gprs[ARM_PC] = GBA_BASE_EWRAM;
gba->cpu->memory.setActiveRegion(gba->cpu, gba->cpu->gprs[ARM_PC]);
// Make sure CPU loop never spins
GBAHalt(gba);
gba->cpu->memory.store16(gba->cpu, BASE_IO | REG_IME, 0, NULL);
gba->cpu->memory.store16(gba->cpu, BASE_IO | REG_IE, 0, NULL);
gba->cpu->memory.store16(gba->cpu, GBA_BASE_IO | REG_IME, 0, NULL);
gba->cpu->memory.store16(gba->cpu, GBA_BASE_IO | REG_IE, 0, NULL);
GBAVideoDeserialize(&gba->video, state);
GBAIODeserialize(gba, state);
GBAAudioReset(&gba->audio);

View File

@ -33,14 +33,14 @@ void GBADMAReset(struct GBA* gba) {
gba->memory.activeDMA = -1;
}
static bool _isValidDMASAD(int dma, uint32_t address) {
if (dma == 0 && address >= BASE_CART0 && address < BASE_CART_SRAM) {
if (dma == 0 && address >= GBA_BASE_ROM0 && address < GBA_BASE_SRAM) {
return false;
}
return address >= BASE_WORKING_RAM;
return address >= GBA_BASE_EWRAM;
}
static bool _isValidDMADAD(int dma, uint32_t address) {
return dma == 3 || address < BASE_CART0;
return dma == 3 || address < GBA_BASE_ROM0;
}
uint32_t GBADMAWriteSAD(struct GBA* gba, int dma, uint32_t address) {
@ -244,7 +244,6 @@ void GBADMAService(struct GBA* gba, int number, struct GBADMA* info) {
struct GBAMemory* memory = &gba->memory;
struct ARMCore* cpu = gba->cpu;
uint32_t width = 2 << GBADMARegisterGetWidth(info->reg);
int32_t wordsRemaining = info->nextCount;
uint32_t source = info->nextSource;
uint32_t dest = info->nextDest;
uint32_t sourceRegion = source >> BASE_OFFSET;
@ -252,6 +251,8 @@ void GBADMAService(struct GBA* gba, int number, struct GBADMA* info) {
int32_t cycles = 2;
gba->cpuBlocked = true;
gba->performingDMA = 1 | (number << 1);
if (info->count == info->nextCount) {
if (width == 4) {
cycles += memory->waitstatesNonseq32[sourceRegion] + memory->waitstatesNonseq32[destRegion];
@ -267,53 +268,47 @@ void GBADMAService(struct GBA* gba, int number, struct GBADMA* info) {
}
info->when += cycles;
gba->performingDMA = 1 | (number << 1);
if (width == 4) {
if (source) {
memory->dmaTransferRegister = cpu->memory.load32(cpu, source, 0);
}
gba->bus = memory->dmaTransferRegister;
cpu->memory.store32(cpu, dest, memory->dmaTransferRegister, 0);
} else {
if (sourceRegion == REGION_CART2_EX && (memory->savedata.type == SAVEDATA_EEPROM || memory->savedata.type == SAVEDATA_EEPROM512)) {
if (sourceRegion == GBA_REGION_ROM2_EX && (memory->savedata.type == SAVEDATA_EEPROM || memory->savedata.type == SAVEDATA_EEPROM512)) {
memory->dmaTransferRegister = GBASavedataReadEEPROM(&memory->savedata);
memory->dmaTransferRegister |= memory->dmaTransferRegister << 16;
} else if (source) {
memory->dmaTransferRegister = cpu->memory.load16(cpu, source, 0);
memory->dmaTransferRegister |= memory->dmaTransferRegister << 16;
}
if (destRegion == REGION_CART2_EX) {
if (destRegion == GBA_REGION_ROM2_EX) {
if (memory->savedata.type == SAVEDATA_AUTODETECT) {
mLOG(GBA_MEM, INFO, "Detected EEPROM savegame");
GBASavedataInitEEPROM(&memory->savedata);
}
if (memory->savedata.type == SAVEDATA_EEPROM512 || memory->savedata.type == SAVEDATA_EEPROM) {
GBASavedataWriteEEPROM(&memory->savedata, memory->dmaTransferRegister, wordsRemaining);
GBASavedataWriteEEPROM(&memory->savedata, memory->dmaTransferRegister, info->nextCount);
}
} else {
cpu->memory.store16(cpu, dest, memory->dmaTransferRegister, 0);
}
gba->bus = memory->dmaTransferRegister;
}
gba->bus = memory->dmaTransferRegister;
int sourceOffset;
if (info->nextSource >= BASE_CART0 && info->nextSource < BASE_CART_SRAM && GBADMARegisterGetSrcControl(info->reg) < 3) {
if (info->nextSource >= GBA_BASE_ROM0 && info->nextSource < GBA_BASE_SRAM && GBADMARegisterGetSrcControl(info->reg) < 3) {
sourceOffset = width;
} else {
sourceOffset = DMA_OFFSET[GBADMARegisterGetSrcControl(info->reg)] * width;
}
int destOffset = DMA_OFFSET[GBADMARegisterGetDestControl(info->reg)] * width;
if (source) {
source += sourceOffset;
info->nextSource += sourceOffset;
}
dest += destOffset;
--wordsRemaining;
gba->performingDMA = 0;
info->nextDest += destOffset;
--info->nextCount;
info->nextCount = wordsRemaining;
info->nextSource = source;
info->nextDest = dest;
gba->performingDMA = 0;
int i;
for (i = 0; i < 4; ++i) {
@ -324,9 +319,9 @@ void GBADMAService(struct GBA* gba, int number, struct GBADMA* info) {
}
}
if (!wordsRemaining) {
if (!info->nextCount) {
info->nextCount |= 0x80000000;
if (sourceRegion < REGION_CART0 || destRegion < REGION_CART0) {
if (sourceRegion < GBA_REGION_ROM0 || destRegion < GBA_REGION_ROM0) {
info->when += 2;
}
}

View File

@ -245,7 +245,7 @@ static void _mp2kReload(struct GBAAudioMixer* mixer) {
}
bool _mp2kEngage(struct GBAAudioMixer* mixer, uint32_t address) {
if (address < BASE_WORKING_RAM) {
if (address < GBA_BASE_EWRAM) {
return false;
}
if (address != mixer->contextAddress) {

View File

@ -63,9 +63,9 @@ void GBAVideoProxyRendererCreate(struct GBAVideoProxyRenderer* renderer, struct
renderer->logger->parsePacket = _parsePacket;
renderer->logger->handleEvent = _handleEvent;
renderer->logger->vramBlock = _vramBlock;
renderer->logger->paletteSize = SIZE_PALETTE_RAM;
renderer->logger->vramSize = SIZE_VRAM;
renderer->logger->oamSize = SIZE_OAM;
renderer->logger->paletteSize = GBA_SIZE_PALETTE_RAM;
renderer->logger->vramSize = GBA_SIZE_VRAM;
renderer->logger->oamSize = GBA_SIZE_OAM;
renderer->backend = backend;
}
@ -82,9 +82,9 @@ static void _init(struct GBAVideoProxyRenderer* proxyRenderer) {
}
static void _reset(struct GBAVideoProxyRenderer* proxyRenderer) {
memcpy(proxyRenderer->logger->oam, &proxyRenderer->d.oam->raw, SIZE_OAM);
memcpy(proxyRenderer->logger->palette, proxyRenderer->d.palette, SIZE_PALETTE_RAM);
memcpy(proxyRenderer->logger->vram, proxyRenderer->d.vram, SIZE_VRAM);
memcpy(proxyRenderer->logger->oam, &proxyRenderer->d.oam->raw, GBA_SIZE_OAM);
memcpy(proxyRenderer->logger->palette, proxyRenderer->d.palette, GBA_SIZE_PALETTE_RAM);
memcpy(proxyRenderer->logger->vram, proxyRenderer->d.vram, GBA_SIZE_VRAM);
mVideoLoggerRendererReset(proxyRenderer->logger);
}
@ -199,19 +199,19 @@ static bool _parsePacket(struct mVideoLogger* logger, const struct mVideoLoggerD
proxyRenderer->backend->writeVideoRegister(proxyRenderer->backend, item->address, item->value);
break;
case DIRTY_PALETTE:
if (item->address < SIZE_PALETTE_RAM) {
if (item->address < GBA_SIZE_PALETTE_RAM) {
STORE_16LE(item->value, item->address, logger->palette);
proxyRenderer->backend->writePalette(proxyRenderer->backend, item->address, item->value);
}
break;
case DIRTY_OAM:
if (item->address < SIZE_OAM) {
if (item->address < GBA_SIZE_OAM) {
STORE_16LE(item->value, item->address << 1, logger->oam);
proxyRenderer->backend->writeOAM(proxyRenderer->backend, item->address);
}
break;
case DIRTY_VRAM:
if (item->address <= SIZE_VRAM - 0x1000) {
if (item->address <= GBA_SIZE_VRAM - 0x1000) {
logger->readData(logger, &logger->vram[item->address >> 1], 0x1000, true);
proxyRenderer->backend->writeVRAM(proxyRenderer->backend, item->address);
} else {

View File

@ -108,7 +108,7 @@ static void GBAInit(void* cpu, struct mCPUComponent* component) {
gba->keyCallback = NULL;
mCoreCallbacksListInit(&gba->coreCallbacks, 0);
gba->biosChecksum = GBAChecksum(gba->memory.bios, SIZE_BIOS);
gba->biosChecksum = GBAChecksum(gba->memory.bios, GBA_SIZE_BIOS);
gba->idleOptimization = IDLE_LOOP_REMOVE;
gba->idleLoop = IDLE_LOOP_NONE;
@ -137,7 +137,7 @@ void GBAUnloadROM(struct GBA* gba) {
gba->yankedRomSize = 0;
}
#ifndef FIXED_ROM_BUFFER
mappedMemoryFree(gba->memory.rom, SIZE_CART0);
mappedMemoryFree(gba->memory.rom, GBA_SIZE_ROM0);
#endif
}
@ -172,7 +172,7 @@ void GBADestroy(struct GBA* gba) {
GBAUnloadMB(gba);
if (gba->biosVf) {
gba->biosVf->unmap(gba->biosVf, gba->memory.bios, SIZE_BIOS);
gba->biosVf->unmap(gba->biosVf, gba->memory.bios, GBA_SIZE_BIOS);
gba->biosVf->close(gba->biosVf);
gba->biosVf = 0;
}
@ -213,6 +213,7 @@ void GBAReset(struct ARMCore* cpu) {
gba->earlyExit = false;
gba->dmaPC = 0;
gba->biosStall = 0;
gba->keysLast = 0x400;
if (gba->yankedRomSize) {
gba->memory.romSize = gba->yankedRomSize;
gba->memory.romMask = toPow2(gba->memory.romSize) - 1;
@ -246,7 +247,7 @@ void GBAReset(struct ARMCore* cpu) {
if (GBAIsMB(gba->mbVf) && !isELF) {
gba->mbVf->seek(gba->mbVf, 0, SEEK_SET);
gba->mbVf->read(gba->mbVf, gba->memory.wram, SIZE_WORKING_RAM);
gba->mbVf->read(gba->mbVf, gba->memory.wram, GBA_SIZE_EWRAM);
}
gba->lastJump = 0;
@ -258,7 +259,7 @@ void GBAReset(struct ARMCore* cpu) {
memset(gba->debugString, 0, sizeof(gba->debugString));
if (gba->romVf && gba->romVf->size(gba->romVf) > SIZE_CART0) {
if (gba->romVf && gba->romVf->size(gba->romVf) > GBA_SIZE_ROM0) {
char ident;
gba->romVf->seek(gba->romVf, 0xAC, SEEK_SET);
gba->romVf->read(gba->romVf, &ident, 1);
@ -273,9 +274,11 @@ void GBASkipBIOS(struct GBA* gba) {
struct ARMCore* cpu = gba->cpu;
if (cpu->gprs[ARM_PC] == BASE_RESET + WORD_SIZE_ARM) {
if (gba->memory.rom) {
cpu->gprs[ARM_PC] = BASE_CART0;
cpu->gprs[ARM_PC] = GBA_BASE_ROM0;
} else if (gba->memory.wram[0x30]) {
cpu->gprs[ARM_PC] = GBA_BASE_EWRAM + 0xC0;
} else {
cpu->gprs[ARM_PC] = BASE_WORKING_RAM + 0xC0;
cpu->gprs[ARM_PC] = GBA_BASE_EWRAM;
}
gba->video.vcount = 0x7E;
gba->memory.io[REG_VCOUNT >> 1] = 0x7E;
@ -357,14 +360,14 @@ bool GBALoadNull(struct GBA* gba) {
gba->romVf = NULL;
gba->pristineRomSize = 0;
#ifndef FIXED_ROM_BUFFER
gba->memory.rom = anonymousMemoryMap(SIZE_CART0);
gba->memory.rom = anonymousMemoryMap(GBA_SIZE_ROM0);
#else
gba->memory.rom = romBuffer;
#endif
gba->isPristine = false;
gba->yankedRomSize = 0;
gba->memory.romSize = SIZE_CART0;
gba->memory.romMask = SIZE_CART0 - 1;
gba->memory.romSize = GBA_SIZE_ROM0;
gba->memory.romMask = GBA_SIZE_ROM0 - 1;
gba->romCrc32 = 0;
if (gba->cpu) {
@ -378,9 +381,9 @@ bool GBALoadMB(struct GBA* gba, struct VFile* vf) {
GBAUnloadMB(gba);
gba->mbVf = vf;
vf->seek(vf, 0, SEEK_SET);
memset(gba->memory.wram, 0, SIZE_WORKING_RAM);
vf->read(vf, gba->memory.wram, SIZE_WORKING_RAM);
if (gba->cpu && gba->memory.activeRegion == REGION_WORKING_RAM) {
memset(gba->memory.wram, 0, GBA_SIZE_EWRAM);
vf->read(vf, gba->memory.wram, GBA_SIZE_EWRAM);
if (gba->cpu && gba->memory.activeRegion == GBA_REGION_IWRAM) {
gba->cpu->memory.setActiveRegion(gba->cpu, gba->cpu->gprs[ARM_PC]);
}
return true;
@ -402,7 +405,7 @@ bool GBALoadROM(struct GBA* gba, struct VFile* vf) {
gba->isPristine = true;
gba->pristineRomSize = vf->size(vf);
vf->seek(vf, 0, SEEK_SET);
if (gba->pristineRomSize > SIZE_CART0) {
if (gba->pristineRomSize > GBA_SIZE_ROM0) {
char ident;
vf->seek(vf, 0xAC, SEEK_SET);
vf->read(vf, &ident, 1);
@ -412,13 +415,13 @@ bool GBALoadROM(struct GBA* gba, struct VFile* vf) {
#ifdef FIXED_ROM_BUFFER
gba->memory.rom = romBuffer;
#else
gba->memory.rom = anonymousMemoryMap(SIZE_CART0);
gba->memory.rom = anonymousMemoryMap(GBA_SIZE_ROM0);
#endif
} else {
gba->memory.rom = vf->map(vf, SIZE_CART0, MAP_READ);
gba->memory.romSize = SIZE_CART0;
gba->memory.rom = vf->map(vf, GBA_SIZE_ROM0, MAP_READ);
gba->memory.romSize = GBA_SIZE_ROM0;
}
gba->pristineRomSize = SIZE_CART0;
gba->pristineRomSize = GBA_SIZE_ROM0;
} else if (gba->pristineRomSize == 0x00100000) {
// 1 MiB ROMs (e.g. Classic NES) all appear as 4x mirrored, but not more
gba->isPristine = false;
@ -426,7 +429,7 @@ bool GBALoadROM(struct GBA* gba, struct VFile* vf) {
#ifdef FIXED_ROM_BUFFER
gba->memory.rom = romBuffer;
#else
gba->memory.rom = anonymousMemoryMap(SIZE_CART0);
gba->memory.rom = anonymousMemoryMap(GBA_SIZE_ROM0);
#endif
vf->read(vf, gba->memory.rom, gba->pristineRomSize);
memcpy(&gba->memory.rom[0x40000], gba->memory.rom, 0x00100000);
@ -447,15 +450,15 @@ bool GBALoadROM(struct GBA* gba, struct VFile* vf) {
if (popcount32(gba->memory.romSize) != 1) {
// This ROM is either a bad dump or homebrew. Emulate flash cart behavior.
#ifndef FIXED_ROM_BUFFER
void* newRom = anonymousMemoryMap(SIZE_CART0);
void* newRom = anonymousMemoryMap(GBA_SIZE_ROM0);
memcpy(newRom, gba->memory.rom, gba->pristineRomSize);
gba->memory.rom = newRom;
#endif
gba->memory.romSize = SIZE_CART0;
gba->memory.romMask = SIZE_CART0 - 1;
gba->memory.romSize = GBA_SIZE_ROM0;
gba->memory.romMask = GBA_SIZE_ROM0 - 1;
gba->isPristine = false;
}
if (gba->cpu && gba->memory.activeRegion >= REGION_CART0) {
if (gba->cpu && gba->memory.activeRegion >= GBA_REGION_ROM0) {
gba->cpu->memory.setActiveRegion(gba->cpu, gba->cpu->gprs[ARM_PC]);
}
GBAHardwareInit(&gba->memory.hw, &((uint16_t*) gba->memory.rom)[GPIO_REG_DATA >> 1]);
@ -482,23 +485,23 @@ void GBAYankROM(struct GBA* gba) {
}
void GBALoadBIOS(struct GBA* gba, struct VFile* vf) {
if (vf->size(vf) != SIZE_BIOS) {
if (vf->size(vf) != GBA_SIZE_BIOS) {
mLOG(GBA, WARN, "Incorrect BIOS size");
return;
}
uint32_t* bios = vf->map(vf, SIZE_BIOS, MAP_READ);
uint32_t* bios = vf->map(vf, GBA_SIZE_BIOS, MAP_READ);
if (!bios) {
mLOG(GBA, WARN, "Couldn't map BIOS");
return;
}
if (gba->biosVf) {
gba->biosVf->unmap(gba->biosVf, gba->memory.bios, SIZE_BIOS);
gba->biosVf->unmap(gba->biosVf, gba->memory.bios, GBA_SIZE_BIOS);
gba->biosVf->close(gba->biosVf);
}
gba->biosVf = vf;
gba->memory.bios = bios;
gba->memory.fullBios = 1;
uint32_t checksum = GBAChecksum(gba->memory.bios, SIZE_BIOS);
uint32_t checksum = GBAChecksum(gba->memory.bios, GBA_SIZE_BIOS);
mLOG(GBA, DEBUG, "BIOS Checksum: 0x%X", checksum);
if (checksum == GBA_BIOS_CHECKSUM) {
mLOG(GBA, INFO, "Official GBA BIOS detected");
@ -508,7 +511,7 @@ void GBALoadBIOS(struct GBA* gba, struct VFile* vf) {
mLOG(GBA, WARN, "BIOS checksum incorrect");
}
gba->biosChecksum = checksum;
if (gba->memory.activeRegion == REGION_BIOS) {
if (gba->memory.activeRegion == GBA_REGION_BIOS) {
gba->cpu->memory.activeRegion = gba->memory.bios;
}
// TODO: error check
@ -516,18 +519,18 @@ void GBALoadBIOS(struct GBA* gba, struct VFile* vf) {
void GBAApplyPatch(struct GBA* gba, struct Patch* patch) {
size_t patchedSize = patch->outputSize(patch, gba->memory.romSize);
if (!patchedSize || patchedSize > SIZE_CART0) {
if (!patchedSize || patchedSize > GBA_SIZE_ROM0) {
return;
}
void* newRom = anonymousMemoryMap(SIZE_CART0);
void* newRom = anonymousMemoryMap(GBA_SIZE_ROM0);
if (!patch->applyPatch(patch, gba->memory.rom, gba->pristineRomSize, newRom, patchedSize)) {
mappedMemoryFree(newRom, SIZE_CART0);
mappedMemoryFree(newRom, GBA_SIZE_ROM0);
return;
}
if (gba->romVf) {
#ifndef FIXED_ROM_BUFFER
if (!gba->isPristine) {
mappedMemoryFree(gba->memory.rom, SIZE_CART0);
mappedMemoryFree(gba->memory.rom, GBA_SIZE_ROM0);
} else {
gba->romVf->unmap(gba->romVf, gba->memory.rom, gba->pristineRomSize);
}
@ -595,6 +598,63 @@ void GBADebug(struct GBA* gba, uint16_t flags) {
gba->debugFlags = GBADebugFlagsClearSend(gba->debugFlags);
}
#ifdef USE_ELF
bool GBAVerifyELFEntry(struct ELF* elf, uint32_t target) {
if (ELFEntry(elf) == target) {
return true;
}
struct ELFProgramHeaders ph;
ELFProgramHeadersInit(&ph, 0);
ELFGetProgramHeaders(elf, &ph);
size_t i;
for (i = 0; i < ELFProgramHeadersSize(&ph); ++i) {
Elf32_Phdr* phdr = ELFProgramHeadersGetPointer(&ph, i);
if (!phdr->p_filesz) {
continue;
}
size_t phdrS = phdr->p_paddr;
size_t phdrE = phdrS + phdr->p_filesz;
// Does the segment contain our target address?
if (target < phdrS || target + 4 > phdrE) {
continue;
}
// File offset to what should be the rom entry instruction
size_t off = phdr->p_offset + target - phdrS;
size_t eSize;
const char* bytes = ELFBytes(elf, &eSize);
// Bounds and alignment check
if (off >= eSize || off & 3) {
continue;
}
uint32_t opcode;
LOAD_32(opcode, off, bytes);
struct ARMInstructionInfo info;
ARMDecodeARM(opcode, &info);
if (info.branchType != ARM_BRANCH && info.branchType != ARM_BRANCH_LINKED) {
continue;
}
uint32_t bTarget = target + info.op1.immediate + 8;
if (ELFEntry(elf) == bTarget) {
ELFProgramHeadersDeinit(&ph);
return true;
}
}
ELFProgramHeadersDeinit(&ph);
return false;
}
#endif
bool GBAIsROM(struct VFile* vf) {
if (!vf) {
return false;
@ -606,7 +666,7 @@ bool GBAIsROM(struct VFile* vf) {
uint32_t entry = ELFEntry(elf);
bool isGBA = true;
isGBA = isGBA && ELFMachine(elf) == EM_ARM;
isGBA = isGBA && (entry == BASE_CART0 || entry == BASE_WORKING_RAM + 0xC0);
isGBA = isGBA && (GBAVerifyELFEntry(elf, GBA_BASE_ROM0) || GBAVerifyELFEntry(elf, GBA_BASE_EWRAM + 0xC0));
ELFClose(elf);
return isGBA;
}
@ -662,12 +722,12 @@ bool GBAIsMB(struct VFile* vf) {
#ifdef USE_ELF
struct ELF* elf = ELFOpen(vf);
if (elf) {
bool isMB = ELFEntry(elf) == BASE_WORKING_RAM + 0xC0;
bool isMB = GBAVerifyELFEntry(elf, GBA_BASE_EWRAM + 0xC0);
ELFClose(elf);
return isMB;
}
#endif
if (vf->size(vf) > SIZE_WORKING_RAM) {
if (vf->size(vf) > GBA_SIZE_EWRAM) {
return false;
}
if (vf->seek(vf, GBA_MB_MAGIC_OFFSET, SEEK_SET) < 0) {
@ -704,10 +764,10 @@ bool GBAIsMB(struct VFile* vf) {
}
pc += 4;
LOAD_32(opcode, 0, &signature);
if ((opcode & ~0x1FFFF) == BASE_WORKING_RAM) {
if ((opcode & ~0x1FFFF) == GBA_BASE_EWRAM) {
++wramAddrs;
}
if ((opcode & ~0x1FFFF) == BASE_CART0) {
if ((opcode & ~0x1FFFF) == GBA_BASE_ROM0) {
++romAddrs;
}
ARMDecodeARM(opcode, &info);
@ -730,10 +790,10 @@ bool GBAIsMB(struct VFile* vf) {
if (vf->seek(vf, pc, SEEK_SET) < 0) {
break;
}
if ((immediate & ~0x1FFFF) == BASE_WORKING_RAM) {
if ((immediate & ~0x1FFFF) == GBA_BASE_EWRAM) {
++wramLoads;
}
if ((immediate & ~0x1FFFF) == BASE_CART0) {
if ((immediate & ~0x1FFFF) == GBA_BASE_ROM0) {
++romLoads;
}
}

View File

@ -2,7 +2,7 @@
#include <mgba/internal/gba/memory.h>
const uint8_t hleBios[SIZE_BIOS] = {
const uint8_t hleBios[GBA_SIZE_BIOS] = {
0xd3, 0x00, 0x00, 0xea, 0x66, 0x00, 0x00, 0xea, 0x0c, 0x00, 0x00, 0xea,
0xfe, 0xff, 0xff, 0xea, 0xfe, 0xff, 0xff, 0xea, 0x00, 0x00, 0xa0, 0xe1,
0x59, 0x00, 0x00, 0xea, 0xfe, 0xff, 0xff, 0xea, 0x00, 0x00, 0x00, 0x00,

View File

@ -15,4 +15,4 @@ hle-bios.c: hle-bios.bin
echo >> $@
echo '#include <mgba/internal/gba/memory.h>' >> $@
echo >> $@
xxd -i $< | sed -e 's/unsigned char hle_bios_bin\[\]/const uint8_t hleBios[SIZE_BIOS]/' -e 's/^ \+/\t/' | grep -v hle_bios_bin_len >> $@
xxd -i $< | sed -e 's/unsigned char hle_bios_bin\[\]/const uint8_t hleBios[GBA_SIZE_BIOS]/' -e 's/^ \+/\t/' | grep -v hle_bios_bin_len >> $@

View File

@ -625,18 +625,18 @@ void GBAIOWrite8(struct GBA* gba, uint32_t address, uint8_t value) {
return;
}
if (address == REG_POSTFLG) {
gba->memory.io[(address & (SIZE_IO - 1)) >> 1] = value;
gba->memory.io[(address & (GBA_SIZE_IO - 1)) >> 1] = value;
return;
}
if (address >= REG_DEBUG_STRING && address - REG_DEBUG_STRING < sizeof(gba->debugString)) {
gba->debugString[address - REG_DEBUG_STRING] = value;
return;
}
if (address > SIZE_IO) {
if (address > GBA_SIZE_IO) {
return;
}
uint16_t value16 = value << (8 * (address & 1));
value16 |= (gba->memory.io[(address & (SIZE_IO - 1)) >> 1]) & ~(0xFF << (8 * (address & 1)));
value16 |= (gba->memory.io[(address & (GBA_SIZE_IO - 1)) >> 1]) & ~(0xFF << (8 * (address & 1)));
GBAIOWrite(gba, address & 0xFFFFFFFE, value16);
}

File diff suppressed because it is too large Load Diff

View File

@ -61,7 +61,7 @@ void GBAVideoCacheAssociate(struct mCacheSet* cache, struct GBAVideo* video) {
mCacheSetAssignVRAM(cache, video->vram);
video->renderer->cache = cache;
size_t i;
for (i = 0; i < SIZE_PALETTE_RAM / 2; ++i) {
for (i = 0; i < GBA_SIZE_PALETTE_RAM / 2; ++i) {
mCacheSetWritePalette(cache, i, mColorFrom555(video->palette[i]));
}
GBAVideoCacheWriteVideoRegister(cache, REG_DISPCNT, video->p->memory.io[REG_DISPCNT >> 1]);

View File

@ -664,10 +664,12 @@ static const char* const _finalize =
" if (((topFlags.y & 13) == 5 || topFlags.w > 0) && (bottomFlags.y & 2) == 2) {\n"
" topPixel.rgb *= float(topFlags.z) / 16.;\n"
" topPixel.rgb += bottomPixel.rgb * float(windowFlags.y) / 16.;\n"
" } else if ((topFlags.y & 13) == 9) {\n"
" topPixel.rgb += (1. - topPixel.rgb) * float(windowFlags.z) / 16.;\n"
" } else if ((topFlags.y & 13) == 13) {\n"
" topPixel.rgb -= topPixel.rgb * float(windowFlags.z) / 16.;\n"
" } else if (topFlags.w == 0) { \n"
" if ((topFlags.y & 13) == 9) {\n"
" topPixel.rgb += (1. - topPixel.rgb) * float(windowFlags.z) / 16.;\n"
" } else if ((topFlags.y & 13) == 13) {\n"
" topPixel.rgb -= topPixel.rgb * float(windowFlags.z) / 16.;\n"
" }\n"
" }\n"
" color = topPixel;\n"
"}";

View File

@ -17,7 +17,6 @@
#define DRAW_BACKGROUND_MODE_0_TILE_SUFFIX_16(BLEND, OBJWIN) \
paletteData = GBA_TEXT_MAP_PALETTE(mapData) << 4; \
palette = &mainPalette[paletteData]; \
charBase = (background->charBase + (GBA_TEXT_MAP_TILE(mapData) << 5)) + (localY << 2); \
LOAD_32(tileData, charBase, vram); \
if (!GBA_TEXT_MAP_HFLIP(mapData)) { \
@ -36,7 +35,6 @@
charBase = (background->charBase + (GBA_TEXT_MAP_TILE(mapData) << 5)) + (localY << 2); \
LOAD_32(tileData, charBase, vram); \
paletteData = GBA_TEXT_MAP_PALETTE(mapData) << 4; \
palette = &mainPalette[paletteData]; \
pixel = &renderer->row[outX]; \
if (!GBA_TEXT_MAP_HFLIP(mapData)) { \
if (outX < renderer->start) { \
@ -93,7 +91,6 @@
carryData = 0; \
} else { \
paletteData = GBA_TEXT_MAP_PALETTE(mapData) << 4; \
palette = &mainPalette[paletteData]; \
LOAD_32(tileData, charBase, vram); \
if (!GBA_TEXT_MAP_HFLIP(mapData)) { \
tileData >>= 4 * baseX; \
@ -123,7 +120,6 @@
carryData = 0; \
} else { \
paletteData = GBA_TEXT_MAP_PALETTE(mapData) << 4; \
palette = &mainPalette[paletteData]; \
LOAD_32(tileData, charBase, vram); \
if (!GBA_TEXT_MAP_HFLIP(mapData)) { \
tileData >>= x * 4; \
@ -154,33 +150,26 @@
localY = 7 - localY; \
} \
paletteData = GBA_TEXT_MAP_PALETTE(mapData) << 4; \
palette = &mainPalette[paletteData]; \
charBase = (background->charBase + (GBA_TEXT_MAP_TILE(mapData) << 5)) + (localY << 2); \
if (UNLIKELY(charBase >= 0x10000)) { \
pixel += 8; \
continue; \
} \
LOAD_32(tileData, charBase, vram); \
if (!GBA_TEXT_MAP_HFLIP(mapData)) { \
LOAD_32(tileData, charBase, vram); \
} else { \
LOAD_32BE(tileData, charBase, vram); \
tileData = ((tileData & 0xF0F0F0F0) >> 4) | ((tileData & 0x0F0F0F0F) << 4); \
} \
if (tileData) { \
if (!GBA_TEXT_MAP_HFLIP(mapData)) { \
BACKGROUND_DRAW_PIXEL_16(BLEND, OBJWIN, 0); \
BACKGROUND_DRAW_PIXEL_16(BLEND, OBJWIN, 1); \
BACKGROUND_DRAW_PIXEL_16(BLEND, OBJWIN, 2); \
BACKGROUND_DRAW_PIXEL_16(BLEND, OBJWIN, 3); \
BACKGROUND_DRAW_PIXEL_16(BLEND, OBJWIN, 4); \
BACKGROUND_DRAW_PIXEL_16(BLEND, OBJWIN, 5); \
BACKGROUND_DRAW_PIXEL_16(BLEND, OBJWIN, 6); \
BACKGROUND_DRAW_PIXEL_16(BLEND, OBJWIN, 7); \
} else { \
BACKGROUND_DRAW_PIXEL_16(BLEND, OBJWIN, 7); \
BACKGROUND_DRAW_PIXEL_16(BLEND, OBJWIN, 6); \
BACKGROUND_DRAW_PIXEL_16(BLEND, OBJWIN, 5); \
BACKGROUND_DRAW_PIXEL_16(BLEND, OBJWIN, 4); \
BACKGROUND_DRAW_PIXEL_16(BLEND, OBJWIN, 3); \
BACKGROUND_DRAW_PIXEL_16(BLEND, OBJWIN, 2); \
BACKGROUND_DRAW_PIXEL_16(BLEND, OBJWIN, 1); \
BACKGROUND_DRAW_PIXEL_16(BLEND, OBJWIN, 0); \
} \
BACKGROUND_DRAW_PIXEL_16(BLEND, OBJWIN, 0); \
BACKGROUND_DRAW_PIXEL_16(BLEND, OBJWIN, 1); \
BACKGROUND_DRAW_PIXEL_16(BLEND, OBJWIN, 2); \
BACKGROUND_DRAW_PIXEL_16(BLEND, OBJWIN, 3); \
BACKGROUND_DRAW_PIXEL_16(BLEND, OBJWIN, 4); \
BACKGROUND_DRAW_PIXEL_16(BLEND, OBJWIN, 5); \
BACKGROUND_DRAW_PIXEL_16(BLEND, OBJWIN, 6); \
BACKGROUND_DRAW_PIXEL_16(BLEND, OBJWIN, 7); \
} \
pixel += 8; \
}
@ -523,17 +512,16 @@ void GBAVideoSoftwareRendererDrawBackgroundMode0(struct GBAVideoSoftwareRenderer
uint32_t screenBase;
uint32_t charBase;
color_t* mainPalette = renderer->normalPalette;
color_t* palette = renderer->normalPalette;
if (renderer->d.highlightAmount && background->highlight) {
mainPalette = renderer->highlightPalette;
palette = renderer->highlightPalette;
}
if (variant) {
mainPalette = renderer->variantPalette;
palette = renderer->variantPalette;
if (renderer->d.highlightAmount && background->highlight) {
mainPalette = renderer->highlightVariantPalette;
palette = renderer->highlightVariantPalette;
}
}
color_t* palette = mainPalette;
PREPARE_OBJWIN;
int outX = renderer->start;

View File

@ -169,10 +169,10 @@ int GBAVideoSoftwareRendererPreprocessSprite(struct GBAVideoSoftwareRenderer* re
(renderer->blendEffect == BLEND_BRIGHTEN || renderer->blendEffect == BLEND_DARKEN);
if (GBAObjAttributesAGetMode(sprite->a) == OBJ_MODE_SEMITRANSPARENT || (renderer->target1Obj && renderer->blendEffect == BLEND_ALPHA) || objwinSlowPath) {
int target2 = renderer->target2Bd;
target2 |= renderer->bg[0].target2;
target2 |= renderer->bg[1].target2;
target2 |= renderer->bg[2].target2;
target2 |= renderer->bg[3].target2;
target2 |= renderer->bg[0].target2 && renderer->bg[0].enabled;
target2 |= renderer->bg[1].target2 && renderer->bg[1].enabled;
target2 |= renderer->bg[2].target2 && renderer->bg[2].enabled;
target2 |= renderer->bg[3].target2 && renderer->bg[3].enabled;
if (target2) {
renderer->forceTarget1 = true;
flags |= FLAG_REBLEND;

View File

@ -86,28 +86,55 @@ static inline void _compositeNoBlendNoObjwin(struct GBAVideoSoftwareRenderer* re
#define COMPOSITE_16_OBJWIN(BLEND, IDX) \
if (objwinForceEnable || (!(current & FLAG_OBJWIN)) == objwinOnly) { \
unsigned color = (current & FLAG_OBJWIN) ? objwinPalette[paletteData | pixelData] : palette[pixelData]; \
unsigned color; \
unsigned mergedFlags = flags; \
if (current & FLAG_OBJWIN) { \
mergedFlags = objwinFlags; \
color = objwinPalette[paletteData | pixelData]; \
} else if ((current & (FLAG_IS_BACKGROUND | FLAG_REBLEND)) == FLAG_REBLEND) { \
color = renderer->normalPalette[paletteData | pixelData]; \
} else { \
color = palette[paletteData | pixelData]; \
} \
_composite ## BLEND ## Objwin(renderer, &pixel[IDX], color | mergedFlags, current); \
}
#define COMPOSITE_16_NO_OBJWIN(BLEND, IDX) \
_composite ## BLEND ## NoObjwin(renderer, &pixel[IDX], palette[pixelData] | flags, current);
{ \
unsigned color; \
if ((current & (FLAG_IS_BACKGROUND | FLAG_REBLEND)) == FLAG_REBLEND) { \
color = renderer->normalPalette[paletteData | pixelData]; \
} else { \
color = palette[paletteData | pixelData]; \
} \
_composite ## BLEND ## NoObjwin(renderer, &pixel[IDX], color | flags, current); \
}
#define COMPOSITE_256_OBJWIN(BLEND, IDX) \
if (objwinForceEnable || (!(current & FLAG_OBJWIN)) == objwinOnly) { \
unsigned color = (current & FLAG_OBJWIN) ? objwinPalette[pixelData] : palette[pixelData]; \
unsigned color; \
unsigned mergedFlags = flags; \
if (current & FLAG_OBJWIN) { \
mergedFlags = objwinFlags; \
color = objwinPalette[pixelData]; \
} else if ((current & (FLAG_IS_BACKGROUND | FLAG_REBLEND)) == FLAG_REBLEND) { \
color = renderer->normalPalette[pixelData]; \
} else { \
color = palette[pixelData]; \
} \
_composite ## BLEND ## Objwin(renderer, &pixel[IDX], color | mergedFlags, current); \
}
#define COMPOSITE_256_NO_OBJWIN COMPOSITE_16_NO_OBJWIN
#define COMPOSITE_256_NO_OBJWIN(BLEND, IDX) \
{ \
unsigned color; \
if ((current & (FLAG_IS_BACKGROUND | FLAG_REBLEND)) == FLAG_REBLEND) { \
color = renderer->normalPalette[pixelData]; \
} else { \
color = palette[pixelData]; \
} \
_composite ## BLEND ## NoObjwin(renderer, &pixel[IDX], color | flags, current); \
}
#define BACKGROUND_DRAW_PIXEL_16(BLEND, OBJWIN, IDX) \
pixelData = tileData & 0xF; \

View File

@ -69,22 +69,22 @@ void GBASavedataDeinit(struct GBASavedata* savedata) {
} else {
switch (savedata->type) {
case SAVEDATA_SRAM:
mappedMemoryFree(savedata->data, SIZE_CART_SRAM);
mappedMemoryFree(savedata->data, GBA_SIZE_SRAM);
break;
case SAVEDATA_SRAM512:
mappedMemoryFree(savedata->data, SIZE_CART_SRAM512);
mappedMemoryFree(savedata->data, GBA_SIZE_SRAM512);
break;
case SAVEDATA_FLASH512:
mappedMemoryFree(savedata->data, SIZE_CART_FLASH512);
mappedMemoryFree(savedata->data, GBA_SIZE_FLASH512);
break;
case SAVEDATA_FLASH1M:
mappedMemoryFree(savedata->data, SIZE_CART_FLASH1M);
mappedMemoryFree(savedata->data, GBA_SIZE_FLASH1M);
break;
case SAVEDATA_EEPROM:
mappedMemoryFree(savedata->data, SIZE_CART_EEPROM);
mappedMemoryFree(savedata->data, GBA_SIZE_EEPROM);
break;
case SAVEDATA_EEPROM512:
mappedMemoryFree(savedata->data, SIZE_CART_EEPROM512);
mappedMemoryFree(savedata->data, GBA_SIZE_EEPROM512);
break;
case SAVEDATA_FORCE_NONE:
case SAVEDATA_AUTODETECT:
@ -129,17 +129,17 @@ bool GBASavedataClone(struct GBASavedata* savedata, struct VFile* out) {
if (savedata->data) {
switch (savedata->type) {
case SAVEDATA_SRAM:
return out->write(out, savedata->data, SIZE_CART_SRAM) == SIZE_CART_SRAM;
return out->write(out, savedata->data, GBA_SIZE_SRAM) == GBA_SIZE_SRAM;
case SAVEDATA_SRAM512:
return out->write(out, savedata->data, SIZE_CART_SRAM512) == SIZE_CART_SRAM512;
return out->write(out, savedata->data, GBA_SIZE_SRAM512) == GBA_SIZE_SRAM512;
case SAVEDATA_FLASH512:
return out->write(out, savedata->data, SIZE_CART_FLASH512) == SIZE_CART_FLASH512;
return out->write(out, savedata->data, GBA_SIZE_FLASH512) == GBA_SIZE_FLASH512;
case SAVEDATA_FLASH1M:
return out->write(out, savedata->data, SIZE_CART_FLASH1M) == SIZE_CART_FLASH1M;
return out->write(out, savedata->data, GBA_SIZE_FLASH1M) == GBA_SIZE_FLASH1M;
case SAVEDATA_EEPROM:
return out->write(out, savedata->data, SIZE_CART_EEPROM) == SIZE_CART_EEPROM;
return out->write(out, savedata->data, GBA_SIZE_EEPROM) == GBA_SIZE_EEPROM;
case SAVEDATA_EEPROM512:
return out->write(out, savedata->data, SIZE_CART_EEPROM512) == SIZE_CART_EEPROM512;
return out->write(out, savedata->data, GBA_SIZE_EEPROM512) == GBA_SIZE_EEPROM512;
case SAVEDATA_AUTODETECT:
case SAVEDATA_FORCE_NONE:
return true;
@ -160,17 +160,17 @@ bool GBASavedataClone(struct GBASavedata* savedata, struct VFile* out) {
size_t GBASavedataSize(const struct GBASavedata* savedata) {
switch (savedata->type) {
case SAVEDATA_SRAM:
return SIZE_CART_SRAM;
return GBA_SIZE_SRAM;
case SAVEDATA_SRAM512:
return SIZE_CART_SRAM512;
return GBA_SIZE_SRAM512;
case SAVEDATA_FLASH512:
return SIZE_CART_FLASH512;
return GBA_SIZE_FLASH512;
case SAVEDATA_FLASH1M:
return SIZE_CART_FLASH1M;
return GBA_SIZE_FLASH1M;
case SAVEDATA_EEPROM:
return SIZE_CART_EEPROM;
return GBA_SIZE_EEPROM;
case SAVEDATA_EEPROM512:
return SIZE_CART_EEPROM512;
return GBA_SIZE_EEPROM512;
case SAVEDATA_FORCE_NONE:
return 0;
case SAVEDATA_AUTODETECT:
@ -262,14 +262,14 @@ void GBASavedataInitFlash(struct GBASavedata* savedata) {
mLOG(GBA_SAVE, WARN, "Can't re-initialize savedata");
return;
}
int32_t flashSize = SIZE_CART_FLASH512;
int32_t flashSize = GBA_SIZE_FLASH512;
if (savedata->type == SAVEDATA_FLASH1M) {
flashSize = SIZE_CART_FLASH1M;
flashSize = GBA_SIZE_FLASH1M;
}
off_t end;
if (!savedata->vf) {
end = 0;
savedata->data = anonymousMemoryMap(SIZE_CART_FLASH1M);
savedata->data = anonymousMemoryMap(GBA_SIZE_FLASH1M);
} else {
end = savedata->vf->size(savedata->vf);
if (end < flashSize) {
@ -279,7 +279,7 @@ void GBASavedataInitFlash(struct GBASavedata* savedata) {
}
savedata->currentBank = savedata->data;
if (end < SIZE_CART_FLASH512) {
if (end < GBA_SIZE_FLASH512) {
memset(&savedata->data[end], 0xFF, flashSize - end);
}
}
@ -291,14 +291,14 @@ void GBASavedataInitEEPROM(struct GBASavedata* savedata) {
mLOG(GBA_SAVE, WARN, "Can't re-initialize savedata");
return;
}
int32_t eepromSize = SIZE_CART_EEPROM512;
int32_t eepromSize = GBA_SIZE_EEPROM512;
if (savedata->type == SAVEDATA_EEPROM) {
eepromSize = SIZE_CART_EEPROM;
eepromSize = GBA_SIZE_EEPROM;
}
off_t end;
if (!savedata->vf) {
end = 0;
savedata->data = anonymousMemoryMap(SIZE_CART_EEPROM);
savedata->data = anonymousMemoryMap(GBA_SIZE_EEPROM);
} else {
end = savedata->vf->size(savedata->vf);
if (end < eepromSize) {
@ -306,8 +306,8 @@ void GBASavedataInitEEPROM(struct GBASavedata* savedata) {
}
savedata->data = savedata->vf->map(savedata->vf, eepromSize, savedata->mapMode);
}
if (end < SIZE_CART_EEPROM512) {
memset(&savedata->data[end], 0xFF, SIZE_CART_EEPROM512 - end);
if (end < GBA_SIZE_EEPROM512) {
memset(&savedata->data[end], 0xFF, GBA_SIZE_EEPROM512 - end);
}
}
@ -321,17 +321,17 @@ void GBASavedataInitSRAM(struct GBASavedata* savedata) {
off_t end;
if (!savedata->vf) {
end = 0;
savedata->data = anonymousMemoryMap(SIZE_CART_SRAM);
savedata->data = anonymousMemoryMap(GBA_SIZE_SRAM);
} else {
end = savedata->vf->size(savedata->vf);
if (end < SIZE_CART_SRAM) {
savedata->vf->truncate(savedata->vf, SIZE_CART_SRAM);
if (end < GBA_SIZE_SRAM) {
savedata->vf->truncate(savedata->vf, GBA_SIZE_SRAM);
}
savedata->data = savedata->vf->map(savedata->vf, SIZE_CART_SRAM, savedata->mapMode);
savedata->data = savedata->vf->map(savedata->vf, GBA_SIZE_SRAM, savedata->mapMode);
}
if (end < SIZE_CART_SRAM) {
memset(&savedata->data[end], 0xFF, SIZE_CART_SRAM - end);
if (end < GBA_SIZE_SRAM) {
memset(&savedata->data[end], 0xFF, GBA_SIZE_SRAM - end);
}
}
@ -345,17 +345,17 @@ void GBASavedataInitSRAM512(struct GBASavedata* savedata) {
off_t end;
if (!savedata->vf) {
end = 0;
savedata->data = anonymousMemoryMap(SIZE_CART_SRAM512);
savedata->data = anonymousMemoryMap(GBA_SIZE_SRAM512);
} else {
end = savedata->vf->size(savedata->vf);
if (end < SIZE_CART_SRAM512) {
savedata->vf->truncate(savedata->vf, SIZE_CART_SRAM512);
if (end < GBA_SIZE_SRAM512) {
savedata->vf->truncate(savedata->vf, GBA_SIZE_SRAM512);
}
savedata->data = savedata->vf->map(savedata->vf, SIZE_CART_SRAM512, savedata->mapMode);
savedata->data = savedata->vf->map(savedata->vf, GBA_SIZE_SRAM512, savedata->mapMode);
}
if (end < SIZE_CART_SRAM512) {
memset(&savedata->data[end], 0xFF, SIZE_CART_SRAM512 - end);
if (end < GBA_SIZE_SRAM512) {
memset(&savedata->data[end], 0xFF, GBA_SIZE_SRAM512 - end);
}
}
@ -465,7 +465,7 @@ void GBASavedataWriteFlash(struct GBASavedata* savedata, uint16_t address, uint8
}
static void _ensureEeprom(struct GBASavedata* savedata, uint32_t size) {
if (size < SIZE_CART_EEPROM512) {
if (size < GBA_SIZE_EEPROM512) {
return;
}
if (savedata->type == SAVEDATA_EEPROM) {
@ -475,13 +475,13 @@ static void _ensureEeprom(struct GBASavedata* savedata, uint32_t size) {
if (!savedata->vf) {
return;
}
savedata->vf->unmap(savedata->vf, savedata->data, SIZE_CART_EEPROM512);
if (savedata->vf->size(savedata->vf) < SIZE_CART_EEPROM) {
savedata->vf->truncate(savedata->vf, SIZE_CART_EEPROM);
savedata->data = savedata->vf->map(savedata->vf, SIZE_CART_EEPROM, savedata->mapMode);
memset(&savedata->data[SIZE_CART_EEPROM512], 0xFF, SIZE_CART_EEPROM - SIZE_CART_EEPROM512);
savedata->vf->unmap(savedata->vf, savedata->data, GBA_SIZE_EEPROM512);
if (savedata->vf->size(savedata->vf) < GBA_SIZE_EEPROM) {
savedata->vf->truncate(savedata->vf, GBA_SIZE_EEPROM);
savedata->data = savedata->vf->map(savedata->vf, GBA_SIZE_EEPROM, savedata->mapMode);
memset(&savedata->data[GBA_SIZE_EEPROM512], 0xFF, GBA_SIZE_EEPROM - GBA_SIZE_EEPROM512);
} else {
savedata->data = savedata->vf->map(savedata->vf, SIZE_CART_EEPROM, savedata->mapMode);
savedata->data = savedata->vf->map(savedata->vf, GBA_SIZE_EEPROM, savedata->mapMode);
}
}
@ -509,7 +509,7 @@ void GBASavedataWriteEEPROM(struct GBASavedata* savedata, uint16_t value, uint32
savedata->writeAddress |= (value & 0x1) << 6;
} else if (writeSize == 1) {
savedata->command = EEPROM_COMMAND_NULL;
} else if ((savedata->writeAddress >> 3) < SIZE_CART_EEPROM) {
} else if ((savedata->writeAddress >> 3) < GBA_SIZE_EEPROM) {
_ensureEeprom(savedata, savedata->writeAddress >> 3);
uint8_t current = savedata->data[savedata->writeAddress >> 3];
current &= ~(1 << (0x7 - (savedata->writeAddress & 0x7)));
@ -551,7 +551,7 @@ uint16_t GBASavedataReadEEPROM(struct GBASavedata* savedata) {
int step = 63 - savedata->readBitsRemaining;
uint32_t address = (savedata->readAddress + step) >> 3;
_ensureEeprom(savedata, address);
if (address >= SIZE_CART_EEPROM) {
if (address >= GBA_SIZE_EEPROM) {
mLOG(GBA_SAVE, GAME_ERROR, "Reading beyond end of EEPROM: %08X", address);
return 0xFF;
}
@ -699,13 +699,13 @@ void _flashSwitchBank(struct GBASavedata* savedata, int bank) {
mLOG(GBA_SAVE, INFO, "Updating flash chip from 512kb to 1Mb");
savedata->type = SAVEDATA_FLASH1M;
if (savedata->vf) {
savedata->vf->unmap(savedata->vf, savedata->data, SIZE_CART_FLASH512);
if (savedata->vf->size(savedata->vf) < SIZE_CART_FLASH1M) {
savedata->vf->truncate(savedata->vf, SIZE_CART_FLASH1M);
savedata->data = savedata->vf->map(savedata->vf, SIZE_CART_FLASH1M, MAP_WRITE);
memset(&savedata->data[SIZE_CART_FLASH512], 0xFF, SIZE_CART_FLASH512);
savedata->vf->unmap(savedata->vf, savedata->data, GBA_SIZE_FLASH512);
if (savedata->vf->size(savedata->vf) < GBA_SIZE_FLASH1M) {
savedata->vf->truncate(savedata->vf, GBA_SIZE_FLASH1M);
savedata->data = savedata->vf->map(savedata->vf, GBA_SIZE_FLASH1M, MAP_WRITE);
memset(&savedata->data[GBA_SIZE_FLASH512], 0xFF, GBA_SIZE_FLASH512);
} else {
savedata->data = savedata->vf->map(savedata->vf, SIZE_CART_FLASH1M, MAP_WRITE);
savedata->data = savedata->vf->map(savedata->vf, GBA_SIZE_FLASH1M, MAP_WRITE);
}
}
}
@ -715,9 +715,9 @@ void _flashSwitchBank(struct GBASavedata* savedata, int bank) {
void _flashErase(struct GBASavedata* savedata) {
mLOG(GBA_SAVE, DEBUG, "Performing flash chip erase");
savedata->dirty |= mSAVEDATA_DIRT_NEW;
size_t size = SIZE_CART_FLASH512;
size_t size = GBA_SIZE_FLASH512;
if (savedata->type == SAVEDATA_FLASH1M) {
size = SIZE_CART_FLASH1M;
size = GBA_SIZE_FLASH1M;
}
memset(savedata->data, 0xFF, size);
}

View File

@ -102,7 +102,7 @@ bool GBADeserialize(struct GBA* gba, const struct GBASerializedState* state) {
mLOG(GBA_STATE, WARN, "Savestate created using a different version of the BIOS: expected %08X, got %08X", gba->biosChecksum, ucheck);
uint32_t pc;
LOAD_32(pc, ARM_PC * sizeof(state->cpu.gprs[0]), state->cpu.gprs);
if ((ucheck == GBA_BIOS_CHECKSUM || gba->biosChecksum == GBA_BIOS_CHECKSUM) && pc < SIZE_BIOS && pc >= 0x20) {
if ((ucheck == GBA_BIOS_CHECKSUM || gba->biosChecksum == GBA_BIOS_CHECKSUM) && pc < GBA_SIZE_BIOS && pc >= 0x20) {
error = true;
}
}
@ -128,7 +128,7 @@ bool GBADeserialize(struct GBA* gba, const struct GBASerializedState* state) {
}
LOAD_32(check, ARM_PC * sizeof(state->cpu.gprs[0]), state->cpu.gprs);
int region = (check >> BASE_OFFSET);
if ((region == REGION_CART0 || region == REGION_CART1 || region == REGION_CART2) && ((check - WORD_SIZE_ARM) & SIZE_CART0) >= gba->memory.romSize - WORD_SIZE_ARM) {
if ((region == GBA_REGION_ROM0 || region == GBA_REGION_ROM1 || region == GBA_REGION_ROM2) && ((check - WORD_SIZE_ARM) & GBA_SIZE_ROM0) >= gba->memory.romSize - WORD_SIZE_ARM) {
mLOG(GBA_STATE, WARN, "Savestate created using a differently sized version of the ROM");
error = true;
}

View File

@ -19,7 +19,7 @@ static bool _importSavedata(struct GBA* gba, void* payload, size_t size) {
bool success = false;
switch (gba->memory.savedata.type) {
case SAVEDATA_FLASH512:
if (size > SIZE_CART_FLASH512) {
if (size > GBA_SIZE_FLASH512) {
GBASavedataForceType(&gba->memory.savedata, SAVEDATA_FLASH1M);
}
// Fall through
@ -33,7 +33,7 @@ static bool _importSavedata(struct GBA* gba, void* payload, size_t size) {
goto cleanup;
}
if (size == SIZE_CART_EEPROM || size == SIZE_CART_EEPROM512) {
if (size == GBA_SIZE_EEPROM || size == GBA_SIZE_EEPROM512) {
size_t i;
for (i = 0; i < size; i += 8) {
uint32_t lo, hi;
@ -119,7 +119,7 @@ int GBASavedataSharkPortPayloadSize(struct VFile* vf) {
void* GBASavedataSharkPortGetPayload(struct VFile* vf, size_t* osize, uint8_t* oheader, bool testChecksum) {
int32_t size = GBASavedataSharkPortPayloadSize(vf);
if (size < 0x1C || size > SIZE_CART_FLASH1M + 0x1C) {
if (size < 0x1C || size > GBA_SIZE_FLASH1M + 0x1C) {
return NULL;
}
size -= 0x1C;
@ -336,15 +336,15 @@ int GBASavedataGSVPayloadSize(struct VFile* vf) {
LOAD_32(type, 0, &header.type);
switch (type) {
case 2:
return SIZE_CART_SRAM;
return GBA_SIZE_SRAM;
case 3:
return SIZE_CART_EEPROM512;
return GBA_SIZE_EEPROM512;
case 4:
return SIZE_CART_EEPROM;
return GBA_SIZE_EEPROM;
case 5:
return SIZE_CART_FLASH512;
return GBA_SIZE_FLASH512;
case 6:
return SIZE_CART_FLASH1M; // Unconfirmed
return GBA_SIZE_FLASH1M; // Unconfirmed
default:
return vf->size(vf) - GSV_PAYLOAD_OFFSET;
}
@ -352,7 +352,7 @@ int GBASavedataGSVPayloadSize(struct VFile* vf) {
void* GBASavedataGSVGetPayload(struct VFile* vf, size_t* osize, uint8_t* ident, bool testChecksum) {
int32_t size = GBASavedataGSVPayloadSize(vf);
if (!size || size > SIZE_CART_FLASH1M) {
if (!size || size > GBA_SIZE_FLASH1M) {
return NULL;
}

View File

@ -54,7 +54,7 @@ MGBA_EXPORT const int GBAVideoObjSizes[16][2] = {
void GBAVideoInit(struct GBAVideo* video) {
video->renderer = NULL;
video->vram = anonymousMemoryMap(SIZE_VRAM);
video->vram = anonymousMemoryMap(GBA_SIZE_VRAM);
video->frameskip = 0;
video->event.name = "GBA Video";
video->event.callback = NULL;
@ -93,7 +93,7 @@ void GBAVideoReset(struct GBAVideo* video) {
void GBAVideoDeinit(struct GBAVideo* video) {
video->renderer->deinit(video->renderer);
mappedMemoryFree(video->vram, SIZE_VRAM);
mappedMemoryFree(video->vram, GBA_SIZE_VRAM);
}
void GBAVideoDummyRendererCreate(struct GBAVideoRenderer* renderer) {
@ -325,9 +325,9 @@ static void GBAVideoDummyRendererPutPixels(struct GBAVideoRenderer* renderer, si
}
void GBAVideoSerialize(const struct GBAVideo* video, struct GBASerializedState* state) {
memcpy(state->vram, video->vram, SIZE_VRAM);
memcpy(state->oam, video->oam.raw, SIZE_OAM);
memcpy(state->pram, video->palette, SIZE_PALETTE_RAM);
memcpy(state->vram, video->vram, GBA_SIZE_VRAM);
memcpy(state->oam, video->oam.raw, GBA_SIZE_OAM);
memcpy(state->pram, video->palette, GBA_SIZE_PALETTE_RAM);
STORE_32(video->event.when - mTimingCurrentTime(&video->p->timing), 0, &state->video.nextEvent);
int32_t flags = 0;
if (video->event.callback == _startHdraw) {
@ -340,16 +340,16 @@ void GBAVideoSerialize(const struct GBAVideo* video, struct GBASerializedState*
}
void GBAVideoDeserialize(struct GBAVideo* video, const struct GBASerializedState* state) {
memcpy(video->vram, state->vram, SIZE_VRAM);
memcpy(video->vram, state->vram, GBA_SIZE_VRAM);
uint16_t value;
int i;
for (i = 0; i < SIZE_OAM; i += 2) {
for (i = 0; i < GBA_SIZE_OAM; i += 2) {
LOAD_16(value, i, state->oam);
GBAStore16(video->p->cpu, BASE_OAM | i, value, 0);
GBAStore16(video->p->cpu, GBA_BASE_OAM | i, value, 0);
}
for (i = 0; i < SIZE_PALETTE_RAM; i += 2) {
for (i = 0; i < GBA_SIZE_PALETTE_RAM; i += 2) {
LOAD_16(value, i, state->pram);
GBAStore16(video->p->cpu, BASE_PALETTE_RAM | i, value, 0);
GBAStore16(video->p->cpu, GBA_BASE_PALETTE_RAM | i, value, 0);
}
LOAD_32(video->frameCounter, 0, &state->video.frameCounter);

View File

@ -1,4 +1,4 @@
set(USE_VFS_3DS ON CACHE BOOL "Use 3DS-specific file support")
set(USE_VFS_3DS OFF CACHE BOOL "Use 3DS-specific file support")
mark_as_advanced(USE_VFS_3DS)
find_program(3DSLINK 3dslink)

View File

@ -817,7 +817,16 @@ THREAD_ENTRY _core2Test(void* context) {
UNUSED(context);
}
int main() {
int main(int argc, char* argv[]) {
char initialPath[PATH_MAX] = { 0 };
if (argc > 1) {
strncpy(initialPath, argv[1], sizeof(PATH_MAX));
} else {
u8 hmac[0x20];
memset(hmac, 0, sizeof(hmac));
APT_ReceiveDeliverArg(initialPath, sizeof(initialPath), hmac, NULL, NULL);
}
rotation.d.sample = _sampleRotation;
rotation.d.readTiltX = _readTiltX;
rotation.d.readTiltY = _readTiltY;
@ -1046,9 +1055,29 @@ int main() {
_map3DSKey(&runner.params.keyMap, KEY_CSTICK_UP, mGUI_INPUT_INCREASE_BRIGHTNESS);
_map3DSKey(&runner.params.keyMap, KEY_CSTICK_DOWN, mGUI_INPUT_DECREASE_BRIGHTNESS);
mGUIRunloop(&runner);
Result res = romfsInit();
bool useRomfs = false;
if (R_SUCCEEDED(res)) {
useRomfs = mGUIGetRom(&runner, initialPath, sizeof(initialPath));
if (!useRomfs) {
romfsExit();
_cleanup();
return 1;
}
}
if (initialPath[0] == '/' || useRomfs) {
mGUILoadInputMaps(&runner);
mGUIRun(&runner, initialPath);
} else {
mGUIRunloop(&runner);
}
mGUIDeinit(&runner);
if (useRomfs) {
romfsExit();
}
_cleanup();
return 0;
}

View File

@ -617,6 +617,39 @@ void retro_run(void) {
core->desiredVideoDimensions(core, &width, &height);
videoCallback(outputBuffer, width, height, BYTES_PER_PIXEL * 256);
#ifdef M_CORE_GBA
if (core->platform(core) == mPLATFORM_GBA) {
blip_t *audioChannelLeft = core->getAudioChannel(core, 0);
blip_t *audioChannelRight = core->getAudioChannel(core, 1);
int samplesAvail = blip_samples_avail(audioChannelLeft);
if (samplesAvail > 0) {
/* Update 'running average' of number of
* samples per frame.
* Note that this is not a true running
* average, but just a leaky-integrator/
* exponential moving average, used because
* it is simple and fast (i.e. requires no
* window of samples). */
audioSamplesPerFrameAvg = (SAMPLES_PER_FRAME_MOVING_AVG_ALPHA * (float)samplesAvail) +
((1.0f - SAMPLES_PER_FRAME_MOVING_AVG_ALPHA) * audioSamplesPerFrameAvg);
size_t samplesToRead = (size_t)(audioSamplesPerFrameAvg);
/* Resize audio output buffer, if required */
if (audioSampleBufferSize < (samplesToRead * 2)) {
audioSampleBufferSize = (samplesToRead * 2);
audioSampleBuffer = realloc(audioSampleBuffer, audioSampleBufferSize * sizeof(int16_t));
}
int produced = blip_read_samples(audioChannelLeft, audioSampleBuffer, samplesToRead, true);
blip_read_samples(audioChannelRight, audioSampleBuffer + 1, samplesToRead, true);
if (produced > 0) {
if (audioLowPassEnabled) {
_audioLowPassFilter(audioSampleBuffer, produced);
}
audioCallback(audioSampleBuffer, (size_t)produced);
}
}
}
#endif
if (rumbleCallback) {
if (rumbleUp) {
rumbleCallback(0, RETRO_RUMBLE_STRONG, rumbleUp * 0xFFFF / (rumbleUp + rumbleDown));
@ -643,66 +676,66 @@ static void _setupMaps(struct mCore* core) {
/* Map internal working RAM */
descs[0].ptr = gba->memory.iwram;
descs[0].start = BASE_WORKING_IRAM;
descs[0].len = SIZE_WORKING_IRAM;
descs[0].start = GBA_BASE_IWRAM;
descs[0].len = GBA_SIZE_IWRAM;
descs[0].select = 0xFF000000;
/* Map working RAM */
descs[1].ptr = gba->memory.wram;
descs[1].start = BASE_WORKING_RAM;
descs[1].len = SIZE_WORKING_RAM;
descs[1].start = GBA_BASE_EWRAM;
descs[1].len = GBA_SIZE_EWRAM;
descs[1].select = 0xFF000000;
/* Map save RAM */
/* TODO: if SRAM is flash, use start=0 addrspace="S" instead */
descs[2].ptr = savedataSize ? savedata : NULL;
descs[2].start = BASE_CART_SRAM;
descs[2].start = GBA_BASE_SRAM;
descs[2].len = savedataSize;
/* Map ROM */
descs[3].ptr = gba->memory.rom;
descs[3].start = BASE_CART0;
descs[3].start = GBA_BASE_ROM0;
descs[3].len = romSize;
descs[3].flags = RETRO_MEMDESC_CONST;
descs[4].ptr = gba->memory.rom;
descs[4].start = BASE_CART1;
descs[4].start = GBA_BASE_ROM1;
descs[4].len = romSize;
descs[4].flags = RETRO_MEMDESC_CONST;
descs[5].ptr = gba->memory.rom;
descs[5].start = BASE_CART2;
descs[5].start = GBA_BASE_ROM2;
descs[5].len = romSize;
descs[5].flags = RETRO_MEMDESC_CONST;
/* Map BIOS */
descs[6].ptr = gba->memory.bios;
descs[6].start = BASE_BIOS;
descs[6].len = SIZE_BIOS;
descs[6].start = GBA_BASE_BIOS;
descs[6].len = GBA_SIZE_BIOS;
descs[6].flags = RETRO_MEMDESC_CONST;
/* Map VRAM */
descs[7].ptr = gba->video.vram;
descs[7].start = BASE_VRAM;
descs[7].len = SIZE_VRAM;
descs[7].start = GBA_BASE_VRAM;
descs[7].len = GBA_SIZE_VRAM;
descs[7].select = 0xFF000000;
/* Map palette RAM */
descs[8].ptr = gba->video.palette;
descs[8].start = BASE_PALETTE_RAM;
descs[8].len = SIZE_PALETTE_RAM;
descs[8].start = GBA_BASE_PALETTE_RAM;
descs[8].len = GBA_SIZE_PALETTE_RAM;
descs[8].select = 0xFF000000;
/* Map OAM */
descs[9].ptr = &gba->video.oam; /* video.oam is a structure */
descs[9].start = BASE_OAM;
descs[9].len = SIZE_OAM;
descs[9].start = GBA_BASE_OAM;
descs[9].len = GBA_SIZE_OAM;
descs[9].select = 0xFF000000;
/* Map mmapped I/O */
descs[10].ptr = gba->memory.io;
descs[10].start = BASE_IO;
descs[10].len = SIZE_IO;
descs[10].start = GBA_BASE_IO;
descs[10].len = GBA_SIZE_IO;
mmaps.descriptors = descs;
mmaps.num_descriptors = sizeof(descs) / sizeof(descs[0]);

View File

@ -12,14 +12,12 @@ CXX_GUARD_START
#ifdef USE_EPOXY
#include <epoxy/gl.h>
#elif defined(BUILD_GL)
#ifdef __APPLE__
#elif defined(__APPLE__)
#include <OpenGL/gl3.h>
#else
#elif defined(BUILD_GL)
#define GL_GLEXT_PROTOTYPES
#include <GL/gl.h>
#include <GL/glext.h>
#endif
#elif defined(BUILD_GLES3)
#include <GLES3/gl3.h>
#else

View File

@ -153,6 +153,8 @@ static enum GUIKeyboardStatus _keyboardRun(struct GUIKeyboardParams* keyboard) {
}
int main() {
char initialPath[PATH_MAX] = { 0 };
vita2d_init();
struct GUIFont* font = GUIFontCreate();
struct mGUIRunner runner = {
@ -278,7 +280,13 @@ int main() {
mPSP2MapKey(&runner.params.keyMap, SCE_CTRL_SQUARE, mGUI_INPUT_SCREEN_MODE);
scePowerSetArmClockFrequency(444);
mGUIRunloop(&runner);
if (mGUIGetRom(&runner, initialPath, sizeof(initialPath))) {
mGUILoadInputMaps(&runner);
mGUIRun(&runner, initialPath);
} else {
mGUIRunloop(&runner);
}
vita2d_fini();
mGUIDeinit(&runner);

View File

@ -123,19 +123,19 @@ class GBAMemory(Memory):
def __init__(self, core, romSize=lib.SIZE_CART0):
super(GBAMemory, self).__init__(core, 0x100000000)
self.bios = Memory(core, lib.SIZE_BIOS, lib.BASE_BIOS)
self.wram = Memory(core, lib.SIZE_WORKING_RAM, lib.BASE_WORKING_RAM)
self.iwram = Memory(core, lib.SIZE_WORKING_IRAM, lib.BASE_WORKING_IRAM)
self.io = Memory(core, lib.SIZE_IO, lib.BASE_IO) # pylint: disable=invalid-name
self.palette = Memory(core, lib.SIZE_PALETTE_RAM, lib.BASE_PALETTE_RAM)
self.vram = Memory(core, lib.SIZE_VRAM, lib.BASE_VRAM)
self.oam = Memory(core, lib.SIZE_OAM, lib.BASE_OAM)
self.bios = Memory(core, lib.GBA_SIZE_BIOS, lib.GBA_BASE_BIOS)
self.wram = Memory(core, lib.GBA_SIZE_EWRAM, lib.GBA_BASE_EWRAM)
self.iwram = Memory(core, lib.GBA_SIZE_IWRAM, lib.GBA_BASE_IWRAM)
self.io = Memory(core, lib.GBA_SIZE_IO, lib.GBA_BASE_IO) # pylint: disable=invalid-name
self.palette = Memory(core, lib.GBA_SIZE_PALETTE_RAM, lib.GBA_BASE_PALETTE_RAM)
self.vram = Memory(core, lib.GBA_SIZE_VRAM, lib.GBA_BASE_VRAM)
self.oam = Memory(core, lib.GBA_SIZE_OAM, lib.GBA_BASE_OAM)
self.cart0 = Memory(core, romSize, lib.BASE_CART0)
self.cart1 = Memory(core, romSize, lib.BASE_CART1)
self.cart2 = Memory(core, romSize, lib.BASE_CART2)
self.cart = self.cart0
self.rom = self.cart0
self.sram = Memory(core, lib.SIZE_CART_SRAM, lib.BASE_CART_SRAM)
self.sram = Memory(core, lib.GBA_SIZE_SRAM, lib.GBA_BASE_SRAM)
class GBASprite(Sprite):

View File

@ -74,7 +74,7 @@ AboutScreen::AboutScreen(QWidget* parent)
{
QString copyright = m_ui.copyright->text();
copyright.replace("{year}", QLatin1String("2022"));
copyright.replace("{year}", QLatin1String("2023"));
m_ui.copyright->setText(copyright);
}
}

View File

@ -8,16 +8,17 @@
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include "GBAApp.h"
using namespace QGBA;
AbstractUpdater::AbstractUpdater(QObject* parent)
: QObject(parent)
, m_netman(new QNetworkAccessManager(this))
{
}
void AbstractUpdater::checkUpdate() {
QNetworkReply* reply = m_netman->get(QNetworkRequest(manifestLocation()));
QNetworkReply* reply = GBAApp::app()->httpGet(manifestLocation());
chaseRedirects(reply, &AbstractUpdater::manifestDownloaded);
}
@ -36,7 +37,7 @@ void AbstractUpdater::downloadUpdate() {
return;
}
m_isUpdating = true;
QNetworkReply* reply = m_netman->get(QNetworkRequest(url));
QNetworkReply* reply = GBAApp::app()->httpGet(url);
chaseRedirects(reply, &AbstractUpdater::updateDownloaded);
}
@ -54,7 +55,7 @@ void AbstractUpdater::chaseRedirects(QNetworkReply* reply, void (AbstractUpdater
connect(reply, &QNetworkReply::finished, this, [this, reply, cb]() {
// TODO: check domains, etc
if (reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt() / 100 == 3) {
QNetworkReply* newReply = m_netman->get(QNetworkRequest(reply->header(QNetworkRequest::LocationHeader).toString()));
QNetworkReply* newReply = GBAApp::app()->httpGet(reply->header(QNetworkRequest::LocationHeader).toString());
chaseRedirects(newReply, cb);
} else {
(this->*cb)(reply);
@ -69,7 +70,7 @@ void AbstractUpdater::manifestDownloaded(QNetworkReply* reply) {
if (!url.isValid()) {
emit updateDone(false);
} else {
QNetworkReply* reply = m_netman->get(QNetworkRequest(url));
QNetworkReply* reply = GBAApp::app()->httpGet(url);
chaseRedirects(reply, &AbstractUpdater::updateDownloaded);
}
} else {

View File

@ -9,7 +9,6 @@
#include <QFile>
#include <QObject>
class QNetworkAccessManager;
class QNetworkReply;
namespace QGBA {
@ -44,7 +43,6 @@ private:
void updateDownloaded(QNetworkReply*);
bool m_isUpdating = false;
QNetworkAccessManager* m_netman;
QByteArray m_manifest;
};

View File

@ -7,6 +7,7 @@
#include <QDir>
#include <QFileInfo>
#include <QRegularExpression>
#include "ApplicationUpdatePrompt.h"
#include "ConfigController.h"
@ -71,9 +72,10 @@ QStringList ApplicationUpdater::listChannels() {
}
QString ApplicationUpdater::currentChannel() {
QLatin1String version(projectVersion);
QLatin1String branch(gitBranch);
if (branch == QLatin1String("heads/") + version) {
QString version(projectVersion);
QString branch(gitBranch);
QRegularExpression stable("^(?:(?:refs/)?(?:tags|heads)/)?[0-9]+\\.[0-9]+\\.[0-9]+$");
if (branch.contains(stable) || (branch == "(unknown)" && version.contains(stable))) {
return QLatin1String("stable");
} else {
return QLatin1String("dev");
@ -136,8 +138,16 @@ QUrl ApplicationUpdater::parseManifest(const QByteArray& manifest) {
QString ApplicationUpdater::destination() const {
QFileInfo path(updateInfo().url.path());
QDir dir(ConfigController::configDir());
return dir.filePath(QLatin1String("update.") + path.completeSuffix());
QDir dir(ConfigController::cacheDir());
// QFileInfo::completeSuffix will eat all .'s in the filename...including
// ones in the version string, turning mGBA-1.0.0-win32.7z into
// 0.0-win32.7z instead of the intended .7z
// As a result, so we have to split out the complete suffix manually.
QString suffix(path.suffix());
if (path.completeBaseName().endsWith(".tar")) {
suffix = "tar." + suffix;
}
return dir.filePath(QLatin1String("update.") + suffix);
}
const char* ApplicationUpdater::platform() {
@ -166,7 +176,8 @@ const char* ApplicationUpdater::platform() {
}
ApplicationUpdater::UpdateInfo::UpdateInfo(const QString& prefix, const mUpdate* update)
: size(update->size)
: rev(-1)
, size(update->size)
, url(prefix + update->path)
{
if (update->rev > 0) {

View File

@ -51,8 +51,8 @@ void AssetTile::setController(std::shared_ptr<CoreController> controller) {
#ifdef M_CORE_GBA
case mPLATFORM_GBA:
m_addressWidth = 8;
m_addressBase = BASE_VRAM;
m_boundaryBase = BASE_VRAM | 0x10000;
m_addressBase = GBA_BASE_VRAM;
m_boundaryBase = GBA_BASE_VRAM | 0x10000;
break;
#endif
#ifdef M_CORE_GB

View File

@ -39,7 +39,6 @@ if(NOT ${QT}Widgets_FOUND)
endif()
if(APPLE)
execute_process(COMMAND xcrun --show-sdk-version OUTPUT_VARIABLE MACOSX_SDK)
if(MACOSX_SDK VERSION_GREATER 10.14)
list(APPEND QT_DEFINES USE_SHARE_WIDGET)
endif()
@ -95,14 +94,24 @@ set(SOURCE_FILES
Display.cpp
DisplayGL.cpp
DisplayQt.cpp
ForwarderController.cpp
ForwarderGenerator.cpp
ForwarderGenerator3DS.cpp
ForwarderGeneratorVita.cpp
ForwarderView.cpp
FrameView.cpp
GBAApp.cpp
GBAKeyEditor.cpp
GIFView.cpp
GamepadAxisEvent.cpp
GamepadButtonEvent.cpp
GamepadHatEvent.cpp
IOViewer.cpp
input/Gamepad.cpp
input/GamepadAxisEvent.cpp
input/GamepadButtonEvent.cpp
input/GamepadHatEvent.cpp
input/InputDriver.cpp
input/InputSource.cpp
input/InputMapper.cpp
input/KeySource.cpp
InputController.cpp
InputProfile.cpp
KeyEditor.cpp
@ -119,6 +128,7 @@ set(SOURCE_FILES
MessagePainter.cpp
MultiplayerController.cpp
ObjView.cpp
OpenGLBug.cpp
OverrideView.cpp
PaletteView.cpp
PlacementControl.cpp
@ -152,6 +162,7 @@ set(UI_FILES
CheatsView.ui
DebuggerConsole.ui
DolphinConnector.ui
ForwarderView.ui
FrameView.ui
GIFView.ui
IOViewer.ui
@ -192,6 +203,7 @@ set(CPACK_DEBIAN_PACKAGE_DEPENDS "${CPACK_DEBIAN_PACKAGE_DEPENDS},libqt5widgets5
set(AUDIO_SRC)
if(BUILD_SDL)
list(APPEND SOURCE_FILES input/SDLInputDriver.cpp)
list(APPEND AUDIO_SRC AudioProcessorSDL.cpp)
endif()
@ -414,7 +426,7 @@ if(QT_STATIC)
list(APPEND QT_LIBRARIES "-framework AVFoundation" "-framework CoreMedia" "-framework SystemConfiguration" "-framework Security")
set_target_properties(${QT}::Core PROPERTIES INTERFACE_LINK_LIBRARIES "${QTPCRE}")
elseif(UNIX)
list(APPEND QT_LIBRARIES ${QT}::FontDatabaseSupport ${QT}::XcbQpa)
list(APPEND QT_LIBRARIES ${QT}::FontDatabaseSupport ${QT}::XcbQpa ${QT}::QWaylandIntegrationPlugin)
endif()
endif()
target_link_libraries(${BINARY_NAME}-qt ${PLATFORM_LIBRARY} ${BINARY_NAME} ${QT_LIBRARIES})

View File

@ -382,3 +382,7 @@ const QString& ConfigController::configDir() {
}
return s_configDir;
}
const QString& ConfigController::cacheDir() {
return configDir();
}

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