Merge branch 'master' into optimization/idle-loop-detection

Conflicts:
	CHANGES
	src/gba/gba-overrides.c
	src/gba/gba-thread.h
	src/gba/gba.c
This commit is contained in:
Jeffrey Pfau 2015-01-16 02:55:21 -08:00
commit d49a9a84f7
18 changed files with 292 additions and 156 deletions

16
CHANGES
View File

@ -19,6 +19,7 @@ Features:
- Save directory of last loaded file - Save directory of last loaded file
- Support BPS patches - Support BPS patches
- Automatically detect and optimize out idle loops - Automatically detect and optimize out idle loops
- Configurable game overrides
Bugfixes: Bugfixes:
- Qt: Fix issue with set frame sizes being the wrong height - Qt: Fix issue with set frame sizes being the wrong height
- Qt: Fix emulator crashing when full screen if a game is not running - Qt: Fix emulator crashing when full screen if a game is not running
@ -51,6 +52,17 @@ Bugfixes:
- GBA Memory: Filter out top nybble of DMA addresses - GBA Memory: Filter out top nybble of DMA addresses
- Debugger: Fix binary print putting spaces between digits - Debugger: Fix binary print putting spaces between digits
- GBA BIOS: Fix LZ77UnCompVram to use 16-bit loads from decompressed memory - GBA BIOS: Fix LZ77UnCompVram to use 16-bit loads from decompressed memory
- GBA BIOS: Fix HuffUnComp to work when games pass an invalid bit length
- GBA BIOS: Fix GetBiosChecksum to return the value of a real GBA, regardless of used BIOS
- GBA Memory: Properly bounds-check VRAM accesses
- GBA Memory: Fix initial DMA state
- GBA BIOS: Fix BIOS prefetch after returning from an IRQ
- GBA BIOS: Fix BIOS prefetch after reset
- GBA Memory: Fix alignment of open bus 8- and 16-bit loads
- GBA BIOS: Fix HuffUnComp boundary conditions
- GBA Video: Fix mode 0 being able to read tiles above appropriate tile range
- GBA Audio: Properly initialize audio FIFO channels
- Util: Fix SOCKET_FAILED macro
Misc: Misc:
- Qt: Disable sync to video by default - Qt: Disable sync to video by default
- GBA: Exit cleanly on FATAL if the port supports it - GBA: Exit cleanly on FATAL if the port supports it
@ -61,6 +73,10 @@ Misc:
- GBA Memory: Implement 16- and 32-bit loads from SRAM - GBA Memory: Implement 16- and 32-bit loads from SRAM
- Qt: Clear active buttons when focus is lost - Qt: Clear active buttons when focus is lost
- GBA Memory: Simplify memory API and use fixed bus width - GBA Memory: Simplify memory API and use fixed bus width
- GBA Video: Start video at the last scanline instead of the first
- Debugger: Watchpoints now work on STM/LDM instructions
- GBA: Improve accuracy of event timing
- Debugger: Clean up GDB stub network interfacing
0.1.0: (2014-12-13) 0.1.0: (2014-12-13)
- Initial release - Initial release

View File

