⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 gbatimer.cpp

📁 一个任天堂掌上游戏机NDS的源代码
💻 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 + -