diff options
Diffstat (limited to 'sim')
-rw-r--r-- | sim/arm/ChangeLog | 6 | ||||
-rw-r--r-- | sim/arm/thumbemu.c | 87 |
2 files changed, 78 insertions, 15 deletions
diff --git a/sim/arm/ChangeLog b/sim/arm/ChangeLog index 1402584..e791416 100644 --- a/sim/arm/ChangeLog +++ b/sim/arm/ChangeLog @@ -1,3 +1,9 @@ +2005-05-24 Nick Clifton <nickc@redhat.com> + + * thumbemu.c (handle_v6_thumb_insn): New function. + (ARMul_ThumbDecode): Call handle_v6_thumb_insn() when an undefined + instruction binary is encountered. + 2005-05-12 Nick Clifton <nickc@redhat.com> * Update the address and phone number of the FSF organization in diff --git a/sim/arm/thumbemu.c b/sim/arm/thumbemu.c index 0aa0f61..8707ca7 100644 --- a/sim/arm/thumbemu.c +++ b/sim/arm/thumbemu.c @@ -31,20 +31,74 @@ existing ARM simulator. */ #include "armemu.h" #include "armos.h" +/* Attempt to emulate an ARMv6 instruction. + Stores t_branch into PVALUE upon success or t_undefined otherwise. */ + +static void +handle_v6_thumb_insn (ARMul_State * state, + ARMword tinstr, + tdstate * pvalid) +{ + ARMword Rd; + ARMword Rm; + + if (! state->is_v6) + { + * pvalid = t_undefined; + return; + } + + switch (tinstr & 0xFFC0) + { + case 0xb660: /* cpsie */ + case 0xb670: /* cpsid */ + case 0x4600: /* cpy */ + case 0xba00: /* rev */ + case 0xba40: /* rev16 */ + case 0xbac0: /* revsh */ + case 0xb650: /* setend */ + default: + printf ("Unhandled v6 thumb insn: %04x\n", tinstr); + * pvalid = t_undefined; + return; + + case 0xb200: /* sxth */ + Rm = state->Reg [(tinstr & 0x38) >> 3]; + if (Rm & 0x8000) + state->Reg [(tinstr & 0x7)] = (Rm & 0xffff) | 0xffff0000; + else + state->Reg [(tinstr & 0x7)] = Rm & 0xffff; + break; + case 0xb240: /* sxtb */ + Rm = state->Reg [(tinstr & 0x38) >> 3]; + if (Rm & 0x80) + state->Reg [(tinstr & 0x7)] = (Rm & 0xff) | 0xffffff00; + else + state->Reg [(tinstr & 0x7)] = Rm & 0xff; + break; + case 0xb280: /* uxth */ + Rm = state->Reg [(tinstr & 0x38) >> 3]; + state->Reg [(tinstr & 0x7)] = Rm & 0xffff; + break; + case 0xb2c0: /* uxtb */ + Rm = state->Reg [(tinstr & 0x38) >> 3]; + state->Reg [(tinstr & 0x7)] = Rm & 0xff; + break; + } + /* Indicate that the instruction has been processed. */ + * pvalid = t_branch; +} + /* Decode a 16bit Thumb instruction. The instruction is in the low 16-bits of the tinstr field, with the following Thumb instruction held in the high 16-bits. Passing in two Thumb instructions allows easier simulation of the special dual BL instruction. */ -tdstate ARMul_ThumbDecode (state, pc, tinstr, ainstr) - ARMul_State * - state; - ARMword - pc; - ARMword - tinstr; - ARMword * - ainstr; +tdstate +ARMul_ThumbDecode (ARMul_State * state, + ARMword pc, + ARMword tinstr, + ARMword * ainstr) { tdstate valid = t_decoded; /* default assumes a valid instruction */ ARMword next_instr; @@ -222,7 +276,7 @@ tdstate ARMul_ThumbDecode (state, pc, tinstr, ainstr) case 0x0: /* UNDEFINED */ case 0x4: /* UNDEFINED */ case 0x8: /* UNDEFINED */ - valid = t_undefined; + handle_v6_thumb_insn (state, tinstr, & valid); break; } } @@ -370,7 +424,7 @@ tdstate ARMul_ThumbDecode (state, pc, tinstr, ainstr) /* Drop through. */ default: /* Everything else is an undefined instruction. */ - valid = t_undefined; + handle_v6_thumb_insn (state, tinstr, & valid); break; } break; @@ -460,8 +514,9 @@ tdstate ARMul_ThumbDecode (state, pc, tinstr, ainstr) } valid = t_branch; } - else /* UNDEFINED : cc=1110(AL) uses different format */ - valid = t_undefined; + else + /* UNDEFINED : cc=1110(AL) uses different format. */ + handle_v6_thumb_insn (state, tinstr, & valid); break; case 28: /* B */ /* Format 18 */ @@ -476,7 +531,7 @@ tdstate ARMul_ThumbDecode (state, pc, tinstr, ainstr) { if (tinstr & 1) { - valid = t_undefined; + handle_v6_thumb_insn (state, tinstr, & valid); break; } /* Drop through. */ @@ -499,8 +554,10 @@ tdstate ARMul_ThumbDecode (state, pc, tinstr, ainstr) break; } } - valid = t_undefined; + + handle_v6_thumb_insn (state, tinstr, & valid); break; + case 30: /* BL instruction 1 */ /* Format 19 */ /* There is no single ARM instruction equivalent for this Thumb |