diff options
| author | Max Roncace <me@caseif.net> | 2026-01-29 17:18:08 -0500 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-01-29 14:18:08 -0800 |
| commit | 050ebb447137e7077903e208b41deccbf0ee23f6 (patch) | |
| tree | c54e4676aca9283aa11628e714ce9cc18d6b304c /src/NdevExi2A | |
| parent | c161523338fedf22e206a1c85d2777b4e6f667d0 (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.c | 174 | ||||
| -rw-r--r-- | src/NdevExi2A/exi2.c | 167 |
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(¶m_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(¶m_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(¶m_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(¶m_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); +} |
