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

📄 arm7tdmi.cpp

📁 一个任天堂掌上游戏机NDS的源代码
💻 CPP
📖 第 1 页 / 共 2 页
字号:
    reg.cpsr |= modeToCpsrLUT[reg.curmode];
}

// Split the CPSR into the flags[] array
void ARM7TDMI::cpsrSplit()
{
    reg.flags[FLAG_N]=(reg.cpsr>>31)&1;
    reg.flags[FLAG_Z]=(reg.cpsr>>30)&1;
    reg.flags[FLAG_C]=(reg.cpsr>>29)&1;
    reg.flags[FLAG_V]=(reg.cpsr>>28)&1;
    reg.flags[FLAG_T]=(reg.cpsr>>5)&1;

    modeSwitch(reg.curmode, modeFromCpsrLUT[reg.cpsr&15]);
}

// Add to the internal clock
void ARM7TDMI::clockAdd(int cyc)
{
    reg.clkcount += cyc;
}

// Toggle a breakpoint on or off at a specific address
void ARM7TDMI::dbgBkptToggle(u32 addr)
{
    if(bkpts.find(addr) != bkpts.end()) bkpts.erase(addr);
    else bkpts[addr]=1;

    status();
}

// Return the map of breakpoint addresses to states
std::map<u32, int> ARM7TDMI::dbgBkptGet()
{
    return bkpts;
}

// Work out how many bits in a 16-bit value are set to 1
// Used by the LDM/STM opcodes
// ACK: Donald Knuth (Sidesum algorithm)
int ARM7TDMI::ssum16(u16 val)
{
    int res=val;
    res=((res>>1)&0x5555)+(res&0x5555);
    res=((res>>2)&0x3333)+(res&0x3333);
    res=((res>>4)&0x0F0F)+(res&0x0F0F);
    res=((res>>8)&0x00FF)+(res&0x00FF);
    return res;
}

// CPU is interrupted; set up the CPU state for the int handler
void ARM7TDMI::interrupt(int type)
{
    // Type ignored for now, IRQ assumed
    reg.flags[FLAG_T]=0;
    cpsrUpdate();
    reg.cpsr |= CPSR_I;
    
    reg.r14irq = reg.r[15];
    reg.spsr[MODE_IRQ] = reg.cpsr;
    modeSwitch(reg.curmode, MODE_IRQ);

    reg.r[15] = 0x00000018;
    reg.blockstart = 0x00000018;
}

// Set the processor's PC from outside
void ARM7TDMI::setPC(u32 pc)
{
    reg.r[15] = pc;
    reg.blockstart = pc;

    // Neutralise the translation, to accommodate SMC
    if(blocks.find(reg.r[15]) != blocks.end())
	blocks[reg.r[15]].target_addr = NULL;
}

// Internal function: execute one instruction
inline int ARM7TDMI::execOne(uint64_t start)
{
	// Check the bkpts map to see if we hit one
        if(bkpts.find(reg.r[15]) != bkpts.end())
        {
            switch(bkpts[reg.r[15]])
            {
                case 1:
                    bkpts[reg.r[15]]=2;
                    return -(reg.clkcount-start);
                case 2:
                    bkpts[reg.r[15]]=1;
                    break;
            }
        }
	
	if(reg.flags[FLAG_T])
	{
	    reg.curop = (u32)MMU->rdH(reg.r[15]);
	    reg.r[15] += 2;

	    reg.clkcount += TLUT[(reg.curop&TMSK_OP)>>TSHFT_OP]();

#ifdef ARM7TDMI_DEBUG
	    cpsrUpdate();
            reg.r[15]+=2; fwrite(reg.r, 4, 17, dumpfile); reg.r[15]-=2;
#endif	    
	    
	} else {
            reg.curop = MMU->rdW(reg.r[15]);
	    
	    reg.r[15] += 4;
	    
            if(condLUT[(reg.curop&MSK_COND)>>SHFT_COND]())
            {
                reg.clkcount += OLUT[((reg.curop&MSK_OP)>>SHFT_OPH)|
                                     ((reg.curop&MSK_FUNC)>>SHFT_FUNC)]();
            }
            else reg.clkcount++;
	    
#ifdef ARM7TDMI_DEBUG
	    cpsrUpdate();
            reg.r[15]+=4; fwrite(reg.r, 4, 17, dumpfile); reg.r[15]-=4;
#endif	    
	    
	}
	return reg.clkcount-start;
}

//---Dispatch--------------------------------------------------------------
// TODO: Optimise the dispatch loop, it's damned slow

// If you want the dynarec, define this.
#ifdef ARM7TDMI_X86

void ARM7TDMI::translate(CODEBLOCK *block)
{
    int blockdone = 0, clk = 0;
    u32 curop, r15;
	
    block->target_addr = (u8*)malloc(4096);
    if(!block->target_addr)
	throw Exception(ERR_CPU_DYNALLOC, pluginName,
			"Couldn't allocate space for a new codeblock");

//    printf("Target block allocated at %08X\n", block->target_addr);
    
    x86::setblock(block);
    r15 = block->ARM_startaddr;
    
    do {
	if(block->flags & BLOCK_THUMB)
	{
	    curop = (u32)MMU->rdH(r15);
	    clk += XTLUT[(curop&TMSK_OP)>>TSHFT_OP]();
	    
	} else {
	
            curop = MMU->rdW(r15);
	    // TODO: Conditional execution, how in the hell.
	    
//            printf("Decoding %08X with function %08X\n", curop, XOLUT[((curop&MSK_OP)>>SHFT_OPH)|((curop&MSK_FUNC)>>SHFT_FUNC)]);
                clk += XOLUT[((curop&MSK_OP)>>SHFT_OPH)|((curop&MSK_FUNC)>>SHFT_FUNC)]();
	}
	
	if(block->flags & BLOCK_THUMB) r15+=2; else r15+=4;
        if(r15 > block->ARM_endaddr) blockdone = 1;
    } while(!blockdone);
    
    x86::RET(clk);
}

