Merge branch 'master' (early part) into medusa

This commit is contained in:
Vicki Pfau 2024-06-21 00:19:59 -07:00
commit 4d104aeac1
90 changed files with 17402 additions and 5486 deletions

View File

@ -41,17 +41,24 @@ Misc:
0.11.0: (Future)
Features:
- Scripting: New `input` API for getting raw keyboard/mouse/controller state
- New unlicensed GB mappers: NT (older types 1 and 2), Li Cheng, GGB-81
- Debugger: Add range watchpoints
Emulation fixes:
- GBA Audio: Fix improperly deserializing GB audio registers (fixes mgba.io/i/2793)
- GBA Memory: Make VRAM access stalls only apply to BG RAM
- GBA SIO: Fix SIOCNT SI pin value after attaching player 2 (fixes mgba.io/i/2805)
- 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)
- Qt: Stop eating boolean action key events (fixes mgba.io/i/2636)
0.10.1: (2023-01-10)
Emulation fixes:

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

@ -23,60 +23,60 @@ CXX_GUARD_START
mLOG_DECLARE_CATEGORY(GBA_MEM);
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

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

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

@ -96,7 +96,7 @@ 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

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

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

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

View File

@ -261,8 +261,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);
@ -277,8 +287,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);
@ -294,6 +304,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

@ -17,7 +17,7 @@
#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

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

@ -123,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) {

View File

@ -33,6 +33,8 @@ struct mGUIBackground {
color_t* image;
size_t imageSize;
uint16_t w;
uint16_t h;
unsigned screenshotId;
};

View File

@ -1089,6 +1089,8 @@ void GBAudioPSGDeserialize(struct GBAudio* audio, const struct GBSerializedPSGSt
audio->ch4.lastEvent = currentTime + (when & (cycles - 1)) - cycles;
}
}
audio->ch4.nSamples = 0;
audio->ch4.samples = 0;
}
void GBAudioSerialize(const struct GBAudio* audio, struct GBSerializedState* state) {

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:
@ -506,6 +506,16 @@ void GBAAudioSerialize(const struct GBAAudio* audio, struct GBASerializedState*
void GBAAudioDeserialize(struct GBAAudio* audio, const struct GBASerializedState* state) {
GBAudioPSGDeserialize(&audio->psg, &state->audio.psg, &state->audio.flags);
uint16_t reg;
LOAD_16(reg, REG_SOUND1CNT_X, state->io);
GBAIOWrite(audio->p, REG_SOUND1CNT_X, reg & 0x7FFF);
LOAD_16(reg, REG_SOUND2CNT_HI, state->io);
GBAIOWrite(audio->p, REG_SOUND2CNT_HI, reg & 0x7FFF);
LOAD_16(reg, REG_SOUND3CNT_X, state->io);
GBAIOWrite(audio->p, REG_SOUND3CNT_X, reg & 0x7FFF);
LOAD_16(reg, REG_SOUND4CNT_HI, state->io);
GBAIOWrite(audio->p, REG_SOUND4CNT_HI, reg & 0x7FFF);
LOAD_32(audio->chA.internalSample, 0, &state->audio.internalA);
LOAD_32(audio->chB.internalSample, 0, &state->audio.internalB);
memcpy(audio->chA.samples, state->samples.chA, sizeof(audio->chA.samples));

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;
@ -486,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;
}
@ -501,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);
@ -510,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;
}
@ -518,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;
}
@ -535,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;
@ -552,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;
}
@ -569,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;
}
@ -587,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

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

