2011-01-16 21:23:03 +00:00
|
|
|
//============================================================================
|
|
|
|
//
|
|
|
|
// SSSS tt lll lll
|
|
|
|
// SS SS tt ll ll
|
|
|
|
// SS tttttt eeee ll ll aaaa
|
|
|
|
// SSSS tt ee ee ll ll aa
|
|
|
|
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
|
|
|
|
// SS SS tt ee ll ll aa aa
|
|
|
|
// SSSS ttt eeeee llll llll aaaaa
|
|
|
|
//
|
|
|
|
// Copyright (c) 1995-2011 by Bradford W. Mott, Stephen Anthony
|
|
|
|
// and the Stella Team
|
|
|
|
//
|
|
|
|
// See the file "License.txt" for information on usage and redistribution of
|
|
|
|
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
|
|
|
//
|
|
|
|
// $Id$
|
|
|
|
//============================================================================
|
|
|
|
|
|
|
|
//============================================================================
|
|
|
|
// This class provides Thumb emulation code ("Thumbulator")
|
|
|
|
// by David Welch (dwelch@dwelch.com)
|
|
|
|
// Modified by Fred Quimby
|
|
|
|
// Code is public domain and used with the author's consent
|
|
|
|
//============================================================================
|
|
|
|
|
2011-04-16 16:53:41 +00:00
|
|
|
#ifdef THUMB_SUPPORT
|
|
|
|
|
2011-01-16 21:23:03 +00:00
|
|
|
#include <cstdio>
|
|
|
|
|
|
|
|
#include "bspf.hxx"
|
|
|
|
#include "Thumbulator.hxx"
|
|
|
|
|
|
|
|
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
Thumbulator::Thumbulator(uInt16* rom_ptr, uInt16* ram_ptr)
|
|
|
|
: rom(rom_ptr),
|
|
|
|
ram(ram_ptr),
|
|
|
|
copydata(0),
|
2011-01-31 03:07:52 +00:00
|
|
|
DBUG(0), // dump detailed execution trace
|
|
|
|
DISS(0) // dump Thumb instruction trace
|
2011-01-16 21:23:03 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
Thumbulator::~Thumbulator()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
int Thumbulator::run( void )
|
|
|
|
{
|
2011-03-09 14:21:32 +00:00
|
|
|
reset();
|
|
|
|
for(;;)
|
|
|
|
{
|
|
|
|
if (execute()) break;
|
|
|
|
if (instructions > 500000) // way more than would otherwise be possible
|
|
|
|
{
|
|
|
|
DISS=1; // dump instructions
|
|
|
|
DBUG=1;
|
|
|
|
}
|
|
|
|
if (instructions > 501000) // Stop dumping, quit executing
|
|
|
|
{
|
|
|
|
DISS=0;
|
|
|
|
DBUG=0;
|
2011-05-10 15:04:19 +00:00
|
|
|
throw "instructions > 501000";
|
2011-03-09 14:21:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
//dump_counters();
|
|
|
|
return 0;
|
2011-01-16 21:23:03 +00:00
|
|
|
}
|
|
|
|
|
2011-03-09 14:21:32 +00:00
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
2011-01-16 21:23:03 +00:00
|
|
|
void Thumbulator::dump_counters ( void )
|
|
|
|
{
|
2011-03-09 14:21:32 +00:00
|
|
|
cout << endl << endl
|
|
|
|
<< "instructions " << instructions << endl
|
|
|
|
<< "fetches " << fetches << endl
|
|
|
|
<< "reads " << reads << endl
|
|
|
|
<< "writes " << writes << endl
|
|
|
|
<< "memcycles " << (fetches+reads+writes) << endl;
|
2011-01-16 21:23:03 +00:00
|
|
|
}
|
|
|
|
|
2011-03-09 14:21:32 +00:00
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
2011-01-16 21:23:03 +00:00
|
|
|
uInt32 Thumbulator::fetch16 ( uInt32 addr )
|
|
|
|
{
|
2011-03-09 14:21:32 +00:00
|
|
|
uInt32 data;
|
|
|
|
|
|
|
|
fetches++;
|
|
|
|
|
|
|
|
if(DBUG)
|
|
|
|
fprintf(stderr,"fetch16(0x%08X)=",addr);
|
|
|
|
|
|
|
|
switch(addr&0xF0000000)
|
|
|
|
{
|
|
|
|
case 0x00000000: //ROM
|
|
|
|
addr &= ROMADDMASK;
|
|
|
|
if(addr<0x50)
|
|
|
|
{
|
2011-05-10 15:04:19 +00:00
|
|
|
sprintf(errorMsg,"fetch16(0x%08X), abort\n",addr);
|
|
|
|
throw errorMsg;
|
2011-03-09 14:21:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
addr>>=1;
|
|
|
|
#ifdef __BIG_ENDIAN__
|
|
|
|
data=((rom[addr]>>8)|(rom[addr]<<8))&0xffff;
|
|
|
|
#else
|
|
|
|
data=rom[addr];
|
|
|
|
#endif
|
|
|
|
if(DBUG)
|
|
|
|
fprintf(stderr,"0x%04X\n",data);
|
|
|
|
return(data);
|
|
|
|
|
|
|
|
case 0x40000000: //RAM
|
|
|
|
addr &= RAMADDMASK;
|
|
|
|
addr>>=1;
|
|
|
|
#ifdef __BIG_ENDIAN__
|
|
|
|
data=((ram[addr]>>8)|(ram[addr]<<8))&0xffff;
|
|
|
|
#else
|
|
|
|
data=ram[addr];
|
|
|
|
#endif
|
|
|
|
if(DBUG)
|
|
|
|
fprintf(stderr,"0x%04X\n",data);
|
|
|
|
return(data);
|
|
|
|
}
|
2011-05-10 15:04:19 +00:00
|
|
|
sprintf(errorMsg,"fetch16(0x%08X), abort\n",addr);
|
|
|
|
throw errorMsg;
|
2011-01-16 21:23:03 +00:00
|
|
|
}
|
|
|
|
|
2011-03-09 14:21:32 +00:00
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
2011-01-16 21:23:03 +00:00
|
|
|
uInt32 Thumbulator::fetch32 ( uInt32 addr )
|
|
|
|
{
|
2011-03-09 14:21:32 +00:00
|
|
|
uInt32 data;
|
|
|
|
|
|
|
|
if(DBUG)
|
|
|
|
fprintf(stderr,"fetch32(0x%08X)=",addr);
|
|
|
|
|
|
|
|
switch(addr&0xF0000000)
|
|
|
|
{
|
|
|
|
case 0x00000000: //ROM
|
|
|
|
if(addr<0x50)
|
|
|
|
{
|
|
|
|
data=read32(addr);
|
|
|
|
if(DBUG)
|
|
|
|
fprintf(stderr,"0x%08X\n",data);
|
|
|
|
if(addr==0x00000000) return(data);
|
|
|
|
if(addr==0x00000004) return(data);
|
2011-05-10 15:04:19 +00:00
|
|
|
sprintf(errorMsg,"fetch32(0x%08X), abort\n",addr);
|
|
|
|
throw errorMsg;
|
2011-03-09 14:21:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
case 0x40000000: //RAM
|
|
|
|
data =fetch16(addr+2);
|
|
|
|
data<<=16;
|
|
|
|
data|=fetch16(addr+0);
|
|
|
|
if(DBUG)
|
|
|
|
fprintf(stderr,"0x%08X\n",data);
|
|
|
|
return(data);
|
|
|
|
}
|
2011-05-10 15:04:19 +00:00
|
|
|
sprintf(errorMsg,"fetch32(0x%08X), abort\n",addr);
|
|
|
|
throw errorMsg;
|
2011-01-16 21:23:03 +00:00
|
|
|
}
|
|
|
|
|
2011-03-09 14:21:32 +00:00
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
2011-01-16 21:23:03 +00:00
|
|
|
void Thumbulator::write16 ( uInt32 addr, uInt32 data )
|
|
|
|
{
|
2011-03-09 14:21:32 +00:00
|
|
|
writes++;
|
|
|
|
|
|
|
|
if(DBUG)
|
|
|
|
fprintf(stderr,"write16(0x%08X,0x%08X)\n",addr,data);
|
|
|
|
|
|
|
|
switch(addr&0xF0000000)
|
|
|
|
{
|
|
|
|
case 0x40000000: //RAM
|
|
|
|
addr&=RAMADDMASK;
|
|
|
|
addr>>=1;
|
|
|
|
#ifdef __BIG_ENDIAN__
|
|
|
|
ram[addr]=(((data&0xFFFF)>>8)|((data&0xffff)<<8))&0xffff;
|
|
|
|
#else
|
|
|
|
ram[addr]=data&0xFFFF;
|
|
|
|
#endif
|
|
|
|
return;
|
|
|
|
}
|
2011-05-10 15:04:19 +00:00
|
|
|
sprintf(errorMsg,"write16(0x%08X,0x%08X), abort\n",addr,data);
|
|
|
|
throw errorMsg;
|
2011-01-16 21:23:03 +00:00
|
|
|
}
|
|
|
|
|
2011-03-09 14:21:32 +00:00
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
2011-01-16 21:23:03 +00:00
|
|
|
void Thumbulator::write32 ( uInt32 addr, uInt32 data )
|
|
|
|
{
|
2011-03-09 14:21:32 +00:00
|
|
|
if(DBUG)
|
|
|
|
fprintf(stderr,"write32(0x%08X,0x%08X)\n",addr,data);
|
|
|
|
|
|
|
|
switch(addr&0xF0000000)
|
|
|
|
{
|
|
|
|
case 0xF0000000: //halt
|
|
|
|
dump_counters();
|
2011-05-10 15:04:19 +00:00
|
|
|
throw "HALT";// exit(0);
|
2011-03-09 14:21:32 +00:00
|
|
|
|
|
|
|
case 0xE0000000: //periph
|
|
|
|
switch(addr)
|
|
|
|
{
|
|
|
|
case 0xE0000000:
|
|
|
|
if(DISS) printf("uart: [");
|
|
|
|
printf("%c",data&0xFF);
|
|
|
|
if(DISS) printf("]\n");
|
|
|
|
fflush(stdout);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
|
|
|
|
case 0xD0000000: //debug
|
|
|
|
fprintf(stderr,"[0x%08X][0x%08X] 0x%08X\n",read_register(14),addr,data);
|
|
|
|
return;
|
|
|
|
|
|
|
|
case 0x40000000: //RAM
|
|
|
|
write16(addr+0,(data>> 0)&0xFFFF);
|
|
|
|
write16(addr+2,(data>>16)&0xFFFF);
|
|
|
|
return;
|
|
|
|
}
|
2011-05-10 15:04:19 +00:00
|
|
|
sprintf(errorMsg,"write32(0x%08X,0x%08X), abort\n",addr,data);
|
|
|
|
throw errorMsg;
|
2011-01-16 21:23:03 +00:00
|
|
|
}
|
|
|
|
|
2011-03-09 14:21:32 +00:00
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
2011-01-16 21:23:03 +00:00
|
|
|
uInt32 Thumbulator::read16 ( uInt32 addr )
|
|
|
|
{
|
2011-03-09 14:21:32 +00:00
|
|
|
uInt32 data;
|
|
|
|
|
|
|
|
reads++;
|
|
|
|
|
|
|
|
if(DBUG)
|
|
|
|
fprintf(stderr,"read16(0x%08X)=",addr);
|
|
|
|
|
|
|
|
switch(addr&0xF0000000)
|
|
|
|
{
|
|
|
|
case 0x00000000: //ROM
|
|
|
|
addr&=ROMADDMASK;
|
|
|
|
addr>>=1;
|
|
|
|
#ifdef __BIG_ENDIAN__
|
|
|
|
data=((rom[addr]>>8)|(rom[addr]<<8))&0xffff;
|
|
|
|
#else
|
|
|
|
data=rom[addr];
|
|
|
|
#endif
|
|
|
|
if(DBUG)
|
|
|
|
fprintf(stderr,"0x%04X\n",data);
|
|
|
|
return(data);
|
|
|
|
|
|
|
|
case 0x40000000: //RAM
|
|
|
|
addr&=RAMADDMASK;
|
|
|
|
addr>>=1;
|
|
|
|
#ifdef __BIG_ENDIAN__
|
|
|
|
data=((ram[addr]>>8)|(ram[addr]<<8))&0xffff;
|
|
|
|
#else
|
|
|
|
data=ram[addr];
|
|
|
|
#endif
|
|
|
|
if(DBUG)
|
|
|
|
fprintf(stderr,"0x%04X\n",data);
|
|
|
|
return(data);
|
|
|
|
}
|
2011-05-10 15:04:19 +00:00
|
|
|
sprintf(errorMsg,"read16(0x%08X), abort\n",addr);
|
|
|
|
throw errorMsg;
|
2011-01-16 21:23:03 +00:00
|
|
|
}
|
|
|
|
|
2011-03-09 14:21:32 +00:00
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
2011-01-16 21:23:03 +00:00
|
|
|
uInt32 Thumbulator::read32 ( uInt32 addr )
|
|
|
|
{
|
2011-03-09 14:21:32 +00:00
|
|
|
uInt32 data;
|
|
|
|
|
|
|
|
if(DBUG)
|
|
|
|
fprintf(stderr,"read32(0x%08X)=",addr);
|
|
|
|
|
|
|
|
switch(addr&0xF0000000)
|
|
|
|
{
|
|
|
|
case 0x00000000: //ROM
|
|
|
|
case 0x40000000: //RAM
|
|
|
|
data =read16(addr+2);
|
|
|
|
data<<=16;
|
|
|
|
data|=read16(addr+0);
|
|
|
|
if(DBUG)
|
|
|
|
fprintf(stderr,"0x%08X\n",data);
|
|
|
|
return(data);
|
|
|
|
}
|
2011-05-10 15:04:19 +00:00
|
|
|
sprintf(errorMsg,"read32(0x%08X), abort\n",addr);
|
|
|
|
throw errorMsg;
|
2011-01-16 21:23:03 +00:00
|
|
|
}
|
|
|
|
|
2011-03-09 14:21:32 +00:00
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
2011-01-16 21:23:03 +00:00
|
|
|
uInt32 Thumbulator::read_register ( uInt32 reg )
|
|
|
|
{
|
2011-03-09 14:21:32 +00:00
|
|
|
uInt32 data;
|
|
|
|
|
|
|
|
reg&=0xF;
|
|
|
|
if(DBUG)
|
|
|
|
fprintf(stderr,"read_register(%u)=",reg);
|
|
|
|
|
|
|
|
switch(cpsr&0x1F)
|
|
|
|
{
|
|
|
|
case MODE_SVC:
|
|
|
|
switch(reg) // TODO (SA) - does this do anything other than default?
|
|
|
|
{
|
|
|
|
default: data=reg_sys[reg]; break;
|
|
|
|
case 13: case 14: data=reg_svc[reg]; break;
|
|
|
|
}
|
|
|
|
if(DBUG)
|
|
|
|
fprintf(stderr,"0x%08X\n",data);
|
|
|
|
return(data);
|
|
|
|
}
|
2011-05-10 15:04:19 +00:00
|
|
|
sprintf(errorMsg,"invalid cpsr mode 0x%08X\n",cpsr);
|
|
|
|
throw errorMsg;
|
2011-01-16 21:23:03 +00:00
|
|
|
}
|
|
|
|
|
2011-03-09 14:21:32 +00:00
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
2011-01-16 21:23:03 +00:00
|
|
|
uInt32 Thumbulator::write_register ( uInt32 reg, uInt32 data )
|
|
|
|
{
|
2011-03-09 14:21:32 +00:00
|
|
|
reg&=0xF;
|
|
|
|
|
|
|
|
if(DBUG)
|
|
|
|
fprintf(stderr,"write_register(%u,0x%08X)\n",reg,data);
|
|
|
|
|
|
|
|
switch(cpsr&0x1F)
|
|
|
|
{
|
|
|
|
case MODE_SVC:
|
|
|
|
switch(reg) // TODO (SA) - does this do anything other than default?
|
|
|
|
{
|
|
|
|
default: reg_sys[reg]=data; break;
|
|
|
|
case 13: case 14: reg_svc[reg]=data; break;
|
|
|
|
}
|
|
|
|
return(data);
|
|
|
|
}
|
2011-05-10 15:04:19 +00:00
|
|
|
sprintf(errorMsg,"invalid cpsr mode 0x%08X\n",cpsr);
|
|
|
|
throw errorMsg;
|
2011-01-16 21:23:03 +00:00
|
|
|
}
|
|
|
|
|
2011-03-09 14:21:32 +00:00
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
2011-01-16 21:23:03 +00:00
|
|
|
void Thumbulator::do_zflag ( uInt32 x )
|
|
|
|
{
|
2011-03-09 14:21:32 +00:00
|
|
|
if(x==0) cpsr|=CPSR_Z;
|
|
|
|
else cpsr&=~CPSR_Z;
|
2011-01-16 21:23:03 +00:00
|
|
|
}
|
|
|
|
|
2011-03-09 14:21:32 +00:00
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
2011-01-16 21:23:03 +00:00
|
|
|
void Thumbulator::do_nflag ( uInt32 x )
|
|
|
|
{
|
2011-03-09 14:21:32 +00:00
|
|
|
if(x&0x80000000) cpsr|=CPSR_N;
|
|
|
|
else cpsr&=~CPSR_N;
|
2011-01-16 21:23:03 +00:00
|
|
|
}
|
|
|
|
|
2011-03-09 14:21:32 +00:00
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
2011-01-16 21:23:03 +00:00
|
|
|
void Thumbulator::do_cflag ( uInt32 a, uInt32 b, uInt32 c )
|
|
|
|
{
|
2011-03-09 14:21:32 +00:00
|
|
|
uInt32 rc;
|
2011-01-16 21:23:03 +00:00
|
|
|
|
2011-03-09 14:21:32 +00:00
|
|
|
cpsr&=~CPSR_C;
|
|
|
|
rc=(a&0x7FFFFFFF)+(b&0x7FFFFFFF)+c; //carry in
|
|
|
|
rc = (rc>>31)+(a>>31)+(b>>31); //carry out
|
|
|
|
if(rc&2)
|
|
|
|
cpsr|=CPSR_C;
|
2011-01-16 21:23:03 +00:00
|
|
|
}
|
|
|
|
|
2011-03-09 14:21:32 +00:00
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
2011-01-16 21:23:03 +00:00
|
|
|
void Thumbulator::do_sub_vflag ( uInt32 a, uInt32 b, uInt32 c )
|
|
|
|
{
|
2011-03-09 14:21:32 +00:00
|
|
|
cpsr&=~CPSR_V;
|
|
|
|
|
|
|
|
//if the sign bits are different
|
|
|
|
if((a&0x80000000)^(b&0x80000000))
|
|
|
|
{
|
|
|
|
//and result matches b
|
|
|
|
if((b&0x80000000)==(c&0x80000000))
|
|
|
|
cpsr|=CPSR_V;
|
|
|
|
}
|
2011-01-16 21:23:03 +00:00
|
|
|
}
|
|
|
|
|
2011-03-09 14:21:32 +00:00
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
2011-01-16 21:23:03 +00:00
|
|
|
void Thumbulator::do_add_vflag ( uInt32 a, uInt32 b, uInt32 c )
|
|
|
|
{
|
2011-03-09 14:21:32 +00:00
|
|
|
cpsr&=~CPSR_V;
|
|
|
|
|
|
|
|
//if sign bits are the same
|
|
|
|
if((a&0x80000000)==(b&0x80000000))
|
|
|
|
{
|
|
|
|
//and the result is different
|
|
|
|
if((b&0x80000000)!=(c&0x80000000))
|
|
|
|
cpsr|=CPSR_V;
|
|
|
|
}
|
2011-01-16 21:23:03 +00:00
|
|
|
}
|
|
|
|
|
2011-03-09 14:21:32 +00:00
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
2011-01-16 21:23:03 +00:00
|
|
|
void Thumbulator::do_cflag_bit ( uInt32 x )
|
|
|
|
{
|
2011-03-09 14:21:32 +00:00
|
|
|
if(x) cpsr|=CPSR_C;
|
|
|
|
else cpsr&=~CPSR_C;
|
2011-01-16 21:23:03 +00:00
|
|
|
}
|
|
|
|
|
2011-03-09 14:21:32 +00:00
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
2011-01-16 21:23:03 +00:00
|
|
|
void Thumbulator::do_vflag_bit ( uInt32 x )
|
|
|
|
{
|
2011-03-09 14:21:32 +00:00
|
|
|
if(x) cpsr|=CPSR_V;
|
|
|
|
else cpsr&=~CPSR_V;
|
2011-01-16 21:23:03 +00:00
|
|
|
}
|
|
|
|
|
2011-03-09 14:21:32 +00:00
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
2011-01-16 21:23:03 +00:00
|
|
|
int Thumbulator::execute ( void )
|
|
|
|
{
|
2011-03-09 14:21:32 +00:00
|
|
|
uInt32 pc, sp, inst,
|
|
|
|
ra,rb,rc,
|
|
|
|
rm,rd,rn,rs,
|
|
|
|
op;
|
|
|
|
|
|
|
|
pc=read_register(15);
|
|
|
|
inst=fetch16(pc-2);
|
|
|
|
pc+=2;
|
|
|
|
write_register(15,pc);
|
|
|
|
if(DISS)
|
|
|
|
fprintf(stderr,"0x%08X: 0x%04X ",(pc-5),inst);
|
|
|
|
|
|
|
|
instructions++;
|
|
|
|
|
|
|
|
//ADC
|
|
|
|
if((inst&0xFFC0)==0x4140)
|
|
|
|
{
|
|
|
|
rd=(inst>>0)&0x07;
|
|
|
|
rm=(inst>>3)&0x07;
|
|
|
|
if(DISS)
|
|
|
|
fprintf(stderr,"adc r%u,r%u\n",rd,rm);
|
|
|
|
ra=read_register(rd);
|
|
|
|
rb=read_register(rm);
|
|
|
|
rc=ra+rb;
|
|
|
|
if(cpsr&CPSR_C)
|
|
|
|
rc++;
|
|
|
|
write_register(rd,rc);
|
|
|
|
do_nflag(rc);
|
|
|
|
do_zflag(rc);
|
|
|
|
if(cpsr&CPSR_C) do_cflag(ra,rb,1);
|
|
|
|
else do_cflag(ra,rb,0);
|
|
|
|
do_add_vflag(ra,rb,rc);
|
|
|
|
return(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
//ADD(1) small immediate two registers
|
|
|
|
if((inst&0xFE00)==0x1C00)
|
|
|
|
{
|
|
|
|
rd=(inst>>0)&0x7;
|
|
|
|
rn=(inst>>3)&0x7;
|
|
|
|
rb=(inst>>6)&0x7;
|
|
|
|
if(rb)
|
|
|
|
{
|
|
|
|
if(DISS)
|
|
|
|
fprintf(stderr,"adds r%u,r%u,#0x%X\n",rd,rn,rb);
|
|
|
|
ra=read_register(rn);
|
|
|
|
rc=ra+rb;
|
|
|
|
//fprintf(stderr,"0x%08X = 0x%08X + 0x%08X\n",rc,ra,rb);
|
|
|
|
write_register(rd,rc);
|
|
|
|
do_nflag(rc);
|
|
|
|
do_zflag(rc);
|
|
|
|
do_cflag(ra,rb,0);
|
|
|
|
do_add_vflag(ra,rb,rc);
|
|
|
|
return(0);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
//this is a mov
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//ADD(2) big immediate one register
|
|
|
|
if((inst&0xF800)==0x3000)
|
|
|
|
{
|
|
|
|
rb=(inst>>0)&0xFF;
|
|
|
|
rd=(inst>>8)&0x7;
|
|
|
|
if(DISS)
|
|
|
|
fprintf(stderr,"adds r%u,#0x%02X\n",rd,rb);
|
|
|
|
ra=read_register(rd);
|
|
|
|
rc=ra+rb;
|
|
|
|
write_register(rd,rc);
|
|
|
|
do_nflag(rc);
|
|
|
|
do_zflag(rc);
|
|
|
|
do_cflag(ra,rb,0);
|
|
|
|
do_add_vflag(ra,-rb,rc);
|
|
|
|
return(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
//ADD(3) three registers
|
|
|
|
if((inst&0xFE00)==0x1800)
|
|
|
|
{
|
|
|
|
rd=(inst>>0)&0x7;
|
|
|
|
rn=(inst>>3)&0x7;
|
|
|
|
rm=(inst>>6)&0x7;
|
|
|
|
if(DISS)
|
|
|
|
fprintf(stderr,"adds r%u,r%u,r%u\n",rd,rn,rm);
|
|
|
|
ra=read_register(rn);
|
|
|
|
rb=read_register(rm);
|
|
|
|
rc=ra+rb;
|
|
|
|
write_register(rd,rc);
|
|
|
|
do_nflag(rc);
|
|
|
|
do_zflag(rc);
|
|
|
|
do_cflag(ra,rb,0);
|
|
|
|
do_add_vflag(ra,rb,rc);
|
|
|
|
return(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
//ADD(4) two registers one or both high no flags
|
|
|
|
if((inst&0xFF00)==0x4400)
|
|
|
|
{
|
|
|
|
if((inst>>6)&3)
|
|
|
|
{
|
|
|
|
//UNPREDICTABLE
|
|
|
|
}
|
|
|
|
rd=(inst>>0)&0x7;
|
|
|
|
rd|=(inst>>4)&0x8;
|
|
|
|
rm=(inst>>3)&0xF;
|
|
|
|
if(DISS)
|
|
|
|
fprintf(stderr,"add r%u,r%u\n",rd,rm);
|
|
|
|
ra=read_register(rd);
|
|
|
|
rb=read_register(rm);
|
|
|
|
rc=ra+rb;
|
|
|
|
//fprintf(stderr,"0x%08X = 0x%08X + 0x%08X\n",rc,ra,rb);
|
|
|
|
write_register(rd,rc);
|
|
|
|
return(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
//ADD(5) rd = pc plus immediate
|
|
|
|
if((inst&0xF800)==0xA000)
|
|
|
|
{
|
|
|
|
rb=(inst>>0)&0xFF;
|
|
|
|
rd=(inst>>8)&0x7;
|
|
|
|
rb<<=2;
|
|
|
|
if(DISS)
|
|
|
|
fprintf(stderr,"add r%u,PC,#0x%02X\n",rd,rb);
|
|
|
|
ra=read_register(15);
|
|
|
|
rc=(ra&(~3))+rb;
|
|
|
|
write_register(rd,rc);
|
|
|
|
return(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
//ADD(6) rd = sp plus immediate
|
|
|
|
if((inst&0xF800)==0xA800)
|
|
|
|
{
|
|
|
|
rb=(inst>>0)&0xFF;
|
|
|
|
rd=(inst>>8)&0x7;
|
|
|
|
rb<<=2;
|
|
|
|
if(DISS)
|
|
|
|
fprintf(stderr,"add r%u,SP,#0x%02X\n",rd,rb);
|
|
|
|
ra=read_register(13);
|
|
|
|
rc=ra+rb;
|
|
|
|
write_register(rd,rc);
|
|
|
|
return(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
//ADD(7) sp plus immediate
|
|
|
|
if((inst&0xFF80)==0xB000)
|
|
|
|
{
|
|
|
|
rb=(inst>>0)&0x7F;
|
|
|
|
rb<<=2;
|
|
|
|
if(DISS)
|
|
|
|
fprintf(stderr,"add SP,#0x%02X\n",rb);
|
|
|
|
ra=read_register(13);
|
|
|
|
rc=ra+rb;
|
|
|
|
write_register(13,rc);
|
|
|
|
return(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
//AND
|
|
|
|
if((inst&0xFFC0)==0x4000)
|
|
|
|
{
|
|
|
|
rd=(inst>>0)&0x7;
|
|
|
|
rm=(inst>>3)&0x7;
|
|
|
|
if(DISS)
|
|
|
|
fprintf(stderr,"ands r%u,r%u\n",rd,rm);
|
|
|
|
ra=read_register(rd);
|
|
|
|
rb=read_register(rm);
|
|
|
|
rc=ra&rb;
|
|
|
|
write_register(rd,rc);
|
|
|
|
do_nflag(rc);
|
|
|
|
do_zflag(rc);
|
|
|
|
return(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
//ASR(1) two register immediate
|
|
|
|
if((inst&0xF800)==0x1000)
|
|
|
|
{
|
|
|
|
rd=(inst>>0)&0x07;
|
|
|
|
rm=(inst>>3)&0x07;
|
|
|
|
rb=(inst>>6)&0x1F;
|
|
|
|
if(DISS)
|
|
|
|
fprintf(stderr,"asrs r%u,r%u,#0x%X\n",rd,rm,rb);
|
|
|
|
rc=read_register(rm);
|
|
|
|
if(rb==0)
|
|
|
|
{
|
|
|
|
if(rc&0x80000000)
|
|
|
|
{
|
|
|
|
do_cflag_bit(1);
|
|
|
|
rc=~0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
do_cflag_bit(0);
|
|
|
|
rc=0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
do_cflag_bit(rc&(1<<(rb-1)));
|
|
|
|
ra=rc&0x80000000;
|
|
|
|
rc>>=rb;
|
|
|
|
if(ra) //asr, sign is shifted in
|
|
|
|
{
|
|
|
|
rc|=(~0)<<(32-rb);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
write_register(rd,rc);
|
|
|
|
do_nflag(rc);
|
|
|
|
do_zflag(rc);
|
|
|
|
return(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
//ASR(2) two register
|
|
|
|
if((inst&0xFFC0)==0x4100)
|
|
|
|
{
|
|
|
|
rd=(inst>>0)&0x07;
|
|
|
|
rs=(inst>>3)&0x07;
|
|
|
|
if(DISS)
|
|
|
|
fprintf(stderr,"asrs r%u,r%u\n",rd,rs);
|
|
|
|
rc=read_register(rd);
|
|
|
|
rb=read_register(rs);
|
|
|
|
rb&=0xFF;
|
|
|
|
if(rb==0)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
else if(rb<32)
|
|
|
|
{
|
|
|
|
do_cflag_bit(rc&(1<<(rb-1)));
|
|
|
|
ra=rc&0x80000000;
|
|
|
|
rc>>=rb;
|
|
|
|
if(ra) //asr, sign is shifted in
|
|
|
|
{
|
|
|
|
rc|=(~0)<<(32-rb);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if(rc&0x80000000)
|
|
|
|
{
|
|
|
|
do_cflag_bit(1);
|
|
|
|
rc=(~0);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
do_cflag_bit(0);
|
|
|
|
rc=0;
|
|
|
|
}
|
2011-01-16 21:23:03 +00:00
|
|
|
}
|
2011-03-09 14:21:32 +00:00
|
|
|
write_register(rd,rc);
|
|
|
|
do_nflag(rc);
|
|
|
|
do_zflag(rc);
|
|
|
|
return(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
//B(1) conditional branch
|
|
|
|
if((inst&0xF000)==0xD000)
|
|
|
|
{
|
|
|
|
rb=(inst>>0)&0xFF;
|
|
|
|
if(rb&0x80)
|
|
|
|
rb|=(~0)<<8;
|
|
|
|
op=(inst>>8)&0xF;
|
|
|
|
rb<<=1;
|
|
|
|
rb+=pc;
|
|
|
|
rb+=2;
|
|
|
|
switch(op)
|
|
|
|
{
|
|
|
|
case 0x0: //b eq z set
|
|
|
|
if(DISS)
|
|
|
|
fprintf(stderr,"beq 0x%08X\n",rb-3);
|
|
|
|
if(cpsr&CPSR_Z)
|
2011-01-16 21:23:03 +00:00
|
|
|
{
|
2011-03-09 14:21:32 +00:00
|
|
|
write_register(15,rb);
|
2011-01-16 21:23:03 +00:00
|
|
|
}
|
2011-03-09 14:21:32 +00:00
|
|
|
return(0);
|
|
|
|
|
|
|
|
case 0x1: //b ne z clear
|
|
|
|
if(DISS)
|
|
|
|
fprintf(stderr,"bne 0x%08X\n",rb-3);
|
|
|
|
if(!(cpsr&CPSR_Z))
|
2011-01-16 21:23:03 +00:00
|
|
|
{
|
2011-03-09 14:21:32 +00:00
|
|
|
write_register(15,rb);
|
2011-01-16 21:23:03 +00:00
|
|
|
}
|
|
|
|
return(0);
|
|
|
|
|
2011-03-09 14:21:32 +00:00
|
|
|
case 0x2: //b cs c set
|
|
|
|
if(DISS)
|
|
|
|
fprintf(stderr,"bcs 0x%08X\n",rb-3);
|
|
|
|
if(cpsr&CPSR_C)
|
|
|
|
{
|
|
|
|
write_register(15,rb);
|
|
|
|
}
|
2011-01-16 21:23:03 +00:00
|
|
|
return(0);
|
|
|
|
|
2011-03-09 14:21:32 +00:00
|
|
|
case 0x3: //b cc c clear
|
|
|
|
if(DISS)
|
|
|
|
fprintf(stderr,"bcc 0x%08X\n",rb-3);
|
|
|
|
if(!(cpsr&CPSR_C))
|
2011-01-16 21:23:03 +00:00
|
|
|
{
|
2011-03-09 14:21:32 +00:00
|
|
|
write_register(15,rb);
|
2011-01-16 21:23:03 +00:00
|
|
|
}
|
|
|
|
return(0);
|
|
|
|
|
2011-03-09 14:21:32 +00:00
|
|
|
case 0x4: //b mi n set
|
|
|
|
if(DISS)
|
|
|
|
fprintf(stderr,"bmi 0x%08X\n",rb-3);
|
|
|
|
if(cpsr&CPSR_N)
|
|
|
|
{
|
|
|
|
write_register(15,rb);
|
|
|
|
}
|
2011-01-16 21:23:03 +00:00
|
|
|
return(0);
|
|
|
|
|
2011-03-09 14:21:32 +00:00
|
|
|
case 0x5: //b pl n clear
|
|
|
|
if(DISS)
|
|
|
|
fprintf(stderr,"bpl 0x%08X\n",rb-3);
|
|
|
|
if(!(cpsr&CPSR_N))
|
|
|
|
{
|
|
|
|
write_register(15,rb);
|
|
|
|
}
|
2011-01-16 21:23:03 +00:00
|
|
|
return(0);
|
|
|
|
|
2011-03-09 14:21:32 +00:00
|
|
|
case 0x6: //b vs v set
|
|
|
|
if(DISS)
|
|
|
|
fprintf(stderr,"bvs 0x%08X\n",rb-3);
|
|
|
|
if(cpsr&CPSR_V)
|
|
|
|
{
|
|
|
|
write_register(15,rb);
|
|
|
|
}
|
2011-01-16 21:23:03 +00:00
|
|
|
return(0);
|
|
|
|
|
2011-03-09 14:21:32 +00:00
|
|
|
case 0x7: //b vc v clear
|
|
|
|
if(DISS)
|
|
|
|
fprintf(stderr,"bvc 0x%08X\n",rb-3);
|
|
|
|
if(!(cpsr&CPSR_V))
|
|
|
|
{
|
|
|
|
write_register(15,rb);
|
|
|
|
}
|
2011-01-16 21:23:03 +00:00
|
|
|
return(0);
|
|
|
|
|
2011-03-09 14:21:32 +00:00
|
|
|
case 0x8: //b hi c set z clear
|
|
|
|
if(DISS)
|
|
|
|
fprintf(stderr,"bhi 0x%08X\n",rb-3);
|
|
|
|
if((cpsr&CPSR_C)&&(!(cpsr&CPSR_Z)))
|
2011-01-16 21:23:03 +00:00
|
|
|
{
|
2011-03-09 14:21:32 +00:00
|
|
|
write_register(15,rb);
|
2011-01-16 21:23:03 +00:00
|
|
|
}
|
2011-03-09 14:21:32 +00:00
|
|
|
return(0);
|
|
|
|
|
|
|
|
case 0x9: //b ls c clear or z set
|
|
|
|
if(DISS)
|
|
|
|
fprintf(stderr,"bls 0x%08X\n",rb-3);
|
|
|
|
if((cpsr&CPSR_Z)||(!(cpsr&CPSR_C)))
|
2011-01-16 21:23:03 +00:00
|
|
|
{
|
2011-03-09 14:21:32 +00:00
|
|
|
write_register(15,rb);
|
2011-01-16 21:23:03 +00:00
|
|
|
}
|
|
|
|
return(0);
|
|
|
|
|
2011-03-09 14:21:32 +00:00
|
|
|
case 0xA: //b ge N == V
|
|
|
|
if(DISS)
|
|
|
|
fprintf(stderr,"bge 0x%08X\n",rb-3);
|
|
|
|
ra=0;
|
|
|
|
if( (cpsr&CPSR_N) && (cpsr&CPSR_V) ) ra++;
|
|
|
|
if((!(cpsr&CPSR_N))&&(!(cpsr&CPSR_V))) ra++;
|
|
|
|
if(ra)
|
2011-01-16 21:23:03 +00:00
|
|
|
{
|
2011-03-09 14:21:32 +00:00
|
|
|
write_register(15,rb);
|
2011-01-16 21:23:03 +00:00
|
|
|
}
|
2011-03-09 14:21:32 +00:00
|
|
|
return(0);
|
|
|
|
|
|
|
|
case 0xB: //b lt N != V
|
|
|
|
if(DISS)
|
|
|
|
fprintf(stderr,"blt 0x%08X\n",rb-3);
|
|
|
|
ra=0;
|
|
|
|
if((!(cpsr&CPSR_N))&&(cpsr&CPSR_V)) ra++;
|
|
|
|
if((!(cpsr&CPSR_V))&&(cpsr&CPSR_N)) ra++;
|
|
|
|
if(ra)
|
2011-01-16 21:23:03 +00:00
|
|
|
{
|
2011-03-09 14:21:32 +00:00
|
|
|
write_register(15,rb);
|
2011-01-16 21:23:03 +00:00
|
|
|
}
|
2011-03-09 14:21:32 +00:00
|
|
|
return(0);
|
|
|
|
|
|
|
|
case 0xC: //b gt Z==0 and N == V
|
|
|
|
if(DISS)
|
|
|
|
fprintf(stderr,"bgt 0x%08X\n",rb-3);
|
|
|
|
ra=0;
|
|
|
|
if( (cpsr&CPSR_N) && (cpsr&CPSR_V) ) ra++;
|
|
|
|
if((!(cpsr&CPSR_N))&&(!(cpsr&CPSR_V))) ra++;
|
|
|
|
if(cpsr&CPSR_Z) ra=0;
|
|
|
|
if(ra)
|
2011-01-16 21:23:03 +00:00
|
|
|
{
|
2011-03-09 14:21:32 +00:00
|
|
|
write_register(15,rb);
|
2011-01-16 21:23:03 +00:00
|
|
|
}
|
|
|
|
return(0);
|
|
|
|
|
2011-03-09 14:21:32 +00:00
|
|
|
case 0xD: //b le Z==1 or N != V
|
|
|
|
if(DISS)
|
|
|
|
fprintf(stderr,"ble 0x%08X\n",rb-3);
|
|
|
|
ra=0;
|
|
|
|
if((!(cpsr&CPSR_N))&&(cpsr&CPSR_V)) ra++;
|
|
|
|
if((!(cpsr&CPSR_V))&&(cpsr&CPSR_N)) ra++;
|
|
|
|
if(cpsr&CPSR_Z) ra++;
|
|
|
|
if(ra)
|
2011-01-16 21:23:03 +00:00
|
|
|
{
|
2011-03-09 14:21:32 +00:00
|
|
|
write_register(15,rb);
|
2011-01-16 21:23:03 +00:00
|
|
|
}
|
2011-03-09 14:21:32 +00:00
|
|
|
return(0);
|
|
|
|
|
|
|
|
case 0xE:
|
|
|
|
//undefined instruction
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0xF:
|
|
|
|
//swi
|
|
|
|
break;
|
2011-01-16 21:23:03 +00:00
|
|
|
}
|
2011-03-09 14:21:32 +00:00
|
|
|
}
|
2011-01-16 21:23:03 +00:00
|
|
|
|
2011-04-16 16:53:41 +00:00
|
|
|
//B(2) unconditional branch
|
|
|
|
if((inst&0xF800)==0xE000)
|
|
|
|
{
|
|
|
|
rb=(inst>>0)&0x7FF;
|
|
|
|
if(rb&(1<<10))
|
|
|
|
rb|=(~0)<<11;
|
|
|
|
rb<<=1;
|
|
|
|
rb+=pc;
|
|
|
|
rb+=2;
|
|
|
|
if(DISS)
|
|
|
|
fprintf(stderr,"B 0x%08X\n",rb-3);
|
|
|
|
write_register(15,rb);
|
|
|
|
return(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
//BIC
|
|
|
|
if((inst&0xFFC0)==0x4380)
|
|
|
|
{
|
|
|
|
rd=(inst>>0)&0x7;
|
|
|
|
rm=(inst>>3)&0x7;
|
|
|
|
if(DISS)
|
|
|
|
fprintf(stderr,"bics r%u,r%u\n",rd,rm);
|
|
|
|
ra=read_register(rd);
|
|
|
|
rb=read_register(rm);
|
|
|
|
rc=ra&(~rb);
|
|
|
|
write_register(rd,rc);
|
|
|
|
do_nflag(rc);
|
|
|
|
do_zflag(rc);
|
|
|
|
return(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
//BKPT
|
|
|
|
if((inst&0xFF00)==0xBE00)
|
|
|
|
{
|
|
|
|
rb=(inst>>0)&0xFF;
|
|
|
|
fprintf(stderr,"bkpt 0x%02X\n",rb);
|
|
|
|
return(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
//BL/BLX(1)
|
|
|
|
if((inst&0xE000)==0xE000) //BL,BLX
|
|
|
|
{
|
|
|
|
if((inst&0x1800)==0x1000) //H=b10
|
2011-01-16 21:23:03 +00:00
|
|
|
{
|
2011-04-16 16:53:41 +00:00
|
|
|
if(DISS)
|
|
|
|
fprintf(stderr,"\n");
|
|
|
|
halfadd=inst;
|
|
|
|
return(0);
|
2011-01-16 21:23:03 +00:00
|
|
|
}
|
2011-04-16 16:53:41 +00:00
|
|
|
else if((inst&0x1800)==0x1800) //H=b11
|
2011-01-16 21:23:03 +00:00
|
|
|
{
|
2011-04-16 16:53:41 +00:00
|
|
|
//branch to thumb
|
|
|
|
rb=halfadd&((1<<11)-1);
|
|
|
|
if(rb&1<<10)
|
|
|
|
rb|=(~((1<<11)-1)); //sign extend
|
|
|
|
rb<<=11;
|
|
|
|
rb|=inst&((1<<11)-1);
|
|
|
|
rb<<=1;
|
|
|
|
rb+=pc;
|
|
|
|
if(DISS)
|
|
|
|
fprintf(stderr,"bl 0x%08X\n",rb-3);
|
|
|
|
write_register(14,pc-2);
|
|
|
|
write_register(15,rb);
|
|
|
|
return(0);
|
2011-01-16 21:23:03 +00:00
|
|
|
}
|
2011-04-16 16:53:41 +00:00
|
|
|
else if((inst&0x1800)==0x0800) //H=b01
|
2011-01-16 21:23:03 +00:00
|
|
|
{
|
2011-04-16 16:53:41 +00:00
|
|
|
//fprintf(stderr,"cannot branch to arm 0x%08X 0x%04X\n",pc,inst);
|
|
|
|
// fxq: this should exit the code without having to detect it
|
|
|
|
return(1);
|
2011-01-16 21:23:03 +00:00
|
|
|
}
|
2011-04-16 16:53:41 +00:00
|
|
|
}
|
2011-01-16 21:23:03 +00:00
|
|
|
|
2011-04-16 16:53:41 +00:00
|
|
|
//BLX(2)
|
|
|
|
if((inst&0xFF87)==0x4780)
|
|
|
|
{
|
|
|
|
rm=(inst>>3)&0xF;
|
|
|
|
if(DISS)
|
|
|
|
fprintf(stderr,"blx r%u\n",rm);
|
|
|
|
rc=read_register(rm);
|
|
|
|
//fprintf(stderr,"blx r%u 0x%X 0x%X\n",rm,rc,pc);
|
|
|
|
rc+=2;
|
|
|
|
if(rc&1)
|
2011-01-16 21:23:03 +00:00
|
|
|
{
|
2011-04-16 16:53:41 +00:00
|
|
|
write_register(14,pc-2);
|
|
|
|
write_register(15,rc);
|
|
|
|
return(0);
|
2011-01-16 21:23:03 +00:00
|
|
|
}
|
2011-04-16 16:53:41 +00:00
|
|
|
else
|
2011-01-16 21:23:03 +00:00
|
|
|
{
|
2011-04-16 16:53:41 +00:00
|
|
|
//fprintf(stderr,"cannot branch to arm 0x%08X 0x%04X\n",pc,inst);
|
|
|
|
// fxq: this could serve as exit code
|
|
|
|
return(1);
|
2011-01-16 21:23:03 +00:00
|
|
|
}
|
2011-04-16 16:53:41 +00:00
|
|
|
}
|
2011-01-16 21:23:03 +00:00
|
|
|
|
2011-04-16 16:53:41 +00:00
|
|
|
//BX
|
|
|
|
if((inst&0xFF87)==0x4700)
|
|
|
|
{
|
|
|
|
rm=(inst>>3)&0xF;
|
|
|
|
if(DISS)
|
|
|
|
fprintf(stderr,"bx r%u\n",rm);
|
|
|
|
rc=read_register(rm);
|
|
|
|
rc+=2;
|
|
|
|
//fprintf(stderr,"bx r%u 0x%X 0x%X\n",rm,rc,pc);
|
|
|
|
if(rc&1)
|
2011-01-16 21:23:03 +00:00
|
|
|
{
|
2011-04-16 16:53:41 +00:00
|
|
|
write_register(15,rc);
|
|
|
|
return(0);
|
2011-01-16 21:23:03 +00:00
|
|
|
}
|
2011-04-16 16:53:41 +00:00
|
|
|
else
|
2011-01-16 21:23:03 +00:00
|
|
|
{
|
2011-04-16 16:53:41 +00:00
|
|
|
//fprintf(stderr,"cannot branch to arm 0x%08X 0x%04X\n",pc,inst);
|
|
|
|
// fxq: or maybe this one??
|
|
|
|
return(1);
|
2011-01-16 21:23:03 +00:00
|
|
|
}
|
2011-04-16 16:53:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//CMN
|
|
|
|
if((inst&0xFFC0)==0x42C0)
|
|
|
|
{
|
|
|
|
rn=(inst>>0)&0x7;
|
|
|
|
rm=(inst>>3)&0x7;
|
|
|
|
if(DISS)
|
|
|
|
fprintf(stderr,"cmns r%u,r%u\n",rn,rm);
|
|
|
|
ra=read_register(rn);
|
|
|
|
rb=read_register(rm);
|
|
|
|
rc=ra+rb;
|
|
|
|
do_nflag(rc);
|
|
|
|
do_zflag(rc);
|
|
|
|
do_cflag(ra,rb,0);
|
|
|
|
do_add_vflag(ra,rb,rc);
|
|
|
|
return(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
//CMP(1) compare immediate
|
|
|
|
if((inst&0xF800)==0x2800)
|
|
|
|
{
|
|
|
|
rb=(inst>>0)&0xFF;
|
|
|
|
rn=(inst>>8)&0x07;
|
|
|
|
if(DISS)
|
|
|
|
fprintf(stderr,"cmp r%u,#0x%02X\n",rn,rb);
|
|
|
|
ra=read_register(rn);
|
|
|
|
rc=ra-rb;
|
|
|
|
//fprintf(stderr,"0x%08X 0x%08X\n",ra,rb);
|
|
|
|
do_nflag(rc);
|
|
|
|
do_zflag(rc);
|
|
|
|
do_cflag(ra,~rb,1);
|
|
|
|
do_sub_vflag(ra,rb,rc);
|
|
|
|
return(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
//CMP(2) compare register
|
|
|
|
if((inst&0xFFC0)==0x4280)
|
|
|
|
{
|
|
|
|
rn=(inst>>0)&0x7;
|
|
|
|
rm=(inst>>3)&0x7;
|
|
|
|
if(DISS)
|
|
|
|
fprintf(stderr,"cmps r%u,r%u\n",rn,rm);
|
|
|
|
ra=read_register(rn);
|
|
|
|
rb=read_register(rm);
|
|
|
|
rc=ra-rb;
|
|
|
|
//fprintf(stderr,"0x%08X 0x%08X\n",ra,rb);
|
|
|
|
do_nflag(rc);
|
|
|
|
do_zflag(rc);
|
|
|
|
do_cflag(ra,~rb,1);
|
|
|
|
do_sub_vflag(ra,rb,rc);
|
|
|
|
return(0);
|
|
|
|
}
|
2011-01-16 21:23:03 +00:00
|
|
|
|
2011-04-16 16:53:41 +00:00
|
|
|
//CMP(3) compare high register
|
|
|
|
if((inst&0xFF00)==0x4500)
|
|
|
|
{
|
|
|
|
if(((inst>>6)&3)==0x0)
|
2011-01-16 21:23:03 +00:00
|
|
|
{
|
2011-04-16 16:53:41 +00:00
|
|
|
//UNPREDICTABLE
|
2011-01-16 21:23:03 +00:00
|
|
|
}
|
2011-04-16 16:53:41 +00:00
|
|
|
rn=(inst>>0)&0x7;
|
|
|
|
rn|=(inst>>4)&0x8;
|
|
|
|
if(rn==0xF)
|
2011-01-16 21:23:03 +00:00
|
|
|
{
|
2011-04-16 16:53:41 +00:00
|
|
|
//UNPREDICTABLE
|
2011-01-16 21:23:03 +00:00
|
|
|
}
|
2011-04-16 16:53:41 +00:00
|
|
|
rm=(inst>>3)&0xF;
|
|
|
|
if(DISS)
|
|
|
|
fprintf(stderr,"cmps r%u,r%u\n",rn,rm);
|
|
|
|
ra=read_register(rn);
|
|
|
|
rb=read_register(rm);
|
|
|
|
rc=ra-rb;
|
|
|
|
do_nflag(rc);
|
|
|
|
do_zflag(rc);
|
|
|
|
do_cflag(ra,~rb,1);
|
|
|
|
do_sub_vflag(ra,rb,rc);
|
2011-01-16 21:23:03 +00:00
|
|
|
|
2011-04-16 16:53:41 +00:00
|
|
|
#if 0
|
2011-01-16 21:23:03 +00:00
|
|
|
if(cpsr&CPSR_N) fprintf(stderr,"N"); else fprintf(stderr,"n");
|
|
|
|
if(cpsr&CPSR_Z) fprintf(stderr,"Z"); else fprintf(stderr,"z");
|
|
|
|
if(cpsr&CPSR_C) fprintf(stderr,"C"); else fprintf(stderr,"c");
|
|
|
|
if(cpsr&CPSR_V) fprintf(stderr,"V"); else fprintf(stderr,"v");
|
|
|
|
fprintf(stderr," -- 0x%08X 0x%08X\n",ra,rb);
|
2011-04-16 16:53:41 +00:00
|
|
|
#endif
|
|
|
|
return(0);
|
|
|
|
}
|
2011-01-16 21:23:03 +00:00
|
|
|
|
2011-04-16 16:53:41 +00:00
|
|
|
//CPS
|
|
|
|
if((inst&0xFFE8)==0xB660)
|
|
|
|
{
|
|
|
|
if(DISS)
|
|
|
|
fprintf(stderr,"cps TODO\n");
|
|
|
|
return(1);
|
|
|
|
}
|
2011-01-16 21:23:03 +00:00
|
|
|
|
2011-04-16 16:53:41 +00:00
|
|
|
//CPY copy high register
|
|
|
|
if((inst&0xFFC0)==0x4600)
|
|
|
|
{
|
|
|
|
//same as mov except you can use both low registers
|
|
|
|
//going to let mov handle high registers
|
|
|
|
rd=(inst>>0)&0x7;
|
|
|
|
rm=(inst>>3)&0x7;
|
|
|
|
if(DISS)
|
|
|
|
fprintf(stderr,"cpy r%u,r%u\n",rd,rm);
|
|
|
|
rc=read_register(rm);
|
|
|
|
write_register(rd,rc);
|
|
|
|
return(0);
|
|
|
|
}
|
2011-01-16 21:23:03 +00:00
|
|
|
|
2011-04-16 16:53:41 +00:00
|
|
|
//EOR
|
|
|
|
if((inst&0xFFC0)==0x4040)
|
|
|
|
{
|
|
|
|
rd=(inst>>0)&0x7;
|
|
|
|
rm=(inst>>3)&0x7;
|
|
|
|
if(DISS)
|
|
|
|
fprintf(stderr,"eors r%u,r%u\n",rd,rm);
|
|
|
|
ra=read_register(rd);
|
|
|
|
rb=read_register(rm);
|
|
|
|
rc=ra^rb;
|
|
|
|
write_register(rd,rc);
|
|
|
|
do_nflag(rc);
|
|
|
|
do_zflag(rc);
|
|
|
|
return(0);
|
|
|
|
}
|
2011-01-16 21:23:03 +00:00
|
|
|
|
2011-04-16 16:53:41 +00:00
|
|
|
//LDMIA
|
|
|
|
if((inst&0xF800)==0xC800)
|
|
|
|
{
|
|
|
|
rn=(inst>>8)&0x7;
|
|
|
|
if(DISS)
|
2011-01-16 21:23:03 +00:00
|
|
|
{
|
2011-04-16 16:53:41 +00:00
|
|
|
fprintf(stderr,"ldmia r%u!,{",rn);
|
|
|
|
for(ra=0,rb=0x01,rc=0;rb;rb=(rb<<1)&0xFF,ra++)
|
|
|
|
{
|
2011-01-16 21:23:03 +00:00
|
|
|
if(inst&rb)
|
|
|
|
{
|
2011-04-16 16:53:41 +00:00
|
|
|
if(rc) fprintf(stderr,",");
|
|
|
|
fprintf(stderr,"r%u",ra);
|
|
|
|
rc++;
|
2011-01-16 21:23:03 +00:00
|
|
|
}
|
2011-04-16 16:53:41 +00:00
|
|
|
}
|
|
|
|
fprintf(stderr,"}\n");
|
2011-01-16 21:23:03 +00:00
|
|
|
}
|
2011-04-16 16:53:41 +00:00
|
|
|
sp=read_register(rn);
|
|
|
|
for(ra=0,rb=0x01;rb;rb=(rb<<1)&0xFF,ra++)
|
2011-01-16 21:23:03 +00:00
|
|
|
{
|
2011-04-16 16:53:41 +00:00
|
|
|
if(inst&rb)
|
|
|
|
{
|
|
|
|
write_register(ra,read32(sp));
|
|
|
|
sp+=4;
|
|
|
|
}
|
2011-01-16 21:23:03 +00:00
|
|
|
}
|
2011-04-16 16:53:41 +00:00
|
|
|
write_register(rn,sp);
|
|
|
|
return(0);
|
|
|
|
}
|
2011-01-16 21:23:03 +00:00
|
|
|
|
2011-04-16 16:53:41 +00:00
|
|
|
//LDR(1) two register immediate
|
|
|
|
if((inst&0xF800)==0x6800)
|
|
|
|
{
|
|
|
|
rd=(inst>>0)&0x07;
|
|
|
|
rn=(inst>>3)&0x07;
|
|
|
|
rb=(inst>>6)&0x1F;
|
|
|
|
rb<<=2;
|
|
|
|
if(DISS)
|
|
|
|
fprintf(stderr,"ldr r%u,[r%u,#0x%X]\n",rd,rn,rb);
|
|
|
|
rb=read_register(rn)+rb;
|
|
|
|
rc=read32(rb);
|
|
|
|
write_register(rd,rc);
|
|
|
|
return(0);
|
|
|
|
}
|
2011-01-16 21:23:03 +00:00
|
|
|
|
2011-04-16 16:53:41 +00:00
|
|
|
//LDR(2) three register
|
|
|
|
if((inst&0xFE00)==0x5800)
|
|
|
|
{
|
|
|
|
rd=(inst>>0)&0x7;
|
|
|
|
rn=(inst>>3)&0x7;
|
|
|
|
rm=(inst>>6)&0x7;
|
|
|
|
if(DISS)
|
|
|
|
fprintf(stderr,"ldr r%u,[r%u,r%u]\n",rd,rn,rm);
|
|
|
|
rb=read_register(rn)+read_register(rm);
|
|
|
|
rc=read32(rb);
|
|
|
|
write_register(rd,rc);
|
|
|
|
return(0);
|
|
|
|
}
|
2011-01-16 21:23:03 +00:00
|
|
|
|
2011-04-16 16:53:41 +00:00
|
|
|
//LDR(3)
|
|
|
|
if((inst&0xF800)==0x4800)
|
|
|
|
{
|
|
|
|
rb=(inst>>0)&0xFF;
|
|
|
|
rd=(inst>>8)&0x07;
|
|
|
|
rb<<=2;
|
|
|
|
if(DISS)
|
|
|
|
fprintf(stderr,"ldr r%u,[PC+#0x%X] ",rd,rb);
|
|
|
|
ra=read_register(15);
|
|
|
|
ra&=~3;
|
|
|
|
rb+=ra;
|
|
|
|
if(DISS)
|
|
|
|
fprintf(stderr,";@ 0x%X\n",rb);
|
|
|
|
rc=read32(rb);
|
|
|
|
write_register(rd,rc);
|
|
|
|
return(0);
|
|
|
|
}
|
2011-01-16 21:23:03 +00:00
|
|
|
|
2011-04-16 16:53:41 +00:00
|
|
|
//LDR(4)
|
|
|
|
if((inst&0xF800)==0x9800)
|
|
|
|
{
|
|
|
|
rb=(inst>>0)&0xFF;
|
|
|
|
rd=(inst>>8)&0x07;
|
|
|
|
rb<<=2;
|
|
|
|
if(DISS)
|
|
|
|
fprintf(stderr,"ldr r%u,[SP+#0x%X]\n",rd,rb);
|
|
|
|
ra=read_register(13);
|
|
|
|
//ra&=~3;
|
|
|
|
rb+=ra;
|
|
|
|
rc=read32(rb);
|
|
|
|
write_register(rd,rc);
|
|
|
|
return(0);
|
|
|
|
}
|
2011-01-16 21:23:03 +00:00
|
|
|
|
2011-04-16 16:53:41 +00:00
|
|
|
//LDRB(1)
|
|
|
|
if((inst&0xF800)==0x7800)
|
|
|
|
{
|
|
|
|
rd=(inst>>0)&0x07;
|
|
|
|
rn=(inst>>3)&0x07;
|
|
|
|
rb=(inst>>6)&0x1F;
|
|
|
|
if(DISS)
|
|
|
|
fprintf(stderr,"ldrb r%u,[r%u,#0x%X]\n",rd,rn,rb);
|
|
|
|
rb=read_register(rn)+rb;
|
|
|
|
rc=read16(rb&(~1));
|
|
|
|
if(rb&1)
|
2011-01-16 21:23:03 +00:00
|
|
|
{
|
2011-04-16 16:53:41 +00:00
|
|
|
rc>>=8;
|
2011-01-16 21:23:03 +00:00
|
|
|
}
|
2011-04-16 16:53:41 +00:00
|
|
|
else
|
2011-01-16 21:23:03 +00:00
|
|
|
{
|
|
|
|
}
|
2011-04-16 16:53:41 +00:00
|
|
|
write_register(rd,rc&0xFF);
|
|
|
|
return(0);
|
|
|
|
}
|
2011-01-16 21:23:03 +00:00
|
|
|
|
2011-04-16 16:53:41 +00:00
|
|
|
//LDRB(2)
|
|
|
|
if((inst&0xFE00)==0x5C00)
|
|
|
|
{
|
|
|
|
rd=(inst>>0)&0x7;
|
|
|
|
rn=(inst>>3)&0x7;
|
|
|
|
rm=(inst>>6)&0x7;
|
|
|
|
if(DISS)
|
|
|
|
fprintf(stderr,"ldrb r%u,[r%u,r%u]\n",rd,rn,rm);
|
|
|
|
rb=read_register(rn)+read_register(rm);
|
|
|
|
rc=read16(rb&(~1));
|
|
|
|
if(rb&1)
|
2011-01-16 21:23:03 +00:00
|
|
|
{
|
2011-04-16 16:53:41 +00:00
|
|
|
rc>>=8;
|
2011-01-16 21:23:03 +00:00
|
|
|
}
|
2011-04-16 16:53:41 +00:00
|
|
|
else
|
2011-01-16 21:23:03 +00:00
|
|
|
{
|
|
|
|
}
|
2011-04-16 16:53:41 +00:00
|
|
|
write_register(rd,rc&0xFF);
|
|
|
|
return(0);
|
|
|
|
}
|
2011-01-16 21:23:03 +00:00
|
|
|
|
2011-04-16 16:53:41 +00:00
|
|
|
//LDRH(1)
|
|
|
|
if((inst&0xF800)==0x8800)
|
|
|
|
{
|
|
|
|
rd=(inst>>0)&0x07;
|
|
|
|
rn=(inst>>3)&0x07;
|
|
|
|
rb=(inst>>6)&0x1F;
|
|
|
|
rb<<=1;
|
|
|
|
if(DISS)
|
|
|
|
fprintf(stderr,"ldrh r%u,[r%u,#0x%X]\n",rd,rn,rb);
|
|
|
|
rb=read_register(rn)+rb;
|
|
|
|
rc=read16(rb);
|
|
|
|
write_register(rd,rc&0xFFFF);
|
|
|
|
return(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
//LDRH(2)
|
|
|
|
if((inst&0xFE00)==0x5A00)
|
|
|
|
{
|
|
|
|
rd=(inst>>0)&0x7;
|
|
|
|
rn=(inst>>3)&0x7;
|
|
|
|
rm=(inst>>6)&0x7;
|
|
|
|
if(DISS)
|
|
|
|
fprintf(stderr,"ldrh r%u,[r%u,r%u]\n",rd,rn,rm);
|
|
|
|
rb=read_register(rn)+read_register(rm);
|
|
|
|
rc=read16(rb);
|
|
|
|
write_register(rd,rc&0xFFFF);
|
|
|
|
return(0);
|
|
|
|
}
|
2011-01-16 21:23:03 +00:00
|
|
|
|
2011-04-16 16:53:41 +00:00
|
|
|
//LDRSB
|
|
|
|
if((inst&0xFE00)==0x5600)
|
|
|
|
{
|
|
|
|
rd=(inst>>0)&0x7;
|
|
|
|
rn=(inst>>3)&0x7;
|
|
|
|
rm=(inst>>6)&0x7;
|
|
|
|
if(DISS)
|
|
|
|
fprintf(stderr,"ldrsb r%u,[r%u,r%u]\n",rd,rn,rm);
|
|
|
|
rb=read_register(rn)+read_register(rm);
|
|
|
|
rc=read16(rb&(~1));
|
|
|
|
if(rb&1)
|
2011-01-16 21:23:03 +00:00
|
|
|
{
|
2011-04-16 16:53:41 +00:00
|
|
|
rc>>=8;
|
2011-01-16 21:23:03 +00:00
|
|
|
}
|
2011-04-16 16:53:41 +00:00
|
|
|
else
|
2011-01-16 21:23:03 +00:00
|
|
|
{
|
|
|
|
}
|
2011-04-16 16:53:41 +00:00
|
|
|
rc&=0xFF;
|
|
|
|
if(rc&0x80) rc|=((~0)<<8);
|
|
|
|
write_register(rd,rc);
|
|
|
|
return(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
//LDRSH
|
|
|
|
if((inst&0xFE00)==0x5E00)
|
|
|
|
{
|
|
|
|
rd=(inst>>0)&0x7;
|
|
|
|
rn=(inst>>3)&0x7;
|
|
|
|
rm=(inst>>6)&0x7;
|
|
|
|
if(DISS)
|
|
|
|
fprintf(stderr,"ldrsh r%u,[r%u,r%u]\n",rd,rn,rm);
|
|
|
|
rb=read_register(rn)+read_register(rm);
|
|
|
|
rc=read16(rb);
|
|
|
|
rc&=0xFFFF;
|
|
|
|
if(rc&0x8000) rc|=((~0)<<16);
|
|
|
|
write_register(rd,rc);
|
|
|
|
return(0);
|
|
|
|
}
|
2011-01-16 21:23:03 +00:00
|
|
|
|
2011-04-16 16:53:41 +00:00
|
|
|
//LSL(1)
|
|
|
|
if((inst&0xF800)==0x0000)
|
|
|
|
{
|
|
|
|
rd=(inst>>0)&0x07;
|
|
|
|
rm=(inst>>3)&0x07;
|
|
|
|
rb=(inst>>6)&0x1F;
|
|
|
|
if(DISS)
|
|
|
|
fprintf(stderr,"lsls r%u,r%u,#0x%X\n",rd,rm,rb);
|
|
|
|
rc=read_register(rm);
|
|
|
|
if(rb==0)
|
2011-01-16 21:23:03 +00:00
|
|
|
{
|
2011-04-16 16:53:41 +00:00
|
|
|
//if immed_5 == 0
|
|
|
|
//C unnaffected
|
|
|
|
//result not shifted
|
2011-01-16 21:23:03 +00:00
|
|
|
}
|
2011-04-16 16:53:41 +00:00
|
|
|
else
|
2011-01-16 21:23:03 +00:00
|
|
|
{
|
2011-04-16 16:53:41 +00:00
|
|
|
//else immed_5 > 0
|
|
|
|
do_cflag_bit(rc&(1<<(32-rb)));
|
|
|
|
rc<<=rb;
|
2011-01-16 21:23:03 +00:00
|
|
|
}
|
2011-04-16 16:53:41 +00:00
|
|
|
write_register(rd,rc);
|
|
|
|
do_nflag(rc);
|
|
|
|
do_zflag(rc);
|
|
|
|
return(0);
|
|
|
|
}
|
2011-01-16 21:23:03 +00:00
|
|
|
|
2011-04-16 16:53:41 +00:00
|
|
|
//LSL(2) two register
|
|
|
|
if((inst&0xFFC0)==0x4080)
|
|
|
|
{
|
|
|
|
rd=(inst>>0)&0x07;
|
|
|
|
rs=(inst>>3)&0x07;
|
|
|
|
if(DISS)
|
|
|
|
fprintf(stderr,"lsls r%u,r%u\n",rd,rs);
|
|
|
|
rc=read_register(rd);
|
|
|
|
rb=read_register(rs);
|
|
|
|
rb&=0xFF;
|
|
|
|
if(rb==0)
|
2011-01-16 21:23:03 +00:00
|
|
|
{
|
|
|
|
}
|
2011-04-16 16:53:41 +00:00
|
|
|
else if(rb<32)
|
2011-01-16 21:23:03 +00:00
|
|
|
{
|
2011-04-16 16:53:41 +00:00
|
|
|
do_cflag_bit(rc&(1<<(32-rb)));
|
|
|
|
rc<<=rb;
|
2011-01-16 21:23:03 +00:00
|
|
|
}
|
2011-04-16 16:53:41 +00:00
|
|
|
else if(rb==32)
|
2011-01-16 21:23:03 +00:00
|
|
|
{
|
2011-04-16 16:53:41 +00:00
|
|
|
do_cflag_bit(rc&1);
|
|
|
|
rc=0;
|
2011-01-16 21:23:03 +00:00
|
|
|
}
|
2011-04-16 16:53:41 +00:00
|
|
|
else
|
2011-01-16 21:23:03 +00:00
|
|
|
{
|
2011-04-16 16:53:41 +00:00
|
|
|
do_cflag_bit(0);
|
|
|
|
rc=0;
|
2011-01-16 21:23:03 +00:00
|
|
|
}
|
2011-04-16 16:53:41 +00:00
|
|
|
write_register(rd,rc);
|
|
|
|
do_nflag(rc);
|
|
|
|
do_zflag(rc);
|
|
|
|
return(0);
|
|
|
|
}
|
2011-01-16 21:23:03 +00:00
|
|
|
|
2011-04-16 16:53:41 +00:00
|
|
|
//LSR(1) two register immediate
|
|
|
|
if((inst&0xF800)==0x0800)
|
|
|
|
{
|
|
|
|
rd=(inst>>0)&0x07;
|
|
|
|
rm=(inst>>3)&0x07;
|
|
|
|
rb=(inst>>6)&0x1F;
|
|
|
|
if(DISS)
|
|
|
|
fprintf(stderr,"lsrs r%u,r%u,#0x%X\n",rd,rm,rb);
|
|
|
|
rc=read_register(rm);
|
|
|
|
if(rb==0)
|
2011-01-16 21:23:03 +00:00
|
|
|
{
|
2011-04-16 16:53:41 +00:00
|
|
|
do_cflag_bit(rc&0x80000000);
|
|
|
|
rc=0;
|
2011-01-16 21:23:03 +00:00
|
|
|
}
|
2011-04-16 16:53:41 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
do_cflag_bit(rc&(1<<(rb-1)));
|
|
|
|
rc>>=rb;
|
|
|
|
}
|
|
|
|
write_register(rd,rc);
|
|
|
|
do_nflag(rc);
|
|
|
|
do_zflag(rc);
|
|
|
|
return(0);
|
|
|
|
}
|
2011-01-16 21:23:03 +00:00
|
|
|
|
2011-04-16 16:53:41 +00:00
|
|
|
//LSR(2) two register
|
|
|
|
if((inst&0xFFC0)==0x40C0)
|
|
|
|
{
|
|
|
|
rd=(inst>>0)&0x07;
|
|
|
|
rs=(inst>>3)&0x07;
|
|
|
|
if(DISS)
|
|
|
|
fprintf(stderr,"lsrs r%u,r%u\n",rd,rs);
|
|
|
|
rc=read_register(rd);
|
|
|
|
rb=read_register(rs);
|
|
|
|
rb&=0xFF;
|
|
|
|
if(rb==0)
|
2011-01-16 21:23:03 +00:00
|
|
|
{
|
|
|
|
}
|
2011-04-16 16:53:41 +00:00
|
|
|
else if(rb<32)
|
|
|
|
{
|
|
|
|
do_cflag_bit(rc&(1<<(32-rb)));
|
|
|
|
rc>>=rb;
|
|
|
|
}
|
|
|
|
else if(rb==32)
|
|
|
|
{
|
|
|
|
do_cflag_bit(rc&0x80000000);
|
|
|
|
rc=0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
do_cflag_bit(0);
|
|
|
|
rc=0;
|
|
|
|
}
|
|
|
|
write_register(rd,rc);
|
|
|
|
do_nflag(rc);
|
|
|
|
do_zflag(rc);
|
|
|
|
return(0);
|
|
|
|
}
|
2011-01-16 21:23:03 +00:00
|
|
|
|
2011-04-16 16:53:41 +00:00
|
|
|
//MOV(1) immediate
|
|
|
|
if((inst&0xF800)==0x2000)
|
|
|
|
{
|
|
|
|
rb=(inst>>0)&0xFF;
|
|
|
|
rd=(inst>>8)&0x07;
|
|
|
|
if(DISS)
|
|
|
|
fprintf(stderr,"movs r%u,#0x%02X\n",rd,rb);
|
|
|
|
write_register(rd,rb);
|
|
|
|
do_nflag(rb);
|
|
|
|
do_zflag(rb);
|
|
|
|
return(0);
|
|
|
|
}
|
2011-01-16 21:23:03 +00:00
|
|
|
|
2011-04-16 16:53:41 +00:00
|
|
|
//MOV(2) two low registers
|
|
|
|
if((inst&0xFFC0)==0x1C00)
|
|
|
|
{
|
|
|
|
rd=(inst>>0)&7;
|
|
|
|
rn=(inst>>3)&7;
|
|
|
|
if(DISS)
|
|
|
|
fprintf(stderr,"movs r%u,r%u\n",rd,rn);
|
|
|
|
rc=read_register(rn);
|
|
|
|
//fprintf(stderr,"0x%08X\n",rc);
|
|
|
|
write_register(rd,rc);
|
|
|
|
do_nflag(rc);
|
|
|
|
do_zflag(rc);
|
|
|
|
do_cflag_bit(0);
|
|
|
|
do_vflag_bit(0);
|
|
|
|
return(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
//MOV(3)
|
|
|
|
if((inst&0xFF00)==0x4600)
|
|
|
|
{
|
|
|
|
rd=(inst>>0)&0x7;
|
|
|
|
rd|=(inst>>4)&0x8;
|
|
|
|
rm=(inst>>3)&0xF;
|
|
|
|
if(DISS)
|
|
|
|
fprintf(stderr,"mov r%u,r%u\n",rd,rm);
|
|
|
|
rc=read_register(rm);
|
|
|
|
if (rd==15) rc+=2; // fxq fix for MOV R15
|
|
|
|
write_register(rd,rc);
|
|
|
|
return(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
//MUL
|
|
|
|
if((inst&0xFFC0)==0x4340)
|
|
|
|
{
|
|
|
|
rd=(inst>>0)&0x7;
|
|
|
|
rm=(inst>>3)&0x7;
|
|
|
|
if(DISS)
|
|
|
|
fprintf(stderr,"muls r%u,r%u\n",rd,rm);
|
|
|
|
ra=read_register(rd);
|
|
|
|
rb=read_register(rm);
|
|
|
|
rc=ra*rb;
|
|
|
|
write_register(rd,rc);
|
|
|
|
do_nflag(rc);
|
|
|
|
do_zflag(rc);
|
|
|
|
return(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
//MVN
|
|
|
|
if((inst&0xFFC0)==0x43C0)
|
|
|
|
{
|
|
|
|
rd=(inst>>0)&0x7;
|
|
|
|
rm=(inst>>3)&0x7;
|
|
|
|
if(DISS)
|
|
|
|
fprintf(stderr,"mvns r%u,r%u\n",rd,rm);
|
|
|
|
ra=read_register(rm);
|
|
|
|
rc=(~ra);
|
|
|
|
write_register(rd,rc);
|
|
|
|
do_nflag(rc);
|
|
|
|
do_zflag(rc);
|
|
|
|
return(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
//NEG
|
|
|
|
if((inst&0xFFC0)==0x4240)
|
|
|
|
{
|
|
|
|
rd=(inst>>0)&0x7;
|
|
|
|
rm=(inst>>3)&0x7;
|
|
|
|
if(DISS)
|
|
|
|
fprintf(stderr,"negs r%u,r%u\n",rd,rm);
|
|
|
|
ra=read_register(rm);
|
|
|
|
rc=0-ra;
|
|
|
|
write_register(rd,rc);
|
|
|
|
do_nflag(rc);
|
|
|
|
do_zflag(rc);
|
|
|
|
do_cflag(0,~ra,1);
|
|
|
|
do_sub_vflag(0,ra,rc);
|
|
|
|
return(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
//ORR
|
|
|
|
if((inst&0xFFC0)==0x4300)
|
|
|
|
{
|
|
|
|
rd=(inst>>0)&0x7;
|
|
|
|
rm=(inst>>3)&0x7;
|
|
|
|
if(DISS)
|
|
|
|
fprintf(stderr,"orrs r%u,r%u\n",rd,rm);
|
|
|
|
ra=read_register(rd);
|
|
|
|
rb=read_register(rm);
|
|
|
|
rc=ra|rb;
|
|
|
|
write_register(rd,rc);
|
|
|
|
do_nflag(rc);
|
|
|
|
do_zflag(rc);
|
|
|
|
return(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
//POP
|
|
|
|
if((inst&0xFE00)==0xBC00)
|
|
|
|
{
|
|
|
|
if(DISS)
|
2011-01-16 21:23:03 +00:00
|
|
|
{
|
2011-04-16 16:53:41 +00:00
|
|
|
fprintf(stderr,"pop {");
|
|
|
|
for(ra=0,rb=0x01,rc=0;rb;rb=(rb<<1)&0xFF,ra++)
|
|
|
|
{
|
2011-01-16 21:23:03 +00:00
|
|
|
if(inst&rb)
|
|
|
|
{
|
2011-04-16 16:53:41 +00:00
|
|
|
if(rc) fprintf(stderr,",");
|
|
|
|
fprintf(stderr,"r%u",ra);
|
|
|
|
rc++;
|
2011-01-16 21:23:03 +00:00
|
|
|
}
|
2011-04-16 16:53:41 +00:00
|
|
|
}
|
|
|
|
if(inst&0x100)
|
|
|
|
{
|
2011-01-16 21:23:03 +00:00
|
|
|
if(rc) fprintf(stderr,",");
|
|
|
|
fprintf(stderr,"pc");
|
2011-04-16 16:53:41 +00:00
|
|
|
}
|
|
|
|
fprintf(stderr,"}\n");
|
2011-01-16 21:23:03 +00:00
|
|
|
}
|
|
|
|
|
2011-04-16 16:53:41 +00:00
|
|
|
sp=read_register(13);
|
|
|
|
for(ra=0,rb=0x01;rb;rb=(rb<<1)&0xFF,ra++)
|
|
|
|
{
|
|
|
|
if(inst&rb)
|
|
|
|
{
|
|
|
|
write_register(ra,read32(sp));
|
|
|
|
sp+=4;
|
|
|
|
}
|
2011-01-16 21:23:03 +00:00
|
|
|
}
|
2011-04-16 16:53:41 +00:00
|
|
|
if(inst&0x100)
|
2011-01-16 21:23:03 +00:00
|
|
|
{
|
2011-04-16 16:53:41 +00:00
|
|
|
rc=read32(sp);
|
|
|
|
rc+=2;
|
|
|
|
write_register(15,rc);
|
|
|
|
sp+=4;
|
|
|
|
}
|
|
|
|
write_register(13,sp);
|
|
|
|
return(0);
|
|
|
|
}
|
2011-01-16 21:23:03 +00:00
|
|
|
|
2011-04-16 16:53:41 +00:00
|
|
|
//PUSH
|
|
|
|
if((inst&0xFE00)==0xB400)
|
|
|
|
{
|
|
|
|
if(DISS)
|
2011-01-16 21:23:03 +00:00
|
|
|
{
|
2011-04-16 16:53:41 +00:00
|
|
|
fprintf(stderr,"push {");
|
|
|
|
for(ra=0,rb=0x01,rc=0;rb;rb=(rb<<1)&0xFF,ra++)
|
|
|
|
{
|
2011-01-16 21:23:03 +00:00
|
|
|
if(inst&rb)
|
|
|
|
{
|
2011-04-16 16:53:41 +00:00
|
|
|
if(rc) fprintf(stderr,",");
|
|
|
|
fprintf(stderr,"r%u",ra);
|
|
|
|
rc++;
|
2011-01-16 21:23:03 +00:00
|
|
|
}
|
2011-04-16 16:53:41 +00:00
|
|
|
}
|
|
|
|
if(inst&0x100)
|
|
|
|
{
|
2011-01-16 21:23:03 +00:00
|
|
|
if(rc) fprintf(stderr,",");
|
|
|
|
fprintf(stderr,"lr");
|
2011-04-16 16:53:41 +00:00
|
|
|
}
|
|
|
|
fprintf(stderr,"}\n");
|
2011-01-16 21:23:03 +00:00
|
|
|
}
|
|
|
|
|
2011-04-16 16:53:41 +00:00
|
|
|
sp=read_register(13);
|
|
|
|
//fprintf(stderr,"sp 0x%08X\n",sp);
|
|
|
|
for(ra=0,rb=0x01,rc=0;rb;rb=(rb<<1)&0xFF,ra++)
|
|
|
|
{
|
|
|
|
if(inst&rb)
|
|
|
|
{
|
|
|
|
rc++;
|
|
|
|
}
|
2011-01-16 21:23:03 +00:00
|
|
|
}
|
2011-04-16 16:53:41 +00:00
|
|
|
if(inst&0x100) rc++;
|
|
|
|
rc<<=2;
|
|
|
|
sp-=rc;
|
|
|
|
rd=sp;
|
|
|
|
for(ra=0,rb=0x01;rb;rb=(rb<<1)&0xFF,ra++)
|
2011-01-16 21:23:03 +00:00
|
|
|
{
|
2011-04-16 16:53:41 +00:00
|
|
|
if(inst&rb)
|
|
|
|
{
|
|
|
|
write32(rd,read_register(ra));
|
|
|
|
rd+=4;
|
|
|
|
}
|
2011-01-16 21:23:03 +00:00
|
|
|
}
|
2011-04-16 16:53:41 +00:00
|
|
|
if(inst&0x100)
|
2011-01-16 21:23:03 +00:00
|
|
|
{
|
2011-04-16 16:53:41 +00:00
|
|
|
write32(rd,read_register(14));
|
2011-01-16 21:23:03 +00:00
|
|
|
}
|
2011-04-16 16:53:41 +00:00
|
|
|
write_register(13,sp);
|
|
|
|
return(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
//REV
|
|
|
|
if((inst&0xFFC0)==0xBA00)
|
|
|
|
{
|
|
|
|
rd=(inst>>0)&0x7;
|
|
|
|
rn=(inst>>3)&0x7;
|
|
|
|
if(DISS)
|
|
|
|
fprintf(stderr,"rev r%u,r%u\n",rd,rn);
|
|
|
|
ra=read_register(rn);
|
|
|
|
rc =((ra>> 0)&0xFF)<<24;
|
|
|
|
rc|=((ra>> 8)&0xFF)<<16;
|
|
|
|
rc|=((ra>>16)&0xFF)<< 8;
|
|
|
|
rc|=((ra>>24)&0xFF)<< 0;
|
|
|
|
write_register(rd,rc);
|
|
|
|
return(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
//REV16
|
|
|
|
if((inst&0xFFC0)==0xBA40)
|
|
|
|
{
|
|
|
|
rd=(inst>>0)&0x7;
|
|
|
|
rn=(inst>>3)&0x7;
|
|
|
|
if(DISS)
|
|
|
|
fprintf(stderr,"rev16 r%u,r%u\n",rd,rn);
|
|
|
|
ra=read_register(rn);
|
|
|
|
rc =((ra>> 0)&0xFF)<< 8;
|
|
|
|
rc|=((ra>> 8)&0xFF)<< 0;
|
|
|
|
rc|=((ra>>16)&0xFF)<<24;
|
|
|
|
rc|=((ra>>24)&0xFF)<<16;
|
|
|
|
write_register(rd,rc);
|
|
|
|
return(0);
|
|
|
|
}
|
2011-01-16 21:23:03 +00:00
|
|
|
|
2011-04-16 16:53:41 +00:00
|
|
|
//REVSH
|
|
|
|
if((inst&0xFFC0)==0xBAC0)
|
|
|
|
{
|
|
|
|
rd=(inst>>0)&0x7;
|
|
|
|
rn=(inst>>3)&0x7;
|
|
|
|
if(DISS)
|
|
|
|
fprintf(stderr,"revsh r%u,r%u\n",rd,rn);
|
|
|
|
ra=read_register(rn);
|
|
|
|
rc =((ra>> 0)&0xFF)<< 8;
|
|
|
|
rc|=((ra>> 8)&0xFF)<< 0;
|
|
|
|
if(rc&0x8000) rc|=0xFFFF0000;
|
|
|
|
else rc&=0x0000FFFF;
|
|
|
|
write_register(rd,rc);
|
|
|
|
return(0);
|
|
|
|
}
|
2011-01-16 21:23:03 +00:00
|
|
|
|
2011-04-16 16:53:41 +00:00
|
|
|
//ROR
|
|
|
|
if((inst&0xFFC0)==0x41C0)
|
|
|
|
{
|
|
|
|
rd=(inst>>0)&0x7;
|
|
|
|
rs=(inst>>3)&0x7;
|
|
|
|
if(DISS)
|
|
|
|
fprintf(stderr,"rors r%u,r%u\n",rd,rs);
|
|
|
|
rc=read_register(rd);
|
|
|
|
ra=read_register(rs);
|
|
|
|
ra&=0xFF;
|
|
|
|
if(ra==0)
|
2011-01-16 21:23:03 +00:00
|
|
|
{
|
|
|
|
}
|
2011-04-16 16:53:41 +00:00
|
|
|
else
|
2011-01-16 21:23:03 +00:00
|
|
|
{
|
2011-04-16 16:53:41 +00:00
|
|
|
ra&=0x1F;
|
|
|
|
if(ra==0)
|
|
|
|
{
|
|
|
|
do_cflag_bit(rc&0x80000000);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
do_cflag_bit(rc&(1<<(ra-1)));
|
|
|
|
rb=rc<<(32-ra);
|
|
|
|
rc>>=ra;
|
|
|
|
rc|=rb;
|
|
|
|
}
|
2011-01-16 21:23:03 +00:00
|
|
|
}
|
2011-04-16 16:53:41 +00:00
|
|
|
write_register(rd,rc);
|
|
|
|
do_nflag(rc);
|
|
|
|
do_zflag(rc);
|
|
|
|
return(0);
|
|
|
|
}
|
2011-01-16 21:23:03 +00:00
|
|
|
|
2011-04-16 16:53:41 +00:00
|
|
|
//SBC
|
|
|
|
if((inst&0xFFC0)==0x4180)
|
|
|
|
{
|
|
|
|
rd=(inst>>0)&0x7;
|
|
|
|
rm=(inst>>3)&0x7;
|
|
|
|
if(DISS)
|
|
|
|
fprintf(stderr,"sbc r%u,r%u\n",rd,rm);
|
|
|
|
ra=read_register(rd);
|
|
|
|
rb=read_register(rm);
|
|
|
|
rc=ra-rb;
|
|
|
|
if(!(cpsr&CPSR_C)) rc--;
|
|
|
|
write_register(rd,rc);
|
|
|
|
do_nflag(rc);
|
|
|
|
do_zflag(rc);
|
|
|
|
do_cflag(ra,rb,0);
|
|
|
|
do_sub_vflag(ra,rb,rc);
|
|
|
|
return(0);
|
|
|
|
}
|
2011-01-16 21:23:03 +00:00
|
|
|
|
2011-04-16 16:53:41 +00:00
|
|
|
//SETEND
|
|
|
|
if((inst&0xFFF7)==0xB650)
|
|
|
|
{
|
|
|
|
fprintf(stderr,"setend not implemented\n");
|
|
|
|
return(1);
|
|
|
|
}
|
2011-01-16 21:23:03 +00:00
|
|
|
|
2011-04-16 16:53:41 +00:00
|
|
|
//STMIA
|
|
|
|
if((inst&0xF800)==0xC000)
|
|
|
|
{
|
|
|
|
rn=(inst>>8)&0x7;
|
|
|
|
if(DISS)
|
2011-01-16 21:23:03 +00:00
|
|
|
{
|
2011-04-16 16:53:41 +00:00
|
|
|
fprintf(stderr,"stmia r%u!,{",rn);
|
|
|
|
for(ra=0,rb=0x01,rc=0;rb;rb=(rb<<1)&0xFF,ra++)
|
|
|
|
{
|
2011-01-16 21:23:03 +00:00
|
|
|
if(inst&rb)
|
|
|
|
{
|
2011-04-16 16:53:41 +00:00
|
|
|
if(rc) fprintf(stderr,",");
|
|
|
|
fprintf(stderr,"r%u",ra);
|
|
|
|
rc++;
|
2011-01-16 21:23:03 +00:00
|
|
|
}
|
2011-04-16 16:53:41 +00:00
|
|
|
}
|
|
|
|
fprintf(stderr,"}\n");
|
2011-01-16 21:23:03 +00:00
|
|
|
}
|
2011-04-16 16:53:41 +00:00
|
|
|
sp=read_register(rn);
|
|
|
|
for(ra=0,rb=0x01;rb;rb=(rb<<1)&0xFF,ra++)
|
2011-01-16 21:23:03 +00:00
|
|
|
{
|
2011-04-16 16:53:41 +00:00
|
|
|
if(inst&rb)
|
|
|
|
{
|
|
|
|
write32(sp,read_register(ra));
|
|
|
|
sp+=4;
|
|
|
|
}
|
2011-01-16 21:23:03 +00:00
|
|
|
}
|
2011-04-16 16:53:41 +00:00
|
|
|
write_register(rn,sp);
|
|
|
|
return(0);
|
|
|
|
}
|
2011-01-16 21:23:03 +00:00
|
|
|
|
2011-04-16 16:53:41 +00:00
|
|
|
//STR(1)
|
|
|
|
if((inst&0xF800)==0x6000)
|
|
|
|
{
|
|
|
|
rd=(inst>>0)&0x07;
|
|
|
|
rn=(inst>>3)&0x07;
|
|
|
|
rb=(inst>>6)&0x1F;
|
|
|
|
rb<<=2;
|
|
|
|
if(DISS)
|
|
|
|
fprintf(stderr,"str r%u,[r%u,#0x%X]\n",rd,rn,rb);
|
|
|
|
rb=read_register(rn)+rb;
|
|
|
|
rc=read_register(rd);
|
|
|
|
write32(rb,rc);
|
|
|
|
return(0);
|
|
|
|
}
|
2011-01-16 21:23:03 +00:00
|
|
|
|
2011-04-16 16:53:41 +00:00
|
|
|
//STR(2)
|
|
|
|
if((inst&0xFE00)==0x5000)
|
|
|
|
{
|
|
|
|
rd=(inst>>0)&0x7;
|
|
|
|
rn=(inst>>3)&0x7;
|
|
|
|
rm=(inst>>6)&0x7;
|
|
|
|
if(DISS)
|
|
|
|
fprintf(stderr,"str r%u,[r%u,r%u]\n",rd,rn,rm);
|
|
|
|
rb=read_register(rn)+read_register(rm);
|
|
|
|
rc=read_register(rd);
|
|
|
|
write32(rb,rc);
|
|
|
|
return(0);
|
|
|
|
}
|
2011-01-16 21:23:03 +00:00
|
|
|
|
2011-04-16 16:53:41 +00:00
|
|
|
//STR(3)
|
|
|
|
if((inst&0xF800)==0x9000)
|
|
|
|
{
|
|
|
|
rb=(inst>>0)&0xFF;
|
|
|
|
rd=(inst>>8)&0x07;
|
|
|
|
rb<<=2;
|
|
|
|
if(DISS)
|
|
|
|
fprintf(stderr,"str r%u,[SP,#0x%X]\n",rd,rb);
|
|
|
|
rb=read_register(13)+rb;
|
|
|
|
//fprintf(stderr,"0x%08X\n",rb);
|
|
|
|
rc=read_register(rd);
|
|
|
|
write32(rb,rc);
|
|
|
|
return(0);
|
|
|
|
}
|
2011-01-16 21:23:03 +00:00
|
|
|
|
2011-04-16 16:53:41 +00:00
|
|
|
//STRB(1)
|
|
|
|
if((inst&0xF800)==0x7000)
|
|
|
|
{
|
|
|
|
rd=(inst>>0)&0x07;
|
|
|
|
rn=(inst>>3)&0x07;
|
|
|
|
rb=(inst>>6)&0x1F;
|
|
|
|
if(DISS)
|
|
|
|
fprintf(stderr,"strb r%u,[r%u,#0x%X]\n",rd,rn,rb);
|
|
|
|
rb=read_register(rn)+rb;
|
|
|
|
rc=read_register(rd);
|
|
|
|
ra=read16(rb&(~1));
|
|
|
|
if(rb&1)
|
2011-01-16 21:23:03 +00:00
|
|
|
{
|
2011-04-16 16:53:41 +00:00
|
|
|
ra&=0x00FF;
|
|
|
|
ra|=rc<<8;
|
2011-01-16 21:23:03 +00:00
|
|
|
}
|
2011-04-16 16:53:41 +00:00
|
|
|
else
|
2011-01-16 21:23:03 +00:00
|
|
|
{
|
2011-04-16 16:53:41 +00:00
|
|
|
ra&=0xFF00;
|
|
|
|
ra|=rc&0x00FF;
|
2011-01-16 21:23:03 +00:00
|
|
|
}
|
2011-04-16 16:53:41 +00:00
|
|
|
write16(rb&(~1),ra&0xFFFF);
|
|
|
|
return(0);
|
|
|
|
}
|
2011-01-16 21:23:03 +00:00
|
|
|
|
2011-04-16 16:53:41 +00:00
|
|
|
//STRB(2)
|
|
|
|
if((inst&0xFE00)==0x5400)
|
|
|
|
{
|
|
|
|
rd=(inst>>0)&0x7;
|
|
|
|
rn=(inst>>3)&0x7;
|
|
|
|
rm=(inst>>6)&0x7;
|
|
|
|
if(DISS)
|
|
|
|
fprintf(stderr,"strb r%u,[r%u,r%u]\n",rd,rn,rm);
|
|
|
|
rb=read_register(rn)+read_register(rm);
|
|
|
|
rc=read_register(rd);
|
|
|
|
ra=read16(rb&(~1));
|
|
|
|
if(rb&1)
|
2011-01-16 21:23:03 +00:00
|
|
|
{
|
2011-04-16 16:53:41 +00:00
|
|
|
ra&=0x00FF;
|
|
|
|
ra|=rc<<8;
|
2011-01-16 21:23:03 +00:00
|
|
|
}
|
2011-04-16 16:53:41 +00:00
|
|
|
else
|
2011-01-16 21:23:03 +00:00
|
|
|
{
|
2011-04-16 16:53:41 +00:00
|
|
|
ra&=0xFF00;
|
|
|
|
ra|=rc&0x00FF;
|
2011-01-16 21:23:03 +00:00
|
|
|
}
|
2011-04-16 16:53:41 +00:00
|
|
|
write16(rb&(~1),ra&0xFFFF);
|
|
|
|
return(0);
|
|
|
|
}
|
2011-01-16 21:23:03 +00:00
|
|
|
|
2011-04-16 16:53:41 +00:00
|
|
|
//STRH(1)
|
|
|
|
if((inst&0xF800)==0x8000)
|
|
|
|
{
|
|
|
|
rd=(inst>>0)&0x07;
|
|
|
|
rn=(inst>>3)&0x07;
|
|
|
|
rb=(inst>>6)&0x1F;
|
|
|
|
rb<<=1;
|
|
|
|
if(DISS)
|
|
|
|
fprintf(stderr,"strh r%u,[r%u,#0x%X]\n",rd,rn,rb);
|
|
|
|
rb=read_register(rn)+rb;
|
|
|
|
rc=read_register(rd);
|
|
|
|
write16(rb,rc&0xFFFF);
|
|
|
|
return(0);
|
|
|
|
}
|
2011-01-16 21:23:03 +00:00
|
|
|
|
2011-04-16 16:53:41 +00:00
|
|
|
//STRH(2)
|
|
|
|
if((inst&0xFE00)==0x5200)
|
|
|
|
{
|
|
|
|
rd=(inst>>0)&0x7;
|
|
|
|
rn=(inst>>3)&0x7;
|
|
|
|
rm=(inst>>6)&0x7;
|
|
|
|
if(DISS)
|
|
|
|
fprintf(stderr,"strh r%u,[r%u,r%u]\n",rd,rn,rm);
|
|
|
|
rb=read_register(rn)+read_register(rm);
|
|
|
|
rc=read_register(rd);
|
|
|
|
write16(rb,rc&0xFFFF);
|
|
|
|
return(0);
|
|
|
|
}
|
2011-01-16 21:23:03 +00:00
|
|
|
|
2011-04-16 16:53:41 +00:00
|
|
|
//SUB(1)
|
|
|
|
if((inst&0xFE00)==0x1E00)
|
|
|
|
{
|
|
|
|
rd=(inst>>0)&7;
|
|
|
|
rn=(inst>>3)&7;
|
|
|
|
rb=(inst>>6)&7;
|
|
|
|
if(DISS)
|
|
|
|
fprintf(stderr,"subs r%u,r%u,#0x%X\n",rd,rn,rb);
|
|
|
|
ra=read_register(rn);
|
|
|
|
rc=ra-rb;
|
|
|
|
write_register(rd,rc);
|
|
|
|
do_nflag(rc);
|
|
|
|
do_zflag(rc);
|
|
|
|
do_cflag(ra,~rb,1);
|
|
|
|
do_sub_vflag(ra,rb,rc);
|
|
|
|
return(0);
|
|
|
|
}
|
2011-01-16 21:23:03 +00:00
|
|
|
|
2011-04-16 16:53:41 +00:00
|
|
|
//SUB(2)
|
|
|
|
if((inst&0xF800)==0x3800)
|
|
|
|
{
|
|
|
|
rb=(inst>>0)&0xFF;
|
|
|
|
rd=(inst>>8)&0x07;
|
|
|
|
if(DISS)
|
|
|
|
fprintf(stderr,"subs r%u,#0x%02X\n",rd,rb);
|
|
|
|
ra=read_register(rd);
|
|
|
|
rc=ra-rb;
|
|
|
|
write_register(rd,rc);
|
|
|
|
do_nflag(rc);
|
|
|
|
do_zflag(rc);
|
|
|
|
do_cflag(ra,~rb,1);
|
|
|
|
do_sub_vflag(ra,rb,rc);
|
|
|
|
return(0);
|
|
|
|
}
|
2011-01-16 21:23:03 +00:00
|
|
|
|
2011-04-16 16:53:41 +00:00
|
|
|
//SUB(3)
|
|
|
|
if((inst&0xFE00)==0x1A00)
|
|
|
|
{
|
|
|
|
rd=(inst>>0)&0x7;
|
|
|
|
rn=(inst>>3)&0x7;
|
|
|
|
rm=(inst>>6)&0x7;
|
|
|
|
if(DISS)
|
|
|
|
fprintf(stderr,"subs r%u,r%u,r%u\n",rd,rn,rm);
|
|
|
|
ra=read_register(rn);
|
|
|
|
rb=read_register(rm);
|
|
|
|
rc=ra-rb;
|
|
|
|
write_register(rd,rc);
|
|
|
|
do_nflag(rc);
|
|
|
|
do_zflag(rc);
|
|
|
|
do_cflag(ra,~rb,1);
|
|
|
|
do_sub_vflag(ra,rb,rc);
|
|
|
|
return(0);
|
|
|
|
}
|
2011-01-16 21:23:03 +00:00
|
|
|
|
2011-04-16 16:53:41 +00:00
|
|
|
//SUB(4)
|
|
|
|
if((inst&0xFF80)==0xB080)
|
|
|
|
{
|
|
|
|
rb=inst&0x7F;
|
|
|
|
rb<<=2;
|
|
|
|
if(DISS)
|
|
|
|
fprintf(stderr,"sub SP,#0x%02X\n",rb);
|
|
|
|
ra=read_register(13);
|
|
|
|
ra-=rb;
|
|
|
|
write_register(13,ra);
|
|
|
|
return(0);
|
|
|
|
}
|
2011-01-16 21:23:03 +00:00
|
|
|
|
2011-04-16 16:53:41 +00:00
|
|
|
//SWI
|
|
|
|
if((inst&0xFF00)==0xDF00)
|
|
|
|
{
|
|
|
|
rb=inst&0xFF;
|
|
|
|
if(DISS)
|
|
|
|
fprintf(stderr,"swi 0x%02X\n",rb);
|
|
|
|
fprintf(stderr,"\n\nswi 0x%02X\n",rb);
|
|
|
|
return(1);
|
|
|
|
}
|
2011-01-16 21:23:03 +00:00
|
|
|
|
2011-04-16 16:53:41 +00:00
|
|
|
//SXTB
|
|
|
|
if((inst&0xFFC0)==0xB240)
|
|
|
|
{
|
|
|
|
rd=(inst>>0)&0x7;
|
|
|
|
rm=(inst>>3)&0x7;
|
|
|
|
if(DISS)
|
|
|
|
fprintf(stderr,"sxtb r%u,r%u\n",rd,rm);
|
|
|
|
ra=read_register(rm);
|
|
|
|
rc=ra&0xFF;
|
|
|
|
if(rc&0x80) rc|=(~0)<<8;
|
|
|
|
write_register(rd,rc);
|
|
|
|
return(0);
|
|
|
|
}
|
2011-01-16 21:23:03 +00:00
|
|
|
|
2011-04-16 16:53:41 +00:00
|
|
|
//SXTH
|
|
|
|
if((inst&0xFFC0)==0xB200)
|
|
|
|
{
|
|
|
|
rd=(inst>>0)&0x7;
|
|
|
|
rm=(inst>>3)&0x7;
|
|
|
|
if(DISS)
|
|
|
|
fprintf(stderr,"sxth r%u,r%u\n",rd,rm);
|
|
|
|
ra=read_register(rm);
|
|
|
|
rc=ra&0xFFFF;
|
|
|
|
if(rc&0x8000) rc|=(~0)<<16;
|
|
|
|
write_register(rd,rc);
|
|
|
|
return(0);
|
|
|
|
}
|
2011-01-16 21:23:03 +00:00
|
|
|
|
2011-04-16 16:53:41 +00:00
|
|
|
//TST
|
|
|
|
if((inst&0xFFC0)==0x4200)
|
|
|
|
{
|
|
|
|
rn=(inst>>0)&0x7;
|
|
|
|
rm=(inst>>3)&0x7;
|
|
|
|
if(DISS)
|
|
|
|
fprintf(stderr,"tst r%u,r%u\n",rn,rm);
|
|
|
|
ra=read_register(rn);
|
|
|
|
rb=read_register(rm);
|
|
|
|
rc=ra&rb;
|
|
|
|
do_nflag(rc);
|
|
|
|
do_zflag(rc);
|
|
|
|
return(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
//UXTB
|
|
|
|
if((inst&0xFFC0)==0xB2C0)
|
|
|
|
{
|
|
|
|
rd=(inst>>0)&0x7;
|
|
|
|
rm=(inst>>3)&0x7;
|
|
|
|
if(DISS)
|
|
|
|
fprintf(stderr,"uxtb r%u,r%u\n",rd,rm);
|
|
|
|
ra=read_register(rm);
|
|
|
|
rc=ra&0xFF;
|
|
|
|
write_register(rd,rc);
|
|
|
|
return(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
//UXTH
|
|
|
|
if((inst&0xFFC0)==0xB280)
|
|
|
|
{
|
|
|
|
rd=(inst>>0)&0x7;
|
|
|
|
rm=(inst>>3)&0x7;
|
|
|
|
if(DISS)
|
|
|
|
fprintf(stderr,"uxth r%u,r%u\n",rd,rm);
|
|
|
|
ra=read_register(rm);
|
|
|
|
rc=ra&0xFFFF;
|
|
|
|
write_register(rd,rc);
|
|
|
|
return(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
fprintf(stderr,"invalid instruction 0x%08X 0x%04X\n",pc,inst);
|
|
|
|
return(1);
|
2011-01-16 21:23:03 +00:00
|
|
|
}
|
|
|
|
|
2011-03-09 14:21:32 +00:00
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
2011-01-16 21:23:03 +00:00
|
|
|
int Thumbulator::reset ( void )
|
|
|
|
{
|
2011-04-16 16:53:41 +00:00
|
|
|
//memset(ram,0xFF,sizeof(ram));
|
|
|
|
cpsr=CPSR_T|CPSR_I|CPSR_F|MODE_SVC;
|
2011-01-16 21:23:03 +00:00
|
|
|
|
2011-04-16 16:53:41 +00:00
|
|
|
reg_svc[13]=0x40001fb4; //sp
|
|
|
|
reg_svc[14]=0x00000c00; //lr (duz this use odd addrs)
|
2011-01-16 21:23:03 +00:00
|
|
|
reg_sys[15]=0x00000c0b; // entry point of 0xc09+2
|
2011-04-16 16:53:41 +00:00
|
|
|
// reg_sys[15]+=2;
|
2011-01-16 21:23:03 +00:00
|
|
|
|
2011-04-16 16:53:41 +00:00
|
|
|
// fxq: don't care about below so much (maybe to guess timing???)
|
|
|
|
instructions=0;
|
|
|
|
fetches=0;
|
|
|
|
reads=0;
|
|
|
|
writes=0;
|
2011-01-16 21:23:03 +00:00
|
|
|
|
2011-04-16 16:53:41 +00:00
|
|
|
return(0);
|
2011-01-16 21:23:03 +00:00
|
|
|
}
|
2011-04-16 16:53:41 +00:00
|
|
|
|
|
|
|
#endif
|