/*
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 <http://www.gnu.org/licenses/>.
*/
#include <sstream>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <cassert>
#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 <stdarg.h>
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<int PROCNUM>
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<VRAM_LCDC_PAGES);
vram_page = vram_lcdc_map[vram_page];
}
else
{
//map addresses in BG/OBJ range to an LCDC range
vram_page = (addr>>14)&(VRAM_ARM9_PAGES-1);
assert(vram_page<VRAM_ARM9_PAGES);
vram_page = vram_arm9_map[vram_page];
}
if(vram_page == VRAM_PAGE_UNMAPPED)
{
unmapped = true;
return 0;
}
else
return LCDC_HACKY_LOCATION + (vram_page<<14) + ofs;
}
//#define LOG_VRAM_ERROR() LOG("No data for block %i MST %i\n", block, VRAMBankCnt & 0x07);
VramConfiguration vramConfiguration;
/*std::string VramConfiguration::describePurpose(Purpose p) {
switch(p) {
case OFF: return "OFF";
case INVALID: return "INVALID";
case ABG: return "ABG";
case BBG: return "BBG";
case AOBJ: return "AOBJ";
case BOBJ: return "BOBJ";
case LCDC: return "LCDC";
case ARM7: return "ARM7";
case TEX: return "TEX";
case TEXPAL: return "TEXPAL";
case ABGEXTPAL: return "ABGEXTPAL";
case BBGEXTPAL: return "BBGEXTPAL";
case AOBJEXTPAL: return "AOBJEXTPAL";
case BOBJEXTPAL: return "BOBJEXTPAL";
default: return "UNHANDLED CASE";
}
}
std::string VramConfiguration::describe() {
std::stringstream ret;
for(int i=0;i<VRAM_BANKS;i++) {
ret << (char)(i+'A') << ": " << banks[i].ofs << " " << describePurpose(banks[i].purpose) << std::endl;
}
return ret.str();
}*/
//maps the specified bank to LCDC
static inline void MMU_vram_lcdc(const int bank)
{
for(int i=0;i<vram_bank_info[bank].num_pages;i++)
{
int page = vram_bank_info[bank].page_addr+i;
vram_lcdc_map[page] = page;
}
}
//maps the specified bank to ARM9 at the provided page offset
static inline void MMU_vram_arm9(const int bank, const int offset)
{
for(int i=0;i<vram_bank_info[bank].num_pages;i++)
{
int page = vram_bank_info[bank].page_addr+i;
vram_arm9_map[i+offset] = page;
}
}
static inline uint8_t* MMU_vram_physical(const int page)
{
return MMU.ARM9_LCD + (page/**ADDRESS_STEP_16KB*/);
}
//todo - templateize
static inline void MMU_VRAMmapRefreshBank(const int bank)
{
int block = bank;
if(bank >= 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;i<VRAM_LCDC_PAGES;i++)
vram_lcdc_map[i] = VRAM_PAGE_UNMAPPED;
for(int i=0;i<VRAM_ARM9_PAGES;i++)
vram_arm9_map[i] = VRAM_PAGE_UNMAPPED;
for (int i = 0; i < 4; i++)
{
MMU.ExtPal[0][i] = MMU.blank_memory;
MMU.ExtPal[1][i] = MMU.blank_memory;
}
MMU.ObjExtPal[0][0] = MMU.blank_memory;
MMU.ObjExtPal[0][1] = MMU.blank_memory;
MMU.ObjExtPal[1][0] = MMU.blank_memory;
MMU.ObjExtPal[1][1] = MMU.blank_memory;
for(int i=0;i<6;i++)
MMU.texInfo.texPalSlot[i] = MMU.blank_memory;
for(int i=0;i<4;i++)
MMU.texInfo.textureSlotAddr[i] = MMU.blank_memory;
}
static inline void MMU_VRAMmapControl(uint8_t block, uint8_t VRAMBankCnt)
{
//dont handle wram mappings in here
if(block == 7) {
//wram
return;
}
//first, save the texture info so we can check it for changes and trigger purges of the texcache
MMU_struct::TextureInfo oldTexInfo = MMU.texInfo;
//unmap everything
MMU_VRAM_unmap_all();
//unmap VRAM_BANK_C and VRAM_BANK_D from arm7. theyll get mapped again in a moment if necessary
T1WriteByte(MMU.MMU_MEM[ARMCPU_ARM7][0x40], 0x240, 0);
//write the new value to the reg
T1WriteByte(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x240 + block, VRAMBankCnt);
//refresh all bank settings
//these are enumerated so that we can tune the order they get applied
//in order to emulate prioritization rules for memory regions
//with multiple banks mapped.
//We're probably still not mapping things 100% correctly, but this helped us get closer:
//goblet of fire "care of magical creatures" maps I and D to BOBJ (the I is an accident)
//and requires A to override it.
//This may create other bugs....
MMU_VRAMmapRefreshBank(VRAM_BANK_I);
MMU_VRAMmapRefreshBank(VRAM_BANK_H);
MMU_VRAMmapRefreshBank(VRAM_BANK_G);
MMU_VRAMmapRefreshBank(VRAM_BANK_F);
MMU_VRAMmapRefreshBank(VRAM_BANK_E);
MMU_VRAMmapRefreshBank(VRAM_BANK_D);
MMU_VRAMmapRefreshBank(VRAM_BANK_C);
MMU_VRAMmapRefreshBank(VRAM_BANK_B);
MMU_VRAMmapRefreshBank(VRAM_BANK_A);
//printf(vramConfiguration.describe().c_str());
//printf("vram remapped at vcount=%d\n",nds.VCount);
//if texInfo changed, trigger notifications
if(memcmp(&oldTexInfo,&MMU.texInfo,sizeof(MMU_struct::TextureInfo)))
{
//if(!nds.isIn3dVblank())
// PROGINFO("Changing texture or texture palette mappings outside of 3d vblank\n");
//gpu3D->NDS_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<ARRAY_SIZE(registers);i++)
registers[i] = 0x00;
reset_command();
}
void DSI_TSC::reset_command()
{
state = 0;
readcount = 0;
read_flag = 1;
}
uint16_t DSI_TSC::write16(uint16_t val)
{
uint16_t ret;
switch(state)
{
case 0:
reg_selection = (val>>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<ARRAY_SIZE(registers);i++)
write8le(registers[i],os);
return true;
}*/
/*bool DSI_TSC::load_state(EMUFILE* is)
{
uint32_t version;
read32le(&version,is);
read8le(®_selection,is);
read8le(&read_flag,is);
read32le(&state,is);
read32le(&readcount,is);
for(int i=0;i<ARRAY_SIZE(registers);i++)
read8le(®isters[i],is);
return true;
}*/
// TODO:
// NAND flash support (used in Made in Ore/WarioWare D.I.Y.)
template<int PROCNUM>
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<<shift)/4;
switch (card.mode)
{
case CardMode_Normal:
break;
case CardMode_KEY1:
{
// TODO
//INFO("Cartridge: KEY1 mode unsupported.\n");
card.address = 0;
card.transfer_count = 0;
val &= 0x7F7FFFFF;
T1WriteLong(MMU.MMU_MEM[TEST_PROCNUM][0x40], 0x1A4, val);
return;
}
break;
case CardMode_KEY2:
//INFO("Cartridge: KEY2 mode unsupported.\n");
break;
}
switch(card.command[0])
{
case 0x9F: //Dummy
card.address = 0;
card.transfer_count = 0x800;
break;
//case 0x90: //Get ROM chip ID
// break;
case 0x3C: //Switch to KEY1 mode
card.mode = CardMode_KEY1;
break;
default:
//fall through to the special slot1 handler
slot1_device.write32(TEST_PROCNUM, REG_GCROMCTRL,val);
break;
}
if(card.transfer_count == 0)
{
val &= 0x7F7FFFFF;
T1WriteLong(MMU.MMU_MEM[TEST_PROCNUM][0x40], 0x1A4, val);
return;
}
val |= 0x00800000;
T1WriteLong(MMU.MMU_MEM[TEST_PROCNUM][0x40], 0x1A4, val);
// Launch DMA if start flag was set to "DS Cart"
//printf("triggering card dma\n");
triggerDma(EDMAMode_Card);
}
template<int PROCNUM>
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<int PROCNUM> 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<int PROCNUM> static void REG_IF_WriteWord(uint32_t addr,uint16_t val)
{
REG_IF_WriteByte<PROCNUM>(addr,val&0xFF);
REG_IF_WriteByte<PROCNUM>(addr+1,(val>>8)&0xFF);
}
template<int PROCNUM> static void REG_IF_WriteLong(uint32_t val)
{
REG_IF_WriteByte<PROCNUM>(0,val&0xFF);
REG_IF_WriteByte<PROCNUM>(1,(val>>8)&0xFF);
REG_IF_WriteByte<PROCNUM>(2,(val>>16)&0xFF);
REG_IF_WriteByte<PROCNUM>(3,(val>>24)&0xFF);
}
template<int PROCNUM>
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<<MMU.timerMODE[proc][timerIndex]);
int32_t ret;
if(units==65536)
ret = 0; //I'm not sure why this is happening...
//whichever instruction setup this counter should advance nds_timer (I think?) and the division should truncate down to 65535 immediately
else if(units>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<uint16_t>(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<<MMU.timerMODE[proc][timerIndex]);
T1WriteWord(MMU.MMU_MEM[proc][0x40], 0x102+timerIndex*4, val);
NDS_RescheduleTimers();
}
//extern CACHE_ALIGN MatrixStack mtxStack[4];
uint32_t TGXSTAT::read32()
{
uint32_t ret = 0;
ret |= tb|(tr<<1);
//int _hack_getMatrixStackLevel(int which);
// stack position always equal zero. possible timings is wrong
// using in "The Wild West"
//ret |= ((_hack_getMatrixStackLevel(0) << 13) | (_hack_getMatrixStackLevel(1) << 8)); //matrix stack levels //no proof that these are needed yet
ret |= sb<<14; //stack busy
ret |= se<<15;
ret |= 255<<16;//(std::min(gxFIFO.size,(uint32_t)255))<<16;
//if(gxFIFO.size>=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<uint32_t *>(&dmaCheck),f); read32le(reinterpret_cast<uint32_t *>(&running),f); read32le(reinterpret_cast<uint32_t *>(&paused),f); read32le(reinterpret_cast<uint32_t *>(&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<uint8_t>(BIT9(valhi));
bitWidth = (EDMABitWidth)BIT10(valhi);
_startmode = (valhi>>11)&7;
if(procnum==ARMCPU_ARM7) _startmode &= 6;
irq = static_cast<uint8_t>(BIT14(valhi));
enable = static_cast<uint8_t>(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<ARMCPU_ARM9>();
else doCopy<ARMCPU_ARM7>();
//printf(";%d\n",gxFIFO.size);
}
}
//driver->DEBUG_UpdateIORegView(BaseDriver::EDEBUG_IOREG_DMA);
}
template<int PROCNUM>
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<PROCNUM,MMU_AT_DMA,32,MMU_AD_READ,true>(src,true);
time_elapsed += _MMU_accesstime<PROCNUM,MMU_AT_DMA,32,MMU_AD_WRITE,true>(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<PROCNUM,MMU_AT_DMA,16,MMU_AD_READ,true>(src,true);
time_elapsed += _MMU_accesstime<PROCNUM,MMU_AT_DMA,16,MMU_AD_WRITE,true>(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<ARMCPU_ARM9>(0,val); break;
case REG_IF+1: REG_IF_WriteByte<ARMCPU_ARM9>(1,val); break;
case REG_IF+2: REG_IF_WriteByte<ARMCPU_ARM9>(2,val); break;
case REG_IF+3: REG_IF_WriteByte<ARMCPU_ARM9>(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<uint8_t>(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<ARMCPU_ARM9>(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<uint8_t>(adr-REG_VRAMCNTA), val & 0xFF);
MMU_VRAMmapControl(static_cast<uint8_t>(adr-REG_VRAMCNTA+1), val >> 8);
break;
case REG_VRAMCNTG:
MMU_VRAMmapControl(static_cast<uint8_t>(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<uint8_t>(adr-REG_VRAMCNTA), val & 0xFF);
MMU_VRAMmapControl(static_cast<uint8_t>(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<ARMCPU_ARM9>(0,val); return;
case REG_IF+2: REG_IF_WriteWord<ARMCPU_ARM9>(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<ARMCPU_ARM9>( (T1ReadLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x1A4) & 0xFFFF0000) | val);
return;
case REG_GCROMCTRL+2 :
MMU_writeToGCControl<ARMCPU_ARM9>( (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/*<ARMCPU_ARM9>*/(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<uint8_t>(adr-REG_VRAMCNTA), val & 0xFF);
MMU_VRAMmapControl(static_cast<uint8_t>(adr-REG_VRAMCNTA+1), (val >> 8) & 0xFF);
MMU_VRAMmapControl(static_cast<uint8_t>(adr-REG_VRAMCNTA+2), (val >> 16) & 0xFF);
MMU_VRAMmapControl(static_cast<uint8_t>(adr-REG_VRAMCNTA+3), (val >> 24) & 0xFF);
break;
case REG_VRAMCNTE:
MMU_VRAMmapControl(static_cast<uint8_t>(adr-REG_VRAMCNTA), val & 0xFF);
MMU_VRAMmapControl(static_cast<uint8_t>(adr-REG_VRAMCNTA+1), (val >> 8) & 0xFF);
MMU_VRAMmapControl(static_cast<uint8_t>(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<uint8_t>(adr-REG_VRAMCNTA), val & 0xFF);
MMU_VRAMmapControl(static_cast<uint8_t>(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<ARMCPU_ARM9>(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<uint16_t>(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<uint16_t>(val));
return;
case REG_IPCFIFOSEND:
IPC_FIFOsend(ARMCPU_ARM9, val);
return;
case REG_GCROMCTRL :
MMU_writeToGCControl<ARMCPU_ARM9>(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/*<ARMCPU_ARM9>*/(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<uint8_t>(MMU_new.read_dma(ARMCPU_ARM9,8,adr));
switch(adr)
{
case REG_IF: return static_cast<uint8_t>(MMU.gen_IF<ARMCPU_ARM9>());
case REG_IF+1: return static_cast<uint8_t>(MMU.gen_IF<ARMCPU_ARM9>()>>8);
case REG_IF+2: return static_cast<uint8_t>(MMU.gen_IF<ARMCPU_ARM9>()>>16);
case REG_IF+3: return static_cast<uint8_t>(MMU.gen_IF<ARMCPU_ARM9>()>>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/*<ARMCPU_ARM9>*/(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<uint16_t>(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<uint16_t>(MMU.gen_IF<ARMCPU_ARM9>());
case REG_IF+2: return static_cast<uint16_t>(MMU.gen_IF<ARMCPU_ARM9>()>>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<ARMCPU_ARM9>(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<ARMCPU_ARM9>();
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<ARMCPU_ARM9>();
//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<ARMCPU_ARM9>(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<ARMCPU_ARM7>(0,val); break;
case REG_IF+1: REG_IF_WriteByte<ARMCPU_ARM7>(1,val); break;
case REG_IF+2: REG_IF_WriteByte<ARMCPU_ARM7>(2,val); break;
case REG_IF+3: REG_IF_WriteByte<ARMCPU_ARM7>(3,val); break;
case REG_POSTFLG:
// hack for patched firmwares
if (val == 1)
{
if (_MMU_ARM7_read08(REG_POSTFLG) != 0)
break;
_MMU_write32<ARMCPU_ARM9>(0x27FFE24, gameInfo.header.ARM9exe);
_MMU_write32<ARMCPU_ARM7>(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<ARMCPU_ARM7>(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<ARMCPU_ARM7>(0,val); return;
case REG_IF+2: REG_IF_WriteWord<ARMCPU_ARM7>(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<ARMCPU_ARM7>( (T1ReadLong(MMU.MMU_MEM[ARMCPU_ARM7][0x40], 0x1A4) & 0xFFFF0000) | val);
return;
case REG_GCROMCTRL+2 :
MMU_writeToGCControl<ARMCPU_ARM7>( (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<ARMCPU_ARM7>(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<ARMCPU_ARM7>(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<uint16_t>(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<uint16_t>(val));
return;
case REG_IPCFIFOSEND:
IPC_FIFOsend(ARMCPU_ARM7, val);
return;
case REG_GCROMCTRL :
MMU_writeToGCControl<ARMCPU_ARM7>(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<ARMCPU_ARM7>(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<uint8_t>(MMU_new.read_dma(ARMCPU_ARM7,8,adr));
// Address is an IO register
switch(adr)
{
case REG_IF: return static_cast<uint8_t>(MMU.gen_IF<ARMCPU_ARM7>());
case REG_IF+1: return static_cast<uint8_t>(MMU.gen_IF<ARMCPU_ARM7>()>>8);
case REG_IF+2: return static_cast<uint8_t>(MMU.gen_IF<ARMCPU_ARM7>()>>16);
case REG_IF+3: return static_cast<uint8_t>(MMU.gen_IF<ARMCPU_ARM7>()>>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<ARMCPU_ARM7>(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<uint16_t>(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<uint16_t>(MMU.gen_IF<ARMCPU_ARM7>());
case REG_IF+2: return static_cast<uint16_t>(MMU.gen_IF<ARMCPU_ARM7>()>>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<ARMCPU_ARM7>(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<ARMCPU_ARM7>();
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<ARMCPU_ARM7>();
}
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<ARMCPU_ARM7>(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<ARMCPU_ARM9>();
template uint32_t MMU_struct::gen_IF<ARMCPU_ARM7>();
////////////////////////////////////////////////////////////
//function pointer handlers for gdb stub stuff
/*static uint16_t FASTCALL arm9_prefetch16( void *, uint32_t adr) {
return _MMU_read16<ARMCPU_ARM9,MMU_AT_CODE>(adr);
}
static uint32_t FASTCALL arm9_prefetch32( void *, uint32_t adr) {
return _MMU_read32<ARMCPU_ARM9,MMU_AT_CODE>(adr);
}
static uint8_t FASTCALL arm9_read8( void *, uint32_t adr) {
return _MMU_read08<ARMCPU_ARM9>(adr);
}
static uint16_t FASTCALL arm9_read16( void *, uint32_t adr) {
return _MMU_read16<ARMCPU_ARM9>(adr);
}
static uint32_t FASTCALL arm9_read32( void *, uint32_t adr) {
return _MMU_read32<ARMCPU_ARM9>(adr);
}
static void FASTCALL arm9_write8(void *, uint32_t adr, uint8_t val) {
_MMU_write08<ARMCPU_ARM9>(adr, val);
}
static void FASTCALL arm9_write16(void *, uint32_t adr, uint16_t val) {
_MMU_write16<ARMCPU_ARM9>(adr, val);
}
static void FASTCALL arm9_write32(void *, uint32_t adr, uint32_t val) {
_MMU_write32<ARMCPU_ARM9>(adr, val);
}
static uint16_t FASTCALL arm7_prefetch16( void *, uint32_t adr) {
return _MMU_read16<ARMCPU_ARM7,MMU_AT_CODE>(adr);
}
static uint32_t FASTCALL arm7_prefetch32( void *, uint32_t adr) {
return _MMU_read32<ARMCPU_ARM7,MMU_AT_CODE>(adr);
}
static uint8_t FASTCALL arm7_read8( void *, uint32_t adr) {
return _MMU_read08<ARMCPU_ARM7>(adr);
}
static uint16_t FASTCALL arm7_read16( void *, uint32_t adr) {
return _MMU_read16<ARMCPU_ARM7>(adr);
}
static uint32_t FASTCALL arm7_read32( void *, uint32_t adr) {
return _MMU_read32<ARMCPU_ARM7>(adr);
}
static void FASTCALL arm7_write8(void *, uint32_t adr, uint8_t val) {
_MMU_write08<ARMCPU_ARM7>(adr, val);
}
static void FASTCALL arm7_write16(void *, uint32_t adr, uint16_t val) {
_MMU_write16<ARMCPU_ARM7>(adr, val);
}
static void FASTCALL arm7_write32(void *, uint32_t adr, uint32_t val) {
_MMU_write32<ARMCPU_ARM7>(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 */