@ -61,76 +61,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[] = {
@ -523,7 +523,7 @@ static bool _GBACoreLoadROM(struct mCore* core, struct VFile* vf) {
#ifdef USE_ELF
struct ELF* elf = ELFOpen(vf);
if (elf) {
if (GBAVerifyELFEntry(elf, BASE_CART0)) {
if (GBAVerifyELFEntry(elf, GBA_BASE_ROM0)) {
GBALoadNull(core->board);
}
bool success = mCoreLoadELF(core, elf);
@ -929,36 +929,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;
}
@ -1175,7 +1175,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;
}
}
@ -1343,7 +1343,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));
@ -1514,8 +1514,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) {
@ -1534,13 +1534,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) {
@ -274,14 +274,14 @@ void GBADMAService(struct GBA* gba, int number, struct GBADMA* info) {
}
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);
@ -296,7 +296,7 @@ void GBADMAService(struct GBA* gba, int number, struct GBADMA* info) {
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;
@ -321,7 +321,7 @@ void GBADMAService(struct GBA* gba, int number, struct GBADMA* info) {
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;
}
@ -89,8 +89,8 @@ 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->oam, &proxyRenderer->d.oam->raw, GBA_SIZE_OAM);
memcpy(proxyRenderer->logger->palette, proxyRenderer->d.palette, GBA_SIZE_PALETTE_RAM);
memcpy(&proxyRenderer->logger->vram[0x0000], proxyRenderer->d.vramBG[0], 0x4000);
memcpy(&proxyRenderer->logger->vram[0x2000], proxyRenderer->d.vramBG[1], 0x4000);
memcpy(&proxyRenderer->logger->vram[0x4000], proxyRenderer->d.vramBG[2], 0x4000);
@ -213,19 +213,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;
}
@ -247,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;
@ -259,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);
@ -274,11 +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] = BASE_WORKING_RAM + 0xC0;
cpu->gprs[ARM_PC] = GBA_BASE_EWRAM + 0xC0;
} else {
cpu->gprs[ARM_PC] = BASE_WORKING_RAM;
cpu->gprs[ARM_PC] = GBA_BASE_EWRAM;
}
gba->video.vcount = 0x7E;
gba->memory.io[REG_VCOUNT >> 1] = 0x7E;
@ -360,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) {
@ -381,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;
@ -405,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);
@ -415,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;
@ -429,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);
@ -450,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]);
@ -485,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");
@ -511,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
@ -519,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);
}
@ -665,7 +665,7 @@ bool GBAIsROM(struct VFile* vf) {
uint32_t entry = ELFEntry(elf);
bool isGBA = true;
isGBA = isGBA && ELFMachine(elf) == EM_ARM;
isGBA = isGBA && (GBAVerifyELFEntry(elf, BASE_CART0) || GBAVerifyELFEntry(elf, BASE_WORKING_RAM + 0xC0));
isGBA = isGBA && (GBAVerifyELFEntry(elf, GBA_BASE_ROM0) || GBAVerifyELFEntry(elf, GBA_BASE_EWRAM + 0xC0));
ELFClose(elf);
return isGBA;
}
@ -721,12 +721,12 @@ bool GBAIsMB(struct VFile* vf) {
#ifdef USE_ELF
struct ELF* elf = ELFOpen(vf);
if (elf) {
bool isMB = GBAVerifyELFEntry(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) {
@ -763,10 +763,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);
@ -789,10 +789,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

@ -296,8 +296,8 @@ static const int _isWSpecialRegister[REG_INTERNAL_MAX >> 1] = {
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
// Audio
1, 1, 1, 0, 1, 0, 1, 0,
1, 0, 1, 0, 1, 0, 1, 0,
0, 0, 1, 0, 0, 0, 1, 0,
0, 0, 1, 0, 0, 0, 1, 0,
0, 0, 1, 0, 0, 0, 0, 0,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 0, 0, 0, 0,
@ -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

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

@ -111,6 +111,18 @@ bool GBASIOLockstepNodeLoad(struct GBASIODriver* driver) {
if (node->id) {
node->d.p->rcnt |= 4;
node->d.p->siocnt = GBASIOMultiplayerFillSlave(node->d.p->siocnt);
int try;
for (try = 0; try < 3; ++try) {
uint16_t masterSiocnt;
ATOMIC_LOAD(masterSiocnt, node->p->players[0]->d.p->siocnt);
if (ATOMIC_CMPXCHG(node->p->players[0]->d.p->siocnt, masterSiocnt, GBASIOMultiplayerClearSlave(masterSiocnt))) {
break;
}
}
} else {
node->d.p->rcnt &= ~4;
node->d.p->siocnt = GBASIOMultiplayerClearSlave(node->d.p->siocnt);
}
break;
case SIO_NORMAL_8:

View File

@ -56,7 +56,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;
@ -107,7 +107,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) {
@ -348,9 +348,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) {
@ -363,16 +363,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

@ -677,66 +677,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

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

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

@ -225,7 +225,7 @@ if(${QT}Multimedia_FOUND)
list(APPEND SOURCE_FILES
VideoDumper.cpp)
if (WIN32 AND QT_STATIC)
list(APPEND QT_LIBRARIES ${QT}::QWindowsAudioPlugin ${QT}::DSServicePlugin ${QT}::QWindowsVistaStylePlugin
list(APPEND QT_LIBRARIES ${QT}::QWindowsAudioPlugin ${QT}::DSServicePlugin ${QT}::QWindowsVistaStylePlugin ${QT}::QJpegPlugin
strmiids mfuuid mfplat mf ksguid dxva2 evr d3d9)
endif()
list(APPEND QT_LIBRARIES ${QT}::Multimedia)

View File

@ -10,6 +10,7 @@
#include "DisplayGL.h"
#include "DisplayQt.h"
#include "LogController.h"
#include "utils.h"
#include <mgba-util/vfs.h>
@ -192,3 +193,32 @@ void QGBA::Display::setSystemDimensions(int width, int height) {
m_coreWidth = width;
m_coreHeight = height;
}
QPoint QGBA::Display::normalizedPoint(CoreController* controller, const QPoint& localRef) {
QSize screen(controller->screenDimensions());
#if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0))
QSize newSize((QSizeF(size()) * devicePixelRatioF()).toSize());
#else
QSize newSize((QSizeF(size()) * devicePixelRatio()).toSize());
#endif
if (m_lockAspectRatio) {
QGBA::lockAspectRatio(screen, newSize);
}
if (m_lockIntegerScaling) {
QGBA::lockIntegerScaling(screen, newSize);
}
QPointF newPos(localRef);
newPos -= QPointF(width() / 2.0, height() / 2.0);
newPos = QPointF(newPos.x() * screen.width(), newPos.y() * screen.height());
newPos = QPointF(newPos.x() / newSize.width(), newPos.y() / newSize.height());
#if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0))
newPos *= devicePixelRatioF();
#else
newPos *= devicePixelRatio();
#endif
newPos += QPointF(screen.width() / 2.0, screen.height() / 2.0);
return newPos.toPoint();
}

View File

@ -44,6 +44,8 @@ public:
bool isShowOSD() const { return m_showOSD; }
bool isShowFrameCounter() const { return m_showFrameCounter; }
QPoint normalizedPoint(CoreController*, const QPoint& localRef);
virtual void attach(std::shared_ptr<CoreController>);
virtual void configure(ConfigController*);
virtual void startDrawing(std::shared_ptr<CoreController>) = 0;

View File

@ -15,7 +15,7 @@
using namespace QGBA;
ForwarderView::ForwarderView(QWidget* parent)
: QDialog(parent)
: QDialog(parent, Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint)
{
m_ui.setupUi(this);
@ -189,7 +189,7 @@ void ForwarderView::connectBrowseButton(QAbstractButton* button, QLineEdit* line
}
void ForwarderView::selectImage() {
QString filename = GBAApp::app()->getOpenFileName(this, tr("Select an image"), {});
QString filename = GBAApp::app()->getOpenFileName(this, tr("Select an image"), tr("Image files (*.png *.jpg *.bmp)"));
if (filename.isEmpty()) {
return;
}

View File

@ -1580,7 +1580,7 @@ IOViewer::IOViewer(std::shared_ptr<CoreController> controller, QWidget* parent)
case mPLATFORM_GBA:
regs = GBAIORegisterNames;
maxRegs = REG_MAX >> 1;
m_base = BASE_IO;
m_base = GBA_BASE_IO;
m_width = 1;
break;
#endif

View File

@ -43,13 +43,12 @@ LoadSaveState::LoadSaveState(std::shared_ptr<CoreController> controller, QWidget
m_slots[7] = m_ui.state8;
m_slots[8] = m_ui.state9;
unsigned width, height;
controller->thread()->core->desiredVideoDimensions(controller->thread()->core, &width, &height);
QSize size = controller->screenDimensions();
int i;
for (i = 0; i < NUM_SLOTS; ++i) {
loadState(i + 1);
m_slots[i]->installEventFilter(this);
m_slots[i]->setMaximumSize(width + 2, height + 2);
m_slots[i]->setMaximumSize(size.width() + 2, size.height() + 2);
connect(m_slots[i], &QAbstractButton::clicked, this, [this, i]() { triggerState(i + 1); });
}
@ -199,11 +198,17 @@ void LoadSaveState::loadState(int slot) {
QDateTime creation;
QImage stateImage;
unsigned width, height;
thread->core->desiredVideoDimensions(thread->core, &width, &height);
QSize size = m_controller->screenDimensions();
mStateExtdataItem item;
if (mStateExtdataGet(&extdata, EXTDATA_SCREENSHOT, &item) && item.size >= static_cast<int32_t>(width * height * 4)) {
stateImage = QImage((uchar*) item.data, width, height, QImage::Format_ARGB32).rgbSwapped();
if (mStateExtdataGet(&extdata, EXTDATA_SCREENSHOT, &item)) {
mStateExtdataItem dims;
if (mStateExtdataGet(&extdata, EXTDATA_SCREENSHOT_DIMENSIONS, &dims) && dims.size == sizeof(uint16_t[2])) {
size.setWidth(static_cast<uint16_t*>(dims.data)[0]);
size.setHeight(static_cast<uint16_t*>(dims.data)[1]);
}
if (item.size >= static_cast<int32_t>(size.width() * size.height() * 4)) {
stateImage = QImage((uchar*) item.data, size.width(), size.height(), QImage::Format_ARGB32).rgbSwapped();
}
}
if (mStateExtdataGet(&extdata, EXTDATA_META_TIME, &item) && item.size == sizeof(uint64_t)) {

View File

@ -43,7 +43,7 @@ MapView::MapView(std::shared_ptr<CoreController> controller, QWidget* parent)
case mPLATFORM_GBA:
m_boundary = 2048;
m_ui.tile->setMaxTile(3096);
m_addressBase = BASE_VRAM;
m_addressBase = GBA_BASE_VRAM;
m_addressWidth = 8;
m_ui.bgInfo->addCustomProperty("priority", tr("Priority"));
m_ui.bgInfo->addCustomProperty("screenBase", tr("Map base"));

View File

@ -157,7 +157,7 @@ void ObjView::updateTilesGBA(bool force) {
m_ui.w->setText(QString::number(newInfo.width * 8));
m_ui.h->setText(QString::number(newInfo.height * 8));
m_ui.address->setText(tr("0x%0").arg(BASE_OAM + m_objId * sizeof(*obj), 8, 16, QChar('0')));
m_ui.address->setText(tr("0x%0").arg(GBA_BASE_OAM + m_objId * sizeof(*obj), 8, 16, QChar('0')));
m_ui.priority->setText(QString::number(newInfo.priority));
m_ui.flippedH->setChecked(newInfo.hflip);
m_ui.flippedV->setChecked(newInfo.vflip);

View File

@ -197,20 +197,20 @@ void SaveConverter::detectFromSavestate(VFile* vf) {
void SaveConverter::detectFromSize(std::shared_ptr<VFileDevice> vf) {
#ifdef M_CORE_GBA
switch (vf->size()) {
case SIZE_CART_SRAM:
case GBA_SIZE_SRAM:
m_validSaves.append(AnnotatedSave{SAVEDATA_SRAM, vf});
break;
case SIZE_CART_FLASH512:
case GBA_SIZE_FLASH512:
m_validSaves.append(AnnotatedSave{SAVEDATA_FLASH512, vf});
break;
case SIZE_CART_FLASH1M:
case GBA_SIZE_FLASH1M:
m_validSaves.append(AnnotatedSave{SAVEDATA_FLASH1M, vf});
break;
case SIZE_CART_EEPROM:
case GBA_SIZE_EEPROM:
m_validSaves.append(AnnotatedSave{SAVEDATA_EEPROM, vf, Endian::LITTLE});
m_validSaves.append(AnnotatedSave{SAVEDATA_EEPROM, vf, Endian::BIG});
break;
case SIZE_CART_EEPROM512:
case GBA_SIZE_EEPROM512:
m_validSaves.append(AnnotatedSave{SAVEDATA_EEPROM512, vf, Endian::LITTLE});
m_validSaves.append(AnnotatedSave{SAVEDATA_EEPROM512, vf, Endian::BIG});
break;
@ -267,13 +267,13 @@ void SaveConverter::detectFromHeaders(std::shared_ptr<VFileDevice> vf) {
if (data) {
QByteArray bytes = QByteArray::fromRawData(static_cast<const char*>(data), size);
bytes.data(); // Trigger a deep copy before we delete the backing
if (size == SIZE_CART_FLASH1M) {
if (size == GBA_SIZE_FLASH1M) {
m_validSaves.append(AnnotatedSave{SAVEDATA_FLASH1M, std::make_shared<VFileDevice>(bytes), Endian::NONE, Container::SHARKPORT});
} else {
m_validSaves.append(AnnotatedSave{SAVEDATA_SRAM, std::make_shared<VFileDevice>(bytes.left(SIZE_CART_SRAM)), Endian::NONE, Container::SHARKPORT});
m_validSaves.append(AnnotatedSave{SAVEDATA_FLASH512, std::make_shared<VFileDevice>(bytes.left(SIZE_CART_FLASH512)), Endian::NONE, Container::SHARKPORT});
m_validSaves.append(AnnotatedSave{SAVEDATA_EEPROM, std::make_shared<VFileDevice>(bytes.left(SIZE_CART_EEPROM)), Endian::BIG, Container::SHARKPORT});
m_validSaves.append(AnnotatedSave{SAVEDATA_EEPROM512, std::make_shared<VFileDevice>(bytes.left(SIZE_CART_EEPROM512)), Endian::BIG, Container::SHARKPORT});
m_validSaves.append(AnnotatedSave{SAVEDATA_SRAM, std::make_shared<VFileDevice>(bytes.left(GBA_SIZE_SRAM)), Endian::NONE, Container::SHARKPORT});
m_validSaves.append(AnnotatedSave{SAVEDATA_FLASH512, std::make_shared<VFileDevice>(bytes.left(GBA_SIZE_FLASH512)), Endian::NONE, Container::SHARKPORT});
m_validSaves.append(AnnotatedSave{SAVEDATA_EEPROM, std::make_shared<VFileDevice>(bytes.left(GBA_SIZE_EEPROM)), Endian::BIG, Container::SHARKPORT});
m_validSaves.append(AnnotatedSave{SAVEDATA_EEPROM512, std::make_shared<VFileDevice>(bytes.left(GBA_SIZE_EEPROM512)), Endian::BIG, Container::SHARKPORT});
}
free(data);
}
@ -284,21 +284,21 @@ void SaveConverter::detectFromHeaders(std::shared_ptr<VFileDevice> vf) {
QByteArray bytes = QByteArray::fromRawData(static_cast<const char*>(data), size);
bytes.data(); // Trigger a deep copy before we delete the backing
switch (size) {
case SIZE_CART_FLASH1M:
case GBA_SIZE_FLASH1M:
m_validSaves.append(AnnotatedSave{SAVEDATA_FLASH1M, std::make_shared<VFileDevice>(bytes), Endian::NONE, Container::GSV});
break;
case SIZE_CART_FLASH512:
case GBA_SIZE_FLASH512:
m_validSaves.append(AnnotatedSave{SAVEDATA_FLASH512, std::make_shared<VFileDevice>(bytes), Endian::NONE, Container::GSV});
m_validSaves.append(AnnotatedSave{SAVEDATA_FLASH1M, std::make_shared<VFileDevice>(bytes), Endian::NONE, Container::GSV});
break;
case SIZE_CART_SRAM:
m_validSaves.append(AnnotatedSave{SAVEDATA_SRAM, std::make_shared<VFileDevice>(bytes.left(SIZE_CART_SRAM)), Endian::NONE, Container::GSV});
case GBA_SIZE_SRAM:
m_validSaves.append(AnnotatedSave{SAVEDATA_SRAM, std::make_shared<VFileDevice>(bytes.left(GBA_SIZE_SRAM)), Endian::NONE, Container::GSV});
break;
case SIZE_CART_EEPROM:
m_validSaves.append(AnnotatedSave{SAVEDATA_EEPROM, std::make_shared<VFileDevice>(bytes.left(SIZE_CART_EEPROM)), Endian::BIG, Container::GSV});
case GBA_SIZE_EEPROM:
m_validSaves.append(AnnotatedSave{SAVEDATA_EEPROM, std::make_shared<VFileDevice>(bytes.left(GBA_SIZE_EEPROM)), Endian::BIG, Container::GSV});
break;
case SIZE_CART_EEPROM512:
m_validSaves.append(AnnotatedSave{SAVEDATA_EEPROM512, std::make_shared<VFileDevice>(bytes.left(SIZE_CART_EEPROM512)), Endian::BIG, Container::GSV});
case GBA_SIZE_EEPROM512:
m_validSaves.append(AnnotatedSave{SAVEDATA_EEPROM512, std::make_shared<VFileDevice>(bytes.left(GBA_SIZE_EEPROM512)), Endian::BIG, Container::GSV});
break;
}
free(data);

View File

@ -7,7 +7,9 @@
#include "ConfigController.h"
#include "input/GamepadButtonEvent.h"
#include "input/GamepadHatEvent.h"
#include "InputProfile.h"
#include "scripting/ScriptingController.h"
#include <QAction>
#include <QKeyEvent>
@ -32,6 +34,10 @@ void ShortcutController::setActionMapper(ActionMapper* actions) {
rebuildItems();
}
void ShortcutController::setScriptingController(ScriptingController* controller) {
m_scripting = controller;
}
void ShortcutController::updateKey(const QString& name, int keySequence) {
auto item = m_items[name];
if (!item) {
@ -132,9 +138,14 @@ void ShortcutController::rebuildItems() {
onSubitems({}, std::bind(&ShortcutController::generateItem, this, std::placeholders::_1));
}
bool ShortcutController::eventFilter(QObject*, QEvent* event) {
bool ShortcutController::eventFilter(QObject* obj, QEvent* event) {
if (event->type() == QEvent::KeyPress || event->type() == QEvent::KeyRelease) {
QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event);
#ifdef ENABLE_SCRIPTING
if (m_scripting) {
m_scripting->event(obj, event);
}
#endif
if (keyEvent->isAutoRepeat()) {
return false;
}
@ -149,10 +160,14 @@ bool ShortcutController::eventFilter(QObject*, QEvent* event) {
Action::BooleanFunction fn = item.value()->action()->booleanAction();
fn(event->type() == QEvent::KeyPress);
event->accept();
return true;
}
}
if (event->type() == GamepadButtonEvent::Down()) {
#ifdef ENABLE_SCRIPTING
if (m_scripting) {
m_scripting->event(obj, event);
}
#endif
auto item = m_buttons.find(static_cast<GamepadButtonEvent*>(event)->value());
if (item == m_buttons.end()) {
return false;
@ -169,6 +184,11 @@ bool ShortcutController::eventFilter(QObject*, QEvent* event) {
return true;
}
if (event->type() == GamepadButtonEvent::Up()) {
#ifdef ENABLE_SCRIPTING
if (m_scripting) {
m_scripting->event(obj, event);
}
#endif
auto item = m_buttons.find(static_cast<GamepadButtonEvent*>(event)->value());
if (item == m_buttons.end()) {
return false;
@ -201,6 +221,13 @@ bool ShortcutController::eventFilter(QObject*, QEvent* event) {
event->accept();
return true;
}
#ifdef ENABLE_SCRIPTING
if (event->type() == GamepadHatEvent::Type()) {
if (m_scripting) {
m_scripting->event(obj, event);
}
}
#endif
return false;
}

View File

@ -21,6 +21,7 @@ namespace QGBA {
class ConfigController;
class InputProfile;
class ScriptingController;
class Shortcut : public QObject {
Q_OBJECT
@ -74,6 +75,7 @@ public:
void setConfigController(ConfigController* controller);
void setActionMapper(ActionMapper* actionMapper);
void setScriptingController(ScriptingController* scriptingController);
void setProfile(const QString& profile);
@ -121,6 +123,7 @@ private:
QHash<int, std::shared_ptr<Shortcut>> m_heldKeys;
ActionMapper* m_actions = nullptr;
ConfigController* m_config = nullptr;
ScriptingController* m_scripting = nullptr;
QString m_profileName;
const InputProfile* m_profile = nullptr;
};

View File

@ -651,8 +651,11 @@ void Window::consoleOpen() {
void Window::scriptingOpen() {
if (!m_scripting) {
m_scripting = std::make_unique<ScriptingController>();
m_scripting->setInputController(&m_inputController);
m_shortcutController->setScriptingController(m_scripting.get());
if (m_controller) {
m_scripting->setController(m_controller);
m_display->installEventFilter(m_scripting.get());
}
}
ScriptingView* view = new ScriptingView(m_scripting.get(), m_config);
@ -1757,7 +1760,7 @@ void Window::setupMenu(QMenuBar* menubar) {
if (m_controller) {
mCheatPressButton(m_controller->cheatDevice(), held);
}
}, "tools", QKeySequence(Qt::Key_Apostrophe));
}, "tools");
for (Action* action : m_gameActions) {
action->setEnabled(false);
@ -2140,6 +2143,12 @@ void Window::attachDisplay() {
m_display->attach(m_controller);
connect(m_display.get(), &QGBA::Display::drawingStarted, this, &Window::changeRenderer);
m_display->startDrawing(m_controller);
#ifdef ENABLE_SCRIPTING
if (m_scripting) {
m_display->installEventFilter(m_scripting.get());
}
#endif
}
void Window::updateMute() {

View File

@ -46,7 +46,7 @@ InputController::InputController(int playerId, QWidget* topLevel, QObject* paren
}
});
m_gamepadTimer.setInterval(50);
m_gamepadTimer.setInterval(15);
m_gamepadTimer.start();
#ifdef BUILD_QT_MULTIMEDIA
@ -332,6 +332,7 @@ void InputController::update() {
loadProfile(driver->type(), newProfile);
}
}
emit updated();
}
int InputController::pollEvents() {

View File

@ -64,6 +64,8 @@ public:
void addInputDriver(std::shared_ptr<InputDriver>);
int playerId() const { return m_playerId; }
void setConfiguration(ConfigController* config);
void saveConfiguration();
bool loadConfiguration(uint32_t type);
@ -111,6 +113,7 @@ public:
GBALuminanceSource* luminance() { return &m_lux; }
signals:
void updated();
void profileLoaded(const QString& profile);
void luminanceValueChanged(int value);

View File

@ -89,6 +89,7 @@ QString SDLInputDriver::currentProfile() const {
}
void SDLInputDriver::loadConfiguration(ConfigController* config) {
m_config = config;
mSDLEventsLoadConfig(&s_sdlEvents, config->input());
if (!m_playerAttached) {
m_playerAttached = mSDLAttachPlayer(&s_sdlEvents, &m_sdlPlayer);
@ -126,7 +127,7 @@ mRotationSource* SDLInputDriver::rotationSource() {
bool SDLInputDriver::update() {
if (!m_playerAttached || !m_sdlPlayer.joystick) {
if (!m_playerAttached) {
return false;
}
@ -148,6 +149,9 @@ QList<Gamepad*> SDLInputDriver::connectedGamepads() const {
#if SDL_VERSION_ATLEAST(2, 0, 0)
void SDLInputDriver::updateGamepads() {
if (m_config) {
mSDLUpdateJoysticks(&s_sdlEvents, m_config->input());
}
for (int i = 0; i < m_gamepads.size(); ++i) {
if (m_gamepads.at(i)->updateIndex()) {
continue;
@ -160,10 +164,12 @@ void SDLInputDriver::updateGamepads() {
});
for (size_t i = 0, j = 0; i < SDL_JoystickListSize(&s_sdlEvents.joysticks); ++i) {
std::shared_ptr<SDLGamepad> gamepad = m_gamepads.at(j);
if (gamepad->m_index == i) {
++j;
continue;
if ((ssize_t) j < m_gamepads.size()) {
std::shared_ptr<SDLGamepad> gamepad = m_gamepads.at(j);
if (gamepad->m_index == i) {
++j;
continue;
}
}
m_gamepads.append(std::make_shared<SDLGamepad>(this, i));
}

View File

@ -62,6 +62,7 @@ public:
mRotationSource* rotationSource() override;
private:
ConfigController* m_config = nullptr;
InputController* m_controller;
mSDLPlayer m_sdlPlayer{};
bool m_playerAttached = false;

View File

@ -28,6 +28,7 @@
#ifdef QT_STATIC
#include <QtPlugin>
#ifdef Q_OS_WIN
Q_IMPORT_PLUGIN(QJpegPlugin);
Q_IMPORT_PLUGIN(QWindowsIntegrationPlugin);
Q_IMPORT_PLUGIN(QWindowsVistaStylePlugin);
#ifdef BUILD_QT_MULTIMEDIA

View File

@ -5,10 +5,24 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "scripting/ScriptingController.h"
#include <QEvent>
#include <QKeyEvent>
#include <QMouseEvent>
#include <QWidget>
#include "CoreController.h"
#include "Display.h"
#include "input/Gamepad.h"
#include "input/GamepadButtonEvent.h"
#include "input/GamepadHatEvent.h"
#include "InputController.h"
#include "scripting/ScriptingTextBuffer.h"
#include "scripting/ScriptingTextBufferModel.h"
#include <mgba/script/input.h>
#include <mgba-util/math.h>
#include <mgba-util/string.h>
using namespace QGBA;
ScriptingController::ScriptingController(QObject* parent)
@ -37,12 +51,15 @@ ScriptingController::ScriptingController(QObject* parent)
m_bufferModel = new ScriptingTextBufferModel(this);
QObject::connect(m_bufferModel, &ScriptingTextBufferModel::textBufferCreated, this, &ScriptingController::textBufferCreated);
mScriptGamepadInit(&m_gamepad);
init();
}
ScriptingController::~ScriptingController() {
clearController();
mScriptContextDeinit(&m_scriptContext);
mScriptGamepadDeinit(&m_gamepad);
}
void ScriptingController::setController(std::shared_ptr<CoreController> controller) {
@ -59,6 +76,14 @@ void ScriptingController::setController(std::shared_ptr<CoreController> controll
connect(m_controller.get(), &CoreController::stopping, this, &ScriptingController::clearController);
}
void ScriptingController::setInputController(InputController* input) {
if (m_inputController) {
m_inputController->disconnect(this);
}
m_inputController = input;
connect(m_inputController, &InputController::updated, this, &ScriptingController::updateGamepad);
}
bool ScriptingController::loadFile(const QString& path) {
VFileDevice vf(path, QIODevice::ReadOnly);
if (!vf.isOpen()) {
@ -73,11 +98,20 @@ bool ScriptingController::load(VFileDevice& vf, const QString& name) {
}
QByteArray utf8 = name.toUtf8();
CoreController::Interrupter interrupter(m_controller);
if (m_controller) {
m_controller->setSync(false);
m_controller->unpaused();
}
bool ok = true;
if (!m_activeEngine->load(m_activeEngine, utf8.constData(), vf) || !m_activeEngine->run(m_activeEngine)) {
emit error(QString::fromUtf8(m_activeEngine->getError(m_activeEngine)));
return false;
ok = false;
}
return true;
if (m_controller && m_controller->isPaused()) {
m_controller->setSync(true);
m_controller->paused();
}
return ok;
}
void ScriptingController::clearController() {
@ -110,10 +144,153 @@ void ScriptingController::runCode(const QString& code) {
load(vf, "*prompt");
}
bool ScriptingController::eventFilter(QObject* obj, QEvent* ev) {
event(obj, ev);
return false;
}
void ScriptingController::event(QObject* obj, QEvent* event) {
if (!m_controller) {
return;
}
switch (event->type()) {
case QEvent::KeyPress:
case QEvent::KeyRelease: {
struct mScriptKeyEvent ev{mSCRIPT_EV_TYPE_KEY};
auto keyEvent = static_cast<QKeyEvent*>(event);
ev.state = event->type() == QEvent::KeyRelease ? mSCRIPT_INPUT_STATE_UP :
static_cast<QKeyEvent*>(event)->isAutoRepeat() ? mSCRIPT_INPUT_STATE_HELD : mSCRIPT_INPUT_STATE_DOWN;
ev.key = qtToScriptingKey(keyEvent);
ev.modifiers = qtToScriptingModifiers(keyEvent->modifiers());
mScriptContextFireEvent(&m_scriptContext, &ev.d);
return;
}
case QEvent::MouseButtonPress:
case QEvent::MouseButtonRelease: {
struct mScriptMouseButtonEvent ev{mSCRIPT_EV_TYPE_MOUSE_BUTTON};
auto mouseEvent = static_cast<QMouseEvent*>(event);
ev.mouse = 0;
ev.state = event->type() == QEvent::MouseButtonPress ? mSCRIPT_INPUT_STATE_DOWN : mSCRIPT_INPUT_STATE_UP;
ev.button = 31 - clz32(mouseEvent->button());
mScriptContextFireEvent(&m_scriptContext, &ev.d);
return;
}
case QEvent::MouseMove: {
struct mScriptMouseMoveEvent ev{mSCRIPT_EV_TYPE_MOUSE_MOVE};
auto mouseEvent = static_cast<QMouseEvent*>(event);
QPoint pos = mouseEvent->pos();
pos = static_cast<Display*>(obj)->normalizedPoint(m_controller.get(), pos);
ev.mouse = 0;
ev.x = pos.x();
ev.y = pos.y();
mScriptContextFireEvent(&m_scriptContext, &ev.d);
return;
}
case QEvent::Wheel: {
struct mScriptMouseWheelEvent ev{mSCRIPT_EV_TYPE_MOUSE_WHEEL};
auto wheelEvent = static_cast<QWheelEvent*>(event);
QPoint adelta = wheelEvent->angleDelta();
QPoint pdelta = wheelEvent->pixelDelta();
ev.mouse = 0;
if (!pdelta.isNull()) {
ev.x = pdelta.x();
ev.y = pdelta.y();
} else {
ev.x = adelta.x();
ev.y = adelta.y();
}
mScriptContextFireEvent(&m_scriptContext, &ev.d);
return;
}
default:
break;
}
auto type = event->type();
if (type == GamepadButtonEvent::Down() || type == GamepadButtonEvent::Up()) {
struct mScriptGamepadButtonEvent ev{mSCRIPT_EV_TYPE_GAMEPAD_BUTTON};
auto gamepadEvent = static_cast<GamepadButtonEvent*>(event);
ev.pad = 0;
ev.state = event->type() == GamepadButtonEvent::Down() ? mSCRIPT_INPUT_STATE_DOWN : mSCRIPT_INPUT_STATE_UP;
ev.button = gamepadEvent->value();
mScriptContextFireEvent(&m_scriptContext, &ev.d);
}
if (type == GamepadHatEvent::Type()) {
struct mScriptGamepadHatEvent ev{mSCRIPT_EV_TYPE_GAMEPAD_HAT};
updateGamepad();
auto gamepadEvent = static_cast<GamepadHatEvent*>(event);
ev.pad = 0;
ev.hat = gamepadEvent->hatId();
ev.direction = gamepadEvent->direction();
mScriptContextFireEvent(&m_scriptContext, &ev.d);
}
}
void ScriptingController::updateGamepad() {
InputDriver* driver = m_inputController->gamepadDriver();
if (!driver) {
detachGamepad();
return;
}
Gamepad* gamepad = driver->activeGamepad();
if (!gamepad) {
detachGamepad();
return;
}
QString name = gamepad->name();
strlcpy(m_gamepad.internalName, name.toUtf8().constData(), sizeof(m_gamepad.internalName));
name = gamepad->visibleName();
strlcpy(m_gamepad.visibleName, name.toUtf8().constData(), sizeof(m_gamepad.visibleName));
attachGamepad();
QList<bool> buttons = gamepad->currentButtons();
int nButtons = gamepad->buttonCount();
mScriptGamepadSetButtonCount(&m_gamepad, nButtons);
for (int i = 0; i < nButtons; ++i) {
mScriptGamepadSetButton(&m_gamepad, i, buttons.at(i));
}
QList<int16_t> axes = gamepad->currentAxes();
int nAxes = gamepad->axisCount();
mScriptGamepadSetAxisCount(&m_gamepad, nAxes);
for (int i = 0; i < nAxes; ++i) {
mScriptGamepadSetAxis(&m_gamepad, i, axes.at(i));
}
QList<GamepadHatEvent::Direction> hats = gamepad->currentHats();
int nHats = gamepad->hatCount();
mScriptGamepadSetHatCount(&m_gamepad, nHats);
for (int i = 0; i < nHats; ++i) {
mScriptGamepadSetHat(&m_gamepad, i, hats.at(i));
}
}
void ScriptingController::attachGamepad() {
mScriptGamepad* pad = mScriptContextGamepadLookup(&m_scriptContext, 0);
if (pad == &m_gamepad) {
return;
}
if (pad) {
mScriptContextGamepadDetach(&m_scriptContext, 0);
}
mScriptContextGamepadAttach(&m_scriptContext, &m_gamepad);
}
void ScriptingController::detachGamepad() {
mScriptGamepad* pad = mScriptContextGamepadLookup(&m_scriptContext, 0);
if (pad != &m_gamepad) {
return;
}
mScriptContextGamepadDetach(&m_scriptContext, 0);
}
void ScriptingController::init() {
mScriptContextInit(&m_scriptContext);
mScriptContextAttachStdlib(&m_scriptContext);
mScriptContextAttachSocket(&m_scriptContext);
mScriptContextAttachInput(&m_scriptContext);
mScriptContextRegisterEngines(&m_scriptContext);
mScriptContextAttachLogger(&m_scriptContext, &m_logger);
@ -128,3 +305,130 @@ void ScriptingController::init() {
m_activeEngine = *m_engines.begin();
}
}
uint32_t ScriptingController::qtToScriptingKey(const QKeyEvent* event) {
QString text(event->text());
int key = event->key();
static const QHash<int, uint32_t> keypadMap{
{'0', mSCRIPT_KEY_KP_0},
{'1', mSCRIPT_KEY_KP_1},
{'2', mSCRIPT_KEY_KP_2},
{'3', mSCRIPT_KEY_KP_3},
{'4', mSCRIPT_KEY_KP_4},
{'5', mSCRIPT_KEY_KP_5},
{'6', mSCRIPT_KEY_KP_6},
{'7', mSCRIPT_KEY_KP_7},
{'8', mSCRIPT_KEY_KP_8},
{'9', 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},
{Qt::Key_Enter, mSCRIPT_KEY_KP_ENTER},
};
static const QHash<int, uint32_t> extraKeyMap{
{Qt::Key_Escape, mSCRIPT_KEY_ESCAPE},
{Qt::Key_Tab, mSCRIPT_KEY_TAB},
{Qt::Key_Backtab, mSCRIPT_KEY_BACKSPACE},
{Qt::Key_Backspace, mSCRIPT_KEY_BACKSPACE},
{Qt::Key_Return, mSCRIPT_KEY_ENTER},
{Qt::Key_Enter, mSCRIPT_KEY_ENTER},
{Qt::Key_Insert, mSCRIPT_KEY_INSERT},
{Qt::Key_Delete, mSCRIPT_KEY_DELETE},
{Qt::Key_Pause, mSCRIPT_KEY_BREAK},
{Qt::Key_Print, mSCRIPT_KEY_PRINT_SCREEN},
{Qt::Key_SysReq, mSCRIPT_KEY_SYSRQ},
{Qt::Key_Clear, mSCRIPT_KEY_CLEAR},
{Qt::Key_Home, mSCRIPT_KEY_HOME},
{Qt::Key_End, mSCRIPT_KEY_END},
{Qt::Key_Left, mSCRIPT_KEY_LEFT},
{Qt::Key_Up, mSCRIPT_KEY_UP},
{Qt::Key_Right, mSCRIPT_KEY_RIGHT},
{Qt::Key_Down, mSCRIPT_KEY_DOWN},
{Qt::Key_PageUp, mSCRIPT_KEY_PAGE_UP},
{Qt::Key_PageDown, mSCRIPT_KEY_DOWN},
{Qt::Key_Shift, mSCRIPT_KEY_SHIFT},
{Qt::Key_Control, mSCRIPT_KEY_CONTROL},
{Qt::Key_Meta, mSCRIPT_KEY_SUPER},
{Qt::Key_Alt, mSCRIPT_KEY_ALT},
{Qt::Key_CapsLock, mSCRIPT_KEY_CAPS_LOCK},
{Qt::Key_NumLock, mSCRIPT_KEY_NUM_LOCK},
{Qt::Key_ScrollLock, mSCRIPT_KEY_SCROLL_LOCK},
{Qt::Key_F1, mSCRIPT_KEY_F1},
{Qt::Key_F2, mSCRIPT_KEY_F2},
{Qt::Key_F3, mSCRIPT_KEY_F3},
{Qt::Key_F4, mSCRIPT_KEY_F4},
{Qt::Key_F5, mSCRIPT_KEY_F5},
{Qt::Key_F6, mSCRIPT_KEY_F6},
{Qt::Key_F7, mSCRIPT_KEY_F7},
{Qt::Key_F8, mSCRIPT_KEY_F8},
{Qt::Key_F9, mSCRIPT_KEY_F9},
{Qt::Key_F10, mSCRIPT_KEY_F10},
{Qt::Key_F11, mSCRIPT_KEY_F11},
{Qt::Key_F12, mSCRIPT_KEY_F12},
{Qt::Key_F13, mSCRIPT_KEY_F13},
{Qt::Key_F14, mSCRIPT_KEY_F14},
{Qt::Key_F15, mSCRIPT_KEY_F15},
{Qt::Key_F16, mSCRIPT_KEY_F16},
{Qt::Key_F17, mSCRIPT_KEY_F17},
{Qt::Key_F18, mSCRIPT_KEY_F18},
{Qt::Key_F19, mSCRIPT_KEY_F19},
{Qt::Key_F20, mSCRIPT_KEY_F20},
{Qt::Key_F21, mSCRIPT_KEY_F21},
{Qt::Key_F22, mSCRIPT_KEY_F22},
{Qt::Key_F23, mSCRIPT_KEY_F23},
{Qt::Key_F24, mSCRIPT_KEY_F24},
{Qt::Key_Menu, mSCRIPT_KEY_MENU},
{Qt::Key_Super_L, mSCRIPT_KEY_SUPER},
{Qt::Key_Super_R, mSCRIPT_KEY_SUPER},
{Qt::Key_Help, mSCRIPT_KEY_HELP},
{Qt::Key_Hyper_L, mSCRIPT_KEY_SUPER},
{Qt::Key_Hyper_R, mSCRIPT_KEY_SUPER},
};
if (event->modifiers() & Qt::KeypadModifier && keypadMap.contains(key)) {
return keypadMap[key];
}
if (key >= 0 && key < 0x100) {
return key;
}
if (key < 0x01000000) {
if (text.isEmpty()) {
return 0;
}
QChar high = text[0];
if (!high.isSurrogate()) {
return high.unicode();
}
if (text.size() < 2) {
return 0;
}
return QChar::surrogateToUcs4(high, text[1]);
}
if (extraKeyMap.contains(key)) {
return extraKeyMap[key];
}
return 0;
}
uint16_t ScriptingController::qtToScriptingModifiers(Qt::KeyboardModifiers modifiers) {
uint16_t mod = 0;
if (modifiers & Qt::ShiftModifier) {
mod |= mSCRIPT_KMOD_SHIFT;
}
if (modifiers & Qt::ControlModifier) {
mod |= mSCRIPT_KMOD_CONTROL;
}
if (modifiers & Qt::AltModifier) {
mod |= mSCRIPT_KMOD_ALT;
}
if (modifiers & Qt::MetaModifier) {
mod |= mSCRIPT_KMOD_SUPER;
}
return mod;
}

View File

@ -9,17 +9,20 @@
#include <QObject>
#include <mgba/script/context.h>
#include <mgba/script/input.h>
#include <mgba/core/scripting.h>
#include "VFileDevice.h"
#include <memory>
class QKeyEvent;
class QTextDocument;
namespace QGBA {
class CoreController;
class InputController;
class ScriptingTextBuffer;
class ScriptingTextBufferModel;
@ -31,10 +34,13 @@ public:
~ScriptingController();
void setController(std::shared_ptr<CoreController> controller);
void setInputController(InputController* controller);
bool loadFile(const QString& path);
bool load(VFileDevice& vf, const QString& name);
void event(QObject* obj, QEvent* ev);
mScriptContext* context() { return &m_scriptContext; }
ScriptingTextBufferModel* textBufferModel() const { return m_bufferModel; }
@ -49,10 +55,20 @@ public slots:
void reset();
void runCode(const QString& code);
protected:
bool eventFilter(QObject*, QEvent*) override;
private slots:
void updateGamepad();
private:
void init();
static mScriptTextBuffer* createTextBuffer(void* context);
void attachGamepad();
void detachGamepad();
static uint32_t qtToScriptingKey(const QKeyEvent*);
static uint16_t qtToScriptingModifiers(Qt::KeyboardModifiers);
struct Logger : mLogger {
ScriptingController* p;
@ -64,7 +80,10 @@ private:
QHash<QString, mScriptEngineContext*> m_engines;
ScriptingTextBufferModel* m_bufferModel;
mScriptGamepad m_gamepad;
std::shared_ptr<CoreController> m_controller;
InputController* m_inputController = nullptr;
};
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -82,6 +82,7 @@ static GLuint insizeLocation;
static GLuint colorLocation;
static GLuint tex;
static GLuint oldTex;
static GLuint screenshotTex;
static struct GUIFont* font;
static color_t* frameBuffer;
@ -379,8 +380,6 @@ static void _gameUnloaded(struct mGUIRunner* runner) {
static void _drawTex(struct mGUIRunner* runner, unsigned width, unsigned height, bool faded, bool blendTop) {
glViewport(0, 1080 - vheight, vwidth, vheight);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glUseProgram(program);
glBindVertexArray(vao);
@ -493,11 +492,16 @@ static void _drawFrame(struct mGUIRunner* runner, bool faded) {
}
if (interframeBlending) {
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glBindTexture(GL_TEXTURE_2D, oldTex);
_drawTex(runner, width, height, faded, false);
glBindTexture(GL_TEXTURE_2D, tex);
_drawTex(runner, width, height, faded, true);
} else {
glDisable(GL_BLEND);
_drawTex(runner, width, height, faded, false);
}
@ -523,10 +527,15 @@ static void _drawFrame(struct mGUIRunner* runner, bool faded) {
static void _drawScreenshot(struct mGUIRunner* runner, const color_t* pixels, unsigned width, unsigned height, bool faded) {
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, tex);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
glBindTexture(GL_TEXTURE_2D, screenshotTex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
runner->core->desiredVideoDimensions(runner->core, &width, &height);
glDisable(GL_BLEND);
bool wasPbo = usePbo;
usePbo = false;
_drawTex(runner, width, height, faded, false);
usePbo = wasPbo;
}
static uint16_t _pollGameInput(struct mGUIRunner* runner) {
@ -711,6 +720,13 @@ static void glInit(void) {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glGenTextures(1, &screenshotTex);
glBindTexture(GL_TEXTURE_2D, screenshotTex);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glGenBuffers(1, &pbo);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo);
glBufferData(GL_PIXEL_UNPACK_BUFFER, 256 * 256 * 4, NULL, GL_STREAM_DRAW);
@ -790,6 +806,7 @@ static void glDeinit(void) {
glDeleteFramebuffers(1, &copyFbo);
glDeleteTextures(1, &tex);
glDeleteTextures(1, &oldTex);
glDeleteTextures(1, &screenshotTex);
glDeleteBuffers(1, &vbo);
glDeleteProgram(program);
glDeleteVertexArrays(1, &vao);

View File

@ -271,7 +271,7 @@ int main(int argc, char* argv[]) {
memset(audioBuffer, 0, sizeof(audioBuffer));
#ifdef FIXED_ROM_BUFFER
romBufferSize = SIZE_CART0;
romBufferSize = GBA_SIZE_ROM0;
romBuffer = SYS_GetArena2Lo();
SYS_SetArena2Lo((void*)((intptr_t) romBuffer + romBufferSize));
#endif

View File

@ -1,6 +1,7 @@
include(ExportDirectory)
set(SOURCE_FILES
context.c
input.c
socket.c
stdlib.c
types.c)
@ -13,6 +14,7 @@ if(USE_LUA)
list(APPEND SOURCE_FILES engines/lua.c)
list(APPEND TEST_FILES
test/context.c
test/input.c
test/lua.c
test/stdlib.c)
endif()

View File

@ -211,7 +211,7 @@ void mScriptContextDisownWeakref(struct mScriptContext* context, uint32_t weakre
poolEntry->refs = mSCRIPT_VALUE_UNREF;
}
void mScriptContextTriggerCallback(struct mScriptContext* context, const char* callback) {
void mScriptContextTriggerCallback(struct mScriptContext* context, const char* callback, struct mScriptList* args) {
struct mScriptValue* list = HashTableLookup(&context->callbacks, callback);
if (!list) {
return;
@ -224,6 +224,9 @@ void mScriptContextTriggerCallback(struct mScriptContext* context, const char* c
continue;
}
mScriptFrameInit(&frame);
if (args) {
mScriptListCopy(&frame.arguments, args);
}
if (fn->type->base == mSCRIPT_TYPE_WRAPPER) {
fn = mScriptValueUnwrap(fn);
}

View File

@ -6,7 +6,9 @@
#include <mgba/core/core.h>
#include <mgba/core/scripting.h>
#include <mgba/core/version.h>
#include <mgba/internal/script/types.h>
#include <mgba/script/context.h>
#include <mgba/script/input.h>
#include <mgba-util/string.h>
struct mScriptContext context;
@ -36,62 +38,6 @@ void explainValue(struct mScriptValue* value, const char* name, int level);
void explainValueScoped(struct mScriptValue* value, const char* name, const char* scope, int level);
void explainType(struct mScriptType* type, int level);
void addTypesFromTuple(const struct mScriptTypeTuple*);
void addTypesFromTable(struct Table*);
void addType(const struct mScriptType* type) {
if (HashTableLookup(&types, type->name) || type->isConst) {
return;
}
HashTableInsert(&types, type->name, (struct mScriptType*) type);
switch (type->base) {
case mSCRIPT_TYPE_FUNCTION:
addTypesFromTuple(&type->details.function.parameters);
addTypesFromTuple(&type->details.function.returnType);
break;
case mSCRIPT_TYPE_OBJECT:
mScriptClassInit(type->details.cls);
if (type->details.cls->parent) {
addType(type->details.cls->parent);
}
addTypesFromTable(&type->details.cls->instanceMembers);
break;
case mSCRIPT_TYPE_OPAQUE:
case mSCRIPT_TYPE_WRAPPER:
if (type->details.type) {
addType(type->details.type);
}
case mSCRIPT_TYPE_VOID:
case mSCRIPT_TYPE_SINT:
case mSCRIPT_TYPE_UINT:
case mSCRIPT_TYPE_FLOAT:
case mSCRIPT_TYPE_STRING:
case mSCRIPT_TYPE_LIST:
case mSCRIPT_TYPE_TABLE:
case mSCRIPT_TYPE_WEAKREF:
// No subtypes
break;
}
}
void addTypesFromTuple(const struct mScriptTypeTuple* tuple) {
size_t i;
for (i = 0; i < tuple->count; ++i) {
addType(tuple->entries[i]);
}
}
void addTypesFromTable(struct Table* table) {
struct TableIterator iter;
if (!HashTableIteratorStart(table, &iter)) {
return;
}
do {
struct mScriptClassMember* member = HashTableIteratorGetValue(table, &iter);
addType(member->type);
} while(HashTableIteratorNext(table, &iter));
}
void printchomp(const char* string, int level) {
char indent[(level + 1) * 2 + 1];
memset(indent, ' ', sizeof(indent) - 1);
@ -265,7 +211,7 @@ void explainObject(struct mScriptValue* value, int level) {
continue;
}
fprintf(out, "%s%s:\n", indent, details->info.member.name);
addType(details->info.member.type);
mScriptTypeAdd(&types, details->info.member.type);
if (mScriptObjectGet(value, details->info.member.name, &member)) {
struct mScriptValue* unwrappedMember;
if (member.type->base == mSCRIPT_TYPE_WRAPPER) {
@ -288,7 +234,7 @@ void explainValueScoped(struct mScriptValue* value, const char* name, const char
memset(indent, ' ', sizeof(indent) - 1);
indent[sizeof(indent) - 1] = '\0';
value = mScriptContextAccessWeakref(&context, value);
addType(value->type);
mScriptTypeAdd(&types, value->type);
fprintf(out, "%stype: %s\n", indent, value->type->name);
const char* docstring = NULL;
@ -421,7 +367,7 @@ void explainCore(struct mCore* core) {
mScriptContextAttachCore(&context, core);
struct mScriptValue* emu = mScriptContextGetGlobal(&context, "emu");
addType(emu->type);
mScriptTypeAdd(&types, emu->type);
if (mScriptObjectGet(emu, "memory", &wrapper)) {
struct mScriptValue* memory = mScriptValueUnwrap(&wrapper);
@ -434,7 +380,7 @@ void explainCore(struct mCore* core) {
fprintf(out, " %s:\n", name->value.string->buffer);
value = mScriptContextAccessWeakref(&context, value);
addType(value->type);
mScriptTypeAdd(&types, value->type);
struct mScriptFrame frame;
uint32_t baseVal;
@ -486,7 +432,7 @@ void initTypes(void) {
size_t i;
for (i = 0; baseTypes[i]; ++i) {
addType(baseTypes[i]);
mScriptTypeAdd(&types, baseTypes[i]);
}
}
@ -523,9 +469,11 @@ int main(int argc, char* argv[]) {
mScriptContextInit(&context);
mScriptContextAttachStdlib(&context);
mScriptContextAttachSocket(&context);
mScriptContextAttachInput(&context);
mScriptContextSetTextBufferFactory(&context, NULL, NULL);
initTypes();
mScriptContextGetInputTypes(&types);
fputs("version:\n", out);
fprintf(out, " string: \"%s\"\n", projectVersion);

View File

@ -584,13 +584,18 @@ struct mScriptValue* _luaCoerceTable(struct mScriptEngineContextLua* luaContext)
return false;
}
mScriptTableInsert(table, key, value);
mScriptValueDeref(key);
if (key->type != mSCRIPT_TYPE_MS_STR) {
// Strings are added to the ref pool, so we need to keep it
// ref'd to prevent it from being collected prematurely
mScriptValueDeref(key);
}
mScriptValueDeref(value);
}
lua_pop(luaContext->lua, 1);
size_t len = mScriptTableSize(table);
if (!isList || !len) {
mScriptContextFillPool(luaContext->d.context, table);
return table;
}
@ -600,6 +605,7 @@ struct mScriptValue* _luaCoerceTable(struct mScriptEngineContextLua* luaContext)
struct mScriptValue* value = mScriptTableLookup(table, &mSCRIPT_MAKE_S64(i));
if (!value) {
mScriptValueDeref(list);
mScriptContextFillPool(luaContext->d.context, table);
return table;
}
mScriptValueWrap(value, mScriptListAppend(list->value.list));
@ -693,6 +699,31 @@ bool _luaWrap(struct mScriptEngineContextLua* luaContext, struct mScriptValue* v
return true;
}
}
struct mScriptValue derefPtr;
if (value->type->base == mSCRIPT_TYPE_OPAQUE) {
if (!value->type->details.type) {
return false;
}
mScriptValueFollowPointer(value, &derefPtr);
switch (derefPtr.type->base) {
case mSCRIPT_TYPE_VOID:
case mSCRIPT_TYPE_SINT:
case mSCRIPT_TYPE_UINT:
case mSCRIPT_TYPE_FLOAT:
value = &derefPtr;
break;
case mSCRIPT_TYPE_OBJECT:
value = mScriptValueAlloc(derefPtr.type);
value->value.opaque = derefPtr.value.opaque;
weakref = mScriptContextSetWeakref(luaContext->d.context, value);
needsWeakref = true;
mScriptContextDisownWeakref(luaContext->d.context, weakref);
mScriptValueDeref(value);
break;
default:
return false;
}
}
if (value->type == mSCRIPT_TYPE_MS_WEAKREF) {
weakref = value->value.u32;
value = mScriptContextAccessWeakref(luaContext->d.context, value);

581
src/script/input.c Normal file
View File

@ -0,0 +1,581 @@
/* 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/. */
#include <mgba/script/input.h>
#include <mgba/internal/script/types.h>
#include <mgba-util/string.h>
#include <mgba-util/table.h>
static const char* eventNames[mSCRIPT_EV_TYPE_MAX] = {
[mSCRIPT_EV_TYPE_KEY] = "key",
[mSCRIPT_EV_TYPE_MOUSE_BUTTON] = "mouseButton",
[mSCRIPT_EV_TYPE_MOUSE_MOVE] = "mouseMove",
[mSCRIPT_EV_TYPE_MOUSE_WHEEL] = "mouseWheel",
[mSCRIPT_EV_TYPE_GAMEPAD_BUTTON] = "gamepadButton",
[mSCRIPT_EV_TYPE_GAMEPAD_HAT] = "gamepadHat",
[mSCRIPT_EV_TYPE_TRIGGER] = "trigger",
};
static const struct mScriptType* eventTypes[mSCRIPT_EV_TYPE_MAX] = {
[mSCRIPT_EV_TYPE_KEY] = mSCRIPT_TYPE_MS_S(mScriptKeyEvent),
[mSCRIPT_EV_TYPE_MOUSE_BUTTON] = mSCRIPT_TYPE_MS_S(mScriptMouseButtonEvent),
[mSCRIPT_EV_TYPE_MOUSE_MOVE] = mSCRIPT_TYPE_MS_S(mScriptMouseMoveEvent),
[mSCRIPT_EV_TYPE_MOUSE_WHEEL] = mSCRIPT_TYPE_MS_S(mScriptMouseWheelEvent),
[mSCRIPT_EV_TYPE_GAMEPAD_BUTTON] = mSCRIPT_TYPE_MS_S(mScriptGamepadButtonEvent),
[mSCRIPT_EV_TYPE_GAMEPAD_HAT] = mSCRIPT_TYPE_MS_S(mScriptGamepadHatEvent),
};
struct mScriptInputContext {
uint64_t seq;
struct Table activeKeys;
struct mScriptGamepad* activeGamepad;
};
static void _mScriptInputDeinit(struct mScriptInputContext*);
static bool _mScriptInputIsKeyActive(const struct mScriptInputContext*, struct mScriptValue*);
static struct mScriptValue* _mScriptInputActiveKeys(const struct mScriptInputContext*);
mSCRIPT_DECLARE_STRUCT(mScriptInputContext);
mSCRIPT_DECLARE_STRUCT_VOID_METHOD(mScriptInputContext, _deinit, _mScriptInputDeinit, 0);
mSCRIPT_DECLARE_STRUCT_C_METHOD(mScriptInputContext, BOOL, isKeyActive, _mScriptInputIsKeyActive, 1, WRAPPER, key);
mSCRIPT_DECLARE_STRUCT_C_METHOD(mScriptInputContext, WLIST, activeKeys, _mScriptInputActiveKeys, 0);
mSCRIPT_DEFINE_STRUCT(mScriptInputContext)
mSCRIPT_DEFINE_STRUCT_DEINIT(mScriptInputContext)
mSCRIPT_DEFINE_DOCSTRING("Sequence number of the next event to be emitted")
mSCRIPT_DEFINE_STRUCT_MEMBER(mScriptInputContext, U64, seq)
mSCRIPT_DEFINE_DOCSTRING("Check if a given keyboard key is currently held. The input can be either the printable character for a key, the numerical Unicode codepoint, or a special value from C.KEY")
mSCRIPT_DEFINE_STRUCT_METHOD(mScriptInputContext, isKeyActive)
mSCRIPT_DEFINE_DOCSTRING("Get a list of the currently active keys. The values are Unicode codepoints or special key values from C.KEY, not strings, so make sure to convert as needed")
mSCRIPT_DEFINE_STRUCT_METHOD(mScriptInputContext, activeKeys)
mSCRIPT_DEFINE_DOCSTRING("The currently active gamepad, if any")
mSCRIPT_DEFINE_STRUCT_MEMBER(mScriptInputContext, PCS(mScriptGamepad), activeGamepad)
mSCRIPT_DEFINE_END;
mSCRIPT_DEFINE_STRUCT(mScriptEvent)
mSCRIPT_DEFINE_CLASS_DOCSTRING(
"The base class for all event types. Different events have their own subclasses."
)
mSCRIPT_DEFINE_DOCSTRING("The type of this event. See C.EV_TYPE for a list of possible types.")
mSCRIPT_DEFINE_STRUCT_MEMBER(mScriptEvent, S32, type)
mSCRIPT_DEFINE_DOCSTRING("Sequence number of this event. This value increases monotinically.")
mSCRIPT_DEFINE_STRUCT_MEMBER(mScriptEvent, U64, seq)
mSCRIPT_DEFINE_END;
mSCRIPT_DEFINE_STRUCT(mScriptKeyEvent)
mSCRIPT_DEFINE_CLASS_DOCSTRING("A keyboard key event.")
mSCRIPT_DEFINE_INHERIT(mScriptEvent)
mSCRIPT_DEFINE_DOCSTRING("The state of the key, represented by a C.INPUT_STATE value")
mSCRIPT_DEFINE_STRUCT_MEMBER(mScriptKeyEvent, U8, state)
mSCRIPT_DEFINE_DOCSTRING("A bitmask of current modifiers, represented by ORed C.KMOD values")
mSCRIPT_DEFINE_STRUCT_MEMBER(mScriptKeyEvent, S16, modifiers)
mSCRIPT_DEFINE_DOCSTRING(
"The relevant key for this event. For most printable characters, this will be the Unicode "
"codepoint of the character. Some special values are present as C.KEY as well."
)
mSCRIPT_DEFINE_STRUCT_MEMBER(mScriptKeyEvent, S32, key)
mSCRIPT_DEFINE_END;
mSCRIPT_DEFINE_STRUCT(mScriptMouseButtonEvent)
mSCRIPT_DEFINE_CLASS_DOCSTRING("A mouse button event.")
mSCRIPT_DEFINE_INHERIT(mScriptEvent)
mSCRIPT_DEFINE_DOCSTRING("Which mouse this event pertains to. Currently, this will always be 0.")
mSCRIPT_DEFINE_STRUCT_MEMBER(mScriptMouseButtonEvent, U8, mouse)
mSCRIPT_DEFINE_DOCSTRING("The state of the button, represented by a C.INPUT_STATE value")
mSCRIPT_DEFINE_STRUCT_MEMBER(mScriptMouseButtonEvent, U8, state)
mSCRIPT_DEFINE_DOCSTRING(
"Which mouse button this event pertains to. Symbolic names for primary (usually left), "
"secondary (usually right), and middle are in C.MOUSE_BUTTON, and further buttons "
"are numeric starting from 3."
)
mSCRIPT_DEFINE_STRUCT_MEMBER(mScriptMouseButtonEvent, U8, button)
mSCRIPT_DEFINE_END;
mSCRIPT_DEFINE_STRUCT(mScriptMouseMoveEvent)
mSCRIPT_DEFINE_CLASS_DOCSTRING("A mouse movement event.")
mSCRIPT_DEFINE_INHERIT(mScriptEvent)
mSCRIPT_DEFINE_DOCSTRING("Which mouse this event pertains to. Currently, this will always be 0.")
mSCRIPT_DEFINE_STRUCT_MEMBER(mScriptMouseMoveEvent, U8, mouse)
mSCRIPT_DEFINE_DOCSTRING(
"The x coordinate of the mouse in the context of game screen pixels. "
"This can be out of bounds of the game screen depending on the size of the window in question."
)
mSCRIPT_DEFINE_STRUCT_MEMBER(mScriptMouseMoveEvent, S32, x)
mSCRIPT_DEFINE_DOCSTRING(
"The y coordinate of the mouse in the context of game screen pixels. "
"This can be out of bounds of the game screen depending on the size of the window in question."
)
mSCRIPT_DEFINE_STRUCT_MEMBER(mScriptMouseMoveEvent, S32, y)
mSCRIPT_DEFINE_END;
mSCRIPT_DEFINE_STRUCT(mScriptMouseWheelEvent)
mSCRIPT_DEFINE_INHERIT(mScriptEvent)
mSCRIPT_DEFINE_DOCSTRING("Which mouse this event pertains to. Currently, this will always be 0.")
mSCRIPT_DEFINE_STRUCT_MEMBER(mScriptMouseWheelEvent, U8, mouse)
mSCRIPT_DEFINE_DOCSTRING("The amount scrolled horizontally")
mSCRIPT_DEFINE_STRUCT_MEMBER(mScriptMouseWheelEvent, S32, x)
mSCRIPT_DEFINE_DOCSTRING("The amount scrolled vertically")
mSCRIPT_DEFINE_STRUCT_MEMBER(mScriptMouseWheelEvent, S32, y)
mSCRIPT_DEFINE_END;
mSCRIPT_DEFINE_STRUCT(mScriptGamepadButtonEvent)
mSCRIPT_DEFINE_CLASS_DOCSTRING("A gamead button event.")
mSCRIPT_DEFINE_INHERIT(mScriptEvent)
mSCRIPT_DEFINE_DOCSTRING("The state of the button, represented by a C.INPUT_STATE value")
mSCRIPT_DEFINE_STRUCT_MEMBER(mScriptGamepadButtonEvent, U8, state)
mSCRIPT_DEFINE_DOCSTRING("Which gamepad this event pertains to. Currently, this will always be 0.")
mSCRIPT_DEFINE_STRUCT_MEMBER(mScriptGamepadButtonEvent, U8, pad)
mSCRIPT_DEFINE_DOCSTRING(
"Which button this event pertains to. There is currently no guaranteed button mapping, "
"and it might change between different controllers."
)
mSCRIPT_DEFINE_STRUCT_MEMBER(mScriptGamepadButtonEvent, U16, button)
mSCRIPT_DEFINE_END;
mSCRIPT_DEFINE_STRUCT(mScriptGamepadHatEvent)
mSCRIPT_DEFINE_CLASS_DOCSTRING("A gamepad POV hat event.")
mSCRIPT_DEFINE_INHERIT(mScriptEvent)
mSCRIPT_DEFINE_DOCSTRING("Which gamepad this event pertains to. Currently, this will always be 0.")
mSCRIPT_DEFINE_STRUCT_MEMBER(mScriptGamepadHatEvent, U8, pad)
mSCRIPT_DEFINE_DOCSTRING("Which hat this event pertains to. For most gamepads this will be 0.")
mSCRIPT_DEFINE_STRUCT_MEMBER(mScriptGamepadHatEvent, U8, hat)
mSCRIPT_DEFINE_DOCSTRING("The current direction of the hat. See C.INPUT_DIR for possible values.")
mSCRIPT_DEFINE_STRUCT_MEMBER(mScriptGamepadHatEvent, U8, direction)
mSCRIPT_DEFINE_END;
mSCRIPT_DEFINE_STRUCT(mScriptGamepad)
mSCRIPT_DEFINE_DOCSTRING("The human-readable name of this gamepad")
mSCRIPT_DEFINE_STRUCT_MEMBER(mScriptGamepad, CHARP, visibleName)
mSCRIPT_DEFINE_DOCSTRING("The internal name of this gamepad, generally unique to the specific type of gamepad")
mSCRIPT_DEFINE_STRUCT_MEMBER(mScriptGamepad, CHARP, internalName)
mSCRIPT_DEFINE_DOCSTRING("An indexed list of the current values of each axis")
mSCRIPT_DEFINE_STRUCT_MEMBER(mScriptGamepad, LIST, axes)
mSCRIPT_DEFINE_DOCSTRING("An indexed list of the current values of each button")
mSCRIPT_DEFINE_STRUCT_MEMBER(mScriptGamepad, LIST, buttons)
mSCRIPT_DEFINE_DOCSTRING("An indexed list of the current values of POV hat")
mSCRIPT_DEFINE_STRUCT_MEMBER(mScriptGamepad, LIST, hats)
mSCRIPT_DEFINE_END;
void mScriptContextAttachInput(struct mScriptContext* context) {
struct mScriptInputContext* inputContext = calloc(1, sizeof(*inputContext));
struct mScriptValue* value = mScriptValueAlloc(mSCRIPT_TYPE_MS_S(mScriptInputContext));
value->flags = mSCRIPT_VALUE_FLAG_FREE_BUFFER;
value->value.opaque = inputContext;
inputContext->seq = 0;
TableInit(&inputContext->activeKeys, 0, NULL);
mScriptContextSetGlobal(context, "input", value);
mScriptContextSetDocstring(context, "input", "Singleton instance of struct::mScriptInputContext");
mScriptContextExportConstants(context, "EV_TYPE", (struct mScriptKVPair[]) {
mSCRIPT_CONSTANT_PAIR(mSCRIPT_EV_TYPE, NONE),
mSCRIPT_CONSTANT_PAIR(mSCRIPT_EV_TYPE, KEY),
mSCRIPT_CONSTANT_PAIR(mSCRIPT_EV_TYPE, MOUSE_BUTTON),
mSCRIPT_CONSTANT_PAIR(mSCRIPT_EV_TYPE, MOUSE_MOVE),
mSCRIPT_CONSTANT_PAIR(mSCRIPT_EV_TYPE, MOUSE_WHEEL),
mSCRIPT_CONSTANT_PAIR(mSCRIPT_EV_TYPE, GAMEPAD_BUTTON),
mSCRIPT_CONSTANT_PAIR(mSCRIPT_EV_TYPE, TRIGGER),
mSCRIPT_KV_SENTINEL
});
mScriptContextExportConstants(context, "INPUT_STATE", (struct mScriptKVPair[]) {
mSCRIPT_CONSTANT_PAIR(mSCRIPT_INPUT_STATE, UP),
mSCRIPT_CONSTANT_PAIR(mSCRIPT_INPUT_STATE, DOWN),
mSCRIPT_CONSTANT_PAIR(mSCRIPT_INPUT_STATE, HELD),
mSCRIPT_KV_SENTINEL
});
mScriptContextExportConstants(context, "INPUT_DIR", (struct mScriptKVPair[]) {
mSCRIPT_CONSTANT_PAIR(mSCRIPT_INPUT_DIR, NONE),
mSCRIPT_CONSTANT_PAIR(mSCRIPT_INPUT_DIR, NORTH),
mSCRIPT_CONSTANT_PAIR(mSCRIPT_INPUT_DIR, EAST),
mSCRIPT_CONSTANT_PAIR(mSCRIPT_INPUT_DIR, SOUTH),
mSCRIPT_CONSTANT_PAIR(mSCRIPT_INPUT_DIR, WEST),
mSCRIPT_CONSTANT_PAIR(mSCRIPT_INPUT_DIR, UP),
mSCRIPT_CONSTANT_PAIR(mSCRIPT_INPUT_DIR, RIGHT),
mSCRIPT_CONSTANT_PAIR(mSCRIPT_INPUT_DIR, DOWN),
mSCRIPT_CONSTANT_PAIR(mSCRIPT_INPUT_DIR, LEFT),
mSCRIPT_CONSTANT_PAIR(mSCRIPT_INPUT_DIR, NORTHEAST),
mSCRIPT_CONSTANT_PAIR(mSCRIPT_INPUT_DIR, NORTHWEST),
mSCRIPT_CONSTANT_PAIR(mSCRIPT_INPUT_DIR, SOUTHEAST),
mSCRIPT_CONSTANT_PAIR(mSCRIPT_INPUT_DIR, SOUTHWEST),
mSCRIPT_KV_SENTINEL
});
mScriptContextExportConstants(context, "KEY", (struct mScriptKVPair[]) {
mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, NONE),
mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, BACKSPACE),
mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, TAB),
mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, ENTER),
mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, ESCAPE),
mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, DELETE),
mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, F1),
mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, F2),
mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, F3),
mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, F4),
mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, F5),
mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, F6),
mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, F7),
mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, F8),
mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, F9),
mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, F10),
mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, F11),
mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, F12),
mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, F13),
mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, F14),
mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, F15),
mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, F16),
mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, F17),
mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, F18),
mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, F19),
mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, F20),
mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, F21),
mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, F22),
mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, F23),
mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, F24),
mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, UP),
mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, RIGHT),
mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, DOWN),
mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, LEFT),
mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, PAGE_UP),
mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, PAGE_DOWN),
mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, HOME),
mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, END),
mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, INSERT),
mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, BREAK),
mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, CLEAR),
mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, PRINT_SCREEN),
mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, SYSRQ),
mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, MENU),
mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, HELP),
mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, LSHIFT),
mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, RSHIFT),
mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, SHIFT),
mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, LCONTROL),
mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, RCONTROL),
mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, CONTROL),
mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, LALT),
mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, RALT),
mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, ALT),
mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, LSUPER),
mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, RSUPER),
mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, SUPER),
mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, CAPS_LOCK),
mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, NUM_LOCK),
mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, SCROLL_LOCK),
mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, KP_0),
mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, KP_1),
mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, KP_2),
mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, KP_3),
mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, KP_4),
mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, KP_5),
mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, KP_6),
mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, KP_7),
mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, KP_8),
mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, KP_9),
mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, KP_PLUS),
mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, KP_MINUS),
mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, KP_MULTIPLY),
mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, KP_DIVIDE),
mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, KP_COMMA),
mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, KP_POINT),
mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, KP_ENTER),
mSCRIPT_KV_SENTINEL
});
mScriptContextExportConstants(context, "KMOD", (struct mScriptKVPair[]) {
mSCRIPT_CONSTANT_PAIR(mSCRIPT_KMOD, NONE),
mSCRIPT_CONSTANT_PAIR(mSCRIPT_KMOD, LSHIFT),
mSCRIPT_CONSTANT_PAIR(mSCRIPT_KMOD, RSHIFT),
mSCRIPT_CONSTANT_PAIR(mSCRIPT_KMOD, SHIFT),
mSCRIPT_CONSTANT_PAIR(mSCRIPT_KMOD, LCONTROL),
mSCRIPT_CONSTANT_PAIR(mSCRIPT_KMOD, RCONTROL),
mSCRIPT_CONSTANT_PAIR(mSCRIPT_KMOD, CONTROL),
mSCRIPT_CONSTANT_PAIR(mSCRIPT_KMOD, LALT),
mSCRIPT_CONSTANT_PAIR(mSCRIPT_KMOD, RALT),
mSCRIPT_CONSTANT_PAIR(mSCRIPT_KMOD, ALT),
mSCRIPT_CONSTANT_PAIR(mSCRIPT_KMOD, LSUPER),
mSCRIPT_CONSTANT_PAIR(mSCRIPT_KMOD, RSUPER),
mSCRIPT_CONSTANT_PAIR(mSCRIPT_KMOD, SUPER),
mSCRIPT_CONSTANT_PAIR(mSCRIPT_KMOD, CAPS_LOCK),
mSCRIPT_CONSTANT_PAIR(mSCRIPT_KMOD, NUM_LOCK),
mSCRIPT_CONSTANT_PAIR(mSCRIPT_KMOD, SCROLL_LOCK),
mSCRIPT_KV_SENTINEL
});
mScriptContextExportConstants(context, "MOUSE_BUTTON", (struct mScriptKVPair[]) {
mSCRIPT_CONSTANT_PAIR(mSCRIPT_MOUSE_BUTTON, PRIMARY),
mSCRIPT_CONSTANT_PAIR(mSCRIPT_MOUSE_BUTTON, SECONDARY),
mSCRIPT_CONSTANT_PAIR(mSCRIPT_MOUSE_BUTTON, MIDDLE),
mSCRIPT_KV_SENTINEL
});
}
void _mScriptInputDeinit(struct mScriptInputContext* context) {
TableDeinit(&context->activeKeys);
}
bool _mScriptInputIsKeyActive(const struct mScriptInputContext* context, struct mScriptValue* value) {
uint32_t key;
struct mScriptValue intValue;
size_t length;
const char* strbuf;
switch (value->type->base) {
case mSCRIPT_TYPE_SINT:
case mSCRIPT_TYPE_UINT:
case mSCRIPT_TYPE_FLOAT:
if (!mScriptCast(mSCRIPT_TYPE_MS_U32, value, &intValue)) {
return false;
}
key = intValue.value.u32;
break;
case mSCRIPT_TYPE_STRING:
if (value->value.string->length > 1) {
return false;
}
strbuf = value->value.string->buffer;
length = value->value.string->size;
key = utf8Char(&strbuf, &length);
break;
default:
return false;
}
void* down = TableLookup(&context->activeKeys, key);
return down != NULL;
}
static struct mScriptValue* _mScriptInputActiveKeys(const struct mScriptInputContext* context) {
struct mScriptValue* list = mScriptValueAlloc(mSCRIPT_TYPE_MS_LIST);
struct TableIterator iter;
if (!TableIteratorStart(&context->activeKeys, &iter)) {
return list;
}
do {
uint32_t key = TableIteratorGetKey(&context->activeKeys, &iter);
*mScriptListAppend(list->value.list) = mSCRIPT_MAKE_U32(key);
} while (TableIteratorNext(&context->activeKeys, &iter));
return list;
}
static bool _updateKeys(struct mScriptContext* context, struct mScriptKeyEvent* event) {
int offset = 0;
switch (event->state) {
case mSCRIPT_INPUT_STATE_UP:
offset = -1;
break;
case mSCRIPT_INPUT_STATE_DOWN:
offset = 1;
break;
default:
return true;
}
struct mScriptValue* input = mScriptContextGetGlobal(context, "input");
if (!input) {
return false;
}
struct mScriptInputContext* inputContext = input->value.opaque;
intptr_t value = (intptr_t) TableLookup(&inputContext->activeKeys, event->key);
value += offset;
if (value < 1) {
TableRemove(&inputContext->activeKeys, event->key);
} else {
TableInsert(&inputContext->activeKeys, event->key, (void*) value);
}
if (offset < 0 && value > 0) {
return false;
}
if (offset > 0 && value != 1) {
event->state = mSCRIPT_INPUT_STATE_HELD;
}
return true;
}
void mScriptContextFireEvent(struct mScriptContext* context, struct mScriptEvent* event) {
struct mScriptValue* input = mScriptContextGetGlobal(context, "input");
if (!input) {
return;
}
struct mScriptInputContext* inputContext = input->value.opaque;
switch (event->type) {
case mSCRIPT_EV_TYPE_KEY:
if (!_updateKeys(context, (struct mScriptKeyEvent*) event)) {
return;
}
break;
case mSCRIPT_EV_TYPE_NONE:
return;
}
struct mScriptList args;
mScriptListInit(&args, 1);
struct mScriptValue* value = mScriptListAppend(&args);
value->type = eventTypes[event->type];
value->refs = mSCRIPT_VALUE_UNREF;
value->flags = 0;
value->value.opaque = event;
event->seq = inputContext->seq;
++inputContext->seq;
mScriptContextTriggerCallback(context, eventNames[event->type], &args);
mScriptListDeinit(&args);
}
int mScriptContextGamepadAttach(struct mScriptContext* context, struct mScriptGamepad* pad) {
struct mScriptValue* input = mScriptContextGetGlobal(context, "input");
if (!input) {
return false;
}
struct mScriptInputContext* inputContext = input->value.opaque;
if (inputContext->activeGamepad) {
return -1;
}
inputContext->activeGamepad = pad;
return 0;
}
bool mScriptContextGamepadDetach(struct mScriptContext* context, int pad) {
if (pad != 0) {
return false;
}
struct mScriptValue* input = mScriptContextGetGlobal(context, "input");
if (!input) {
return false;
}
struct mScriptInputContext* inputContext = input->value.opaque;
if (!inputContext->activeGamepad) {
return false;
}
inputContext->activeGamepad = NULL;
return true;
}
struct mScriptGamepad* mScriptContextGamepadLookup(struct mScriptContext* context, int pad) {
if (pad != 0) {
return NULL;
}
struct mScriptValue* input = mScriptContextGetGlobal(context, "input");
if (!input) {
return false;
}
struct mScriptInputContext* inputContext = input->value.opaque;
return inputContext->activeGamepad;
}
void mScriptGamepadInit(struct mScriptGamepad* gamepad) {
memset(gamepad, 0, sizeof(*gamepad));
mScriptListInit(&gamepad->axes, 8);
mScriptListInit(&gamepad->buttons, 1);
mScriptListInit(&gamepad->hats, 1);
}
void mScriptGamepadDeinit(struct mScriptGamepad* gamepad) {
mScriptListDeinit(&gamepad->axes);
mScriptListDeinit(&gamepad->buttons);
mScriptListDeinit(&gamepad->hats);
}
void mScriptGamepadSetAxisCount(struct mScriptGamepad* gamepad, unsigned count) {
if (count > UINT8_MAX) {
count = UINT8_MAX;
}
unsigned oldSize = mScriptListSize(&gamepad->axes);
mScriptListResize(&gamepad->axes, (ssize_t) count - oldSize);
unsigned i;
for (i = oldSize; i < count; ++i) {
*mScriptListGetPointer(&gamepad->axes, i) = mSCRIPT_MAKE_S16(0);
}
}
void mScriptGamepadSetButtonCount(struct mScriptGamepad* gamepad, unsigned count) {
if (count > UINT16_MAX) {
count = UINT16_MAX;
}
unsigned oldSize = mScriptListSize(&gamepad->buttons);
mScriptListResize(&gamepad->buttons, (ssize_t) count - oldSize);
unsigned i;
for (i = oldSize; i < count; ++i) {
*mScriptListGetPointer(&gamepad->buttons, i) = mSCRIPT_MAKE_BOOL(false);
}
}
void mScriptGamepadSetHatCount(struct mScriptGamepad* gamepad, unsigned count) {
if (count > UINT8_MAX) {
count = UINT8_MAX;
}
unsigned oldSize = mScriptListSize(&gamepad->hats);
mScriptListResize(&gamepad->hats, (ssize_t) count - oldSize);
unsigned i;
for (i = oldSize; i < count; ++i) {
*mScriptListGetPointer(&gamepad->hats, i) = mSCRIPT_MAKE_U8(0);
}
}
void mScriptGamepadSetAxis(struct mScriptGamepad* gamepad, unsigned id, int16_t value) {
if (id >= mScriptListSize(&gamepad->axes)) {
return;
}
mScriptListGetPointer(&gamepad->axes, id)->value.s32 = value;
}
void mScriptGamepadSetButton(struct mScriptGamepad* gamepad, unsigned id, bool down) {
if (id >= mScriptListSize(&gamepad->buttons)) {
return;
}
mScriptListGetPointer(&gamepad->buttons, id)->value.u32 = down;
}
void mScriptGamepadSetHat(struct mScriptGamepad* gamepad, unsigned id, int direction) {
if (id >= mScriptListSize(&gamepad->hats)) {
return;
}
mScriptListGetPointer(&gamepad->hats, id)->value.u32 = direction;
}
int16_t mScriptGamepadGetAxis(struct mScriptGamepad* gamepad, unsigned id) {
if (id >= mScriptListSize(&gamepad->axes)) {
return 0;
}
return mScriptListGetPointer(&gamepad->axes, id)->value.s32;
}
bool mScriptGamepadGetButton(struct mScriptGamepad* gamepad, unsigned id) {
if (id >= mScriptListSize(&gamepad->buttons)) {
return false;
}
return mScriptListGetPointer(&gamepad->buttons, id)->value.u32;
}
int mScriptGamepadGetHat(struct mScriptGamepad* gamepad, unsigned id) {
if (id >= mScriptListSize(&gamepad->hats)) {
return mSCRIPT_INPUT_DIR_NONE;
}
return mScriptListGetPointer(&gamepad->hats, id)->value.u32;
}
void mScriptContextGetInputTypes(struct Table* types) {
mScriptTypeAdd(types, mSCRIPT_TYPE_MS_S(mScriptEvent));
mScriptTypeAdd(types, mSCRIPT_TYPE_MS_S(mScriptKeyEvent));
mScriptTypeAdd(types, mSCRIPT_TYPE_MS_S(mScriptMouseMoveEvent));
mScriptTypeAdd(types, mSCRIPT_TYPE_MS_S(mScriptMouseButtonEvent));
mScriptTypeAdd(types, mSCRIPT_TYPE_MS_S(mScriptGamepadButtonEvent));
mScriptTypeAdd(types, mSCRIPT_TYPE_MS_S(mScriptGamepadHatEvent));
mScriptTypeAdd(types, mSCRIPT_TYPE_MS_S(mScriptGamepad));
}

