📄 gbatimer.cpp
字号:
/*************************************************************************** DSemu - The Next Generation ** GBA interval timer emulation [gbatimer.cpp] ** Copyright Imran Nazar, 2005; released under the BSD public licence. ***************************************************************************/#include "gbatimer.h"#include "events.h"#include "log.h"//---Static private class members------------------------------------------// Every plugin has an INFO structure attached, with info about the plugin.PLUGININFO gbaTimer::pInfo={ PLUGIN_TYPE_NULL, 0x00010001, "GBA timer", "DSemu-ng"};gbaTimer::IOREG gbaTimer::reg[4];u16 gbaTimer::counter[4];u16 gbaTimer::limits[4];u32 gbaTimer::shifts[4]={1,1,1,1};uint64_t gbaTimer::cntTimestamps[4];u16 gbaTimer::oldf[4]={0};MMU32Plugin *gbaTimer::MMU=NULL;CPUPlugin *gbaTimer::CPU=NULL;GUIPlugin *gbaTimer::GUI=NULL;gbaTimer *gbaTimer::cls=NULL;std::string gbaTimer::pluginName;// Initialise plugin: register with MMU mmio spacegbaTimer::gbaTimer(std::string name, REQPTR req, UNREQPTR unreq){ pName = std::string(name); pClass = pName.substr(0, pName.find(".")+1); pRequest = req; pUnrequest = unreq; pluginName = pName; CPU = (CPUPlugin*)pRequest("GBA_CPU0.main"); MMU = (MMU32Plugin*)pRequest("GBA_CPU0.mmu"); GUI = (GUIPlugin*)pRequest("UI"); cls=this; MMU->mmioReg(0x10, rdB, rdH, rdW, wrB, wrH, wrW); Logger::log(pluginName) << "Initialised.";}// Shut down plugingbaTimer::~gbaTimer(){ pUnrequest("UI",0); GUI=NULL; pUnrequest("GBA_CPU0.mmu",1); MMU=NULL; pUnrequest("GBA_CPU0.main",1); CPU=NULL; Logger::log(pluginName) << "Shutdown.";}// Reset plugin: Clear internal values and registersvoid gbaTimer::reset(){ for(int i=0;i<4;++i) { reg[i].w=0; counter[i]=0; shifts[i]=0; cntTimestamps[i]=0; } Logger::log(pluginName) << "Reset.";}// Provide status: Nothing to say, reallyvoid gbaTimer::status(int opt1, int opt2){}// MMIO access handlers// NOTE: Whenever the registers are read, the internal counters are updated// in order that the count read is accurate.u8 gbaTimer::rdB(u32 a){ uint64_t curtime = GUI->getTimestamp(); if(!(reg[(a&15)>>2].h[1]&0x04)) counter[(a&15)>>2]=(curtime-cntTimestamps[(a&15)>>2])/shifts[(a&15)>>2]; if(counter[(a&15)>>2] == limits[(a&15)>>2]) post((a&15)>>2); switch(a&15) { case 0: return counter[0]&255; case 4: return counter[1]&255; case 8: return counter[2]&255; case 12: return counter[3]&255; case 1: return counter[0]>>8; case 5: return counter[1]>>8; case 9: return counter[2]>>8; case 13: return counter[3]>>8; default: return reg[(a&15)>>2].b[a&3]; }}u16 gbaTimer::rdH(u32 a){ uint64_t curtime = GUI->getTimestamp(); if(!(reg[(a&15)>>2].h[1]&0x04)) counter[(a&15)>>2]=(curtime-cntTimestamps[(a&15)>>2])/shifts[(a&15)>>2]; if(counter[(a&15)>>2] == limits[(a&15)>>2]) post((a&15)>>2); switch(a&14) { case 0: return counter[0]; case 4: return counter[1]; case 8: return counter[2]; case 12: return counter[3]; default: return reg[(a&15)>>2].h[(a&2)>>1]; }}u32 gbaTimer::rdW(u32 a){ uint64_t curtime = GUI->getTimestamp(); if(!(reg[(a&15)>>2].h[1]&0x04)) counter[(a&15)>>2]=(curtime-cntTimestamps[(a&15)>>2])/shifts[(a&15)>>2]; if(counter[(a&15)>>2] == limits[(a&15)>>2]) post((a&15)>>2); switch(a&12) { case 0: return counter[0]|(reg[0].h[1]<<16); case 4: return counter[1]|(reg[1].h[1]<<16); case 8: return counter[2]|(reg[2].h[1]<<16); case 12: return counter[3]|(reg[3].h[1]<<16); default: return 0xFFFFFFFF; }}// NOTE: Whenever the registers are written to, a check is performed// to see if an event needs to be posted.void gbaTimer::wrB(u32 a, u8 d) { reg[(a&15)>>2].b[a&3]=d; check((a&15)>>2, ((a&2)>>1)?2:1); }void gbaTimer::wrH(u32 a, u16 d){ reg[(a&15)>>2].h[(a&2)>>1]=d; check((a&15)>>2, ((a&2)>>1)?2:1); }void gbaTimer::wrW(u32 a, u32 d){ reg[(a&15)>>2].w=d; check((a&15)>>2, 3); }// Check the registers for a pending postvoid gbaTimer::check(int timer, int half){ if(half&1) { cntTimestamps[timer] = GUI->getTimestamp(); limits[timer] = reg[timer].h[0];// printf("At time %lld: Timer %d inited to cut at %d.\n", cntTimestamps[timer], timer, limits[timer]); } if(half&2) { if(oldf[timer] != (reg[timer].h[1]&128)) { oldf[timer] = (reg[timer].h[1]&128); if(oldf[timer]==128) post(timer); } }}// Post an event for a given timervoid gbaTimer::post(int timer){ if(!(reg[timer].h[1]&128)) return; // Calculate the amount of time to wait u32 t = limits[timer];// cntTimestamps[timer] = GUI->getTimestamp(); switch(reg[timer].h[1]&3) { case 0: t<<=0; shifts[timer]=1; break; case 1: t<<=6; shifts[timer]=64; break; case 2: t<<=8; shifts[timer]=256; break; case 3: t<<=10; shifts[timer]=1024; break; }// printf("Timer %d fired. Resetting to %08X.\n", timer, t); // Fire an interrupt if requested if(reg[timer].h[1]&0x40) { if((MMU->rdH(0x04000200)&(1<<(3+timer))) && MMU->rdH(0x04000208)) { MMU->wrH(0x04000202, MMU->rdH(0x04000202)&~(1<<(3+timer))); CPU->interrupt(CPU_INTERRUPT_NORMAL); } } // If there is a time to the next event, tell the GUI to get // back to us then. if(t) { switch(timer) { case 0: GUI->eventPush(t, EVENT_TIMER, (vfptr)post0, cls); break; case 1: GUI->eventPush(t, EVENT_TIMER, (vfptr)post1, cls); break; case 2: GUI->eventPush(t, EVENT_TIMER, (vfptr)post2, cls); break; case 3: GUI->eventPush(t, EVENT_TIMER, (vfptr)post3, cls); break; } } // If countup is set, increment the next timer's counter if(timer<3 && reg[timer+1].h[1]&0x04) { counter[timer+1]++; // printf("Countup on timer %d. Now %d out of %d.\n", timer+1, counter[timer+1], limits[timer+1]); }}// Wrapper functions that the GUI can use to call us back.void gbaTimer::post0(Plugin *plg) { ((gbaTimer*)plg)->post(0); }void gbaTimer::post1(Plugin *plg) { ((gbaTimer*)plg)->post(1); }void gbaTimer::post2(Plugin *plg) { ((gbaTimer*)plg)->post(2); }void gbaTimer::post3(Plugin *plg) { ((gbaTimer*)plg)->post(3); }//---Plugin Support--------------------------------------------------------// Retrieve Plugin class from outside// Parameters: plg - Address of a pointer to a Plugin class to 'new'// name - FQPN of plugin as listed in INI file// req - Pointer to PluginRequest API function// unreq - Pointer to PluginUnrequest API functionEXPORTFUNC void getPlugin(Plugin **plg, std::string name, REQPTR req, UNREQPTR unreq){ // Initialise a new Test plugin at the parameter *plg = new gbaTimer(name, req, unreq);}// Provide plugin version informationPLUGININFO *gbaTimer::getinfo(){ return &pInfo;}// Release plugin from outsidevoid gbaTimer::release(){ // Delete the Test plugin that was 'new'd in getPlugin. delete this;}/*** EOF: gbatimer.cpp ***************************************************/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -