mirror of
https://github.com/Ninjdai1/pokeemerald.git
synced 2024-12-26 03:34:15 +01:00
Merge pull request #155 from ProjectRevoTPP/assert
add assert support to pokeemerald.
This commit is contained in:
commit
d1630d481a
4
Makefile
4
Makefile
@ -32,6 +32,8 @@ OBJCOPY := $(DEVKITARM)/bin/arm-none-eabi-objcopy
|
|||||||
|
|
||||||
LIBGCC := tools/agbcc/lib/libgcc.a
|
LIBGCC := tools/agbcc/lib/libgcc.a
|
||||||
|
|
||||||
|
LIBC := tools/agbcc/lib/libc.a
|
||||||
|
|
||||||
SHA1 := sha1sum -c
|
SHA1 := sha1sum -c
|
||||||
|
|
||||||
GFX := tools/gbagfx/gbagfx
|
GFX := tools/gbagfx/gbagfx
|
||||||
@ -160,7 +162,7 @@ $(OBJ_DIR)/ld_script.ld: ld_script.txt $(OBJ_DIR)/sym_bss.ld $(OBJ_DIR)/sym_comm
|
|||||||
cd $(OBJ_DIR) && sed -f ../../ld_script.sed ../../$< | sed "s#tools/#../../tools/#g" > ld_script.ld
|
cd $(OBJ_DIR) && sed -f ../../ld_script.sed ../../$< | sed "s#tools/#../../tools/#g" > ld_script.ld
|
||||||
|
|
||||||
$(ELF): $(OBJ_DIR)/ld_script.ld $(OBJS)
|
$(ELF): $(OBJ_DIR)/ld_script.ld $(OBJS)
|
||||||
cd $(OBJ_DIR) && $(LD) $(LDFLAGS) -T ld_script.ld -o ../../$@ $(OBJS_REL) ../../$(LIBGCC)
|
cd $(OBJ_DIR) && $(LD) $(LDFLAGS) -T ld_script.ld -o ../../$@ $(OBJS_REL) ../../$(LIBGCC) ../../$(LIBC)
|
||||||
|
|
||||||
$(ROM): $(ELF)
|
$(ROM): $(ELF)
|
||||||
$(OBJCOPY) -O binary --gap-fill 0xFF --pad-to 0x9000000 $< $@
|
$(OBJCOPY) -O binary --gap-fill 0xFF --pad-to 0x9000000 $< $@
|
||||||
|
@ -1,6 +1,23 @@
|
|||||||
#ifndef GUARD_CONFIG_H
|
#ifndef GUARD_CONFIG_H
|
||||||
#define 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.
|
||||||
|
#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().
|
||||||
|
|
||||||
|
// NOTE: Don't try to enable assert right now as many pointers
|
||||||
|
// still exist in defines and WILL likely result in a broken ROM.
|
||||||
|
|
||||||
#define ENGLISH
|
#define ENGLISH
|
||||||
|
|
||||||
#ifdef ENGLISH
|
#ifdef ENGLISH
|
||||||
|
@ -7,5 +7,6 @@
|
|||||||
#include "gba/multiboot.h"
|
#include "gba/multiboot.h"
|
||||||
#include "gba/syscall.h"
|
#include "gba/syscall.h"
|
||||||
#include "gba/macro.h"
|
#include "gba/macro.h"
|
||||||
|
#include "gba/isagbprint.h"
|
||||||
|
|
||||||
#endif // GUARD_GBA_GBA_H
|
#endif // GUARD_GBA_GBA_H
|
||||||
|
50
include/gba/isagbprint.h
Executable file
50
include/gba/isagbprint.h
Executable file
@ -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
|
@ -1,8 +1,8 @@
|
|||||||
#ifndef GUARD_GLOBAL_H
|
#ifndef GUARD_GLOBAL_H
|
||||||
#define 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 "gba/gba.h"
|
||||||
#include "config.h"
|
|
||||||
|
|
||||||
// Prevent cross-jump optimization.
|
// Prevent cross-jump optimization.
|
||||||
#define BLOCK_CROSS_JUMP asm("");
|
#define BLOCK_CROSS_JUMP asm("");
|
||||||
|
@ -31,7 +31,8 @@ SECTIONS {
|
|||||||
|
|
||||||
/* COMMON starts at 0x30022A8 */
|
/* COMMON starts at 0x30022A8 */
|
||||||
<COMMON>
|
<COMMON>
|
||||||
|
tools/agbcc/lib/libc.a:sbrkr.o(COMMON);
|
||||||
|
end = .;
|
||||||
. = 0x8000;
|
. = 0x8000;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -325,7 +326,42 @@ SECTIONS {
|
|||||||
tools/agbcc/lib/libgcc.a:fp-bit.o(.text);
|
tools/agbcc/lib/libgcc.a:fp-bit.o(.text);
|
||||||
tools/agbcc/lib/libgcc.a:_lshrdi3.o(.text);
|
tools/agbcc/lib/libgcc.a:_lshrdi3.o(.text);
|
||||||
tools/agbcc/lib/libgcc.a:_negdi2.o(.text);
|
tools/agbcc/lib/libgcc.a:_negdi2.o(.text);
|
||||||
src/libc.o(.text);
|
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:strcpy.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/libisagbprn.o(.text);
|
||||||
} =0
|
} =0
|
||||||
|
|
||||||
.rodata :
|
.rodata :
|
||||||
@ -1059,6 +1095,10 @@ SECTIONS {
|
|||||||
data/librfu_rodata.o(.rodata);
|
data/librfu_rodata.o(.rodata);
|
||||||
tools/agbcc/lib/libgcc.a:_divdi3.o(.rodata);
|
tools/agbcc/lib/libgcc.a:_divdi3.o(.rodata);
|
||||||
tools/agbcc/lib/libgcc.a:_udivdi3.o(.rodata);
|
tools/agbcc/lib/libgcc.a:_udivdi3.o(.rodata);
|
||||||
|
tools/agbcc/lib/libc.a(.rodata);
|
||||||
|
tools/agbcc/lib/libc.a(.data);
|
||||||
|
tools/agbcc/lib/libc.a:syscalls.o(.rodata);
|
||||||
|
src/libisagbprn.o(.rodata);
|
||||||
} =0
|
} =0
|
||||||
|
|
||||||
other_data :
|
other_data :
|
||||||
|
173
src/libc.c
173
src/libc.c
@ -1,173 +0,0 @@
|
|||||||
#include "global.h"
|
|
||||||
#include <stddef.h>
|
|
||||||
|
|
||||||
#define LBLOCKSIZE (sizeof(long))
|
|
||||||
|
|
||||||
// Nonzero if (long)X contains a NULL byte.
|
|
||||||
#define CONTAINSNULL(X) (((X) - 0x01010101) & ~(X) & 0x80808080)
|
|
||||||
|
|
||||||
// Nonzero if X is not aligned on a "long" boundary.
|
|
||||||
#define UNALIGNED(X) ((long)X & (LBLOCKSIZE - 1))
|
|
||||||
|
|
||||||
void *memcpy(void *dst0, const void *src0, size_t len0)
|
|
||||||
{
|
|
||||||
char *dst = dst0;
|
|
||||||
const char *src = src0;
|
|
||||||
long *aligned_dst;
|
|
||||||
const long *aligned_src;
|
|
||||||
unsigned int len = len0;
|
|
||||||
|
|
||||||
// If the size is small, or either src or dst is unaligned,
|
|
||||||
// then go to the byte copy loop. This should be rare.
|
|
||||||
if(len >= 16 && !(UNALIGNED(src) | UNALIGNED(dst)))
|
|
||||||
{
|
|
||||||
aligned_dst = (long *)dst;
|
|
||||||
aligned_src = (long *)src;
|
|
||||||
|
|
||||||
// Copy 4X long words at a time if possible.
|
|
||||||
while(len >= 16)
|
|
||||||
{
|
|
||||||
*aligned_dst++ = *aligned_src++;
|
|
||||||
*aligned_dst++ = *aligned_src++;
|
|
||||||
*aligned_dst++ = *aligned_src++;
|
|
||||||
*aligned_dst++ = *aligned_src++;
|
|
||||||
len -= 16;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Copy one long word at a time if possible
|
|
||||||
while(len >= 4)
|
|
||||||
{
|
|
||||||
*aligned_dst++ = *aligned_src++;
|
|
||||||
len -= 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
dst = (char *)aligned_dst;
|
|
||||||
src = (char *)aligned_src;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Pick up any remaining bytes with a byte copier.
|
|
||||||
while(len--)
|
|
||||||
*dst++ = *src++;
|
|
||||||
|
|
||||||
return dst0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void *memset(void *m, int c, size_t n)
|
|
||||||
{
|
|
||||||
char *s = (char *)m;
|
|
||||||
int count, i;
|
|
||||||
unsigned long buffer;
|
|
||||||
unsigned long *aligned_addr;
|
|
||||||
unsigned char *unaligned_addr;
|
|
||||||
|
|
||||||
// If the size is small or m is unaligned,
|
|
||||||
// then go to the byte copy loop. This should be rare.
|
|
||||||
if(n >= LBLOCKSIZE && !UNALIGNED(m))
|
|
||||||
{
|
|
||||||
// We know that n is large and m is word-aligned.
|
|
||||||
aligned_addr = (unsigned long *)m;
|
|
||||||
|
|
||||||
// Store C into each char sized location in buffer so that
|
|
||||||
// we can set large blocks quickly.
|
|
||||||
c &= 0xFF;
|
|
||||||
if(LBLOCKSIZE == 4)
|
|
||||||
{
|
|
||||||
buffer = (c << 8) | c;
|
|
||||||
buffer |= (buffer << 16);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
buffer = 0;
|
|
||||||
for(i = 0; i < LBLOCKSIZE; i++)
|
|
||||||
buffer = (buffer << 8) | c;
|
|
||||||
}
|
|
||||||
|
|
||||||
while(n >= LBLOCKSIZE * 4)
|
|
||||||
{
|
|
||||||
*aligned_addr++ = buffer;
|
|
||||||
*aligned_addr++ = buffer;
|
|
||||||
*aligned_addr++ = buffer;
|
|
||||||
*aligned_addr++ = buffer;
|
|
||||||
n -= LBLOCKSIZE * 4;
|
|
||||||
}
|
|
||||||
while(n >= LBLOCKSIZE)
|
|
||||||
{
|
|
||||||
*aligned_addr++ = buffer;
|
|
||||||
n -= LBLOCKSIZE;
|
|
||||||
}
|
|
||||||
|
|
||||||
s = (char *)aligned_addr;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Pick up the remainder with a bytewise loop.
|
|
||||||
while(n--)
|
|
||||||
*s++ = (char)c;
|
|
||||||
|
|
||||||
return m;
|
|
||||||
}
|
|
||||||
|
|
||||||
int strcmp(const char *s1, const char *s2)
|
|
||||||
{
|
|
||||||
unsigned long *a1;
|
|
||||||
unsigned long *a2;
|
|
||||||
|
|
||||||
// If s1 or s2 are unaligned, then skip this and compare bytes.
|
|
||||||
if(!(UNALIGNED(s1) | UNALIGNED(s2)))
|
|
||||||
{
|
|
||||||
// Compare them a word at a time.
|
|
||||||
a1 = (unsigned long *)s1;
|
|
||||||
a2 = (unsigned long *)s2;
|
|
||||||
while(*a1 == *a2)
|
|
||||||
{
|
|
||||||
// If *a1 == *a2, and we find a null in *a1,
|
|
||||||
// then the strings must be equal, so return zero.
|
|
||||||
if(CONTAINSNULL(*a1))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
a1++;
|
|
||||||
a2++;
|
|
||||||
}
|
|
||||||
|
|
||||||
s1 = (char *)a1;
|
|
||||||
s2 = (char *)a2;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check the remaining few bytes.
|
|
||||||
while(*s1 != '\0' && *s1 == *s2)
|
|
||||||
{
|
|
||||||
s1++;
|
|
||||||
s2++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (*(unsigned char *) s1) - (*(unsigned char *) s2);
|
|
||||||
}
|
|
||||||
|
|
||||||
char* strcpy(char *dst0, const char *src0)
|
|
||||||
{
|
|
||||||
char *dst = dst0;
|
|
||||||
const char *src = src0;
|
|
||||||
unsigned long *a1;
|
|
||||||
const unsigned long *a2;
|
|
||||||
|
|
||||||
// If SRC or DEST is unaligned, then copy bytes.
|
|
||||||
if(!(UNALIGNED(src) | UNALIGNED(dst)))
|
|
||||||
{
|
|
||||||
// SRC and DEST are both "long int" aligned, try to do "long int"
|
|
||||||
// sized copies.
|
|
||||||
a1 = (unsigned long *)dst;
|
|
||||||
a2 = (unsigned long *)src;
|
|
||||||
while(!CONTAINSNULL(*a2))
|
|
||||||
{
|
|
||||||
*a1++ = *a2++;
|
|
||||||
}
|
|
||||||
|
|
||||||
dst = (char *)a1;
|
|
||||||
src = (char *)a2;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Copy the remaining few bytes.
|
|
||||||
while(*dst++ = *src++);
|
|
||||||
|
|
||||||
return dst0;
|
|
||||||
}
|
|
||||||
|
|
177
src/libisagbprn.c
Executable file
177
src/libisagbprn.c
Executable file
@ -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
|
@ -198,3 +198,4 @@ gUnknown_03001300: @ 3001300
|
|||||||
.include "src/siirtc.o"
|
.include "src/siirtc.o"
|
||||||
.include "tools/agbcc/lib/libgcc.a:dp-bit.o"
|
.include "tools/agbcc/lib/libgcc.a:dp-bit.o"
|
||||||
.include "tools/agbcc/lib/libgcc.a:fp-bit.o"
|
.include "tools/agbcc/lib/libgcc.a:fp-bit.o"
|
||||||
|
.include "tools/agbcc/lib/libc.a:syscalls.o"
|
||||||
|
Loading…
Reference in New Issue
Block a user