/* Copyright (C) 2006 yopyop Copyright (C) 2007 shash Copyright (C) 2007-2012 DeSmuME team This file is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This file is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with the this software. If not, see . */ #include #include #include #include #include #include "common.h" //#include "debug.h" #include "NDSSystem.h" #include "cp15.h" //#include "wifi.h" #include "registers.h" //#include "render3D.h" //#include "gfx3d.h" //#include "rtc.h" #include "mc.h" //#include "addons.h" #include "slot1.h" //#include "mic.h" //#include "movie.h" #include "readwrite.h" #include "MMU_timing.h" //#undef min /*#ifdef DO_ASSERT_UNALIGNED #define ASSERT_UNALIGNED(x) assert(x) #else #define ASSERT_UNALIGNED(x) #endif*/ //http://home.utah.edu/~nahaj/factoring/isqrt.c.html static uint64_t isqrt (uint64_t x) { uint64_t squaredbit, remainder, root; if (x<1) return 0; /* Load the binary constant 01 00 00 ... 00, where the number * of zero bits to the right of the single one bit * is even, and the one bit is as far left as is consistant * with that condition.) */ squaredbit = (uint64_t) ((((uint64_t) ~0LL) >> 1) & ~(((uint64_t) ~0LL) >> 2)); /* This portable load replaces the loop that used to be * here, and was donated by legalize@xmission.com */ /* Form bits of the answer. */ remainder = x; root = 0; while (squaredbit > 0) { if (remainder >= (squaredbit | root)) { remainder -= (squaredbit | root); root >>= 1; root |= squaredbit; } else { root >>= 1; } squaredbit >>= 2; } return root; } uint32_t partie = 1; uint32_t _MMU_MAIN_MEM_MASK = 0x3FFFFF; uint32_t _MMU_MAIN_MEM_MASK16 = 0x3FFFFF & ~1; uint32_t _MMU_MAIN_MEM_MASK32 = 0x3FFFFF & ~3; //#define _MMU_DEBUG /*#ifdef _MMU_DEBUG #include void mmu_log_debug_ARM9(uint32_t adr, const char *fmt, ...) { if (adr < 0x4000000) return; // if (adr > 0x4100014) return; //#if 1 if (adr >= 0x4000000 && adr <= 0x400006E) return; // Display Engine A if (adr >= 0x40000B0 && adr <= 0x4000134) return; // DMA, Timers and Keypad if (adr >= 0x4000180 && adr <= 0x40001BC) return; // IPC/ROM if (adr >= 0x4000204 && adr <= 0x400024A) return; // Memory & IRQ control if (adr >= 0x4000280 && adr <= 0x4000306) return; // Maths if (adr >= 0x4000320 && adr <= 0x40006A3) return; // 3D dispaly engine if (adr >= 0x4001000 && adr <= 0x400106E) return; // Display Engine B if (adr >= 0x4100000 && adr <= 0x4100014) return; // IPC/ROM //#endif va_list list; char msg[512]; memset(msg,0,512); va_start(list,fmt); _vsnprintf(msg,511,fmt,list); va_end(list); INFO("MMU ARM9 0x%08X: %s\n", adr, msg); } void mmu_log_debug_ARM7(uint32_t adr, const char *fmt, ...) { if (adr < 0x4000004) return; if (adr > 0x4808FFF) return; #if 1 if (adr >= 0x4000004 && adr < 0x4000180) return; // ARM7 I/O Map if (adr >= 0x4000180 && adr <= 0x40001C4) return; // IPC/ROM if (adr >= 0x4000204 && adr <= 0x400030C) return; // Memory and IRQ Control if (adr >= 0x4000400 && adr <= 0x400051E) return; // Sound Registers if (adr >= 0x4100000 && adr <= 0x4100014) return; // IPC/ROM if (adr >= 0x4800000 && adr <= 0x4808FFF) return; // WLAN Registers #endif va_list list; char msg[512]; memset(msg,0,512); va_start(list,fmt); _vsnprintf(msg,511,fmt,list); va_end(list); INFO("MMU ARM7 0x%08X: %s\n", adr, msg); } #else #define mmu_log_debug_ARM9(...) #define mmu_log_debug_ARM7(...) #endif*/ //#define LOG_CARD //#define LOG_GPU //#define LOG_DMA //#define LOG_DMA2 //#define LOG_DIV #define DUP2(x) x, x #define DUP4(x) x, x, x, x #define DUP8(x) x, x, x, x, x, x, x, x #define DUP16(x) x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x MMU_struct MMU; MMU_struct_new MMU_new; MMU_struct_timing MMU_timing; uint8_t * MMU_struct::MMU_MEM[2][256] = { //arm9 { /* 0X*/ DUP16(MMU.ARM9_ITCM), /* 1X*/ //DUP16(MMU.ARM9_ITCM) /* 1X*/ DUP16(MMU.UNUSED_RAM), /* 2X*/ DUP16(MMU.MAIN_MEM), /* 3X*/ DUP16(MMU.SWIRAM), /* 4X*/ DUP16(MMU.ARM9_REG), /* 5X*/ DUP16(MMU.ARM9_VMEM), /* 6X*/ DUP16(MMU.ARM9_LCD), /* 7X*/ DUP16(MMU.ARM9_OAM), /* 8X*/ DUP16(NULL), /* 9X*/ DUP16(NULL), /* AX*/ DUP16(MMU.UNUSED_RAM), /* BX*/ DUP16(MMU.UNUSED_RAM), /* CX*/ DUP16(MMU.UNUSED_RAM), /* DX*/ DUP16(MMU.UNUSED_RAM), /* EX*/ DUP16(MMU.UNUSED_RAM), /* FX*/ DUP16(MMU.ARM9_BIOS) }, //arm7 { /* 0X*/ DUP16(MMU.ARM7_BIOS), /* 1X*/ DUP16(MMU.UNUSED_RAM), /* 2X*/ DUP16(MMU.MAIN_MEM), /* 3X*/ DUP8(MMU.SWIRAM), DUP8(MMU.ARM7_ERAM), /* 4X*/ DUP8(MMU.ARM7_REG), DUP8(MMU.ARM7_WIRAM), /* 5X*/ DUP16(MMU.UNUSED_RAM), /* 6X*/ DUP16(MMU.ARM9_LCD), /* 7X*/ DUP16(MMU.UNUSED_RAM), /* 8X*/ DUP16(NULL), /* 9X*/ DUP16(NULL), /* AX*/ DUP16(MMU.UNUSED_RAM), /* BX*/ DUP16(MMU.UNUSED_RAM), /* CX*/ DUP16(MMU.UNUSED_RAM), /* DX*/ DUP16(MMU.UNUSED_RAM), /* EX*/ DUP16(MMU.UNUSED_RAM), /* FX*/ DUP16(MMU.UNUSED_RAM) } }; uint32_t MMU_struct::MMU_MASK[2][256] = { //arm9 { /* 0X*/ DUP16(0x00007FFF), /* 1X*/ //DUP16(0x00007FFF) /* 1X*/ DUP16(0x00000003), /* 2X*/ DUP16(0x003FFFFF), /* 3X*/ DUP16(0x00007FFF), /* 4X*/ DUP16(0x00FFFFFF), /* 5X*/ DUP16(0x000007FF), /* 6X*/ DUP16(0x00FFFFFF), /* 7X*/ DUP16(0x000007FF), /* 8X*/ DUP16(0x00000003), /* 9X*/ DUP16(0x00000003), /* AX*/ DUP16(0x00000003), /* BX*/ DUP16(0x00000003), /* CX*/ DUP16(0x00000003), /* DX*/ DUP16(0x00000003), /* EX*/ DUP16(0x00000003), /* FX*/ DUP16(0x00007FFF) }, //arm7 { /* 0X*/ DUP16(0x00003FFF), /* 1X*/ DUP16(0x00000003), /* 2X*/ DUP16(0x003FFFFF), /* 3X*/ DUP8(0x00007FFF), DUP8(0x0000FFFF), /* 4X*/ DUP8(0x00FFFFFF), DUP8(0x0000FFFF), /* 5X*/ DUP16(0x00000003), /* 6X*/ DUP16(0x00FFFFFF), /* 7X*/ DUP16(0x00000003), /* 8X*/ DUP16(0x00000003), /* 9X*/ DUP16(0x00000003), /* AX*/ DUP16(0x00000003), /* BX*/ DUP16(0x00000003), /* CX*/ DUP16(0x00000003), /* DX*/ DUP16(0x00000003), /* EX*/ DUP16(0x00000003), /* FX*/ DUP16(0x00000003) } }; // this logic was moved to MMU_timing.h //CACHE_ALIGN //TWaitState MMU_struct::MMU_WAIT16[2][16] = { // { 1, 1, 1, 1, 1, 1, 1, 1, 5, 5, 5, 1, 1, 1, 1, 1 }, //arm9 // { 1, 1, 1, 1, 1, 1, 1, 1, 5, 5, 5, 1, 1, 1, 1, 1 }, //arm7 //}; // //CACHE_ALIGN //TWaitState MMU_struct::MMU_WAIT32[2][16] = { // { 1, 1, 1, 1, 1, 2, 2, 1, 8, 8, 5, 1, 1, 1, 1, 1 }, //arm9 // { 1, 1, 1, 1, 1, 1, 1, 1, 8, 8, 5, 1, 1, 1, 1, 1 }, //arm7 //}; ////////////////////////////////////////////////////////////// //------------- //VRAM MEMORY MAPPING //------------- //(Everything is mapped through to ARM9_LCD in blocks of 16KB) //for all of the below, values = 41 indicate unmapped memory static const uint8_t VRAM_PAGE_UNMAPPED = 41; static const unsigned VRAM_LCDC_PAGES = 41; uint8_t vram_lcdc_map[VRAM_LCDC_PAGES]; //in the range of 0x06000000 - 0x06800000 in 16KB pages (the ARM9 vram mappable area) //this maps to 16KB pages in the LCDC buffer which is what will actually contain the data uint8_t vram_arm9_map[VRAM_ARM9_PAGES]; //this chooses which banks are mapped in the 128K banks starting at 0x06000000 in ARM7 uint8_t vram_arm7_map[2]; //-----> //consider these later, for better recordkeeping, instead of using the uint8_t* in MMU ////for each 128KB texture slot, this maps to a 16KB starting page in the LCDC buffer //#define VRAM_TEX_SLOTS 4 //uint8_t vram_tex_map[VRAM_TEX_SLOTS]; // ////for each 16KB tex palette slot, this maps to a 16KB starting page in the LCDC buffer //#define VRAM_TEX_PALETTE_SLOTS 6 //uint8_t vram_tex_palette_map[VRAM_TEX_PALETTE_SLOTS]; //<--------- //void MMU_VRAM_unmap_all(); struct TVramBankInfo { uint8_t page_addr, num_pages; }; static const TVramBankInfo vram_bank_info[VRAM_BANKS] = { {0,8}, {8,8}, {16,8}, {24,8}, {32,4}, {36,1}, {37,1}, {38,2}, {40,1} }; //this is to remind you that the LCDC mapping returns a strange value (not 0x06800000) as you would expect //in order to play nicely with the MMU address and mask tables static const uint32_t LCDC_HACKY_LOCATION = 0x06000000; //maps an ARM9 BG/OBJ or LCDC address into an LCDC address, and informs the caller of whether it isn't mapped //TODO - in cases where this does some mapping work, we could bypass the logic at the end of the _read* and _write* routines //this is a good optimization to consider //template static inline uint32_t MMU_LCDmap(uint32_t addr, bool& unmapped, bool& restricted) { unmapped = false; restricted = false; //this will track whether 8bit writes are allowed //in case the address is entirely outside of the interesting ranges if(addr < 0x06000000) return addr; if(addr >= 0x07000000) return addr; //shared wram mapping for arm7 /*if(PROCNUM==ARMCPU_ARM7) { //necessary? not sure //addr &= 0x3FFFF; //addr += 0x06000000; uint32_t ofs = addr & 0x1FFFF; uint32_t bank = (addr >> 17)&1; if(vram_arm7_map[bank] == VRAM_PAGE_UNMAPPED) { unmapped = true; return 0; } return LCDC_HACKY_LOCATION + (vram_arm7_map[bank]<<14) + ofs; }*/ restricted = true; //handle LCD memory mirroring if(addr>=0x068A4000) addr = 0x06800000 + //(addr%0xA4000); //yuck!! is this even how it mirrors? but we have to keep from overrunning the buffer somehow (addr&0x80000); //just as likely to be right (I have no clue how it should work) but faster. uint32_t vram_page; uint32_t ofs = addr & 0x3FFF; //return addresses in LCDC range if(addr>=0x06800000) { //already in LCDC range. just look it up to see whether it is unmapped vram_page = (addr>>14)&63; assert(vram_page>14)&(VRAM_ARM9_PAGES-1); assert(vram_page= VRAM_BANK_H) block++; uint8_t VRAMBankCnt = T1ReadByte(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x240 + block); //do nothing if the bank isnt enabled uint8_t en = VRAMBankCnt & 0x80; if(!en) return; int mst,ofs=0; switch(bank) { case VRAM_BANK_A: case VRAM_BANK_B: mst = VRAMBankCnt & 3; ofs = (VRAMBankCnt>>3) & 3; switch(mst) { case 0: //LCDC vramConfiguration.banks[bank].purpose = VramConfiguration::LCDC; MMU_vram_lcdc(bank); //if(ofs != 0) PROGINFO("Bank %i: MST %i OFS %i\n", mst, ofs); break; case 1: //ABG vramConfiguration.banks[bank].purpose = VramConfiguration::ABG; MMU_vram_arm9(bank,VRAM_PAGE_ABG+ofs*8); break; case 2: //AOBJ vramConfiguration.banks[bank].purpose = VramConfiguration::AOBJ; switch(ofs) { case 0: case 1: MMU_vram_arm9(bank,VRAM_PAGE_AOBJ+ofs*8); break; //default: //PROGINFO("Unsupported ofs setting %d for engine A OBJ vram bank %c\n", ofs, 'A'+bank); } break; case 3: //texture vramConfiguration.banks[bank].purpose = VramConfiguration::TEX; MMU.texInfo.textureSlotAddr[ofs] = MMU_vram_physical(vram_bank_info[bank].page_addr); break; default: goto unsupported_mst; } break; case VRAM_BANK_C: case VRAM_BANK_D: mst = VRAMBankCnt & 7; ofs = (VRAMBankCnt>>3) & 3; switch(mst) { case 0: //LCDC vramConfiguration.banks[bank].purpose = VramConfiguration::LCDC; MMU_vram_lcdc(bank); //if(ofs != 0) PROGINFO("Bank %i: MST %i OFS %i\n", mst, ofs); break; case 1: //ABG vramConfiguration.banks[bank].purpose = VramConfiguration::ABG; MMU_vram_arm9(bank,VRAM_PAGE_ABG+ofs*8); break; case 2: //arm7 vramConfiguration.banks[bank].purpose = VramConfiguration::ARM7; if(bank == 2) T1WriteByte(MMU.MMU_MEM[ARMCPU_ARM7][0x40], 0x240, T1ReadByte(MMU.MMU_MEM[ARMCPU_ARM7][0x40], 0x240) | 1); if(bank == 3) T1WriteByte(MMU.MMU_MEM[ARMCPU_ARM7][0x40], 0x240, T1ReadByte(MMU.MMU_MEM[ARMCPU_ARM7][0x40], 0x240) | 2); switch(ofs) { case 0: case 1: vram_arm7_map[ofs] = vram_bank_info[bank].page_addr; break; //default: //PROGINFO("Unsupported ofs setting %d for arm7 vram bank %c\n", ofs, 'A'+bank); } break; case 3: //texture vramConfiguration.banks[bank].purpose = VramConfiguration::TEX; MMU.texInfo.textureSlotAddr[ofs] = MMU_vram_physical(vram_bank_info[bank].page_addr); break; case 4: //BGB or BOBJ if(bank == VRAM_BANK_C) { vramConfiguration.banks[bank].purpose = VramConfiguration::BBG; MMU_vram_arm9(bank,VRAM_PAGE_BBG); //BBG } else { vramConfiguration.banks[bank].purpose = VramConfiguration::BOBJ; MMU_vram_arm9(bank,VRAM_PAGE_BOBJ); //BOBJ } //if(ofs != 0) PROGINFO("Bank %i: MST %i OFS %i\n", mst, ofs); break; default: goto unsupported_mst; } break; case VRAM_BANK_E: mst = VRAMBankCnt & 7; //if(((VRAMBankCnt>>3)&3) != 0) PROGINFO("Bank %i: MST %i OFS %i\n", mst, ofs); switch(mst) { case 0: //LCDC vramConfiguration.banks[bank].purpose = VramConfiguration::LCDC; MMU_vram_lcdc(bank); break; case 1: //ABG vramConfiguration.banks[bank].purpose = VramConfiguration::ABG; MMU_vram_arm9(bank,VRAM_PAGE_ABG); break; case 2: //AOBJ vramConfiguration.banks[bank].purpose = VramConfiguration::AOBJ; MMU_vram_arm9(bank,VRAM_PAGE_AOBJ); break; case 3: //texture palette vramConfiguration.banks[bank].purpose = VramConfiguration::TEXPAL; MMU.texInfo.texPalSlot[0] = MMU_vram_physical(vram_bank_info[bank].page_addr); MMU.texInfo.texPalSlot[1] = MMU_vram_physical(vram_bank_info[bank].page_addr+1); MMU.texInfo.texPalSlot[2] = MMU_vram_physical(vram_bank_info[bank].page_addr+2); MMU.texInfo.texPalSlot[3] = MMU_vram_physical(vram_bank_info[bank].page_addr+3); break; case 4: //A BG extended palette vramConfiguration.banks[bank].purpose = VramConfiguration::ABGEXTPAL; MMU.ExtPal[0][0] = MMU_vram_physical(vram_bank_info[bank].page_addr); MMU.ExtPal[0][1] = MMU.ExtPal[0][0]/* + ADDRESS_STEP_8KB*/; MMU.ExtPal[0][2] = MMU.ExtPal[0][1]/* + ADDRESS_STEP_8KB*/; MMU.ExtPal[0][3] = MMU.ExtPal[0][2]/* + ADDRESS_STEP_8KB*/; break; default: goto unsupported_mst; } break; case VRAM_BANK_F: case VRAM_BANK_G: { mst = VRAMBankCnt & 7; ofs = (VRAMBankCnt>>3) & 3; const int pageofslut[] = {0,1,4,5}; const int pageofs = pageofslut[ofs]; switch(mst) { case 0: //LCDC vramConfiguration.banks[bank].purpose = VramConfiguration::LCDC; MMU_vram_lcdc(bank); //if(ofs != 0) PROGINFO("Bank %i: MST %i OFS %i\n", mst, ofs); break; case 1: //ABG vramConfiguration.banks[bank].purpose = VramConfiguration::ABG; MMU_vram_arm9(bank,VRAM_PAGE_ABG+pageofs); MMU_vram_arm9(bank,VRAM_PAGE_ABG+pageofs+2); //unexpected mirroring (required by spyro eternal night) break; case 2: //AOBJ vramConfiguration.banks[bank].purpose = VramConfiguration::AOBJ; MMU_vram_arm9(bank,VRAM_PAGE_AOBJ+pageofs); MMU_vram_arm9(bank,VRAM_PAGE_AOBJ+pageofs+2); //unexpected mirroring - I have no proof, but it is inferred from the ABG above break; case 3: //texture palette vramConfiguration.banks[bank].purpose = VramConfiguration::TEXPAL; MMU.texInfo.texPalSlot[pageofs] = MMU_vram_physical(vram_bank_info[bank].page_addr); break; case 4: //A BG extended palette switch(ofs) { case 0: case 1: vramConfiguration.banks[bank].purpose = VramConfiguration::ABGEXTPAL; MMU.ExtPal[0][ofs*2] = MMU_vram_physical(vram_bank_info[bank].page_addr); MMU.ExtPal[0][ofs*2+1] = MMU.ExtPal[0][ofs*2]/* + ADDRESS_STEP_8KB*/; break; default: vramConfiguration.banks[bank].purpose = VramConfiguration::INVALID; //PROGINFO("Unsupported ofs setting %d for engine A bgextpal vram bank %c\n", ofs, 'A'+bank); break; } break; case 5: //A OBJ extended palette vramConfiguration.banks[bank].purpose = VramConfiguration::AOBJEXTPAL; MMU.ObjExtPal[0][0] = MMU_vram_physical(vram_bank_info[bank].page_addr); MMU.ObjExtPal[0][1] = MMU.ObjExtPal[0][1]/* + ADDRESS_STEP_8KB*/; //if(ofs != 0) PROGINFO("Bank %i: MST %i OFS %i\n", mst, ofs); break; default: goto unsupported_mst; } break; } case VRAM_BANK_H: mst = VRAMBankCnt & 3; //if(((VRAMBankCnt>>3)&3) != 0) PROGINFO("Bank %i: MST %i OFS %i\n", mst, ofs); switch(mst) { case 0: //LCDC vramConfiguration.banks[bank].purpose = VramConfiguration::LCDC; MMU_vram_lcdc(bank); break; case 1: //BBG vramConfiguration.banks[bank].purpose = VramConfiguration::BBG; MMU_vram_arm9(bank,VRAM_PAGE_BBG); MMU_vram_arm9(bank,VRAM_PAGE_BBG + 4); //unexpected mirroring break; case 2: //B BG extended palette vramConfiguration.banks[bank].purpose = VramConfiguration::BBGEXTPAL; MMU.ExtPal[1][0] = MMU_vram_physical(vram_bank_info[bank].page_addr); MMU.ExtPal[1][1] = MMU.ExtPal[1][0]/* + ADDRESS_STEP_8KB*/; MMU.ExtPal[1][2] = MMU.ExtPal[1][1]/* + ADDRESS_STEP_8KB*/; MMU.ExtPal[1][3] = MMU.ExtPal[1][2]/* + ADDRESS_STEP_8KB*/; break; default: goto unsupported_mst; } break; case VRAM_BANK_I: mst = VRAMBankCnt & 3; //if(((VRAMBankCnt>>3)&3) != 0) PROGINFO("Bank %i: MST %i OFS %i\n", mst, ofs); switch(mst) { case 0: //LCDC vramConfiguration.banks[bank].purpose = VramConfiguration::LCDC; MMU_vram_lcdc(bank); break; case 1: //BBG vramConfiguration.banks[bank].purpose = VramConfiguration::BBG; MMU_vram_arm9(bank,VRAM_PAGE_BBG+2); MMU_vram_arm9(bank,VRAM_PAGE_BBG+3); //unexpected mirroring break; case 2: //BOBJ vramConfiguration.banks[bank].purpose = VramConfiguration::BOBJ; MMU_vram_arm9(bank,VRAM_PAGE_BOBJ); MMU_vram_arm9(bank,VRAM_PAGE_BOBJ+1); //FF3 end scene (lens flare sprite) needs this as it renders a sprite off the end of the 16KB and back around break; case 3: //B OBJ extended palette vramConfiguration.banks[bank].purpose = VramConfiguration::BOBJEXTPAL; MMU.ObjExtPal[1][0] = MMU_vram_physical(vram_bank_info[bank].page_addr); MMU.ObjExtPal[1][1] = MMU.ObjExtPal[1][1]/* + ADDRESS_STEP_8KB*/; break; default: goto unsupported_mst; } break; } //switch(bank) vramConfiguration.banks[bank].ofs = ofs; return; unsupported_mst: vramConfiguration.banks[bank].purpose = VramConfiguration::INVALID; //PROGINFO("Unsupported mst setting %d for vram bank %c\n", mst, 'A'+bank); } void MMU_VRAM_unmap_all() { vramConfiguration.clear(); vram_arm7_map[0] = VRAM_PAGE_UNMAPPED; vram_arm7_map[1] = VRAM_PAGE_UNMAPPED; for(int i=0;iNDS_3D_VramReconfigureSignal(); } //------------------------------- //set up arm9 mirrorings //these are probably not entirely accurate. more study will be necessary. //in general, we find that it is not uncommon at all for games to accidentally do this. // //being able to easily do these experiments was one of the primary motivations for this remake of the vram mapping system //see the "unexpected mirroring" comments above for some more mirroring //so far "unexpected mirrorings" are tested by combining these games: //despereaux - storybook subtitles //NSMB - world map sub screen //drill spirits EU - mission select (just for control purposes, as it doesnt use H or I) //... //note that the "unexpected mirroring" items above may at some point rely on being executed in a certain order. //(sequentially A..I) const int types[] = {VRAM_PAGE_ABG,VRAM_PAGE_BBG,VRAM_PAGE_AOBJ,VRAM_PAGE_BOBJ}; const int sizes[] = {32,8,16,8}; for(int t=0;t<4;t++) { //the idea here is to pad out the mirrored space with copies of the mappable area, //without respect to what is mapped within that mappable area. //we hope that this is correct in all cases //required for driller spirits in mission select (mapping is simple A,B,C,D to each purpose) const int size = sizes[t]; const int mask = size-1; const int type = types[t]; for(int i=size;i<128;i++) { const int page = type + i; vram_arm9_map[page] = vram_arm9_map[type+(i&mask)]; } //attempt #1: screen corruption in drill spirits EU //it seems like these shouldnt pad out 128K banks (space beyond those should have remained unmapped) //int mirrorMask = -1; //int type = types[t]; ////if(type==VRAM_PAGE_BOBJ) continue; //if(type==VRAM_PAGE_AOBJ) continue; //for(int i=0;i<128;i++) //{ // int page = type + i; // if(vram_arm9_map[page] == VRAM_PAGE_UNMAPPED) // { // if(i==0) break; //can't mirror anything if theres nothing mapped! // if(mirrorMask == -1) // mirrorMask = i-1; // vram_arm9_map[page] = vram_arm9_map[type+(i&mirrorMask)]; // } //} } //------------------------------- } ////////////////////////////////////////////////////////////// //end vram ////////////////////////////////////////////////////////////// void MMU_Init() { //LOG("MMU init\n"); memset(&MMU, 0, sizeof(MMU_struct)); MMU.CART_ROM = MMU.UNUSED_RAM; //MMU.DTCMRegion = 0x027C0000; //even though apps may change dtcm immediately upon startup, this is the correct hardware starting value: MMU.DTCMRegion = 0x08000000; MMU.ITCMRegion = 0x00000000; IPC_FIFOinit(ARMCPU_ARM9); IPC_FIFOinit(ARMCPU_ARM7); //GFX_PIPEclear(); //GFX_FIFOclear(); //DISP_FIFOinit(); new(&MMU_new) MMU_struct_new; mc_init(&MMU.fw, MC_TYPE_FLASH); /* init fw device */ mc_alloc(&MMU.fw, NDS_FW_SIZE_V1); MMU.fw.fp = NULL; MMU.fw.isFirmware = true; // Init Backup Memory device, this should really be done when the rom is loaded //mc_init(&MMU.bupmem, MC_TYPE_AUTODETECT); //mc_alloc(&MMU.bupmem, 1); //MMU.bupmem.fp = NULL; //rtcInit(); //addonsInit(); //slot1Init(); /*if(Mic_Init() == false) INFO("Microphone init failed.\n"); else INFO("Microphone successfully inited.\n");*/ } void MMU_DeInit() { //LOG("MMU deinit\n"); /*if (MMU.fw.fp) fclose(MMU.fw.fp);*/ mc_free(&MMU.fw); //if (MMU.bupmem.fp) // fclose(MMU.bupmem.fp); //mc_free(&MMU.bupmem); //addonsClose(); //slot1Close(); //Mic_DeInit(); } void MMU_Reset() { memset(MMU.ARM9_DTCM, 0, sizeof(MMU.ARM9_DTCM)); memset(MMU.ARM9_ITCM, 0, sizeof(MMU.ARM9_ITCM)); memset(MMU.ARM9_LCD, 0, sizeof(MMU.ARM9_LCD)); memset(MMU.ARM9_OAM, 0, sizeof(MMU.ARM9_OAM)); memset(MMU.ARM9_REG, 0, sizeof(MMU.ARM9_REG)); memset(MMU.ARM9_VMEM, 0, sizeof(MMU.ARM9_VMEM)); memset(MMU.MAIN_MEM, 0, sizeof(MMU.MAIN_MEM)); memset(MMU.blank_memory, 0, sizeof(MMU.blank_memory)); memset(MMU.UNUSED_RAM, 0, sizeof(MMU.UNUSED_RAM)); memset(MMU.MORE_UNUSED_RAM, 0, sizeof(MMU.UNUSED_RAM)); memset(MMU.ARM7_ERAM, 0, sizeof(MMU.ARM7_ERAM)); memset(MMU.ARM7_REG, 0, sizeof(MMU.ARM7_REG)); memset(MMU.ARM7_WIRAM, 0, sizeof(MMU.ARM7_WIRAM)); memset(MMU.SWIRAM, 0, sizeof(MMU.SWIRAM)); IPC_FIFOinit(ARMCPU_ARM9); IPC_FIFOinit(ARMCPU_ARM7); //GFX_PIPEclear(); //GFX_FIFOclear(); //DISP_FIFOinit(); MMU.DTCMRegion = 0x027C0000; MMU.ITCMRegion = 0x00000000; memset(MMU.timer, 0, sizeof(uint16_t) * 2 * 4); memset(MMU.timerMODE, 0, sizeof(int32_t) * 2 * 4); memset(MMU.timerON, 0, sizeof(uint32_t) * 2 * 4); memset(MMU.timerRUN, 0, sizeof(uint32_t) * 2 * 4); memset(MMU.timerReload, 0, sizeof(uint16_t) * 2 * 4); memset(MMU.reg_IME, 0, sizeof(uint32_t) * 2); memset(MMU.reg_IE, 0, sizeof(uint32_t) * 2); memset(MMU.reg_IF_bits, 0, sizeof(uint32_t) * 2); memset(MMU.reg_IF_pending, 0, sizeof(uint32_t) * 2); memset(MMU.dscard, 0, sizeof(nds_dscard) * 2); MMU.divRunning = 0; MMU.divResult = 0; MMU.divMod = 0; MMU.divCycles = 0; MMU.sqrtRunning = 0; MMU.sqrtResult = 0; MMU.sqrtCycles = 0; MMU.SPI_CNT = 0; MMU.AUX_SPI_CNT = 0; // Enable the sound speakers T1WriteWord(MMU.ARM7_REG, 0x304, 0x0001); //MainScreen.offset = 0; //SubScreen.offset = 192; MMU_VRAM_unmap_all(); MMU.powerMan_CntReg = 0x00; MMU.powerMan_CntRegWritten = false; MMU.powerMan_Reg[0] = 0x0B; MMU.powerMan_Reg[1] = 0x00; MMU.powerMan_Reg[2] = 0x01; MMU.powerMan_Reg[3] = 0x00; //rtcInit(); partie = 1; //addonsReset(); //slot1Reset(); //Mic_Reset(); //MMU.gfx3dCycles = 0; memset(MMU.dscard[ARMCPU_ARM9].command, 0, 8); MMU.dscard[ARMCPU_ARM9].address = 0; MMU.dscard[ARMCPU_ARM9].transfer_count = 0; MMU.dscard[ARMCPU_ARM9].mode = CardMode_Normal; memset(MMU.dscard[ARMCPU_ARM7].command, 0, 8); MMU.dscard[ARMCPU_ARM7].address = 0; MMU.dscard[ARMCPU_ARM7].transfer_count = 0; MMU.dscard[ARMCPU_ARM7].mode = CardMode_Normal; //HACK!!! //until we improve all our session tracking stuff, we need to save the backup memory filename std::string bleh = MMU_new.backupDevice.getFilename(); BackupDevice tempBackupDevice; //bool bleh2 = MMU_new.backupDevice.isMovieMode; //if(bleh2) tempBackupDevice = MMU_new.backupDevice; reconstruct(&MMU_new); /*if(bleh2) { MMU_new.backupDevice = tempBackupDevice; MMU_new.backupDevice.reset_hardware(); } else*/ MMU_new.backupDevice.load_rom(bleh.c_str()); MMU_timing.arm7codeFetch.Reset(); MMU_timing.arm7dataFetch.Reset(); MMU_timing.arm9codeFetch.Reset(); MMU_timing.arm9dataFetch.Reset(); MMU_timing.arm9codeCache.Reset(); MMU_timing.arm9dataCache.Reset(); } void SetupMMU(bool debugConsole, bool dsi) { if(debugConsole) _MMU_MAIN_MEM_MASK = 0x7FFFFF; else _MMU_MAIN_MEM_MASK = 0x3FFFFF; if(dsi) _MMU_MAIN_MEM_MASK = 0xFFFFFF; _MMU_MAIN_MEM_MASK16 = _MMU_MAIN_MEM_MASK & ~1; _MMU_MAIN_MEM_MASK32 = _MMU_MAIN_MEM_MASK & ~3; } void MMU_setRom(uint8_t * rom, uint32_t) { MMU.CART_ROM = rom; } void MMU_unsetRom() { MMU.CART_ROM=MMU.UNUSED_RAM; } static void execsqrt() { uint32_t ret; uint8_t mode = MMU_new.sqrt.mode; MMU_new.sqrt.busy = 1; if (mode) { uint64_t v = T1ReadQuad(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x2B8); ret = (uint32_t)isqrt(v); } else { uint32_t v = T1ReadLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x2B8); ret = (uint32_t)isqrt(v); } //clear the result while the sqrt unit is busy //todo - is this right? is it reasonable? T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x2B4, 0); MMU.sqrtCycles = nds_timer + 26; MMU.sqrtResult = ret; MMU.sqrtRunning = true; NDS_Reschedule(); } static void execdiv() { int64_t num,den; int64_t res,mod; uint8_t mode = MMU_new.div.mode; MMU_new.div.busy = 1; MMU_new.div.div0 = 0; switch(mode) { case 0: // 32/32 num = (int64_t) (int32_t) T1ReadLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x290); den = (int64_t) (int32_t) T1ReadLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x298); MMU.divCycles = nds_timer + 36; break; case 1: // 64/32 case 3: //gbatek says this is same as mode 1 num = (int64_t) T1ReadQuad(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x290); den = (int64_t) (int32_t) T1ReadLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x298); MMU.divCycles = nds_timer + 68; break; case 2: // 64/64 default: num = (int64_t) T1ReadQuad(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x290); den = (int64_t) T1ReadQuad(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x298); MMU.divCycles = nds_timer + 68; break; } if(den==0) { res = ((num < 0) ? 1 : -1); mod = num; // the DIV0 flag in DIVCNT is set only if the full 64bit DIV_DENOM value is zero, even in 32bit mode if ((uint64_t)T1ReadQuad(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x298) == 0) MMU_new.div.div0 = 1; } else { res = num / den; mod = num % den; } /*DIVLOG("DIV %08X%08X / %08X%08X = %08X%08X\r\n", (uint32_t)(num>>32), (uint32_t)num, (uint32_t)(den>>32), (uint32_t)den, (uint32_t)(res>>32), (uint32_t)res);*/ T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x2A0, 0); T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x2A4, 0); T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x2A8, 0); T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x2AC, 0); MMU.divResult = res; MMU.divMod = mod; MMU.divRunning = true; NDS_Reschedule(); } DSI_TSC::DSI_TSC() { for(unsigned i=0;i>1)&0x7F; read_flag = val&1; state = 1; return read16(); case 1: if(read_flag) { } else { registers[reg_selection] = (uint8_t)val; } ret = read16(); reg_selection++; reg_selection &= 0x7F; return ret; } return 0; } uint16_t DSI_TSC::read16() { uint8_t page = registers[0]; switch(page) { case 3: //page 3 switch(reg_selection) { case 9: /*if(nds.isTouch) return 0; else */return 0x40; break; case 14: /*if(nds.isTouch) return 0; else */return 0x02; break; } break; case 252: //page 252 switch(reg_selection) { //high byte of X: /*case 1: case 3: case 5: case 7: case 9: return (nds.scr_touchX>>8)&0xFF; //low byte of X: case 2: case 4: case 6: case 8: case 10: return nds.scr_touchX&0xFF; //high byte of Y: case 11: case 13: case 15: case 17: case 19: return (nds.scr_touchY>>8)&0xFF; //low byte of Y: case 12: case 14: case 16: case 18: case 20: return nds.scr_touchY&0xFF;*/ default: return 0xFF; } break; } //switch(page) //unknown page or register return 0xFF; } /*bool DSI_TSC::save_state(EMUFILE* os) { uint32_t version = 0; write32le(version,os); write8le(reg_selection,os); write8le(read_flag,os); write32le(state,os); write32le(readcount,os); for(int i=0;i void FASTCALL MMU_writeToGCControl(uint32_t val) { const int TEST_PROCNUM = PROCNUM; nds_dscard& card = MMU.dscard[TEST_PROCNUM]; memcpy(&card.command[0], &MMU.MMU_MEM[TEST_PROCNUM][0x40][0x1A8], 8); card.blocklen = 0; slot1_device.write32(PROCNUM,0xFFFFFFFF,val); //Special case for some flashcarts if(card.blocklen==0x01020304) return; if(!(val & 0x80000000)) { card.address = 0; card.transfer_count = 0; val &= 0x7F7FFFFF; T1WriteLong(MMU.MMU_MEM[TEST_PROCNUM][0x40], 0x1A4, val); return; } uint32_t shift = (val>>24&7); if(shift == 7) card.transfer_count = 1; else if(shift == 0) card.transfer_count = 0; else card.transfer_count = (0x100< uint32_t MMU_readFromGC() { const int TEST_PROCNUM = PROCNUM; nds_dscard& card = MMU.dscard[TEST_PROCNUM]; uint32_t val = 0; if(card.transfer_count == 0) return 0; switch(card.command[0]) { case 0x9F: //Dummy val = 0xFFFFFFFF; break; case 0x3C: //Switch to KEY1 mode val = 0xFFFFFFFF; break; default: val = slot1_device.read32(TEST_PROCNUM, REG_GCDATAIN); break; } card.address += 4; // increment address card.transfer_count--; // update transfer counter if(card.transfer_count) // if transfer is not ended return val; // return data // transfer is done T1WriteLong(MMU.MMU_MEM[TEST_PROCNUM][0x40], 0x1A4, T1ReadLong(MMU.MMU_MEM[TEST_PROCNUM][0x40], 0x1A4) & 0x7F7FFFFF); // if needed, throw irq for the end of transfer if(MMU.AUX_SPI_CNT & 0x4000) NDS_makeIrq(TEST_PROCNUM, IRQ_BIT_GC_TRANSFER_COMPLETE); return val; } //does some validation on the game's choice of IF value, correcting it if necessary /*static void validateIF_arm9() { }*/ template static void REG_IF_WriteByte(uint32_t addr, uint8_t val) { //the following bits are generated from logic and should not be affected here //Bit 21 NDS9 only: Geometry Command FIFO //arm9: IF &= ~0x00200000; //arm7: IF &= ~0x00000000; //UPDATE IN setIF() ALSO!!!!!!!!!!!!!!!! //UPDATE IN mmu_loadstate ALSO!!!!!!!!!!!! if(addr==2) { if(PROCNUM==ARMCPU_ARM9) val &= ~0x20; else val &= ~0x00; } //ZERO 01-dec-2010 : I am no longer sure this approach is correct.. it proved to be wrong for IPC fifo....... //it seems as if IF bits should always be cached (only the user can clear them) MMU.reg_IF_bits[PROCNUM] &= (~(((uint32_t)val)<<(addr<<3))); NDS_Reschedule(); } template static void REG_IF_WriteWord(uint32_t addr,uint16_t val) { REG_IF_WriteByte(addr,val&0xFF); REG_IF_WriteByte(addr+1,(val>>8)&0xFF); } template static void REG_IF_WriteLong(uint32_t val) { REG_IF_WriteByte(0,val&0xFF); REG_IF_WriteByte(1,(val>>8)&0xFF); REG_IF_WriteByte(2,(val>>16)&0xFF); REG_IF_WriteByte(3,(val>>24)&0xFF); } template uint32_t MMU_struct::gen_IF() { uint32_t IF = reg_IF_bits[PROCNUM]; /*if(PROCNUM==ARMCPU_ARM9) { //according to gbatek, these flags are forced on until the condition is removed. //no proof of this though... switch(MMU_new.gxstat.gxfifo_irq) { case 0: //never break; case 1: //less than half full if(MMU_new.gxstat.fifo_low) IF |= IRQ_MASK_ARM9_GXFIFO; break; case 2: //empty if(MMU_new.gxstat.fifo_empty) IF |= IRQ_MASK_ARM9_GXFIFO; break; case 3: //reserved/unknown break; } }*/ return IF; } /*static void writereg_DISP3DCNT(const int size, const uint32_t adr, const uint32_t val) { //UGH. rewrite this shite to use individual values and reconstruct the return value instead of packing things in this !@#)ing register //nanostray2 cutscene will test this vs old desmumes by using some kind of 32bit access for setting up this reg for cutscenes switch(size) { case 8: switch(adr) { case REG_DISPA_DISP3DCNT: MMU.reg_DISP3DCNT_bits &= 0xFFFFFF00; MMU.reg_DISP3DCNT_bits |= val; //gfx3d_Control(MMU.reg_DISP3DCNT_bits); break; case REG_DISPA_DISP3DCNT+1: { uint32_t myval = (val & ~0x30) | (~val & ((MMU.reg_DISP3DCNT_bits>>8) & 0x30)); // bits 12,13 are ack bits myval &= 0x7F; //top bit isnt connected MMU.reg_DISP3DCNT_bits = MMU.reg_DISP3DCNT_bits&0xFFFF00FF; MMU.reg_DISP3DCNT_bits |= (myval<<8); //gfx3d_Control(MMU.reg_DISP3DCNT_bits); } break; } break; case 16: case 32: writereg_DISP3DCNT(8,adr,val&0xFF); writereg_DISP3DCNT(8,adr+1,(val>>8)&0xFF); break; } }*/ /*static uint32_t readreg_DISP3DCNT(const int size, const uint32_t adr) { //UGH. rewrite this shite to use individual values and reconstruct the return value instead of packing things in this !@#)ing register switch(size) { case 8: switch(adr) { case REG_DISPA_DISP3DCNT: return MMU.reg_DISP3DCNT_bits & 0xFF; case REG_DISPA_DISP3DCNT+1: return ((MMU.reg_DISP3DCNT_bits)>>8)& 0xFF; } break; case 16: case 32: return readreg_DISP3DCNT(8,adr)|(readreg_DISP3DCNT(8,adr+1)<<8); } assert(false); return 0; }*/ /*static uint32_t readreg_POWCNT1(const int size, const uint32_t adr) { switch(size) { case 8: switch(adr) { case REG_POWCNT1: { uint8_t ret = 0; ret |= nds.power1.lcd?BIT(0):0; ret |= nds.power1.gpuMain?BIT(1):0; ret |= nds.power1.gfx3d_render?BIT(2):0; ret |= nds.power1.gfx3d_geometry?BIT(3):0; return ret; } case REG_POWCNT1+1: { uint8_t ret = 0; ret |= nds.power1.gpuSub?BIT(1):0; ret |= nds.power1.dispswap?BIT(7):0; return ret; } } case 16: case 32: return readreg_POWCNT1(8,adr)|(readreg_POWCNT1(8,adr+1)<<8); } assert(false); return 0; }*/ /*static void writereg_POWCNT1(const int size, const uint32_t adr, const uint32_t val) { switch(size) { case 8: switch(adr) { case REG_POWCNT1: nds.power1.lcd = BIT0(val); nds.power1.gpuMain = BIT1(val); nds.power1.gfx3d_render = BIT2(val); nds.power1.gfx3d_geometry = BIT3(val); break; case REG_POWCNT1+1: nds.power1.gpuSub = BIT1(val); nds.power1.dispswap = BIT7(val); if(nds.power1.dispswap) { //printf("Main core on top (vcount=%d)\n",nds.VCount); //MainScreen.offset = 0; //SubScreen.offset = 192; } else { //printf("Main core on bottom (vcount=%d)\n",nds.VCount); //MainScreen.offset = 192; //SubScreen.offset = 0; } break; } break; case 16: case 32: writereg_POWCNT1(8,adr,val&0xFF); writereg_POWCNT1(8,adr+1,(val>>8)&0xFF); break; } }*/ static inline void MMU_IPCSync(uint8_t proc, uint32_t val) { //INFO("IPC%s sync 0x%04X (0x%02X|%02X)\n", proc?"7":"9", val, val >> 8, val & 0xFF); uint32_t sync_l = T1ReadLong(MMU.MMU_MEM[proc][0x40], 0x180) & 0xFFFF; uint32_t sync_r = T1ReadLong(MMU.MMU_MEM[proc^1][0x40], 0x180) & 0xFFFF; sync_l = ( sync_l & 0x000F ) | ( val & 0x0F00 ); sync_r = ( sync_r & 0x6F00 ) | ( (val >> 8) & 0x000F ); sync_l |= val & 0x6000; /*if(nds.ensataEmulation && proc==1 && nds.ensataIpcSyncCounter<9) { uint32_t iteration = (val&0x0F00)>>8;*/ /*if(iteration==8-nds.ensataIpcSyncCounter) nds.ensataIpcSyncCounter++; else printf("ERROR: ENSATA IPC SYNC HACK FAILED; BAD THINGS MAY HAPPEN\n");*/ //for some reason, the arm9 doesn't handshake when ensata is detected. //so we complete the protocol here, which is to mirror the values 8..0 back to //the arm7 as they are written by the arm7 /*sync_r &= 0xF0FF; sync_r |= (iteration<<8); sync_l &= 0xFFF0; sync_l |= iteration; }*/ T1WriteLong(MMU.MMU_MEM[proc][0x40], 0x180, sync_l); T1WriteLong(MMU.MMU_MEM[proc^1][0x40], 0x180, sync_r); if ((sync_l & IPCSYNC_IRQ_SEND) && (sync_r & IPCSYNC_IRQ_RECV)) NDS_makeIrq(proc^1, IRQ_BIT_IPCSYNC); NDS_Reschedule(); } static inline uint16_t read_timer(int proc, int timerIndex) { //chained timers are always up to date if(MMU.timerMODE[proc][timerIndex] == 0xFFFF) return MMU.timer[proc][timerIndex]; //sometimes a timer will be read when it is not enabled. //we should have the value cached if(!MMU.timerON[proc][timerIndex]) return MMU.timer[proc][timerIndex]; //for unchained timers, we do not keep the timer up to date. its value will need to be calculated here int32_t diff = (int32_t)(nds.timerCycle[proc][timerIndex] - nds_timer); assert(diff>=0); if(diff<0) printf("NEW EMULOOP BAD NEWS PLEASE REPORT: TIME READ DIFF < 0 (%d) (%d) (%d)\n",diff,timerIndex,MMU.timerMODE[proc][timerIndex]); int32_t units = diff / (1<65536) { printf("NEW EMULOOP BAD NEWS PLEASE REPORT: UNITS %d:%d = %d\n",proc,timerIndex,units); ret = 0; } else ret = 65535 - units; return static_cast(ret); } static inline void write_timer(int proc, int timerIndex, uint16_t val) { #if 0 int mask = ((val&0x80)>>7) << timerIndex; MMU.CheckTimers = (MMU.CheckTimers & (~mask)) | mask; #endif if(val&0x80) MMU.timer[proc][timerIndex] = MMU.timerReload[proc][timerIndex]; else { if(MMU.timerON[proc][timerIndex]) //read the timer value one last time MMU.timer[proc][timerIndex] = read_timer(proc,timerIndex); } MMU.timerON[proc][timerIndex] = val & 0x80; switch(val&7) { case 0 : MMU.timerMODE[proc][timerIndex] = 0+1; break; case 1 : MMU.timerMODE[proc][timerIndex] = 6+1; break; case 2 : MMU.timerMODE[proc][timerIndex] = 8+1; break; case 3 : MMU.timerMODE[proc][timerIndex] = 10+1; break; default : MMU.timerMODE[proc][timerIndex] = 0xFFFF; break; } int remain = 65536 - MMU.timerReload[proc][timerIndex]; nds.timerCycle[proc][timerIndex] = nds_timer + (remain<=255) ret |= BIT(24); //fifo full //if(gxFIFO.size<128) ret |= BIT(25); //fifo half //if(gxFIFO.size==0) ret |= BIT(26); //fifo empty //determine busy flag. //if we're waiting for a flush, we're busy //if(isSwapBuffers) ret |= BIT(27); //if fifo is nonempty, we're busy //if(gxFIFO.size!=0) ret |= BIT(27); ret |= ((gxfifo_irq & 0x3) << 30); //user's irq flags //printf("vc=%03d Returning gxstat read: %08X\n",nds.VCount,ret); //ret = (2 << 8); //INFO("gxSTAT 0x%08X (proj %i, pos %i)\n", ret, _hack_getMatrixStackLevel(1), _hack_getMatrixStackLevel(2)); return ret; } void TGXSTAT::write32(const uint32_t val) { gxfifo_irq = (val>>30)&3; if(BIT15(val)) { // Writing "1" to Bit15 does reset the Error Flag (Bit15), // and additionally resets the Projection Stack Pointer (Bit13) //mtxStack[0].position = 0; se = 0; //clear stack error flag } //printf("gxstat write: %08X while gxfifo.size=%d\n",val,gxFIFO.size); //if (val & (1<<29)) // clear? (only in homebrew?) //{ // GFX_PIPEclear(); // GFX_FIFOclear(); // return; //} } /*void TGXSTAT::savestate(EMUFILE *f) { write32le(1,f); //version write8le(tb,f); write8le(tr,f); write8le(se,f); write8le(gxfifo_irq,f); write8le(sb,f); }*/ bool TGXSTAT::loadstate(EMUFILE *f) { uint32_t version; if(read32le(&version,f) != 1) return false; if(version > 1) return false; read8le(&tb,f); read8le(&tr,f); read8le(&se,f); read8le(&gxfifo_irq,f); if (version >= 1) read8le(&sb,f); return true; } //this could be inlined... void MMU_struct_new::write_dma(const int proc, const int size, const uint32_t _adr, const uint32_t val) { //printf("%08lld -- write_dma: %d %d %08X %08X\n",nds_timer,proc,size,_adr,val); const uint32_t adr = _adr - _REG_DMA_CONTROL_MIN; const uint32_t chan = adr/12; const uint32_t regnum = (adr - chan*12)>>2; if(proc==0&&chan==0) { //int zzz=9; } if(proc==1) { //int zzz=9; } MMU_new.dma[proc][chan].regs[regnum]->write(size,adr,val); } //this could be inlined... uint32_t MMU_struct_new::read_dma(const int proc, const int size, const uint32_t _adr) { const uint32_t adr = _adr - _REG_DMA_CONTROL_MIN; const uint32_t chan = adr/12; const uint32_t regnum = (adr - chan*12)>>2; const uint32_t temp = MMU_new.dma[proc][chan].regs[regnum]->read(size,adr); //printf("%08lld -- read_dma: %d %d %08X = %08X\n",nds_timer,proc,size,_adr,temp); if(temp == 0xAF00 && size == 16) { //int zzz=9; } return temp; } MMU_struct_new::MMU_struct_new() { for(int i=0;i<2;i++) for(int j=0;j<4;j++) { dma[i][j].procnum = i; dma[i][j].chan = j; } } bool DmaController::loadstate(EMUFILE* f) { uint32_t version; if(read32le(&version,f) != 1) return false; if(version >1) return false; read8le(&enable,f); read8le(&irq,f); read8le(&repeatMode,f); read8le(&_startmode,f); read8le(&userEnable,f); read32le(&wordcount,f); uint8_t temp; read8le(&temp,f); startmode = (EDMAMode)temp; read8le(&temp,f); bitWidth = (EDMABitWidth)temp; read8le(&temp,f); sar = (EDMASourceUpdate)temp; read8le(&temp,f); dar = (EDMADestinationUpdate)temp; read32le(&saddr,f); read32le(&daddr,f); read32le(reinterpret_cast(&dmaCheck),f); read32le(reinterpret_cast(&running),f); read32le(reinterpret_cast(&paused),f); read32le(reinterpret_cast(&triggered),f); read64le(&nextEvent,f); if(version==1) { read32le(&saddr_user,f); read32le(&daddr_user,f); } return true; } /*void DmaController::savestate(EMUFILE *f) { write32le(1,f); //version write8le(enable,f); write8le(irq,f); write8le(repeatMode,f); write8le(_startmode,f); write8le(userEnable,f); write32le(wordcount,f); write8le(startmode,f); write8le(bitWidth,f); write8le(sar,f); write8le(dar,f); write32le(saddr,f); write32le(daddr,f); write32le(check,f); write32le(running,f); write32le(paused,f); write32le(triggered,f); write64le(nextEvent,f); write32le(saddr_user,f); write32le(daddr_user,f); }*/ void DmaController::write32(const uint32_t val) { if(this->chan==0 && this->procnum==0) { //int zzz=9; } if(running) { //desp triggers this a lot. figure out whats going on //printf("thats weird..user edited dma control while it was running\n"); } //printf("dma %d,%d WRITE %08X\n",procnum,chan,val); wordcount = val&0x1FFFFF; if(wordcount==0x9FbFC || wordcount == 0x1FFFFC || wordcount == 0x1EFFFC || wordcount == 0x1FFFFF) { //int zzz=9; } //uint8_t wasRepeatMode = repeatMode; uint8_t wasEnable = enable; uint32_t valhi = val>>16; dar = (EDMADestinationUpdate)((valhi>>5)&3); sar = (EDMASourceUpdate)((valhi>>7)&3); repeatMode = static_cast(BIT9(valhi)); bitWidth = (EDMABitWidth)BIT10(valhi); _startmode = (valhi>>11)&7; if(procnum==ARMCPU_ARM7) _startmode &= 6; irq = static_cast(BIT14(valhi)); enable = static_cast(BIT15(valhi)); if(val==0x84400076 && saddr ==0x023BCEC4) { //int zzz=9; } //if(irq) printf("!!!!!!!!!!!!IRQ!!!!!!!!!!!!!\n"); //make sure we don't get any old triggers if(!wasEnable && enable) triggered = false; if(enable) { //address registers are reloaded from user's settings whenever dma is enabled //this is tested well by contra4 classic games, which use this to hdma scroll registers //specifically in the fit-screen mode. saddr = saddr_user; daddr = daddr_user; } //printf("dma %d,%d set to startmode %d with wordcount set to: %08X\n",procnum,chan,_startmode,wordcount); if(_startmode==0 && wordcount==1) { //int zzz=9; } if(enable) { //int zzz=9; } //analyze enabling and startmode. //note that we only do this if the dma was freshly enabled. //we should probably also only be latching these other regs in that case too.. //but for now just this one will do (otherwise the dma repeat stop procedure (in this case the ff4 title menu load with gamecard dma) will fail) //if(!running) enable = userEnable; //if we were previously in a triggered mode, and were already enabled, //then don't re-trigger now. this is rather confusing.. //we really only want to auto-trigger gxfifo and immediate modes. //but we don't know what mode we're in yet. //so this is our workaround //(otherwise the dma repeat stop procedure (in this case the ff4 title menu load with gamecard dma) will fail) bool doNotStart = false; if(startmode != EDMAMode_Immediate/* && startmode != EDMAMode_GXFifo*/ && wasEnable) doNotStart = true; //this dma may need to trigger now, so give it a chance //if(!(wasRepeatMode && !repeatMode)) //this was an older test if(!doNotStart) doSchedule(); //driver->DEBUG_UpdateIORegView(BaseDriver::EDEBUG_IOREG_DMA); } void DmaController::exec() { //this function runs when the DMA ends. the dma start actually queues this event after some kind of guess as to how long the DMA should take //we'll need to unfreeze the arm9 bus now if(procnum==ARMCPU_ARM9) nds.freezeBus &= ~(1<<(chan+1)); dmaCheck = false; if(running) { switch(startmode) { /*case EDMAMode_GXFifo: //this dma mode won't finish always its job when it gets signalled //sometimes it will have words left to transfer. //if(!paused) printf("gxfifo dma ended with %d remaining\n",wordcount); //only print this once if(wordcount>0) { doPause(); break; }*/ default: doStop(); //driver->DEBUG_UpdateIORegView(BaseDriver::EDEBUG_IOREG_DMA); return; } } if(enable) { //analyze startmode (this only gets latched when a dma begins) if(procnum==ARMCPU_ARM9) startmode = (EDMAMode)_startmode; else { //arm7 startmode analysis: static const EDMAMode lookup[] = {EDMAMode_Immediate,EDMAMode_VBlank,EDMAMode_Card,EDMAMode7_Wifi}; //arm7 has a slightly different startmode encoding startmode = lookup[_startmode>>1]; if(startmode == EDMAMode7_Wifi && (chan==1 || chan==3)) startmode = EDMAMode7_GBASlot; } //make it run, if it is triggered //but first, scan for triggering conditions switch(startmode) { case EDMAMode_Immediate: triggered = true; break; /*case EDMAMode_GXFifo: if(gxFIFO.size<=127) triggered = true; break;*/ default: break; } if(triggered) { //if(procnum==0) printf("vc=%03d %08lld trig type %d dma#%d w/words %d at src:%08X dst:%08X gxf:%d",nds.VCount,nds_timer,startmode,chan,wordcount,saddr,daddr,gxFIFO.size); if(saddr ==0x023BCCEC && wordcount==118) { //int zzz=9; } if(startmode==0 && daddr == 0x4000400) { //int zzz=9; } running = true; paused = false; if(procnum == ARMCPU_ARM9) doCopy(); else doCopy(); //printf(";%d\n",gxFIFO.size); } } //driver->DEBUG_UpdateIORegView(BaseDriver::EDEBUG_IOREG_DMA); } template void DmaController::doCopy() { //generate a copy count depending on various copy mode's behavior uint32_t todo = wordcount; if(todo == 0) todo = 0x200000; //according to gbatek.. //TODO - this should not work this way for arm7 according to gbatek if(startmode == EDMAMode_MemDisplay) { todo = 128; //this is a hack. maybe an alright one though. it should be 4 words at a time. this is a whole scanline //apparently this dma turns off after it finishes a frame if(nds.VCount==191) enable = 0; } if(startmode == EDMAMode_Card) todo *= 0x80; //if(startmode == EDMAMode_GXFifo) todo = std::min(todo,(uint32_t)112); //determine how we're going to copy bool bogarted = false; uint32_t sz = (bitWidth==EDMABitWidth_16)?2:4; uint32_t dstinc = 0,srcinc = 0; switch(dar) { case EDMADestinationUpdate_Increment : dstinc = sz; break; case EDMADestinationUpdate_Decrement : dstinc = (uint32_t)-(int32_t)sz; break; case EDMADestinationUpdate_Fixed : dstinc = 0; break; case EDMADestinationUpdate_IncrementReload : dstinc = sz; break; default: bogarted = true; break; } switch(sar) { case EDMASourceUpdate_Increment : srcinc = sz; break; case EDMASourceUpdate_Decrement : srcinc = (uint32_t)-(int32_t)sz; break; case EDMASourceUpdate_Fixed : srcinc = 0; break; case EDMASourceUpdate_Invalid : bogarted = true; break; default: bogarted = true; break; } //need to figure out what to do about this if(bogarted) { printf("YOUR GAME IS BOGARTED!!! PLEASE REPORT!!!\n"); assert(false); return; } uint32_t src = saddr; uint32_t dst = daddr; //if these do not use MMU_AT_DMA and the corresponding code in the read/write routines, //then danny phantom title screen will be filled with a garbage char which is made by //dmaing from 0x00000000 to 0x06000000 //TODO - these might be losing out a lot by not going through the templated version anymore. //we might make another function to do just the raw copy op which can use them with checks //outside the loop int time_elapsed = 0; if(sz==4) { for(int32_t i=(int32_t)todo; i>0; i--) { time_elapsed += _MMU_accesstime(src,true); time_elapsed += _MMU_accesstime(dst,true); uint32_t temp = _MMU_read32(procnum,MMU_AT_DMA,src); _MMU_write32(procnum,MMU_AT_DMA,dst, temp); dst += dstinc; src += srcinc; } } else { for(int32_t i=(int32_t)todo; i>0; i--) { time_elapsed += _MMU_accesstime(src,true); time_elapsed += _MMU_accesstime(dst,true); uint16_t temp = _MMU_read16(procnum,MMU_AT_DMA,src); _MMU_write16(procnum,MMU_AT_DMA,dst, temp); dst += dstinc; src += srcinc; } } //reschedule an event for the end of this dma, and figure out how much it cost us doSchedule(); // zeromus, check it if (wordcount > todo) nextEvent += todo/4; //TODO - surely this is a gross simplification //apparently moon has very, very tight timing (i didnt spy it using waitbyloop swi...) //so lets bump this down a bit for now, //(i think this code is in nintendo libraries) //write back the addresses saddr = src; if(dar != EDMADestinationUpdate_IncrementReload) //but dont write back dst if we were supposed to reload daddr = dst; //do wordcount accounting if(startmode == EDMAMode_Card) todo /= 0x80; //divide this funky one back down before subtracting it if(!repeatMode) wordcount -= todo; } void triggerDma(EDMAMode mode) { MACRODO2(0, { const int i=X; MACRODO4(0, { const int j=X; MMU_new.dma[i][j].tryTrigger(mode); }); }); } void DmaController::tryTrigger(EDMAMode mode) { if(startmode != mode) return; if(!enable) return; //hmm dont trigger it if its already running! //but paused things need triggers to continue if(running && !paused) return; triggered = true; doSchedule(); } void DmaController::doSchedule() { dmaCheck = true; nextEvent = nds_timer; NDS_RescheduleDMA(); } void DmaController::doPause() { triggered = false; paused = true; } void DmaController::doStop() { //if(procnum==0) printf("%08lld stop type %d dma#%d\n",nds_timer,startmode,chan); running = false; if(!repeatMode) enable = false; if(irq) { NDS_makeIrq(procnum,IRQ_BIT_DMA_0+chan); } } uint32_t DmaController::read32() { uint32_t ret = 0; ret |= enable<<31; ret |= irq<<30; ret |= _startmode<<27; ret |= bitWidth<<26; ret |= repeatMode<<25; ret |= sar<<23; ret |= dar<<21; ret |= wordcount; //printf("dma %d,%d READ %08X\n",procnum,chan,ret); if(ret == 0xAF000001) { //int zzz=9; } return ret; } /*static inline void write_auxspicnt(const int, const int size, const int adr, const int val) { //why val==0 to reset? is it a particular bit? its not bit 6... switch(size) { case 16: MMU.AUX_SPI_CNT = val; if (val == 0) MMU_new.backupDevice.reset_command(); break; case 8: switch(adr) { case 0: T1WriteByte((uint8_t*)&MMU.AUX_SPI_CNT,0,val); if (val == 0) MMU_new.backupDevice.reset_command(); break; case 1: T1WriteByte((uint8_t*)&MMU.AUX_SPI_CNT,1,val); break; } } }*/ //================================================================================================== ARM9 * //========================================================================================================= //========================================================================================================= //================================================= MMU write 08 void FASTCALL _MMU_ARM9_write08(uint32_t adr, uint8_t val) { adr &= 0x0FFFFFFF; //mmu_log_debug_ARM9(adr, "(write08) 0x%02X", val); if(adr < 0x02000000) { T1WriteByte(MMU.ARM9_ITCM, adr&0x7FFF, val); return; } if ( (adr >= 0x08000000) && (adr < 0x0A010000) ) { //addon.write08(adr, val); return; } //block 8bit writes to OAM and palette memory if((adr&0x0F000000)==0x07000000) return; if((adr&0x0F000000)==0x05000000) return; if (adr >> 24 == 4) { // TODO: add pal reg /*if (nds.power1.gpuMain == 0) if ((adr >= 0x04000008) && (adr<=0x0400005F)) return;*/ /*if (nds.power1.gpuSub == 0) if ((adr >= 0x04001008) && (adr<=0x0400105F)) return;*/ /*if (nds.power1.gfx3d_geometry == 0) if ((adr >= 0x04000400) && (adr<=0x040006FF)) return; if (nds.power1.gfx3d_render == 0) if ((adr >= 0x04000320) && (adr<=0x040003FF)) return;*/ if(MMU_new.is_dma(adr)) { MMU_new.write_dma(ARMCPU_ARM9,8,adr,val); return; } switch(adr) { case REG_SQRTCNT: printf("ERROR 8bit SQRTCNT WRITE\n"); return; case REG_SQRTCNT+1: printf("ERROR 8bit SQRTCNT1 WRITE\n"); return; case REG_SQRTCNT+2: printf("ERROR 8bit SQRTCNT2 WRITE\n"); return; case REG_SQRTCNT+3: printf("ERROR 8bit SQRTCNT3 WRITE\n"); return; #if 1 case REG_DIVCNT: printf("ERROR 8bit DIVCNT WRITE\n"); return; case REG_DIVCNT+1: printf("ERROR 8bit DIVCNT1 WRITE\n"); return; case REG_DIVCNT+2: printf("ERROR 8bit DIVCNT2 WRITE\n"); return; case REG_DIVCNT+3: printf("ERROR 8bit DIVCNT3 WRITE\n"); return; #endif //fog table: only write bottom 7 bits /*case eng_3D_FOG_TABLE+0x00: case eng_3D_FOG_TABLE+0x01: case eng_3D_FOG_TABLE+0x02: case eng_3D_FOG_TABLE+0x03: case eng_3D_FOG_TABLE+0x04: case eng_3D_FOG_TABLE+0x05: case eng_3D_FOG_TABLE+0x06: case eng_3D_FOG_TABLE+0x07: case eng_3D_FOG_TABLE+0x08: case eng_3D_FOG_TABLE+0x09: case eng_3D_FOG_TABLE+0x0A: case eng_3D_FOG_TABLE+0x0B: case eng_3D_FOG_TABLE+0x0C: case eng_3D_FOG_TABLE+0x0D: case eng_3D_FOG_TABLE+0x0E: case eng_3D_FOG_TABLE+0x0F: case eng_3D_FOG_TABLE+0x10: case eng_3D_FOG_TABLE+0x11: case eng_3D_FOG_TABLE+0x12: case eng_3D_FOG_TABLE+0x13: case eng_3D_FOG_TABLE+0x14: case eng_3D_FOG_TABLE+0x15: case eng_3D_FOG_TABLE+0x16: case eng_3D_FOG_TABLE+0x17: case eng_3D_FOG_TABLE+0x18: case eng_3D_FOG_TABLE+0x19: case eng_3D_FOG_TABLE+0x1A: case eng_3D_FOG_TABLE+0x1B: case eng_3D_FOG_TABLE+0x1C: case eng_3D_FOG_TABLE+0x1D: case eng_3D_FOG_TABLE+0x1E: case eng_3D_FOG_TABLE+0x1F: val &= 0x7F; break;*/ //ensata putchar port /*case 0x04FFF000: if(nds.ensataEmulation) printf("%c",val); break; case eng_3D_GXSTAT: MMU_new.gxstat.write(8,adr,val); break;*/ /*case REG_DISPA_WIN0H: GPU_setWIN0_H1(MainScreen.gpu, val); break ; case REG_DISPA_WIN0H+1: GPU_setWIN0_H0 (MainScreen.gpu, val); break ; case REG_DISPA_WIN1H: GPU_setWIN1_H1 (MainScreen.gpu,val); break ; case REG_DISPA_WIN1H+1: GPU_setWIN1_H0 (MainScreen.gpu,val); break ; */ /*case REG_DISPB_WIN0H: GPU_setWIN0_H1(SubScreen.gpu,val); break ; case REG_DISPB_WIN0H+1: GPU_setWIN0_H0(SubScreen.gpu,val); break ; case REG_DISPB_WIN1H: GPU_setWIN1_H1(SubScreen.gpu,val); break ; case REG_DISPB_WIN1H+1: GPU_setWIN1_H0(SubScreen.gpu,val); break ;*/ /*case REG_DISPA_WIN0V: GPU_setWIN0_V1(MainScreen.gpu,val) ; break ; case REG_DISPA_WIN0V+1: GPU_setWIN0_V0(MainScreen.gpu,val) ; break ; case REG_DISPA_WIN1V: GPU_setWIN1_V1(MainScreen.gpu,val) ; break ; case REG_DISPA_WIN1V+1: GPU_setWIN1_V0(MainScreen.gpu,val) ; break ; */ /*case REG_DISPB_WIN0V: GPU_setWIN0_V1(SubScreen.gpu,val) ; break ; case REG_DISPB_WIN0V+1: GPU_setWIN0_V0(SubScreen.gpu,val) ; break ; case REG_DISPB_WIN1V: GPU_setWIN1_V1(SubScreen.gpu,val) ; break ; case REG_DISPB_WIN1V+1: GPU_setWIN1_V0(SubScreen.gpu,val) ; break ;*/ /*case REG_DISPA_WININ: GPU_setWININ0(MainScreen.gpu,val) ; break ; case REG_DISPA_WININ+1: GPU_setWININ1(MainScreen.gpu,val) ; break ; case REG_DISPA_WINOUT: GPU_setWINOUT(MainScreen.gpu,val) ; break ; case REG_DISPA_WINOUT+1: GPU_setWINOBJ(MainScreen.gpu,val); break ; */ /*case REG_DISPB_WININ: GPU_setWININ0(SubScreen.gpu,val) ; break ; case REG_DISPB_WININ+1: GPU_setWININ1(SubScreen.gpu,val) ; break ; case REG_DISPB_WINOUT: GPU_setWINOUT(SubScreen.gpu,val) ; break ; case REG_DISPB_WINOUT+1: GPU_setWINOBJ(SubScreen.gpu,val) ; break ;*/ /*case REG_DISPA_BLDCNT: GPU_setBLDCNT_HIGH(MainScreen.gpu,val); break; case REG_DISPA_BLDCNT+1: GPU_setBLDCNT_LOW (MainScreen.gpu,val); break;*/ /*case REG_DISPB_BLDCNT: GPU_setBLDCNT_HIGH (SubScreen.gpu,val); break; case REG_DISPB_BLDCNT+1: GPU_setBLDCNT_LOW (SubScreen.gpu,val); break;*/ /*case REG_DISPA_BLDALPHA: MainScreen.gpu->setBLDALPHA_EVB(val); break; case REG_DISPA_BLDALPHA+1: MainScreen.gpu->setBLDALPHA_EVA(val); break;*/ /*case REG_DISPB_BLDALPHA: SubScreen.gpu->setBLDALPHA_EVB(val); break; case REG_DISPB_BLDALPHA+1: SubScreen.gpu->setBLDALPHA_EVA(val); break;*/ /*case REG_DISPA_BLDY: GPU_setBLDY_EVY(MainScreen.gpu,val) ; break ; case REG_DISPB_BLDY: GPU_setBLDY_EVY(SubScreen.gpu,val) ; break;*/ /*case REG_AUXSPICNT: write_auxspicnt(9,8,0,val); return; case REG_AUXSPICNT+1: write_auxspicnt(9,8,1,val); return; case REG_AUXSPIDATA: if(val!=0) MMU.AUX_SPI_CMD = val & 0xFF; T1WriteWord(MMU.MMU_MEM[ARMCPU_ARM9][(REG_AUXSPIDATA >> 20) & 0xff], REG_AUXSPIDATA & 0xfff, MMU_new.backupDevice.data_command((uint8_t)val,ARMCPU_ARM9)); MMU.AUX_SPI_CNT &= ~0x80; //remove busy flag return;*/ case REG_WRAMCNT: /* Update WRAMSTAT at the ARM7 side */ T1WriteByte(MMU.MMU_MEM[ARMCPU_ARM7][0x40], 0x241, val); break; //case REG_POWCNT1: writereg_POWCNT1(8,adr,val); break; //case REG_DISPA_DISP3DCNT: writereg_DISP3DCNT(8,adr,val); return; //case REG_DISPA_DISP3DCNT+1: writereg_DISP3DCNT(8,adr,val); return; case REG_IF: REG_IF_WriteByte(0,val); break; case REG_IF+1: REG_IF_WriteByte(1,val); break; case REG_IF+2: REG_IF_WriteByte(2,val); break; case REG_IF+3: REG_IF_WriteByte(3,val); break; /*case eng_3D_CLEAR_COLOR+0: case eng_3D_CLEAR_COLOR+1: case eng_3D_CLEAR_COLOR+2: case eng_3D_CLEAR_COLOR+3: //T1WriteByte((uint8_t*)&gfx3d.state.clearColor,adr-eng_3D_CLEAR_COLOR,val); break;*/ case REG_VRAMCNTA: case REG_VRAMCNTB: case REG_VRAMCNTC: case REG_VRAMCNTD: case REG_VRAMCNTE: case REG_VRAMCNTF: case REG_VRAMCNTG: case REG_VRAMCNTH: case REG_VRAMCNTI: MMU_VRAMmapControl(static_cast(adr-REG_VRAMCNTA), val); break; /*case REG_DISPA_DISPMMEMFIFO: { DISP_FIFOsend(val); return; }*/ #ifdef LOG_CARD case 0x040001A0 : /* TODO (clear): ??? */ case 0x040001A1 : case 0x040001A2 : case 0x040001A8 : case 0x040001A9 : case 0x040001AA : case 0x040001AB : case 0x040001AC : case 0x040001AD : case 0x040001AE : case 0x040001AF : LOG("%08X : %02X\r\n", adr, val); #endif } MMU.MMU_MEM[ARMCPU_ARM9][adr>>20][adr&MMU.MMU_MASK[ARMCPU_ARM9][adr>>20]]=val; return; } //bool unmapped = false, restricted = false; //adr = MMU_LCDmap(adr, unmapped, restricted); //if(unmapped) return; //if(restricted) return; //block 8bit vram writes // Removed the &0xFF as they are implicit with the adr&0x0FFFFFFF [shash] MMU.MMU_MEM[ARMCPU_ARM9][adr>>20][adr&MMU.MMU_MASK[ARMCPU_ARM9][adr>>20]]=val; } //================================================= MMU ARM9 write 16 void FASTCALL _MMU_ARM9_write16(uint32_t adr, uint16_t val) { adr &= 0x0FFFFFFE; //mmu_log_debug_ARM9(adr, "(write16) 0x%04X", val); if (adr < 0x02000000) { T1WriteWord(MMU.ARM9_ITCM, adr&0x7FFF, val); return; } if ( (adr >= 0x08000000) && (adr < 0x0A010000) ) { //addon.write16(adr, val); return; } if((adr >> 24) == 4) { // TODO: add pal reg /*if (nds.power1.gpuMain == 0) if ((adr >= 0x04000008) && (adr<=0x0400005F)) return;*/ /*if (nds.power1.gpuSub == 0) if ((adr >= 0x04001008) && (adr<=0x0400105F)) return;*/ /*if (nds.power1.gfx3d_geometry == 0) if ((adr >= 0x04000400) && (adr<=0x040006FF)) return; if (nds.power1.gfx3d_render == 0) if ((adr >= 0x04000320) && (adr<=0x040003FF)) return;*/ if(MMU_new.is_dma(adr)) { if(val==0x02e9) { //int zzz=9; } MMU_new.write_dma(ARMCPU_ARM9,16,adr,val); return; } switch (adr >> 4) { //toon table case 0x0400038: case 0x0400039: case 0x040003A: case 0x040003B: ((uint16_t *)(MMU.MMU_MEM[ARMCPU_ARM9][0x40]))[(adr & 0xFFF)>>1] = val; //gfx3d_UpdateToonTable((adr & 0x3F) >> 1, val); return; } // Address is an IO register switch(adr) { /*case eng_3D_GXSTAT: MMU_new.gxstat.write(16,adr,val); break;*/ //fog table: only write bottom 7 bits /*case eng_3D_FOG_TABLE+0x00: case eng_3D_FOG_TABLE+0x02: case eng_3D_FOG_TABLE+0x04: case eng_3D_FOG_TABLE+0x06: case eng_3D_FOG_TABLE+0x08: case eng_3D_FOG_TABLE+0x0A: case eng_3D_FOG_TABLE+0x0C: case eng_3D_FOG_TABLE+0x0E: case eng_3D_FOG_TABLE+0x10: case eng_3D_FOG_TABLE+0x12: case eng_3D_FOG_TABLE+0x14: case eng_3D_FOG_TABLE+0x16: case eng_3D_FOG_TABLE+0x18: case eng_3D_FOG_TABLE+0x1A: case eng_3D_FOG_TABLE+0x1C: case eng_3D_FOG_TABLE+0x1E: val &= 0x7F7F; break;*/ /*case REG_DISPA_BG2XL: MainScreen.gpu->setAffineStartWord(2,0,val,0); break; case REG_DISPA_BG2XH: MainScreen.gpu->setAffineStartWord(2,0,val,1); break; case REG_DISPA_BG2YL: MainScreen.gpu->setAffineStartWord(2,1,val,0); break; case REG_DISPA_BG2YH: MainScreen.gpu->setAffineStartWord(2,1,val,1); break; case REG_DISPA_BG3XL: MainScreen.gpu->setAffineStartWord(3,0,val,0); break; case REG_DISPA_BG3XH: MainScreen.gpu->setAffineStartWord(3,0,val,1); break; case REG_DISPA_BG3YL: MainScreen.gpu->setAffineStartWord(3,1,val,0); break; case REG_DISPA_BG3YH: MainScreen.gpu->setAffineStartWord(3,1,val,1); break; case REG_DISPB_BG2XL: SubScreen.gpu->setAffineStartWord(2,0,val,0); break; case REG_DISPB_BG2XH: SubScreen.gpu->setAffineStartWord(2,0,val,1); break; case REG_DISPB_BG2YL: SubScreen.gpu->setAffineStartWord(2,1,val,0); break; case REG_DISPB_BG2YH: SubScreen.gpu->setAffineStartWord(2,1,val,1); break; case REG_DISPB_BG3XL: SubScreen.gpu->setAffineStartWord(3,0,val,0); break; case REG_DISPB_BG3XH: SubScreen.gpu->setAffineStartWord(3,0,val,1); break; case REG_DISPB_BG3YL: SubScreen.gpu->setAffineStartWord(3,1,val,0); break; case REG_DISPB_BG3YH: SubScreen.gpu->setAffineStartWord(3,1,val,1); break;*/ //case REG_DISPA_DISP3DCNT: writereg_DISP3DCNT(16,adr,val); return; // Alpha test reference value - Parameters:1 /*case eng_3D_ALPHA_TEST_REF: { ((uint16_t *)(MMU.MMU_MEM[ARMCPU_ARM9][0x40]))[0x340>>1] = val; //gfx3d_glAlphaFunc(val); return; } case eng_3D_CLEAR_COLOR: case eng_3D_CLEAR_COLOR+2: { //T1WriteWord((uint8_t*)&gfx3d.state.clearColor,adr-eng_3D_CLEAR_COLOR,val); break; } // Clear background depth setup - Parameters:2 case eng_3D_CLEAR_DEPTH: { ((uint16_t *)(MMU.MMU_MEM[ARMCPU_ARM9][0x40]))[0x354>>1] = val; //gfx3d_glClearDepth(val); return; } // Fog Color - Parameters:4b case eng_3D_FOG_COLOR: { ((uint16_t *)(MMU.MMU_MEM[ARMCPU_ARM9][0x40]))[0x358>>1] = val; //gfx3d_glFogColor(val); return; } case eng_3D_FOG_OFFSET: { ((uint32_t *)(MMU.MMU_MEM[ARMCPU_ARM9][0x40]))[0x35C>>1] = val; //gfx3d_glFogOffset(val); return; }*/ case REG_DIVCNT: MMU_new.div.write16(val); execdiv(); return; #if 1 case REG_DIVNUMER: case REG_DIVNUMER+2: case REG_DIVNUMER+4: printf("DIV: 16 write NUMER %08X. PLEASE REPORT! \n", val); break; case REG_DIVDENOM: case REG_DIVDENOM+2: case REG_DIVDENOM+4: printf("DIV: 16 write DENOM %08X. PLEASE REPORT! \n", val); break; #endif case REG_SQRTCNT: MMU_new.sqrt.write16(val); execsqrt(); return; /*case REG_DISPA_BLDCNT: GPU_setBLDCNT(MainScreen.gpu,val) ; break ; case REG_DISPB_BLDCNT: GPU_setBLDCNT(SubScreen.gpu,val) ; break ; case REG_DISPA_BLDALPHA: MainScreen.gpu->setBLDALPHA(val); break ; case REG_DISPB_BLDALPHA: SubScreen.gpu->setBLDALPHA(val); break ; case REG_DISPA_BLDY: GPU_setBLDY_EVY(MainScreen.gpu,val) ; break ; case REG_DISPB_BLDY: GPU_setBLDY_EVY(SubScreen.gpu,val) ; break; case REG_DISPA_MASTERBRIGHT: GPU_setMasterBrightness (MainScreen.gpu, val); break;*/ /* case REG_DISPA_MOSAIC: GPU_setMOSAIC(MainScreen.gpu,val) ; break ; case REG_DISPB_MOSAIC: GPU_setMOSAIC(SubScreen.gpu,val) ; break ; */ //case REG_DISPA_BG0HOFS: // GPU_setBGxHOFS(0, MainScreen.gpu, val); // break; //case REG_DISPA_BG0VOFS: // GPU_setBGxVOFS(0, MainScreen.gpu, val); // break; //case REG_DISPA_BG1HOFS: // GPU_setBGxHOFS(1, MainScreen.gpu, val); // break; //case REG_DISPA_BG1VOFS: // GPU_setBGxVOFS(1, MainScreen.gpu, val); // break; //case REG_DISPA_BG2HOFS: // GPU_setBGxHOFS(2, MainScreen.gpu, val); // break; //case REG_DISPA_BG2VOFS: // GPU_setBGxVOFS(2, MainScreen.gpu, val); // break; //case REG_DISPA_BG3HOFS: // GPU_setBGxHOFS(3, MainScreen.gpu, val); // break; //case REG_DISPA_BG3VOFS: // GPU_setBGxVOFS(3, MainScreen.gpu, val); // break; /*case REG_DISPA_WIN0H: GPU_setWIN0_H (MainScreen.gpu,val) ; break ; case REG_DISPA_WIN1H: GPU_setWIN1_H(MainScreen.gpu,val) ; break ; case REG_DISPB_WIN0H: GPU_setWIN0_H(SubScreen.gpu,val) ; break ; case REG_DISPB_WIN1H: GPU_setWIN1_H(SubScreen.gpu,val) ; break ; case REG_DISPA_WIN0V: GPU_setWIN0_V(MainScreen.gpu,val) ; break ; case REG_DISPA_WIN1V: GPU_setWIN1_V(MainScreen.gpu,val) ; break ; case REG_DISPB_WIN0V: GPU_setWIN0_V(SubScreen.gpu,val) ; break ; case REG_DISPB_WIN1V: GPU_setWIN1_V(SubScreen.gpu,val) ; break ; case REG_DISPA_WININ: GPU_setWININ(MainScreen.gpu, val) ; break ; case REG_DISPA_WINOUT: GPU_setWINOUT16(MainScreen.gpu, val) ; break ; */ /* case REG_DISPB_BG0HOFS: GPU_setBGxHOFS(0, SubScreen.gpu, val); break; case REG_DISPB_BG0VOFS: GPU_setBGxVOFS(0, SubScreen.gpu, val); break; case REG_DISPB_BG1HOFS: GPU_setBGxHOFS(1, SubScreen.gpu, val); break; case REG_DISPB_BG1VOFS: GPU_setBGxVOFS(1, SubScreen.gpu, val); break; case REG_DISPB_BG2HOFS: GPU_setBGxHOFS(2, SubScreen.gpu, val); break; case REG_DISPB_BG2VOFS: GPU_setBGxVOFS(2, SubScreen.gpu, val); break; case REG_DISPB_BG3HOFS: GPU_setBGxHOFS(3, SubScreen.gpu, val); break; case REG_DISPB_BG3VOFS: GPU_setBGxVOFS(3, SubScreen.gpu, val); break;*/ /*case REG_DISPB_WININ: GPU_setWININ(SubScreen.gpu, val) ; break ; case REG_DISPB_WINOUT: GPU_setWINOUT16(SubScreen.gpu, val) ; break ;*/ /*case REG_DISPB_MASTERBRIGHT: GPU_setMasterBrightness (SubScreen.gpu, val); break;*/ /*case REG_POWCNT1: writereg_POWCNT1(16,adr,val); return;*/ case REG_EXMEMCNT: { uint16_t remote_proc = T1ReadWord(MMU.MMU_MEM[ARMCPU_ARM7][0x40], 0x204); T1WriteWord(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x204, val); T1WriteWord(MMU.MMU_MEM[ARMCPU_ARM7][0x40], 0x204, (val & 0xFF80) | (remote_proc & 0x7F)); return; } /*case REG_AUXSPICNT: write_auxspicnt(9,16,0,val); return; case REG_AUXSPIDATA: if(val!=0) MMU.AUX_SPI_CMD = val & 0xFF; //T1WriteWord(MMU.MMU_MEM[ARMCPU_ARM7][(REG_AUXSPIDATA >> 20) & 0xff], REG_AUXSPIDATA & 0xfff, bm_transfer(&MMU.bupmem, val)); T1WriteWord(MMU.MMU_MEM[ARMCPU_ARM9][(REG_AUXSPIDATA >> 20) & 0xff], REG_AUXSPIDATA & 0xfff, MMU_new.backupDevice.data_command((uint8_t)val,ARMCPU_ARM9)); MMU.AUX_SPI_CNT &= ~0x80; //remove busy flag return;*/ /*case REG_DISPA_BG0CNT : //GPULOG("MAIN BG0 SETPROP 16B %08X\r\n", val); //GPU_setBGProp(MainScreen.gpu, 0, val); T1WriteWord(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x8, val); return; case REG_DISPA_BG1CNT : //GPULOG("MAIN BG1 SETPROP 16B %08X\r\n", val); //GPU_setBGProp(MainScreen.gpu, 1, val); T1WriteWord(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0xA, val); return; case REG_DISPA_BG2CNT : //GPULOG("MAIN BG2 SETPROP 16B %08X\r\n", val); //GPU_setBGProp(MainScreen.gpu, 2, val); T1WriteWord(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0xC, val); return; case REG_DISPA_BG3CNT : //GPULOG("MAIN BG3 SETPROP 16B %08X\r\n", val); //GPU_setBGProp(MainScreen.gpu, 3, val); T1WriteWord(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0xE, val); return; case REG_DISPB_BG0CNT : //GPULOG("SUB BG0 SETPROP 16B %08X\r\n", val); //GPU_setBGProp(SubScreen.gpu, 0, val); T1WriteWord(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x1008, val); return; case REG_DISPB_BG1CNT : //GPULOG("SUB BG1 SETPROP 16B %08X\r\n", val); //GPU_setBGProp(SubScreen.gpu, 1, val); T1WriteWord(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x100A, val); return; case REG_DISPB_BG2CNT : //GPULOG("SUB BG2 SETPROP 16B %08X\r\n", val); //GPU_setBGProp(SubScreen.gpu, 2, val); T1WriteWord(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x100C, val); return; case REG_DISPB_BG3CNT : //GPULOG("SUB BG3 SETPROP 16B %08X\r\n", val); //GPU_setBGProp(SubScreen.gpu, 3, val); T1WriteWord(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x100E, val); return;*/ case REG_VRAMCNTA: case REG_VRAMCNTC: case REG_VRAMCNTE: MMU_VRAMmapControl(static_cast(adr-REG_VRAMCNTA), val & 0xFF); MMU_VRAMmapControl(static_cast(adr-REG_VRAMCNTA+1), val >> 8); break; case REG_VRAMCNTG: MMU_VRAMmapControl(static_cast(adr-REG_VRAMCNTA), val & 0xFF); /* Update WRAMSTAT at the ARM7 side */ T1WriteByte(MMU.MMU_MEM[ARMCPU_ARM7][0x40], 0x241, val >> 8); break; case REG_VRAMCNTH: MMU_VRAMmapControl(static_cast(adr-REG_VRAMCNTA), val & 0xFF); MMU_VRAMmapControl(static_cast(adr-REG_VRAMCNTA+1), val >> 8); break; case REG_IME: NDS_Reschedule(); MMU.reg_IME[ARMCPU_ARM9] = val & 0x01; T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x208, val); return; case REG_IE : NDS_Reschedule(); MMU.reg_IE[ARMCPU_ARM9] = (MMU.reg_IE[ARMCPU_ARM9]&0xFFFF0000) | val; return; case REG_IE + 2 : NDS_Reschedule(); MMU.reg_IE[ARMCPU_ARM9] = (MMU.reg_IE[ARMCPU_ARM9]&0xFFFF) | (((uint32_t)val)<<16); return; case REG_IF: REG_IF_WriteWord(0,val); return; case REG_IF+2: REG_IF_WriteWord(2,val); return; case REG_IPCSYNC : MMU_IPCSync(ARMCPU_ARM9, val); return; case REG_IPCFIFOCNT : IPC_FIFOcnt(ARMCPU_ARM9, val); return; case REG_TM0CNTL : case REG_TM1CNTL : case REG_TM2CNTL : case REG_TM3CNTL : MMU.timerReload[ARMCPU_ARM9][(adr>>2)&3] = val; return; case REG_TM0CNTH : case REG_TM1CNTH : case REG_TM2CNTH : case REG_TM3CNTH : { int timerIndex = ((adr-2)>>2)&0x3; write_timer(ARMCPU_ARM9, timerIndex, val); return; } /*case REG_DISPA_DISPCNT : { uint32_t v = (T1ReadLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0) & 0xFFFF0000) | val; //GPU_setVideoProp(MainScreen.gpu, v); T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0, v); return; } case REG_DISPA_DISPCNT+2 : { uint32_t v = (T1ReadLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0) & 0xFFFF) | ((uint32_t) val << 16); //GPU_setVideoProp(MainScreen.gpu, v); T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0, v); } return; case REG_DISPA_DISPCAPCNT : { uint32_t v = (T1ReadLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x64) & 0xFFFF0000) | val; //GPU_set_DISPCAPCNT(v); T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x64, v); return; } case REG_DISPA_DISPCAPCNT + 2: { uint32_t v = (T1ReadLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x64) & 0xFFFF) | ((uint32_t)val << 16); //GPU_set_DISPCAPCNT(v); T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x64, v); return; } case REG_DISPB_DISPCNT : { uint32_t v = (T1ReadLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x1000) & 0xFFFF0000) | val; //GPU_setVideoProp(SubScreen.gpu, v); T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x1000, v); return; } case REG_DISPB_DISPCNT+2 : { //emu_halt(); uint32_t v = (T1ReadLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x1000) & 0xFFFF) | ((uint32_t) val << 16); //GPU_setVideoProp(SubScreen.gpu, v); T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x1000, v); return; }*/ /*case REG_DISPA_DISPMMEMFIFO: { DISP_FIFOsend(val); return; }*/ case REG_GCROMCTRL : MMU_writeToGCControl( (T1ReadLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x1A4) & 0xFFFF0000) | val); return; case REG_GCROMCTRL+2 : MMU_writeToGCControl( (T1ReadLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x1A4) & 0xFFFF) | ((uint32_t) val << 16)); return; } T1WriteWord(MMU.MMU_MEM[ARMCPU_ARM9][adr>>20], adr&MMU.MMU_MASK[ARMCPU_ARM9][adr>>20], val); return; } bool unmapped, restricted; adr = MMU_LCDmap/**/(adr, unmapped, restricted); if(unmapped) return; // Removed the &0xFF as they are implicit with the adr&0x0FFFFFFF [shash] T1WriteWord(MMU.MMU_MEM[ARMCPU_ARM9][adr>>20], adr&MMU.MMU_MASK[ARMCPU_ARM9][adr>>20], val); } //================================================= MMU ARM9 write 32 void FASTCALL _MMU_ARM9_write32(uint32_t adr, uint32_t val) { adr &= 0x0FFFFFFC; //mmu_log_debug_ARM9(adr, "(write32) 0x%08X", val); if(adr<0x02000000) { T1WriteLong(MMU.ARM9_ITCM, adr&0x7FFF, val); return ; } if ( (adr >= 0x08000000) && (adr < 0x0A010000) ) { //addon.write32(adr, val); return; } if((adr&0x0F000000)==0x05000000) { //int zzz=9; } #if 0 if ((adr & 0xFF800000) == 0x04800000) { // access to non regular hw registers // return to not overwrite valid data return ; } #endif if((adr>>24)==4) { // TODO: add pal reg /*if (nds.power1.gpuMain == 0) if ((adr >= 0x04000008) && (adr<=0x0400005F)) return;*/ /*if (nds.power1.gpuSub == 0) if ((adr >= 0x04001008) && (adr<=0x0400105F)) return;*/ /*if (nds.power1.gfx3d_geometry == 0) if ((adr >= 0x04000400) && (adr<=0x040006FF)) return; if (nds.power1.gfx3d_render == 0) if ((adr >= 0x04000320) && (adr<=0x040003FF)) return;*/ // MightyMax: no need to do several ifs, when only one can happen // switch/case instead // both comparison >=,< per if can be replaced by one bit comparison since // they are 2^4 aligned and 2^4n wide // this looks ugly but should reduce load on register writes, they are done as // lookups by the compiler /*switch (adr >> 4) { case 0x400033: //edge color table ((uint32_t *)(MMU.MMU_MEM[ARMCPU_ARM9][0x40]))[(adr & 0xFFF) >> 2] = val; return; case 0x400038: case 0x400039: case 0x40003A: case 0x40003B: //toon table ((uint32_t *)(MMU.MMU_MEM[ARMCPU_ARM9][0x40]))[(adr & 0xFFF) >> 2] = val; //gfx3d_UpdateToonTable((adr & 0x3F) >> 1, val); return; case 0x400040: case 0x400041: case 0x400042: case 0x400043: // FIFO Commands ((uint32_t *)(MMU.MMU_MEM[ARMCPU_ARM9][0x40]))[(adr & 0xFFF) >> 2] = val; //gfx3d_sendCommandToFIFO(val); return; case 0x400044: case 0x400045: case 0x400046: case 0x400047: case 0x400048: case 0x400049: case 0x40004A: case 0x40004B: case 0x40004C: case 0x40004D: case 0x40004E: case 0x40004F: case 0x400050: case 0x400051: case 0x400052: case 0x400053: case 0x400054: case 0x400055: case 0x400056: case 0x400057: case 0x400058: case 0x400059: case 0x40005A: case 0x40005B: case 0x40005C: // Individual Commands if (gxFIFO.size > 254) nds.freezeBus = true; ((uint32_t *)(MMU.MMU_MEM[ARMCPU_ARM9][0x40]))[(adr & 0xFFF) >> 2] = val; //gfx3d_sendCommand(adr, val); return; default: break; }*/ if(MMU_new.is_dma(adr)) { MMU_new.write_dma(ARMCPU_ARM9,32,adr,val); return; } switch(adr) { case REG_SQRTCNT: MMU_new.sqrt.write16((uint16_t)val); return; case REG_DIVCNT: MMU_new.div.write16((uint16_t)val); return; //case REG_POWCNT1: writereg_POWCNT1(32,adr,val); break; //fog table: only write bottom 7 bits /*case eng_3D_FOG_TABLE+0x00: case eng_3D_FOG_TABLE+0x04: case eng_3D_FOG_TABLE+0x08: case eng_3D_FOG_TABLE+0x0C: case eng_3D_FOG_TABLE+0x10: case eng_3D_FOG_TABLE+0x14: case eng_3D_FOG_TABLE+0x18: case eng_3D_FOG_TABLE+0x1C: val &= 0x7F7F7F7F; break;*/ //ensata handshaking port? /*case 0x04FFF010: if(nds.ensataEmulation && nds.ensataHandshake == ENSATA_HANDSHAKE_ack && val == 0x13579bdf) nds.ensataHandshake = ENSATA_HANDSHAKE_confirm; if(nds.ensataEmulation && nds.ensataHandshake == ENSATA_HANDSHAKE_confirm && val == 0xfdb97531) { printf("ENSATA HANDSHAKE COMPLETE\n"); nds.ensataHandshake = ENSATA_HANDSHAKE_complete; } break;*/ //todo - these are usually write only regs (these and 1000 more) //shouldnt we block them from getting written? ugh /*case eng_3D_CLIPMTX_RESULT: if(nds.ensataEmulation && nds.ensataHandshake == ENSATA_HANDSHAKE_none && val==0x2468ace0) { printf("ENSATA HANDSHAKE BEGIN\n"); nds.ensataHandshake = ENSATA_HANDSHAKE_query; } break; case eng_3D_GXSTAT: MMU_new.gxstat.write32(val); break;*/ /*case REG_DISPA_BG2XL: MainScreen.gpu->setAffineStart(2,0,val); return; case REG_DISPA_BG2YL: MainScreen.gpu->setAffineStart(2,1,val); return; case REG_DISPB_BG2XL: SubScreen.gpu->setAffineStart(2,0,val); return; case REG_DISPB_BG2YL: SubScreen.gpu->setAffineStart(2,1,val); return; case REG_DISPA_BG3XL: MainScreen.gpu->setAffineStart(3,0,val); return; case REG_DISPA_BG3YL: MainScreen.gpu->setAffineStart(3,1,val); return; case REG_DISPB_BG3XL: SubScreen.gpu->setAffineStart(3,0,val); return; case REG_DISPB_BG3YL: SubScreen.gpu->setAffineStart(3,1,val); return;*/ // Alpha test reference value - Parameters:1 /*case eng_3D_ALPHA_TEST_REF: { ((uint32_t *)(MMU.MMU_MEM[ARMCPU_ARM9][0x40]))[0x340>>2] = val; //gfx3d_glAlphaFunc(val); return; } case eng_3D_CLEAR_COLOR: //T1WriteLong((uint8_t*)&gfx3d.state.clearColor,0,val); break; // Clear background depth setup - Parameters:2 case eng_3D_CLEAR_DEPTH: { ((uint32_t *)(MMU.MMU_MEM[ARMCPU_ARM9][0x40]))[0x354>>2] = val; //gfx3d_glClearDepth(val); return; } // Fog Color - Parameters:4b case 0x04000358: { ((uint32_t *)(MMU.MMU_MEM[ARMCPU_ARM9][0x40]))[0x358>>2] = val; //gfx3d_glFogColor(val); return; } case 0x0400035C: { ((uint32_t *)(MMU.MMU_MEM[ARMCPU_ARM9][0x40]))[0x35C>>2] = val; //gfx3d_glFogOffset(val); return; }*/ //case REG_DISPA_BG0HOFS: // GPU_setBGxHOFS(0, MainScreen.gpu, val&0xFFFF); // GPU_setBGxVOFS(0, MainScreen.gpu, (val>>16)); // break; /*case REG_DISPA_WININ: { GPU_setWININ(MainScreen.gpu, val & 0xFFFF) ; GPU_setWINOUT16(MainScreen.gpu, (val >> 16) & 0xFFFF) ; break; } case REG_DISPB_WININ: { GPU_setWININ(SubScreen.gpu, val & 0xFFFF) ; GPU_setWINOUT16(SubScreen.gpu, (val >> 16) & 0xFFFF) ; break; }*/ /*case REG_DISPA_WIN0H: { GPU_setWIN0_H(MainScreen.gpu, val&0xFFFF); GPU_setWIN1_H(MainScreen.gpu, val>>16); break; } case REG_DISPA_WIN0V: { GPU_setWIN0_V(MainScreen.gpu, val&0xFFFF); GPU_setWIN1_V(MainScreen.gpu, val>>16); break; } case REG_DISPB_WIN0H: { GPU_setWIN0_H(SubScreen.gpu, val&0xFFFF); GPU_setWIN1_H(SubScreen.gpu, val>>16); break; } case REG_DISPB_WIN0V: { GPU_setWIN0_V(SubScreen.gpu, val&0xFFFF); GPU_setWIN1_V(SubScreen.gpu, val>>16); break; }*/ /*case REG_DISPA_MASTERBRIGHT: GPU_setMasterBrightness(MainScreen.gpu, val & 0xFFFF); break; case REG_DISPB_MASTERBRIGHT: GPU_setMasterBrightness(SubScreen.gpu, val & 0xFFFF); break;*/ /*case REG_DISPA_BLDCNT: { GPU_setBLDCNT (MainScreen.gpu,val&0xffff); MainScreen.gpu->setBLDALPHA(val>>16); break; } case REG_DISPB_BLDCNT: { GPU_setBLDCNT (SubScreen.gpu,val&0xffff); SubScreen.gpu->setBLDALPHA(val>>16); break; }*/ /*case REG_DISPA_BLDY: GPU_setBLDY_EVY(MainScreen.gpu,val&0xFFFF) ; break ; case REG_DISPB_BLDY: GPU_setBLDY_EVY(SubScreen.gpu,val&0xFFFF); break;*/ /*case REG_DISPA_DISPCNT : //GPU_setVideoProp(MainScreen.gpu, val); //GPULOG("MAIN INIT 32B %08X\r\n", val); T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0, val); return; case REG_DISPB_DISPCNT : //GPU_setVideoProp(SubScreen.gpu, val); //GPULOG("SUB INIT 32B %08X\r\n", val); T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x1000, val); return;*/ case REG_VRAMCNTA: MMU_VRAMmapControl(static_cast(adr-REG_VRAMCNTA), val & 0xFF); MMU_VRAMmapControl(static_cast(adr-REG_VRAMCNTA+1), (val >> 8) & 0xFF); MMU_VRAMmapControl(static_cast(adr-REG_VRAMCNTA+2), (val >> 16) & 0xFF); MMU_VRAMmapControl(static_cast(adr-REG_VRAMCNTA+3), (val >> 24) & 0xFF); break; case REG_VRAMCNTE: MMU_VRAMmapControl(static_cast(adr-REG_VRAMCNTA), val & 0xFF); MMU_VRAMmapControl(static_cast(adr-REG_VRAMCNTA+1), (val >> 8) & 0xFF); MMU_VRAMmapControl(static_cast(adr-REG_VRAMCNTA+2), (val >> 16) & 0xFF); /* Update WRAMSTAT at the ARM7 side */ T1WriteByte(MMU.MMU_MEM[ARMCPU_ARM7][0x40], 0x241, (val >> 24) & 0xFF); break; case REG_VRAMCNTH: MMU_VRAMmapControl(static_cast(adr-REG_VRAMCNTA), val & 0xFF); MMU_VRAMmapControl(static_cast(adr-REG_VRAMCNTA+1), (val >> 8) & 0xFF); break; case REG_IME : NDS_Reschedule(); MMU.reg_IME[ARMCPU_ARM9] = val & 0x01; T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x208, val); return; case REG_IE : NDS_Reschedule(); MMU.reg_IE[ARMCPU_ARM9] = val; return; case REG_IF: REG_IF_WriteLong(val); return; case REG_TM0CNTL: case REG_TM1CNTL: case REG_TM2CNTL: case REG_TM3CNTL: { int timerIndex = (adr>>2)&0x3; MMU.timerReload[ARMCPU_ARM9][timerIndex] = (uint16_t)val; T1WriteWord(MMU.MMU_MEM[ARMCPU_ARM9][0x40], adr & 0xFFF, static_cast(val)); write_timer(ARMCPU_ARM9, timerIndex, val>>16); return; } case REG_DIVNUMER: T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x290, val); execdiv(); return; case REG_DIVNUMER+4: T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x294, val); execdiv(); return; case REG_DIVDENOM : { T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x298, val); execdiv(); return; } case REG_DIVDENOM+4 : { T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x29C, val); execdiv(); return; } case REG_SQRTPARAM : { T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x2B8, val); execsqrt(); return; } case REG_SQRTPARAM+4 : { T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x2BC, val); execsqrt(); return; } case REG_IPCSYNC: MMU_IPCSync(ARMCPU_ARM9, val); return; case REG_IPCFIFOCNT: IPC_FIFOcnt(ARMCPU_ARM9, static_cast(val)); return; case REG_IPCFIFOSEND: IPC_FIFOsend(ARMCPU_ARM9, val); return; case REG_GCROMCTRL : MMU_writeToGCControl(val); return; case REG_DISPA_DISPCAPCNT : //INFO("MMU write32: REG_DISPA_DISPCAPCNT 0x%X\n", val); //GPU_set_DISPCAPCNT(val); T1WriteLong(MMU.ARM9_REG, 0x64, val); return; /*case REG_DISPA_BG0CNT : //GPU_setBGProp(MainScreen.gpu, 0, (val&0xFFFF)); //GPU_setBGProp(MainScreen.gpu, 1, (val>>16)); //if((val>>16)==0x400) emu_halt(); T1WriteLong(MMU.ARM9_REG, 8, val); return; case REG_DISPA_BG2CNT : //GPU_setBGProp(MainScreen.gpu, 2, (val&0xFFFF)); //GPU_setBGProp(MainScreen.gpu, 3, (val>>16)); T1WriteLong(MMU.ARM9_REG, 0xC, val); return; case REG_DISPB_BG0CNT : //GPU_setBGProp(SubScreen.gpu, 0, (val&0xFFFF)); //GPU_setBGProp(SubScreen.gpu, 1, (val>>16)); T1WriteLong(MMU.ARM9_REG, 0x1008, val); return; case REG_DISPB_BG2CNT : //GPU_setBGProp(SubScreen.gpu, 2, (val&0xFFFF)); //GPU_setBGProp(SubScreen.gpu, 3, (val>>16)); T1WriteLong(MMU.ARM9_REG, 0x100C, val); return;*/ /*case REG_DISPA_DISPMMEMFIFO: { DISP_FIFOsend(val); return; }*/ //case REG_DISPA_DISP3DCNT: writereg_DISP3DCNT(32,adr,val); return; case REG_GCDATAIN: slot1_device.write32(ARMCPU_ARM9, REG_GCDATAIN,val); return; } T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][adr>>20], adr & MMU.MMU_MASK[ARMCPU_ARM9][adr>>20], val); return; } bool unmapped, restricted; adr = MMU_LCDmap/**/(adr, unmapped, restricted); if(unmapped) return; // Removed the &0xFF as they are implicit with the adr&0x0FFFFFFF [shash] T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][adr>>20], adr&MMU.MMU_MASK[ARMCPU_ARM9][adr>>20], val); } //================================================= MMU ARM9 read 08 uint8_t FASTCALL _MMU_ARM9_read08(uint32_t adr) { adr &= 0x0FFFFFFF; //mmu_log_debug_ARM9(adr, "(read08) 0x%02X", MMU.MMU_MEM[ARMCPU_ARM9][(adr>>20)&0xFF][adr&MMU.MMU_MASK[ARMCPU_ARM9][(adr>>20)&0xFF]]); if(adr<0x02000000) return T1ReadByte(MMU.ARM9_ITCM, adr&0x7FFF); if ( (adr >= 0x08000000) && (adr < 0x0A010000) ) return 0/*addon.read08(adr)*/; if (adr >> 24 == 4) { //Address is an IO register if(MMU_new.is_dma(adr)) return static_cast(MMU_new.read_dma(ARMCPU_ARM9,8,adr)); switch(adr) { case REG_IF: return static_cast(MMU.gen_IF()); case REG_IF+1: return static_cast(MMU.gen_IF()>>8); case REG_IF+2: return static_cast(MMU.gen_IF()>>16); case REG_IF+3: return static_cast(MMU.gen_IF()>>24); /*case REG_DISPA_DISPSTAT: break; case REG_DISPA_DISPSTAT+1: break; case REG_DISPx_VCOUNT: return nds.VCount & 0xFF; case REG_DISPx_VCOUNT+1: return (nds.VCount>>8) & 0xFF;*/ #if 0 case REG_SQRTCNT: printf("ERROR 8bit SQRTCNT READ\n"); return 0; case REG_SQRTCNT+1: printf("ERROR 8bit SQRTCNT1 READ\n"); return 0;//(MMU_new.sqrt.read16() & 0xFF00)>>8; #else case REG_SQRTCNT: return MMU_new.sqrt.read16() & 0xFF; case REG_SQRTCNT+1: return (MMU_new.sqrt.read16()>>8) & 0xFF; #endif case REG_SQRTCNT+2: printf("ERROR 8bit SQRTCNT2 READ\n"); return 0; case REG_SQRTCNT+3: printf("ERROR 8bit SQRTCNT3 READ\n"); return 0; #if 1 case REG_DIVCNT: printf("ERROR 8bit DIVCNT READ\n"); return 0; case REG_DIVCNT+1: printf("ERROR 8bit DIVCNT1 READ\n"); return 0; #else case REG_DIVCNT: return MMU_new.div.read16() & 0xFF; case REG_DIVCNT+1: return (MMU_new.div.read16()>>8) & 0xFF; #endif case REG_DIVCNT+2: printf("ERROR 8bit DIVCNT2 READ\n"); return 0; case REG_DIVCNT+3: printf("ERROR 8bit DIVCNT3 READ\n"); return 0; //fog table: write only /*case eng_3D_FOG_TABLE+0x00: case eng_3D_FOG_TABLE+0x01: case eng_3D_FOG_TABLE+0x02: case eng_3D_FOG_TABLE+0x03: case eng_3D_FOG_TABLE+0x04: case eng_3D_FOG_TABLE+0x05: case eng_3D_FOG_TABLE+0x06: case eng_3D_FOG_TABLE+0x07: case eng_3D_FOG_TABLE+0x08: case eng_3D_FOG_TABLE+0x09: case eng_3D_FOG_TABLE+0x0A: case eng_3D_FOG_TABLE+0x0B: case eng_3D_FOG_TABLE+0x0C: case eng_3D_FOG_TABLE+0x0D: case eng_3D_FOG_TABLE+0x0E: case eng_3D_FOG_TABLE+0x0F: case eng_3D_FOG_TABLE+0x10: case eng_3D_FOG_TABLE+0x11: case eng_3D_FOG_TABLE+0x12: case eng_3D_FOG_TABLE+0x13: case eng_3D_FOG_TABLE+0x14: case eng_3D_FOG_TABLE+0x15: case eng_3D_FOG_TABLE+0x16: case eng_3D_FOG_TABLE+0x17: case eng_3D_FOG_TABLE+0x18: case eng_3D_FOG_TABLE+0x19: case eng_3D_FOG_TABLE+0x1A: case eng_3D_FOG_TABLE+0x1B: case eng_3D_FOG_TABLE+0x1C: case eng_3D_FOG_TABLE+0x1D: case eng_3D_FOG_TABLE+0x1E: case eng_3D_FOG_TABLE+0x1F: return 0;*/ /*case REG_POWCNT1: case REG_POWCNT1+1: case REG_POWCNT1+2: case REG_POWCNT1+3: return readreg_POWCNT1(8,adr);*/ /*case eng_3D_GXSTAT: return MMU_new.gxstat.read(8,adr);*/ //case REG_DISPA_DISP3DCNT: return readreg_DISP3DCNT(8,adr); //case REG_DISPA_DISP3DCNT+1: return readreg_DISP3DCNT(8,adr); //case REG_DISPA_DISP3DCNT+2: return readreg_DISP3DCNT(8,adr); //case REG_DISPA_DISP3DCNT+3: return readreg_DISP3DCNT(8,adr); } } bool unmapped, restricted; adr = MMU_LCDmap/**/(adr, unmapped, restricted); if(unmapped) return 0; return MMU.MMU_MEM[ARMCPU_ARM9][(adr>>20)&0xFF][adr&MMU.MMU_MASK[ARMCPU_ARM9][(adr>>20)&0xFF]]; } //================================================= MMU ARM9 read 16 uint16_t FASTCALL _MMU_ARM9_read16(uint32_t adr) { adr &= 0x0FFFFFFE; //mmu_log_debug_ARM9(adr, "(read16) 0x%04X", T1ReadWord_guaranteedAligned(MMU.MMU_MEM[ARMCPU_ARM9][adr >> 20], adr & MMU.MMU_MASK[ARMCPU_ARM9][adr >> 20])); if(adr<0x02000000) return T1ReadWord_guaranteedAligned(MMU.ARM9_ITCM, adr & 0x7FFE); if ( (adr >= 0x08000000) && (adr < 0x0A010000) ) return 0/*addon.read16(adr)*/; if (adr >> 24 == 4) { if(MMU_new.is_dma(adr)) return static_cast(MMU_new.read_dma(ARMCPU_ARM9,16,adr)); // Address is an IO register switch(adr) { /*case REG_DISPA_DISPSTAT: break;*/ case REG_SQRTCNT: return MMU_new.sqrt.read16(); case REG_DIVCNT: return MMU_new.div.read16(); //case eng_3D_GXSTAT: return MMU_new.gxstat.read(16,adr); /*case REG_DISPA_VCOUNT: if(nds.ensataEmulation && nds.ensataHandshake == ENSATA_HANDSHAKE_query) { nds.ensataHandshake = ENSATA_HANDSHAKE_ack; return 270; } else return nds.VCount; // ============================================= 3D case eng_3D_RAM_COUNT: return 0; //almost worthless for now //return gfx3d_GetNumPolys(); case eng_3D_RAM_COUNT+2: return 0; //almost worthless for now //return gfx3d_GetNumVertex();*/ // ============================================= 3D end case REG_IME : return (uint16_t)MMU.reg_IME[ARMCPU_ARM9]; case REG_IE : return (uint16_t)MMU.reg_IE[ARMCPU_ARM9]; case REG_IE + 2 : return (uint16_t)(MMU.reg_IE[ARMCPU_ARM9]>>16); case REG_IF: return static_cast(MMU.gen_IF()); case REG_IF+2: return static_cast(MMU.gen_IF()>>16); case REG_TM0CNTL : case REG_TM1CNTL : case REG_TM2CNTL : case REG_TM3CNTL : return read_timer(ARMCPU_ARM9,(adr&0xF)>>2); case REG_AUXSPICNT: return MMU.AUX_SPI_CNT; /*case REG_POWCNT1: case REG_POWCNT1+2: return readreg_POWCNT1(16,adr);*/ //case REG_DISPA_DISP3DCNT: return readreg_DISP3DCNT(16,adr); //case REG_DISPA_DISP3DCNT+2: return readreg_DISP3DCNT(16,adr); /*case 0x04000130: case 0x04000136: //not sure whether these should trigger from byte reads LagFrameFlag=0; break;*/ //fog table: write only /*case eng_3D_FOG_TABLE+0x00: case eng_3D_FOG_TABLE+0x02: case eng_3D_FOG_TABLE+0x04: case eng_3D_FOG_TABLE+0x06: case eng_3D_FOG_TABLE+0x08: case eng_3D_FOG_TABLE+0x0A: case eng_3D_FOG_TABLE+0x0C: case eng_3D_FOG_TABLE+0x0E: case eng_3D_FOG_TABLE+0x10: case eng_3D_FOG_TABLE+0x12: case eng_3D_FOG_TABLE+0x14: case eng_3D_FOG_TABLE+0x16: case eng_3D_FOG_TABLE+0x18: case eng_3D_FOG_TABLE+0x1A: case eng_3D_FOG_TABLE+0x1C: case eng_3D_FOG_TABLE+0x1E: return 0;*/ } return T1ReadWord_guaranteedAligned(MMU.MMU_MEM[ARMCPU_ARM9][adr>>20], adr & MMU.MMU_MASK[ARMCPU_ARM9][adr>>20]); } //bool unmapped = false/*, restricted*/; //adr = MMU_LCDmap(adr,unmapped, restricted); //if(unmapped) return 0; // Removed the &0xFF as they are implicit with the adr&0x0FFFFFFF return T1ReadWord_guaranteedAligned(MMU.MMU_MEM[ARMCPU_ARM9][adr >> 20], adr & MMU.MMU_MASK[ARMCPU_ARM9][adr >> 20]); } //================================================= MMU ARM9 read 32 uint32_t FASTCALL _MMU_ARM9_read32(uint32_t adr) { adr &= 0x0FFFFFFC; //mmu_log_debug_ARM9(adr, "(read32) 0x%08X", T1ReadLong_guaranteedAligned(MMU.MMU_MEM[ARMCPU_ARM9][adr >> 20], adr & MMU.MMU_MASK[ARMCPU_ARM9][adr>>20])); if(adr<0x02000000) return T1ReadLong_guaranteedAligned(MMU.ARM9_ITCM, adr&0x7FFC); if ( (adr >= 0x08000000) && (adr < 0x0A010000) ) return 0/*addon.read32(adr)*/; // Address is an IO register if((adr >> 24) == 4) { if(MMU_new.is_dma(adr)) return MMU_new.read_dma(ARMCPU_ARM9,32,adr); switch(adr) { case REG_DSIMODE: if(!nds.Is_DSI()) break; return 1; case 0x04004008: if(!nds.Is_DSI()) break; return 0x8000; /*case REG_DISPA_DISPSTAT: break; case REG_DISPx_VCOUNT: return nds.VCount;*/ //Dolphin Island Underwater Adventures uses this amidst seemingly reasonable divs so we're going to emulate it. case REG_DIVCNT: return MMU_new.div.read16(); //I guess we'll do this also case REG_SQRTCNT: return MMU_new.sqrt.read16(); //fog table: write only /*case eng_3D_FOG_TABLE+0x00: case eng_3D_FOG_TABLE+0x04: case eng_3D_FOG_TABLE+0x08: case eng_3D_FOG_TABLE+0x0C: case eng_3D_FOG_TABLE+0x10: case eng_3D_FOG_TABLE+0x14: case eng_3D_FOG_TABLE+0x18: case eng_3D_FOG_TABLE+0x1C: return 0;*/ /*case eng_3D_CLIPMTX_RESULT: case eng_3D_CLIPMTX_RESULT+4: case eng_3D_CLIPMTX_RESULT+8: case eng_3D_CLIPMTX_RESULT+12: case eng_3D_CLIPMTX_RESULT+16: case eng_3D_CLIPMTX_RESULT+20: case eng_3D_CLIPMTX_RESULT+24: case eng_3D_CLIPMTX_RESULT+28: case eng_3D_CLIPMTX_RESULT+32: case eng_3D_CLIPMTX_RESULT+36: case eng_3D_CLIPMTX_RESULT+40: case eng_3D_CLIPMTX_RESULT+44: case eng_3D_CLIPMTX_RESULT+48: case eng_3D_CLIPMTX_RESULT+52: case eng_3D_CLIPMTX_RESULT+56: case eng_3D_CLIPMTX_RESULT+60: { //LOG("4000640h..67Fh - CLIPMTX_RESULT - Read Current Clip Coordinates Matrix (R)"); return gfx3d_GetClipMatrix ((adr-0x04000640)/4); }*/ /*case eng_3D_VECMTX_RESULT: case eng_3D_VECMTX_RESULT+4: case eng_3D_VECMTX_RESULT+8: case eng_3D_VECMTX_RESULT+12: case eng_3D_VECMTX_RESULT+16: case eng_3D_VECMTX_RESULT+20: case eng_3D_VECMTX_RESULT+24: case eng_3D_VECMTX_RESULT+28: case eng_3D_VECMTX_RESULT+32: { //LOG("4000680h..6A3h - VECMTX_RESULT - Read Current Directional Vector Matrix (R)"); return gfx3d_GetDirectionalMatrix ((adr-0x04000680)/4); }*/ /*case eng_3D_RAM_COUNT: { return gfx3d_GetNumPolys() | ((gfx3d_GetNumVertex()) << 16); //LOG ("read32 - RAM_COUNT -> 0x%X", ((uint32_t *)(MMU.MMU_MEM[ARMCPU_ARM9][(adr>>20)&0xFF]))[(adr&MMU.MMU_MASK[ARMCPU_ARM9][(adr>>20)&0xFF])>>2]); }*/ /*case eng_3D_POS_RESULT: case eng_3D_POS_RESULT+4: case eng_3D_POS_RESULT+8: case eng_3D_POS_RESULT+12: { return gfx3d_glGetPosRes((adr & 0xF) >> 2); }*/ /*case eng_3D_GXSTAT: return MMU_new.gxstat.read(32,adr);*/ // ======================================== 3D end case REG_IME : return MMU.reg_IME[ARMCPU_ARM9]; case REG_IE : return MMU.reg_IE[ARMCPU_ARM9]; case REG_IF: return MMU.gen_IF(); case REG_IPCFIFORECV : return IPC_FIFOrecv(ARMCPU_ARM9); case REG_TM0CNTL : case REG_TM1CNTL : case REG_TM2CNTL : case REG_TM3CNTL : { uint32_t val = T1ReadWord(MMU.MMU_MEM[ARMCPU_ARM9][0x40], (adr + 2) & 0xFFF); return MMU.timer[ARMCPU_ARM9][(adr&0xF)>>2] | (val<<16); } case REG_GCDATAIN: return MMU_readFromGC(); //case REG_POWCNT1: return readreg_POWCNT1(32,adr); //case REG_DISPA_DISP3DCNT: return readreg_DISP3DCNT(32,adr); } return T1ReadLong_guaranteedAligned(MMU.MMU_MEM[ARMCPU_ARM9][adr>>20], adr & MMU.MMU_MASK[ARMCPU_ARM9][adr>>20]); } //bool unmapped = false/*, restricted*/; //adr = MMU_LCDmap(adr,unmapped, restricted); //if(unmapped) return 0; // Removed the &0xFF as they are implicit with the adr&0x0FFFFFFF [zeromus, inspired by shash] return T1ReadLong_guaranteedAligned(MMU.MMU_MEM[ARMCPU_ARM9][adr >> 20], adr & MMU.MMU_MASK[ARMCPU_ARM9][adr>>20]); } //================================================================================================== ARM7 * //========================================================================================================= //========================================================================================================= //================================================= MMU ARM7 write 08 void FASTCALL _MMU_ARM7_write08(uint32_t adr, uint8_t val) { adr &= 0x0FFFFFFF; //mmu_log_debug_ARM7(adr, "(write08) 0x%02X", val); if (adr < 0x4000) return; // PU BIOS if ( (adr >= 0x08000000) && (adr < 0x0A010000) ) { //addon.write08(adr, val); return; } if ((adr>=0x04000400)&&(adr<0x04000520)) { SPU_WriteByte(adr, val); return; } if ((adr & 0xFFFF0000) == 0x04800000) { /* is wifi hardware, dont intermix with regular hardware registers */ // 8-bit writes to wifi I/O and RAM are ignored // Reference: http://nocash.emubase.de/gbatek.htm#dswifiiomap return; } if (adr >> 24 == 4) { if(MMU_new.is_dma(adr)) { MMU_new.write_dma(ARMCPU_ARM7,8,adr,val); return; } switch(adr) { case REG_IF: REG_IF_WriteByte(0,val); break; case REG_IF+1: REG_IF_WriteByte(1,val); break; case REG_IF+2: REG_IF_WriteByte(2,val); break; case REG_IF+3: REG_IF_WriteByte(3,val); break; case REG_POSTFLG: // hack for patched firmwares if (val == 1) { if (_MMU_ARM7_read08(REG_POSTFLG) != 0) break; _MMU_write32(0x27FFE24, gameInfo.header.ARM9exe); _MMU_write32(0x27FFE34, gameInfo.header.ARM7exe); } break; case REG_HALTCNT: //printf("halt 0x%02X\n", val); switch(val) { case 0xC0: NDS_Sleep(); break; case 0x80: armcpu_Wait4IRQ(&NDS_ARM7); break; default: break; } break; /*case REG_RTC: rtcWrite(val); return;*/ /*case REG_AUXSPICNT: write_auxspicnt(9,8,0,val); return; case REG_AUXSPICNT+1: write_auxspicnt(9,8,1,val); return; case REG_AUXSPIDATA: if(val!=0) MMU.AUX_SPI_CMD = val & 0xFF; T1WriteWord(MMU.MMU_MEM[ARMCPU_ARM7][(REG_AUXSPIDATA >> 20) & 0xff], REG_AUXSPIDATA & 0xfff, MMU_new.backupDevice.data_command((uint8_t)val,ARMCPU_ARM7)); MMU.AUX_SPI_CNT &= ~0x80; //remove busy flag return;*/ } MMU.MMU_MEM[ARMCPU_ARM7][adr>>20][adr&MMU.MMU_MASK[ARMCPU_ARM7][adr>>20]]=val; return; } //bool unmapped = false/*, restricted*/; //adr = MMU_LCDmap(adr,unmapped, restricted); //if(unmapped) return; // Removed the &0xFF as they are implicit with the adr&0x0FFFFFFF [shash] MMU.MMU_MEM[ARMCPU_ARM7][adr>>20][adr&MMU.MMU_MASK[ARMCPU_ARM7][adr>>20]]=val; } //================================================= MMU ARM7 write 16 void FASTCALL _MMU_ARM7_write16(uint32_t adr, uint16_t val) { adr &= 0x0FFFFFFE; //mmu_log_debug_ARM7(adr, "(write16) 0x%04X", val); if (adr < 0x4000) return; // PU BIOS if ( (adr >= 0x08000000) && (adr < 0x0A010000) ) { //addon.write16(adr, val); return; } //wifi mac access /*if ((adr & 0xFFFF0000) == 0x04800000) { WIFI_write16(adr,val); T1WriteWord(MMU.MMU_MEM[ARMCPU_ARM7][0x48], adr&MMU.MMU_MASK[ARMCPU_ARM7][0x48], val); return; }*/ if ((adr>=0x04000400)&&(adr<0x04000520)) { SPU_WriteWord(adr, val); return; } if((adr >> 24) == 4) { if(MMU_new.is_dma(adr)) { MMU_new.write_dma(ARMCPU_ARM7,16,adr,val); return; } //Address is an IO register switch(adr) { case REG_DISPA_VCOUNT: if (nds.VCount >= 202 && nds.VCount <= 212) { printf("VCOUNT set to %i (previous value %i)\n", val, nds.VCount); nds.VCount = val; } else printf("Attempt to set VCOUNT while not within 202-212 (%i), ignored\n", nds.VCount); return; /*case REG_RTC: rtcWrite(val); break;*/ case REG_EXMEMCNT: { uint16_t remote_proc = T1ReadWord(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x204); T1WriteWord(MMU.MMU_MEM[ARMCPU_ARM7][0x40], 0x204, (val & 0x7F) | (remote_proc & 0xFF80)); } return; /*case REG_EXTKEYIN: //readonly return;*/ /*case REG_POWCNT2: { nds.power2.speakers = BIT0(val); nds.power2.wifi = BIT0(val); } return;*/ /*case REG_AUXSPICNT: write_auxspicnt(7,16,0,val); return; case REG_AUXSPIDATA: if(val!=0) MMU.AUX_SPI_CMD = val & 0xFF; //T1WriteWord(MMU.MMU_MEM[ARMCPU_ARM7][(REG_AUXSPIDATA >> 20) & 0xff], REG_AUXSPIDATA & 0xfff, bm_transfer(&MMU.bupmem, val)); T1WriteWord(MMU.MMU_MEM[ARMCPU_ARM7][(REG_AUXSPIDATA >> 20) & 0xff], REG_AUXSPIDATA & 0xfff, MMU_new.backupDevice.data_command((uint8_t)val,ARMCPU_ARM7)); MMU.AUX_SPI_CNT &= ~0x80; //remove busy flag return;*/ case REG_SPICNT : { int reset_firmware = 1; if ( ((MMU.SPI_CNT >> 8) & 0x3) == 1) { if ( ((val >> 8) & 0x3) == 1) { if ( BIT11(MMU.SPI_CNT)) { // select held reset_firmware = 0; } } } //MMU.fw.com == 0; // reset fw device communication if ( reset_firmware) { // reset fw device communication fw_reset_com(&MMU.fw); } MMU.SPI_CNT = val; T1WriteWord(MMU.MMU_MEM[ARMCPU_ARM7][(REG_SPICNT >> 20) & 0xff], REG_SPICNT & 0xfff, val); } return; case REG_SPIDATA : { uint16_t spicnt; if(val!=0) MMU.SPI_CMD = val; spicnt = T1ReadWord(MMU.MMU_MEM[ARMCPU_ARM7][(REG_SPICNT >> 20) & 0xff], REG_SPICNT & 0xfff); switch((spicnt >> 8) & 0x3) { case 0 : { if(!MMU.powerMan_CntRegWritten) { MMU.powerMan_CntReg = (val & 0xFF); MMU.powerMan_CntRegWritten = true; } else { uint16_t reg = MMU.powerMan_CntReg&0x7F; reg &= 0x7; if(reg==5 || reg==6 || reg==7) reg = 4; //(let's start with emulating a DS lite, since it is the more complex case) if(MMU.powerMan_CntReg & 0x80) { //read val = MMU.powerMan_Reg[reg]; } else { //write MMU.powerMan_Reg[reg] = (uint8_t)val; //enum PM_Bits //from libnds //{ //PM_SOUND_AMP = BIT(0) , /*!< \brief Power the sound hardware (needed to hear stuff in GBA mode too) */ //PM_SOUND_MUTE = BIT(1), /*!< \brief Mute the main speakers, headphone output will still work. */ //PM_BACKLIGHT_BOTTOM = BIT(2), /*!< \brief Enable the top backlight if set */ //PM_BACKLIGHT_TOP = BIT(3) , /*!< \brief Enable the bottom backlight if set */ static const uint32_t PM_SYSTEM_PWR = BIT(6); /*!< \brief Turn the power *off* if set */ //}; //our totally pathetic register handling, only the one thing we've wanted so far if(MMU.powerMan_Reg[0]&PM_SYSTEM_PWR) { printf("SYSTEM POWERED OFF VIA ARM7 SPI POWER DEVICE\n"); //emu_halt(); execute = false; } } MMU.powerMan_CntRegWritten = false; } } break; case 1 : /* firmware memory device */ if((spicnt & 0x3) != 0) /* check SPI baudrate (must be 4mhz) */ { T1WriteWord(MMU.MMU_MEM[ARMCPU_ARM7][(REG_SPIDATA >> 20) & 0xff], REG_SPIDATA & 0xfff, 0); break; } T1WriteWord(MMU.MMU_MEM[ARMCPU_ARM7][(REG_SPIDATA >> 20) & 0xff], REG_SPIDATA & 0xfff, fw_transfer(&MMU.fw, (uint8_t)val)); return; case 2: { if(nds.Is_DSI()) { //pass data to TSC val = MMU_new.dsi_tsc.write16(val); //apply reset command if appropriate if(!BIT11(MMU.SPI_CNT)) MMU_new.dsi_tsc.reset_command(); break; } int channel = (MMU.SPI_CMD&0x70)>>4; //printf("%08X\n",channel); switch(channel) { case TSC_MEASURE_TEMP1: if(spicnt & 0x800) { if(partie) { val = ((716<<3)&0x7FF); partie = 0; break; } val = (716>>5); partie = 1; break; } val = ((716<<3)&0x7FF); partie = 1; break; case TSC_MEASURE_TEMP2: if(spicnt & 0x800) { if(partie) { val = ((865<<3)&0x7FF); partie = 0; break; } val = (865>>5); partie = 1; break; } val = ((865<<3)&0x7FF); partie = 1; break; case TSC_MEASURE_Y: { //counter the number of adc touch coord reads and jitter it after a while to simulate a shaky human hand or multiple reads /*nds.adc_jitterctr++; if(nds.adc_jitterctr == 25) { nds.adc_jitterctr = 0; nds.adc_touchY ^= 16; nds.adc_touchX ^= 16; }*/ if(MMU.SPI_CNT&(1<<11)) { if(partie) { //val = (nds.adc_touchY<<3) & 0xFF; partie = 0; break; } //val = (nds.adc_touchY>>5) & 0xFF; partie = 1; break; } //val = (nds.adc_touchY<<3)&0xFF; partie = 1; break; } case TSC_MEASURE_Z1: //Z1 //used for pressure calculation - must be nonzero or else some softwares will think the stylus is up. //something is wrong in here and some of these LSB dont make it back to libnds... whatever. /*{ u16 scratch; CalculateTouchPressure(CommonSettings.StylusPressure,val,scratch); }*/ if(spicnt & 0x800) { if(partie) { val = ((val<<3)&0x7FF); partie = 0; break; } val = (val>>5); partie = 1; break; } val = ((val<<3)&0x7FF); partie = 1; break; case TSC_MEASURE_Z2: //Z2 //used for pressure calculation - must be nonzero or else some softwares will think the stylus is up. //something is wrong in here and some of these LSB dont make it back to libnds... whatever. /*{ u16 scratch; CalculateTouchPressure(CommonSettings.StylusPressure,scratch,val); }*/ if(spicnt & 0x800) { if(partie) { val = ((val<<3)&0x7FF); partie = 0; break; } val = (val>>5); partie = 1; break; } val = ((val<<3)&0x7FF); partie = 1; break; case TSC_MEASURE_X: if(spicnt & 0x800) { if(partie) { //val = (nds.adc_touchX << 3) & 0xFF; partie = 0; break; } //val = (nds.adc_touchX>>5) & 0xFF; partie = 1; break; } //val = (nds.adc_touchX<<3) & 0xFF; partie = 1; break; case TSC_MEASURE_AUX: /*if(!(val & 0x80)) val = (Mic_ReadSample() & 0xFF); else*/ val = 0; break; } break; } case 3 : /* NOTICE: Device 3 of SPI is reserved (unused and unusable) */ break; } } T1WriteWord(MMU.MMU_MEM[ARMCPU_ARM7][(REG_SPIDATA >> 20) & 0xff], REG_SPIDATA & 0xfff, val); return; /* NOTICE: Perhaps we have to use gbatek-like reg names instead of libnds-like ones ...*/ case REG_IME : NDS_Reschedule(); MMU.reg_IME[ARMCPU_ARM7] = val & 0x01; T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM7][0x40], 0x208, val); return; case REG_IE : NDS_Reschedule(); MMU.reg_IE[ARMCPU_ARM7] = (MMU.reg_IE[ARMCPU_ARM7]&0xFFFF0000) | val; return; case REG_IE + 2 : NDS_Reschedule(); //emu_halt(); MMU.reg_IE[ARMCPU_ARM7] = (MMU.reg_IE[ARMCPU_ARM7]&0xFFFF) | (((uint32_t)val)<<16); return; case REG_IF: REG_IF_WriteWord(0,val); return; case REG_IF+2: REG_IF_WriteWord(2,val); return; case REG_IPCSYNC : MMU_IPCSync(ARMCPU_ARM7, val); return; case REG_IPCFIFOCNT : IPC_FIFOcnt(ARMCPU_ARM7, val); return; case REG_TM0CNTL : case REG_TM1CNTL : case REG_TM2CNTL : case REG_TM3CNTL : MMU.timerReload[ARMCPU_ARM7][(adr>>2)&3] = val; return; case REG_TM0CNTH : case REG_TM1CNTH : case REG_TM2CNTH : case REG_TM3CNTH : { int timerIndex = ((adr-2)>>2)&0x3; write_timer(ARMCPU_ARM7, timerIndex, val); return; } case REG_GCROMCTRL : MMU_writeToGCControl( (T1ReadLong(MMU.MMU_MEM[ARMCPU_ARM7][0x40], 0x1A4) & 0xFFFF0000) | val); return; case REG_GCROMCTRL+2 : MMU_writeToGCControl( (T1ReadLong(MMU.MMU_MEM[ARMCPU_ARM7][0x40], 0x1A4) & 0xFFFF) | ((uint32_t) val << 16)); return; } T1WriteWord(MMU.MMU_MEM[ARMCPU_ARM7][adr>>20], adr&MMU.MMU_MASK[ARMCPU_ARM7][adr>>20], val); return; } //bool unmapped = false/*, restricted*/; //adr = MMU_LCDmap(adr,unmapped, restricted); //if(unmapped) return; // Removed the &0xFF as they are implicit with the adr&0x0FFFFFFF [shash] T1WriteWord(MMU.MMU_MEM[ARMCPU_ARM7][adr>>20], adr&MMU.MMU_MASK[ARMCPU_ARM7][adr>>20], val); } //================================================= MMU ARM7 write 32 void FASTCALL _MMU_ARM7_write32(uint32_t adr, uint32_t val) { adr &= 0x0FFFFFFC; //mmu_log_debug_ARM7(adr, "(write32) 0x%08X", val); if (adr < 0x4000) return; // PU BIOS if ( (adr >= 0x08000000) && (adr < 0x0A010000) ) { //addon.write32(adr, val); return; } /*if ((adr & 0xFFFF0000) == 0x04800000) { WIFI_write16(adr, val & 0xFFFF); WIFI_write16(adr+2, val >> 16); T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM7][0x48], adr&MMU.MMU_MASK[ARMCPU_ARM7][0x48], val); return; }*/ if ((adr>=0x04000400)&&(adr<0x04000520)) { SPU_WriteLong(adr, val); return; } if((adr>>24)==4) { if(MMU_new.is_dma(adr)) { MMU_new.write_dma(ARMCPU_ARM7,32,adr,val); return; } switch(adr) { /*case REG_RTC: rtcWrite((uint16_t)val); break;*/ case REG_IME : NDS_Reschedule(); MMU.reg_IME[ARMCPU_ARM7] = val & 0x01; T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM7][0x40], 0x208, val); return; case REG_IE : NDS_Reschedule(); MMU.reg_IE[ARMCPU_ARM7] = val; return; case REG_IF: REG_IF_WriteLong(val); return; case REG_TM0CNTL: case REG_TM1CNTL: case REG_TM2CNTL: case REG_TM3CNTL: { int timerIndex = (adr>>2)&0x3; MMU.timerReload[ARMCPU_ARM7][timerIndex] = (uint16_t)val; T1WriteWord(MMU.MMU_MEM[ARMCPU_ARM7][0x40], adr & 0xFFF, static_cast(val)); write_timer(ARMCPU_ARM7, timerIndex, val>>16); return; } case REG_IPCSYNC: MMU_IPCSync(ARMCPU_ARM7, val); return; case REG_IPCFIFOCNT: IPC_FIFOcnt(ARMCPU_ARM7, static_cast(val)); return; case REG_IPCFIFOSEND: IPC_FIFOsend(ARMCPU_ARM7, val); return; case REG_GCROMCTRL : MMU_writeToGCControl(val); return; case REG_GCDATAIN: slot1_device.write32(ARMCPU_ARM7, REG_GCDATAIN,val); return; } T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM7][adr>>20], adr & MMU.MMU_MASK[ARMCPU_ARM7][adr>>20], val); return; } //bool unmapped = false/*, restricted*/; //adr = MMU_LCDmap(adr,unmapped, restricted); //if(unmapped) return; // Removed the &0xFF as they are implicit with the adr&0x0FFFFFFF [shash] T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM7][adr>>20], adr&MMU.MMU_MASK[ARMCPU_ARM7][adr>>20], val); } //================================================= MMU ARM7 read 08 uint8_t FASTCALL _MMU_ARM7_read08(uint32_t adr) { adr &= 0x0FFFFFFF; //mmu_log_debug_ARM7(adr, "(read08) 0x%02X", MMU.MMU_MEM[ARMCPU_ARM7][(adr>>20)&0xFF][adr&MMU.MMU_MASK[ARMCPU_ARM7][(adr>>20)&0xFF]]); if (adr < 0x4000) { //uint32_t prot = T1ReadLong_guaranteedAligned(MMU.MMU_MEM[ARMCPU_ARM7][0x40], 0x04000308 & MMU.MMU_MASK[ARMCPU_ARM7][0x40]); //if (prot) INFO("MMU7 read 08 at 0x%08X (PC 0x%08X) BIOSPROT address 0x%08X\n", adr, NDS_ARM7.R[15], prot); //How accurate is this? our R[15] may not be exactly what the hardware uses (may use something less by up to 0x08) //This may be inaccurate at the very edge cases. if (NDS_ARM7.R[15] > 0x3FFF) return 0xFF; } // wifi mac access /*if ((adr & 0xFFFF0000) == 0x04800000) { if (adr & 1) return (WIFI_read16(adr-1) >> 8) & 0xFF; else return WIFI_read16(adr) & 0xFF; }*/ if ( (adr >= 0x08000000) && (adr < 0x0A010000) ) return 0/*addon.read08(adr)*/; if ((adr>=0x04000400)&&(adr<0x04000520)) { return SPU_ReadByte(adr); } //if (adr == REG_RTC) return (uint8_t)rtcRead(); if (adr >> 24 == 4) { if(MMU_new.is_dma(adr)) return static_cast(MMU_new.read_dma(ARMCPU_ARM7,8,adr)); // Address is an IO register switch(adr) { case REG_IF: return static_cast(MMU.gen_IF()); case REG_IF+1: return static_cast(MMU.gen_IF()>>8); case REG_IF+2: return static_cast(MMU.gen_IF()>>16); case REG_IF+3: return static_cast(MMU.gen_IF()>>24); /*case REG_DISPx_VCOUNT: return nds.VCount&0xFF; case REG_DISPx_VCOUNT+1: return (nds.VCount>>8)&0xFF;*/ } return MMU.MMU_MEM[ARMCPU_ARM7][adr>>20][adr&MMU.MMU_MASK[ARMCPU_ARM7][adr>>20]]; } //bool unmapped = false/*, restricted*/; //adr = MMU_LCDmap(adr,unmapped, restricted); //if(unmapped) return 0; return MMU.MMU_MEM[ARMCPU_ARM7][adr>>20][adr&MMU.MMU_MASK[ARMCPU_ARM7][adr>>20]]; } //================================================= MMU ARM7 read 16 uint16_t FASTCALL _MMU_ARM7_read16(uint32_t adr) { adr &= 0x0FFFFFFE; //mmu_log_debug_ARM7(adr, "(read16) 0x%04X", T1ReadWord(MMU.MMU_MEM[ARMCPU_ARM7][(adr>>20)&0xFF], adr & MMU.MMU_MASK[ARMCPU_ARM7][(adr>>20)&0xFF])); if (adr < 0x4000) { //uint32_t prot = T1ReadLong_guaranteedAligned(MMU.MMU_MEM[ARMCPU_ARM7][0x40], 0x04000308 & MMU.MMU_MASK[ARMCPU_ARM7][0x40]); //if (prot) INFO("MMU7 read 16 at 0x%08X (PC 0x%08X) BIOSPROT address 0x%08X\n", adr, NDS_ARM7.R[15], prot); if (NDS_ARM7.R[15] > 0x3FFF) return 0xFFFF; } //wifi mac access /*if ((adr & 0xFFFF0000) == 0x04800000) return WIFI_read16(adr) ;*/ if ( (adr >= 0x08000000) && (adr < 0x0A010000) ) return 0/*addon.read16(adr)*/; if ((adr>=0x04000400)&&(adr<0x04000520)) { return SPU_ReadWord(adr); } if(adr>>24==4) { //Address is an IO register if(MMU_new.is_dma(adr)) return static_cast(MMU_new.read_dma(ARMCPU_ARM7,16,adr)); switch(adr) { /*case REG_POWCNT2: { uint16_t ret = 0; ret |= nds.power2.speakers?BIT(0):0; ret |= nds.power2.wifi?BIT(1):0; return ret; }*/ //case REG_DISPx_VCOUNT: return nds.VCount; //case REG_RTC: return rtcRead(); case REG_IME: return (uint16_t)MMU.reg_IME[ARMCPU_ARM7]; case REG_IE: return (uint16_t)MMU.reg_IE[ARMCPU_ARM7]; case REG_IE + 2: return (uint16_t)(MMU.reg_IE[ARMCPU_ARM7]>>16); case REG_IF: return static_cast(MMU.gen_IF()); case REG_IF+2: return static_cast(MMU.gen_IF()>>16); case REG_TM0CNTL : case REG_TM1CNTL : case REG_TM2CNTL : case REG_TM3CNTL : return read_timer(ARMCPU_ARM7,(adr&0xF)>>2); /*case REG_AUXSPICNT: return MMU.AUX_SPI_CNT;*/ /*case REG_KEYINPUT: //here is an example of what not to do: //since the arm7 polls this (and EXTKEYIN) every frame, we shouldnt count this as an input check //LagFrameFlag=0; break;*/ /*case REG_EXTKEYIN: { //this is gross. we should generate this whole reg instead of poking it in ndssystem uint16_t ret = MMU.ARM7_REG[0x136]; if(nds.isTouch) ret &= ~64; else ret |= 64; return ret; }*/ } return T1ReadWord_guaranteedAligned(MMU.MMU_MEM[ARMCPU_ARM7][adr>>20], adr & MMU.MMU_MASK[ARMCPU_ARM7][adr>>20]); } //bool unmapped = false/*, restricted*/; //adr = MMU_LCDmap(adr,unmapped, restricted); //if(unmapped) return 0; /* Returns data from memory */ // Removed the &0xFF as they are implicit with the adr&0x0FFFFFFF return T1ReadWord_guaranteedAligned(MMU.MMU_MEM[ARMCPU_ARM7][adr >> 20], adr & MMU.MMU_MASK[ARMCPU_ARM7][adr >> 20]); } //================================================= MMU ARM7 read 32 uint32_t FASTCALL _MMU_ARM7_read32(uint32_t adr) { adr &= 0x0FFFFFFC; //mmu_log_debug_ARM7(adr, "(read32) 0x%08X", T1ReadLong(MMU.MMU_MEM[ARMCPU_ARM7][(adr>>20)&0xFF], adr & MMU.MMU_MASK[ARMCPU_ARM7][(adr>>20)&0xFF])); if (adr < 0x4000) { //uint32_t prot = T1ReadLong_guaranteedAligned(MMU.MMU_MEM[ARMCPU_ARM7][0x40], 0x04000308 & MMU.MMU_MASK[ARMCPU_ARM7][0x40]); //if (prot) INFO("MMU7 read 32 at 0x%08X (PC 0x%08X) BIOSPROT address 0x%08X\n", adr, NDS_ARM7.R[15], prot); if (NDS_ARM7.R[15] > 0x3FFF) return 0xFFFFFFFF; } //wifi mac access /*if ((adr & 0xFFFF0000) == 0x04800000) return WIFI_read16(adr) | (WIFI_read16(adr+2) << 16);*/ if ( (adr >= 0x08000000) && (adr < 0x0A010000) ) return 0/*addon.read32(adr)*/; if ((adr>=0x04000400)&&(adr<0x04000520)) { return SPU_ReadLong(adr); } if((adr >> 24) == 4) { //Address is an IO register if(MMU_new.is_dma(adr)) return MMU_new.read_dma(ARMCPU_ARM7,32,adr); switch(adr) { //case REG_RTC: return (uint32_t)rtcRead(); //case REG_DISPx_VCOUNT: return nds.VCount; case REG_IME : return MMU.reg_IME[ARMCPU_ARM7]; case REG_IE : return MMU.reg_IE[ARMCPU_ARM7]; case REG_IF: return MMU.gen_IF(); case REG_IPCFIFORECV : return IPC_FIFOrecv(ARMCPU_ARM7); case REG_TM0CNTL : case REG_TM1CNTL : case REG_TM2CNTL : case REG_TM3CNTL : { uint32_t val = T1ReadWord(MMU.MMU_MEM[ARMCPU_ARM7][0x40], (adr + 2) & 0xFFF); return MMU.timer[ARMCPU_ARM7][(adr&0xF)>>2] | (val<<16); } case REG_GCROMCTRL: { //INFO("arm7 romctrl read\n"); break; } case REG_GCDATAIN: return MMU_readFromGC(); } return T1ReadLong_guaranteedAligned(MMU.MMU_MEM[ARMCPU_ARM7][adr>>20], adr & MMU.MMU_MASK[ARMCPU_ARM7][adr>>20]); } //bool unmapped = false/*, restricted*/; //adr = MMU_LCDmap(adr,unmapped, restricted); //if(unmapped) return 0; //Returns data from memory // Removed the &0xFF as they are implicit with the adr&0x0FFFFFFF [zeromus, inspired by shash] return T1ReadLong_guaranteedAligned(MMU.MMU_MEM[ARMCPU_ARM7][adr >> 20], adr & MMU.MMU_MASK[ARMCPU_ARM7][adr >> 20]); } //========================================================================================================= /*uint32_t FASTCALL MMU_read32(uint32_t proc, uint32_t adr) { ASSERT_UNALIGNED((adr&3)==0); if(proc==0) return _MMU_ARM9_read32(adr); else return _MMU_ARM7_read32(adr); }*/ /*uint16_t FASTCALL MMU_read16(uint32_t proc, uint32_t adr) { ASSERT_UNALIGNED((adr&1)==0); if(proc==0) return _MMU_ARM9_read16(adr); else return _MMU_ARM7_read16(adr); }*/ /*uint8_t FASTCALL MMU_read8(uint32_t proc, uint32_t adr) { if(proc==0) return _MMU_ARM9_read08(adr); else return _MMU_ARM7_read08(adr); }*/ /*void FASTCALL MMU_write32(uint32_t proc, uint32_t adr, uint32_t val) { ASSERT_UNALIGNED((adr&3)==0); if(proc==0) _MMU_ARM9_write32(adr, val); else _MMU_ARM7_write32(adr,val); }*/ /*void FASTCALL MMU_write16(uint32_t proc, uint32_t adr, uint16_t val) { ASSERT_UNALIGNED((adr&1)==0); if(proc==0) _MMU_ARM9_write16(adr, val); else _MMU_ARM7_write16(adr,val); }*/ /*void FASTCALL MMU_write8(uint32_t proc, uint32_t adr, uint8_t val) { if(proc==0) _MMU_ARM9_write08(adr, val); else _MMU_ARM7_write08(adr,val); }*/ /*void FASTCALL MMU_DumpMemBlock(uint8_t proc, uint32_t address, uint32_t size, uint8_t *buffer) { uint32_t i; uint32_t curaddr; for(i = 0, curaddr = address; i < size; i++, curaddr++) { buffer[i] = _MMU_read08(proc,MMU_AT_DEBUG,curaddr); } }*/ //these templates needed to be instantiated manually template uint32_t MMU_struct::gen_IF(); template uint32_t MMU_struct::gen_IF(); //////////////////////////////////////////////////////////// //function pointer handlers for gdb stub stuff /*static uint16_t FASTCALL arm9_prefetch16( void *, uint32_t adr) { return _MMU_read16(adr); } static uint32_t FASTCALL arm9_prefetch32( void *, uint32_t adr) { return _MMU_read32(adr); } static uint8_t FASTCALL arm9_read8( void *, uint32_t adr) { return _MMU_read08(adr); } static uint16_t FASTCALL arm9_read16( void *, uint32_t adr) { return _MMU_read16(adr); } static uint32_t FASTCALL arm9_read32( void *, uint32_t adr) { return _MMU_read32(adr); } static void FASTCALL arm9_write8(void *, uint32_t adr, uint8_t val) { _MMU_write08(adr, val); } static void FASTCALL arm9_write16(void *, uint32_t adr, uint16_t val) { _MMU_write16(adr, val); } static void FASTCALL arm9_write32(void *, uint32_t adr, uint32_t val) { _MMU_write32(adr, val); } static uint16_t FASTCALL arm7_prefetch16( void *, uint32_t adr) { return _MMU_read16(adr); } static uint32_t FASTCALL arm7_prefetch32( void *, uint32_t adr) { return _MMU_read32(adr); } static uint8_t FASTCALL arm7_read8( void *, uint32_t adr) { return _MMU_read08(adr); } static uint16_t FASTCALL arm7_read16( void *, uint32_t adr) { return _MMU_read16(adr); } static uint32_t FASTCALL arm7_read32( void *, uint32_t adr) { return _MMU_read32(adr); } static void FASTCALL arm7_write8(void *, uint32_t adr, uint8_t val) { _MMU_write08(adr, val); } static void FASTCALL arm7_write16(void *, uint32_t adr, uint16_t val) { _MMU_write16(adr, val); } static void FASTCALL arm7_write32(void *, uint32_t adr, uint32_t val) { _MMU_write32(adr, val); }*/ /* * the base memory interfaces */ /*struct armcpu_memory_iface arm9_base_memory_iface = { arm9_prefetch32, arm9_prefetch16, arm9_read8, arm9_read16, arm9_read32, arm9_write8, arm9_write16, arm9_write32 }; struct armcpu_memory_iface arm7_base_memory_iface = { arm7_prefetch32, arm7_prefetch16, arm7_read8, arm7_read16, arm7_read32, arm7_write8, arm7_write16, arm7_write32 };*/ /* * The direct memory interface for the ARM9. * This avoids the ARM9 protection unit when accessing * memory. */ /*struct armcpu_memory_iface arm9_direct_memory_iface = { NULL, NULL, arm9_read8, arm9_read16, arm9_read32, arm9_write8, arm9_write16, arm9_write32 };*/ ///////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////// //#ifdef PROFILE_MEMORY_ACCESS // //#define PROFILE_PREFETCH 0 //#define PROFILE_READ 1 //#define PROFILE_WRITE 2 // //struct mem_access_profile { // uint64_t num_accesses; // uint32_t address_mask; // uint32_t masked_value; //}; // //#define PROFILE_NUM_MEM_ACCESS_PROFILES 4 // //static uint64_t profile_num_accesses[2][3]; //static uint64_t profile_unknown_addresses[2][3]; //static struct mem_access_profile //profile_memory_accesses[2][3][PROFILE_NUM_MEM_ACCESS_PROFILES]; // //static void //setup_profiling() { // int i; // // for ( i = 0; i < 2; i++) { // int access_type; // // for ( access_type = 0; access_type < 3; access_type++) { // profile_num_accesses[i][access_type] = 0; // profile_unknown_addresses[i][access_type] = 0; // // /* // * Setup the access testing structures // */ // profile_memory_accesses[i][access_type][0].address_mask = 0x0e000000; // profile_memory_accesses[i][access_type][0].masked_value = 0x00000000; // profile_memory_accesses[i][access_type][0].num_accesses = 0; // // /* main memory */ // profile_memory_accesses[i][access_type][1].address_mask = 0x0f000000; // profile_memory_accesses[i][access_type][1].masked_value = 0x02000000; // profile_memory_accesses[i][access_type][1].num_accesses = 0; // // /* shared memory */ // profile_memory_accesses[i][access_type][2].address_mask = 0x0f800000; // profile_memory_accesses[i][access_type][2].masked_value = 0x03000000; // profile_memory_accesses[i][access_type][2].num_accesses = 0; // // /* arm7 memory */ // profile_memory_accesses[i][access_type][3].address_mask = 0x0f800000; // profile_memory_accesses[i][access_type][3].masked_value = 0x03800000; // profile_memory_accesses[i][access_type][3].num_accesses = 0; // } // } //} // //static void //profile_memory_access( int arm9, uint32_t adr, int access_type) { // static int first = 1; // int mem_profile; // int address_found = 0; // // if ( first) { // setup_profiling(); // first = 0; // } // // profile_num_accesses[arm9][access_type] += 1; // // for ( mem_profile = 0; // mem_profile < PROFILE_NUM_MEM_ACCESS_PROFILES && // !address_found; // mem_profile++) { // if ( (adr & profile_memory_accesses[arm9][access_type][mem_profile].address_mask) == // profile_memory_accesses[arm9][access_type][mem_profile].masked_value) { // /*printf( "adr %08x mask %08x res %08x expected %08x\n", // adr, // profile_memory_accesses[arm9][access_type][mem_profile].address_mask, // adr & profile_memory_accesses[arm9][access_type][mem_profile].address_mask, // profile_memory_accesses[arm9][access_type][mem_profile].masked_value);*/ // address_found = 1; // profile_memory_accesses[arm9][access_type][mem_profile].num_accesses += 1; // } // } // // if ( !address_found) { // profile_unknown_addresses[arm9][access_type] += 1; // } //} // // //static const char *access_type_strings[] = { // "prefetch", // "read ", // "write " //}; // //void //print_memory_profiling() { // int arm; // // printf("------ Memory access profile ------\n"); // // for ( arm = 0; arm < 2; arm++) { // int access_type; // // for ( access_type = 0; access_type < 3; access_type++) { // int mem_profile; // printf("ARM%c: num of %s %lld\n", // arm ? '9' : '7', // access_type_strings[access_type], // profile_num_accesses[arm][access_type]); // // for ( mem_profile = 0; // mem_profile < PROFILE_NUM_MEM_ACCESS_PROFILES; // mem_profile++) { // printf( "address %08x: %lld\n", // profile_memory_accesses[arm][access_type][mem_profile].masked_value, // profile_memory_accesses[arm][access_type][mem_profile].num_accesses); // } // // printf( "unknown addresses %lld\n", // profile_unknown_addresses[arm][access_type]); // // printf( "\n"); // } // } // // printf("------ End of Memory access profile ------\n\n"); //} //#else //void //print_memory_profiling() { //} //#endif /* End of PROFILE_MEMORY_ACCESS area */