summaryrefslogtreecommitdiff
path: root/src/NdevExi2A
diff options
context:
space:
mode:
authorMax Roncace <me@caseif.net>2026-01-29 17:18:08 -0500
committerGitHub <noreply@github.com>2026-01-29 14:18:08 -0800
commit050ebb447137e7077903e208b41deccbf0ee23f6 (patch)
treec54e4676aca9283aa11628e714ce9cc18d6b304c /src/NdevExi2A
parentc161523338fedf22e206a1c85d2777b4e6f667d0 (diff)
Add missing TUs for Wii/Shield retail (+ filename cleanup) (#3072)
* Fix GCN_mem_alloc.c filename capitalization * Fix up TRK file names in Wii/Shield splits * Add string_TRK * Add cc_gdev * Add Shield-only wstring TUs * Implement NdevExi2A * Add missing JSystem TUs (more are still missing from ShieldD) * Clean up includes
Diffstat (limited to 'src/NdevExi2A')
-rw-r--r--src/NdevExi2A/DebuggerDriver.c174
-rw-r--r--src/NdevExi2A/exi2.c167
2 files changed, 341 insertions, 0 deletions
diff --git a/src/NdevExi2A/DebuggerDriver.c b/src/NdevExi2A/DebuggerDriver.c
new file mode 100644
index 0000000000..8bbc082f23
--- /dev/null
+++ b/src/NdevExi2A/DebuggerDriver.c
@@ -0,0 +1,174 @@
+#include "NdevExi2A/DebuggerDriver.h"
+
+#include "NdevExi2A/exi2.h"
+#include <dolphin/exi.h>
+#include <dolphin/os.h>
+
+static s32 __DBRecvDataSize;
+static u32 __DBRecvMail;
+
+static u8 EXIInputFlag;
+
+static MtrCallback __DBDbgCallback;
+static MtrCallback __DBMtrCallback;
+
+static u8 SendCount = 0x80;
+
+#define IS_TRUE(x) ((x) != FALSE)
+#define IS_FALSE(x) !IS_TRUE(x)
+#define ROUND_UP(x, align) (((x) + (align)-1) & (-(align)))
+
+void __DBMtrHandler(s32 param_0, OSContext* ctx) {
+ EXIInputFlag = 1;
+ if (__DBMtrCallback != (void*)NULL) {
+ __DBMtrCallback(0, ctx);
+ }
+}
+
+void __DBIntrHandler(s16 param_0, OSContext* ctx) {
+ *__PIRegs = 0x1000;
+ if (__DBDbgCallback != NULL) {
+ __DBDbgCallback(param_0, ctx);
+ }
+}
+
+void __DBCheckMailBox(void) {
+ u8 sp08;
+ u32 mail;
+ sp08 = __DBReadUSB_CSR();
+ if (!(sp08 & 0x8)) {
+ __DBReadMailbox(&mail);
+
+ if (ODEMUIsValidMail(mail)) {
+ __DBRecvMail = mail;
+ __DBRecvDataSize = ODEMUGetSize(mail);
+ EXIInputFlag = 1;
+ }
+ }
+}
+
+u8 __DBReadUSB_CSR() {
+ u8 result;
+ __DBEXIReadReg(0x34000000, &result, 1);
+ return result;
+}
+
+void DBInitComm(u8** a, MtrCallback callback) {
+ BOOL interrupts = OSDisableInterrupts();
+
+ //pEXIInputFlag = &EXIInputFlag;
+ *a = &EXIInputFlag;
+ __DBMtrCallback = callback;
+ __DBEXIInit();
+
+ OSRestoreInterrupts(interrupts);
+}
+
+void DBInitInterrupts(void) {
+ __OSMaskInterrupts(0x18000);
+ __OSMaskInterrupts(0x40);
+ __DBDbgCallback = &__DBMtrHandler;
+ __OSSetInterruptHandler(0x19, __DBIntrHandler);
+ __OSUnmaskInterrupts(0x40);
+}
+
+u32 DBQueryData(void) {
+ BOOL interrupts;
+ EXIInputFlag = 0;
+ if (__DBRecvDataSize == 0) {
+ interrupts = OSDisableInterrupts();
+ __DBCheckMailBox();
+ OSRestoreInterrupts(interrupts);
+ }
+ return __DBRecvDataSize;
+}
+
+BOOL DBRead(u32* buffer, s32 count) {
+ u32 v;
+ u32 interrupts = OSDisableInterrupts();
+ v = ODEMUGetPc2NngcOffset(__DBRecvMail) + 0x1000;
+
+ __DBRead(v, buffer, ROUND_UP(count, 4));
+
+ __DBRecvDataSize = 0;
+ EXIInputFlag = 0;
+
+ OSRestoreInterrupts(interrupts);
+
+ return 0;
+}
+
+BOOL DBWrite(void* src, u32 size) {
+ BOOL interrupts;
+ u32 v;
+ u32 mail;
+
+ interrupts = OSDisableInterrupts();
+
+ __DBWaitForSendMail();
+
+ SendCount++;
+ v = (SendCount & 0x1) ? 0x800 : 0;
+
+ while (!__DBWrite(v, src, ROUND_UP(size, 4)))
+ ;
+
+ __DBWaitForSendMail();
+
+ mail = ODEMUGenMailData(SendCount, size);
+ while (!__DBWriteMailbox(mail))
+ ;
+
+ __DBWaitForSendMail();
+
+ OSRestoreInterrupts(interrupts);
+
+ return 0;
+}
+
+void __DBWaitForSendMail() {
+ u8 busyFlag;
+ do {
+ busyFlag = __DBReadUSB_CSR();
+ } while (busyFlag & 0x4);
+}
+
+void DBOpen(void) {}
+
+void DBClose(void) {}
+
+static u32 ODEMUGetSize(u32 mail) {
+ return mail & 0x1FFF;
+}
+
+BOOL ODEMUIsValidMail(u32 mail) {
+ return (mail & 0x1F000000) == 0x1F000000;
+}
+
+u32 ODEMUGetPc2NngcOffset(u32 v) {
+ return ODEMUGetPage(v) & 0x1 ? 0x800 : 0;
+}
+
+u32 ODEMUGetPage(u32 v) {
+ return (v & 0xFF0000) >> 16;
+}
+
+u32 ODEMUGenMailData(u32 v, u32 size) {
+ return (0x1f000000 | ((v << 16) & 0xFF0000)) | (size & 0x1FFF);
+}
+
+void __DBReadMailbox(u32* out) {
+ __DBEXIReadReg(0x34000200, out, 4);
+}
+
+BOOL __DBRead(u32 param_0, void* dst, u32 count) {
+ return __DBEXIReadRam(((param_0 + 0xD10000) << 6) & 0x3FFFFF00, dst, count);
+}
+
+BOOL __DBWriteMailbox(u32 val) {
+ return __DBEXIWriteReg(0xB4000100, &val, 0x4);
+}
+
+BOOL __DBWrite(u32 param_0, void* dst, u32 count) {
+ return __DBEXIWriteRam((((param_0 + 0xD10000) << 6) & 0x3FFFFF00) | 0x80000000, dst, count);
+}
diff --git a/src/NdevExi2A/exi2.c b/src/NdevExi2A/exi2.c
new file mode 100644
index 0000000000..83035a0991
--- /dev/null
+++ b/src/NdevExi2A/exi2.c
@@ -0,0 +1,167 @@
+#include "NdevExi2A/exi2.h"
+
+#include <revolution/os.h>
+
+#define IS_TRUE(x) ((x) != FALSE)
+#define IS_FALSE(x) !IS_TRUE(x)
+#define ROUND_UP(x, align) (((x) + (align)-1) & (-(align)))
+
+BOOL __EXI2Select() {
+ u32 regs = __EXIRegs[10];
+ regs &= 0x405;
+ regs |= 0xC0;
+ __EXIRegs[10] = regs;
+ return TRUE;
+}
+
+BOOL __EXI2Deselect() {
+ u32 regs = __EXIRegs[10];
+ __EXIRegs[10] = regs & 0x405;
+ return TRUE;
+}
+
+BOOL __EXI2Sync() {
+ while (__EXIRegs[13] & 0x1) {
+ }
+ return TRUE;
+}
+
+BOOL __EXI2Imm(u32* param_0, int width, int param_2) {
+ int i1; // r31
+ int i2; // r30
+ u32 var_r29;
+ u8* var_r28;
+ u32 var_r25;
+
+ if (param_2 != 0) {
+ var_r29 = 0;
+ for (i1 = 0; i1 < width; i1++) {
+ var_r29 |= ((u8*)param_0)[i1] << ((3 - i1) << 3);
+ }
+ __EXIRegs[14] = var_r29;
+ }
+
+ __EXIRegs[13] = 0x1 | (param_2 << 2) | ((width - 1) << 4);
+ __EXI2Sync();
+
+ if (param_2 == 0) {
+ var_r28 = (u8*)param_0;
+ var_r25 = __EXIRegs[14];
+ for (i2 = 0; i2 < width; i2++) {
+ *var_r28 = var_r25 >> ((3 - i2) << 3);
+ var_r28++;
+ }
+ }
+
+ return 1;
+}
+
+void __DBEXIInit() {
+ u8 sp08;
+
+ __OSMaskInterrupts(0x18000);
+
+ while ((__EXIRegs[13] & 0x1) == 0x1) {
+ };
+
+ __EXIRegs[10] = 0;
+ sp08 = 0xD4;
+ __DBEXIWriteReg(0xB4000000, &sp08, 1);
+}
+
+BOOL __DBEXIReadReg(u32 param_0, void* dst, u32 param_2) {
+ int is_failed = FALSE;
+ u32 val = 0;
+
+ is_failed |= IS_FALSE(__EXI2Select());
+ is_failed |= IS_FALSE(__EXI2Imm(&param_0, 4, 1));
+ is_failed |= IS_FALSE(__EXI2Sync());
+ is_failed |= IS_FALSE(__EXI2Imm(&val, 4, 0));
+ is_failed |= IS_FALSE(__EXI2Sync());
+ is_failed |= IS_FALSE(__EXI2Deselect());
+
+ switch (param_2) {
+ case 1:
+ *(u8*)dst = val >> 24;
+ break;
+ case 2:
+ *(u16*)dst = (val >> 24) | ((val >> 8) & 0xff00);
+ break;
+ default:
+ *(u32*)dst = __EXISwap32(val);
+ break;
+ }
+ return IS_FALSE(is_failed);
+}
+
+BOOL __DBEXIWriteReg(u32 param_0, void* src, u32 width) {
+ int is_failed = FALSE;
+ u32 val;
+
+ switch (width) {
+ case 1:
+ val = (*(u8*)src & 0xFF) << 24;
+ break;
+ case 2:
+ val = ((*(u16*)src & 0xFF) << 24) | ((*(u16*)src & 0xff00) << 8);
+ break;
+ default:
+ val = __EXISwap32(*(u32*)src);
+ break;
+ }
+
+ is_failed |= IS_FALSE(__EXI2Select());
+ is_failed |= IS_FALSE(__EXI2Imm(&param_0, 4, 1));
+ is_failed |= IS_FALSE(__EXI2Sync());
+ is_failed |= IS_FALSE(__EXI2Imm(&val, 4, 1));
+ is_failed |= IS_FALSE(__EXI2Sync());
+ is_failed |= IS_FALSE(__EXI2Deselect());
+
+ return IS_FALSE(is_failed);
+}
+
+BOOL __DBEXIReadRam(u32 param_0, void* dst, int count) {
+ int is_failed = FALSE;
+ u32 cur_val;
+ u32* cursor = (u32*)dst;
+
+ is_failed |= IS_FALSE(__EXI2Select());
+ is_failed |= IS_FALSE(__EXI2Imm(&param_0, 4, 1));
+ is_failed |= IS_FALSE(__EXI2Sync());
+
+ while (count > 0) {
+ is_failed |= IS_FALSE(__EXI2Imm(&cur_val, 4, 0));
+ is_failed |= IS_FALSE(__EXI2Sync());
+ *cursor++ = cur_val;
+ count -= 4;
+ }
+
+ is_failed |= IS_FALSE(__EXI2Deselect());
+
+ return IS_FALSE(is_failed);
+}
+
+BOOL __DBEXIWriteRam(u32 param_0, void* src, int count) {
+ int is_failed = FALSE;
+ u32 cur_val;
+ u32* cursor = (u32*)src;
+
+ is_failed |= IS_FALSE(__EXI2Select());
+ is_failed |= IS_FALSE(__EXI2Imm(&param_0, 4, 1));
+ is_failed |= IS_FALSE(__EXI2Sync());
+
+ while (count > 0) {
+ cur_val = *cursor++;
+ is_failed |= IS_FALSE(__EXI2Imm(&cur_val, 4, 1));
+ is_failed |= IS_FALSE(__EXI2Sync());
+ count -= 4;
+ }
+
+ is_failed |= IS_FALSE(__EXI2Deselect());
+
+ return IS_FALSE(is_failed);
+}
+
+u32 __EXISwap32(u32 v) {
+ return (v >> 24) | ((v >> 8) & 0xFF00) | ((v << 8) & 0xFF0000) | ((v << 24) & 0xFF000000);
+}