2 Thumb Disassembler. 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>
12 Copyright (c) 2021, Arm Limited. All rights reserved.<BR>
14 SPDX-License-Identifier: BSD-2-Clause-Patent
19 #include <Library/BaseLib.h>
20 #include <Library/DebugLib.h>
21 #include <Library/PrintLib.h>
23 extern CHAR8
*gCondition
[];
27 // Thumb address modes
28 #define LOAD_STORE_FORMAT1 1
29 #define LOAD_STORE_FORMAT1_H 101
30 #define LOAD_STORE_FORMAT1_B 111
31 #define LOAD_STORE_FORMAT2 2
32 #define LOAD_STORE_FORMAT3 3
33 #define LOAD_STORE_FORMAT4 4
34 #define LOAD_STORE_MULTIPLE_FORMAT1 5
36 #define POP_FORMAT 106
38 #define CONDITIONAL_BRANCH 8
39 #define UNCONDITIONAL_BRANCH 9
40 #define UNCONDITIONAL_BRANCH_SHORT 109
41 #define BRANCH_EXCHANGE 10
42 #define DATA_FORMAT1 11
43 #define DATA_FORMAT2 12
44 #define DATA_FORMAT3 13
45 #define DATA_FORMAT4 14
46 #define DATA_FORMAT5 15
47 #define DATA_FORMAT6_SP 16
48 #define DATA_FORMAT6_PC 116
49 #define DATA_FORMAT7 17
50 #define DATA_FORMAT8 19
52 #define ENDIAN_FORMAT 21
57 // Thumb2 address modes
63 #define STM_FORMAT 205
64 #define LDM_REG_IMM12_SIGNED 206
65 #define LDM_REG_IMM12_LSL 207
66 #define LDM_REG_IMM8 208
67 #define LDM_REG_IMM12 209
68 #define LDM_REG_INDIRECT_LSL 210
69 #define LDM_REG_IMM8_SIGNED 211
70 #define LDRD_REG_IMM8 212
73 #define SRS_FORMAT 215
74 #define RFE_FORMAT 216
75 #define LDRD_REG_IMM8_SIGNED 217
78 #define ADR_THUMB2 220
79 #define CMN_THUMB2 221
82 #define BFC_THUMB2 224
83 #define CDP_THUMB2 225
84 #define THUMB2_NO_ARGS 226
85 #define THUMB2_2REGS 227
86 #define ADD_IMM5_2REG 228
87 #define CPD_THUMB2 229
88 #define THUMB2_4REGS 230
89 #define ADD_IMM12_1REG 231
90 #define THUMB2_IMM16 232
91 #define MRC_THUMB2 233
92 #define MRRC_THUMB2 234
93 #define THUMB2_MRS 235
94 #define THUMB2_MSR 236
101 } THUMB_INSTRUCTIONS
;
103 THUMB_INSTRUCTIONS gOpThumb
[] = {
104 // Thumb 16-bit instructions
106 { "ADC", 0x4140, 0xffc0, DATA_FORMAT5
}, // ADC <Rndn>, <Rm>
107 { "ADR", 0xa000, 0xf800, ADR_FORMAT
}, // ADR <Rd>, <label>
108 { "ADD", 0x1c00, 0xfe00, DATA_FORMAT2
},
109 { "ADD", 0x3000, 0xf800, DATA_FORMAT3
},
110 { "ADD", 0x1800, 0xfe00, DATA_FORMAT1
},
111 { "ADD", 0x4400, 0xff00, DATA_FORMAT8
}, // A8.6.9
112 { "ADD", 0xa000, 0xf100, DATA_FORMAT6_PC
},
113 { "ADD", 0xa800, 0xf800, DATA_FORMAT6_SP
},
114 { "ADD", 0xb000, 0xff80, DATA_FORMAT7
},
116 { "AND", 0x4000, 0xffc0, DATA_FORMAT5
},
118 { "ASR", 0x1000, 0xf800, DATA_FORMAT4
},
119 { "ASR", 0x4100, 0xffc0, DATA_FORMAT5
},
121 { "B", 0xd000, 0xf000, CONDITIONAL_BRANCH
},
122 { "B", 0xe000, 0xf800, UNCONDITIONAL_BRANCH_SHORT
},
123 { "BLX", 0x4780, 0xff80, BRANCH_EXCHANGE
},
124 { "BX", 0x4700, 0xff87, BRANCH_EXCHANGE
},
126 { "BIC", 0x4380, 0xffc0, DATA_FORMAT5
},
127 { "BKPT", 0xdf00, 0xff00, IMMED_8
},
128 { "CBZ", 0xb100, 0xfd00, DATA_CBZ
},
129 { "CBNZ", 0xb900, 0xfd00, DATA_CBZ
},
130 { "CMN", 0x42c0, 0xffc0, DATA_FORMAT5
},
132 { "CMP", 0x2800, 0xf800, DATA_FORMAT3
},
133 { "CMP", 0x4280, 0xffc0, DATA_FORMAT5
},
134 { "CMP", 0x4500, 0xff00, DATA_FORMAT8
},
136 { "CPS", 0xb660, 0xffe8, CPS_FORMAT
},
137 { "MOV", 0x4600, 0xff00, DATA_FORMAT8
},
138 { "EOR", 0x4040, 0xffc0, DATA_FORMAT5
},
140 { "LDMIA", 0xc800, 0xf800, LOAD_STORE_MULTIPLE_FORMAT1
},
141 { "LDR", 0x6800, 0xf800, LOAD_STORE_FORMAT1
}, // LDR <Rt>, [<Rn> {,#<imm>}]
142 { "LDR", 0x5800, 0xfe00, LOAD_STORE_FORMAT2
}, // STR <Rt>, [<Rn>, <Rm>]
143 { "LDR", 0x4800, 0xf800, LOAD_STORE_FORMAT3
},
144 { "LDR", 0x9800, 0xf800, LOAD_STORE_FORMAT4
}, // LDR <Rt>, [SP, #<imm>]
145 { "LDRB", 0x7800, 0xf800, LOAD_STORE_FORMAT1_B
},
146 { "LDRB", 0x5c00, 0xfe00, LOAD_STORE_FORMAT2
}, // STR <Rt>, [<Rn>, <Rm>]
147 { "LDRH", 0x8800, 0xf800, LOAD_STORE_FORMAT1_H
},
148 { "LDRH", 0x7a00, 0xfe00, LOAD_STORE_FORMAT2
},
149 { "LDRSB", 0x5600, 0xfe00, LOAD_STORE_FORMAT2
}, // STR <Rt>, [<Rn>, <Rm>]
150 { "LDRSH", 0x5e00, 0xfe00, LOAD_STORE_FORMAT2
},
152 { "MOVS", 0x0000, 0xffc0, DATA_FORMAT5
}, // LSL with imm5 == 0 is a MOVS, so this must go before LSL
153 { "LSL", 0x0000, 0xf800, DATA_FORMAT4
},
154 { "LSL", 0x4080, 0xffc0, DATA_FORMAT5
},
155 { "LSR", 0x0001, 0xf800, DATA_FORMAT4
},
156 { "LSR", 0x40c0, 0xffc0, DATA_FORMAT5
},
157 { "LSRS", 0x0800, 0xf800, DATA_FORMAT4
}, // LSRS <Rd>, <Rm>, #<imm5>
159 { "MOVS", 0x2000, 0xf800, DATA_FORMAT3
},
160 { "MOV", 0x1c00, 0xffc0, DATA_FORMAT3
},
161 { "MOV", 0x4600, 0xff00, DATA_FORMAT8
},
163 { "MUL", 0x4340, 0xffc0, DATA_FORMAT5
},
164 { "MVN", 0x41c0, 0xffc0, DATA_FORMAT5
},
165 { "NEG", 0x4240, 0xffc0, DATA_FORMAT5
},
166 { "ORR", 0x4300, 0xffc0, DATA_FORMAT5
},
167 { "POP", 0xbc00, 0xfe00, POP_FORMAT
},
168 { "PUSH", 0xb400, 0xfe00, PUSH_FORMAT
},
170 { "REV", 0xba00, 0xffc0, DATA_FORMAT5
},
171 { "REV16", 0xba40, 0xffc0, DATA_FORMAT5
},
172 { "REVSH", 0xbac0, 0xffc0, DATA_FORMAT5
},
174 { "ROR", 0x41c0, 0xffc0, DATA_FORMAT5
},
175 { "SBC", 0x4180, 0xffc0, DATA_FORMAT5
},
176 { "SETEND", 0xb650, 0xfff0, ENDIAN_FORMAT
},
178 { "STMIA", 0xc000, 0xf800, LOAD_STORE_MULTIPLE_FORMAT1
},
179 { "STR", 0x6000, 0xf800, LOAD_STORE_FORMAT1
}, // STR <Rt>, [<Rn> {,#<imm>}]
180 { "STR", 0x5000, 0xfe00, LOAD_STORE_FORMAT2
}, // STR <Rt>, [<Rn>, <Rm>]
181 { "STR", 0x9000, 0xf800, LOAD_STORE_FORMAT4
}, // STR <Rt>, [SP, #<imm>]
182 { "STRB", 0x7000, 0xf800, LOAD_STORE_FORMAT1_B
}, // STRB <Rt>, [<Rn>, #<imm5>]
183 { "STRB", 0x5400, 0xfe00, LOAD_STORE_FORMAT2
}, // STRB <Rt>, [<Rn>, <Rm>]
184 { "STRH", 0x8000, 0xf800, LOAD_STORE_FORMAT1_H
}, // STRH <Rt>, [<Rn>{,#<imm>}]
185 { "STRH", 0x5200, 0xfe00, LOAD_STORE_FORMAT2
}, // STRH <Rt>, [<Rn>, <Rm>]
187 { "SUB", 0x1e00, 0xfe00, DATA_FORMAT2
},
188 { "SUB", 0x3800, 0xf800, DATA_FORMAT3
},
189 { "SUB", 0x1a00, 0xfe00, DATA_FORMAT1
},
190 { "SUB", 0xb080, 0xff80, DATA_FORMAT7
},
192 { "SBC", 0x4180, 0xffc0, DATA_FORMAT5
},
194 { "SWI", 0xdf00, 0xff00, IMMED_8
},
195 { "SXTB", 0xb240, 0xffc0, DATA_FORMAT5
},
196 { "SXTH", 0xb200, 0xffc0, DATA_FORMAT5
},
197 { "TST", 0x4200, 0xffc0, DATA_FORMAT5
},
198 { "UXTB", 0xb2c0, 0xffc0, DATA_FORMAT5
},
199 { "UXTH", 0xb280, 0xffc0, DATA_FORMAT5
},
201 { "IT", 0xbf00, 0xff00, IT_BLOCK
}
204 THUMB_INSTRUCTIONS gOpThumb2
[] = {
205 // Instruct OpCode OpCode Mask Addressig Mode
207 { "ADR", 0xf2af0000, 0xfbff8000, ADR_THUMB2
}, // ADDR <Rd>, <label> ;Needs to go before ADDW
208 { "CMN", 0xf1100f00, 0xfff08f00, CMN_THUMB2
}, // CMN <Rn>, #<const> ;Needs to go before ADD
209 { "CMN", 0xeb100f00, 0xfff08f00, ADD_IMM5_2REG
}, // CMN <Rn>, <Rm> {,<shift> #<const>}
210 { "CMP", 0xf1a00f00, 0xfff08f00, CMN_THUMB2
}, // CMP <Rn>, #<const>
211 { "TEQ", 0xf0900f00, 0xfff08f00, CMN_THUMB2
}, // CMP <Rn>, #<const>
212 { "TEQ", 0xea900f00, 0xfff08f00, ADD_IMM5_2REG
}, // CMN <Rn>, <Rm> {,<shift> #<const>}
213 { "TST", 0xf0100f00, 0xfff08f00, CMN_THUMB2
}, // CMP <Rn>, #<const>
214 { "TST", 0xea100f00, 0xfff08f00, ADD_IMM5_2REG
}, // TST <Rn>, <Rm> {,<shift> #<const>}
216 { "MOV", 0xf04f0000, 0xfbef8000, ADD_IMM12_1REG
}, // MOV <Rd>, #<const>
217 { "MOVW", 0xf2400000, 0xfbe08000, THUMB2_IMM16
}, // MOVW <Rd>, #<const>
218 { "MOVT", 0xf2c00000, 0xfbe08000, THUMB2_IMM16
}, // MOVT <Rd>, #<const>
220 { "ADC", 0xf1400000, 0xfbe08000, ADD_IMM12
}, // ADC{S} <Rd>, <Rn>, #<const>
221 { "ADC", 0xeb400000, 0xffe08000, ADD_IMM5
}, // ADC{S} <Rd>, <Rn>, <Rm> {,<shift> #<const>}
222 { "ADD", 0xf1000000, 0xfbe08000, ADD_IMM12
}, // ADD{S} <Rd>, <Rn>, #<const>
223 { "ADD", 0xeb000000, 0xffe08000, ADD_IMM5
}, // ADD{S} <Rd>, <Rn>, <Rm> {,<shift> #<const>}
224 { "ADDW", 0xf2000000, 0xfbe08000, ADD_IMM12
}, // ADDW{S} <Rd>, <Rn>, #<const>
225 { "AND", 0xf0000000, 0xfbe08000, ADD_IMM12
}, // AND{S} <Rd>, <Rn>, #<const>
226 { "AND", 0xea000000, 0xffe08000, ADD_IMM5
}, // AND{S} <Rd>, <Rn>, <Rm> {,<shift> #<const>}
227 { "BIC", 0xf0200000, 0xfbe08000, ADD_IMM12
}, // BIC{S} <Rd>, <Rn>, #<const>
228 { "BIC", 0xea200000, 0xffe08000, ADD_IMM5
}, // BIC{S} <Rd>, <Rn>, <Rm> {,<shift> #<const>}
229 { "EOR", 0xf0800000, 0xfbe08000, ADD_IMM12
}, // EOR{S} <Rd>, <Rn>, #<const>
230 { "EOR", 0xea800000, 0xffe08000, ADD_IMM5
}, // EOR{S} <Rd>, <Rn>, <Rm> {,<shift> #<const>}
231 { "ORN", 0xf0600000, 0xfbe08000, ADD_IMM12
}, // ORN{S} <Rd>, <Rn>, #<const>
232 { "ORN", 0xea600000, 0xffe08000, ADD_IMM5
}, // ORN{S} <Rd>, <Rn>, <Rm> {,<shift> #<const>}
233 { "ORR", 0xf0400000, 0xfbe08000, ADD_IMM12
}, // ORR{S} <Rd>, <Rn>, #<const>
234 { "ORR", 0xea400000, 0xffe08000, ADD_IMM5
}, // ORR{S} <Rd>, <Rn>, <Rm> {,<shift> #<const>}
235 { "RSB", 0xf1c00000, 0xfbe08000, ADD_IMM12
}, // RSB{S} <Rd>, <Rn>, #<const>
236 { "RSB", 0xebc00000, 0xffe08000, ADD_IMM5
}, // RSB{S} <Rd>, <Rn>, <Rm> {,<shift> #<const>}
237 { "SBC", 0xf1600000, 0xfbe08000, ADD_IMM12
}, // SBC{S} <Rd>, <Rn>, #<const>
238 { "SBC", 0xeb600000, 0xffe08000, ADD_IMM5
}, // SBC{S} <Rd>, <Rn>, <Rm> {,<shift> #<const>}
239 { "SUB", 0xf1a00000, 0xfbe08000, ADD_IMM12
}, // SUB{S} <Rd>, <Rn>, #<const>
240 { "SUB", 0xeba00000, 0xffe08000, ADD_IMM5
}, // SUB{S} <Rd>, <Rn>, <Rm> {,<shift> #<const>}
242 { "ASR", 0xea4f0020, 0xffef8030, ASR_IMM5
}, // ARS <Rd>, <Rm> #<const>} imm3:imm2
243 { "ASR", 0xfa40f000, 0xffe0f0f0, ASR_3REG
}, // ARS <Rd>, <Rn>, <Rm>
244 { "LSR", 0xea4f0010, 0xffef8030, ASR_IMM5
}, // LSR <Rd>, <Rm> #<const>} imm3:imm2
245 { "LSR", 0xfa20f000, 0xffe0f0f0, ASR_3REG
}, // LSR <Rd>, <Rn>, <Rm>
246 { "ROR", 0xea4f0030, 0xffef8030, ASR_IMM5
}, // ROR <Rd>, <Rm> #<const>} imm3:imm2
247 { "ROR", 0xfa60f000, 0xffe0f0f0, ASR_3REG
}, // ROR <Rd>, <Rn>, <Rm>
249 { "BFC", 0xf36f0000, 0xffff8010, BFC_THUMB2
}, // BFC <Rd>, #<lsb>, #<width>
250 { "BIC", 0xf3600000, 0xfff08010, BFC_THUMB2
}, // BIC <Rn>, <Rd>, #<lsb>, #<width>
251 { "SBFX", 0xf3400000, 0xfff08010, BFC_THUMB2
}, // SBFX <Rn>, <Rd>, #<lsb>, #<width>
252 { "UBFX", 0xf3c00000, 0xfff08010, BFC_THUMB2
}, // UBFX <Rn>, <Rd>, #<lsb>, #<width>
254 { "CPD", 0xee000000, 0xff000010, CPD_THUMB2
}, // CPD <coproc>,<opc1>,<CRd>,<CRn>,<CRm>,<opc2>
255 { "CPD2", 0xfe000000, 0xff000010, CPD_THUMB2
}, // CPD <coproc>,<opc1>,<CRd>,<CRn>,<CRm>,<opc2>
257 { "MRC", 0xee100000, 0xff100000, MRC_THUMB2
}, // MRC <coproc>,<opc1>,<Rt>,<CRn>,<CRm>,<opc2>
258 { "MRC2", 0xfe100000, 0xff100000, MRC_THUMB2
}, // MRC2 <coproc>,<opc1>,<Rt>,<CRn>,<CRm>,<opc2>
259 { "MRRC", 0xec500000, 0xfff00000, MRRC_THUMB2
}, // MRRC <coproc>,<opc1>,<Rt>,<Rt2>,<CRm>
260 { "MRRC2", 0xfc500000, 0xfff00000, MRRC_THUMB2
}, // MRR2 <coproc>,<opc1>,<Rt>,<Rt2>,<CRm>
262 { "MRS", 0xf3ef8000, 0xfffff0ff, THUMB2_MRS
}, // MRS <Rd>, CPSR
263 { "MSR", 0xf3808000, 0xfff0fcff, THUMB2_MSR
}, // MSR CPSR_fs, <Rn>
265 { "CLREX", 0xf3bf8f2f, 0xfffffff, THUMB2_NO_ARGS
}, // CLREX
267 { "CLZ", 0xfab0f080, 0xfff0f0f0, THUMB2_2REGS
}, // CLZ <Rd>,<Rm>
268 { "MOV", 0xec4f0000, 0xfff0f0f0, THUMB2_2REGS
}, // MOV <Rd>,<Rm>
269 { "MOVS", 0xec5f0000, 0xfff0f0f0, THUMB2_2REGS
}, // MOVS <Rd>,<Rm>
270 { "RBIT", 0xfb90f0a0, 0xfff0f0f0, THUMB2_2REGS
}, // RBIT <Rd>,<Rm>
271 { "REV", 0xfb90f080, 0xfff0f0f0, THUMB2_2REGS
}, // REV <Rd>,<Rm>
272 { "REV16", 0xfa90f090, 0xfff0f0f0, THUMB2_2REGS
}, // REV16 <Rd>,<Rm>
273 { "REVSH", 0xfa90f0b0, 0xfff0f0f0, THUMB2_2REGS
}, // REVSH <Rd>,<Rm>
274 { "RRX", 0xea4f0030, 0xfffff0f0, THUMB2_2REGS
}, // RRX <Rd>,<Rm>
275 { "RRXS", 0xea5f0030, 0xfffff0f0, THUMB2_2REGS
}, // RRXS <Rd>,<Rm>
277 { "MLA", 0xfb000000, 0xfff000f0, THUMB2_4REGS
}, // MLA <Rd>, <Rn>, <Rm>, <Ra>
278 { "MLS", 0xfb000010, 0xfff000f0, THUMB2_4REGS
}, // MLA <Rd>, <Rn>, <Rm>, <Ra>
280 { "SMLABB", 0xfb100000, 0xfff000f0, THUMB2_4REGS
}, // SMLABB <Rd>, <Rn>, <Rm>, <Ra>
281 { "SMLABT", 0xfb100010, 0xfff000f0, THUMB2_4REGS
}, // SMLABT <Rd>, <Rn>, <Rm>, <Ra>
282 { "SMLABB", 0xfb100020, 0xfff000f0, THUMB2_4REGS
}, // SMLATB <Rd>, <Rn>, <Rm>, <Ra>
283 { "SMLATT", 0xfb100030, 0xfff000f0, THUMB2_4REGS
}, // SMLATT <Rd>, <Rn>, <Rm>, <Ra>
284 { "SMLAWB", 0xfb300000, 0xfff000f0, THUMB2_4REGS
}, // SMLAWB <Rd>, <Rn>, <Rm>, <Ra>
285 { "SMLAWT", 0xfb300010, 0xfff000f0, THUMB2_4REGS
}, // SMLAWT <Rd>, <Rn>, <Rm>, <Ra>
286 { "SMLSD", 0xfb400000, 0xfff000f0, THUMB2_4REGS
}, // SMLSD <Rd>, <Rn>, <Rm>, <Ra>
287 { "SMLSDX", 0xfb400010, 0xfff000f0, THUMB2_4REGS
}, // SMLSDX <Rd>, <Rn>, <Rm>, <Ra>
288 { "SMMLA", 0xfb500000, 0xfff000f0, THUMB2_4REGS
}, // SMMLA <Rd>, <Rn>, <Rm>, <Ra>
289 { "SMMLAR", 0xfb500010, 0xfff000f0, THUMB2_4REGS
}, // SMMLAR <Rd>, <Rn>, <Rm>, <Ra>
290 { "SMMLS", 0xfb600000, 0xfff000f0, THUMB2_4REGS
}, // SMMLS <Rd>, <Rn>, <Rm>, <Ra>
291 { "SMMLSR", 0xfb600010, 0xfff000f0, THUMB2_4REGS
}, // SMMLSR <Rd>, <Rn>, <Rm>, <Ra>
292 { "USADA8", 0xfb700000, 0xfff000f0, THUMB2_4REGS
}, // USADA8 <Rd>, <Rn>, <Rm>, <Ra>
293 { "SMLAD", 0xfb200000, 0xfff000f0, THUMB2_4REGS
}, // SMLAD <Rd>, <Rn>, <Rm>, <Ra>
294 { "SMLADX", 0xfb200010, 0xfff000f0, THUMB2_4REGS
}, // SMLADX <Rd>, <Rn>, <Rm>, <Ra>
296 { "B", 0xf0008000, 0xf800d000, B_T3
}, // B<c> <label>
297 { "B", 0xf0009000, 0xf800d000, B_T4
}, // B<c> <label>
298 { "BL", 0xf000d000, 0xf800d000, B_T4
}, // BL<c> <label>
299 { "BLX", 0xf000c000, 0xf800d000, BL_T2
}, // BLX<c> <label>
301 { "POP", 0xe8bd0000, 0xffff2000, POP_T2
}, // POP <registers>
302 { "POP", 0xf85d0b04, 0xffff0fff, POP_T3
}, // POP <register>
303 { "PUSH", 0xe8ad0000, 0xffffa000, POP_T2
}, // PUSH <registers>
304 { "PUSH", 0xf84d0d04, 0xffff0fff, POP_T3
}, // PUSH <register>
305 { "STM", 0xe8800000, 0xffd0a000, STM_FORMAT
}, // STM <Rn>{!},<registers>
306 { "STMDB", 0xe9800000, 0xffd0a000, STM_FORMAT
}, // STMDB <Rn>{!},<registers>
307 { "LDM", 0xe8900000, 0xffd02000, STM_FORMAT
}, // LDM <Rn>{!},<registers>
308 { "LDMDB", 0xe9100000, 0xffd02000, STM_FORMAT
}, // LDMDB <Rn>{!},<registers>
310 { "LDR", 0xf8d00000, 0xfff00000, LDM_REG_IMM12
}, // LDR <rt>, [<rn>, {, #<imm12>]}
311 { "LDRB", 0xf8900000, 0xfff00000, LDM_REG_IMM12
}, // LDRB <rt>, [<rn>, {, #<imm12>]}
312 { "LDRH", 0xf8b00000, 0xfff00000, LDM_REG_IMM12
}, // LDRH <rt>, [<rn>, {, #<imm12>]}
313 { "LDRSB", 0xf9900000, 0xfff00000, LDM_REG_IMM12
}, // LDRSB <rt>, [<rn>, {, #<imm12>]}
314 { "LDRSH", 0xf9b00000, 0xfff00000, LDM_REG_IMM12
}, // LDRSH <rt>, [<rn>, {, #<imm12>]}
316 { "LDR", 0xf85f0000, 0xff7f0000, LDM_REG_IMM12_SIGNED
}, // LDR <Rt>, <label>
317 { "LDRB", 0xf81f0000, 0xff7f0000, LDM_REG_IMM12_SIGNED
}, // LDRB <Rt>, <label>
318 { "LDRH", 0xf83f0000, 0xff7f0000, LDM_REG_IMM12_SIGNED
}, // LDRH <Rt>, <label>
319 { "LDRSB", 0xf91f0000, 0xff7f0000, LDM_REG_IMM12_SIGNED
}, // LDRSB <Rt>, <label>
320 { "LDRSH", 0xf93f0000, 0xff7f0000, LDM_REG_IMM12_SIGNED
}, // LDRSB <Rt>, <label>
322 { "LDR", 0xf8500000, 0xfff00fc0, LDM_REG_INDIRECT_LSL
}, // LDR <rt>, [<rn>, <rm> {, LSL #<imm2>]}
323 { "LDRB", 0xf8100000, 0xfff00fc0, LDM_REG_INDIRECT_LSL
}, // LDRB <rt>, [<rn>, <rm> {, LSL #<imm2>]}
324 { "LDRH", 0xf8300000, 0xfff00fc0, LDM_REG_INDIRECT_LSL
}, // LDRH <rt>, [<rn>, <rm> {, LSL #<imm2>]}
325 { "LDRSB", 0xf9100000, 0xfff00fc0, LDM_REG_INDIRECT_LSL
}, // LDRSB <rt>, [<rn>, <rm> {, LSL #<imm2>]}
326 { "LDRSH", 0xf9300000, 0xfff00fc0, LDM_REG_INDIRECT_LSL
}, // LDRSH <rt>, [<rn>, <rm> {, LSL #<imm2>]}
328 { "LDR", 0xf8500800, 0xfff00800, LDM_REG_IMM8
}, // LDR <rt>, [<rn>, {, #<imm8>]}
329 { "LDRBT", 0xf8100e00, 0xfff00f00, LDM_REG_IMM8
}, // LDRBT <rt>, [<rn>, {, #<imm8>]}
330 { "LDRHT", 0xf8300e00, 0xfff00f00, LDM_REG_IMM8
}, // LDRHT <rt>, [<rn>, {, #<imm8>]}
331 { "LDRSB", 0xf9100800, 0xfff00800, LDM_REG_IMM8
}, // LDRHT <rt>, [<rn>, {, #<imm8>]} {!} form?
332 { "LDRSBT", 0xf9100e00, 0xfff00f00, LDM_REG_IMM8
}, // LDRHBT <rt>, [<rn>, {, #<imm8>]} {!} form?
333 { "LDRSH", 0xf9300800, 0xfff00800, LDM_REG_IMM8
}, // LDRSH <rt>, [<rn>, {, #<imm8>]}
334 { "LDRSHT", 0xf9300e00, 0xfff00f00, LDM_REG_IMM8
}, // LDRSHT <rt>, [<rn>, {, #<imm8>]}
335 { "LDRT", 0xf8500e00, 0xfff00f00, LDM_REG_IMM8
}, // LDRT <rt>, [<rn>, {, #<imm8>]}
337 { "LDRD", 0xe8500000, 0xfe500000, LDRD_REG_IMM8_SIGNED
}, // LDRD <rt>, <rt2>, [<rn>, {, #<imm8>]}{!}
338 { "LDRD", 0xe8500000, 0xfe500000, LDRD_REG_IMM8
}, // LDRD <rt>, <rt2>, <label>
340 { "LDREX", 0xe8500f00, 0xfff00f00, LDM_REG_IMM8
}, // LDREX <Rt>, [Rn, {#imm8}]]
341 { "LDREXB", 0xe8d00f4f, 0xfff00fff, LDREXB
}, // LDREXB <Rt>, [<Rn>]
342 { "LDREXH", 0xe8d00f5f, 0xfff00fff, LDREXB
}, // LDREXH <Rt>, [<Rn>]
344 { "LDREXD", 0xe8d00f4f, 0xfff00fff, LDREXD
}, // LDREXD <Rt>, <Rt2>, [<Rn>]
346 { "STR", 0xf8c00000, 0xfff00000, LDM_REG_IMM12
}, // STR <rt>, [<rn>, {, #<imm12>]}
347 { "STRB", 0xf8800000, 0xfff00000, LDM_REG_IMM12
}, // STRB <rt>, [<rn>, {, #<imm12>]}
348 { "STRH", 0xf8a00000, 0xfff00000, LDM_REG_IMM12
}, // STRH <rt>, [<rn>, {, #<imm12>]}
350 { "STR", 0xf8400000, 0xfff00fc0, LDM_REG_INDIRECT_LSL
}, // STR <rt>, [<rn>, <rm> {, LSL #<imm2>]}
351 { "STRB", 0xf8000000, 0xfff00fc0, LDM_REG_INDIRECT_LSL
}, // STRB <rt>, [<rn>, <rm> {, LSL #<imm2>]}
352 { "STRH", 0xf8200000, 0xfff00fc0, LDM_REG_INDIRECT_LSL
}, // STRH <rt>, [<rn>, <rm> {, LSL #<imm2>]}
354 { "STR", 0xf8400800, 0xfff00800, LDM_REG_IMM8
}, // STR <rt>, [<rn>, {, #<imm8>]}
355 { "STRH", 0xf8200800, 0xfff00800, LDM_REG_IMM8
}, // STRH <rt>, [<rn>, {, #<imm8>]}
356 { "STRBT", 0xf8000e00, 0xfff00f00, LDM_REG_IMM8
}, // STRBT <rt>, [<rn>, {, #<imm8>]}
357 { "STRHT", 0xf8200e00, 0xfff00f00, LDM_REG_IMM8
}, // STRHT <rt>, [<rn>, {, #<imm8>]}
358 { "STRT", 0xf8400e00, 0xfff00f00, LDM_REG_IMM8
}, // STRT <rt>, [<rn>, {, #<imm8>]}
360 { "STRD", 0xe8400000, 0xfe500000, LDRD_REG_IMM8_SIGNED
}, // STRD <rt>, <rt2>, [<rn>, {, #<imm8>]}{!}
362 { "STREX", 0xe8400f00, 0xfff00f00, LDM_REG_IMM8
}, // STREX <Rt>, [Rn, {#imm8}]]
363 { "STREXB", 0xe8c00f4f, 0xfff00fff, LDREXB
}, // STREXB <Rd>, <Rt>, [<Rn>]
364 { "STREXH", 0xe8c00f5f, 0xfff00fff, LDREXB
}, // STREXH <Rd>, <Rt>, [<Rn>]
366 { "STREXD", 0xe8d00f4f, 0xfff00fff, LDREXD
}, // STREXD <Rd>, <Rt>, <Rt2>, [<Rn>]
368 { "SRSDB", 0xe80dc000, 0xffdffff0, SRS_FORMAT
}, // SRSDB<c> SP{!},#<mode>
369 { "SRS", 0xe98dc000, 0xffdffff0, SRS_FORMAT
}, // SRS{IA}<c> SP{!},#<mode>
370 { "RFEDB", 0xe810c000, 0xffd0ffff, RFE_FORMAT
}, // RFEDB<c> <Rn>{!}
371 { "RFE", 0xe990c000, 0xffd0ffff, RFE_FORMAT
} // RFE{IA}<c> <Rn>{!}
374 CHAR8
*gShiftType
[] = {
381 CHAR8 mThumbMregListStr
[4*15 + 1];
388 UINTN Index
, Start
, End
;
391 mThumbMregListStr
[0] = '\0';
392 AsciiStrCatS (mThumbMregListStr
, sizeof mThumbMregListStr
, "{");
394 for (Index
= 0, First
= TRUE
; Index
<= 15; Index
++) {
395 if ((RegBitMask
& (1 << Index
)) != 0) {
397 for (Index
++; ((RegBitMask
& (1 << Index
)) != 0) && (Index
<= 9); Index
++) {
402 AsciiStrCatS (mThumbMregListStr
, sizeof mThumbMregListStr
, ",");
408 AsciiStrCatS (mThumbMregListStr
, sizeof mThumbMregListStr
, gReg
[Start
]);
410 AsciiStrCatS (mThumbMregListStr
, sizeof mThumbMregListStr
, gReg
[Start
]);
411 AsciiStrCatS (mThumbMregListStr
, sizeof mThumbMregListStr
, "-");
412 AsciiStrCatS (mThumbMregListStr
, sizeof mThumbMregListStr
, gReg
[End
]);
418 AsciiStrCatS (mThumbMregListStr
, sizeof mThumbMregListStr
, "ERROR");
421 AsciiStrCatS (mThumbMregListStr
, sizeof mThumbMregListStr
, "}");
423 // BugBug: Make caller pass in buffer it is cleaner
424 return mThumbMregListStr
;
433 if (((Data
& TopBit
) == 0) || (TopBit
== BIT31
)) {
440 } while ((TopBit
& BIT31
) != BIT31
);
446 // Some instructions specify the PC is always considered aligned
447 // The PC is after the instruction that is executing. So you pass
448 // in the instruction address and you get back the aligned answer
455 return (Data
+ 4) & 0xfffffffc;
459 Place a disassembly of **OpCodePtr into buffer, and update OpCodePtr to
460 point to next instruction.
462 We cheat and only decode instructions that access
463 memory. If the instruction is not found we dump the instruction in hex.
465 @param OpCodePtrPtr Pointer to pointer of ARM Thumb instruction to disassemble.
466 @param Buf Buffer to sprintf disassembly into.
467 @param Size Size of Buf in bytes.
468 @param Extended TRUE dump hex for instruction too.
472 DisassembleThumbInstruction (
473 IN UINT16
**OpCodePtrPtr
,
485 UINT16 Rd
, Rn
, Rm
, Rt
, Rt2
;
488 BOOLEAN IMod
; // imod
490 UINT32 Pc
, Target
, MsBit
, LsBit
;
497 BOOLEAN WriteBack
; // W
498 UINT32 Coproc
, Opc1
, Opc2
, CRd
, CRn
, CRm
;
501 OpCodePtr
= *OpCodePtrPtr
;
502 OpCode
= **OpCodePtrPtr
;
504 // Thumb2 is a stream of 16-bit instructions not a 32-bit instruction.
505 OpCode32
= (((UINT32
)OpCode
) << 16) | *(OpCodePtr
+ 1);
507 // These register names match branch form, but not others
509 Rn
= (OpCode
>> 3) & 0x7;
510 Rm
= (OpCode
>> 6) & 0x7;
511 H1Bit
= (OpCode
& BIT7
) != 0;
512 H2Bit
= (OpCode
& BIT6
) != 0;
513 IMod
= (OpCode
& BIT4
) != 0;
514 Pc
= (UINT32
)(UINTN
)OpCodePtr
;
516 // Increment by the minimum instruction size, Thumb2 could be bigger
519 // Manage IT Block ItFlag TRUE means we are in an IT block
521 /*if (*ItBlock != 0) {
528 for (Index
= 0; Index
< sizeof (gOpThumb
)/sizeof (THUMB_INSTRUCTIONS
); Index
++) {
529 if ((OpCode
& gOpThumb
[Index
].Mask
) == gOpThumb
[Index
].OpCode
) {
531 Offset
= AsciiSPrint (Buf
, Size
, "0x%04x %-6a", OpCode
, gOpThumb
[Index
].Start
);
533 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)));
582 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " 0x%x", OpCode
& 0xff);
585 case CONDITIONAL_BRANCH
:
586 // A6.3.1 B<cond> <target_address>
587 // Patch in the condition code. A little hack but based on "%-6a"
588 Cond
= gCondition
[(OpCode
>> 8) & 0xf];
589 Buf
[Offset
-5] = *Cond
++;
590 Buf
[Offset
-4] = *Cond
;
591 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " 0x%04x", Pc
+ 4 + SignExtend32 ((OpCode
& 0xff) << 1, BIT8
));
593 case UNCONDITIONAL_BRANCH_SHORT
:
594 // A6.3.2 B <target_address>
595 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " 0x%04x", Pc
+ 4 + SignExtend32 ((OpCode
& 0x3ff) << 1, BIT11
));
598 case BRANCH_EXCHANGE
:
599 // A6.3.3 BX|BLX <Rm>
600 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a", gReg
[Rn
| (H2Bit
? 8 : 0)]);
604 // A6.4.3 <Rd>, <Rn>, <Rm>
605 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " r%d, r%d, r%d", Rd
, Rn
, Rm
);
608 // A6.4.3 <Rd>, <Rn>, #3_bit_immed
609 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " r%d, r%d, 0x%x", Rd
, Rn
, Rm
);
612 // A6.4.3 <Rd>|<Rn>, #imm8
613 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " r%d, #0x%x", (OpCode
>> 8) & 7, OpCode
& 0xff);
616 // A6.4.3 <Rd>|<Rm>, #immed_5
617 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " r%d, r%d, 0x%x", Rn
, Rd
, (OpCode
>> 6) & 0x1f);
620 // A6.4.3 <Rd>|<Rm>, <Rm>|<Rs>
621 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " r%d, r%d", Rd
, Rn
);
623 case DATA_FORMAT6_SP
:
624 // A6.4.3 <Rd>, <reg>, #<8_Bit_immed>
625 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " r%d, sp, 0x%x", (OpCode
>> 8) & 7, (OpCode
& 0xff) << 2);
627 case DATA_FORMAT6_PC
:
628 // A6.4.3 <Rd>, <reg>, #<8_Bit_immed>
629 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " r%d, pc, 0x%x", (OpCode
>> 8) & 7, (OpCode
& 0xff) << 2);
632 // A6.4.3 SP, SP, #<7_Bit_immed>
633 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " sp, sp, 0x%x", (OpCode
& 0x7f)*4);
636 // A6.4.3 <Rd>|<Rn>, <Rm>
637 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a, %a", gReg
[Rd
| (H1Bit
? 8 : 0)], gReg
[Rn
| (H2Bit
? 8 : 0)]);
642 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, "%a %a%a%a", IMod
? "ID" : "IE", ((OpCode
& BIT2
) == 0) ? "" : "a", ((OpCode
& BIT1
) == 0) ? "" : "i", ((OpCode
& BIT0
) == 0) ? "" : "f");
647 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a", (OpCode
& BIT3
) == 0 ? "LE" : "BE");
651 // CB{N}Z <Rn>, <Lable>
652 Target
= ((OpCode
>> 2) & 0x3e) | (((OpCode
& BIT9
) == BIT9
) ? BIT6
: 0);
653 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a, %08x", gReg
[Rd
], Pc
+ 4 + Target
);
658 Target
= (OpCode
& 0xff) << 2;
659 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a, %08x", gReg
[(OpCode
>> 8) & 7], PcAlign4 (Pc
) + Target
);
663 // ITSTATE = cond:mask OpCode[7:4]:OpCode[3:0]
664 // ITSTATE[7:5] == cond[3:1]
665 // ITSTATE[4] == 1st Instruction cond[0]
666 // ITSTATE[3] == 2st Instruction cond[0]
667 // ITSTATE[2] == 3st Instruction cond[0]
668 // ITSTATE[1] == 4st Instruction cond[0]
669 // ITSTATE[0] == 1 4 instruction IT block. 0 means 0,1,2 or 3 instructions
670 // 1st one in ITSTATE low bits defines the number of instructions
671 Mask
= (OpCode
& 0xf);
672 if ((Mask
& 0x1) == 0x1) {
674 Offset
+= AsciiSPrint (&Buf
[Offset
], Size
- Offset
, "%a%a%a", (Mask
& BIT3
) ? "T" : "E", (Mask
& BIT2
) ? "T" : "E", (Mask
& BIT1
) ? "T" : "E");
675 } else if ((OpCode
& 0x3) == 0x2) {
677 Offset
+= AsciiSPrint (&Buf
[Offset
], Size
- Offset
, "%a%a", (Mask
& BIT3
) ? "T" : "E", (Mask
& BIT2
) ? "T" : "E");
678 } else if ((OpCode
& 0x7) == 0x4) {
680 Offset
+= AsciiSPrint (&Buf
[Offset
], Size
- Offset
, "%a", (Mask
& BIT3
) ? "T" : "E");
681 } else if ((OpCode
& 0xf) == 0x8) {
685 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a", gCondition
[(OpCode
>> 4) & 0xf]);
691 // Thumb2 are 32-bit instructions
693 Rt
= (OpCode32
>> 12) & 0xf;
694 Rt2
= (OpCode32
>> 8) & 0xf;
695 Rd
= (OpCode32
>> 8) & 0xf;
696 Rm
= (OpCode32
& 0xf);
697 Rn
= (OpCode32
>> 16) & 0xf;
698 for (Index
= 0; Index
< sizeof (gOpThumb2
)/sizeof (THUMB_INSTRUCTIONS
); Index
++) {
699 if ((OpCode32
& gOpThumb2
[Index
].Mask
) == gOpThumb2
[Index
].OpCode
) {
701 Offset
= AsciiSPrint (Buf
, Size
, "0x%04x %-6a", OpCode32
, gOpThumb2
[Index
].Start
);
703 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 Sign
= (OpCode32
& BIT26
) == BIT26
;
723 J1Bit
= (OpCode32
& BIT13
) == BIT13
;
724 J2Bit
= (OpCode32
& BIT11
) == BIT11
;
725 Target
|= (!(J2Bit
^ Sign
) ? BIT22
: 0); // I2
726 Target
|= (!(J1Bit
^ Sign
) ? BIT23
: 0); // I1
727 Target
|= (Sign
? 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 Sign
= (OpCode32
& BIT26
) == BIT26
;
736 J1Bit
= (OpCode32
& BIT13
) == BIT13
;
737 J2Bit
= (OpCode32
& BIT11
) == BIT11
;
738 Target
|= (!(J2Bit
^ Sign
) ? BIT23
: 0); // I2
739 Target
|= (!(J1Bit
^ Sign
) ? BIT24
: 0); // I1
740 Target
|= (Sign
? 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 WriteBack
= (OpCode32
& BIT21
) == BIT21
;
758 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a%a, %a", gReg
[(OpCode32
>> 16) & 0xf], WriteBack
? "!" : "", 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
769 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a, %a", gReg
[(OpCode32
>> 12) & 0xf], PcAlign4 (Pc
) + Target
);
772 case LDM_REG_INDIRECT_LSL
:
773 // <rt>, [<rn>, <rm> {, LSL #<imm2>]}
774 Offset
+= AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a, [%a, %a", gReg
[Rt
], gReg
[Rn
], gReg
[Rm
]);
775 if (((OpCode32
>> 4) & 3) == 0) {
776 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, "]");
778 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, ", LSL #%d]", (OpCode32
>> 4) & 3);
784 // <rt>, [<rn>, {, #<imm12>]}
785 Offset
+= AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a, [%a", gReg
[Rt
], gReg
[Rn
]);
786 if ((OpCode32
& 0xfff) == 0) {
787 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, "]");
789 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, ", #0x%x]", OpCode32
& 0xfff);
795 // <rt>, [<rn>, {, #<imm8>}]{!}
796 WriteBack
= (OpCode32
& BIT8
) == BIT8
;
797 UAdd
= (OpCode32
& BIT9
) == BIT9
;
798 Pre
= (OpCode32
& BIT10
) == BIT10
;
799 Offset
+= AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a, [%a", gReg
[Rt
], gReg
[Rn
]);
801 if ((OpCode32
& 0xff) == 0) {
802 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, "]%a", WriteBack
? "!" : "");
804 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, ", #%a0x%x]%a", UAdd
? "" : "-", OpCode32
& 0xff, WriteBack
? "!" : "");
807 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, "], #%a0x%x", UAdd
? "" : "-", OpCode32
& 0xff);
812 case LDRD_REG_IMM8_SIGNED
:
813 // LDRD <rt>, <rt2>, [<rn>, {, #<imm8>]}{!}
814 Pre
= (OpCode32
& BIT24
) == BIT24
; // index = P
815 UAdd
= (OpCode32
& BIT23
) == BIT23
;
816 WriteBack
= (OpCode32
& BIT21
) == BIT21
;
817 Offset
+= AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a, %a, [%a", gReg
[Rt
], gReg
[Rt2
], gReg
[Rn
]);
819 if ((OpCode32
& 0xff) == 0) {
820 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, "]");
822 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, ", #%a0x%x]%a", UAdd
? "" : "-", (OpCode32
& 0xff) << 2, WriteBack
? "!" : "");
825 if ((OpCode32
& 0xff) != 0) {
826 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, ", #%a0x%x", UAdd
? "" : "-", (OpCode32
& 0xff) << 2);
833 // LDRD <rt>, <rt2>, <label>
834 Target
= (OpCode32
& 0xff) << 2;
835 if ((OpCode32
& BIT23
) == 0) {
836 // U == 0 means subtrack, U == 1 means add
840 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a, %a, %a", gReg
[Rt
], gReg
[Rt2
], Pc
+ 4 + Target
);
845 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a, [%a]", gReg
[Rt
], gReg
[Rn
]);
849 // LDREXD <Rt>, <Rt2>, [<Rn>]
850 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a, ,%a, [%a]", gReg
[Rt
], gReg
[Rt2
], gReg
[Rn
]);
855 WriteBack
= (OpCode32
& BIT21
) == BIT21
;
856 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " SP%a, #0x%x", WriteBack
? "!" : "", OpCode32
& 0x1f);
861 WriteBack
= (OpCode32
& BIT21
) == BIT21
;
862 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a%a, #0x%x", gReg
[Rn
], WriteBack
? "!" : "");
866 // ADD{S} <Rd>, <Rn>, #<const> i:imm3:imm8
867 if ((OpCode32
& BIT20
) == BIT20
) {
868 Buf
[Offset
- 3] = 'S'; // assume %-6a
871 Target
= (OpCode32
& 0xff) | ((OpCode32
>> 4) & 0x700) | ((OpCode
& BIT26
) == BIT26
? BIT11
: 0);
872 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a, %a, #0x%x", gReg
[Rd
], gReg
[Rn
], Target
);
876 // MOV{S} <Rd>, #<const> i:imm3:imm8
877 if ((OpCode32
& BIT20
) == BIT20
) {
878 Buf
[Offset
- 3] = 'S'; // assume %-6a
881 Target
= (OpCode32
& 0xff) | ((OpCode32
>> 4) & 0x700) | ((OpCode
& BIT26
) == BIT26
? BIT11
: 0);
882 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a, #0x%x", gReg
[Rd
], Target
);
886 // MOVW <Rd>, #<const> i:imm3:imm8
887 Target
= (OpCode32
& 0xff) | ((OpCode32
>> 4) & 0x700) | ((OpCode
& BIT26
) == BIT26
? BIT11
: 0);
888 Target
|= ((OpCode32
>> 4) & 0xf0000);
889 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a, #0x%x", gReg
[Rd
], Target
);
893 // ADC{S} <Rd>, <Rn>, <Rm> {,LSL #<const>} imm3:imm2
894 if ((OpCode32
& BIT20
) == BIT20
) {
895 Buf
[Offset
- 3] = 'S'; // assume %-6a
898 Target
= ((OpCode32
>> 6) & 3) | ((OpCode32
>> 10) & 0x1c0);
899 Offset
+= AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a, %a, %a", gReg
[Rd
], gReg
[Rn
], gReg
[Rm
]);
901 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, ", LSL %d", gShiftType
[(OpCode
>> 5) & 3], Target
);
907 // CMP <Rn>, <Rm> {,LSL #<const>} imm3:imm2
908 Target
= ((OpCode32
>> 6) & 3) | ((OpCode32
>> 10) & 0x1c0);
909 Offset
+= AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a, %a", gReg
[Rn
], gReg
[Rm
]);
911 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, ", LSL %d", gShiftType
[(OpCode
>> 5) & 3], Target
);
915 // ARS <Rd>, <Rm> #<const>} imm3:imm2
916 if ((OpCode32
& BIT20
) == BIT20
) {
917 Buf
[Offset
- 3] = 'S'; // assume %-6a
920 Target
= ((OpCode32
>> 6) & 3) | ((OpCode32
>> 10) & 0x1c0);
921 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a, %a #%d", gReg
[Rd
], gReg
[Rm
], Target
);
925 // ARS <Rd>, <Rn>, <Rm>
926 if ((OpCode32
& BIT20
) == BIT20
) {
927 Buf
[Offset
- 3] = 'S'; // assume %-6a
930 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a, %a %a", gReg
[Rd
], gReg
[Rn
], gReg
[Rm
]);
934 // ADDR <Rd>, <label>
935 Target
= (OpCode32
& 0xff) | ((OpCode32
>> 8) & 0x700) | ((OpCode
& BIT26
) == BIT26
? BIT11
: 0);
936 if ((OpCode
& (BIT23
| BIT21
)) == (BIT23
| BIT21
)) {
937 Target
= PcAlign4 (Pc
) - Target
;
939 Target
= PcAlign4 (Pc
) + Target
;
942 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a, 0x%08x", gReg
[Rd
], Target
);
946 // CMN <Rn>, #<const>}
947 Target
= (OpCode32
& 0xff) | ((OpCode
>> 4) & 0x700) | ((OpCode
& BIT26
) == BIT26
? BIT11
: 0);
948 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a, #0x%x", gReg
[Rn
], Target
);
952 // BFI <Rd>, <Rn>, #<lsb>, #<width>
953 MsBit
= OpCode32
& 0x1f;
954 LsBit
= ((OpCode32
>> 6) & 3) | ((OpCode
>> 10) & 0x1c);
955 if ((Rn
== 0xf) & (AsciiStrCmp (gOpThumb2
[Index
].Start
, "BFC") == 0)) {
956 // BFC <Rd>, #<lsb>, #<width>
957 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a, #%d, #%d", gReg
[Rd
], LsBit
, MsBit
- LsBit
+ 1);
958 } else if (AsciiStrCmp (gOpThumb2
[Index
].Start
, "BFI") == 0) {
959 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a, %a, #%d, #%d", gReg
[Rd
], gReg
[Rn
], LsBit
, MsBit
- LsBit
+ 1);
961 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a, %a, #%d, #%d", gReg
[Rd
], gReg
[Rn
], LsBit
, MsBit
+ 1);
967 // <coproc>,<opc1>,<CRd>,<CRn>,<CRm>,<opc2>
968 Coproc
= (OpCode32
>> 8) & 0xf;
969 Opc1
= (OpCode32
>> 20) & 0xf;
970 Opc2
= (OpCode32
>> 5) & 0x7;
971 CRd
= (OpCode32
>> 12) & 0xf;
972 CRn
= (OpCode32
>> 16) & 0xf;
973 CRm
= OpCode32
& 0xf;
974 Offset
+= AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " p%d,#%d,c%d,c%d,c%d", Coproc
, Opc1
, CRd
, CRn
, CRm
);
976 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, ",#%d,", Opc2
);
982 // MRC <coproc>,<opc1>,<Rt>,<CRn>,<CRm>,<opc2>
983 Coproc
= (OpCode32
>> 8) & 0xf;
984 Opc1
= (OpCode32
>> 20) & 0xf;
985 Opc2
= (OpCode32
>> 5) & 0x7;
986 CRn
= (OpCode32
>> 16) & 0xf;
987 CRm
= OpCode32
& 0xf;
988 Offset
+= AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " p%d,#%d,%a,c%d,c%d", Coproc
, Opc1
, gReg
[Rt
], CRn
, CRm
);
990 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, ",#%d,", Opc2
);
996 // MRC <coproc>,<opc1>,<Rt>,<Rt2>,<CRm>,<opc2>
997 Coproc
= (OpCode32
>> 8) & 0xf;
998 Opc1
= (OpCode32
>> 20) & 0xf;
999 CRn
= (OpCode32
>> 16) & 0xf;
1000 CRm
= OpCode32
& 0xf;
1001 Offset
+= AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " p%d,#%d,%a,%a,c%d", Coproc
, Opc1
, gReg
[Rt
], gReg
[Rt2
], CRm
);
1006 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a, %a", gReg
[Rd
], gReg
[Rm
]);
1010 // <Rd>, <Rn>, <Rm>, <Ra>
1011 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a, %a, %a, %a", gReg
[Rd
], gReg
[Rn
], gReg
[Rm
], gReg
[Rt
]);
1016 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a, CPSR", gReg
[Rd
]);
1020 // MRS CPSR_<fields>, <Rd>
1021 Target
= (OpCode32
>> 10) & 3;
1022 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " CPSR_%a%a, %a", (Target
& 2) == 0 ? "" : "f", (Target
& 1) == 0 ? "" : "s", gReg
[Rd
]);
1025 case THUMB2_NO_ARGS
:
1032 AsciiSPrint (Buf
, Size
, "0x%08x", OpCode32
);
1036 DisassembleArmInstruction (
1037 IN UINT32
**OpCodePtr
,
1044 Place a disassembly of **OpCodePtr into buffer, and update OpCodePtr to
1045 point to next instruction.
1047 We cheat and only decode instructions that access
1048 memory. If the instruction is not found we dump the instruction in hex.
1050 @param OpCodePtrPtr Pointer to pointer of ARM Thumb instruction to disassemble.
1051 @param Thumb TRUE for Thumb(2), FALSE for ARM instruction stream
1052 @param Extended TRUE dump hex for instruction too.
1053 @param ItBlock Size of IT Block
1054 @param Buf Buffer to sprintf disassembly into.
1055 @param Size Size of Buf in bytes.
1059 DisassembleInstruction (
1060 IN UINT8
**OpCodePtr
,
1062 IN BOOLEAN Extended
,
1063 IN OUT UINT32
*ItBlock
,
1069 DisassembleThumbInstruction ((UINT16
**)OpCodePtr
, Buf
, Size
, ItBlock
, Extended
);
1071 DisassembleArmInstruction ((UINT32
**)OpCodePtr
, Buf
, Size
, Extended
);