View
File renamed without changes.
View
File renamed without changes.
View
File renamed without changes.
View
File renamed without changes.
View
File renamed without changes.
View
File renamed without changes.
View
File renamed without changes.
View
File renamed without changes.
View
File renamed without changes.
View
Binary file not shown.
View
Binary file not shown.
View
Binary file not shown.
View
Binary file not shown.
View
File renamed without changes.
View
File renamed without changes.
View
File renamed without changes.
View
File renamed without changes.
View
File renamed without changes.
View
File renamed without changes.
View
File renamed without changes.
View
File renamed without changes.
View
File renamed without changes.
View
File renamed without changes.
View
File renamed without changes.
View
File renamed without changes.
View
File renamed without changes.
View
File renamed without changes.
View
File renamed without changes.
View
File renamed without changes.
View
File renamed without changes.
View
Diff not rendered.
View
Diff not rendered.
View
Diff not rendered.
View
Diff not rendered.
View
Diff not rendered.
View
Diff not rendered.
View
File renamed without changes.
View
File renamed without changes.
View
Diff not rendered.
View
Diff not rendered.
View
Diff not rendered.
View
File renamed without changes.
View
Diff not rendered.
View
Diff not rendered.
View
Diff not rendered.
View
Diff not rendered.
View
Diff not rendered.
View
Diff not rendered.
View
Binary file not shown.
View
Diff not rendered.
View
Diff not rendered.
View
Diff not rendered.
View
Diff not rendered.
View
Binary file not shown.
View
Diff not rendered.
View
Diff not rendered.
View
Diff not rendered.
View
Diff not rendered.
View
Diff not rendered.
View
Diff not rendered.
View
Diff not rendered.
View
Diff not rendered.
View
Diff not rendered.
View
Diff not rendered.
View
Diff not rendered.
View
Diff not rendered.
View
Diff not rendered.
View
Diff not rendered.
View
Diff not rendered.
View
Diff not rendered.
View
Diff not rendered.
View
Diff not rendered.
View
File renamed without changes.
View
Diff not rendered.
View
Diff not rendered.
View
Diff not rendered.
View
Diff not rendered.
View
Binary file not shown.
View
Diff not rendered.
View
Diff not rendered.
View
Diff not rendered.
View
Diff not rendered.
View
Diff not rendered.
View
Diff not rendered.
View
Diff not rendered.
View
Diff not rendered.
View
Diff not rendered.
View
Diff not rendered.
View
Diff not rendered.
View
Diff not rendered.
View
Diff not rendered.
View
Diff not rendered.
View
Diff not rendered.
View
Diff not rendered.
View
Diff not rendered.
View
Diff not rendered.
View
Diff not rendered.
View
Diff not rendered.
View
Diff not rendered.
View
Diff not rendered.
View
Diff not rendered.
View
Diff not rendered.
View
Diff not rendered.
View
File renamed without changes.
View
Diff not rendered.
View
Diff not rendered.
View
Diff not rendered.
View
Diff not rendered.
View
Diff not rendered.
View
Diff not rendered.
View
Diff not rendered.
View
Diff not rendered.
View
Diff not rendered.
View
Diff not rendered.
View
Diff not rendered.
View
Diff not rendered.
View
Diff not rendered.
View
Diff not rendered.
View
Diff not rendered.
View
Diff not rendered.
View
Diff not rendered.
View
Diff not rendered.
View
Diff not rendered.
View
Diff not rendered.
View
Diff not rendered.
View
Diff not rendered.
View
Diff not rendered.
View
Diff not rendered.
View
Diff not rendered.
View
Diff not rendered.
View
Diff not rendered.
View
Diff not rendered.
View
File renamed without changes.
View
@@ -73,7 +73,7 @@ typedef intptr_t ssize_t;
#define M_PI 3.141592654f
#endif
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) && (defined(__llvm__) || (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7))
#define ATOMIC_STORE(DST, SRC) __atomic_store_n(&DST, SRC, __ATOMIC_RELEASE)
#define ATOMIC_LOAD(DST, SRC) DST = __atomic_load_n(&SRC, __ATOMIC_ACQUIRE)
#define ATOMIC_ADD(DST, OP) __atomic_add_fetch(&DST, OP, __ATOMIC_RELEASE)
@@ -101,6 +101,8 @@ typedef intptr_t ssize_t;
#define PRIz "z"
#endif
+#if defined __BIG_ENDIAN__
+#define LOAD_32BE(DEST, ADDR, ARR) DEST = *(uint32_t*) ((uintptr_t) (ARR) + (size_t) (ADDR))
#if defined(__PPC__) || defined(__POWERPC__)
#define LOAD_32LE(DEST, ADDR, ARR) { \
uint32_t _addr = (ADDR); \
@@ -126,10 +128,39 @@ typedef intptr_t ssize_t;
__asm__("sthbrx %0, %1, %2" : : "r"(SRC), "b"(_ptr), "r"(_addr)); \
}
-#define LOAD_64LE(DEST, ADDR, ARR) DEST = __builtin_bswap64(((uint64_t*) ARR)[(ADDR) >> 3])
-#define STORE_64LE(SRC, ADDR, ARR) ((uint64_t*) ARR)[(ADDR) >> 3] = __builtin_bswap64(SRC)
-#elif defined __BIG_ENDIAN__
-#if defined(__llvm__) || (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)
+#define LOAD_64LE(DEST, ADDR, ARR) { \
+ uint32_t _addr = (ADDR); \
+ union { \
+ struct { \
+ uint32_t hi; \
+ uint32_t lo; \
+ }; \
+ uint64_t b64; \
+ } *bswap = (void*) &DEST; \
+ const void* _ptr = (ARR); \
+ __asm__( \
+ "lwbrx %0, %2, %3 \n" \
+ "lwbrx %1, %2, %4 \n" \
+ : "=r"(bswap->lo), "=r"(bswap->hi) : "b"(_ptr), "r"(_addr), "r"(_addr + 4)); \
+}
+
+#define STORE_64LE(SRC, ADDR, ARR) { \
+ uint32_t _addr = (ADDR); \
+ union { \
+ struct { \
+ uint32_t hi; \
+ uint32_t lo; \
+ }; \
+ uint64_t b64; \
+ } *bswap = (void*) &SRC; \
+ const void* _ptr = (ARR); \
+ __asm__( \
+ "stwbrx %0, %2, %3 \n" \
+ "stwbrx %1, %2, %4 \n" \
+ : : "r"(bswap->hi), "r"(bswap->lo), "b"(_ptr), "r"(_addr), "r"(_addr + 4)); \
+}
+
+#elif defined(__llvm__) || (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)
#define LOAD_64LE(DEST, ADDR, ARR) DEST = __builtin_bswap64(((uint64_t*) ARR)[(ADDR) >> 3])
#define LOAD_32LE(DEST, ADDR, ARR) DEST = __builtin_bswap32(((uint32_t*) ARR)[(ADDR) >> 2])
#define LOAD_16LE(DEST, ADDR, ARR) DEST = __builtin_bswap16(((uint16_t*) ARR)[(ADDR) >> 1])
@@ -146,6 +177,7 @@ typedef intptr_t ssize_t;
#define STORE_64LE(SRC, ADDR, ARR) *(uint64_t*) ((uintptr_t) (ARR) + (size_t) (ADDR)) = SRC
#define STORE_32LE(SRC, ADDR, ARR) *(uint32_t*) ((uintptr_t) (ARR) + (size_t) (ADDR)) = SRC
#define STORE_16LE(SRC, ADDR, ARR) *(uint16_t*) ((uintptr_t) (ARR) + (size_t) (ADDR)) = SRC
+#define LOAD_32BE(DEST, ADDR, ARR) DEST = __builtin_bswap32(((uint32_t*) ARR)[(ADDR) >> 2])
#endif
#define MAKE_MASK(START, END) (((1 << ((END) - (START))) - 1) << (START))
View
@@ -11,18 +11,9 @@
#include <3ds.h>
#include <malloc.h>
-#ifdef _3DS
-// ctrulib already has a type called Thread
-#define Thread CustomThread
-#endif
-
#define THREAD_ENTRY void
typedef ThreadFunc ThreadEntry;
-typedef struct {
- Handle handle;
- u8* stack;
-} Thread;
typedef LightLock Mutex;
typedef struct {
Mutex mutex;
@@ -103,22 +94,12 @@ static inline int ThreadCreate(Thread* thread, ThreadEntry entry, void* context)
if (!entry || !thread) {
return 1;
}
- thread->stack = memalign(8, 0x8000);
- if (!thread->stack) {
- return 1;
- }
- bool isNew3DS;
- APT_CheckNew3DS(&isNew3DS);
- if (isNew3DS && svcCreateThread(&thread->handle, entry, (u32) context, (u32*) &thread->stack[0x8000], 0x18, 2) == 0) {
- return 0;
- }
- return svcCreateThread(&thread->handle, entry, (u32) context, (u32*) &thread->stack[0x8000], 0x18, -1);
+ *thread = threadCreate(entry, context, 0x8000, 0x18, 2, true);
+ return !*thread;
}
static inline int ThreadJoin(Thread thread) {
- svcWaitSynchronization(thread.handle, U64_MAX);
- free(thread.stack);
- return 0;
+ return threadJoin(thread, U64_MAX);
}
static inline void ThreadSetName(const char* name) {
View
@@ -86,7 +86,12 @@ static inline int ThreadJoin(Thread thread) {
static inline int ThreadSetName(const char* name) {
#ifdef __APPLE__
+#if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 1060
return pthread_setname_np(name);
+#else
+ UNUSED(name);
+ return 0;
+#endif
#elif defined(__FreeBSD__) || defined(__OpenBSD__)
pthread_set_name_np(pthread_self(), name);
return 0;
View
@@ -10,6 +10,10 @@
CXX_GUARD_START
+#ifdef vector
+#undef vector
+#endif
+
#define DECLARE_VECTOR(NAME, TYPE) \
struct NAME { \
TYPE* vector; \
View
@@ -87,7 +87,7 @@ struct VDir* VDirOpenZip(const char* path, int flags);
struct VDir* VDirOpen7z(const char* path, int flags);
#endif
-#if defined(__wii__) || defined(_3DS)
+#if defined(__wii__) || defined(_3DS) || defined(PSP2)
struct VDir* VDeviceList(void);
#endif
View
@@ -14,8 +14,6 @@ CXX_GUARD_START
#include <mgba/core/log.h>
#include <mgba-util/vector.h>
-#define MAX_ROM_PATCHES 4
-
enum mCheatType {
CHEAT_ASSIGN,
CHEAT_ASSIGN_INDIRECT,
@@ -30,7 +28,8 @@ enum mCheatType {
CHEAT_IF_UGT,
CHEAT_IF_AND,
CHEAT_IF_LAND,
- CHEAT_IF_NAND
+ CHEAT_IF_NAND,
+ CHEAT_IF_BUTTON,
};
struct mCheat {
@@ -79,6 +78,8 @@ struct mCheatDevice {
struct mCheatSet* (*createSet)(struct mCheatDevice*, const char* name);
struct mCheatSets cheats;
+ bool autosave;
+ bool buttonDown;
};
struct VFile;
@@ -99,7 +100,12 @@ void mCheatRemoveSet(struct mCheatDevice*, struct mCheatSet*);
bool mCheatParseFile(struct mCheatDevice*, struct VFile*);
bool mCheatSaveFile(struct mCheatDevice*, struct VFile*);
+#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2
+void mCheatAutosave(struct mCheatDevice*);
+#endif
+
void mCheatRefresh(struct mCheatDevice*, struct mCheatSet*);
+void mCheatPressButton(struct mCheatDevice*, bool down);
CXX_GUARD_END
View
@@ -51,6 +51,7 @@ struct mCoreOptions {
char* savestatePath;
char* screenshotPath;
char* patchPath;
+ char* cheatsPath;
int volume;
bool mute;
View
@@ -148,6 +148,7 @@ struct mCore {
void (*detachDebugger)(struct mCore*);
void (*loadSymbols)(struct mCore*, struct VFile*);
+ bool (*lookupIdentifier)(struct mCore*, const char* name, int32_t* value, int* segment);
#endif
struct mCheatDevice* (*cheatDevice)(struct mCore*);
@@ -175,6 +176,7 @@ bool mCorePreloadFile(struct mCore* core, const char* path);
bool mCoreAutoloadSave(struct mCore* core);
bool mCoreAutoloadPatch(struct mCore* core);
+bool mCoreAutoloadCheats(struct mCore* core);
bool mCoreSaveState(struct mCore* core, int slot, int flags);
bool mCoreLoadState(struct mCore* core, int slot, int flags);
View
@@ -21,6 +21,7 @@ struct mDirectorySet {
struct VDir* patch;
struct VDir* state;
struct VDir* screenshot;
+ struct VDir* cheats;
};
void mDirectorySetInit(struct mDirectorySet* dirs);
View
@@ -13,29 +13,38 @@ CXX_GUARD_START
#include <mgba-util/vector.h>
enum mCoreMemorySearchType {
- mCORE_MEMORY_SEARCH_32,
- mCORE_MEMORY_SEARCH_16,
- mCORE_MEMORY_SEARCH_8,
+ mCORE_MEMORY_SEARCH_INT,
mCORE_MEMORY_SEARCH_STRING,
mCORE_MEMORY_SEARCH_GUESS,
};
+enum mCoreMemorySearchOp {
+ mCORE_MEMORY_SEARCH_EQUAL,
+ mCORE_MEMORY_SEARCH_GREATER,
+ mCORE_MEMORY_SEARCH_LESS,
+ mCORE_MEMORY_SEARCH_DELTA,
+};
+
struct mCoreMemorySearchParams {
int memoryFlags;
enum mCoreMemorySearchType type;
+ enum mCoreMemorySearchOp op;
+ int align;
+ int width;
union {
const char* valueStr;
- uint32_t value32;
- uint32_t value16;
- uint32_t value8;
+ int32_t valueInt;
};
};
struct mCoreMemorySearchResult {
uint32_t address;
int segment;
- uint64_t guessDivisor;
+ uint32_t guessDivisor;
+ uint32_t guessMultiplier;
enum mCoreMemorySearchType type;
+ int width;
+ int32_t oldValue;
};
DECLARE_VECTOR(mCoreMemorySearchResults, struct mCoreMemorySearchResult);
View
@@ -60,16 +60,17 @@ struct mDebuggerEntryInfo {
uint32_t newValue;
enum mWatchpointType watchType;
enum mWatchpointType accessType;
- };
+ } wp;
struct {
uint32_t opcode;
enum mBreakpointType breakType;
- };
- };
+ } bp;
+ } type;
};
struct mDebugger;
+struct ParseTree;
struct mDebuggerPlatform {
struct mDebugger* p;
@@ -79,14 +80,19 @@ struct mDebuggerPlatform {
bool (*hasBreakpoints)(struct mDebuggerPlatform*);
void (*setBreakpoint)(struct mDebuggerPlatform*, uint32_t address, int segment);
+ void (*setConditionalBreakpoint)(struct mDebuggerPlatform*, uint32_t address, int segment, struct ParseTree* condition);
void (*clearBreakpoint)(struct mDebuggerPlatform*, uint32_t address, int segment);
void (*setWatchpoint)(struct mDebuggerPlatform*, uint32_t address, int segment, enum mWatchpointType type);
+ void (*setConditionalWatchpoint)(struct mDebuggerPlatform*, uint32_t address, int segment, enum mWatchpointType type, struct ParseTree* condition);
void (*clearWatchpoint)(struct mDebuggerPlatform*, uint32_t address, int segment);
void (*checkBreakpoints)(struct mDebuggerPlatform*);
void (*trace)(struct mDebuggerPlatform*, char* out, size_t* length);
+
+ bool (*getRegister)(struct mDebuggerPlatform*, const char* name, int32_t* value);
+ bool (*setRegister)(struct mDebuggerPlatform*, const char* name, int32_t value);
+ bool (*lookupIdentifier)(struct mDebuggerPlatform*, const char* name, int32_t* value, int* segment);
};
-struct mDebuggerSymbols;
struct mDebugger {
struct mCPUComponent d;
struct mDebuggerPlatform* platform;
@@ -109,6 +115,8 @@ void mDebuggerRun(struct mDebugger*);
void mDebuggerRunFrame(struct mDebugger*);
void mDebuggerEnter(struct mDebugger*, enum mDebuggerEntryReason, struct mDebuggerEntryInfo*);
+bool mDebuggerLookupIdentifier(struct mDebugger* debugger, const char* name, int32_t* value, int* segment);
+
CXX_GUARD_END
#endif
View
@@ -21,6 +21,13 @@ enum GBASIOMode {
SIO_JOYBUS = 12
};
+enum GBASIOJOYCommand {
+ JOY_RESET = 0xFF,
+ JOY_POLL = 0x00,
+ JOY_TRANS = 0x14,
+ JOY_RECV = 0x15
+};
+
struct GBA;
struct GBAAudio;
struct GBASIO;
@@ -48,6 +55,10 @@ struct GBASIODriver {
uint16_t (*writeRegister)(struct GBASIODriver* driver, uint32_t address, uint16_t value);
};
+void GBASIOJOYCreate(struct GBASIODriver* sio);
+int GBASIOJOYSendCommand(struct GBASIODriver* sio, enum GBASIOJOYCommand command, uint8_t* data);
+
+
CXX_GUARD_END
#endif
View
@@ -15,8 +15,10 @@ CXX_GUARD_START
#include <mgba/internal/arm/arm.h>
#include <mgba-util/vector.h>
+struct ParseTree;
struct ARMDebugBreakpoint {
uint32_t address;
+ struct ParseTree* condition;
bool isSw;
struct {
uint32_t opcode;
@@ -27,6 +29,7 @@ struct ARMDebugBreakpoint {
struct ARMDebugWatchpoint {
uint32_t address;
enum mWatchpointType type;
+ struct ParseTree* condition;
};
DECLARE_VECTOR(ARMDebugBreakpointList, struct ARMDebugBreakpoint);
View
@@ -14,6 +14,7 @@ CXX_GUARD_START
extern const char* ERROR_MISSING_ARGS;
extern const char* ERROR_OVERFLOW;
+extern const char* ERROR_INVALID_ARGS;
struct CLIDebugger;
@@ -24,22 +25,17 @@ struct CLIDebugVector {
CLIDV_INT_TYPE,
CLIDV_CHAR_TYPE,
} type;
- union {
- char* charValue;
- struct {
- int32_t intValue;
- int segmentValue;
- };
- };
+ char* charValue;
+ int32_t intValue;
+ int segmentValue;
};
typedef void (*CLIDebuggerCommand)(struct CLIDebugger*, struct CLIDebugVector*);
-typedef struct CLIDebugVector* (*CLIDVParser)(struct CLIDebugger* debugger, const char* string, size_t length);
struct CLIDebuggerCommandSummary {
const char* name;
CLIDebuggerCommand command;
- CLIDVParser parser;
+ const char* format;
const char* summary;
};
@@ -51,8 +47,6 @@ struct CLIDebuggerSystem {
bool (*custom)(struct CLIDebuggerSystem*);
void (*disassemble)(struct CLIDebuggerSystem*, struct CLIDebugVector* dv);
- uint32_t (*lookupIdentifier)(struct CLIDebuggerSystem*, const char* name, struct CLIDebugVector* dv);
- uint32_t (*lookupPlatformIdentifier)(struct CLIDebuggerSystem*, const char* name, struct CLIDebugVector* dv);
void (*printStatus)(struct CLIDebuggerSystem*);
struct CLIDebuggerCommandSummary* commands;
@@ -82,9 +76,6 @@ struct CLIDebugger {
struct CLIDebuggerBackend* backend;
};
-struct CLIDebugVector* CLIDVParse(struct CLIDebugger* debugger, const char* string, size_t length);
-struct CLIDebugVector* CLIDVStringParse(struct CLIDebugger* debugger, const char* string, size_t length);
-
void CLIDebuggerCreate(struct CLIDebugger*);
void CLIDebuggerAttachSystem(struct CLIDebugger*, struct CLIDebuggerSystem*);
void CLIDebuggerAttachBackend(struct CLIDebugger*, struct CLIDebuggerBackend*);
View
@@ -8,27 +8,36 @@
#include <mgba-util/common.h>
-CXX_GUARD_START
+#include <mgba-util/vector.h>
-#include <mgba/debugger/debugger.h>
+CXX_GUARD_START
-enum LexState {
- LEX_ERROR = -1,
- LEX_ROOT = 0,
- LEX_EXPECT_IDENTIFIER,
- LEX_EXPECT_BINARY,
- LEX_EXPECT_DECIMAL,
- LEX_EXPECT_HEX,
- LEX_EXPECT_PREFIX,
- LEX_EXPECT_OPERATOR
-};
+struct Token;
+DECLARE_VECTOR(LexVector, struct Token);
enum Operation {
OP_ASSIGN,
OP_ADD,
OP_SUBTRACT,
OP_MULTIPLY,
- OP_DIVIDE
+ OP_DIVIDE,
+ OP_MODULO,
+ OP_AND,
+ OP_OR,
+ OP_XOR,
+ OP_LESS,
+ OP_GREATER,
+ OP_EQUAL,
+ OP_NOT_EQUAL,
+ OP_LOGICAL_AND,
+ OP_LOGICAL_OR,
+ OP_LE,
+ OP_GE,
+ OP_NEGATE,
+ OP_FLIP,
+ OP_NOT,
+ OP_SHIFT_L,
+ OP_SHIFT_R,
};
struct Token {
@@ -48,23 +57,21 @@ struct Token {
};
};
-struct LexVector {
- struct LexVector* next;
- struct Token token;
-};
-
struct ParseTree {
struct Token token;
struct ParseTree* lhs;
struct ParseTree* rhs;
};
-size_t lexExpression(struct LexVector* lv, const char* string, size_t length);
+size_t lexExpression(struct LexVector* lv, const char* string, size_t length, const char* eol);
void parseLexedExpression(struct ParseTree* tree, struct LexVector* lv);
void lexFree(struct LexVector* lv);
void parseFree(struct ParseTree* tree);
+struct mDebugger;
+bool mDebuggerEvaluateParseTree(struct mDebugger* debugger, struct ParseTree* tree, int32_t* value, int* segment);
+
CXX_GUARD_END
#endif
View
@@ -145,6 +145,8 @@ void GBCreate(struct GB* gb);
void GBDestroy(struct GB* gb);
void GBReset(struct LR35902Core* cpu);
+void GBSkipBIOS(struct GB* gb);
+void GBUnmapBIOS(struct GB* gb);
void GBDetectModel(struct GB* gb);
void GBUpdateIRQs(struct GB* gb);
View
@@ -84,6 +84,7 @@ enum GBIORegisters {
REG_WX = 0x4B,
// CGB
+ REG_UNK4C = 0x4C,
REG_KEY1 = 0x4D,
REG_VBK = 0x4F,
REG_HDMA1 = 0x51,
@@ -101,8 +102,8 @@ enum GBIORegisters {
REG_UNK72 = 0x72,
REG_UNK73 = 0x73,
REG_UNK74 = 0x74,
- REG_UNK75 = 0x75,
- REG_UNK76 = 0x76,
+ REG_PCM12 = 0x75,
+ REG_PCM34 = 0x76,
REG_UNK77 = 0x77,
REG_MAX = 0x100
};
View
@@ -207,7 +207,7 @@ int GBCurrentSegment(struct LR35902Core* cpu, uint16_t address);
uint8_t GBView8(struct LR35902Core* cpu, uint16_t address, int segment);
void GBMemoryDMA(struct GB* gb, uint16_t base);
-void GBMemoryWriteHDMA5(struct GB* gb, uint8_t value);
+uint8_t GBMemoryWriteHDMA5(struct GB* gb, uint8_t value);
void GBPatch8(struct LR35902Core* cpu, uint16_t address, int8_t value, int8_t* old, int segment);
View
@@ -32,6 +32,8 @@ struct GBVideoSoftwareRenderer {
uint8_t wy;
uint8_t wx;
uint8_t currentWy;
+ int lastY;
+ bool hasWindow;
GBRegisterLCDC lcdc;
enum GBModel model;
@@ -43,6 +45,9 @@ struct GBVideoSoftwareRenderer {
int sgbDataSets;
uint8_t sgbPartialDataSet[15];
bool sgbBorders;
+ int sgbAttrX;
+ int sgbAttrY;
+ int sgbAttrDirection;
};
void GBVideoSoftwareRendererCreate(struct GBVideoSoftwareRenderer*);
View
@@ -169,7 +169,9 @@ mLOG_DECLARE_CATEGORY(GB_STATE);
* | 0x0C7DC - 0x0C7DF: Flags
* | bits 0 - 1: Current P1 bits
* | bits 2 - 3: Current render mode
- * | bits 4 - 31: Reserved (leave 0)
+ * | bit 4: Is a mode event not scheduled?
+ * | bit 5: Is a frame event not scheduled?
+ * | bits 6 - 31: Reserved (leave 0)
* | 0x0C7E0 - 0x0C7EF: Current packet
* | 0x0C7F0 - 0x0C7FF: Reserved
* | 0x0C800 - 0x0E7FF: Character VRAM
View
@@ -159,7 +159,7 @@ void GBVideoInit(struct GBVideo* video);
void GBVideoReset(struct GBVideo* video);
void GBVideoDeinit(struct GBVideo* video);
void GBVideoAssociateRenderer(struct GBVideo* video, struct GBVideoRenderer* renderer);
-void GBVideoProcessDots(struct GBVideo* video);
+void GBVideoProcessDots(struct GBVideo* video, uint32_t cyclesLate);
void GBVideoWriteLCDC(struct GBVideo* video, GBRegisterLCDC value);
void GBVideoWriteSTAT(struct GBVideo* video, GBRegisterSTAT value);
View
@@ -13,7 +13,7 @@ CXX_GUARD_START
#include <mgba/internal/arm/arm.h>
#include <mgba/core/cheats.h>
-#define MAX_ROM_PATCHES 4
+#define MAX_ROM_PATCHES 10
#define COMPLETE ((size_t) -1)
enum GBACheatType {
@@ -63,7 +63,7 @@ enum GBAActionReplay3Condition {
PAR3_COND_GT = 0x20000000,
PAR3_COND_ULT = 0x28000000,
PAR3_COND_UGT = 0x30000000,
- PAR3_COND_LAND = 0x38000000,
+ PAR3_COND_AND = 0x38000000,
};
enum GBAActionReplay3Width {
View
@@ -10,18 +10,18 @@
CXX_GUARD_START
-enum DMAControl {
- DMA_INCREMENT = 0,
- DMA_DECREMENT = 1,
- DMA_FIXED = 2,
- DMA_INCREMENT_RELOAD = 3
+enum GBADMAControl {
+ GBA_DMA_INCREMENT = 0,
+ GBA_DMA_DECREMENT = 1,
+ GBA_DMA_FIXED = 2,
+ GBA_DMA_INCREMENT_RELOAD = 3
};
-enum DMATiming {
- DMA_TIMING_NOW = 0,
- DMA_TIMING_VBLANK = 1,
- DMA_TIMING_HBLANK = 2,
- DMA_TIMING_CUSTOM = 3
+enum GBADMATiming {
+ GBA_DMA_TIMING_NOW = 0,
+ GBA_DMA_TIMING_VBLANK = 1,
+ GBA_DMA_TIMING_HBLANK = 2,
+ GBA_DMA_TIMING_CUSTOM = 3
};
DECL_BITFIELD(GBADMARegister, uint16_t);
@@ -59,6 +59,7 @@ struct GBADMA;
void GBADMASchedule(struct GBA* gba, int number, struct GBADMA* info);
void GBADMARunHblank(struct GBA* gba, int32_t cycles);
void GBADMARunVblank(struct GBA* gba, int32_t cycles);
+void GBADMARunDisplayStart(struct GBA* gba, int32_t cycles);
void GBADMAUpdate(struct GBA* gba);
CXX_GUARD_END
View
@@ -0,0 +1,28 @@
+/* Copyright (c) 2013-2018 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 GBA_MATRIX_H
+#define GBA_MATRIX_H
+
+#include <mgba-util/common.h>
+
+CXX_GUARD_START
+
+struct GBAMatrix {
+ uint32_t cmd;
+ uint32_t paddr;
+ uint32_t vaddr;
+ uint32_t size;
+};
+
+struct GBA;
+struct GBAMemory;
+void GBAMatrixReset(struct GBA*);
+void GBAMatrixWrite(struct GBA*, uint32_t address, uint32_t value);
+void GBAMatrixWrite16(struct GBA*, uint32_t address, uint16_t value);
+
+CXX_GUARD_END
+
+#endif
View
@@ -17,6 +17,7 @@ CXX_GUARD_START
#include <mgba/internal/gba/hardware.h>
#include <mgba/internal/gba/savedata.h>
#include <mgba/internal/gba/vfame.h>
+#include <mgba/internal/gba/matrix.h>
mLOG_DECLARE_CATEGORY(GBA_MEM);
@@ -71,14 +72,31 @@ enum {
SIZE_CART_FLASH512 = 0x00010000,
SIZE_CART_FLASH1M = 0x00020000,
SIZE_CART_EEPROM = 0x00002000,
- SIZE_CART_EEPROM512 = 0x00000200
+ SIZE_CART_EEPROM512 = 0x00000200,
+
+ SIZE_AGB_PRINT = 0x10000
};
enum {
OFFSET_MASK = 0x00FFFFFF,
BASE_OFFSET = 24
};
+enum {
+ AGB_PRINT_BASE = 0x00FD0000,
+ AGB_PRINT_TOP = 0x00FE0000,
+ AGB_PRINT_PROTECT = 0x00FE2FFE,
+ AGB_PRINT_STRUCT = 0x01FE20F8,
+ AGB_PRINT_FLUSH_ADDR = 0x01FE209C,
+};
+
+struct GBAPrintContext {
+ uint16_t request;
+ uint16_t bank;
+ uint16_t get;
+ uint16_t put;
+};
+
struct GBAMemory {
uint32_t* bios;
uint32_t* wram;
@@ -89,6 +107,7 @@ struct GBAMemory {
struct GBACartridgeHardware hw;
struct GBASavedata savedata;
struct GBAVFameCart vfame;
+ struct GBAMatrix matrix;
size_t romSize;
uint32_t romMask;
uint16_t romID;
@@ -106,6 +125,11 @@ struct GBAMemory {
struct GBADMA dma[4];
struct mTimingEvent dmaEvent;
int activeDMA;
+ uint32_t dmaTransferRegister;
+
+ uint16_t agbPrint;
+ struct GBAPrintContext agbPrintCtx;
+ uint16_t* agbPrintBuffer;
bool mirroring;
};
@@ -145,6 +169,8 @@ struct GBASerializedState;
void GBAMemorySerialize(const struct GBAMemory* memory, struct GBASerializedState* state);
void GBAMemoryDeserialize(struct GBAMemory* memory, const struct GBASerializedState* state);
+void GBAPrintFlush(struct GBA* gba);
+
CXX_GUARD_END
#endif
View
@@ -43,6 +43,8 @@ struct GBAVideoSoftwareBackground {
int16_t dmy;
int32_t sx;
int32_t sy;
+ int yCache;
+ uint16_t mapCache[64];
color_t* extPalette;
color_t* variantPalette;
};
View
@@ -169,7 +169,8 @@ mLOG_DECLARE_CATEGORY(GBA_STATE);
* | bits 4 - 8: GB Player transmit position
* | bits 9 - 23: Reserved
* 0x002C4 - 0x002C7: Game Boy Player next event
- * 0x002C8 - 0x002DF: Reserved (leave zero)
+ * 0x002C8 - 0x002CB: Current DMA transfer word
+ * 0x002CC - 0x002DF: Reserved (leave zero)
* 0x002E0 - 0x002EF: Savedata state
* | 0x002E0 - 0x002E0: Savedata type
* | 0x002E1 - 0x002E1: Savedata command (see savedata.h)
@@ -293,7 +294,9 @@ struct GBASerializedState {
uint32_t gbpNextEvent;
} hw;
- uint32_t reservedHardware[6];
+ uint32_t dmaTransferRegister;
+
+ uint32_t reservedHardware[5];
struct {
uint8_t type;
View
@@ -15,16 +15,18 @@ CXX_GUARD_START
#include <mgba/internal/lr35902/lr35902.h>
#include <mgba-util/vector.h>
-
+struct ParseTree;
struct LR35902DebugBreakpoint {
uint16_t address;
int segment;
+ struct ParseTree* condition;
};
struct LR35902DebugWatchpoint {
uint16_t address;
int segment;
enum mWatchpointType type;
+ struct ParseTree* condition;
};
struct LR35902Segment {
View
@@ -17,23 +17,21 @@ static void _disassembleArm(struct CLIDebugger*, struct CLIDebugVector*);
static void _disassembleThumb(struct CLIDebugger*, struct CLIDebugVector*);
static void _setBreakpointARM(struct CLIDebugger*, struct CLIDebugVector*);
static void _setBreakpointThumb(struct CLIDebugger*, struct CLIDebugVector*);
-static void _writeRegister(struct CLIDebugger*, struct CLIDebugVector*);
static void _disassembleMode(struct CLIDebugger*, struct CLIDebugVector*, enum ExecutionMode mode);
static uint32_t _printLine(struct CLIDebugger* debugger, uint32_t address, enum ExecutionMode mode);
static struct CLIDebuggerCommandSummary _armCommands[] = {
- { "b/a", _setBreakpointARM, CLIDVParse, "Set a software breakpoint as ARM" },
- { "b/t", _setBreakpointThumb, CLIDVParse, "Set a software breakpoint as Thumb" },
- { "break/a", _setBreakpointARM, CLIDVParse, "Set a software breakpoint as ARM" },
- { "break/t", _setBreakpointThumb, CLIDVParse, "Set a software breakpoint as Thumb" },
- { "dis/a", _disassembleArm, CLIDVParse, "Disassemble instructions as ARM" },
- { "dis/t", _disassembleThumb, CLIDVParse, "Disassemble instructions as Thumb" },
- { "disasm/a", _disassembleArm, CLIDVParse, "Disassemble instructions as ARM" },
- { "disasm/t", _disassembleThumb, CLIDVParse, "Disassemble instructions as Thumb" },
- { "disassemble/a", _disassembleArm, CLIDVParse, "Disassemble instructions as ARM" },
- { "disassemble/t", _disassembleThumb, CLIDVParse, "Disassemble instructions as Thumb" },
- { "w/r", _writeRegister, CLIDVParse, "Write a register" },
+ { "b/a", _setBreakpointARM, "I", "Set a software breakpoint as ARM" },
+ { "b/t", _setBreakpointThumb, "I", "Set a software breakpoint as Thumb" },
+ { "break/a", _setBreakpointARM, "I", "Set a software breakpoint as ARM" },
+ { "break/t", _setBreakpointThumb, "I", "Set a software breakpoint as Thumb" },
+ { "dis/a", _disassembleArm, "Ii", "Disassemble instructions as ARM" },
+ { "dis/t", _disassembleThumb, "Ii", "Disassemble instructions as Thumb" },
+ { "disasm/a", _disassembleArm, "Ii", "Disassemble instructions as ARM" },
+ { "disasm/t", _disassembleThumb, "Ii", "Disassemble instructions as Thumb" },
+ { "disassemble/a", _disassembleArm, "Ii", "Disassemble instructions as ARM" },
+ { "disassemble/t", _disassembleThumb, "Ii", "Disassemble instructions as Thumb" },
{ 0, 0, 0, 0 }
};
@@ -145,25 +143,6 @@ static void _printStatus(struct CLIDebuggerSystem* debugger) {
_printLine(debugger->p, cpu->gprs[ARM_PC] - instructionLength, mode);
}
-static void _writeRegister(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
- struct CLIDebuggerBackend* be = debugger->backend;
- struct ARMCore* cpu = debugger->d.core->cpu;
- if (!dv || dv->type != CLIDV_INT_TYPE) {
- be->printf(be, "%s\n", ERROR_MISSING_ARGS);
- return;
- }
- if (!dv->next || dv->next->type != CLIDV_INT_TYPE) {
- be->printf(be, "%s\n", ERROR_MISSING_ARGS);
- return;
- }
- uint32_t regid = dv->intValue;
- uint32_t value = dv->next->intValue;
- if (regid >= ARM_PC) {
- return;
- }
- cpu->gprs[regid] = value;
-}
-
static void _setBreakpointARM(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
struct CLIDebuggerBackend* be = debugger->backend;
if (!dv || dv->type != CLIDV_INT_TYPE) {
@@ -184,38 +163,9 @@ static void _setBreakpointThumb(struct CLIDebugger* debugger, struct CLIDebugVec
ARMDebuggerSetSoftwareBreakpoint(debugger->d.platform, address, MODE_THUMB);
}
-static uint32_t _lookupPlatformIdentifier(struct CLIDebuggerSystem* debugger, const char* name, struct CLIDebugVector* dv) {
- struct ARMCore* cpu = debugger->p->d.core->cpu;
- if (strcmp(name, "sp") == 0) {
- return cpu->gprs[ARM_SP];
- }
- if (strcmp(name, "lr") == 0) {
- return cpu->gprs[ARM_LR];
- }
- if (strcmp(name, "pc") == 0) {
- return cpu->gprs[ARM_PC];
- }
- if (strcmp(name, "cpsr") == 0) {
- return cpu->cpsr.packed;
- }
- // TODO: test if mode has SPSR
- if (strcmp(name, "spsr") == 0) {
- return cpu->spsr.packed;
- }
- if (name[0] == 'r' && name[1] >= '0' && name[1] <= '9') {
- int reg = atoi(&name[1]);
- if (reg < 16) {
- return cpu->gprs[reg];
- }
- }
- dv->type = CLIDV_ERROR_TYPE;
- return 0;
-}
-
void ARMCLIDebuggerCreate(struct CLIDebuggerSystem* debugger) {
debugger->printStatus = _printStatus;
debugger->disassemble = _disassemble;
- debugger->lookupPlatformIdentifier = _lookupPlatformIdentifier;
debugger->platformName = "ARM";
debugger->platformCommands = _armCommands;
}
View
@@ -10,6 +10,7 @@
#include <mgba/internal/arm/decoder.h>
#include <mgba/internal/arm/isa-inlines.h>
#include <mgba/internal/arm/debugger/memory-debugger.h>
+#include <mgba/internal/debugger/parser.h>
DEFINE_VECTOR(ARMDebugBreakpointList, struct ARMDebugBreakpoint);
DEFINE_VECTOR(ARMDebugWatchpointList, struct ARMDebugWatchpoint);
@@ -24,6 +25,20 @@ static struct ARMDebugBreakpoint* _lookupBreakpoint(struct ARMDebugBreakpointLis
return 0;
}
+static void _destroyBreakpoint(struct ARMDebugBreakpoint* breakpoint) {
+ if (breakpoint->condition) {
+ parseFree(breakpoint->condition);
+ free(breakpoint->condition);
+ }
+}
+
+static void _destroyWatchpoint(struct ARMDebugWatchpoint* watchpoint) {
+ if (watchpoint->condition) {
+ parseFree(watchpoint->condition);
+ free(watchpoint->condition);
+ }
+}
+
static void ARMDebuggerCheckBreakpoints(struct mDebuggerPlatform* d) {
struct ARMDebugger* debugger = (struct ARMDebugger*) d;
int instructionLength;
@@ -37,9 +52,16 @@ static void ARMDebuggerCheckBreakpoints(struct mDebuggerPlatform* d) {
if (!breakpoint) {
return;
}
+ if (breakpoint->condition) {
+ int32_t value;
+ int segment;
+ if (!mDebuggerEvaluateParseTree(d->p, breakpoint->condition, &value, &segment) || !(value || segment >= 0)) {
+ return;
+ }
+ }
struct mDebuggerEntryInfo info = {
.address = breakpoint->address,
- .breakType = BREAKPOINT_HARDWARE
+ .type.bp.breakType = BREAKPOINT_HARDWARE
};
mDebuggerEnter(d->p, DEBUGGER_ENTER_BREAKPOINT, &info);
}
@@ -50,25 +72,33 @@ static void ARMDebuggerDeinit(struct mDebuggerPlatform* platform);
static void ARMDebuggerEnter(struct mDebuggerPlatform* d, enum mDebuggerEntryReason reason, struct mDebuggerEntryInfo* info);
static void ARMDebuggerSetBreakpoint(struct mDebuggerPlatform*, uint32_t address, int segment);
+static void ARMDebuggerSetConditionalBreakpoint(struct mDebuggerPlatform*, uint32_t address, int segment, struct ParseTree* condition);
static void ARMDebuggerClearBreakpoint(struct mDebuggerPlatform*, uint32_t address, int segment);
static void ARMDebuggerSetWatchpoint(struct mDebuggerPlatform*, uint32_t address, int segment, enum mWatchpointType type);
+static void ARMDebuggerSetConditionalWatchpoint(struct mDebuggerPlatform*, uint32_t address, int segment, enum mWatchpointType type, struct ParseTree* condition);
static void ARMDebuggerClearWatchpoint(struct mDebuggerPlatform*, uint32_t address, int segment);
static void ARMDebuggerCheckBreakpoints(struct mDebuggerPlatform*);
static bool ARMDebuggerHasBreakpoints(struct mDebuggerPlatform*);
static void ARMDebuggerTrace(struct mDebuggerPlatform*, char* out, size_t* length);
+static bool ARMDebuggerGetRegister(struct mDebuggerPlatform*, const char* name, int32_t* value);
+static bool ARMDebuggerSetRegister(struct mDebuggerPlatform*, const char* name, int32_t value);
struct mDebuggerPlatform* ARMDebuggerPlatformCreate(void) {
struct mDebuggerPlatform* platform = (struct mDebuggerPlatform*) malloc(sizeof(struct ARMDebugger));
platform->entered = ARMDebuggerEnter;
platform->init = ARMDebuggerInit;
platform->deinit = ARMDebuggerDeinit;
platform->setBreakpoint = ARMDebuggerSetBreakpoint;
+ platform->setConditionalBreakpoint = ARMDebuggerSetConditionalBreakpoint;
platform->clearBreakpoint = ARMDebuggerClearBreakpoint;
platform->setWatchpoint = ARMDebuggerSetWatchpoint;
+ platform->setConditionalWatchpoint = ARMDebuggerSetConditionalWatchpoint;
platform->clearWatchpoint = ARMDebuggerClearWatchpoint;
platform->checkBreakpoints = ARMDebuggerCheckBreakpoints;
platform->hasBreakpoints = ARMDebuggerHasBreakpoints;
platform->trace = ARMDebuggerTrace;
+ platform->getRegister = ARMDebuggerGetRegister;
+ platform->setRegister = ARMDebuggerSetRegister;
return platform;
}
@@ -93,7 +123,15 @@ void ARMDebuggerDeinit(struct mDebuggerPlatform* platform) {
}
ARMDebuggerRemoveMemoryShim(debugger);
+ size_t i;
+ for (i = 0; i < ARMDebugBreakpointListSize(&debugger->breakpoints); ++i) {
+ _destroyBreakpoint(ARMDebugBreakpointListGetPointer(&debugger->breakpoints, i));
+ }
ARMDebugBreakpointListDeinit(&debugger->breakpoints);
+
+ for (i = 0; i < ARMDebugWatchpointListSize(&debugger->watchpoints); ++i) {
+ _destroyWatchpoint(ARMDebugWatchpointListGetPointer(&debugger->watchpoints, i));
+ }
ARMDebugBreakpointListDeinit(&debugger->swBreakpoints);
ARMDebugWatchpointListDeinit(&debugger->watchpoints);
}
@@ -161,9 +199,14 @@ void ARMDebuggerClearSoftwareBreakpoint(struct mDebuggerPlatform* d, uint32_t ad
}
static void ARMDebuggerSetBreakpoint(struct mDebuggerPlatform* d, uint32_t address, int segment) {
+ ARMDebuggerSetConditionalBreakpoint(d, address, segment, NULL);
+}
+
+static void ARMDebuggerSetConditionalBreakpoint(struct mDebuggerPlatform* d, uint32_t address, int segment, struct ParseTree* condition) {
UNUSED(segment);
struct ARMDebugger* debugger = (struct ARMDebugger*) d;
struct ARMDebugBreakpoint* breakpoint = ARMDebugBreakpointListAppend(&debugger->breakpoints);
+ breakpoint->condition = condition;
breakpoint->address = address;
breakpoint->isSw = false;
}
@@ -175,6 +218,7 @@ static void ARMDebuggerClearBreakpoint(struct mDebuggerPlatform* d, uint32_t add
size_t i;
for (i = 0; i < ARMDebugBreakpointListSize(breakpoints); ++i) {
if (ARMDebugBreakpointListGetPointer(breakpoints, i)->address == address) {
+ _destroyBreakpoint(ARMDebugBreakpointListGetPointer(breakpoints, i));
ARMDebugBreakpointListShift(breakpoints, i, 1);
}
}
@@ -186,6 +230,10 @@ static bool ARMDebuggerHasBreakpoints(struct mDebuggerPlatform* d) {
}
static void ARMDebuggerSetWatchpoint(struct mDebuggerPlatform* d, uint32_t address, int segment, enum mWatchpointType type) {
+ ARMDebuggerSetConditionalWatchpoint(d, address, segment, type, NULL);
+}
+
+static void ARMDebuggerSetConditionalWatchpoint(struct mDebuggerPlatform* d, uint32_t address, int segment, enum mWatchpointType type, struct ParseTree* condition) {
UNUSED(segment);
struct ARMDebugger* debugger = (struct ARMDebugger*) d;
if (!ARMDebugWatchpointListSize(&debugger->watchpoints)) {
@@ -194,6 +242,7 @@ static void ARMDebuggerSetWatchpoint(struct mDebuggerPlatform* d, uint32_t addre
struct ARMDebugWatchpoint* watchpoint = ARMDebugWatchpointListAppend(&debugger->watchpoints);
watchpoint->address = address;
watchpoint->type = type;
+ watchpoint->condition = condition;
}
static void ARMDebuggerClearWatchpoint(struct mDebuggerPlatform* d, uint32_t address, int segment) {
@@ -203,6 +252,7 @@ static void ARMDebuggerClearWatchpoint(struct mDebuggerPlatform* d, uint32_t add
size_t i;
for (i = 0; i < ARMDebugWatchpointListSize(watchpoints); ++i) {
if (ARMDebugWatchpointListGetPointer(watchpoints, i)->address == address) {
+ _destroyWatchpoint(ARMDebugWatchpointListGetPointer(watchpoints, i));
ARMDebugWatchpointListShift(watchpoints, i, 1);
}
}
@@ -246,3 +296,81 @@ static void ARMDebuggerTrace(struct mDebuggerPlatform* d, char* out, size_t* len
cpu->gprs[12], cpu->gprs[13], cpu->gprs[14], cpu->gprs[15],
cpu->cpsr.packed, disassembly);
}
+
+bool ARMDebuggerGetRegister(struct mDebuggerPlatform* d, const char* name, int32_t* value) {
+ struct ARMDebugger* debugger = (struct ARMDebugger*) d;
+ struct ARMCore* cpu = debugger->cpu;
+
+ if (strcmp(name, "sp") == 0) {
+ *value = cpu->gprs[ARM_SP];
+ return true;
+ }
+ if (strcmp(name, "lr") == 0) {
+ *value = cpu->gprs[ARM_LR];
+ return true;
+ }
+ if (strcmp(name, "pc") == 0) {
+ *value = cpu->gprs[ARM_PC];
+ return true;
+ }
+ if (strcmp(name, "cpsr") == 0) {
+ *value = cpu->cpsr.packed;
+ return true;
+ }
+ // TODO: test if mode has SPSR
+ if (strcmp(name, "spsr") == 0) {
+ *value = cpu->spsr.packed;
+ return true;
+ }
+ if (name[0] == 'r') {
+ char* end;
+ uint32_t reg = strtoul(&name[1], &end, 10);
+ if (reg <= ARM_PC) {
+ *value = cpu->gprs[reg];
+ return true;
+ }
+ }
+ return false;
+}
+
+bool ARMDebuggerSetRegister(struct mDebuggerPlatform* d, const char* name, int32_t value) {
+ struct ARMDebugger* debugger = (struct ARMDebugger*) d;
+ struct ARMCore* cpu = debugger->cpu;
+
+ if (strcmp(name, "sp") == 0) {
+ cpu->gprs[ARM_SP] = value;
+ return true;
+ }
+ if (strcmp(name, "lr") == 0) {
+ cpu->gprs[ARM_LR] = value;
+ return true;
+ }
+ if (strcmp(name, "pc") == 0) {
+ cpu->gprs[ARM_PC] = value;
+ int32_t currentCycles = 0;
+ if (cpu->executionMode == MODE_ARM) {
+ ARM_WRITE_PC;
+ } else {
+ THUMB_WRITE_PC;
+ }
+ return true;
+ }
+ if (name[0] == 'r') {
+ char* end;
+ uint32_t reg = strtoul(&name[1], &end, 10);
+ if (reg > ARM_PC) {
+ return false;
+ }
+ cpu->gprs[reg] = value;
+ if (reg == ARM_PC) {
+ int32_t currentCycles = 0;
+ if (cpu->executionMode == MODE_ARM) {
+ ARM_WRITE_PC;
+ } else {
+ THUMB_WRITE_PC;
+ }
+ }
+ return true;
+ }
+ return false;
+}
View
@@ -6,6 +6,7 @@
#include <mgba/internal/arm/debugger/memory-debugger.h>
#include <mgba/internal/arm/debugger/debugger.h>
+#include <mgba/internal/debugger/parser.h>
#include <mgba-util/math.h>
@@ -97,21 +98,29 @@ static bool _checkWatchpoints(struct ARMDebugger* debugger, uint32_t address, st
for (i = 0; i < ARMDebugWatchpointListSize(&debugger->watchpoints); ++i) {
watchpoint = ARMDebugWatchpointListGetPointer(&debugger->watchpoints, i);
if (!((watchpoint->address ^ address) & ~width) && watchpoint->type & type) {
+ if (watchpoint->condition) {
+ int32_t value;
+ int segment;
+ if (!mDebuggerEvaluateParseTree(debugger->d.p, watchpoint->condition, &value, &segment) || !(value || segment >= 0)) {
+ return false;
+ }
+ }
+
switch (width + 1) {
case 1:
- info->oldValue = debugger->originalMemory.load8(debugger->cpu, address, 0);
+ info->type.wp.oldValue = debugger->originalMemory.load8(debugger->cpu, address, 0);
break;
case 2:
- info->oldValue = debugger->originalMemory.load16(debugger->cpu, address, 0);
+ info->type.wp.oldValue = debugger->originalMemory.load16(debugger->cpu, address, 0);
break;
case 4:
- info->oldValue = debugger->originalMemory.load32(debugger->cpu, address, 0);
+ info->type.wp.oldValue = debugger->originalMemory.load32(debugger->cpu, address, 0);
break;
}
- info->newValue = newValue;
+ info->type.wp.newValue = newValue;
info->address = address;
- info->watchType = watchpoint->type;
- info->accessType = type;
+ info->type.wp.watchType = watchpoint->type;
+ info->type.wp.accessType = type;
return true;
}
}
View
@@ -51,6 +51,8 @@ void mCheatDeviceCreate(struct mCheatDevice* device) {
device->d.id = M_CHEAT_DEVICE_ID;
device->d.init = mCheatDeviceInit;
device->d.deinit = mCheatDeviceDeinit;
+ device->autosave = false;
+ device->buttonDown = false;
mCheatSetsInit(&device->cheats, 4);
}
@@ -252,11 +254,25 @@ bool mCheatSaveFile(struct mCheatDevice* device, struct VFile* vf) {
return true;
}
+#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2
+void mCheatAutosave(struct mCheatDevice* device) {
+ if (!device->autosave) {
+ return;
+ }
+ struct VFile* vf = mDirectorySetOpenSuffix(&device->p->dirs, device->p->dirs.cheats, ".cheats", O_WRONLY | O_CREAT | O_TRUNC);
+ if (!vf) {
+ return;
+ }
+ mCheatSaveFile(device, vf);
+ vf->close(vf);
+}
+#endif
+
void mCheatRefresh(struct mCheatDevice* device, struct mCheatSet* cheats) {
+ cheats->refresh(cheats, device);
if (!cheats->enabled) {
return;
}
- cheats->refresh(cheats, device);
size_t elseLoc = 0;
size_t endLoc = 0;
@@ -350,6 +366,12 @@ void mCheatRefresh(struct mCheatDevice* device, struct mCheatSet* cheats) {
negativeConditionRemaining = cheat->negativeRepeat;
operationsRemaining = 1;
break;
+ case CHEAT_IF_BUTTON:
+ condition = device->buttonDown;
+ conditionRemaining = cheat->repeat;
+ negativeConditionRemaining = cheat->negativeRepeat;
+ operationsRemaining = 1;
+ break;
}
if (performAssignment) {
@@ -374,6 +396,10 @@ void mCheatRefresh(struct mCheatDevice* device, struct mCheatSet* cheats) {
}
}
+void mCheatPressButton(struct mCheatDevice* device, bool down) {
+ device->buttonDown = down;
+}
+
void mCheatDeviceInit(void* cpu, struct mCPUComponent* component) {
UNUSED(cpu);
struct mCheatDevice* device = (struct mCheatDevice*) component;
View
@@ -379,6 +379,7 @@ void mCoreConfigMap(const struct mCoreConfig* config, struct mCoreOptions* opts)
_lookupCharValue(config, "savestatePath", &opts->savestatePath);
_lookupCharValue(config, "screenshotPath", &opts->screenshotPath);
_lookupCharValue(config, "patchPath", &opts->patchPath);
+ _lookupCharValue(config, "cheatsPath", &opts->cheatsPath);
}
void mCoreConfigLoadDefaults(struct mCoreConfig* config, const struct mCoreOptions* opts) {
@@ -443,10 +444,12 @@ void mCoreConfigFreeOpts(struct mCoreOptions* opts) {
free(opts->savestatePath);
free(opts->screenshotPath);
free(opts->patchPath);
+ free(opts->cheatsPath);
opts->bios = 0;
opts->shader = 0;
opts->savegamePath = 0;
opts->savestatePath = 0;
opts->screenshotPath = 0;
opts->patchPath = 0;
+ opts->cheatsPath = 0;
}
View
@@ -5,6 +5,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include <mgba/core/core.h>
+#include <mgba/core/cheats.h>
#include <mgba/core/log.h>
#include <mgba/core/serialize.h>
#include <mgba-util/vfs.h>
@@ -172,6 +173,30 @@ bool mCoreAutoloadPatch(struct mCore* core) {
core->loadPatch(core, mDirectorySetOpenSuffix(&core->dirs, core->dirs.patch, ".bps", O_RDONLY));
}
+bool mCoreAutoloadCheats(struct mCore* core) {
+ bool success = true;
+ int cheatAuto;
+ if (!mCoreConfigGetIntValue(&core->config, "cheatAutoload", &cheatAuto) || cheatAuto) {
+ struct VFile* vf = mDirectorySetOpenSuffix(&core->dirs, core->dirs.cheats, ".cheats", O_RDONLY);
+ if (vf) {
+ struct mCheatDevice* device = core->cheatDevice(core);
+ if (!device) {
+ success = false;
+ } else {
+ success = mCheatParseFile(device, vf);
+ }
+ vf->close(vf);
+ }
+ }
+ if (!mCoreConfigGetIntValue(&core->config, "cheatAutosave", &cheatAuto) || cheatAuto) {
+ struct mCheatDevice* device = core->cheatDevice(core);
+ if (device) {
+ device->autosave = true;
+ }
+ }
+ return success;
+}
+
bool mCoreSaveState(struct mCore* core, int slot, int flags) {
struct VFile* vf = mCoreGetState(core, slot, true);
if (!vf) {
@@ -264,20 +289,24 @@ void mCoreInitConfig(struct mCore* core, const char* port) {
}
void mCoreLoadConfig(struct mCore* core) {
-#ifndef MINIMAL_CORE
+#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2
mCoreConfigLoad(&core->config);
#endif
mCoreLoadForeignConfig(core, &core->config);
}
void mCoreLoadForeignConfig(struct mCore* core, const struct mCoreConfig* config) {
mCoreConfigMap(config, &core->opts);
-#ifndef MINIMAL_CORE
+#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2
mDirectorySetMapOptions(&core->dirs, &core->opts);
#endif
if (core->opts.audioBuffers) {
core->setAudioBufferSize(core, core->opts.audioBuffers);
}
+
+ mCoreConfigCopyValue(&core->config, config, "cheatAutosave");
+ mCoreConfigCopyValue(&core->config, config, "cheatAutoload");
+
core->loadConfig(core, config);
}
View
@@ -16,6 +16,7 @@ void mDirectorySetInit(struct mDirectorySet* dirs) {
dirs->patch = 0;
dirs->state = 0;
dirs->screenshot = 0;
+ dirs->cheats = 0;
}
void mDirectorySetDeinit(struct mDirectorySet* dirs) {
@@ -34,6 +35,9 @@ void mDirectorySetDeinit(struct mDirectorySet* dirs) {
if (dirs->archive == dirs->screenshot) {
dirs->screenshot = NULL;
}
+ if (dirs->archive == dirs->cheats) {
+ dirs->cheats = NULL;
+ }
dirs->archive->close(dirs->archive);
dirs->archive = NULL;
}
@@ -48,6 +52,9 @@ void mDirectorySetDeinit(struct mDirectorySet* dirs) {
if (dirs->save == dirs->screenshot) {
dirs->screenshot = NULL;
}
+ if (dirs->save == dirs->cheats) {
+ dirs->cheats = NULL;
+ }
dirs->save->close(dirs->save);
dirs->save = NULL;
}
@@ -59,6 +66,9 @@ void mDirectorySetDeinit(struct mDirectorySet* dirs) {
if (dirs->patch == dirs->screenshot) {
dirs->screenshot = NULL;
}
+ if (dirs->patch == dirs->cheats) {
+ dirs->cheats = NULL;
+ }
dirs->patch->close(dirs->patch);
dirs->patch = NULL;
}
@@ -67,14 +77,25 @@ void mDirectorySetDeinit(struct mDirectorySet* dirs) {
if (dirs->state == dirs->screenshot) {
dirs->state = NULL;
}
+ if (dirs->state == dirs->cheats) {
+ dirs->cheats = NULL;
+ }
dirs->state->close(dirs->state);
dirs->state = NULL;
}
if (dirs->screenshot) {
+ if (dirs->screenshot == dirs->cheats) {
+ dirs->cheats = NULL;
+ }
dirs->screenshot->close(dirs->screenshot);
dirs->screenshot = NULL;
}
+
+ if (dirs->cheats) {
+ dirs->cheats->close(dirs->cheats);
+ dirs->cheats = NULL;
+ }
}
void mDirectorySetAttachBase(struct mDirectorySet* dirs, struct VDir* base) {
@@ -91,6 +112,9 @@ void mDirectorySetAttachBase(struct mDirectorySet* dirs, struct VDir* base) {
if (!dirs->screenshot) {
dirs->screenshot = dirs->base;
}
+ if (!dirs->cheats) {
+ dirs->cheats = dirs->base;
+ }
}
void mDirectorySetDetachBase(struct mDirectorySet* dirs) {
@@ -106,6 +130,9 @@ void mDirectorySetDetachBase(struct mDirectorySet* dirs) {
if (dirs->screenshot == dirs->base) {
dirs->screenshot = NULL;
}
+ if (dirs->cheats == dirs->base) {
+ dirs->cheats = NULL;
+ }
if (dirs->base) {
dirs->base->close(dirs->base);
@@ -183,5 +210,15 @@ void mDirectorySetMapOptions(struct mDirectorySet* dirs, const struct mCoreOptio
dirs->patch = dir;
}
}
+
+ if (opts->cheatsPath) {
+ struct VDir* dir = VDirOpen(opts->cheatsPath);
+ if (dir) {
+ if (dirs->cheats && dirs->cheats != dirs->base) {
+ dirs->cheats->close(dirs->cheats);
+ }
+ dirs->cheats = dir;
+ }
+ }
}
#endif
View
@@ -11,7 +11,7 @@
#include <inttypes.h>
-#define SECTION_NAME_MAX 50
+#define SECTION_NAME_MAX 128
#define KEY_NAME_MAX 32
#define KEY_VALUE_MAX 16
#define AXIS_INFO_MAX 12
View

Large diffs are not rendered by default.

Oops, something went wrong.
View
@@ -623,6 +623,12 @@ static void _mCoreLog(struct mLogger* logger, int category, enum mLogLevel level
printf("%s: ", mLogCategoryName(category));
vprintf(format, args);
printf("\n");
+ struct mCoreThread* thread = mCoreThreadGet();
+ if (thread && level == mLOG_FATAL) {
+#ifndef DISABLE_THREADING
+ mCoreThreadMarkCrashed(thread);
+#endif
+ }
}
struct mLogger* mCoreThreadLogger(void) {
View

Large diffs are not rendered by default.

Oops, something went wrong.
View
@@ -8,6 +8,7 @@
#include <mgba/core/core.h>
#include <mgba/internal/debugger/cli-debugger.h>
+#include <mgba/internal/debugger/symbols.h>
#ifdef USE_GDB_STUB
#include <mgba/internal/debugger/gdb-stub.h>
@@ -137,3 +138,22 @@ static void mDebuggerDeinit(struct mCPUComponent* component) {
}
debugger->platform->deinit(debugger->platform);
}
+
+bool mDebuggerLookupIdentifier(struct mDebugger* debugger, const char* name, int32_t* value, int* segment) {
+ *segment = -1;
+#ifdef ENABLE_SCRIPTING
+ if (debugger->bridge && mScriptBridgeLookupSymbol(debugger->bridge, name, value)) {
+ return true;
+ }
+#endif
+ if (debugger->core->symbolTable && mDebuggerSymbolLookup(debugger->core->symbolTable, name, value, segment)) {
+ return true;
+ }
+ if (debugger->core->lookupIdentifier(debugger->core, name, value, segment)) {
+ return true;
+ }
+ if (debugger->platform && debugger->platform->getRegister(debugger->platform, name, value)) {
+ return true;
+ }
+ return false;
+}
View
@@ -46,17 +46,17 @@ static void _gdbStubEntered(struct mDebugger* debugger, enum mDebuggerEntryReaso
break;
case DEBUGGER_ENTER_BREAKPOINT:
if (stub->supportsHwbreak && stub->supportsSwbreak && info) {
- snprintf(stub->outgoing, GDB_STUB_MAX_LINE - 4, "T%02x%cwbreak:;", SIGTRAP, info->breakType == BREAKPOINT_SOFTWARE ? 's' : 'h');
+ snprintf(stub->outgoing, GDB_STUB_MAX_LINE - 4, "T%02x%cwbreak:;", SIGTRAP, info->type.bp.breakType == BREAKPOINT_SOFTWARE ? 's' : 'h');
} else {
snprintf(stub->outgoing, GDB_STUB_MAX_LINE - 4, "S%02xk", SIGTRAP);
}
break;
case DEBUGGER_ENTER_WATCHPOINT:
if (info) {
const char* type = 0;
- switch (info->watchType) {
+ switch (info->type.wp.watchType) {
case WATCHPOINT_WRITE:
- if (info->newValue == info->oldValue) {
+ if (info->type.wp.newValue == info->type.wp.oldValue) {
if (stub->d.state == DEBUGGER_PAUSED) {
stub->d.state = DEBUGGER_RUNNING;
}
@@ -363,7 +363,7 @@ static void _writeRegister(struct GDBStub* stub, const char* message) {
#ifdef _MSC_VER
value = _byteswap_ulong(value);
#else
- value = __builtin_bswap32(value);
+ LOAD_32BE(value, 0, &value);
#endif
if (reg <= ARM_PC) {
View

Large diffs are not rendered by default.

Oops, something went wrong.
View

Large diffs are not rendered by default.

Oops, something went wrong.
View
@@ -0,0 +1,118 @@
+/* Copyright (c) 2013-2017 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/debugger/parser.h>
+
+struct LPTest {
+ struct LexVector lv;
+ struct ParseTree tree;
+};
+
+#define PARSE(STR) \
+ struct LPTest* lp = *state; \
+ lexFree(&lp->lv); \
+ LexVectorClear(&lp->lv); \
+ size_t adjusted = lexExpression(&lp->lv, STR, strlen(STR), ""); \
+ assert_false(adjusted > strlen(STR)); \
+ struct ParseTree* tree = &lp->tree; \
+ parseLexedExpression(tree, &lp->lv)
+
+M_TEST_SUITE_SETUP(Parser) {
+ struct LPTest* lp = malloc(sizeof(struct LPTest));
+ LexVectorInit(&lp->lv, 0);
+ *state = lp;
+ return 0;
+}
+
+M_TEST_SUITE_TEARDOWN(Parser) {
+ struct LPTest* lp = *state;
+ parseFree(&lp->tree); \
+ lexFree(&lp->lv);
+ LexVectorDeinit(&lp->lv);
+ free(lp);
+ return 0;
+}
+
+M_TEST_DEFINE(parseEmpty) {
+ PARSE("");
+
+ assert_int_equal(tree->token.type, TOKEN_ERROR_TYPE);
+}
+
+M_TEST_DEFINE(parseInt) {
+ PARSE("0");
+
+ assert_int_equal(tree->token.type, TOKEN_UINT_TYPE);
+ assert_int_equal(tree->token.uintValue, 0);
+}
+
+M_TEST_DEFINE(parseLexError) {
+ PARSE("@");
+
+ assert_int_equal(tree->token.type, TOKEN_ERROR_TYPE);
+}
+
+M_TEST_DEFINE(parseSimpleExpression) {
+ PARSE("1+2");
+
+ assert_int_equal(tree->token.type, TOKEN_OPERATOR_TYPE);
+ assert_int_equal(tree->token.operatorValue, OP_ADD);
+ assert_int_equal(tree->lhs->token.type, TOKEN_UINT_TYPE);
+ assert_int_equal(tree->lhs->token.uintValue, 1);
+ assert_int_equal(tree->rhs->token.type, TOKEN_UINT_TYPE);
+ assert_int_equal(tree->rhs->token.uintValue, 2);
+}
+
+M_TEST_DEFINE(parseAddMultplyExpression) {
+ PARSE("1+2*3");
+
+ assert_int_equal(tree->token.type, TOKEN_OPERATOR_TYPE);
+ assert_int_equal(tree->token.operatorValue, OP_ADD);
+ assert_int_equal(tree->lhs->token.type, TOKEN_UINT_TYPE);
+ assert_int_equal(tree->lhs->token.uintValue, 1);
+ assert_int_equal(tree->rhs->token.type, TOKEN_OPERATOR_TYPE);
+ assert_int_equal(tree->rhs->token.uintValue, OP_MULTIPLY);
+ assert_int_equal(tree->rhs->lhs->token.type, TOKEN_UINT_TYPE);
+ assert_int_equal(tree->rhs->lhs->token.uintValue, 2);
+ assert_int_equal(tree->rhs->rhs->token.type, TOKEN_UINT_TYPE);
+ assert_int_equal(tree->rhs->rhs->token.uintValue, 3);
+}
+
+M_TEST_DEFINE(parseParentheticalExpression) {
+ PARSE("(1+2)");
+
+ assert_int_equal(tree->token.type, TOKEN_OPERATOR_TYPE);
+ assert_int_equal(tree->token.operatorValue, OP_ADD);
+ assert_int_equal(tree->lhs->token.type, TOKEN_UINT_TYPE);
+ assert_int_equal(tree->lhs->token.uintValue, 1);
+ assert_int_equal(tree->rhs->token.type, TOKEN_UINT_TYPE);
+ assert_int_equal(tree->rhs->token.uintValue, 2);
+}
+
+M_TEST_DEFINE(parseParentheticalAddMultplyExpression) {
+ PARSE("(1+2)*3");
+
+ assert_int_equal(tree->token.type, TOKEN_OPERATOR_TYPE);
+ assert_int_equal(tree->token.operatorValue, OP_MULTIPLY);
+ assert_int_equal(tree->lhs->token.type, TOKEN_OPERATOR_TYPE);
+ assert_int_equal(tree->lhs->token.uintValue, OP_ADD);
+ assert_int_equal(tree->lhs->lhs->token.type, TOKEN_UINT_TYPE);
+ assert_int_equal(tree->lhs->lhs->token.uintValue, 1);
+ assert_int_equal(tree->lhs->lhs->token.type, TOKEN_UINT_TYPE);
+ assert_int_equal(tree->lhs->rhs->token.uintValue, 2);
+ assert_int_equal(tree->rhs->token.type, TOKEN_UINT_TYPE);
+ assert_int_equal(tree->rhs->token.uintValue, 3);
+}
+
+M_TEST_SUITE_DEFINE_SETUP_TEARDOWN(Parser,
+ cmocka_unit_test(parseEmpty),
+ cmocka_unit_test(parseInt),
+ cmocka_unit_test(parseLexError),
+ cmocka_unit_test(parseSimpleExpression),
+ cmocka_unit_test(parseAddMultplyExpression),
+ cmocka_unit_test(parseParentheticalExpression),
+ cmocka_unit_test(parseParentheticalAddMultplyExpression))
View
@@ -133,13 +133,13 @@ void _dmaEvent(struct mTiming* timing, void* context, uint32_t cyclesLate) {
}
} else {
dma->nextCount = 0;
- if (!GBADMARegisterIsRepeat(dma->reg) || GBADMARegisterGetTiming(dma->reg) == DMA_TIMING_NOW) {
+ if (!GBADMARegisterIsRepeat(dma->reg) || GBADMARegisterGetTiming(dma->reg) == GBA_DMA_TIMING_NOW) {
dma->reg = GBADMARegisterClearEnable(dma->reg);
// Clear the enable bit in memory
memory->io[(DS_REG_DMA0CNT_HI + memory->activeDMA * (DS_REG_DMA1CNT_HI - DS_REG_DMA0CNT_HI)) >> 1] &= 0x7FFF;
}
- if (GBADMARegisterGetDestControl(dma->reg) == DMA_INCREMENT_RELOAD) {
+ if (GBADMARegisterGetDestControl(dma->reg) == GBA_DMA_INCREMENT_RELOAD) {
dma->nextDest = dma->dest;
}
if (GBADMARegisterIsDoIRQ(dma->reg)) {
View
@@ -617,7 +617,7 @@ void DSHitStub(struct ARMCore* cpu, uint32_t opcode) {
if (ds->debugger) {
struct mDebuggerEntryInfo info = {
.address = _ARMPCAddress(cpu),
- .opcode = opcode
+ .type.bp.opcode = opcode
};
mDebuggerEnter(ds->debugger->d.p, DEBUGGER_ENTER_ILLEGAL_OP, &info);
}
@@ -641,7 +641,7 @@ void DSIllegal(struct ARMCore* cpu, uint32_t opcode) {
} else if (ds->debugger) {
struct mDebuggerEntryInfo info = {
.address = _ARMPCAddress(cpu),
- .opcode = opcode
+ .type.bp.opcode = opcode
};
mDebuggerEnter(ds->debugger->d.p, DEBUGGER_ENTER_ILLEGAL_OP, &info);
#endif
View
@@ -12,7 +12,6 @@
static void _DSCLIDebuggerInit(struct CLIDebuggerSystem*);
static bool _DSCLIDebuggerCustom(struct CLIDebuggerSystem*);
-static uint32_t _DSCLIDebuggerLookupIdentifier(struct CLIDebuggerSystem*, const char* name, struct CLIDebugVector* dv);
static void _frame(struct CLIDebugger*, struct CLIDebugVector*);
static void _switchCpu(struct CLIDebugger*, struct CLIDebugVector*);
@@ -29,7 +28,6 @@ struct DSCLIDebugger* DSCLIDebuggerCreate(struct mCore* core) {
debugger->d.init = _DSCLIDebuggerInit;
debugger->d.deinit = NULL;
debugger->d.custom = _DSCLIDebuggerCustom;
- debugger->d.lookupIdentifier = _DSCLIDebuggerLookupIdentifier;
debugger->d.name = "DS";
debugger->d.commands = _DSCLIDebuggerCommands;
@@ -49,12 +47,6 @@ static bool _DSCLIDebuggerCustom(struct CLIDebuggerSystem* debugger) {
return false;
}
-static uint32_t _DSCLIDebuggerLookupIdentifier(struct CLIDebuggerSystem* debugger, const char* name, struct CLIDebugVector* dv) {
- UNUSED(debugger);
- dv->type = CLIDV_ERROR_TYPE;
- return 0;
-}
-
static void _frame(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
UNUSED(dv);
debugger->d.state = DEBUGGER_CUSTOM;
View
@@ -235,7 +235,11 @@ bool FFmpegEncoderOpen(struct FFmpegEncoder* encoder, const char* outfile) {
AVDictionary* opts = 0;
av_dict_set(&opts, "strict", "-2", 0);
if (encoder->context->oformat->flags & AVFMT_GLOBALHEADER) {
+#ifdef AV_CODEC_FLAG_GLOBAL_HEADER
+ encoder->audio->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
+#else
encoder->audio->flags |= CODEC_FLAG_GLOBAL_HEADER;
+#endif
}
avcodec_open2(encoder->audio, acodec, &opts);
av_dict_free(&opts);
@@ -298,7 +302,11 @@ bool FFmpegEncoderOpen(struct FFmpegEncoder* encoder, const char* outfile) {
encoder->video->gop_size = 60;
encoder->video->max_b_frames = 3;
if (encoder->context->oformat->flags & AVFMT_GLOBALHEADER) {
+#ifdef AV_CODEC_FLAG_GLOBAL_HEADER
+ encoder->video->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
+#else
encoder->video->flags |= CODEC_FLAG_GLOBAL_HEADER;
+#endif
}
if (strcmp(vcodec->name, "libx264") == 0) {
// Try to adaptively figure out when you can use a slower encoder
View
@@ -10,6 +10,9 @@
#include "feature/gui/gui-runner.h"
#include "feature/gui/remap.h"
#include <mgba/internal/gba/gba.h>
+#ifdef M_CORE_GB
+#include <mgba/internal/gb/gb.h>
+#endif
#include <mgba-util/gui/file-select.h>
#include <mgba-util/gui/menu.h>
@@ -44,6 +47,26 @@ void mGUIShowConfig(struct mGUIRunner* runner, struct GUIMenuItem* extra, size_t
},
.nStates = 2
};
+ *GUIMenuItemListAppend(&menu.items) = (struct GUIMenuItem) {
+ .title = "Autosave state",
+ .data = "autosave",
+ .submenu = 0,
+ .state = true,
+ .validStates = (const char*[]) {
+ "Off", "On"
+ },
+ .nStates = 2
+ };
+ *GUIMenuItemListAppend(&menu.items) = (struct GUIMenuItem) {
+ .title = "Autoload state",
+ .data = "autoload",
+ .submenu = 0,
+ .state = true,
+ .validStates = (const char*[]) {
+ "Off", "On"
+ },
+ .nStates = 2
+ };
*GUIMenuItemListAppend(&menu.items) = (struct GUIMenuItem) {
.title = "Use BIOS if found",
.data = "useBios",
@@ -55,9 +78,23 @@ void mGUIShowConfig(struct mGUIRunner* runner, struct GUIMenuItem* extra, size_t
.nStates = 2
};
*GUIMenuItemListAppend(&menu.items) = (struct GUIMenuItem) {
- .title = "Select BIOS path",
- .data = "bios",
+ .title = "Select GBA BIOS path",
+ .data = "gba.bios",
+ };
+#ifdef M_CORE_GB
+ *GUIMenuItemListAppend(&menu.items) = (struct GUIMenuItem) {
+ .title = "Select GB BIOS path",
+ .data = "gb.bios",
+ };
+ *GUIMenuItemListAppend(&menu.items) = (struct GUIMenuItem) {
+ .title = "Select GBC BIOS path",
+ .data = "gbc.bios",
};
+ *GUIMenuItemListAppend(&menu.items) = (struct GUIMenuItem) {
+ .title = "Select SGB BIOS path",
+ .data = "sgb.bios",
+ };
+#endif
size_t i;
const char* mapNames[GUI_MAX_INPUTS + 1];
if (runner->keySources) {
@@ -88,7 +125,12 @@ void mGUIShowConfig(struct mGUIRunner* runner, struct GUIMenuItem* extra, size_t
.data = 0,
};
enum GUIMenuExitReason reason;
- char biosPath[256] = "";
+ char gbaBiosPath[256] = "";
+#ifdef M_CORE_GB
+ char gbBiosPath[256] = "";
+ char gbcBiosPath[256] = "";
+ char sgbBiosPath[256] = "";
+#endif
struct GUIMenuItem* item;
for (i = 0; i < GUIMenuItemListSize(&menu.items); ++i) {
@@ -105,8 +147,17 @@ void mGUIShowConfig(struct mGUIRunner* runner, struct GUIMenuItem* extra, size_t
break;
}
if (!strcmp(item->data, "*SAVE")) {
- if (biosPath[0]) {
- mCoreConfigSetValue(&runner->config, "bios", biosPath);
+ if (gbaBiosPath[0]) {
+ mCoreConfigSetValue(&runner->config, "gba.bios", gbaBiosPath);
+ }
+ if (gbBiosPath[0]) {
+ mCoreConfigSetValue(&runner->config, "gb.bios", gbBiosPath);
+ }
+ if (gbcBiosPath[0]) {
+ mCoreConfigSetValue(&runner->config, "gbc.bios", gbcBiosPath);
+ }
+ if (sgbBiosPath[0]) {
+ mCoreConfigSetValue(&runner->config, "sgb.bios", sgbBiosPath);
}
for (i = 0; i < GUIMenuItemListSize(&menu.items); ++i) {
item = GUIMenuItemListGetPointer(&menu.items, i);
@@ -130,13 +181,36 @@ void mGUIShowConfig(struct mGUIRunner* runner, struct GUIMenuItem* extra, size_t
mGUIRemapKeys(&runner->params, &runner->core->inputMap, &runner->keySources[item->state]);
continue;
}
- if (!strcmp(item->data, "bios")) {
+ if (!strcmp(item->data, "gba.bios")) {
+ // TODO: show box if failed
+ if (!GUISelectFile(&runner->params, gbaBiosPath, sizeof(gbaBiosPath), GBAIsBIOS)) {
+ gbaBiosPath[0] = '\0';
+ }
+ continue;
+ }
+#ifdef M_CORE_GB
+ if (!strcmp(item->data, "gb.bios")) {
+ // TODO: show box if failed
+ if (!GUISelectFile(&runner->params, gbBiosPath, sizeof(gbBiosPath), GBIsBIOS)) {
+ gbBiosPath[0] = '\0';
+ }
+ continue;
+ }
+ if (!strcmp(item->data, "gbc.bios")) {
// TODO: show box if failed
- if (!GUISelectFile(&runner->params, biosPath, sizeof(biosPath), GBAIsBIOS)) {
- biosPath[0] = '\0';
+ if (!GUISelectFile(&runner->params, gbcBiosPath, sizeof(gbcBiosPath), GBIsBIOS)) {
+ gbcBiosPath[0] = '\0';
}
continue;
}
+ if (!strcmp(item->data, "sgb.bios")) {
+ // TODO: show box if failed
+ if (!GUISelectFile(&runner->params, sgbBiosPath, sizeof(sgbBiosPath), GBIsBIOS)) {
+ sgbBiosPath[0] = '\0';
+ }
+ continue;
+ }
+#endif
if (item->validStates) {
++item->state;
if (item->state >= item->nStates) {
View
@@ -18,15 +18,12 @@
#include <mgba-util/png-io.h>
#include <mgba-util/vfs.h>
-#ifdef _3DS
-#include <3ds.h>
-#endif
-
#include <sys/time.h>
mLOG_DECLARE_CATEGORY(GUI_RUNNER);
mLOG_DEFINE_CATEGORY(GUI_RUNNER, "GUI Runner", "gui.runner");
+#define AUTOSAVE_GRANULARITY 600
#define FPS_GRANULARITY 120
#define FPS_BUFFER_SIZE 3
@@ -38,19 +35,11 @@ enum {
RUNNER_SCREENSHOT,
RUNNER_CONFIG,
RUNNER_RESET,
- RUNNER_COMMAND_MASK = 0xFFFF,
-
- RUNNER_STATE_1 = 0x10000,
- RUNNER_STATE_2 = 0x20000,
- RUNNER_STATE_3 = 0x30000,
- RUNNER_STATE_4 = 0x40000,
- RUNNER_STATE_5 = 0x50000,
- RUNNER_STATE_6 = 0x60000,
- RUNNER_STATE_7 = 0x70000,
- RUNNER_STATE_8 = 0x80000,
- RUNNER_STATE_9 = 0x90000,
+ RUNNER_COMMAND_MASK = 0xFFFF
};
+#define RUNNER_STATE(X) ((X) << 16)
+
static const struct mInputPlatformInfo _mGUIKeyInfo = {
.platformName = "gui",
.keyId = (const char*[GUI_INPUT_MAX]) {
@@ -145,6 +134,27 @@ static uint8_t _readLux(struct GBALuminanceSource* lux) {
return 0xFF - value;
}
+static void _tryAutosave(struct mGUIRunner* runner) {
+ int autosave = false;
+ mCoreConfigGetIntValue(&runner->config, "autosave", &autosave);
+ if (!autosave) {
+ return;
+ }
+
+#ifdef DISABLE_THREADING
+ mCoreSaveState(runner->core, 0, SAVESTATE_SAVEDATA | SAVESTATE_RTC | SAVESTATE_METADATA);
+#else
+ if (!runner->autosave.buffer) {
+ runner->autosave.buffer = VFileMemChunk(NULL, 0);
+ }
+ MutexLock(&runner->autosave.mutex);
+ runner->autosave.core = runner->core;
+ mCoreSaveStateNamed(runner->core, runner->autosave.buffer, SAVESTATE_SAVEDATA | SAVESTATE_RTC | SAVESTATE_METADATA);
+ ConditionWake(&runner->autosave.cond);
+ MutexUnlock(&runner->autosave.mutex);
+#endif
+}
+
void mGUIInit(struct mGUIRunner* runner, const char* port) {
GUIInit(&runner->params);
runner->port = port;
@@ -164,7 +174,14 @@ void mGUIInit(struct mGUIRunner* runner, const char* port) {
// TODO: Do we need to load more defaults?
mCoreConfigSetDefaultIntValue(&runner->config, "volume", 0x100);
mCoreConfigSetDefaultValue(&runner->config, "idleOptimization", "detect");
+ mCoreConfigSetDefaultIntValue(&runner->config, "autoload", true);
+#ifdef DISABLE_THREADING
+ mCoreConfigSetDefaultIntValue(&runner->config, "autosave", false);
+#else
+ mCoreConfigSetDefaultIntValue(&runner->config, "autosave", true);
+#endif
mCoreConfigLoad(&runner->config);
+ mCoreConfigGetIntValue(&runner->config, "logLevel", &logger.logLevel);
char path[PATH_MAX];
mCoreConfigDirectory(path, PATH_MAX);
@@ -177,9 +194,34 @@ void mGUIInit(struct mGUIRunner* runner, const char* port) {
strncpy(runner->params.currentPath, lastPath, PATH_MAX - 1);
runner->params.currentPath[PATH_MAX - 1] = '\0';
}
+
+#ifndef DISABLE_THREADING
+ if (!runner->autosave.running) {
+ runner->autosave.running = true;
+ MutexInit(&runner->autosave.mutex);
+ ConditionInit(&runner->autosave.cond);
+ ThreadCreate(&runner->autosave.thread, mGUIAutosaveThread, &runner->autosave);
+ }
+#endif
}
void mGUIDeinit(struct mGUIRunner* runner) {
+#ifndef DISABLE_THREADING
+ MutexLock(&runner->autosave.mutex);
+ runner->autosave.running = false;
+ ConditionWake(&runner->autosave.cond);
+ MutexUnlock(&runner->autosave.mutex);
+
+ ThreadJoin(runner->autosave.thread);
+
+ ConditionDeinit(&runner->autosave.cond);
+ MutexDeinit(&runner->autosave.mutex);
+
+ if (runner->autosave.buffer) {
+ runner->autosave.buffer->close(runner->autosave.buffer);
+ }
+#endif
+
if (runner->teardown) {
runner->teardown(runner);
}
@@ -242,25 +284,26 @@ void mGUIRun(struct mGUIRunner* runner, const char* path) {
*GUIMenuItemListAppend(&pauseMenu.items) = (struct GUIMenuItem) { .title = "Save state", .submenu = &stateSaveMenu };
*GUIMenuItemListAppend(&pauseMenu.items) = (struct GUIMenuItem) { .title = "Load state", .submenu = &stateLoadMenu };
- *GUIMenuItemListAppend(&stateSaveMenu.items) = (struct GUIMenuItem) { .title = "State 1", .data = (void*) (RUNNER_SAVE_STATE | RUNNER_STATE_1) };
- *GUIMenuItemListAppend(&stateSaveMenu.items) = (struct GUIMenuItem) { .title = "State 2", .data = (void*) (RUNNER_SAVE_STATE | RUNNER_STATE_2) };
- *GUIMenuItemListAppend(&stateSaveMenu.items) = (struct GUIMenuItem) { .title = "State 3", .data = (void*) (RUNNER_SAVE_STATE | RUNNER_STATE_3) };
- *GUIMenuItemListAppend(&stateSaveMenu.items) = (struct GUIMenuItem) { .title = "State 4", .data = (void*) (RUNNER_SAVE_STATE | RUNNER_STATE_4) };
- *GUIMenuItemListAppend(&stateSaveMenu.items) = (struct GUIMenuItem) { .title = "State 5", .data = (void*) (RUNNER_SAVE_STATE | RUNNER_STATE_5) };
- *GUIMenuItemListAppend(&stateSaveMenu.items) = (struct GUIMenuItem) { .title = "State 6", .data = (void*) (RUNNER_SAVE_STATE | RUNNER_STATE_6) };
- *GUIMenuItemListAppend(&stateSaveMenu.items) = (struct GUIMenuItem) { .title = "State 7", .data = (void*) (RUNNER_SAVE_STATE | RUNNER_STATE_7) };
- *GUIMenuItemListAppend(&stateSaveMenu.items) = (struct GUIMenuItem) { .title = "State 8", .data = (void*) (RUNNER_SAVE_STATE | RUNNER_STATE_8) };
- *GUIMenuItemListAppend(&stateSaveMenu.items) = (struct GUIMenuItem) { .title = "State 9", .data = (void*) (RUNNER_SAVE_STATE | RUNNER_STATE_9) };
-
- *GUIMenuItemListAppend(&stateLoadMenu.items) = (struct GUIMenuItem) { .title = "State 1", .data = (void*) (RUNNER_LOAD_STATE | RUNNER_STATE_1) };
- *GUIMenuItemListAppend(&stateLoadMenu.items) = (struct GUIMenuItem) { .title = "State 2", .data = (void*) (RUNNER_LOAD_STATE | RUNNER_STATE_2) };
- *GUIMenuItemListAppend(&stateLoadMenu.items) = (struct GUIMenuItem) { .title = "State 3", .data = (void*) (RUNNER_LOAD_STATE | RUNNER_STATE_3) };
- *GUIMenuItemListAppend(&stateLoadMenu.items) = (struct GUIMenuItem) { .title = "State 4", .data = (void*) (RUNNER_LOAD_STATE | RUNNER_STATE_4) };
- *GUIMenuItemListAppend(&stateLoadMenu.items) = (struct GUIMenuItem) { .title = "State 5", .data = (void*) (RUNNER_LOAD_STATE | RUNNER_STATE_5) };
- *GUIMenuItemListAppend(&stateLoadMenu.items) = (struct GUIMenuItem) { .title = "State 6", .data = (void*) (RUNNER_LOAD_STATE | RUNNER_STATE_6) };
- *GUIMenuItemListAppend(&stateLoadMenu.items) = (struct GUIMenuItem) { .title = "State 7", .data = (void*) (RUNNER_LOAD_STATE | RUNNER_STATE_7) };
- *GUIMenuItemListAppend(&stateLoadMenu.items) = (struct GUIMenuItem) { .title = "State 8", .data = (void*) (RUNNER_LOAD_STATE | RUNNER_STATE_8) };
- *GUIMenuItemListAppend(&stateLoadMenu.items) = (struct GUIMenuItem) { .title = "State 9", .data = (void*) (RUNNER_LOAD_STATE | RUNNER_STATE_9) };
+ *GUIMenuItemListAppend(&stateSaveMenu.items) = (struct GUIMenuItem) { .title = "State 1", .data = (void*) (RUNNER_SAVE_STATE | RUNNER_STATE(1)) };
+ *GUIMenuItemListAppend(&stateSaveMenu.items) = (struct GUIMenuItem) { .title = "State 2", .data = (void*) (RUNNER_SAVE_STATE | RUNNER_STATE(2)) };
+ *GUIMenuItemListAppend(&stateSaveMenu.items) = (struct GUIMenuItem) { .title = "State 3", .data = (void*) (RUNNER_SAVE_STATE | RUNNER_STATE(3)) };
+ *GUIMenuItemListAppend(&stateSaveMenu.items) = (struct GUIMenuItem) { .title = "State 4", .data = (void*) (RUNNER_SAVE_STATE | RUNNER_STATE(4)) };
+ *GUIMenuItemListAppend(&stateSaveMenu.items) = (struct GUIMenuItem) { .title = "State 5", .data = (void*) (RUNNER_SAVE_STATE | RUNNER_STATE(5)) };
+ *GUIMenuItemListAppend(&stateSaveMenu.items) = (struct GUIMenuItem) { .title = "State 6", .data = (void*) (RUNNER_SAVE_STATE | RUNNER_STATE(6)) };
+ *GUIMenuItemListAppend(&stateSaveMenu.items) = (struct GUIMenuItem) { .title = "State 7", .data = (void*) (RUNNER_SAVE_STATE | RUNNER_STATE(7)) };
+ *GUIMenuItemListAppend(&stateSaveMenu.items) = (struct GUIMenuItem) { .title = "State 8", .data = (void*) (RUNNER_SAVE_STATE | RUNNER_STATE(8)) };
+ *GUIMenuItemListAppend(&stateSaveMenu.items) = (struct GUIMenuItem) { .title = "State 9", .data = (void*) (RUNNER_SAVE_STATE | RUNNER_STATE(9)) };
+
+ *GUIMenuItemListAppend(&stateLoadMenu.items) = (struct GUIMenuItem) { .title = "Autosave", .data = (void*) (RUNNER_LOAD_STATE | RUNNER_STATE(0)) };
+ *GUIMenuItemListAppend(&stateLoadMenu.items) = (struct GUIMenuItem) { .title = "State 1", .data = (void*) (RUNNER_LOAD_STATE | RUNNER_STATE(1)) };
+ *GUIMenuItemListAppend(&stateLoadMenu.items) = (struct GUIMenuItem) { .title = "State 2", .data = (void*) (RUNNER_LOAD_STATE | RUNNER_STATE(2)) };
+ *GUIMenuItemListAppend(&stateLoadMenu.items) = (struct GUIMenuItem) { .title = "State 3", .data = (void*) (RUNNER_LOAD_STATE | RUNNER_STATE(3)) };
+ *GUIMenuItemListAppend(&stateLoadMenu.items) = (struct GUIMenuItem) { .title = "State 4", .data = (void*) (RUNNER_LOAD_STATE | RUNNER_STATE(4)) };
+ *GUIMenuItemListAppend(&stateLoadMenu.items) = (struct GUIMenuItem) { .title = "State 5", .data = (void*) (RUNNER_LOAD_STATE | RUNNER_STATE(5)) };
+ *GUIMenuItemListAppend(&stateLoadMenu.items) = (struct GUIMenuItem) { .title = "State 6", .data = (void*) (RUNNER_LOAD_STATE | RUNNER_STATE(6)) };
+ *GUIMenuItemListAppend(&stateLoadMenu.items) = (struct GUIMenuItem) { .title = "State 7", .data = (void*) (RUNNER_LOAD_STATE | RUNNER_STATE(7)) };
+ *GUIMenuItemListAppend(&stateLoadMenu.items) = (struct GUIMenuItem) { .title = "State 8", .data = (void*) (RUNNER_LOAD_STATE | RUNNER_STATE(8)) };
+ *GUIMenuItemListAppend(&stateLoadMenu.items) = (struct GUIMenuItem) { .title = "State 9", .data = (void*) (RUNNER_LOAD_STATE | RUNNER_STATE(9)) };
*GUIMenuItemListAppend(&pauseMenu.items) = (struct GUIMenuItem) { .title = "Take screenshot", .data = (void*) RUNNER_SCREENSHOT };
*GUIMenuItemListAppend(&pauseMenu.items) = (struct GUIMenuItem) { .title = "Configure", .data = (void*) RUNNER_CONFIG };
@@ -283,7 +326,7 @@ void mGUIRun(struct mGUIRunner* runner, const char* path) {
if (runner->core) {
mLOG(GUI_RUNNER, INFO, "Found core");
runner->core->init(runner->core);
- mCoreConfigInit(&runner->core->config, runner->port);
+ mCoreInitConfig(runner->core, runner->port);
mInputMapInit(&runner->core->inputMap, &GBAInputInfo);
found = mCoreLoadFile(runner->core, path);
if (!found) {
@@ -302,10 +345,10 @@ void mGUIRun(struct mGUIRunner* runner, const char* path) {
}
mLOG(GUI_RUNNER, DEBUG, "Loading config...");
mCoreLoadForeignConfig(runner->core, &runner->config);
- logger.logLevel = runner->core->opts.logLevel;
mLOG(GUI_RUNNER, DEBUG, "Loading save...");
mCoreAutoloadSave(runner->core);
+ mCoreAutoloadCheats(runner->core);
if (runner->setup) {
mLOG(GUI_RUNNER, DEBUG, "Setting up runner...");
runner->setup(runner);
@@ -320,7 +363,22 @@ void mGUIRun(struct mGUIRunner* runner, const char* path) {
mLOG(GUI_RUNNER, DEBUG, "Reseting...");
runner->core->reset(runner->core);
mLOG(GUI_RUNNER, DEBUG, "Reset!");
+
+
+ int autoload = false;
+ mCoreConfigGetIntValue(&runner->config, "autoload", &autoload);
+ if (autoload) {
+ mCoreLoadState(runner->core, 0, SAVESTATE_SCREENSHOT | SAVESTATE_RTC);
+ }
+
bool running = true;
+
+#ifndef DISABLE_THREADING
+ MutexLock(&runner->autosave.mutex);
+ runner->autosave.core = runner->core;
+ MutexUnlock(&runner->autosave.mutex);
+#endif
+
if (runner->gameLoaded) {
runner->gameLoaded(runner);
}
@@ -333,13 +391,14 @@ void mGUIRun(struct mGUIRunner* runner, const char* path) {
gettimeofday(&tv, 0);
runner->lastFpsCheck = 1000000LL * tv.tv_sec + tv.tv_usec;
- while (true) {
-#ifdef _3DS
- running = aptMainLoop();
- if (!running) {
- break;
+ int frame = 0;
+ while (running) {
+ if (runner->running) {
+ running = runner->running(runner);
+ if (!running) {
+ break;
+ }
}
-#endif
uint32_t guiKeys;
uint32_t heldKeys;
GUIPollInput(&runner->params, &guiKeys, &heldKeys);
@@ -411,6 +470,11 @@ void mGUIRun(struct mGUIRunner* runner, const char* path) {
runner->fps = (CircleBufferSize(&runner->fpsBuffer) * FPS_GRANULARITY * 1000000.0f) / (runner->totalDelta * sizeof(uint32_t));
}
}
+ if (frame == AUTOSAVE_GRANULARITY) {
+ frame = 0;
+ _tryAutosave(runner);
+ }
+ ++frame;
}
}
@@ -463,6 +527,18 @@ void mGUIRun(struct mGUIRunner* runner, const char* path) {
if (runner->gameUnloaded) {
runner->gameUnloaded(runner);
}
+#ifndef DISABLE_THREADING
+ MutexLock(&runner->autosave.mutex);
+ runner->autosave.core = NULL;
+ MutexUnlock(&runner->autosave.mutex);
+#endif
+
+ int autosave = false;
+ mCoreConfigGetIntValue(&runner->config, "autosave", &autosave);
+ if (autosave) {
+ mCoreSaveState(runner->core, 0, SAVESTATE_SAVEDATA | SAVESTATE_RTC | SAVESTATE_METADATA);
+ }
+
mLOG(GUI_RUNNER, DEBUG, "Unloading game...");
runner->core->unloadROM(runner->core);
drawState.screenshotId = 0;
@@ -486,6 +562,7 @@ void mGUIRun(struct mGUIRunner* runner, const char* path) {
mInputMapDeinit(&runner->core->inputMap);
mLOG(GUI_RUNNER, DEBUG, "Deinitializing core...");
runner->core->deinit(runner->core);
+ runner->core = NULL;
GUIMenuItemListDeinit(&pauseMenu.items);
GUIMenuItemListDeinit(&stateSaveMenu.items);
@@ -511,3 +588,21 @@ void mGUIRunloop(struct mGUIRunner* runner) {
mGUIRun(runner, path);
}
}
+
+#ifndef DISABLE_THREADING
+THREAD_ENTRY mGUIAutosaveThread(void* context) {
+ struct mGUIAutosaveContext* autosave = context;
+ MutexLock(&autosave->mutex);
+ while (autosave->running) {
+ ConditionWait(&autosave->cond, &autosave->mutex);
+ if (autosave->running && autosave->core) {
+ struct VFile* vf = mCoreGetState(autosave->core, 0, true);
+ void* mem = autosave->buffer->map(autosave->buffer, autosave->buffer->size(autosave->buffer), MAP_READ);
+ vf->write(vf, mem, autosave->buffer->size(autosave->buffer));
+ autosave->buffer->unmap(autosave->buffer, mem, autosave->buffer->size(autosave->buffer));
+ vf->close(vf);
+ }
+ }
+ MutexUnlock(&autosave->mutex);
+}
+#endif
View
@@ -15,6 +15,7 @@ CXX_GUARD_START
#include <mgba/internal/gba/hardware.h>
#include <mgba-util/circle-buffer.h>
#include <mgba-util/gui.h>
+#include <mgba-util/threading.h>
enum mGUIInput {
mGUI_INPUT_INCREASE_BRIGHTNESS = GUI_INPUT_USER_START,
@@ -38,12 +39,27 @@ struct mGUIRunnerLux {
int luxLevel;
};
+#ifndef DISABLE_THREADING
+struct VFile;
+struct mGUIAutosaveContext {
+ struct VFile* buffer;
+ struct mCore* core;
+ Thread thread;
+ Mutex mutex;
+ Condition cond;
+ bool running;
+};
+#endif
+
struct mGUIRunner {
struct mCore* core;
struct GUIParams params;
struct mGUIBackground background;
struct mGUIRunnerLux luminanceSource;
+#ifndef DISABLE_THREADING
+ struct mGUIAutosaveContext autosave;
+#endif
struct mInputMap guiKeys;
struct mCoreConfig config;
@@ -70,13 +86,18 @@ struct mGUIRunner {
void (*incrementScreenMode)(struct mGUIRunner*);
void (*setFrameLimiter)(struct mGUIRunner*, bool limit);
uint16_t (*pollGameInput)(struct mGUIRunner*);
+ bool (*running)(struct mGUIRunner*);
};
void mGUIInit(struct mGUIRunner*, const char* port);
void mGUIDeinit(struct mGUIRunner*);
void mGUIRun(struct mGUIRunner*, const char* path);
void mGUIRunloop(struct mGUIRunner*);
+#ifndef DISABLE_THREADING
+THREAD_ENTRY mGUIAutosaveThread(void* context);
+#endif
+
CXX_GUARD_END
#endif
View
@@ -244,7 +244,11 @@ bool GBCheatAddLine(struct mCheatSet* set, const char* line, int type) {
static void GBCheatRefresh(struct mCheatSet* cheats, struct mCheatDevice* device) {
struct GBCheatSet* gbset = (struct GBCheatSet*) cheats;
- _patchROM(device, gbset);
+ if (cheats->enabled) {
+ _patchROM(device, gbset);
+ } else {
+ _unpatchROM(device, gbset);
+ }
}
static void GBCheatSetCopyProperties(struct mCheatSet* set, struct mCheatSet* oldSet) {
View
@@ -463,6 +463,10 @@ static void _GBCoreReset(struct mCore* core) {
#endif
LR35902Reset(core->cpu);
+
+ if (core->opts.skipBios) {
+ GBSkipBIOS(core->board);
+ }
}
static void _GBCoreRunFrame(struct mCore* core) {
@@ -746,6 +750,20 @@ static void _GBCoreLoadSymbols(struct mCore* core, struct VFile* vf) {
}
GBLoadSymbols(core->symbolTable, vf);
}
+
+static bool _GBCoreLookupIdentifier(struct mCore* core, const char* name, int32_t* value, int* segment) {
+ UNUSED(core);
+ *segment = -1;
+ int i;
+ for (i = 0; i < REG_MAX; ++i) {
+ const char* reg = GBIORegisterNames[i];
+ if (reg && strcasecmp(reg, name) == 0) {
+ *value = GB_BASE_IO | i;
+ return true;
+ }
+ }
+ return false;
+}
#endif
static struct mCheatDevice* _GBCoreCheatDevice(struct mCore* core) {
@@ -835,6 +853,7 @@ static void _GBCoreEnableAudioChannel(struct mCore* core, size_t id, bool enable
}
}
+#ifndef MINIMAL_CORE
static void _GBCoreStartVideoLog(struct mCore* core, struct mVideoLogContext* context) {
struct GBCore* gbcore = (struct GBCore*) core;
struct GB* gb = core->board;
@@ -857,6 +876,7 @@ static void _GBCoreEndVideoLog(struct mCore* core) {
free(gbcore->proxyRenderer.logger);
gbcore->proxyRenderer.logger = NULL;
}
+#endif
struct mCore* GBCoreCreate(void) {
struct GBCore* gbcore = malloc(sizeof(*gbcore));
@@ -928,6 +948,7 @@ struct mCore* GBCoreCreate(void) {
core->attachDebugger = _GBCoreAttachDebugger;
core->detachDebugger = _GBCoreDetachDebugger;
core->loadSymbols = _GBCoreLoadSymbols;
+ core->lookupIdentifier = _GBCoreLookupIdentifier;
#endif
core->cheatDevice = _GBCoreCheatDevice;
core->savedataClone = _GBCoreSavedataClone;
View
@@ -14,16 +14,15 @@
static void _GBCLIDebuggerInit(struct CLIDebuggerSystem*);
static bool _GBCLIDebuggerCustom(struct CLIDebuggerSystem*);
-static uint32_t _GBCLIDebuggerLookupIdentifier(struct CLIDebuggerSystem*, const char* name, struct CLIDebugVector* dv);
static void _frame(struct CLIDebugger*, struct CLIDebugVector*);
static void _load(struct CLIDebugger*, struct CLIDebugVector*);
static void _save(struct CLIDebugger*, struct CLIDebugVector*);
struct CLIDebuggerCommandSummary _GBCLIDebuggerCommands[] = {
- { "frame", _frame, 0, "Frame advance" },
- { "load", _load, CLIDVParse, "Load a savestate" },
- { "save", _save, CLIDVParse, "Save a savestate" },
+ { "frame", _frame, "", "Frame advance" },
+ { "load", _load, "*", "Load a savestate" },
+ { "save", _save, "*", "Save a savestate" },
{ 0, 0, 0, 0 }
};
@@ -34,7 +33,6 @@ struct CLIDebuggerSystem* GBCLIDebuggerCreate(struct mCore* core) {
debugger->d.init = _GBCLIDebuggerInit;
debugger->d.deinit = NULL;
debugger->d.custom = _GBCLIDebuggerCustom;
- debugger->d.lookupIdentifier = _GBCLIDebuggerLookupIdentifier;
debugger->d.name = "Game Boy";
debugger->d.commands = _GBCLIDebuggerCommands;
@@ -65,19 +63,6 @@ static bool _GBCLIDebuggerCustom(struct CLIDebuggerSystem* debugger) {
return false;
}
-static uint32_t _GBCLIDebuggerLookupIdentifier(struct CLIDebuggerSystem* debugger, const char* name, struct CLIDebugVector* dv) {
- UNUSED(debugger);
- int i;
- for (i = 0; i < REG_MAX; ++i) {
- const char* reg = GBIORegisterNames[i];
- if (reg && strcasecmp(reg, name) == 0) {
- return GB_BASE_IO | i;
- }
- }
- dv->type = CLIDV_ERROR_TYPE;
- return 0;
-}
-
static void _frame(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
UNUSED(dv);
debugger->d.state = DEBUGGER_CUSTOM;
View
@@ -435,84 +435,11 @@ void GBReset(struct LR35902Core* cpu) {
cpu->d = 0;
gb->timer.internalDiv = 0;
- int nextDiv = 0;
- if (!gb->biosVf) {
- switch (gb->model) {
- case GB_MODEL_AUTODETECT: // Silence warnings
- gb->model = GB_MODEL_DMG;
- case GB_MODEL_DMG:
- cpu->a = 1;
- cpu->f.packed = 0xB0;
- cpu->c = 0x13;
- cpu->e = 0xD8;
- cpu->h = 1;
- cpu->l = 0x4D;
- gb->timer.internalDiv = 0xABC;
- nextDiv = 4;
- break;
- case GB_MODEL_SGB:
- cpu->a = 1;
- cpu->f.packed = 0x00;
- cpu->c = 0x14;
- cpu->e = 0x00;
- cpu->h = 0xC0;
- cpu->l = 0x60;
- gb->timer.internalDiv = 0xABC;
- nextDiv = 4;
- break;
- case GB_MODEL_MGB:
- cpu->a = 0xFF;
- cpu->f.packed = 0xB0;
- cpu->c = 0x13;
- cpu->e = 0xD8;
- cpu->h = 1;
- cpu->l = 0x4D;
- gb->timer.internalDiv = 0xABC;
- nextDiv = 4;
- break;
- case GB_MODEL_SGB2:
- cpu->a = 0xFF;
- cpu->f.packed = 0x00;
- cpu->c = 0x14;
- cpu->e = 0x00;
- cpu->h = 0xC0;
- cpu->l = 0x60;
- gb->timer.internalDiv = 0xABC;
- nextDiv = 4;
- break;
- case GB_MODEL_AGB:
- cpu->a = 0x11;
- cpu->b = 1;
- cpu->f.packed = 0x00;
- cpu->c = 0;
- cpu->e = 0x08;
- cpu->h = 0;
- cpu->l = 0x7C;
- gb->timer.internalDiv = 0x1EA;
- nextDiv = 0xC;
- break;
- case GB_MODEL_CGB:
- cpu->a = 0x11;
- cpu->f.packed = 0x80;
- cpu->c = 0;
- cpu->e = 0x08;
- cpu->h = 0;
- cpu->l = 0x7C;
- gb->timer.internalDiv = 0x1EA;
- nextDiv = 0xC;
- break;
- }
-
- cpu->sp = 0xFFFE;
- cpu->pc = 0x100;
- }
gb->cpuBlocked = false;
gb->earlyExit = false;
gb->doubleSpeed = 0;
- cpu->memory.setActiveRegion(cpu, cpu->pc);
-
if (gb->yankedRomSize) {
gb->memory.romSize = gb->yankedRomSize;
gb->yankedRomSize = 0;
@@ -527,15 +454,109 @@ void GBReset(struct LR35902Core* cpu) {
GBMemoryReset(gb);
GBVideoReset(&gb->video);
GBTimerReset(&gb->timer);
- mTimingSchedule(&gb->timing, &gb->timer.event, nextDiv);
+ if (!gb->biosVf) {
+ GBSkipBIOS(gb);
+ } else {
+ mTimingSchedule(&gb->timing, &gb->timer.event, 0);
+ }
GBIOReset(gb);
GBAudioReset(&gb->audio);
GBSIOReset(&gb->sio);
+ cpu->memory.setActiveRegion(cpu, cpu->pc);
+
GBSavedataUnmask(gb);
}
+void GBSkipBIOS(struct GB* gb) {
+ struct LR35902Core* cpu = gb->cpu;
+ int nextDiv = 0;
+
+ switch (gb->model) {
+ case GB_MODEL_AUTODETECT: // Silence warnings
+ gb->model = GB_MODEL_DMG;
+ case GB_MODEL_DMG:
+ cpu->a = 1;
+ cpu->f.packed = 0xB0;
+ cpu->c = 0x13;
+ cpu->e = 0xD8;
+ cpu->h = 1;
+ cpu->l = 0x4D;
+ gb->timer.internalDiv = 0xABC;
+ nextDiv = 4;
+ break;
+ case GB_MODEL_SGB:
+ cpu->a = 1;
+ cpu->f.packed = 0x00;
+ cpu->c = 0x14;
+ cpu->e = 0x00;
+ cpu->h = 0xC0;
+ cpu->l = 0x60;
+ gb->timer.internalDiv = 0xABC;
+ nextDiv = 4;
+ break;
+ case GB_MODEL_MGB:
+ cpu->a = 0xFF;
+ cpu->f.packed = 0xB0;
+ cpu->c = 0x13;
+ cpu->e = 0xD8;
+ cpu->h = 1;
+ cpu->l = 0x4D;
+ gb->timer.internalDiv = 0xABC;
+ nextDiv = 4;
+ break;
+ case GB_MODEL_SGB2:
+ cpu->a = 0xFF;
+ cpu->f.packed = 0x00;
+ cpu->c = 0x14;
+ cpu->e = 0x00;
+ cpu->h = 0xC0;
+ cpu->l = 0x60;
+ gb->timer.internalDiv = 0xABC;
+ nextDiv = 4;
+ break;
+ case GB_MODEL_AGB:
+ cpu->a = 0x11;
+ cpu->b = 1;
+ cpu->f.packed = 0x00;
+ cpu->c = 0;
+ cpu->e = 0x08;
+ cpu->h = 0;
+ cpu->l = 0x7C;
+ gb->timer.internalDiv = 0x1EA;
+ nextDiv = 0xC;
+ break;
+ case GB_MODEL_CGB:
+ cpu->a = 0x11;
+ cpu->f.packed = 0x80;
+ cpu->c = 0;
+ cpu->e = 0x08;
+ cpu->h = 0;
+ cpu->l = 0x7C;
+ gb->timer.internalDiv = 0x1EA;
+ nextDiv = 0xC;
+ break;
+ }
+
+ cpu->sp = 0xFFFE;
+ cpu->pc = 0x100;
+
+ mTimingDeschedule(&gb->timing, &gb->timer.event);
+ mTimingSchedule(&gb->timing, &gb->timer.event, 0);
+
+ if (gb->biosVf) {
+ GBUnmapBIOS(gb);
+ }
+}
+
+void GBUnmapBIOS(struct GB* gb) {
+ if (gb->memory.romBase < gb->memory.rom || gb->memory.romBase > &gb->memory.rom[gb->memory.romSize - 1]) {
+ free(gb->memory.romBase);
+ gb->memory.romBase = gb->memory.rom;
+ }
+}
+
void GBDetectModel(struct GB* gb) {
if (gb->model != GB_MODEL_AUTODETECT) {
return;
@@ -677,9 +698,12 @@ static void _enableInterrupts(struct mTiming* timing, void* user, uint32_t cycle
}
void GBHalt(struct LR35902Core* cpu) {
- if (!cpu->irqPending) {
+ struct GB* gb = (struct GB*) cpu->master;
+ if (!(gb->memory.ie & gb->memory.io[REG_IF])) {
cpu->cycles = cpu->nextEvent;
cpu->halted = true;
+ } else if (gb->model < GB_MODEL_CGB) {
+ mLOG(GB, STUB, "Unimplemented HALT bug");
}
}
@@ -698,7 +722,7 @@ void GBStop(struct LR35902Core* cpu) {
if (cpu->components && cpu->components[CPU_COMPONENT_DEBUGGER]) {
struct mDebuggerEntryInfo info = {
.address = cpu->pc - 1,
- .opcode = 0x1000 | cpu->bus
+ .type.bp.opcode = 0x1000 | cpu->bus
};
mDebuggerEnter((struct mDebugger*) cpu->components[CPU_COMPONENT_DEBUGGER], DEBUGGER_ENTER_ILLEGAL_OP, &info);
}
@@ -717,7 +741,7 @@ void GBIllegal(struct LR35902Core* cpu) {
if (cpu->components && cpu->components[CPU_COMPONENT_DEBUGGER]) {
struct mDebuggerEntryInfo info = {
.address = cpu->pc,
- .opcode = cpu->bus
+ .type.bp.opcode = cpu->bus
};
mDebuggerEnter((struct mDebugger*) cpu->components[CPU_COMPONENT_DEBUGGER], DEBUGGER_ENTER_ILLEGAL_OP, &info);
}
View
@@ -101,7 +101,6 @@ static const uint8_t _registerMask[] = {
[REG_BCPS] = 0x40,
[REG_UNK6C] = 0xFE,
[REG_SVBK] = 0xF8,
- [REG_UNK75] = 0x8F,
[REG_IE] = 0xE0,
};
@@ -174,6 +173,7 @@ void GBIOReset(struct GB* gb) {
GBIOWrite(gb, REG_WY, 0x00);
GBIOWrite(gb, REG_WX, 0x00);
if (gb->model >= GB_MODEL_CGB) {
+ GBIOWrite(gb, REG_UNK4C, 0);
GBIOWrite(gb, REG_JOYP, 0xFF);
GBIOWrite(gb, REG_VBK, 0);
GBIOWrite(gb, REG_BCPS, 0);
@@ -392,7 +392,7 @@ void GBIOWrite(struct GB* gb, unsigned address, uint8_t value) {
return;
case REG_LCDC:
// TODO: handle GBC differences
- GBVideoProcessDots(&gb->video);
+ GBVideoProcessDots(&gb->video, 0);
value = gb->video.renderer->writeVideoRegister(gb->video.renderer, address, value);
GBVideoWriteLCDC(&gb->video, value);
break;
@@ -406,25 +406,22 @@ void GBIOWrite(struct GB* gb, unsigned address, uint8_t value) {
case REG_SCX:
case REG_WY:
case REG_WX:
- GBVideoProcessDots(&gb->video);
+ GBVideoProcessDots(&gb->video, 0);
value = gb->video.renderer->writeVideoRegister(gb->video.renderer, address, value);
break;
case REG_BGP:
case REG_OBP0:
case REG_OBP1:
- GBVideoProcessDots(&gb->video);
+ GBVideoProcessDots(&gb->video, 0);
GBVideoWritePalette(&gb->video, address, value);
break;
case REG_STAT:
GBVideoWriteSTAT(&gb->video, value);
value = gb->video.stat;
break;
case 0x50:
- if (gb->memory.romBase < gb->memory.rom || gb->memory.romBase > &gb->memory.rom[gb->memory.romSize - 1]) {
- free(gb->memory.romBase);
- gb->memory.romBase = gb->memory.rom;
- }
- if (gb->model >= GB_MODEL_CGB && gb->memory.io[0x6C]) {
+ GBUnmapBIOS(gb);
+ if (gb->model >= GB_MODEL_CGB && gb->memory.io[REG_UNK4C] < 0x80) {
gb->model = GB_MODEL_DMG;
GBVideoDisableCGB(&gb->video);
}
@@ -436,6 +433,8 @@ void GBIOWrite(struct GB* gb, unsigned address, uint8_t value) {
default:
if (gb->model >= GB_MODEL_CGB) {
switch (address) {
+ case REG_UNK4C:
+ break;
case REG_KEY1:
value &= 0x1;
value |= gb->memory.io[address] & 0x80;
@@ -450,16 +449,15 @@ void GBIOWrite(struct GB* gb, unsigned address, uint8_t value) {
// Handled transparently by the registers
break;
case REG_HDMA5:
- GBMemoryWriteHDMA5(gb, value);
- value &= 0x7F;
+ value = GBMemoryWriteHDMA5(gb, value);
break;
case REG_BCPS:
gb->video.bcpIndex = value & 0x3F;
gb->video.bcpIncrement = value & 0x80;
gb->memory.io[REG_BCPD] = gb->video.palette[gb->video.bcpIndex >> 1] >> (8 * (gb->video.bcpIndex & 1));
break;
case REG_BCPD:
- GBVideoProcessDots(&gb->video);
+ GBVideoProcessDots(&gb->video, 0);
GBVideoWritePalette(&gb->video, address, value);
return;
case REG_OCPS:
@@ -468,7 +466,7 @@ void GBIOWrite(struct GB* gb, unsigned address, uint8_t value) {
gb->memory.io[REG_OCPD] = gb->video.palette[8 * 4 + (gb->video.ocpIndex >> 1)] >> (8 * (gb->video.ocpIndex & 1));
break;
case REG_OCPD:
- GBVideoProcessDots(&gb->video);
+ GBVideoProcessDots(&gb->video, 0);
GBVideoWritePalette(&gb->video, address, value);
return;
case REG_SVBK:
View
@@ -31,6 +31,7 @@ static void _GBHuC3(struct GB*, uint16_t address, uint8_t value);
static void _GBPocketCam(struct GB* gb, uint16_t address, uint8_t value);
static void _GBTAMA5(struct GB* gb, uint16_t address, uint8_t value);
+static uint8_t _GBMBC2Read(struct GBMemory*, uint16_t address);
static uint8_t _GBMBC7Read(struct GBMemory*, uint16_t address);
static void _GBMBC7Write(struct GBMemory* memory, uint16_t address, uint8_t value);
@@ -45,9 +46,6 @@ void GBMBCSwitchBank(struct GB* gb, int bank) {
mLOG(GB_MBC, GAME_ERROR, "Attempting to switch to an invalid ROM bank: %0X", bank);
bankStart &= (gb->memory.romSize - 1);
bank = bankStart / GB_SIZE_CART_BANK0;
- if (!bank) {
- ++bank;
- }
}
gb->memory.romBank = &gb->memory.rom[bankStart];
gb->memory.currentBank = bank;
@@ -217,7 +215,8 @@ void GBMBCInit(struct GB* gb) {
break;
case GB_MBC2:
gb->memory.mbcWrite = _GBMBC2;
- gb->sramSize = 0x200;
+ gb->memory.mbcRead = _GBMBC2Read;
+ gb->sramSize = 0x100;
break;
case GB_MBC3:
gb->memory.mbcWrite = _GBMBC3;
@@ -399,6 +398,7 @@ void _GBMBC1(struct GB* gb, uint16_t address, uint8_t value) {
void _GBMBC2(struct GB* gb, uint16_t address, uint8_t value) {
struct GBMemory* memory = &gb->memory;
+ int shift = (address & 1) * 4;
int bank = value & 0xF;
switch (address >> 13) {
case 0x0:
@@ -408,7 +408,6 @@ void _GBMBC2(struct GB* gb, uint16_t address, uint8_t value) {
break;
case 0xA:
memory->sramAccess = true;
- GBMBCSwitchSramBank(gb, memory->sramCurrentBank);
break;
default:
// TODO
@@ -422,13 +421,26 @@ void _GBMBC2(struct GB* gb, uint16_t address, uint8_t value) {
}
GBMBCSwitchBank(gb, bank);
break;
+ case 0x5:
+ if (!memory->sramAccess) {
+ return;
+ }
+ address &= 0x1FF;
+ memory->sramBank[(address >> 1)] &= 0xF0 >> shift;
+ memory->sramBank[(address >> 1)] |= (value & 0xF) << shift;
default:
// TODO
mLOG(GB_MBC, STUB, "MBC2 unknown address: %04X:%02X", address, value);
break;
}
}
+static uint8_t _GBMBC2Read(struct GBMemory* memory, uint16_t address) {
+ address &= 0x1FF;
+ int shift = (address & 1) * 4;
+ return (memory->sramBank[(address >> 1)] >> shift) | 0xF0;
+}
+
void _GBMBC3(struct GB* gb, uint16_t address, uint8_t value) {
struct GBMemory* memory = &gb->memory;
int bank = value & 0x7F;
View
@@ -294,7 +294,7 @@ void GBStore8(struct LR35902Core* cpu, uint16_t address, int8_t value) {
case GB_REGION_EXTERNAL_RAM + 1:
if (memory->rtcAccess) {
memory->rtcRegs[memory->activeRtcReg] = value;
- } else if (memory->sramAccess && memory->sram) {
+ } else if (memory->sramAccess && memory->sram && memory->mbcType != GB_MBC2) {
memory->sramBank[address & (GB_SIZE_EXTERNAL_RAM - 1)] = value;
} else {
memory->mbcWrite(gb, address, value);
@@ -454,15 +454,15 @@ void GBMemoryDMA(struct GB* gb, uint16_t base) {
gb->memory.dmaRemaining = 0xA0;
}
-void GBMemoryWriteHDMA5(struct GB* gb, uint8_t value) {
+uint8_t GBMemoryWriteHDMA5(struct GB* gb, uint8_t value) {
gb->memory.hdmaSource = gb->memory.io[REG_HDMA1] << 8;
gb->memory.hdmaSource |= gb->memory.io[REG_HDMA2];
gb->memory.hdmaDest = gb->memory.io[REG_HDMA3] << 8;
gb->memory.hdmaDest |= gb->memory.io[REG_HDMA4];
gb->memory.hdmaSource &= 0xFFF0;
if (gb->memory.hdmaSource >= 0x8000 && gb->memory.hdmaSource < 0xA000) {
mLOG(GB_MEM, GAME_ERROR, "Invalid HDMA source: %04X", gb->memory.hdmaSource);
- return;
+ return value | 0x80;
}
gb->memory.hdmaDest &= 0x1FF0;
gb->memory.hdmaDest |= 0x8000;
@@ -476,7 +476,10 @@ void GBMemoryWriteHDMA5(struct GB* gb, uint8_t value) {
}
gb->cpuBlocked = true;
mTimingSchedule(&gb->timing, &gb->memory.hdmaEvent, 0);
+ } else if (gb->memory.isHdma && !GBRegisterLCDCIsEnable(gb->memory.io[REG_LCDC])) {
+ return 0x80 | ((value + 1) & 0x7F);
}
+ return value & 0x7F;
}
void _GBMemoryDMAService(struct mTiming* timing, void* context, uint32_t cyclesLate) {
View
@@ -146,6 +146,10 @@ static void _parseAttrBlock(struct GBVideoSoftwareRenderer* renderer, int start)
}
}
+static bool _inWindow(struct GBVideoSoftwareRenderer* renderer) {
+ return GBRegisterLCDCIsWindow(renderer->lcdc) && GB_VIDEO_HORIZONTAL_PIXELS + 7 > renderer->wx;
+}
+
void GBVideoSoftwareRendererCreate(struct GBVideoSoftwareRenderer* renderer) {
renderer->d.init = GBVideoSoftwareRendererInit;
renderer->d.deinit = GBVideoSoftwareRendererDeinit;
@@ -174,6 +178,8 @@ static void GBVideoSoftwareRendererInit(struct GBVideoRenderer* renderer, enum G
softwareRenderer->scx = 0;
softwareRenderer->wy = 0;
softwareRenderer->currentWy = 0;
+ softwareRenderer->lastY = 0;
+ softwareRenderer->hasWindow = false;
softwareRenderer->wx = 0;
softwareRenderer->model = model;
softwareRenderer->sgbTransfer = 0;
@@ -193,14 +199,34 @@ static void GBVideoSoftwareRendererDeinit(struct GBVideoRenderer* renderer) {
UNUSED(softwareRenderer);
}
+static void GBVideoSoftwareRendererUpdateWindow(struct GBVideoSoftwareRenderer* renderer, bool before, bool after) {
+ if (renderer->lastY >= GB_VIDEO_VERTICAL_PIXELS || after == before) {
+ return;
+ }
+ if (renderer->lastY >= renderer->wy) {
+ if (!after) {
+ renderer->currentWy -= renderer->lastY;
+ renderer->hasWindow = true;
+ } else {
+ if (!renderer->hasWindow) {
+ renderer->currentWy = renderer->lastY + 1 - renderer->wy;
+ } else {
+ renderer->currentWy += renderer->lastY;
+ }
+ }
+ }
+}
+
static uint8_t GBVideoSoftwareRendererWriteVideoRegister(struct GBVideoRenderer* renderer, uint16_t address, uint8_t value) {
struct GBVideoSoftwareRenderer* softwareRenderer = (struct GBVideoSoftwareRenderer*) renderer;
if (renderer->cache) {
GBVideoCacheWriteVideoRegister(renderer->cache, address, value);
}
+ bool wasWindow = _inWindow(softwareRenderer);
switch (address) {
case REG_LCDC:
softwareRenderer->lcdc = value;
+ GBVideoSoftwareRendererUpdateWindow(softwareRenderer, wasWindow, _inWindow(softwareRenderer));
break;
case REG_SCY:
softwareRenderer->scy = value;
@@ -210,9 +236,11 @@ static uint8_t GBVideoSoftwareRendererWriteVideoRegister(struct GBVideoRenderer*
break;
case REG_WY:
softwareRenderer->wy = value;
+ GBVideoSoftwareRendererUpdateWindow(softwareRenderer, wasWindow, _inWindow(softwareRenderer));
break;
case REG_WX:
softwareRenderer->wx = value;
+ GBVideoSoftwareRendererUpdateWindow(softwareRenderer, wasWindow, _inWindow(softwareRenderer));
break;
case REG_BGP:
softwareRenderer->lookup[0] = value & 3;
@@ -274,6 +302,51 @@ static void GBVideoSoftwareRendererWriteSGBPacket(struct GBVideoRenderer* render
if (i < 16 && softwareRenderer->sgbDataSets) {
memcpy(softwareRenderer->sgbPartialDataSet, &softwareRenderer->sgbPacket[i], 16 - i);
}
+ break;
+ case SGB_ATTR_CHR:
+ if (softwareRenderer->sgbPacketId == 1) {
+ softwareRenderer->sgbAttrX = softwareRenderer->sgbPacket[1];
+ softwareRenderer->sgbAttrY = softwareRenderer->sgbPacket[2];
+ if (softwareRenderer->sgbAttrX >= GB_VIDEO_HORIZONTAL_PIXELS / 8) {
+ softwareRenderer->sgbAttrX = 0;
+ }
+ if (softwareRenderer->sgbAttrY >= GB_VIDEO_VERTICAL_PIXELS / 8) {
+ softwareRenderer->sgbAttrY = 0;
+ }
+ softwareRenderer->sgbDataSets = softwareRenderer->sgbPacket[3];
+ softwareRenderer->sgbDataSets |= softwareRenderer->sgbPacket[4] << 8;
+ softwareRenderer->sgbAttrDirection = softwareRenderer->sgbPacket[5];
+ i = 6;
+ } else {
+ i = 0;
+ }
+ for (; i < 16 && softwareRenderer->sgbDataSets; ++i) {
+ int j;
+ for (j = 0; j < 4 && softwareRenderer->sgbDataSets; ++j, --softwareRenderer->sgbDataSets) {
+ uint8_t p = softwareRenderer->sgbPacket[i] >> (6 - j * 2);
+ _setAttribute(renderer->sgbAttributes, softwareRenderer->sgbAttrX, softwareRenderer->sgbAttrY, p & 3);
+ if (softwareRenderer->sgbAttrDirection) {
+ ++softwareRenderer->sgbAttrY;
+ if (softwareRenderer->sgbAttrY >= GB_VIDEO_VERTICAL_PIXELS / 8) {
+ softwareRenderer->sgbAttrY = 0;
+ ++softwareRenderer->sgbAttrX;
+ }
+ if (softwareRenderer->sgbAttrX >= GB_VIDEO_HORIZONTAL_PIXELS / 8) {
+ softwareRenderer->sgbAttrX = 0;
+ }
+ } else {
+ ++softwareRenderer->sgbAttrX;
+ if (softwareRenderer->sgbAttrX >= GB_VIDEO_HORIZONTAL_PIXELS / 8) {
+ softwareRenderer->sgbAttrX = 0;
+ ++softwareRenderer->sgbAttrY;
+ }
+ if (softwareRenderer->sgbAttrY >= GB_VIDEO_VERTICAL_PIXELS / 8) {
+ softwareRenderer->sgbAttrY = 0;
+ }
+ }
+ }
+ }
+
break;
case SGB_ATRC_EN:
if (softwareRenderer->sgbBorders) {
@@ -306,6 +379,7 @@ static void GBVideoSoftwareRendererWriteOAM(struct GBVideoRenderer* renderer, ui
static void GBVideoSoftwareRendererDrawRange(struct GBVideoRenderer* renderer, int startX, int endX, int y, struct GBObj* obj, size_t oamMax) {
struct GBVideoSoftwareRenderer* softwareRenderer = (struct GBVideoSoftwareRenderer*) renderer;
+ softwareRenderer->lastY = y;
uint8_t* maps = &softwareRenderer->d.vram[GB_BASE_MAP];
if (GBRegisterLCDCIsTileMap(softwareRenderer->lcdc)) {
maps += GB_SIZE_MAP;
@@ -314,7 +388,8 @@ static void GBVideoSoftwareRendererDrawRange(struct GBVideoRenderer* renderer, i
memset(&softwareRenderer->row[startX], 0, endX - startX);
}
if (GBRegisterLCDCIsBgEnable(softwareRenderer->lcdc) || softwareRenderer->model >= GB_MODEL_CGB) {
- if (GBRegisterLCDCIsWindow(softwareRenderer->lcdc) && softwareRenderer->wy <= y && endX >= softwareRenderer->wx - 7) {
+ int wy = softwareRenderer->wy + softwareRenderer->currentWy;
+ if (GBRegisterLCDCIsWindow(softwareRenderer->lcdc) && wy <= y && endX >= softwareRenderer->wx - 7) {
if (softwareRenderer->wx - 7 > 0 && !softwareRenderer->d.disableBG) {
GBVideoSoftwareRendererDrawBackground(softwareRenderer, maps, startX, softwareRenderer->wx - 7, softwareRenderer->scx, softwareRenderer->scy + y);
}
@@ -324,7 +399,7 @@ static void GBVideoSoftwareRendererDrawRange(struct GBVideoRenderer* renderer, i
maps += GB_SIZE_MAP;
}
if (!softwareRenderer->d.disableWIN) {
- GBVideoSoftwareRendererDrawBackground(softwareRenderer, maps, softwareRenderer->wx - 7, endX, 7 - softwareRenderer->wx, softwareRenderer->currentWy);
+ GBVideoSoftwareRendererDrawBackground(softwareRenderer, maps, softwareRenderer->wx - 7, endX, 7 - softwareRenderer->wx, y - wy);
}
} else if (!softwareRenderer->d.disableBG) {
GBVideoSoftwareRendererDrawBackground(softwareRenderer, maps, startX, endX, softwareRenderer->scx, softwareRenderer->scy + y);
@@ -428,9 +503,6 @@ static void GBVideoSoftwareRendererDrawRange(struct GBVideoRenderer* renderer, i
static void GBVideoSoftwareRendererFinishScanline(struct GBVideoRenderer* renderer, int y) {
struct GBVideoSoftwareRenderer* softwareRenderer = (struct GBVideoSoftwareRenderer*) renderer;
- if (GBRegisterLCDCIsWindow(softwareRenderer->lcdc) && softwareRenderer->wy <= y && softwareRenderer->wx - 7 < GB_VIDEO_HORIZONTAL_PIXELS) {
- ++softwareRenderer->currentWy;
- }
if (softwareRenderer->sgbTransfer == 1) {
size_t offset = 2 * ((y & 7) + (y >> 3) * GB_VIDEO_HORIZONTAL_PIXELS);
if (offset >= 0x1000) {
@@ -520,7 +592,9 @@ static void GBVideoSoftwareRendererFinishFrame(struct GBVideoRenderer* renderer)
break;
}
}
+ softwareRenderer->lastY = GB_VIDEO_VERTICAL_PIXELS;
softwareRenderer->currentWy = 0;
+ softwareRenderer->hasWindow = false;
}
static void GBVideoSoftwareRendererDrawBackground(struct GBVideoSoftwareRenderer* renderer, uint8_t* maps, int startX, int endX, int sx, int sy) {
View
@@ -9,6 +9,8 @@
#include <mgba/internal/gb/timer.h>
#include <mgba/internal/lr35902/lr35902.h>
+#include <mgba-util/memory.h>
+
mLOG_DEFINE_CATEGORY(GB_STATE, "GB Savestate", "gb.serialize");
const uint32_t GB_SAVESTATE_MAGIC = 0x00400000;
@@ -171,6 +173,7 @@ bool GBDeserialize(struct GB* gb, const struct GBSerializedState* state) {
mTimingSchedule(&gb->timing, &gb->eiPending, when);
}
+ enum GBModel oldModel = gb->model;
gb->model = state->model;
if (gb->model < GB_MODEL_CGB) {
@@ -179,6 +182,10 @@ bool GBDeserialize(struct GB* gb, const struct GBSerializedState* state) {
gb->audio.style = GB_AUDIO_CGB;
}
+ if (gb->model != GB_MODEL_SGB || oldModel != GB_MODEL_SGB) {
+ gb->video.sgbBorders = false;
+ }
+
GBMemoryDeserialize(gb, state);
GBVideoDeserialize(&gb->video, state);
GBIODeserialize(gb, state);
@@ -237,22 +244,28 @@ void GBSGBDeserialize(struct GB* gb, const struct GBSerializedState* state) {
memcpy(gb->sgbPacket, state->sgb.packet, sizeof(state->sgb.packet));
- if (gb->video.renderer->sgbCharRam) {
- memcpy(gb->video.renderer->sgbCharRam, state->sgb.charRam, sizeof(state->sgb.charRam));
+ if (!gb->video.renderer->sgbCharRam) {
+ gb->video.renderer->sgbCharRam = anonymousMemoryMap(SGB_SIZE_CHAR_RAM);
}
- if (gb->video.renderer->sgbMapRam) {
- memcpy(gb->video.renderer->sgbMapRam, state->sgb.mapRam, sizeof(state->sgb.mapRam));
+ if (!gb->video.renderer->sgbMapRam) {
+ gb->video.renderer->sgbMapRam = anonymousMemoryMap(SGB_SIZE_MAP_RAM);
}
- if (gb->video.renderer->sgbPalRam) {
- memcpy(gb->video.renderer->sgbPalRam, state->sgb.palRam, sizeof(state->sgb.palRam));
+ if (!gb->video.renderer->sgbPalRam) {
+ gb->video.renderer->sgbPalRam = anonymousMemoryMap(SGB_SIZE_PAL_RAM);
}
- if (gb->video.renderer->sgbAttributeFiles) {
- memcpy(gb->video.renderer->sgbAttributeFiles, state->sgb.atfRam, sizeof(state->sgb.atfRam));
+ if (!gb->video.renderer->sgbAttributeFiles) {
+ gb->video.renderer->sgbAttributeFiles = anonymousMemoryMap(SGB_SIZE_ATF_RAM);
}
- if (gb->video.renderer->sgbAttributes) {
- memcpy(gb->video.renderer->sgbAttributes, state->sgb.attributes, sizeof(state->sgb.attributes));
+ if (!gb->video.renderer->sgbAttributes) {
+ gb->video.renderer->sgbAttributes = malloc(90 * 45);
}
+ memcpy(gb->video.renderer->sgbCharRam, state->sgb.charRam, sizeof(state->sgb.charRam));
+ memcpy(gb->video.renderer->sgbMapRam, state->sgb.mapRam, sizeof(state->sgb.mapRam));
+ memcpy(gb->video.renderer->sgbPalRam, state->sgb.palRam, sizeof(state->sgb.palRam));
+ memcpy(gb->video.renderer->sgbAttributeFiles, state->sgb.atfRam, sizeof(state->sgb.atfRam));
+ memcpy(gb->video.renderer->sgbAttributes, state->sgb.attributes, sizeof(state->sgb.attributes));
+
GBVideoWriteSGBPacket(&gb->video, (uint8_t[16]) { (SGB_ATRC_EN << 3) | 1, 0 });
GBVideoWriteSGBPacket(&gb->video, gb->sgbPacket);
}
Oops, something went wrong.