diff options
-rw-r--r-- | Makefile | 3 | ||||
-rw-r--r-- | include/config.h | 22 | ||||
-rw-r--r-- | include/gba/gba.h | 1 | ||||
-rwxr-xr-x | include/gba/isagbprint.h | 50 | ||||
-rw-r--r-- | include/global.h | 2 | ||||
-rw-r--r-- | ld_script.txt | 38 | ||||
-rw-r--r-- | src/engine/main.c | 12 | ||||
-rwxr-xr-x | src/libs/libisagbprn.c | 177 | ||||
-rw-r--r-- | sym_bss.txt | 1 |
9 files changed, 303 insertions, 3 deletions
@@ -64,6 +64,8 @@ LD_SCRIPT := $(BUILD_DIR)/ld_script.ld %src/libs/agb_flash_mx.o: CC1FLAGS := -O1 -mthumb-interwork %src/libs/m4a_2.o: CC1 := tools/agbcc/bin/old_agbcc %src/libs/m4a_4.o: CC1 := tools/agbcc/bin/old_agbcc +%src/libs/libisagbprn.o: CC1 := tools/agbcc/bin/old_agbcc +%src/libs/libisagbprn.o: CC1FLAGS := -mthumb-interwork #### Main Rules #### @@ -158,7 +160,6 @@ include override.mk %.lz: % ; $(GBAGFX) $< $@ $(GFX_OPTS) %.rl: % ; $(GBAGFX) $< $@ $(GFX_OPTS) - #### Sound Rules #### sound/direct_sound_samples/cry_%.bin: sound/direct_sound_samples/cry_%.aif diff --git a/include/config.h b/include/config.h index 6a77c4c74..796da359c 100644 --- a/include/config.h +++ b/include/config.h @@ -1,6 +1,28 @@ #ifndef GUARD_CONFIG_H #define GUARD_CONFIG_H +// In the Generation 3 games, Asserts were used in various debug builds. +// Ruby/Sapphire and Emerald do not have these asserts while Fire Red +// still has them in the ROM. This is because the developers forgot +// to define NDEBUG before release, however this has been changed as +// Ruby's actual debug build does not use the AGBPrint features. + +// To note, Ruby/Sapphire likely did not use AGBPrint. This is because +// the german debug ROM of Ruby did not have any uses of AGBPrint and +// the assert commands but instead a "crash" screen. This config exists +// for convenience for the user of pokeruby and NOT because it is +// authoritative. These additions are for user convenience based on +// officially recommended SDK practices for debugging and is therefore +// still in part authoritative. +#define NDEBUG + +// To enable print debugging, comment out "#define NDEBUG". This allows +// the various AGBPrint functions to be used. (See include/gba/isagbprint.h). +// Some emulators support a debug console window: uncomment NoCashGBAPrint() +// and NoCashGBAPrintf() in libisagbprn.c to use no$gba's own proprietary +// printing system. Use NoCashGBAPrint() and NoCashGBAPrintf() like you +// would normally use AGBPrint() and AGBPrintf(). + #ifndef REVISION #define REVISION 0 #endif diff --git a/include/gba/gba.h b/include/gba/gba.h index 42ae3cdde..349344031 100644 --- a/include/gba/gba.h +++ b/include/gba/gba.h @@ -7,5 +7,6 @@ #include "gba/multiboot.h" #include "gba/syscall.h" #include "gba/macro.h" +#include "gba/isagbprint.h" #endif // GUARD_GBA_GBA_H diff --git a/include/gba/isagbprint.h b/include/gba/isagbprint.h new file mode 100755 index 000000000..c5eb456c3 --- /dev/null +++ b/include/gba/isagbprint.h @@ -0,0 +1,50 @@ +#ifndef GUARD_GBA_ISAGBPRINT_H +#define GUARD_GBA_ISAGBPRINT_H + +#ifdef NDEBUG +#define AGBPrintInit() +#define AGBPutc(cChr) +#define AGBPrint(pBuf) +#define AGBPrintf(pBuf, ...) +#define AGBPrintFlush1Block() +#define AGBPrintFlush() +#define AGBAssert(pFile, nLine, pExpression, nStopProgram) +#else +void AGBPrintInit(void); +void AGBPutc(const char cChr); +void AGBPrint(const char *pBuf); +void AGBPrintf(const char *pBuf, ...); +void AGBPrintFlush1Block(void); +void AGBPrintFlush(void); +void AGBAssert(const char *pFile, int nLine, const char *pExpression, int nStopProgram); +#endif + +#undef AGB_ASSERT +#ifdef NDEBUG +#define AGB_ASSERT(exp) +#else +#define AGB_ASSERT(exp) (exp) ? ((void*)0) : AGBAssert(__FILE__, __LINE__, #exp, 1); +#endif + +#undef AGB_WARNING +#ifdef NDEBUG +#define AGB_WARNING(exp) +#else +#define AGB_WARNING(exp) (exp) ? ((void*)0) : AGBAssert(__FILE__, __LINE__, #exp, 0); +#endif + +// for matching purposes + +#ifdef NDEBUG +#define AGB_ASSERT_EX(exp, file, line) +#else +#define AGB_ASSERT_EX(exp, file, line) (exp) ? ((void*)0) : AGBAssert(file, line, #exp, 1); +#endif + +#ifdef NDEBUG +#define AGB_WARNING_EX(exp, file, line) +#else +#define AGB_WARNING_EX(exp, file, line) (exp) ? ((void*)0) : AGBAssert(file, line, #exp, 0); +#endif + +#endif // GUARD_GBA_ISAGBPRINT_H diff --git a/include/global.h b/include/global.h index eea1574b7..d0af4a4d1 100644 --- a/include/global.h +++ b/include/global.h @@ -1,8 +1,8 @@ #ifndef GUARD_GLOBAL_H #define GUARD_GLOBAL_H +#include "config.h" // we need to define config before gba headers as print stuff needs the functions nulled before defines. #include "gba/gba.h" -#include "config.h" // IDE support #if defined(__APPLE__) || defined(__CYGWIN__) diff --git a/ld_script.txt b/ld_script.txt index b668449e4..54aca5b2b 100644 --- a/ld_script.txt +++ b/ld_script.txt @@ -27,7 +27,8 @@ SECTIONS { /* COMMON starts at 0x3001760 */ <COMMON> - + tools/agbcc/lib/libc.a:sbrkr.o(COMMON); + end = .; . = 0x8000; } @@ -434,6 +435,38 @@ SECTIONS { tools/agbcc/lib/libc.a:memcpy.o(.text); tools/agbcc/lib/libc.a:memset.o(.text); tools/agbcc/lib/libc.a:strcmp.o(.text); + tools/agbcc/lib/libc.a:vfprintf.o(.text); + tools/agbcc/lib/libc.a:vsprintf.o(.text); + tools/agbcc/lib/libc.a:fvwrite.o(.text); + tools/agbcc/lib/libc.a:locale.o(.text); + tools/agbcc/lib/libc.a:findfp.o(.text); + tools/agbcc/lib/libc.a:fflush.o(.text); + tools/agbcc/lib/libc.a:wsetup.o(.text); + tools/agbcc/lib/libc.a:mbtowc_r.o(.text); + tools/agbcc/lib/libc.a:s_isinf.o(.text); + tools/agbcc/lib/libc.a:s_isnan.o(.text); + tools/agbcc/lib/libc.a:memchr.o(.text); + tools/agbcc/lib/libc.a:strlen.o(.text); + tools/agbcc/lib/libc.a:dtoa.o(.text); + tools/agbcc/lib/libc.a:memmove.o(.text); + tools/agbcc/lib/libc.a:stdio.o(.text); + tools/agbcc/lib/libc.a:mprec.o(.text); + tools/agbcc/lib/libc.a:mallocr.o(.text); + tools/agbcc/lib/libc.a:fwalk.o(.text); + tools/agbcc/lib/libc.a:freer.o(.text); + tools/agbcc/lib/libc.a:makebuf.o(.text); + tools/agbcc/lib/libc.a:readr.o(.text); + tools/agbcc/lib/libc.a:writer.o(.text); + tools/agbcc/lib/libc.a:lseekr.o(.text); + tools/agbcc/lib/libc.a:closer.o(.text); + tools/agbcc/lib/libc.a:callocr.o(.text); + tools/agbcc/lib/libc.a:sbrkr.o(.text); + tools/agbcc/lib/libc.a:mlock.o(.text); + tools/agbcc/lib/libc.a:fstatr.o(.text); + tools/agbcc/lib/libc.a:libcfunc.o(.text); + tools/agbcc/lib/libc.a:syscalls.o(.text); + tools/agbcc/lib/libc.a:errno.o(.text); + src/libs/libisagbprn.o(.text); } =0 .rodata : @@ -1038,6 +1071,9 @@ SECTIONS { src/libs/agb_flash_le.o(.rodata); src/libs/siirtc.o(.rodata); tools/agbcc/lib/libgcc.a:_udivdi3.o(.rodata); + tools/agbcc/lib/libc.a(.rodata); + tools/agbcc/lib/libc.a(.data); + src/libs/libisagbprn.o(.rodata); } =0 . = 0x8D00000; diff --git a/src/engine/main.c b/src/engine/main.c index 1bed4080b..54a443e80 100644 --- a/src/engine/main.c +++ b/src/engine/main.c @@ -83,6 +83,10 @@ static void WaitForVBlank(void); #define B_START_SELECT (B_BUTTON | START_BUTTON | SELECT_BUTTON) +#ifndef NDEBUG + #include <stdlib.h> // don't include if not needed. +#endif + void AgbMain() { RegisterRamReset(RESET_ALL); @@ -98,6 +102,14 @@ void AgbMain() gSoftResetDisabled = FALSE; +// In Fire Red, AGBPrintInit is called at this spot. For user convenience, I +// opt to initialize the print area here. It is up to the user where they choose +// to print stuff from, as anything else declared is NOT authoritative. +#ifndef NDEBUG + AGBPrintInit(); + __mb_cur_max = 1; // fix for AGBPrintf +#endif + if (gFlashMemoryPresent != TRUE) SetMainCallback2(NULL); diff --git a/src/libs/libisagbprn.c b/src/libs/libisagbprn.c new file mode 100755 index 000000000..e0e979e95 --- /dev/null +++ b/src/libs/libisagbprn.c @@ -0,0 +1,177 @@ +#include <stdarg.h> +#include <stdio.h> +#include "gba/gba.h" +#include "config.h" + +#define AGB_PRINT_FLUSH_ADDR 0x9FE209D +#define AGB_PRINT_STRUCT_ADDR 0x9FE20F8 +#define AGB_PRINT_PROTECT_ADDR 0x9FE2FFE +#define WSCNT_DATA (WAITCNT_PHI_OUT_16MHZ | WAITCNT_WS0_S_2 | WAITCNT_WS0_N_4) + +// originally for auto no$gba support, the string "no$gba" should be at this address, +// the user needs to read this string out as the memory viewer won't show it. +#define NOCASHGBAIDADDR 0x4FFFA00 +#define NOCASHGBAPRINTADDR1 0x4FFFA10 // automatically adds a newline after the string has finished +#define NOCASHGBAPRINTADDR2 0x4FFFA14 // does not automatically add the newline. by default, NOCASHGBAPRINTADDR2 is used. this is used to keep strings consistent between no$gba and VBA-RR, but a user can choose to forgo this. + +struct AGBPrintStruct +{ + u16 m_nRequest; + u16 m_nBank; + u16 m_nGet; + u16 m_nPut; +}; + +typedef void (*LPFN_PRINT_FLUSH)(void); + +#ifndef NDEBUG + +void AGBPrintFlush1Block(void); + +void AGBPrintInit(void) +{ + volatile struct AGBPrintStruct *pPrint = (struct AGBPrintStruct *)AGB_PRINT_STRUCT_ADDR; + u16 *pWSCNT = (u16 *)REG_ADDR_WAITCNT; + u16 *pProtect = (u16 *)AGB_PRINT_PROTECT_ADDR; + u16 nOldWSCNT = *pWSCNT; + *pWSCNT = WSCNT_DATA; + *pProtect = 0x20; + pPrint->m_nRequest = pPrint->m_nGet = pPrint->m_nPut = 0; + pPrint->m_nBank = 0xFD; + *pProtect = 0; + *pWSCNT = nOldWSCNT; +} + +static void AGBPutcInternal(const char cChr) +{ + volatile struct AGBPrintStruct *pPrint = (struct AGBPrintStruct *)AGB_PRINT_STRUCT_ADDR; + u16 *pPrintBuf = (u16 *)(0x8000000 + (pPrint->m_nBank << 16)); + u16 *pProtect = (u16 *)AGB_PRINT_PROTECT_ADDR; + u16 nData = pPrintBuf[pPrint->m_nPut / 2]; + *pProtect = 0x20; + nData = (pPrint->m_nPut & 1) ? (nData & 0xFF) | (cChr << 8) : (nData & 0xFF00) | cChr; + pPrintBuf[pPrint->m_nPut / 2] = nData; + pPrint->m_nPut++; + *pProtect = 0; +} + +void AGBPutc(const char cChr) +{ + u16 *pWSCNT = (u16 *)REG_ADDR_WAITCNT; + u16 nOldWSCNT = *pWSCNT; + volatile struct AGBPrintStruct *pPrint; + *pWSCNT = WSCNT_DATA; + AGBPutcInternal(cChr); + *pWSCNT = nOldWSCNT; + pPrint = (struct AGBPrintStruct *)AGB_PRINT_STRUCT_ADDR; + if (pPrint->m_nPut == ((pPrint->m_nGet - 1) & 0xFFFF)) + AGBPrintFlush1Block(); +} + +void AGBPrint(const char *pBuf) +{ + volatile struct AGBPrintStruct *pPrint = (struct AGBPrintStruct *)AGB_PRINT_STRUCT_ADDR; + u16 *pWSCNT = (u16 *)REG_ADDR_WAITCNT; + u16 nOldWSCNT = *pWSCNT; + *pWSCNT = WSCNT_DATA; + while (*pBuf) + { + AGBPutc(*pBuf); + pBuf++; + } + *pWSCNT = nOldWSCNT; +} + +void AGBPrintf(const char *pBuf, ...) +{ + char bufPrint[0x100]; + va_list vArgv; + va_start(vArgv, pBuf); + vsprintf(bufPrint, pBuf, vArgv); + va_end(vArgv); + AGBPrint(bufPrint); +} + +static void AGBPrintTransferDataInternal(u32 bAllData) +{ + LPFN_PRINT_FLUSH lpfnFuncFlush; + u16 *pIME; + u16 nIME; + u16 *pWSCNT; + u16 nOldWSCNT; + u16 *pProtect; + volatile struct AGBPrintStruct *pPrint; + + pProtect = (u16 *)AGB_PRINT_PROTECT_ADDR; + pPrint = (struct AGBPrintStruct *)AGB_PRINT_STRUCT_ADDR; + lpfnFuncFlush = (LPFN_PRINT_FLUSH)AGB_PRINT_FLUSH_ADDR; + pIME = (u16 *)REG_ADDR_IME; + nIME = *pIME; + pWSCNT = (u16 *)REG_ADDR_WAITCNT; + nOldWSCNT = *pWSCNT; + *pIME = nIME & ~1; + *pWSCNT = WSCNT_DATA; + + if (bAllData) + { + while (pPrint->m_nPut != pPrint->m_nGet) + { + *pProtect = 0x20; + lpfnFuncFlush(); + *pProtect = 0; + } + } + else if (pPrint->m_nPut != pPrint->m_nGet) + { + *pProtect = 0x20; + lpfnFuncFlush(); + *pProtect = 0; + } + + *pWSCNT = nOldWSCNT; + *pIME = nIME; +} + +void AGBPrintFlush1Block(void) +{ + AGBPrintTransferDataInternal(FALSE); +} + +void AGBPrintFlush(void) +{ + AGBPrintTransferDataInternal(TRUE); +} + +void AGBAssert(const char *pFile, int nLine, const char *pExpression, int nStopProgram) +{ + if (nStopProgram) + { + AGBPrintf("ASSERTION FAILED FILE=[%s] LINE=[%d] EXP=[%s] \n", pFile, nLine, pExpression); + AGBPrintFlush(); + asm(".hword 0xEFFF"); + } + else + { + AGBPrintf("WARING FILE=[%s] LINE=[%d] EXP=[%s] \n", pFile, nLine, pExpression); + } +} + +// no$gba print functions, uncomment to use +/* +void NoCashGBAPrint(const char *pBuf) +{ + *(volatile u32*)NOCASHGBAPRINTADDR2 = (u32)pBuf; +} + +void NoCashGBAPrintf(const char *pBuf, ...) +{ + char bufPrint[0x100]; + va_list vArgv; + va_start(vArgv, pBuf); + vsprintf(bufPrint, pBuf, vArgv); + va_end(vArgv); + NoCashGBAPrint(bufPrint); +} +*/ + +#endif diff --git a/sym_bss.txt b/sym_bss.txt index 531a700e9..6e95a609f 100644 --- a/sym_bss.txt +++ b/sym_bss.txt @@ -39,3 +39,4 @@ .include "src/libs/siirtc.o" .include "tools/agbcc/lib/libgcc.a:dp-bit.o" .include "tools/agbcc/lib/libgcc.a:fp-bit.o" + .include "tools/agbcc/lib/libc.a:syscalls.o" |