#ifndef MODET
#if 1
#error "MODET needs to be defined for the Thumb world to work"
#else
#define MODET (1)
#endif
#endif
#include "armdefs.h"
#include "armemu.h"
#include "armos.h"
tdstate ARMul_ThumbDecode (state, pc, tinstr, ainstr)
ARMul_State *
state;
ARMword
pc;
ARMword
tinstr;
ARMword *
ainstr;
{
tdstate valid = t_decoded;
ARMword next_instr;
if (state->bigendSig)
{
next_instr = tinstr & 0xFFFF;
tinstr >>= 16;
}
else
{
next_instr = tinstr >> 16;
tinstr &= 0xFFFF;
}
#if 1
*ainstr = 0xDEADC0DE;
#endif
switch ((tinstr & 0xF800) >> 11)
{
case 0:
case 1:
case 2:
*ainstr = 0xE1B00000
| ((tinstr & 0x1800) >> (11 - 5))
| ((tinstr & 0x07C0) << (7 - 6))
| ((tinstr & 0x0038) >> 3)
| ((tinstr & 0x0007) << 12);
break;
case 3:
{
ARMword subset[4] = {
0xE0900000,
0xE0500000,
0xE2900000,
0xE2500000
};
*ainstr = subset[(tinstr & 0x0600) >> 9]
| ((tinstr & 0x01C0) >> 6)
| ((tinstr & 0x0038) << (16 - 3))
| ((tinstr & 0x0007) << (12 - 0));
}
break;
case 4:
case 5:
case 6:
case 7:
{
ARMword subset[4] = {
0xE3B00000,
0xE3500000,
0xE2900000,
0xE2500000,
};
*ainstr = subset[(tinstr & 0x1800) >> 11]
| ((tinstr & 0x00FF) >> 0)
| ((tinstr & 0x0700) << (16 - 8))
| ((tinstr & 0x0700) << (12 - 8));
}
break;
case 8:
if ((tinstr & (1 << 10)) == 0)
{
struct
{
ARMword opcode;
enum
{ t_norm, t_shift, t_neg, t_mul }
otype;
}
subset[16] =
{
{ 0xE0100000, t_norm},
{ 0xE0300000, t_norm},
{ 0xE1B00010, t_shift},
{ 0xE1B00030, t_shift},
{ 0xE1B00050, t_shift},
{ 0xE0B00000, t_norm},
{ 0xE0D00000, t_norm},
{ 0xE1B00070, t_shift},
{ 0xE1100000, t_norm},
{ 0xE2700000, t_neg},
{ 0xE1500000, t_norm},
{ 0xE1700000, t_norm},
{ 0xE1900000, t_norm},
{ 0xE0100090, t_mul} ,
{ 0xE1D00000, t_norm},
{ 0xE1F00000, t_norm}
};
*ainstr = subset[(tinstr & 0x03C0) >> 6].opcode;
switch (subset[(tinstr & 0x03C0) >> 6].otype)
{
case t_norm:
*ainstr |= ((tinstr & 0x0007) << 16)
| ((tinstr & 0x0007) << 12)
| ((tinstr & 0x0038) >> 3);
break;
case t_shift:
*ainstr |= ((tinstr & 0x0007) << 12)
| ((tinstr & 0x0007) >> 0)
| ((tinstr & 0x0038) << (8 - 3));
break;
case t_neg:
*ainstr |= ((tinstr & 0x0007) << 12)
| ((tinstr & 0x0038) << (16 - 3));
break;
case t_mul:
*ainstr |= ((tinstr & 0x0007) << 16)
| ((tinstr & 0x0007) << 8)
| ((tinstr & 0x0038) >> 3);
break;
}
}
else
{
ARMword Rd = ((tinstr & 0x0007) >> 0);
ARMword Rs = ((tinstr & 0x0038) >> 3);
if (tinstr & (1 << 7))
Rd += 8;
if (tinstr & (1 << 6))
Rs += 8;
switch ((tinstr & 0x03C0) >> 6)
{
case 0x1:
case 0x2:
case 0x3:
*ainstr = 0xE0800000
| (Rd << 16)
| (Rd << 12)
| (Rs << 0);
break;
case 0x5:
case 0x6:
case 0x7:
*ainstr = 0xE1500000
| (Rd << 16)
| (Rd << 12)
| (Rs << 0);
break;
case 0x9:
case 0xA:
case 0xB:
*ainstr = 0xE1A00000
| (Rd << 16)
| (Rd << 12)
| (Rs << 0);
break;
case 0xC:
case 0xD:
*ainstr = 0xE12FFF10
| ((tinstr & 0x0078) >> 3);
break;
case 0xE:
case 0xF:
if (state->is_v5)
{
*ainstr = 0xE12FFF30
| ((tinstr & 0x0078) >> 3);
break;
}
case 0x0:
case 0x4:
case 0x8:
valid = t_undefined;
break;
}
}
break;
case 9:
*ainstr = 0xE59F0000
| ((tinstr & 0x0700) << (12 - 8))
| ((tinstr & 0x00FF) << (2 - 0));
break;
case 10:
case 11:
if ((tinstr & (1 << 9)) == 0)
{
ARMword subset[4] = {
0xE7800000,
0xE7C00000,
0xE7900000,
0xE7D00000
};
*ainstr = subset[(tinstr & 0x0C00) >> 10]
| ((tinstr & 0x0007) << (12 - 0))
| ((tinstr & 0x0038) << (16 - 3))
| ((tinstr & 0x01C0) >> 6);
}
else
{
ARMword subset[4] = {
0xE18000B0,
0xE19000D0,
0xE19000B0,
0xE19000F0
};
*ainstr = subset[(tinstr & 0x0C00) >> 10]
| ((tinstr & 0x0007) << (12 - 0))
| ((tinstr & 0x0038) << (16 - 3))
| ((tinstr & 0x01C0) >> 6);
}
break;
case 12:
case 13:
case 14:
case 15:
{
ARMword subset[4] = {
0xE5800000,
0xE5900000,
0xE5C00000,
0xE5D00000
};
*ainstr = subset[(tinstr & 0x1800) >> 11]
| ((tinstr & 0x0007) << (12 - 0))
| ((tinstr & 0x0038) << (16 - 3))
| ((tinstr & 0x07C0) >> (6 - ((tinstr & (1 << 12)) ? 0 : 2)));
}
break;
case 16:
case 17:
*ainstr = ((tinstr & (1 << 11))
? 0xE1D000B0
: 0xE1C000B0)
| ((tinstr & 0x0007) << (12 - 0))
| ((tinstr & 0x0038) << (16 - 3))
| ((tinstr & 0x01C0) >> (6 - 1))
| ((tinstr & 0x0600) >> (9 - 8));
break;
case 18:
case 19:
*ainstr = ((tinstr & (1 << 11))
? 0xE59D0000
: 0xE58D0000)
| ((tinstr & 0x0700) << (12 - 8))
| ((tinstr & 0x00FF) << 2);
break;
case 20:
case 21:
if ((tinstr & (1 << 11)) == 0)
{
*ainstr = 0xE28F0F00
| ((tinstr & 0x0700) << (12 - 8))
| (tinstr & 0x00FF);
}
else
{
*ainstr = 0xE28D0F00
| ((tinstr & 0x0700) << (12 - 8))
| (tinstr & 0x00FF);
}
break;
case 22:
case 23:
switch (tinstr & 0x0F00)
{
case 0x0000:
*ainstr = ((tinstr & (1 << 7))
? 0xE24DDF00
: 0xE28DDF00)
| (tinstr & 0x007F);
break;
case 0x0400:
* ainstr = 0xE92D0000 | (tinstr & 0x00FF);
break;
case 0x0500:
* ainstr = 0xE92D4000 | (tinstr & 0x00FF);
break;
case 0x0c00:
* ainstr = 0xE8BD0000 | (tinstr & 0x00FF);
break;
case 0x0d00:
* ainstr = 0xE8BD8000 | (tinstr & 0x00FF);
break;
case 0x0e00:
if (state->is_v5)
{
* ainstr = 0xE1200070 | ((tinstr & 0xf0) << 4) | (tinstr & 0xf);
break;
}
default:
valid = t_undefined;
break;
}
break;
case 24:
case 25:
*ainstr = ((tinstr & (1 << 11))
? 0xE8B00000
: 0xE8A00000)
| ((tinstr & 0x0700) << (16 - 8))
| (tinstr & 0x00FF);
break;
case 26:
case 27:
if ((tinstr & 0x0F00) == 0x0F00)
{
*ainstr = 0xEF000000;
if ((tinstr & 0x00FF) == 0x18)
*ainstr |= ((tinstr & 0x00FF) << 16);
else if ((tinstr & 0x00FF) == 0xFE)
*ainstr |= SWI_Breakpoint;
else
*ainstr |= (tinstr & 0x00FF);
}
else if ((tinstr & 0x0F00) != 0x0E00)
{
int doit = FALSE;
switch ((tinstr & 0x0F00) >> 8)
{
case EQ:
doit = ZFLAG;
break;
case NE:
doit = !ZFLAG;
break;
case VS:
doit = VFLAG;
break;
case VC:
doit = !VFLAG;
break;
case MI:
doit = NFLAG;
break;
case PL:
doit = !NFLAG;
break;
case CS:
doit = CFLAG;
break;
case CC:
doit = !CFLAG;
break;
case HI:
doit = (CFLAG && !ZFLAG);
break;
case LS:
doit = (!CFLAG || ZFLAG);
break;
case GE:
doit = ((!NFLAG && !VFLAG) || (NFLAG && VFLAG));
break;
case LT:
doit = ((NFLAG && !VFLAG) || (!NFLAG && VFLAG));
break;
case GT:
doit = ((!NFLAG && !VFLAG && !ZFLAG)
|| (NFLAG && VFLAG && !ZFLAG));
break;
case LE:
doit = ((NFLAG && !VFLAG) || (!NFLAG && VFLAG)) || ZFLAG;
break;
}
if (doit)
{
state->Reg[15] = (pc + 4
+ (((tinstr & 0x7F) << 1)
| ((tinstr & (1 << 7)) ? 0xFFFFFF00 : 0)));
FLUSHPIPE;
}
valid = t_branch;
}
else
valid = t_undefined;
break;
case 28:
state->Reg[15] = (pc + 4
+ (((tinstr & 0x3FF) << 1)
| ((tinstr & (1 << 10)) ? 0xFFFFF800 : 0)));
FLUSHPIPE;
valid = t_branch;
break;
case 29:
if (state->is_v5)
{
if (tinstr & 1)
{
valid = t_undefined;
break;
}
{
ARMword tmp = (pc + 2);
state->Reg[15] = ((state->Reg[14] + ((tinstr & 0x07FF) << 1))
& 0xFFFFFFFC);
CLEART;
state->Reg[14] = (tmp | 1);
valid = t_branch;
FLUSHPIPE;
break;
}
}
valid = t_undefined;
break;
case 30:
state->Reg[14] = state->Reg[15] \
+ (((tinstr & 0x07FF) << 12) \
| ((tinstr & (1 << 10)) ? 0xFF800000 : 0));
valid = t_branch;
tinstr = next_instr;
pc += 2;
if (((tinstr & 0xF800) >> 11) != 31)
{
if (((tinstr & 0xF800) >> 11) == 29)
{
ARMword tmp = (pc + 2);
state->Reg[15] = ((state->Reg[14]
+ ((tinstr & 0x07FE) << 1))
& 0xFFFFFFFC);
CLEART;
state->Reg[14] = (tmp | 1);
valid = t_branch;
FLUSHPIPE;
}
else
pc -= 2;
break;
}
pc += 2;
case 31:
{
ARMword tmp = pc;
state->Reg[15] = (state->Reg[14] + ((tinstr & 0x07FF) << 1));
state->Reg[14] = (tmp | 1);
valid = t_branch;
FLUSHPIPE;
}
break;
}
return valid;
}