Skip to content

Commit 5f77811

Browse files
committed
B4DS: Add support for full version of *Digidrive* on retail consoles
1 parent 9ba8dcd commit 5f77811

8 files changed

Lines changed: 293 additions & 51 deletions

File tree

retail/arm9/include/blz.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#ifndef BLZ_DECOMPRESS_H
2+
#define BLZ_DECOMPRESS_H
3+
4+
#ifdef __cplusplus
5+
extern "C" {
6+
#endif
7+
u32 decompressLZ77Backwards(u8* addr, u32 size);
8+
9+
#ifdef __cplusplus
10+
}
11+
#endif
12+
#endif /* DECOMPRESS_H */

retail/arm9/source/blz.c

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
#include <nds/ndstypes.h>
2+
#include "tonccpy.h"
3+
4+
u32 decompressLZ77Backwards(u8* addr, u32 size) {
5+
u32 len = *(u32*)(addr + size - 4) + size;
6+
7+
if(len == size) {
8+
size -= 12;
9+
}
10+
11+
len = *(u32*)(addr + size - 4) + size;
12+
13+
u32 end = *(u32*)(addr + size - 8) & 0xFFFFFF;
14+
15+
u8* result = addr;
16+
17+
int Offs = (int)(size - (*(u32*)(addr + size - 8) >> 24));
18+
int dstoffs = (int)len;
19+
while (true) {
20+
u8 header = result[--Offs];
21+
for (int i = 0; i < 8; i++) {
22+
if ((header & 0x80) == 0) {
23+
toncset(result + (--dstoffs), result[--Offs], 1);
24+
} else {
25+
u8 a = result[--Offs];
26+
u8 b = result[--Offs];
27+
int offs = (((a & 0xF) << 8) | b) + 2;//+ 1;
28+
int length = (a >> 4) + 2;
29+
do {
30+
toncset(result + (dstoffs - 1), result[dstoffs + offs], 1);
31+
dstoffs--;
32+
length--;
33+
} while (length >= 0);
34+
}
35+
36+
if (Offs <= size - end) {
37+
return len;
38+
}
39+
40+
header <<= 1;
41+
}
42+
}
43+
44+
return len;
45+
}

retail/arm9/source/conf_sd.cpp

Lines changed: 137 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include <fat.h>
1919
#include <easysave/ini.hpp>
2020
#include "myDSiMode.h"
21+
#include "blz.h"
2122
#include "lzss.h"
2223
#include "lzx.h"
2324
#include "text.h"
@@ -107,6 +108,30 @@ off_t getFileSize(FILE* fp) {
107108
return fsize;
108109
}
109110

111+
void s2RamAccess(bool open) {
112+
if (io_dldi_data->ioInterface.features & FEATURE_SLOT_NDS) return;
113+
114+
const u16 s2FlashcardId = *(u16*)0x020000C0;
115+
116+
if (open) {
117+
if (s2FlashcardId == 0x334D) {
118+
_M3_changeMode(M3_MODE_RAM);
119+
} else if (s2FlashcardId == 0x3647) {
120+
_G6_SelectOperation(G6_MODE_RAM);
121+
} else if (s2FlashcardId == 0x4353) {
122+
_SC_changeMode(SC_MODE_RAM);
123+
}
124+
} else {
125+
if (s2FlashcardId == 0x334D) {
126+
_M3_changeMode(M3_MODE_MEDIA);
127+
} else if (s2FlashcardId == 0x3647) {
128+
_G6_SelectOperation(G6_MODE_MEDIA);
129+
} else if (s2FlashcardId == 0x4353) {
130+
_SC_changeMode(SC_MODE_MEDIA);
131+
}
132+
}
133+
}
134+
110135
char sdmcText[4] = {'s','d','m','c'};
111136