View File

@ -14,6 +14,7 @@ struct TestA {
int32_t i2;
int8_t b8;
int16_t hUnaligned;
char str[6];
struct mScriptValue table;
struct mScriptList list;
int32_t (*ifn0)(struct TestA*);
@ -105,6 +106,7 @@ mSCRIPT_DEFINE_STRUCT(TestA)
mSCRIPT_DEFINE_STRUCT_MEMBER(TestA, S32, i2)
mSCRIPT_DEFINE_STRUCT_MEMBER(TestA, S8, b8)
mSCRIPT_DEFINE_STRUCT_MEMBER(TestA, S16, hUnaligned)
mSCRIPT_DEFINE_STRUCT_MEMBER(TestA, CHARP, str)
mSCRIPT_DEFINE_STRUCT_MEMBER(TestA, TABLE, table)
mSCRIPT_DEFINE_STRUCT_MEMBER(TestA, LIST, list)
mSCRIPT_DEFINE_STRUCT_METHOD(TestA, ifn0)
@ -191,6 +193,13 @@ M_TEST_DEFINE(testALayout) {
assert_ptr_equal(member->type, mSCRIPT_TYPE_MS_S16);
assert_int_not_equal(member->offset, sizeof(int32_t) * 2 + 1);
member = HashTableLookup(&cls->instanceMembers, "str");
assert_non_null(member);
assert_string_equal(member->name, "str");
assert_null(member->docstring);
assert_ptr_equal(member->type, mSCRIPT_TYPE_MS_CHARP);
assert_int_equal(member->offset, &((struct TestA*) 0)->str);
member = HashTableLookup(&cls->instanceMembers, "table");
assert_non_null(member);
assert_string_equal(member->name, "table");
@ -304,6 +313,8 @@ M_TEST_DEFINE(testAGet) {
s.table.type = mSCRIPT_TYPE_MS_TABLE;
s.table.type->alloc(&s.table);
strcpy(s.str, "test");
struct mScriptValue sval = mSCRIPT_MAKE_S(TestA, &s);
struct mScriptValue val;
struct mScriptValue compare;
@ -324,6 +335,10 @@ M_TEST_DEFINE(testAGet) {
assert_true(mScriptObjectGet(&sval, "hUnaligned", &val));
assert_true(compare.type->equal(&compare, &val));
compare = mSCRIPT_MAKE_CHARP("test");
assert_true(mScriptObjectGet(&sval, "str", &val));
assert_true(compare.type->equal(&compare, &val));
compare = mSCRIPT_MAKE_S32(5);
assert_true(mScriptObjectGet(&sval, "list", &val));
assert_ptr_equal(val.type, mSCRIPT_TYPE_MS_LIST);

180
src/script/test/input.c Normal file
View File

@ -0,0 +1,180 @@
/* 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/. */
#include "util/test/suite.h"
#include <mgba/internal/script/lua.h>
#include <mgba/script/context.h>
#include <mgba/script/input.h>
#include <mgba/script/types.h>
#include "script/test.h"
#define SETUP_LUA \
struct mScriptContext context; \
mScriptContextInit(&context); \
struct mScriptEngineContext* lua = mScriptContextRegisterEngine(&context, mSCRIPT_ENGINE_LUA); \
mScriptContextAttachStdlib(&context); \
mScriptContextAttachInput(&context)
M_TEST_SUITE_SETUP(mScriptInput) {
if (mSCRIPT_ENGINE_LUA->init) {
mSCRIPT_ENGINE_LUA->init(mSCRIPT_ENGINE_LUA);
}
return 0;
}
M_TEST_SUITE_TEARDOWN(mScriptInput) {
if (mSCRIPT_ENGINE_LUA->deinit) {
mSCRIPT_ENGINE_LUA->deinit(mSCRIPT_ENGINE_LUA);
}
return 0;
}
M_TEST_DEFINE(members) {
SETUP_LUA;
TEST_PROGRAM("assert(input)");
TEST_PROGRAM("assert(input.seq == 0)");
TEST_PROGRAM("assert(input.isKeyActive)");
mScriptContextDeinit(&context);
}
M_TEST_DEFINE(seq) {
SETUP_LUA;
TEST_PROGRAM("assert(input.seq == 0)");
TEST_PROGRAM(
"seq = nil\n"
"function cb(ev)\n"
" seq = ev.seq\n"
"end\n"
"id = callbacks:add('key', cb)\n"
);
struct mScriptKeyEvent keyEvent = {
.d = { .type = mSCRIPT_EV_TYPE_KEY },
.state = mSCRIPT_INPUT_STATE_DOWN,
};
mScriptContextFireEvent(&context, &keyEvent.d);
TEST_PROGRAM("assert(input.seq == 1)");
TEST_PROGRAM("assert(seq == 0)");
mScriptContextFireEvent(&context, &keyEvent.d);
TEST_PROGRAM("assert(input.seq == 2)");
TEST_PROGRAM("assert(seq == 1)");
mScriptContextDeinit(&context);
}
M_TEST_DEFINE(fireKey) {
SETUP_LUA;
TEST_PROGRAM("assert(not input:isKeyActive('a'))");
TEST_PROGRAM(
"activeKey = false\n"
"state = nil\n"
"function cb(ev)\n"
" assert(ev.type == C.EV_TYPE.KEY)\n"
" activeKey = string.char(ev.key)\n"
" state = ev.state\n"
"end\n"
"id = callbacks:add('key', cb)\n"
"assert(id)\n"
"assert(not activeKey)\n"
);
struct mScriptKeyEvent keyEvent = {
.d = { .type = mSCRIPT_EV_TYPE_KEY },
.state = mSCRIPT_INPUT_STATE_DOWN,
.key = 'a'
};
mScriptContextFireEvent(&context, &keyEvent.d);
TEST_PROGRAM("assert(input:isKeyActive('a'))");
TEST_PROGRAM("assert(activeKey == 'a')");
TEST_PROGRAM("assert(state == C.INPUT_STATE.DOWN)");
keyEvent.state = mSCRIPT_INPUT_STATE_UP;
mScriptContextFireEvent(&context, &keyEvent.d);
TEST_PROGRAM("assert(not input:isKeyActive('a'))");
TEST_PROGRAM("assert(state == C.INPUT_STATE.UP)");
mScriptContextDeinit(&context);
}
M_TEST_DEFINE(activeKeys) {
SETUP_LUA;
TEST_PROGRAM("assert(#input:activeKeys() == 0)");
struct mScriptKeyEvent keyEvent = {
.d = { .type = mSCRIPT_EV_TYPE_KEY },
.state = mSCRIPT_INPUT_STATE_DOWN,
.key = 'a'
};
mScriptContextFireEvent(&context, &keyEvent.d);
TEST_PROGRAM("assert(#input:activeKeys() == 1)");
TEST_PROGRAM("assert(input:activeKeys()[1] == string.byte('a'))");
keyEvent.state = mSCRIPT_INPUT_STATE_UP;
mScriptContextFireEvent(&context, &keyEvent.d);
TEST_PROGRAM("assert(#input:activeKeys() == 0)");
mScriptContextDeinit(&context);
}
M_TEST_DEFINE(gamepadExport) {
SETUP_LUA;
struct mScriptGamepad m_gamepad;
mScriptGamepadInit(&m_gamepad);
TEST_PROGRAM("assert(not input.activeGamepad)");
assert_int_equal(mScriptContextGamepadAttach(&context, &m_gamepad), 0);
TEST_PROGRAM("assert(input.activeGamepad)");
TEST_PROGRAM("assert(#input.activeGamepad.axes == 0)");
TEST_PROGRAM("assert(#input.activeGamepad.buttons == 0)");
TEST_PROGRAM("assert(#input.activeGamepad.hats == 0)");
mScriptGamepadSetAxisCount(&m_gamepad, 1);
TEST_PROGRAM("assert(#input.activeGamepad.axes == 1)");
TEST_PROGRAM("assert(input.activeGamepad.axes[1] == 0)");
mScriptGamepadSetAxis(&m_gamepad, 0, 123);
TEST_PROGRAM("assert(input.activeGamepad.axes[1] == 123)");
mScriptGamepadSetButtonCount(&m_gamepad, 1);
TEST_PROGRAM("assert(#input.activeGamepad.buttons == 1)");
TEST_PROGRAM("assert(input.activeGamepad.buttons[1] == false)");
mScriptGamepadSetButton(&m_gamepad, 0, true);
TEST_PROGRAM("assert(input.activeGamepad.buttons[1] == true)");
mScriptGamepadSetHatCount(&m_gamepad, 1);
TEST_PROGRAM("assert(#input.activeGamepad.hats == 1)");
TEST_PROGRAM("assert(input.activeGamepad.hats[1] == C.INPUT_DIR.NONE)");
mScriptGamepadSetHat(&m_gamepad, 0, mSCRIPT_INPUT_DIR_NORTHWEST);
TEST_PROGRAM("assert(input.activeGamepad.hats[1] == C.INPUT_DIR.NORTHWEST)");
mScriptContextGamepadDetach(&context, 0);
TEST_PROGRAM("assert(not input.activeGamepad)");
mScriptGamepadDeinit(&m_gamepad);
mScriptContextDeinit(&context);
}
M_TEST_SUITE_DEFINE_SETUP_TEARDOWN(mScriptInput,
cmocka_unit_test(members),
cmocka_unit_test(seq),
cmocka_unit_test(fireKey),
cmocka_unit_test(activeKeys),
cmocka_unit_test(gamepadExport),
)

View File

@ -22,6 +22,7 @@ struct Test {
void (*vfn0)(struct Test*);
void (*vfn1)(struct Test*, int);
int32_t (*icfn0)(const struct Test*);
struct Test* next;
};
static int identityInt(int in) {
@ -83,6 +84,7 @@ mSCRIPT_DECLARE_STRUCT_VOID_METHOD(Test, v1, testV1, 1, S32, b);
mSCRIPT_DEFINE_STRUCT(Test)
mSCRIPT_DEFINE_STRUCT_MEMBER(Test, S32, i)
mSCRIPT_DEFINE_STRUCT_MEMBER(Test, PS(Test), next)
mSCRIPT_DEFINE_STRUCT_METHOD(Test, ifn0)
mSCRIPT_DEFINE_STRUCT_METHOD(Test, ifn1)
mSCRIPT_DEFINE_STRUCT_METHOD(Test, icfn0)
@ -726,6 +728,42 @@ M_TEST_DEFINE(callList) {
mScriptContextDeinit(&context);
}
M_TEST_DEFINE(linkedList) {
SETUP_LUA;
struct Test first = {
.i = 1
};
struct Test second = {
.i = 2
};
struct mScriptValue a = mSCRIPT_MAKE_S(Test, &first);
assert_true(lua->setGlobal(lua, "l", &a));
TEST_PROGRAM("assert(l)");
TEST_PROGRAM("assert(l.i == 1)");
TEST_PROGRAM("assert(not l.next)");
first.next = &second;
TEST_PROGRAM("assert(l)");
TEST_PROGRAM("assert(l.i == 1)");
TEST_PROGRAM("assert(l.next)");
TEST_PROGRAM("assert(l.next.i == 2)");
TEST_PROGRAM("assert(not l.next.next)");
TEST_PROGRAM(
"n = l.next\n"
"function readN()\n"
" assert(n)\n"
" assert(n.i or not n.i)\n"
"end\n"
"assert(pcall(readN))\n");
// The weakref stored in `n` gets pruned between executions to avoid stale pointers
TEST_PROGRAM("assert(not pcall(readN))");
mScriptContextDeinit(&context);
}
M_TEST_SUITE_DEFINE_SETUP_TEARDOWN(mScriptLua,
cmocka_unit_test(create),
cmocka_unit_test(loadGood),
@ -744,4 +782,5 @@ M_TEST_SUITE_DEFINE_SETUP_TEARDOWN(mScriptLua,
cmocka_unit_test(tableLookup),
cmocka_unit_test(tableIterate),
cmocka_unit_test(callList),
cmocka_unit_test(linkedList)
)

View File

@ -82,15 +82,15 @@ M_TEST_DEFINE(callbacks) {
TEST_VALUE(S32, "val", 0);
mScriptContextTriggerCallback(&context, "test");
mScriptContextTriggerCallback(&context, "test", NULL);
TEST_VALUE(S32, "val", 1);
mScriptContextTriggerCallback(&context, "test");
mScriptContextTriggerCallback(&context, "test", NULL);
TEST_VALUE(S32, "val", 2);
TEST_PROGRAM("callbacks:remove(id)");
mScriptContextTriggerCallback(&context, "test");
mScriptContextTriggerCallback(&context, "test", NULL);
TEST_VALUE(S32, "val", 2);
mScriptContextDeinit(&context);

View File

@ -5,6 +5,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include <mgba/script/types.h>
#include <mgba/internal/script/types.h>
#include <mgba/script/context.h>
#include <mgba/script/macros.h>
#include <mgba-util/hash.h>
@ -853,6 +854,21 @@ const struct mScriptValue* mScriptValueUnwrapConst(const struct mScriptValue* va
return NULL;
}
void mScriptValueFollowPointer(struct mScriptValue* ptr, struct mScriptValue* out) {
if (ptr->type->base != mSCRIPT_TYPE_OPAQUE || !ptr->type->details.type) {
return;
}
out->value.opaque = *(void**) ptr->value.opaque;
if (out->value.opaque) {
out->type = ptr->type->details.type;
} else {
out->type = mSCRIPT_TYPE_MS_VOID;
}
out->refs = mSCRIPT_VALUE_UNREF;
out->flags = 0;
}
struct mScriptValue* mScriptStringCreateEmpty(size_t size) {
struct mScriptValue* val = mScriptValueAlloc(mSCRIPT_TYPE_MS_STR);
struct mScriptString* internal = val->value.opaque;
@ -1178,6 +1194,15 @@ static bool _accessRawMember(struct mScriptClassMember* member, void* raw, bool
val->type = mSCRIPT_TYPE_MS_WRAPPER;
val->value.table = raw;
break;
case mSCRIPT_TYPE_STRING:
if (member->type == mSCRIPT_TYPE_MS_CHARP) {
val->refs = mSCRIPT_VALUE_UNREF;
val->flags = 0;
val->type = mSCRIPT_TYPE_MS_CHARP;
val->value.opaque = raw;
break;
}
return false;
case mSCRIPT_TYPE_LIST:
val->refs = mSCRIPT_VALUE_UNREF;
val->flags = 0;
@ -1500,3 +1525,56 @@ bool mScriptCoerceFrame(const struct mScriptTypeTuple* types, struct mScriptList
}
return true;
}
static void addTypesFromTuple(struct Table* types, const struct mScriptTypeTuple* tuple) {
size_t i;
for (i = 0; i < tuple->count; ++i) {
mScriptTypeAdd(types, tuple->entries[i]);
}
}
static void addTypesFromTable(struct Table* types, struct Table* table) {
struct TableIterator iter;
if (!HashTableIteratorStart(table, &iter)) {
return;
}
do {
struct mScriptClassMember* member = HashTableIteratorGetValue(table, &iter);
mScriptTypeAdd(types, member->type);
} while(HashTableIteratorNext(table, &iter));
}
void mScriptTypeAdd(struct Table* types, const struct mScriptType* type) {
if (HashTableLookup(types, type->name) || type->isConst) {
return;
}
HashTableInsert(types, type->name, (struct mScriptType*) type);
switch (type->base) {
case mSCRIPT_TYPE_FUNCTION:
addTypesFromTuple(types, &type->details.function.parameters);
addTypesFromTuple(types, &type->details.function.returnType);
break;
case mSCRIPT_TYPE_OBJECT:
mScriptClassInit(type->details.cls);
if (type->details.cls->parent) {
mScriptTypeAdd(types, type->details.cls->parent);
}
addTypesFromTable(types, &type->details.cls->instanceMembers);
break;
case mSCRIPT_TYPE_OPAQUE:
case mSCRIPT_TYPE_WRAPPER:
if (type->details.type) {
mScriptTypeAdd(types, type->details.type);
}
case mSCRIPT_TYPE_VOID:
case mSCRIPT_TYPE_SINT:
case mSCRIPT_TYPE_UINT:
case mSCRIPT_TYPE_FLOAT:
case mSCRIPT_TYPE_STRING:
case mSCRIPT_TYPE_LIST:
case mSCRIPT_TYPE_TABLE:
case mSCRIPT_TYPE_WEAKREF:
// No subtypes
break;
}
}