summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile3
-rw-r--r--include/config.h22
-rw-r--r--include/gba/gba.h1
-rwxr-xr-xinclude/gba/isagbprint.h50
-rw-r--r--include/global.h2
-rw-r--r--ld_script.txt38
-rw-r--r--src/engine/main.c12
-rwxr-xr-xsrc/libs/libisagbprn.c177
-rw-r--r--sym_bss.txt1
9 files changed, 303 insertions, 3 deletions
diff --git a/Makefile b/Makefile
index bb5c1b563..8cbfd8245 100644
--- a/Makefile
+++ b/Makefile
@@ -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"