int ARM7TDMI::exec(int cycles)
{
    uint64_t stamp = reg.clkcount+cycles, start = reg.clkcount;

    // Handle the special case for single-stepping
    if(cycles == 1) 
	return execOne(start);

    do {
/*	if(blocks.find(reg.r[15]) != blocks.end())
	{
	    // The interpreter's found a block, and filled in a
	    // CODEBLOCK structure. If it's not translated yet,
	    // do that, and then use it.

//	    printf("Block found for r15=%08X to %08X, x86=%08X\n", reg.r[15], blocks[reg.r[15]].ARM_endaddr, blocks[reg.r[15]].target_addr);
		
            // If a breakpoint is found within this block, drop out now.
	    for(std::map<u32,int>::iterator i=bkpts.begin(); i!=bkpts.end(); ++i)
	    {
		if(((*i).first >= reg.r[15]) && 
		   ((*i).first <= blocks[reg.r[15]].ARM_endaddr))
		{
		    return -1;
		}
	    }
	    
	    if(!blocks[reg.r[15]].target_addr)
		translate(&blocks[reg.r[15]]);

	    blocks[reg.r[15]].timestamp = reg.clkcount;
	    reg.clkcount += ((opfptr)(blocks[reg.r[15]].target_addr))();

//	    printf("That block went fine.\n");
	    
	}
	else
	{
*/	    uint64_t blockstart = reg.clkcount;	
	    int blockdone=0;
	    
	    do {
	        u32 r15=reg.r[15], tmode=reg.flags[FLAG_T];
		
		// Run an instruction. If it changed the PC, that's the end
		// of this block, so save info to a new CODEBLOCK.
		execOne(start);
		if((reg.r[15] != (r15+4)) || (tmode != reg.flags[FLAG_T]))
		{
		//    char str[128];
		//    sprintf(str,"Block end detected. %08X to %08X for %d cycles", reg.blockstart, r15, reg.clkcount-blockstart);
		//    Logger::log(pluginName) << str;

		    CODEBLOCK blk={0};
		    blk.target_addr=NULL;
		    blk.ARM_startaddr=reg.blockstart;
		    blk.ARM_endaddr=r15;
		    blk.ARM_cycles=reg.clkcount-blockstart;
		    if(tmode) blk.flags |= BLOCK_THUMB; else blk.flags &= ~BLOCK_THUMB;

		    blocks[reg.blockstart] = blk;
		    reg.blockstart = reg.r[15];
		    blockdone = 1;
		}
	    } while(!blockdone);
//	}
    } while(reg.clkcount < stamp);
    return reg.clkcount - start;
}

// If you want the plain old interpreter, don't define it.
#else

int ARM7TDMI::exec(int cycles)
{
    uint64_t stamp = reg.clkcount+cycles, start = reg.clkcount;
    do execOne(start); while(reg.clkcount < stamp);
    return reg.clkcount - start;
}

#endif//ARM7TDMI_X86

//---Exceptional opcode handlers-------------------------------------------
// NOTE: As of right now, these do nothing; they are there such that the
//       opcodes can safely call them if a problem occurs. 

OPC opUND()
{
    //char str[80];
    //sprintf(str, "%08X: %08X", reg.r[15], reg.curop);
    //Logger::log(pluginName) << "Undefined opcode at " << str;
    return 1;
}

OPC opUNP()
{
    //char str[80];
    //sprintf(str, "%08X: %08X", reg.r[15], reg.curop);
    //Logger::log(pluginName) << "Unpredictable opcode at " << str;
    return 1;
}

OPC opUNI()
{
    //char str[80];
    //sprintf(str, "%08X: %08X", reg.r[15], reg.curop);
    //Logger::log(pluginName) << "Unimplemented opcode at " << str;
    return 1;
}

OPC opUNL()
{
    // Would act as cache filler
    return 1;
}

#ifdef ARM7TDMI_X86

OPC xopUND() { return opUND(); }
OPC xopUNP() { return opUNP(); }
OPC xopUNI() { return opUNI(); }
OPC xopUNL() { return opUNL(); }

#endif

//---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 function
EXPORTFUNC void getPlugin(Plugin **plg,
                          std::string name,
                          REQPTR req, UNREQPTR unreq)
{
    // Initialise a new Test plugin at the parameter
    *plg = new ARM7TDMI(name, req, unreq);
}

// Provide plugin version information
PLUGININFO *ARM7TDMI::getinfo()
{
    return &pInfo;
}

// Release plugin from outside
void ARM7TDMI::release()
{
    // Delete the Test plugin that was 'new'd in getPlugin.
    delete this;
}

/*** EOF: arm7tdmi.cpp ***************************************************/

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -