Fixed GBA mode switch.

* libnds's swiSwitchToGBAMode ASM function was broken. They used r0
instead of r2 so it didn't work. It must have been correct when GBA
Exploader was last compiled more then a decade ago, but now it's broken
so this ASM function had to be reimplemented. GBA Mode switch now
appears to function as intended.
* As I currently lack a compatible slot-2 flashcart (SuperCard Lite
doesn't work even after trying a few hardcoded card types in main.c)
further testing can't be done on the rest of the code. It appears to
work but I won't know for sure until someone with compatible hardware
tests it.
This commit is contained in:
ApacheThunder 2024-05-08 20:15:20 -05:00
parent 11ea610150
commit 6c10c47a61
6 changed files with 177 additions and 179 deletions

View File

@ -46,7 +46,7 @@ checkarm9:
$(TARGET).nds : arm7/$(TARGET).elf arm9/$(TARGET).elf $(TARGET).nds : arm7/$(TARGET).elf arm9/$(TARGET).elf
@ndstool -c $@ -7 arm7/$(TARGET).elf -9 arm9/$(TARGET).elf \ @ndstool -c $@ -7 arm7/$(TARGET).elf -9 arm9/$(TARGET).elf \
-b $(CURDIR)/logo32.bmp "GBA ExpLoader;Version $(VERSTRING);By Rudolph;" \ -b $(CURDIR)/logo32.bmp "GBA ExpLoader;Version $(VERSTRING);By Rudolph;" \
-g GBEX 01 "GBAEXPLOADER" -z 80040000 -u 00030004 -a 00000138 -p 0001 \ -g #### 01 "GBAEXPLOADER" -z 80040000 -u 00030004 -a 00000138 -p 0001 \
data: data:
@mkdir -p data @mkdir -p data

View File

@ -35,8 +35,6 @@ CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions
ASFLAGS := -g $(ARCH) ASFLAGS := -g $(ARCH)
LDFLAGS = -specs=ds_arm7.specs -g $(ARCH) -Wl,-Map,$(notdir $*).map LDFLAGS = -specs=ds_arm7.specs -g $(ARCH) -Wl,-Map,$(notdir $*).map
# LDFLAGS = -specs=ds_arm7_iwram.specs -g $(ARCH) -Wl,-Map,$(notdir $*).map
LIBS := -lnds7 LIBS := -lnds7

15
arm7/source/biosCalls.s Normal file
View File

@ -0,0 +1,15 @@
.TEXT
.ARM
@---------------------------------------------------------------------------------------
.GLOBAL swiSwitchToGBAModeFixed
.func swiSwitchToGBAModeFixed
@---------------------------------------------------------------------------------------
swiSwitchToGBAModeFixed:
mov r2,#0x40
swi 0x1f0000
.endfunc
.end

View File

@ -39,22 +39,22 @@ extern void ret_menu7_R4(void);
extern void ret_menu7_Gen(void); extern void ret_menu7_Gen(void);
extern void ret_menu7_mse(void); extern void ret_menu7_mse(void);
// libnds messed up the original SWI bios call ASM.
// They used r0 instead of r2. This reimplementation fixes that issue for now.
extern void swiSwitchToGBAModeFixed();
void gbaMode() { void gbaMode() {
vu32 vr; vu32 vr;
REG_IME = IME_DISABLE; REG_IME = IME_DISABLE;
for(vr = 0; vr < 0x1000; vr++); // Wait ARM9 for(vr = 0; vr < 0x1000; vr++); // Wait ARM9
if (((*(vu32*)0x027FFCE4 >> 3) & 0x01) == 0x01) { if (PersonalData->gbaScreen) {
writePowerManagement(0, PM_BACKLIGHT_BOTTOM | PM_SOUND_AMP); writePowerManagement(PM_CONTROL_REG, PM_BACKLIGHT_BOTTOM | PM_SOUND_AMP);
} else { } else {
writePowerManagement(0, PM_BACKLIGHT_TOP | PM_SOUND_AMP); writePowerManagement(PM_CONTROL_REG, PM_BACKLIGHT_TOP | PM_SOUND_AMP);
} }
swiSwitchToGBAModeFixed();
swiSwitchToGBAMode();
// asm("mov r2, #0x40");
// asm("swi 0x1F0000");
while(1); while(1);
} }

View File

@ -197,32 +197,28 @@ static void resetToSlot2() {
swiSoftReset(); swiSoftReset();
} }
void gbaMode() { ITCM_CODE void gbaMode() {
/*if(strncmp(GBA_HEADER.gamecode, "PASS", 4) == 0) { if(strncmp(GBA_HEADER.gamecode, "PASS", 4) == 0) {
resetARM9Memory(); resetARM9Memory();
resetToSlot2(); resetToSlot2();
}*/ }
videoSetMode(0); videoSetMode(0);
videoSetModeSub(0); videoSetModeSub(0);
// vramSetMainBanks(VRAM_A_MAIN_BG, VRAM_B_MAIN_BG, VRAM_C_MAIN_BG, VRAM_D_MAIN_BG);
vramSetPrimaryBanks(VRAM_A_MAIN_BG, VRAM_B_MAIN_BG, VRAM_C_MAIN_BG, VRAM_D_MAIN_BG); vramSetPrimaryBanks(VRAM_A_MAIN_BG, VRAM_B_MAIN_BG, VRAM_C_MAIN_BG, VRAM_D_MAIN_BG);
// vramSetMainBanks(VRAM_A_MAIN_BG, VRAM_B_MAIN_BG, VRAM_C_ARM7, VRAM_D_ARM7); // vramSetMainBanks(VRAM_A_MAIN_BG, VRAM_B_MAIN_BG, VRAM_C_ARM7, VRAM_D_ARM7);
if(PersonalData->gbaScreen) { lcdMainOnBottom(); } else { lcdMainOnTop(); } if(PersonalData->gbaScreen) { lcdMainOnBottom(); } else { lcdMainOnTop(); }
// FIFOSend(IPC_CMD_GBAMODE);
fifoSendValue32(FIFO_USER_01, 1);
gba_frame(); gba_frame();
// FIFOSend(IPC_CMD_GBAMODE); // FIFOSend(IPC_CMD_GBAMODE);
fifoSendValue32(FIFO_USER_01, 1);
sysSetBusOwners(ARM7_OWNS_CARD, ARM7_OWNS_ROM); sysSetBusOwners(ARM7_OWNS_CARD, ARM7_OWNS_ROM);
fifoSendValue32(FIFO_USER_01, 1);
REG_IME = 0; REG_IME = 0;
while(1)swiWaitForVBlank(); while(1);
} }

