1 /* radare - LGPL - Copyright 2010-2018 - pancake */
2 
3 #include <stdio.h>
4 #include <string.h>
5 #include <ctype.h>
6 #include <stdlib.h>
7 #include <r_util.h>
8 #include "armass16_const.h"
9 
10 // TODO: only lo registers accessible in thumb arm
11 
12 typedef struct {
13 	ut64 off;
14 	ut32 o;
15 	char op[128];
16 	char opstr[128];
17 	char *a[16]; /* only 15 arguments can be used! */
18 } ArmOpcode;
19 
20 typedef struct {
21 	const char *name;
22 	int code;
23 	int type;
24 } ArmOp;
25 
26 enum {
27 	TYPE_MOV = 1,
28 	TYPE_TST = 2,
29 	TYPE_SWI = 3,
30 	TYPE_HLT = 4,
31 	TYPE_BRA = 5,
32 	TYPE_BRR = 6,
33 	TYPE_ARI = 7,
34 	TYPE_IMM = 8,
35 	TYPE_MEM = 9,
36 	TYPE_BKP = 10,
37 	TYPE_SWP = 11,
38 	TYPE_MOVW = 12,
39 	TYPE_MOVT = 13,
40 	TYPE_UDF = 14,
41 	TYPE_SHFT = 15,
42 	TYPE_COPROC = 16,
43 	TYPE_ENDIAN = 17,
44 	TYPE_MUL = 18,
45 	TYPE_CLZ = 19,
46 	TYPE_REV = 20,
47 	TYPE_NEG = 21
48 };
49 
strcmpnull(const char * a,const char * b)50 static int strcmpnull(const char *a, const char *b) {
51 	return (a && b) ? strcmp (a, b) : -1;
52 }
53 
54 // static const char *const arm_shift[] = {"lsl", "lsr", "asr", "ror"};
55 
56 static ArmOp ops[] = {
57 	{ "adc", 0xa000, TYPE_ARI },
58 	{ "adcs", 0xb000, TYPE_ARI },
59 	{ "adds", 0x9000, TYPE_ARI },
60 	{ "add", 0x8000, TYPE_ARI },
61 	{ "bkpt", 0x2001, TYPE_BKP },
62 	{ "subs", 0x5000, TYPE_ARI },
63 	{ "sub", 0x4000, TYPE_ARI },
64 	{ "sbcs", 0xd000, TYPE_ARI },
65 	{ "sbc", 0xc000, TYPE_ARI },
66 	{ "rsb", 0x6000, TYPE_ARI },
67 	{ "rsbs", 0x7000, TYPE_ARI },
68 	{ "rsc", 0xe000, TYPE_ARI },
69 	{ "rscs", 0xf000, TYPE_ARI },
70 	{ "bic", 0x0000c0e1, TYPE_ARI },
71 
72 	{ "udf", 0xf000f000, TYPE_UDF },
73 
74 	{ "push", 0x2d09, TYPE_IMM },
75 	{ "pop", 0xbd08, TYPE_IMM },
76 
77 	{ "cps", 0xb1, TYPE_IMM },
78 	{ "nop", 0xa0e1, -1 },
79 
80 	{ "ldrex", 0x9f0f9000, TYPE_MEM },
81 	{ "ldr", 0x9000, TYPE_MEM },
82 
83 	{ "strexh", 0x900fe000, TYPE_MEM },
84 	{ "strexb", 0x900fc000, TYPE_MEM },
85 	{ "strex", 0x900f8000, TYPE_MEM },
86 	{ "strbt", 0x0000e0e4, TYPE_MEM },
87 	{ "strb", 0x0000c0e5, TYPE_MEM },
88 	{ "strd", 0xf000c0e1, TYPE_MEM },
89 	{ "strh", 0xb00080e1, TYPE_MEM },
90 	{ "str", 0x8000, TYPE_MEM },
91 
92 	{ "blx", 0x30ff2fe1, TYPE_BRR },
93 	{ "bx", 0x10ff2fe1, TYPE_BRR },
94 
95 	{ "bl", 0xb, TYPE_BRA },
96 // bx/blx - to register, b, bne,.. justjust  offset
97 //    2220:       e12fff1e        bx      lr
98 //    2224:       e12fff12        bx      r2
99 //    2228:       e12fff13        bx      r3
100 
101 	//{ "bx", 0xb, TYPE_BRA },
102 	{ "b", 0xa, TYPE_BRA },
103 
104 	//{ "mov", 0x3, TYPE_MOV },
105 	//{ "mov", 0x0a3, TYPE_MOV },
106 	{ "movw", 0x3, TYPE_MOVW },
107 	{ "movt", 0x4003, TYPE_MOVT },
108 	{ "mov", 0xa001, TYPE_MOV },
109 	{ "mvn", 0xe000, TYPE_MOV },
110 	{ "svc", 0xf, TYPE_SWI }, // ???
111 	{ "hlt", 0x70000001, TYPE_HLT }, // ???u
112 
113 	{ "mul", 0x900000e0, TYPE_MUL},
114 	{ "smull", 0x9000c0e0, TYPE_MUL},
115 	{ "umull", 0x900080e0, TYPE_MUL},
116 	{ "smlal", 0x9000e0e0, TYPE_MUL},
117 	{ "smlabb", 0x800000e1, TYPE_MUL},
118 	{ "smlabt", 0xc00000e1, TYPE_MUL},
119 	{ "smlatb", 0xa00000e1, TYPE_MUL},
120 	{ "smlatt", 0xe00000e1, TYPE_MUL},
121 	{ "smlawb", 0x800020e1, TYPE_MUL},
122 	{ "smlawt", 0xc00020e1, TYPE_MUL},
123 
124 
125 	{ "ands", 0x1000, TYPE_ARI },
126 	{ "and", 0x0000, TYPE_ARI },
127 	{ "eors", 0x3000, TYPE_ARI },
128 	{ "eor", 0x2000, TYPE_ARI },
129 	{ "orrs", 0x9001, TYPE_ARI },
130 	{ "orr", 0x8001, TYPE_ARI },
131 
132 	{ "cmp", 0x5001, TYPE_TST },
133 	{ "swp", 0xe1, TYPE_SWP },
134 	{ "cmn", 0x0, TYPE_TST },
135 	{ "teq", 0x0, TYPE_TST },
136 	{ "tst", 0xe1, TYPE_TST },
137 
138 	{"lsr", 0x3000a0e1, TYPE_SHFT},
139 	{"asr", 0x5000a0e1, TYPE_SHFT},
140 	{"lsl", 0x1000a0e1, TYPE_SHFT},
141 	{"ror", 0x7000a0e1, TYPE_SHFT},
142 
143 	{"rev16", 0xb00fbf06, TYPE_REV},
144 	{"revsh", 0xb00fff06, TYPE_REV},
145 	{"rev",   0x300fbf06, TYPE_REV},
146 	{"rbit",  0x300fff06, TYPE_REV},
147 
148 	{"mrc", 0x100010ee, TYPE_COPROC},
149 	{"setend", 0x000001f1, TYPE_ENDIAN},
150 	{ "clz", 0x000f6f01, TYPE_CLZ},
151 	{ "neg", 0x7000, TYPE_NEG },
152 
153 	{ NULL }
154 };
155 
156 static const ut64 M_BIT = 0x1;
157 static const ut64 S_BIT = 0x2;
158 static const ut64 C_BITS = 0x3c;
159 static const ut64 DOTN_BIT = 0x40;
160 static const ut64 DOTW_BIT = 0x80;
161 static const ut64 L_BIT = 0x100;
162 static const ut64 X_BIT = 0x200;
163 static const ut64 TWO_BIT = 0x400;
164 static const ut64 IE_BIT = 0x800;
165 static const ut64 ID_BIT = 0x1000;
166 static const ut64 EA_BIT = 0x2000;
167 static const ut64 FD_BIT = 0x4000;
168 static const ut64 T_BIT = 0x8000;
169 static const ut64 B_BIT = 0x10000;
170 static const ut64 H_BIT = 0x20000;
171 static const ut64 D_BIT = 0x40000;
172 static const ut64 W_BIT = 0x80000;
173 static const ut64 EIGHT_BIT = 0x100000;
174 static const ut64 SIXTEEN_BIT = 0x200000;
175 static const ut64 BB_BIT = 0x400000;
176 static const ut64 BT_BIT = 0x800000;
177 static const ut64 TB_BIT = 0x1000000;
178 static const ut64 TT_BIT = 0x2000000;
179 static const ut64 R_BIT = 0x4000000;
180 static const ut64 IA_BIT = 0x8000000;
181 static const ut64 DB_BIT = 0x10000000;
182 static const ut64 SH_BIT = 0x20000000;
183 static const ut64 WB_BIT = 0x40000000;
184 static const ut64 WT_BIT = 0x80000000;
185 static const ut64 C_MATCH_BIT = 0x100000000;
186 
parse_hints(char * input)187 static char *parse_hints(char *input) {
188 	if (!strcmpnull (input, "unst")) {
189 		return "6";
190 	}
191 	if (!strcmpnull (input, "un")) {
192 		return "7";
193 	}
194 	if (!strcmpnull (input, "st")) {
195 		return "14";
196 	}
197 	if (!strcmpnull (input, "sy")) {
198 		return "15";
199 	}
200 	return "-1";
201 }
202 
iflag(char * input)203 static st8 iflag(char *input) {
204 	st8 res = 0;
205 	r_str_case (input, false);
206 
207 	for (; *input; input++) {
208 		switch (*input) {
209 		case 'a':
210 			res |= 0x4;
211 			break;
212 		case 'i':
213 			res |= 0x2;
214 			break;
215 		case 'f':
216 			res |= 0x1;
217 			break;
218 		default:
219 			return -1;
220 		}
221 	}
222 	return res;
223 }
224 
cqcheck(char ** input)225 static ut64 cqcheck(char **input) {
226 	ut64 res = 0;
227 	int i;
228 	ut8 offset = 0;
229 
230 	const char *conds[] = {
231 		"eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc",
232 		"hi", "ls", "ge", "lt", "gt", "le", "al", "nv", 0
233 	};
234 	for (i = 0; conds[i]; i++) {
235 		if (r_str_startswith (*input, conds[i])) {
236 			res |= C_MATCH_BIT;
237 			res |= i << 2;
238 			*input += 2;
239 			offset += 2;
240 			break;
241 		}
242 	}
243 	if (r_str_startswith (*input, ".n")) {
244 		res |= DOTN_BIT;
245 		*input += 2;
246 		offset += 2;
247 	} else
248 	if (r_str_startswith (*input, ".w")) {
249 		res |= DOTW_BIT;
250 		*input += 2;
251 		offset += 2;
252 	}
253 
254 	if (**input == '\0') {
255 		return res;
256 	}
257 	*input -= offset;
258 	return 0;
259 }
260 
opmask(char * input,char * opcode,ut64 allowed_mask)261 static ut64 opmask(char *input, char *opcode, ut64 allowed_mask) {
262 	ut64 res = 0;
263 
264 	r_str_case (input, false);
265 	if (strlen (opcode) > strlen (input)) {
266 		return 0;
267 	}
268 	if (r_str_startswith (input, opcode)) {
269 		input += strlen (opcode);
270 		res |= M_BIT;
271 		res |= cqcheck (&input);
272 
273 		if ((*input == 's') && (S_BIT & allowed_mask)) {
274 			res |= S_BIT;
275 			input++;
276 		}
277 		res |= cqcheck (&input);
278 
279 		if ((r_str_startswith (input, "wb")) && (WB_BIT & allowed_mask)) {
280 			res |= WB_BIT;
281 			input += 2;
282 		}
283 		if ((r_str_startswith (input, "wt")) && (WT_BIT & allowed_mask)) {
284 			res |= WT_BIT;
285 			input += 2;
286 		}
287 		res |= cqcheck (&input);
288 		if ((r_str_startswith (input, "db")) && (DB_BIT & allowed_mask)) {
289 			res |= DB_BIT;
290 			input += 2;
291 		}
292 		if ((r_str_startswith (input, "ea")) && (EA_BIT & allowed_mask)) {
293 			res |= EA_BIT;
294 			input += 2;
295 		}
296 		if ((r_str_startswith (input, "ia")) && (IA_BIT & allowed_mask)) {
297 			res |= IA_BIT;
298 			input += 2;
299 		}
300 		if ((r_str_startswith (input, "fd")) && (FD_BIT & allowed_mask)) {
301 			res |= FD_BIT;
302 			input += 2;
303 		}
304 		res |= cqcheck (&input);
305 		if ((*input == 'l') && (L_BIT & allowed_mask)) {
306 			res |= L_BIT;
307 			input++;
308 		}
309 		res |= cqcheck (&input);
310 		if ((r_str_startswith (input, "bb")) && (BB_BIT & allowed_mask)) {
311 			res |= BB_BIT;
312 			input += 2;
313 		}
314 		if ((r_str_startswith (input, "tt")) && (TT_BIT & allowed_mask)) {
315 			res |= TT_BIT;
316 			input += 2;
317 		}
318 		if ((r_str_startswith (input, "bt")) && (BT_BIT & allowed_mask)) {
319 			res |= BT_BIT;
320 			input += 2;
321 		}
322 		if ((r_str_startswith (input, "tb")) && (TB_BIT & allowed_mask)) {
323 			res |= TB_BIT;
324 			input += 2;
325 		}
326 		res |= cqcheck (&input);
327 		if ((*input == 'w') && (W_BIT & allowed_mask)) {
328 			res |= W_BIT;
329 			input++;
330 		}
331 		if ((*input == 'b') && (B_BIT & allowed_mask)) {
332 			res |= B_BIT;
333 			input++;
334 		} else
335 	        if ((*input == 'h') && (H_BIT & allowed_mask)) {
336 			res |= H_BIT;
337 			input++;
338 		} else
339 		if ((*input == 'd') && (D_BIT & allowed_mask)) {
340 			res |= D_BIT;
341 			input++;
342 		}
343 		if ((*input == 't') && (T_BIT & allowed_mask)) {
344 			res |= T_BIT;
345 			input++;
346 		}
347 		if ((*input == 's') && (S_BIT & allowed_mask)) {
348 			res |= S_BIT;
349 			input++;
350 		}
351 		res |= cqcheck (&input);
352 		if ((*input == 'r') && (R_BIT & allowed_mask)) {
353 			res |= R_BIT;
354 			input++;
355 		}
356 		res |= cqcheck (&input);
357 		if ((*input == '2') && (TWO_BIT & allowed_mask)) {
358 			res |= TWO_BIT;
359 			input++;
360 		}
361 		if ((*input == '8') && (EIGHT_BIT & allowed_mask)) {
362 			res |= EIGHT_BIT;
363 			input++;
364 		}
365 		if ((r_str_startswith (input, "16")) && (SIXTEEN_BIT & allowed_mask)) {
366 			res |= SIXTEEN_BIT;
367 			input += 2;
368 		}
369 		res |= cqcheck (&input);
370 		if ((*input == 'l') && (L_BIT & allowed_mask)) {
371 			res |= L_BIT;
372 			input++;
373 		}
374 		if ((*input == 'x') && (X_BIT & allowed_mask)) {
375 			res |= X_BIT;
376 			input++;
377 		}
378 		res |= cqcheck (&input);
379 		if ((r_str_startswith (input, "id")) && (ID_BIT & allowed_mask)) {
380 			res |= ID_BIT;
381 			input += 2;
382 		}
383 		if ((r_str_startswith (input, "ie")) && (IE_BIT & allowed_mask)) {
384 			res |= IE_BIT;
385 			input += 2;
386 		}
387 		res |= cqcheck (&input);
388 		if ((r_str_startswith (input, "sh")) && (SH_BIT & allowed_mask)) {
389 			res |= SH_BIT;
390 			input += 2;
391 		}
392 		res |= cqcheck (&input);
393 		if (!(res & C_MATCH_BIT)) {
394 			res |= 15 << 2; // nv is the default condition
395 		}
396 		if (*input == 0) {
397 			return res;
398 		}
399 	}
400 	return 0;
401 }
402 
itmask(char * input)403 static ut32 itmask(char *input) {
404 	ut32 res = 0;
405 	ut32 i, length;
406 	r_str_case (input, false);
407 	if (2 > strlen (input)) {
408 		return 0;
409 	}
410 	if (r_str_startswith (input, "it")) {
411 		input += 2;
412 		res |= 1; // matched
413 		if (strlen(input) > 3) {
414 			return 0;
415 		}
416 		res |= (strlen (input) & 0x3) << 4;
417 		length = strlen (input);
418 		for (i = 0; i < length; i++, input++ ) {
419 			if (*input == 'e') {
420 				res |= 1 << (3 - i);
421 				continue;
422 			}
423 			if (*input == 't') {
424 				continue;
425 			}
426 			return 0;
427 		}
428 		return res;
429 	}
430 	return 0;
431 }
432 
433 static bool err;
434 //decode str as number
getnum(const char * str)435 static ut64 getnum(const char *str) {
436 	char *endptr;
437 	err = false;
438 	ut64 val;
439 
440 	if (!str) {
441 		err = true;
442 		return 0;
443 	}
444 	while (*str == '$' || *str == '#') {
445 		str++;
446 	}
447 	val = strtoll (str, &endptr, 0);
448 	if (str != endptr && *endptr == '\0') {
449 		return val;
450 	}
451 	err = true;
452 	return 0;
453 }
454 
getnumbang(const char * str)455 static ut64 getnumbang(const char *str) {
456 	ut64 res;
457 
458 	if (!str || !*str || !r_str_endswith (str, "!")) {
459 		err = true;
460 		return 0;
461 	}
462 	char *temp = r_str_ndup (str, strlen (str) - 1);
463 	if (!temp) {
464 		return -1;
465 	}
466 	err = false;
467 	res = getnum (temp);
468 	free (temp);
469 	return res; // err propagates
470 }
471 
getimmed8(const char * str)472 static ut32 getimmed8(const char *str) {
473 	ut32 num = getnum (str);
474 	if (err) {
475 		return 0;
476 	}
477 	ut32 rotate;
478 	if (num <= 0xff) {
479 		return num;
480 	} else {
481 		for (rotate = 1; rotate < 16; rotate++) {
482 			// rol 2
483 			num = ((num << 2) | (num >> 30));
484 			if (num == (num & 0xff)) {
485 				return (num | (rotate << 8));
486 			}
487 		}
488 		err = 1;
489 		return 0;
490 	}
491 }
492 
firstsigdigit(ut32 num)493 static st32 firstsigdigit (ut32 num) {
494 	st32 f = -1;
495 	st32 b = -1;
496 	ut32 forwardmask = 0x80000000;
497 	ut32 backwardmask = 0x1;
498 	ut32 i;
499 	for (i = 0; i < 32; i++ ) {
500 		if ( (forwardmask & num) && (f == -1)) {
501 			f = i;
502 		}
503 		if ( (backwardmask & num) && (b == -1)) {
504 			b = 32-i;
505 		}
506 		forwardmask >>= 1;
507 		backwardmask <<= 1;
508 	}
509 
510 	if ((b-f) < 9) {
511 		return f;
512 	}
513 	return -1;
514 }
515 
getthbimmed(st32 number)516 static ut32 getthbimmed(st32 number) {
517 	ut32 res = 0;
518 	if (number < 0) {
519 		res |= 1 << 18;
520 	}
521 	number >>= 1;
522 	res |= (( number & 0xff) << 8);
523 	number >>= 8;
524 	res |= ( number & 0x07);
525 	number >>= 3;
526 	res |= (( number & 0xff) << 24);
527 	number >>= 8;
528 	res |= (( number & 0x3) << 16);
529 	number >>= 2;
530 	if (number < 0) {
531 		res |= (( number & 0x1) << 3);
532 		number >>= 1;
533 		res |= (( number & 0x1) << 5);
534 	} else {
535 		res |= ((!( number & 0x1)) << 3);
536 		number >>= 1;
537 		res |= ((!( number & 0x1)) << 5);
538 	}
539 	return res;
540 }
541 
getthzeroimmed12(ut32 number)542 static ut32 getthzeroimmed12(ut32 number) {
543 	ut32 res = 0;
544 	res |= (number & 0x800) << 7;
545 	res |= (number & 0x700) >> 4;
546 	res |= (number & 0x0ff) << 8;
547 	return res;
548 }
549 
getthzeroimmed16(ut32 number)550 static ut32 getthzeroimmed16(ut32 number) {
551 	ut32 res = 0;
552 	res |= (number & 0xf000) << 12;
553 	res |= (number & 0x0800) << 7;
554 	res |= (number & 0x0700) >> 4;
555 	res |= (number & 0x00ff) << 8;
556 	return res;
557 }
558 
getthimmed12(const char * str)559 static ut32 getthimmed12(const char *str) {
560 	ut64 num = getnum (str);
561 	if (err) {
562 		return 0;
563 	}
564 
565 	st32 FSD = 0;
566 	ut64 result = 0;
567 	if (num <= 0xff) {
568 		return num << 8;
569 	} else if ( ((num & 0xff00ff00) == 0) && ((num & 0x00ff0000) == ((num & 0x000000ff) << 16)) ) {
570 		result |= (num & 0x000000ff) << 8;
571 		result |= 0x00000010;
572 		return result;
573 	} else if ( ((num & 0x00ff00ff) == 0) && ((num & 0xff000000) == ((num & 0x0000ff00) << 16)) ) {
574 		result |= num & 0x0000ff00;
575 		result |= 0x00000020;
576 		return result;
577 	} else if ( ((num & 0xff000000) == ((num & 0x00ff0000) << 8)) && ((num & 0xff000000) == ((num & 0x0000ff00) << 16)) && ((num &0xff000000) == ((num & 0x000000ff) << 24)) ) {
578 		result |= num & 0x0000ff00;
579 		result |= 0x00000030;
580 		return result;
581 	} else {
582 		FSD = firstsigdigit(num);
583 		if (FSD != -1) {
584 		        result |= ((num >> (24-FSD)) & 0x0000007f) << 8;
585 			result |= ((8+FSD) & 0x1) << 15;
586 			result |= ((8+FSD) & 0xe) << 3;
587 			result |= ((8+FSD) & 0x10) << 14;
588 			return result;
589 		} else {
590 			err = true;
591 			return 0;
592 		}
593 	}
594 }
595 
getrange(char * s)596 static char *getrange(char *s) {
597 	char *p = NULL;
598 	while (s && *s) {
599 		if (*s == ',') {
600 			p = s+1;
601 			*p=0;
602 		}
603 		if (*s == '[' || *s == ']') {
604 			memmove (s, s + 1, strlen (s + 1) + 1);
605 		}
606 		if (*s == '}') {
607 			*s = 0;
608 		}
609 		s++;
610 	}
611 	while (p && *p == ' ') {
612 		p++;
613 	}
614 	return p;
615 }
616 
617 //ret register #; -1 if failed
getreg(const char * str)618 static int getreg(const char *str) {
619 	int i;
620 	char *ep;
621 	const char *aliases[] = { "sl", "fp", "ip", "sp", "lr", "pc", NULL };
622 	if (!str || !*str) {
623 		return -1;
624 	}
625 	if (*str == 'r') {
626 		int reg = strtol (str + 1, &ep, 10);
627 		if ((ep[0] != '\0') || (str[1] == '\0')) {
628 			return -1;
629 		}
630 		if (reg < 16 && reg >= 0) {
631 			return reg;
632 		}
633 	}
634 	for (i=0; aliases[i]; i++) {
635 		if (!strcmpnull (str, aliases[i])) {
636 			return 10 + i;
637 		}
638 	}
639 	return -1;
640 }
641 
642 
getlistmask(char * input)643 static st32 getlistmask(char *input) {
644 	st32 tempres, res = 0;
645 	int i, j, start, end;
646 	char *temp = NULL;
647 	char *otemp = NULL;
648 	char *temp2 = malloc (strlen (input) + 1);
649 	if (!temp2) {
650 		res = -1;
651 		goto end;
652 	}
653 	temp = (char *)malloc (strlen (input) + 1);
654 	if (!temp) {
655 		res = -1;
656 		goto end;
657 	}
658 	otemp = temp;
659 	while (*input != '\0') {
660 		for (; *input == ' '; input++) {
661 			;
662 		}
663 		for (i = 0; input[i] != ',' && input[i] != '\0'; i++) {
664 			;
665 		}
666 		r_str_ncpy (temp, input, i + 1);
667 
668 		input += i;
669 		if (*input != '\0') {
670 			input++;
671 		}
672 
673 		for (i = 0; temp[i] != '-' && temp[i] != '\0'; i++) {
674 			;
675 		}
676 		if (i == strlen (temp)) {
677 			tempres = getreg (temp);
678 			if (tempres == -1 || tempres > 15) {
679 				res = -1;
680 				goto end;
681 			}
682 			res |= 1 << tempres;
683 		} else {
684 			strncpy (temp2, temp, i);
685 			temp2[i] = 0;
686 			temp += i + 1;
687 			start = getreg (temp2);
688 			if (start == -1 || start > 15) {
689 				res = -1;
690 				goto end;
691 			}
692 			end = getreg (temp);
693 			if (end == -1 || end > 15) {
694 				res = -1;
695 				goto end;
696 			}
697 
698 			for (j = start; j <= end; j++ ) {
699 				res |= 1 << j;
700 			}
701 		}
702 	}
703 end:
704 	free (otemp);
705 	free (temp2);
706 	return res;
707 }
708 
getregmemstart(const char * input)709 static st32 getregmemstart(const char *input) {
710 	if ((strlen (input) < 1) || (!(*input == '['))) {
711 		return -1;
712 	}
713 	input++;
714 	return getreg (input);
715 }
716 
getregmemstartend(const char * input)717 static st32 getregmemstartend(const char *input) {
718 	st32 res;
719 	if (!input || (strlen (input) < 2) || (*input != '[') || !r_str_endswith (input, "]")) {
720 		return -1;
721 	}
722 	input++;
723 	char *temp = r_str_ndup (input, strlen (input) - 1);
724 	if (!temp) {
725 		return -1;
726 	}
727 	res = getreg (temp);
728 	free (temp);
729 	return res;
730 }
731 
getregmemend(const char * input)732 static st32 getregmemend(const char *input) {
733 	st32 res;
734 	if (!input || !*input || !r_str_endswith (input, "]")) {
735 		return -1;
736 	}
737 
738 	char *temp = r_str_ndup (input, strlen (input) - 1);
739 	if (!temp) {
740 		return -1;
741 	}
742 	res = getreg (temp);
743 	free (temp);
744 	return res;
745 }
746 
getreglist(const char * input)747 static st32 getreglist(const char *input) {
748 	st32 res;
749 
750 	if (!input || (strlen (input) < 2) || (*input != '{') || !r_str_endswith (input, "}")) {
751 		return -1;
752 	}
753 	if (*input) {
754 		input++;
755 	}
756 	char *temp = r_str_ndup (input, strlen (input) - 1);
757 	if (!temp) {
758 		return -1;
759 	}
760 	res = getlistmask (temp);
761 	free (temp);
762 	return res;
763 }
764 
getnummemend(const char * input)765 static st32 getnummemend (const char *input) {
766 	st32 res;
767 	err = false;
768 	if (!input || !*input || !r_str_endswith (input, "]")) {
769 		err = true;
770 		return -1;
771 	}
772 	char *temp = r_str_ndup (input, strlen (input) - 1);
773 	if (!temp) {
774 		err = true;
775 		return -1;
776 	}
777 	res = getnum (temp);
778 	free (temp);
779 	return res;
780 }
781 
getnummemendbang(const char * input)782 static st32 getnummemendbang (const char *input) {
783 	st32 res;
784 	err = false;
785 	if (!input || (strlen (input) < 2) || (input[strlen(input) - 2] != ']' || !r_str_endswith (input, "!"))) {
786 		err = true;
787 		return 0;
788 	}
789 	char *temp = r_str_ndup (input, strlen (input) - 2);
790 	if (!temp) {
791 		err = true;
792 		return 0;
793 	}
794 	res = getnum (temp);
795 	free (temp);
796 	return res;
797 }
798 
getregmembang(const char * input)799 static st32 getregmembang(const char *input) {
800 	st32 res;
801 	if (!input || !*input || !r_str_endswith (input, "!")) {
802 		return -1;
803 	}
804 	char *temp = r_str_ndup (input, strlen (input) - 1);
805 	if (!temp) {
806 		return -1;
807 	}
808 	res = getreg (temp);
809 	free (temp);
810 	return res;
811 }
812 
getcoproc(const char * str)813 static int getcoproc(const char *str) {
814 	char *ep;
815 	if (!str || !*str) {
816 		return -1;
817 	}
818 	if (*str == 'p') {
819 		int coproc = strtol (str + 1, &ep, 10);
820 		if ((ep[0] != '\0') || (str[1] == '\0')) {
821 			return -1;
822 		}
823 		if (coproc < 16 && coproc >= 0) {
824 			return coproc;
825 		}
826 	}
827 	return -1;
828 }
829 
getcoprocreg(const char * str)830 static int getcoprocreg(const char *str) {
831 	char *ep;
832 
833 	if (!str || !*str) {
834 		return -1;
835 	}
836 	if (r_str_startswith (str, "c")) {
837 		int reg = strtol (str + 1, &ep, 10);
838 		if ((ep[0] != '\0') || (str[1] == '\0')) {
839 			return -1;
840 		}
841 		if (reg < 16 && reg >= 0) {
842 			return reg;
843 		}
844 	}
845 	return -1;
846 }
847 
interpret_msrbank(char * str,ut8 * spsr)848 static ut8 interpret_msrbank (char *str, ut8 *spsr) {
849 	const char fields[] = {'c', 'x', 's', 'f', 0};
850 	int res = 0;
851 	int i, j;
852 	if (r_str_startswith (str, "spsr_")) {
853 		*spsr = 1;
854 	} else {
855 		*spsr = 0;
856 	}
857 
858 	if (r_str_startswith (str, "apsr_")) {
859 		if (!(strcmp (str+5, "g"))) {
860 			return 0x4;
861 		}
862 		if (!(strcmp (str+5, "nzcvq"))) {
863 			return 0x8;
864 		}
865 		if (!(strcmp (str+5, "nzcvqg"))) {
866 			return 0xc;
867 		}
868 	}
869 	if (r_str_startswith (str, "cpsr_") || r_str_startswith (str, "spsr_")) {
870 		for (i = 0; str[5+i]; i++) {
871 			for (j = 0; fields[j]; j++) {
872 				if (str[5+i] == fields[j]) {
873 					break;
874 				}
875 			}
876 			if (!(fields[j])) {
877 				return 0;
878 			}
879 			res |= 1 << j;
880 		}
881 		return res;
882 	}
883 	return 0;
884 }
885 
thumb_getshift(const char * str)886 static ut32 thumb_getshift(const char *str) {
887 	// only immediate shifts are ever used by thumb-2. Bit positions are different from ARM.
888 	const char *shifts[] = {
889 		"LSL", "LSR", "ASR", "ROR", 0, "RRX"
890 	};
891 	char *type = strdup (str);
892 	char *arg;
893 	char *space;
894 	ut32 res = 0;
895 	ut32 shift = false;
896 	err = false;
897 	ut32 argn;
898 	ut32 i;
899 
900 	r_str_case (type,true);
901 
902 	if (!strcmp (type, shifts[5])) {
903 		// handle RRX alias case
904 		res |= 3 << 12;
905 		free (type);
906 		return res;
907 	}
908 
909 	space = strchr (type, ' ');
910 	if (!space) {
911 		free (type);
912 		err = true;
913 		return 0;
914 	}
915 	*space = 0;
916 	arg = strdup (++space);
917 
918 	for (i = 0; shifts[i]; i++) {
919 		if (!strcmp (type, shifts[i])) {
920 			shift = true;
921 			break;
922 		}
923 	}
924 	if (!shift) {
925 		err = true;
926 		free (type);
927 		free (arg);
928 		return 0;
929 	}
930 	res |= i << 12;
931 
932 	argn = getnum (arg);
933 	if (err || argn > 32) {
934 		err = true;
935 		free (type);
936 		free (arg);
937 		return 0;
938 	}
939 	res |= ( (argn & 0x1c) << 2);
940 	res |= ( (argn & 0x3) << 14);
941 
942 	free (type);
943 	free (arg);
944 	return res;
945 }
946 
getshiftmemend(const char * input)947 static st32 getshiftmemend(const char *input) {
948 	st32 res;
949 	if (!input || !*input || !r_str_endswith (input, "]")) {
950 		return -1;
951 	}
952 
953 	char *temp = r_str_ndup (input, strlen (input) - 1);
954 	if (!temp) {
955 		return -1;
956 	}
957 	res = thumb_getshift (temp);
958 	free (temp);
959 	return res;
960 }
961 
collect_list(char * input[])962 void collect_list(char *input[]) {
963 	if (input[0] == NULL) {
964 		return;
965 	}
966 	char *temp  = malloc (500);
967 	if (!temp) {
968 		return;
969 	}
970 	temp[0] = 0;
971 	int i;
972 	int conc = 0;
973 	int start, end = 0;
974 	int arrsz;
975 	for (arrsz = 1; input[arrsz] != NULL; arrsz++) {
976 		;
977 	}
978 
979 	for (i = 0; input[i]; i++) {
980 		if (conc) {
981 			strcat (temp, ", ");
982 			strcat (temp, input[i]);
983 		}
984 		if (input[i][0] == '{') {
985 			conc = 1;
986 			strcat (temp, input[i]);
987 			start = i;
988 		}
989 		if ((conc) & (input[i][strlen (input[i]) - 1] == '}')) {
990 			conc = 0;
991 			end = i;
992 		}
993 	}
994 	if (end == 0) {
995 		free (temp);
996 		return;
997 	}
998 	input[start] = temp;
999 	for (i = start + 1; i < arrsz; i++) {
1000 		input[i] = input[(end-start) + i];
1001 	}
1002 	input[i] = NULL;
1003 }
1004 
thumb_selector(char * args[])1005 static ut64 thumb_selector(char *args[]) {
1006 	collect_list(args);
1007 	ut64 res = 0;
1008 	ut8 i;
1009 	for (i = 0; i < 15; i++) {
1010 		if (args[i] == NULL) {
1011 			break;
1012 		}
1013 		if (getreg (args[i]) != -1) {
1014 			res |= 1 << (i*4);
1015 			continue;
1016 		}
1017 		err = false;
1018 		getnum (args[i]);
1019 		if (!err) {
1020 			res |= 2 << (i*4);
1021 			continue;
1022 		}
1023 		err = false;
1024 		thumb_getshift (args[i]);
1025 		if (!err) {
1026 			res |= 3 << (i*4);
1027 			continue;
1028 		}
1029 		if (getcoproc (args[i]) != -1) {
1030 			res |= 4 << (i*4);
1031 			continue;
1032 		}
1033 		if (getcoprocreg (args[i]) != -1) {
1034 			res |= 5 << (i*4);
1035 			continue;
1036 		}
1037 		if (getregmemstart (args[i]) != -1) {
1038 			res |= 6 << (i*4);
1039 			continue;
1040 		}
1041 		if (getregmemstartend (args[i]) != -1) {
1042 			res |= 7 << (i*4);
1043 			continue;
1044 		}
1045 		err = false;
1046 		getnummemend(args[i]);
1047 		if (!err) {
1048 			res |= 8 << (i*4);
1049 			continue;
1050 		}
1051 		err = false;
1052 		getnummemendbang(args[i]);
1053 		if (!err) {
1054 			res |= 9 << (i*4);
1055 			continue;
1056 		}
1057 		if (getregmembang (args[i]) != -1) {
1058 			res |= 0xa << (i*4);
1059 			continue;
1060 		}
1061 		if (getreglist (args[i]) != -1) {
1062 			res |= 0xb << (i*4);
1063 			continue;
1064 		}
1065 		if (getregmemend (args[i]) != -1) {
1066 			res |= 0xc << (i*4);
1067 			continue;
1068 		}
1069 		if (getshiftmemend (args[i]) != -1) {
1070 			res |= 0xd << (i*4);
1071 			continue;
1072 		}
1073 		err = false;
1074 		getnumbang(args[i]);
1075 		if (!err) {
1076 			res |= 0xe << (i*4);
1077 			continue;
1078 		}
1079 		res |= 0xf << (i*4);
1080 	}
1081 	err = false;
1082 	return res;
1083 }
1084 
getshift(const char * str)1085 static ut32 getshift(const char *str) {
1086 	char type[128];
1087 	char arg[128];
1088 	char *space;
1089 	ut32 i=0, shift=0;
1090 	const char *shifts[] = {
1091 		"LSL", "LSR", "ASR", "ROR",
1092 		0, "RRX" // alias for ROR #0
1093 	};
1094 
1095 	strncpy (type, str, sizeof (type) - 1);
1096 	// XXX strcaecmp is probably unportable
1097 	if (!r_str_casecmp (type, shifts[5])) {
1098 		// handle RRX alias case
1099 		shift = 6;
1100 	} else { // all other shift types
1101 		space = strchr (type, ' ');
1102 		if (!space) {
1103 			return 0;
1104 		}
1105 		*space = 0;
1106 		strncpy (arg, ++space, sizeof(arg) - 1);
1107 
1108 		for (i = 0; shifts[i]; i++) {
1109 			if (!r_str_casecmp (type, shifts[i])) {
1110 				shift = 1;
1111 				break;
1112 			}
1113 		}
1114 		if (!shift) {
1115 			return 0;
1116 		}
1117 		shift = i * 2;
1118 		if ((i = getreg (arg)) != -1) {
1119 			i <<= 8; // set reg
1120 //			i|=1; // use reg
1121 			i |= (1 << 4); // bitshift
1122 			i |= shift << 4; // set shift mode
1123 			if (shift == 6) {
1124 				i |= (1 << 20);
1125 			}
1126 		} else {
1127 			char *bracket = strchr (arg, ']');
1128 			if (bracket) {
1129 				*bracket = '\0';
1130 			}
1131 			// ensure only the bottom 5 bits are used
1132 			i &= 0x1f;
1133 			if (!i) {
1134 				i = 32;
1135 			}
1136 			i = (i * 8);
1137 			i |= shift; // lsl, ror, ...
1138 			i = i << 4;
1139 		}
1140 	}
1141 
1142 	return i;
1143 }
1144 
arm_opcode_parse(ArmOpcode * ao,const char * str)1145 static void arm_opcode_parse(ArmOpcode *ao, const char *str) {
1146 	int i;
1147 	memset (ao, 0, sizeof (ArmOpcode));
1148 	if (strlen (str) + 1 >= sizeof (ao->op)) {
1149 		return;
1150 	}
1151 	strncpy (ao->op, str, sizeof (ao->op)-1);
1152 	strcpy (ao->opstr, ao->op);
1153 	ao->a[0] = strchr (ao->op, ' ');
1154 	for (i=0; i<15; i++) {
1155 		if (ao->a[i]) {
1156 			*ao->a[i] = 0;
1157 			ao->a[i+1] = strchr (++ao->a[i], ',');
1158 		} else {
1159 			break;
1160 		}
1161 	}
1162 	if (ao->a[i]) {
1163 		*ao->a[i] = 0;
1164 		ao->a[i]++;
1165 	}
1166 	for (i=0; i<16; i++) {
1167 		while (ao->a[i] && *ao->a[i] == ' ') {
1168 			ao->a[i]++;
1169 		}
1170 	}
1171 }
1172 
arm_opcode_cond(ArmOpcode * ao,int delta)1173 static inline int arm_opcode_cond(ArmOpcode *ao, int delta) {
1174 	const char *conds[] = {
1175 		"eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc",
1176 		"hi", "ls", "ge", "lt", "gt", "le", "al", "nv", 0
1177 	};
1178 	int i, cond = 14; // 'always' is default
1179 	char *c = ao->op+delta;
1180 	for (i=0; conds[i]; i++) {
1181 		if (!strcmpnull (c, conds[i])) {
1182 			cond = i;
1183 			break;
1184 		}
1185 	}
1186 	ao->o |= cond << 4;
1187 	return cond;
1188 }
1189 
thumb_getoffset(char * label,ut64 cur)1190 static st32 thumb_getoffset(char *label, ut64 cur) {
1191 	st32 res = r_num_math (NULL, label);
1192 	res -= 4;
1193 	res -= cur; // possible integer underflow
1194 	//printf("thumb_getoffset: %s, %lld, %lld\n", label, res, cur);
1195 	return res;
1196 }
1197 
std_16bit_2reg(ArmOpcode * ao,ut64 m)1198 static st8 std_16bit_2reg(ArmOpcode *ao, ut64 m) {
1199 	ut8 rd = getreg (ao->a[0]);
1200 	ut8 rn = getreg (ao->a[1]);
1201 	if ( (rd < 8) && (rn < 8) && !(m & DOTW_BIT)) {
1202 		ao->o |= rd << 8;
1203 		ao->o |= rn << 11;
1204 		return 2;
1205 	}
1206 	return 0;
1207 }
1208 
mem_16bit_2reg(ArmOpcode * ao,ut64 m)1209 static st8 mem_16bit_2reg(ArmOpcode *ao, ut64 m) {
1210 	ut8 rd = getreg (ao->a[0]);
1211 	ut8 rn = getregmemstart (ao->a[1]);
1212 	if ( (rd < 8) && (rn < 8) && !(m & DOTW_BIT)) {
1213 		ao->o |= rd << 8;
1214 		ao->o |= rn << 11;
1215 		return 2;
1216 	}
1217 	return 0;
1218 }
1219 
std_32bit_2reg(ArmOpcode * ao,ut64 m,bool shift)1220 static st8 std_32bit_2reg(ArmOpcode *ao, ut64 m, bool shift) {
1221 	ut8 rd = getreg (ao->a[0]);
1222 	ut8 rn = getreg (ao->a[1]);
1223 	if ((rd > 15) || (rn > 15) || (m & DOTN_BIT)) {
1224 		return -1;
1225 	}
1226 	if (m & S_BIT) {
1227 		ao->o |= 1 << 28;
1228 	}
1229 	if (shift) {
1230 		err = false;
1231 		ut32 shiftnum = thumb_getshift (ao->a[2]);
1232 		if (err) {
1233 			return -1;
1234 		}
1235 		ao->o |= shiftnum;
1236 		ao->o |= rd << 24;
1237 		ao->o |= rn << 8;
1238 	} else {
1239 		ao->o |= rd;
1240 		ao->o |= rn << 24;
1241 	}
1242 	return 4;
1243 }
1244 
mem_32bit_2reg(ArmOpcode * ao,ut64 m)1245 static st8 mem_32bit_2reg(ArmOpcode *ao, ut64 m) {
1246 	ut8 rd = getreg (ao->a[0]);
1247 	ut8 rn = getregmemstart (ao->a[1]);
1248 	if ((rd > 15) || (rn > 15) || (m & DOTN_BIT)) {
1249 		return -1;
1250 	}
1251 	ao->o |= rd << 4;
1252 	ao->o |= rn << 24;
1253 	return 4;
1254 }
1255 
std_32bit_3reg(ArmOpcode * ao,ut64 m,bool shift)1256 static st8 std_32bit_3reg(ArmOpcode *ao, ut64 m, bool shift) {
1257 	ut8 rd = getreg (ao->a[0]);
1258 	ut8 rn = getreg (ao->a[1]);
1259 	ut8 rm = getreg (ao->a[2]);
1260 	if ((rd > 15) || (rn > 15) || (rm > 15) || (m & DOTN_BIT)) {
1261 		return -1;
1262 	}
1263 	ao->o |= rd;
1264 	ao->o |= rn << 24;
1265 	ao->o |= rm << 8;
1266 	if (shift) {
1267 		err = false;
1268 		ut32 shiftnum = thumb_getshift (ao->a[3]);
1269 		if (err) {
1270 			return -1;
1271 		}
1272 		ao->o |= shiftnum;
1273 	}
1274 	if (m & S_BIT) {
1275 		ao->o |= 1 << 28;
1276 	}
1277 	return 4;
1278 }
1279 
std_opt_2(ArmOpcode * ao)1280 static void std_opt_2(ArmOpcode *ao) {
1281 	ao->a[2] = ao->a[1];
1282 	ao->a[1] = ao->a[0];
1283 }
1284 
std_opt_3(ArmOpcode * ao)1285 static void std_opt_3(ArmOpcode *ao) {
1286 	ao->a[3] = ao->a[2];
1287 	ao->a[2] = ao->a[1];
1288 	ao->a[1] = ao->a[0];
1289 }
1290 
1291 // TODO: group similar instructions like for non-thumb
thumb_assemble(ArmOpcode * ao,ut64 off,const char * str)1292 static int thumb_assemble(ArmOpcode *ao, ut64 off, const char *str) {
1293 	ut64 m;
1294 	ao->o = UT32_MAX;
1295 	if (!strcmpnull (ao->op, "udf")) {
1296 		ao->o = 0xde;
1297 		ao->o |= getnum (ao->a[0]) << 8;
1298 		return 2;
1299 	} else
1300 	if ((m = opmask (ao->op, "add", S_BIT | W_BIT))) {
1301 		ut64 argt = thumb_selector (ao->a);
1302 		switch (argt) {
1303 		case THUMB_REG_CONST: {
1304 			std_opt_2 (ao);
1305 		        }
1306 			// intentional fallthrough
1307 		case THUMB_REG_REG_CONST: {
1308 			ut8 reg1 = getreg (ao->a[0]);
1309 			ut8 reg2 = getreg (ao->a[1]);
1310 			ut32 num = getnum (ao->a[2]);
1311 
1312 			if ((reg1 > 15) || (reg2 > 15)) {
1313 				return -1;
1314 			}
1315 
1316 			if (reg2 == 13) {
1317 				if ((reg1 < 8) && (num < 1024) && (num % 4 == 0) && (!(m & DOTW_BIT)) && (!(m & W_BIT))) {
1318 					ao->o = 0x00a8;
1319 					ao->o |= reg1;
1320 					ao->o |= (num >> 2) << 8;
1321 					return 2;
1322 				}
1323 
1324 				if ((reg1 == 13) && (num < 512) && (num % 4 == 0) && (!(m & DOTW_BIT)) && (!(m & W_BIT))) {
1325 					ao->o = 0x00b0;
1326 					ao->o |= (num >> 2) << 8;
1327 					return 2;
1328 				}
1329 
1330 				err = false;
1331 				ut32 thnum = getthimmed12 (ao->a[2]);
1332 				if (!err && (!(m & W_BIT))) {
1333 					ao->o = 0x0df10000;
1334 					ao->o |= reg1;
1335 					ao->o |= thnum;
1336 					if (m & S_BIT) {
1337 						ao->o |= 1 << 28;
1338 					}
1339 					return 4;
1340 				}
1341 
1342 				if (num > 4095) {
1343 					return -1;
1344 				}
1345 
1346 				ao->o = 0x0df20000;
1347 				ao->o |= reg1;
1348 				ao->o |= getthzeroimmed12 (num);
1349 				return 4;
1350 			}
1351 
1352 			if (num < 8) {
1353 				ao->o = 0x001c;
1354 				ao->o |= (num & 0x3) << 14;
1355 				ao->o |= (num >> 2);
1356 				if (std_16bit_2reg (ao, m)) {
1357 					return 2;
1358 				}
1359 			}
1360 
1361 			if ((reg1 < 8) && (reg1 == reg2) && (num < 256)) {
1362 				ao->o = 0x0030;
1363 				ao->o |= reg1;
1364 				ao->o |= num << 8;
1365 				return 2;
1366 			}
1367 
1368 			err = false;
1369 			ut32 thnum = getthimmed12 (ao->a[2]);
1370 			if (!err && (!(m & W_BIT))) {
1371 				ao->o = 0x00f10000;
1372 				ao->o |= thnum;
1373 				return std_32bit_2reg (ao, m, false);
1374 			}
1375 
1376 			if (num > 4095) {
1377 				return -1;
1378 			}
1379 
1380 			ao->o = 0x00f20000;
1381 			ao->o |= getthzeroimmed12 (num);
1382 			return std_32bit_2reg (ao, m, false);
1383 		        }
1384 			break;
1385 		case THUMB_REG_REG: {
1386 			std_opt_2 (ao);
1387 		        }
1388 			// intentional fallthrough
1389 		case THUMB_REG_REG_REG: {
1390 			ao->a[3] = "lsl 0";
1391 		        }
1392 			// intentional fallthrough
1393 		case THUMB_REG_REG_SHIFT: {
1394 			if (ao->a[3] == NULL) { // double fallthrough
1395 				std_opt_3 (ao);
1396 			}
1397 		        }
1398 			// intentional fallthrough
1399 		case THUMB_REG_REG_REG_SHIFT: {
1400 			ut8 reg1 = getreg (ao->a[0]);
1401 			ut8 reg2 = getreg (ao->a[1]);
1402 			ut8 reg3 = getreg (ao->a[2]);
1403 			ut32 shift = thumb_getshift (ao->a[3]);
1404 
1405 			if ((reg1 > 15) || (reg2 > 15) || (reg3 > 15)) {
1406 				return -1;
1407 			}
1408 
1409 			if (reg2 == 13) {
1410 				if ((reg1 == reg3) && (!(m & DOTW_BIT)) && (shift == 0)) {
1411 					ao->o = 0x6844;
1412 					ao->o |= (reg1 & 0x7) << 8;
1413 					ao->o |= (reg1 >> 3) << 15;
1414 					return 2;
1415 				}
1416 
1417 				if ((reg1 == 13) && (!(m & DOTW_BIT)) && (shift == 0)) {
1418 					ao->o = 0x8544;
1419 					ao->o |= reg3 << 11;
1420 					return 2;
1421 				}
1422 
1423 				ao->o = 0x0deb0000;
1424 				ao->o |= reg1;
1425 				ao->o |= reg3 << 8;
1426 				ao->o |= shift;
1427 				if (m & S_BIT) {
1428 					ao->o |= 1 << 28;
1429 				}
1430 				return 4;
1431 			}
1432 
1433 			if ((reg3 < 8) && (!(m & DOTW_BIT)) && (shift == 0)) {
1434 				ao->o = 0x0018;
1435 				ao->o |= (reg3 >> 2);
1436 				ao->o |= (reg3 & 0x3) << 14;
1437 				if (std_16bit_2reg (ao, m)) {
1438 					return 2;
1439 				}
1440 			}
1441 
1442 			if ((reg1 == reg2) && (!(m & DOTW_BIT)) && (shift == 0)) {
1443 				ao->o = 0x0044;
1444 				ao->o |= (reg1 & 0x7) << 8;
1445 				ao->o |= (reg1 >> 3) << 15;
1446 				ao->o |= reg3 << 11;
1447 				return 2;
1448 			}
1449 
1450 			ao->o = 0x00eb0000;
1451 			return std_32bit_3reg (ao, m, true);
1452 		        }
1453 			break;
1454 		default:
1455 			return -1;
1456 		}
1457 	} else
1458 	if ((m = opmask (ao->op, "adc", S_BIT))) {
1459 		ut64 argt = thumb_selector (ao->a);
1460 		switch (argt) {
1461 		case THUMB_REG_CONST: {
1462 			std_opt_2 (ao);
1463 		        }
1464 			// intentional fallthrough
1465 		case THUMB_REG_REG_CONST: {
1466 			ao->o = 0x40f10000;
1467 			ao->o |= getthimmed12 (ao->a[2]);
1468 			return std_32bit_2reg (ao, m, false);
1469 		        }
1470 			break;
1471 		case THUMB_REG_REG: {
1472 			ao->o = 0x4041;
1473 			if (std_16bit_2reg (ao, m)) {
1474 				return 2;
1475 			}
1476 			std_opt_2 (ao);
1477 		        }
1478 			// intentional fallthrough
1479 		case THUMB_REG_REG_REG: {
1480 			ao->o = 0x40eb0000;
1481 			return std_32bit_3reg (ao, m, false);
1482 		        }
1483 			break;
1484 		case THUMB_REG_REG_SHIFT: {
1485 			std_opt_3 (ao);
1486 		        }
1487 			// intentional fallthrough
1488 			// a bit naughty, perhaps?
1489 		case THUMB_REG_REG_REG_SHIFT: {
1490 			ao->o = 0x40eb0000;
1491 			return std_32bit_3reg(ao, m, true);
1492 		        }
1493 			break;
1494 		default:
1495 			return -1;
1496 		}
1497 	} else
1498 	if ((m = opmask (ao->op, "adr", 0))) {
1499 		ut64 argt = thumb_selector (ao->a);
1500 		switch (argt) {
1501 		case THUMB_REG_CONST: {
1502 			ut8 reg = getreg (ao->a[0]);
1503 			st32 label = getnum (ao->a[1]);
1504 			if ( !(m & DOTW_BIT) && (reg < 8) && (label < 1024) && (label >= 0) && (label % 4 == 0)) {
1505 				ao->o = 0x00a0;
1506 				ao->o |= reg;
1507 				ao->o |= (label / 4) << 8;
1508 				return 2;
1509 			} else if ((label < 0) && (label > -4096)) {
1510 				if (m & DOTN_BIT) {
1511 					// this is explicitly an error
1512 					return -1;
1513 				}
1514 				ao->o = 0xaff20000;
1515 				ao->o |= reg;
1516 				ao->o |= getthzeroimmed12 (-label);
1517 				return 4;
1518 			} else if ((label > 0) && (label < 4096)) {
1519 				if (m & DOTN_BIT) {
1520 					// this is explicitly an error
1521 					return -1;
1522 				}
1523 				ao->o = 0x0ff20000;
1524 				ao->o |= reg;
1525 				ao->o |= getthzeroimmed12 (label);
1526 				return 4;
1527 			}
1528 			return -1;
1529 		        }
1530 			break;
1531 		default:
1532 			return -1;
1533 		}
1534 	} else
1535 	if ((m = opmask (ao->op, "and", S_BIT))) {
1536 		ut64 argt = thumb_selector (ao->a);
1537 		switch (argt) {
1538 		case THUMB_REG_REG: {
1539 			ao->o = 0x0040;
1540 			if (std_16bit_2reg (ao, m)) {
1541 				return 2;
1542 			}
1543 			std_opt_2 (ao);
1544 		        }
1545 			// intentional fallthrough
1546 		case THUMB_REG_REG_REG: {
1547 			ao->o = 0x00ea0000;
1548 			return std_32bit_3reg (ao, m, false);
1549 		        }
1550 			break;
1551 		case THUMB_REG_CONST: {
1552 			std_opt_2 (ao);
1553 		        }
1554 			// intentional fallthrough
1555 		case THUMB_REG_REG_CONST: {
1556 			ut32 imm = getthimmed12 (ao->a[2]);
1557 			ao->o = 0x00f00000;
1558 			ao->o |= imm;
1559 			return std_32bit_2reg (ao, m, false);
1560 		        }
1561 			break;
1562 		case THUMB_REG_REG_SHIFT: {
1563 			std_opt_3 (ao);
1564 		        }
1565 			// intentional fallthrough
1566 		case THUMB_REG_REG_REG_SHIFT: {
1567 			ao->o = 0x00ea0000;
1568 			return std_32bit_3reg (ao, m, true);
1569 		        }
1570 			break;
1571 		default:
1572 			return -1;
1573 		}
1574 	} else
1575 	if ((m = opmask (ao->op, "asr", S_BIT))) {
1576 		ut64 argt = thumb_selector (ao->a);
1577 		switch (argt) {
1578 		case THUMB_REG_REG_CONST: {
1579 			ut8 reg1 = getreg (ao->a[0]);
1580 			ut8 reg2 = getreg (ao->a[1]);
1581 			ut32 imm = getnum (ao->a[2]);
1582 			if (((int)imm < 1) && ((int)imm > 32)) {
1583 				return -1;
1584 			}
1585 			ao->o = 0x0010;
1586 			ao->o |= (imm & 0x3) << 14;
1587 			ao->o |= (imm & 0x1c) >> 2;
1588 			if (std_16bit_2reg (ao, m)) {
1589 				return 2;
1590 			}
1591 			ao->o = 0x4fea2000;
1592 			ao->o |= reg1;
1593 			ao->o |= reg2 << 8;
1594 			ao->o |= (imm & 0x3) << 14;
1595 			ao->o |= (imm & 0x1c) << 2;
1596 			if (m & S_BIT) {
1597 				ao->o |= 1 << 28;
1598 			}
1599 			return 4;
1600 		        }
1601 			break;
1602 		case THUMB_REG_REG: {
1603 			ao->o = 0x0041;
1604 			if (std_16bit_2reg (ao, m)) {
1605 				return 2;
1606 			}
1607 			std_opt_2 (ao);
1608 		        }
1609 			// intentional fallthrough
1610 		case THUMB_REG_REG_REG: {
1611 			ao->o = 0x40fa00f0;
1612 			return std_32bit_3reg (ao, m, false);
1613 		        }
1614 			break;
1615 		default:
1616 			return -1;
1617 		}
1618 	} else
1619 	if (( m = opmask (ao->op, "b", 0) )) {
1620 		ut64 argt = thumb_selector (ao->a);
1621 		switch (argt) {
1622 		case THUMB_CONST: {
1623 			st32 offset = thumb_getoffset (ao->a[0], off);
1624 			if (offset % 2 != 0) {
1625 				return -1;
1626 			}
1627 
1628 			if ((m & C_BITS) == C_BITS) {
1629 				if ((offset >= -2048) && (offset <= 2046) && (!(m & DOTW_BIT))) {
1630 					ao->o = 0x00e0;
1631 					ao->o |= ((offset/2 & 0xff) << 8);
1632 					ao->o |= ((offset/2 & 0x700) >> 8);
1633 					return 2;
1634 				}
1635 				if ((offset < -16777216) || (offset > 16777214) || (offset % 2 != 0)) {
1636 					return -1;
1637 				}
1638 				ao->o = 0x00f00090;
1639 				ao->o |= getthbimmed(offset);
1640 				return 4;
1641 			} else {
1642 				if ((offset >= -256) && (offset <= 254) && (!(m & DOTW_BIT))) {
1643 					ao->o = 0x00d0;
1644 					ao->o |= (ut16) ((offset/2) << 8);
1645 					ao->o |= ((m & C_BITS) >> 2);
1646 					return 2;
1647 				}
1648 				if ((offset < -1048576) || (offset > 1048574) || (offset % 2 != 0)) {
1649 					return -1;
1650 				}
1651 
1652 				ao->o = 0x00f00080;
1653 				ao->o |= (ut32)(offset & 0x80000) >> 16;
1654 				ao->o |= (ut32)(offset & 0x40000) >> 13;
1655 				ao->o |= (ut32)(offset & 0x3f000) << 12;
1656 				ao->o |= (ut32)(offset & 0xe00) >> 9;
1657 				ao->o |= (ut32)(offset & 0x1fe) << 7;
1658 				if (offset < 0) {
1659 					ao->o |= 1 << 18;
1660 				}
1661 				ao->o |= (((m & C_BITS) & 0xc) << 28);
1662 				ao->o |= (((m & C_BITS) & 0x30) << 12);
1663 				return 4;
1664 			}
1665 		        }
1666 			break;
1667 		default:
1668 			return -1;
1669 		}
1670 	} else
1671 	if (( m = opmask (ao->op, "bl", 0) )) {
1672 		ut64 argt = thumb_selector (ao->a);
1673 		switch (argt) {
1674 		case THUMB_CONST: {
1675 			st32 offset = thumb_getoffset (ao->a[0], off);
1676 			ao->o = 0x00f000d0;
1677 			if ((offset > 16777214) || (offset < -16777216) || (offset % 2 != 0)) {
1678 				return -1;
1679 			}
1680 			ao->o |= getthbimmed(offset);
1681 			return 4;
1682 		        }
1683 			break;
1684 		default:
1685 			return -1;
1686 		}
1687 	} else
1688 	if (( m = opmask (ao->op, "bx", 0) )) {
1689 		ut64 argt = thumb_selector (ao->a);
1690 		switch (argt) {
1691 		case THUMB_REG: {
1692 			ut32 reg1 = getreg (ao->a[0]);
1693 			ao->o = 0x0047;
1694 			ao->o |= reg1 << 11;
1695 			return 2;
1696 		        }
1697 			break;
1698 		default:
1699 			return -1;
1700 		}
1701 	} else
1702 	if (( m = opmask (ao->op, "blx", 0) )) {
1703 		ut64 argt = thumb_selector (ao->a);
1704 		switch (argt) {
1705 		case THUMB_REG: {
1706 			ut32 reg1 = getreg (ao->a[0]);
1707 			ao->o = 0x8047;
1708 			ao->o |= reg1 << 11;
1709 			return 2;
1710 		        }
1711 			break;
1712 		case THUMB_CONST: {
1713 			st32 offset = thumb_getoffset (ao->a[0], off);
1714 			ao->o = 0x00f000c0;
1715 			if ((offset > 16777214) || (offset < -16777216) || (offset % 2 != 0)) {
1716 				return -1;
1717 			}
1718 			offset += off & 0x2; // (Align(PC,4)
1719 			ao->o |= getthbimmed (offset);
1720 			return 4;
1721 		        }
1722 			break;
1723 		default:
1724 			return -1;
1725 		}
1726 	} else
1727 	if (( m = opmask (ao->op, "bfc", 0) )) {
1728 		ut64 argt = thumb_selector (ao->a);
1729 		switch (argt) {
1730 		case THUMB_REG_CONST_CONST: {
1731 			if (m & DOTN_BIT) {
1732 				// this is explicitly an error
1733 				return -1;
1734 			}
1735 			ut8 reg1 = getreg (ao->a[0]);
1736 			ut32 lsb = getnum (ao->a[1]);
1737 			ut32 width = getnum (ao->a[2]);
1738 			ut32 msb = lsb + width - 1;
1739 			if ((lsb > 31) || (msb > 31)) {
1740 				return -1;
1741 			}
1742 			ao->o = 0x6ff30000;
1743 			ao->o |= reg1;
1744 			ao->o |= ((lsb & 0x1c) << 2);
1745 			ao->o |= ((lsb & 0x3) << 14);
1746 			ao->o |= (msb << 8);
1747 			return 4;
1748 		        }
1749 			break;
1750 		default:
1751 			return -1;
1752 		}
1753 	} else
1754 	if (( m = opmask (ao->op, "bfi", 0) )) {
1755 		ut64 argt = thumb_selector (ao->a);
1756 		switch (argt) {
1757 		case THUMB_REG_REG_CONST_CONST: {
1758 			ut32 lsb = getnum (ao->a[2]);
1759 			ut32 width = getnum (ao->a[3]);
1760 			ut32 msb = lsb + width - 1;
1761 			if ((lsb > 31) || (msb > 31)) {
1762 				return -1;
1763 			}
1764 			ao->o = 0x60f30000;
1765 			ao->o |= ((lsb & 0x1c) << 2);
1766 			ao->o |= ((lsb & 0x3) << 14);
1767 			ao->o |= (msb << 8);
1768 			return std_32bit_2reg (ao, m, false);
1769 		        }
1770 			break;
1771 		default:
1772 			return -1;
1773 		}
1774 	} else
1775 	if (( m = opmask (ao->op, "bic", S_BIT) )) {
1776 		ut64 argt = thumb_selector (ao->a);
1777 		switch (argt) {
1778 		case THUMB_REG_REG: {
1779 			ao->o = 0x8043;
1780 			if (std_16bit_2reg (ao, m)) {
1781 				return 2;
1782 			}
1783 			std_opt_2 (ao);
1784 		        }
1785 			// intentional fallthrough
1786 		case THUMB_REG_REG_REG: {
1787 			ao->o = 0x20ea0000;
1788 			return std_32bit_3reg (ao, m, false);
1789 		        }
1790 			break;
1791 		case THUMB_REG_CONST: {
1792 			std_opt_2 (ao);
1793 		        }
1794 			// intentional fallthrough
1795 		case THUMB_REG_REG_CONST: {
1796 			ao->o = 0x20f00000;
1797 			ao->o |= getthimmed12 (ao->a[2]);
1798 			return std_32bit_2reg (ao, m, false);
1799 		        }
1800 			break;
1801 		case THUMB_REG_REG_SHIFT: {
1802 			std_opt_3 (ao);
1803 		        }
1804 			// intentional fallthrough
1805 		case THUMB_REG_REG_REG_SHIFT: {
1806 			ao->o = 0x20ea0000;
1807 			return std_32bit_3reg (ao, m, true);
1808 		        }
1809 			break;
1810 		default:
1811 			return -1;
1812 		}
1813 	} else
1814 	if (( m = opmask (ao->op, "bkpt", 0) )) {
1815 		ut64 argt = thumb_selector (ao->a);
1816 		switch (argt) {
1817 		case THUMB_CONST: {
1818 			ut32 num = getnum (ao->a[0]);
1819 			if (num > 255) {
1820 				return -1;
1821 			}
1822 			ao->o = 0x00be;
1823 			ao->o |= num << 8;
1824 			return 2;
1825 		        }
1826 			break;
1827 		default:
1828 			return -1;
1829 		}
1830 	} else
1831 	if (( m = opmask (ao->op, "cbnz", 0) )) {
1832 		ut64 argt = thumb_selector (ao->a);
1833 		switch (argt) {
1834 		case THUMB_REG_CONST: {
1835 			ut8 reg1 = getreg (ao->a[0]);
1836 			st32 offset = thumb_getoffset (ao->a[1], off);
1837 			if ((reg1 > 7) || (offset > 127) || (offset % 2 != 0)) {
1838 				return -1;
1839 			}
1840 			ao->o = 0x00b9;
1841 			ao->o |= reg1 << 8;
1842 			ao->o |= (offset & 0x3e) << 10;
1843 			ao->o |= (offset & 0x40) >> 5;
1844 			return 2;
1845 		        }
1846 			break;
1847 		default:
1848 			return -1;
1849 		}
1850 	} else
1851 	if (( m = opmask (ao->op, "cbz", 0) )) {
1852 		ut64 argt = thumb_selector (ao->a);
1853 		switch (argt) {
1854 		case THUMB_REG_CONST: {
1855 			ut8 reg1 = getreg (ao->a[0]);
1856 			st32 offset = thumb_getoffset (ao->a[1], off);
1857 			if ((reg1 > 7) || (offset > 127) || (offset % 2 != 0)) {
1858 				return -1;
1859 			}
1860 			ao->o = 0x00b1;
1861 			ao->o |= reg1 << 8;
1862 			ao->o |= (offset & 0x3e) << 10;
1863 			ao->o |= (offset & 0x40) >> 5;
1864 			return 2;
1865 		        }
1866 			break;
1867 		default:
1868 			return -1;
1869 		}
1870 	} else
1871 	if (( m = opmask (ao->op, "cdp", TWO_BIT) )) {
1872 		ut64 argt = thumb_selector (ao->a);
1873 		switch (argt) {
1874 		case THUMB_COPROC_CONST_COREG_COREG_COREG: {
1875 			ao->a[5] = "0";
1876 		        }
1877 			//intentional fallthrough
1878 		case THUMB_COPROC_CONST_COREG_COREG_COREG_CONST: {
1879 			ut32 coproc = getcoproc (ao->a[0]);
1880 			ut32 opc1 = getnum (ao->a[1]);
1881 			ut8 reg1 = getcoprocreg (ao->a[2]);
1882 			ut8 reg2 = getcoprocreg (ao->a[3]);
1883 			ut8 reg3 = getcoprocreg (ao->a[4]);
1884 			ut32 opc2 = getnum (ao->a[5]);
1885 		        if ((coproc > 15) || (opc1 > 15) || (opc2 > 7)) {
1886 				return -1;
1887 			}
1888 			ao->o = 0x00ee0000;
1889 			if (m & TWO_BIT) {
1890 				ao->o |= 1 << 20;
1891 			}
1892 			ao->o |= coproc;
1893 			ao->o |= opc1 << 28;
1894 			ao->o |= reg1 << 4;
1895 			ao->o |= reg2 << 24;
1896 			ao->o |= reg3 << 8;
1897 			ao->o |= opc2 << 13;
1898 			return 4;
1899 		        }
1900 			break;
1901 		default:
1902 			return -1;
1903 		}
1904 	} else
1905 	if (( m = opmask (ao->op, "clrex", 0) )) {
1906 		ut64 argt = thumb_selector (ao->a);
1907 		switch (argt) {
1908 		case THUMB_NONE: {
1909 			ao->o = 0xbff32f8f;
1910 			return 4;
1911 		        }
1912 			break;
1913 		default:
1914 			return -1;
1915 		}
1916 	} else
1917 	if (( m = opmask (ao->op, "clz", 0) )) {
1918 		ut64 argt = thumb_selector (ao->a);
1919 		switch (argt) {
1920 		case THUMB_REG_REG: {
1921 			ao->o = 0xb0fa80f0;
1922 			ao->a[2] = ao->a[1];
1923 			return std_32bit_3reg (ao, m, false);
1924 		        }
1925 			break;
1926 		default:
1927 			return -1;
1928 		}
1929 	} else
1930 	if (( m = opmask (ao->op, "cmn", 0) )) {
1931 		ut64 argt = thumb_selector (ao->a);
1932 		switch (argt) {
1933 		case THUMB_REG_CONST: {
1934 			ut8 reg1 = getreg (ao->a[0]);
1935 			ut32 num = getthimmed12 (ao->a[1]);
1936 			ao->o = 0x10f1000f;
1937 			ao->o |= reg1 << 24;
1938 			ao->o |= num;
1939 			return 4;
1940 		        }
1941 			break;
1942 		case THUMB_REG_REG: {
1943 			ao->o = 0xc042;
1944 			if (std_16bit_2reg (ao, m)) {
1945 				return 2;
1946 			}
1947 			ao->a[2] = "lsl 0";
1948 		        }
1949 			// intentional fallthrough
1950 		case THUMB_REG_REG_SHIFT: {
1951 			ao->o = 0x10eb000f;
1952 			return std_32bit_2reg (ao, m, true);
1953 		        }
1954 			break;
1955 		default:
1956 			return -1;
1957 		}
1958 	} else
1959 	if (( m = opmask (ao->op, "cmp", 0) )) {
1960 		ut64 argt = thumb_selector (ao->a);
1961 		switch (argt) {
1962 		case THUMB_REG_CONST: {
1963 			ut8 reg1 = getreg (ao->a[0]);
1964 			ut32 num = getnum (ao->a[1]);
1965 			if ((num < 256) && (!(m & DOTW_BIT))) {
1966 				ao->o = 0x0028;
1967 				ao->o |= reg1;
1968 				ao->o |= num << 8;
1969 				return 2;
1970 			}
1971 			num = getthimmed12 (ao->a[1]);
1972 			ao->o = 0xb0f1000f;
1973 			ao->o |= reg1 << 24;
1974 			ao->o |= num;
1975 			return 4;
1976 		        }
1977 			break;
1978 		case THUMB_REG_REG: {
1979 			ut8 reg1 = getreg (ao->a[0]);
1980 			ut8 reg2 = getreg (ao->a[1]);
1981 			ao->o = 0x8042;
1982 			if (std_16bit_2reg (ao, m)) {
1983 				return 2;
1984 			}
1985 			if (!(m & DOTW_BIT)) {
1986 				ao->o = 0x0045;
1987 				ao->o |= ((reg1 & 0x7) << 8);
1988 				ao->o |= ((reg1 & 0x8) << 12);
1989 				ao->o |= reg2 << 11;
1990 				return 2;
1991 			}
1992 			ao->a[2] = "lsl 0";
1993 		        }
1994 			// intentional fallthrough
1995 		case THUMB_REG_REG_SHIFT: {
1996 			ut8 reg1 = getreg (ao->a[0]);
1997 			ut8 reg2 = getreg (ao->a[1]);
1998 			ut32 shift = thumb_getshift (ao->a[2]);
1999 			ao->o = 0xb0eb000f;
2000 			ao->o |= reg1 << 24;
2001 			ao->o |= reg2 << 8;
2002 			ao->o |= shift;
2003 			return 4;
2004 		        }
2005 			break;
2006 		default:
2007 			return -1;
2008 		}
2009 	} else
2010 	if (( m = opmask (ao->op, "cps", ID_BIT | IE_BIT) )) {
2011 		ut64 argt = thumb_selector (ao->a);
2012 		switch (argt) {
2013 		case THUMB_OTHER: {
2014 			st8 aif = iflag(ao->a[0]);
2015 			if (aif == -1) {
2016 				return -1;
2017 			}
2018 			if (!(m & DOTW_BIT)) {
2019 				ao->o = 0x60b6;
2020 				ao->o |= aif << 8;
2021 				if (m & ID_BIT) {
2022 					ao->o |= 1 << 12;
2023 				}
2024 				return 2;
2025 			}
2026 			ao->a[1] = "0";
2027 		        }
2028 			// intentional fallthrough
2029 		case THUMB_OTHER_CONST: {
2030 			st8 aif = iflag(ao->a[0]);
2031 			ut8 mode = getnum (ao->a[1]);
2032 			if ((mode > 31) || (aif == -1)) {
2033 				return -1;
2034 			}
2035 			ao->o = 0xaff30085;
2036 			ao->o |= mode << 8;
2037 			ao->o |= aif << 13;
2038 			if (m & ID_BIT) {
2039 				ao->o |= 1 << 1;
2040 			}
2041 			return 4;
2042 		        }
2043 			break;
2044 		case THUMB_CONST: {
2045 			ut8 mode = getnum (ao->a[0]);
2046 			if ((m & ID_BIT) || (m & IE_BIT) || (mode > 31)) {
2047 				return -1;
2048 			}
2049 			ao->o = 0xaff30081;
2050 			ao->o |= mode << 8;
2051 			return 4;
2052 		        }
2053 			break;
2054 		default:
2055 			return -1;
2056 		}
2057 	} else
2058 	if ((m = opmask (ao->op, "dbg", 0))) {
2059 		ut64 argt = thumb_selector (ao->a);
2060 		switch (argt) {
2061 		case THUMB_CONST: {
2062 			ut32 option = getnum (ao->a[0]);
2063 			if (option > 15) {
2064 				return -1;
2065 			}
2066 			ao->o = 0xaff3f080;
2067 			ao->o |= option << 8;
2068 			return 4;
2069 		        }
2070 		default:
2071 			return -1;
2072 		}
2073 	} else
2074 	if ((m = opmask (ao->op, "dmb", 0))) {
2075 		ut64 argt = thumb_selector (ao->a);
2076 		switch (argt) {
2077 		case THUMB_NONE: {
2078 			ao->o = 0xbff35f8f;
2079 			return 4;
2080 		        }
2081 			break;
2082 		case THUMB_OTHER: {
2083 			r_str_case (ao->a[0], false);
2084 			if (strcmpnull (ao->a[0], "sy")) {
2085 				return -1;
2086 			}
2087 			ao->a[0] = "15";
2088 		        }
2089 			// intentional fallthrough
2090 		case THUMB_CONST: {
2091 			ut32 option = getnum (ao->a[0]);
2092 			if (option != 15) {
2093 				return -1;
2094 			}
2095 			ao->o = 0xbff3508f;
2096 			ao->o |= option << 8;
2097 			return 4;
2098 		        }
2099 			break;
2100 		default:
2101 			return -1;
2102 		}
2103 	} else
2104 	if ((m = opmask (ao->op, "dsb", 0))) {
2105 		ut64 argt = thumb_selector (ao->a);
2106 		switch (argt) {
2107 		case THUMB_NONE: {
2108 			ao->o = 0xbff34f8f;
2109 			return 4;
2110 		        }
2111 			// intentional fallthrough
2112 		case THUMB_OTHER: {
2113 			r_str_case (ao->a[0], false);
2114 			if (!strcmpnull ((ao->a[0] = parse_hints(ao->a[0])), "-1")) {
2115 				return -1;
2116 			}
2117 		        }
2118 			// intentional fallthrough
2119 		case THUMB_CONST: {
2120 			ut32 option = getnum (ao->a[0]);
2121 			if ((option != 6) && (option != 7) && (option != 14) && (option != 15)) {
2122 				return -1;
2123 			}
2124 			ao->o = 0xbff3408f;
2125 			ao->o |= option << 8;
2126 			return 4;
2127 		        }
2128 			break;
2129 		default:
2130 			return -1;
2131 		}
2132 	} else
2133 	if ((m = opmask (ao->op, "eor", S_BIT))) {
2134 		ut64 argt = thumb_selector (ao->a);
2135 		switch (argt) {
2136 		case THUMB_REG_CONST:
2137 			std_opt_2 (ao);
2138 			// intentional fallthrough
2139 		case THUMB_REG_REG_CONST: {
2140 			err = false;
2141 			ut32 imm = getthimmed12 (ao->a[2]);
2142 			if (err) {
2143 				return -1;
2144 			}
2145 			ao->o = 0x80f00000;
2146 			ao->o |= imm;
2147 			return std_32bit_2reg (ao, m, false);
2148 		        }
2149 			break;
2150 		case THUMB_REG_REG: {
2151 			ao->o = 0x4040;
2152 			if (std_16bit_2reg (ao, m)) {
2153 				return 2;
2154 			}
2155 			std_opt_2 (ao);
2156 		        }
2157 			// intentional fallthrough
2158 		case THUMB_REG_REG_REG:
2159 			ao->a[3] = "lsl 0";
2160 			// intentional fallthrough
2161 		case THUMB_REG_REG_REG_SHIFT: {
2162 			ao->o = 0x80ea0000;
2163 			return std_32bit_3reg (ao, m, true);
2164 		        }
2165 			break;
2166 		default:
2167 			return -1;
2168 		}
2169 	} else
2170 	if ((m = opmask (ao->op, "isb", 0))) {
2171 		ut64 argt = thumb_selector (ao->a);
2172 		switch (argt) {
2173 		case THUMB_NONE: {
2174 			ao->o = 0xbff36f8f;
2175 			return 4;
2176 		        }
2177 			// intentional fallthrough
2178 		case THUMB_OTHER: {
2179 			r_str_case (ao->a[0], false);
2180 			if (strcmpnull (ao->a[0], "sy")) {
2181 				return -1;
2182 			}
2183 			ao->a[0] = "15";
2184 		        }
2185 			// intentional fallthrough
2186 		case THUMB_CONST: {
2187 			ut32 option = getnum (ao->a[0]);
2188 			if (option != 15) {
2189 				return -1;
2190 			}
2191 			ao->o = 0xbff3608f;
2192 			ao->o |= option << 8;
2193 			return 4;
2194 		        }
2195 			break;
2196 		default:
2197 			return -1;
2198 		}
2199 	} else
2200 	if ((m = itmask (ao->op))) {
2201 		ut64 argt = thumb_selector (ao->a);
2202 		switch (argt) {
2203 		case THUMB_OTHER: {
2204 			ut16 cond = 0;
2205 			ut16 i;
2206 
2207 			const char *conds[] = {
2208 				"eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc",
2209 				"hi", "ls", "ge", "lt", "gt", "le", "al", "nv", 0
2210 			};
2211 			r_str_case (ao->a[0], false);
2212 			for (i = 0; conds[i]; i++) {
2213 				if (!(strcmpnull(ao->a[0], conds[i]))) {
2214 					cond = i;
2215 					break;
2216 				}
2217 			}
2218 
2219 			if (i == 16) {
2220 				return -1;
2221 			}
2222 			ao->o = 0x00bf;
2223 			ao->o |= cond << 12;
2224 
2225 			ut8 nrcs = (m & 0x30) >> 4;
2226 			ut8 thiset = 0;
2227 
2228 			for (i = 0; i < nrcs; i++) {
2229 				thiset = ((m & (1 << (3 - i))) >> (3 - i));
2230 				ao->o |= ((cond & 0x1) ^ thiset) << (11 - i);
2231 			}
2232 			ao->o |= 1 << (11 - i);
2233 			return 2;
2234 		        }
2235 			break;
2236 		default:
2237 			return -1;
2238 		}
2239 	} else
2240 	if ((m = opmask (ao->op, "ldc", TWO_BIT | L_BIT))) {
2241 		ut64 argt = thumb_selector (ao->a);
2242 		switch (argt) {
2243 		case THUMB_COPROC_COREG_BRACKREG_CONSTBRACK: {
2244 			ut8 proc = getcoproc (ao->a[0]);
2245 			ut8 reg1 = getcoprocreg (ao->a[1]);
2246 			ut8 reg2 = getregmemstart (ao->a[2]);
2247 			st32 imm = getnummemend (ao->a[3]);
2248 			ao->o = 0x10ed0000;
2249 			if (m & L_BIT) {
2250 				ao->o |= 1 << 30;
2251 			}
2252 			if (m & TWO_BIT) {
2253 				ao->o |= 1 << 20;
2254 			}
2255 			if (imm < 0) {
2256 				imm = -imm;
2257 			} else {
2258 				ao->o |= 1 << 31;
2259 			}
2260 			if ((proc > 15) || (reg1 > 15) || (reg2 > 15) || (imm > 1024) || (imm % 4 != 0)) {
2261 				return -1;
2262 			}
2263 			ao->o |= proc;
2264 			ao->o |= reg1 << 4;
2265 			ao->o |= (imm >> 2) << 8;
2266 			ao->o |= reg2 << 24;
2267 			return 4;
2268 		        }
2269 			break;
2270 		case THUMB_COPROC_COREG_BRACKREGBRACK:
2271 			ao->a[3] = "0";
2272 			// intentional fallthrough
2273 		case THUMB_COPROC_COREG_BRACKREGBRACK_CONST: {
2274 			ut8 proc = getcoproc (ao->a[0]);
2275 			ut8 reg1 = getcoprocreg (ao->a[1]);
2276 			ut8 reg2 = getregmemstartend (ao->a[2]);
2277 			st32 imm = getnum (ao->a[3]);
2278 			ao->o = 0x30ec0000;
2279 			if (m & L_BIT) {
2280 				ao->o |= 1 << 30;
2281 			}
2282 			if (m & TWO_BIT) {
2283 				ao->o |= 1 << 20;
2284 			}
2285 			if (imm < 0) {
2286 				imm = -imm;
2287 			} else {
2288 				ao->o |= 1 << 31;
2289 			}
2290 			if ((proc > 15) || (reg1 > 15) || (reg2 > 15) || (imm > 1024) || (imm % 4 != 0)) {
2291 				return -1;
2292 			}
2293 			ao->o |= proc;
2294 			ao->o |= reg1 << 4;
2295 			ao->o |= (imm >> 2) << 8;
2296 			ao->o |= reg2 << 24;
2297 			return 4;
2298 		        }
2299 			break;
2300 		case THUMB_COPROC_COREG_BRACKREG_CONSTBRACKBANG: {
2301 			ut8 proc = getcoproc (ao->a[0]);
2302 			ut8 reg1 = getcoprocreg (ao->a[1]);
2303 			ut8 reg2 = getregmemstart (ao->a[2]);
2304 			st32 imm = getnummemendbang (ao->a[3]);
2305 			ao->o = 0x30ed0000;
2306 			if (m & L_BIT) {
2307 				ao->o |= 1 << 30;
2308 			}
2309 			if (m & TWO_BIT) {
2310 				ao->o |= 1 << 20;
2311 			}
2312 			if (imm < 0) {
2313 				imm = -imm;
2314 			} else {
2315 				ao->o |= 1 << 31;
2316 			}
2317 			if ((proc > 15) || (reg1 > 15) || (reg2 > 15) || (imm > 1024) || (imm % 4 != 0)) {
2318 				return -1;
2319 			}
2320 			ao->o |= proc;
2321 			ao->o |= reg1 << 4;
2322 			ao->o |= (imm >> 2) << 8;
2323 			ao->o |= reg2 << 24;
2324 			return 4;
2325 		        }
2326 			break;
2327 		default:
2328 			return -1;
2329 		}
2330 	} else
2331 	if ((m = opmask (ao->op, "ldm", DB_BIT | EA_BIT | IA_BIT | FD_BIT))) {
2332 		ut64 argt = thumb_selector (ao->a);
2333 		switch (argt) {
2334 		case THUMB_REGBANG_LIST: {
2335 			ut8 reg1 = getregmembang (ao->a[0]);
2336 			ut32 list = getreglist (ao->a[1]);
2337 			if (!((m & DB_BIT) || (m & EA_BIT)) && !(list & 0xff00) && (reg1 < 8) && !(m & DOTW_BIT)) {
2338 				ao->o = 0x00c8;
2339 				ao->o |= reg1;
2340 				if (list & (1 << reg1)) {
2341 					list ^= 1 << (reg1);
2342 				}
2343 				ao->o |= (list & 0xff) << 8;
2344 
2345 				return 2;
2346 			}
2347 			if (list & 0x2000) {
2348 				return -1;
2349 			}
2350 			if ((m & DB_BIT) || (m & EA_BIT)) {
2351 				ao->o = 0x30e90000;
2352 			} else {
2353 				// ldmia is the default!
2354 				ao->o = 0xb0e80000;
2355 			}
2356 
2357 			ao->o |= reg1 << 24;
2358 			ao->o |= (list & 0xff) << 8;
2359 			ao->o |= (list & 0xff00) >> 8;
2360 			return 4;
2361 		        }
2362 			break;
2363 		case THUMB_REG_LIST: {
2364 			ut8 reg1 = getreg (ao->a[0]);
2365 			ut32 list = getreglist (ao->a[1]);
2366 			if (!((m & DB_BIT) || (m & EA_BIT)) && !(list & 0xff00) && (reg1 < 8) && !(m & DOTW_BIT)) {
2367 				ao->o = 0x00c8;
2368 				ao->o |= reg1;
2369 				ao->o |= 1 << (reg1 + 8);
2370 				ao->o |= (list & 0xff) << 8;
2371 				return 2;
2372 			}
2373 			if (list & 0x2000) {
2374 				return -1;
2375 			}
2376 
2377 			if ((m & DB_BIT) || (m & EA_BIT)) {
2378 				ao->o = 0x10e90000;
2379 			} else {
2380 				ao->o = 0x90e80000;
2381 			}
2382 
2383 			ao->o |= reg1 << 24;
2384 			ao->o |= (list & 0xff) << 8;
2385 			ao->o |= (list & 0xff00) >> 8;
2386 			return 4;
2387 		        }
2388 			break;
2389 		default:
2390 			return -1;
2391 		}
2392 	} else
2393 	if ((m = opmask (ao->op, "ldr", B_BIT | H_BIT | D_BIT | T_BIT | S_BIT))) {
2394 		ut64 argt = thumb_selector (ao->a);
2395 		ut32 ldrsel = m & (B_BIT | H_BIT | D_BIT);
2396 		if ((m & S_BIT) && !(m & (B_BIT | H_BIT))) {
2397 			return -1;
2398 		}
2399 		switch (argt) {
2400 		case THUMB_REG_CONST:
2401 			ao->a[2] = ao->a[1];
2402 			strcat (ao->a[2],"]");
2403 			ao->a[1] = "[r15";
2404 			// intentional fallthrough
2405 		case THUMB_REG_BRACKREGBRACK:
2406 			if (ao->a[2] == NULL) { // double fallthrough
2407 				ao->a[1][strlen (ao->a[1]) -1] = '\0';
2408 				ao->a[2] = "0]";
2409 			}
2410 			// intentional fallthrough
2411 		case THUMB_REG_BRACKREG_CONSTBRACK: {
2412 			ut8 reg1 = getreg (ao->a[0]);
2413 			ut8 reg2 = getregmemstart (ao->a[1]);
2414 			st32 num = getnummemend (ao->a[2]);
2415 			if (ldrsel == 0) {
2416 				if (m & T_BIT) {
2417 					if ((num < 0) || (num > 255)) {
2418 						return -1;
2419 					}
2420 					ao->o = 0x50f8000e;
2421 					ao->o |= num << 8;
2422 					return mem_32bit_2reg (ao, m);
2423 				}
2424 				if (reg2 == 15) {
2425 					if ((num > 4095) || (num < -4095)) {
2426 						return -1;
2427 					}
2428 					if ((reg1 < 8) && (num < 1024) && (num % 4 == 0)) {
2429 						ao->o = 0x0048;
2430 						ao->o |= reg1;
2431 						ao->o |= (num >> 2) << 8;
2432 						return 2;
2433 					}
2434 					ao->o = 0x5ff80000;
2435 					if (num < 0) {
2436 						num = -num;
2437 					} else {
2438 						ao->o |= 1 << 31;
2439 					}
2440 					ao->o |= reg1 << 4;
2441 					ao->o |= (num & 0xff) << 8;
2442 					ao->o |= (num & 0x0f00) >> 8;
2443 					return 4;
2444 				}
2445 				if ((reg2 == 13) && (reg1 < 8) && (num >= 0) && (num < 1024) && (num % 4 == 0) && (!(m & DOTW_BIT))) {
2446 					ao->o = 0x0098;
2447 					ao->o |= reg1;
2448 					ao->o |= (num >> 2) << 8;
2449 					return 2;
2450 				}
2451 				if ((num >= 0) && (num < 128) && (num % 4 == 0)) {
2452 					ao->o = 0x0068;
2453 					ao->o |= (num >> 4);
2454 					ao->o |= ((num >> 2) & 0x3) << 14;
2455 					if (mem_16bit_2reg (ao, m)) {
2456 						return 2;
2457 					}
2458 				}
2459 				if ((num > 4095) || (num < -1023)) {
2460 					return -1;
2461 				}
2462 				if (num >= 0) {
2463 					ao->o = 0xd0f80000;
2464 					ao->o |= (num & 0xff) << 8;
2465 					ao->o |= (num & 0xf00) >> 8;
2466 					return mem_32bit_2reg (ao, m);
2467 				}
2468 				ao->o = 0x50f8000c;
2469 				ao->o |= (-num & 0xff) << 8;
2470 				return mem_32bit_2reg (ao, m);
2471 			} else
2472 			if (ldrsel == B_BIT) {
2473 				if (m & T_BIT) {
2474 					if ((num < 0) || (num > 255)) {
2475 						return -1;
2476 					}
2477 					ao->o = 0x10f8000e;
2478 					if (m & S_BIT) {
2479 						ao->o |= 1 << 16;
2480 					}
2481 					ao->o |= num << 8;
2482 					return mem_32bit_2reg (ao, m);
2483 				}
2484 				if (reg2 == 15) {
2485 					if ((num > 4095) || (num < -4095)) {
2486 						return -1;
2487 					}
2488 					ao->o = 0x1ff80000;
2489 					if (m & S_BIT) {
2490 						ao->o |= 1 << 16;
2491 					}
2492 					if (num < 0) {
2493 						num = -num;
2494 					} else {
2495 						ao->o |= 1 << 31;
2496 					}
2497 					ao->o |= reg1 << 4;
2498 					ao->o |= (num & 0xff) << 8;
2499 					ao->o |= (num & 0x0f00) >> 8;
2500 					return 4;
2501 				}
2502 				if ((num >= 0) && (num < 32) && (!(m & S_BIT))) {
2503 					ao->o = 0x0078;
2504 					ao->o |= (num >> 2);
2505 					ao->o |= (num & 0x3) << 14;
2506 					if (mem_16bit_2reg (ao, m)) {
2507 						return 2;
2508 					}
2509 				}
2510 				if ((num > 4095) || (num < -255)) {
2511 					return -1;
2512 				}
2513 				if (num >= 0) {
2514 					ao->o = 0x90f80000;
2515 					if (m & S_BIT) {
2516 						ao->o |= 1 << 16;
2517 					}
2518 					ao->o |= (num & 0xff) << 8;
2519 					ao->o |= (num & 0xf00) >> 8;
2520 					return mem_32bit_2reg (ao, m);
2521 				}
2522 				ao->o = 0x10f8000c;
2523 				if (m & S_BIT) {
2524 					ao->o |= 1 << 16;
2525 				}
2526 				ao->o |= -num << 8;
2527 				return mem_32bit_2reg (ao, m);
2528 			} else
2529 			if (ldrsel == H_BIT) {
2530 				if (m & T_BIT) {
2531 					if ((num < 0) || (num > 255)) {
2532 						return -1;
2533 					}
2534 					ao->o = 0x30f8000e;
2535 					if (m & S_BIT) {
2536 						ao->o |= 1 << 16;
2537 					}
2538 					ao->o |= num << 8;
2539 					return mem_32bit_2reg (ao, m);
2540 				}
2541 				if (reg2 == 15) {
2542 					if ((num > 4095) || (num < -4095)) {
2543 						return -1;
2544 					}
2545 					ao->o = 0x3ff80000;
2546 					if (m & S_BIT) {
2547 						ao->o |= 1 << 16;
2548 					}
2549 					if (num < 0) {
2550 						num = -num;
2551 					} else {
2552 						ao->o |= 1 << 31;
2553 					}
2554 					ao->o |= reg1 << 4;
2555 					ao->o |= (num & 0xff) << 8;
2556 					ao->o |= (num & 0x0f00) >> 8;
2557 					return 4;
2558 				}
2559 				if ((num >= 0) && (num < 64) && (num % 2 == 0) && (!(m & S_BIT))) {
2560 					ao->o = 0x0088;
2561 					ao->o |= (num >> 3);
2562 					ao->o |= ((num >> 1) & 0x3) << 14;
2563 					if (mem_16bit_2reg (ao, m)) {
2564 						return 2;
2565 					}
2566 				}
2567 				if ((num > 4095) || (num < -255)) {
2568 					return -1;
2569 				}
2570 				if (num >= 0) {
2571 					ao->o = 0xb0f80000;
2572 					if (m & S_BIT) {
2573 						ao->o |= 1 << 16;
2574 					}
2575 					ao->o |= (num & 0xff) << 8;
2576 					ao->o |= (num & 0xf00) >> 8;
2577 					return mem_32bit_2reg (ao, m);
2578 				}
2579 				ao->o = 0x30f8000c;
2580 				if (m & S_BIT) {
2581 					ao->o |= 1 << 16;
2582 				}
2583 				ao->o |= -num << 8;
2584 				return mem_32bit_2reg (ao, m);
2585 			} else {
2586 				return -1;
2587 			}
2588 		        }
2589 			break;
2590 		case THUMB_REG_BRACKREGBRACK_CONST: {
2591 			ut8 reg1 = getreg (ao->a[0]);
2592 			ut8 reg2 = getregmemstartend (ao->a[1]);
2593 			st32 num = getnum (ao->a[2]);
2594 			if ((num < -255) || (num > 255)) {
2595 				return -1;
2596 			}
2597 			if (ldrsel == 0) {
2598 				ao->o = 0x50f80009;
2599 			} else
2600 			if (ldrsel == B_BIT) {
2601 				ao->o = 0x10f80009;
2602 			} else
2603 			if (ldrsel == H_BIT) {
2604 				ao->o = 0x30f80009;
2605 			} else {
2606 				return -1;
2607 			}
2608 			if (m & S_BIT) {
2609 				ao->o |= 1 << 16;
2610 			}
2611 			if (num < 0) {
2612 				num = -num;
2613 			} else {
2614 				ao->o |= 1 << 1;
2615 			}
2616 			ao->o |= num << 8;
2617 			ao->o |= reg1 << 4;
2618 			ao->o |= reg2 << 24;
2619 			return 4;
2620 		        }
2621 			break;
2622 		case THUMB_REG_BRACKREG_CONSTBRACKBANG: {
2623 			st32 num = getnummemendbang (ao->a[2]);
2624 			if ((num < -255) || (num > 255)) {
2625 				return -1;
2626 			}
2627 			if (ldrsel == 0) {
2628 				ao->o = 0x50f8000d;
2629 			} else
2630 			if (ldrsel == B_BIT) {
2631 				ao->o = 0x10f8000d;
2632 			} else
2633 			if (ldrsel == H_BIT) {
2634 				ao->o = 0x30f8000d;
2635 			} else {
2636 				return -1;
2637 			}
2638 			if (m & S_BIT) {
2639 				ao->o |= 1 << 16;
2640 			}
2641 			if (num < 0) {
2642 				num = -num;
2643 			} else {
2644 				ao->o |= 1 << 1;
2645 			}
2646 			ao->o |= num << 8;
2647 			return mem_32bit_2reg (ao, m);
2648 		        }
2649 			break;
2650 		case THUMB_REG_BRACKREG_REGBRACK: {
2651 			ut8 reg3 = getregmemend (ao->a[2]);
2652 			if (reg3 < 8) {
2653 				if (ldrsel == 0) {
2654 					ao->o = 0x0058;
2655 				} else
2656 				if (ldrsel == B_BIT) {
2657 					if (m & S_BIT) {
2658 						ao->o = 0x0056;
2659 					} else {
2660 						ao->o = 0x005c;
2661 					}
2662 				} else
2663 				if (ldrsel == H_BIT) {
2664 					if (m & S_BIT) {
2665 						ao->o = 0x005e;
2666 					} else {
2667 						ao->o = 0x005a;
2668 					}
2669 				} else
2670 				{
2671 					return -1;
2672 				}
2673 				ao->o |= (reg3 & 0x3) << 14;
2674 				ao->o |= (reg3 & 0x4) >> 2;
2675 				if (mem_16bit_2reg (ao, m)) {
2676 					return 2;
2677 				}
2678 			}
2679 			ao->a[2][strlen (ao->a[2]) -1] = '\0';
2680 			ao->a[3] = "lsl 0]";
2681 		        }
2682 			// intentional fallthrough
2683 		case THUMB_REG_BRACKREG_REG_SHIFTBRACK: {
2684 			ut8 reg3 = getreg (ao->a[2]);
2685 			ut32 shift = getshiftmemend (ao->a[3]);
2686 
2687 			shift >>= 2;
2688 			if (shift & 0xffffcfff) {
2689 				return -1;
2690 			}
2691 
2692 			if (ldrsel == 0) {
2693 				ao->o = 0x50f80000;
2694 			} else
2695 			if (ldrsel == B_BIT) {
2696 				ao->o = 0x10f80000;
2697 			} else
2698 			if (ldrsel == H_BIT) {
2699 				ao->o = 0x30f80000;
2700 			} else
2701 			{
2702 				return -1;
2703 			}
2704 			if (m & S_BIT) {
2705 				ao->o |= 1 << 16;
2706 			}
2707 			ao->o |= reg3 << 8;
2708 			ao->o |= shift;
2709 			return mem_32bit_2reg (ao, m);
2710 		        }
2711 			break;
2712 		case THUMB_REG_REG_BRACKREGBRACK: {
2713 			ao->a[2][strlen (ao->a[2]) -1] = '\0';
2714 			ao->a[3] = "0]";
2715 		        }
2716 			// intentional fallthrough
2717 		case THUMB_REG_REG_BRACKREG_CONSTBRACK: {
2718 			ut8 reg1 = getreg (ao->a[0]);
2719 			ut8 reg2 = getreg (ao->a[1]);
2720 			ut8 reg3 = getregmemstart (ao->a[2]);
2721 			st32 num = getnummemend (ao->a[3]);
2722 
2723 			if ((num > 1020) || (num < -1020) || (num % 4 != 0) || (ldrsel != D_BIT)) {
2724 				return -1;
2725 			}
2726 			ao->o = 0x50e90000;
2727 			if (num < 0) {
2728 				num = -num;
2729 			} else {
2730 				ao->o |= 1 << 31;
2731 			}
2732 			ao->o |= reg1 << 4;
2733 			ao->o |= reg2;
2734 			ao->o |= reg3 << 24;
2735 			ao->o |= (num >> 2) << 8;
2736 			return 4;
2737 		        }
2738 			break;
2739 		case THUMB_REG_REG_BRACKREGBRACK_CONST: {
2740 			ut8 reg1 = getreg (ao->a[0]);
2741 			ut8 reg2 = getreg (ao->a[1]);
2742 			ut8 reg3 = getregmemstartend (ao->a[2]);
2743 			st32 num = getnum (ao->a[3]);
2744 			if ((num > 1020) || (num < -1020) || (num % 4 != 0) || (ldrsel != D_BIT)) {
2745 				return -1;
2746 			}
2747 			ao->o = 0x70e80000;
2748 			if (num < 0) {
2749 				num = -num;
2750 			} else {
2751 				ao->o |= 1 << 31;
2752 			}
2753 			ao->o |= reg1 << 4;
2754 			ao->o |= reg2;
2755 			ao->o |= reg3 << 24;
2756 			ao->o |= (num >> 2) << 8;
2757 			return 4;
2758 		        }
2759 			break;
2760 		case THUMB_REG_REG_BRACKREG_CONSTBRACKBANG: {
2761 			ut8 reg1 = getreg (ao->a[0]);
2762 			ut8 reg2 = getreg (ao->a[1]);
2763 			ut8 reg3 = getregmemstart (ao->a[2]);
2764 			st32 num = getnummemendbang (ao->a[3]);
2765 			if ((num > 1020) || (num < -1020) || (num % 4 != 0) || (ldrsel != D_BIT)) {
2766 				return -1;
2767 			}
2768 			ao->o = 0x70e90000;
2769 			if (num < 0) {
2770 				num = -num;
2771 			} else {
2772 				ao->o |= 1 << 31;
2773 			}
2774 			ao->o |= reg1 << 4;
2775 			ao->o |= reg2;
2776 			ao->o |= reg3 << 24;
2777 			ao->o |= (num >> 2) << 8;
2778 			return 4;
2779 		        }
2780 			break;
2781 		default:
2782 			return -1;
2783 		}
2784 	} else
2785 	if ((m = opmask (ao->op, "ldrex", B_BIT | H_BIT | D_BIT))) {
2786 		ut64 argt = thumb_selector (ao->a);
2787 		ut32 ldrsel = m & (B_BIT | H_BIT | D_BIT);
2788 		switch (argt) {
2789 		case THUMB_REG_BRACKREGBRACK: {
2790 			ut8 reg1 = getreg (ao->a[0]);
2791 			ut8 reg2 = getregmemstartend (ao->a[1]);
2792 
2793 			if (ldrsel == B_BIT) {
2794 				ao->o = 0xd0e84f0f;
2795 				ao->o |= reg1 << 4;
2796 				ao->o |= reg2 << 24;
2797 				return 4;
2798 			} else
2799 			if (ldrsel == H_BIT) {
2800 				ao->o = 0xd0e85f0f;
2801 				ao->o |= reg1 << 4;
2802 				ao->o |= reg2 << 24;
2803 				return 4;
2804 			} else
2805 			if (ldrsel == 0) {
2806 				ao->a[1][strlen (ao->a[1]) - 1] = '\0';
2807 				ao->a[2] = "0]";
2808 			} else {
2809 				return -1;
2810 			}
2811 			}
2812 			// intentional fallthrough
2813 		case THUMB_REG_BRACKREG_CONSTBRACK: {
2814 			st32 num = getnummemend (ao->a[2]);
2815 			if ((ldrsel != 0) || (num < 0) || (num > 1020) || (num % 4 != 0)) {
2816 				return -1;
2817 			}
2818 			ao->o = 0x50e8000f;
2819 			ao->o |= (num >> 2) << 8;
2820 			return mem_32bit_2reg (ao, m);
2821 		        }
2822 			break;
2823 		case THUMB_REG_REG_BRACKREGBRACK: {
2824 			ut8 reg1 = getreg (ao->a[0]);
2825 			ut8 reg2 = getreg (ao->a[1]);
2826 			ut8 reg3 = getregmemstartend (ao->a[2]);
2827 			if (!(ldrsel & D_BIT)) {
2828 				return -1;
2829 			}
2830 			ao->o = 0xd0e87f00;
2831 			ao->o |= reg1 << 4;
2832 			ao->o |= reg2;
2833 			ao->o |= reg3 << 24;
2834 			return 4;
2835 		}
2836 			break;
2837 		default:
2838 			return -1;
2839 		}
2840 	} else
2841 	if ((m = opmask (ao->op, "lsl", S_BIT))) {
2842 		ut64 argt = thumb_selector (ao->a);
2843 		switch (argt) {
2844 		case THUMB_REG_REG_CONST: {
2845 			ut8 reg1 = getreg (ao->a[0]);
2846 			ut8 reg2 = getreg (ao->a[1]);
2847 			ut32 num = getnum (ao->a[2]);
2848 			if (num > 32) {
2849 				return -1;
2850 			}
2851 			ao->o = 0x0000;
2852 			if (std_16bit_2reg (ao, m)) {
2853 				ao->o |= (num & 0x03) << 14;
2854 				ao->o |= num >> 2;
2855 				return 2;
2856 			}
2857 			ao->o = 0x4fea0000;
2858 			ao->o |= reg1;
2859 			ao->o |= reg2 << 8;
2860 			ao->o |= (num >> 2) << 4;
2861 			ao->o |= (num & 0x3) << 14;
2862 			if (m & S_BIT) {
2863 				ao->o |= 1 << 28;
2864 			}
2865 			return 4;
2866 		        }
2867 			break;
2868 		case THUMB_REG_REG: {
2869 			ao->o = 0x8040;
2870 			if (std_16bit_2reg (ao, m)) {
2871 				return 2;
2872 			}
2873 			std_opt_2 (ao);
2874 		        }
2875 			// intentional fallthrough
2876 		case THUMB_REG_REG_REG: {
2877 			ao->o = 0x00fa00f0;
2878 			return std_32bit_3reg (ao, m, false);
2879 		        }
2880 			break;
2881 		default:
2882 			return -1;
2883 		}
2884 	} else
2885 	if ((m = opmask (ao->op, "lsr", S_BIT))) {
2886 		ut64 argt = thumb_selector (ao->a);
2887 		switch (argt) {
2888 		case THUMB_REG_REG_CONST: {
2889 			ut8 reg1 = getreg (ao->a[0]);
2890 			ut8 reg2 = getreg (ao->a[1]);
2891 			ut32 num = getnum (ao->a[2]);
2892 			if (num > 32) {
2893 				return -1;
2894 			}
2895 			ao->o = 0x0008;
2896 			if (std_16bit_2reg (ao, m)) {
2897 				ao->o |= (num & 0x03) << 14;
2898 				ao->o |= num >> 2;
2899 				return 2;
2900 			}
2901 			ao->o = 0x4fea1000;
2902 			ao->o |= reg1;
2903 			ao->o |= reg2 << 8;
2904 			ao->o |= (num >> 2) << 4;
2905 			ao->o |= (num & 0x3) << 14;
2906 			if (m & S_BIT) {
2907 				ao->o |= 1 << 28;
2908 			}
2909 			return 4;
2910 		        }
2911 			break;
2912 		case THUMB_REG_REG: {
2913 			ao->o = 0xc040;
2914 			if (std_16bit_2reg (ao, m)) {
2915 				return 2;
2916 			}
2917 			std_opt_2 (ao);
2918 		        }
2919 			// intentional fallthrough
2920 		case THUMB_REG_REG_REG: {
2921 			ao->o = 0x20fa00f0;
2922 			return std_32bit_3reg (ao, m, false);
2923 		        }
2924 			break;
2925 		default:
2926 			return -1;
2927 		}
2928 	} else
2929 	if ((m = opmask (ao->op, "mcr", R_BIT | TWO_BIT))) {
2930 		ut64 argt = thumb_selector (ao->a);
2931 		switch (argt) {
2932 		case THUMB_COPROC_CONST_REG_COREG_COREG: {
2933 			ao->a[5] = "0";
2934 		        }
2935 			// intentional fallthrough
2936 		case THUMB_COPROC_CONST_REG_COREG_COREG_CONST: {
2937 			ut32 coproc = getcoproc (ao->a[0]);
2938 			ut32 opc1 = getnum (ao->a[1]);
2939 			ut32 reg1 = getreg (ao->a[2]);
2940 			ut32 coreg1 = getcoprocreg (ao->a[3]);
2941 			ut32 coreg2 = getcoprocreg (ao->a[4]);
2942 			ut32 opc2 = getnum (ao->a[5]);
2943 
2944 			if ((coproc > 15) || (opc1 > 7) || (reg1 > 15) || (coreg1 > 15) || (coreg2 > 15) || (opc2 > 7) || (m & R_BIT)) {
2945 				return -1;
2946 			}
2947 
2948 			ao->o = 0x00ee1000;
2949 			if (m & TWO_BIT) {
2950 				ao->o |= 1 << 20;
2951 			}
2952 			ao->o |= coproc;
2953 			ao->o |= opc1 << 29;
2954 			ao->o |= reg1 << 4;
2955 			ao->o |= coreg1 << 24;
2956 			ao->o |= coreg2 << 8;
2957 			ao->o |= opc2 << 13;
2958 			return 4;
2959 		        }
2960 			break;
2961 		case THUMB_COPROC_CONST_REG_REG_COREG: {
2962 			ut32 coproc = getcoproc (ao->a[0]);
2963 			ut32 opc = getnum (ao->a[1]);
2964 			ut32 reg1 = getreg (ao->a[2]);
2965 			ut32 reg2 = getreg (ao->a[3]);
2966 			ut32 coreg = getcoprocreg (ao->a[4]);
2967 
2968 			if ((coproc > 15) || (opc > 15) || (reg1 > 15) || (reg2 > 15) || (coreg > 15) || (!(m & R_BIT))) {
2969 				return -1;
2970 			}
2971 
2972 			ao->o = 0x40ec0000;
2973 			if (m & TWO_BIT) {
2974 				ao->o |= 1 << 20;
2975 			}
2976 			ao->o |= coproc;
2977 			ao->o |= opc << 12;
2978 			ao->o |= reg1 << 4;
2979 			ao->o |= reg2 << 24;
2980 			ao->o |= coreg << 8;
2981 			return 4;
2982 		        }
2983 			break;
2984 		default:
2985 			return -1;
2986 		}
2987 	} else
2988 	if ((m = opmask (ao->op, "mla", 0))) {
2989 		ut64 argt = thumb_selector (ao->a);
2990 		switch (argt) {
2991 		case THUMB_REG_REG_REG_REG: {
2992 			ut32 reg4 = getreg (ao->a[3]);
2993 			if (reg4 > 15) {
2994 				return -1;
2995 			}
2996 			ao->o = 0x00fb0000;
2997 			ao->o |= reg4 << 4;
2998 
2999 			return std_32bit_3reg (ao, m, false);
3000 		        }
3001 			break;
3002 		default:
3003 			return -1;
3004 		}
3005 	} else
3006 	if ((m = opmask (ao->op, "mls", 0))) {
3007 		ut64 argt = thumb_selector (ao->a);
3008 		switch (argt) {
3009 		case THUMB_REG_REG_REG_REG: {
3010 			ut32 reg4 = getreg (ao->a[3]);
3011 			if (reg4 > 15) {
3012 				return -1;
3013 			}
3014 			ao->o = 0x00fb1000;
3015 			ao->o |= reg4 << 4;
3016 
3017 			return std_32bit_3reg (ao, m, false);
3018 		        }
3019 			break;
3020 		default:
3021 			return -1;
3022 		}
3023 	} else
3024 	if ((m = opmask (ao->op, "mov", S_BIT | W_BIT | T_BIT))) {
3025 		ut64 argt = thumb_selector (ao->a);
3026 		switch (argt) {
3027 		case THUMB_REG_CONST: {
3028 			ut32 reg1 = getreg (ao->a[0]);
3029 			err = false;
3030 			ut32 num = getnum (ao->a[1]);
3031 
3032 			if (reg1 > 15) {
3033 				return -1;
3034 			}
3035 
3036 			if ((m & W_BIT) || (m & T_BIT)) {
3037 				ut32 wnum = getnum (ao->a[1]);
3038 				if (wnum > 65535) {
3039 					return -1;
3040 				}
3041 				ao->o = 0x40f20000;
3042 				if (m & T_BIT) {
3043 					ao->o |= 1 << 31;
3044 				}
3045 				ao->o |= reg1;
3046 				ao->o |= getthzeroimmed16 (wnum);
3047 				return 4;
3048 			}
3049 
3050 			if (err) {
3051 				return -1;
3052 			}
3053 
3054 			if ((num < 256) && (reg1 < 8) && (!(m & DOTW_BIT))) {
3055 				ao->o = 0x0020;
3056 				ao->o |= reg1;
3057 				ao->o |= num << 8;
3058 				return 2;
3059 			}
3060 
3061 			ao->o = 0x4ff00000;
3062 			ao->o |= reg1;
3063 			ao->o |= getthimmed12 (ao->a[1]);
3064 			if (m & S_BIT) {
3065 				ao->o |= 1 << 28;
3066 			}
3067 			return 4;
3068 		        }
3069 			break;
3070 		case THUMB_REG_REG: {
3071 			ut32 reg1 = getreg (ao->a[0]);
3072 			ut32 reg2 = getreg (ao->a[1]);
3073 
3074 			if ((reg1 > 15) || (reg2 > 15)) {
3075 				return -1;
3076 			}
3077 
3078 			if ((!(m & S_BIT)) && (!(m & DOTW_BIT))) {
3079 				ao->o = 0x0046;
3080 				ao->o |= (reg1 & 0x7) << 8;
3081 				ao->o |= (reg1 & 0x8) << 12;
3082 				ao->o |= reg2 << 11;
3083 				return 2;
3084 			}
3085 
3086 			if ((reg1 < 8) && (reg2 < 8) && (!(m & DOTW_BIT))) {
3087 				ao->o = 0;
3088 				ao->o |= reg1 << 8;
3089 				ao->o |= reg2 << 11;
3090 				return 2;
3091 			}
3092 
3093 			ao->o = 0x4fea0000;
3094 			ao->o |= reg1;
3095 			ao->o |= reg2 << 8;
3096 			if (m & S_BIT) {
3097 				ao->o |= 1 << 28;
3098 			}
3099 			return 4;
3100 		        }
3101 			break;
3102 		default:
3103 			return -1;
3104 		}
3105 	} else
3106 	if ((m = opmask (ao->op, "mrc", TWO_BIT))) {
3107 		ut64 argt = thumb_selector (ao->a);
3108 		switch (argt) {
3109 		case THUMB_COPROC_CONST_REG_COREG_COREG: {
3110 			ao->a[5] = "0";
3111 		        }
3112 			// intentional fallthrough
3113 		case THUMB_COPROC_CONST_REG_COREG_COREG_CONST: {
3114 			ut32 coproc = getcoproc (ao->a[0]);
3115 			ut32 opc1 = getnum (ao->a[1]);
3116 			ut32 reg1 = getreg (ao->a[2]);
3117 			ut32 coreg1 = getcoprocreg (ao->a[3]);
3118 			ut32 coreg2 = getcoprocreg (ao->a[4]);
3119 			ut32 opc2 = getnum (ao->a[5]);
3120 
3121 			if ((coproc > 15) || (opc1 > 7) || (reg1 > 15) || (coreg1 > 15) || (coreg2 > 15) || (opc2 > 7)) {
3122 				return -1;
3123 			}
3124 
3125 			ao->o = 0x10ee1000;
3126 			if (m & TWO_BIT) {
3127 				ao->o |= 1 << 20;
3128 			}
3129 			ao->o |= coproc;
3130 			ao->o |= opc1 << 29;
3131 			ao->o |= reg1 << 4;
3132 			ao->o |= coreg1 << 24;
3133 			ao->o |= coreg2 << 8;
3134 			ao->o |= opc2 << 13;
3135 			return 4;
3136 		        }
3137 			break;
3138 		default:
3139 			return -1;
3140 		}
3141 	} else
3142 	if ((m = opmask (ao->op, "mrrc", TWO_BIT))) {
3143 		ut64 argt = thumb_selector (ao->a);
3144 		switch (argt) {
3145 		case THUMB_COPROC_CONST_REG_REG_COREG: {
3146 			ut32 coproc = getcoproc (ao->a[0]);
3147 			ut32 opc = getnum (ao->a[1]);
3148 			ut32 reg1 = getreg (ao->a[2]);
3149 			ut32 reg2 = getreg (ao->a[3]);
3150 			ut32 coreg = getcoprocreg (ao->a[4]);
3151 
3152 			if ((coproc > 15) || (opc > 15) || (reg1 > 15) || (reg2 > 15) || (coreg > 15)) {
3153 				return -1;
3154 			}
3155 
3156 			ao->o = 0x50ec0000;
3157 			if (m & TWO_BIT) {
3158 				ao->o |= 1 << 20;
3159 			}
3160 			ao->o |= coproc;
3161 			ao->o |= opc << 12;
3162 			ao->o |= reg1 << 4;
3163 			ao->o |= reg2 << 24;
3164 			ao->o |= coreg << 8;
3165 			return 4;
3166 		        }
3167 			break;
3168 		default:
3169 			return -1;
3170 		}
3171 	} else
3172 	if ((m = opmask (ao->op, "mrs", 0))) {
3173 		ut64 argt = thumb_selector (ao->a);
3174 		switch (argt) {
3175 		case THUMB_REG_OTHER: {
3176 			ut32 reg1 = getreg (ao->a[0]);
3177 			r_str_case (ao->a[1], false);
3178 
3179 			if (reg1 > 15) {
3180 				return -1;
3181 			}
3182 
3183 			if ((!strcmp(ao->a[1], "cpsr")) || (!strcmp(ao->a[1], "apsr"))) {
3184 				ao->o = 0xeff30080;
3185 				ao->o |= reg1;
3186 				return 4;
3187 			}
3188 
3189 			if (!strcmp(ao->a[1], "spsr")) {
3190 				ao->o = 0xfff30080;
3191 				ao->o |= reg1;
3192 				return 4;
3193 			}
3194 
3195 			return -1;
3196 		        }
3197 			break;
3198 		default:
3199 			return -1;
3200 		}
3201 	} else
3202 	if ((m = opmask (ao->op, "msr", 0))) {
3203 		ut64 argt = thumb_selector (ao->a);
3204 		switch (argt) {
3205 		case THUMB_OTHER_REG: {
3206 			r_str_case (ao->a[0], false);
3207 			ut8 spsr = 0;
3208 			ut8 bank = interpret_msrbank (ao->a[0], &spsr);
3209 			ut32 reg1 = getreg (ao->a[1]);
3210 
3211 			if ((bank == 0) || (reg1 > 15)) {
3212 				return -1;
3213 			}
3214 
3215 			ao->o = 0x80f30080;
3216 			ao->o |= reg1 << 24;
3217 			ao->o |= bank;
3218 			if (spsr != 0) {
3219 				ao->o |= 1 << 28;
3220 			}
3221 			return 4;
3222 		        }
3223 			break;
3224 		default:
3225 			return -1;
3226 		}
3227 	} else
3228 	if ((m = opmask (ao->op, "mul", 0))) {
3229 		ut64 argt = thumb_selector (ao->a);
3230 		switch (argt) {
3231 		case THUMB_REG_REG: {
3232 			std_opt_2 (ao);
3233 		        }
3234 			// intentional fallthrough
3235 		case THUMB_REG_REG_REG: {
3236 			ut8 reg1 = getreg (ao->a[0]);
3237 			ut8 reg3 = getreg (ao->a[2]);
3238 
3239 			ao->o = 0x4043;
3240 			if ((reg1 == reg3) && (std_16bit_2reg (ao, m))) {
3241 				return 2;
3242 			}
3243 
3244 			ao->o = 0x00fb00f0;
3245 			return std_32bit_3reg (ao, m, false);
3246 		        }
3247 			break;
3248 		default:
3249 			return -1;
3250 		}
3251 	} else
3252 	if ((m = opmask (ao->op, "mvn", S_BIT))) {
3253 		ut64 argt = thumb_selector (ao->a);
3254 		switch (argt) {
3255 		case THUMB_REG_CONST: {
3256 			ut8 reg1 = getreg (ao->a[0]);
3257 			err = false;
3258 			ut32 num = getthimmed12 (ao->a[1]);
3259 
3260 			if ((reg1 > 15) || err) {
3261 				return -1;
3262 			}
3263 
3264 			ao->o = 0x6ff00000;
3265 			ao->o |= reg1;
3266 			ao->o |= num;
3267 			if (m & S_BIT) {
3268 				ao->o |= 1 << 28;
3269 			}
3270 			return 4;
3271 		        }
3272 			break;
3273 		case THUMB_REG_REG: {
3274 			ao->a[2] = "lsl 0";
3275 		        }
3276 			// intentional fallthrough
3277 		case THUMB_REG_REG_SHIFT: {
3278 			ut8 reg1 = getreg (ao->a[0]);
3279 			ut8 reg2 = getreg (ao->a[1]);
3280 			ut32 shift = thumb_getshift (ao->a[2]);
3281 
3282 			if ((reg1 > 15) || (reg2 > 15)) {
3283 				return -1;
3284 			}
3285 
3286 			ao->o = 0xc043;
3287 			if ((shift == 0) && (std_16bit_2reg (ao, m))) {
3288 				return 2;
3289 			}
3290 
3291 			ao->o = 0x6fea0000;
3292 			ao->o |= reg1;
3293 			ao->o |= reg2 << 8;
3294 			ao->o |= shift;
3295 			if (m & S_BIT) {
3296 				ao->o |= 1 << 28;
3297 			}
3298 			return 4;
3299 		        }
3300 			break;
3301 		default:
3302 			return -1;
3303 		}
3304 	} else
3305 	if ((m = opmask (ao->op, "nop", 0))) {
3306 		ut64 argt = thumb_selector (ao->a);
3307 		switch (argt) {
3308 		case THUMB_NONE: {
3309 			if (m & DOTW_BIT) {
3310 				ao->o = 0xaff30080;
3311 				return 4;
3312 			}
3313 			ao->o = 0x00bf;
3314 			return 2;
3315 		        }
3316 			break;
3317 		default:
3318 			return -1;
3319 		}
3320 	} else
3321 	if ((m = opmask (ao->op, "orn", S_BIT))) {
3322 		ut64 argt = thumb_selector (ao->a);
3323 		switch (argt) {
3324 		case THUMB_REG_CONST: {
3325 			std_opt_2 (ao);
3326 		        }
3327 			// intentional fallthrough
3328 		case THUMB_REG_REG_CONST: {
3329 			err = false;
3330 			ut32 num = getthimmed12 (ao->a[2]);
3331 
3332 			if (err) {
3333 				return -1;
3334 			}
3335 
3336 			ao->o = 0x60f00000;
3337 			ao->o |= num;
3338 			return (std_32bit_2reg (ao, m, false));
3339 		        }
3340 			break;
3341 		case THUMB_REG_REG: {
3342 			std_opt_2 (ao);
3343 		        }
3344 			// intentional fallthrough
3345 		case THUMB_REG_REG_REG: {
3346 			ao->a[3] = "lsl 0";
3347 		        }
3348 			// intentional fallthrough
3349 		case THUMB_REG_REG_SHIFT: {
3350 			if (ao->a[3] == NULL) { // double fallthrough
3351 				std_opt_3 (ao);
3352 			}
3353 		        }
3354 			// intentional fallthrough
3355 		case THUMB_REG_REG_REG_SHIFT: {
3356 			ao->o = 0x60ea0000;
3357 			return std_32bit_3reg (ao, m, true);
3358 		        }
3359 			break;
3360 		default:
3361 			return -1;
3362 		}
3363 	} else
3364 	if ((m = opmask (ao->op, "orr", S_BIT))) {
3365 		ut64 argt = thumb_selector (ao->a);
3366 		switch (argt) {
3367 		case THUMB_REG_CONST: {
3368 			std_opt_2 (ao);
3369 		        }
3370 			// intentional fallthrough
3371 		case THUMB_REG_REG_CONST: {
3372 			err = false;
3373 			ut32 num = getthimmed12 (ao->a[2]);
3374 
3375 			if (err) {
3376 				return -1;
3377 			}
3378 
3379 			ao->o = 0x40f00000;
3380 			ao->o |= num;
3381 			return std_32bit_2reg (ao, m, false);
3382 		        }
3383 			break;
3384 		case THUMB_REG_REG: {
3385 			ao->o = 0x0043;
3386 			if (std_16bit_2reg (ao, m)) {
3387 				return 2;
3388 			}
3389 			std_opt_2 (ao);
3390 		        }
3391 			// intentional fallthrough
3392 		case THUMB_REG_REG_REG: {
3393 			ao->a[3] = "lsl 0";
3394 		        }
3395 			// intentional fallthrough
3396 		case THUMB_REG_REG_SHIFT: {
3397 			if (ao->a[3] == NULL) { // double fallthrough
3398 				std_opt_3 (ao);
3399 			}
3400 		        }
3401 			// intentional fallthrough
3402 		case THUMB_REG_REG_REG_SHIFT: {
3403 			ao->o = 0x40ea0000;
3404 			return (std_32bit_3reg (ao, m, true));
3405 		        }
3406 			break;
3407 		default:
3408 			return -1;
3409 		}
3410 	} else
3411 	if ((m = opmask (ao->op, "pkh", BT_BIT | TB_BIT))) {
3412 		ut64 argt = thumb_selector (ao->a);
3413 		switch (argt) {
3414 		case THUMB_REG_REG: {
3415 			std_opt_2 (ao);
3416 		        }
3417 			// intentional fallthrough
3418 		case THUMB_REG_REG_REG: {
3419 			if (m & TB_BIT) {
3420 				ao->a[3] = "asr 0";
3421 			} else
3422 			if (m & BT_BIT) {
3423 				ao->a[3] = "lsl 0";
3424 			} else {
3425 				return -1;
3426 			}
3427 		        }
3428 			// intentional fallthrough
3429 		case THUMB_REG_REG_SHIFT: {
3430 			if (ao->a[3] == NULL) { // double fallthrough
3431 				std_opt_3 (ao);
3432 			}
3433 		        }
3434 			// intentional fallthrough
3435 		case THUMB_REG_REG_REG_SHIFT: {
3436 			ut32 shift = thumb_getshift (ao->a[3]);
3437 
3438 			if (((m & TB_BIT) && ((shift & 0x00003000) != 0x00002000)) || ((m & BT_BIT) && ((shift & 0x00003000) != 0)) || ((m & (TB_BIT | BT_BIT)) == 0)) {
3439 				return -1;
3440 			}
3441 
3442 			ao->o = 0xc0ea0000;
3443 			return (std_32bit_3reg (ao, m, true));
3444 		        }
3445 			break;
3446 		default:
3447 			return -1;
3448 		}
3449 	} else
3450 	if ((m = opmask (ao->op, "pld", 0))) {
3451 		ut64 argt = thumb_selector (ao->a);
3452 		switch (argt) {
3453 		case THUMB_BRACKREG_CONSTBRACK: {
3454 			ut8 reg1 = getregmemstart (ao->a[0]);
3455 			st32 num = getnummemend (ao->a[1]);
3456 
3457 			if (reg1 == 15) {
3458 				if ((num < -4095) || (num > 4095)) {
3459 					return -1;
3460 				}
3461 				ao->o = 0x1ff800f0;
3462 				if (num > 0) {
3463 					ao->o |= 1 << 31;
3464 				} else {
3465 					num = -num;
3466 				}
3467 				ao->o |= (num & 0x0ff) << 8;
3468 				ao->o |= (num & 0xf00) >> 8;
3469 				return 4;
3470 			}
3471 
3472 			if ((reg1 > 15) || (num < -255) || (num > 4095)) {
3473 				return -1;
3474 			}
3475 
3476 			if (num > 0) {
3477 				ao->o = 0x90f800f0;
3478 				ao->o |= (num & 0x0ff) << 8;
3479 				ao->o |= (num & 0xf00) >> 8;
3480 				ao->o |= reg1 << 24;
3481 				return 4;
3482 			}
3483 			num = -num;
3484 			ao->o = 0x10f800fc;
3485 			ao->o |= num << 8;
3486 			ao->o |= reg1 << 24;
3487 			return 4;
3488 		        }
3489 			break;
3490 		case THUMB_BRACKREG_REGBRACK: {
3491 			ao->a[1][strlen (ao->a[1]) - 1] = '\0';
3492 			ao->a[2] = "lsl 0]";
3493 		        }
3494 			// intentional fallthrough
3495 		case THUMB_BRACKREG_REG_SHIFTBRACK: {
3496 			ut8 reg1 = getregmemstart (ao->a[0]);
3497 			ut8 reg2 = getreg (ao->a[1]);
3498 			ut32 shift = getshiftmemend (ao->a[2]) >> 2;
3499 
3500 			if ((reg1 > 15) || (reg2 > 15) || ((shift & 0xffffcfff) != 0)) {
3501 				return -1;
3502 			}
3503 
3504 			ao->o = 0x10f800f0;
3505 			ao->o |= reg1 << 24;
3506 			ao->o |= reg2 << 8;
3507 			ao->o |= shift;
3508 			return 4;
3509 		        }
3510 			break;
3511 		default:
3512 			return -1;
3513 		}
3514 	} else
3515 	if ((m = opmask (ao->op, "pli", 0))) {
3516 		ut64 argt = thumb_selector (ao->a);
3517 		switch (argt) {
3518 		case THUMB_BRACKREG_CONSTBRACK: {
3519 			ut8 reg1 = getregmemstart (ao->a[0]);
3520 			st32 num = getnummemend (ao->a[1]);
3521 
3522 			if (reg1 == 15) {
3523 				if ((num < -4095) || (num > 4095)) {
3524 					return -1;
3525 				}
3526 				ao->o = 0x1ff900f0;
3527 				if (num > 0) {
3528 					ao->o |= 1 << 31;
3529 				} else {
3530 					num = -num;
3531 				}
3532 				ao->o |= (num & 0x0ff) << 8;
3533 				ao->o |= (num & 0xf00) >> 8;
3534 				return 4;
3535 			}
3536 
3537 			if ((reg1 > 15) || (num < -255) || (num > 4095)) {
3538 				return -1;
3539 			}
3540 
3541 			if (num > 0) {
3542 				ao->o = 0x90f900f0;
3543 				ao->o |= (num & 0x0ff) << 8;
3544 				ao->o |= (num & 0xf00) >> 8;
3545 				ao->o |= reg1 << 24;
3546 				return 4;
3547 			}
3548 			num = -num;
3549 			ao->o = 0x10f900fc;
3550 			ao->o |= num << 8;
3551 			ao->o |= reg1 << 24;
3552 			return 4;
3553 		        }
3554 			break;
3555 		case THUMB_BRACKREG_REGBRACK: {
3556 			ao->a[1][strlen (ao->a[1]) -1] = '\0';
3557 			ao->a[2] = "lsl 0]";
3558 		        }
3559 			// intentional fallthrough
3560 		case THUMB_BRACKREG_REG_SHIFTBRACK: {
3561 			ut8 reg1 = getregmemstart (ao->a[0]);
3562 			ut8 reg2 = getreg (ao->a[1]);
3563 			ut32 shift = getshiftmemend (ao->a[2]) >> 2;
3564 
3565 			if ((reg1 > 15) || (reg2 > 15) || ((shift & 0xffffcfff) != 0)) {
3566 				return -1;
3567 			}
3568 
3569 			ao->o = 0x10f900f0;
3570 			ao->o |= reg1 << 24;
3571 			ao->o |= reg2 << 8;
3572 			ao->o |= shift;
3573 			return 4;
3574 		        }
3575 			break;
3576 		default:
3577 			return -1;
3578 		}
3579 	} else
3580 	if ((m = opmask (ao->op, "pop", 0))) {
3581 		ut64 argt = thumb_selector (ao->a);
3582 		switch (argt) {
3583 		case THUMB_LIST: {
3584 			st32 list = getreglist (ao->a[0]);
3585 			if ((list <= 0) || ((list & (1 << 13)) != 0)) {
3586 				return -1;
3587 			}
3588 			if ((!(m & DOTW_BIT)) && ((list & 0x00007f00) == 0)) {
3589 				ao->o = 0x00bc;
3590 				ao->o |= (list & 0x8000) >> 15;
3591 				ao->o |= (list & 0xff) << 8;
3592 				return 2;
3593 			}
3594 			ao->o = 0xbde80000;
3595 			ao->o |= (list & 0xff00) >> 8;
3596 			ao->o |= (list & 0xff) << 8;
3597 			return 4;
3598 		        }
3599 			break;
3600 		default:
3601 			return -1;
3602 		}
3603 	} else
3604 	if ((m = opmask (ao->op, "push", 0))) {
3605 		ut64 argt = thumb_selector (ao->a);
3606 		switch (argt) {
3607 		case THUMB_LIST: {
3608 			st32 list = getreglist (ao->a[0]);
3609 			if ((list <= 0) || ((list & 0x0000a000) != 0)) {
3610 				return -1;
3611 			}
3612 			if ((!(m & DOTW_BIT)) && ((list & 0x00001f00) == 0)) {
3613 				ao->o = 0x00b4;
3614 				ao->o |= (list & 0x4000) >> 14;
3615 				ao->o |= (list & 0xff) << 8;
3616 				return 2;
3617 			}
3618 			ao->o = 0x2de90000;
3619 			ao->o |= (list & 0xff00) >> 8;
3620 			ao->o |= (list & 0xff) << 8;
3621 			return 4;
3622 		        }
3623 			break;
3624 		default:
3625 			return -1;
3626 		}
3627 	} else
3628 	if ((m = opmask (ao->op, "qadd", EIGHT_BIT | SIXTEEN_BIT))) {
3629 		ut64 argt = thumb_selector (ao->a);
3630 		switch (argt) {
3631 		case THUMB_REG_REG: {
3632 			std_opt_2 (ao);
3633 		        }
3634 			// intentional fallthrough
3635 		case THUMB_REG_REG_REG: {
3636 			if (m & SIXTEEN_BIT) {
3637 				ao->o = 0x90fa10f0;
3638 			} else
3639 			if (m & EIGHT_BIT) {
3640 				ao->o = 0x80fa10f0;
3641 			} else {
3642 				ao->o = 0x80fa80f0;
3643 			}
3644 
3645 			return std_32bit_3reg (ao, m, false);
3646 		        }
3647 			break;
3648 		default:
3649 			return -1;
3650 		}
3651 	} else
3652 	if ((m = opmask (ao->op, "qasx", 0))) {
3653 		ut64 argt = thumb_selector (ao->a);
3654 		switch (argt) {
3655 		case THUMB_REG_REG: {
3656 			std_opt_2 (ao);
3657 		        }
3658 			// intentional fallthrough
3659 		case THUMB_REG_REG_REG: {
3660 			ao->o = 0xa0fa10f0;
3661 			return std_32bit_3reg (ao, m, false);
3662 		        }
3663 			break;
3664 		default:
3665 			return -1;
3666 		}
3667 	} else
3668 	if ((m = opmask (ao->op, "qdadd", 0))) {
3669 		ut64 argt = thumb_selector (ao->a);
3670 		switch (argt) {
3671 		case THUMB_REG_REG: {
3672 			std_opt_2 (ao);
3673 		        }
3674 			// intentional fallthrough
3675 		case THUMB_REG_REG_REG: {
3676 			ao->o = 0x80fa90f0;
3677 			return std_32bit_3reg (ao, m, false);
3678 		        }
3679 			break;
3680 		default:
3681 			return -1;
3682 		}
3683 	} else
3684 	if ((m = opmask (ao->op, "qdsub", 0))) {
3685 		ut64 argt = thumb_selector (ao->a);
3686 		switch (argt) {
3687 		case THUMB_REG_REG: {
3688 			std_opt_2 (ao);
3689 		        }
3690 			// intentional fallthrough
3691 		case THUMB_REG_REG_REG: {
3692 			ao->o = 0x80fab0f0;
3693 			return std_32bit_3reg (ao, m, false);
3694 		        }
3695 			break;
3696 		default:
3697 			return -1;
3698 		}
3699 	} else
3700 	if ((m = opmask (ao->op, "qsax", 0))) {
3701 		ut64 argt = thumb_selector (ao->a);
3702 		switch (argt) {
3703 		case THUMB_REG_REG: {
3704 			std_opt_2 (ao);
3705 		        }
3706 			// intentional fallthrough
3707 		case THUMB_REG_REG_REG: {
3708 			ao->o = 0xe0fa10f0;
3709 			return std_32bit_3reg (ao, m, false);
3710 		        }
3711 			break;
3712 		default:
3713 			return -1;
3714 		}
3715 	} else
3716 	if ((m = opmask (ao->op, "qsub", EIGHT_BIT | SIXTEEN_BIT))) {
3717 		ut64 argt = thumb_selector (ao->a);
3718 		switch (argt) {
3719 		case THUMB_REG_REG: {
3720 			std_opt_2 (ao);
3721 		        }
3722 			// intentional fallthrough
3723 		case THUMB_REG_REG_REG: {
3724 			if (m & SIXTEEN_BIT) {
3725 				ao->o = 0xd0fa10f0;
3726 			} else
3727 			if (m & EIGHT_BIT) {
3728 				ao->o = 0xc0fa10f0;
3729 			} else {
3730 				ao->o = 0x80faa0f0;
3731 			}
3732 			return std_32bit_3reg (ao, m, false);
3733 		        }
3734 			break;
3735 		default:
3736 			return -1;
3737 		}
3738 	} else
3739 	if ((m = opmask (ao->op, "rbit", 0))) {
3740 		ut64 argt = thumb_selector (ao->a);
3741 		switch (argt) {
3742 		case THUMB_REG_REG: {
3743 			ao->a[2] = ao->a[1];
3744 			ao->o = 0x90faa0f0;
3745 			return std_32bit_3reg (ao, m, false);
3746 		        }
3747 			break;
3748 		default:
3749 			return -1;
3750 		}
3751 	} else
3752 	if ((m = opmask (ao->op, "rev", SIXTEEN_BIT | SH_BIT))) {
3753 		ut64 argt = thumb_selector (ao->a);
3754 		switch (argt) {
3755 		case THUMB_REG_REG: {
3756 			if (m & SIXTEEN_BIT) {
3757 				ao->o = 0x40ba;
3758 			} else
3759 			if (m & SH_BIT) {
3760 				ao->o = 0xc0ba;
3761 			} else {
3762 				ao->o = 0x00ba;
3763 			}
3764 
3765 			if (std_16bit_2reg (ao, m)) {
3766 				return 2;
3767 			}
3768 
3769 			if (m & SIXTEEN_BIT) {
3770 				ao->o = 0x90fa90f0;
3771 			} else
3772 			if (m & SH_BIT) {
3773 				ao->o = 0x90fab0f0;
3774 			} else {
3775 				ao->o = 0x90fa80f0;
3776 			}
3777 			ao->a[2] = ao->a[1];
3778 			return std_32bit_3reg (ao, m, false);
3779 		        }
3780 			break;
3781 		default:
3782 			return -1;
3783 		}
3784 	} else
3785 	if ((m = opmask (ao->op, "rfe", IA_BIT | FD_BIT | DB_BIT | EA_BIT))) {
3786 		ut64 argt = thumb_selector (ao->a);
3787 		ut32 wb = 0;
3788 		switch (argt) {
3789 		case THUMB_REGBANG: {
3790 			ao->a[0][strlen (ao->a[0]) - 1] = '\0';
3791 			wb = 0x20000000;
3792 		        }
3793 			// intentional fallthrough
3794 		case THUMB_REG: {
3795 			ut8 reg1 = getreg (ao->a[0]);
3796 
3797 			if (reg1 > 15) {
3798 				return -1;
3799 			}
3800 
3801 			if ((m & DB_BIT) || (m & EA_BIT)) {
3802 				ao->o = 0x10e800c0;
3803 			} else {
3804 				ao->o = 0x90e900c0;
3805 			}
3806 
3807 			ao->o |= reg1 << 24;
3808 			ao->o |= wb;
3809 			return 4;
3810 		        }
3811 			break;
3812 		default:
3813 			return -1;
3814 		}
3815 	} else
3816 	if ((m = opmask (ao->op, "ror", S_BIT))) {
3817 		ut64 argt = thumb_selector (ao->a);
3818 		switch (argt) {
3819 		case THUMB_REG_REG_CONST: {
3820 			ut8 reg1 = getreg (ao->a[0]);
3821 			ut8 reg2 = getreg (ao->a[1]);
3822 			ut32 num = getnum (ao->a[2]);
3823 
3824 			if ((reg1 > 15) || (reg2 > 15) || (num > 31) || (num < 1)) {
3825 				return -1;
3826 			}
3827 
3828 			ao->o = 0x4fea3000;
3829 			ao->o |= reg1;
3830 			ao->o |= reg2 << 8;
3831 			ao->o |= (num & 0x3) << 14;
3832 			ao->o |= (num & 0x1c) << 2;
3833 			if (m & S_BIT) {
3834 				ao->o |= 1 << 28;
3835 			}
3836 			return 4;
3837 		        }
3838 			break;
3839 		case THUMB_REG_REG: {
3840 			ao->o = 0xc041;
3841 			if (std_16bit_2reg (ao, m)) {
3842 				return 2;
3843 			}
3844 			std_opt_2 (ao);
3845 		        }
3846 			// intentional fallthrough
3847 		case THUMB_REG_REG_REG: {
3848 			ao->o = 0x60fa00f0;
3849 			return (std_32bit_3reg (ao, m, false));
3850 		        }
3851 			break;
3852 		default:
3853 			return -1;
3854 		}
3855 	} else
3856 	if ((m = opmask (ao->op, "rrx", S_BIT))) {
3857 		ut64 argt = thumb_selector (ao->a);
3858 		switch (argt) {
3859 		case THUMB_REG_REG: {
3860 			ut8 reg1 = getreg (ao->a[0]);
3861 			ut8 reg2 = getreg (ao->a[1]);
3862 
3863 			if ((reg1 > 15) || (reg2 > 15)) {
3864 				return -1;
3865 			}
3866 
3867 			ao->o = 0x4fea3000;
3868 			ao->o |= reg1;
3869 			ao->o |= reg2 << 8;
3870 			if (m & S_BIT) {
3871 				ao->o |= 1 << 28;
3872 			}
3873 			return 4;
3874 		        }
3875 			break;
3876 		default:
3877 			return -1;
3878 		}
3879 	} else
3880 	if ((m = opmask (ao->op, "rsb", S_BIT))) {
3881 		ut64 argt = thumb_selector (ao->a);
3882 		switch (argt) {
3883 		case THUMB_REG_CONST: {
3884 			std_opt_2 (ao);
3885 		        }
3886 			// intentional fallthrough
3887 		case THUMB_REG_REG_CONST: {
3888 			err = false;
3889 			ut32 num = getthimmed12 (ao->a[2]);
3890 
3891 			if (err) {
3892 				return -1;
3893 			}
3894 
3895 			ao->o = 0x4042;
3896 			if ((num == 0) && std_16bit_2reg (ao, m)) {
3897 				return 2;
3898 			}
3899 
3900 			ao->o = 0xc0f10000;
3901 			ao->o |= num;
3902 			return (std_32bit_2reg (ao, m, false));
3903 		        }
3904 			break;
3905 		case THUMB_REG_REG: {
3906 			std_opt_2 (ao);
3907 		        }
3908 			// intentional fallthrough
3909 		case THUMB_REG_REG_REG: {
3910 			ao->a[3] = "lsl 0";
3911 		        }
3912 			// intentional fallthrough
3913 		case THUMB_REG_REG_SHIFT: {
3914 			if (ao->a[3] == NULL) { // double fallthrough
3915 				std_opt_3 (ao);
3916 			}
3917 		        }
3918 			// intentional fallthrough
3919 		case THUMB_REG_REG_REG_SHIFT: {
3920 			ao->o = 0xc0eb0000;
3921 			return (std_32bit_3reg (ao, m, true));
3922 		        }
3923 			break;
3924 		default:
3925 			return -1;
3926 		}
3927 	} else
3928 	if ((m = opmask (ao->op, "sadd", EIGHT_BIT | SIXTEEN_BIT))) {
3929 		ut64 argt = thumb_selector (ao->a);
3930 		switch (argt) {
3931 		case THUMB_REG_REG: {
3932 			std_opt_2 (ao);
3933 		        }
3934 			// intentional fallthrough
3935 		case THUMB_REG_REG_REG: {
3936 			if (m & SIXTEEN_BIT) {
3937 				ao->o = 0x90fa00f0;
3938 			} else
3939 			if (m & EIGHT_BIT) {
3940 				ao->o = 0x80fa00f0;
3941 			} else {
3942 				return -1;
3943 			}
3944 			return std_32bit_3reg (ao, m, false);
3945 		        }
3946 			break;
3947 		default:
3948 			return -1;
3949 		}
3950 	} else
3951 	if ((m = opmask (ao->op, "sasx", 0))) {
3952 		ut64 argt = thumb_selector (ao->a);
3953 		switch (argt) {
3954 		case THUMB_REG_REG: {
3955 			std_opt_2 (ao);
3956 		        }
3957 			// intentional fallthrough
3958 		case THUMB_REG_REG_REG: {
3959 			ao->o = 0xa0fa00f0;
3960 			return std_32bit_3reg (ao, m, false);
3961 		        }
3962 			break;
3963 		default:
3964 			return -1;
3965 		}
3966 	} else
3967 	if ((m = opmask (ao->op, "sbc", S_BIT))) {
3968 		ut64 argt = thumb_selector (ao->a);
3969 		switch (argt) {
3970 		case THUMB_REG_REG: {
3971 			ao->o = 0x8041;
3972 			if (std_16bit_2reg (ao, m)) {
3973 				return 2;
3974 			}
3975 			std_opt_2 (ao);
3976 		        }
3977 			// intentional fallthrough
3978 		case THUMB_REG_REG_REG: {
3979 			ao->a[3] = "lsl 0";
3980 		        }
3981 			// intentional fallthrough
3982 		case THUMB_REG_REG_SHIFT: {
3983 			if (ao->a[3] == NULL) { // double fallthrough
3984 				std_opt_3 (ao);
3985 			}
3986 		        }
3987 			// intentional fallthrough
3988 		case THUMB_REG_REG_REG_SHIFT: {
3989 			ao->o = 0x60eb0000;
3990 			return std_32bit_3reg (ao, m, true);
3991 		        }
3992 			break;
3993 		case THUMB_REG_CONST: {
3994 			std_opt_2 (ao);
3995 		        }
3996 			// intentional fallthrough
3997 		case THUMB_REG_REG_CONST: {
3998 			ao->o = 0x60f10000;
3999 			err = false;
4000 			ut32 num = getthimmed12 (ao->a[2]);
4001 
4002 			if (err) {
4003 				return -1;
4004 			}
4005 			ao->o |= num;
4006 
4007 			return std_32bit_2reg (ao, m, false);
4008 		        }
4009 			break;
4010 		default:
4011 			return -1;
4012 		}
4013 	} else
4014 	if (( m = opmask (ao->op, "sbfx", 0) )) {
4015 		ut64 argt = thumb_selector (ao->a);
4016 		switch (argt) {
4017 		case THUMB_REG_REG_CONST_CONST: {
4018 			ut32 lsb = getnum (ao->a[2]);
4019 			ut32 width = getnum (ao->a[3]);
4020 			ut32 msb = lsb + width - 1;
4021 			if ((lsb > 31) || (msb > 31)) {
4022 				return -1;
4023 			}
4024 			ao->o = 0x40f30000;
4025 			ao->o |= ((lsb & 0x1c) << 2);
4026 			ao->o |= ((lsb & 0x3) << 14);
4027 			ao->o |= ((width - 1) << 8);
4028 			return std_32bit_2reg (ao, m, false);
4029 		        }
4030 			break;
4031 		default:
4032 			return -1;
4033 		}
4034 	} else
4035 	if ((m = opmask (ao->op, "sdiv", 0))) {
4036 		ut64 argt = thumb_selector (ao->a);
4037 		switch (argt) {
4038 		case THUMB_REG_REG: {
4039 			std_opt_2 (ao);
4040 		        }
4041 			// intentional fallthrough
4042 		case THUMB_REG_REG_REG: {
4043 			ao->o = 0x90fbf0f0;
4044 			return std_32bit_3reg (ao, m, false);
4045 		        }
4046 			break;
4047 		default:
4048 			return -1;
4049 		}
4050 	} else
4051 	if ((m = opmask (ao->op, "sel", 0))) {
4052 		ut64 argt = thumb_selector (ao->a);
4053 		switch (argt) {
4054 		case THUMB_REG_REG: {
4055 			std_opt_2 (ao);
4056 		        }
4057 			// intentional fallthrough
4058 		case THUMB_REG_REG_REG: {
4059 			ao->o = 0xa0fa80f0;
4060 			return std_32bit_3reg (ao, m, false);
4061 		        }
4062 			break;
4063 		default:
4064 			return -1;
4065 		}
4066 	} else
4067 	if ((m = opmask (ao->op, "setend", 0))) {
4068 		ut64 argt = thumb_selector (ao->a);
4069 		switch (argt) {
4070 		case THUMB_OTHER: {
4071 			r_str_case (ao->a[0], false);
4072 			ao->o = 0x50b6;
4073 			if (!(strcmpnull (ao->a[0], "be"))) {
4074 				ao->o |= 1 << 11;
4075 				return 2;
4076 			} else
4077 			if (!(strcmpnull (ao->a[0], "le"))) {
4078 				return 2;
4079 			} else {
4080 				return -1;
4081 			}
4082 			break;
4083 		        }
4084 		default:
4085 			return -1;
4086 		}
4087 	} else
4088 	if ((m = opmask (ao->op, "sev", 0))) {
4089 		ut64 argt = thumb_selector (ao->a);
4090 		switch (argt) {
4091 		case THUMB_NONE:
4092 			if (m & DOTW_BIT) {
4093 				ao->o = 0xaff30480;
4094 				return 4;
4095 			} else {
4096 				ao->o = 0x40bf;
4097 				return 2;
4098 			}
4099 			break;
4100 		default:
4101 			return -1;
4102 		}
4103 	} else
4104 	if ((m = opmask (ao->op, "shadd", EIGHT_BIT | SIXTEEN_BIT ))) {
4105 		ut64 argt = thumb_selector (ao->a);
4106 		switch (argt) {
4107 		case THUMB_REG_REG: {
4108 			std_opt_2 (ao);
4109 		        }
4110 			// intentional fallthrough
4111 		case THUMB_REG_REG_REG: {
4112 			if (m & SIXTEEN_BIT) {
4113 				ao->o = 0x90fa20f0;
4114 			} else
4115 			if (m & EIGHT_BIT) {
4116 				ao->o = 0x80fa20f0;
4117 			} else {
4118 				return -1;
4119 			}
4120 			return std_32bit_3reg (ao, m, false);
4121 		        }
4122 			break;
4123 		default:
4124 			return -1;
4125 		}
4126 	} else
4127 	if ((m = opmask (ao->op, "shasx", 0))) {
4128 		ut64 argt = thumb_selector (ao->a);
4129 		switch (argt) {
4130 		case THUMB_REG_REG: {
4131 			std_opt_2 (ao);
4132 		        }
4133 			// intentional fallthrough
4134 		case THUMB_REG_REG_REG: {
4135 			ao->o = 0xa0fa20f0;
4136 			return std_32bit_3reg (ao, m, false);
4137 		        }
4138 			break;
4139 		default:
4140 			return -1;
4141 		}
4142 	} else
4143 	if ((m = opmask (ao->op, "shsax", 0))) {
4144 		ut64 argt = thumb_selector (ao->a);
4145 		switch (argt) {
4146 		case THUMB_REG_REG: {
4147 			std_opt_2 (ao);
4148 		        }
4149 			// intentional fallthrough
4150 		case THUMB_REG_REG_REG: {
4151 			ao->o = 0xe0fa20f0;
4152 			return std_32bit_3reg (ao, m, false);
4153 		        }
4154 			break;
4155 		default:
4156 			return -1;
4157 		}
4158 	} else
4159 	if ((m = opmask (ao->op, "shsub", EIGHT_BIT | SIXTEEN_BIT))) {
4160 		ut64 argt = thumb_selector (ao->a);
4161 		switch (argt) {
4162 		case THUMB_REG_REG: {
4163 			std_opt_2 (ao);
4164 		        }
4165 			// intentional fallthrough
4166 		case THUMB_REG_REG_REG: {
4167 			if (m & SIXTEEN_BIT) {
4168 				ao->o = 0xd0fa20f0;
4169 			} else
4170 			if (m & EIGHT_BIT) {
4171 				ao->o = 0xc0fa20f0;
4172 			} else {
4173 				return -1;
4174 			}
4175 			return std_32bit_3reg (ao, m, false);
4176 		        }
4177 			break;
4178 		default:
4179 			return -1;
4180 		}
4181 	} else
4182 	if ((m = opmask (ao->op, "smc", 0))) {
4183 		ut64 argt = thumb_selector (ao->a);
4184 		switch (argt) {
4185 		case THUMB_CONST: {
4186 			err = false;
4187 			ut32 num = getnum (ao->a[0]);
4188 
4189 			if (err || (num > 15)) {
4190 				return -1;
4191 			}
4192 
4193 			ao->o = 0xf0f70080;
4194 			ao->o |= num << 24;
4195 			return 4;
4196 		        }
4197 			break;
4198 		default:
4199 			return -1;
4200 		}
4201 	} else
4202 	if ((m = opmask (ao->op, "smla", BB_BIT | BT_BIT | TB_BIT | TT_BIT | WB_BIT | WT_BIT | L_BIT | D_BIT | X_BIT))) {
4203 		ut64 argt = thumb_selector (ao->a);
4204 		switch (argt) {
4205 		case THUMB_REG_REG_REG_REG: {
4206 			ut8 reg1 = getreg (ao->a[0]);
4207 			ut8 reg2 = getreg (ao->a[1]);
4208 			ut8 reg3 = getreg (ao->a[2]);
4209 			ut8 reg4 = getreg (ao->a[3]);
4210 
4211 			if ((reg1 > 15) || (reg2 > 15) || (reg3 > 15) || (reg4 > 15) || (m & DOTN_BIT)) {
4212 				return -1;
4213 			}
4214 			if (m & L_BIT) {
4215 				if (m & BB_BIT) {
4216 					ao->o = 0xc0fb8000;
4217 				} else
4218 				if (m & BT_BIT) {
4219 					ao->o = 0xc0fb9000;
4220 				} else
4221 				if (m & TB_BIT) {
4222 					ao->o = 0xc0fba000;
4223 				} else
4224 				if (m & TT_BIT) {
4225 					ao->o = 0xc0fbb000;
4226 				} else
4227 				if (m & D_BIT) {
4228 					ao->o = 0xc0fbc000;
4229 					if (m & X_BIT) {
4230 						ao->o |= 1 << 12;
4231 					}
4232 				} else {
4233 					ao->o = 0xc0fb0000;
4234 				}
4235 				ao->o |= reg1 << 4;
4236 				ao->o |= reg2;
4237 				ao->o |= reg3 << 24;
4238 				ao->o |= reg4 << 8;
4239 				return 4;
4240 			}
4241 			if (m & BB_BIT) {
4242 				ao->o = 0x10fb0000;
4243 				ao->o |= reg4 << 4;
4244 				return std_32bit_3reg (ao, m, false);
4245 			}
4246 			if (m & BT_BIT) {
4247 				ao->o = 0x10fb1000;
4248 				ao->o |= reg4 << 4;
4249 				return std_32bit_3reg (ao, m, false);
4250 			}
4251 			if (m & TB_BIT) {
4252 				ao->o = 0x10fb2000;
4253 				ao->o |= reg4 << 4;
4254 				return std_32bit_3reg (ao, m, false);
4255 			}
4256 			if (m & TT_BIT) {
4257 				ao->o = 0x10fb3000;
4258 				ao->o |= reg4 << 4;
4259 				return std_32bit_3reg (ao, m, false);
4260 			}
4261 			if (m & D_BIT) {
4262 				ao->o = 0x20fb0000;
4263 				if (m & X_BIT) {
4264 					ao->o |= 1 << 12;
4265 				}
4266 				ao->o |= reg4 << 4;
4267 				return std_32bit_3reg (ao, m, false);
4268 			}
4269 			if (m & WB_BIT) {
4270 				ao->o = 0x30fb0000;
4271 				ao->o |= reg4 << 4;
4272 				return std_32bit_3reg (ao, m, false);
4273 			}
4274 			if (m & WT_BIT) {
4275 				ao->o = 0x30fb1000;
4276 				ao->o |= reg4 << 4;
4277 				return std_32bit_3reg (ao, m, false);
4278 			}
4279 			return -1;
4280 		        }
4281 			break;
4282 		default:
4283 			return -1;
4284 		}
4285 	} else
4286 	if ((m = opmask (ao->op, "smlsd", X_BIT))) {
4287 		ut64 argt = thumb_selector (ao->a);
4288 		switch (argt) {
4289 		case THUMB_REG_REG_REG_REG: {
4290 			ut8 reg4 = getreg (ao->a[3]);
4291 
4292 			if (reg4 > 15) {
4293 				return -1;
4294 			}
4295 			ao->o = 0x40fb0000;
4296 			if (m & X_BIT) {
4297 				ao->o |= 1 << 12;
4298 			}
4299 			ao->o |= reg4 << 4;
4300 			return std_32bit_3reg (ao, m, false);
4301 		        }
4302 			break;
4303 		default:
4304 			return -1;
4305 		}
4306 	} else
4307 	if ((m = opmask (ao->op, "smlsld", X_BIT))) {
4308 		ut64 argt = thumb_selector (ao->a);
4309 		switch (argt) {
4310 		case THUMB_REG_REG_REG_REG: {
4311 			ut8 reg1 = getreg (ao->a[0]);
4312 			ut8 reg2 = getreg (ao->a[1]);
4313 			ut8 reg3 = getreg (ao->a[2]);
4314 			ut8 reg4 = getreg (ao->a[3]);
4315 
4316 			if ((reg1 > 15) || (reg2 > 15) || (reg3 > 15) || (reg4 > 15) || (m & DOTN_BIT)) {
4317 				return -1;
4318 			}
4319 			ao->o = 0xd0fbc000;
4320 
4321 			if (m & X_BIT) {
4322 				ao->o |= 1 << 12;
4323 			}
4324 
4325 			ao->o |= reg1 << 4;
4326 			ao->o |= reg2;
4327 			ao->o |= reg3 << 24;
4328 			ao->o |= reg4 << 8;
4329 			return 4;
4330 		        }
4331 			break;
4332 		default:
4333 			return -1;
4334 		}
4335 	} else
4336 	if ((m = opmask (ao->op, "smmla", R_BIT))) {
4337 		ut64 argt = thumb_selector (ao->a);
4338 		switch (argt) {
4339 		case THUMB_REG_REG_REG_REG: {
4340 			ut8 reg4 = getreg (ao->a[3]);
4341 
4342 			if (reg4 > 15) {
4343 				return -1;
4344 			}
4345 			ao->o = 0x50fb0000;
4346 			if (m & R_BIT) {
4347 				ao->o |= 1 << 12;
4348 			}
4349 			ao->o |= reg4 << 4;
4350 			return std_32bit_3reg (ao, m, false);
4351 		        }
4352 			break;
4353 		default:
4354 			return -1;
4355 		}
4356 	} else
4357 	if ((m = opmask (ao->op, "smmls", R_BIT))) {
4358 		ut64 argt = thumb_selector (ao->a);
4359 		switch (argt) {
4360 		case THUMB_REG_REG_REG_REG: {
4361 			ut8 reg4 = getreg (ao->a[3]);
4362 
4363 			if (reg4 > 15) {
4364 				return -1;
4365 			}
4366 			ao->o = 0x60fb0000;
4367 			if (m & R_BIT) {
4368 				ao->o |= 1 << 12;
4369 			}
4370 			ao->o |= reg4 << 4;
4371 			return std_32bit_3reg (ao, m, false);
4372 		        }
4373 			break;
4374 		default:
4375 			return -1;
4376 		}
4377 	} else
4378 	if ((m = opmask (ao->op, "smmul", R_BIT))) {
4379 		ut64 argt = thumb_selector (ao->a);
4380 		switch (argt) {
4381 		case THUMB_REG_REG: {
4382 			std_opt_2 (ao);
4383 		        }
4384 			// intentional fallthrough
4385 		case THUMB_REG_REG_REG: {
4386 			ao->o = 0x50fb00f0;
4387 			if (m & R_BIT) {
4388 				ao->o |= 1 << 12;
4389 			}
4390 			return std_32bit_3reg (ao, m, false);
4391 		        }
4392 			break;
4393 		default:
4394 			return -1;
4395 		}
4396 	} else
4397 	if ((m = opmask (ao->op, "smuad", X_BIT))) {
4398 		ut64 argt = thumb_selector (ao->a);
4399 		switch (argt) {
4400 		case THUMB_REG_REG: {
4401 			std_opt_2 (ao);
4402 		        }
4403 			// intentional fallthrough
4404 		case THUMB_REG_REG_REG: {
4405 			ao->o = 0x20fb00f0;
4406 			if (m & X_BIT) {
4407 				ao->o |= 1 << 12;
4408 			}
4409 			return std_32bit_3reg (ao, m, false);
4410 		        }
4411 			break;
4412 		default:
4413 			return -1;
4414 		}
4415 	} else
4416 	if ((m = opmask (ao->op, "smul", BB_BIT | BT_BIT | TB_BIT | TT_BIT | WB_BIT | WT_BIT | L_BIT))) {
4417 		ut64 argt = thumb_selector (ao->a);
4418 		switch (argt) {
4419 		case THUMB_REG_REG: {
4420 			std_opt_2 (ao);
4421 		        }
4422 			// intentional fallthrough
4423 		case THUMB_REG_REG_REG: {
4424 			if (m & BB_BIT) {
4425 				ao->o = 0x10fb00f0;
4426 			} else
4427 			if (m & BT_BIT) {
4428 				ao->o = 0x10fb10f0;
4429 			} else
4430 			if (m & TB_BIT) {
4431 				ao->o = 0x10fb20f0;
4432 			} else
4433 			if (m & TT_BIT) {
4434 				ao->o = 0x10fb30f0;
4435 			} else
4436 			if (m & WB_BIT) {
4437 				ao->o = 0x30fb00f0;
4438 			} else
4439 			if (m & WT_BIT) {
4440 				ao->o = 0x30fb10f0;
4441 			} else {
4442 				return -1;
4443 			}
4444 			return std_32bit_3reg (ao, m, false);
4445 		        }
4446 			break;
4447 		case THUMB_REG_REG_REG_REG: {
4448 			ut8 reg1 = getreg (ao->a[0]);
4449 			ut8 reg2 = getreg (ao->a[1]);
4450 			ut8 reg3 = getreg (ao->a[2]);
4451 			ut8 reg4 = getreg (ao->a[3]);
4452 
4453 			if ((reg1 > 15) || (reg2 > 15) || (reg3 > 15) || (reg4 > 15) || (m & DOTN_BIT) || (!(m & L_BIT))) {
4454 				return -1;
4455 			}
4456 
4457 			ao->o = 0x80fb0000;
4458 			ao->o |= reg1 << 4;
4459 			ao->o |= reg2;
4460 			ao->o |= reg3 << 24;
4461 			ao->o |= reg4 << 8;
4462 			return 4;
4463 		        }
4464 			break;
4465 		default:
4466 			return -1;
4467 		}
4468 	} else
4469 	if ((m = opmask (ao->op, "smusd", X_BIT))) {
4470 		ut64 argt = thumb_selector (ao->a);
4471 		switch (argt) {
4472 		case THUMB_REG_REG: {
4473 			std_opt_2 (ao);
4474 		        }
4475 			// intentional fallthrough
4476 		case THUMB_REG_REG_REG: {
4477 			ao->o = 0x40fb00f0;
4478 			if (m & X_BIT) {
4479 				ao->o |= 1 << 12;
4480 			}
4481 			return std_32bit_3reg (ao, m, false);
4482 		        }
4483 			break;
4484 		default:
4485 			return -1;
4486 		}
4487 	} else
4488 	if ((m = opmask (ao->op, "srs", DB_BIT | FD_BIT | IA_BIT | EA_BIT))) {
4489 		ut32 w = 0;
4490 		ut64 argt = thumb_selector (ao->a);
4491 		switch (argt) {
4492 		case THUMB_CONSTBANG: {
4493 			ao->a[0][strlen (ao->a[0]) - 1] = '\0';
4494 			w = 1;
4495 		        }
4496 			// intentional fallthrough
4497 		case THUMB_CONST: {
4498 			ut32 num = getnum (ao->a[0]);
4499 			if (num > 31) {
4500 				return -1;
4501 			}
4502 			if ((m & DB_BIT) || (m & FD_BIT)) {
4503 				ao->o = 0x0de800c0;
4504 			} else {
4505 				ao->o = 0x8de900c0;
4506 			}
4507 			ao->o |= num << 8;
4508 			ao->o |= w << 29;
4509 			return 4;
4510 		        }
4511 			break;
4512 		default:
4513 			return -1;
4514 		}
4515 	} else
4516 	if ((m = opmask (ao->op, "ssat", SIXTEEN_BIT))) {
4517 		ut64 argt = thumb_selector (ao->a);
4518 		switch (argt) {
4519 		case THUMB_REG_CONST_REG: {
4520 			ao->a[3] = "lsl 0";
4521 		        }
4522 			// intentional fallthrough
4523 		case THUMB_REG_CONST_REG_SHIFT: {
4524 			ut8 reg1 = getreg (ao->a[0]);
4525 			ut32 num = getnum (ao->a[1]) - 1;
4526 			ut8 reg2 = getreg (ao->a[2]);
4527 			ut32 shift = thumb_getshift (ao->a[3]);
4528 
4529 			if (err || (reg1 > 15) || (reg2 > 15) || (num > 31) || (shift & 0x00001000) || ((m & SIXTEEN_BIT) && shift)) {
4530 				return -1;
4531 			}
4532 
4533 			if (shift & 0x00002000) {
4534 				shift |= 0x20000000;
4535 				shift &= 0xffffdfff;
4536 			}
4537 
4538 			if (m & SIXTEEN_BIT) {
4539 				ao->o = 0x20f30000;
4540 			} else {
4541 				ao->o = 0x00f30000;
4542 			}
4543 
4544 			ao->o |= reg1;
4545 			ao->o |= reg2 << 24;
4546 			ao->o |= num << 8;
4547 			ao->o |= shift;
4548 			return 4;
4549 		        }
4550 			break;
4551 		default:
4552 			return -1;
4553 		}
4554 	} else
4555 	if ((m = opmask (ao->op, "ssax", 0))) {
4556 		ut64 argt = thumb_selector (ao->a);
4557 		switch (argt) {
4558 		case THUMB_REG_REG: {
4559 			std_opt_2 (ao);
4560 		        }
4561 			// intentional fallthrough
4562 		case THUMB_REG_REG_REG: {
4563 			ao->o = 0xe0fa00f0;
4564 			return std_32bit_3reg (ao, m, false);
4565 		        }
4566 			break;
4567 		default:
4568 			return -1;
4569 		}
4570 	} else
4571 	if ((m = opmask (ao->op, "ssub", EIGHT_BIT | SIXTEEN_BIT))) {
4572 		ut64 argt = thumb_selector (ao->a);
4573 		switch (argt) {
4574 		case THUMB_REG_REG: {
4575 			std_opt_2 (ao);
4576 		        }
4577 			// intentional fallthrough
4578 		case THUMB_REG_REG_REG: {
4579 			if (m & EIGHT_BIT) {
4580 				ao->o = 0xc0fa00f0;
4581 			} else
4582 			if (m & SIXTEEN_BIT) {
4583 				ao->o = 0xd0fa00f0;
4584 			} else {
4585 				return -1;
4586 			}
4587 			return std_32bit_3reg (ao, m, false);
4588 		        }
4589 			break;
4590 		default:
4591 			return -1;
4592 		}
4593 	} else if ((m = opmask (ao->op, "stc", L_BIT | TWO_BIT))) {
4594 		ut64 argt = thumb_selector (ao->a);
4595 		switch (argt) {
4596 		case THUMB_COPROC_COREG_BRACKREGBRACK: {
4597 			ao->a[2][strlen (ao->a[2]) - 1] = '\0';
4598 			ao->a[3] = "0]";
4599 		        }
4600 			// intentional fallthrough
4601 		case THUMB_COPROC_COREG_BRACKREG_CONSTBRACK: {
4602 			ut8 coproc = getcoproc (ao->a[0]);
4603 			ut8 coreg = getcoprocreg (ao->a[1]);
4604 			ut8 reg = getregmemstart (ao->a[2]);
4605 			st32 num = getnummemend (ao->a[3]);
4606 
4607 			if ((coproc > 15) || (coreg > 15) || (reg > 15) || (num > 4092) || (num < -4092) || (num % 4 != 0)) {
4608 				return -1;
4609 			}
4610 
4611 			ao->o = 0x00ed0000;
4612 			if (m & L_BIT) {
4613 				ao->o |= 1 << 30;
4614 			}
4615 			if (m & TWO_BIT) {
4616 				ao->o |= 1 << 20;
4617 			}
4618 			if (num < 0) {
4619 				num = -num;
4620 			} else {
4621 				ao->o |= 1 << 31;
4622 			}
4623 			ao->o |= coproc;
4624 			ao->o |= coreg << 4;
4625 			ao->o |= reg << 24;
4626 			ao->o |= (num >> 2) << 8;
4627 			return 4;
4628 		        }
4629 			break;
4630 		case THUMB_COPROC_COREG_BRACKREGBRACK_CONST: {
4631 			ut8 coproc = getcoproc (ao->a[0]);
4632 			ut8 coreg = getcoprocreg (ao->a[1]);
4633 			ut8 reg = getregmemstartend (ao->a[2]);
4634 			st32 num = getnum (ao->a[3]);
4635 
4636 			if ((coproc > 15) || (coreg > 15) || (reg > 15) || (num > 4092) || (num < -4092) || (num % 4 != 0)) {
4637 				return -1;
4638 			}
4639 
4640 			ao->o = 0x20ec0000;
4641 			if (m & L_BIT) {
4642 				ao->o |= 1 << 30;
4643 			}
4644 			if (m & TWO_BIT) {
4645 				ao->o |= 1 << 20;
4646 			}
4647 			if (num < 0) {
4648 				num = -num;
4649 			} else {
4650 				ao->o |= 1 << 31;
4651 			}
4652 			ao->o |= coproc;
4653 			ao->o |= coreg << 4;
4654 			ao->o |= reg << 24;
4655 			ao->o |= (num >> 2) << 8;
4656 			return 4;
4657 		        }
4658 			break;
4659 		case THUMB_COPROC_COREG_BRACKREG_CONSTBRACKBANG: {
4660 			ut8 coproc = getcoproc (ao->a[0]);
4661 			ut8 coreg = getcoprocreg (ao->a[1]);
4662 			ut8 reg = getregmemstart (ao->a[2]);
4663 			st32 num = getnummemendbang (ao->a[3]);
4664 
4665 			if ((coproc > 15) || (coreg > 15) || (reg > 15) || (num > 4092) || (num < -4092) || (num % 4 != 0)) {
4666 				return -1;
4667 			}
4668 
4669 			ao->o = 0x20ed0000;
4670 			if (m & L_BIT) {
4671 				ao->o |= 1 << 30;
4672 			}
4673 			if (m & TWO_BIT) {
4674 				ao->o |= 1 << 20;
4675 			}
4676 			if (num < 0) {
4677 				num = -num;
4678 			} else {
4679 				ao->o |= 1 << 31;
4680 			}
4681 			ao->o |= coproc;
4682 			ao->o |= coreg << 4;
4683 			ao->o |= reg << 24;
4684 			ao->o |= (num >> 2) << 8;
4685 			return 4;
4686 		        }
4687 			break;
4688 		default:
4689 			return -1;
4690 		}
4691 	} else if ((m = opmask (ao->op, "stm", FD_BIT | DB_BIT | IA_BIT | EA_BIT))) {
4692 		ut64 argt = thumb_selector (ao->a);
4693 		bool wb = false;
4694 		switch (argt) {
4695 		case THUMB_REGBANG_LIST: {
4696 			wb = true;
4697 			ao->a[0][strlen (ao->a[0]) - 1] = '\0';
4698 		        }
4699 			// intentional fallthrough
4700 		case THUMB_REG_LIST: {
4701 			ut8 reg = getreg (ao->a[0]);
4702 			st32 list = getreglist (ao->a[1]);
4703 			if ((list <= 0) || ((list & 0x0000a000) != 0)) {
4704 				return -1;
4705 			}
4706 
4707 			if ((!(m & DOTW_BIT)) && ((list & 0x0000ff00) == 0) && (!(m & (FD_BIT | DB_BIT))) && wb) {
4708 				ao->o = 0x00c0;
4709 				ao->o |= (list & 0x000000ff) << 8;
4710 				ao->o |= reg;
4711 				return 2;
4712 			}
4713 
4714 			if ((m & (FD_BIT | DB_BIT | IA_BIT | EA_BIT)) == 0) {
4715 				return -1;
4716 			}
4717 
4718 			if (m & (FD_BIT | DB_BIT)) {
4719 				ao->o = 0x00e90000;
4720 			} else {
4721 				ao->o = 0x80e80000;
4722 			}
4723 
4724 			if (wb) {
4725 				ao->o |= 1 << 29;
4726 			}
4727 
4728 			ao->o |= reg << 24;
4729 			ao->o |= (list & 0x000000ff) << 8;
4730 			ao->o |= (list & 0x0000ff00) >> 8;
4731 			return 4;
4732 		        }
4733 			break;
4734 		default:
4735 			return -1;
4736 		}
4737 	} else if ((m = opmask (ao->op, "str", B_BIT | T_BIT | D_BIT | H_BIT))) {
4738 		ut64 argt = thumb_selector (ao->a);
4739 		ut32 strsel = m & (B_BIT | H_BIT | D_BIT);
4740 		switch (argt) {
4741 		case THUMB_REG_BRACKREGBRACK:
4742 			if (ao->a[2] == NULL) { // double fallthrough
4743 				ao->a[1][strlen (ao->a[1]) -1] = '\0';
4744 				ao->a[2] = "0]";
4745 			}
4746 			// intentional fallthrough
4747 		case THUMB_REG_BRACKREG_CONSTBRACK: {
4748 			ut8 reg1 = getreg (ao->a[0]);
4749 			ut8 reg2 = getregmemstart (ao->a[1]);
4750 			st32 num = getnummemend (ao->a[2]);
4751 			if (m & T_BIT) {
4752 				if ((num < 0) || (num > 255)) {
4753 					return -1;
4754 				}
4755 				if (strsel == 0) {
4756 					ao->o = 0x40f8000e;
4757 				} else
4758 			        if (strsel == H_BIT) {
4759 					ao->o = 0x20f8000e;
4760 				} else
4761 			        if (strsel == B_BIT) {
4762 					ao->o = 0x00f8000e;
4763 				} else {
4764 					return -1;
4765 				}
4766 				ao->o |= num << 8;
4767 				return mem_32bit_2reg (ao, m);
4768 			}
4769 
4770 			if ((strsel == 0) && (reg2 == 13) && (num >= 0) && (num < 1024) && ((num % 4) == 0) && (reg1 < 8) & (!(m & DOTW_BIT))) {
4771 				ao->o = 0x0090;
4772 				ao->o |= reg1;
4773 				ao->o |= (num >> 2) << 8;
4774 				return 2;
4775 			}
4776 
4777 			bool t1form = false;
4778 			if ((strsel == 0) && (num < 128) && (num >= 0) && (num % 4 == 0)) {
4779 				ao->o = 0x0060;
4780 				ao->o |= (num >> 4);
4781 				ao->o |= ((num >> 2) & 0x3) << 14;
4782 				t1form = true;
4783 			}
4784 			if ((strsel == B_BIT) && (num < 32) && (num >= 0)) {
4785 				ao->o = 0x0070;
4786 				ao->o |= (num >> 2);
4787 				ao->o |= (num & 0x3) << 14;
4788 				t1form = true;
4789 			}
4790 			if ((strsel == H_BIT) && (num < 64) && (num >= 0) && (num % 2 == 0)) {
4791 				ao->o = 0x0080;
4792 				ao->o |= (num >> 3);
4793 				ao->o |= ((num >> 1) & 0x3) << 14;
4794 				t1form = true;
4795 			}
4796 			if (t1form) {
4797 				if (mem_16bit_2reg (ao, m)) {
4798 					return 2;
4799 				}
4800 			}
4801 
4802 			if ((num > 4095) || (num < -255)) {
4803 				return -1;
4804 			}
4805 			if (num >= 0) {
4806 				if (strsel == 0) {
4807 					ao->o = 0xc0f80000;
4808 				} else
4809 				if (strsel == B_BIT) {
4810 					ao->o = 0x80f80000;
4811 				} else
4812 				if (strsel == H_BIT) {
4813 					ao->o = 0xa0f80000;
4814 				} else {
4815 					return -1;
4816 				}
4817 				ao->o |= (num >> 8);
4818 				ao->o |= (num & 0x000000ff) << 8;
4819 				return mem_32bit_2reg (ao, m);
4820 			}
4821 			if (strsel == 0) {
4822 				ao->o = 0x40f8000c;
4823 			} else
4824 			if (strsel == B_BIT) {
4825 				ao->o = 0x00f8000c;
4826 			} else
4827 			if (strsel == H_BIT) {
4828 				ao->o = 0x20f8000c;
4829 			} else {
4830 				return -1;
4831 			}
4832 			ao->o |= -num << 8;
4833 			return mem_32bit_2reg (ao, m);
4834 		        }
4835 			break;
4836 		case THUMB_REG_BRACKREGBRACK_CONST: {
4837 			ut8 reg1 = getreg (ao->a[0]);
4838 			ut8 reg2 = getregmemstartend (ao->a[1]);
4839 			st32 num = getnum (ao->a[2]);
4840 
4841 			if ((num > 255) || (num < -255)) {
4842 				return -1;
4843 			}
4844 
4845 			if (strsel == 0) {
4846 				ao->o = 0x40f80009;
4847 			} else
4848 			if (strsel == B_BIT) {
4849 				ao->o = 0x00f80009;
4850 			} else
4851 			if (strsel == H_BIT) {
4852 				ao->o = 0x20f80009;
4853 			} else {
4854 				return -1;
4855 			}
4856 
4857 			if (num < 0) {
4858 				num = -num;
4859 			} else {
4860 				ao->o |= 1 << 1;
4861 			}
4862 			ao->o |= num << 8;
4863 			ao->o |= reg1 << 4;
4864 			ao->o |= reg2 << 24;
4865 			return 4;
4866 		        }
4867 			break;
4868 		case THUMB_REG_BRACKREG_CONSTBRACKBANG: {
4869 			st32 num = getnummemendbang (ao->a[2]);
4870 
4871 			if ((num > 255) || (num < -255)) {
4872 				return -1;
4873 			}
4874 
4875 			if (strsel == 0) {
4876 				ao->o = 0x40f8000d;
4877 			} else
4878 			if (strsel == B_BIT) {
4879 				ao->o = 0x00f8000d;
4880 			} else
4881 			if (strsel == H_BIT) {
4882 				ao->o = 0x20f8000d;
4883 			} else {
4884 				return -1;
4885 			}
4886 
4887 			if (num < 0) {
4888 				num = -num;
4889 			} else {
4890 				ao->o |= 1 << 1;
4891 			}
4892 			ao->o |= num << 8;
4893 			return mem_32bit_2reg (ao, m);
4894 		        }
4895 			break;
4896 		case THUMB_REG_BRACKREG_REGBRACK: {
4897 			ut8 reg1 = getreg (ao->a[0]);
4898 			ut8 reg2 = getregmemstart (ao->a[1]);
4899 			ut8 reg3 = getregmemend (ao->a[2]);
4900 			if ((reg1 < 8) && (reg2 < 8) && (reg3 < 8) && (!(m & DOTW_BIT))) {
4901 				if (strsel == 0) {
4902 					ao->o = 0x0050;
4903 				} else
4904 				if (strsel == B_BIT) {
4905 					ao->o = 0x0054;
4906 				} else
4907 				if (strsel == H_BIT) {
4908 					ao->o = 0x0052;
4909 				} else {
4910 					return -1;
4911 				}
4912 				ao->o |= reg1 << 8;
4913 				ao->o |= reg2 << 11;
4914 				ao->o |= (reg3 & 0x3) << 14;
4915 				ao->o |= (reg3 >> 2);
4916 				return 2;
4917 			}
4918 			ao->a[2][strlen (ao->a[2]) - 1] = '\0';
4919 			ao->a[3] = "lsl 0]";
4920 		        }
4921 			// intentional fallthrough
4922 		case THUMB_REG_BRACKREG_REG_SHIFTBRACK: {
4923 			ut8 reg1 = getreg (ao->a[0]);
4924 			ut8 reg2 = getregmemstart (ao->a[1]);
4925 			ut8 reg3 = getreg (ao->a[2]);
4926 			ut32 shift = getshiftmemend (ao->a[3]) >> 2;
4927 
4928 			if (((shift & 0xffffcfff) != 0) || (reg1 > 15) || (reg2 > 15) || (reg3 > 15)) {
4929 				return -1;
4930 			}
4931 
4932 			if (strsel == 0) {
4933 				ao->o = 0x40f80000;
4934 			} else
4935 			if (strsel == B_BIT) {
4936 				ao->o = 0x00f80000;
4937 			} else
4938 			if (strsel == H_BIT) {
4939 				ao->o = 0x20f80000;
4940 			} else {
4941 				return -1;
4942 			}
4943 
4944 			ao->o |= reg1 << 4;
4945 			ao->o |= reg2 << 24;
4946 			ao->o |= reg3 << 8;
4947 			ao->o |= shift;
4948 			return 4;
4949 		        }
4950 			break;
4951 		case THUMB_REG_REG_BRACKREGBRACK: {
4952 			ao->a[2][strlen (ao->a[2]) - 1] = '\0';
4953 			ao->a[3] = "0]";
4954 		        }
4955 			// intentional fallthrough
4956 		case THUMB_REG_REG_BRACKREG_CONSTBRACK: {
4957 			ut8 reg1 = getreg (ao->a[0]);
4958 			ut8 reg2 = getreg (ao->a[1]);
4959 			ut8 reg3 = getregmemstart (ao->a[2]);
4960 			st32 num = getnummemend (ao->a[3]);
4961 
4962 			if ((reg1 > 15) || (reg2 > 15) || (reg3 > 15) || (strsel != D_BIT) || (num > 1023) || (num < -1023) || ((num % 4) != 0)) {
4963 				return -1;
4964 			}
4965 
4966 			ao->o = 0x40e90000;
4967 
4968 			if (num < 0) {
4969 				num = -num;
4970 			} else {
4971 				ao->o |= 1 << 31;
4972 			}
4973 			ao->o |= reg1 << 4;
4974 			ao->o |= reg2;
4975 			ao->o |= reg3 << 24;
4976 			ao->o |= (num >> 2) << 8;
4977 			return 4;
4978 		        }
4979 			break;
4980 		case THUMB_REG_REG_BRACKREG_CONSTBRACKBANG: {
4981 			ut8 reg1 = getreg (ao->a[0]);
4982 			ut8 reg2 = getreg (ao->a[1]);
4983 			ut8 reg3 = getregmemstart (ao->a[2]);
4984 			st32 num = getnummemendbang (ao->a[3]);
4985 
4986 			if ((reg1 > 15) || (reg2 > 15) || (reg3 > 15) || (strsel != D_BIT) || (num > 1023) || (num < -1023) || ((num % 4) != 0)) {
4987 				return -1;
4988 			}
4989 
4990 			ao->o = 0x60e90000;
4991 
4992 			if (num < 0) {
4993 				num = -num;
4994 			} else {
4995 				ao->o |= 1 << 31;
4996 			}
4997 			ao->o |= reg1 << 4;
4998 			ao->o |= reg2;
4999 			ao->o |= reg3 << 24;
5000 			ao->o |= (num >> 2) << 8;
5001 			return 4;
5002 		        }
5003 			break;
5004 		case THUMB_REG_REG_BRACKREGBRACK_CONST: {
5005 			ut8 reg1 = getreg (ao->a[0]);
5006 			ut8 reg2 = getreg (ao->a[1]);
5007 			ut8 reg3 = getregmemstartend (ao->a[2]);
5008 			st32 num = getnum (ao->a[3]);
5009 
5010 			if ((reg1 > 15) || (reg2 > 15) || (reg3 > 15) || (strsel != D_BIT) || (num > 1023) || (num < -1023) || ((num % 4) != 0)) {
5011 				return -1;
5012 			}
5013 
5014 			ao->o = 0x60e80000;
5015 
5016 			if (num < 0) {
5017 				num = -num;
5018 			} else {
5019 				ao->o |= 1 << 31;
5020 			}
5021 			ao->o |= reg1 << 4;
5022 			ao->o |= reg2;
5023 			ao->o |= reg3 << 24;
5024 			ao->o |= (num >> 2) << 8;
5025 			return 4;
5026 		        }
5027 			break;
5028 		default:
5029 			return -1;
5030 		}
5031 	} else
5032 	if ((m = opmask (ao->op, "strex", B_BIT | D_BIT | H_BIT))) {
5033 		ut64 argt = thumb_selector (ao->a);
5034 		ut32 strsel = m & (B_BIT | H_BIT | D_BIT);
5035 		switch (argt) {
5036 		case THUMB_REG_REG_BRACKREGBRACK: {
5037 			ut8 reg1 = getreg (ao->a[0]);
5038 			ut8 reg2 = getreg (ao->a[1]);
5039 			ut8 reg3 = getregmemstartend (ao->a[2]);
5040 
5041 			if ((strsel == D_BIT) || (reg1 > 15) || (reg2 > 15) || (reg3 > 15)) {
5042 				return -1;
5043 			}
5044 			if (strsel == B_BIT) {
5045 				ao->o = 0xc0e8400f;
5046 				ao->o |= reg1 << 8;
5047 				ao->o |= reg2 << 4;
5048 				ao->o |= reg3 << 24;
5049 				return 4;
5050 			} else
5051 			if (strsel == H_BIT) {
5052 				ao->o = 0xc0e8500f;
5053 				ao->o |= reg1 << 8;
5054 				ao->o |= reg2 << 4;
5055 				ao->o |= reg3 << 24;
5056 				return 4;
5057 			}
5058 
5059 			ao->a[2][strlen (ao->a[2]) - 1] = '\0';
5060 			ao->a[3] = "0]";
5061 		        }
5062 			// intentional fallthrough
5063 		case THUMB_REG_REG_BRACKREG_CONSTBRACK: {
5064 			ut8 reg1 = getreg (ao->a[0]);
5065 			ut8 reg2 = getreg (ao->a[1]);
5066 			ut8 reg3 = getregmemstart (ao->a[2]);
5067 			st32 num = getnummemend (ao->a[3]);
5068 
5069 			if ((strsel != 0) || (reg1 > 15) || (reg2 > 15) || (reg3 > 15) || (num < 0) || (num > 1023) || ((num % 4) !=0)) {
5070 				return -1;
5071 			}
5072 
5073 			ao->o = 0x40e80000;
5074 			ao->o |= reg1;
5075 			ao->o |= reg2 << 4;
5076 			ao->o |= reg3 << 24;
5077 			ao->o |= (num >> 2) << 8;
5078 			return 4;
5079 		        }
5080 			break;
5081 		case THUMB_REG_REG_REG_BRACKREGBRACK: {
5082 			ut8 reg1 = getreg (ao->a[0]);
5083 			ut8 reg2 = getreg (ao->a[1]);
5084 			ut8 reg3 = getreg (ao->a[2]);
5085 			ut8 reg4 = getregmemstartend (ao->a[3]);
5086 
5087 			if ((strsel != D_BIT) || (reg1 > 15) || (reg2 > 15) || (reg3 > 15) || (reg4 > 15)) {
5088 				return -1;
5089 			}
5090 
5091 			ao->o = 0xc0e87000;
5092 			ao->o |= reg1 << 8;
5093 			ao->o |= reg2 << 4;
5094 			ao->o |= reg3;
5095 			ao->o |= reg4 << 24;
5096 			return 4;
5097 		        }
5098 			break;
5099 		}
5100 	} else
5101 	if ((m = opmask (ao->op, "sub", S_BIT | W_BIT))) {
5102 		ut64 argt = thumb_selector (ao->a);
5103 		switch (argt) {
5104 		case THUMB_REG_CONST: {
5105 			std_opt_2 (ao);
5106 		        }
5107 			// intentional fallthrough
5108 		case THUMB_REG_REG_CONST: {
5109 			ut8 reg1 = getreg (ao->a[0]);
5110 			ut8 reg2 = getreg (ao->a[1]);
5111 			ut32 num = getnum (ao->a[2]);
5112 
5113 			if ((reg1 > 15) || (reg2 > 15)) {
5114 				return -1;
5115 			}
5116 
5117 			if ((reg1 == 15) && (reg2 == 14) && (num < 256)) {
5118 				ao->o = 0xdef3008f;
5119 				ao->o |= num << 8;
5120 				return 4;
5121 			}
5122 			if (reg2 == 13) {
5123 				if ((reg1 == 13) && (!(m & DOTW_BIT)) && (!(m & W_BIT)) && (num <= 4096) && (num % 4 == 0)) {
5124 					ao->o = 0x80b0;
5125 					ao->o |= (num >> 2) << 8;
5126 					return 2;
5127 				}
5128 				err = false;
5129 				ut32 thnum = getthimmed12 (ao->a[2]);
5130 
5131 				if (!err && (!(m & W_BIT))) {
5132 					ao->o = 0xadf10000;
5133 					ao->o |= thnum;
5134 					ao->o |= reg1;
5135 					if (m & S_BIT) {
5136 						ao->o |= 1 << 28;
5137 					}
5138 					return 4;
5139 				}
5140 
5141 				if (num > 4096) {
5142 					return -1;
5143 				}
5144 
5145 				ao->o = 0xadf20000;
5146 				ao->o |= getthzeroimmed12 (num);
5147 				ao->o |= reg1;
5148 				return 4;
5149 			}
5150 
5151 			if ((reg1 < 8) && (reg2 < 8) && (!(m & DOTW_BIT)) && (!(m & W_BIT)) && (num < 8)) {
5152 				ao->o = 0x001e;
5153 				ao->o |= reg1 << 8;
5154 				ao->o |= reg2 << 11;
5155 				ao->o |= (num & 0x3) << 14;
5156 				ao->o |= (num >> 2);
5157 				return 2;
5158 			}
5159 
5160 			if ((reg1 < 8) && (reg1 == reg2) && (!(m & DOTW_BIT)) && (!(m & W_BIT)) && (num < 256)) {
5161 				ao->o = 0x0038;
5162 				ao->o |= reg1;
5163 				ao->o |= num << 8;
5164 				return 2;
5165 			}
5166 
5167 			err = false;
5168 			ut32 thnum = getthimmed12 (ao->a[2]);
5169 
5170 			if (!err && (!(m & W_BIT))) {
5171 				ao->o = 0xa0f10000;
5172 				ao->o |= thnum;
5173 				return std_32bit_2reg (ao, m, false);
5174 			}
5175 
5176 			if (num > 4096) {
5177 				return -1;
5178 			}
5179 
5180 			ao->o = 0xa0f20000;
5181 			ao->o |= reg1;
5182 			ao->o |= reg2 << 24;
5183 			ao->o |= getthzeroimmed12 (num);
5184 			return 4;
5185 		        }
5186 			break;
5187 		case THUMB_REG_REG: {
5188 			std_opt_2 (ao);
5189 		        }
5190 			// intentional fallthrough
5191 		case THUMB_REG_REG_REG: {
5192 			ao->a[3] = "lsl 0";
5193 		        }
5194 			// intentional fallthrough
5195 		case THUMB_REG_REG_SHIFT:
5196 			if (ao->a[3] == NULL) { // double fallthrough
5197 				std_opt_3 (ao);
5198 			}
5199 			// intentional fallthrough
5200 		case THUMB_REG_REG_REG_SHIFT: {
5201 			ut8 reg1 = getreg (ao->a[0]);
5202 			ut8 reg2 = getreg (ao->a[1]);
5203 			ut8 reg3 = getreg (ao->a[2]);
5204 			ut32 shift = thumb_getshift (ao->a[3]);
5205 
5206 			if (reg2 == 13) {
5207 				ao->o = 0xadeb0000;
5208 				ao->o |= reg1;
5209 				ao->o |= reg3 << 8;
5210 				ao->o |= shift;
5211 				if (m & S_BIT) {
5212 					ao->o |= 1 << 28;
5213 				}
5214 				return 4;
5215 			}
5216 
5217 			if ((shift == 0) && (reg1 < 8) && (reg2 < 8) && (reg3 < 8) && (!(m & DOTW_BIT))) {
5218 				ao->o = 0x001a;
5219 				ao->o |= reg1 << 8;
5220 				ao->o |= reg2 << 11;
5221 				ao->o |= (reg3 & 0x3) << 14;
5222 				ao->o |= (reg3 >> 2);
5223 				return 2;
5224 			}
5225 
5226 			ao->o = 0xa0eb0000;
5227 			return std_32bit_3reg (ao, m, true);
5228 		        }
5229 			break;
5230 		default:
5231 			return -1;
5232 		}
5233 	} else
5234 	if ((m = opmask (ao->op, "svc", 0))) {
5235 		ut64 argt = thumb_selector (ao->a);
5236 		switch (argt) {
5237 		case THUMB_CONST: {
5238 			ut32 num = getnum (ao->a[0]);
5239 			if (num > 255) {
5240 				return -1;
5241 			}
5242 			ao->o = 0x00df;
5243 			ao->o |= num << 8;
5244 			return 2;
5245 		        }
5246 			break;
5247 		default:
5248 			return -1;
5249 		}
5250 	} else
5251 	if ((m = opmask (ao->op, "sxta", B_BIT | H_BIT | SIXTEEN_BIT))) {
5252 		ut64 argt = thumb_selector (ao->a);
5253 		switch (argt) {
5254 		case THUMB_REG_REG: {
5255 			std_opt_2 (ao);
5256 		        }
5257 			// intentional fallthrough
5258 		case THUMB_REG_REG_REG: {
5259 			ao->a[3] = "lsl 0";
5260 		        }
5261 			// intentional fallthrough
5262 		case THUMB_REG_REG_SHIFT: {
5263 			if (ao->a[3] == NULL) { // double fallthrough
5264 				std_opt_3 (ao);
5265 			}
5266 		        }
5267 			// intentional fallthrough
5268 		case THUMB_REG_REG_REG_SHIFT: {
5269 			ut32 shift = thumb_getshift (ao->a[3]);
5270 
5271 			if ((shift != 0) && ((shift & 0x0000f010) != 0x00003000)) {
5272 				return -1;
5273 			}
5274 
5275 			ut64 sufsel = m & (B_BIT | H_BIT | SIXTEEN_BIT);
5276 
5277 			if (sufsel == B_BIT) {
5278 				ao->o = 0x40fa80f0;
5279 			} else
5280 			if (sufsel == (B_BIT | SIXTEEN_BIT)) {
5281 				ao->o = 0x20fa80f0;
5282 			} else
5283 			if (sufsel == H_BIT) {
5284 				ao->o = 0x00fa80f0;
5285 			} else {
5286 				return -1;
5287 			}
5288 
5289 			ao->o |= (shift & 0x00000060) << 7;
5290 			return std_32bit_3reg (ao, m, false);
5291 		        }
5292 			break;
5293 		}
5294 	} else
5295 	if ((m = opmask (ao->op, "sxt", B_BIT | H_BIT | SIXTEEN_BIT))) {
5296 		ut64 sufsel = m & (B_BIT | H_BIT | SIXTEEN_BIT);
5297 		ut64 argt = thumb_selector (ao->a);
5298 		switch (argt) {
5299 		case THUMB_REG_REG: {
5300 			ao->a[2] = "lsl 0";
5301 		        }
5302 			// intentional fallthrough
5303 		case THUMB_REG_REG_SHIFT: {
5304 			ut8 reg1 = getreg (ao->a[0]);
5305 			ut8 reg2 = getreg (ao->a[1]);
5306 			ut32 shift = thumb_getshift (ao->a[2]);
5307 
5308 			if ((reg1 > 15) && (reg2 > 15) && (shift != 0) && ((shift & 0x0000f010) != 0x00003000)) {
5309 				return -1;
5310 			}
5311 
5312 			if (sufsel == B_BIT) {
5313 				ao->o = 0x40b2;
5314 				if ((shift == 0) && std_16bit_2reg (ao, m)) {
5315 					return 2;
5316 				}
5317 				ao->o = 0x4ffa80f0;
5318 			} else
5319 			if (sufsel == (B_BIT | SIXTEEN_BIT)) {
5320 				ao->o = 0x2ffa80f0;
5321 			} else
5322 			if (sufsel == H_BIT) {
5323 				ao->o = 0x00b2;
5324 				if ((shift == 0) && std_16bit_2reg (ao, m)) {
5325 					return 2;
5326 				}
5327 				ao->o = 0x0ffa80f0;
5328 			} else {
5329 				return -1;
5330 			}
5331 
5332 			ao->o |= (shift & 0x00000060) << 7;
5333 			ao->o |= reg1;
5334 			ao->o |= reg2 << 8;
5335 			return 4;
5336 		        }
5337 			break;
5338 		}
5339 	} else
5340 	if ((m = opmask (ao->op, "tb", B_BIT | H_BIT))) {
5341 		ut64 argt = thumb_selector (ao->a);
5342 		ut64 sufsel = m & (B_BIT | H_BIT);
5343 		switch (argt) {
5344 		case THUMB_BRACKREG_REGBRACK: {
5345 			ut8 reg1 = getregmemstart (ao->a[0]);
5346 			ut8 reg2 = getregmemend (ao->a[1]);
5347 
5348 			if ((reg1 > 15) || (reg2 > 15)) {
5349 				return -1;
5350 			}
5351 
5352 			if (sufsel == B_BIT) {
5353 				ao->o = 0xd0e800f0;
5354 				ao->o |= reg1 << 24;
5355 				ao->o |= reg2 << 8;
5356 				return 4;
5357 			}
5358 			ao->a[1][strlen (ao->a[1]) - 1] = '\0';
5359 			ao->a[2] = "lsl 1]";
5360 		        }
5361 			// intentional fallthrough
5362 		case THUMB_BRACKREG_REG_SHIFTBRACK: {
5363 			ut8 reg1 = getregmemstart (ao->a[0]);
5364 			ut8 reg2 = getreg (ao->a[1]);
5365 			ut32 shift = getshiftmemend (ao->a[2]);
5366 
5367 			if ((reg1 > 15) || (reg2 > 15) || (shift != 0x00004000) || (sufsel != H_BIT)) {
5368 				return -1;
5369 			}
5370 
5371 			ao->o = 0xd0e810f0;
5372 			ao->o |= reg1 << 24;
5373 			ao->o |= reg2 << 8;
5374 			return 4;
5375 		        }
5376 			break;
5377 		default:
5378 			return -1;
5379 		}
5380 	} else
5381 	if ((m = opmask (ao->op, "teq", 0))) {
5382 		ut64 argt = thumb_selector (ao->a);
5383 		switch (argt) {
5384 		case THUMB_REG_CONST: {
5385 			ut8 reg = getreg (ao->a[0]);
5386 			err = false;
5387 			ut32 num = getthimmed12 (ao->a[1]);
5388 
5389 			if (err || (reg > 15)) {
5390 				return -1;
5391 			}
5392 
5393 			ao->o = 0x90f0000f;
5394 			ao->o |= reg << 24;
5395 			ao->o |= num;
5396 			return 4;
5397 		        }
5398 			break;
5399 		case THUMB_REG_REG: {
5400 			ao->a[2] = "lsl 0";
5401 		        }
5402 			// intentional fallthrough
5403 		case THUMB_REG_REG_SHIFT: {
5404 			ao->o = 0x90ea000f;
5405 			return std_32bit_2reg (ao, m, true);
5406 		        }
5407 			break;
5408 		default:
5409 			return -1;
5410 		}
5411 	} else
5412 	if ((m = opmask (ao->op, "tst", 0))) {
5413 		ut64 argt = thumb_selector (ao->a);
5414 		switch (argt) {
5415 		case THUMB_REG_CONST: {
5416 			ut8 reg1 = getreg (ao->a[0]);
5417 			err = false;
5418 			ut32 num = getthimmed12 (ao->a[1]);
5419 
5420 			if (err || (reg1 > 15)) {
5421 				return -1;
5422 			}
5423 
5424 			ao->o = 0x10f0000f;
5425 			ao->o |= reg1 << 24;
5426 			ao->o |= num;
5427 			return 4;
5428 		        }
5429 			break;
5430 		case THUMB_REG_REG: {
5431 			ao->o = 0x0042;
5432 
5433 			if (std_16bit_2reg (ao, m)) {
5434 				return 2;
5435 			}
5436 
5437 			ao->a[2] = "lsl 0";
5438 		        }
5439 			// intentional fallthrough
5440 		case THUMB_REG_REG_SHIFT: {
5441 			ao->o = 0x10ea000f;
5442 			return std_32bit_2reg (ao, m, true);
5443 		        }
5444 			break;
5445 		default:
5446 			return -1;
5447 		}
5448 	} else
5449 	if ((m = opmask (ao->op, "uadd", EIGHT_BIT | SIXTEEN_BIT))) {
5450 		ut64 argt = thumb_selector (ao->a);
5451 		switch (argt) {
5452 		case THUMB_REG_REG: {
5453 			std_opt_2 (ao);
5454 		        }
5455 			// intentional fallthrough
5456 		case THUMB_REG_REG_REG: {
5457 			if (m & EIGHT_BIT) {
5458 				ao->o = 0x80fa40f0;
5459 			} else
5460 			if (m & SIXTEEN_BIT) {
5461 				ao->o = 0x90fa40f0;
5462 			} else {
5463 				return -1;
5464 			}
5465 
5466 			return std_32bit_3reg (ao, m, false);
5467 		        }
5468 			break;
5469 		default:
5470 			return -1;
5471 		}
5472 	} else
5473 	if ((m = opmask (ao->op, "uasx", 0))) {
5474 		ut64 argt = thumb_selector (ao->a);
5475 		switch (argt) {
5476 		case THUMB_REG_REG: {
5477 			std_opt_2 (ao);
5478 		        }
5479 			// intentional fallthrough
5480 		case THUMB_REG_REG_REG: {
5481 			ao->o = 0xa0fa40f0;
5482 			return std_32bit_3reg (ao, m, false);
5483 		        }
5484 			break;
5485 		default:
5486 			return -1;
5487 		}
5488 	} else
5489 	if ((m = opmask (ao->op, "ubfx", 0))) {
5490 		ut64 argt = thumb_selector (ao->a);
5491 		switch (argt) {
5492 		case THUMB_REG_REG_CONST_CONST: {
5493 			ut8 reg1 = getreg (ao->a[0]);
5494 			ut8 reg2 = getreg (ao->a[1]);
5495 			ut32 lsb = getnum (ao->a[2]);
5496 			ut32 widthm1 = getnum (ao->a[3]) - 1;
5497 
5498 			if ((reg1 > 15) || (reg2 > 15) || (lsb > 31) || ((31 - lsb) <= widthm1)) {
5499 				return -1;
5500 			}
5501 
5502 			ao->o = 0xc0f30000;
5503 			ao->o |= reg1;
5504 			ao->o |= reg2 << 24;
5505 			ao->o |= (lsb & 0x1c) << 2;
5506 			ao->o |= (lsb & 0x3) << 14;
5507 			ao->o |= widthm1 << 8;
5508 			return 4;
5509 		        }
5510 			break;
5511 		default:
5512 			return -1;
5513 		}
5514 	} else
5515 	if ((m = opmask (ao->op, "udiv", 0))) {
5516 		ut64 argt = thumb_selector (ao->a);
5517 		switch (argt) {
5518 		case THUMB_REG_REG: {
5519 			std_opt_2 (ao);
5520 		        }
5521 			// intentional fallthrough
5522 		case THUMB_REG_REG_REG: {
5523 			ao->o = 0xb0fbf0f0;
5524 			return std_32bit_3reg (ao, m, false);
5525 		        }
5526 			break;
5527 		default:
5528 			return -1;
5529 		}
5530 	} else
5531 	if ((m = opmask (ao->op, "uhadd", EIGHT_BIT | SIXTEEN_BIT))) {
5532 		ut64 argt = thumb_selector (ao->a);
5533 		ut64 sufsel = m & (EIGHT_BIT | SIXTEEN_BIT);
5534 		switch (argt) {
5535 		case THUMB_REG_REG: {
5536 			std_opt_2 (ao);
5537 		        }
5538 			// intentional fallthrough
5539 		case THUMB_REG_REG_REG: {
5540 			if (sufsel == EIGHT_BIT) {
5541 				ao->o = 0x80fa60f0;
5542 			} else
5543 			if (sufsel == SIXTEEN_BIT) {
5544 				ao->o = 0x90fa60f0;
5545 			} else {
5546 				return -1;
5547 			}
5548 
5549 			return std_32bit_3reg (ao, m, false);
5550 		        }
5551 			break;
5552 		default:
5553 			return -1;
5554 		}
5555 	} else
5556 	if ((m = opmask (ao->op, "uhasx", 0))) {
5557 		ut64 argt = thumb_selector (ao->a);
5558 		switch (argt) {
5559 		case THUMB_REG_REG: {
5560 			std_opt_2 (ao);
5561 		        }
5562 			// intentional fallthrough
5563 		case THUMB_REG_REG_REG: {
5564 			ao->o = 0xa0fa60f0;
5565 
5566 			return std_32bit_3reg (ao, m, false);
5567 
5568 		        }
5569 			break;
5570 		default:
5571 			return -1;
5572 		}
5573 	} else
5574 	if ((m = opmask (ao->op, "uhsax", 0))) {
5575 		ut64 argt = thumb_selector (ao->a);
5576 		switch (argt) {
5577 		case THUMB_REG_REG: {
5578 			std_opt_2 (ao);
5579 		        }
5580 			// intentional fallthrough
5581 		case THUMB_REG_REG_REG: {
5582 			ao->o = 0xe0fa60f0;
5583 
5584 			return std_32bit_3reg (ao, m, false);
5585 		        }
5586 			break;
5587 		default:
5588 			return -1;
5589 		}
5590 	} else
5591 	if ((m = opmask (ao->op, "uhsub", EIGHT_BIT | SIXTEEN_BIT))) {
5592 		ut64 argt = thumb_selector (ao->a);
5593 		ut64 sufsel = m & (EIGHT_BIT | SIXTEEN_BIT);
5594 		switch (argt) {
5595 		case THUMB_REG_REG: {
5596 			std_opt_2 (ao);
5597 		        }
5598 			// intentional fallthrough
5599 		case THUMB_REG_REG_REG: {
5600 			if (sufsel == EIGHT_BIT) {
5601 				ao->o = 0xc0fa60f0;
5602 			} else
5603 			if (sufsel == SIXTEEN_BIT) {
5604 				ao->o = 0xd0fa60f0;
5605 			} else {
5606 				return -1;
5607 			}
5608 
5609 			return std_32bit_3reg (ao, m, false);
5610 		        }
5611 			break;
5612 		default:
5613 			return -1;
5614 		}
5615 	} else
5616 	if ((m = opmask (ao->op, "umaal", 0))) {
5617 		ut64 argt = thumb_selector (ao->a);
5618 		switch (argt) {
5619 		case THUMB_REG_REG_REG_REG: {
5620 			ut8 reg1 = getreg (ao->a[0]);
5621 			ut8 reg2 = getreg (ao->a[1]);
5622 			ut8 reg3 = getreg (ao->a[2]);
5623 			ut8 reg4 = getreg (ao->a[3]);
5624 
5625 			if ((reg1 > 15) || (reg2 > 15) || (reg3 > 15) || (reg4 > 15)) {
5626 				return -1;
5627 			}
5628 
5629 			ao->o = 0xe0fb6000;
5630 			ao->o |= reg1 << 4;
5631 			ao->o |= reg2;
5632 			ao->o |= reg3 << 24;
5633 			ao->o |= reg4 << 8;
5634 			return 4;
5635 		        }
5636 			break;
5637 		default:
5638 			return -1;
5639 		}
5640 	} else
5641 	if ((m = opmask (ao->op, "umlal", 0))) {
5642 		ut64 argt = thumb_selector (ao->a);
5643 		switch (argt) {
5644 		case THUMB_REG_REG_REG_REG: {
5645 			ut8 reg1 = getreg (ao->a[0]);
5646 			ut8 reg2 = getreg (ao->a[1]);
5647 			ut8 reg3 = getreg (ao->a[2]);
5648 			ut8 reg4 = getreg (ao->a[3]);
5649 
5650 			if ((reg1 > 15) || (reg2 > 15) || (reg3 > 15) || (reg4 > 15)) {
5651 				return -1;
5652 			}
5653 
5654 			ao->o = 0xe0fb0000;
5655 			ao->o |= reg1 << 4;
5656 			ao->o |= reg2;
5657 			ao->o |= reg3 << 24;
5658 			ao->o |= reg4 << 8;
5659 			return 4;
5660 		        }
5661 			break;
5662 		default:
5663 			return -1;
5664 		}
5665 	} else
5666 	if ((m = opmask (ao->op, "umull", 0))) {
5667 		ut64 argt = thumb_selector (ao->a);
5668 		switch (argt) {
5669 		case THUMB_REG_REG_REG_REG: {
5670 			ut8 reg1 = getreg (ao->a[0]);
5671 			ut8 reg2 = getreg (ao->a[1]);
5672 			ut8 reg3 = getreg (ao->a[2]);
5673 			ut8 reg4 = getreg (ao->a[3]);
5674 
5675 			if ((reg1 > 15) || (reg2 > 15) || (reg3 > 15) || (reg4 > 15)) {
5676 				return -1;
5677 			}
5678 
5679 			ao->o = 0xa0fb0000;
5680 			ao->o |= reg1 << 4;
5681 			ao->o |= reg2;
5682 			ao->o |= reg3 << 24;
5683 			ao->o |= reg4 << 8;
5684 			return 4;
5685 		        }
5686 			break;
5687 		default:
5688 			return -1;
5689 		}
5690 	} else
5691 	if ((m = opmask (ao->op, "uqadd", EIGHT_BIT | SIXTEEN_BIT))) {
5692 		ut64 argt = thumb_selector (ao->a);
5693 		ut64 sufsel = m & (EIGHT_BIT | SIXTEEN_BIT);
5694 		switch (argt) {
5695 		case THUMB_REG_REG: {
5696 			std_opt_2 (ao);
5697 		        }
5698 			// intentional fallthrough
5699 		case THUMB_REG_REG_REG: {
5700 			if (sufsel == EIGHT_BIT) {
5701 				ao->o = 0x80fa50f0;
5702 			} else
5703 			if (sufsel == SIXTEEN_BIT) {
5704 				ao->o = 0x90fa50f0;
5705 			} else {
5706 				return -1;
5707 			}
5708 
5709 			return std_32bit_3reg (ao, m, false);
5710 		        }
5711 			break;
5712 		default:
5713 			return -1;
5714 		}
5715 	} else
5716 	if ((m = opmask (ao->op, "uqasx", 0))) {
5717 		ut64 argt = thumb_selector (ao->a);
5718 		switch (argt) {
5719 		case THUMB_REG_REG: {
5720 			std_opt_2 (ao);
5721 		        }
5722 			// intentional fallthrough
5723 		case THUMB_REG_REG_REG: {
5724 			ao->o = 0xa0fa50f0;
5725 
5726 			return std_32bit_3reg (ao, m, false);
5727 		        }
5728 			break;
5729 		default:
5730 			return -1;
5731 		}
5732 	} else
5733 	if ((m = opmask (ao->op, "uqsax", 0))) {
5734 		ut64 argt = thumb_selector (ao->a);
5735 		switch (argt) {
5736 		case THUMB_REG_REG: {
5737 			std_opt_2 (ao);
5738 		        }
5739 			// intentional fallthrough
5740 		case THUMB_REG_REG_REG: {
5741 			ao->o = 0xe0fa50f0;
5742 
5743 			return std_32bit_3reg (ao, m, false);
5744 		        }
5745 			break;
5746 		default:
5747 			return -1;
5748 		}
5749 	} else
5750 	if ((m = opmask (ao->op, "uqsub", EIGHT_BIT | SIXTEEN_BIT))) {
5751 		ut64 argt = thumb_selector (ao->a);
5752 		ut64 sufsel = m & (EIGHT_BIT | SIXTEEN_BIT);
5753 		switch (argt) {
5754 		case THUMB_REG_REG: {
5755 			std_opt_2 (ao);
5756 		        }
5757 			// intentional fallthrough
5758 		case THUMB_REG_REG_REG: {
5759 			if (sufsel == EIGHT_BIT) {
5760 				ao->o = 0xc0fa50f0;
5761 			} else
5762 			if (sufsel == SIXTEEN_BIT) {
5763 				ao->o = 0xd0fa50f0;
5764 			} else {
5765 				return -1;
5766 			}
5767 
5768 			return std_32bit_3reg (ao, m, false);
5769 		        }
5770 			break;
5771 		default:
5772 			return -1;
5773 		}
5774 	} else
5775 	if ((m = opmask (ao->op, "usad8", 0))) {
5776 		ut64 argt = thumb_selector (ao->a);
5777 		switch (argt) {
5778 		case THUMB_REG_REG: {
5779 			std_opt_2 (ao);
5780 		        }
5781 			// intentional fallthrough
5782 		case THUMB_REG_REG_REG: {
5783 			ao->o = 0x70fb00f0;
5784 
5785 			return std_32bit_3reg (ao, m, false);
5786 		        }
5787 			break;
5788 		default:
5789 			return -1;
5790 		}
5791 	} else
5792 	if ((m = opmask (ao->op, "usada8", 0))) {
5793 		ut64 argt = thumb_selector (ao->a);
5794 		switch (argt) {
5795 		case THUMB_REG_REG_REG_REG: {
5796 			ut8 reg1 = getreg (ao->a[0]);
5797 			ut8 reg2 = getreg (ao->a[1]);
5798 			ut8 reg3 = getreg (ao->a[2]);
5799 			ut8 reg4 = getreg (ao->a[3]);
5800 
5801 			if ((reg1 > 15) || (reg2 > 15) || (reg3 > 15) || (reg4 > 15)) {
5802 				return -1;
5803 			}
5804 
5805 			ao->o = 0x70fb0000;
5806 			ao->o |= reg1;
5807 			ao->o |= reg2 << 24;
5808 			ao->o |= reg3 << 8;
5809 			ao->o |= reg4 << 4;
5810 			return 4;
5811 		        }
5812 			break;
5813 		default:
5814 			return -1;
5815 		}
5816 	} else
5817 	if ((m = opmask (ao->op, "usat", SIXTEEN_BIT))) {
5818 		ut64 argt = thumb_selector (ao->a);
5819 		switch (argt) {
5820 		case THUMB_REG_CONST_REG: {
5821 			if (m & SIXTEEN_BIT) {
5822 				ut8 reg1 = getreg (ao->a[0]);
5823 				ut32 num = getnum (ao->a[1]);
5824 				ut8 reg2 = getreg (ao->a[2]);
5825 
5826 				if ((reg1 > 15) || (num > 15) || (reg2 > 15)) {
5827 					return -1;
5828 				}
5829 
5830 				ao->o = 0xa0f30000;
5831 				ao->o |= reg1;
5832 				ao->o |= reg2 << 24;
5833 				ao->o |= num << 8;
5834 				return 4;
5835 			}
5836 
5837 			ao->a[3] = "lsl 0";
5838 		        }
5839 			// intentional fallthrough
5840 		case THUMB_REG_CONST_REG_SHIFT: {
5841 			ut8 reg1 = getreg (ao->a[0]);
5842 			ut32 num = getnum (ao->a[1]);
5843 			ut8 reg2 = getreg (ao->a[2]);
5844 			ut32 shift = thumb_getshift (ao->a[3]);
5845 
5846 			if ((reg1 > 15) || (num > 31) || (reg2 > 15) || (m & SIXTEEN_BIT) || ((shift & 0x00001000) != 0)) {
5847 				return -1;
5848 			}
5849 
5850 			ao->o = 0x80f30000;
5851 			ao->o |= reg1;
5852 			ao->o |= (num & 0xf) << 8;
5853 			ao->o |= (num >> 4 ) << 12;
5854 			ao->o |= reg2 << 24;
5855 			ao->o |= (shift & 0x00002000) << 16;
5856 			ao->o |= (shift & 0x0000c070);
5857 			return 4;
5858 		        }
5859 			break;
5860 		default:
5861 			return -1;
5862 		}
5863 	} else
5864 	if ((m = opmask (ao->op, "usax", 0))) {
5865 		ut64 argt = thumb_selector (ao->a);
5866 		switch (argt) {
5867 		case THUMB_REG_REG: {
5868 			std_opt_2 (ao);
5869 		        }
5870 			// intentional fallthrough
5871 		case THUMB_REG_REG_REG: {
5872 			ao->o = 0xe0fa40f0;
5873 
5874 			return std_32bit_3reg (ao, m, false);
5875 		        }
5876 			break;
5877 		default:
5878 			return -1;
5879 		}
5880 	} else
5881 	if ((m = opmask (ao->op, "usub", EIGHT_BIT | SIXTEEN_BIT))) {
5882 		ut64 argt = thumb_selector (ao->a);
5883 		ut64 sufsel = m & (EIGHT_BIT | SIXTEEN_BIT);
5884 		switch (argt) {
5885 		case THUMB_REG_REG: {
5886 			std_opt_2 (ao);
5887 		        }
5888 			// intentional fallthrough
5889 		case THUMB_REG_REG_REG: {
5890 			if (sufsel == EIGHT_BIT) {
5891 				ao->o = 0xc0fa40f0;
5892 			} else
5893 			if (sufsel == SIXTEEN_BIT) {
5894 				ao->o = 0xd0fa40f0;
5895 			} else {
5896 				return -1;
5897 			}
5898 
5899 			return std_32bit_3reg (ao, m, false);
5900 		        }
5901 			break;
5902 		default:
5903 			return -1;
5904 		}
5905 	} else
5906 	if ((m = opmask (ao->op, "uxta", B_BIT | H_BIT | SIXTEEN_BIT))) {
5907 		ut64 argt = thumb_selector (ao->a);
5908 		ut64 sufsel = m & (B_BIT | H_BIT | SIXTEEN_BIT);
5909 		switch (argt) {
5910 		case THUMB_REG_REG: {
5911 			std_opt_2 (ao);
5912 		        }
5913 			// intentional fallthrough
5914 		case THUMB_REG_REG_REG: {
5915 			ao->a[3] = "lsl 0";
5916 		        }
5917 			// intentional fallthrough
5918 		case THUMB_REG_REG_SHIFT: {
5919 			if (ao->a[3] == NULL) { // double fallthrough
5920 				std_opt_3 (ao);
5921 			}
5922 		        }
5923 			// intentional fallthrough
5924 		case THUMB_REG_REG_REG_SHIFT: {
5925 			ut32 shift = thumb_getshift (ao->a[3]);
5926 
5927 			if (shift && ((shift & 0x0000f010) != 0x00003000)) {
5928 				return -1;
5929 			}
5930 
5931 			if (sufsel == B_BIT) {
5932 				ao->o = 0x50fa80f0;
5933 			} else
5934 			if (sufsel == (B_BIT | SIXTEEN_BIT)) {
5935 				ao->o = 0x30fa80f0;
5936 			} else
5937 			if (sufsel == H_BIT) {
5938 				ao->o = 0x10fa80f0;
5939 			} else {
5940 				return -1;
5941 			}
5942 
5943 			ao->o |= (shift & 0x00000060) << 7;
5944 			return (std_32bit_3reg (ao, m, false));
5945 		        }
5946 			break;
5947 		default:
5948 			return -1;
5949 		}
5950 	} else
5951 	if ((m = opmask (ao->op, "uxt", B_BIT | H_BIT | SIXTEEN_BIT))) {
5952 		ut64 argt = thumb_selector (ao->a);
5953 		ut64 sufsel = m & (B_BIT | H_BIT | SIXTEEN_BIT);
5954 		switch (argt) {
5955 		case THUMB_REG_REG: {
5956 			if ((sufsel == B_BIT) || (sufsel == H_BIT)) {
5957 				if (sufsel == B_BIT) {
5958 					ao->o = 0xc0b2;
5959 				} else {
5960 					ao->o = 0x80b2;
5961 				}
5962 				if (std_16bit_2reg (ao, m)) {
5963 					return 2;
5964 				}
5965 			}
5966 			ao->a[2] = "lsl 0";
5967 		        }
5968 			// intentional fallthrough
5969 		case THUMB_REG_REG_SHIFT: {
5970 			ut8 reg1 = getreg (ao->a[0]);
5971 			ut8 reg2 = getreg (ao->a[1]);
5972 			ut32 shift = thumb_getshift (ao->a[2]);
5973 
5974 			if ((reg1 > 15) || (reg2 > 15) || (shift && ((shift & 0x0000f010) != 0x00003000))) {
5975 				return -1;
5976 			}
5977 
5978 			if (sufsel == B_BIT) {
5979 				ao->o = 0x5ffa80f0;
5980 			} else
5981 			if (sufsel == (B_BIT | SIXTEEN_BIT)) {
5982 				ao->o = 0x3ffa80f0;
5983 			} else
5984 			if (sufsel == H_BIT) {
5985 				ao->o = 0x1ffa80f0;
5986 			} else {
5987 				return -1;
5988 			}
5989 
5990 			ao->o |= (shift & 0x00000060) << 7;
5991 			ao->o |= reg1;
5992 			ao->o |= reg2 << 8;
5993 			return 4;
5994 		        }
5995 			break;
5996 		default:
5997 			return -1;
5998 
5999 		}
6000 	} else
6001 	if ((m = opmask (ao->op, "wfe", 0))) {
6002 		ut64 argt = thumb_selector (ao->a);
6003 		switch (argt) {
6004 		case THUMB_NONE: {
6005 			if (m & DOTW_BIT) {
6006 				ao->o = 0xaff30280;
6007 				return 4;
6008 		        } else {
6009 				ao->o = 0x20bf;
6010 				return 2;
6011 		        }
6012 		        }
6013 			break;
6014 		default:
6015 			return -1;
6016 		}
6017 	} else
6018 	if ((m = opmask (ao->op, "wfi", 0))) {
6019 		ut64 argt = thumb_selector (ao->a);
6020 		switch (argt) {
6021 		case THUMB_NONE: {
6022 			if (m & DOTW_BIT) {
6023 				ao->o = 0xaff30380;
6024 				return 4;
6025 		        } else {
6026 				ao->o = 0x30bf;
6027 				return 2;
6028 		        }
6029 		        }
6030 			break;
6031 		default:
6032 			return -1;
6033 		}
6034 	} else
6035 	if ((m = opmask (ao->op, "yield", 0))) {
6036 		ut64 argt = thumb_selector (ao->a);
6037 		switch (argt) {
6038 		case THUMB_NONE: {
6039 			if (m & DOTW_BIT) {
6040 				ao->o = 0xaff30180;
6041 				return 4;
6042 		        } else {
6043 				ao->o = 0x10bf;
6044 				return 2;
6045 		        }
6046 		        }
6047 			break;
6048 		default:
6049 			return -1;
6050 		}
6051 	}
6052 	return 0;
6053 }
6054 
findyz(int x,int * y,int * z)6055 static int findyz(int x, int *y, int *z) {
6056 	int i, j;
6057 	for (i = 0;i < 0xff; i++) {
6058 		for (j = 0;j < 0xf;j++) {
6059 			int v = i << j;
6060 			if (v > x) {
6061 				continue;
6062 			}
6063 			if (v == x) {
6064 				*y = i;
6065 				*z = 16 - (j / 2);
6066 				return 1;
6067 			}
6068 		}
6069 	}
6070 	return 0;
6071 }
6072 
arm_assemble(ArmOpcode * ao,ut64 off,const char * str)6073 static int arm_assemble(ArmOpcode *ao, ut64 off, const char *str) {
6074 	int i, j, ret, reg, a, b;
6075 	int coproc, opc;
6076 	bool rex = false;
6077 	int shift, low, high;
6078 	for (i = 0; ops[i].name; i++) {
6079 		if (!strncmp (ao->op, ops[i].name, strlen (ops[i].name))) {
6080 			ao->o = ops[i].code;
6081 			arm_opcode_cond (ao, strlen(ops[i].name));
6082 			if (ao->a[0] || ops[i].type == TYPE_BKP) {
6083 				switch (ops[i].type) {
6084 				case TYPE_MEM:
6085 					if (!strncmp (ops[i].name, "strex", 5)) {
6086 						rex = 1;
6087 					}
6088 					if (!strcmp (ops[i].name, "str") || !strcmp (ops[i].name, "ldr")) {
6089 						if (!ao->a[2]) {
6090 							ao->a[2] = "0";
6091 						}
6092 					}
6093 					getrange (ao->a[0]);
6094 					getrange (ao->a[1]);
6095 					getrange (ao->a[2]);
6096 					if (ao->a[0] && ao->a[1]) {
6097 						char rn[8];
6098 						strncpy (rn, ao->a[1], 7);
6099 						int r0 = getreg (ao->a[0]);
6100 						int r1 = getreg (ao->a[1]);
6101 						if ((r0 < 0 || r0 > 15) || (r1 > 15 || r1 < 0)) {
6102 							return 0;
6103 						}
6104 						ao->o |= r0 << 20;
6105 						if (!strcmp (ops[i].name, "strd")) {
6106 							r1 = getreg (ao->a[2]);
6107 							if (r1 == -1) {
6108 								break;
6109 							}
6110 							ao->o |= r1 << 8;
6111 							if (ao->a[3]) {
6112 								char *bracket = strchr (ao->a[3], ']');
6113 								if (bracket) {
6114 									*bracket = '\0';
6115 								}
6116 								int num = getnum (ao->a[3]);
6117 								ao->o |= (num & 0x0f) << 24;
6118 								ao->o |= ((num >> 4) & 0x0f) << 16;
6119 							}
6120 							break;
6121 						}
6122 						if (!strcmp (ops[i].name, "strh")) {
6123 							ao->o |= r1 << 8;
6124 							if (ao->a[2]) {
6125 								reg = getreg (ao->a[2]);
6126 								if (reg != -1) {
6127 									ao->o |= reg << 24;
6128 								} else {
6129 									ao->o |= 1 << 14;
6130 									ao->o |= getnum (ao->a[2]) << 24;
6131 								}
6132 							} else {
6133 								ao->o |= 1 << 14;
6134 							}
6135 							break;
6136 						}
6137 						if (rex) {
6138 							ao->o |= r1 << 24;
6139 						} else {
6140 							ao->o |= r1 << 8; // delta
6141 						}
6142 					} else {
6143 						return 0;
6144 					}
6145 
6146 					ret = getreg (ao->a[2]);
6147 					if (ret != -1) {
6148 						if (rex) {
6149 							ao->o |= 1;
6150 							ao->o |= (ret & 0x0f) << 8;
6151 						} else {
6152 							ao->o |= (strstr (str, "],")) ? 6 : 7;
6153 							ao->o |= (ret & 0x0f) << 24;
6154 						}
6155 						if (ao->a[3]) {
6156 							shift = getshift (ao->a[3]);
6157 							low = shift & 0xFF;
6158 							high = shift & 0xFF00;
6159 							ao->o |= low << 24;
6160 							ao->o |= high << 8;
6161 						}
6162 					} else {
6163 						int num = getnum (ao->a[2]) & 0xfff;
6164 						if (err) {
6165 							break;
6166 						}
6167 						if (rex) {
6168 							ao->o |= 1;
6169 						} else {
6170 							ao->o |= (strstr (str, "],")) ? 4 : 5;
6171 						}
6172 						ao->o |= 1;
6173 						ao->o |= (num & 0xff) << 24;
6174 						ao->o |= ((num >> 8) & 0xf) << 16;
6175 					}
6176 
6177 					break;
6178 				case TYPE_IMM:
6179 					if (*ao->a[0]++ == '{') {
6180 						for (j = 0; j < 16; j++) {
6181 							if (ao->a[j] && *ao->a[j]) {
6182 								getrange (ao->a[j]); // XXX filter regname string
6183 								reg = getreg (ao->a[j]);
6184 								if (reg != -1) {
6185 									if (reg < 8) {
6186 										ao->o |= 1 << (24 + reg);
6187 									} else {
6188 										ao->o |= 1 << (8 + reg);
6189 									}
6190 								}
6191 							}
6192 						}
6193 					} else {
6194 						ao->o |= getnum (ao->a[0]) << 24; // ???
6195 					}
6196 					break;
6197 				case TYPE_BRA:
6198 					if ((ret = getreg (ao->a[0])) == -1) {
6199 						// TODO: control if branch out of range
6200 						ret = (getnum (ao->a[0]) - (int)ao->off - 8) / 4;
6201 						if (ret >= 0x00800000 || ret < (int)0xff800000) {
6202 							eprintf ("Branch into out of range\n");
6203 							return 0;
6204 						}
6205 						ao->o |= ((ret >> 16) & 0xff) << 8;
6206 						ao->o |= ((ret >> 8) & 0xff) << 16;
6207 						ao->o |= ((ret)&0xff) << 24;
6208 					} else {
6209 						eprintf ("This branch does not accept reg as arg\n");
6210 						return 0;
6211 					}
6212 					break;
6213 				case TYPE_BKP:
6214 					ao->o |= 0x70 << 24;
6215 					if (ao->a[0]) {
6216 						int n = getnum (ao->a[0]);
6217 						ao->o |= ((n & 0xf) << 24);
6218 						ao->o |= (((n >> 4) & 0xff) << 16);
6219 					}
6220 					break;
6221 				case TYPE_BRR:
6222 					if ((ret = getreg (ao->a[0])) == -1) {
6223 						ut32 dst = getnum (ao->a[0]);
6224 						dst -= (ao->off + 8);
6225 						if (dst & 0x2) {
6226 							ao->o = 0xfb;
6227 						} else {
6228 							ao->o = 0xfa;
6229 						}
6230 						dst /= 4;
6231 						ao->o |= ((dst >> 16) & 0xff) << 8;
6232 						ao->o |= ((dst >> 8) & 0xff) << 16;
6233 						ao->o |= ((dst)&0xff) << 24;
6234 						return 4;
6235 					} else {
6236 						ao->o |= (getreg (ao->a[0]) << 24);
6237 					}
6238 					break;
6239 				case TYPE_HLT: {
6240 					ut32 o = 0, n = getnum (ao->a[0]);
6241 					o |= ((n >> 12) & 0xf) << 8;
6242 					o |= ((n >> 8) & 0xf) << 20;
6243 					o |= ((n >> 4) & 0xf) << 16;
6244 					o |= ((n) & 0xf) << 24;
6245 					ao->o |=o;
6246 				}
6247 				break;
6248 			case TYPE_SWI:
6249 				ao->o |= (getnum (ao->a[0]) & 0xff) << 24;
6250 				ao->o |= ((getnum (ao->a[0]) >> 8) & 0xff) << 16;
6251 				ao->o |= ((getnum (ao->a[0]) >> 16) & 0xff) << 8;
6252 				break;
6253 			case TYPE_UDF:
6254 				{
6255 					// e7f000f0 = udf 0
6256 					// e7ffffff = udf 0xffff
6257 					ut32 n = getnum (ao->a[0]);
6258 					ao->o |= 0xe7;
6259 					ao->o |= (n & 0xf) << 24;
6260 					ao->o |= ((n >> 4) & 0xff) << 16;
6261 					ao->o |= ((n >> 12) & 0xf) << 8;
6262 				}
6263 				break;
6264 			case TYPE_ARI:
6265 				if (!ao->a[2]) {
6266 					ao->a[2] = ao->a[1];
6267 					ao->a[1] = ao->a[0];
6268 				}
6269 				reg = getreg (ao->a[0]);
6270 				if (reg == -1) {
6271 					return 0;
6272 				}
6273 				ao->o |= reg << 20;
6274 
6275 				reg = getreg (ao->a[1]);
6276 				if (reg == -1) {
6277 					return 0;
6278 				}
6279 				ao->o |= reg << 8;
6280 				reg = getreg (ao->a[2]);
6281 				if (reg == -1) {
6282 					int imm = getnum(ao->a[2]);
6283 					if (imm && !(imm & (imm - 1)) && imm > 255) {
6284 						int r;
6285 						for (r = 0; r != 32; r += 2) {
6286 							if (!(imm & ~0xff)) {
6287 								ao->o |= (r << 15) | (imm << 24) | 2;
6288 								break;
6289 							}
6290 							imm = (imm << 2) | (imm >> 30);
6291 						}
6292 					} else {
6293 						ao->o |= (imm << 24) | 2;
6294 					}
6295 				} else {
6296 					ao->o |= reg << 24;
6297 				}
6298 				if (ao->a[3]) {
6299 					ao->o |= getshift(ao->a[3]);
6300 				}
6301 				break;
6302 			case TYPE_SWP:
6303 				{
6304 				int a1 = getreg (ao->a[1]);
6305 				if (a1) {
6306 					ao->o = 0xe1;
6307 					ao->o |= (getreg (ao->a[0]) << 4) << 16;
6308 					ao->o |= (0x90 + a1) << 24;
6309 					if (ao->a[2]) {
6310 						ao->o |= (getreg (ao->a[2] + 1)) << 8;
6311 					} else {
6312 						return 0;
6313 					}
6314 				}
6315 				if (0xff == ((ao->o >> 16) & 0xff)) {
6316 					return 0;
6317 				}
6318 				}
6319 				break;
6320 			case TYPE_MOV:
6321 				if (!strcmpnull (ao->op, "movs")) {
6322 					ao->o = 0xb0e1;
6323 				}
6324 				ao->o |= getreg (ao->a[0]) << 20;
6325 				ret = getreg (ao->a[1]);
6326 				if (ret != -1) {
6327 					ao->o |= ret << 24;
6328 				} else {
6329 					int immed = getimmed8 (ao->a[1]);
6330 					if (err) {
6331 						return 0;
6332 					}
6333 					ao->o |= 0xa003 | (immed & 0xff) << 24 | (immed >> 8) << 16;
6334 				}
6335 				break;
6336 			case TYPE_MOVW:
6337 				reg = getreg (ao->a[0]);
6338 				if (reg == -1) {
6339 					return 0;
6340 				}
6341 				ao->o |= getreg (ao->a[0]) << 20;
6342 				ret = getnum (ao->a[1]);
6343 
6344 				ao->o |= 0x3 | ret << 24;
6345 				ao->o |= (ret & 0xf000) >> 4;
6346 				ao->o |= (ret & 0xf00) << 8;
6347 				break;
6348 			case TYPE_MOVT:
6349 				ao->o |= getreg (ao->a[0]) << 20;
6350 				ret = getnum (ao->a[1]);
6351 
6352 				ao->o |= 0x4003 | ret << 24;
6353 				ao->o |= (ret & 0xf000) >> 4;
6354 				ao->o |= (ret & 0xf00) << 8;
6355 				break;
6356 			case TYPE_MUL:
6357 				if (!strcmpnull (ao->op, "mul")) {
6358 					ret = getreg (ao->a[0]);
6359 					a = getreg (ao->a[1]);
6360 					b = getreg (ao->a[2]);
6361 					if (b == -1) {
6362 						b = a;
6363 						a = ret;
6364 					}
6365 					if (ret == -1 || a == -1) {
6366 						return 0;
6367 					}
6368 					ao->o |= ret << 8;
6369 					ao->o |= a << 24;
6370 					ao->o |= b << 16;
6371 				} else {
6372 					low = getreg (ao->a[0]);
6373 					high = getreg (ao->a[1]);
6374 					a = getreg (ao->a[2]);
6375 					b = getreg (ao->a[3]);
6376 					if (low == -1 || high == -1 || a == -1 || b == -1) {
6377 						return 0;
6378 					}
6379 					if (!strcmpnull (ao->op, "smlal")) {
6380 						ao->o |= low << 20;
6381 						ao->o |= high << 8;
6382 						ao->o |= a << 24;
6383 						ao->o |= b << 16;
6384 					} else if (!strncmp (ao->op, "smla", 4)) {
6385 						if (low > 14 || high > 14 || a > 14) {
6386 							return 0;
6387 						}
6388 						ao->o |= low << 8;
6389 						ao->o |= high << 24;
6390 						ao->o |= a << 16;
6391 						ao->o |= b << 20;
6392 						break;
6393 					} else {
6394 						ao->o |= low << 20;
6395 						ao->o |= high << 8;
6396 						ao->o |= a << 24;
6397 						ao->o |= b << 16;
6398 					}
6399 				}
6400 				break;
6401 			case TYPE_TST:
6402 				a = getreg (ao->a[0]);
6403 				b = getreg (ao->a[1]);
6404 				if (b == -1) {
6405 					int y, z;
6406 					b = getnum (ao->a[1]);
6407 					if (b >= 0 && b <= 0xff) {
6408 						ao->o = 0x50e3;
6409 						// TODO: if (b>255) -> automatic multiplier
6410 						ao->o |= (a << 8);
6411 						ao->o |= ((b & 0xff) << 24);
6412 					} else
6413 					if (findyz (b, &y, &z)) {
6414 						ao->o = 0x50e3;
6415 						ao->o |= (y << 24);
6416 						ao->o |= (z << 16);
6417 					} else {
6418 						eprintf ("Parameter %d out0x3000a0e1 of range (0-255)\n", (int)b);
6419 						return 0;
6420 					}
6421 				} else {
6422 					ao->o |= (a << 8);
6423 					ao->o |= (b << 24);
6424 					if (ao->a[2]) {
6425 						ao->o |= getshift (ao->a[2]);
6426 					}
6427 				}
6428 				if (ao->a[2]) {
6429 					int n = getnum (ao->a[2]);
6430 					if (n & 1) {
6431 						eprintf ("Invalid multiplier\n");
6432 						return 0;
6433 					}
6434 					ao->o |= (n >> 1) << 16;
6435 				}
6436 				break;
6437 			case TYPE_SHFT:
6438 				reg = getreg (ao->a[2]);
6439 				if (reg == -1 || reg > 14) {
6440 					return 0;
6441 				}
6442 				ao->o |= reg << 16;
6443 
6444 				reg = getreg (ao->a[0]);
6445 				if (reg == -1 || reg > 14) {
6446 					return 0;
6447 				}
6448 				ao->o |= reg << 20;
6449 
6450 				reg = getreg (ao->a[1]);
6451 				if (reg == -1 || reg > 14) {
6452 					return 0;
6453 				}
6454 				ao->o |= reg << 24;
6455 				break;
6456 			case TYPE_REV:
6457 				reg = getreg (ao->a[0]);
6458 				if (reg == -1 || reg > 14) {
6459 					return 0;
6460 				}
6461 				ao->o |= reg << 20;
6462 
6463 				reg = getreg (ao->a[1]);
6464 				if (reg == -1 || reg > 14) {
6465 					return 0;
6466 				}
6467 				ao->o |= reg << 24;
6468 
6469 				break;
6470 			case TYPE_ENDIAN:
6471 				if (!strcmp (ao->a[0], "le")) {
6472 					ao->o |= 0;
6473 				} else if (!strcmp (ao->a[0], "be")) {
6474 					ao->o |= 0x20000;
6475 				} else {
6476 					return 0;
6477 				}
6478 				break;
6479 			case TYPE_COPROC:
6480 				//printf ("%s %s %s %s %s\n", ao->a[0], ao->a[1], ao->a[2], ao->a[3], ao->a[4] );
6481 				if (ao->a[0]) {
6482 					coproc = getnum (ao->a[0] + 1);
6483 					if (coproc == -1 || coproc > 9) {
6484 						return 0;
6485 					}
6486 					ao->o |= coproc << 16;
6487 				}
6488 
6489 				opc = getnum (ao->a[1]);
6490 				if (opc == -1 || opc > 7) {
6491 					return 0;
6492 				}
6493 				ao->o |= opc << 13;
6494 
6495 				reg = getreg (ao->a[2]);
6496 				if (reg == -1 || reg > 14) {
6497 					return 0;
6498 				}
6499 				ao->o |= reg << 20;
6500 
6501 				// coproc register 1
6502 				const char *a3 = ao->a[3];
6503 				if (a3) {
6504 					coproc = getnum (a3 + 1);
6505 					if (coproc == -1 || coproc > 15) {
6506 						return 0;
6507 					}
6508 					ao->o |= coproc << 8;
6509 				}
6510 
6511 				const char *a4 = ao->a[4];
6512 				if (a4) {
6513 					coproc = getnum (ao->a[4] + 1);
6514 					if (coproc == -1 || coproc > 15) {
6515 						return 0;
6516 					}
6517 					ao->o |= coproc << 24;
6518 				}
6519 
6520 				coproc = getnum (ao->a[5]);
6521 				if (coproc > -1) {
6522 					if (coproc > 7) {
6523 						return 0;
6524 					}
6525 					// optional opcode
6526 					ao->o |= coproc << 29;
6527 				}
6528 
6529 				break;
6530 			case TYPE_CLZ:
6531 				ao->o |= 1 << 28;
6532 
6533 				reg = getreg (ao->a[0]);
6534 				if (reg == -1 || reg > 14) {
6535 					return 0;
6536 				}
6537 				ao->o |= reg << 20;
6538 
6539 				reg = getreg (ao->a[1]);
6540 				if (reg == -1 || reg > 14) {
6541 					return 0;
6542 				}
6543 				ao->o |= reg << 24;
6544 
6545 				break;
6546 			case TYPE_NEG:
6547 				if (!ao->a[0] || !ao->a[1]) {
6548 					return 0;
6549 				}
6550 				ao->a[2] = "0";
6551 				int len = strlen (ao->a[1]) + 1;
6552 				memmove (ao->a[0] + 1, ao->a[0], ao->a[1] - ao->a[0] + len);
6553 				ao->a[0]++;
6554 				ao->a[1]++;
6555 				strncpy (ao->op, "rsbs", 5);
6556 				arm_assemble (ao, off, str); // rsbs reg0, reg1, #0
6557 				break;
6558 			}
6559 			}
6560 			return 1;
6561 		}
6562 	}
6563 	return 0;
6564 }
6565 
6566 typedef int (*AssembleFunction)(ArmOpcode *, ut64, const char *);
6567 static AssembleFunction assemble[2] = { &arm_assemble, &thumb_assemble };
6568 
armass_assemble(const char * str,ut64 off,int thumb)6569 ut32 armass_assemble(const char *str, ut64 off, int thumb) {
6570 	int i, j;
6571 	char buf[128];
6572 	ArmOpcode aop = {.off = off};
6573 	for (i = j = 0; i < sizeof (buf) - 1 && str[j]; i++, j++) {
6574 		if (str[j] == '#') {
6575 			i--; continue;
6576 		}
6577 		buf[i] = tolower ((const ut8)str[j]);
6578 	}
6579 	buf[i] = 0;
6580 	arm_opcode_parse (&aop, buf);
6581 	aop.off = off;
6582 	if (thumb < 0 || thumb > 1) {
6583 		return -1;
6584 	}
6585 	if (assemble[thumb] (&aop, off, buf) <= 0) {
6586 		//eprintf ("armass: Unknown opcode (%s)\n", buf);
6587 		return -1;
6588 	}
6589 	return aop.o;
6590 }
6591 
6592 #ifdef MAIN
thisplay(const char * str)6593 void thisplay(const char *str) {
6594 	char cmd[32];
6595 	int op = armass_assemble (str, 0x1000, 1);
6596 	printf ("[%04x] %s\n", op, str);
6597 	snprintf (cmd, sizeof(cmd), "rasm2 -d -b 16 -a arm %04x", op);
6598 	system (cmd);
6599 }
6600 
display(const char * str)6601 void display(const char *str) {
6602 	char cmd[32];
6603 	int op = armass_assemble (str, 0x1000, 0);
6604 	printf ("[%08x] %s\n", op, str);
6605 	snprintf (cmd, sizeof(cmd), "rasm2 -d -a arm %08x", op);
6606 	system (cmd);
6607 }
6608 
main()6609 int main() {
6610 	thisplay ("ldmia r1!, {r3, r4, r5}");
6611 	thisplay ("stmia r1!, {r3, r4, r5}");
6612 	thisplay ("bkpt 12");
6613 return 0;
6614 	thisplay("sub r1, r2, 0");
6615 	thisplay("sub r1, r2, 4");
6616 	thisplay("sub r1, r2, 5");
6617 	thisplay("sub r1, r2, 7");
6618 	thisplay("sub r3, 44");
6619 return 0;
6620 #if 0
6621 	thisplay("mov r0, 11");
6622 	thisplay("mov r0, r2");
6623 	thisplay("mov r1, r4");
6624 	thisplay("cmp r1, r2");
6625 	thisplay("cmp r3, 44");
6626 	thisplay("nop");
6627 	thisplay("svc 15");
6628 	thisplay("add r1, r2");
6629 	thisplay("add r3, 44");
6630 	thisplay("sub r1, r2, 3");
6631 	thisplay("sub r3, 44");
6632 	thisplay("tst r3,r4");
6633 	thisplay("bx r3");
6634 	thisplay("b 33");
6635 	thisplay("b 0");
6636 	thisplay("bne 44");
6637 	thisplay("and r2,r3");
6638 #endif
6639 	// INVALID thisplay("ldr r1, [pc, r2]");
6640 	// INVALID thisplay("ldr r1, [sp, r2]");
6641 #if 0
6642 	thisplay("ldr r1, [pc, 12]");
6643 	thisplay("ldr r1, [sp, 24]");
6644 	thisplay("ldr r1, [r2, r3]");
6645 #endif
6646 	// INVALID thisplay("str r1, [pc, 22]");
6647 	// INVALID thisplay("str r1, [pc, r2]");
6648 	// INVALID thisplay("str r1, [sp, r2]");
6649 #if 0
6650    0:   8991            ldrh    r1, [r2, #12]
6651    2:   7b11            ldrb    r1, [r2, #12]
6652    4:   8191            strh    r1, [r2, #12]
6653    6:   7311            strb    r1, [r2, #12]
6654 #endif
6655 	thisplay("ldrh r1, [r2, 8]"); // aligned to 4
6656 	thisplay("ldrh r1, [r3, 8]"); // aligned to 4
6657 	thisplay("ldrh r1, [r4, 16]"); // aligned to 4
6658 	thisplay("ldrh r1, [r2, 32]"); // aligned to 4
6659 	thisplay("ldrb r1, [r2, 20]"); // aligned to 4
6660 	thisplay("strh r1, [r2, 20]"); // aligned to 4
6661 	thisplay("strb r1, [r2, 20]"); // aligned to 4
6662 	thisplay("str r1, [sp, 20]"); // aligned to 4
6663 	thisplay("str r1, [r2, 12]"); // OK
6664 	thisplay("str r1, [r2, r3]");
6665 return 0;
6666 #if 0
6667 	display("mov r0, 33");
6668 	display("mov r1, 33");
6669 	display("movne r0, 33");
6670 	display("tst r0, r1, lsl #2");
6671 	display("svc 0x80");
6672 	display("sub r3, r1, r2");
6673 	display("add r0, r1, r2");
6674 	display("mov fp, 0");
6675 	display("pop {pc}");
6676 	display("pop {r3}");
6677 	display("bx r1");
6678 	display("bx r3");
6679 	display("bx pc");
6680 	display("blx fp");
6681 	display("pop {pc}");
6682 	display("add lr, pc, lr");
6683 	display("adds r3, #8");
6684 	display("adds r3, r2, #8");
6685 	display("subs r2, #1");
6686 	display("cmp r0, r4");
6687 	display("cmp r7, pc");
6688 	display("cmp r1, r3");
6689 	display("mov pc, 44");
6690 	display("mov pc, r3");
6691 	display("push {pc}");
6692 	display("pop {pc}");
6693 	display("nop");
6694 	display("ldr r1, [r2, 33]");
6695 	display("ldr r1, [r2, r3]");
6696 	display("ldr r3, [r4, r6]");
6697 	display("str r1, [pc, 33]");
6698 	display("str r1, [pc], 2");
6699 	display("str r1, [pc, 3]");
6700 	display("str r1, [pc, r4]");
6701 	display("bx r3");
6702 	display("bcc 33");
6703 	display("blx r3");
6704 	display("bne 0x1200");
6705 	display("str r0, [r1]");
6706 	display("push {fp,lr}");
6707 	display("pop {fp,lr}");
6708 	display("pop {pc}");
6709 #endif
6710 
6711    //10ab4:       00047e30        andeq   r7, r4, r0, lsr lr
6712    //10ab8:       00036e70        andeq   r6, r3, r0, ror lr
6713 
6714 	display("andeq r7, r4, r0, lsr lr");
6715 	display("andeq r6, r3, r0, ror lr");
6716 //  c4:   e8bd80f0        pop     {r4, r5, r6, r7, pc}
6717 	display("pop {r4,r5,r6,r7,pc}");
6718 
6719 
6720 #if 0
6721 	display("blx r1");
6722 	display("blx 0x8048");
6723 #endif
6724 
6725 #if 0
6726 	display("b 0x123");
6727 	display("bl 0x123");
6728 	display("blt 0x123"); // XXX: not supported
6729 #endif
6730 	return 0;
6731 }
6732 #endif
6733