2 * \file trc_idec_arminst.cpp
5 * \copyright Copyright (c) 2015, ARM Limited. All Rights Reserved.
10 * Redistribution and use in source and binary forms, with or without modification,
11 * are permitted provided that the following conditions are met:
13 * 1. Redistributions of source code must retain the above copyright notice,
14 * this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright notice,
17 * this list of conditions and the following disclaimer in the documentation
18 * and/or other materials provided with the distribution.
20 * 3. Neither the name of the copyright holder nor the names of its contributors
21 * may be used to endorse or promote products derived from this software without
22 * specific prior written permission.
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
26 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
27 * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
28 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
29 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
31 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 Basic ARM/Thumb/A64 instruction decode, suitable for e.g. basic
38 block identification and trace decode.
41 #include "i_dec/trc_idec_arminst.h"
44 #include <stddef.h> /* for NULL */
48 static ocsd_instr_subtype instr_sub_type = OCSD_S_INSTR_NONE;
50 ocsd_instr_subtype get_instr_subtype()
52 return instr_sub_type;
55 void clear_instr_subtype()
57 instr_sub_type = OCSD_S_INSTR_NONE;
60 int inst_ARM_is_direct_branch(uint32_t inst)
62 int is_direct_branch = 1;
63 if ((inst & 0xf0000000) == 0xf0000000) {
65 if ((inst & 0xfe000000) == 0xfa000000){
70 } else if ((inst & 0x0e000000) == 0x0a000000) {
75 return is_direct_branch;
79 int inst_ARM_is_indirect_branch(uint32_t inst)
81 int is_indirect_branch = 1;
82 if ((inst & 0xf0000000) == 0xf0000000) {
84 if ((inst & 0xfe500000) == 0xf8100000) {
87 is_indirect_branch = 0;
89 } else if ((inst & 0x0ff000d0) == 0x01200010) {
90 /* BLX (register), BX */
91 } else if ((inst & 0x0e108000) == 0x08108000) {
92 /* POP {...,pc} or LDMxx {...,pc} */
93 } else if ((inst & 0x0e50f000) == 0x0410f000) {
94 /* LDR PC,imm... inc. POP {PC} */
95 } else if ((inst & 0x0e50f010) == 0x0610f000) {
97 } else if ((inst & 0x0fe0f000) == 0x01a0f000) {
99 } else if ((inst & 0x0f900080) == 0x01000000) {
100 /* "Miscellaneous instructions" - in DP space */
101 is_indirect_branch = 0;
102 } else if ((inst & 0x0f9000f0) == 0x01800090) {
103 /* Some extended loads and stores */
104 is_indirect_branch = 0;
105 } else if ((inst & 0x0fb0f000) == 0x0320f000) {
107 is_indirect_branch = 0;
108 } else if ((inst & 0x0e00f000) == 0x0200f000) {
109 /* DP PC,imm shift */
110 if ((inst & 0x0f90f000) == 0x0310f000) {
112 is_indirect_branch = 0;
114 } else if ((inst & 0x0e00f000) == 0x0000f000) {
117 is_indirect_branch = 0;
119 return is_indirect_branch;
123 int inst_Thumb_is_direct_branch(uint32_t inst)
125 int is_direct_branch = 1;
126 if ((inst & 0xf0000000) == 0xd0000000 && (inst & 0x0e000000) != 0x0e000000) {
127 /* B<c> (encoding T1) */
128 } else if ((inst & 0xf8000000) == 0xe0000000) {
129 /* B (encoding T2) */
130 } else if ((inst & 0xf800d000) == 0xf0008000 && (inst & 0x03800000) != 0x03800000) {
131 /* B (encoding T3) */
132 } else if ((inst & 0xf8009000) == 0xf0009000) {
133 /* B (encoding T4); BL (encoding T1) */
134 } else if ((inst & 0xf800d001) == 0xf000c000) {
135 /* BLX (imm) (encoding T2) */
136 } else if ((inst & 0xf5000000) == 0xb1000000) {
139 is_direct_branch = 0;
141 return is_direct_branch;
145 int inst_Thumb_is_indirect_branch(uint32_t inst)
147 /* See e.g. PFT Table 2-3 and Table 2-5 */
149 if ((inst & 0xff000000) == 0x47000000) {
151 } else if ((inst & 0xff000000) == 0xbd000000) {
153 } else if ((inst & 0xfd870000) == 0x44870000) {
154 /* MOV PC,reg or ADD PC,reg */
155 } else if ((inst & 0xfff0ffe0) == 0xe8d0f000) {
157 } else if ((inst & 0xffd00000) == 0xe8100000) {
159 } else if ((inst & 0xffd00000) == 0xe9900000) {
161 } else if ((inst & 0xfff0d000) == 0xf3d08000) {
162 /* SUBS PC,LR,#imm inc.ERET */
163 } else if ((inst & 0xfff0f000) == 0xf8d0f000) {
164 /* LDR PC,imm (T3) */
165 } else if ((inst & 0xff7ff000) == 0xf85ff000) {
166 /* LDR PC,literal (T2) */
167 } else if ((inst & 0xfff0f800) == 0xf850f800) {
168 /* LDR PC,imm (T4) */
169 } else if ((inst & 0xfff0ffc0) == 0xf850f000) {
170 /* LDR PC,reg (T2) */
171 } else if ((inst & 0xfe508000) == 0xe8108000) {
180 int inst_A64_is_direct_branch(uint32_t inst)
182 int is_direct_branch = 1;
183 if ((inst & 0x7c000000) == 0x34000000) {
185 } else if ((inst & 0xff000010) == 0x54000000) {
187 } else if ((inst & 0x7c000000) == 0x14000000) {
190 is_direct_branch = 0;
192 return is_direct_branch;
196 int inst_A64_is_indirect_branch(uint32_t inst)
198 int is_indirect_branch = 1;
199 if ((inst & 0xffdffc1f) == 0xd61f0000) {
201 } else if ((inst & 0xfffffc1f) == 0xd65f0000) {
202 instr_sub_type = OCSD_S_INSTR_V8_RET;
204 } else if ((inst & 0xffffffff) == 0xd69f03e0) {
206 instr_sub_type = OCSD_S_INSTR_V8_ERET;
208 is_indirect_branch = 0;
210 return is_indirect_branch;
214 int inst_ARM_branch_destination(uint32_t addr, uint32_t inst, uint32_t *pnpc)
217 int is_direct_branch = 1;
218 if ((inst & 0x0e000000) == 0x0a000000) {
224 npc = addr + 8 + ((int32_t)((inst & 0xffffff) << 8) >> 6);
225 if ((inst & 0xf0000000) == 0xf0000000) {
226 npc |= 1; /* indicate ISA is now Thumb */
227 npc |= ((inst >> 23) & 2); /* apply the H bit */
230 is_direct_branch = 0;
232 if (is_direct_branch && pnpc != NULL) {
235 return is_direct_branch;
239 int inst_Thumb_branch_destination(uint32_t addr, uint32_t inst, uint32_t *pnpc)
242 int is_direct_branch = 1;
243 if ((inst & 0xf0000000) == 0xd0000000 && (inst & 0x0e000000) != 0x0e000000) {
244 /* B<c> (encoding T1) */
245 npc = addr + 4 + ((int32_t)((inst & 0x00ff0000) << 8) >> 23);
247 } else if ((inst & 0xf8000000) == 0xe0000000) {
248 /* B (encoding T2) */
249 npc = addr + 4 + ((int32_t)((inst & 0x07ff0000) << 5) >> 20);
251 } else if ((inst & 0xf800d000) == 0xf0008000 && (inst & 0x03800000) != 0x03800000) {
252 /* B (encoding T3) */
253 npc = addr + 4 + ((int32_t)(((inst & 0x04000000) << 5) |
254 ((inst & 0x0800) << 19) |
255 ((inst & 0x2000) << 16) |
256 ((inst & 0x003f0000) << 7) |
257 ((inst & 0x000007ff) << 12)) >> 11);
259 } else if ((inst & 0xf8009000) == 0xf0009000) {
260 /* B (encoding T4); BL (encoding T1) */
261 uint32_t S = ((inst & 0x04000000) >> 26)-1; /* ffffffff or 0 according to S bit */
262 npc = addr + 4 + ((int32_t)(((inst & 0x04000000) << 5) |
263 (((inst^S) & 0x2000) << 17) |
264 (((inst^S) & 0x0800) << 18) |
265 ((inst & 0x03ff0000) << 3) |
266 ((inst & 0x000007ff) << 8)) >> 7);
268 } else if ((inst & 0xf800d001) == 0xf000c000) {
269 /* BLX (encoding T2) */
270 uint32_t S = ((inst & 0x04000000) >> 26)-1; /* ffffffff or 0 according to S bit */
271 addr &= 0xfffffffc; /* Align(PC,4) */
272 npc = addr + 4 + ((int32_t)(((inst & 0x04000000) << 5) |
273 (((inst^S) & 0x2000) << 17) |
274 (((inst^S) & 0x0800) << 18) |
275 ((inst & 0x03ff0000) << 3) |
276 ((inst & 0x000007fe) << 8)) >> 7);
277 /* don't set the Thumb bit, as we're transferring to ARM */
278 } else if ((inst & 0xf5000000) == 0xb1000000) {
280 /* Note that it's zero-extended - always a forward branch */
281 npc = addr + 4 + ((((inst & 0x02000000) << 6) |
282 ((inst & 0x00f80000) << 7)) >> 25);
285 is_direct_branch = 0;
287 if (is_direct_branch && pnpc != NULL) {
290 return is_direct_branch;
294 int inst_A64_branch_destination(uint64_t addr, uint32_t inst, uint64_t *pnpc)
297 int is_direct_branch = 1;
298 if ((inst & 0xff000010) == 0x54000000) {
300 npc = addr + ((int32_t)((inst & 0x00ffffe0) << 8) >> 11);
301 } else if ((inst & 0x7c000000) == 0x14000000) {
303 npc = addr + ((int32_t)((inst & 0x03ffffff) << 6) >> 4);
304 } else if ((inst & 0x7e000000) == 0x34000000) {
306 npc = addr + ((int32_t)((inst & 0x00ffffe0) << 8) >> 11);
307 } else if ((inst & 0x7e000000) == 0x36000000) {
309 npc = addr + ((int32_t)((inst & 0x0007ffe0) << 13) >> 16);
311 is_direct_branch = 0;
313 if (is_direct_branch && pnpc != NULL) {
316 return is_direct_branch;
319 int inst_ARM_is_branch(uint32_t inst)
321 return inst_ARM_is_indirect_branch(inst) ||
322 inst_ARM_is_direct_branch(inst);
326 int inst_Thumb_is_branch(uint32_t inst)
328 return inst_Thumb_is_indirect_branch(inst) ||
329 inst_Thumb_is_direct_branch(inst);
333 int inst_A64_is_branch(uint32_t inst)
335 return inst_A64_is_indirect_branch(inst) ||
336 inst_A64_is_direct_branch(inst);
340 int inst_ARM_is_branch_and_link(uint32_t inst)
343 if ((inst & 0xf0000000) == 0xf0000000) {
344 if ((inst & 0xfe000000) == 0xfa000000){
345 instr_sub_type = OCSD_S_INSTR_BR_LINK;
350 } else if ((inst & 0x0f000000) == 0x0b000000) {
351 instr_sub_type = OCSD_S_INSTR_BR_LINK;
353 } else if ((inst & 0x0ff000f0) == 0x01200030) {
354 instr_sub_type = OCSD_S_INSTR_BR_LINK;
363 int inst_Thumb_is_branch_and_link(uint32_t inst)
366 if ((inst & 0xff800000) == 0x47800000) {
367 instr_sub_type = OCSD_S_INSTR_BR_LINK;
369 } else if ((inst & 0xf800c000) == 0xf000c000) {
370 instr_sub_type = OCSD_S_INSTR_BR_LINK;
379 int inst_A64_is_branch_and_link(uint32_t inst)
382 if ((inst & 0xfffffc1f) == 0xd63f0000) {
384 instr_sub_type = OCSD_S_INSTR_BR_LINK;
385 } else if ((inst & 0xfc000000) == 0x94000000) {
387 instr_sub_type = OCSD_S_INSTR_BR_LINK;
395 int inst_ARM_is_conditional(uint32_t inst)
397 return (inst & 0xe0000000) != 0xe0000000;
401 int inst_Thumb_is_conditional(uint32_t inst)
403 if ((inst & 0xf0000000) == 0xd0000000 && (inst & 0x0e000000) != 0x0e000000) {
404 /* B<c> (encoding T1) */
406 } else if ((inst & 0xf800d000) == 0xf0008000 && (inst & 0x03800000) != 0x03800000) {
407 /* B<c> (encoding T3) */
409 } else if ((inst & 0xf5000000) == 0xb1000000) {
417 unsigned int inst_Thumb_is_IT(uint32_t inst)
419 if ((inst & 0xff000000) == 0xbf000000 &&
420 (inst & 0x000f0000) != 0x00000000) {
421 if (inst & 0x00010000) {
423 } else if (inst & 0x00020000) {
425 } else if (inst & 0x00040000) {
428 assert(inst & 0x00080000);
438 Test whether an A64 instruction is conditional.
440 Instructions like CSEL, CSINV, CCMP are not classed as conditional.
441 They use the condition code but do one of two things with it,
442 neither a NOP. The "intruction categories" section of ETMv4
443 lists no (non branch) conditional instructions for A64.
445 int inst_A64_is_conditional(uint32_t inst)
447 if ((inst & 0x7c000000) == 0x34000000) {
450 } else if ((inst & 0xff000010) == 0x54000000) {
458 arm_barrier_t inst_ARM_barrier(uint32_t inst)
460 if ((inst & 0xfff00000) == 0xf5700000) {
461 switch (inst & 0xf0) {
463 return ARM_BARRIER_DSB;
465 return ARM_BARRIER_DMB;
467 return ARM_BARRIER_ISB;
469 return ARM_BARRIER_NONE;
471 } else if ((inst & 0x0fff0f00) == 0x0e070f00) {
472 switch (inst & 0xff) {
474 return ARM_BARRIER_DSB; /* mcr p15,0,Rt,c7,c10,4 */
476 return ARM_BARRIER_DMB; /* mcr p15,0,Rt,c7,c10,5 */
478 return ARM_BARRIER_ISB; /* mcr p15,0,Rt,c7,c5,4 */
480 return ARM_BARRIER_NONE;
483 return ARM_BARRIER_NONE;
488 arm_barrier_t inst_Thumb_barrier(uint32_t inst)
490 if ((inst & 0xffffff00) == 0xf3bf8f00) {
491 switch (inst & 0xf0) {
493 return ARM_BARRIER_DSB;
495 return ARM_BARRIER_DMB;
497 return ARM_BARRIER_ISB;
499 return ARM_BARRIER_NONE;
501 } else if ((inst & 0xffff0f00) == 0xee070f00) {
502 /* Thumb2 CP15 barriers are unlikely... 1156T2 only? */
503 switch (inst & 0xff) {
505 return ARM_BARRIER_DSB; /* mcr p15,0,Rt,c7,c10,4 */
507 return ARM_BARRIER_DMB; /* mcr p15,0,Rt,c7,c10,5 */
509 return ARM_BARRIER_ISB; /* mcr p15,0,Rt,c7,c5,4 */
511 return ARM_BARRIER_NONE;
513 return ARM_BARRIER_NONE;
515 return ARM_BARRIER_NONE;
520 arm_barrier_t inst_A64_barrier(uint32_t inst)
522 if ((inst & 0xfffff09f) == 0xd503309f) {
523 switch (inst & 0x60) {
525 return ARM_BARRIER_DSB;
527 return ARM_BARRIER_DMB;
529 return ARM_BARRIER_ISB;
531 return ARM_BARRIER_NONE;
534 return ARM_BARRIER_NONE;
539 int inst_ARM_is_UDF(uint32_t inst)
541 return (inst & 0xfff000f0) == 0xe7f000f0;
545 int inst_Thumb_is_UDF(uint32_t inst)
547 return (inst & 0xff000000) == 0xde000000 || /* T1 */
548 (inst & 0xfff0f000) == 0xf7f0a000; /* T2 */
552 int inst_A64_is_UDF(uint32_t inst)
554 /* No A64 encodings are formally allocated as permanently undefined,
555 but it is intended not to allocate any instructions in the 21-bit
556 regions at the bottom or top of the range. */
557 return (inst & 0xffe00000) == 0x00000000 ||
558 (inst & 0xffe00000) == 0xffe00000;
561 /* End of File trc_idec_arminst.cpp */