View File

@ -7,9 +7,6 @@
#include <string.h> #include <string.h>
#include <ctype.h> #include <ctype.h>
//#include "disc_io.h"
//#include "gba_nds_fat.h"
#include "skin.h" #include "skin.h"
@ -19,30 +16,29 @@
#define BI_Bitfields (3) #define BI_Bitfields (3)
typedef struct { typedef struct {
u8 bfType[2]; u8 bfType[2];
u32 bfSize; u32 bfSize;
u16 bfReserved1; u16 bfReserved1;
u16 bfReserved2; u16 bfReserved2;
u32 bfOffset; u32 bfOffset;
u32 biSize; u32 biSize;
u32 biWidth; u32 biWidth;
u32 biHeight; u32 biHeight;
u16 biPlanes; u16 biPlanes;
u16 biBitCount; u16 biBitCount;
u32 biCopmression; u32 biCopmression;
u32 biSizeImage; u32 biSizeImage;
u32 biXPixPerMeter; u32 biXPixPerMeter;
u32 biYPixPerMeter; u32 biYPixPerMeter;
u32 biClrUsed; u32 biClrUsed;
u32 biCirImportant; u32 biCirImportant;
u8 *pPalette; u8 *pPalette;
u8 *pBitmap; u8 *pBitmap;
u32 DataWidth; u32 DataWidth;
} TBMPHeader; } TBMPHeader;
static u16 GetVariable16bit(void *pb) static u16 GetVariable16bit(void *pb) {
{
u16 res; u16 res;
u8 *pb8=(u8*)pb; u8 *pb8=(u8*)pb;
@ -52,8 +48,7 @@ static u16 GetVariable16bit(void *pb)
return(res); return(res);
} }
static u32 GetVariable32bit(void *pb) static u32 GetVariable32bit(void *pb) {
{
u32 res; u32 res;
u8 *pb8=(u8*)pb; u8 *pb8=(u8*)pb;
@ -66,8 +61,7 @@ static u32 GetVariable32bit(void *pb)
} }
static bool GetBMPHeader(u8 *pb,TBMPHeader *pBMPHeader) static bool GetBMPHeader(u8 *pb,TBMPHeader *pBMPHeader) {
{
if(pb==NULL){ if(pb==NULL){
// BMP_LoadErrorStr="SourceData Null."; // BMP_LoadErrorStr="SourceData Null.";
return(false); return(false);
@ -153,21 +147,20 @@ static bool GetBMPHeader(u8 *pb,TBMPHeader *pBMPHeader)
} }
static bool intLoadBM(const char *bmpfn,u16 *pbm,const u32 bmw,const u32 bmh) static bool intLoadBM(const char *bmpfn,u16 *pbm,const u32 bmw,const u32 bmh) {
{ FILE *fh;
FILE *fh;
// bmerrstr1[0]=0; // bmerrstr1[0]=0;
// bmerrstr2[0]=0; // bmerrstr2[0]=0;
if(pbm==NULL){ if(pbm == NULL) {
// snprintf(bmerrstr1,256,"BitmapMemory is NULL."); // snprintf(bmerrstr1,256,"BitmapMemory is NULL.");
// snprintf(bmerrstr2,256,"The memory is insufficient?"); // snprintf(bmerrstr2,256,"The memory is insufficient?");
// _consolePrintf("%s\n",bmerrstr1); // _consolePrintf("%s\n",bmerrstr1);
// _consolePrintf("%s\n",bmerrstr2); // _consolePrintf("%s\n",bmerrstr2);
return(false); return(false);
} }
u8 *bmdata = NULL; u8 *bmdata = NULL;
u32 bmsize; u32 bmsize;
@ -175,156 +168,152 @@ static bool intLoadBM(const char *bmpfn,u16 *pbm,const u32 bmw,const u32 bmh)
fh=fopen(bmpfn, "rb"); fh=fopen(bmpfn, "rb");
if(fh!=NULL){ if(fh != NULL) {
fseek(fh, 0, SEEK_END); fseek(fh, 0, SEEK_END);
bmsize=ftell(fh); bmsize=ftell(fh);
fseek(fh, 0, SEEK_SET); fseek(fh, 0, SEEK_SET);
bmdata = (u8*)malloc(bmsize); bmdata = (u8*)malloc(bmsize);
fread(bmdata, 1, bmsize, fh); fread(bmdata, 1, bmsize, fh);
fclose(fh); fclose(fh);
} }
if(bmdata==NULL){ if(bmdata==NULL){
return(false); return(false);
}else{ }/* else {
// _consolePrintf("loadskin /shell/%s\n",bmpfn); _consolePrintf("loadskin /shell/%s\n",bmpfn);
} }*/
TBMPHeader BMPHeader; TBMPHeader BMPHeader;
if(GetBMPHeader(bmdata,&BMPHeader)==false){ if(!GetBMPHeader(bmdata,&BMPHeader)) {
// snprintf(bmerrstr1,256,"Request /shell/%s WindowsBitmapFormat",bmpfn); // snprintf(bmerrstr1,256,"Request /shell/%s WindowsBitmapFormat",bmpfn);
// snprintf(bmerrstr2,256,"%s",BMP_LoadErrorStr); // snprintf(bmerrstr2,256,"%s",BMP_LoadErrorStr);
// _consolePrintf("%s\n",bmerrstr1); // _consolePrintf("%s\n",bmerrstr1);
// _consolePrintf("%s\n",bmerrstr2); // _consolePrintf("%s\n",bmerrstr2);
free(bmdata); bmdata=NULL; free(bmdata); bmdata=NULL;
return(false);
}
if((BMPHeader.biWidth==1)&&(BMPHeader.biHeight==1)){
free(bmdata); bmdata=NULL;
return(false);
}
if(BMPHeader.biBitCount==32){
// _consolePrintf("Error. not support 32bit color.");
free(bmdata); bmdata=NULL;
return(false);
}
if((BMPHeader.biWidth<bmw)||(BMPHeader.biHeight<bmh)){
// snprintf(bmerrstr1,256,"Request /shell/%s WindowsBitmapFormat",bmpfn);
// snprintf(bmerrstr2,256,"%d x %dpixel 8 or 24bitcolor NoCompression.",bmw,bmh);
// _consolePrintf("%s\n",bmerrstr1);
// _consolePrintf("%s\n",bmerrstr2);
free(bmdata); bmdata=NULL;
return(false);
}
u32 gr=0,gg=0,gb=0;
#define Gravity(c,cg) { \
c+=cg; \
cg=c&7; \
c=c>>3; \
if((c&(~0x1f))!=0) c=(c<0) ? 0x00 : 0x1f; \
}
for(u32 y=0;y<bmh;y++){
u8 *pSrcBM=&BMPHeader.pBitmap[(BMPHeader.biHeight-1-y)*BMPHeader.DataWidth];
u16 *pDstBM=&pbm[y*bmw];
switch(BMPHeader.biBitCount){
case 8: {
u8 *PaletteTable=BMPHeader.pPalette;
for(u32 x=0;x<bmw;x++){
u8 *pal;
u32 r,g,b;
pal=&PaletteTable[*pSrcBM*4];
pSrcBM+=1;
b=pal[0];
g=pal[1];
r=pal[2];
Gravity(b,gb);
Gravity(g,gg);
Gravity(r,gr);
pDstBM[x]=RGB15(r,g,b) | BIT(15);
}
break;
}
case 24: {
for(u32 x=0;x<bmw;x++){
u32 r,g,b;
b=pSrcBM[0];
g=pSrcBM[1];
r=pSrcBM[2];
pSrcBM+=3;
Gravity(b,gb);
Gravity(g,gg);
Gravity(r,gr);
pDstBM[x]=RGB15(r,g,b) | BIT(15);
}
break;
}
}
}
#undef Gravity
free(bmdata); bmdata=NULL;
return(true);
}
bool LoadSkin(int mod, char *Name)
{
u16 *pBuf;
u16 *pDstBuf1;
u16 *pDstBuf2;
pBuf=(u16*)malloc(256*192*2);
if(intLoadBM(Name, pBuf, 256, 192) == false) {
free(pBuf);
return(false); return(false);
} }
if(mod == 0) { if((BMPHeader.biWidth==1)&&(BMPHeader.biHeight==1)) {
pDstBuf1 = (u16*)0x06020000; free(bmdata);
bmdata=NULL;
return false;
} }
if(mod == 1) {
pDstBuf1 = (u16*)0x06220000; if(BMPHeader.biBitCount==32) {
// _consolePrintf("Error. not support 32bit color.");
free(bmdata);
bmdata=NULL;
return false;
} }
if(mod == 2) {
pDstBuf1 = (u16*)0x06000000; if((BMPHeader.biWidth<bmw)||(BMPHeader.biHeight<bmh)) {
pDstBuf2 = (u16*)0x06020000; // snprintf(bmerrstr1,256,"Request /shell/%s WindowsBitmapFormat",bmpfn);
// pDstBuf1 = (u16*)0x06800000; // snprintf(bmerrstr2,256,"%d x %dpixel 8 or 24bitcolor NoCompression.",bmw,bmh);
// pDstBuf2 = (u16*)0x06820000; // _consolePrintf("%s\n",bmerrstr1);
// _consolePrintf("%s\n",bmerrstr2);
free(bmdata);
bmdata=NULL;
return false;
}
u32 gr=0,gg=0,gb=0;
#define Gravity(c,cg) { \
c+=cg; \
cg=c&7; \
c=c>>3; \
if((c&(~0x1f))!=0) c=(c<0) ? 0x00 : 0x1f; \
}
for(u32 y=0;y<bmh;y++) {
u8 *pSrcBM=&BMPHeader.pBitmap[(BMPHeader.biHeight-1-y)*BMPHeader.DataWidth];
u16 *pDstBM=&pbm[y*bmw];
switch(BMPHeader.biBitCount) {
case 8: {
u8 *PaletteTable=BMPHeader.pPalette;
for(u32 x=0;x<bmw;x++){
u8 *pal;
u32 r,g,b;
pal=&PaletteTable[*pSrcBM*4];
pSrcBM+=1;
b=pal[0];
g=pal[1];
r=pal[2];
Gravity(b,gb);
Gravity(g,gg);
Gravity(r,gr);
pDstBM[x]=RGB15(r,g,b) | BIT(15);
}
break;
}
case 24: {
for(u32 x=0;x<bmw;x++) {
u32 r,g,b;
b=pSrcBM[0];
g=pSrcBM[1];
r=pSrcBM[2];
pSrcBM+=3;
Gravity(b,gb);
Gravity(g,gg);
Gravity(r,gr);
pDstBM[x]=RGB15(r,g,b) | BIT(15);
}
break;
}
}
}
#undef Gravity
free(bmdata);
bmdata=NULL;
return true;
}
DTCM_DATA ALIGN(4) static u16 *pBuf;
ITCM_CODE bool LoadSkin(int mod, char *Name) {
u16 *pDstBuf1;
u16 *pDstBuf2;
pBuf = (u16*)malloc(256*192*2);
if(!intLoadBM(Name, pBuf, 256, 192)) { free(pBuf); return false; }
switch (mod) {
case 0: pDstBuf1 = (u16*)0x06020000; break;
case 1: pDstBuf1 = (u16*)0x06220000; break;
case 2:
pDstBuf1 = (u16*)0x06000000;
pDstBuf2 = (u16*)0x06020000;
// pDstBuf1 = (u16*)0x06800000;
// pDstBuf2 = (u16*)0x06820000;
break;
default: pDstBuf1 = (u16*)0x06020000; break;
} }
for(s32 y=0;y<192;y++) { for(s32 y=0;y<192;y++) {
for(s32 x=0;x<256;x++) { for(s32 x=0;x<256;x++) {
pDstBuf1[x]=pBuf[x]; pDstBuf1[x]=pBuf[x];
if(mod == 2) if(mod == 2)pDstBuf2[x]=pBuf[x];
pDstBuf2[x]=pBuf[x];
} }
pDstBuf1+=256; pDstBuf1+=256;
if(mod == 2) if(mod == 2)pDstBuf2+=256;
pDstBuf2+=256;
pBuf+=256; pBuf+=256;
} }
// free(pBuf);
free(pBuf); return true;
return(true);
} }