/************************************************************************** * DSemu: Memory management and handling (mmu.c) * * Released under the terms of the BSD Public Licence * * Imran Nazar (tf@oopsilon.com), 2004 * **************************************************************************/ #include #include "vtbl.h" #include "err.h" #include "mmu.h" #include "dma.h" #include "ioreg.h" #include "gpu.h" #include "unzip.h" //#define MMUIOLOG //#define BIOSsize 1024 int mmuioimpl[]={ 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, }; extern u16 *VRAM; extern u8 *VRAM8; extern u16 OAM[512]; extern u32 LCDcolour[32768]; extern u16 BGPAL[256]; extern u16 OBJPAL[256]; extern u8 *BGPAL8; extern u8 *OBJPAL8; RAMWORD mmuEmpty; u32 ROMsize, BIOSsize; char *ROMfile; RAMWORD *MMUbanks[16]={NULL}; u32 MMUmask[16]={0x1FF,0,0x3FFFF,0x7FFF,0,0,0,0, 0xFFFFFF,0xFFFFFF,0xFFFFFF, 0xFFFFFF,0xFFFFFF,0xFFFFFF,0,0}; int MMUinit(char *file) { FILE *fp; u8 c; int a; ROMfile=file; EWRAM=(RAMWORD*)malloc(65536*sizeof(RAMWORD)); if(!EWRAM) RETFAIL("FAIL: MMU: EWRAM allocation."); IWRAM=(RAMWORD*)malloc(8192*sizeof(RAMWORD)); if(!IWRAM) RETFAIL("FAIL: MMU: IWRAM allocation."); // if(MMUreset()) RETFAIL("FAIL: MMU: Reset."); MMUbanks[0x0]=BIOS; MMUbanks[0x2]=EWRAM; MMUbanks[0x3]=IWRAM; MMUbanks[0x8]=GameROM; MMUbanks[0x9]=GameROM; MMUbanks[0xA]=GameROM; MMUbanks[0xB]=GameROM; MMUbanks[0xC]=GameROM; MMUbanks[0xD]=GameROM; mmuEmpty.data=0xFFFFFFFF; mmuEmpty.op=ARM7opUNL; mmuEmpty.cond=ARM7condAL; // mmuEmpty.cyc=1; RETPASS("MMU: Memoryspace allocation complete."); } int MMUreset() { HANDLE hFile; u8 c; int a,done=0,bytesread; u8 *tempROM; char BIOSpath[1024], INIpath[1024], str[256], strout[384]; int pathsize; HZIP hz; ZIPENTRY ze; int cnt; memset(EWRAM,0,0x3FFFF); memset(IWRAM,0,0x7FFF); pathsize=strstr(logvt->file,"\\log.txt")-logvt->file; strncpy(BIOSpath, logvt->file, pathsize); BIOSpath[pathsize]=0; sprintf(INIpath, "%s\\dsemu.ini", BIOSpath); GetPrivateProfileString("General","BIOS","bioshack.bin",str,256,INIpath); sprintf(BIOSpath, "%s\\%s", BIOSpath,str); // fp=fopen(ROMfile,"rb"); if(strstr(ROMfile,".zip")) { hz=OpenZipFromName(ROMfile,0); if(!hz) RETFAIL("FAIL: MMU: Zip file open."); #ifdef MMUDEBUG logvt->append("MMU: Zip file open."); #endif GetZipItem(hz,-1,&ze); cnt=ze.index; a=0; do { GetZipItem(hz,a,&ze); if(ze.unc_size && (strstr(ze.name,".gba") || strstr(ze.name,".bin"))) done=1; else a++; } while(!done && aappend(strout); GameROM=(RAMWORD*)malloc((ROMsize/4)*sizeof(RAMWORD)); tempROM=(u8*)malloc(ROMsize); if(!GameROM || !tempROM) RETFAIL("FAIL: MMU: GameROM allocation."); #ifdef MMUDEBUG logvt->append("MMU: GameROM allocated."); #endif a=UnzipItemToBlock(hz,a,tempROM,ROMsize); if(a && a!=ZR_MORE) { FormatZipMessage(a,str,256); sprintf(strout,"FAIL: MMU: Zip read: %s.",str); RETFAIL(strout); } CloseZip(hz); #ifdef MMUDEBUG logvt->append("MMU: Zip read and closed."); #endif } else { hFile=CreateFile(ROMfile,GENERIC_READ,0,NULL,OPEN_EXISTING,0,NULL); if(hFile==INVALID_HANDLE_VALUE) { FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError(), 0, (LPTSTR)str, 256, NULL); sprintf(strout,"FAIL: MMU: ROM file open: %s.",str); RETFAIL(strout); } #ifdef MMUDEBUG logvt->append("MMU: ROM file open."); #endif ROMsize=GetFileSize(hFile,NULL); sprintf(str, "MMU: ROM size: %d bytes.",ROMsize); logvt->append(str); GameROM=(RAMWORD*)malloc(((ROMsize/4)+1)*sizeof(RAMWORD)); tempROM=(u8*)malloc(ROMsize); if(!GameROM || !tempROM) RETFAIL("FAIL: MMU: GameROM allocation."); #ifdef MMUDEBUG logvt->append("MMU: GameROM allocated."); #endif ReadFile(hFile,tempROM,ROMsize,&bytesread,NULL); if(bytesread != ROMsize) RETFAIL("FAIL: ROM read."); CloseHandle(hFile); hFile=NULL; #ifdef MMUDEBUG logvt->append("MMU: ROM read and closed."); #endif } for(a=0;a>2].b[3-(a&3)]=tempROM[a]; #else GameROM[a>>2].b[a&3]=tempROM[a]; #endif } free(tempROM); for(a=0;a<(ROMsize>>2);a++) { // GameROM[a].op=ARM7opUNL; // GameROM[a].cond=ARM7condAL; GameROM[a]=ARM7opDecode(GameROM[a].data); // GameROM[a].cyc=1; } // logvt->append(ARM7DASM(GameROM[48].data)); // fp=fopen("bioshack.bin","rb"); // logvt->append(BIOSpath); hFile=CreateFile(BIOSpath,GENERIC_READ,0,NULL,OPEN_EXISTING,0,NULL); if(!hFile) RETFAIL("FAIL: MMU: BIOS file open."); BIOSsize=GetFileSize(hFile,NULL); BIOS=(RAMWORD*)malloc(BIOSsize/4*sizeof(RAMWORD)); tempROM=(u8*)malloc(BIOSsize); if(!BIOS || !tempROM) RETFAIL("FAIL: MMU: BIOS allocation."); ReadFile(hFile,tempROM,BIOSsize,&bytesread,NULL); if(bytesread != BIOSsize) { sprintf(str,"FAIL: BIOS read after %d bytes.",bytesread); RETFAIL(str); } CloseHandle(hFile); hFile=NULL; #ifdef MMUDEBUG logvt->append("MMU: BIOS read and closed."); #endif for(a=0;a>2].b[3-(a&3)]=tempROM[a]; #else BIOS[a>>2].b[a&3]=tempROM[a]; #endif } free(tempROM); for(a=0;aappend("MMU: Shutdown."); } /* #if WORDS_BIGENDIAN #define MMUintRdB(ram,addr) b=ram[addr].b[3-(addr&3)] #define MMUintRdH(ram,addr) \ h=(addr&2)? \ ((ram[addr].b[0])| \ (ram[addr].b[1]<<8)): \ ((ram[addr].b[2])| \ (ram[addr].b[3]<<8)) #define MMUintRdW(ram,addr) \ w=(ram[addr].b[0])| \ (ram[addr].b[1]<<8)| \ (ram[addr].b[2]<<16)| \ (ram[addr].b[3]<<24) #else */ #define MMUintRdB(ram,addr) b=ram[(addr)>>2].b[(addr)&3] #define MMUintRdH(ram,addr) \ h=((addr)&1) \ ?(((addr)&2) \ ?(ram[(addr)>>2].b[3] | ((ram[((addr)>>2)+1].b[0])<<8)) \ :(ram[(addr)>>2].b[1] | ((ram[(addr)>>2].b[2])<<8))) \ :(ram[(addr)>>2].h[((addr)&2)>>1]) #define MMUintRdW(ram,addr) \ switch((addr)&3) \ { \ /* case 0: w=ram[(addr)>>2].data; break; \ case 1: w=(ram[(addr)>>2].b[1]) | ((ram[(addr)>>2].h[1])<<8) | ((ram[((addr)>>2)+1].b[0])<<24); break; \ case 2: w=(ram[(addr)>>2].h[1]) | ((ram[((addr)>>2)+1].h[0])<<16); break; \ case 3: w=(ram[(addr)>>2].b[3]) | ((ram[((addr)>>2)+1].h[0])<<8) | ((ram[((addr)>>2)+1].b[2])<<24); break; */ \ case 0: w=ram[(addr)>>2].data; break; \ case 1: w=(ram[(addr)>>2].data>> 8)+((ram[(addr)>>2].data&0x000000FF)<<24); break; \ case 2: w=ram[(addr)>>2].h[1]+((ram[(addr)>>2].h[0])<<16); break; \ case 3: w=(ram[(addr)>>2].data>>24)+((ram[(addr)>>2].data&0x00FFFFFF)<< 8); break; \ } /* #endif */ u8 MMUrdB(u32 prot, u32 addr) { u8 b; char str[80]; switch(addr&0x0F000000) { case 0x00000000: if(prot) MMUintRdB(BIOS, addr&0x000001FF); else return 0; break; case 0x02000000: MMUintRdB(EWRAM, addr&0x0003FFFF); ARM7addClock(2); break; case 0x03000000: MMUintRdB(IWRAM, addr&0x00007FFF); break; case 0x04000000: if(prot || GBAio[(addr&0x3FF)>>1].flags®_FLAG_R) b=GBAio[(addr&0x3FF)>>1].b[addr&1]; else b=0; #ifdef MMUDEBUG if((!prot) && mmuioimpl[(addr&0x3FF)>>1]==1) { sprintf(str,"MMU: IORd: %03X=%02X",addr&0x3FF,b); logvt->append(str); } #endif break; case 0x05000000: if(addr&0x00000200) b=(addr&1)?OBJPAL[(addr&0x1FF)>>1]>>8:OBJPAL[(addr&0x1FF)>>1]&255; else b=(addr&1)?BGPAL[(addr&0x1FF)>>1]>>8:BGPAL[(addr&0x1FF)>>1]&255; break; case 0x06000000: b=(addr&1)?VRAM[(addr&0x0001FFFF)>>1]>>8:VRAM[(addr&0x0001FFFF)>>1]&255; break; case 0x07000000: b=(addr&1)?OAM[(addr&0x3FF)>>1]>>8:OAM[(addr&0x3FF)>>1]&255; #ifdef MMUDEBUG sprintf(str,"MMU: OAMRd: %03X=%02X",addr&0x3FF,b); logvt->append(str); #endif break; case 0x08000000: case 0x09000000: if((addr&0x00FFFFFF)<=ROMsize) MMUintRdB(GameROM, addr&0x00FFFFFF); else b=mmuEmpty.b[addr&3]; ARM7addClock(4); break; case 0x0A000000: case 0x0B000000: if((addr&0x00FFFFFF)<=ROMsize) MMUintRdB(GameROM, addr&0x00FFFFFF); else b=mmuEmpty.b[addr&3]; ARM7addClock(5); break; case 0x0C000000: case 0x0D000000: if((addr&0x00FFFFFF)<=ROMsize) MMUintRdB(GameROM, addr&0x00FFFFFF); else b=mmuEmpty.b[addr&3]; ARM7addClock(6); break; default: break; } return b; } u16 MMUrdH(u32 prot, u32 addr) { u16 h; char str[80]; switch(addr&0x0F000000) { case 0x00000000: if(prot) MMUintRdH(BIOS, addr&0x000001FF); else return 0; break; case 0x02000000: MMUintRdH(EWRAM, addr&0x0003FFFF); ARM7addClock(2); break; case 0x03000000: MMUintRdH(IWRAM, addr&0x00007FFF); break; case 0x04000000: if(prot || GBAio[(addr&0x3FF)>>1].flags®_FLAG_R) h=GBAio[(addr&0x3FF)>>1].data; else h=0; #ifdef MMUDEBUG if((!prot) && mmuioimpl[(addr&0x3FF)>>1]==1) { sprintf(str,"MMU: IORd: %03X=%04X",addr&0x3FF,h); logvt->append(str); } #endif break; case 0x05000000: if(addr&0x00000200) h=OBJPAL[(addr&0x1FF)>>1]; else h=BGPAL [(addr&0x1FF)>>1]; break; case 0x06000000: h=VRAM[(addr&0x0001FFFF)>>1]; break; case 0x07000000: h=OAM[(addr&0x3FF)>>1]; #ifdef MMUDEBUG sprintf(str,"MMU: OAMRd: %03X=%04X",addr&0x3FF,h); logvt->append(str); #endif break; case 0x08000000: case 0x09000000: if((addr&0x00FFFFFF)<=ROMsize) MMUintRdH(GameROM, addr&0x00FFFFFF); else h=mmuEmpty.h[(addr&2)>>1]; ARM7addClock(4); break; case 0x0A000000: case 0x0B000000: if((addr&0x00FFFFFF)<=ROMsize) MMUintRdH(GameROM, addr&0x00FFFFFF); else h=mmuEmpty.h[(addr&2)>>1]; ARM7addClock(5); break; case 0x0C000000: case 0x0D000000: if((addr&0x00FFFFFF)<=ROMsize) MMUintRdH(GameROM, addr&0x00FFFFFF); else h=mmuEmpty.h[(addr&2)>>1]; ARM7addClock(6); break; default: break; } return h; } u32 MMUrdW(u32 prot, u32 addr) { u32 w; u16 hl,hh; char str[80]; switch(addr&0x0F000000) { case 0x00000000: if(prot) {MMUintRdW(BIOS, addr&0x000001FF);} else return 0; break; case 0x02000000: MMUintRdW(EWRAM, addr&0x0003FFFF); ARM7addClock(5); break; case 0x03000000: MMUintRdW(IWRAM, addr&0x00007FFF); break; case 0x04000000: if(prot || GBAio[(addr&0x3FF)>>1].flags®_FLAG_R) hl=GBAio[(addr&0x3FF)>>1].data; else hl=0; addr+=2; if(prot || GBAio[(addr&0x3FF)>>1].flags®_FLAG_R) hh=GBAio[(addr&0x3FF)>>1].data; else hh=0; w=hl+(hh<<16); #ifdef MMUDEBUG if((!prot) && mmuioimpl[(addr&0x3FF)>>1]==1) { sprintf(str,"MMU: IORd: %03X=%08X",addr&0x3FF,w); logvt->append(str); } #endif break; case 0x05000000: if(addr&0x00000200) hl=OBJPAL[(addr&0x1FF)>>1]; else hl=BGPAL [(addr&0x1FF)>>1]; addr+=2; if(addr&0x00000200) hh=OBJPAL[(addr&0x1FF)>>1]; else hh=BGPAL [(addr&0x1FF)>>1]; w=hl+(hh<<16); break; case 0x06000000: hl=VRAM[(addr&0x0001FFFF)>>1]; addr+=2; hh=VRAM[(addr&0x0001FFFF)>>1]; w=hl+(hh<<16); break; case 0x07000000: hl=OAM[(addr&0x0001FFFF)>>1]; addr+=2; hh=OAM[(addr&0x0001FFFF)>>1]; w=hl+(hh<<16); #ifdef MMUDEBUG sprintf(str,"MMU: OAMRd: %03X=%08X",addr&0x3FF,w); logvt->append(str); #endif break; case 0x08000000: case 0x09000000: // sprintf(str,"MMU: RdW at %08X",addr); logvt->append(str); if((addr&0x00FFFFFF)<=ROMsize){ MMUintRdW(GameROM, addr&0x00FFFFFF); } else w=mmuEmpty.data; ARM7addClock(7); break; case 0x0A000000: case 0x0B000000: if((addr&0x00FFFFFF)<=ROMsize){ MMUintRdW(GameROM, addr&0x00FFFFFF); } else w=mmuEmpty.data; ARM7addClock(8); break; case 0x0C000000: case 0x0D000000: if((addr&0x00FFFFFF)<=ROMsize){ MMUintRdW(GameROM, addr&0x00FFFFFF); } else w=mmuEmpty.data; ARM7addClock(9); break; default: break; } return w; } RAMWORD MMUrdS(u32 prot, u32 addr) { /* RAMWORD def; def.data=0xEC000000; switch(addr&0x0F000000) // switch((addr>>24)&15) { case 0x00000000: return BIOS[(addr&0x001FF)>>2]; break; case 0x02000000: return EWRAM[(addr&0x3FFFF)>>2]; break; case 0x03000000: return IWRAM[(addr&0x07FFF)>>2]; break; case 0x08000000: case 0x09000000: case 0x0A000000: case 0x0B000000: case 0x0C000000: case 0x0D000000: if((addr&0x00FFFFFF)<=ROMsize) return GameROM[(addr&0xFFFFFF)>>2]; else return mmuEmpty; break; //default: return def; break; } /* int bank=(addr>>24)&15; if(MMUbanks[bank]!=NULL) return MMUbanks[bank][(addr&MMUmask[bank])>>2];*/ //E and F handling if(addr&0x08000000) { if((addr&0x00FFFFFF)<=ROMsize) return GameROM[(addr&0xFFFFFF)>>2]; else return mmuEmpty; } switch(addr&0x0F000000) { case 0x03000000: return IWRAM[(addr&0x07FFF)>>2]; case 0x02000000: return EWRAM[(addr&0x3FFFF)>>2]; case 0x00000000: return BIOS[(addr&0x001FF)>>2]; default: return mmuEmpty; } } /* #if WORDS_BIGENDIAN #define MMUintWrB(ram,addr,val) \ ram[addr].b[3-(addr&3)]=val; \ ram[addr].op=ARM7opUNL; \ ram[addr].cond=ARM7condAL #define MMUintWrH(ram,addr,val) \ if(addr&2){ \ ram[addr].b[0]=val&255; \ ram[addr].b[1]=val>>8; \ }else{ \ ram[addr].b[2]=val&255; \ ram[addr].b[3]=val>>8; \ } \ ram[addr].op=ARM7opUNL; \ ram[addr].cond=ARM7condAL #define MMUintWrW(ram,addr,val) \ ram[addr].b[0]=val&255; \ ram[addr].b[1]=val>>8; \ ram[addr].b[2]=val>>16; \ ram[addr].b[3]=val>>24; \ ram[addr].op=ARM7opUNL; \ ram[addr].cond=ARM7condAL #else */ #define MMUintWrB(ram,addr,val) \ ram[(addr)>>2].b[(addr)&3]=val; \ ram[(addr)>>2].op=ARM7opUNL; \ ram[(addr)>>2].cond=ARM7condAL #define MMUintWrH(ram,addr,val) \ ram[(addr)>>2].h[((addr)&2)>>1]=val; \ ram[(addr)>>2].op=ARM7opUNL; \ ram[(addr)>>2].cond=ARM7condAL #define MMUintWrW(ram,addr,val) \ ram[(addr)>>2].data=val; \ ram[(addr)>>2].op=ARM7opUNL; \ ram[(addr)>>2].cond=ARM7condAL /* #endif */ void MMUwrB(u32 bus, u32 addr, u8 val) { switch(addr&0x0F000000) { case 0x02000000: MMUintWrB(EWRAM, addr&0x0003FFFF, val); ARM7addClock(2); break; case 0x03000000: MMUintWrB(IWRAM, addr&0x00007FFF, val); break; default: break; } } void MMUwrH(u32 bus, u32 addr, u16 val) { char str[80]; switch(addr&0x0F000000) { case 0x02000000: MMUintWrH(EWRAM, addr&0x0003FFFF, val); ARM7addClock(2); break; case 0x03000000: MMUintWrH(IWRAM, addr&0x00007FFF, val); break; case 0x04000000: if(GBAio[(addr&0x3FF)>>1].flags®_FLAG_W) { if((addr&0x3FE)==0x202) IntClear(val); else GBAio[(addr&0x3FF)>>1].data=val; DMAcheck(DMA_TIMENOW); #ifdef MMUDEBUG if(mmuioimpl[(addr&0x3FF)>>1]==1) { sprintf(str,"MMU: IOWr: %03X=%04X",addr&0x3FF,val); logvt->append(str); } #endif } break; case 0x05000000: if(addr&0x00000200) OBJPAL[(addr&0x1FF)>>1]=val; else BGPAL [(addr&0x1FF)>>1]=val; break; case 0x06000000: VRAM[(addr&0x0001FFFF)>>1]=val; break; case 0x07000000: OAM[(addr&0x0001FFFF)>>1]=val; #ifdef MMUDEBUG sprintf(str,"MMU: OAMWr: %03X=%04X",addr&0x3FF,val); logvt->append(str); #endif break; default: break; } } void MMUwrW(u32 bus, u32 addr, u32 val) { char str[80]; switch(addr&0x0F000000) { case 0x02000000: MMUintWrW(EWRAM, addr&0x0003FFFF, val); ARM7addClock(2); break; case 0x03000000: MMUintWrW(IWRAM, addr&0x00007FFF, val); break; case 0x04000000: if(GBAio[(addr&0x3FF)>>1].flags®_FLAG_W) { if((addr&0x3FE)==0x202) IntClear(val&65535); else GBAio[(addr&0x3FF)>>1].data=val&65535; } #ifdef MMUDEBUG if(mmuioimpl[(addr&0x3FF)>>1]==1) { sprintf(str,"MMU: IOWr: %03X=%08X",addr&0x3FF,val); logvt->append(str); } #endif addr+=2; if(GBAio[(addr&0x3FF)>>1].flags®_FLAG_W) { if((addr&0x3FE)==0x202) IntClear(val>>16); else GBAio[(addr&0x3FF)>>1].data=val>>16; } DMAcheck(DMA_TIMENOW); break; case 0x05000000: if(addr&0x00000200) OBJPAL[(addr&0x1FF)>>1]=val&65535; else BGPAL [(addr&0x1FF)>>1]=val&65535; addr+=2; if(addr&0x00000200) OBJPAL[(addr&0x1FF)>>1]=val>>16; else BGPAL [(addr&0x1FF)>>1]=val>>16; case 0x06000000: VRAM[(addr&0x0001FFFF)>>1]=val&65535; addr+=2; VRAM[(addr&0x0001FFFF)>>1]=val>>16; break; case 0x07000000: OAM[(addr&0x0001FFFF)>>1]=val&65535; addr+=2; OAM[(addr&0x0001FFFF)>>1]=val>>16; #ifdef MMUDEBUG sprintf(str,"MMU: OAMWr: %03X=%08X",addr&0x3FF,val); logvt->append(str); #endif break; default: break; } } void MMUwrS(u32 bus, u32 addr, RAMWORD val) { switch(addr&0x0F000000) { case 0x02000000: EWRAM[(addr&0x3FFFF)>>2]=val; break; case 0x03000000: IWRAM[(addr&0x07FFF)>>2]=val; break; case 0x08000000: case 0x09000000: case 0x0A000000: case 0x0B000000: case 0x0C000000: case 0x0D000000: GameROM[(addr&0xFFFFFF)>>2]=val; break; default: break; } } /*** EOF:mmu.c ***********************************************************/