Enabled more debugging techniques by default in debug builds.

Added more Arm intrinsics.
ARM7 stub now waits for REG_VCOUNT == 126 (same as after BIOS intro).
Enable ROM mirroring for all 8 Mbit games instead of just Classic NES Series.
Other misc. changes.
This commit is contained in:
profi200 2020-11-22 01:47:58 +01:00
parent 5316c8938d
commit 5f25739286
No known key found for this signature in database
GPG Key ID: 17B42AE5911139F3
17 changed files with 229 additions and 133 deletions

View File

@ -36,18 +36,24 @@ endif
#---------------------------------------------------------------------------------
ARCH := -march=armv6k+vfpv2 -mtune=mpcore -mfloat-abi=hard -mtp=soft -marm -mthumb-interwork
CFLAGS := $(ARCH) -std=gnu17 -O2 -g -flto -mword-relocations -ffunction-sections \
-fno-math-errno -Wall -Wextra -Wno-unused-function
CFLAGS := $(ARCH) -std=c17 -O2 -g -flto -mword-relocations \
-ffunction-sections -fno-math-errno -Wall -Wextra
CFLAGS += $(INCLUDE) $(DEFINES)
CXXFLAGS := $(ARCH) -std=c++17 -O2 -g -flto -fno-rtti -fno-exceptions \
-mword-relocations -ffunction-sections -fno-math-errno -Wall -Wextra \
-Wno-unused-function
-mword-relocations -ffunction-sections -fno-math-errno -Wall -Wextra
CXXFLAGS += $(INCLUDE) $(DEFINES)
ASFLAGS := $(ARCH) -g -flto $(INCLUDE) $(DEFINES)
LDFLAGS = $(ARCH) -g -flto -specs=../arm11.specs -Wl,-Map,$(notdir $*.map) -nostartfiles
ifeq ($(strip $(NO_DEBUG)),)
CFLAGS := $(subst -flto,,$(CFLAGS)) -fstack-protector-strong -fno-inline
CXXFLAGS := $(subst -flto,,$(CXXFLAGS)) -fstack-protector-strong -fno-inline
ASFLAGS := $(subst -flto,,$(ASFLAGS))
LDFLAGS := $(subst -flto,,$(LDFLAGS)) -fstack-protector-strong -fno-inline -Wl,-wrap=malloc,-wrap=calloc,-wrap=free
endif
LIBS := -lm
#---------------------------------------------------------------------------------
@ -188,4 +194,3 @@ endef
#---------------------------------------------------------------------------------------
endif
#---------------------------------------------------------------------------------------

View File

