summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPikalaxALT <PikalaxALT@users.noreply.github.com>2019-08-14 11:14:16 -0400
committerGitHub <noreply@github.com>2019-08-14 11:14:16 -0400
commita4ba98bed820f6cb0cd19007764e9626f25a2aa8 (patch)
tree0fc4ae85748a2322c49dfa3271bf7ad8f5210047 /src
parentd75a62af27b3cc472fdbd8facca146f2744d2572 (diff)
parentfbd4bbc146d4ed35e2d016b5845408a1f3e2d99a (diff)
Merge pull request #7 from Kermalis/master
Some save.c functions + add libisagbprn
Diffstat (limited to 'src')
-rw-r--r--src/libisagbprn.c177
-rw-r--r--src/save.c211
2 files changed, 386 insertions, 2 deletions
diff --git a/src/libisagbprn.c b/src/libisagbprn.c
new file mode 100644
index 0000000..e0e979e
--- /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
diff --git a/src/save.c b/src/save.c
index 5d39bfe..6478c12 100644
--- a/src/save.c
+++ b/src/save.c
@@ -1,10 +1,55 @@
#include "global.h"
+#include "flash.h"
+#include "memory.h"
+struct UnkStruct_203B184 {
+ u8 fill000[0x4C];
+ u8 *unk04C;
+ u32 unk050;
+ u32 unk054;
+ u32 unk058;
+};
+
+struct UnkStruct_sub_8011DAC {
+ u8 fill000[0x4];
+ u8 unk004[0x400];
+ u8 fill404[0x10];
+ u32 unk414;
+ u32 unk418;
+ u32 unk41C;
+ u32 unk420;
+ u32 unk424;
+ u32 unk428;
+ u8 fill42C[0x4];
+ u32 unk430;
+ u32 unk434;
+ u32 unk438;
+ u32 unk43C;
+ u32 unk440;
+ u32 unk444;
+ u8 fill448[0x538C];
+};
+
+extern u32 gUnknown_202DE28;
extern u32 gUnknown_203B17C;
extern u32 gUnknown_203B180;
-extern u32 *gUnknown_203B184;
-extern u32 gUnknown_202DE28;
+extern volatile struct UnkStruct_203B184 *gUnknown_203B184;
+extern void* MemoryAlloc(u32 a, u32 b);
+extern void MemoryFree(void* a);
+extern void SetRngState(s32 state);
+extern bool8 sub_8002718(u8 *a);
+extern bool8 sub_800DAB0(u16, u8*, s32);
+extern bool8 sub_800DAB4(u16, u8*, s32);
+extern bool8 sub_800DAB8(void);
+extern u32 sub_808EE9C(void* a, s32 b);
+extern u32 sub_808F2B0(void* a, s32 b);
+extern u32 sub_8091D14(void* a, s32 b);
+extern u32 sub_809222C(void* a, s32 b);
+extern u32 sub_80927F4(void* a, s32 b);
+extern u32 sub_80954CC(void* a, s32 b);
+extern u32 sub_8096FA0(void* a, s32 b);
+extern u32 sub_8097D98(void* a, s32 b);
u32 sub_8011C1C(void)
{
@@ -62,3 +107,165 @@ bool8 ValidateChecksum(u8 *in, u32 size)
return TRUE;
return FALSE;
}
+
+void sub_8011CA8(u32 *out, s32 size)
+{
+ if (gUnknown_203B184 == NULL) {
+ AGB_WARNING("A warning most likely went here.");
+ *out += (size + 0xFFF) / 0x1000;
+ } else {
+ *out += (size + 0xFFF) / 0x1000;
+ }
+}
+
+u32 WriteSaveSector(s32 *a, u8 *src, s32 size)
+{
+ u32 r1;
+ s32 r6 = *a;
+ sub_8011CA8(a, size);
+ CalculateChecksum(src, size);
+ if (gUnknown_203B184 == NULL) {
+ r1 = WriteFlashData(r6, src, size);
+ }
+ else if (sub_800DAB8()) {
+ if (!sub_800DAB4(r6, src, size)) {
+ r1 = 3;
+ }
+ else {
+ r1 = 0;
+ }
+ }
+ else {
+ return 2;
+ }
+ if (r1 == 4) {
+ return 1;
+ }
+ if (r1) {
+ return 2;
+ }
+ return 0;
+}
+
+u32 ReadSaveSector(s32 *a, u8 *dest, s32 size)
+{
+ u32 r1;
+ s32 r6 = *a;
+ sub_8011CA8(a, size);
+ if (gUnknown_203B184 == NULL) {
+ r1 = ReadFlashData(r6, dest, size);
+ }
+ else if (sub_800DAB8()) {
+ if (!sub_800DAB0(r6, dest, size)) {
+ r1 = 1;
+ }
+ else {
+ r1 = 0;
+ }
+ }
+ else {
+ return 1;
+ }
+ if (r1) {
+ return 1;
+ }
+ if (ValidateChecksum(dest, size)) {
+ return 2;
+ }
+ return 0;
+}
+
+bool8 sub_8011DA8(void)
+{
+ return TRUE;
+}
+
+u32 sub_8011DAC(u32 *a)
+{
+ struct UnkStruct_sub_8011DAC *r5 = MemoryAlloc(sizeof(struct UnkStruct_sub_8011DAC), 5);
+ u8 *r4 = (u8*)r5->fill448;
+ u32 r7 = ReadSaveSector(a, (u8*)r5, sizeof(struct UnkStruct_sub_8011DAC));
+ u32 r1;
+ if (r7)
+ {
+ r7 = ReadSaveSector(a, (u8*)r5, sizeof(struct UnkStruct_sub_8011DAC));
+ }
+ else
+ {
+ sub_8011CA8(a, sizeof(struct UnkStruct_sub_8011DAC));
+ }
+ if (!r7)
+ {
+ if (r5->unk414 != 0x5071412) {
+ r7 = 4;
+ }
+ }
+ if (!r7)
+ {
+ if (gUnknown_203B184 == NULL) {
+ sub_8011C28(r5->unk41C);
+ sub_8011C40(r5->unk418);
+ SetRngState(r5->unk420);
+ }
+ else {
+ gUnknown_203B184->unk054 = r5->unk41C;
+ gUnknown_203B184->unk050 = r5->unk418;
+ gUnknown_203B184->unk058 = r5->unk420;
+ }
+ }
+ if (!r7)
+ {
+ if (gUnknown_203B184 == NULL) {
+ if (!sub_8002718(r5->unk004)) {
+ r7 = 4;
+ }
+ }
+ else {
+ MemoryCopy8(gUnknown_203B184->unk04C, r5->unk004, ARRAY_COUNT(r5->unk004));
+ }
+ }
+ if (!r7)
+ {
+ r1 = sub_808EE9C(r4, 0x4650);
+ if (r1 != r5->unk424) {
+ r7 = 3;
+ }
+ r4 += 0x4650;
+ r1 = sub_808F2B0(r4, 0x258);
+ if (r1 != r5->unk428) {
+ r7 = 3;
+ }
+ r4 += 0x258;
+ r1 = sub_8091D14(r4, 0x1D8);
+ if (r1 != r5->unk430) {
+ r7 = 3;
+ }
+ r4 += 0x1d8;
+ r1 = sub_809222C(r4, 0x10);
+ if (r1 != r5->unk434) {
+ r7 = 3;
+ }
+ r4 += 0x10;
+ r1 = sub_80927F4(r4, 0x8);
+ if (r1 != r5->unk438) {
+ r7 = 3;
+ }
+ r4 += 0x8;
+ r1 = sub_8097D98(r4, 0x100);
+ if (r1 != r5->unk43C) {
+ r7 = 3;
+ }
+ r4 += 0x100;
+ r1 = sub_80954CC(r4, 0x594);
+ if (r1 != r5->unk440) {
+ r7 = 3;
+ }
+ r4 += 0x594;
+ r1 = sub_8096FA0(r4, 0x221);
+ if (r1 != r5->unk444) {
+ r7 = 3;
+ }
+ }
+ MemoryFree(r5);
+ return r7;
+}