Yeah sadly PSRAM is read only while in Game Mode. You have to use kernel mode to write to PSRAM and that requires using their page switching to manage a 8MB block at any one time. This is easier to deal with in NDS homebrew I suppose but would be tricky to do in GBA mode with GBA homebrew because the rom address space for kernel/OS mode changes. So not only is PSRAM only writeable and readable in 8MB blocks while in kernel mode, the address where it starts changes.
In game mode PSRAM starts at 0x08000000 but in kernel mode it's moved to 0x08800000.
To switch pages you can setup a function that looks like this which is what the official kernel uses:
void SetPSRampage(u16 page) {
*(vu16*)0x9fe0000 = 0xd200;
*(vu16*)0x8000000 = 0x1500;
*(vu16*)0x8020000 = 0xd200;
*(vu16*)0x8040000 = 0x1500;
*(vu16*)0x9860000 = page; //C3
*(vu16*)0x9fc0000 = 0x1500;
}
Where page == a u16 value starting with 0x0 being first page, and 0x1000 being next page and so on. I believe there are 4 pages total.
This was how I deal with it in GBA Exploader when I added Omega support to it:
for(siz = 0; siz < fs[sel].filesize; siz += 0x100000, exp += 0x100000) {
fseek(gbaFile, siz, SEEK_SET);
fread(rwbuf, 1, 0x100000+0x400, gbaFile);
dsp_bar(2, siz * 100 / fs[sel].filesize);
if(siz == 0 && gba)header_rep(rwbuf);
savesize = gba_check_Ram1(rwbuf, 0x100000, fs[sel].filesize, siz);
// EZ Flash Omega and it's silly mapping schemes.... :P
if (isOmega) {
if (exp >= 0x09000000) {
PSRamPage += 0x1000;
SetPSRampage(PSRamPage);
exp = PSRAMBase_S98;
}
}
dmaCopy((void*)rwbuf, (void*)exp, 0x100000);
dmaCopyWords(3, rwbuf, (void *)exp, 0x100000);
}
Since you are dealing with GBA homebrew you will need to ensure you aren't currently relying on any data that gets moved to the new address range while in kernel mode hence why it would still be possible but tricky to manage in GBA mode.
This is easier to manage in GBA Exploader because all that app does is write a GBA rom to PSRAM, a save save to sram, and then put the card into game mode before switching to GBA mode and since it's running in DS mode from slot-1 I don't have to worry about my currently executing code getting shifted out of existence by the sudden address changes when putting Omega into kernel mode.
Though adjusting the sram patching system was a pain as I had to account for the page switching too anytime it wanted to read back any PSRAM data for it's patches.
