summaryrefslogtreecommitdiff
path: root/src/agb_sram.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/agb_sram.c')
-rw-r--r--src/agb_sram.c89
1 files changed, 89 insertions, 0 deletions
diff --git a/src/agb_sram.c b/src/agb_sram.c
new file mode 100644
index 0000000..e58d5fa
--- /dev/null
+++ b/src/agb_sram.c
@@ -0,0 +1,89 @@
+#include "global.h"
+#include "agb_sram.h"
+
+static u16 verifySramFast_Work[80]; // buffer to hold code of VerifySramFast_Core
+static u16 readSramFast_Work[64]; // buffer to hold code of ReadSramFast_Core
+
+u32 (*VerifySramFast)(const u8 *src, u8 *dest, u32 size); // pointer to verifySramFast_Work
+void (*ReadSramFast)(const u8 *src, u8 *dest, u32 size); // pointer to readSramFast_Work
+
+void ReadSramFast_Core(const u8 *src, u8 *dest, u32 size)
+{
+ REG_WAITCNT = (REG_WAITCNT & ~3) | 3;
+ while (--size != -1)
+ *dest++ = *src++;
+}
+
+void WriteSramFast(const u8 *src, u8 *dest, u32 size)
+{
+ REG_WAITCNT = (REG_WAITCNT & ~3) | 3;
+ while (--size != -1)
+ *dest++ = *src++;
+}
+
+u32 VerifySramFast_Core(const u8 *src, u8 *dest, u32 size)
+{
+ REG_WAITCNT = (REG_WAITCNT & ~3) | 3;
+ while (--size != -1)
+ {
+ if (*dest++ != *src++)
+ return (u32)(dest - 1);
+ }
+ return 0;
+}
+
+void SetSramFastFunc(void)
+{
+ u16 *src;
+ u16 *dest;
+ u16 size;
+
+ src = (u16 *)ReadSramFast_Core;
+ // clear the least significant bit so that we get the actual start address of the function
+ src = (u16 *)((uintptr_t)src ^ 1); // NOTE: In Fire Emblem 8, this is '& ~1' instead of '^ 1'.
+ dest = readSramFast_Work;
+ // get the size of the function by subtracting the address of the next function
+ size = ((uintptr_t)WriteSramFast - (uintptr_t)ReadSramFast_Core) / 2;
+ // copy the function into the WRAM buffer
+ while (size != 0)
+ {
+ *dest++ = *src++;
+ size--;
+ }
+ // add 1 to the address of the buffer so that we stay in THUMB mode when bx-ing to the address
+ ReadSramFast = (void *)((uintptr_t)readSramFast_Work + 1);
+
+ src = (u16 *)VerifySramFast_Core;
+ // clear the least significant bit so that we get the actual start address of the function
+ src = (u16 *)((uintptr_t)src ^ 1); // NOTE: In Fire Emblem 8, this is '& ~1' instead of '^ 1'.
+ dest = verifySramFast_Work;
+ // get the size of the function by subtracting the address of the next function
+ size = ((uintptr_t)SetSramFastFunc - (uintptr_t)VerifySramFast_Core) / 2;
+ // copy the function into the WRAM buffer
+ while (size != 0)
+ {
+ *dest++ = *src++;
+ size--;
+ }
+ // add 1 to the address of the buffer so that we stay in THUMB mode when bx-ing to the address
+ VerifySramFast = (void *)((uintptr_t)verifySramFast_Work + 1);
+
+ REG_WAITCNT = (REG_WAITCNT & ~3) | 3;
+}
+
+u32 WriteAndVerifySramFast(const u8 *src, u8 *dest, u32 size)
+{
+ u8 i;
+ u32 errorAddr;
+
+ // try writing and verifying the data 3 times
+ for (i = 0; i < 3; i++)
+ {
+ WriteSramFast(src, dest, size);
+ errorAddr = VerifySramFast(src, dest, size);
+ if (errorAddr == 0)
+ break;
+ }
+
+ return errorAddr;
+}