X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=sim%2Farm%2Fthumbemu.c;h=72929c76b524803eadb49493f3875d4b1404218a;hb=87f83f20023bf366c14ec4e0fd307948d96caaee;hp=e4c91f6c30ee8f29f7b8313687d3c677006031d8;hpb=8d052926671eb0e8c83ffab6d15a98790c215a36;p=deliverable%2Fbinutils-gdb.git diff --git a/sim/arm/thumbemu.c b/sim/arm/thumbemu.c index e4c91f6c30..72929c76b5 100644 --- a/sim/arm/thumbemu.c +++ b/sim/arm/thumbemu.c @@ -30,12 +30,1788 @@ existing ARM simulator. */ #include "armemu.h" #include "armos.h" +#define tBIT(n) ( (ARMword)(tinstr >> (n)) & 1) +#define tBITS(m,n) ( (ARMword)(tinstr << (31 - (n))) >> ((31 - (n)) + (m)) ) + +#define ntBIT(n) ( (ARMword)(next_instr >> (n)) & 1) +#define ntBITS(m,n) ( (ARMword)(next_instr << (31 - (n))) >> ((31 - (n)) + (m)) ) + +static int +test_cond (int cond, ARMul_State * state) +{ + switch (cond) + { + case EQ: return ZFLAG; + case NE: return !ZFLAG; + case VS: return VFLAG; + case VC: return !VFLAG; + case MI: return NFLAG; + case PL: return !NFLAG; + case CS: return CFLAG; + case CC: return !CFLAG; + case HI: return (CFLAG && !ZFLAG); + case LS: return (!CFLAG || ZFLAG); + case GE: return ((!NFLAG && !VFLAG) || (NFLAG && VFLAG)); + case LT: return ((NFLAG && !VFLAG) || (!NFLAG && VFLAG)); + case GT: return ((!NFLAG && !VFLAG && !ZFLAG) + || (NFLAG && VFLAG && !ZFLAG)); + case LE: return ((NFLAG && !VFLAG) || (!NFLAG && VFLAG)) || ZFLAG; + case AL: return TRUE; + case NV: + default: return FALSE; + } +} + +static ARMword skipping_32bit_thumb = 0; + +static int IT_block_cond = AL; +static ARMword IT_block_mask = 0; +static int IT_block_first = FALSE; + +static void +handle_IT_block (ARMul_State * state, + ARMword tinstr, + tdstate * pvalid) +{ + * pvalid = t_branch; + IT_block_mask = tBITS (0, 3); + + if (IT_block_mask == 0) + // NOP or a HINT. + return; + + IT_block_cond = tBITS (4, 7); + IT_block_first = TRUE; +} + +static int +in_IT_block (void) +{ + return IT_block_mask != 0; +} + +static int +IT_block_allow (ARMul_State * state) +{ + int cond; + + if (IT_block_mask == 0) + return TRUE; + + cond = IT_block_cond; + + if (IT_block_first) + IT_block_first = FALSE; + else + { + if ((IT_block_mask & 8) == 0) + cond &= 0xe; + else + cond |= 1; + IT_block_mask <<= 1; + IT_block_mask &= 0xF; + } + + if (IT_block_mask == 0x8) + IT_block_mask = 0; + + return test_cond (cond, state); +} + +static ARMword +ThumbExpandImm (ARMword tinstr) +{ + ARMword val; + + if (tBITS (10, 11) == 0) + { + switch (tBITS (8, 9)) + { + case 0: val = tBITS (0, 7); break; + case 1: val = tBITS (0, 7) << 8; break; + case 2: val = (tBITS (0, 7) << 8) | (tBITS (0, 7) << 24); break; + case 3: val = tBITS (0, 7) * 0x01010101; break; + default: val = 0; + } + } + else + { + int ror = tBITS (7, 11); + + val = (1 << 7) | tBITS (0, 6); + val = (val >> ror) | (val << (32 - ror)); + } + + return val; +} + +#define tASSERT(truth) \ + do \ + { \ + if (! (truth)) \ + { \ + fprintf (stderr, "unhandled T2 insn %04x|%04x detected at thumbemu.c:%d\n", \ + tinstr, next_instr, __LINE__); \ + return ; \ + } \ + } \ + while (0) + + +/* Attempt to emulate a 32-bit ARMv7 Thumb instruction. + Stores t_branch into PVALUE upon success or t_undefined otherwise. */ + +static void +handle_T2_insn (ARMul_State * state, + ARMword tinstr, + ARMword next_instr, + ARMword pc, + ARMword * ainstr, + tdstate * pvalid) +{ + * pvalid = t_undefined; + + if (! state->is_v6) + return; + + if (trace) + fprintf (stderr, "|%04x ", next_instr); + + if (tBITS (11, 15) == 0x1E && ntBIT (15) == 1) + { + ARMsword simm32 = 0; + int S = tBIT (10); + + * pvalid = t_branch; + switch ((ntBIT (14) << 1) | ntBIT (12)) + { + case 0: /* B.W */ + { + ARMword cond = tBITS (6, 9); + ARMword imm6; + ARMword imm11; + ARMword J1; + ARMword J2; + + tASSERT (cond != AL && cond != NV); + if (! test_cond (cond, state)) + return; + + imm6 = tBITS (0, 5); + imm11 = ntBITS (0, 10); + J1 = ntBIT (13); + J2 = ntBIT (11); + + simm32 = (J1 << 19) | (J2 << 18) | (imm6 << 12) | (imm11 << 1); + if (S) + simm32 |= -(1 << 20); + break; + } + + case 1: /* B.W */ + { + ARMword imm10 = tBITS (0, 9); + ARMword imm11 = ntBITS (0, 10); + ARMword I1 = (ntBIT (13) ^ S) ? 0 : 1; + ARMword I2 = (ntBIT (11) ^ S) ? 0 : 1; + + simm32 = (I1 << 23) | (I2 << 22) | (imm10 << 12) | (imm11 << 1); + if (S) + simm32 |= -(1 << 24); + break; + } + + case 2: /* BLX