📄 arm7tdmi.cpp
字号:
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 + -