summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/libc.c173
-rwxr-xr-xsrc/libisagbprn.c177
2 files changed, 177 insertions, 173 deletions
diff --git a/src/libc.c b/src/libc.c
deleted file mode 100644
index 1f457957b..000000000
--- a/src/libc.c
+++ /dev/null
@@ -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;
-}
-
diff --git a/src/libisagbprn.c b/src/libisagbprn.c
new file mode 100755
index 000000000..e0e979e95
--- /dev/null
+++ b/src/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