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
|
|
|
|
//
|
2015-12-29 19:22:46 +00:00
|
|
|
// Copyright (c) 1995-2016 by Bradford W. Mott, Stephen Anthony
|
2011-01-16 21:23:03 +00:00
|
|
|
// 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 "bspf.hxx"
|
2013-07-27 22:28:41 +00:00
|
|
|
#include "Base.hxx"
|
2011-01-16 21:23:03 +00:00
|
|
|
#include "Thumbulator.hxx"
|
2013-07-27 22:28:41 +00:00
|
|
|
using namespace Common;
|
2011-01-16 21:23:03 +00:00
|
|
|
|
2012-12-26 21:16:34 +00:00
|
|
|
// Uncomment the following to enable specific functionality
|
|
|
|
// WARNING!!! This slows the runtime to a crawl
|
|
|
|
//#define THUMB_DISS
|
|
|
|
//#define THUMB_DBUG
|
|
|
|
|
|
|
|
#if defined(THUMB_DISS)
|
|
|
|
#define DO_DISS(statement) statement
|
|
|
|
#else
|
|
|
|
#define DO_DISS(statement)
|
|
|
|
#endif
|
|
|
|
#if defined(THUMB_DBUG)
|
|
|
|
#define DO_DBUG(statement) statement
|
|
|
|
#else
|
|
|
|
#define DO_DBUG(statement)
|
|
|
|
#endif
|
2011-01-16 21:23:03 +00:00
|
|
|
|
2015-08-09 21:19:10 +00:00
|
|
|
#ifdef __BIG_ENDIAN__
|
|
|
|
#define CONV_DATA(d) (((d & 0xFFFF)>>8) | ((d & 0xffff)<<8)) & 0xffff;
|
|
|
|
#define CONV_RAMROM(d) ((d>>8) | (d<<8)) & 0xffff;
|
|
|
|
#else
|
|
|
|
#define CONV_DATA(d) (d & 0xFFFF);
|
|
|
|
#define CONV_RAMROM(d) (d);
|
|
|
|
#endif
|
|
|
|
|
2011-01-16 21:23:03 +00:00
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
2012-06-03 18:05:14 +00:00
|
|
|
Thumbulator::Thumbulator(const uInt16* rom_ptr, uInt16* ram_ptr, bool traponfatal)
|
2011-01-16 21:23:03 +00:00
|
|
|
: rom(rom_ptr),
|
2016-02-27 19:58:20 +00:00
|
|
|
ram(ram_ptr)
|
2011-01-16 21:23:03 +00:00
|
|
|
{
|
2011-11-07 22:50:23 +00:00
|
|
|
trapFatalErrors(traponfatal);
|
2016-02-27 19:58:20 +00:00
|
|
|
reset();
|
2011-01-16 21:23:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
2016-02-27 19:58:20 +00:00
|
|
|
string Thumbulator::run()
|
2011-01-16 21:23:03 +00:00
|
|
|
{
|
2011-03-09 14:21:32 +00:00
|
|
|
reset();
|
|
|
|
for(;;)
|
|
|
|
{
|
2016-02-27 19:58:20 +00:00
|
|
|
if(execute()) break;
|
|
|
|
if(instructions > 500000) // way more than would otherwise be possible
|
2015-06-12 20:44:09 +00:00
|
|
|
throw runtime_error("instructions > 500000");
|
2011-03-09 14:21:32 +00:00
|
|
|
}
|
2012-12-26 21:16:34 +00:00
|
|
|
#if defined(THUMB_DISS) || defined(THUMB_DBUG)
|
|
|
|
dump_counters();
|
|
|
|
cout << statusMsg.str() << endl;
|
|
|
|
#endif
|
2011-05-24 16:04:48 +00:00
|
|
|
return statusMsg.str();
|
|
|
|
}
|
|
|
|
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
inline int Thumbulator::fatalError(const char* opcode, uInt32 v1, const char* msg)
|
|
|
|
{
|
2011-05-26 16:14:46 +00:00
|
|
|
statusMsg << "Thumb ARM emulation fatal error: " << endl
|
2013-07-27 22:28:41 +00:00
|
|
|
<< opcode << "(" << Base::HEX8 << v1 << "), " << msg << endl;
|
2011-05-24 16:04:48 +00:00
|
|
|
dump_regs();
|
2011-11-07 22:50:23 +00:00
|
|
|
if(trapOnFatal)
|
2015-06-12 20:44:09 +00:00
|
|
|
throw runtime_error(statusMsg.str());
|
2011-11-07 22:50:23 +00:00
|
|
|
return 0;
|
2011-05-24 16:04:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
inline int Thumbulator::fatalError(const char* opcode, uInt32 v1, uInt32 v2,
|
|
|
|
const char* msg)
|
|
|
|
{
|
2011-05-26 16:14:46 +00:00
|
|
|
statusMsg << "Thumb ARM emulation fatal error: " << endl
|
2013-07-27 22:28:41 +00:00
|
|
|
<< opcode << "(" << Base::HEX8 << v1 << "," << v2 << "), " << msg << endl;
|
2011-05-24 16:04:48 +00:00
|
|
|
dump_regs();
|
2011-11-07 22:50:23 +00:00
|
|
|
if(trapOnFatal)
|
2015-06-12 20:44:09 +00:00
|
|
|
throw runtime_error(statusMsg.str());
|
2011-11-07 22:50:23 +00:00
|
|
|
return 0;
|
2011-01-16 21:23:03 +00:00
|
|
|
}
|
|
|
|
|
2011-03-09 14:21:32 +00:00
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
2016-02-27 19:58:20 +00:00
|
|
|
void Thumbulator::dump_counters()
|
2011-01-16 21:23:03 +00:00
|
|
|
{
|
2011-03-09 14:21:32 +00:00
|
|
|
cout << endl << endl
|
|
|
|
<< "instructions " << instructions << endl
|
|
|
|
<< "fetches " << fetches << endl
|
|
|
|
<< "reads " << reads << endl
|
|
|
|
<< "writes " << writes << endl
|
2016-02-27 19:58:20 +00:00
|
|
|
<< "memcycles " << (fetches+reads+writes) << endl
|
|
|
|
<< "systick_ints " << systick_ints << endl;
|
2011-01-16 21:23:03 +00:00
|
|
|
}
|
|
|
|
|
2011-05-24 16:04:48 +00:00
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
2016-02-27 19:58:20 +00:00
|
|
|
void Thumbulator::dump_regs()
|
2011-05-24 16:04:48 +00:00
|
|
|
{
|
|
|
|
for (int cnt = 1; cnt < 14; cnt++)
|
|
|
|
{
|
2016-02-27 19:58:20 +00:00
|
|
|
statusMsg << "R" << cnt << " = " << Base::HEX8 << reg_norm[cnt-1] << " ";
|
2011-05-24 16:04:48 +00:00
|
|
|
if(cnt % 4 == 0) statusMsg << endl;
|
|
|
|
}
|
|
|
|
statusMsg << endl
|
2016-02-27 19:58:20 +00:00
|
|
|
<< "SP = " << Base::HEX8 << reg_norm[13] << " "
|
|
|
|
<< "LR = " << Base::HEX8 << reg_norm[14] << " "
|
|
|
|
<< "PC = " << Base::HEX8 << reg_norm[15] << " "
|
2011-05-24 16:04:48 +00:00
|
|
|
<< endl;
|
|
|
|
}
|
|
|
|
|
2011-03-09 14:21:32 +00:00
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
2016-02-27 19:58:20 +00:00
|
|
|
uInt32 Thumbulator::fetch16(uInt32 addr)
|
2011-01-16 21:23:03 +00:00
|
|
|
{
|
2011-03-09 14:21:32 +00:00
|
|
|
fetches++;
|
|
|
|
|
2011-11-07 22:50:23 +00:00
|
|
|
uInt32 data;
|
2016-02-27 19:58:20 +00:00
|
|
|
switch(addr & 0xF0000000)
|
2011-03-09 14:21:32 +00:00
|
|
|
{
|
|
|
|
case 0x00000000: //ROM
|
|
|
|
addr &= ROMADDMASK;
|
2016-02-27 19:58:20 +00:00
|
|
|
if(addr < 0x50)
|
2011-05-24 16:04:48 +00:00
|
|
|
fatalError("fetch16", addr, "abort");
|
2011-03-09 14:21:32 +00:00
|
|
|
|
2016-02-27 19:58:20 +00:00
|
|
|
addr >>= 1;
|
|
|
|
data = CONV_RAMROM(rom[addr]);
|
2013-07-27 22:28:41 +00:00
|
|
|
DO_DBUG(statusMsg << "fetch16(" << Base::HEX8 << addr << ")=" << Base::HEX4 << data << endl);
|
2016-02-27 19:58:20 +00:00
|
|
|
return data;
|
2011-03-09 14:21:32 +00:00
|
|
|
|
|
|
|
case 0x40000000: //RAM
|
|
|
|
addr &= RAMADDMASK;
|
2016-02-27 19:58:20 +00:00
|
|
|
addr >>= 1;
|
2015-08-09 21:19:10 +00:00
|
|
|
data=CONV_RAMROM(ram[addr]);
|
2013-07-27 22:28:41 +00:00
|
|
|
DO_DBUG(statusMsg << "fetch16(" << Base::HEX8 << addr << ")=" << Base::HEX4 << data << endl);
|
2016-02-27 19:58:20 +00:00
|
|
|
return data;
|
2011-03-09 14:21:32 +00:00
|
|
|
}
|
2011-05-24 16:04:48 +00:00
|
|
|
return fatalError("fetch16", addr, "abort");
|
2011-01-16 21:23:03 +00:00
|
|
|
}
|
|
|
|
|
2011-03-09 14:21:32 +00:00
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
2016-02-27 19:58:20 +00:00
|
|
|
uInt32 Thumbulator::fetch32(uInt32 addr)
|
2011-01-16 21:23:03 +00:00
|
|
|
{
|
2011-03-09 14:21:32 +00:00
|
|
|
uInt32 data;
|
2016-02-27 19:58:20 +00:00
|
|
|
switch(addr & 0xF0000000)
|
2011-03-09 14:21:32 +00:00
|
|
|
{
|
|
|
|
case 0x00000000: //ROM
|
2016-02-27 19:58:20 +00:00
|
|
|
if(addr < 0x50)
|
2011-03-09 14:21:32 +00:00
|
|
|
{
|
2016-02-27 19:58:20 +00:00
|
|
|
data = read32(addr);
|
2013-07-27 22:28:41 +00:00
|
|
|
DO_DBUG(statusMsg << "fetch32(" << Base::HEX8 << addr << ")=" << Base::HEX8 << data << endl);
|
2016-02-27 19:58:20 +00:00
|
|
|
if(addr == 0x00000000) return data;
|
|
|
|
if(addr == 0x00000004) return data;
|
|
|
|
if(addr == 0x0000003C) return data;
|
2011-05-24 16:04:48 +00:00
|
|
|
fatalError("fetch32", addr, "abort");
|
2011-03-09 14:21:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
case 0x40000000: //RAM
|
2016-02-27 19:58:20 +00:00
|
|
|
data = read32(addr);
|
2013-07-27 22:28:41 +00:00
|
|
|
DO_DBUG(statusMsg << "fetch32(" << Base::HEX8 << addr << ")=" << Base::HEX8 << data << endl);
|
2016-02-27 19:58:20 +00:00
|
|
|
return data;
|
2011-03-09 14:21:32 +00:00
|
|
|
}
|
2011-05-24 16:04:48 +00:00
|
|
|
return fatalError("fetch32", addr, "abort");
|
2011-01-16 21:23:03 +00:00
|
|
|
}
|
|
|
|
|
2011-03-09 14:21:32 +00:00
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
2016-02-27 19:58:20 +00:00
|
|
|
void Thumbulator::write16(uInt32 addr, uInt32 data)
|
2011-01-16 21:23:03 +00:00
|
|
|
{
|
2016-02-27 19:58:20 +00:00
|
|
|
if((addr > 0x40001fff) && (addr < 0x50000000))
|
2011-05-24 16:04:48 +00:00
|
|
|
fatalError("write16", addr, "abort - out of range");
|
2016-02-27 19:58:20 +00:00
|
|
|
else if((addr > 0x40000028) && (addr < 0x40000c00))
|
2011-05-24 16:04:48 +00:00
|
|
|
fatalError("write16", addr, "to bankswitch code area");
|
2016-02-27 19:58:20 +00:00
|
|
|
if(addr & 1)
|
2011-05-24 16:04:48 +00:00
|
|
|
fatalError("write16", addr, "abort - misaligned");
|
|
|
|
|
2011-03-09 14:21:32 +00:00
|
|
|
writes++;
|
|
|
|
|
2013-07-27 22:28:41 +00:00
|
|
|
DO_DBUG(statusMsg << "write16(" << Base::HEX8 << addr << "," << Base::HEX8 << data << ")" << endl);
|
2011-03-09 14:21:32 +00:00
|
|
|
|
2016-02-27 19:58:20 +00:00
|
|
|
switch(addr & 0xF0000000)
|
2011-03-09 14:21:32 +00:00
|
|
|
{
|
|
|
|
case 0x40000000: //RAM
|
2016-02-27 19:58:20 +00:00
|
|
|
addr &= RAMADDMASK;
|
|
|
|
addr >>= 1;
|
|
|
|
ram[addr] = CONV_DATA(data);
|
2011-03-09 14:21:32 +00:00
|
|
|
return;
|
2011-11-05 22:31:40 +00:00
|
|
|
|
|
|
|
case 0xE0000000: //MAMCR
|
|
|
|
if(addr == 0xE01FC000)
|
|
|
|
{
|
2013-07-27 22:28:41 +00:00
|
|
|
DO_DBUG(statusMsg << "write16(" << Base::HEX8 << "MAMCR" << "," << Base::HEX8 << data << ") *" << endl);
|
2011-11-05 22:31:40 +00:00
|
|
|
mamcr = data;
|
|
|
|
return;
|
|
|
|
}
|
2011-03-09 14:21:32 +00:00
|
|
|
}
|
2011-05-24 16:04:48 +00:00
|
|
|
fatalError("write16", addr, data, "abort");
|
2011-01-16 21:23:03 +00:00
|
|
|
}
|
|
|
|
|
2011-03-09 14:21:32 +00:00
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
2016-02-27 19:58:20 +00:00
|
|
|
void Thumbulator::write32(uInt32 addr, uInt32 data)
|
2011-01-16 21:23:03 +00:00
|
|
|
{
|
2016-02-27 19:58:20 +00:00
|
|
|
if(addr & 3)
|
2011-05-24 16:04:48 +00:00
|
|
|
fatalError("write32", addr, "abort - misaligned");
|
|
|
|
|
2013-07-27 22:28:41 +00:00
|
|
|
DO_DBUG(statusMsg << "write32(" << Base::HEX8 << addr << "," << Base::HEX8 << data << ")" << endl);
|
2011-03-09 14:21:32 +00:00
|
|
|
|
2016-02-27 19:58:20 +00:00
|
|
|
switch(addr & 0xF0000000)
|
2011-03-09 14:21:32 +00:00
|
|
|
{
|
|
|
|
case 0xF0000000: //halt
|
|
|
|
dump_counters();
|
2016-02-27 19:58:20 +00:00
|
|
|
throw runtime_error("HALT");
|
2011-03-09 14:21:32 +00:00
|
|
|
|
|
|
|
case 0xE0000000: //periph
|
|
|
|
switch(addr)
|
|
|
|
{
|
|
|
|
case 0xE0000000:
|
2012-12-26 21:16:34 +00:00
|
|
|
DO_DISS(statusMsg << "uart: [" << char(data&0xFF) << "]" << endl);
|
2011-03-09 14:21:32 +00:00
|
|
|
break;
|
2016-02-27 19:58:20 +00:00
|
|
|
|
|
|
|
case 0xE000E010:
|
|
|
|
{
|
|
|
|
uInt32 old = systick_ctrl;
|
|
|
|
systick_ctrl = data & 0x00010007;
|
|
|
|
if(((old & 1) == 0) && (systick_ctrl & 1))
|
|
|
|
{
|
|
|
|
// timer started, load count
|
|
|
|
systick_count = systick_reload;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case 0xE000E014:
|
|
|
|
systick_reload = data & 0x00FFFFFF;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0xE000E018:
|
|
|
|
systick_count = data & 0x00FFFFFF;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0xE000E01C:
|
|
|
|
systick_calibrate = data & 0x00FFFFFF;
|
|
|
|
break;
|
2011-03-09 14:21:32 +00:00
|
|
|
}
|
|
|
|
return;
|
|
|
|
|
|
|
|
case 0xD0000000: //debug
|
2016-02-27 19:58:20 +00:00
|
|
|
switch(addr & 0xFF)
|
|
|
|
{
|
|
|
|
case 0x00:
|
|
|
|
statusMsg << "[" << Base::HEX8 << read_register(14) << "]["
|
|
|
|
<< addr << "] " << data << endl;
|
|
|
|
return;
|
|
|
|
|
|
|
|
case 0x10:
|
|
|
|
statusMsg << Base::HEX8 << data << endl;
|
|
|
|
return;
|
|
|
|
|
|
|
|
case 0x20:
|
|
|
|
statusMsg << Base::HEX8 << data << endl;
|
|
|
|
return;
|
|
|
|
}
|
2011-03-09 14:21:32 +00:00
|
|
|
return;
|
2016-02-27 19:58:20 +00:00
|
|
|
|
2011-03-09 14:21:32 +00:00
|
|
|
case 0x40000000: //RAM
|
2016-02-27 19:58:20 +00:00
|
|
|
write16(addr+0, (data >> 0) & 0xFFFF);
|
|
|
|
write16(addr+2, (data >> 16) & 0xFFFF);
|
2011-03-09 14:21:32 +00:00
|
|
|
return;
|
|
|
|
}
|
2011-05-24 16:04:48 +00:00
|
|
|
fatalError("write32", addr, data, "abort");
|
2011-01-16 21:23:03 +00:00
|
|
|
}
|
|
|
|
|
2011-03-09 14:21:32 +00:00
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
2016-02-27 19:58:20 +00:00
|
|
|
uInt32 Thumbulator::read16(uInt32 addr)
|
2011-01-16 21:23:03 +00:00
|
|
|
{
|
2011-03-09 14:21:32 +00:00
|
|
|
uInt32 data;
|
|
|
|
|
2016-02-27 19:58:20 +00:00
|
|
|
if((addr > 0x40001fff) && (addr < 0x50000000))
|
2011-05-24 16:04:48 +00:00
|
|
|
fatalError("read16", addr, "abort - out of range");
|
2016-02-27 19:58:20 +00:00
|
|
|
else if((addr > 0x7fff) && (addr < 0x10000000))
|
2011-05-24 16:04:48 +00:00
|
|
|
fatalError("read16", addr, "abort - out of range");
|
2016-02-27 19:58:20 +00:00
|
|
|
if(addr & 1)
|
2011-05-24 16:04:48 +00:00
|
|
|
fatalError("read16", addr, "abort - misaligned");
|
|
|
|
|
2011-03-09 14:21:32 +00:00
|
|
|
reads++;
|
|
|
|
|
2016-02-27 19:58:20 +00:00
|
|
|
switch(addr & 0xF0000000)
|
2011-03-09 14:21:32 +00:00
|
|
|
{
|
|
|
|
case 0x00000000: //ROM
|
2016-02-27 19:58:20 +00:00
|
|
|
addr &= ROMADDMASK;
|
|
|
|
addr >>= 1;
|
|
|
|
data = CONV_RAMROM(rom[addr]);
|
2013-07-27 22:28:41 +00:00
|
|
|
DO_DBUG(statusMsg << "read16(" << Base::HEX8 << addr << ")=" << Base::HEX4 << data << endl);
|
2016-02-27 19:58:20 +00:00
|
|
|
return data;
|
2011-03-09 14:21:32 +00:00
|
|
|
|
|
|
|
case 0x40000000: //RAM
|
2016-02-27 19:58:20 +00:00
|
|
|
addr &= RAMADDMASK;
|
|
|
|
addr >>= 1;
|
|
|
|
data = CONV_RAMROM(ram[addr]);
|
2013-07-27 22:28:41 +00:00
|
|
|
DO_DBUG(statusMsg << "read16(" << Base::HEX8 << addr << ")=" << Base::HEX4 << data << endl);
|
2016-02-27 19:58:20 +00:00
|
|
|
return data;
|
2011-11-05 22:31:40 +00:00
|
|
|
|
|
|
|
case 0xE0000000: //MAMCR
|
|
|
|
if(addr == 0xE01FC000)
|
2011-11-07 22:50:23 +00:00
|
|
|
{
|
2012-12-26 21:16:34 +00:00
|
|
|
DO_DBUG(statusMsg << "read16(" << "MAMCR" << addr << ")=" << mamcr << " *");
|
2011-11-05 22:31:40 +00:00
|
|
|
return mamcr;
|
2011-11-07 22:50:23 +00:00
|
|
|
}
|
2011-03-09 14:21:32 +00:00
|
|
|
}
|
2011-05-24 16:04:48 +00:00
|
|
|
return fatalError("read16", addr, "abort");
|
2011-01-16 21:23:03 +00:00
|
|
|
}
|
|
|
|
|
2011-03-09 14:21:32 +00:00
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
2016-02-27 19:58:20 +00:00
|
|
|
uInt32 Thumbulator::read32(uInt32 addr)
|
2011-01-16 21:23:03 +00:00
|
|
|
{
|
2016-02-27 19:58:20 +00:00
|
|
|
if(addr & 3)
|
2011-05-24 16:04:48 +00:00
|
|
|
fatalError("read32", addr, "abort - misaligned");
|
2011-03-09 14:21:32 +00:00
|
|
|
|
2011-05-24 16:04:48 +00:00
|
|
|
uInt32 data;
|
2016-02-27 19:58:20 +00:00
|
|
|
switch(addr & 0xF0000000)
|
2011-03-09 14:21:32 +00:00
|
|
|
{
|
|
|
|
case 0x00000000: //ROM
|
|
|
|
case 0x40000000: //RAM
|
2016-02-27 19:58:20 +00:00
|
|
|
data = read16(addr+0);
|
|
|
|
data |= (uInt32(read16(addr+2))) << 16;
|
2013-07-27 22:28:41 +00:00
|
|
|
DO_DBUG(statusMsg << "read32(" << Base::HEX8 << addr << ")=" << Base::HEX8 << data << endl);
|
2016-02-27 19:58:20 +00:00
|
|
|
return data;
|
|
|
|
|
|
|
|
case 0xE0000000:
|
|
|
|
{
|
|
|
|
switch(addr)
|
|
|
|
{
|
|
|
|
case 0xE000E010:
|
|
|
|
data = systick_ctrl;
|
|
|
|
systick_ctrl &= (~0x00010000);
|
|
|
|
return data;
|
|
|
|
|
|
|
|
case 0xE000E014:
|
|
|
|
data = systick_reload;
|
|
|
|
return data;
|
|
|
|
|
|
|
|
case 0xE000E018:
|
|
|
|
data = systick_count;
|
|
|
|
return data;
|
|
|
|
|
|
|
|
case 0xE000E01C:
|
|
|
|
data = systick_calibrate;
|
|
|
|
return data;
|
|
|
|
}
|
|
|
|
}
|
2011-03-09 14:21:32 +00:00
|
|
|
}
|
2011-05-24 16:04:48 +00:00
|
|
|
return fatalError("read32", addr, "abort");
|
2011-01-16 21:23:03 +00:00
|
|
|
}
|
|
|
|
|
2011-03-09 14:21:32 +00:00
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
2016-02-27 19:58:20 +00:00
|
|
|
uInt32 Thumbulator::read_register(uInt32 reg)
|
2011-01-16 21:23:03 +00:00
|
|
|
{
|
2016-02-27 19:58:20 +00:00
|
|
|
reg &= 0xF;
|
2011-03-09 14:21:32 +00:00
|
|
|
|
2016-02-27 19:58:20 +00:00
|
|
|
uInt32 data = reg_norm[reg];
|
|
|
|
DO_DBUG(statusMsg << "read_register(" << dec << reg << ")=" << Base::HEX8 << data << endl);
|
|
|
|
if(reg == 15)
|
2011-03-09 14:21:32 +00:00
|
|
|
{
|
2016-02-27 19:58:20 +00:00
|
|
|
if(data & 1)
|
|
|
|
{
|
|
|
|
DO_DBUG(statusMsg << "pc has lsbit set 0x" << Base::HEX8 << data << endl);
|
|
|
|
}
|
|
|
|
data &= ~1;
|
2011-03-09 14:21:32 +00:00
|
|
|
}
|
2016-02-27 19:58:20 +00:00
|
|
|
return data;
|
2011-01-16 21:23:03 +00:00
|
|
|
}
|
|
|
|
|
2011-03-09 14:21:32 +00:00
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
2016-02-27 19:58:20 +00:00
|
|
|
void Thumbulator::write_register(uInt32 reg, uInt32 data)
|
2011-01-16 21:23:03 +00:00
|
|
|
{
|
2016-02-27 19:58:20 +00:00
|
|
|
reg &= 0xF;
|
2011-03-09 14:21:32 +00:00
|
|
|
|
2013-07-27 22:28:41 +00:00
|
|
|
DO_DBUG(statusMsg << "write_register(" << dec << reg << "," << Base::HEX8 << data << ")" << endl);
|
2016-02-27 19:58:20 +00:00
|
|
|
if(reg == 15) data &= ~1;
|
|
|
|
reg_norm[reg] = data;
|
2011-01-16 21:23:03 +00:00
|
|
|
}
|
|
|
|
|
2011-03-09 14:21:32 +00:00
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
2016-02-27 19:58:20 +00:00
|
|
|
void Thumbulator::do_zflag(uInt32 x)
|
2011-01-16 21:23:03 +00:00
|
|
|
{
|
2016-02-27 19:58:20 +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
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
2016-02-27 19:58:20 +00:00
|
|
|
void Thumbulator::do_nflag(uInt32 x)
|
2011-01-16 21:23:03 +00:00
|
|
|
{
|
2016-02-27 19:58:20 +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
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
2016-02-27 19:58:20 +00:00
|
|
|
void Thumbulator::do_cflag(uInt32 a, uInt32 b, uInt32 c)
|
2011-01-16 21:23:03 +00:00
|
|
|
{
|
2011-03-09 14:21:32 +00:00
|
|
|
uInt32 rc;
|
2011-01-16 21:23:03 +00:00
|
|
|
|
2016-02-27 19:58:20 +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
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
2016-02-27 19:58:20 +00:00
|
|
|
void Thumbulator::do_vflag(uInt32 a, uInt32 b, uInt32 c)
|
2011-01-16 21:23:03 +00:00
|
|
|
{
|
2016-02-27 19:58:20 +00:00
|
|
|
uInt32 rc, rd;
|
|
|
|
|
|
|
|
cpsr &= ~CPSR_V;
|
|
|
|
rc = (a & 0x7FFFFFFF) + (b & 0x7FFFFFFF) + c; //carry in
|
|
|
|
rc >>= 31; //carry in in lsbit
|
|
|
|
rd = (rc & 1) + ((a >> 31) & 1) + ((b >> 31) & 1); //carry out
|
|
|
|
rd >>= 1; //carry out in lsbit
|
|
|
|
rc = (rc^rd) & 1; //if carry in != carry out then signed overflow
|
|
|
|
if(rc)
|
|
|
|
cpsr |= CPSR_V;
|
2011-01-16 21:23:03 +00:00
|
|
|
}
|
|
|
|
|
2011-03-09 14:21:32 +00:00
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
2016-02-27 19:58:20 +00:00
|
|
|
void Thumbulator::do_cflag_bit(uInt32 x)
|
2011-01-16 21:23:03 +00:00
|
|
|
{
|
2016-02-27 19:58:20 +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
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
2016-02-27 19:58:20 +00:00
|
|
|
void Thumbulator::do_vflag_bit(uInt32 x)
|
2011-01-16 21:23:03 +00:00
|
|
|
{
|
2016-02-27 19:58:20 +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
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
2016-02-27 19:58:20 +00:00
|
|
|
int Thumbulator::execute()
|
2011-01-16 21:23:03 +00:00
|
|
|
{
|
2016-02-27 19:58:20 +00:00
|
|
|
uInt32 pc, sp, inst, ra, rb, rc, rm, rd, rn, rs, op;
|
2011-01-16 21:23:03 +00:00
|
|
|
|
2016-02-27 19:58:20 +00:00
|
|
|
pc = read_register(15);
|
|
|
|
|
|
|
|
#if 0 // FIXME SA - not sure if this should be enabled
|
|
|
|
if(handler_mode)
|
|
|
|
{
|
|
|
|
if((pc & 0xF0000000) == 0xF0000000)
|
|
|
|
{
|
|
|
|
uInt32 sp = read_register(13);
|
|
|
|
handler_mode = false;
|
|
|
|
write_register(0, read32(sp)); sp += 4;
|
|
|
|
write_register(1, read32(sp)); sp += 4;
|
|
|
|
write_register(2, read32(sp)); sp += 4;
|
|
|
|
write_register(3, read32(sp)); sp += 4;
|
|
|
|
write_register(12, read32(sp)); sp += 4;
|
|
|
|
write_register(14, read32(sp)); sp += 4;
|
|
|
|
pc = read32(sp); sp += 4;
|
|
|
|
cpsr = read32(sp); sp += 4;
|
|
|
|
write_register(13, sp);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(systick_ctrl & 1)
|
|
|
|
{
|
|
|
|
if(systick_count)
|
|
|
|
{
|
|
|
|
systick_count--;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
systick_count = systick_reload;
|
|
|
|
systick_ctrl |= 0x00010000;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if((systick_ctrl & 3) == 3)
|
|
|
|
{
|
|
|
|
if(systick_ctrl & 0x00010000)
|
|
|
|
{
|
|
|
|
if(!handler_mode)
|
|
|
|
{
|
|
|
|
systick_ints++;
|
|
|
|
uInt32 sp = read_register(13);
|
|
|
|
sp -= 4; write32(sp, cpsr);
|
|
|
|
sp -= 4; write32(sp, pc);
|
|
|
|
sp -= 4; write32(sp, read_register(14));
|
|
|
|
sp -= 4; write32(sp, read_register(12));
|
|
|
|
sp -= 4; write32(sp, read_register(3));
|
|
|
|
sp -= 4; write32(sp, read_register(2));
|
|
|
|
sp -= 4; write32(sp, read_register(1));
|
|
|
|
sp -= 4; write32(sp, read_register(0));
|
|
|
|
write_register(13, sp);
|
|
|
|
pc = fetch32(0x0000003C); //systick vector
|
|
|
|
pc += 2;
|
|
|
|
//write_register(14, 0xFFFFFF00);
|
|
|
|
write_register(14, 0xFFFFFFF9);
|
|
|
|
|
|
|
|
handler_mode = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
inst = fetch16(pc-2);
|
|
|
|
pc += 2;
|
|
|
|
write_register(15, pc);
|
2013-07-27 22:28:41 +00:00
|
|
|
DO_DISS(statusMsg << Base::HEX8 << (pc-5) << ": " << Base::HEX4 << inst << " ");
|
2011-03-09 14:21:32 +00:00
|
|
|
|
|
|
|
instructions++;
|
|
|
|
|
|
|
|
//ADC
|
2016-02-27 19:58:20 +00:00
|
|
|
if((inst & 0xFFC0) == 0x4140)
|
2011-03-09 14:21:32 +00:00
|
|
|
{
|
2016-02-27 19:58:20 +00:00
|
|
|
rd = (inst >> 0) & 0x07;
|
|
|
|
rm = (inst >> 3) & 0x07;
|
2012-12-26 21:16:34 +00:00
|
|
|
DO_DISS(statusMsg << "adc r" << dec << rd << ",r" << dec << rm << endl);
|
2016-02-27 19:58:20 +00:00
|
|
|
ra = read_register(rd);
|
|
|
|
rb = read_register(rm);
|
|
|
|
rc = ra + rb;
|
|
|
|
if(cpsr & CPSR_C)
|
2011-03-09 14:21:32 +00:00
|
|
|
rc++;
|
2016-02-27 19:58:20 +00:00
|
|
|
write_register(rd, rc);
|
2011-03-09 14:21:32 +00:00
|
|
|
do_nflag(rc);
|
|
|
|
do_zflag(rc);
|
2016-02-27 19:58:20 +00:00
|
|
|
if(cpsr & CPSR_C) { do_cflag(ra, rb, 1); do_vflag(ra, rb, 1); }
|
|
|
|
else { do_cflag(ra, rb, 0); do_vflag(ra, rb, 0); }
|
|
|
|
return 0;
|
2011-03-09 14:21:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//ADD(1) small immediate two registers
|
2016-02-27 19:58:20 +00:00
|
|
|
if((inst & 0xFE00) == 0x1C00)
|
2011-03-09 14:21:32 +00:00
|
|
|
{
|
2016-02-27 19:58:20 +00:00
|
|
|
rd = (inst >> 0) & 0x7;
|
|
|
|
rn = (inst >> 3) & 0x7;
|
|
|
|
rb = (inst >> 6) & 0x7;
|
2011-03-09 14:21:32 +00:00
|
|
|
if(rb)
|
|
|
|
{
|
2012-12-26 21:16:34 +00:00
|
|
|
DO_DISS(statusMsg << "adds r" << dec << rd << ",r" << dec << rn << ","
|
2013-07-27 22:28:41 +00:00
|
|
|
<< "#0x" << Base::HEX2 << rb << endl);
|
2016-02-27 19:58:20 +00:00
|
|
|
ra = read_register(rn);
|
|
|
|
rc = ra + rb;
|
2011-03-09 14:21:32 +00:00
|
|
|
//fprintf(stderr,"0x%08X = 0x%08X + 0x%08X\n",rc,ra,rb);
|
2016-02-27 19:58:20 +00:00
|
|
|
write_register(rd, rc);
|
2011-03-09 14:21:32 +00:00
|
|
|
do_nflag(rc);
|
|
|
|
do_zflag(rc);
|
2016-02-27 19:58:20 +00:00
|
|
|
do_cflag(ra, rb, 0);
|
|
|
|
do_vflag(ra, rb, 0);
|
|
|
|
return 0;
|
2011-03-09 14:21:32 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
//this is a mov
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//ADD(2) big immediate one register
|
2016-02-27 19:58:20 +00:00
|
|
|
if((inst & 0xF800) == 0x3000)
|
2011-03-09 14:21:32 +00:00
|
|
|
{
|
2016-02-27 19:58:20 +00:00
|
|
|
rb = (inst >> 0) & 0xFF;
|
|
|
|
rd = (inst >> 8) & 0x7;
|
2013-07-27 22:28:41 +00:00
|
|
|
DO_DISS(statusMsg << "adds r" << dec << rd << ",#0x" << Base::HEX2 << rb << endl);
|
2016-02-27 19:58:20 +00:00
|
|
|
ra = read_register(rd);
|
|
|
|
rc = ra + rb;
|
|
|
|
write_register(rd, rc);
|
2011-03-09 14:21:32 +00:00
|
|
|
do_nflag(rc);
|
|
|
|
do_zflag(rc);
|
2016-02-27 19:58:20 +00:00
|
|
|
do_cflag(ra, rb, 0);
|
|
|
|
do_vflag(ra, rb, 0);
|
|
|
|
return 0;
|
2011-03-09 14:21:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//ADD(3) three registers
|
2016-02-27 19:58:20 +00:00
|
|
|
if((inst & 0xFE00) == 0x1800)
|
2011-03-09 14:21:32 +00:00
|
|
|
{
|
2016-02-27 19:58:20 +00:00
|
|
|
rd = (inst >> 0) & 0x7;
|
|
|
|
rn = (inst >> 3) & 0x7;
|
|
|
|
rm = (inst >> 6) & 0x7;
|
2012-12-26 21:16:34 +00:00
|
|
|
DO_DISS(statusMsg << "adds r" << dec << rd << ",r" << dec << rn << ",r" << rm << endl);
|
2016-02-27 19:58:20 +00:00
|
|
|
ra = read_register(rn);
|
|
|
|
rb = read_register(rm);
|
|
|
|
rc = ra + rb;
|
|
|
|
write_register(rd, rc);
|
2011-03-09 14:21:32 +00:00
|
|
|
do_nflag(rc);
|
|
|
|
do_zflag(rc);
|
2016-02-27 19:58:20 +00:00
|
|
|
do_cflag(ra, rb, 0);
|
|
|
|
do_vflag(ra, rb, 0);
|
|
|
|
return 0;
|
2011-03-09 14:21:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//ADD(4) two registers one or both high no flags
|
2016-02-27 19:58:20 +00:00
|
|
|
if((inst & 0xFF00) == 0x4400)
|
2011-03-09 14:21:32 +00:00
|
|
|
{
|
2016-02-27 19:58:20 +00:00
|
|
|
if((inst >> 6) & 3)
|
2011-03-09 14:21:32 +00:00
|
|
|
{
|
|
|
|
//UNPREDICTABLE
|
|
|
|
}
|
2016-02-27 19:58:20 +00:00
|
|
|
rd = (inst >> 0) & 0x7;
|
|
|
|
rd |= (inst >> 4) & 0x8;
|
|
|
|
rm = (inst >> 3) & 0xF;
|
2012-12-26 21:16:34 +00:00
|
|
|
DO_DISS(statusMsg << "add r" << dec << rd << ",r" << dec << rm << endl);
|
2016-02-27 19:58:20 +00:00
|
|
|
ra = read_register(rd);
|
|
|
|
rb = read_register(rm);
|
|
|
|
rc = ra + rb;
|
|
|
|
if(rd == 15)
|
|
|
|
{
|
|
|
|
if((rc & 1) == 0)
|
|
|
|
fatalError("add pc", pc, rc, " produced an arm address");
|
|
|
|
|
|
|
|
rc &= ~1; //write_register may do this as well
|
|
|
|
rc += 2; //The program counter is special
|
|
|
|
}
|
2011-03-09 14:21:32 +00:00
|
|
|
//fprintf(stderr,"0x%08X = 0x%08X + 0x%08X\n",rc,ra,rb);
|
2016-02-27 19:58:20 +00:00
|
|
|
write_register(rd, rc);
|
|
|
|
return 0;
|
2011-03-09 14:21:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//ADD(5) rd = pc plus immediate
|
2016-02-27 19:58:20 +00:00
|
|
|
if((inst & 0xF800) == 0xA000)
|
2011-03-09 14:21:32 +00:00
|
|
|
{
|
2016-02-27 19:58:20 +00:00
|
|
|
rb = (inst >> 0) & 0xFF;
|
|
|
|
rd = (inst >> 8) & 0x7;
|
|
|
|
rb <<= 2;
|
2013-07-27 22:28:41 +00:00
|
|
|
DO_DISS(statusMsg << "add r" << dec << rd << ",PC,#0x" << Base::HEX2 << rb << endl);
|
2016-02-27 19:58:20 +00:00
|
|
|
ra = read_register(15);
|
|
|
|
rc = (ra & (~3u)) + rb;
|
|
|
|
write_register(rd, rc);
|
|
|
|
return 0;
|
2011-03-09 14:21:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//ADD(6) rd = sp plus immediate
|
2016-02-27 19:58:20 +00:00
|
|
|
if((inst & 0xF800) == 0xA800)
|
2011-03-09 14:21:32 +00:00
|
|
|
{
|
2016-02-27 19:58:20 +00:00
|
|
|
rb = (inst >> 0) & 0xFF;
|
|
|
|
rd = (inst >> 8) & 0x7;
|
|
|
|
rb <<= 2;
|
2013-07-27 22:28:41 +00:00
|
|
|
DO_DISS(statusMsg << "add r" << dec << rd << ",SP,#0x" << Base::HEX2 << rb << endl);
|
2016-02-27 19:58:20 +00:00
|
|
|
ra = read_register(13);
|
|
|
|
rc = ra + rb;
|
|
|
|
write_register(rd, rc);
|
|
|
|
return 0;
|
2011-03-09 14:21:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//ADD(7) sp plus immediate
|
2016-02-27 19:58:20 +00:00
|
|
|
if((inst & 0xFF80) == 0xB000)
|
2011-03-09 14:21:32 +00:00
|
|
|
{
|
2016-02-27 19:58:20 +00:00
|
|
|
rb = (inst >> 0) & 0x7F;
|
|
|
|
rb <<= 2;
|
2013-07-27 22:28:41 +00:00
|
|
|
DO_DISS(statusMsg << "add SP,#0x" << Base::HEX2 << rb << endl);
|
2016-02-27 19:58:20 +00:00
|
|
|
ra = read_register(13);
|
|
|
|
rc = ra + rb;
|
|
|
|
write_register(13, rc);
|
|
|
|
return 0;
|
2011-03-09 14:21:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//AND
|
2016-02-27 19:58:20 +00:00
|
|
|
if((inst & 0xFFC0) == 0x4000)
|
2011-03-09 14:21:32 +00:00
|
|
|
{
|
2016-02-27 19:58:20 +00:00
|
|
|
rd = (inst >> 0) & 0x7;
|
|
|
|
rm = (inst >> 3) & 0x7;
|
2012-12-26 21:16:34 +00:00
|
|
|
DO_DISS(statusMsg << "ands r" << dec << rd << ",r" << dec << rm << endl);
|
2016-02-27 19:58:20 +00:00
|
|
|
ra = read_register(rd);
|
|
|
|
rb = read_register(rm);
|
|
|
|
rc = ra & rb;
|
|
|
|
write_register(rd, rc);
|
2011-03-09 14:21:32 +00:00
|
|
|
do_nflag(rc);
|
|
|
|
do_zflag(rc);
|
2016-02-27 19:58:20 +00:00
|
|
|
return 0;
|
2011-03-09 14:21:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//ASR(1) two register immediate
|
2016-02-27 19:58:20 +00:00
|
|
|
if((inst & 0xF800) == 0x1000)
|
2011-03-09 14:21:32 +00:00
|
|
|
{
|
2016-02-27 19:58:20 +00:00
|
|
|
rd = (inst >> 0) & 0x07;
|
|
|
|
rm = (inst >> 3) & 0x07;
|
|
|
|
rb = (inst >> 6) & 0x1F;
|
2013-07-27 22:28:41 +00:00
|
|
|
DO_DISS(statusMsg << "asrs r" << dec << rd << ",r" << dec << rm << ",#0x" << Base::HEX2 << rb << endl);
|
2016-02-27 19:58:20 +00:00
|
|
|
rc = read_register(rm);
|
|
|
|
if(rb == 0)
|
2011-03-09 14:21:32 +00:00
|
|
|
{
|
2016-02-27 19:58:20 +00:00
|
|
|
if(rc & 0x80000000)
|
2011-03-09 14:21:32 +00:00
|
|
|
{
|
|
|
|
do_cflag_bit(1);
|
2016-02-27 19:58:20 +00:00
|
|
|
rc = ~0;
|
2011-03-09 14:21:32 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
do_cflag_bit(0);
|
2016-02-27 19:58:20 +00:00
|
|
|
rc = 0;
|
2011-03-09 14:21:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-02-27 19:58:20 +00:00
|
|
|
do_cflag_bit(rc & (1 << (rb-1)));
|
|
|
|
ra = rc & 0x80000000;
|
|
|
|
rc >>= rb;
|
2011-03-09 14:21:32 +00:00
|
|
|
if(ra) //asr, sign is shifted in
|
2016-02-27 19:58:20 +00:00
|
|
|
rc |= (~0u) << (32-rb);
|
2011-03-09 14:21:32 +00:00
|
|
|
}
|
2016-02-27 19:58:20 +00:00
|
|
|
write_register(rd, rc);
|
2011-03-09 14:21:32 +00:00
|
|
|
do_nflag(rc);
|
|
|
|
do_zflag(rc);
|
2016-02-27 19:58:20 +00:00
|
|
|
return 0;
|
2011-03-09 14:21:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//ASR(2) two register
|
2016-02-27 19:58:20 +00:00
|
|
|
if((inst & 0xFFC0) == 0x4100)
|
2011-03-09 14:21:32 +00:00
|
|
|
{
|
2016-02-27 19:58:20 +00:00
|
|
|
rd = (inst >> 0) & 0x07;
|
|
|
|
rs = (inst >> 3) & 0x07;
|
2012-12-26 21:16:34 +00:00
|
|
|
DO_DISS(statusMsg << "asrs r" << dec << rd << ",r" << dec << rs << endl);
|
2016-02-27 19:58:20 +00:00
|
|
|
rc = read_register(rd);
|
|
|
|
rb = read_register(rs);
|
|
|
|
rb &= 0xFF;
|
|
|
|
if(rb == 0)
|
2011-03-09 14:21:32 +00:00
|
|
|
{
|
|
|
|
}
|
2016-02-27 19:58:20 +00:00
|
|
|
else if(rb < 32)
|
2011-03-09 14:21:32 +00:00
|
|
|
{
|
2016-02-27 19:58:20 +00:00
|
|
|
do_cflag_bit(rc & (1 << (rb-1)));
|
|
|
|
ra = rc & 0x80000000;
|
|
|
|
rc >>= rb;
|
2011-03-09 14:21:32 +00:00
|
|
|
if(ra) //asr, sign is shifted in
|
|
|
|
{
|
2016-02-27 19:58:20 +00:00
|
|
|
rc |= (~0u) << (32-rb);
|
2011-03-09 14:21:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-02-27 19:58:20 +00:00
|
|
|
if(rc & 0x80000000)
|
2011-03-09 14:21:32 +00:00
|
|
|
{
|
|
|
|
do_cflag_bit(1);
|
2016-02-27 19:58:20 +00:00
|
|
|
rc = (~0u);
|
2011-03-09 14:21:32 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
do_cflag_bit(0);
|
2016-02-27 19:58:20 +00:00
|
|
|
rc = 0;
|
2011-03-09 14:21:32 +00:00
|
|
|
}
|
2011-01-16 21:23:03 +00:00
|
|
|
}
|
2016-02-27 19:58:20 +00:00
|
|
|
write_register(rd, rc);
|
2011-03-09 14:21:32 +00:00
|
|
|
do_nflag(rc);
|
|
|
|
do_zflag(rc);
|
2016-02-27 19:58:20 +00:00
|
|
|
return 0;
|
2011-03-09 14:21:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//B(1) conditional branch
|
2016-02-27 19:58:20 +00:00
|
|
|
if((inst & 0xF000) == 0xD000)
|
|
|
|
{
|
|
|
|
rb = (inst >> 0) & 0xFF;
|
|
|
|
if(rb & 0x80)
|
|
|
|
rb |= (~0u) << 8;
|
|
|
|
op=(inst >> 8) & 0xF;
|
|
|
|
rb <<= 1;
|
|
|
|
rb += pc;
|
|
|
|
rb += 2;
|
2011-03-09 14:21:32 +00:00
|
|
|
switch(op)
|
|
|
|
{
|
|
|
|
case 0x0: //b eq z set
|
2013-07-27 22:28:41 +00:00
|
|
|
DO_DISS(statusMsg << "beq 0x" << Base::HEX8 << (rb-3) << endl);
|
2016-02-27 19:58:20 +00:00
|
|
|
if(cpsr & CPSR_Z)
|
|
|
|
write_register(15, rb);
|
|
|
|
return 0;
|
2011-03-09 14:21:32 +00:00
|
|
|
|
|
|
|
case 0x1: //b ne z clear
|
2013-07-27 22:28:41 +00:00
|
|
|
DO_DISS(statusMsg << "bne 0x" << Base::HEX8 << (rb-3) << endl);
|
2016-02-27 19:58:20 +00:00
|
|
|
if(!(cpsr & CPSR_Z))
|
|
|
|
write_register(15, rb);
|
|
|
|
return 0;
|
2011-01-16 21:23:03 +00:00
|
|
|
|
2011-03-09 14:21:32 +00:00
|
|
|
case 0x2: //b cs c set
|
2013-07-27 22:28:41 +00:00
|
|
|
DO_DISS(statusMsg << "bcs 0x" << Base::HEX8 << (rb-3) << endl);
|
2016-02-27 19:58:20 +00:00
|
|
|
if(cpsr & CPSR_C)
|
|
|
|
write_register(15, rb);
|
|
|
|
return 0;
|
2011-01-16 21:23:03 +00:00
|
|
|
|
2011-03-09 14:21:32 +00:00
|
|
|
case 0x3: //b cc c clear
|
2013-07-27 22:28:41 +00:00
|
|
|
DO_DISS(statusMsg << "bcc 0x" << Base::HEX8 << (rb-3) << endl);
|
2016-02-27 19:58:20 +00:00
|
|
|
if(!(cpsr & CPSR_C))
|
|
|
|
write_register(15, rb);
|
|
|
|
return 0;
|
2011-01-16 21:23:03 +00:00
|
|
|
|
2011-03-09 14:21:32 +00:00
|
|
|
case 0x4: //b mi n set
|
2013-07-27 22:28:41 +00:00
|
|
|
DO_DISS(statusMsg << "bmi 0x" << Base::HEX8 << (rb-3) << endl);
|
2016-02-27 19:58:20 +00:00
|
|
|
if(cpsr & CPSR_N)
|
|
|
|
write_register(15, rb);
|
|
|
|
return 0;
|
2011-01-16 21:23:03 +00:00
|
|
|
|
2011-03-09 14:21:32 +00:00
|
|
|
case 0x5: //b pl n clear
|
2013-07-27 22:28:41 +00:00
|
|
|
DO_DISS(statusMsg << "bpl 0x" << Base::HEX8 << (rb-3) << endl);
|
2016-02-27 19:58:20 +00:00
|
|
|
if(!(cpsr & CPSR_N))
|
|
|
|
write_register(15, rb);
|
|
|
|
return 0;
|
2011-01-16 21:23:03 +00:00
|
|
|
|
2011-03-09 14:21:32 +00:00
|
|
|
case 0x6: //b vs v set
|
2013-07-27 22:28:41 +00:00
|
|
|
DO_DISS(statusMsg << "bvs 0x" << Base::HEX8 << (rb-3) << endl);
|
2016-02-27 19:58:20 +00:00
|
|
|
if(cpsr & CPSR_V)
|
2011-03-09 14:21:32 +00:00
|
|
|
write_register(15,rb);
|
2016-02-27 19:58:20 +00:00
|
|
|
return 0;
|
2011-01-16 21:23:03 +00:00
|
|
|
|
2011-03-09 14:21:32 +00:00
|
|
|
case 0x7: //b vc v clear
|
2013-07-27 22:28:41 +00:00
|
|
|
DO_DISS(statusMsg << "bvc 0x" << Base::HEX8 << (rb-3) << endl);
|
2016-02-27 19:58:20 +00:00
|
|
|
if(!(cpsr & CPSR_V))
|
|
|
|
write_register(15, rb);
|
|
|
|
return 0;
|
2011-01-16 21:23:03 +00:00
|
|
|
|
2011-03-09 14:21:32 +00:00
|
|
|
case 0x8: //b hi c set z clear
|
2013-07-27 22:28:41 +00:00
|
|
|
DO_DISS(statusMsg << "bhi 0x" << Base::HEX8 << (rb-3) << endl);
|
2016-02-27 19:58:20 +00:00
|
|
|
if((cpsr & CPSR_C) && (!(cpsr & CPSR_Z)))
|
|
|
|
write_register(15, rb);
|
|
|
|
return 0;
|
2011-03-09 14:21:32 +00:00
|
|
|
|
|
|
|
case 0x9: //b ls c clear or z set
|
2013-07-27 22:28:41 +00:00
|
|
|
DO_DISS(statusMsg << "bls 0x" << Base::HEX8 << (rb-3) << endl);
|
2016-02-27 19:58:20 +00:00
|
|
|
if((cpsr & CPSR_Z) || (!(cpsr & CPSR_C)))
|
|
|
|
write_register(15, rb);
|
|
|
|
return 0;
|
2011-01-16 21:23:03 +00:00
|
|
|
|
2011-03-09 14:21:32 +00:00
|
|
|
case 0xA: //b ge N == V
|
2013-07-27 22:28:41 +00:00
|
|
|
DO_DISS(statusMsg << "bge 0x" << Base::HEX8 << (rb-3) << endl);
|
2016-02-27 19:58:20 +00:00
|
|
|
ra = 0;
|
|
|
|
if( (cpsr & CPSR_N) && (cpsr & CPSR_V) ) ra++;
|
|
|
|
if((!(cpsr & CPSR_N)) && (!(cpsr & CPSR_V))) ra++;
|
2011-03-09 14:21:32 +00:00
|
|
|
if(ra)
|
2016-02-27 19:58:20 +00:00
|
|
|
write_register(15, rb);
|
|
|
|
return 0;
|
2011-03-09 14:21:32 +00:00
|
|
|
|
|
|
|
case 0xB: //b lt N != V
|
2013-07-27 22:28:41 +00:00
|
|
|
DO_DISS(statusMsg << "blt 0x" << Base::HEX8 << (rb-3) << endl);
|
2016-02-27 19:58:20 +00:00
|
|
|
ra = 0;
|
|
|
|
if((!(cpsr & CPSR_N)) && (cpsr & CPSR_V)) ra++;
|
|
|
|
if((!(cpsr & CPSR_V)) && (cpsr & CPSR_N)) ra++;
|
2011-03-09 14:21:32 +00:00
|
|
|
if(ra)
|
2016-02-27 19:58:20 +00:00
|
|
|
write_register(15, rb);
|
|
|
|
return 0;
|
2011-03-09 14:21:32 +00:00
|
|
|
|
|
|
|
case 0xC: //b gt Z==0 and N == V
|
2013-07-27 22:28:41 +00:00
|
|
|
DO_DISS(statusMsg << "bgt 0x" << Base::HEX8 << (rb-3) << endl);
|
2016-02-27 19:58:20 +00:00
|
|
|
ra = 0;
|
|
|
|
if( (cpsr & CPSR_N) && (cpsr & CPSR_V) ) ra++;
|
|
|
|
if((!(cpsr & CPSR_N)) && (!(cpsr & CPSR_V))) ra++;
|
|
|
|
if(cpsr & CPSR_Z) ra = 0;
|
2011-03-09 14:21:32 +00:00
|
|
|
if(ra)
|
2016-02-27 19:58:20 +00:00
|
|
|
write_register(15, rb);
|
|
|
|
return 0;
|
2011-01-16 21:23:03 +00:00
|
|
|
|
2011-03-09 14:21:32 +00:00
|
|
|
case 0xD: //b le Z==1 or N != V
|
2013-07-27 22:28:41 +00:00
|
|
|
DO_DISS(statusMsg << "ble 0x" << Base::HEX8 << (rb-3) << endl);
|
2016-02-27 19:58:20 +00:00
|
|
|
ra = 0;
|
|
|
|
if((!(cpsr & CPSR_N)) && (cpsr & CPSR_V)) ra++;
|
|
|
|
if((!(cpsr & CPSR_V)) && (cpsr & CPSR_N)) ra++;
|
|
|
|
if(cpsr & CPSR_Z) ra++;
|
2011-03-09 14:21:32 +00:00
|
|
|
if(ra)
|
2016-02-27 19:58:20 +00:00
|
|
|
write_register(15, rb);
|
|
|
|
return 0;
|
2011-03-09 14:21:32 +00:00
|
|
|
|
|
|
|
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
|
2016-02-27 19:58:20 +00:00
|
|
|
if((inst & 0xF800) == 0xE000)
|
|
|
|
{
|
|
|
|
rb = (inst >> 0) & 0x7FF;
|
|
|
|
if(rb & (1 << 10))
|
|
|
|
rb |= (~0u) << 11;
|
|
|
|
rb <<= 1;
|
|
|
|
rb += pc;
|
|
|
|
rb += 2;
|
2013-07-27 22:28:41 +00:00
|
|
|
DO_DISS(statusMsg << "B 0x" << Base::HEX8 << (rb-3) << endl);
|
2016-02-27 19:58:20 +00:00
|
|
|
write_register(15, rb);
|
|
|
|
return 0;
|
2011-04-16 16:53:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//BIC
|
2016-02-27 19:58:20 +00:00
|
|
|
if((inst & 0xFFC0) == 0x4380)
|
2011-04-16 16:53:41 +00:00
|
|
|
{
|
2016-02-27 19:58:20 +00:00
|
|
|
rd = (inst >> 0) & 0x7;
|
|
|
|
rm = (inst >> 3) & 0x7;
|
2012-12-26 21:16:34 +00:00
|
|
|
DO_DISS(statusMsg << "bics r" << dec << rd << ",r" << dec << rm << endl);
|
2016-02-27 19:58:20 +00:00
|
|
|
ra = read_register(rd);
|
|
|
|
rb = read_register(rm);
|
|
|
|
rc = ra & (~rb);
|
|
|
|
write_register(rd, rc);
|
2011-04-16 16:53:41 +00:00
|
|
|
do_nflag(rc);
|
|
|
|
do_zflag(rc);
|
2016-02-27 19:58:20 +00:00
|
|
|
return 0;
|
2011-04-16 16:53:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//BKPT
|
2016-02-27 19:58:20 +00:00
|
|
|
if((inst & 0xFF00) == 0xBE00)
|
2011-04-16 16:53:41 +00:00
|
|
|
{
|
2016-02-27 19:58:20 +00:00
|
|
|
rb = (inst >> 0) & 0xFF;
|
2013-07-27 22:28:41 +00:00
|
|
|
statusMsg << "bkpt 0x" << Base::HEX2 << rb << endl;
|
2016-02-27 19:58:20 +00:00
|
|
|
return 1;
|
2011-04-16 16:53:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//BL/BLX(1)
|
2016-02-27 19:58:20 +00:00
|
|
|
if((inst & 0xE000) == 0xE000) //BL,BLX
|
2011-04-16 16:53:41 +00:00
|
|
|
{
|
2016-02-27 19:58:20 +00:00
|
|
|
if((inst & 0x1800) == 0x1000) //H=b10
|
2011-01-16 21:23:03 +00:00
|
|
|
{
|
2012-12-26 21:16:34 +00:00
|
|
|
DO_DISS(statusMsg << endl);
|
2016-02-27 19:58:20 +00:00
|
|
|
rb = inst & ((1 << 11) - 1);
|
|
|
|
if(rb & 1<<10) rb |= (~((1 << 11) - 1)); //sign extend
|
|
|
|
rb <<= 12;
|
|
|
|
rb += pc;
|
|
|
|
write_register(14, rb);
|
|
|
|
return 0;
|
2011-01-16 21:23:03 +00:00
|
|
|
}
|
2016-02-27 19:58:20 +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
|
2016-02-27 19:58:20 +00:00
|
|
|
rb = read_register(14);
|
|
|
|
rb += (inst & ((1 << 11) - 1)) << 1;;
|
|
|
|
rb += 2;
|
2013-07-27 22:28:41 +00:00
|
|
|
DO_DISS(statusMsg << "bl 0x" << Base::HEX8 << (rb-3) << endl);
|
2016-02-27 19:58:20 +00:00
|
|
|
write_register(14, (pc-2) | 1);
|
|
|
|
write_register(15, rb);
|
|
|
|
return 0;
|
2011-01-16 21:23:03 +00:00
|
|
|
}
|
2016-02-27 19:58:20 +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
|
2016-02-27 19:58:20 +00:00
|
|
|
rb = read_register(14);
|
|
|
|
rb += (inst & ((1 << 11) - 1)) << 1;;
|
|
|
|
rb &= 0xFFFFFFFC;
|
|
|
|
rb += 2;
|
|
|
|
DO_DISS(statusMsg << "bl 0x" << Base::HEX8 << (rb-3) << endl);
|
|
|
|
write_register(14, (pc-2) | 1);
|
|
|
|
write_register(15, rb);
|
|
|
|
return 0;
|
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)
|
2016-02-27 19:58:20 +00:00
|
|
|
if((inst & 0xFF87) == 0x4780)
|
2011-04-16 16:53:41 +00:00
|
|
|
{
|
2016-02-27 19:58:20 +00:00
|
|
|
rm = (inst >> 3) & 0xF;
|
2012-12-26 21:16:34 +00:00
|
|
|
DO_DISS(statusMsg << "blx r" << dec << rm << endl);
|
2016-02-27 19:58:20 +00:00
|
|
|
rc = read_register(rm);
|
2011-04-16 16:53:41 +00:00
|
|
|
//fprintf(stderr,"blx r%u 0x%X 0x%X\n",rm,rc,pc);
|
2016-02-27 19:58:20 +00:00
|
|
|
rc += 2;
|
|
|
|
if(rc & 1)
|
2011-01-16 21:23:03 +00:00
|
|
|
{
|
2016-02-27 19:58:20 +00:00
|
|
|
write_register(14, (pc-2) | 1);
|
|
|
|
rc &= ~1;
|
|
|
|
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
|
2016-02-27 19:58:20 +00:00
|
|
|
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
|
2016-02-27 19:58:20 +00:00
|
|
|
if((inst & 0xFF87) == 0x4700)
|
2011-04-16 16:53:41 +00:00
|
|
|
{
|
2016-02-27 19:58:20 +00:00
|
|
|
rm = (inst >> 3) & 0xF;
|
2012-12-26 21:16:34 +00:00
|
|
|
DO_DISS(statusMsg << "bx r" << dec << rm << endl);
|
2016-02-27 19:58:20 +00:00
|
|
|
rc = read_register(rm);
|
|
|
|
rc += 2;
|
2011-04-16 16:53:41 +00:00
|
|
|
//fprintf(stderr,"bx r%u 0x%X 0x%X\n",rm,rc,pc);
|
2016-02-27 19:58:20 +00:00
|
|
|
if(rc & 1)
|
2011-01-16 21:23:03 +00:00
|
|
|
{
|
2016-02-27 19:58:20 +00:00
|
|
|
rc &= ~1;
|
|
|
|
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??
|
2016-02-27 19:58:20 +00:00
|
|
|
return 1;
|
2011-01-16 21:23:03 +00:00
|
|
|
}
|
2011-04-16 16:53:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//CMN
|
2016-02-27 19:58:20 +00:00
|
|
|
if((inst & 0xFFC0) == 0x42C0)
|
2011-04-16 16:53:41 +00:00
|
|
|
{
|
2016-02-27 19:58:20 +00:00
|
|
|
rn = (inst >> 0) & 0x7;
|
|
|
|
rm = (inst >> 3) & 0x7;
|
2012-12-26 21:16:34 +00:00
|
|
|
DO_DISS(statusMsg << "cmns r" << dec << rn << ",r" << dec << rm << endl);
|
2016-02-27 19:58:20 +00:00
|
|
|
ra = read_register(rn);
|
|
|
|
rb = read_register(rm);
|
|
|
|
rc = ra + rb;
|
2011-04-16 16:53:41 +00:00
|
|
|
do_nflag(rc);
|
|
|
|
do_zflag(rc);
|
2016-02-27 19:58:20 +00:00
|
|
|
do_cflag(ra, rb, 0);
|
|
|
|
do_vflag(ra, rb, 0);
|
|
|
|
return 0;
|
2011-04-16 16:53:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//CMP(1) compare immediate
|
2016-02-27 19:58:20 +00:00
|
|
|
if((inst & 0xF800) == 0x2800)
|
2011-04-16 16:53:41 +00:00
|
|
|
{
|
2016-02-27 19:58:20 +00:00
|
|
|
rb = (inst >> 0) & 0xFF;
|
|
|
|
rn = (inst >> 8) & 0x07;
|
2013-07-27 22:28:41 +00:00
|
|
|
DO_DISS(statusMsg << "cmp r" << dec << rn << ",#0x" << Base::HEX2 << rb << endl);
|
2016-02-27 19:58:20 +00:00
|
|
|
ra = read_register(rn);
|
|
|
|
rc = ra - rb;
|
2011-04-16 16:53:41 +00:00
|
|
|
//fprintf(stderr,"0x%08X 0x%08X\n",ra,rb);
|
|
|
|
do_nflag(rc);
|
|
|
|
do_zflag(rc);
|
2016-02-27 19:58:20 +00:00
|
|
|
do_cflag(ra, ~rb, 1);
|
|
|
|
do_vflag(ra, ~rb, 1);
|
|
|
|
return 0;
|
2011-04-16 16:53:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//CMP(2) compare register
|
2016-02-27 19:58:20 +00:00
|
|
|
if((inst & 0xFFC0) == 0x4280)
|
2011-04-16 16:53:41 +00:00
|
|
|
{
|
2016-02-27 19:58:20 +00:00
|
|
|
rn = (inst >> 0) & 0x7;
|
|
|
|
rm = (inst >> 3) & 0x7;
|
2012-12-26 21:16:34 +00:00
|
|
|
DO_DISS(statusMsg << "cmps r" << dec << rn << ",r" << dec << rm << endl);
|
2016-02-27 19:58:20 +00:00
|
|
|
ra = read_register(rn);
|
|
|
|
rb = read_register(rm);
|
|
|
|
rc = ra - rb;
|
2011-04-16 16:53:41 +00:00
|
|
|
//fprintf(stderr,"0x%08X 0x%08X\n",ra,rb);
|
|
|
|
do_nflag(rc);
|
|
|
|
do_zflag(rc);
|
2016-02-27 19:58:20 +00:00
|
|
|
do_cflag(ra, ~rb, 1);
|
|
|
|
do_vflag(ra, ~rb, 1);
|
|
|
|
return 0;
|
2011-04-16 16:53:41 +00:00
|
|
|
}
|
2011-01-16 21:23:03 +00:00
|
|
|
|
2011-04-16 16:53:41 +00:00
|
|
|
//CMP(3) compare high register
|
2016-02-27 19:58:20 +00:00
|
|
|
if((inst & 0xFF00) == 0x4500)
|
2011-04-16 16:53:41 +00:00
|
|
|
{
|
2016-02-27 19:58:20 +00:00
|
|
|
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
|
|
|
}
|
2016-02-27 19:58:20 +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
|
|
|
}
|
2016-02-27 19:58:20 +00:00
|
|
|
rm = (inst >> 3) & 0xF;
|
2012-12-26 21:16:34 +00:00
|
|
|
DO_DISS(statusMsg << "cmps r" << dec << rn << ",r" << dec << rm << endl);
|
2016-02-27 19:58:20 +00:00
|
|
|
ra = read_register(rn);
|
|
|
|
rb = read_register(rm);
|
|
|
|
rc = ra - rb;
|
2011-04-16 16:53:41 +00:00
|
|
|
do_nflag(rc);
|
|
|
|
do_zflag(rc);
|
2016-02-27 19:58:20 +00:00
|
|
|
do_cflag(ra, ~rb, 1);
|
|
|
|
do_vflag(ra, ~rb, 1);
|
|
|
|
return 0;
|
2011-04-16 16:53:41 +00:00
|
|
|
}
|
2011-01-16 21:23:03 +00:00
|
|
|
|
2011-04-16 16:53:41 +00:00
|
|
|
//CPS
|
2016-02-27 19:58:20 +00:00
|
|
|
if((inst & 0xFFE8) == 0xB660)
|
2011-04-16 16:53:41 +00:00
|
|
|
{
|
2012-12-26 21:16:34 +00:00
|
|
|
DO_DISS(statusMsg << "cps TODO" << endl);
|
2016-02-27 19:58:20 +00:00
|
|
|
return 1;
|
2011-04-16 16:53:41 +00:00
|
|
|
}
|
2011-01-16 21:23:03 +00:00
|
|
|
|
2011-04-16 16:53:41 +00:00
|
|
|
//CPY copy high register
|
2016-02-27 19:58:20 +00:00
|
|
|
if((inst & 0xFFC0) == 0x4600)
|
2011-04-16 16:53:41 +00:00
|
|
|
{
|
|
|
|
//same as mov except you can use both low registers
|
|
|
|
//going to let mov handle high registers
|
2016-02-27 19:58:20 +00:00
|
|
|
rd = (inst >> 0) & 0x7;
|
|
|
|
rm = (inst >> 3) & 0x7;
|
2012-12-26 21:16:34 +00:00
|
|
|
DO_DISS(statusMsg << "cpy r" << dec << rd << ",r" << dec << rm << endl);
|
2016-02-27 19:58:20 +00:00
|
|
|
rc = read_register(rm);
|
|
|
|
write_register(rd, rc);
|
|
|
|
return 0;
|
2011-04-16 16:53:41 +00:00
|
|
|
}
|
2011-01-16 21:23:03 +00:00
|
|
|
|
2011-04-16 16:53:41 +00:00
|
|
|
//EOR
|
2016-02-27 19:58:20 +00:00
|
|
|
if((inst & 0xFFC0) == 0x4040)
|
2011-04-16 16:53:41 +00:00
|
|
|
{
|
2016-02-27 19:58:20 +00:00
|
|
|
rd = (inst >> 0) & 0x7;
|
|
|
|
rm = (inst >> 3) & 0x7;
|
2012-12-26 21:16:34 +00:00
|
|
|
DO_DISS(statusMsg << "eors r" << dec << rd << ",r" << dec << rm << endl);
|
2016-02-27 19:58:20 +00:00
|
|
|
ra = read_register(rd);
|
|
|
|
rb = read_register(rm);
|
|
|
|
rc = ra ^ rb;
|
|
|
|
write_register(rd, rc);
|
2011-04-16 16:53:41 +00:00
|
|
|
do_nflag(rc);
|
|
|
|
do_zflag(rc);
|
2016-02-27 19:58:20 +00:00
|
|
|
return 0;
|
2011-04-16 16:53:41 +00:00
|
|
|
}
|
2011-01-16 21:23:03 +00:00
|
|
|
|
2011-04-16 16:53:41 +00:00
|
|
|
//LDMIA
|
2016-02-27 19:58:20 +00:00
|
|
|
if((inst & 0xF800) == 0xC800)
|
2011-04-16 16:53:41 +00:00
|
|
|
{
|
2016-02-27 19:58:20 +00:00
|
|
|
rn = (inst >> 8) & 0x7;
|
2012-12-26 21:16:34 +00:00
|
|
|
#if defined(THUMB_DISS)
|
|
|
|
statusMsg << "ldmia r" << dec << rn << "!,{";
|
|
|
|
for(ra=0,rb=0x01,rc=0;rb;rb=(rb<<1)&0xFF,ra++)
|
2011-01-16 21:23:03 +00:00
|
|
|
{
|
2012-12-26 21:16:34 +00:00
|
|
|
if(inst&rb)
|
2011-04-16 16:53:41 +00:00
|
|
|
{
|
2012-12-26 21:16:34 +00:00
|
|
|
if(rc) statusMsg << ",";
|
|
|
|
statusMsg << "r" << dec << ra;
|
|
|
|
rc++;
|
2011-04-16 16:53:41 +00:00
|
|
|
}
|
2011-01-16 21:23:03 +00:00
|
|
|
}
|
2012-12-26 21:16:34 +00:00
|
|
|
statusMsg << "}" << endl;
|
|
|
|
#endif
|
2016-02-27 19:58:20 +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
|
|
|
{
|
2016-02-27 19:58:20 +00:00
|
|
|
if(inst & rb)
|
2011-04-16 16:53:41 +00:00
|
|
|
{
|
2016-02-27 19:58:20 +00:00
|
|
|
write_register(ra, read32(sp));
|
|
|
|
sp += 4;
|
2011-04-16 16:53:41 +00:00
|
|
|
}
|
2011-01-16 21:23:03 +00:00
|
|
|
}
|
2016-02-27 19:58:20 +00:00
|
|
|
//there is a write back exception.
|
|
|
|
if((inst & (1 << rn)) == 0)
|
|
|
|
write_register(rn, sp);
|
|
|
|
|
|
|
|
return 0;
|
2011-04-16 16:53:41 +00:00
|
|
|
}
|
2011-01-16 21:23:03 +00:00
|
|
|
|
2011-04-16 16:53:41 +00:00
|
|
|
//LDR(1) two register immediate
|
2016-02-27 19:58:20 +00:00
|
|
|
if((inst & 0xF800) == 0x6800)
|
2011-04-16 16:53:41 +00:00
|
|
|
{
|
2016-02-27 19:58:20 +00:00
|
|
|
rd = (inst >> 0) & 0x07;
|
|
|
|
rn = (inst >> 3) & 0x07;
|
|
|
|
rb = (inst >> 6) & 0x1F;
|
|
|
|
rb <<= 2;
|
2013-07-27 22:28:41 +00:00
|
|
|
DO_DISS(statusMsg << "ldr r" << dec << rd << ",[r" << dec << rn << ",#0x" << Base::HEX2 << rb << "]" << endl);
|
2016-02-27 19:58:20 +00:00
|
|
|
rb = read_register(rn) + rb;
|
|
|
|
rc = read32(rb);
|
|
|
|
write_register(rd, rc);
|
|
|
|
return 0;
|
2011-04-16 16:53:41 +00:00
|
|
|
}
|
2011-01-16 21:23:03 +00:00
|
|
|
|
2011-04-16 16:53:41 +00:00
|
|
|
//LDR(2) three register
|
2016-02-27 19:58:20 +00:00
|
|
|
if((inst & 0xFE00) == 0x5800)
|
2011-04-16 16:53:41 +00:00
|
|
|
{
|
2016-02-27 19:58:20 +00:00
|
|
|
rd = (inst >> 0) & 0x7;
|
|
|
|
rn = (inst >> 3) & 0x7;
|
|
|
|
rm = (inst >> 6) & 0x7;
|
2012-12-26 21:16:34 +00:00
|
|
|
DO_DISS(statusMsg << "ldr r" << dec << rd << ",[r" << dec << rn << ",r" << dec << "]" << endl);
|
2016-02-27 19:58:20 +00:00
|
|
|
rb = read_register(rn) + read_register(rm);
|
|
|
|
rc = read32(rb);
|
|
|
|
write_register(rd, rc);
|
|
|
|
return 0;
|
2011-04-16 16:53:41 +00:00
|
|
|
}
|
2011-01-16 21:23:03 +00:00
|
|
|
|
2011-04-16 16:53:41 +00:00
|
|
|
//LDR(3)
|
2016-02-27 19:58:20 +00:00
|
|
|
if((inst & 0xF800) == 0x4800)
|
2011-04-16 16:53:41 +00:00
|
|
|
{
|
2016-02-27 19:58:20 +00:00
|
|
|
rb = (inst >> 0) & 0xFF;
|
|
|
|
rd = (inst >> 8) & 0x07;
|
|
|
|
rb <<= 2;
|
2013-07-27 22:28:41 +00:00
|
|
|
DO_DISS(statusMsg << "ldr r" << dec << rd << ",[PC+#0x" << Base::HEX2 << rb << "] ");
|
2016-02-27 19:58:20 +00:00
|
|
|
ra = read_register(15);
|
|
|
|
ra &= ~3;
|
|
|
|
rb += ra;
|
2013-07-27 22:28:41 +00:00
|
|
|
DO_DISS(statusMsg << ";@ 0x" << Base::HEX2 << rb << endl);
|
2016-02-27 19:58:20 +00:00
|
|
|
rc = read32(rb);
|
|
|
|
write_register(rd, rc);
|
|
|
|
return 0;
|
2011-04-16 16:53:41 +00:00
|
|
|
}
|
2011-01-16 21:23:03 +00:00
|
|
|
|
2011-04-16 16:53:41 +00:00
|
|
|
//LDR(4)
|
2016-02-27 19:58:20 +00:00
|
|
|
if((inst & 0xF800) == 0x9800)
|
2011-04-16 16:53:41 +00:00
|
|
|
{
|
2016-02-27 19:58:20 +00:00
|
|
|
rb = (inst >> 0) & 0xFF;
|
|
|
|
rd = (inst >> 8) & 0x07;
|
|
|
|
rb <<= 2;
|
2013-07-27 22:28:41 +00:00
|
|
|
DO_DISS(statusMsg << "ldr r" << dec << rd << ",[SP+#0x" << Base::HEX2 << rb << "]" << endl);
|
2016-02-27 19:58:20 +00:00
|
|
|
ra = read_register(13);
|
2011-04-16 16:53:41 +00:00
|
|
|
//ra&=~3;
|
2016-02-27 19:58:20 +00:00
|
|
|
rb += ra;
|
|
|
|
rc = read32(rb);
|
|
|
|
write_register(rd, rc);
|
|
|
|
return 0;
|
2011-04-16 16:53:41 +00:00
|
|
|
}
|
2011-01-16 21:23:03 +00:00
|
|
|
|
2011-04-16 16:53:41 +00:00
|
|
|
//LDRB(1)
|
2016-02-27 19:58:20 +00:00
|
|
|
if((inst & 0xF800) == 0x7800)
|
2011-04-16 16:53:41 +00:00
|
|
|
{
|
2016-02-27 19:58:20 +00:00
|
|
|
rd = (inst >> 0) & 0x07;
|
|
|
|
rn = (inst >> 3) & 0x07;
|
|
|
|
rb = (inst >> 6) & 0x1F;
|
2013-07-27 22:28:41 +00:00
|
|
|
DO_DISS(statusMsg << "ldrb r" << dec << rd << ",[r" << dec << rn << ",#0x" << Base::HEX2 << rb << "]" << endl);
|
2016-02-27 19:58:20 +00:00
|
|
|
rb = read_register(rn) + rb;
|
|
|
|
rc = read16(rb & (~1u));
|
|
|
|
if(rb & 1)
|
2011-01-16 21:23:03 +00:00
|
|
|
{
|
2016-02-27 19:58:20 +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
|
|
|
{
|
|
|
|
}
|
2016-02-27 19:58:20 +00:00
|
|
|
write_register(rd, rc & 0xFF);
|
|
|
|
return 0;
|
2011-04-16 16:53:41 +00:00
|
|
|
}
|
2011-01-16 21:23:03 +00:00
|
|
|
|
2011-04-16 16:53:41 +00:00
|
|
|
//LDRB(2)
|
2016-02-27 19:58:20 +00:00
|
|
|
if((inst & 0xFE00) == 0x5C00)
|
2011-04-16 16:53:41 +00:00
|
|
|
{
|
2016-02-27 19:58:20 +00:00
|
|
|
rd = (inst >> 0) & 0x7;
|
|
|
|
rn = (inst >> 3) & 0x7;
|
|
|
|
rm = (inst >> 6) & 0x7;
|
2012-12-26 21:16:34 +00:00
|
|
|
DO_DISS(statusMsg << "ldrb r" << dec << rd << ",[r" << dec << rn << ",r" << dec << rm << "]" << endl);
|
2016-02-27 19:58:20 +00:00
|
|
|
rb = read_register(rn) + read_register(rm);
|
|
|
|
rc = read16(rb & (~1u));
|
|
|
|
if(rb & 1)
|
2011-01-16 21:23:03 +00:00
|
|
|
{
|
2016-02-27 19:58:20 +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
|
|
|
{
|
|
|
|
}
|
2016-02-27 19:58:20 +00:00
|
|
|
write_register(rd, rc & 0xFF);
|
|
|
|
return 0;
|
2011-04-16 16:53:41 +00:00
|
|
|
}
|
2011-01-16 21:23:03 +00:00
|
|
|
|
2011-04-16 16:53:41 +00:00
|
|
|
//LDRH(1)
|
2016-02-27 19:58:20 +00:00
|
|
|
if((inst & 0xF800) == 0x8800)
|
2011-04-16 16:53:41 +00:00
|
|
|
{
|
2016-02-27 19:58:20 +00:00
|
|
|
rd = (inst >> 0) & 0x07;
|
|
|
|
rn = (inst >> 3) & 0x07;
|
|
|
|
rb = (inst >> 6) & 0x1F;
|
|
|
|
rb <<= 1;
|
2013-07-27 22:28:41 +00:00
|
|
|
DO_DISS(statusMsg << "ldrh r" << dec << rd << ",[r" << dec << rn << ",#0x" << Base::HEX2 << rb << "]" << endl);
|
2016-02-27 19:58:20 +00:00
|
|
|
rb=read_register(rn) + rb;
|
|
|
|
rc = read16(rb);
|
|
|
|
write_register(rd, rc & 0xFFFF);
|
|
|
|
return 0;
|
2011-04-16 16:53:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//LDRH(2)
|
2016-02-27 19:58:20 +00:00
|
|
|
if((inst & 0xFE00) == 0x5A00)
|
2011-04-16 16:53:41 +00:00
|
|
|
{
|
2016-02-27 19:58:20 +00:00
|
|
|
rd = (inst >> 0) & 0x7;
|
|
|
|
rn = (inst >> 3) & 0x7;
|
|
|
|
rm = (inst >> 6) & 0x7;
|
2012-12-26 21:16:34 +00:00
|
|
|
DO_DISS(statusMsg << "ldrh r" << dec << rd << ",[r" << dec << rn << ",r" << dec << rm << "]" << endl);
|
2016-02-27 19:58:20 +00:00
|
|
|
rb = read_register(rn) + read_register(rm);
|
|
|
|
rc = read16(rb);
|
|
|
|
write_register(rd, rc & 0xFFFF);
|
|
|
|
return 0;
|
2011-04-16 16:53:41 +00:00
|
|
|
}
|
2011-01-16 21:23:03 +00:00
|
|
|
|
2011-04-16 16:53:41 +00:00
|
|
|
//LDRSB
|
2016-02-27 19:58:20 +00:00
|
|
|
if((inst & 0xFE00) == 0x5600)
|
2011-04-16 16:53:41 +00:00
|
|
|
{
|
2016-02-27 19:58:20 +00:00
|
|
|
rd = (inst >> 0) & 0x7;
|
|
|
|
rn = (inst >> 3) & 0x7;
|
|
|
|
rm = (inst >> 6) & 0x7;
|
2012-12-26 21:16:34 +00:00
|
|
|
DO_DISS(statusMsg << "ldrsb r" << dec << rd << ",[r" << dec << rn << ",r" << dec << rm << "]" << endl);
|
2016-02-27 19:58:20 +00:00
|
|
|
rb = read_register(rn) + read_register(rm);
|
|
|
|
rc = read16(rb & (~1u));
|
|
|
|
if(rb & 1)
|
2011-01-16 21:23:03 +00:00
|
|
|
{
|
2016-02-27 19:58:20 +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
|
|
|
{
|
|
|
|
}
|
2016-02-27 19:58:20 +00:00
|
|
|
rc &= 0xFF;
|
|
|
|
if(rc & 0x80)
|
|
|
|
rc |= ((~0u) << 8);
|
|
|
|
write_register(rd, rc);
|
|
|
|
return 0;
|
2011-04-16 16:53:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//LDRSH
|
2016-02-27 19:58:20 +00:00
|
|
|
if((inst & 0xFE00) == 0x5E00)
|
2011-04-16 16:53:41 +00:00
|
|
|
{
|
2016-02-27 19:58:20 +00:00
|
|
|
rd = (inst >> 0) & 0x7;
|
|
|
|
rn = (inst >> 3) & 0x7;
|
|
|
|
rm = (inst >> 6) & 0x7;
|
2012-12-26 21:16:34 +00:00
|
|
|
DO_DISS(statusMsg << "ldrsh r" << dec << rd << ",[r" << dec << rn << ",r" << dec << rm << "]" << endl);
|
2016-02-27 19:58:20 +00:00
|
|
|
rb = read_register(rn) + read_register(rm);
|
|
|
|
rc = read16(rb);
|
|
|
|
rc &= 0xFFFF;
|
|
|
|
if(rc & 0x8000)
|
|
|
|
rc |= ((~0u) << 16);
|
|
|
|
write_register(rd, rc);
|
|
|
|
return 0;
|
2011-04-16 16:53:41 +00:00
|
|
|
}
|
2011-01-16 21:23:03 +00:00
|
|
|
|
2011-04-16 16:53:41 +00:00
|
|
|
//LSL(1)
|
2016-02-27 19:58:20 +00:00
|
|
|
if((inst & 0xF800) == 0x0000)
|
2011-04-16 16:53:41 +00:00
|
|
|
{
|
2016-02-27 19:58:20 +00:00
|
|
|
rd = (inst >> 0) & 0x07;
|
|
|
|
rm = (inst >> 3) & 0x07;
|
|
|
|
rb = (inst >> 6) & 0x1F;
|
2013-07-27 22:28:41 +00:00
|
|
|
DO_DISS(statusMsg << "lsls r" << dec << rd << ",r" << dec << rm << ",#0x" << Base::HEX2 << rb << endl);
|
2016-02-27 19:58:20 +00:00
|
|
|
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
|
2016-02-27 19:58:20 +00:00
|
|
|
//C unaffected
|
2011-04-16 16:53:41 +00:00
|
|
|
//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
|
2016-02-27 19:58:20 +00:00
|
|
|
do_cflag_bit(rc & (1 << (32-rb)));
|
|
|
|
rc <<= rb;
|
2011-01-16 21:23:03 +00:00
|
|
|
}
|
2016-02-27 19:58:20 +00:00
|
|
|
write_register(rd, rc);
|
2011-04-16 16:53:41 +00:00
|
|
|
do_nflag(rc);
|
|
|
|
do_zflag(rc);
|
2016-02-27 19:58:20 +00:00
|
|
|
return 0;
|
2011-04-16 16:53:41 +00:00
|
|
|
}
|
2011-01-16 21:23:03 +00:00
|
|
|
|
2011-04-16 16:53:41 +00:00
|
|
|
//LSL(2) two register
|
2016-02-27 19:58:20 +00:00
|
|
|
if((inst & 0xFFC0) == 0x4080)
|
2011-04-16 16:53:41 +00:00
|
|
|
{
|
2016-02-27 19:58:20 +00:00
|
|
|
rd = (inst >> 0) & 0x07;
|
|
|
|
rs = (inst >> 3) & 0x07;
|
2012-12-26 21:16:34 +00:00
|
|
|
DO_DISS(statusMsg << "lsls r" << dec << rd << ",r" << dec << rs << endl);
|
2016-02-27 19:58:20 +00:00
|
|
|
rc = read_register(rd);
|
|
|
|
rb = read_register(rs);
|
|
|
|
rb &= 0xFF;
|
|
|
|
if(rb == 0)
|
2011-01-16 21:23:03 +00:00
|
|
|
{
|
|
|
|
}
|
2016-02-27 19:58:20 +00:00
|
|
|
else if(rb < 32)
|
2011-01-16 21:23:03 +00:00
|
|
|
{
|
2016-02-27 19:58:20 +00:00
|
|
|
do_cflag_bit(rc & (1 << (32-rb)));
|
|
|
|
rc <<= rb;
|
2011-01-16 21:23:03 +00:00
|
|
|
}
|
2016-02-27 19:58:20 +00:00
|
|
|
else if(rb == 32)
|
2011-01-16 21:23:03 +00:00
|
|
|
{
|
2016-02-27 19:58:20 +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);
|
2016-02-27 19:58:20 +00:00
|
|
|
rc = 0;
|
2011-01-16 21:23:03 +00:00
|
|
|
}
|
2016-02-27 19:58:20 +00:00
|
|
|
write_register(rd, rc);
|
2011-04-16 16:53:41 +00:00
|
|
|
do_nflag(rc);
|
|
|
|
do_zflag(rc);
|
2016-02-27 19:58:20 +00:00
|
|
|
return 0;
|
2011-04-16 16:53:41 +00:00
|
|
|
}
|
2011-01-16 21:23:03 +00:00
|
|
|
|
2011-04-16 16:53:41 +00:00
|
|
|
//LSR(1) two register immediate
|
2016-02-27 19:58:20 +00:00
|
|
|
if((inst & 0xF800) == 0x0800)
|
2011-04-16 16:53:41 +00:00
|
|
|
{
|
2016-02-27 19:58:20 +00:00
|
|
|
rd = (inst >> 0) & 0x07;
|
|
|
|
rm = (inst >> 3) & 0x07;
|
|
|
|
rb = (inst >> 6) & 0x1F;
|
2013-07-27 22:28:41 +00:00
|
|
|
DO_DISS(statusMsg << "lsrs r" << dec << rd << ",r" << dec << rm << ",#0x" << Base::HEX2 << rb << endl);
|
2016-02-27 19:58:20 +00:00
|
|
|
rc = read_register(rm);
|
|
|
|
if(rb == 0)
|
2011-01-16 21:23:03 +00:00
|
|
|
{
|
2016-02-27 19:58:20 +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
|
|
|
|
{
|
2016-02-27 19:58:20 +00:00
|
|
|
do_cflag_bit(rc & (1 << (rb-1)));
|
|
|
|
rc >>= rb;
|
2011-04-16 16:53:41 +00:00
|
|
|
}
|
2016-02-27 19:58:20 +00:00
|
|
|
write_register(rd, rc);
|
2011-04-16 16:53:41 +00:00
|
|
|
do_nflag(rc);
|
|
|
|
do_zflag(rc);
|
2016-02-27 19:58:20 +00:00
|
|
|
return 0;
|
2011-04-16 16:53:41 +00:00
|
|
|
}
|
2011-01-16 21:23:03 +00:00
|
|
|
|
2011-04-16 16:53:41 +00:00
|
|
|
//LSR(2) two register
|
2016-02-27 19:58:20 +00:00
|
|
|
if((inst & 0xFFC0) == 0x40C0)
|
2011-04-16 16:53:41 +00:00
|
|
|
{
|
2016-02-27 19:58:20 +00:00
|
|
|
rd = (inst >> 0) & 0x07;
|
|
|
|
rs = (inst >> 3) & 0x07;
|
2012-12-26 21:16:34 +00:00
|
|
|
DO_DISS(statusMsg << "lsrs r" << dec << rd << ",r" << dec << rs << endl);
|
2016-02-27 19:58:20 +00:00
|
|
|
rc = read_register(rd);
|
|
|
|
rb = read_register(rs);
|
|
|
|
rb &= 0xFF;
|
|
|
|
if(rb == 0)
|
2011-01-16 21:23:03 +00:00
|
|
|
{
|
|
|
|
}
|
2016-02-27 19:58:20 +00:00
|
|
|
else if(rb < 32)
|
2011-04-16 16:53:41 +00:00
|
|
|
{
|
2016-02-27 19:58:20 +00:00
|
|
|
do_cflag_bit(rc & (1 << (rb-1)));
|
|
|
|
rc >>= rb;
|
2011-04-16 16:53:41 +00:00
|
|
|
}
|
2016-02-27 19:58:20 +00:00
|
|
|
else if(rb == 32)
|
2011-04-16 16:53:41 +00:00
|
|
|
{
|
2016-02-27 19:58:20 +00:00
|
|
|
do_cflag_bit(rc & 0x80000000);
|
|
|
|
rc = 0;
|
2011-04-16 16:53:41 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
do_cflag_bit(0);
|
2016-02-27 19:58:20 +00:00
|
|
|
rc = 0;
|
2011-04-16 16:53:41 +00:00
|
|
|
}
|
2016-02-27 19:58:20 +00:00
|
|
|
write_register(rd, rc);
|
2011-04-16 16:53:41 +00:00
|
|
|
do_nflag(rc);
|
|
|
|
do_zflag(rc);
|
2016-02-27 19:58:20 +00:00
|
|
|
return 0;
|
2011-04-16 16:53:41 +00:00
|
|
|
}
|
2011-01-16 21:23:03 +00:00
|
|
|
|
2011-04-16 16:53:41 +00:00
|
|
|
//MOV(1) immediate
|
2016-02-27 19:58:20 +00:00
|
|
|
if((inst & 0xF800) == 0x2000)
|
2011-04-16 16:53:41 +00:00
|
|
|
{
|
2016-02-27 19:58:20 +00:00
|
|
|
rb = (inst >> 0) & 0xFF;
|
|
|
|
rd = (inst >> 8) & 0x07;
|
2013-07-27 22:28:41 +00:00
|
|
|
DO_DISS(statusMsg << "movs r" << dec << rd << ",#0x" << Base::HEX2 << rb << endl);
|
2016-02-27 19:58:20 +00:00
|
|
|
write_register(rd, rb);
|
2011-04-16 16:53:41 +00:00
|
|
|
do_nflag(rb);
|
|
|
|
do_zflag(rb);
|
2016-02-27 19:58:20 +00:00
|
|
|
return 0;
|
2011-04-16 16:53:41 +00:00
|
|
|
}
|
2011-01-16 21:23:03 +00:00
|
|
|
|
2011-04-16 16:53:41 +00:00
|
|
|
//MOV(2) two low registers
|
2016-02-27 19:58:20 +00:00
|
|
|
if((inst & 0xFFC0) == 0x1C00)
|
2011-04-16 16:53:41 +00:00
|
|
|
{
|
2016-02-27 19:58:20 +00:00
|
|
|
rd = (inst >> 0) & 7;
|
|
|
|
rn = (inst >> 3) & 7;
|
2012-12-26 21:16:34 +00:00
|
|
|
DO_DISS(statusMsg << "movs r" << dec << rd << ",r" << dec << rn << endl);
|
2016-02-27 19:58:20 +00:00
|
|
|
rc = read_register(rn);
|
2011-04-16 16:53:41 +00:00
|
|
|
//fprintf(stderr,"0x%08X\n",rc);
|
2016-02-27 19:58:20 +00:00
|
|
|
write_register(rd, rc);
|
2011-04-16 16:53:41 +00:00
|
|
|
do_nflag(rc);
|
|
|
|
do_zflag(rc);
|
|
|
|
do_cflag_bit(0);
|
|
|
|
do_vflag_bit(0);
|
2016-02-27 19:58:20 +00:00
|
|
|
return 0;
|
2011-04-16 16:53:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//MOV(3)
|
2016-02-27 19:58:20 +00:00
|
|
|
if((inst & 0xFF00) == 0x4600)
|
2011-04-16 16:53:41 +00:00
|
|
|
{
|
2016-02-27 19:58:20 +00:00
|
|
|
rd = (inst >> 0) & 0x7;
|
|
|
|
rd |= (inst >> 4) & 0x8;
|
|
|
|
rm = (inst >> 3) & 0xF;
|
2012-12-26 21:16:34 +00:00
|
|
|
DO_DISS(statusMsg << "mov r" << dec << rd << ",r" << dec << rm << endl);
|
2016-02-27 19:58:20 +00:00
|
|
|
rc = read_register(rm);
|
|
|
|
if((rd == 14) && (rm == 15))
|
|
|
|
{
|
|
|
|
//printf("mov lr,pc warning 0x%08X\n",pc-2);
|
|
|
|
//rc|=1;
|
|
|
|
}
|
|
|
|
if(rd == 15)
|
|
|
|
{
|
|
|
|
rc &= ~1; //write_register may do this as well
|
|
|
|
rc += 2; //The program counter is special
|
|
|
|
}
|
|
|
|
write_register(rd, rc);
|
|
|
|
return 0;
|
2011-04-16 16:53:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//MUL
|
2016-02-27 19:58:20 +00:00
|
|
|
if((inst & 0xFFC0) == 0x4340)
|
2011-04-16 16:53:41 +00:00
|
|
|
{
|
2016-02-27 19:58:20 +00:00
|
|
|
rd = (inst >> 0) & 0x7;
|
|
|
|
rm = (inst >> 3) & 0x7;
|
2012-12-26 21:16:34 +00:00
|
|
|
DO_DISS(statusMsg << "muls r" << dec << rd << ",r" << dec << rm << endl);
|
2016-02-27 19:58:20 +00:00
|
|
|
ra = read_register(rd);
|
|
|
|
rb = read_register(rm);
|
|
|
|
rc = ra * rb;
|
|
|
|
write_register(rd, rc);
|
2011-04-16 16:53:41 +00:00
|
|
|
do_nflag(rc);
|
|
|
|
do_zflag(rc);
|
2016-02-27 19:58:20 +00:00
|
|
|
return 0;
|
2011-04-16 16:53:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//MVN
|
2016-02-27 19:58:20 +00:00
|
|
|
if((inst & 0xFFC0) == 0x43C0)
|
2011-04-16 16:53:41 +00:00
|
|
|
{
|
2016-02-27 19:58:20 +00:00
|
|
|
rd = (inst >> 0) & 0x7;
|
|
|
|
rm = (inst >> 3) & 0x7;
|
2012-12-26 21:16:34 +00:00
|
|
|
DO_DISS(statusMsg << "mvns r" << dec << rd << ",r" << dec << rm << endl);
|
2016-02-27 19:58:20 +00:00
|
|
|
ra = read_register(rm);
|
|
|
|
rc = (~ra);
|
|
|
|
write_register(rd, rc);
|
2011-04-16 16:53:41 +00:00
|
|
|
do_nflag(rc);
|
|
|
|
do_zflag(rc);
|
2016-02-27 19:58:20 +00:00
|
|
|
return 0;
|
2011-04-16 16:53:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//NEG
|
2016-02-27 19:58:20 +00:00
|
|
|
if((inst & 0xFFC0) == 0x4240)
|
2011-04-16 16:53:41 +00:00
|
|
|
{
|
2016-02-27 19:58:20 +00:00
|
|
|
rd = (inst >> 0) & 0x7;
|
|
|
|
rm = (inst >> 3) & 0x7;
|
2012-12-26 21:16:34 +00:00
|
|
|
DO_DISS(statusMsg << "negs r" << dec << rd << ",r" << dec << rm << endl);
|
2016-02-27 19:58:20 +00:00
|
|
|
ra = read_register(rm);
|
|
|
|
rc = 0 - ra;
|
|
|
|
write_register(rd, rc);
|
2011-04-16 16:53:41 +00:00
|
|
|
do_nflag(rc);
|
|
|
|
do_zflag(rc);
|
2016-02-27 19:58:20 +00:00
|
|
|
do_cflag(0, ~ra, 1);
|
|
|
|
do_vflag(0, ~ra, 1);
|
|
|
|
return 0;
|
2011-04-16 16:53:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//ORR
|
2016-02-27 19:58:20 +00:00
|
|
|
if((inst & 0xFFC0) == 0x4300)
|
2011-04-16 16:53:41 +00:00
|
|
|
{
|
2016-02-27 19:58:20 +00:00
|
|
|
rd = (inst >> 0) & 0x7;
|
|
|
|
rm = (inst >> 3) & 0x7;
|
2012-12-26 21:16:34 +00:00
|
|
|
DO_DISS(statusMsg << "orrs r" << dec << rd << ",r" << dec << rm << endl);
|
2016-02-27 19:58:20 +00:00
|
|
|
ra = read_register(rd);
|
|
|
|
rb = read_register(rm);
|
|
|
|
rc = ra | rb;
|
|
|
|
write_register(rd, rc);
|
2011-04-16 16:53:41 +00:00
|
|
|
do_nflag(rc);
|
|
|
|
do_zflag(rc);
|
2016-02-27 19:58:20 +00:00
|
|
|
return 0;
|
2011-04-16 16:53:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//POP
|
2016-02-27 19:58:20 +00:00
|
|
|
if((inst & 0xFE00) == 0xBC00)
|
2011-04-16 16:53:41 +00:00
|
|
|
{
|
2012-12-26 21:16:34 +00:00
|
|
|
#if defined(THUMB_DISS)
|
|
|
|
statusMsg << "pop {";
|
|
|
|
for(ra=0,rb=0x01,rc=0;rb;rb=(rb<<1)&0xFF,ra++)
|
2011-01-16 21:23:03 +00:00
|
|
|
{
|
2012-12-26 21:16:34 +00:00
|
|
|
if(inst&rb)
|
2011-04-16 16:53:41 +00:00
|
|
|
{
|
2011-05-24 16:04:48 +00:00
|
|
|
if(rc) statusMsg << ",";
|
2012-12-26 21:16:34 +00:00
|
|
|
statusMsg << "r" << dec << ra;
|
|
|
|
rc++;
|
2011-04-16 16:53:41 +00:00
|
|
|
}
|
2011-01-16 21:23:03 +00:00
|
|
|
}
|
2012-12-26 21:16:34 +00:00
|
|
|
if(inst&0x100)
|
|
|
|
{
|
|
|
|
if(rc) statusMsg << ",";
|
|
|
|
statusMsg << "pc";
|
|
|
|
}
|
|
|
|
statusMsg << "}" << endl;
|
|
|
|
#endif
|
2011-01-16 21:23:03 +00:00
|
|
|
|
2016-02-27 19:58:20 +00:00
|
|
|
sp = read_register(13);
|
|
|
|
for(ra = 0, rb = 0x01; rb; rb = (rb << 1) & 0xFF, ra++)
|
2011-04-16 16:53:41 +00:00
|
|
|
{
|
2016-02-27 19:58:20 +00:00
|
|
|
if(inst & rb)
|
2011-04-16 16:53:41 +00:00
|
|
|
{
|
2016-02-27 19:58:20 +00:00
|
|
|
write_register(ra, read32(sp));
|
|
|
|
sp += 4;
|
2011-04-16 16:53:41 +00:00
|
|
|
}
|
2011-01-16 21:23:03 +00:00
|
|
|
}
|
2016-02-27 19:58:20 +00:00
|
|
|
if(inst & 0x100)
|
2011-01-16 21:23:03 +00:00
|
|
|
{
|
2016-02-27 19:58:20 +00:00
|
|
|
rc = read32(sp);
|
|
|
|
rc += 2;
|
|
|
|
write_register(15, rc);
|
|
|
|
sp += 4;
|
2011-04-16 16:53:41 +00:00
|
|
|
}
|
2016-02-27 19:58:20 +00:00
|
|
|
write_register(13, sp);
|
|
|
|
return 0;
|
2011-04-16 16:53:41 +00:00
|
|
|
}
|
2011-01-16 21:23:03 +00:00
|
|
|
|
2011-04-16 16:53:41 +00:00
|
|
|
//PUSH
|
2016-02-27 19:58:20 +00:00
|
|
|
if((inst & 0xFE00) == 0xB400)
|
2011-04-16 16:53:41 +00:00
|
|
|
{
|
2012-12-26 21:16:34 +00:00
|
|
|
#if defined(THUMB_DISS)
|
|
|
|
statusMsg << "push {";
|
|
|
|
for(ra=0,rb=0x01,rc=0;rb;rb=(rb<<1)&0xFF,ra++)
|
2011-01-16 21:23:03 +00:00
|
|
|
{
|
2012-12-26 21:16:34 +00:00
|
|
|
if(inst&rb)
|
2011-04-16 16:53:41 +00:00
|
|
|
{
|
2011-05-24 16:04:48 +00:00
|
|
|
if(rc) statusMsg << ",";
|
2012-12-26 21:16:34 +00:00
|
|
|
statusMsg << "r" << dec << ra;
|
|
|
|
rc++;
|
2011-04-16 16:53:41 +00:00
|
|
|
}
|
2011-01-16 21:23:03 +00:00
|
|
|
}
|
2012-12-26 21:16:34 +00:00
|
|
|
if(inst&0x100)
|
|
|
|
{
|
|
|
|
if(rc) statusMsg << ",";
|
|
|
|
statusMsg << "lr";
|
|
|
|
}
|
|
|
|
statusMsg << "}" << endl;
|
|
|
|
#endif
|
2011-01-16 21:23:03 +00:00
|
|
|
|
2016-02-27 19:58:20 +00:00
|
|
|
sp = read_register(13);
|
2011-04-16 16:53:41 +00:00
|
|
|
//fprintf(stderr,"sp 0x%08X\n",sp);
|
2016-02-27 19:58:20 +00:00
|
|
|
for(ra = 0, rb = 0x01, rc = 0; rb; rb = (rb << 1) & 0xFF, ra++)
|
2011-04-16 16:53:41 +00:00
|
|
|
{
|
2016-02-27 19:58:20 +00:00
|
|
|
if(inst & rb)
|
2011-04-16 16:53:41 +00:00
|
|
|
{
|
|
|
|
rc++;
|
|
|
|
}
|
2011-01-16 21:23:03 +00:00
|
|
|
}
|
2016-02-27 19:58:20 +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
|
|
|
{
|
2016-02-27 19:58:20 +00:00
|
|
|
if(inst & rb)
|
2011-04-16 16:53:41 +00:00
|
|
|
{
|
2016-02-27 19:58:20 +00:00
|
|
|
write32(rd, read_register(ra));
|
|
|
|
rd += 4;
|
2011-04-16 16:53:41 +00:00
|
|
|
}
|
2011-01-16 21:23:03 +00:00
|
|
|
}
|
2016-02-27 19:58:20 +00:00
|
|
|
if(inst & 0x100)
|
2011-01-16 21:23:03 +00:00
|
|
|
{
|
2016-02-27 19:58:20 +00:00
|
|
|
rc = read_register(14);
|
|
|
|
write32(rd, rc);
|
|
|
|
if((rc & 1) == 0)
|
|
|
|
{
|
|
|
|
// FIXME fprintf(stderr,"push {lr} with an ARM address pc 0x%08X popped 0x%08X\n",pc,rc);
|
|
|
|
}
|
2011-01-16 21:23:03 +00:00
|
|
|
}
|
2016-02-27 19:58:20 +00:00
|
|
|
write_register(13, sp);
|
|
|
|
return 0;
|
2011-04-16 16:53:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//REV
|
2016-02-27 19:58:20 +00:00
|
|
|
if((inst & 0xFFC0) == 0xBA00)
|
2011-04-16 16:53:41 +00:00
|
|
|
{
|
2016-02-27 19:58:20 +00:00
|
|
|
rd = (inst >> 0) & 0x7;
|
|
|
|
rn = (inst >> 3) & 0x7;
|
2012-12-26 21:16:34 +00:00
|
|
|
DO_DISS(statusMsg << "rev r" << dec << rd << ",r" << dec << rn << endl);
|
2016-02-27 19:58:20 +00:00
|
|
|
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;
|
2011-04-16 16:53:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//REV16
|
2016-02-27 19:58:20 +00:00
|
|
|
if((inst & 0xFFC0) == 0xBA40)
|
2011-04-16 16:53:41 +00:00
|
|
|
{
|
2016-02-27 19:58:20 +00:00
|
|
|
rd = (inst >> 0) & 0x7;
|
|
|
|
rn = (inst >> 3) & 0x7;
|
2012-12-26 21:16:34 +00:00
|
|
|
DO_DISS(statusMsg << "rev16 r" << dec << rd << ",r" << dec << rn << endl);
|
2016-02-27 19:58:20 +00:00
|
|
|
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-04-16 16:53:41 +00:00
|
|
|
}
|
2011-01-16 21:23:03 +00:00
|
|
|
|
2011-04-16 16:53:41 +00:00
|
|
|
//REVSH
|
2016-02-27 19:58:20 +00:00
|
|
|
if((inst & 0xFFC0) == 0xBAC0)
|
2011-04-16 16:53:41 +00:00
|
|
|
{
|
2016-02-27 19:58:20 +00:00
|
|
|
rd = (inst >> 0) & 0x7;
|
|
|
|
rn = (inst >> 3) & 0x7;
|
2012-12-26 21:16:34 +00:00
|
|
|
DO_DISS(statusMsg << "revsh r" << dec << rd << ",r" << dec << rn << endl);
|
2016-02-27 19:58:20 +00:00
|
|
|
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-04-16 16:53:41 +00:00
|
|
|
}
|
2011-01-16 21:23:03 +00:00
|
|
|
|
2011-04-16 16:53:41 +00:00
|
|
|
//ROR
|
2016-02-27 19:58:20 +00:00
|
|
|
if((inst & 0xFFC0) == 0x41C0)
|
2011-04-16 16:53:41 +00:00
|
|
|
{
|
2016-02-27 19:58:20 +00:00
|
|
|
rd = (inst >> 0) & 0x7;
|
|
|
|
rs = (inst >> 3) & 0x7;
|
2012-12-26 21:16:34 +00:00
|
|
|
DO_DISS(statusMsg << "rors r" << dec << rd << ",r" << dec << rs << endl);
|
2016-02-27 19:58:20 +00:00
|
|
|
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
|
|
|
{
|
2016-02-27 19:58:20 +00:00
|
|
|
ra &= 0x1F;
|
|
|
|
if(ra == 0)
|
2011-04-16 16:53:41 +00:00
|
|
|
{
|
2016-02-27 19:58:20 +00:00
|
|
|
do_cflag_bit(rc & 0x80000000);
|
2011-04-16 16:53:41 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-02-27 19:58:20 +00:00
|
|
|
do_cflag_bit(rc & (1 << (ra-1)));
|
|
|
|
rb = rc << (32-ra);
|
|
|
|
rc >>= ra;
|
|
|
|
rc |= rb;
|
2011-04-16 16:53:41 +00:00
|
|
|
}
|
2011-01-16 21:23:03 +00:00
|
|
|
}
|
2016-02-27 19:58:20 +00:00
|
|
|
write_register(rd, rc);
|
2011-04-16 16:53:41 +00:00
|
|
|
do_nflag(rc);
|
|
|
|
do_zflag(rc);
|
2016-02-27 19:58:20 +00:00
|
|
|
return 0;
|
2011-04-16 16:53:41 +00:00
|
|
|
}
|
2011-01-16 21:23:03 +00:00
|
|
|
|
2011-04-16 16:53:41 +00:00
|
|
|
//SBC
|
2016-02-27 19:58:20 +00:00
|
|
|
if((inst & 0xFFC0) == 0x4180)
|
2011-04-16 16:53:41 +00:00
|
|
|
{
|
2016-02-27 19:58:20 +00:00
|
|
|
rd = (inst >> 0) & 0x7;
|
|
|
|
rm = (inst >> 3) & 0x7;
|
2012-12-26 21:16:34 +00:00
|
|
|
DO_DISS(statusMsg << "sbc r" << dec << rd << ",r" << dec << rm << endl);
|
2016-02-27 19:58:20 +00:00
|
|
|
ra = read_register(rd);
|
|
|
|
rb = read_register(rm);
|
|
|
|
rc = ra - rb;
|
|
|
|
if(!(cpsr & CPSR_C)) rc--;
|
|
|
|
write_register(rd, rc);
|
2011-04-16 16:53:41 +00:00
|
|
|
do_nflag(rc);
|
|
|
|
do_zflag(rc);
|
2016-02-27 19:58:20 +00:00
|
|
|
if(cpsr & CPSR_C)
|
|
|
|
{
|
|
|
|
do_cflag(ra, ~rb, 1);
|
|
|
|
do_vflag(ra, ~rb, 1);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
do_cflag(ra, ~rb, 0);
|
|
|
|
do_vflag(ra, ~rb, 0);
|
|
|
|
}
|
|
|
|
return 0;
|
2011-04-16 16:53:41 +00:00
|
|
|
}
|
2011-01-16 21:23:03 +00:00
|
|
|
|
2011-04-16 16:53:41 +00:00
|
|
|
//SETEND
|
2016-02-27 19:58:20 +00:00
|
|
|
if((inst & 0xFFF7) == 0xB650)
|
2011-04-16 16:53:41 +00:00
|
|
|
{
|
2011-05-24 16:04:48 +00:00
|
|
|
statusMsg << "setend not implemented" << endl;
|
2016-02-27 19:58:20 +00:00
|
|
|
return 1;
|
2011-04-16 16:53:41 +00:00
|
|
|
}
|
2011-01-16 21:23:03 +00:00
|
|
|
|
2011-04-16 16:53:41 +00:00
|
|
|
//STMIA
|
2016-02-27 19:58:20 +00:00
|
|
|
if((inst & 0xF800) == 0xC000)
|
2011-04-16 16:53:41 +00:00
|
|
|
{
|
2016-02-27 19:58:20 +00:00
|
|
|
rn = (inst >> 8) & 0x7;
|
2012-12-26 21:16:34 +00:00
|
|
|
#if defined(THUMB_DISS)
|
|
|
|
statusMsg << "stmia r" << dec << rn << "!,{";
|
|
|
|
for(ra=0,rb=0x01,rc=0;rb;rb=(rb<<1)&0xFF,ra++)
|
2011-01-16 21:23:03 +00:00
|
|
|
{
|
2016-02-27 19:58:20 +00:00
|
|
|
if(inst & rb)
|
2011-04-16 16:53:41 +00:00
|
|
|
{
|
2012-12-26 21:16:34 +00:00
|
|
|
if(rc) statusMsg << ",";
|
|
|
|
statusMsg << "r" << dec << ra;
|
|
|
|
rc++;
|
2011-04-16 16:53:41 +00:00
|
|
|
}
|
2011-01-16 21:23:03 +00:00
|
|
|
}
|
2012-12-26 21:16:34 +00:00
|
|
|
statusMsg << "}" << endl;
|
|
|
|
#endif
|
|
|
|
|
2016-02-27 19:58:20 +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
|
|
|
{
|
2016-02-27 19:58:20 +00:00
|
|
|
if(inst & rb)
|
2011-04-16 16:53:41 +00:00
|
|
|
{
|
2016-02-27 19:58:20 +00:00
|
|
|
write32(sp, read_register(ra));
|
|
|
|
sp += 4;
|
2011-04-16 16:53:41 +00:00
|
|
|
}
|
2011-01-16 21:23:03 +00:00
|
|
|
}
|
2016-02-27 19:58:20 +00:00
|
|
|
write_register(rn, sp);
|
|
|
|
return 0;
|
2011-04-16 16:53:41 +00:00
|
|
|
}
|
2011-01-16 21:23:03 +00:00
|
|
|
|
2011-04-16 16:53:41 +00:00
|
|
|
//STR(1)
|
2016-02-27 19:58:20 +00:00
|
|
|
if((inst & 0xF800) == 0x6000)
|
2011-04-16 16:53:41 +00:00
|
|
|
{
|
2016-02-27 19:58:20 +00:00
|
|
|
rd = (inst >> 0) & 0x07;
|
|
|
|
rn = (inst >> 3) & 0x07;
|
|
|
|
rb = (inst >> 6) & 0x1F;
|
|
|
|
rb <<= 2;
|
2013-07-27 22:28:41 +00:00
|
|
|
DO_DISS(statusMsg << "str r" << dec << rd << ",[r" << dec << rn << ",#0x" << Base::HEX2 << rb << "]" << endl);
|
2016-02-27 19:58:20 +00:00
|
|
|
rb = read_register(rn) + rb;
|
|
|
|
rc = read_register(rd);
|
|
|
|
write32(rb, rc);
|
|
|
|
return 0;
|
2011-04-16 16:53:41 +00:00
|
|
|
}
|
2011-01-16 21:23:03 +00:00
|
|
|
|
2011-04-16 16:53:41 +00:00
|
|
|
//STR(2)
|
2016-02-27 19:58:20 +00:00
|
|
|
if((inst & 0xFE00) == 0x5000)
|
2011-04-16 16:53:41 +00:00
|
|
|
{
|
2016-02-27 19:58:20 +00:00
|
|
|
rd = (inst >> 0) & 0x7;
|
|
|
|
rn = (inst >> 3) & 0x7;
|
|
|
|
rm = (inst >> 6) & 0x7;
|
2012-12-26 21:16:34 +00:00
|
|
|
DO_DISS(statusMsg << "str r" << dec << rd << ",[r" << dec << rn << ",r" << dec << rm << "]" << endl);
|
2016-02-27 19:58:20 +00:00
|
|
|
rb = read_register(rn) + read_register(rm);
|
|
|
|
rc = read_register(rd);
|
|
|
|
write32(rb, rc);
|
|
|
|
return 0;
|
2011-04-16 16:53:41 +00:00
|
|
|
}
|
2011-01-16 21:23:03 +00:00
|
|
|
|
2011-04-16 16:53:41 +00:00
|
|
|
//STR(3)
|
2016-02-27 19:58:20 +00:00
|
|
|
if((inst & 0xF800) == 0x9000)
|
2011-04-16 16:53:41 +00:00
|
|
|
{
|
2016-02-27 19:58:20 +00:00
|
|
|
rb = (inst >> 0) & 0xFF;
|
|
|
|
rd = (inst >> 8) & 0x07;
|
|
|
|
rb <<= 2;
|
2013-07-27 22:28:41 +00:00
|
|
|
DO_DISS(statusMsg << "str r" << dec << rd << ",[SP,#0x" << Base::HEX2 << rb << "]" << endl);
|
2016-02-27 19:58:20 +00:00
|
|
|
rb = read_register(13) + rb;
|
2011-04-16 16:53:41 +00:00
|
|
|
//fprintf(stderr,"0x%08X\n",rb);
|
2016-02-27 19:58:20 +00:00
|
|
|
rc = read_register(rd);
|
|
|
|
write32(rb, rc);
|
|
|
|
return 0;
|
2011-04-16 16:53:41 +00:00
|
|
|
}
|
2011-01-16 21:23:03 +00:00
|
|
|
|
2011-04-16 16:53:41 +00:00
|
|
|
//STRB(1)
|
2016-02-27 19:58:20 +00:00
|
|
|
if((inst & 0xF800) == 0x7000)
|
2011-04-16 16:53:41 +00:00
|
|
|
{
|
2016-02-27 19:58:20 +00:00
|
|
|
rd = (inst >> 0) & 0x07;
|
|
|
|
rn = (inst >> 3) & 0x07;
|
|
|
|
rb = (inst >> 6) & 0x1F;
|
2013-07-27 22:28:41 +00:00
|
|
|
DO_DISS(statusMsg << "strb r" << dec << rd << ",[r" << dec << rn << ",#0x" << Base::HEX8 << rb << "]" << endl);
|
2016-02-27 19:58:20 +00:00
|
|
|
rb = read_register(rn) + rb;
|
|
|
|
rc = read_register(rd);
|
|
|
|
ra = read16(rb & (~1u));
|
|
|
|
if(rb & 1)
|
2011-01-16 21:23:03 +00:00
|
|
|
{
|
2016-02-27 19:58:20 +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
|
|
|
{
|
2016-02-27 19:58:20 +00:00
|
|
|
ra &= 0xFF00;
|
|
|
|
ra |= rc & 0x00FF;
|
2011-01-16 21:23:03 +00:00
|
|
|
}
|
2016-02-27 19:58:20 +00:00
|
|
|
write16(rb & (~1u), ra & 0xFFFF);
|
|
|
|
return 0;
|
2011-04-16 16:53:41 +00:00
|
|
|
}
|
2011-01-16 21:23:03 +00:00
|
|
|
|
2011-04-16 16:53:41 +00:00
|
|
|
//STRB(2)
|
2016-02-27 19:58:20 +00:00
|
|
|
if((inst & 0xFE00) == 0x5400)
|
2011-04-16 16:53:41 +00:00
|
|
|
{
|
2016-02-27 19:58:20 +00:00
|
|
|
rd = (inst >> 0) & 0x7;
|
|
|
|
rn = (inst >> 3) & 0x7;
|
|
|
|
rm = (inst >> 6) & 0x7;
|
2012-12-26 21:16:34 +00:00
|
|
|
DO_DISS(statusMsg << "strb r" << dec << rd << ",[r" << dec << rn << ",r" << rm << "]" << endl);
|
2016-02-27 19:58:20 +00:00
|
|
|
rb = read_register(rn) + read_register(rm);
|
|
|
|
rc = read_register(rd);
|
|
|
|
ra = read16(rb & (~1u));
|
|
|
|
if(rb & 1)
|
2011-01-16 21:23:03 +00:00
|
|
|
{
|
2016-02-27 19:58:20 +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
|
|
|
{
|
2016-02-27 19:58:20 +00:00
|
|
|
ra &= 0xFF00;
|
|
|
|
ra |= rc & 0x00FF;
|
2011-01-16 21:23:03 +00:00
|
|
|
}
|
2016-02-27 19:58:20 +00:00
|
|
|
write16(rb & (~1u), ra & 0xFFFF);
|
|
|
|
return 0;
|
2011-04-16 16:53:41 +00:00
|
|
|
}
|
2011-01-16 21:23:03 +00:00
|
|
|
|
2011-04-16 16:53:41 +00:00
|
|
|
//STRH(1)
|
2016-02-27 19:58:20 +00:00
|
|
|
if((inst & 0xF800) == 0x8000)
|
2011-04-16 16:53:41 +00:00
|
|
|
{
|
2016-02-27 19:58:20 +00:00
|
|
|
rd = (inst >> 0) & 0x07;
|
|
|
|
rn = (inst >> 3) & 0x07;
|
|
|
|
rb = (inst >> 6) & 0x1F;
|
|
|
|
rb <<= 1;
|
2013-07-27 22:28:41 +00:00
|
|
|
DO_DISS(statusMsg << "strh r" << dec << rd << ",[r" << dec << rn << ",#0x" << Base::HEX2 << rb << "]" << endl);
|
2016-02-27 19:58:20 +00:00
|
|
|
rb = read_register(rn) + rb;
|
|
|
|
rc= read_register(rd);
|
|
|
|
write16(rb, rc & 0xFFFF);
|
|
|
|
return 0;
|
2011-04-16 16:53:41 +00:00
|
|
|
}
|
2011-01-16 21:23:03 +00:00
|
|
|
|
2011-04-16 16:53:41 +00:00
|
|
|
//STRH(2)
|
2016-02-27 19:58:20 +00:00
|
|
|
if((inst & 0xFE00) == 0x5200)
|
2011-04-16 16:53:41 +00:00
|
|
|
{
|
2016-02-27 19:58:20 +00:00
|
|
|
rd = (inst >> 0) & 0x7;
|
|
|
|
rn = (inst >> 3) & 0x7;
|
|
|
|
rm = (inst >> 6) & 0x7;
|
2012-12-26 21:16:34 +00:00
|
|
|
DO_DISS(statusMsg << "strh r" << dec << rd << ",[r" << dec << rn << ",r" << dec << rm << "]" << endl);
|
2016-02-27 19:58:20 +00:00
|
|
|
rb = read_register(rn) + read_register(rm);
|
|
|
|
rc = read_register(rd);
|
|
|
|
write16(rb, rc & 0xFFFF);
|
|
|
|
return 0;
|
2011-04-16 16:53:41 +00:00
|
|
|
}
|
2011-01-16 21:23:03 +00:00
|
|
|
|
2011-04-16 16:53:41 +00:00
|
|
|
//SUB(1)
|
2016-02-27 19:58:20 +00:00
|
|
|
if((inst & 0xFE00) == 0x1E00)
|
2011-04-16 16:53:41 +00:00
|
|
|
{
|
2016-02-27 19:58:20 +00:00
|
|
|
rd = (inst >> 0) & 0x7;
|
|
|
|
rn = (inst >> 3) & 0x7;
|
|
|
|
rb = (inst >> 6) & 0x7;
|
2013-07-27 22:28:41 +00:00
|
|
|
DO_DISS(statusMsg << "subs r" << dec << rd << ",r" << dec << rn << ",#0x" << Base::HEX2 << rb << endl);
|
2016-02-27 19:58:20 +00:00
|
|
|
ra = read_register(rn);
|
|
|
|
rc = ra - rb;
|
|
|
|
write_register(rd, rc);
|
2011-04-16 16:53:41 +00:00
|
|
|
do_nflag(rc);
|
|
|
|
do_zflag(rc);
|
2016-02-27 19:58:20 +00:00
|
|
|
do_cflag(ra, ~rb, 1);
|
|
|
|
do_vflag(ra, ~rb, 1);
|
|
|
|
return 0;
|
2011-04-16 16:53:41 +00:00
|
|
|
}
|
2011-01-16 21:23:03 +00:00
|
|
|
|
2011-04-16 16:53:41 +00:00
|
|
|
//SUB(2)
|
2016-02-27 19:58:20 +00:00
|
|
|
if((inst & 0xF800) == 0x3800)
|
2011-04-16 16:53:41 +00:00
|
|
|
{
|
2016-02-27 19:58:20 +00:00
|
|
|
rb = (inst >> 0) & 0xFF;
|
|
|
|
rd = (inst >> 8) & 0x07;
|
2013-07-27 22:28:41 +00:00
|
|
|
DO_DISS(statusMsg << "subs r" << dec << rd << ",#0x" << Base::HEX2 << rb << endl);
|
2016-02-27 19:58:20 +00:00
|
|
|
ra = read_register(rd);
|
|
|
|
rc = ra - rb;
|
|
|
|
write_register(rd, rc);
|
2011-04-16 16:53:41 +00:00
|
|
|
do_nflag(rc);
|
|
|
|
do_zflag(rc);
|
2016-02-27 19:58:20 +00:00
|
|
|
do_cflag(ra, ~rb, 1);
|
|
|
|
do_vflag(ra, ~rb, 1);
|
|
|
|
return 0;
|
2011-04-16 16:53:41 +00:00
|
|
|
}
|
2011-01-16 21:23:03 +00:00
|
|
|
|
2011-04-16 16:53:41 +00:00
|
|
|
//SUB(3)
|
2016-02-27 19:58:20 +00:00
|
|
|
if((inst & 0xFE00) == 0x1A00)
|
2011-04-16 16:53:41 +00:00
|
|
|
{
|
2016-02-27 19:58:20 +00:00
|
|
|
rd = (inst >> 0) & 0x7;
|
|
|
|
rn = (inst >> 3) & 0x7;
|
|
|
|
rm = (inst >> 6) & 0x7;
|
2012-12-26 21:16:34 +00:00
|
|
|
DO_DISS(statusMsg << "subs r" << dec << rd << ",r" << dec << rn << ",r" << dec << rm << endl);
|
2016-02-27 19:58:20 +00:00
|
|
|
ra = read_register(rn);
|
|
|
|
rb = read_register(rm);
|
|
|
|
rc = ra - rb;
|
|
|
|
write_register(rd, rc);
|
2011-04-16 16:53:41 +00:00
|
|
|
do_nflag(rc);
|
|
|
|
do_zflag(rc);
|
2016-02-27 19:58:20 +00:00
|
|
|
do_cflag(ra, ~rb, 1);
|
|
|
|
do_vflag(ra, ~rb, 1);
|
|
|
|
return 0;
|
2011-04-16 16:53:41 +00:00
|
|
|
}
|
2011-01-16 21:23:03 +00:00
|
|
|
|
2011-04-16 16:53:41 +00:00
|
|
|
//SUB(4)
|
2016-02-27 19:58:20 +00:00
|
|
|
if((inst & 0xFF80) == 0xB080)
|
2011-04-16 16:53:41 +00:00
|
|
|
{
|
2016-02-27 19:58:20 +00:00
|
|
|
rb = inst & 0x7F;
|
|
|
|
rb <<= 2;
|
2013-07-27 22:28:41 +00:00
|
|
|
DO_DISS(statusMsg << "sub SP,#0x" << Base::HEX2 << rb << endl);
|
2016-02-27 19:58:20 +00:00
|
|
|
ra = read_register(13);
|
|
|
|
ra -= rb;
|
|
|
|
write_register(13, ra);
|
|
|
|
return 0;
|
2011-04-16 16:53:41 +00:00
|
|
|
}
|
2011-01-16 21:23:03 +00:00
|
|
|
|
2011-04-16 16:53:41 +00:00
|
|
|
//SWI
|
2016-02-27 19:58:20 +00:00
|
|
|
if((inst & 0xFF00) == 0xDF00)
|
2011-04-16 16:53:41 +00:00
|
|
|
{
|
2016-02-27 19:58:20 +00:00
|
|
|
rb = inst & 0xFF;
|
2013-07-27 22:28:41 +00:00
|
|
|
DO_DISS(statusMsg << "swi 0x" << Base::HEX2 << rb << endl);
|
2016-02-27 19:58:20 +00:00
|
|
|
|
|
|
|
if((inst & 0xFF) == 0xCC)
|
|
|
|
{
|
|
|
|
write_register(0, cpsr);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
statusMsg << endl << endl << "swi 0x" << Base::HEX2 << rb << endl;
|
|
|
|
return 1;
|
|
|
|
}
|
2011-04-16 16:53:41 +00:00
|
|
|
}
|
2011-01-16 21:23:03 +00:00
|
|
|
|
2011-04-16 16:53:41 +00:00
|
|
|
//SXTB
|
2016-02-27 19:58:20 +00:00
|
|
|
if((inst & 0xFFC0) == 0xB240)
|
2011-04-16 16:53:41 +00:00
|
|
|
{
|
2016-02-27 19:58:20 +00:00
|
|
|
rd = (inst >> 0) & 0x7;
|
|
|
|
rm = (inst >> 3) & 0x7;
|
2012-12-26 21:16:34 +00:00
|
|
|
DO_DISS(statusMsg << "sxtb r" << dec << rd << ",r" << dec << rm << endl);
|
2016-02-27 19:58:20 +00:00
|
|
|
ra = read_register(rm);
|
|
|
|
rc = ra & 0xFF;
|
|
|
|
if(rc & 0x80)
|
|
|
|
rc |= (~0u) << 8;
|
|
|
|
write_register(rd, rc);
|
|
|
|
return 0;
|
2011-04-16 16:53:41 +00:00
|
|
|
}
|
2011-01-16 21:23:03 +00:00
|
|
|
|
2011-04-16 16:53:41 +00:00
|
|
|
//SXTH
|
2016-02-27 19:58:20 +00:00
|
|
|
if((inst & 0xFFC0) == 0xB200)
|
2011-04-16 16:53:41 +00:00
|
|
|
{
|
2016-02-27 19:58:20 +00:00
|
|
|
rd = (inst >> 0) & 0x7;
|
|
|
|
rm = (inst >> 3) & 0x7;
|
2012-12-26 21:16:34 +00:00
|
|
|
DO_DISS(statusMsg << "sxth r" << dec << rd << ",r" << dec << rm << endl);
|
2016-02-27 19:58:20 +00:00
|
|
|
ra = read_register(rm);
|
|
|
|
rc = ra & 0xFFFF;
|
|
|
|
if(rc & 0x8000)
|
|
|
|
rc |= (~0u) << 16;
|
|
|
|
write_register(rd, rc);
|
|
|
|
return 0;
|
2011-04-16 16:53:41 +00:00
|
|
|
}
|
2011-01-16 21:23:03 +00:00
|
|
|
|
2011-04-16 16:53:41 +00:00
|
|
|
//TST
|
2016-02-27 19:58:20 +00:00
|
|
|
if((inst & 0xFFC0) == 0x4200)
|
2011-04-16 16:53:41 +00:00
|
|
|
{
|
2016-02-27 19:58:20 +00:00
|
|
|
rn = (inst >> 0) & 0x7;
|
|
|
|
rm = (inst >> 3) & 0x7;
|
2012-12-26 21:16:34 +00:00
|
|
|
DO_DISS(statusMsg << "tst r" << dec << rn << ",r" << dec << rm << endl);
|
2016-02-27 19:58:20 +00:00
|
|
|
ra = read_register(rn);
|
|
|
|
rb = read_register(rm);
|
|
|
|
rc = ra & rb;
|
2011-04-16 16:53:41 +00:00
|
|
|
do_nflag(rc);
|
|
|
|
do_zflag(rc);
|
2016-02-27 19:58:20 +00:00
|
|
|
return 0;
|
2011-04-16 16:53:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//UXTB
|
2016-02-27 19:58:20 +00:00
|
|
|
if((inst & 0xFFC0) == 0xB2C0)
|
2011-04-16 16:53:41 +00:00
|
|
|
{
|
2016-02-27 19:58:20 +00:00
|
|
|
rd = (inst >> 0) & 0x7;
|
|
|
|
rm = (inst >> 3) & 0x7;
|
2012-12-26 21:16:34 +00:00
|
|
|
DO_DISS(statusMsg << "uxtb r" << dec << rd << ",r" << dec << rm << endl);
|
2016-02-27 19:58:20 +00:00
|
|
|
ra = read_register(rm);
|
|
|
|
rc = ra & 0xFF;
|
|
|
|
write_register(rd, rc);
|
|
|
|
return 0;
|
2011-04-16 16:53:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//UXTH
|
2016-02-27 19:58:20 +00:00
|
|
|
if((inst & 0xFFC0) == 0xB280)
|
2011-04-16 16:53:41 +00:00
|
|
|
{
|
2016-02-27 19:58:20 +00:00
|
|
|
rd = (inst >> 0) & 0x7;
|
|
|
|
rm = (inst >> 3) & 0x7;
|
2012-12-26 21:16:34 +00:00
|
|
|
DO_DISS(statusMsg << "uxth r" << dec << rd << ",r" << dec << rm << endl);
|
2016-02-27 19:58:20 +00:00
|
|
|
ra = read_register(rm);
|
|
|
|
rc = ra & 0xFFFF;
|
|
|
|
write_register(rd, rc);
|
|
|
|
return 0;
|
2011-04-16 16:53:41 +00:00
|
|
|
}
|
|
|
|
|
2013-07-27 22:28:41 +00:00
|
|
|
statusMsg << "invalid instruction " << Base::HEX8 << pc << " " << Base::HEX4 << inst << endl;
|
2016-02-27 19:58:20 +00:00
|
|
|
return 1;
|
2011-01-16 21:23:03 +00:00
|
|
|
}
|
|
|
|
|
2011-03-09 14:21:32 +00:00
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
2016-02-27 19:58:20 +00:00
|
|
|
int Thumbulator::reset()
|
2011-01-16 21:23:03 +00:00
|
|
|
{
|
2016-02-27 19:58:20 +00:00
|
|
|
std::fill(reg_norm, reg_norm+12, 0);
|
|
|
|
reg_norm[13] = 0x40001FB4;
|
|
|
|
reg_norm[14] = 0x00000C00;
|
|
|
|
reg_norm[15] = 0x00000C0B;
|
2011-01-16 21:23:03 +00:00
|
|
|
|
2016-02-27 19:58:20 +00:00
|
|
|
cpsr = mamcr = 0;
|
|
|
|
handler_mode = false;
|
|
|
|
|
|
|
|
systick_ctrl = 0x00000004;
|
|
|
|
systick_reload = 0x00000000;
|
|
|
|
systick_count = 0x00000000;
|
|
|
|
systick_calibrate = 0x00ABCDEF;
|
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???)
|
2016-02-27 19:58:20 +00:00
|
|
|
instructions = fetches = reads = writes = systick_ints = 0;
|
2011-01-16 21:23:03 +00:00
|
|
|
|
2011-05-24 16:04:48 +00:00
|
|
|
statusMsg.str("");
|
|
|
|
|
2016-02-27 19:58:20 +00:00
|
|
|
return 0;
|
2011-01-16 21:23:03 +00:00
|
|
|
}
|
2011-04-16 16:53:41 +00:00
|
|
|
|
2011-11-07 22:50:23 +00:00
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
bool Thumbulator::trapOnFatal = true;
|
|
|
|
|
2011-04-16 16:53:41 +00:00
|
|
|
#endif
|