@ -197,6 +197,59 @@ ALWAYS_INLINE u32 __strex(vu32 *addr, u32 val)
MAKE_INTR_NO_INOUT(1, clrex, "memory")
// Debug ID Register
MAKE_INTR_GET_REG(0, getDidr, "mrc p14, 0, %0, c0, c0, 0")
// Debug Status and Control Register
MAKE_INTR_GET_REG(1, getDscr, "mrc p14, 0, %0, c0, c1, 0")
MAKE_INTR_SET_REG(1, setDscr, "mcr p14, 0, %0, c0, c1, 0", "memory")
// Data Transfer Register
// Vector Catch Register
MAKE_INTR_GET_REG(1, getVcr, "mrc p14, 0, %0, c0, c7, 0")
MAKE_INTR_SET_REG(1, setVcr, "mcr p14, 0, %0, c0, c7, 0", "memory")
// Breakpoint Value Register 0-5
MAKE_INTR_GET_REG(1, getBvr0, "mrc p14, 0, %0, c0, c0, 4")
MAKE_INTR_SET_REG(1, setBvr0, "mcr p14, 0, %0, c0, c0, 4", "memory")
MAKE_INTR_GET_REG(1, getBvr1, "mrc p14, 0, %0, c0, c1, 4")
MAKE_INTR_SET_REG(1, setBvr1, "mcr p14, 0, %0, c0, c1, 4", "memory")
MAKE_INTR_GET_REG(1, getBvr2, "mrc p14, 0, %0, c0, c2, 4")
MAKE_INTR_SET_REG(1, setBvr2, "mcr p14, 0, %0, c0, c2, 4", "memory")
MAKE_INTR_GET_REG(1, getBvr3, "mrc p14, 0, %0, c0, c3, 4")
MAKE_INTR_SET_REG(1, setBvr3, "mcr p14, 0, %0, c0, c3, 4", "memory")
MAKE_INTR_GET_REG(1, getBvr4, "mrc p14, 0, %0, c0, c4, 4")
MAKE_INTR_SET_REG(1, setBvr4, "mcr p14, 0, %0, c0, c4, 4", "memory")
MAKE_INTR_GET_REG(1, getBvr5, "mrc p14, 0, %0, c0, c5, 4")
MAKE_INTR_SET_REG(1, setBvr5, "mcr p14, 0, %0, c0, c5, 4", "memory")
// Breakpoint Control Register 0-5
MAKE_INTR_GET_REG(1, getBcr0, "mrc p14, 0, %0, c0, c0, 5")
MAKE_INTR_SET_REG(1, setBcr0, "mcr p14, 0, %0, c0, c0, 5", "memory")
MAKE_INTR_GET_REG(1, getBcr1, "mrc p14, 0, %0, c0, c1, 5")
MAKE_INTR_SET_REG(1, setBcr1, "mcr p14, 0, %0, c0, c1, 5", "memory")
MAKE_INTR_GET_REG(1, getBcr2, "mrc p14, 0, %0, c0, c2, 5")
MAKE_INTR_SET_REG(1, setBcr2, "mcr p14, 0, %0, c0, c2, 5", "memory")
MAKE_INTR_GET_REG(1, getBcr3, "mrc p14, 0, %0, c0, c3, 5")
MAKE_INTR_SET_REG(1, setBcr3, "mcr p14, 0, %0, c0, c3, 5", "memory")
MAKE_INTR_GET_REG(1, getBcr4, "mrc p14, 0, %0, c0, c4, 5")
MAKE_INTR_SET_REG(1, setBcr4, "mcr p14, 0, %0, c0, c4, 5", "memory")
MAKE_INTR_GET_REG(1, getBcr5, "mrc p14, 0, %0, c0, c5, 5")
MAKE_INTR_SET_REG(1, setBcr5, "mcr p14, 0, %0, c0, c5, 5", "memory")
// Watchpoint Value Register 0-1
MAKE_INTR_GET_REG(1, getWvr0, "mrc p14, 0, %0, c0, c0, 6")
MAKE_INTR_SET_REG(1, setWvr0, "mcr p14, 0, %0, c0, c0, 6", "memory")
MAKE_INTR_GET_REG(1, getWvr1, "mrc p14, 0, %0, c0, c1, 6")
MAKE_INTR_SET_REG(1, setWvr1, "mcr p14, 0, %0, c0, c1, 6", "memory")
// Watchpoint Control Register 0-1
MAKE_INTR_GET_REG(1, getWcr0, "mrc p14, 0, %0, c0, c0, 7")
MAKE_INTR_SET_REG(1, setWcr0, "mcr p14, 0, %0, c0, c0, 7", "memory")
MAKE_INTR_GET_REG(1, getWcr1, "mrc p14, 0, %0, c0, c1, 7")
MAKE_INTR_SET_REG(1, setWcr1, "mcr p14, 0, %0, c0, c1, 7", "memory")
ALWAYS_INLINE u32 __getCpuId(void)
{
u32 cpuId;
@ -224,6 +277,22 @@ MAKE_INTR_SET_REG(1, setTtbcr, "mcr p15, 0, %0, c2, c0, 2", "memory")
MAKE_INTR_GET_REG(1, getDacr, "mrc p15, 0, %0, c3, c0, 0")
MAKE_INTR_SET_REG(1, setDacr, "mcr p15, 0, %0, c3, c0, 0", "memory")
// Data Fault Status Register
MAKE_INTR_GET_REG(1, getDfsr, "mrc p15, 0, %0, c5, c0, 0")
MAKE_INTR_SET_REG(1, setDfsr, "mcr p15, 0, %0, c5, c0, 0", "memory")
// Instruction Fault Status Register
MAKE_INTR_GET_REG(1, getIfsr, "mrc p15, 0, %0, c5, c0, 1")
MAKE_INTR_SET_REG(1, setIfsr, "mcr p15, 0, %0, c5, c0, 1", "memory")
// Fault Address Register
MAKE_INTR_GET_REG(1, getFar, "mrc p15, 0, %0, c6, c0, 0")
MAKE_INTR_SET_REG(1, setFar, "mcr p15, 0, %0, c6, c0, 0", "memory")
// Watchpoint Fault Address Register
MAKE_INTR_GET_REG(1, getWfar, "mrc p15, 0, %0, c6, c0, 1")
MAKE_INTR_SET_REG(1, setWfar, "mcr p15, 0, %0, c6, c0, 1", "memory")
// Flush Prefetch Buffer
// Data Synchronization Barrier
// Data Memory Barrier

View File

@ -22,9 +22,8 @@
noreturn void panic();
noreturn void panic(void);
noreturn void panicMsg(const char *msg);
//void debugMemdump(const char *filepath, void *mem, size_t size);
// Exception tests
/*static inline regTest(void)

View File

@ -4,6 +4,9 @@
extern const u32 _arm7_stub_start[];
extern const u32 _arm7_stub_swi[]; // Final ARM9 mem location.
extern const u32 _arm7_stub_size[];
noreturn void _a7_overlay_stub(void);
extern const u32 _a7_overlay_stub_size[];
noreturn void _a7_stub_start(void);
extern u16 _a7_stub9_swi[]; // Final ARM9 mem location.
extern const u32 _a7_stub_size[];

View File

@ -111,6 +111,7 @@ ALWAYS_INLINE u64 __##inst(u32 op1, u32 op2, u64 acc)
// Pack Halfword Bottom Top.
#define __pkhbt(op1, op2, sh) \
({ \
u32 __res; \
@ -118,6 +119,7 @@ ALWAYS_INLINE u64 __##inst(u32 op1, u32 op2, u64 acc)
__res; \
})
// Pack Halfword Top Bottom.
#define __pkhtb(op1, op2, sh) \
({ \
u32 __res, __sh = (sh); \

View File

@ -64,7 +64,7 @@ typedef enum
IPC_CMD9_BACKUP_GBA_SAVE = MAKE_CMD9(0, 0, 0),
// Miscellaneous API.
IPC_CMD9_PREPARE_POWER = MAKE_CMD9(0, 0, 0)
IPC_CMD9_PREPARE_POWER = MAKE_CMD9(0, 0, 0) // Also used for panic() and guruMeditation().
} IpcCmd9;
enum {_CMD11_C_BASE = __COUNTER__ + 1}; // Start at 0.

View File

@ -42,7 +42,7 @@ typedef struct
KRes switchContext(KRes res, void *oldSp, uintptr_t newSp);
KRes switchContext(KRes res, uintptr_t *oldSp, uintptr_t newSp);
#ifdef __cplusplus
}

View File

@ -54,7 +54,7 @@ switchContextAllRegs_end:
cpsie i
bx lr*/
@ KRes switchContext(KRes res, void *oldSp, uintptr_t newSp);
@ KRes switchContext(KRes res, uintptr_t *oldSp, uintptr_t newSp);
BEGIN_ASM_FUNC switchContext
stmfd sp!, {r4-r11, lr}
str sp, [r1]

View File

@ -195,6 +195,10 @@ bool waitQueueWakeN(ListNode *waitQueue, u32 wakeCount, KRes res, bool reschedul
static KRes scheduler(TaskState curTaskState)
{
#ifndef NDEBUG
if((__getCpsr() & PSR_MODE_MASK) != PSR_SYS_MODE) panic();
#endif
TaskCb *const curDeadTask = g_curDeadTask;
// TODO: Get rid of this and find a better way.
if(UNLIKELY(curDeadTask != NULL))

View File

@ -17,6 +17,7 @@
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "types.h"
#include "mem_map.h"
@ -24,7 +25,6 @@
#include "arm11/fmt.h"
#include "hardware/pxi.h"
#include "ipc_handler.h"
#include "hardware/gfx.h"
#include "arm11/hardware/interrupt.h"
#include "arm.h"
#include "arm11/hardware/mcu.h"
@ -32,20 +32,17 @@
noreturn void panic()
noreturn void panic(void)
{
enterCriticalSection();
consoleInit(SCREEN_BOT, NULL);
ee_printf("\x1b[41m\x1b[0J\x1b[15C****PANIC!!!****\n");
//PXI_sendPanicCmd(IPC_CMD9_PANIC);
PXI_sendPanicCmd(IPC_CMD9_PREPARE_POWER);
// Wait for A/B/X or Y
do
{
hidScanInput();
} while(!(hidKeysDown() & (KEY_A | KEY_B | KEY_X | KEY_Y)));
while(!(REG_HID_PAD & (KEY_A | KEY_B | KEY_X | KEY_Y)));
MCU_powerOffSys();
while(1) __wfi();
@ -59,32 +56,21 @@ noreturn void panicMsg(const char *msg)
ee_printf("\x1b[41m\x1b[0J\x1b[15C****PANIC!!!****\n\n");
ee_printf("\nERROR MESSAGE:\n%s\n", msg);
//PXI_sendPanicCmd(IPC_CMD9_PANIC);
PXI_sendPanicCmd(IPC_CMD9_PREPARE_POWER);
// Wait for A/B/X or Y
do
{
hidScanInput();
} while(!(hidKeysDown() & (KEY_A | KEY_B | KEY_X | KEY_Y)));
while(!(REG_HID_PAD & (KEY_A | KEY_B | KEY_X | KEY_Y)));
MCU_powerOffSys();
while(1) __wfi();
}
// Expects the registers in the exception stack to be in the following order:
// r0-r14, pc (unmodified), cpsr
// r0-r14, pc (unmodified), CPSR, DFSR, IFSR, FAR, WFAR
noreturn void guruMeditation(u8 type, const u32 *excStack)
{
const char *const typeStr[3] = {"Undefined instruction", "Prefetch abort", "Data abort"};
u32 realPc, instSize = 4;
//bool codeChanged = false;
// verify text and rodata
/*u32 prevHash = debugHash;
debugHashCodeRoData();
if(prevHash != debugHash)
codeChanged = true;*/
consoleInit(SCREEN_BOT, NULL);
@ -123,32 +109,72 @@ noreturn void guruMeditation(u8 type, const u32 *excStack)
}
}
//if(codeChanged) ee_printf("Attention: RO section data changed!!");
//PXI_sendPanicCmd(IPC_CMD9_EXCEPTION);
PXI_sendPanicCmd(IPC_CMD9_PREPARE_POWER);
// Wait for A/B/X or Y
do
{
hidScanInput();
} while(!(hidKeysDown() & (KEY_A | KEY_B | KEY_X | KEY_Y)));
while(!(REG_HID_PAD & (KEY_A | KEY_B | KEY_X | KEY_Y)));
MCU_powerOffSys();
while(1) __wfi();
}
/*void debugMemdump(const char *filepath, void *mem, size_t size)
#ifndef NDEBUG
// Needs to be marked as used to work with LTO.
// The used attribute also overrides the newlib symbol.
// This is for debugging purposes only. For security this value needs to be random!
__attribute__((used)) uintptr_t __stack_chk_guard = 0xC724B66D;
// Needs to be marked as noinline and used to work with LTO.
// The used attribute also overrides the newlib symbol.
// Combine -fstack-protector-all with -fno-inline to get the most effective detection.
__attribute__((noinline, used)) noreturn void __stack_chk_fail(void)
{
s32 file;
panicMsg("Stack smash!");
}
if((file = fOpen(filepath, FS_CREATE_ALWAYS | FS_OPEN_WRITE)) < 0)
{
return;
}
fWrite(file, mem, size);
fSync(file);
fClose(file);
}*/
// Add "-Wl,-wrap=malloc,-wrap=calloc,-wrap=free" to LDFLAGS to enable the heap check.
static const u32 __heap_chk_guard[4] = {0x9240A724, 0x6A6594A0, 0x976F0392, 0xB3A669AB};
void* __real_malloc(size_t size);
void __real_free(void *ptr);
void* __wrap_malloc(size_t size)
{
void *const buf = __real_malloc(size + 32);
if(buf == NULL) return NULL;
memcpy(buf, &size, sizeof(size_t));
memcpy(buf + sizeof(size_t), (u8*)__heap_chk_guard + sizeof(size_t), 16 - sizeof(size_t));
memcpy(buf + 16 + size, __heap_chk_guard, 16);
return buf + 16;
}
void* __wrap_calloc(size_t num, size_t size)
{
void *const buf = __wrap_malloc(num * size);
if(buf == NULL) return NULL;
memset(buf, 0, num * size);
return buf;
}
void __wrap_free(void *ptr)
{
if(ptr == NULL) return;
if(memcmp(ptr - (16 - sizeof(size_t)), (u8*)__heap_chk_guard + sizeof(size_t), 16 - sizeof(size_t)) != 0)
panicMsg("Heap underflow!");
size_t size;
memcpy(&size, ptr - 16, sizeof(size_t));
// Important! Adjust the size check if needed.
// 1024u * 512 is roughly ok for AXIWRAM.
if(size > (1024u * 512) || memcmp(ptr + size, __heap_chk_guard, 16) != 0)
panicMsg("Heap overflow!");
__real_free(ptr - 16);
}
#endif

View File

@ -36,7 +36,7 @@ EXCEPTION_ENTRY undefInstrHandler, 0<<29
EXCEPTION_ENTRY prefetchAbortHandler, 1<<29
EXCEPTION_ENTRY dataAbortHandler, 2<<29
BEGIN_ASM_FUNC exceptionHandler
sub sp, #68
sub sp, #84
stmia sp, {r0-r14}^ @ Save all user/system mode regs except pc
mrs r2, spsr @ Get saved cpsr
mrs r3, cpsr
@ -51,13 +51,21 @@ BEGIN_ASM_FUNC exceptionHandler
exceptionHandler_skip_other_mode:
str lr, [sp, #60] @ Save lr (pc) on exception stack
str r2, [sp, #64] @ Save spsr (cpsr) on exception stack
mrc p15, 0, r3, c5, c0, 0
str r3, [sp, #68] @ DFSR
mrc p15, 0, r3, c5, c0, 1
str r3, [sp, #72] @ IFSR
mrc p15, 0, r3, c6, c0, 0
str r3, [sp, #76] @ FAR
mrc p15, 0, r3, c6, c0, 1
str r3, [sp, #80] @ WFAR
mov r4, r0
mov r5, sp
bl deinitCpu
mov r0, r4
mov sp, r5
mov r1, r5
b guruMeditation @ r0 = exception type, r1 = reg dump ptr {r0-r14, pc (unmodified), cpsr}
b guruMeditation @ r0 = exception type, r1 = reg dump ptr {r0-r14, pc (unmodified), CPSR, DFSR, IFSR, FAR, WFAR}
END_ASM_FUNC

View File

@ -57,7 +57,6 @@ static u8 fmt2PixSize(GfxFbFmt fmt);
static void setupFramebufs(GfxFbFmt fmtTop, GfxFbFmt fmtBot);
static void deallocFramebufs(void);
static void setupDislayController(u8 lcd);
static void gfxIrqHandler(u32 intSource);
void GFX_init(GfxFbFmt fmtTop, GfxFbFmt fmtBot)
{

View File

@ -54,7 +54,7 @@ static u32 padRomArea(u32 romFileSize)
if(romSize < 0x100000u) romSize = 0x100000u;
memset((void*)(ROM_LOC + romFileSize), 0xFFFFFFFFu, romSize - romFileSize);
if((*(u32*)(ROM_LOC + 0xAC) & 0xFFu) != 'F')
if(romSize > 0x100000u)
{
// Fake "open bus" padding.
u32 padding = (ROM_LOC + romSize) / 2;
@ -62,13 +62,13 @@ static u32 padRomArea(u32 romFileSize)
for(uintptr_t i = ROM_LOC + romSize; i < ROM_LOC + MAX_ROM_SIZE; i += 4)
{
*(u32*)i = padding;
padding = __uadd16(padding, 0x00020002u); // 0xBA028B
padding = __uadd16(padding, 0x00020002u); // Unsigned parallel halfword-wise addition.
}
}
else
{
// Classic NES Series ROM mirroring.
// Mirror ROM area across the entire 32 MiB range.
// ROM mirroring (Classic NES Series/possibly others with 8 Mbit ROM).
// Mirror ROM across the entire 32 MiB area.
for(uintptr_t i = ROM_LOC + romSize; i < ROM_LOC + MAX_ROM_SIZE; i += romSize)
{
//memcpy((void*)i, (void*)(i - romSize), romSize); // 0x23A15DD
@ -398,39 +398,30 @@ static void adjustGammaTableForGba(void)
}
}
static void dumpFrameTex(void)
static Result dumpFrameTex(void)
{
// 512x-512 (hight negative to flip vertically).
alignas(4) static const u8 bmpHeader[122] =
// Pixels at offset 0x40.
alignas(4) static const u8 bmpHeader[54] =
{
0x42, 0x4D, 0x7A, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7A, 0x00,
0x00, 0x00, 0x6C, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0xFE,
0xFF, 0xFF, 0x01, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x0C, 0x00, 0x13, 0x0B, 0x00, 0x00, 0x13, 0x0B, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x47, 0x52, 0x73, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00
0x42, 0x4D, 0x40, 0x00, 0x0C, 0x00, 0x00, 0x00,
0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x28, 0x00,
0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0xFE,
0xFF, 0xFF, 0x01, 0x00, 0x18, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x13, 0x0B,
0x00, 0x00, 0x13, 0x0B, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
/*GX_displayTransfer((u32*)0x18200000, 160u<<16 | 256u, (u32*)0x18400000, 160u<<16 | 256u, 1u<<12 | 1u<<8);
GFX_waitForPPF();
//fsQuickWrite("sdmc:/lgyfb_dbg_frame.bgr", (void*)0x18400000, 256 * 160 * 3);*/
GX_displayTransfer((u32*)0x18200000, 240u<<16 | 512u, (u32*)0x18400000, 240u<<16 | 512u, 1u<<12 | 1u<<8);
GX_displayTransfer((u32*)0x18200000, 240u<<16 | 512u, (u32*)0x18400040, 240u<<16 | 512u, 1u<<12 | 1u<<8);
GFX_waitForPPF();
FHandle f;
if(fOpen(&f, "sdmc:/texture_dump.bmp", FA_CREATE_ALWAYS | FA_WRITE) == RES_OK)
{
fLseek(f, 0x0C007A);
fLseek(f, 0);
fWrite(f, bmpHeader, sizeof(bmpHeader), NULL);
fWrite(f, (void*)0x18400000, 512 * 512 * 3, NULL);
fClose(f);
}
memcpy((void*)0x18400000, bmpHeader, sizeof(bmpHeader));
return fsQuickWrite("sdmc:/texture_dump.bmp", (void*)0x18400000, 0x40 + 512 * 512 * 3);
}
static void gbaGfxHandler(void *args)

View File

@ -6,48 +6,55 @@
BEGIN_ASM_FUNC _a7_overlay_stub
mov r0, #1
mov r1, #0x4000000
strb r0, [r1, #0x300] @ "POSTFLG"
ldr pc, =0x3007E00
.pool
.global _a7_overlay_stub_size
_a7_overlay_stub_size = . - _a7_overlay_stub
END_ASM_FUNC
@ Must be located at 0x3007E00.
BEGIN_ASM_FUNC _arm7_stub_start
mov r0, #PSR_INT_OFF | PSR_SVC_MODE
adr r1, _arm7_stub_start + 0x200 @ 0x3008000
msr CPSR_cxsf, r0
@mov r0, #PSR_INT_OFF | PSR_IRQ_MODE
mov sp, r1
@msr CPSR_cxsf, r0
mov r0, #PSR_INT_OFF | PSR_SYS_MODE
@sub sp, r1, #0x60 @ 0x3007FA0
msr CPSR_cxsf, r0
BEGIN_ASM_FUNC _a7_stub_start
adr r1, _a7_stub_thumb + 1 @ 0x3007E1D
msr CPSR_fsxc, #PSR_INT_OFF | PSR_SVC_MODE
add sp, r1, #0x6B @ 0x3007E88
msr CPSR_fsxc, #PSR_INT_OFF | PSR_SYS_MODE
add sp, r1, #0x5B @ 0x3007E78
mov r3, #0x4700000
adr r2, _arm7_stub_16 + 1
sub sp, r1, #0x80 @ 0x3007F80
bx r2
bx r1
.thumb
_arm7_stub_16:
_a7_stub_thumb:
mov r0, #1
str r0, [r3] @ Disable BIOS overlay.
@ The original ARM7 stub waits 256 cycles here (for the BIOS overlay disable?).
@ The original ARM7 stub waits 1677800 cycles (100 ms) here for LCD/LgyFb sync.
@ The original ARM7 stub waits for REG_VCOUNT = 160 here.
lsl r3, r0, #26 @ 0x4000000
wait_vcount_160_lp:
ldrb r0, [r3, #6] @ REG_VCOUNT
cmp r0, #160 @ Wait for REG_VCOUNT == 160.
bne wait_vcount_160_lp
lsl r4, r0, #26 @ 0x4000000 Needed for "function" call 0xBC below.
mov r0, #0xFF @ Clear WRAM, iWRAM, palette RAM, VRAM, OAM
@ + reset SIO, sound and all other registers.
mov r4, r3 @ Needed for "function" call 0xBC below.
mov r0, #0xFF @ Clear WRAM, iWRAM, palette RAM, VRAM, OAM
@ + reset SIO, sound and all other registers.
.global _arm7_stub_swi
_arm7_stub_swi = . - _arm7_stub_start + 0x80BFE00 @ Final ARM9 mem location.
.global _a7_stub9_swi
_a7_stub9_swi = . - _a7_stub_start + 0x80BFE00 @ Final ARM9 mem location.
swi 0x01 @ RegisterRamReset
mov r0, #0xBC @ SoftReset (0xB4) but skipping r2 & r4 loading.
mov r2, #0
@ REG_VCOUNT should be 126 at ROM entry like after BIOS intro.
_a7_stub_vcount_lp:
ldrb r1, [r4, #6] @ REG_VCOUNT
cmp r1, #126 @ Loop until REG_VCOUNT == 126.
bne _a7_stub_vcount_lp
bx r0
.pool
.align 2
.global _arm7_stub_size
_arm7_stub_size = . - _arm7_stub_start
.global _a7_stub_size
_a7_stub_size = . - _a7_stub_start
END_ASM_FUNC

View File

@ -31,28 +31,15 @@ static char g_savePath[512] = {0};
#define STRINGIFY(s) #s
#define STR(s) STRINGIFY(s)
NAKED static void _overlay_stub(void)
{
__asm__("mov r0, #0x4000000\n\t"
"mov r1, #1\n\t"
"strb r1, [r0, #0x300]\n\t" // "POSTFLG"
"ldr pc, _overlay_stub_jmp\n\t"
"_overlay_stub_jmp: .4byte " STR(ARM7_STUB_LOC) "\n\t"
"_overlay_stub_size = . - _overlay_stub\n\t" : : : );
}
extern const u32 _overlay_stub_size[];
static void setupBiosOverlay(bool biosIntro)
{
iomemcpy(REGs_LGY_A7_VECTOR, (u32*)_overlay_stub, (u32)_overlay_stub_size);
iomemcpy(REGs_LGY_A7_VECTOR, (u32*)_a7_overlay_stub, (u32)_a7_overlay_stub_size);
//static const u32 biosVectors[8] = {0xEA000018, 0xEA000004, 0xEA00004C, 0xEA000002,
// 0xEA000001, 0xEA000000, 0xEA000042, 0xE59FD1A0};
//iomemcpy(REGs_LGY_A7_VECTOR, biosVectors, 32);
NDMA_copy((u32*)ARM7_STUB_LOC9, _arm7_stub_start, (u32)_arm7_stub_size);
if(biosIntro) *((vu8*)_arm7_stub_swi) = 0x26; // Patch swi 0x01 (RegisterRamReset) to swi 0x26 (HardReset).
NDMA_copy((u32*)ARM7_STUB_LOC9, (u32*)_a7_stub_start, (u32)_a7_stub_size);
if(biosIntro) *((vu8*)_a7_stub9_swi) = 0x26; // Patch swi 0x01 (RegisterRamReset) to swi 0x26 (HardReset).
}
static u32 setupSaveType(u16 saveType)

View File

@ -108,6 +108,7 @@ u32 IPC_handleCmd(u8 cmdId, u32 inBufs, u32 outBufs, const u32 *const buf)
// Miscellaneous API.
case IPC_CMD_ID_MASK(IPC_CMD9_PREPARE_POWER):
fsDeinit();
break;
default:
panic();

View File

@ -43,12 +43,7 @@ Result fsQuickWrite(const char *const path, const void *const buf, u32 size)
FHandle f;
if((res = fOpen(&f, path, FA_OPEN_ALWAYS | FA_WRITE)) == RES_OK)
{
if((res = fLseek(f, size)) == RES_OK && fTell(f) == size)
{
fLseek(f, 0);
res = fWrite(f, buf, size, NULL);
}
else if(res == RES_OK) res = RES_DISK_FULL; // Seek pre-allocation fail.
res = fWrite(f, buf, size, NULL);
fClose(f);
}