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
104 } THUMB_INSTRUCTIONS
;
106 THUMB_INSTRUCTIONS gOpThumb
[] = {
107 // Thumb 16-bit instructions
109 { "ADC" , 0x4140, 0xffc0, DATA_FORMAT5
}, // ADC <Rndn>, <Rm>
110 { "ADR", 0xa000, 0xf800, ADR_FORMAT
}, // ADR <Rd>, <label>
111 { "ADD" , 0x1c00, 0xfe00, DATA_FORMAT2
},
112 { "ADD" , 0x3000, 0xf800, DATA_FORMAT3
},
113 { "ADD" , 0x1800, 0xfe00, DATA_FORMAT1
},
114 { "ADD" , 0x4400, 0xff00, DATA_FORMAT8
}, // A8.6.9
115 { "ADD" , 0xa000, 0xf100, DATA_FORMAT6_PC
},
116 { "ADD" , 0xa800, 0xf800, DATA_FORMAT6_SP
},
117 { "ADD" , 0xb000, 0xff80, DATA_FORMAT7
},
119 { "AND" , 0x4000, 0xffc0, DATA_FORMAT5
},
121 { "ASR" , 0x1000, 0xf800, DATA_FORMAT4
},
122 { "ASR" , 0x4100, 0xffc0, DATA_FORMAT5
},
124 { "B" , 0xd000, 0xf000, CONDITIONAL_BRANCH
},
125 { "B" , 0xe000, 0xf800, UNCONDITIONAL_BRANCH_SHORT
},
126 { "BLX" , 0x4780, 0xff80, BRANCH_EXCHANGE
},
127 { "BX" , 0x4700, 0xff87, BRANCH_EXCHANGE
},
129 { "BIC" , 0x4380, 0xffc0, DATA_FORMAT5
},
130 { "BKPT", 0xdf00, 0xff00, IMMED_8
},
131 { "CBZ", 0xb100, 0xfd00, DATA_CBZ
},
132 { "CBNZ", 0xb900, 0xfd00, DATA_CBZ
},
133 { "CMN" , 0x42c0, 0xffc0, DATA_FORMAT5
},
135 { "CMP" , 0x2800, 0xf800, DATA_FORMAT3
},
136 { "CMP" , 0x4280, 0xffc0, DATA_FORMAT5
},
137 { "CMP" , 0x4500, 0xff00, DATA_FORMAT8
},
139 { "CPS" , 0xb660, 0xffe8, CPS_FORMAT
},
140 { "MOV" , 0x4600, 0xff00, DATA_FORMAT8
},
141 { "EOR" , 0x4040, 0xffc0, DATA_FORMAT5
},
143 { "LDMIA" , 0xc800, 0xf800, LOAD_STORE_MULTIPLE_FORMAT1
},
144 { "LDR" , 0x6800, 0xf800, LOAD_STORE_FORMAT1
}, // LDR <Rt>, [<Rn> {,#<imm>}]
145 { "LDR" , 0x5800, 0xfe00, LOAD_STORE_FORMAT2
}, // STR <Rt>, [<Rn>, <Rm>]
146 { "LDR" , 0x4800, 0xf800, LOAD_STORE_FORMAT3
},
147 { "LDR" , 0x9800, 0xf800, LOAD_STORE_FORMAT4
}, // LDR <Rt>, [SP, #<imm>]
148 { "LDRB" , 0x7800, 0xf800, LOAD_STORE_FORMAT1_B
},
149 { "LDRB" , 0x5c00, 0xfe00, LOAD_STORE_FORMAT2
}, // STR <Rt>, [<Rn>, <Rm>]
150 { "LDRH" , 0x8800, 0xf800, LOAD_STORE_FORMAT1_H
},
151 { "LDRH" , 0x7a00, 0xfe00, LOAD_STORE_FORMAT2
},
152 { "LDRSB" , 0x5600, 0xfe00, LOAD_STORE_FORMAT2
}, // STR <Rt>, [<Rn>, <Rm>]
153 { "LDRSH" , 0x5e00, 0xfe00, LOAD_STORE_FORMAT2
},
155 { "MOVS", 0x0000, 0xffc0, DATA_FORMAT5
}, // LSL with imm5 == 0 is a MOVS, so this must go before LSL
156 { "LSL" , 0x0000, 0xf800, DATA_FORMAT4
},
157 { "LSL" , 0x4080, 0xffc0, DATA_FORMAT5
},
158 { "LSR" , 0x0001, 0xf800, DATA_FORMAT4
},
159 { "LSR" , 0x40c0, 0xffc0, DATA_FORMAT5
},
160 { "LSRS", 0x0800, 0xf800, DATA_FORMAT4
}, // LSRS <Rd>, <Rm>, #<imm5>
162 { "MOVS", 0x2000, 0xf800, DATA_FORMAT3
},
163 { "MOV" , 0x1c00, 0xffc0, DATA_FORMAT3
},
164 { "MOV" , 0x4600, 0xff00, DATA_FORMAT8
},
166 { "MUL" , 0x4340, 0xffc0, DATA_FORMAT5
},
167 { "MVN" , 0x41c0, 0xffc0, DATA_FORMAT5
},
168 { "NEG" , 0x4240, 0xffc0, DATA_FORMAT5
},
169 { "ORR" , 0x4300, 0xffc0, DATA_FORMAT5
},
170 { "POP" , 0xbc00, 0xfe00, POP_FORMAT
},
171 { "PUSH", 0xb400, 0xfe00, PUSH_FORMAT
},
173 { "REV" , 0xba00, 0xffc0, DATA_FORMAT5
},
174 { "REV16" , 0xba40, 0xffc0, DATA_FORMAT5
},
175 { "REVSH" , 0xbac0, 0xffc0, DATA_FORMAT5
},
177 { "ROR" , 0x41c0, 0xffc0, DATA_FORMAT5
},
178 { "SBC" , 0x4180, 0xffc0, DATA_FORMAT5
},
179 { "SETEND" , 0xb650, 0xfff0, ENDIAN_FORMAT
},
181 { "STMIA" , 0xc000, 0xf800, LOAD_STORE_MULTIPLE_FORMAT1
},
182 { "STR" , 0x6000, 0xf800, LOAD_STORE_FORMAT1
}, // STR <Rt>, [<Rn> {,#<imm>}]
183 { "STR" , 0x5000, 0xfe00, LOAD_STORE_FORMAT2
}, // STR <Rt>, [<Rn>, <Rm>]
184 { "STR" , 0x9000, 0xf800, LOAD_STORE_FORMAT4
}, // STR <Rt>, [SP, #<imm>]
185 { "STRB" , 0x7000, 0xf800, LOAD_STORE_FORMAT1_B
}, // STRB <Rt>, [<Rn>, #<imm5>]
186 { "STRB" , 0x5400, 0xfe00, LOAD_STORE_FORMAT2
}, // STRB <Rt>, [<Rn>, <Rm>]
187 { "STRH" , 0x8000, 0xf800, LOAD_STORE_FORMAT1_H
}, // STRH <Rt>, [<Rn>{,#<imm>}]
188 { "STRH" , 0x5200, 0xfe00, LOAD_STORE_FORMAT2
}, // STRH <Rt>, [<Rn>, <Rm>]
190 { "SUB" , 0x1e00, 0xfe00, DATA_FORMAT2
},
191 { "SUB" , 0x3800, 0xf800, DATA_FORMAT3
},
192 { "SUB" , 0x1a00, 0xfe00, DATA_FORMAT1
},
193 { "SUB" , 0xb080, 0xff80, DATA_FORMAT7
},
195 { "SBC" , 0x4180, 0xffc0, DATA_FORMAT5
},
197 { "SWI" , 0xdf00, 0xff00, IMMED_8
},
198 { "SXTB", 0xb240, 0xffc0, DATA_FORMAT5
},
199 { "SXTH", 0xb200, 0xffc0, DATA_FORMAT5
},
200 { "TST" , 0x4200, 0xffc0, DATA_FORMAT5
},
201 { "UXTB", 0xb2c0, 0xffc0, DATA_FORMAT5
},
202 { "UXTH", 0xb280, 0xffc0, DATA_FORMAT5
},
204 { "IT", 0xbf00, 0xff00, IT_BLOCK
}
208 THUMB_INSTRUCTIONS gOpThumb2
[] = {
209 //Instruct OpCode OpCode Mask Addressig Mode
211 { "ADR", 0xf2af0000, 0xfbff8000, ADR_THUMB2
}, // ADDR <Rd>, <label> ;Needs to go before ADDW
212 { "CMN", 0xf1100f00, 0xfff08f00, CMN_THUMB2
}, // CMN <Rn>, #<const> ;Needs to go before ADD
213 { "CMN", 0xeb100f00, 0xfff08f00, ADD_IMM5_2REG
}, // CMN <Rn>, <Rm> {,<shift> #<const>}
214 { "CMP", 0xf1a00f00, 0xfff08f00, CMN_THUMB2
}, // CMP <Rn>, #<const>
215 { "TEQ", 0xf0900f00, 0xfff08f00, CMN_THUMB2
}, // CMP <Rn>, #<const>
216 { "TEQ", 0xea900f00, 0xfff08f00, ADD_IMM5_2REG
}, // CMN <Rn>, <Rm> {,<shift> #<const>}
217 { "TST", 0xf0100f00, 0xfff08f00, CMN_THUMB2
}, // CMP <Rn>, #<const>
218 { "TST", 0xea100f00, 0xfff08f00, ADD_IMM5_2REG
}, // TST <Rn>, <Rm> {,<shift> #<const>}
220 { "MOV", 0xf04f0000, 0xfbef8000, ADD_IMM12_1REG
}, // MOV <Rd>, #<const>
221 { "MOVW", 0xf2400000, 0xfbe08000, THUMB2_IMM16
}, // MOVW <Rd>, #<const>
222 { "MOVT", 0xf2c00000, 0xfbe08000, THUMB2_IMM16
}, // MOVT <Rd>, #<const>
224 { "ADC", 0xf1400000, 0xfbe08000, ADD_IMM12
}, // ADC{S} <Rd>, <Rn>, #<const>
225 { "ADC", 0xeb400000, 0xffe08000, ADD_IMM5
}, // ADC{S} <Rd>, <Rn>, <Rm> {,<shift> #<const>}
226 { "ADD", 0xf1000000, 0xfbe08000, ADD_IMM12
}, // ADD{S} <Rd>, <Rn>, #<const>
227 { "ADD", 0xeb000000, 0xffe08000, ADD_IMM5
}, // ADD{S} <Rd>, <Rn>, <Rm> {,<shift> #<const>}
228 { "ADDW", 0xf2000000, 0xfbe08000, ADD_IMM12
}, // ADDW{S} <Rd>, <Rn>, #<const>
229 { "AND", 0xf0000000, 0xfbe08000, ADD_IMM12
}, // AND{S} <Rd>, <Rn>, #<const>
230 { "AND", 0xea000000, 0xffe08000, ADD_IMM5
}, // AND{S} <Rd>, <Rn>, <Rm> {,<shift> #<const>}
231 { "BIC", 0xf0200000, 0xfbe08000, ADD_IMM12
}, // BIC{S} <Rd>, <Rn>, #<const>
232 { "BIC", 0xea200000, 0xffe08000, ADD_IMM5
}, // BIC{S} <Rd>, <Rn>, <Rm> {,<shift> #<const>}
233 { "EOR", 0xf0800000, 0xfbe08000, ADD_IMM12
}, // EOR{S} <Rd>, <Rn>, #<const>
234 { "EOR", 0xea800000, 0xffe08000, ADD_IMM5
}, // EOR{S} <Rd>, <Rn>, <Rm> {,<shift> #<const>}
235 { "ORN", 0xf0600000, 0xfbe08000, ADD_IMM12
}, // ORN{S} <Rd>, <Rn>, #<const>
236 { "ORN", 0xea600000, 0xffe08000, ADD_IMM5
}, // ORN{S} <Rd>, <Rn>, <Rm> {,<shift> #<const>}
237 { "ORR", 0xf0400000, 0xfbe08000, ADD_IMM12
}, // ORR{S} <Rd>, <Rn>, #<const>
238 { "ORR", 0xea400000, 0xffe08000, ADD_IMM5
}, // ORR{S} <Rd>, <Rn>, <Rm> {,<shift> #<const>}
239 { "RSB", 0xf1c00000, 0xfbe08000, ADD_IMM12
}, // RSB{S} <Rd>, <Rn>, #<const>
240 { "RSB", 0xebc00000, 0xffe08000, ADD_IMM5
}, // RSB{S} <Rd>, <Rn>, <Rm> {,<shift> #<const>}
241 { "SBC", 0xf1600000, 0xfbe08000, ADD_IMM12
}, // SBC{S} <Rd>, <Rn>, #<const>
242 { "SBC", 0xeb600000, 0xffe08000, ADD_IMM5
}, // SBC{S} <Rd>, <Rn>, <Rm> {,<shift> #<const>}
243 { "SUB", 0xf1a00000, 0xfbe08000, ADD_IMM12
}, // SUB{S} <Rd>, <Rn>, #<const>
244 { "SUB", 0xeba00000, 0xffe08000, ADD_IMM5
}, // SUB{S} <Rd>, <Rn>, <Rm> {,<shift> #<const>}
246 { "ASR", 0xea4f0020, 0xffef8030, ASR_IMM5
}, // ARS <Rd>, <Rm> #<const>} imm3:imm2
247 { "ASR", 0xfa40f000, 0xffe0f0f0, ASR_3REG
}, // ARS <Rd>, <Rn>, <Rm>
248 { "LSR", 0xea4f0010, 0xffef8030, ASR_IMM5
}, // LSR <Rd>, <Rm> #<const>} imm3:imm2
249 { "LSR", 0xfa20f000, 0xffe0f0f0, ASR_3REG
}, // LSR <Rd>, <Rn>, <Rm>
250 { "ROR", 0xea4f0030, 0xffef8030, ASR_IMM5
}, // ROR <Rd>, <Rm> #<const>} imm3:imm2
251 { "ROR", 0xfa60f000, 0xffe0f0f0, ASR_3REG
}, // ROR <Rd>, <Rn>, <Rm>
253 { "BFC", 0xf36f0000, 0xffff8010, BFC_THUMB2
}, // BFC <Rd>, #<lsb>, #<width>
254 { "BIC", 0xf3600000, 0xfff08010, BFC_THUMB2
}, // BIC <Rn>, <Rd>, #<lsb>, #<width>
255 { "SBFX", 0xf3400000, 0xfff08010, BFC_THUMB2
}, // SBFX <Rn>, <Rd>, #<lsb>, #<width>
256 { "UBFX", 0xf3c00000, 0xfff08010, BFC_THUMB2
}, // UBFX <Rn>, <Rd>, #<lsb>, #<width>
258 { "CPD", 0xee000000, 0xff000010, CPD_THUMB2
}, // CPD <coproc>,<opc1>,<CRd>,<CRn>,<CRm>,<opc2>
259 { "CPD2", 0xfe000000, 0xff000010, CPD_THUMB2
}, // CPD <coproc>,<opc1>,<CRd>,<CRn>,<CRm>,<opc2>
261 { "MRC", 0xee100000, 0xff100000, MRC_THUMB2
}, // MRC <coproc>,<opc1>,<Rt>,<CRn>,<CRm>,<opc2>
262 { "MRC2", 0xfe100000, 0xff100000, MRC_THUMB2
}, // MRC2 <coproc>,<opc1>,<Rt>,<CRn>,<CRm>,<opc2>
263 { "MRRC", 0xec500000, 0xfff00000, MRRC_THUMB2
}, // MRRC <coproc>,<opc1>,<Rt>,<Rt2>,<CRm>
264 { "MRRC2", 0xfc500000, 0xfff00000, MRRC_THUMB2
}, // MRR2 <coproc>,<opc1>,<Rt>,<Rt2>,<CRm>
266 { "MRS", 0xf3ef8000, 0xfffff0ff, THUMB2_MRS
}, // MRS <Rd>, CPSR
267 { "MSR", 0xf3808000, 0xfff0fcff, THUMB2_MSR
}, // MSR CPSR_fs, <Rn>
269 { "CLREX", 0xf3bf8f2f, 0xfffffff, THUMB2_NO_ARGS
}, // CLREX
271 { "CLZ", 0xfab0f080, 0xfff0f0f0, THUMB2_2REGS
}, // CLZ <Rd>,<Rm>
272 { "MOV", 0xec4f0000, 0xfff0f0f0, THUMB2_2REGS
}, // MOV <Rd>,<Rm>
273 { "MOVS", 0xec5f0000, 0xfff0f0f0, THUMB2_2REGS
}, // MOVS <Rd>,<Rm>
274 { "RBIT", 0xfb90f0a0, 0xfff0f0f0, THUMB2_2REGS
}, // RBIT <Rd>,<Rm>
275 { "REV", 0xfb90f080, 0xfff0f0f0, THUMB2_2REGS
}, // REV <Rd>,<Rm>
276 { "REV16", 0xfa90f090, 0xfff0f0f0, THUMB2_2REGS
}, // REV16 <Rd>,<Rm>
277 { "REVSH", 0xfa90f0b0, 0xfff0f0f0, THUMB2_2REGS
}, // REVSH <Rd>,<Rm>
278 { "RRX", 0xea4f0030, 0xfffff0f0, THUMB2_2REGS
}, // RRX <Rd>,<Rm>
279 { "RRXS", 0xea5f0030, 0xfffff0f0, THUMB2_2REGS
}, // RRXS <Rd>,<Rm>
281 { "MLA", 0xfb000000, 0xfff000f0, THUMB2_4REGS
}, // MLA <Rd>, <Rn>, <Rm>, <Ra>
282 { "MLS", 0xfb000010, 0xfff000f0, THUMB2_4REGS
}, // MLA <Rd>, <Rn>, <Rm>, <Ra>
285 { "SMLABB", 0xfb100000, 0xfff000f0, THUMB2_4REGS
}, // SMLABB <Rd>, <Rn>, <Rm>, <Ra>
286 { "SMLABT", 0xfb100010, 0xfff000f0, THUMB2_4REGS
}, // SMLABT <Rd>, <Rn>, <Rm>, <Ra>
287 { "SMLABB", 0xfb100020, 0xfff000f0, THUMB2_4REGS
}, // SMLATB <Rd>, <Rn>, <Rm>, <Ra>
288 { "SMLATT", 0xfb100030, 0xfff000f0, THUMB2_4REGS
}, // SMLATT <Rd>, <Rn>, <Rm>, <Ra>
289 { "SMLAWB", 0xfb300000, 0xfff000f0, THUMB2_4REGS
}, // SMLAWB <Rd>, <Rn>, <Rm>, <Ra>
290 { "SMLAWT", 0xfb300010, 0xfff000f0, THUMB2_4REGS
}, // SMLAWT <Rd>, <Rn>, <Rm>, <Ra>
291 { "SMLSD", 0xfb400000, 0xfff000f0, THUMB2_4REGS
}, // SMLSD <Rd>, <Rn>, <Rm>, <Ra>
292 { "SMLSDX", 0xfb400010, 0xfff000f0, THUMB2_4REGS
}, // SMLSDX <Rd>, <Rn>, <Rm>, <Ra>
293 { "SMMLA", 0xfb500000, 0xfff000f0, THUMB2_4REGS
}, // SMMLA <Rd>, <Rn>, <Rm>, <Ra>
294 { "SMMLAR", 0xfb500010, 0xfff000f0, THUMB2_4REGS
}, // SMMLAR <Rd>, <Rn>, <Rm>, <Ra>
295 { "SMMLS", 0xfb600000, 0xfff000f0, THUMB2_4REGS
}, // SMMLS <Rd>, <Rn>, <Rm>, <Ra>
296 { "SMMLSR", 0xfb600010, 0xfff000f0, THUMB2_4REGS
}, // SMMLSR <Rd>, <Rn>, <Rm>, <Ra>
297 { "USADA8", 0xfb700000, 0xfff000f0, THUMB2_4REGS
}, // USADA8 <Rd>, <Rn>, <Rm>, <Ra>
298 { "SMLAD", 0xfb200000, 0xfff000f0, THUMB2_4REGS
}, // SMLAD <Rd>, <Rn>, <Rm>, <Ra>
299 { "SMLADX", 0xfb200010, 0xfff000f0, THUMB2_4REGS
}, // SMLADX <Rd>, <Rn>, <Rm>, <Ra>
302 { "B", 0xf0008000, 0xf800d000, B_T3
}, // B<c> <label>
303 { "B", 0xf0009000, 0xf800d000, B_T4
}, // B<c> <label>
304 { "BL", 0xf000d000, 0xf800d000, B_T4
}, // BL<c> <label>
305 { "BLX", 0xf000c000, 0xf800d000, BL_T2
}, // BLX<c> <label>
307 { "POP", 0xe8bd0000, 0xffff2000, POP_T2
}, // POP <registers>
308 { "POP", 0xf85d0b04, 0xffff0fff, POP_T3
}, // POP <register>
309 { "PUSH", 0xe8ad0000, 0xffffa000, POP_T2
}, // PUSH <registers>
310 { "PUSH", 0xf84d0d04, 0xffff0fff, POP_T3
}, // PUSH <register>
311 { "STM" , 0xe8800000, 0xffd0a000, STM_FORMAT
}, // STM <Rn>{!},<registers>
312 { "STMDB", 0xe9800000, 0xffd0a000, STM_FORMAT
}, // STMDB <Rn>{!},<registers>
313 { "LDM" , 0xe8900000, 0xffd02000, STM_FORMAT
}, // LDM <Rn>{!},<registers>
314 { "LDMDB", 0xe9100000, 0xffd02000, STM_FORMAT
}, // LDMDB <Rn>{!},<registers>
316 { "LDR", 0xf8d00000, 0xfff00000, LDM_REG_IMM12
}, // LDR <rt>, [<rn>, {, #<imm12>]}
317 { "LDRB", 0xf8900000, 0xfff00000, LDM_REG_IMM12
}, // LDRB <rt>, [<rn>, {, #<imm12>]}
318 { "LDRH", 0xf8b00000, 0xfff00000, LDM_REG_IMM12
}, // LDRH <rt>, [<rn>, {, #<imm12>]}
319 { "LDRSB", 0xf9900000, 0xfff00000, LDM_REG_IMM12
}, // LDRSB <rt>, [<rn>, {, #<imm12>]}
320 { "LDRSH", 0xf9b00000, 0xfff00000, LDM_REG_IMM12
}, // LDRSH <rt>, [<rn>, {, #<imm12>]}
322 { "LDR", 0xf85f0000, 0xff7f0000, LDM_REG_IMM12_SIGNED
}, // LDR <Rt>, <label>
323 { "LDRB", 0xf81f0000, 0xff7f0000, LDM_REG_IMM12_SIGNED
}, // LDRB <Rt>, <label>
324 { "LDRH", 0xf83f0000, 0xff7f0000, LDM_REG_IMM12_SIGNED
}, // LDRH <Rt>, <label>
325 { "LDRSB", 0xf91f0000, 0xff7f0000, LDM_REG_IMM12_SIGNED
}, // LDRSB <Rt>, <label>
326 { "LDRSH", 0xf93f0000, 0xff7f0000, LDM_REG_IMM12_SIGNED
}, // LDRSB <Rt>, <label>
328 { "LDR", 0xf8500000, 0xfff00fc0, LDM_REG_INDIRECT_LSL
}, // LDR <rt>, [<rn>, <rm> {, LSL #<imm2>]}
329 { "LDRB", 0xf8100000, 0xfff00fc0, LDM_REG_INDIRECT_LSL
}, // LDRB <rt>, [<rn>, <rm> {, LSL #<imm2>]}
330 { "LDRH", 0xf8300000, 0xfff00fc0, LDM_REG_INDIRECT_LSL
}, // LDRH <rt>, [<rn>, <rm> {, LSL #<imm2>]}
331 { "LDRSB", 0xf9100000, 0xfff00fc0, LDM_REG_INDIRECT_LSL
}, // LDRSB <rt>, [<rn>, <rm> {, LSL #<imm2>]}
332 { "LDRSH", 0xf9300000, 0xfff00fc0, LDM_REG_INDIRECT_LSL
}, // LDRSH <rt>, [<rn>, <rm> {, LSL #<imm2>]}
334 { "LDR", 0xf8500800, 0xfff00800, LDM_REG_IMM8
}, // LDR <rt>, [<rn>, {, #<imm8>]}
335 { "LDRBT", 0xf8100e00, 0xfff00f00, LDM_REG_IMM8
}, // LDRBT <rt>, [<rn>, {, #<imm8>]}
336 { "LDRHT", 0xf8300e00, 0xfff00f00, LDM_REG_IMM8
}, // LDRHT <rt>, [<rn>, {, #<imm8>]}
337 { "LDRSB", 0xf9100800, 0xfff00800, LDM_REG_IMM8
}, // LDRHT <rt>, [<rn>, {, #<imm8>]} {!} form?
338 { "LDRSBT",0xf9100e00, 0xfff00f00, LDM_REG_IMM8
}, // LDRHBT <rt>, [<rn>, {, #<imm8>]} {!} form?
339 { "LDRSH" ,0xf9300800, 0xfff00800, LDM_REG_IMM8
}, // LDRSH <rt>, [<rn>, {, #<imm8>]}
340 { "LDRSHT",0xf9300e00, 0xfff00f00, LDM_REG_IMM8
}, // LDRSHT <rt>, [<rn>, {, #<imm8>]}
341 { "LDRT", 0xf8500e00, 0xfff00f00, LDM_REG_IMM8
}, // LDRT <rt>, [<rn>, {, #<imm8>]}
343 { "LDRD", 0xe8500000, 0xfe500000, LDRD_REG_IMM8_SIGNED
}, // LDRD <rt>, <rt2>, [<rn>, {, #<imm8>]}{!}
344 { "LDRD", 0xe8500000, 0xfe500000, LDRD_REG_IMM8
}, // LDRD <rt>, <rt2>, <label>
346 { "LDREX", 0xe8500f00, 0xfff00f00, LDM_REG_IMM8
}, // LDREX <Rt>, [Rn, {#imm8}]]
347 { "LDREXB", 0xe8d00f4f, 0xfff00fff, LDREXB
}, // LDREXB <Rt>, [<Rn>]
348 { "LDREXH", 0xe8d00f5f, 0xfff00fff, LDREXB
}, // LDREXH <Rt>, [<Rn>]
350 { "LDREXD", 0xe8d00f4f, 0xfff00fff, LDREXD
}, // LDREXD <Rt>, <Rt2>, [<Rn>]
352 { "STR", 0xf8c00000, 0xfff00000, LDM_REG_IMM12
}, // STR <rt>, [<rn>, {, #<imm12>]}
353 { "STRB", 0xf8800000, 0xfff00000, LDM_REG_IMM12
}, // STRB <rt>, [<rn>, {, #<imm12>]}
354 { "STRH", 0xf8a00000, 0xfff00000, LDM_REG_IMM12
}, // STRH <rt>, [<rn>, {, #<imm12>]}
356 { "STR", 0xf8400000, 0xfff00fc0, LDM_REG_INDIRECT_LSL
}, // STR <rt>, [<rn>, <rm> {, LSL #<imm2>]}
357 { "STRB", 0xf8000000, 0xfff00fc0, LDM_REG_INDIRECT_LSL
}, // STRB <rt>, [<rn>, <rm> {, LSL #<imm2>]}
358 { "STRH", 0xf8200000, 0xfff00fc0, LDM_REG_INDIRECT_LSL
}, // STRH <rt>, [<rn>, <rm> {, LSL #<imm2>]}
360 { "STR", 0xf8400800, 0xfff00800, LDM_REG_IMM8
}, // STR <rt>, [<rn>, {, #<imm8>]}
361 { "STRH", 0xf8200800, 0xfff00800, LDM_REG_IMM8
}, // STRH <rt>, [<rn>, {, #<imm8>]}
362 { "STRBT", 0xf8000e00, 0xfff00f00, LDM_REG_IMM8
}, // STRBT <rt>, [<rn>, {, #<imm8>]}
363 { "STRHT", 0xf8200e00, 0xfff00f00, LDM_REG_IMM8
}, // STRHT <rt>, [<rn>, {, #<imm8>]}
364 { "STRT", 0xf8400e00, 0xfff00f00, LDM_REG_IMM8
}, // STRT <rt>, [<rn>, {, #<imm8>]}
366 { "STRD", 0xe8400000, 0xfe500000, LDRD_REG_IMM8_SIGNED
}, // STRD <rt>, <rt2>, [<rn>, {, #<imm8>]}{!}
368 { "STREX", 0xe8400f00, 0xfff00f00, LDM_REG_IMM8
}, // STREX <Rt>, [Rn, {#imm8}]]
369 { "STREXB", 0xe8c00f4f, 0xfff00fff, LDREXB
}, // STREXB <Rd>, <Rt>, [<Rn>]
370 { "STREXH", 0xe8c00f5f, 0xfff00fff, LDREXB
}, // STREXH <Rd>, <Rt>, [<Rn>]
372 { "STREXD", 0xe8d00f4f, 0xfff00fff, LDREXD
}, // STREXD <Rd>, <Rt>, <Rt2>, [<Rn>]
374 { "SRSDB", 0xe80dc000, 0xffdffff0, SRS_FORMAT
}, // SRSDB<c> SP{!},#<mode>
375 { "SRS" , 0xe98dc000, 0xffdffff0, SRS_FORMAT
}, // SRS{IA}<c> SP{!},#<mode>
376 { "RFEDB", 0xe810c000, 0xffd0ffff, RFE_FORMAT
}, // RFEDB<c> <Rn>{!}
377 { "RFE" , 0xe990c000, 0xffd0ffff, RFE_FORMAT
} // RFE{IA}<c> <Rn>{!}
380 CHAR8
*gShiftType
[] = {
387 CHAR8 mThumbMregListStr
[4*15 + 1];
394 UINTN Index
, Start
, End
;
397 mThumbMregListStr
[0] = '\0';
398 AsciiStrCatS (mThumbMregListStr
, sizeof mThumbMregListStr
, "{");
400 for (Index
= 0, First
= TRUE
; Index
<= 15; Index
++) {
401 if ((RegBitMask
& (1 << Index
)) != 0) {
403 for (Index
++; ((RegBitMask
& (1 << Index
)) != 0) && (Index
<= 9); Index
++) {
408 AsciiStrCatS (mThumbMregListStr
, sizeof mThumbMregListStr
, ",");
414 AsciiStrCatS (mThumbMregListStr
, sizeof mThumbMregListStr
, gReg
[Start
]);
416 AsciiStrCatS (mThumbMregListStr
, sizeof mThumbMregListStr
, gReg
[Start
]);
417 AsciiStrCatS (mThumbMregListStr
, sizeof mThumbMregListStr
, "-");
418 AsciiStrCatS (mThumbMregListStr
, sizeof mThumbMregListStr
, gReg
[End
]);
423 AsciiStrCatS (mThumbMregListStr
, sizeof mThumbMregListStr
, "ERROR");
425 AsciiStrCatS (mThumbMregListStr
, sizeof mThumbMregListStr
, "}");
427 // BugBug: Make caller pass in buffer it is cleaner
428 return mThumbMregListStr
;
437 if (((Data
& TopBit
) == 0) || (TopBit
== BIT31
)) {
444 } while ((TopBit
& BIT31
) != BIT31
);
450 // Some instructions specify the PC is always considered aligned
451 // The PC is after the instruction that is executing. So you pass
452 // in the instruction address and you get back the aligned answer
459 return (Data
+ 4) & 0xfffffffc;
463 Place a disassembly of **OpCodePtr into buffer, and update OpCodePtr to
464 point to next instruction.
466 We cheat and only decode instructions that access
467 memory. If the instruction is not found we dump the instruction in hex.
469 @param OpCodePtrPtr Pointer to pointer of ARM Thumb instruction to disassemble.
470 @param Buf Buffer to sprintf disassembly into.
471 @param Size Size of Buf in bytes.
472 @param Extended TRUE dump hex for instruction too.
476 DisassembleThumbInstruction (
477 IN UINT16
**OpCodePtrPtr
,
489 UINT16 Rd
, Rn
, Rm
, Rt
, Rt2
;
492 BOOLEAN IMod
; // imod
494 UINT32 Pc
, Target
, MsBit
, LsBit
;
501 BOOLEAN WriteBack
; // W
502 UINT32 Coproc
, Opc1
, Opc2
, CRd
, CRn
, CRm
;
505 OpCodePtr
= *OpCodePtrPtr
;
506 OpCode
= **OpCodePtrPtr
;
508 // Thumb2 is a stream of 16-bit instructions not a 32-bit instruction.
509 OpCode32
= (((UINT32
)OpCode
) << 16) | *(OpCodePtr
+ 1);
511 // These register names match branch form, but not others
513 Rn
= (OpCode
>> 3) & 0x7;
514 Rm
= (OpCode
>> 6) & 0x7;
515 H1Bit
= (OpCode
& BIT7
) != 0;
516 H2Bit
= (OpCode
& BIT6
) != 0;
517 IMod
= (OpCode
& BIT4
) != 0;
518 Pc
= (UINT32
)(UINTN
)OpCodePtr
;
520 // Increment by the minimum instruction size, Thumb2 could be bigger
523 // Manage IT Block ItFlag TRUE means we are in an IT block
524 /*if (*ItBlock != 0) {
531 for (Index
= 0; Index
< sizeof (gOpThumb
)/sizeof (THUMB_INSTRUCTIONS
); Index
++) {
532 if ((OpCode
& gOpThumb
[Index
].Mask
) == gOpThumb
[Index
].OpCode
) {
534 Offset
= AsciiSPrint (Buf
, Size
, "0x%04x %-6a", OpCode
, gOpThumb
[Index
].Start
);
536 Offset
= AsciiSPrint (Buf
, Size
, "%-6a", gOpThumb
[Index
].Start
);
538 switch (gOpThumb
[Index
].AddressMode
) {
539 case LOAD_STORE_FORMAT1
:
540 // A6.5.1 <Rd>, [<Rn>, #<5_bit_offset>]
541 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " r%d, [r%d #0x%x]", Rd
, Rn
, (OpCode
>> 4) & 0x7c);
543 case LOAD_STORE_FORMAT1_H
:
544 // A6.5.1 <Rd>, [<Rn>, #<5_bit_offset>]
545 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " r%d, [r%d #0x%x]", Rd
, Rn
, (OpCode
>> 5) & 0x3e);
547 case LOAD_STORE_FORMAT1_B
:
548 // A6.5.1 <Rd>, [<Rn>, #<5_bit_offset>]
549 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " r%d, [r%d #0x%x]", Rd
, Rn
, (OpCode
>> 6) & 0x1f);
552 case LOAD_STORE_FORMAT2
:
553 // A6.5.1 <Rd>, [<Rn>, <Rm>]
554 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " r%d, [r%d, r%d]", Rd
, Rn
, Rm
);
556 case LOAD_STORE_FORMAT3
:
557 // A6.5.1 <Rd>, [PC, #<8_bit_offset>]
558 Target
= (OpCode
& 0xff) << 2;
559 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " r%d, [pc, #0x%x] ;0x%08x", (OpCode
>> 8) & 7, Target
, PcAlign4 (Pc
) + Target
);
561 case LOAD_STORE_FORMAT4
:
563 Target
= (OpCode
& 0xff) << 2;
564 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " r%d, [sp, #0x%x]", (OpCode
>> 8) & 7, Target
);
567 case LOAD_STORE_MULTIPLE_FORMAT1
:
569 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " r%d!, %a", (OpCode
>> 8) & 7, ThumbMRegList (OpCode
& 0xff));
574 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a", ThumbMRegList ((OpCode
& 0xff) | ((OpCode
& BIT8
) == BIT8
? BIT15
: 0)));
579 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a", ThumbMRegList ((OpCode
& 0xff) | ((OpCode
& BIT8
) == BIT8
? BIT14
: 0)));
585 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " 0x%x", OpCode
& 0xff);
588 case CONDITIONAL_BRANCH
:
589 // A6.3.1 B<cond> <target_address>
590 // Patch in the condition code. A little hack but based on "%-6a"
591 Cond
= gCondition
[(OpCode
>> 8) & 0xf];
592 Buf
[Offset
-5] = *Cond
++;
593 Buf
[Offset
-4] = *Cond
;
594 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " 0x%04x", Pc
+ 4 + SignExtend32 ((OpCode
& 0xff) << 1, BIT8
));
596 case UNCONDITIONAL_BRANCH_SHORT
:
597 // A6.3.2 B <target_address>
598 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " 0x%04x", Pc
+ 4 + SignExtend32 ((OpCode
& 0x3ff) << 1, BIT11
));
601 case BRANCH_EXCHANGE
:
602 // A6.3.3 BX|BLX <Rm>
603 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a", gReg
[Rn
| (H2Bit
? 8:0)]);
607 // A6.4.3 <Rd>, <Rn>, <Rm>
608 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " r%d, r%d, r%d", Rd
, Rn
, Rm
);
611 // A6.4.3 <Rd>, <Rn>, #3_bit_immed
612 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " r%d, r%d, 0x%x", Rd
, Rn
, Rm
);
615 // A6.4.3 <Rd>|<Rn>, #imm8
616 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " r%d, #0x%x", (OpCode
>> 8) & 7, OpCode
& 0xff);
619 // A6.4.3 <Rd>|<Rm>, #immed_5
620 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " r%d, r%d, 0x%x", Rn
, Rd
, (OpCode
>> 6) & 0x1f);
623 // A6.4.3 <Rd>|<Rm>, <Rm>|<Rs>
624 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " r%d, r%d", Rd
, Rn
);
626 case DATA_FORMAT6_SP
:
627 // A6.4.3 <Rd>, <reg>, #<8_Bit_immed>
628 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " r%d, sp, 0x%x", (OpCode
>> 8) & 7, (OpCode
& 0xff) << 2);
630 case DATA_FORMAT6_PC
:
631 // A6.4.3 <Rd>, <reg>, #<8_Bit_immed>
632 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " r%d, pc, 0x%x", (OpCode
>> 8) & 7, (OpCode
& 0xff) << 2);
635 // A6.4.3 SP, SP, #<7_Bit_immed>
636 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " sp, sp, 0x%x", (OpCode
& 0x7f)*4);
639 // A6.4.3 <Rd>|<Rn>, <Rm>
640 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a, %a", gReg
[Rd
| (H1Bit
? 8:0)], gReg
[Rn
| (H2Bit
? 8:0)]);
645 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, "%a %a%a%a", IMod
? "ID":"IE", ((OpCode
& BIT2
) == 0) ? "":"a", ((OpCode
& BIT1
) == 0) ? "":"i", ((OpCode
& BIT0
) == 0) ? "":"f");
650 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a", (OpCode
& BIT3
) == 0 ? "LE":"BE");
654 // CB{N}Z <Rn>, <Lable>
655 Target
= ((OpCode
>> 2) & 0x3e) | (((OpCode
& BIT9
) == BIT9
) ? BIT6
: 0);
656 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a, %08x", gReg
[Rd
], Pc
+ 4 + Target
);
661 Target
= (OpCode
& 0xff) << 2;
662 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a, %08x", gReg
[(OpCode
>> 8) & 7], PcAlign4 (Pc
) + Target
);
666 // ITSTATE = cond:mask OpCode[7:4]:OpCode[3:0]
667 // ITSTATE[7:5] == cond[3:1]
668 // ITSTATE[4] == 1st Instruction cond[0]
669 // ITSTATE[3] == 2st Instruction cond[0]
670 // ITSTATE[2] == 3st Instruction cond[0]
671 // ITSTATE[1] == 4st Instruction cond[0]
672 // ITSTATE[0] == 1 4 instruction IT block. 0 means 0,1,2 or 3 instructions
673 // 1st one in ITSTATE low bits defines the number of instructions
674 Mask
= (OpCode
& 0xf);
675 if ((Mask
& 0x1) == 0x1) {
677 Offset
+= AsciiSPrint (&Buf
[Offset
], Size
- Offset
, "%a%a%a", (Mask
& BIT3
)?"T":"E", (Mask
& BIT2
)?"T":"E", (Mask
& BIT1
)?"T":"E");
678 } else if ((OpCode
& 0x3) == 0x2) {
680 Offset
+= AsciiSPrint (&Buf
[Offset
], Size
- Offset
, "%a%a", (Mask
& BIT3
)?"T":"E", (Mask
& BIT2
)?"T":"E");
681 } else if ((OpCode
& 0x7) == 0x4) {
683 Offset
+= AsciiSPrint (&Buf
[Offset
], Size
- Offset
, "%a", (Mask
& BIT3
)?"T":"E");
684 } else if ((OpCode
& 0xf) == 0x8) {
687 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a", gCondition
[(OpCode
>> 4) & 0xf]);
694 // Thumb2 are 32-bit instructions
696 Rt
= (OpCode32
>> 12) & 0xf;
697 Rt2
= (OpCode32
>> 8) & 0xf;
698 Rd
= (OpCode32
>> 8) & 0xf;
699 Rm
= (OpCode32
& 0xf);
700 Rn
= (OpCode32
>> 16) & 0xf;
701 for (Index
= 0; Index
< sizeof (gOpThumb2
)/sizeof (THUMB_INSTRUCTIONS
); Index
++) {
702 if ((OpCode32
& gOpThumb2
[Index
].Mask
) == gOpThumb2
[Index
].OpCode
) {
704 Offset
= AsciiSPrint (Buf
, Size
, "0x%04x %-6a", OpCode32
, gOpThumb2
[Index
].Start
);
706 Offset
= AsciiSPrint (Buf
, Size
, " %-6a", gOpThumb2
[Index
].Start
);
708 switch (gOpThumb2
[Index
].AddressMode
) {
710 Cond
= gCondition
[(OpCode32
>> 22) & 0xf];
711 Buf
[Offset
-5] = *Cond
++;
712 Buf
[Offset
-4] = *Cond
;
713 // S:J2:J1:imm6:imm11:0
714 Target
= ((OpCode32
<< 1) & 0xffe) + ((OpCode32
>> 4) & 0x3f000);
715 Target
|= ((OpCode32
& BIT11
) == BIT11
)? BIT19
: 0; // J2
716 Target
|= ((OpCode32
& BIT13
) == BIT13
)? BIT18
: 0; // J1
717 Target
|= ((OpCode32
& BIT26
) == BIT26
)? BIT20
: 0; // S
718 Target
= SignExtend32 (Target
, BIT20
);
719 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " 0x%08x", Pc
+ 4 + Target
);
722 // S:I1:I2:imm10:imm11:0
723 Target
= ((OpCode32
<< 1) & 0xffe) + ((OpCode32
>> 4) & 0x3ff000);
724 Sign
= (OpCode32
& BIT26
) == BIT26
;
725 J1Bit
= (OpCode32
& BIT13
) == BIT13
;
726 J2Bit
= (OpCode32
& BIT11
) == BIT11
;
727 Target
|= (!(J2Bit
^ Sign
) ? BIT22
: 0); // I2
728 Target
|= (!(J1Bit
^ Sign
) ? BIT23
: 0); // I1
729 Target
|= (Sign
? BIT24
: 0); // S
730 Target
= SignExtend32 (Target
, BIT24
);
731 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " 0x%08x", Pc
+ 4 + Target
);
735 // BLX S:I1:I2:imm10:imm11:0
736 Target
= ((OpCode32
<< 1) & 0xffc) + ((OpCode32
>> 4) & 0x3ff000);
737 Sign
= (OpCode32
& BIT26
) == BIT26
;
738 J1Bit
= (OpCode32
& BIT13
) == BIT13
;
739 J2Bit
= (OpCode32
& BIT11
) == BIT11
;
740 Target
|= (!(J2Bit
^ Sign
) ? BIT23
: 0); // I2
741 Target
|= (!(J1Bit
^ Sign
) ? BIT24
: 0); // I1
742 Target
|= (Sign
? BIT25
: 0); // S
743 Target
= SignExtend32 (Target
, BIT25
);
744 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " 0x%08x", PcAlign4 (Pc
) + Target
);
748 // <reglist> some must be zero, handled in table
749 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a", ThumbMRegList (OpCode32
& 0xffff));
754 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a", gReg
[(OpCode32
>> 12) & 0xf]);
758 // <Rn>{!}, <registers>
759 WriteBack
= (OpCode32
& BIT21
) == BIT21
;
760 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a%a, %a", gReg
[(OpCode32
>> 16) & 0xf], WriteBack
? "!":"", ThumbMRegList (OpCode32
& 0xffff));
763 case LDM_REG_IMM12_SIGNED
:
765 Target
= OpCode32
& 0xfff;
766 if ((OpCode32
& BIT23
) == 0) {
767 // U == 0 means subtrack, U == 1 means add
770 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a, %a", gReg
[(OpCode32
>> 12) & 0xf], PcAlign4 (Pc
) + Target
);
773 case LDM_REG_INDIRECT_LSL
:
774 // <rt>, [<rn>, <rm> {, LSL #<imm2>]}
775 Offset
+= AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a, [%a, %a", gReg
[Rt
], gReg
[Rn
], gReg
[Rm
]);
776 if (((OpCode32
>> 4) & 3) == 0) {
777 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, "]");
779 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);
794 // <rt>, [<rn>, {, #<imm8>}]{!}
795 WriteBack
= (OpCode32
& BIT8
) == BIT8
;
796 UAdd
= (OpCode32
& BIT9
) == BIT9
;
797 Pre
= (OpCode32
& BIT10
) == BIT10
;
798 Offset
+= AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a, [%a", gReg
[Rt
], gReg
[Rn
]);
800 if ((OpCode32
& 0xff) == 0) {
801 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, "]%a", WriteBack
?"!":"");
803 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, ", #%a0x%x]%a", UAdd
?"":"-" , OpCode32
& 0xff, WriteBack
?"!":"");
806 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, "], #%a0x%x", UAdd
?"":"-", OpCode32
& 0xff);
810 case LDRD_REG_IMM8_SIGNED
:
811 // LDRD <rt>, <rt2>, [<rn>, {, #<imm8>]}{!}
812 Pre
= (OpCode32
& BIT24
) == BIT24
; // index = P
813 UAdd
= (OpCode32
& BIT23
) == BIT23
;
814 WriteBack
= (OpCode32
& BIT21
) == BIT21
;
815 Offset
+= AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a, %a, [%a", gReg
[Rt
], gReg
[Rt2
], gReg
[Rn
]);
817 if ((OpCode32
& 0xff) == 0) {
818 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, "]");
820 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, ", #%a0x%x]%a", UAdd
?"":"-", (OpCode32
& 0xff) << 2, WriteBack
?"!":"");
823 if ((OpCode32
& 0xff) != 0) {
824 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, ", #%a0x%x", UAdd
?"":"-", (OpCode32
& 0xff) << 2);
830 // LDRD <rt>, <rt2>, <label>
831 Target
= (OpCode32
& 0xff) << 2;
832 if ((OpCode32
& BIT23
) == 0) {
833 // U == 0 means subtrack, U == 1 means add
836 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a, %a, %a", gReg
[Rt
], gReg
[Rt2
], Pc
+ 4 + Target
);
841 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a, [%a]", gReg
[Rt
], gReg
[Rn
]);
845 // LDREXD <Rt>, <Rt2>, [<Rn>]
846 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a, ,%a, [%a]", gReg
[Rt
], gReg
[Rt2
], gReg
[Rn
]);
851 WriteBack
= (OpCode32
& BIT21
) == BIT21
;
852 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " SP%a, #0x%x", WriteBack
?"!":"", OpCode32
& 0x1f);
857 WriteBack
= (OpCode32
& BIT21
) == BIT21
;
858 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a%a, #0x%x", gReg
[Rn
], WriteBack
?"!":"");
862 // ADD{S} <Rd>, <Rn>, #<const> i:imm3:imm8
863 if ((OpCode32
& BIT20
) == BIT20
) {
864 Buf
[Offset
- 3] = 'S'; // assume %-6a
866 Target
= (OpCode32
& 0xff) | ((OpCode32
>> 4) & 0x700) | ((OpCode
& BIT26
) == BIT26
? BIT11
: 0);
867 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a, %a, #0x%x", gReg
[Rd
], gReg
[Rn
], Target
);
871 // MOV{S} <Rd>, #<const> i:imm3:imm8
872 if ((OpCode32
& BIT20
) == BIT20
) {
873 Buf
[Offset
- 3] = 'S'; // assume %-6a
875 Target
= (OpCode32
& 0xff) | ((OpCode32
>> 4) & 0x700) | ((OpCode
& BIT26
) == BIT26
? BIT11
: 0);
876 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a, #0x%x", gReg
[Rd
], Target
);
880 // MOVW <Rd>, #<const> i:imm3:imm8
881 Target
= (OpCode32
& 0xff) | ((OpCode32
>> 4) & 0x700) | ((OpCode
& BIT26
) == BIT26
? BIT11
: 0);
882 Target
|= ((OpCode32
>> 4) & 0xf0000);
883 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a, #0x%x", gReg
[Rd
], Target
);
887 // ADC{S} <Rd>, <Rn>, <Rm> {,LSL #<const>} imm3:imm2
888 if ((OpCode32
& BIT20
) == BIT20
) {
889 Buf
[Offset
- 3] = 'S'; // assume %-6a
891 Target
= ((OpCode32
>> 6) & 3) | ((OpCode32
>> 10) & 0x1c0);
892 Offset
+= AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a, %a, %a", gReg
[Rd
], gReg
[Rn
], gReg
[Rm
]);
894 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, ", LSL %d", gShiftType
[(OpCode
>> 5) & 3], Target
);
899 // CMP <Rn>, <Rm> {,LSL #<const>} imm3:imm2
900 Target
= ((OpCode32
>> 6) & 3) | ((OpCode32
>> 10) & 0x1c0);
901 Offset
+= AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a, %a", gReg
[Rn
], gReg
[Rm
]);
903 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, ", LSL %d", gShiftType
[(OpCode
>> 5) & 3], Target
);
908 // ARS <Rd>, <Rm> #<const>} imm3:imm2
909 if ((OpCode32
& BIT20
) == BIT20
) {
910 Buf
[Offset
- 3] = 'S'; // assume %-6a
912 Target
= ((OpCode32
>> 6) & 3) | ((OpCode32
>> 10) & 0x1c0);
913 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a, %a #%d", gReg
[Rd
], gReg
[Rm
], Target
);
917 // ARS <Rd>, <Rn>, <Rm>
918 if ((OpCode32
& BIT20
) == BIT20
) {
919 Buf
[Offset
- 3] = 'S'; // assume %-6a
921 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a, %a %a", gReg
[Rd
], gReg
[Rn
], gReg
[Rm
]);
925 // ADDR <Rd>, <label>
926 Target
= (OpCode32
& 0xff) | ((OpCode32
>> 8) & 0x700) | ((OpCode
& BIT26
) == BIT26
? BIT11
: 0);
927 if ((OpCode
& (BIT23
| BIT21
)) == (BIT23
| BIT21
)) {
928 Target
= PcAlign4 (Pc
) - Target
;
930 Target
= PcAlign4 (Pc
) + Target
;
932 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a, 0x%08x", gReg
[Rd
], Target
);
936 // CMN <Rn>, #<const>}
937 Target
= (OpCode32
& 0xff) | ((OpCode
>> 4) & 0x700) | ((OpCode
& BIT26
) == BIT26
? BIT11
: 0);
938 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a, #0x%x", gReg
[Rn
], Target
);
942 // BFI <Rd>, <Rn>, #<lsb>, #<width>
943 MsBit
= OpCode32
& 0x1f;
944 LsBit
= ((OpCode32
>> 6) & 3) | ((OpCode
>> 10) & 0x1c);
945 if ((Rn
== 0xf) & (AsciiStrCmp (gOpThumb2
[Index
].Start
, "BFC") == 0)){
946 // BFC <Rd>, #<lsb>, #<width>
947 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a, #%d, #%d", gReg
[Rd
], LsBit
, MsBit
- LsBit
+ 1);
948 } else if (AsciiStrCmp (gOpThumb2
[Index
].Start
, "BFI") == 0) {
949 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a, %a, #%d, #%d", gReg
[Rd
], gReg
[Rn
], LsBit
, MsBit
- LsBit
+ 1);
951 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a, %a, #%d, #%d", gReg
[Rd
], gReg
[Rn
], LsBit
, MsBit
+ 1);
956 // <coproc>,<opc1>,<CRd>,<CRn>,<CRm>,<opc2>
957 Coproc
= (OpCode32
>> 8) & 0xf;
958 Opc1
= (OpCode32
>> 20) & 0xf;
959 Opc2
= (OpCode32
>> 5) & 0x7;
960 CRd
= (OpCode32
>> 12) & 0xf;
961 CRn
= (OpCode32
>> 16) & 0xf;
962 CRm
= OpCode32
& 0xf;
963 Offset
+= AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " p%d,#%d,c%d,c%d,c%d", Coproc
, Opc1
, CRd
, CRn
, CRm
);
965 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, ",#%d,", Opc2
);
970 // MRC <coproc>,<opc1>,<Rt>,<CRn>,<CRm>,<opc2>
971 Coproc
= (OpCode32
>> 8) & 0xf;
972 Opc1
= (OpCode32
>> 20) & 0xf;
973 Opc2
= (OpCode32
>> 5) & 0x7;
974 CRn
= (OpCode32
>> 16) & 0xf;
975 CRm
= OpCode32
& 0xf;
976 Offset
+= AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " p%d,#%d,%a,c%d,c%d", Coproc
, Opc1
, gReg
[Rt
], CRn
, CRm
);
978 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, ",#%d,", Opc2
);
983 // MRC <coproc>,<opc1>,<Rt>,<Rt2>,<CRm>,<opc2>
984 Coproc
= (OpCode32
>> 8) & 0xf;
985 Opc1
= (OpCode32
>> 20) & 0xf;
986 CRn
= (OpCode32
>> 16) & 0xf;
987 CRm
= OpCode32
& 0xf;
988 Offset
+= AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " p%d,#%d,%a,%a,c%d", Coproc
, Opc1
, gReg
[Rt
], gReg
[Rt2
], CRm
);
993 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a, %a", gReg
[Rd
], gReg
[Rm
]);
997 // <Rd>, <Rn>, <Rm>, <Ra>
998 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a, %a, %a, %a", gReg
[Rd
], gReg
[Rn
], gReg
[Rm
], gReg
[Rt
]);
1003 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a, CPSR", gReg
[Rd
]);
1007 // MRS CPSR_<fields>, <Rd>
1008 Target
= (OpCode32
>> 10) & 3;
1009 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " CPSR_%a%a, %a", (Target
& 2) == 0 ? "":"f", (Target
& 1) == 0 ? "":"s", gReg
[Rd
]);
1012 case THUMB2_NO_ARGS
:
1019 AsciiSPrint (Buf
, Size
, "0x%08x", OpCode32
);
1025 DisassembleArmInstruction (
1026 IN UINT32
**OpCodePtr
,
1034 Place a disassembly of **OpCodePtr into buffer, and update OpCodePtr to
1035 point to next instruction.
1037 We cheat and only decode instructions that access
1038 memory. If the instruction is not found we dump the instruction in hex.
1040 @param OpCodePtrPtr Pointer to pointer of ARM Thumb instruction to disassemble.
1041 @param Thumb TRUE for Thumb(2), FALSE for ARM instruction stream
1042 @param Extended TRUE dump hex for instruction too.
1043 @param ItBlock Size of IT Block
1044 @param Buf Buffer to sprintf disassembly into.
1045 @param Size Size of Buf in bytes.
1049 DisassembleInstruction (
1050 IN UINT8
**OpCodePtr
,
1052 IN BOOLEAN Extended
,
1053 IN OUT UINT32
*ItBlock
,
1059 DisassembleThumbInstruction ((UINT16
**)OpCodePtr
, Buf
, Size
, ItBlock
, Extended
);
1061 DisassembleArmInstruction ((UINT32
**)OpCodePtr
, Buf
, Size
, Extended
);