2 Thumb Dissassembler. Still a work in progress.
4 Wrong output is a bug, so please fix it.
5 Hex output means there is not yet an entry or a decode bug.
6 gOpThumb[] are Thumb 16-bit, and gOpThumb2[] work on the 32-bit
7 16-bit stream of Thumb2 instruction. Then there are big case
8 statements to print everything out. If you are adding instructions
9 try to reuse existing case entries if possible.
11 Copyright (c) 2008 - 2010, Apple Inc. All rights reserved.<BR>
13 This program and the accompanying materials
14 are licensed and made available under the terms and conditions of the BSD License
15 which accompanies this distribution. The full text of the license may be found at
16 http://opensource.org/licenses/bsd-license.php
18 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
19 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
24 #include <Library/BaseLib.h>
25 #include <Library/DebugLib.h>
26 #include <Library/PrintLib.h>
28 extern CHAR8
*gCondition
[];
32 // Thumb address modes
33 #define LOAD_STORE_FORMAT1 1
34 #define LOAD_STORE_FORMAT1_H 101
35 #define LOAD_STORE_FORMAT1_B 111
36 #define LOAD_STORE_FORMAT2 2
37 #define LOAD_STORE_FORMAT3 3
38 #define LOAD_STORE_FORMAT4 4
39 #define LOAD_STORE_MULTIPLE_FORMAT1 5
41 #define POP_FORMAT 106
43 #define CONDITIONAL_BRANCH 8
44 #define UNCONDITIONAL_BRANCH 9
45 #define UNCONDITIONAL_BRANCH_SHORT 109
46 #define BRANCH_EXCHANGE 10
47 #define DATA_FORMAT1 11
48 #define DATA_FORMAT2 12
49 #define DATA_FORMAT3 13
50 #define DATA_FORMAT4 14
51 #define DATA_FORMAT5 15
52 #define DATA_FORMAT6_SP 16
53 #define DATA_FORMAT6_PC 116
54 #define DATA_FORMAT7 17
55 #define DATA_FORMAT8 19
57 #define ENDIAN_FORMAT 21
62 // Thumb2 address modes
68 #define STM_FORMAT 205
69 #define LDM_REG_IMM12_SIGNED 206
70 #define LDM_REG_IMM12_LSL 207
71 #define LDM_REG_IMM8 208
72 #define LDM_REG_IMM12 209
73 #define LDM_REG_INDIRECT_LSL 210
74 #define LDM_REG_IMM8_SIGNED 211
75 #define LDRD_REG_IMM8 212
78 #define SRS_FORMAT 215
79 #define RFE_FORMAT 216
80 #define LDRD_REG_IMM8_SIGNED 217
83 #define ADR_THUMB2 220
84 #define CMN_THUMB2 221
87 #define BFC_THUMB2 224
88 #define CDP_THUMB2 225
89 #define THUMB2_NO_ARGS 226
90 #define THUMB2_2REGS 227
91 #define ADD_IMM5_2REG 228
92 #define CPD_THUMB2 229
93 #define THUMB2_4REGS 230
94 #define ADD_IMM12_1REG 231
95 #define THUMB2_IMM16 232
96 #define MRC_THUMB2 233
97 #define MRRC_THUMB2 234
98 #define THUMB2_MRS 235
99 #define THUMB2_MSR 236
109 } THUMB_INSTRUCTIONS
;
111 THUMB_INSTRUCTIONS gOpThumb
[] = {
112 // Thumb 16-bit instrucitons
114 { "ADC" , 0x4140, 0xffc0, DATA_FORMAT5
}, // ADC <Rndn>, <Rm>
115 { "ADR", 0xa000, 0xf800, ADR_FORMAT
}, // ADR <Rd>, <label>
116 { "ADD" , 0x1c00, 0xfe00, DATA_FORMAT2
},
117 { "ADD" , 0x3000, 0xf800, DATA_FORMAT3
},
118 { "ADD" , 0x1800, 0xfe00, DATA_FORMAT1
},
119 { "ADD" , 0x4400, 0xff00, DATA_FORMAT8
}, // A8.6.9
120 { "ADD" , 0xa000, 0xf100, DATA_FORMAT6_PC
},
121 { "ADD" , 0xa800, 0xf800, DATA_FORMAT6_SP
},
122 { "ADD" , 0xb000, 0xff80, DATA_FORMAT7
},
124 { "AND" , 0x4000, 0xffc0, DATA_FORMAT5
},
126 { "ASR" , 0x1000, 0xf800, DATA_FORMAT4
},
127 { "ASR" , 0x4100, 0xffc0, DATA_FORMAT5
},
129 { "B" , 0xd000, 0xf000, CONDITIONAL_BRANCH
},
130 { "B" , 0xe000, 0xf800, UNCONDITIONAL_BRANCH_SHORT
},
131 { "BLX" , 0x4780, 0xff80, BRANCH_EXCHANGE
},
132 { "BX" , 0x4700, 0xff87, BRANCH_EXCHANGE
},
134 { "BIC" , 0x4380, 0xffc0, DATA_FORMAT5
},
135 { "BKPT", 0xdf00, 0xff00, IMMED_8
},
136 { "CBZ", 0xb100, 0xfd00, DATA_CBZ
},
137 { "CBNZ", 0xb900, 0xfd00, DATA_CBZ
},
138 { "CMN" , 0x42c0, 0xffc0, DATA_FORMAT5
},
140 { "CMP" , 0x2800, 0xf800, DATA_FORMAT3
},
141 { "CMP" , 0x4280, 0xffc0, DATA_FORMAT5
},
142 { "CMP" , 0x4500, 0xff00, DATA_FORMAT8
},
144 { "CPS" , 0xb660, 0xffe8, CPS_FORMAT
},
145 { "MOV" , 0x4600, 0xff00, DATA_FORMAT8
},
146 { "EOR" , 0x4040, 0xffc0, DATA_FORMAT5
},
148 { "LDMIA" , 0xc800, 0xf800, LOAD_STORE_MULTIPLE_FORMAT1
},
149 { "LDR" , 0x6800, 0xf800, LOAD_STORE_FORMAT1
}, // LDR <Rt>, [<Rn> {,#<imm>}]
150 { "LDR" , 0x5800, 0xfe00, LOAD_STORE_FORMAT2
}, // STR <Rt>, [<Rn>, <Rm>]
151 { "LDR" , 0x4800, 0xf800, LOAD_STORE_FORMAT3
},
152 { "LDR" , 0x9800, 0xf800, LOAD_STORE_FORMAT4
}, // LDR <Rt>, [SP, #<imm>]
153 { "LDRB" , 0x7800, 0xf800, LOAD_STORE_FORMAT1_B
},
154 { "LDRB" , 0x5c00, 0xfe00, LOAD_STORE_FORMAT2
}, // STR <Rt>, [<Rn>, <Rm>]
155 { "LDRH" , 0x8800, 0xf800, LOAD_STORE_FORMAT1_H
},
156 { "LDRH" , 0x7a00, 0xfe00, LOAD_STORE_FORMAT2
},
157 { "LDRSB" , 0x5600, 0xfe00, LOAD_STORE_FORMAT2
}, // STR <Rt>, [<Rn>, <Rm>]
158 { "LDRSH" , 0x5e00, 0xfe00, LOAD_STORE_FORMAT2
},
160 { "MOVS", 0x0000, 0xffc0, DATA_FORMAT5
}, // LSL with imm5 == 0 is a MOVS, so this must go before LSL
161 { "LSL" , 0x0000, 0xf800, DATA_FORMAT4
},
162 { "LSL" , 0x4080, 0xffc0, DATA_FORMAT5
},
163 { "LSR" , 0x0001, 0xf800, DATA_FORMAT4
},
164 { "LSR" , 0x40c0, 0xffc0, DATA_FORMAT5
},
165 { "LSRS", 0x0800, 0xf800, DATA_FORMAT4
}, // LSRS <Rd>, <Rm>, #<imm5>
167 { "MOVS", 0x2000, 0xf800, DATA_FORMAT3
},
168 { "MOV" , 0x1c00, 0xffc0, DATA_FORMAT3
},
169 { "MOV" , 0x4600, 0xff00, DATA_FORMAT8
},
171 { "MUL" , 0x4340, 0xffc0, DATA_FORMAT5
},
172 { "MVN" , 0x41c0, 0xffc0, DATA_FORMAT5
},
173 { "NEG" , 0x4240, 0xffc0, DATA_FORMAT5
},
174 { "ORR" , 0x4300, 0xffc0, DATA_FORMAT5
},
175 { "POP" , 0xbc00, 0xfe00, POP_FORMAT
},
176 { "PUSH", 0xb400, 0xfe00, PUSH_FORMAT
},
178 { "REV" , 0xba00, 0xffc0, DATA_FORMAT5
},
179 { "REV16" , 0xba40, 0xffc0, DATA_FORMAT5
},
180 { "REVSH" , 0xbac0, 0xffc0, DATA_FORMAT5
},
182 { "ROR" , 0x41c0, 0xffc0, DATA_FORMAT5
},
183 { "SBC" , 0x4180, 0xffc0, DATA_FORMAT5
},
184 { "SETEND" , 0xb650, 0xfff0, ENDIAN_FORMAT
},
186 { "STMIA" , 0xc000, 0xf800, LOAD_STORE_MULTIPLE_FORMAT1
},
187 { "STR" , 0x6000, 0xf800, LOAD_STORE_FORMAT1
}, // STR <Rt>, [<Rn> {,#<imm>}]
188 { "STR" , 0x5000, 0xfe00, LOAD_STORE_FORMAT2
}, // STR <Rt>, [<Rn>, <Rm>]
189 { "STR" , 0x9000, 0xf800, LOAD_STORE_FORMAT4
}, // STR <Rt>, [SP, #<imm>]
190 { "STRB" , 0x7000, 0xf800, LOAD_STORE_FORMAT1_B
}, // STRB <Rt>, [<Rn>, #<imm5>]
191 { "STRB" , 0x5400, 0xfe00, LOAD_STORE_FORMAT2
}, // STRB <Rt>, [<Rn>, <Rm>]
192 { "STRH" , 0x8000, 0xf800, LOAD_STORE_FORMAT1_H
}, // STRH <Rt>, [<Rn>{,#<imm>}]
193 { "STRH" , 0x5200, 0xfe00, LOAD_STORE_FORMAT2
}, // STRH <Rt>, [<Rn>, <Rm>]
195 { "SUB" , 0x1e00, 0xfe00, DATA_FORMAT2
},
196 { "SUB" , 0x3800, 0xf800, DATA_FORMAT3
},
197 { "SUB" , 0x1a00, 0xfe00, DATA_FORMAT1
},
198 { "SUB" , 0xb080, 0xff80, DATA_FORMAT7
},
200 { "SBC" , 0x4180, 0xffc0, DATA_FORMAT5
},
202 { "SWI" , 0xdf00, 0xff00, IMMED_8
},
203 { "SXTB", 0xb240, 0xffc0, DATA_FORMAT5
},
204 { "SXTH", 0xb200, 0xffc0, DATA_FORMAT5
},
205 { "TST" , 0x4200, 0xffc0, DATA_FORMAT5
},
206 { "UXTB", 0xb2c0, 0xffc0, DATA_FORMAT5
},
207 { "UXTH", 0xb280, 0xffc0, DATA_FORMAT5
},
209 { "IT", 0xbf00, 0xff00, IT_BLOCK
}
213 THUMB_INSTRUCTIONS gOpThumb2
[] = {
214 //Instruct OpCode OpCode Mask Addressig Mode
216 { "ADR", 0xf2af0000, 0xfbff8000, ADR_THUMB2
}, // ADDR <Rd>, <label> ;Needs to go before ADDW
217 { "CMN", 0xf1100f00, 0xfff08f00, CMN_THUMB2
}, // CMN <Rn>, #<const> ;Needs to go before ADD
218 { "CMN", 0xeb100f00, 0xfff08f00, ADD_IMM5_2REG
}, // CMN <Rn>, <Rm> {,<shift> #<const>}
219 { "CMP", 0xf1a00f00, 0xfff08f00, CMN_THUMB2
}, // CMP <Rn>, #<const>
220 { "TEQ", 0xf0900f00, 0xfff08f00, CMN_THUMB2
}, // CMP <Rn>, #<const>
221 { "TEQ", 0xea900f00, 0xfff08f00, ADD_IMM5_2REG
}, // CMN <Rn>, <Rm> {,<shift> #<const>}
222 { "TST", 0xf0100f00, 0xfff08f00, CMN_THUMB2
}, // CMP <Rn>, #<const>
223 { "TST", 0xea100f00, 0xfff08f00, ADD_IMM5_2REG
}, // TST <Rn>, <Rm> {,<shift> #<const>}
225 { "MOV", 0xf04f0000, 0xfbef8000, ADD_IMM12_1REG
}, // MOV <Rd>, #<const>
226 { "MOVW", 0xf2400000, 0xfbe08000, THUMB2_IMM16
}, // MOVW <Rd>, #<const>
227 { "MOVT", 0xf2c00000, 0xfbe08000, THUMB2_IMM16
}, // MOVT <Rd>, #<const>
229 { "ADC", 0xf1400000, 0xfbe08000, ADD_IMM12
}, // ADC{S} <Rd>, <Rn>, #<const>
230 { "ADC", 0xeb400000, 0xffe08000, ADD_IMM5
}, // ADC{S} <Rd>, <Rn>, <Rm> {,<shift> #<const>}
231 { "ADD", 0xf1000000, 0xfbe08000, ADD_IMM12
}, // ADD{S} <Rd>, <Rn>, #<const>
232 { "ADD", 0xeb000000, 0xffe08000, ADD_IMM5
}, // ADD{S} <Rd>, <Rn>, <Rm> {,<shift> #<const>}
233 { "ADDW", 0xf2000000, 0xfbe08000, ADD_IMM12
}, // ADDW{S} <Rd>, <Rn>, #<const>
234 { "AND", 0xf0000000, 0xfbe08000, ADD_IMM12
}, // AND{S} <Rd>, <Rn>, #<const>
235 { "AND", 0xea000000, 0xffe08000, ADD_IMM5
}, // AND{S} <Rd>, <Rn>, <Rm> {,<shift> #<const>}
236 { "BIC", 0xf0200000, 0xfbe08000, ADD_IMM12
}, // BIC{S} <Rd>, <Rn>, #<const>
237 { "BIC", 0xea200000, 0xffe08000, ADD_IMM5
}, // BIC{S} <Rd>, <Rn>, <Rm> {,<shift> #<const>}
238 { "EOR", 0xf0800000, 0xfbe08000, ADD_IMM12
}, // EOR{S} <Rd>, <Rn>, #<const>
239 { "EOR", 0xea800000, 0xffe08000, ADD_IMM5
}, // EOR{S} <Rd>, <Rn>, <Rm> {,<shift> #<const>}
240 { "ORN", 0xf0600000, 0xfbe08000, ADD_IMM12
}, // ORN{S} <Rd>, <Rn>, #<const>
241 { "ORN", 0xea600000, 0xffe08000, ADD_IMM5
}, // ORN{S} <Rd>, <Rn>, <Rm> {,<shift> #<const>}
242 { "ORR", 0xf0400000, 0xfbe08000, ADD_IMM12
}, // ORR{S} <Rd>, <Rn>, #<const>
243 { "ORR", 0xea400000, 0xffe08000, ADD_IMM5
}, // ORR{S} <Rd>, <Rn>, <Rm> {,<shift> #<const>}
244 { "RSB", 0xf1c00000, 0xfbe08000, ADD_IMM12
}, // RSB{S} <Rd>, <Rn>, #<const>
245 { "RSB", 0xebc00000, 0xffe08000, ADD_IMM5
}, // RSB{S} <Rd>, <Rn>, <Rm> {,<shift> #<const>}
246 { "SBC", 0xf1600000, 0xfbe08000, ADD_IMM12
}, // SBC{S} <Rd>, <Rn>, #<const>
247 { "SBC", 0xeb600000, 0xffe08000, ADD_IMM5
}, // SBC{S} <Rd>, <Rn>, <Rm> {,<shift> #<const>}
248 { "SUB", 0xf1a00000, 0xfbe08000, ADD_IMM12
}, // SUB{S} <Rd>, <Rn>, #<const>
249 { "SUB", 0xeba00000, 0xffe08000, ADD_IMM5
}, // SUB{S} <Rd>, <Rn>, <Rm> {,<shift> #<const>}
251 { "ASR", 0xea4f0020, 0xffef8030, ASR_IMM5
}, // ARS <Rd>, <Rm> #<const>} imm3:imm2
252 { "ASR", 0xfa40f000, 0xffe0f0f0, ASR_3REG
}, // ARS <Rd>, <Rn>, <Rm>
253 { "LSR", 0xea4f0010, 0xffef8030, ASR_IMM5
}, // LSR <Rd>, <Rm> #<const>} imm3:imm2
254 { "LSR", 0xfa20f000, 0xffe0f0f0, ASR_3REG
}, // LSR <Rd>, <Rn>, <Rm>
255 { "ROR", 0xea4f0030, 0xffef8030, ASR_IMM5
}, // ROR <Rd>, <Rm> #<const>} imm3:imm2
256 { "ROR", 0xfa60f000, 0xffe0f0f0, ASR_3REG
}, // ROR <Rd>, <Rn>, <Rm>
258 { "BFC", 0xf36f0000, 0xffff8010, BFC_THUMB2
}, // BFC <Rd>, #<lsb>, #<width>
259 { "BIC", 0xf3600000, 0xfff08010, BFC_THUMB2
}, // BIC <Rn>, <Rd>, #<lsb>, #<width>
260 { "SBFX", 0xf3400000, 0xfff08010, BFC_THUMB2
}, // SBFX <Rn>, <Rd>, #<lsb>, #<width>
261 { "UBFX", 0xf3c00000, 0xfff08010, BFC_THUMB2
}, // UBFX <Rn>, <Rd>, #<lsb>, #<width>
263 { "CPD", 0xee000000, 0xff000010, CPD_THUMB2
}, // CPD <coproc>,<opc1>,<CRd>,<CRn>,<CRm>,<opc2>
264 { "CPD2", 0xfe000000, 0xff000010, CPD_THUMB2
}, // CPD <coproc>,<opc1>,<CRd>,<CRn>,<CRm>,<opc2>
266 { "MRC", 0xee100000, 0xff100000, MRC_THUMB2
}, // MRC <coproc>,<opc1>,<Rt>,<CRn>,<CRm>,<opc2>
267 { "MRC2", 0xfe100000, 0xff100000, MRC_THUMB2
}, // MRC2 <coproc>,<opc1>,<Rt>,<CRn>,<CRm>,<opc2>
268 { "MRRC", 0xec500000, 0xfff00000, MRRC_THUMB2
}, // MRRC <coproc>,<opc1>,<Rt>,<Rt2>,<CRm>
269 { "MRRC2", 0xfc500000, 0xfff00000, MRRC_THUMB2
}, // MRR2 <coproc>,<opc1>,<Rt>,<Rt2>,<CRm>
271 { "MRS", 0xf3ef8000, 0xfffff0ff, THUMB2_MRS
}, // MRS <Rd>, CPSR
272 { "MSR", 0xf3808000, 0xfff0fcff, THUMB2_MSR
}, // MSR CPSR_fs, <Rn>
274 { "CLREX", 0xf3bf8f2f, 0xfffffff, THUMB2_NO_ARGS
}, // CLREX
276 { "CLZ", 0xfab0f080, 0xfff0f0f0, THUMB2_2REGS
}, // CLZ <Rd>,<Rm>
277 { "MOV", 0xec4f0000, 0xfff0f0f0, THUMB2_2REGS
}, // MOV <Rd>,<Rm>
278 { "MOVS", 0xec5f0000, 0xfff0f0f0, THUMB2_2REGS
}, // MOVS <Rd>,<Rm>
279 { "RBIT", 0xfb90f0a0, 0xfff0f0f0, THUMB2_2REGS
}, // RBIT <Rd>,<Rm>
280 { "REV", 0xfb90f080, 0xfff0f0f0, THUMB2_2REGS
}, // REV <Rd>,<Rm>
281 { "REV16", 0xfa90f090, 0xfff0f0f0, THUMB2_2REGS
}, // REV16 <Rd>,<Rm>
282 { "REVSH", 0xfa90f0b0, 0xfff0f0f0, THUMB2_2REGS
}, // REVSH <Rd>,<Rm>
283 { "RRX", 0xea4f0030, 0xfffff0f0, THUMB2_2REGS
}, // RRX <Rd>,<Rm>
284 { "RRXS", 0xea5f0030, 0xfffff0f0, THUMB2_2REGS
}, // RRXS <Rd>,<Rm>
286 { "MLA", 0xfb000000, 0xfff000f0, THUMB2_4REGS
}, // MLA <Rd>, <Rn>, <Rm>, <Ra>
287 { "MLS", 0xfb000010, 0xfff000f0, THUMB2_4REGS
}, // MLA <Rd>, <Rn>, <Rm>, <Ra>
290 { "SMLABB", 0xfb100000, 0xfff000f0, THUMB2_4REGS
}, // SMLABB <Rd>, <Rn>, <Rm>, <Ra>
291 { "SMLABT", 0xfb100010, 0xfff000f0, THUMB2_4REGS
}, // SMLABT <Rd>, <Rn>, <Rm>, <Ra>
292 { "SMLABB", 0xfb100020, 0xfff000f0, THUMB2_4REGS
}, // SMLATB <Rd>, <Rn>, <Rm>, <Ra>
293 { "SMLATT", 0xfb100030, 0xfff000f0, THUMB2_4REGS
}, // SMLATT <Rd>, <Rn>, <Rm>, <Ra>
294 { "SMLAWB", 0xfb300000, 0xfff000f0, THUMB2_4REGS
}, // SMLAWB <Rd>, <Rn>, <Rm>, <Ra>
295 { "SMLAWT", 0xfb300010, 0xfff000f0, THUMB2_4REGS
}, // SMLAWT <Rd>, <Rn>, <Rm>, <Ra>
296 { "SMLSD", 0xfb400000, 0xfff000f0, THUMB2_4REGS
}, // SMLSD <Rd>, <Rn>, <Rm>, <Ra>
297 { "SMLSDX", 0xfb400010, 0xfff000f0, THUMB2_4REGS
}, // SMLSDX <Rd>, <Rn>, <Rm>, <Ra>
298 { "SMMLA", 0xfb500000, 0xfff000f0, THUMB2_4REGS
}, // SMMLA <Rd>, <Rn>, <Rm>, <Ra>
299 { "SMMLAR", 0xfb500010, 0xfff000f0, THUMB2_4REGS
}, // SMMLAR <Rd>, <Rn>, <Rm>, <Ra>
300 { "SMMLS", 0xfb600000, 0xfff000f0, THUMB2_4REGS
}, // SMMLS <Rd>, <Rn>, <Rm>, <Ra>
301 { "SMMLSR", 0xfb600010, 0xfff000f0, THUMB2_4REGS
}, // SMMLSR <Rd>, <Rn>, <Rm>, <Ra>
302 { "USADA8", 0xfb700000, 0xfff000f0, THUMB2_4REGS
}, // USADA8 <Rd>, <Rn>, <Rm>, <Ra>
303 { "SMLAD", 0xfb200000, 0xfff000f0, THUMB2_4REGS
}, // SMLAD <Rd>, <Rn>, <Rm>, <Ra>
304 { "SMLADX", 0xfb200010, 0xfff000f0, THUMB2_4REGS
}, // SMLADX <Rd>, <Rn>, <Rm>, <Ra>
307 { "B", 0xf0008000, 0xf800d000, B_T3
}, // B<c> <label>
308 { "B", 0xf0009000, 0xf800d000, B_T4
}, // B<c> <label>
309 { "BL", 0xf000d000, 0xf800d000, B_T4
}, // BL<c> <label>
310 { "BLX", 0xf000c000, 0xf800d000, BL_T2
}, // BLX<c> <label>
312 { "POP", 0xe8bd0000, 0xffff2000, POP_T2
}, // POP <registers>
313 { "POP", 0xf85d0b04, 0xffff0fff, POP_T3
}, // POP <register>
314 { "PUSH", 0xe8ad0000, 0xffffa000, POP_T2
}, // PUSH <registers>
315 { "PUSH", 0xf84d0d04, 0xffff0fff, POP_T3
}, // PUSH <register>
316 { "STM" , 0xe8800000, 0xffd0a000, STM_FORMAT
}, // STM <Rn>{!},<registers>
317 { "STMDB", 0xe9800000, 0xffd0a000, STM_FORMAT
}, // STMDB <Rn>{!},<registers>
318 { "LDM" , 0xe8900000, 0xffd02000, STM_FORMAT
}, // LDM <Rn>{!},<registers>
319 { "LDMDB", 0xe9100000, 0xffd02000, STM_FORMAT
}, // LDMDB <Rn>{!},<registers>
321 { "LDR", 0xf8d00000, 0xfff00000, LDM_REG_IMM12
}, // LDR <rt>, [<rn>, {, #<imm12>]}
322 { "LDRB", 0xf8900000, 0xfff00000, LDM_REG_IMM12
}, // LDRB <rt>, [<rn>, {, #<imm12>]}
323 { "LDRH", 0xf8b00000, 0xfff00000, LDM_REG_IMM12
}, // LDRH <rt>, [<rn>, {, #<imm12>]}
324 { "LDRSB", 0xf9900000, 0xfff00000, LDM_REG_IMM12
}, // LDRSB <rt>, [<rn>, {, #<imm12>]}
325 { "LDRSH", 0xf9b00000, 0xfff00000, LDM_REG_IMM12
}, // LDRSH <rt>, [<rn>, {, #<imm12>]}
327 { "LDR", 0xf85f0000, 0xff7f0000, LDM_REG_IMM12_SIGNED
}, // LDR <Rt>, <label>
328 { "LDRB", 0xf81f0000, 0xff7f0000, LDM_REG_IMM12_SIGNED
}, // LDRB <Rt>, <label>
329 { "LDRH", 0xf83f0000, 0xff7f0000, LDM_REG_IMM12_SIGNED
}, // LDRH <Rt>, <label>
330 { "LDRSB", 0xf91f0000, 0xff7f0000, LDM_REG_IMM12_SIGNED
}, // LDRSB <Rt>, <label>
331 { "LDRSH", 0xf93f0000, 0xff7f0000, LDM_REG_IMM12_SIGNED
}, // LDRSB <Rt>, <label>
333 { "LDR", 0xf8500000, 0xfff00fc0, LDM_REG_INDIRECT_LSL
}, // LDR <rt>, [<rn>, <rm> {, LSL #<imm2>]}
334 { "LDRB", 0xf8100000, 0xfff00fc0, LDM_REG_INDIRECT_LSL
}, // LDRB <rt>, [<rn>, <rm> {, LSL #<imm2>]}
335 { "LDRH", 0xf8300000, 0xfff00fc0, LDM_REG_INDIRECT_LSL
}, // LDRH <rt>, [<rn>, <rm> {, LSL #<imm2>]}
336 { "LDRSB", 0xf9100000, 0xfff00fc0, LDM_REG_INDIRECT_LSL
}, // LDRSB <rt>, [<rn>, <rm> {, LSL #<imm2>]}
337 { "LDRSH", 0xf9300000, 0xfff00fc0, LDM_REG_INDIRECT_LSL
}, // LDRSH <rt>, [<rn>, <rm> {, LSL #<imm2>]}
339 { "LDR", 0xf8500800, 0xfff00800, LDM_REG_IMM8
}, // LDR <rt>, [<rn>, {, #<imm8>]}
340 { "LDRBT", 0xf8100e00, 0xfff00f00, LDM_REG_IMM8
}, // LDRBT <rt>, [<rn>, {, #<imm8>]}
341 { "LDRHT", 0xf8300e00, 0xfff00f00, LDM_REG_IMM8
}, // LDRHT <rt>, [<rn>, {, #<imm8>]}
342 { "LDRSB", 0xf9100800, 0xfff00800, LDM_REG_IMM8
}, // LDRHT <rt>, [<rn>, {, #<imm8>]} {!} form?
343 { "LDRSBT",0xf9100e00, 0xfff00f00, LDM_REG_IMM8
}, // LDRHBT <rt>, [<rn>, {, #<imm8>]} {!} form?
344 { "LDRSH" ,0xf9300800, 0xfff00800, LDM_REG_IMM8
}, // LDRSH <rt>, [<rn>, {, #<imm8>]}
345 { "LDRSHT",0xf9300e00, 0xfff00f00, LDM_REG_IMM8
}, // LDRSHT <rt>, [<rn>, {, #<imm8>]}
346 { "LDRT", 0xf8500e00, 0xfff00f00, LDM_REG_IMM8
}, // LDRT <rt>, [<rn>, {, #<imm8>]}
348 { "LDRD", 0xe8500000, 0xfe500000, LDRD_REG_IMM8_SIGNED
}, // LDRD <rt>, <rt2>, [<rn>, {, #<imm8>]}{!}
349 { "LDRD", 0xe8500000, 0xfe500000, LDRD_REG_IMM8
}, // LDRD <rt>, <rt2>, <label>
351 { "LDREX", 0xe8500f00, 0xfff00f00, LDM_REG_IMM8
}, // LDREX <Rt>, [Rn, {#imm8}]]
352 { "LDREXB", 0xe8d00f4f, 0xfff00fff, LDREXB
}, // LDREXB <Rt>, [<Rn>]
353 { "LDREXH", 0xe8d00f5f, 0xfff00fff, LDREXB
}, // LDREXH <Rt>, [<Rn>]
355 { "LDREXD", 0xe8d00f4f, 0xfff00fff, LDREXD
}, // LDREXD <Rt>, <Rt2>, [<Rn>]
357 { "STR", 0xf8c00000, 0xfff00000, LDM_REG_IMM12
}, // STR <rt>, [<rn>, {, #<imm12>]}
358 { "STRB", 0xf8800000, 0xfff00000, LDM_REG_IMM12
}, // STRB <rt>, [<rn>, {, #<imm12>]}
359 { "STRH", 0xf8a00000, 0xfff00000, LDM_REG_IMM12
}, // STRH <rt>, [<rn>, {, #<imm12>]}
361 { "STR", 0xf8400000, 0xfff00fc0, LDM_REG_INDIRECT_LSL
}, // STR <rt>, [<rn>, <rm> {, LSL #<imm2>]}
362 { "STRB", 0xf8000000, 0xfff00fc0, LDM_REG_INDIRECT_LSL
}, // STRB <rt>, [<rn>, <rm> {, LSL #<imm2>]}
363 { "STRH", 0xf8200000, 0xfff00fc0, LDM_REG_INDIRECT_LSL
}, // STRH <rt>, [<rn>, <rm> {, LSL #<imm2>]}
365 { "STR", 0xf8400800, 0xfff00800, LDM_REG_IMM8
}, // STR <rt>, [<rn>, {, #<imm8>]}
366 { "STRH", 0xf8200800, 0xfff00800, LDM_REG_IMM8
}, // STRH <rt>, [<rn>, {, #<imm8>]}
367 { "STRBT", 0xf8000e00, 0xfff00f00, LDM_REG_IMM8
}, // STRBT <rt>, [<rn>, {, #<imm8>]}
368 { "STRHT", 0xf8200e00, 0xfff00f00, LDM_REG_IMM8
}, // STRHT <rt>, [<rn>, {, #<imm8>]}
369 { "STRT", 0xf8400e00, 0xfff00f00, LDM_REG_IMM8
}, // STRT <rt>, [<rn>, {, #<imm8>]}
371 { "STRD", 0xe8400000, 0xfe500000, LDRD_REG_IMM8_SIGNED
}, // STRD <rt>, <rt2>, [<rn>, {, #<imm8>]}{!}
373 { "STREX", 0xe8400f00, 0xfff00f00, LDM_REG_IMM8
}, // STREX <Rt>, [Rn, {#imm8}]]
374 { "STREXB", 0xe8c00f4f, 0xfff00fff, LDREXB
}, // STREXB <Rd>, <Rt>, [<Rn>]
375 { "STREXH", 0xe8c00f5f, 0xfff00fff, LDREXB
}, // STREXH <Rd>, <Rt>, [<Rn>]
377 { "STREXD", 0xe8d00f4f, 0xfff00fff, LDREXD
}, // STREXD <Rd>, <Rt>, <Rt2>, [<Rn>]
379 { "SRSDB", 0xe80dc000, 0xffdffff0, SRS_FORMAT
}, // SRSDB<c> SP{!},#<mode>
380 { "SRS" , 0xe98dc000, 0xffdffff0, SRS_FORMAT
}, // SRS{IA}<c> SP{!},#<mode>
381 { "RFEDB", 0xe810c000, 0xffd0ffff, RFE_FORMAT
}, // RFEDB<c> <Rn>{!}
382 { "RFE" , 0xe990c000, 0xffd0ffff, RFE_FORMAT
} // RFE{IA}<c> <Rn>{!}
385 CHAR8
*gShiftType
[] = {
392 CHAR8 mThumbMregListStr
[4*15 + 1];
399 UINTN Index
, Start
, End
;
402 mThumbMregListStr
[0] = '\0';
403 AsciiStrCatS (mThumbMregListStr
, sizeof mThumbMregListStr
, "{");
405 for (Index
= 0, First
= TRUE
; Index
<= 15; Index
++) {
406 if ((RegBitMask
& (1 << Index
)) != 0) {
408 for (Index
++; ((RegBitMask
& (1 << Index
)) != 0) && (Index
<= 9); Index
++) {
413 AsciiStrCatS (mThumbMregListStr
, sizeof mThumbMregListStr
, ",");
419 AsciiStrCatS (mThumbMregListStr
, sizeof mThumbMregListStr
, gReg
[Start
]);
421 AsciiStrCatS (mThumbMregListStr
, sizeof mThumbMregListStr
, gReg
[Start
]);
422 AsciiStrCatS (mThumbMregListStr
, sizeof mThumbMregListStr
, "-");
423 AsciiStrCatS (mThumbMregListStr
, sizeof mThumbMregListStr
, gReg
[End
]);
428 AsciiStrCatS (mThumbMregListStr
, sizeof mThumbMregListStr
, "ERROR");
430 AsciiStrCatS (mThumbMregListStr
, sizeof mThumbMregListStr
, "}");
432 // BugBug: Make caller pass in buffer it is cleaner
433 return mThumbMregListStr
;
442 if (((Data
& TopBit
) == 0) || (TopBit
== BIT31
)) {
449 } while ((TopBit
& BIT31
) != BIT31
);
455 // Some instructions specify the PC is always considered aligned
456 // The PC is after the instruction that is excuting. So you pass
457 // in the instruction address and you get back the aligned answer
464 return (Data
+ 4) & 0xfffffffc;
468 Place a dissasembly of of **OpCodePtr into buffer, and update OpCodePtr to
469 point to next instructin.
471 We cheat and only decode instructions that access
472 memory. If the instruction is not found we dump the instruction in hex.
474 @param OpCodePtrPtr Pointer to pointer of ARM Thumb instruction to disassemble.
475 @param Buf Buffer to sprintf disassembly into.
476 @param Size Size of Buf in bytes.
477 @param Extended TRUE dump hex for instruction too.
481 DisassembleThumbInstruction (
482 IN UINT16
**OpCodePtrPtr
,
494 UINT16 Rd
, Rn
, Rm
, Rt
, Rt2
;
495 BOOLEAN H1
, H2
, imod
;
497 UINT32 PC
, Target
, msbit
, lsbit
;
499 BOOLEAN S
, J1
, J2
, P
, U
, W
;
500 UINT32 coproc
, opc1
, opc2
, CRd
, CRn
, CRm
;
503 OpCodePtr
= *OpCodePtrPtr
;
504 OpCode
= **OpCodePtrPtr
;
506 // Thumb2 is a stream of 16-bit instructions not a 32-bit instruction.
507 OpCode32
= (((UINT32
)OpCode
) << 16) | *(OpCodePtr
+ 1);
509 // These register names match branch form, but not others
511 Rn
= (OpCode
>> 3) & 0x7;
512 Rm
= (OpCode
>> 6) & 0x7;
513 H1
= (OpCode
& BIT7
) != 0;
514 H2
= (OpCode
& BIT6
) != 0;
515 imod
= (OpCode
& BIT4
) != 0;
516 PC
= (UINT32
)(UINTN
)OpCodePtr
;
518 // Increment by the minimum instruction size, Thumb2 could be bigger
521 // Manage IT Block ItFlag TRUE means we are in an IT block
522 /*if (*ItBlock != 0) {
529 for (Index
= 0; Index
< sizeof (gOpThumb
)/sizeof (THUMB_INSTRUCTIONS
); Index
++) {
530 if ((OpCode
& gOpThumb
[Index
].Mask
) == gOpThumb
[Index
].OpCode
) {
532 Offset
= AsciiSPrint (Buf
, Size
, "0x%04x %-6a", OpCode
, gOpThumb
[Index
].Start
);
534 Offset
= AsciiSPrint (Buf
, Size
, "%-6a", gOpThumb
[Index
].Start
);
536 switch (gOpThumb
[Index
].AddressMode
) {
537 case LOAD_STORE_FORMAT1
:
538 // A6.5.1 <Rd>, [<Rn>, #<5_bit_offset>]
539 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " r%d, [r%d #0x%x]", Rd
, Rn
, (OpCode
>> 4) & 0x7c);
541 case LOAD_STORE_FORMAT1_H
:
542 // A6.5.1 <Rd>, [<Rn>, #<5_bit_offset>]
543 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " r%d, [r%d #0x%x]", Rd
, Rn
, (OpCode
>> 5) & 0x3e);
545 case LOAD_STORE_FORMAT1_B
:
546 // A6.5.1 <Rd>, [<Rn>, #<5_bit_offset>]
547 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " r%d, [r%d #0x%x]", Rd
, Rn
, (OpCode
>> 6) & 0x1f);
550 case LOAD_STORE_FORMAT2
:
551 // A6.5.1 <Rd>, [<Rn>, <Rm>]
552 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " r%d, [r%d, r%d]", Rd
, Rn
, Rm
);
554 case LOAD_STORE_FORMAT3
:
555 // A6.5.1 <Rd>, [PC, #<8_bit_offset>]
556 Target
= (OpCode
& 0xff) << 2;
557 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " r%d, [pc, #0x%x] ;0x%08x", (OpCode
>> 8) & 7, Target
, PCAlign4 (PC
) + Target
);
559 case LOAD_STORE_FORMAT4
:
561 Target
= (OpCode
& 0xff) << 2;
562 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " r%d, [sp, #0x%x]", (OpCode
>> 8) & 7, Target
);
565 case LOAD_STORE_MULTIPLE_FORMAT1
:
567 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " r%d!, %a", (OpCode
>> 8) & 7, ThumbMRegList (OpCode
& 0xff));
572 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a", ThumbMRegList ((OpCode
& 0xff) | ((OpCode
& BIT8
) == BIT8
? BIT15
: 0)));
577 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a", ThumbMRegList ((OpCode
& 0xff) | ((OpCode
& BIT8
) == BIT8
? BIT14
: 0)));
583 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " 0x%x", OpCode
& 0xff);
586 case CONDITIONAL_BRANCH
:
587 // A6.3.1 B<cond> <target_address>
588 // Patch in the condition code. A little hack but based on "%-6a"
589 Cond
= gCondition
[(OpCode
>> 8) & 0xf];
590 Buf
[Offset
-5] = *Cond
++;
591 Buf
[Offset
-4] = *Cond
;
592 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " 0x%04x", PC
+ 4 + SignExtend32 ((OpCode
& 0xff) << 1, BIT8
));
594 case UNCONDITIONAL_BRANCH_SHORT
:
595 // A6.3.2 B <target_address>
596 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " 0x%04x", PC
+ 4 + SignExtend32 ((OpCode
& 0x3ff) << 1, BIT11
));
599 case BRANCH_EXCHANGE
:
600 // A6.3.3 BX|BLX <Rm>
601 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a", gReg
[Rn
| (H2
? 8:0)]);
605 // A6.4.3 <Rd>, <Rn>, <Rm>
606 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " r%d, r%d, r%d", Rd
, Rn
, Rm
);
609 // A6.4.3 <Rd>, <Rn>, #3_bit_immed
610 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " r%d, r%d, 0x%x", Rd
, Rn
, Rm
);
613 // A6.4.3 <Rd>|<Rn>, #imm8
614 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " r%d, #0x%x", (OpCode
>> 8) & 7, OpCode
& 0xff);
617 // A6.4.3 <Rd>|<Rm>, #immed_5
618 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " r%d, r%d, 0x%x", Rn
, Rd
, (OpCode
>> 6) & 0x1f);
621 // A6.4.3 <Rd>|<Rm>, <Rm>|<Rs>
622 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " r%d, r%d", Rd
, Rn
);
624 case DATA_FORMAT6_SP
:
625 // A6.4.3 <Rd>, <reg>, #<8_Bit_immed>
626 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " r%d, sp, 0x%x", (OpCode
>> 8) & 7, (OpCode
& 0xff) << 2);
628 case DATA_FORMAT6_PC
:
629 // A6.4.3 <Rd>, <reg>, #<8_Bit_immed>
630 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " r%d, pc, 0x%x", (OpCode
>> 8) & 7, (OpCode
& 0xff) << 2);
633 // A6.4.3 SP, SP, #<7_Bit_immed>
634 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " sp, sp, 0x%x", (OpCode
& 0x7f)*4);
637 // A6.4.3 <Rd>|<Rn>, <Rm>
638 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a, %a", gReg
[Rd
| (H1
? 8:0)], gReg
[Rn
| (H2
? 8:0)]);
643 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, "%a %a%a%a", imod
? "ID":"IE", ((OpCode
& BIT2
) == 0) ? "":"a", ((OpCode
& BIT1
) == 0) ? "":"i", ((OpCode
& BIT0
) == 0) ? "":"f");
648 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a", (OpCode
& BIT3
) == 0 ? "LE":"BE");
652 // CB{N}Z <Rn>, <Lable>
653 Target
= ((OpCode
>> 2) & 0x3e) | (((OpCode
& BIT9
) == BIT9
) ? BIT6
: 0);
654 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a, %08x", gReg
[Rd
], PC
+ 4 + Target
);
659 Target
= (OpCode
& 0xff) << 2;
660 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a, %08x", gReg
[(OpCode
>> 8) & 7], PCAlign4 (PC
) + Target
);
664 // ITSTATE = cond:mask OpCode[7:4]:OpCode[3:0]
665 // ITSTATE[7:5] == cond[3:1]
666 // ITSTATE[4] == 1st Instruction cond[0]
667 // ITSTATE[3] == 2st Instruction cond[0]
668 // ITSTATE[2] == 3st Instruction cond[0]
669 // ITSTATE[1] == 4st Instruction cond[0]
670 // ITSTATE[0] == 1 4 instruction IT block. 0 means 0,1,2 or 3 instructions
671 // 1st one in ITSTATE low bits defines the number of instructions
672 Mask
= (OpCode
& 0xf);
673 if ((Mask
& 0x1) == 0x1) {
675 Offset
+= AsciiSPrint (&Buf
[Offset
], Size
- Offset
, "%a%a%a", (Mask
& BIT3
)?"T":"E", (Mask
& BIT2
)?"T":"E", (Mask
& BIT1
)?"T":"E");
676 } else if ((OpCode
& 0x3) == 0x2) {
678 Offset
+= AsciiSPrint (&Buf
[Offset
], Size
- Offset
, "%a%a", (Mask
& BIT3
)?"T":"E", (Mask
& BIT2
)?"T":"E");
679 } else if ((OpCode
& 0x7) == 0x4) {
681 Offset
+= AsciiSPrint (&Buf
[Offset
], Size
- Offset
, "%a", (Mask
& BIT3
)?"T":"E");
682 } else if ((OpCode
& 0xf) == 0x8) {
685 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a", gCondition
[(OpCode
>> 4) & 0xf]);
692 // Thumb2 are 32-bit instructions
694 Rt
= (OpCode32
>> 12) & 0xf;
695 Rt2
= (OpCode32
>> 8) & 0xf;
696 Rd
= (OpCode32
>> 8) & 0xf;
697 Rm
= (OpCode32
& 0xf);
698 Rn
= (OpCode32
>> 16) & 0xf;
699 for (Index
= 0; Index
< sizeof (gOpThumb2
)/sizeof (THUMB_INSTRUCTIONS
); Index
++) {
700 if ((OpCode32
& gOpThumb2
[Index
].Mask
) == gOpThumb2
[Index
].OpCode
) {
702 Offset
= AsciiSPrint (Buf
, Size
, "0x%04x %-6a", OpCode32
, gOpThumb2
[Index
].Start
);
704 Offset
= AsciiSPrint (Buf
, Size
, " %-6a", gOpThumb2
[Index
].Start
);
706 switch (gOpThumb2
[Index
].AddressMode
) {
708 Cond
= gCondition
[(OpCode32
>> 22) & 0xf];
709 Buf
[Offset
-5] = *Cond
++;
710 Buf
[Offset
-4] = *Cond
;
711 // S:J2:J1:imm6:imm11:0
712 Target
= ((OpCode32
<< 1) & 0xffe) + ((OpCode32
>> 4) & 0x3f000);
713 Target
|= ((OpCode32
& BIT11
) == BIT11
)? BIT19
: 0; // J2
714 Target
|= ((OpCode32
& BIT13
) == BIT13
)? BIT18
: 0; // J1
715 Target
|= ((OpCode32
& BIT26
) == BIT26
)? BIT20
: 0; // S
716 Target
= SignExtend32 (Target
, BIT20
);
717 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " 0x%08x", PC
+ 4 + Target
);
720 // S:I1:I2:imm10:imm11:0
721 Target
= ((OpCode32
<< 1) & 0xffe) + ((OpCode32
>> 4) & 0x3ff000);
722 S
= (OpCode32
& BIT26
) == BIT26
;
723 J1
= (OpCode32
& BIT13
) == BIT13
;
724 J2
= (OpCode32
& BIT11
) == BIT11
;
725 Target
|= (!(J2
^ S
) ? BIT22
: 0); // I2
726 Target
|= (!(J1
^ S
) ? BIT23
: 0); // I1
727 Target
|= (S
? BIT24
: 0); // S
728 Target
= SignExtend32 (Target
, BIT24
);
729 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " 0x%08x", PC
+ 4 + Target
);
733 // BLX S:I1:I2:imm10:imm11:0
734 Target
= ((OpCode32
<< 1) & 0xffc) + ((OpCode32
>> 4) & 0x3ff000);
735 S
= (OpCode32
& BIT26
) == BIT26
;
736 J1
= (OpCode32
& BIT13
) == BIT13
;
737 J2
= (OpCode32
& BIT11
) == BIT11
;
738 Target
|= (!(J2
^ S
) ? BIT23
: 0); // I2
739 Target
|= (!(J1
^ S
) ? BIT24
: 0); // I1
740 Target
|= (S
? BIT25
: 0); // S
741 Target
= SignExtend32 (Target
, BIT25
);
742 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " 0x%08x", PCAlign4 (PC
) + Target
);
746 // <reglist> some must be zero, handled in table
747 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a", ThumbMRegList (OpCode32
& 0xffff));
752 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a", gReg
[(OpCode32
>> 12) & 0xf]);
756 // <Rn>{!}, <registers>
757 W
= (OpCode32
& BIT21
) == BIT21
;
758 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a%a, %a", gReg
[(OpCode32
>> 16) & 0xf], W
? "!":"", ThumbMRegList (OpCode32
& 0xffff));
761 case LDM_REG_IMM12_SIGNED
:
763 Target
= OpCode32
& 0xfff;
764 if ((OpCode32
& BIT23
) == 0) {
765 // U == 0 means subtrack, U == 1 means add
768 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a, %a", gReg
[(OpCode32
>> 12) & 0xf], PCAlign4 (PC
) + Target
);
771 case LDM_REG_INDIRECT_LSL
:
772 // <rt>, [<rn>, <rm> {, LSL #<imm2>]}
773 Offset
+= AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a, [%a, %a", gReg
[Rt
], gReg
[Rn
], gReg
[Rm
]);
774 if (((OpCode32
>> 4) & 3) == 0) {
775 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, "]");
777 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, ", LSL #%d]", (OpCode32
>> 4) & 3);
782 // <rt>, [<rn>, {, #<imm12>]}
783 Offset
+= AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a, [%a", gReg
[Rt
], gReg
[Rn
]);
784 if ((OpCode32
& 0xfff) == 0) {
785 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, "]");
787 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, ", #0x%x]", OpCode32
& 0xfff);
792 // <rt>, [<rn>, {, #<imm8>}]{!}
793 W
= (OpCode32
& BIT8
) == BIT8
;
794 U
= (OpCode32
& BIT9
) == BIT9
;
795 P
= (OpCode32
& BIT10
) == BIT10
;
796 Offset
+= AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a, [%a", gReg
[Rt
], gReg
[Rn
]);
798 if ((OpCode32
& 0xff) == 0) {
799 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, "]%a", W
?"!":"");
801 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, ", #%a0x%x]%a", U
?"":"-" , OpCode32
& 0xff, W
?"!":"");
804 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, "], #%a0x%x", U
?"":"-", OpCode32
& 0xff);
808 case LDRD_REG_IMM8_SIGNED
:
809 // LDRD <rt>, <rt2>, [<rn>, {, #<imm8>]}{!}
810 P
= (OpCode32
& BIT24
) == BIT24
; // index = P
811 U
= (OpCode32
& BIT23
) == BIT23
;
812 W
= (OpCode32
& BIT21
) == BIT21
;
813 Offset
+= AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a, %a, [%a", gReg
[Rt
], gReg
[Rt2
], gReg
[Rn
]);
815 if ((OpCode32
& 0xff) == 0) {
816 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, "]");
818 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, ", #%a0x%x]%a", U
?"":"-", (OpCode32
& 0xff) << 2, W
?"!":"");
821 if ((OpCode32
& 0xff) != 0) {
822 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, ", #%a0x%x", U
?"":"-", (OpCode32
& 0xff) << 2);
828 // LDRD <rt>, <rt2>, <label>
829 Target
= (OpCode32
& 0xff) << 2;
830 if ((OpCode32
& BIT23
) == 0) {
831 // U == 0 means subtrack, U == 1 means add
834 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a, %a, %a", gReg
[Rt
], gReg
[Rt2
], PC
+ 4 + Target
);
839 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a, [%a]", gReg
[Rt
], gReg
[Rn
]);
843 // LDREXD <Rt>, <Rt2>, [<Rn>]
844 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a, ,%a, [%a]", gReg
[Rt
], gReg
[Rt2
], gReg
[Rn
]);
849 W
= (OpCode32
& BIT21
) == BIT21
;
850 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " SP%a, #0x%x", W
?"!":"", OpCode32
& 0x1f);
855 W
= (OpCode32
& BIT21
) == BIT21
;
856 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a%a, #0x%x", gReg
[Rn
], W
?"!":"");
860 // ADD{S} <Rd>, <Rn>, #<const> i:imm3:imm8
861 if ((OpCode32
& BIT20
) == BIT20
) {
862 Buf
[Offset
- 3] = 'S'; // assume %-6a
864 Target
= (OpCode32
& 0xff) | ((OpCode32
>> 4) & 0x700) | ((OpCode
& BIT26
) == BIT26
? BIT11
: 0);
865 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a, %a, #0x%x", gReg
[Rd
], gReg
[Rn
], Target
);
869 // MOV{S} <Rd>, #<const> i:imm3:imm8
870 if ((OpCode32
& BIT20
) == BIT20
) {
871 Buf
[Offset
- 3] = 'S'; // assume %-6a
873 Target
= (OpCode32
& 0xff) | ((OpCode32
>> 4) & 0x700) | ((OpCode
& BIT26
) == BIT26
? BIT11
: 0);
874 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a, #0x%x", gReg
[Rd
], Target
);
878 // MOVW <Rd>, #<const> i:imm3:imm8
879 Target
= (OpCode32
& 0xff) | ((OpCode32
>> 4) & 0x700) | ((OpCode
& BIT26
) == BIT26
? BIT11
: 0);
880 Target
|= ((OpCode32
>> 4) & 0xf0000);
881 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a, #0x%x", gReg
[Rd
], Target
);
885 // ADC{S} <Rd>, <Rn>, <Rm> {,LSL #<const>} imm3:imm2
886 if ((OpCode32
& BIT20
) == BIT20
) {
887 Buf
[Offset
- 3] = 'S'; // assume %-6a
889 Target
= ((OpCode32
>> 6) & 3) | ((OpCode32
>> 10) & 0x1c0);
890 Offset
+= AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a, %a, %a", gReg
[Rd
], gReg
[Rn
], gReg
[Rm
]);
892 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, ", LSL %d", gShiftType
[(OpCode
>> 5) & 3], Target
);
897 // CMP <Rn>, <Rm> {,LSL #<const>} imm3:imm2
898 Target
= ((OpCode32
>> 6) & 3) | ((OpCode32
>> 10) & 0x1c0);
899 Offset
+= AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a, %a", gReg
[Rn
], gReg
[Rm
]);
901 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, ", LSL %d", gShiftType
[(OpCode
>> 5) & 3], Target
);
906 // ARS <Rd>, <Rm> #<const>} imm3:imm2
907 if ((OpCode32
& BIT20
) == BIT20
) {
908 Buf
[Offset
- 3] = 'S'; // assume %-6a
910 Target
= ((OpCode32
>> 6) & 3) | ((OpCode32
>> 10) & 0x1c0);
911 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a, %a #%d", gReg
[Rd
], gReg
[Rm
], Target
);
915 // ARS <Rd>, <Rn>, <Rm>
916 if ((OpCode32
& BIT20
) == BIT20
) {
917 Buf
[Offset
- 3] = 'S'; // assume %-6a
919 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a, %a %a", gReg
[Rd
], gReg
[Rn
], gReg
[Rm
]);
923 // ADDR <Rd>, <label>
924 Target
= (OpCode32
& 0xff) | ((OpCode32
>> 8) & 0x700) | ((OpCode
& BIT26
) == BIT26
? BIT11
: 0);
925 if ((OpCode
& (BIT23
| BIT21
)) == (BIT23
| BIT21
)) {
926 Target
= PCAlign4 (PC
) - Target
;
928 Target
= PCAlign4 (PC
) + Target
;
930 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a, 0x%08x", gReg
[Rd
], Target
);
934 // CMN <Rn>, #<const>}
935 Target
= (OpCode32
& 0xff) | ((OpCode
>> 4) & 0x700) | ((OpCode
& BIT26
) == BIT26
? BIT11
: 0);
936 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a, #0x%x", gReg
[Rn
], Target
);
940 // BFI <Rd>, <Rn>, #<lsb>, #<width>
941 msbit
= OpCode32
& 0x1f;
942 lsbit
= ((OpCode32
>> 6) & 3) | ((OpCode
>> 10) & 0x1c);
943 if ((Rn
== 0xf) & (AsciiStrCmp (gOpThumb2
[Index
].Start
, "BFC") == 0)){
944 // BFC <Rd>, #<lsb>, #<width>
945 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a, #%d, #%d", gReg
[Rd
], lsbit
, msbit
- lsbit
+ 1);
946 } else if (AsciiStrCmp (gOpThumb2
[Index
].Start
, "BFI") == 0) {
947 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a, %a, #%d, #%d", gReg
[Rd
], gReg
[Rn
], lsbit
, msbit
- lsbit
+ 1);
949 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a, %a, #%d, #%d", gReg
[Rd
], gReg
[Rn
], lsbit
, msbit
+ 1);
954 // <coproc>,<opc1>,<CRd>,<CRn>,<CRm>,<opc2>
955 coproc
= (OpCode32
>> 8) & 0xf;
956 opc1
= (OpCode32
>> 20) & 0xf;
957 opc2
= (OpCode32
>> 5) & 0x7;
958 CRd
= (OpCode32
>> 12) & 0xf;
959 CRn
= (OpCode32
>> 16) & 0xf;
960 CRm
= OpCode32
& 0xf;
961 Offset
+= AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " p%d,#%d,c%d,c%d,c%d", coproc
, opc1
, CRd
, CRn
, CRm
);
963 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, ",#%d,", opc2
);
968 // MRC <coproc>,<opc1>,<Rt>,<CRn>,<CRm>,<opc2>
969 coproc
= (OpCode32
>> 8) & 0xf;
970 opc1
= (OpCode32
>> 20) & 0xf;
971 opc2
= (OpCode32
>> 5) & 0x7;
972 CRn
= (OpCode32
>> 16) & 0xf;
973 CRm
= OpCode32
& 0xf;
974 Offset
+= AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " p%d,#%d,%a,c%d,c%d", coproc
, opc1
, gReg
[Rt
], CRn
, CRm
);
976 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, ",#%d,", opc2
);
981 // MRC <coproc>,<opc1>,<Rt>,<Rt2>,<CRm>,<opc2>
982 coproc
= (OpCode32
>> 8) & 0xf;
983 opc1
= (OpCode32
>> 20) & 0xf;
984 CRn
= (OpCode32
>> 16) & 0xf;
985 CRm
= OpCode32
& 0xf;
986 Offset
+= AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " p%d,#%d,%a,%a,c%d", coproc
, opc1
, gReg
[Rt
], gReg
[Rt2
], CRm
);
991 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a, %a", gReg
[Rd
], gReg
[Rm
]);
995 // <Rd>, <Rn>, <Rm>, <Ra>
996 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a, %a, %a, %a", gReg
[Rd
], gReg
[Rn
], gReg
[Rm
], gReg
[Rt
]);
1001 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a, CPSR", gReg
[Rd
]);
1005 // MRS CPSR_<fields>, <Rd>
1006 Target
= (OpCode32
>> 10) & 3;
1007 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " CPSR_%a%a, %a", (Target
& 2) == 0 ? "":"f", (Target
& 1) == 0 ? "":"s", gReg
[Rd
]);
1010 case THUMB2_NO_ARGS
:
1017 AsciiSPrint (Buf
, Size
, "0x%08x", OpCode32
);
1023 DisassembleArmInstruction (
1024 IN UINT32
**OpCodePtr
,
1032 Place a dissasembly of of **OpCodePtr into buffer, and update OpCodePtr to
1033 point to next instructin.
1035 We cheat and only decode instructions that access
1036 memory. If the instruction is not found we dump the instruction in hex.
1038 @param OpCodePtrPtr Pointer to pointer of ARM Thumb instruction to disassemble.
1039 @param Thumb TRUE for Thumb(2), FALSE for ARM instruction stream
1040 @param Extended TRUE dump hex for instruction too.
1041 @param ItBlock Size of IT Block
1042 @param Buf Buffer to sprintf disassembly into.
1043 @param Size Size of Buf in bytes.
1047 DisassembleInstruction (
1048 IN UINT8
**OpCodePtr
,
1050 IN BOOLEAN Extended
,
1051 IN OUT UINT32
*ItBlock
,
1057 DisassembleThumbInstruction ((UINT16
**)OpCodePtr
, Buf
, Size
, ItBlock
, Extended
);
1059 DisassembleArmInstruction ((UINT32
**)OpCodePtr
, Buf
, Size
, Extended
);