112137
void addTwlDevice(const char letter, u8 flags, u8 accessRights, const char* name, const char* path) {
@@ -713,6 +738,8 @@ int loadFromSD(configuration* conf, const char *bootstrapPath) {
713738
return -1;
714739
}
715740

741+
bool expansionPakFound = false;
742+
716743
if (*(u16*)0x02FFFC30 == 0) {
717744
sysSetCartOwner(BUS_OWNER_ARM9); // Allow arm9 to access GBA ROM
718745
if (*(u16*)(0x020000C0) != 0x334D && *(u16*)(0x020000C0) != 0x3647 && *(u16*)(0x020000C0) != 0x4353 && *(u16*)(0x020000C0) != 0x5A45) {
@@ -747,6 +774,7 @@ int loadFromSD(configuration* conf, const char *bootstrapPath) {
747774
if (*(vu16*)(0x08000000) != 0x4D54) {
748775
*(u16*)(0x020000C0) = 0;
749776
}
777+
sysSetCartOwner(BUS_OWNER_ARM7);
750778
} else if (io_dldi_data->ioInterface.features & FEATURE_SLOT_GBA) {
751779
if (memcmp(io_dldi_data->friendlyName, "M3 Adapter", 10) == 0) {
752780
*(u16*)(0x020000C0) = 0x334D;
@@ -762,6 +790,15 @@ int loadFromSD(configuration* conf, const char *bootstrapPath) {
762790
}
763791
}
764792
}
793+
expansionPakFound = (*(u16*)(0x020000C0) != 0);
794+
if (!expansionPakFound) {
795+
sysSetCartOwner(BUS_OWNER_ARM9);
796+
797+
*(vu16*)0x08240000 = 1;
798+
expansionPakFound = (*(vu16*)0x08240000 == 1);
799+
800+
sysSetCartOwner(BUS_OWNER_ARM7);
801+
}
765802
} else if (!conf->forceSleepPatch) {
766803
conf->forceSleepPatch = (
767804
(memcmp(io_dldi_data->friendlyName, "Ace3DS+", 7) == 0)
@@ -2133,7 +2170,7 @@ int loadFromSD(configuration* conf, const char *bootstrapPath) {
21332170

21342171
if (accessControl & BIT(4)) {
21352172
romFSInited = (romFSInit(conf->ndsPath));
2136-
startMultibootSrl = (strncmp(romTid, "KCX", 3) == 0 || (!b4dsDebugRam && strncmp(romTid, "KAV", 3) == 0) || strncmp(romTid, "KNK", 3) == 0);
2173+
startMultibootSrl = (strncmp(romTid, "KCX", 3) == 0 || strncmp(romTid, "KNK", 3) == 0);
21372174
}
21382175

21392176
const char* donorNdsPath = "";
@@ -2550,6 +2587,105 @@ int loadFromSD(configuration* conf, const char *bootstrapPath) {
25502587
}
25512588
fclose(sdatFile);
25522589
}
2590+
} else if (!b4dsDebugRam && expansionPakFound && (strncmp(romTid, "KAV", 3) == 0)) {
2591+
// Load overlay 1 for DIGIDRIVE + Sound data from multiboot SRL
2592+
sysSetCartOwner(BUS_OWNER_ARM9); // Allow arm9 to access GBA ROM
2593+
2594+
const u32 mepAddr = (*(u16*)0x020000C0 == 0x5A45) ? 0x08000000 : 0x09000000;
2595+
2596+
u32 overlayOffset = 0x021BC7A0;
2597+
u32 sdatOffsetMB = 0x11D040;
2598+
u32 sdatSizeMB = 0x87540;
2599+
u32 sdatSize = 0x44C2C0;
2600+
switch (romTid[3]) {
2601+
case 'V':
2602+
sdatSize = 0x44CD80;
2603+
break;
2604+
case 'J':
2605+
overlayOffset = 0x021BBB20;
2606+
sdatOffsetMB = 0x11CCC0;
2607+
sdatSizeMB = 0x7C2C0;
2608+
sdatSize = 0x44F880;
2609+
break;
2610+
}
2611+
u32 ndsArm9Size = 0;
2612+
u32 overlayStart = 0;
2613+
u32 overlayEnd = 0;
2614+
2615+
// Load ARM9 binary from multiboot SRL
2616+
FILE* ndsFile = fopen(multibootSrl, "rb");
2617+
2618+
fseek(ndsFile, 0x20, SEEK_SET);
2619+
fread(&ndsArm9BinOffset, sizeof(u32), 1, ndsFile);
2620+
fseek(ndsFile, 0x2C, SEEK_SET);
2621+
fread(&ndsArm9Size, sizeof(u32), 1, ndsFile);
2622+
2623+
fseek(ndsFile, ndsArm9BinOffset, SEEK_SET);
2624+
if (io_dldi_data->ioInterface.features & FEATURE_SLOT_GBA) {
2625+
u32 pos = 0;
2626+
u32 currentLen = ndsArm9Size;
2627+
while (currentLen > 0) {
2628+
const u16 readLen = currentLen > sizeof_lz77ImageBuffer ? sizeof_lz77ImageBuffer : currentLen;
2629+
s2RamAccess(false);
2630+
fread(lz77ImageBuffer, 1, readLen, ndsFile);
2631+
s2RamAccess(true);
2632+
tonccpy((u8*)mepAddr+pos, lz77ImageBuffer, readLen);
2633+
pos += readLen;
2634+
currentLen -= readLen;
2635+
}
2636+
s2RamAccess(false);
2637+
} else {
2638+
fread((void*)mepAddr, 1, ndsArm9Size, ndsFile);
2639+
}
2640+
2641+
fclose(ndsFile);
2642+
2643+
s2RamAccess(true);
2644+
decompressLZ77Backwards((u8*)mepAddr+0x4000, ndsArm9Size-0x4000);
2645+
tonccpy((u8*)overlayOffset+0x18E0, (u8*)mepAddr+sdatOffsetMB, sdatSizeMB); // Grab sound data from ARM9 binary
2646+
s2RamAccess(false);
2647+
2648+
// Load overlay
2649+
ndsFile = fopen(conf->ndsPath, "rb");
2650+
2651+
fseek(ndsFile, 0x48, SEEK_SET);
2652+
fread(&fatAddr, sizeof(u32), 1, ndsFile);
2653+
fseek(ndsFile, fatAddr+8, SEEK_SET);
2654+
fread(&overlayStart, sizeof(u32), 1, ndsFile);
2655+
fread(&overlayEnd, sizeof(u32), 1, ndsFile);
2656+
const u32 overlaySize = overlayEnd - overlayStart;
2657+
2658+
fseek(ndsFile, overlayStart, SEEK_SET);
2659+
if (io_dldi_data->ioInterface.features & FEATURE_SLOT_GBA) {
2660+
u32 pos = 0;
2661+
u32 currentLen = overlaySize;
2662+
while (currentLen > 0) {
2663+
const u16 readLen = currentLen > sizeof_lz77ImageBuffer ? sizeof_lz77ImageBuffer : currentLen;
2664+
s2RamAccess(false);
2665+
fread(lz77ImageBuffer, 1, readLen, ndsFile);
2666+
s2RamAccess(true);
2667+
tonccpy((u8*)mepAddr+pos, lz77ImageBuffer, readLen);
2668+
pos += readLen;
2669+
currentLen -= readLen;
2670+
}
2671+
s2RamAccess(false);
2672+
} else {
2673+
fread((void*)mepAddr, 1, overlaySize, ndsFile);
2674+
}
2675+
2676+
fclose(ndsFile);
2677+
2678+
s2RamAccess(true);
2679+
const u32 len = decompressLZ77Backwards((u8*)mepAddr, overlaySize);
2680+
tonccpy((u8*)overlayOffset, (u8*)mepAddr, 0x18E0); // Load the overlay, but skip it's sound data
2681+
tonccpy((u8*)overlayOffset+0x18E0+sdatSize, (u8*)mepAddr+0x18E0+sdatSize, len-(0x18E0+sdatSize)); // Overwrites a sample used in music (which will be disabled anyway)
2682+
s2RamAccess(false);
2683+
2684+
if (io_dldi_data->ioInterface.features & FEATURE_SLOT_NDS) {
2685+
sysSetCartOwner(BUS_OWNER_ARM7);
2686+
}
2687+
2688+
*(u32*)((romTid[3] == 'J') ? 0x021BBFD4 : 0x021BCC54) = 0xE8BD80F8; // ldmfd sp!, {r3-r7,pc} (Disable music)
25532689
} else if (!b4dsDebugRam && (strncmp(romTid, "KEG", 3) == 0)) {
25542690
// Convert stereo title intro music to mono in Electroplankton: Lumiloop
25552691
const u32 sdatSize = getFileSize("rom:/sound_data_hw.sdat");

retail/bootloader/source/arm7/dsi2ds_patches.c

Lines changed: 82 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -9572,48 +9572,91 @@ void patchDSiModeToDSMode(cardengineArm9* ce9, const tNDSHeader* ndsHeader) {
95729572

95739573
// Art Style: DIGIDRIVE (USA)
95749574
// Art Style: INTERSECT (Europe, Australia)
9575-
// Saving not supported due to code taking place in overlays
9575+
// Art Style: DIGIDRIVE (Japan)
95769576
// Requires 8MB of RAM
9577-
else if ((strcmp(romTid, "KAVE") == 0 || strcmp(romTid, "KAVV") == 0) && extendedMemory) {
9578-
doubleNopT(0x020931C0);
9579-
doubleNopT(0x020A8ECA);
9580-
doubleNopT(0x020AEAFA);
9581-
patchInitDSiWare(0x020A1018, heapEnd);
9582-
patchUserSettingsReadDSiWare(0x020A2810);
9583-
*(u32*)0x020A2838 = 0xE3A00000; // mov r0, #0
9584-
*(u32*)0x020A283C = 0xE12FFF1E; // bx lr
9585-
*(u32*)0x020A2844 = 0xE3A00000; // mov r0, #0
9586-
*(u32*)0x020A2848 = 0xE12FFF1E; // bx lr
9587-
9588-
*(u32*)0x020A4930 = 0xE12FFF1E; // bx lr
9589-
*(u32*)0x020A493C = 0xE12FFF1E; // bx lr
9590-
if (romTid[3] == 'E') {
9591-
*(u32*)0x0260C1F4 = 0xE12FFF1E; // bx lr
9592-
*(u32*)0x0260C258 = 0xE12FFF1E; // bx lr
9577+
else if (strncmp(romTid, "KAV", 3) == 0) {
9578+
if (!isJpn) {
9579+
// Part of .pck file
9580+
/* *(u16*)0x02019662 = 0x2001; // movs r0, #1 (dsiSaveGetArcSrc)
9581+
*(u16*)0x02019664 = nopT; // nop
9582+
setBLXThumb(0x0201967C, (u32)dsiSaveOpen);
9583+
setBLXThumb(0x02019688, (u32)dsiSaveCreate);
9584+
setBLXThumb(0x02019692, (u32)dsiSaveOpen);
9585+
setBLXThumb(0x020196A6, (u32)dsiSaveClose);
9586+
setBLXThumb(0x020196BC, (u32)dsiSaveWrite);
9587+
setBLXThumb(0x020196CA, (u32)dsiSaveClose);
9588+
doubleNopT(0x020196D4); // dsiSaveFlush
9589+
setBLXThumb(0x020196DA, (u32)dsiSaveClose);
9590+
setBLXThumb(0x020196FC, (u32)dsiSaveOpen);
9591+
setBLXThumb(0x02019716, (u32)dsiSaveRead);
9592+
setBLXThumb(0x02019724, (u32)dsiSaveClose);
9593+
setBLXThumb(0x0201972E, (u32)dsiSaveClose); */
9594+
9595+
doubleNopT(0x020931C0);
9596+
if (!extendedMemory) {
9597+
*(u16*)0x020947F4 = 0x4770; // bx lr (Overlay is already loaded before boot)
9598+
}
9599+
doubleNopT(0x020A8ECA);
9600+
doubleNopT(0x020AEAFA);
9601+
patchInitDSiWare(0x020A1018, heapEnd);
9602+
// *(u32*)0x020A1388 = *(u32*)0x020AD998;
9603+
if (!extendedMemory) {
9604+
*(u32*)0x020A1388 -= 0x400000;
9605+
}
9606+
patchUserSettingsReadDSiWare(0x020A2810);
9607+
*(u32*)0x020A2838 = 0xE3A00000; // mov r0, #0
9608+
*(u32*)0x020A283C = 0xE12FFF1E; // bx lr
9609+
*(u32*)0x020A2844 = 0xE3A00000; // mov r0, #0
9610+
*(u32*)0x020A2848 = 0xE12FFF1E; // bx lr
9611+
9612+
*(u32*)0x020A4930 = 0xE12FFF1E; // bx lr
9613+
*(u32*)0x020A493C = 0xE12FFF1E; // bx lr
9614+
if (isUsa) {
9615+
*(u32*)0x0260C1F4 = 0xE12FFF1E; // bx lr
9616+
*(u32*)0x0260C258 = 0xE12FFF1E; // bx lr
9617+
} else {
9618+
*(u32*)0x0260CCB4 = 0xE12FFF1E; // bx lr
9619+
*(u32*)0x0260CD18 = 0xE12FFF1E; // bx lr
9620+
}
95939621
} else {
9594-
*(u32*)0x0260CCB4 = 0xE12FFF1E; // bx lr
9595-
*(u32*)0x0260CD18 = 0xE12FFF1E; // bx lr
9596-
}
9597-
}
9622+
// Part of .pck file
9623+
/* *(u16*)0x0201965E = 0x2001; // movs r0, #1 (dsiSaveGetArcSrc)
9624+
*(u16*)0x02019660 = nopT; // nop
9625+
setBLXThumb(0x02019678, (u32)dsiSaveOpen);
9626+
setBLXThumb(0x02019684, (u32)dsiSaveCreate);
9627+
setBLXThumb(0x0201968E, (u32)dsiSaveOpen);
9628+
setBLXThumb(0x020196A2, (u32)dsiSaveClose);
9629+
setBLXThumb(0x020196B8, (u32)dsiSaveWrite);
9630+
setBLXThumb(0x020196C6, (u32)dsiSaveClose);
9631+
doubleNopT(0x020196D0); // dsiSaveFlush
9632+
setBLXThumb(0x020196D6, (u32)dsiSaveClose);
9633+
setBLXThumb(0x020196F8, (u32)dsiSaveOpen);
9634+
setBLXThumb(0x02019712, (u32)dsiSaveRead);
9635+
setBLXThumb(0x02019720, (u32)dsiSaveClose);
9636+
setBLXThumb(0x0201972A, (u32)dsiSaveClose); */
9637+
9638+
doubleNopT(0x02092EA0);
9639+
if (!extendedMemory) {
9640+
*(u16*)0x020944A4 = 0x4770; // bx lr (Overlay is already loaded before boot)
9641+
}
9642+
doubleNopT(0x020A8A76);
9643+
doubleNopT(0x020AE672);
9644+
patchInitDSiWare(0x020A0BE4, heapEnd);
9645+
// *(u32*)0x020A0F54 = *(u32*)0x020AD544;
9646+
if (!extendedMemory) {
9647+
*(u32*)0x020A0F54 -= 0x400000;
9648+
}
9649+
patchUserSettingsReadDSiWare(0x020A23DC);
9650+
*(u32*)0x020A2404 = 0xE3A00000; // mov r0, #0
9651+
*(u32*)0x020A2408 = 0xE12FFF1E; // bx lr
9652+
*(u32*)0x020A2410 = 0xE3A00000; // mov r0, #0
9653+
*(u32*)0x020A2414 = 0xE12FFF1E; // bx lr
95989654

9599-
// Art Style: DIGIDRIVE (Japan)
9600-
// Saving not supported due to code taking place in overlays
9601-
// Requires 8MB of RAM
9602-
else if (strcmp(romTid, "KAVJ") == 0 && extendedMemory) {
9603-
doubleNopT(0x02092EA0);
9604-
doubleNopT(0x020A8A76);
9605-
doubleNopT(0x020AE672);
9606-
patchInitDSiWare(0x020A0BE4, heapEnd);
9607-
patchUserSettingsReadDSiWare(0x020A23DC);
9608-
*(u32*)0x020A2404 = 0xE3A00000; // mov r0, #0
9609-
*(u32*)0x020A2408 = 0xE12FFF1E; // bx lr
9610-
*(u32*)0x020A2410 = 0xE3A00000; // mov r0, #0
9611-
*(u32*)0x020A2414 = 0xE12FFF1E; // bx lr
9612-
9613-
*(u32*)0x020A44EC = 0xE12FFF1E; // bx lr
9614-
*(u32*)0x020A44F8 = 0xE12FFF1E; // bx lr
9615-
*(u32*)0x0260EB34 = 0xE12FFF1E; // bx lr
9616-
*(u32*)0x0260EB98 = 0xE12FFF1E; // bx lr
9655+
*(u32*)0x020A44EC = 0xE12FFF1E; // bx lr
9656+
*(u32*)0x020A44F8 = 0xE12FFF1E; // bx lr
9657+
*(u32*)0x0260EB34 = 0xE12FFF1E; // bx lr
9658+
*(u32*)0x0260EB98 = 0xE12FFF1E; // bx lr
9659+
}
96179660
}
96189661

96199662
// Discolight (USA)

0 commit comments

Comments
 (0)