@ -53,15 +53,39 @@ static void _gdbStubEntered(struct ARMDebugger* debugger, enum DebuggerEntryReas
static void _gdbStubPoll(struct ARMDebugger* debugger) { static void _gdbStubPoll(struct ARMDebugger* debugger) {
struct GDBStub* stub = (struct GDBStub*) debugger; struct GDBStub* stub = (struct GDBStub*) debugger;
while (stub->d.state == DEBUGGER_PAUSED) { --stub->untilPoll;
if (!SOCKET_FAILED(stub->connection)) { if (stub->untilPoll > 0) {
if (!SocketSetBlocking(stub->connection, 1)) { return;
GDBStubHangup(stub);
return;
}
}
GDBStubUpdate(stub);
} }
stub->untilPoll = GDB_STUB_INTERVAL;
if (stub->shouldBlock) {
stub->shouldBlock = false;
if (!SocketSetBlocking(stub->socket, false)) {
GDBStubHangup(stub);
return;
}
if (!SOCKET_FAILED(stub->connection) && !SocketSetBlocking(stub->connection, false)) {
GDBStubHangup(stub);
return;
}
}
GDBStubUpdate(stub);
}
static void _gdbStubWait(struct ARMDebugger* debugger) {
struct GDBStub* stub = (struct GDBStub*) debugger;
if (!stub->shouldBlock) {
stub->shouldBlock = true;
if (!SocketSetBlocking(stub->socket, true)) {
GDBStubHangup(stub);
return;
}
if (!SOCKET_FAILED(stub->connection) && !SocketSetBlocking(stub->connection, true)) {
GDBStubHangup(stub);
return;
}
}
GDBStubUpdate(stub);
} }
static void _ack(struct GDBStub* stub) { static void _ack(struct GDBStub* stub) {
@ -169,7 +193,8 @@ static void _writeHostInfo(struct GDBStub* stub) {
} }
static void _continue(struct GDBStub* stub, const char* message) { static void _continue(struct GDBStub* stub, const char* message) {
stub->d.state = DEBUGGER_RUNNING; stub->d.state = DEBUGGER_CUSTOM;
stub->untilPoll = GDB_STUB_INTERVAL;
if (!SOCKET_FAILED(stub->connection)) { if (!SOCKET_FAILED(stub->connection)) {
if (!SocketSetBlocking(stub->connection, 0)) { if (!SocketSetBlocking(stub->connection, 0)) {
GDBStubHangup(stub); GDBStubHangup(stub);
@ -441,9 +466,11 @@ void GDBStubCreate(struct GDBStub* stub) {
stub->connection = INVALID_SOCKET; stub->connection = INVALID_SOCKET;
stub->d.init = 0; stub->d.init = 0;
stub->d.deinit = _gdbStubDeinit; stub->d.deinit = _gdbStubDeinit;
stub->d.paused = _gdbStubPoll; stub->d.paused = _gdbStubWait;
stub->d.entered = _gdbStubEntered; stub->d.entered = _gdbStubEntered;
stub->d.custom = _gdbStubPoll;
stub->d.log = 0; stub->d.log = 0;
stub->untilPoll = GDB_STUB_INTERVAL;
} }
int GDBStubListen(struct GDBStub* stub, int port, const struct Address* bindAddress) { int GDBStubListen(struct GDBStub* stub, int port, const struct Address* bindAddress) {
@ -461,9 +488,6 @@ int GDBStubListen(struct GDBStub* stub, int port, const struct Address* bindAddr
if (err) { if (err) {
goto cleanup; goto cleanup;
} }
if (!SocketSetBlocking(stub->socket, 0)) {
goto cleanup;
}
return 1; return 1;
@ -501,9 +525,6 @@ void GDBStubUpdate(struct GDBStub* stub) {
if (stub->connection == INVALID_SOCKET) { if (stub->connection == INVALID_SOCKET) {
stub->connection = SocketAccept(stub->socket, 0); stub->connection = SocketAccept(stub->socket, 0);
if (!SOCKET_FAILED(stub->connection)) { if (!SOCKET_FAILED(stub->connection)) {
if (!SocketSetBlocking(stub->connection, 0)) {
goto connectionLost;
}
ARMDebuggerEnter(&stub->d, DEBUGGER_ENTER_ATTACHED); ARMDebuggerEnter(&stub->d, DEBUGGER_ENTER_ATTACHED);
} else if (errno == EWOULDBLOCK || errno == EAGAIN) { } else if (errno == EWOULDBLOCK || errno == EAGAIN) {
return; return;

View File

@ -13,6 +13,7 @@
#include "util/socket.h" #include "util/socket.h"
#define GDB_STUB_MAX_LINE 1200 #define GDB_STUB_MAX_LINE 1200
#define GDB_STUB_INTERVAL 32
enum GDBStubAckState { enum GDBStubAckState {
GDB_ACK_PENDING = 0, GDB_ACK_PENDING = 0,
@ -30,6 +31,9 @@ struct GDBStub {
Socket socket; Socket socket;
Socket connection; Socket connection;
bool shouldBlock;
int untilPoll;
}; };
void GDBStubCreate(struct GDBStub*); void GDBStubCreate(struct GDBStub*);

View File

@ -10,6 +10,11 @@
#include <string.h> #include <string.h>
static bool _checkWatchpoints(struct DebugBreakpoint* watchpoints, uint32_t address, int width); static bool _checkWatchpoints(struct DebugBreakpoint* watchpoints, uint32_t address, int width);
static uint32_t _popcount32(unsigned bits) {
bits = bits - ((bits >> 1) & 0x55555555);
bits = (bits & 0x33333333) + ((bits >> 2) & 0x33333333);
return (((bits + (bits >> 4)) & 0xF0F0F0F) * 0x1010101) >> 24;
}
#define FIND_DEBUGGER(DEBUGGER, CPU) \ #define FIND_DEBUGGER(DEBUGGER, CPU) \
{ \ { \
@ -40,12 +45,37 @@ static bool _checkWatchpoints(struct DebugBreakpoint* watchpoints, uint32_t addr
return debugger->originalMemory.NAME(cpu, ARGS); \ return debugger->originalMemory.NAME(cpu, ARGS); \
} }
#define CREATE_MULTIPLE_WATCHPOINT_SHIM(NAME) \
static uint32_t ARMDebuggerShim_ ## NAME (struct ARMCore* cpu, uint32_t address, int mask, enum LSMDirection direction, int* cycleCounter) { \
struct ARMDebugger* debugger; \
FIND_DEBUGGER(debugger, cpu); \
uint32_t popcount = _popcount32(mask); \
int offset = 4; \
int base = address; \
if (direction & LSM_D) { \
offset = -4; \
base -= (popcount << 2) - 4; \
} \
if (direction & LSM_B) { \
base += offset; \
} \
unsigned i; \
for (i = 0; i < popcount; ++i) { \
if (_checkWatchpoints(debugger->watchpoints, base + 4 * i, 4)) { \
ARMDebuggerEnter(debugger, DEBUGGER_ENTER_WATCHPOINT); \
} \
} \
return debugger->originalMemory.NAME(cpu, address, mask, direction, cycleCounter); \
}
CREATE_WATCHPOINT_SHIM(load32, 4, uint32_t, (struct ARMCore* cpu, uint32_t address, int* cycleCounter), address, cycleCounter) CREATE_WATCHPOINT_SHIM(load32, 4, uint32_t, (struct ARMCore* cpu, uint32_t address, int* cycleCounter), address, cycleCounter)
CREATE_WATCHPOINT_SHIM(load16, 2, uint32_t, (struct ARMCore* cpu, uint32_t address, int* cycleCounter), address, cycleCounter) CREATE_WATCHPOINT_SHIM(load16, 2, uint32_t, (struct ARMCore* cpu, uint32_t address, int* cycleCounter), address, cycleCounter)
CREATE_WATCHPOINT_SHIM(load8, 1, uint32_t, (struct ARMCore* cpu, uint32_t address, int* cycleCounter), address, cycleCounter) CREATE_WATCHPOINT_SHIM(load8, 1, uint32_t, (struct ARMCore* cpu, uint32_t address, int* cycleCounter), address, cycleCounter)
CREATE_WATCHPOINT_SHIM(store32, 4, void, (struct ARMCore* cpu, uint32_t address, int32_t value, int* cycleCounter), address, value, cycleCounter) CREATE_WATCHPOINT_SHIM(store32, 4, void, (struct ARMCore* cpu, uint32_t address, int32_t value, int* cycleCounter), address, value, cycleCounter)
CREATE_WATCHPOINT_SHIM(store16, 2, void, (struct ARMCore* cpu, uint32_t address, int16_t value, int* cycleCounter), address, value, cycleCounter) CREATE_WATCHPOINT_SHIM(store16, 2, void, (struct ARMCore* cpu, uint32_t address, int16_t value, int* cycleCounter), address, value, cycleCounter)
CREATE_WATCHPOINT_SHIM(store8, 1, void, (struct ARMCore* cpu, uint32_t address, int8_t value, int* cycleCounter), address, value, cycleCounter) CREATE_WATCHPOINT_SHIM(store8, 1, void, (struct ARMCore* cpu, uint32_t address, int8_t value, int* cycleCounter), address, value, cycleCounter)
CREATE_MULTIPLE_WATCHPOINT_SHIM(loadMultiple)
CREATE_MULTIPLE_WATCHPOINT_SHIM(storeMultiple)
CREATE_SHIM(setActiveRegion, void, (struct ARMCore* cpu, uint32_t address), address) CREATE_SHIM(setActiveRegion, void, (struct ARMCore* cpu, uint32_t address), address)
static bool _checkWatchpoints(struct DebugBreakpoint* watchpoints, uint32_t address, int width) { static bool _checkWatchpoints(struct DebugBreakpoint* watchpoints, uint32_t address, int width) {
@ -66,6 +96,8 @@ void ARMDebuggerInstallMemoryShim(struct ARMDebugger* debugger) {
debugger->cpu->memory.load32 = ARMDebuggerShim_load32; debugger->cpu->memory.load32 = ARMDebuggerShim_load32;
debugger->cpu->memory.load16 = ARMDebuggerShim_load16; debugger->cpu->memory.load16 = ARMDebuggerShim_load16;
debugger->cpu->memory.load8 = ARMDebuggerShim_load8; debugger->cpu->memory.load8 = ARMDebuggerShim_load8;
debugger->cpu->memory.storeMultiple = ARMDebuggerShim_storeMultiple;
debugger->cpu->memory.loadMultiple = ARMDebuggerShim_loadMultiple;
debugger->cpu->memory.setActiveRegion = ARMDebuggerShim_setActiveRegion; debugger->cpu->memory.setActiveRegion = ARMDebuggerShim_setActiveRegion;
} }
@ -76,5 +108,7 @@ void ARMDebuggerRemoveMemoryShim(struct ARMDebugger* debugger) {
debugger->cpu->memory.load32 = debugger->originalMemory.load32; debugger->cpu->memory.load32 = debugger->originalMemory.load32;
debugger->cpu->memory.load16 = debugger->originalMemory.load16; debugger->cpu->memory.load16 = debugger->originalMemory.load16;
debugger->cpu->memory.load8 = debugger->originalMemory.load8; debugger->cpu->memory.load8 = debugger->originalMemory.load8;
debugger->cpu->memory.storeMultiple = debugger->originalMemory.storeMultiple;
debugger->cpu->memory.loadMultiple = debugger->originalMemory.loadMultiple;
debugger->cpu->memory.setActiveRegion = debugger->originalMemory.setActiveRegion; debugger->cpu->memory.setActiveRegion = debugger->originalMemory.setActiveRegion;
} }

View File

@ -53,8 +53,8 @@ void GBAAudioReset(struct GBAAudio* audio) {
audio->ch2 = (struct GBAAudioChannel2) { .envelope = { .nextStep = INT_MAX } }; audio->ch2 = (struct GBAAudioChannel2) { .envelope = { .nextStep = INT_MAX } };
audio->ch3 = (struct GBAAudioChannel3) { .bank = { .bank = 0 } }; audio->ch3 = (struct GBAAudioChannel3) { .bank = { .bank = 0 } };
audio->ch4 = (struct GBAAudioChannel4) { .envelope = { .nextStep = INT_MAX } }; audio->ch4 = (struct GBAAudioChannel4) { .envelope = { .nextStep = INT_MAX } };
audio->chA.dmaSource = 0; audio->chA.dmaSource = 1;
audio->chB.dmaSource = 0; audio->chB.dmaSource = 2;
audio->chA.sample = 0; audio->chA.sample = 0;
audio->chB.sample = 0; audio->chB.sample = 0;
audio->eventDiff = 0; audio->eventDiff = 0;

View File

@ -215,7 +215,10 @@ void GBASwi16(struct ARMCore* cpu, int immediate) {
ARMRaiseSWI(cpu); ARMRaiseSWI(cpu);
break; break;
case 0xD: case 0xD:
cpu->gprs[0] = GBAChecksum(gba->memory.bios, SIZE_BIOS); cpu->gprs[0] = GBA_BIOS_CHECKSUM;
cpu->gprs[1] = 1;
cpu->gprs[3] = SIZE_BIOS;
break;
case 0xE: case 0xE:
_BgAffineSet(gba); _BgAffineSet(gba);
break; break;
@ -288,6 +291,7 @@ void GBASwi16(struct ARMCore* cpu, int immediate) {
default: default:
GBALog(gba, GBA_LOG_STUB, "Stub software interrupt: %02X", immediate); GBALog(gba, GBA_LOG_STUB, "Stub software interrupt: %02X", immediate);
} }
gba->memory.biosPrefetch = 0xE3A02004;
} }
void GBASwi32(struct ARMCore* cpu, int immediate) { void GBASwi32(struct ARMCore* cpu, int immediate) {
@ -385,12 +389,14 @@ static void _unHuffman(struct GBA* gba) {
uint32_t header = cpu->memory.load32(cpu, source, 0); uint32_t header = cpu->memory.load32(cpu, source, 0);
int remaining = header >> 8; int remaining = header >> 8;
int bits = header & 0xF; int bits = header & 0xF;
if (32 % bits) { if (bits == 0) {
GBALog(gba, GBA_LOG_GAME_ERROR, "Invalid Huffman bits");
bits = 8;
}
if (32 % bits || bits == 1) {
GBALog(gba, GBA_LOG_STUB, "Unimplemented unaligned Huffman"); GBALog(gba, GBA_LOG_STUB, "Unimplemented unaligned Huffman");
return; return;
} }
int padding = (4 - remaining) & 0x3;
remaining &= 0xFFFFFFFC;
// We assume the signature byte (0x20) is correct // We assume the signature byte (0x20) is correct
int treesize = (cpu->memory.load8(cpu, source + 4, 0) << 1) + 1; int treesize = (cpu->memory.load8(cpu, source + 4, 0) << 1) + 1;
int block = 0; int block = 0;
@ -441,9 +447,6 @@ static void _unHuffman(struct GBA* gba) {
} }
} }
if (padding) {
cpu->memory.store32(cpu, dest, block, 0);
}
cpu->gprs[0] = source; cpu->gprs[0] = source;
cpu->gprs[1] = dest; cpu->gprs[1] = dest;
} }

View File

@ -101,9 +101,10 @@ void GBAMemoryReset(struct GBA* gba) {
memset(gba->memory.dma, 0, sizeof(gba->memory.dma)); memset(gba->memory.dma, 0, sizeof(gba->memory.dma));
int i; int i;
for (i = 0; i < 4; ++i) { for (i = 0; i < 4; ++i) {
gba->memory.dma[i].count = 0x10000; gba->memory.dma[i].count = 0x4000;
gba->memory.dma[i].nextEvent = INT_MAX; gba->memory.dma[i].nextEvent = INT_MAX;
} }
gba->memory.dma[3].count = 0x10000;
gba->memory.activeDMA = -1; gba->memory.activeDMA = -1;
gba->memory.nextDMA = INT_MAX; gba->memory.nextDMA = INT_MAX;
gba->memory.eventDiff = 0; gba->memory.eventDiff = 0;
@ -300,7 +301,11 @@ static void GBASetActiveRegion(struct ARMCore* cpu, uint32_t address) {
++wait; ++wait;
#define LOAD_VRAM \ #define LOAD_VRAM \
LOAD_32(value, address & 0x0001FFFF, gba->video.renderer->vram); \ if ((address & 0x0001FFFF) < SIZE_VRAM) { \
LOAD_32(value, address & 0x0001FFFF, gba->video.renderer->vram); \
} else { \
LOAD_32(value, address & 0x00017FFF, gba->video.renderer->vram); \
} \
++wait; ++wait;
#define LOAD_OAM LOAD_32(value, address & (SIZE_OAM - 1), gba->video.oam.raw); #define LOAD_OAM LOAD_32(value, address & (SIZE_OAM - 1), gba->video.oam.raw);
@ -388,14 +393,14 @@ uint32_t GBALoad16(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
LOAD_16(value, address, memory->bios); LOAD_16(value, address, memory->bios);
} else { } else {
GBALog(gba, GBA_LOG_GAME_ERROR, "Bad BIOS Load16: 0x%08X", address); GBALog(gba, GBA_LOG_GAME_ERROR, "Bad BIOS Load16: 0x%08X", address);
value = memory->biosPrefetch & 0xFFFF; LOAD_16(value, address & 2, &memory->biosPrefetch);
} }
} else { } else {
GBALog(gba, GBA_LOG_GAME_ERROR, "Bad memory Load16: 0x%08X", address); GBALog(gba, GBA_LOG_GAME_ERROR, "Bad memory Load16: 0x%08X", address);
if (cpu->cycles >= cpu->nextEvent) { if (cpu->cycles >= cpu->nextEvent) {
value = gba->bus & 0xFFFF; LOAD_16(value, address & 2, &gba->bus);
} else { } else {
value = cpu->prefetch[1] & 0xFFFF; LOAD_16(value, address & 2, &cpu->prefetch[1]);
} }
} }
break; break;
@ -413,7 +418,11 @@ uint32_t GBALoad16(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
LOAD_16(value, address & (SIZE_PALETTE_RAM - 1), gba->video.palette); LOAD_16(value, address & (SIZE_PALETTE_RAM - 1), gba->video.palette);
break; break;
case REGION_VRAM: case REGION_VRAM:
LOAD_16(value, address & 0x0001FFFF, gba->video.renderer->vram); if ((address & 0x0001FFFF) < SIZE_VRAM) {
LOAD_16(value, address & 0x0001FFFF, gba->video.renderer->vram);
} else {
LOAD_16(value, address & 0x00017FFF, gba->video.renderer->vram);
}
break; break;
case REGION_OAM: case REGION_OAM:
LOAD_16(value, address & (SIZE_OAM - 1), gba->video.oam.raw); LOAD_16(value, address & (SIZE_OAM - 1), gba->video.oam.raw);
@ -451,9 +460,9 @@ uint32_t GBALoad16(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
default: default:
GBALog(gba, GBA_LOG_GAME_ERROR, "Bad memory Load16: 0x%08X", address); GBALog(gba, GBA_LOG_GAME_ERROR, "Bad memory Load16: 0x%08X", address);
if (cpu->cycles >= cpu->nextEvent) { if (cpu->cycles >= cpu->nextEvent) {
value = gba->bus; LOAD_16(value, address & 2, &gba->bus);
} else { } else {
value = cpu->prefetch[1]; LOAD_16(value, address & 2, &cpu->prefetch[1]);
} }
break; break;
} }
@ -479,14 +488,14 @@ uint32_t GBALoad8(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
value = ((int8_t*) memory->bios)[address]; value = ((int8_t*) memory->bios)[address];
} else { } else {
GBALog(gba, GBA_LOG_GAME_ERROR, "Bad BIOS Load8: 0x%08X", address); GBALog(gba, GBA_LOG_GAME_ERROR, "Bad BIOS Load8: 0x%08X", address);
value = memory->biosPrefetch; value = ((uint8_t*) &memory->biosPrefetch)[address & 3];
} }
} else { } else {
GBALog(gba, GBA_LOG_GAME_ERROR, "Bad memory Load8: 0x%08x", address); GBALog(gba, GBA_LOG_GAME_ERROR, "Bad memory Load8: 0x%08x", address);
if (cpu->cycles >= cpu->nextEvent) { if (cpu->cycles >= cpu->nextEvent) {
value = gba->bus; value = ((uint8_t*) &gba->bus)[address & 3];
} else { } else {
value = cpu->prefetch[1]; value = ((uint8_t*) &cpu->prefetch[1])[address & 3];
} }
} }
break; break;
@ -504,7 +513,11 @@ uint32_t GBALoad8(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
value = ((int8_t*) gba->video.palette)[address & (SIZE_PALETTE_RAM - 1)]; value = ((int8_t*) gba->video.palette)[address & (SIZE_PALETTE_RAM - 1)];
break; break;
case REGION_VRAM: case REGION_VRAM:
value = ((int8_t*) gba->video.renderer->vram)[address & 0x0001FFFF]; if ((address & 0x0001FFFF) < SIZE_VRAM) {
value = ((int8_t*) gba->video.renderer->vram)[address & 0x0001FFFF];
} else {
value = ((int8_t*) gba->video.renderer->vram)[address & 0x00017FFF];
}
break; break;
case REGION_OAM: case REGION_OAM:
GBALog(gba, GBA_LOG_STUB, "Unimplemented memory Load8: 0x%08X", address); GBALog(gba, GBA_LOG_STUB, "Unimplemented memory Load8: 0x%08X", address);
@ -544,9 +557,9 @@ uint32_t GBALoad8(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
default: default:
GBALog(gba, GBA_LOG_GAME_ERROR, "Bad memory Load8: 0x%08x", address); GBALog(gba, GBA_LOG_GAME_ERROR, "Bad memory Load8: 0x%08x", address);
if (cpu->cycles >= cpu->nextEvent) { if (cpu->cycles >= cpu->nextEvent) {
value = gba->bus; value = ((uint8_t*) &gba->bus)[address & 3];
} else { } else {
value = cpu->prefetch[1]; value = ((uint8_t*) &cpu->prefetch[1])[address & 3];
} }
break; break;
} }
@ -574,9 +587,9 @@ uint32_t GBALoad8(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
gba->video.renderer->writePalette(gba->video.renderer, address & (SIZE_PALETTE_RAM - 1), value); gba->video.renderer->writePalette(gba->video.renderer, address & (SIZE_PALETTE_RAM - 1), value);
#define STORE_VRAM \ #define STORE_VRAM \
if ((address & OFFSET_MASK) < SIZE_VRAM) { \ if ((address & 0x0001FFFF) < SIZE_VRAM) { \
STORE_32(value, address & 0x0001FFFF, gba->video.renderer->vram); \ STORE_32(value, address & 0x0001FFFF, gba->video.renderer->vram); \
} else if ((address & OFFSET_MASK) < 0x00020000) { \ } else { \
STORE_32(value, address & 0x00017FFF, gba->video.renderer->vram); \ STORE_32(value, address & 0x00017FFF, gba->video.renderer->vram); \
} \ } \
++wait; ++wait;
@ -663,9 +676,9 @@ void GBAStore16(struct ARMCore* cpu, uint32_t address, int16_t value, int* cycle
gba->video.renderer->writePalette(gba->video.renderer, address & (SIZE_PALETTE_RAM - 1), value); gba->video.renderer->writePalette(gba->video.renderer, address & (SIZE_PALETTE_RAM - 1), value);
break; break;
case REGION_VRAM: case REGION_VRAM:
if ((address & OFFSET_MASK) < SIZE_VRAM) { if ((address & 0x0001FFFF) < SIZE_VRAM) {
STORE_16(value, address & 0x0001FFFF, gba->video.renderer->vram); STORE_16(value, address & 0x0001FFFF, gba->video.renderer->vram);
} else if ((address & OFFSET_MASK) < 0x00020000) { } else {
STORE_16(value, address & 0x00017FFF, gba->video.renderer->vram); STORE_16(value, address & 0x00017FFF, gba->video.renderer->vram);
} }
break; break;

View File

@ -40,6 +40,10 @@ void GBASerialize(struct GBA* gba, struct GBASerializedState* state) {
memcpy(state->cpu.bankedRegisters, gba->cpu->bankedRegisters, 6 * 7 * sizeof(int32_t)); memcpy(state->cpu.bankedRegisters, gba->cpu->bankedRegisters, 6 * 7 * sizeof(int32_t));
memcpy(state->cpu.bankedSPSRs, gba->cpu->bankedSPSRs, 6 * sizeof(int32_t)); memcpy(state->cpu.bankedSPSRs, gba->cpu->bankedSPSRs, 6 * sizeof(int32_t));
state->biosPrefetch = gba->memory.biosPrefetch;
state->cpuPrefetch[0] = gba->cpu->prefetch[0];
state->cpuPrefetch[1] = gba->cpu->prefetch[1];
GBAMemorySerialize(&gba->memory, state); GBAMemorySerialize(&gba->memory, state);
GBAIOSerialize(gba, state); GBAIOSerialize(gba, state);
GBAVideoSerialize(&gba->video, state); GBAVideoSerialize(&gba->video, state);
@ -80,14 +84,29 @@ void GBADeserialize(struct GBA* gba, struct GBASerializedState* state) {
memcpy(gba->cpu->bankedSPSRs, state->cpu.bankedSPSRs, 6 * sizeof(int32_t)); memcpy(gba->cpu->bankedSPSRs, state->cpu.bankedSPSRs, 6 * sizeof(int32_t));
gba->cpu->privilegeMode = gba->cpu->cpsr.priv; gba->cpu->privilegeMode = gba->cpu->cpsr.priv;
gba->cpu->memory.setActiveRegion(gba->cpu, gba->cpu->gprs[ARM_PC]); gba->cpu->memory.setActiveRegion(gba->cpu, gba->cpu->gprs[ARM_PC]);
if (state->biosPrefetch) {
gba->memory.biosPrefetch = state->biosPrefetch;
}
if (gba->cpu->cpsr.t) { if (gba->cpu->cpsr.t) {
gba->cpu->executionMode = MODE_THUMB; gba->cpu->executionMode = MODE_THUMB;
LOAD_16(gba->cpu->prefetch[0], (gba->cpu->gprs[ARM_PC] - WORD_SIZE_THUMB) & gba->cpu->memory.activeMask, gba->cpu->memory.activeRegion); if (state->cpuPrefetch[0] && state->cpuPrefetch[1]) {
LOAD_16(gba->cpu->prefetch[1], (gba->cpu->gprs[ARM_PC]) & gba->cpu->memory.activeMask, gba->cpu->memory.activeRegion); gba->cpu->prefetch[0] = state->cpuPrefetch[0] & 0xFFFF;
gba->cpu->prefetch[1] = state->cpuPrefetch[1] & 0xFFFF;
} else {
// Maintain backwards compat
LOAD_16(gba->cpu->prefetch[0], (gba->cpu->gprs[ARM_PC] - WORD_SIZE_THUMB) & gba->cpu->memory.activeMask, gba->cpu->memory.activeRegion);
LOAD_16(gba->cpu->prefetch[1], (gba->cpu->gprs[ARM_PC]) & gba->cpu->memory.activeMask, gba->cpu->memory.activeRegion);
}
} else { } else {
gba->cpu->executionMode = MODE_ARM; gba->cpu->executionMode = MODE_ARM;
LOAD_32(gba->cpu->prefetch[0], (gba->cpu->gprs[ARM_PC] - WORD_SIZE_ARM) & gba->cpu->memory.activeMask, gba->cpu->memory.activeRegion); if (state->cpuPrefetch[0] && state->cpuPrefetch[1]) {
LOAD_32(gba->cpu->prefetch[1], (gba->cpu->gprs[ARM_PC]) & gba->cpu->memory.activeMask, gba->cpu->memory.activeRegion); gba->cpu->prefetch[0] = state->cpuPrefetch[0];
gba->cpu->prefetch[1] = state->cpuPrefetch[1];
} else {
// Maintain backwards compat
LOAD_32(gba->cpu->prefetch[0], (gba->cpu->gprs[ARM_PC] - WORD_SIZE_ARM) & gba->cpu->memory.activeMask, gba->cpu->memory.activeRegion);
LOAD_32(gba->cpu->prefetch[1], (gba->cpu->gprs[ARM_PC]) & gba->cpu->memory.activeMask, gba->cpu->memory.activeRegion);
}
} }
GBAMemoryDeserialize(&gba->memory, state); GBAMemoryDeserialize(&gba->memory, state);

View File

@ -150,7 +150,11 @@ extern const uint32_t GBA_SAVESTATE_MAGIC;
* | 0x002C1 - 0x002C3: Flags * | 0x002C1 - 0x002C3: Flags
* | bits 0 - 1: Tilt state machine * | bits 0 - 1: Tilt state machine
* | bits 2 - 31: Reserved * | bits 2 - 31: Reserved
* 0x002C4 - 0x002FF: Reserved (leave zero) * 0x002C4 - 0x002F3: Reserved (leave zero)
* 0x002F4 - 0x002FF: Prefetch
* | 0x002F4 - 0x002F7: GBA BIOS bus prefetch
* | 0x002F8 - 0x002FB: CPU prefecth (decode slot)
* | 0x002FC - 0x002FF: CPU prefetch (fetch slot)
* 0x00300 - 0x00303: Associated movie stream ID for record/replay (or 0 if no stream) * 0x00300 - 0x00303: Associated movie stream ID for record/replay (or 0 if no stream)
* 0x00304 - 0x003FF: Reserved (leave zero) * 0x00304 - 0x003FF: Reserved (leave zero)
* 0x00400 - 0x007FF: I/O memory * 0x00400 - 0x007FF: I/O memory
@ -267,7 +271,10 @@ struct GBASerializedState {
unsigned : 22; unsigned : 22;
} gpio; } gpio;
uint32_t reservedGpio[15]; uint32_t reservedGpio[12];
uint32_t biosPrefetch;
uint32_t cpuPrefetch[2];
uint32_t associatedStreamId; uint32_t associatedStreamId;

View File

@ -42,7 +42,7 @@ void GBAVideoInit(struct GBAVideo* video) {
void GBAVideoReset(struct GBAVideo* video) { void GBAVideoReset(struct GBAVideo* video) {
video->dispstat = 0; video->dispstat = 0;
video->vcount = 0; video->vcount = VIDEO_VERTICAL_TOTAL_PIXELS - 1;
video->lastHblank = 0; video->lastHblank = 0;
video->nextHblank = VIDEO_HDRAW_LENGTH; video->nextHblank = VIDEO_HDRAW_LENGTH;

View File

@ -21,8 +21,8 @@
const uint32_t GBA_ARM7TDMI_FREQUENCY = 0x1000000; const uint32_t GBA_ARM7TDMI_FREQUENCY = 0x1000000;
const uint32_t GBA_COMPONENT_MAGIC = 0x1000000; const uint32_t GBA_COMPONENT_MAGIC = 0x1000000;
static const size_t GBA_ROM_MAGIC_OFFSET = 2; static const size_t GBA_ROM_MAGIC_OFFSET = 3;
static const uint8_t GBA_ROM_MAGIC[] = { 0x00, 0xEA }; static const uint8_t GBA_ROM_MAGIC[] = { 0xEA };
static void GBAInit(struct ARMCore* cpu, struct ARMComponent* component); static void GBAInit(struct ARMCore* cpu, struct ARMComponent* component);
static void GBAInterruptHandlerInit(struct ARMInterruptHandler* irqh); static void GBAInterruptHandlerInit(struct ARMInterruptHandler* irqh);
@ -145,7 +145,7 @@ void GBASkipBIOS(struct ARMCore* cpu) {
static void GBAProcessEvents(struct ARMCore* cpu) { static void GBAProcessEvents(struct ARMCore* cpu) {
do { do {
struct GBA* gba = (struct GBA*) cpu->master; struct GBA* gba = (struct GBA*) cpu->master;
int32_t cycles = cpu->cycles; int32_t cycles = cpu->nextEvent;
int32_t nextEvent = INT_MAX; int32_t nextEvent = INT_MAX;
int32_t testEvent; int32_t testEvent;

View File

@ -1,55 +1,51 @@
/* Copyright (c) 2013-2014 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 "hle-bios.h" #include "hle-bios.h"
#include "gba-memory.h" #include "gba-memory.h"
const uint8_t hleBios[SIZE_BIOS] = { const uint8_t hleBios[SIZE_BIOS] = {
0x06, 0x00, 0x00, 0xea, 0xfe, 0xff, 0xff, 0xea, 0x05, 0x00, 0x00, 0xea, 0x06, 0x00, 0x00, 0xea, 0xfe, 0xff, 0xff, 0xea, 0x07, 0x00, 0x00, 0xea,
0xfe, 0xff, 0xff, 0xea, 0xfe, 0xff, 0xff, 0xea, 0x00, 0x00, 0xa0, 0xe1, 0xfe, 0xff, 0xff, 0xea, 0xfe, 0xff, 0xff, 0xea, 0x00, 0x00, 0xa0, 0xe1,
0x26, 0x00, 0x00, 0xea, 0xfe, 0xff, 0xff, 0xea, 0x02, 0xf3, 0xa0, 0xe3, 0x28, 0x00, 0x00, 0xea, 0xfe, 0xff, 0xff, 0xea, 0x02, 0xf3, 0xa0, 0xe3,
0x00, 0x00, 0x5d, 0xe3, 0x01, 0xd3, 0xa0, 0x03, 0x20, 0xd0, 0x4d, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x29, 0xe1, 0x00, 0x00, 0x5d, 0xe3,
0x00, 0x58, 0x2d, 0xe9, 0x02, 0xb0, 0x5e, 0xe5, 0x84, 0xc0, 0xa0, 0xe3, 0x01, 0xd3, 0xa0, 0x03, 0x20, 0xd0, 0x4d, 0x02, 0x00, 0x58, 0x2d, 0xe9,
0x0b, 0xb1, 0x9c, 0xe7, 0x00, 0x00, 0x5b, 0xe3, 0x00, 0xc0, 0x4f, 0xe1, 0x02, 0xb0, 0x5e, 0xe5, 0x8c, 0xc0, 0xa0, 0xe3, 0x0b, 0xb1, 0x9c, 0xe7,
0x00, 0x10, 0x2d, 0xe9, 0x80, 0xc0, 0x0c, 0xe2, 0x1f, 0xc0, 0x8c, 0xe3, 0x00, 0x00, 0x5b, 0xe3, 0x00, 0xc0, 0x4f, 0xe1, 0x00, 0x10, 0x2d, 0xe9,
0x0c, 0xf0, 0x29, 0xe1, 0x00, 0x40, 0x2d, 0xe9, 0x0f, 0xe0, 0xa0, 0xe1, 0x80, 0xc0, 0x0c, 0xe2, 0x1f, 0xc0, 0x8c, 0xe3, 0x0c, 0xf0, 0x29, 0xe1,
0x1b, 0xff, 0x2f, 0x11, 0x00, 0x40, 0xbd, 0xe8, 0x93, 0xf0, 0x29, 0xe3, 0x00, 0x40, 0x2d, 0xe9, 0x0f, 0xe0, 0xa0, 0xe1, 0x1b, 0xff, 0x2f, 0x11,
0x00, 0x10, 0xbd, 0xe8, 0x0c, 0xf0, 0x69, 0xe1, 0x00, 0x58, 0xbd, 0xe8, 0x00, 0x40, 0xbd, 0xe8, 0x93, 0xf0, 0x29, 0xe3, 0x00, 0x10, 0xbd, 0xe8,
0x0e, 0xf0, 0xb0, 0xe1, 0x00, 0x00, 0x00, 0x00, 0x04, 0x20, 0xa0, 0xe3, 0x0c, 0xf0, 0x69, 0xe1, 0x00, 0x58, 0xbd, 0xe8, 0x0e, 0xf0, 0xb0, 0xe1,
0x00, 0x00, 0x00, 0x00, 0x04, 0x20, 0xa0, 0xe3, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xd8, 0x00, 0x00, 0x00, 0xd0, 0x00, 0x00, 0x00, 0xe8, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00,
0xb0, 0x01, 0x00, 0x00, 0x0f, 0x50, 0x2d, 0xe9, 0x01, 0x03, 0xa0, 0xe3, 0x0f, 0x50, 0x2d, 0xe9, 0x01, 0x03, 0xa0, 0xe3, 0x00, 0xe0, 0x8f, 0xe2,
0x00, 0xe0, 0x8f, 0xe2, 0x04, 0xf0, 0x10, 0xe5, 0x0f, 0x50, 0xbd, 0xe8, 0x04, 0xf0, 0x10, 0xe5, 0x0f, 0x50, 0xbd, 0xe8, 0x04, 0xf0, 0x5e, 0xe2,
0x04, 0xf0, 0x5e, 0xe2, 0x01, 0x00, 0xa0, 0xe3, 0x01, 0x10, 0xa0, 0xe3, 0x00, 0x00, 0x00, 0x00, 0x02, 0xc0, 0x5e, 0xe5, 0x01, 0x00, 0xa0, 0xe3,
0x0c, 0x40, 0x2d, 0xe9, 0x01, 0xc3, 0xa0, 0xe3, 0x00, 0x00, 0x50, 0xe3, 0x01, 0x10, 0xa0, 0xe3, 0x0c, 0x40, 0x2d, 0xe9, 0x01, 0xc3, 0xa0, 0xe3,
0x00, 0x00, 0xa0, 0xe3, 0x01, 0x20, 0xa0, 0xe3, 0x03, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x50, 0xe3, 0x00, 0x00, 0xa0, 0xe3, 0x01, 0x20, 0xa0, 0xe3,
0xb8, 0x30, 0x5c, 0xe1, 0x01, 0x30, 0xc3, 0xe1, 0xb8, 0x30, 0x4c, 0xe1, 0x03, 0x00, 0x00, 0x0a, 0xb8, 0x30, 0x5c, 0xe1, 0x01, 0x30, 0xc3, 0xe1,
0x01, 0x03, 0xcc, 0xe5, 0x08, 0x02, 0xcc, 0xe5, 0xb8, 0x30, 0x5c, 0xe1, 0xb8, 0x30, 0x4c, 0xe1, 0x01, 0x03, 0xcc, 0xe5, 0x08, 0x02, 0xcc, 0xe5,
0x01, 0x30, 0x13, 0xe0, 0x01, 0x30, 0x23, 0x10, 0xb8, 0x30, 0x4c, 0x11, 0xb8, 0x30, 0x5c, 0xe1, 0x01, 0x30, 0x13, 0xe0, 0x01, 0x30, 0x23, 0x10,
0x08, 0x22, 0xcc, 0xe5, 0xf7, 0xff, 0xff, 0x0a, 0x0c, 0x80, 0xbd, 0xe8, 0xb8, 0x30, 0x4c, 0x11, 0x08, 0x22, 0xcc, 0xe5, 0xf7, 0xff, 0xff, 0x0a,
0x00, 0x40, 0x2d, 0xe9, 0x02, 0x36, 0xa0, 0xe1, 0x01, 0x04, 0x12, 0xe3, 0x0c, 0x80, 0xbd, 0xe8, 0x00, 0x40, 0x2d, 0xe9, 0x02, 0x36, 0xa0, 0xe1,
0x0f, 0x00, 0x00, 0x0a, 0x01, 0x03, 0x12, 0xe3, 0x05, 0x00, 0x00, 0x0a, 0x01, 0x04, 0x12, 0xe3, 0x0f, 0x00, 0x00, 0x0a, 0x01, 0x03, 0x12, 0xe3,
0x23, 0x35, 0x81, 0xe0, 0x04, 0x00, 0xb0, 0xe8, 0x03, 0x00, 0x51, 0xe1, 0x05, 0x00, 0x00, 0x0a, 0x23, 0x35, 0x81, 0xe0, 0x04, 0x00, 0xb0, 0xe8,
0x04, 0x00, 0xa1, 0xb8, 0xfc, 0xff, 0xff, 0xba, 0x16, 0x00, 0x00, 0xea, 0x03, 0x00, 0x51, 0xe1, 0x04, 0x00, 0xa1, 0xb8, 0xfc, 0xff, 0xff, 0xba,
0x01, 0x00, 0xc0, 0xe3, 0x01, 0x10, 0xc1, 0xe3, 0xa3, 0x35, 0x81, 0xe0, 0x16, 0x00, 0x00, 0xea, 0x01, 0x00, 0xc0, 0xe3, 0x01, 0x10, 0xc1, 0xe3,
0xb0, 0x20, 0xd0, 0xe1, 0x03, 0x00, 0x51, 0xe1, 0xb2, 0x20, 0xc1, 0xb0, 0xa3, 0x35, 0x81, 0xe0, 0xb0, 0x20, 0xd0, 0xe1, 0x03, 0x00, 0x51, 0xe1,
0xfc, 0xff, 0xff, 0xba, 0x0e, 0x00, 0x00, 0xea, 0x01, 0x03, 0x12, 0xe3, 0xb2, 0x20, 0xc1, 0xb0, 0xfc, 0xff, 0xff, 0xba, 0x0e, 0x00, 0x00, 0xea,
0x05, 0x00, 0x00, 0x0a, 0x23, 0x35, 0x81, 0xe0, 0x03, 0x00, 0x51, 0xe1, 0x01, 0x03, 0x12, 0xe3, 0x05, 0x00, 0x00, 0x0a, 0x23, 0x35, 0x81, 0xe0,
0x04, 0x00, 0xb0, 0xb8, 0x04, 0x00, 0xa1, 0xb8, 0xfb, 0xff, 0xff, 0xba, 0x03, 0x00, 0x51, 0xe1, 0x04, 0x00, 0xb0, 0xb8, 0x04, 0x00, 0xa1, 0xb8,
0x06, 0x00, 0x00, 0xea, 0xa3, 0x35, 0x81, 0xe0, 0x01, 0x00, 0xc0, 0xe3, 0xfb, 0xff, 0xff, 0xba, 0x06, 0x00, 0x00, 0xea, 0xa3, 0x35, 0x81, 0xe0,
0x01, 0x10, 0xc1, 0xe3, 0x03, 0x00, 0x51, 0xe1, 0xb2, 0x20, 0xd0, 0xb0, 0x01, 0x00, 0xc0, 0xe3, 0x01, 0x10, 0xc1, 0xe3, 0x03, 0x00, 0x51, 0xe1,
0xb2, 0x20, 0xc1, 0xb0, 0xfb, 0xff, 0xff, 0xba, 0x00, 0x80, 0xbd, 0xe8, 0xb2, 0x20, 0xd0, 0xb0, 0xb2, 0x20, 0xc1, 0xb0, 0xfb, 0xff, 0xff, 0xba,
0xf0, 0x47, 0x2d, 0xe9, 0x01, 0x04, 0x12, 0xe3, 0x02, 0x36, 0xa0, 0xe1, 0x00, 0x80, 0xbd, 0xe8, 0xf0, 0x47, 0x2d, 0xe9, 0x01, 0x04, 0x12, 0xe3,
0x23, 0x25, 0x81, 0xe0, 0x0b, 0x00, 0x00, 0x0a, 0x00, 0x30, 0x90, 0xe5, 0x02, 0x36, 0xa0, 0xe1, 0x23, 0x25, 0x81, 0xe0, 0x0b, 0x00, 0x00, 0x0a,
0x03, 0x40, 0xa0, 0xe1, 0x03, 0x50, 0xa0, 0xe1, 0x03, 0x60, 0xa0, 0xe1, 0x00, 0x30, 0x90, 0xe5, 0x03, 0x40, 0xa0, 0xe1, 0x03, 0x50, 0xa0, 0xe1,
0x03, 0x70, 0xa0, 0xe1, 0x03, 0x80, 0xa0, 0xe1, 0x03, 0x90, 0xa0, 0xe1, 0x03, 0x60, 0xa0, 0xe1, 0x03, 0x70, 0xa0, 0xe1, 0x03, 0x80, 0xa0, 0xe1,
0x03, 0xa0, 0xa0, 0xe1, 0x02, 0x00, 0x51, 0xe1, 0xf8, 0x07, 0xa1, 0xb8, 0x03, 0x90, 0xa0, 0xe1, 0x03, 0xa0, 0xa0, 0xe1, 0x02, 0x00, 0x51, 0xe1,
0xfc, 0xff, 0xff, 0xba, 0x03, 0x00, 0x00, 0xea, 0x02, 0x00, 0x51, 0xe1, 0xf8, 0x07, 0xa1, 0xb8, 0xfc, 0xff, 0xff, 0xba, 0x03, 0x00, 0x00, 0xea,
0xf8, 0x07, 0xb0, 0xb8, 0xf8, 0x07, 0xa1, 0xb8, 0xfb, 0xff, 0xff, 0xba, 0x02, 0x00, 0x51, 0xe1, 0xf8, 0x07, 0xb0, 0xb8, 0xf8, 0x07, 0xa1, 0xb8,
0xf0, 0x87, 0xbd, 0xe8 0xfb, 0xff, 0xff, 0xba, 0xf0, 0x87, 0xbd, 0xe8
}; };

View File

@ -18,6 +18,8 @@ b fiqBase
resetBase: resetBase:
mov pc, #0x8000000 mov pc, #0x8000000
.word 0
.word 0xE129F000
swiBase: swiBase:
cmp sp, #0 cmp sp, #0
@ -68,6 +70,8 @@ add lr, pc, #0
ldr pc, [r0, #-4] ldr pc, [r0, #-4]
ldmfd sp!, {r0-r3, r12, lr} ldmfd sp!, {r0-r3, r12, lr}
subs pc, lr, #4 subs pc, lr, #4
.word 0
.word 0xE55EC002
VBlankIntrWait: VBlankIntrWait:
mov r0, #1 mov r0, #1

View File

@ -1010,6 +1010,10 @@ static inline void _compositeNoBlendNoObjwin(struct GBAVideoSoftwareRenderer* re
paletteData = GBA_TEXT_MAP_PALETTE(mapData) << 4; \ paletteData = GBA_TEXT_MAP_PALETTE(mapData) << 4; \
palette = &mainPalette[paletteData]; \ palette = &mainPalette[paletteData]; \
charBase = (background->charBase + (GBA_TEXT_MAP_TILE(mapData) << 5)) + (localY << 2); \ charBase = (background->charBase + (GBA_TEXT_MAP_TILE(mapData) << 5)) + (localY << 2); \
if (UNLIKELY(charBase >= 0x10000)) { \
pixel += 8; \
continue; \
} \
LOAD_32(tileData, charBase, vram); \ LOAD_32(tileData, charBase, vram); \
if (tileData) { \ if (tileData) { \
if (!GBA_TEXT_MAP_HFLIP(mapData)) { \ if (!GBA_TEXT_MAP_HFLIP(mapData)) { \
@ -1058,35 +1062,43 @@ static inline void _compositeNoBlendNoObjwin(struct GBAVideoSoftwareRenderer* re
int end2 = end - 4; \ int end2 = end - 4; \
if (!GBA_TEXT_MAP_HFLIP(mapData)) { \ if (!GBA_TEXT_MAP_HFLIP(mapData)) { \
int shift = inX & 0x3; \ int shift = inX & 0x3; \
if (end2 > outX) { \ if (LIKELY(charBase < 0x10000)) { \
LOAD_32(tileData, charBase, vram); \ if (end2 > outX) { \
tileData >>= 8 * shift; \ LOAD_32(tileData, charBase, vram); \
shift = 0; \ tileData >>= 8 * shift; \
for (; outX < end2; ++outX, ++pixel) { \ shift = 0; \
BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN); \ for (; outX < end2; ++outX, ++pixel) { \
BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN); \
} \
} \ } \
} \ } \
\ \
LOAD_32(tileData, charBase + 4, vram); \ if (LIKELY(charBase < 0x10000)) { \
tileData >>= 8 * shift; \ LOAD_32(tileData, charBase + 4, vram); \
for (; outX < end; ++outX, ++pixel) { \ tileData >>= 8 * shift; \
BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN); \ for (; outX < end; ++outX, ++pixel) { \
BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN); \
} \
} \ } \
} else { \ } else { \
int start = outX; \ int start = outX; \
outX = end - 1; \ outX = end - 1; \
pixel = &renderer->row[outX]; \ pixel = &renderer->row[outX]; \
if (end2 > start) { \ if (LIKELY(charBase < 0x10000)) { \
LOAD_32(tileData, charBase, vram); \ if (end2 > start) { \
for (; outX >= end2; --outX, --pixel) { \ LOAD_32(tileData, charBase, vram); \
BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN); \ for (; outX >= end2; --outX, --pixel) { \
BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN); \
} \
charBase += 4; \
} \ } \
charBase += 4; \
} \ } \
\ \
LOAD_32(tileData, charBase, vram); \ if (LIKELY(charBase < 0x10000)) { \
for (; outX >= renderer->start; --outX, --pixel) { \ LOAD_32(tileData, charBase, vram); \
BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN); \ for (; outX >= renderer->start; --outX, --pixel) { \
BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN); \
} \
} \ } \
outX = end; \ outX = end; \
pixel = &renderer->row[outX]; \ pixel = &renderer->row[outX]; \
@ -1094,6 +1106,9 @@ static inline void _compositeNoBlendNoObjwin(struct GBAVideoSoftwareRenderer* re
#define DRAW_BACKGROUND_MODE_0_TILE_PREFIX_256(BLEND, OBJWIN) \ #define DRAW_BACKGROUND_MODE_0_TILE_PREFIX_256(BLEND, OBJWIN) \
charBase = (background->charBase + (GBA_TEXT_MAP_TILE(mapData) << 6)) + (localY << 3); \ charBase = (background->charBase + (GBA_TEXT_MAP_TILE(mapData) << 6)) + (localY << 3); \
if (UNLIKELY(charBase >= 0x10000)) { \
return; \
} \
int end = mod8 - 4; \ int end = mod8 - 4; \
pixel = &renderer->row[outX]; \ pixel = &renderer->row[outX]; \
if (!GBA_TEXT_MAP_HFLIP(mapData)) { \ if (!GBA_TEXT_MAP_HFLIP(mapData)) { \
@ -1139,6 +1154,10 @@ static inline void _compositeNoBlendNoObjwin(struct GBAVideoSoftwareRenderer* re
for (; tileX < tileEnd; ++tileX) { \ for (; tileX < tileEnd; ++tileX) { \
BACKGROUND_TEXT_SELECT_CHARACTER; \ BACKGROUND_TEXT_SELECT_CHARACTER; \
charBase = (background->charBase + (GBA_TEXT_MAP_TILE(mapData) << 6)) + (localY << 3); \ charBase = (background->charBase + (GBA_TEXT_MAP_TILE(mapData) << 6)) + (localY << 3); \
if (UNLIKELY(charBase >= 0x10000)) { \
pixel += 8; \
continue; \
} \
if (!GBA_TEXT_MAP_HFLIP(mapData)) { \ if (!GBA_TEXT_MAP_HFLIP(mapData)) { \
LOAD_32(tileData, charBase, vram); \ LOAD_32(tileData, charBase, vram); \
if (tileData) { \ if (tileData) { \

View File

@ -112,46 +112,43 @@ static void _GBASDLHandleKeypress(struct GBAThread* context, struct GBASDLEvents
} }
return; return;
} }
switch (event->keysym.sym) { if (event->keysym.sym == SDLK_TAB) {
case SDLK_F11: context->sync.audioWait = event->type != SDL_KEYDOWN;
if (event->type == SDL_KEYDOWN && context->debugger) {
ARMDebuggerEnter(context->debugger, DEBUGGER_ENTER_MANUAL);
}
return; return;
}
if (event->type == SDL_KEYDOWN) {
switch (event->keysym.sym) {
case SDLK_F11:
if (context->debugger) {
ARMDebuggerEnter(context->debugger, DEBUGGER_ENTER_MANUAL);
}
return;
#ifdef USE_PNG #ifdef USE_PNG
case SDLK_F12: case SDLK_F12:
if (event->type == SDL_KEYDOWN) {
GBAThreadInterrupt(context); GBAThreadInterrupt(context);
GBAThreadTakeScreenshot(context); GBAThreadTakeScreenshot(context);
GBAThreadContinue(context); GBAThreadContinue(context);
} return;
return;
#endif #endif
case SDLK_TAB: case SDLK_BACKSLASH:
context->sync.audioWait = event->type != SDL_KEYDOWN;
return;
case SDLK_BACKSLASH:
if (event->type == SDL_KEYDOWN) {
GBAThreadPause(context); GBAThreadPause(context);
context->frameCallback = _pauseAfterFrame; context->frameCallback = _pauseAfterFrame;
GBAThreadUnpause(context); GBAThreadUnpause(context);
} return;
return; case SDLK_BACKQUOTE:
case SDLK_LEFTBRACKET: GBAThreadInterrupt(context);
GBAThreadInterrupt(context); GBARewind(context, 10);
GBARewind(context, 10); GBAThreadContinue(context);
GBAThreadContinue(context); return;
return; case SDLK_ESCAPE:
case SDLK_ESCAPE: GBAThreadInterrupt(context);
GBAThreadInterrupt(context); if (context->gba->rr) {
if (context->gba->rr) { GBARRStopPlaying(context->gba->rr);
GBARRStopPlaying(context->gba->rr); GBARRStopRecording(context->gba->rr);
GBARRStopRecording(context->gba->rr); }
} GBAThreadContinue(context);
GBAThreadContinue(context); return;
return; default:
default:
if (event->type == SDL_KEYDOWN) {
if ((event->keysym.mod & GUI_MOD) && (event->keysym.mod & GUI_MOD) == event->keysym.mod) { if ((event->keysym.mod & GUI_MOD) && (event->keysym.mod & GUI_MOD) == event->keysym.mod) {
switch (event->keysym.sym) { switch (event->keysym.sym) {
#if SDL_VERSION_ATLEAST(2, 0, 0) #if SDL_VERSION_ATLEAST(2, 0, 0)
@ -238,8 +235,8 @@ static void _GBASDLHandleKeypress(struct GBAThread* context, struct GBASDLEvents
break; break;
} }
} }
return;
} }
return;
} }
} }

View File

@ -129,6 +129,9 @@ bool _BPSApplyPatch(struct Patch* patch, void* in, size_t inSize, void* out, siz
if (_decodeLength(patch->vf) != outSize) { if (_decodeLength(patch->vf) != outSize) {
return false; return false;
} }
if (inSize > SSIZE_MAX || outSize > SSIZE_MAX) {
return false;
}
size_t metadataLength = _decodeLength(patch->vf); size_t metadataLength = _decodeLength(patch->vf);
patch->vf->seek(patch->vf, metadataLength, SEEK_CUR); // Skip metadata patch->vf->seek(patch->vf, metadataLength, SEEK_CUR); // Skip metadata
size_t writeLocation = 0; size_t writeLocation = 0;
@ -153,7 +156,7 @@ bool _BPSApplyPatch(struct Patch* patch, void* in, size_t inSize, void* out, siz
break; break;
case 0x1: case 0x1:
// TargetRead // TargetRead
if (patch->vf->read(patch->vf, &writeBuffer[writeLocation], length) != length) { if (patch->vf->read(patch->vf, &writeBuffer[writeLocation], length) != (ssize_t) length) {
return false; return false;
} }
outputChecksum = updateCrc32(outputChecksum, &writeBuffer[writeLocation], length); outputChecksum = updateCrc32(outputChecksum, &writeBuffer[writeLocation], length);
@ -167,7 +170,7 @@ bool _BPSApplyPatch(struct Patch* patch, void* in, size_t inSize, void* out, siz
} else { } else {
readSourceLocation += readOffset >> 1; readSourceLocation += readOffset >> 1;
} }
if (readSourceLocation < 0 || readSourceLocation > inSize) { if (readSourceLocation < 0 || readSourceLocation > (ssize_t) inSize) {
return false; return false;
} }
memmove(&writeBuffer[writeLocation], &readBuffer[readSourceLocation], length); memmove(&writeBuffer[writeLocation], &readBuffer[readSourceLocation], length);
@ -183,7 +186,7 @@ bool _BPSApplyPatch(struct Patch* patch, void* in, size_t inSize, void* out, siz
} else { } else {
readTargetLocation += readOffset >> 1; readTargetLocation += readOffset >> 1;
} }
if (readTargetLocation < 0 || readTargetLocation > outSize) { if (readTargetLocation < 0 || readTargetLocation > (ssize_t) outSize) {
return false; return false;
} }
for (i = 0; i < length; ++i) { for (i = 0; i < length; ++i) {

View File

@ -16,7 +16,7 @@
#include <winsock2.h> #include <winsock2.h>
#include <ws2tcpip.h> #include <ws2tcpip.h>
#define SOCKET_FAILED(s) (s) == INVALID_SOCKET #define SOCKET_FAILED(s) ((s) == INVALID_SOCKET)
typedef SOCKET Socket; typedef SOCKET Socket;
#else #else
#include <fcntl.h> #include <fcntl.h>
@ -25,7 +25,7 @@ typedef SOCKET Socket;
#include <sys/socket.h> #include <sys/socket.h>
#define INVALID_SOCKET (-1) #define INVALID_SOCKET (-1)
#define SOCKET_FAILED(s) (s) < 0 #define SOCKET_FAILED(s) ((s) < 0)
typedef int Socket; typedef int Socket;
#endif #endif
@ -157,7 +157,7 @@ static inline int SocketClose(Socket socket) {
return close(socket) >= 0; return close(socket) >= 0;
} }
static inline int SocketSetBlocking(Socket socket, int blocking) { static inline int SocketSetBlocking(Socket socket, bool blocking) {
#ifdef _WIN32 #ifdef _WIN32
u_long unblocking = !blocking; u_long unblocking = !blocking;
return ioctlsocket(socket, FIONBIO, &unblocking) == NO_ERROR; return ioctlsocket(socket, FIONBIO, &unblocking) == NO_ERROR;

View File

@ -76,7 +76,7 @@ class Suite(object):
def collect_tests(self): def collect_tests(self):
roms = [] roms = []
for f in os.listdir(self.cwd): for f in os.listdir(self.cwd):
if f.endswith('.gba'): if f.endswith('.gba') or f.endswith('.zip'):
roms.append(f) roms.append(f)
roms.sort() roms.sort()
for rom in roms: for rom in roms: