📄 dsmmusub.cpp
字号:
/*************************************************************************** DSemu - The Next Generation ** GBA memory management: Plugin implementation [gbammu.cpp] ** Copyright Imran Nazar, 2005; released under the BSD public licence. ***************************************************************************/#include <string>#include <fstream>#include "defs.h"#include "dsmmusub.h"#include "arm7tdmi.h"#include "plgcpu.h"#include "config.h"#include "log.h"#include "err.h"#include "font5x7.h"#include "byteswap.h"//---Static private class members------------------------------------------// Every plugin has an INFO structure attached, with info about the plugin.PLUGININFO dsMMUsub::pInfo={ PLUGIN_TYPE_MMU, 0x00010001, "DS SubCPU memory manager", "DSemu-ng"};u8 *dsMMUsub::EWRAM , *dsMMUsub::IWRAM , *dsMMUsub::BIOS , *dsMMUsub::ROM ;u16 *dsMMUsub::EWRAMh, *dsMMUsub::IWRAMh, *dsMMUsub::BIOSh, *dsMMUsub::ROMh;u32 *dsMMUsub::EWRAMw, *dsMMUsub::IWRAMw, *dsMMUsub::BIOSw, *dsMMUsub::ROMw;u8 *dsMMUsub::SWRAM; u16 *dsMMUsub::SWRAMh; u32 *dsMMUsub::SWRAMw;std::string dsMMUsub::pluginName;GUIPlugin *dsMMUsub::GUI=NULL;ARM7TDMI *dsMMUsub::CPU=NULL;int dsMMUsub::dmpwinID;u32 *dsMMUsub::dmpbuffer;u32 dsMMUsub::dmpaddr = 0x04000000;dsMMUsub::PAGE dsMMUsub::mmioPages[256];dsMMUsub::IOREG dsMMUsub::interruptIO[4];u32 dsMMUsub::ROMsize;u32 dsMMUsub::BIOSsize;std::string dsMMUsub::ROMfile;int dsMMUsub::waitSRAM, dsMMUsub::waitROM0;int dsMMUsub::waitROM1, dsMMUsub::waitROM2;int dsMMUsub::waitROM0s, dsMMUsub::waitROM1s, dsMMUsub::waitROM2s;u32 dsMMUsub::prevROMaddr;// Pointer to the DMA subhandlerdsMMUsub::DMA *dsMMUsub::dma=NULL;//---Implementation--------------------------------------------------------// Load a binaryvoid dsMMUsub::load(std::string fname){ ROMfile = std::string(fname); NDShead hd(fname); std::ifstream input(fname.c_str(), std::ios::binary); u8 *tmp = new u8[hd.head.arm7size]; if(!tmp) throw Exception(ERR_MMU_LOAD, pName, "Couldn't allocate temporary ROM space."); input.seekg(hd.head.arm7src, std::ios::beg); input.read((char*)tmp, hd.head.arm7size); input.close(); ROMsize=nlpo2(hd.head.arm7size); for(u32 i=0; i<hd.head.arm7size>>2; i++) wrW(hd.head.arm7dest+(i<<2), ((u32*)tmp)[i]); CPU->setPC(hd.head.arm7exec); char str[256]; sprintf(str, "Loaded %d bytes to %08X, starting ARM7 execution at %08X.", hd.head.arm7size, hd.head.arm7dest, hd.head.arm7exec); Logger::log(pluginName) << str;}// Switch privilege levels (totally ignored in GBA's MMU)void dsMMUsub::priv(u8 level) { }void dsMMUsub::waitstates(u16 r){ switch(r&0x0003) { case 0: waitSRAM=4; break; case 1: waitSRAM=3; break; case 2: waitSRAM=2; break; case 3: waitSRAM=8; break; } switch(r&0x000C) { case 0x0000: waitROM0=4; break; case 0x0004: waitROM0=3; break; case 0x0008: waitROM0=2; break; case 0x000C: waitROM0=8; break; } waitROM0s=(r&0x0010)?1:2; switch(r&0x0060) { case 0x0000: waitROM1=4; break; case 0x0020: waitROM1=3; break; case 0x0040: waitROM1=2; break; case 0x0060: waitROM1=8; break; } waitROM1s=(r&0x0080)?1:4; switch(r&0x0300) { case 0x0000: waitROM2=4; break; case 0x0100: waitROM2=3; break; case 0x0200: waitROM2=2; break; case 0x0300: waitROM2=8; break; } waitROM2s=(r&0x0400)?1:8; prevROMaddr=0;}// NOTE: The MMU works by splitting the address space into pages, each of// which may be assigned a set of access handlers. The default handlers// simply signal an unknown access; these are overwritten if a plugin// wants to do something interesting.// Register a range (set the pagetable entry)void dsMMUsub::rangeReg(u8 page, rdBptr _rdB, rdHptr _rdH, rdWptr _rdW, wrBptr _wrB, wrHptr _wrH, wrWptr _wrW){ if(!pagetable[page].set) { if(_rdB) pagetable[page].rdB=_rdB; if(_rdH) pagetable[page].rdH=_rdH; if(_rdW) pagetable[page].rdW=_rdW; if(_wrB) pagetable[page].wrB=_wrB; if(_wrH) pagetable[page].wrH=_wrH; if(_wrW) pagetable[page].wrW=_wrW; pagetable[page].set = 1; }}// Wrappers for the pagetable entry for a given address// NOTE: Endianness is automatically adjusted between host and emulationu8 dsMMUsub::rdB(u32 addr) { return pagetable[PAGE_INDEX].rdB(addr); }u16 dsMMUsub::rdH(u32 addr){ return mtohs(pagetable[PAGE_INDEX].rdH(addr)); }u32 dsMMUsub::rdW(u32 addr){ return mtohl(pagetable[PAGE_INDEX].rdW(addr)); }void dsMMUsub::wrB(u32 addr, u8 data) { pagetable[PAGE_INDEX].wrB(addr, data); }void dsMMUsub::wrH(u32 addr, u16 data){ pagetable[PAGE_INDEX].wrH(addr, htoms(data)); }void dsMMUsub::wrW(u32 addr, u32 data){ pagetable[PAGE_INDEX].wrW(addr, htoml(data)); }// Region-specific I/O// NOTE: The BIOS and ROM are (of course) non-writableu8 dsMMUsub::rdB_EWRAM(u32 addr) { CPU->clockAdd(2); return EWRAM [(addr&0x003FFFFF) ]; }u16 dsMMUsub::rdH_EWRAM(u32 addr) { CPU->clockAdd(2); return EWRAMh[(addr&0x003FFFFF)>>1]; }u32 dsMMUsub::rdW_EWRAM(u32 addr) { CPU->clockAdd(5); return EWRAMw[(addr&0x003FFFFF)>>2]; }u8 dsMMUsub::rdB_IWRAM(u32 addr) { return IWRAM [(addr&0x0000FFFF) ]; }u16 dsMMUsub::rdH_IWRAM(u32 addr) { return IWRAMh[(addr&0x0000FFFF)>>1]; }u32 dsMMUsub::rdW_IWRAM(u32 addr) { return IWRAMw[(addr&0x0000FFFF)>>2]; }u8 dsMMUsub::rdB_SWRAM(u32 addr) { return SWRAM [(addr&0x0000FFFF) ]; }u16 dsMMUsub::rdH_SWRAM(u32 addr) { return SWRAMh[(addr&0x0000FFFF)>>1]; }u32 dsMMUsub::rdW_SWRAM(u32 addr) { return SWRAMw[(addr&0x0000FFFF)>>2]; }u8 dsMMUsub::rdB_BIOS (u32 addr) { return BIOS [(addr&BIOSsize ) ]; }u16 dsMMUsub::rdH_BIOS (u32 addr) { return BIOSh [(addr&BIOSsize )>>1]; }u32 dsMMUsub::rdW_BIOS (u32 addr) { return BIOSw [(addr&BIOSsize )>>2]; }u8 dsMMUsub::rdB_ROM (u32 addr){ switch(addr&0x0E000000) { case 0x08000000: CPU->clockAdd((addr==(prevROMaddr+1))?waitROM0s:waitROM0); break; case 0x0A000000: CPU->clockAdd((addr==(prevROMaddr+1))?waitROM1s:waitROM1); break; case 0x0C000000: CPU->clockAdd((addr==(prevROMaddr+1))?waitROM2s:waitROM2); break; } prevROMaddr=addr; return ROM [(addr&ROMsize ) ];}u16 dsMMUsub::rdH_ROM (u32 addr){ switch(addr&0x0E000000) { case 0x08000000: CPU->clockAdd((addr==(prevROMaddr+2))?waitROM0s:waitROM0); break; case 0x0A000000: CPU->clockAdd((addr==(prevROMaddr+2))?waitROM1s:waitROM1); break; case 0x0C000000: CPU->clockAdd((addr==(prevROMaddr+2))?waitROM2s:waitROM2); break; } prevROMaddr=addr; return ROMh [(addr&ROMsize )>>1];}u32 dsMMUsub::rdW_ROM (u32 addr){ switch(addr&0x0E000000) { case 0x08000000: CPU->clockAdd((addr==(prevROMaddr+4))?waitROM0s+3:waitROM0+3); break; case 0x0A000000: CPU->clockAdd((addr==(prevROMaddr+4))?waitROM1s+3:waitROM1+3); break; case 0x0C000000: CPU->clockAdd((addr==(prevROMaddr+4))?waitROM2s+3:waitROM2+3); break; } prevROMaddr=addr; return ROMw [(addr&ROMsize )>>2];}void dsMMUsub::wrB_EWRAM(u32 a, u8 d) { CPU->clockAdd(2); EWRAM [(a&0x003FFFFF) ]=d; }void dsMMUsub::wrH_EWRAM(u32 a, u16 d) { CPU->clockAdd(2); EWRAMh[(a&0x003FFFFF)>>1]=d; }void dsMMUsub::wrW_EWRAM(u32 a, u32 d) { CPU->clockAdd(5); EWRAMw[(a&0x003FFFFF)>>2]=d; }void dsMMUsub::wrB_IWRAM(u32 a, u8 d) { IWRAM [(a&0x0000FFFF) ]=d; }void dsMMUsub::wrH_IWRAM(u32 a, u16 d) { IWRAMh[(a&0x0000FFFF)>>1]=d; }void dsMMUsub::wrW_IWRAM(u32 a, u32 d) { IWRAMw[(a&0x0000FFFF)>>2]=d; }void dsMMUsub::wrB_SWRAM(u32 a, u8 d) { SWRAM [(a&0x00007FFF) ]=d; }void dsMMUsub::wrH_SWRAM(u32 a, u16 d) { SWRAMh[(a&0x00007FFF)>>1]=d; }void dsMMUsub::wrW_SWRAM(u32 a, u32 d) { SWRAMw[(a&0x00007FFF)>>2]=d; }void dsMMUsub::wrB_BIOS (u32 a, u8 d) { }void dsMMUsub::wrH_BIOS (u32 a, u16 d) { }void dsMMUsub::wrW_BIOS (u32 a, u32 d) { }void dsMMUsub::wrB_ROM (u32 a, u8 d) { }void dsMMUsub::wrH_ROM (u32 a, u16 d) { }void dsMMUsub::wrW_ROM (u32 a, u32 d) { }// Default pagetable entries (signal that something bad happened)u8 dsMMUsub::rdB_BAD(u32 a){ char str[128]; sprintf(str, "Bad access: rdB %08X", a);// Logger::log(pluginName) << str; return 0;}u16 dsMMUsub::rdH_BAD(u32 a){ char str[128]; sprintf(str, "Bad access: rdH %08X", a);// Logger::log(pluginName) << str; return 0;}u32 dsMMUsub::rdW_BAD(u32 a){ char str[128]; sprintf(str, "Bad access: rdW %08X", a);// Logger::log(pluginName) << str; return 0;}void dsMMUsub::wrB_BAD(u32 a, u8 d){ char str[128]; sprintf(str, "Bad access: wrB %08X, %02X", a, d); Logger::log(pluginName) << str;}void dsMMUsub::wrH_BAD(u32 a, u16 d){ char str[128]; sprintf(str, "Bad access: wrH %08X, %04X", a, d); Logger::log(pluginName) << str;}void dsMMUsub::wrW_BAD(u32 a, u32 d){ char str[128]; sprintf(str, "Bad access: wrW %08X, %08X", a, d); Logger::log(pluginName) << str;}// Memory-mapped I/O registration. This works similarly to main memory,// by paging the space. Of course, each page is much smaller.void dsMMUsub::mmioReg(u8 page, rdBptr _rdB, rdHptr _rdH, rdWptr _rdW, wrBptr _wrB, wrHptr _wrH, wrWptr _wrW){ if(!mmioPages[page].set) { if(_rdB) mmioPages[page].rdB=_rdB; if(_rdH) mmioPages[page].rdH=_rdH; if(_rdW) mmioPages[page].rdW=_rdW; if(_wrB) mmioPages[page].wrB=_wrB; if(_wrH) mmioPages[page].wrH=_wrH; if(_wrW) mmioPages[page].wrW=_wrW; mmioPages[page].set = 1; }}// Wrapper functions that will be called to access MMIO; these index// the MMIO page table.// NOTE: No endian conversions are done here; they're performed by the// top-level rd?/wr? functions.u8 dsMMUsub::rdB_MMIO(u32 a) { return mmioPages[MMIO_PAGE_INDEX].rdB(a); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -