📄 thumbemu.c
字号:
/* thumbemu.c -- Thumb instruction emulation. Copyright (C) 1996, Cygnus Software Technologies Ltd. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *//* We can provide simple Thumb simulation by decoding the Thumbinstruction into its corresponding ARM instruction, and using theexisting ARM simulator. */#ifndef MODET /* required for the Thumb instruction support */#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"/* 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 valid = t_decoded; /* default assumes a valid instruction */ ARMword next_instr; if (state->bigendSig) { next_instr = tinstr & 0xFFFF; tinstr >>= 16; } else { next_instr = tinstr >> 16; tinstr &= 0xFFFF; }#if 1 /* debugging to catch non updates */ *ainstr = 0xDEADC0DE;#endif switch ((tinstr & 0xF800) >> 11) { case 0: /* LSL */ case 1: /* LSR */ case 2: /* ASR */ /* Format 1 */ *ainstr = 0xE1B00000 /* base opcode */ | ((tinstr & 0x1800) >> (11 - 5)) /* shift type */ | ((tinstr & 0x07C0) << (7 - 6)) /* imm5 */ | ((tinstr & 0x0038) >> 3) /* Rs */ | ((tinstr & 0x0007) << 12); /* Rd */ break; case 3: /* ADD/SUB */ /* Format 2 */ { ARMword subset[4] = { 0xE0900000, /* ADDS Rd,Rs,Rn */ 0xE0500000, /* SUBS Rd,Rs,Rn */ 0xE2900000, /* ADDS Rd,Rs,#imm3 */ 0xE2500000 /* SUBS Rd,Rs,#imm3 */ }; /* It is quicker indexing into a table, than performing switch or conditionals: */ *ainstr = subset[(tinstr & 0x0600) >> 9] /* base opcode */ | ((tinstr & 0x01C0) >> 6) /* Rn or imm3 */ | ((tinstr & 0x0038) << (16 - 3)) /* Rs */ | ((tinstr & 0x0007) << (12 - 0)); /* Rd */ } break; case 4: /* MOV */ case 5: /* CMP */ case 6: /* ADD */ case 7: /* SUB */ /* Format 3 */ { ARMword subset[4] = { 0xE3B00000, /* MOVS Rd,#imm8 */ 0xE3500000, /* CMP Rd,#imm8 */ 0xE2900000, /* ADDS Rd,Rd,#imm8 */ 0xE2500000, /* SUBS Rd,Rd,#imm8 */ }; *ainstr = subset[(tinstr & 0x1800) >> 11] /* base opcode */ | ((tinstr & 0x00FF) >> 0) /* imm8 */ | ((tinstr & 0x0700) << (16 - 8)) /* Rn */ | ((tinstr & 0x0700) << (12 - 8)); /* Rd */ } break; case 8: /* Arithmetic and high register transfers */ /* TODO: Since the subsets for both Format 4 and Format 5 instructions are made up of different ARM encodings, we could save the following conditional, and just have one large subset. */ if ((tinstr & (1 << 10)) == 0) { /* Format 4 */ struct { ARMword opcode; enum { t_norm, t_shift, t_neg, t_mul } otype; } subset[16] = { { 0xE0100000, t_norm}, /* ANDS Rd,Rd,Rs */ { 0xE0300000, t_norm}, /* EORS Rd,Rd,Rs */ { 0xE1B00010, t_shift}, /* MOVS Rd,Rd,LSL Rs */ { 0xE1B00030, t_shift}, /* MOVS Rd,Rd,LSR Rs */ { 0xE1B00050, t_shift}, /* MOVS Rd,Rd,ASR Rs */ { 0xE0B00000, t_norm}, /* ADCS Rd,Rd,Rs */ { 0xE0D00000, t_norm}, /* SBCS Rd,Rd,Rs */ { 0xE1B00070, t_shift}, /* MOVS Rd,Rd,ROR Rs */ { 0xE1100000, t_norm}, /* TST Rd,Rs */ { 0xE2700000, t_neg}, /* RSBS Rd,Rs,#0 */ { 0xE1500000, t_norm}, /* CMP Rd,Rs */ { 0xE1700000, t_norm}, /* CMN Rd,Rs */ { 0xE1900000, t_norm}, /* ORRS Rd,Rd,Rs */ { 0xE0100090, t_mul} , /* MULS Rd,Rd,Rs */ { 0xE1D00000, t_norm}, /* BICS Rd,Rd,Rs */ { 0xE1F00000, t_norm} /* MVNS Rd,Rs */ }; *ainstr = subset[(tinstr & 0x03C0) >> 6].opcode; /* base */ switch (subset[(tinstr & 0x03C0) >> 6].otype) { case t_norm: *ainstr |= ((tinstr & 0x0007) << 16) /* Rn */ | ((tinstr & 0x0007) << 12) /* Rd */ | ((tinstr & 0x0038) >> 3); /* Rs */ break; case t_shift: *ainstr |= ((tinstr & 0x0007) << 12) /* Rd */ | ((tinstr & 0x0007) >> 0) /* Rm */ | ((tinstr & 0x0038) << (8 - 3)); /* Rs */ break; case t_neg: *ainstr |= ((tinstr & 0x0007) << 12) /* Rd */ | ((tinstr & 0x0038) << (16 - 3)); /* Rn */ break; case t_mul: *ainstr |= ((tinstr & 0x0007) << 16) /* Rd */ | ((tinstr & 0x0007) << 8) /* Rs */ | ((tinstr & 0x0038) >> 3); /* Rm */ break; } } else { /* Format 5 */ 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: /* ADD Rd,Rd,Hs */ case 0x2: /* ADD Hd,Hd,Rs */ case 0x3: /* ADD Hd,Hd,Hs */ *ainstr = 0xE0800000 /* base */ | (Rd << 16) /* Rn */ | (Rd << 12) /* Rd */ | (Rs << 0); /* Rm */ break; case 0x5: /* CMP Rd,Hs */ case 0x6: /* CMP Hd,Rs */ case 0x7: /* CMP Hd,Hs */ *ainstr = 0xE1500000 /* base */ | (Rd << 16) /* Rn */ | (Rd << 12) /* Rd */ | (Rs << 0); /* Rm */ break; case 0x9: /* MOV Rd,Hs */ case 0xA: /* MOV Hd,Rs */ case 0xB: /* MOV Hd,Hs */ *ainstr = 0xE1A00000 /* base */ | (Rd << 16) /* Rn */ | (Rd << 12) /* Rd */ | (Rs << 0); /* Rm */ break; case 0xC: /* BX Rs */ case 0xD: /* BX Hs */ *ainstr = 0xE12FFF10 /* base */ | ((tinstr & 0x0078) >> 3); /* Rd */ break; case 0xE: /* UNDEFINED */ case 0xF: /* UNDEFINED */ if (state->is_v5) { /* BLX Rs; BLX Hs */ *ainstr = 0xE12FFF30 /* base */ | ((tinstr & 0x0078) >> 3); /* Rd */ break; } /* Drop through. */ case 0x0: /* UNDEFINED */ case 0x4: /* UNDEFINED */ case 0x8: /* UNDEFINED */ valid = t_undefined; break; } } break; case 9: /* LDR Rd,[PC,#imm8] */ /* Format 6 */ *ainstr = 0xE59F0000 /* base */ | ((tinstr & 0x0700) << (12 - 8)) /* Rd */ | ((tinstr & 0x00FF) << (2 - 0)); /* off8 */ break; case 10: case 11: /* TODO: Format 7 and Format 8 perform the same ARM encoding, so the following could be merged into a single subset, saving on the following boolean: */ if ((tinstr & (1 << 9)) == 0) { /* Format 7 */ ARMword subset[4] = { 0xE7800000, /* STR Rd,[Rb,Ro] */ 0xE7C00000, /* STRB Rd,[Rb,Ro] */ 0xE7900000, /* LDR Rd,[Rb,Ro] */ 0xE7D00000 /* LDRB Rd,[Rb,Ro] */ }; *ainstr = subset[(tinstr & 0x0C00) >> 10] /* base */ | ((tinstr & 0x0007) << (12 - 0)) /* Rd */ | ((tinstr & 0x0038) << (16 - 3)) /* Rb */ | ((tinstr & 0x01C0) >> 6); /* Ro */ } else { /* Format 8 */ ARMword subset[4] = { 0xE18000B0, /* STRH Rd,[Rb,Ro] */ 0xE19000D0, /* LDRSB Rd,[Rb,Ro] */ 0xE19000B0, /* LDRH Rd,[Rb,Ro] */ 0xE19000F0 /* LDRSH Rd,[Rb,Ro] */ }; *ainstr = subset[(tinstr & 0x0C00) >> 10] /* base */ | ((tinstr & 0x0007) << (12 - 0)) /* Rd */ | ((tinstr & 0x0038) << (16 - 3)) /* Rb */ | ((tinstr & 0x01C0) >> 6); /* Ro */ } break; case 12: /* STR Rd,[Rb,#imm5] */ case 13: /* LDR Rd,[Rb,#imm5] */ case 14: /* STRB Rd,[Rb,#imm5] */ case 15: /* LDRB Rd,[Rb,#imm5] */ /* Format 9 */ { ARMword subset[4] = { 0xE5800000, /* STR Rd,[Rb,#imm5] */ 0xE5900000, /* LDR Rd,[Rb,#imm5] */ 0xE5C00000, /* STRB Rd,[Rb,#imm5] */ 0xE5D00000 /* LDRB Rd,[Rb,#imm5] */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -