Rizin
unix-like reverse engineering framework and cli tools
assembler.c
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: 2021 deroad <wargio@libero.it>
2 // SPDX-License-Identifier: LGPL-3.0-only
3 
4 #include "assembler.h"
5 #include "common.h"
6 
7 #define MAX_TOKENS 6
8 #define IS_INDIRECT_ADDRESS_REGISTER(x) ((x)=='x'||(x)=='y'||(x)=='z')
9 
10 #define throw_error(msg, ...) \
11  do { \
12  RZ_LOG_ERROR("[!] avr_assembler: " msg, ##__VA_ARGS__); \
13  return AVR_INVALID_SIZE; \
14  } while (0)
15 
16 #define return_error_if_empty_input(a, b) \
17  do { \
18  if (RZ_STR_ISEMPTY(a) || b < 1) { \
19  RZ_LOG_ERROR("[!] avr_assembler: the input is empty.\n"); \
20  return AVR_INVALID_SIZE; \
21  } \
22  } while (0)
23 
24 #define expected_const_or_error(a,exp) \
25  do { \
26  if (RZ_STR_ISEMPTY((a)) || strcmp((a),(exp))) { \
27  RZ_LOG_ERROR("[!] avr_assembler: expected '%s' but got '%s'.\n", (exp), (a)); \
28  return AVR_INVALID_SIZE; \
29  } \
30  } while (0)
31 
32 #define parse_register_or_error_limit(rn,rs,min,max) \
33  do { \
34  cchar *tmp = (rs); \
35  if (*tmp == 'r') { \
36  tmp++; \
37  } \
38  if (RZ_STR_ISEMPTY(tmp)) { \
39  RZ_LOG_ERROR("[!] avr_assembler: invalid register '%s'.\n", (rs)); \
40  return AVR_INVALID_SIZE; \
41  } \
42  (rn) = strtoll(tmp, NULL, 0); \
43  if ((rn) < (min) || (rn) > (max)) { \
44  RZ_LOG_ERROR("[!] avr_assembler: expected register %u <= reg <= 31 (parsed %u).\n", (min), (rn)); \
45  return AVR_INVALID_SIZE; \
46  } \
47  } while (0)
48 
49 #define parse_register_or_error(rn,rs) \
50  do { \
51  cchar *tmp = (rs); \
52  if (*tmp == 'r') { \
53  tmp++; \
54  } \
55  if (RZ_STR_ISEMPTY(tmp)) { \
56  RZ_LOG_ERROR("[!] avr_assembler: invalid register '%s'.\n", (rs)); \
57  return AVR_INVALID_SIZE; \
58  } \
59  (rn) = strtoll(tmp, NULL, 0); \
60  if ((rn) > 31) { \
61  RZ_LOG_ERROR("[!] avr_assembler: expected register 0 <= reg <= 31 (parsed %u).\n", (rn)); \
62  return AVR_INVALID_SIZE; \
63  } \
64  } while (0)
65 
67 #define parse_register_pair_or_error(rn,rs) \
68  do { \
69  cchar *tmp = (rs); \
70  if (*tmp == 'r') { \
71  tmp++; \
72  } \
73  if (RZ_STR_ISEMPTY(tmp)) { \
74  RZ_LOG_ERROR("[!] avr_assembler: invalid register '%s'.\n", (rs)); \
75  return AVR_INVALID_SIZE; \
76  } \
77  (rn) = strtoll(tmp, (char **)&tmp, 0); \
78  if ((rn) > 31) { \
79  RZ_LOG_ERROR("[!] avr_assembler: expected register 0 <= reg <= 31 (parsed %u).\n", (rn)); \
80  return AVR_INVALID_SIZE; \
81  } \
82  if (*tmp == ':') { \
83  tmp++; \
84  ut16 high = (rn); \
85  if (*tmp == 'r') { \
86  tmp++; \
87  } \
88  (rn) = strtoll(tmp, NULL, 0); \
89  if ((rn) > 31) { \
90  RZ_LOG_ERROR("[!] avr_assembler: expected register 0 <= reg <= 31 (parsed %u).\n", (rn)); \
91  return AVR_INVALID_SIZE; \
92  } \
93  if (high != (rn) + 1) { \
94  RZ_LOG_ERROR("[!] avr_assembler: register pair r%u:r%u invalid: %u != %u + 1.\n", \
95  (unsigned int)high, (unsigned int)(rn), (unsigned int)high, (unsigned int)(rn)); \
96  return AVR_INVALID_SIZE; \
97  } \
98  } \
99  } while (0)
100 
101 #define parse_unsigned_or_error(rn,rs,limit) \
102  do { \
103  cchar *tmp = (rs); \
104  ut32 base = 0; \
105  if (tmp[0] == '$') { \
106  tmp++; \
107  base = 16; \
108  } \
109  if (RZ_STR_ISEMPTY(tmp)) { \
110  RZ_LOG_ERROR("[!] avr_assembler: invalid unsigned number '%s'.\n", (rs)); \
111  return AVR_INVALID_SIZE; \
112  } \
113  (rn) = strtoull(tmp, NULL, base); \
114  if ((rn) > (limit)) { \
115  RZ_LOG_ERROR("[!] avr_assembler: unsigned number '%s' >= %u.\n", (rs), limit); \
116  return AVR_INVALID_SIZE; \
117  } \
118  } while (0)
119 
120 #define parse_address_or_error(rn,rs,pc,llow,lhigh) \
121  do { \
122  cchar *tmp = (rs); \
123  if (RZ_STR_ISEMPTY(tmp)) { \
124  RZ_LOG_ERROR("[!] avr_assembler: invalid address '%s'.\n", (rs)); \
125  return AVR_INVALID_SIZE; \
126  } \
127  if (tmp[0] == '.') { \
128  (rn) = (st64)strtoull(tmp + 1, NULL, 0); \
129  } else { \
130  st64 abs = strtoull(tmp, NULL, 0); \
131  (rn) = abs - pc; \
132  } \
133  if ((rn) < 0) { \
134  (rn) = ~(-((rn) - 1)); \
135  } else { \
136  (rn) -= 2; \
137  } \
138  (rn) /= 2; \
139  if (((rn) < (llow) || (rn) > (lhigh))) { \
140  RZ_LOG_ERROR("[!] avr_assembler: invalid address -64 <= addr <= 63 (parsed %d).\n", (rn)); \
141  return AVR_INVALID_SIZE; \
142  } \
143  } while (0)
144 
145 #define parse_signed_or_error(rn,rs,min,max) \
146  do { \
147  cchar *tmp = (rs); \
148  if (RZ_STR_ISEMPTY(tmp)) { \
149  RZ_LOG_ERROR("[!] avr_assembler: invalid unsigned number '%s'.\n", (rs)); \
150  return AVR_INVALID_SIZE; \
151  } \
152  (rn) = atoi(tmp); \
153  if ((rn) < (min)) { \
154  RZ_LOG_ERROR("[!] avr_assembler: signed number '%s' < %u.\n", (rs), min); \
155  return AVR_INVALID_SIZE; \
156  } \
157  if ((rn) > (max)) { \
158  RZ_LOG_ERROR("[!] avr_assembler: signed number '%s' > %u.\n", (rs), max); \
159  return AVR_INVALID_SIZE; \
160  } \
161  } while (0)
162 
163 #define auto_write16(buf,val,be) \
164  do { \
165  if (be) { \
166  rz_write_be16(buf, val); \
167  } else { \
168  rz_write_le16(buf, val); \
169  } \
170  } while (0)
171 
172 typedef ut32 (*Encode)(ut16 cbins, cchar** tokens, ut32 ntokens, ut8 *data, ut64 pc, bool be);
173 
174 typedef struct avr_decoder_t {
175  cchar* opcode; /* instruction name */
176  ut16 cbits; /* constant bits */
177  ut32 mintoks; /* required min token number */
178  ut32 maxtoks; /* required max token number */
181 
182 
183 static ut32 avr_unique(ut16 cbins, cchar** tokens, ut32 ntokens, ut8 *data, ut64 pc, bool be) {
184  auto_write16(data, cbins, be);
185  return 2;
186 }
187 
188 
189 static ut32 avr_rdddddrrrr(ut16 cbins, cchar** tokens, ut32 ntokens, ut8 *data, ut64 pc, bool be) {
190  /* <opcode> Rd,Rr | 0 <= d <= 31 | 0 <= r <= 31 */
191  ut16 Rd, Rr;
192  parse_register_or_error(Rd, tokens[1]);
193  parse_register_or_error(Rr, tokens[2]);
194 
195 
196  cbins |= (Rr & 0x000F);
197  cbins |= ((Rr << 5) & 0x0200);
198  cbins |= ((Rd << 4) & 0x01F0);
199 
200  auto_write16(data, cbins, be);
201  return 2;
202 }
203 
204 
205 static ut32 avr_KKddKKKK(ut16 cbins, cchar** tokens, ut32 ntokens, ut8 *data, ut64 pc, bool be) {
206  /* <opcode> Rd, K | d = {24,26,28,30}, 0 <= K <= 63 */
207  ut16 Rd, K;
208  parse_register_pair_or_error(Rd, tokens[1]);
209  parse_unsigned_or_error(K, tokens[2], 63);
210 
211  if (Rd < 24 || Rd & 1) {
212  throw_error("register must be Rd = {24,26,28,30} (parsed r%u)\n", Rd);
213  }
214 
215  Rd -= 24;
216  Rd >>= 1;
217 
218  cbins |= (K & 0x000F);
219  cbins |= ((K << 2) & 0x00C0);
220  cbins |= ((Rd << 4) & 0x0030);
221 
222  auto_write16(data, cbins, be);
223  return 2;
224 }
225 
226 
227 static ut32 avr_KKKKddddKKKK(ut16 cbins, cchar** tokens, ut32 ntokens, ut8 *data, ut64 pc, bool be) {
228  /* <opcode> Rd, K | 16 <= d <= 31, 0 <= K <= 255 */
229  ut16 Rd, K;
230  parse_register_or_error_limit(Rd, tokens[1], 16, 31);
231  parse_unsigned_or_error(K, tokens[2], 255);
232 
233  Rd -= 16;
234 
235  cbins |= (K & 0x000F);
236  cbins |= ((K << 4) & 0x0F00);
237  cbins |= ((Rd << 4) & 0x00F0);
238 
239  auto_write16(data, cbins, be);
240  return 2;
241 }
242 
243 
244 static ut32 avr_cbr(ut16 cbins, cchar** tokens, ut32 ntokens, ut8 *data, ut64 pc, bool be) {
245  /* <opcode> Rd, K | 16 <= d <= 31, 0 <= K <= 255 */
246  ut16 Rd, K;
247  parse_register_or_error_limit(Rd, tokens[1], 16, 31);
248  parse_unsigned_or_error(K, tokens[2], 255);
249 
250  Rd -= 16;
251  K = 0xFF - K;
252 
253  cbins |= (K & 0x000F);
254  cbins |= ((K << 4) & 0x0F00);
255  cbins |= ((Rd << 4) & 0x00F0);
256 
257  auto_write16(data, cbins, be);
258  return 2;
259 }
260 
261 
262 static ut32 avr_dddddcccc(ut16 cbins, cchar** tokens, ut32 ntokens, ut8 *data, ut64 pc, bool be) {
263  /* <opcode> Rd | 0 <= d <= 31 */
264  ut16 Rd;
265  parse_register_or_error(Rd, tokens[1]);
266  cbins |= ((Rd << 4) & 0x01F0);
267 
268  auto_write16(data, cbins, be);
269  return 2;
270 }
271 
272 
273 static ut32 avr_dddddcbbb(ut16 cbins, cchar** tokens, ut32 ntokens, ut8 *data, ut64 pc, bool be) {
274  /* <opcode> Rd, b | 0 <= d <= 31, 0 <= b <= 7 */
275 
276  ut16 Rd, b;
277  parse_register_or_error(Rd, tokens[1]);
278  parse_unsigned_or_error(b, tokens[2], 7);
279 
280  cbins |= (b & 0x0007);
281  cbins |= ((Rd << 4) & 0x01F0);
282 
283  auto_write16(data, cbins, be);
284  return 2;
285 }
286 
287 
288 static ut32 avr_kkkkkkkccc(ut16 cbins, cchar** tokens, ut32 ntokens, ut8 *data, ut64 pc, bool be) {
289  /* <opcode> k | -64 <= k <= 63 */
290  st16 k;
291  parse_address_or_error(k, tokens[1], pc, -64, 63);
292  cbins |= ((k << 3) & 0x03F8);
293  auto_write16(data, cbins, be);
294  return 2;
295 }
296 
297 
298 static ut32 avr_kkkkkccck(ut16 cbins, cchar** tokens, ut32 ntokens, ut8 *data, ut64 pc, bool be) {
299  // <opcode> k | 0 <= k < 0x7ffffe
300  ut32 k;
301  parse_unsigned_or_error(k, tokens[1], 0x7ffffe);
302 
303  k /= 2;
304 
305  ut16 kh = k >> 16;
306  ut16 kl = k & 0xFFFF;
307 
308  cbins |= (kh & 0x0001);
309  cbins |= ((kh << 3) & 0x01F0);
310 
311  auto_write16(data, cbins, be);
312  auto_write16(data + 2, kl, be);
313  return 4;
314 }
315 
316 
317 static ut32 avr_AAAAAbbb(ut16 cbins, cchar** tokens, ut32 ntokens, ut8 *data, ut64 pc, bool be) {
318  // CBI A,b | 0 <= A <= 31 | 0 <= b <= 7
319  ut16 A, b;
320  parse_unsigned_or_error(A, tokens[1], 31);
321  parse_unsigned_or_error(b, tokens[2], 7);
322 
323 
324  cbins |= (b & 0x0007);
325  cbins |= ((A << 3) & 0x00F8);
326 
327  auto_write16(data, cbins, be);
328  return 2;
329 }
330 
331 
332 static ut32 avr_dddddddddd(ut16 cbins, cchar** tokens, ut32 ntokens, ut8 *data, ut64 pc, bool be) {
333  /* <opcode> Rd | 0 <= d <= 31 */
334  ut16 Rd;
335  parse_register_or_error(Rd, tokens[1]);
336 
337  cbins |= (Rd & 0x000F);
338  cbins |= ((Rd << 5) & 0x0200);
339  cbins |= ((Rd << 4) & 0x01F0);
340 
341  auto_write16(data, cbins, be);
342  return 2;
343 }
344 
345 
346 static ut32 avr_KKKKcccc(ut16 cbins, cchar** tokens, ut32 ntokens, ut8 *data, ut64 pc, bool be) {
347  /* <opcode> K | 0 <= K <= 0xF */
348  ut16 K;
349  parse_unsigned_or_error(K, tokens[1], 0xF);
350 
351  cbins |= ((K << 4) & 0x00F0);
352 
353  auto_write16(data, cbins, be);
354  return 2;
355 }
356 
357 
358 static ut32 avr_elpm(ut16 cbins, cchar** tokens, ut32 ntokens, ut8 *data, ut64 pc, bool be) {
359  if (ntokens == 1) {
360  /* elpm */
361  /* 1001010111011000 */
362  cbins = 0x95D8;
363  } else if (ntokens == 3) {
364  /* elpm Rd, Z | 0 <= Rd <= 31 */
365  ut16 Rd;
366  parse_register_or_error(Rd, tokens[1]);
367  expected_const_or_error(tokens[2], "z");
368 
369  /* 1001000ddddd0110 */
370  cbins = 0x9006;
371  cbins |= ((Rd << 4) & 0x01F0);
372  } else if (ntokens == 4) {
373  /* elpm Rd, Z+ | 0 <= Rd <= 31 */
374  ut16 Rd;
375  parse_register_or_error(Rd, tokens[1]);
376  expected_const_or_error(tokens[2], "z");
377  expected_const_or_error(tokens[3], "+");
378 
379  /* 1001000ddddd0111 */
380  cbins = 0x9007;
381  cbins |= ((Rd << 4) & 0x01F0);
382  } else {
383  throw_error("expected 'elpm' or 'elpm Rd, M' | 0 <= d <= 31 | M = {Z,Z+}\n");
384  }
385 
386  auto_write16(data, cbins, be);
387  return 2;
388 }
389 
390 static ut32 avr_dddcrrr(ut16 cbins, cchar** tokens, ut32 ntokens, ut8 *data, ut64 pc, bool be) {
391  /* <opcode> Rd,Rr | 16 <= d <= 23 | 16 <= r <= 23 */
392  ut16 Rd, Rr;
393  parse_register_or_error_limit(Rd, tokens[1], 16, 23);
394  parse_register_or_error_limit(Rr, tokens[2], 16, 23);
395 
396  Rd -= 16;
397  Rr -= 16;
398 
399  cbins |= (Rr & 0x0007);
400  cbins |= ((Rd << 4) & 0x0070);
401 
402  auto_write16(data, cbins, be);
403  return 2;
404 }
405 
406 
407 static ut32 avr_AAdddddAAAA(ut16 cbins, cchar** tokens, ut32 ntokens, ut8 *data, ut64 pc, bool be) {
408  /* <opcode> Rd, A | 0 <= d <= 31, 0 <= A <= 63 */
409  ut16 Rd, A;
410  parse_register_or_error(Rd, tokens[1]);
411  parse_unsigned_or_error(A, tokens[2], 63);
412 
413  cbins |= (A & 0x000F);
414  cbins |= ((A << 5) & 0x0600);
415  cbins |= ((Rd << 4) & 0x01F0);
416 
417  auto_write16(data, cbins, be);
418  return 2;
419 }
420 
421 static ut32 avr_rrrrrcccc(ut16 cbins, cchar** tokens, ut32 ntokens, ut8 *data, ut64 pc, bool be) {
422  /* <opcode> Rd | 0 <= d <= 31 */
423  ut16 Rd;
424  expected_const_or_error(tokens[1], "z");
425  parse_register_or_error(Rd, tokens[2]);
426  cbins |= ((Rd << 4) & 0x01F0);
427 
428  auto_write16(data, cbins, be);
429  return 2;
430 }
431 
432 
433 
434 static ut32 avr_ld(ut16 cbins, cchar** tokens, ut32 ntokens, ut8 *data, ut64 pc, bool be) {
435  /* ld Rd, M | 0 <= d <= 31 | M = {X,Y,Z,X+,Y+,Z+,-X,-Y,-Z} */
436  ut16 Rd;
437  parse_register_or_error(Rd, tokens[1]);
438 
439  if (ntokens == 3) {
440  if (!strcmp(tokens[2], "x")) {
441  /* ld Rd, X */
442  /* 1001000ddddd1100 */
443  cbins = 0x900C;
444  } else if (!strcmp(tokens[2], "y")) {
445  /* ld Rd, Y */
446  /* 1000000ddddd1000 */
447  cbins = 0x8008;
448  } else if (!strcmp(tokens[2], "z")) {
449  /* ld Rd, Z */
450  /* 1001000ddddd0000 */
451  cbins = 0x8000;
452  } else if (!strcmp(tokens[2], "-x")) {
453  /* ld Rd, -X */
454  /* 1001000ddddd1110 */
455  cbins = 0x900E;
456  } else if (!strcmp(tokens[2], "-y")) {
457  /* ld Rd, -Y */
458  /* 1001000ddddd1010 */
459  cbins = 0x900A;
460  } else if (!strcmp(tokens[2], "-z")) {
461  /* ld Rd, -Z */
462  /* 1001000ddddd0010 */
463  cbins = 0x9002;
464  } else {
465  throw_error("expected 'X' or 'Y' or 'Z' or '-X' or '-Y' or '-Z', but got '%s'\n", tokens[2]);
466  }
467  } else if (ntokens == 4 && !strcmp(tokens[3], "+")) {
468  if (!strcmp(tokens[2], "x")) {
469  /* ld Rd, X+ */
470  /* 1001000ddddd1101 */
471  cbins = 0x900D;
472  } else if (!strcmp(tokens[2], "y")) {
473  /* ld Rd, Y+ */
474  /* 1001000ddddd1001 */
475  cbins = 0x9009;
476  } else if (!strcmp(tokens[2], "z")) {
477  /* ld Rd, Z+ */
478  /* 1001000ddddd0001 */
479  cbins = 0x9001;
480  } else {
481  throw_error("expected 'X+' or 'Y+' or 'Z+', but got '%s+'\n", tokens[2]);
482  }
483  } else {
484  throw_error("expected ld Rd, M | 0 <= d <= 31 | M = {X,Y,Z,X+,Y+,Z+,-X,-Y,-Z}\n");
485  }
486 
487  cbins |= ((Rd << 4) & 0x01F0);
488  auto_write16(data, cbins, be);
489  return 2;
490 }
491 
492 
493 static ut32 avr_ldd(ut16 cbins, cchar** tokens, ut32 ntokens, ut8 *data, ut64 pc, bool be) {
494  /* ldd Rd, M + q | 0 <= d <= 31 | M = {Y,Z} | 0 <= q <= 63*/
495  ut16 Rd, q;
496  parse_register_or_error(Rd, tokens[1]);
497  parse_unsigned_or_error(q, tokens[4], 63);
498 
499  if (!strcmp(tokens[3], "+")) {
500  if (!strcmp(tokens[2], "y")) {
501  /* ldd Rd, Y+q */
502  /* 10q0qq0ddddd1qqq */
503  cbins = 0x8008;
504  } else if (!strcmp(tokens[2], "z")) {
505  /* ldd Rd, Z+q */
506  /* 10q0qq0ddddd0qqq */
507  cbins = 0x8000;
508  } else {
509  throw_error("expected 'Y+' or 'Z+', but got '%s+'\n", tokens[2]);
510  }
511  } else {
512  throw_error("expected ldd Rd, M + q | 0 <= d <= 31 | M = {Y,Z} | 0 <= q <= 63\n");
513  }
514 
515  cbins |= q & 0x0007;
516  cbins |= ((q << 7) & 0x0C00);
517  cbins |= ((q << 8) & 0x2000);
518  cbins |= ((Rd << 4) & 0x01F0);
519  auto_write16(data, cbins, be);
520  return 2;
521 }
522 
523 
524 static ut32 avr_lds(ut16 cbins, cchar** tokens, ut32 ntokens, ut8 *data, ut64 pc, bool be) {
525  ut16 Rd;
526  ut32 k;
527  parse_register_or_error(Rd, tokens[1]);
528  parse_unsigned_or_error(k, tokens[2], 0xFFFF);
529 
530 #if 0
531  // The STS (16-bit) and LDS (16-bit) instructions only exist in the reduced AVR cores.
532  // This includes only the ATtiny4/5/9/10 family, and the ATtiny20/40 family.
533  // They also lack some features like the lack of CPU registers R0 to R15.
534  // On rizin these platforms are not supported, therefore this code is commented, but works as intended.
535  if (k <= 127 && Rd >= 16) {
536  /* lds Rd, k | 16 <= d <= 31 | 0 <= k <= 127 */
537  /* 10100kkkddddkkkk */
538  cbins = 0xA000;
539  Rd -= 16;
540  cbins |= k & 0x000F;
541  cbins |= ((k << 4) & 0x0700);
542  cbins |= ((Rd << 4) & 0x00F0);
543 
544  auto_write16(data, cbins, be);
545  return 2;
546  }
547 #endif
548  /* lds Rd, k | 0 <= d <= 31 | 0 <= k <= 0xFFFF */
549  /* 1001000ddddd0000 kkkkkkkkkkkkkkkk */
550  cbins = 0x9000;
551  cbins |= ((Rd << 4) & 0x01F0);
552  auto_write16(data, cbins, be);
553  auto_write16(data + 2, k, be);
554  return 4;
555 }
556 
557 
558 static ut32 avr_lpm(ut16 cbins, cchar** tokens, ut32 ntokens, ut8 *data, ut64 pc, bool be) {
559  if (ntokens == 1) {
560  /* lpm */
561  /* 1001010111001000 */
562  cbins = 0x95C8;
563  } else if (ntokens == 3) {
564  /* lpm Rd, Z | 0 <= Rd <= 31 */
565  ut16 Rd;
566  parse_register_or_error(Rd, tokens[1]);
567  expected_const_or_error(tokens[2], "z");
568 
569  /* 1001000ddddd0100 */
570  cbins = 0x9004;
571  cbins |= ((Rd << 4) & 0x01F0);
572  } else if (ntokens == 4) {
573  /* lpm Rd, Z+ | 0 <= Rd <= 31 */
574  ut16 Rd;
575  parse_register_or_error(Rd, tokens[1]);
576  expected_const_or_error(tokens[2], "z");
577  expected_const_or_error(tokens[3], "+");
578 
579  /* 1001000ddddd0101 */
580  cbins = 0x9005;
581  cbins |= ((Rd << 4) & 0x01F0);
582  } else {
583  throw_error("expected 'lpm' or 'lpm Rd, M' | 0 <= d <= 31 | M = {Z,Z+}\n");
584  }
585 
586  auto_write16(data, cbins, be);
587  return 2;
588 }
589 
590 
591 static ut32 avr_kkkkkkkkkkkk(ut16 cbins, cchar** tokens, ut32 ntokens, ut8 *data, ut64 pc, bool be) {
592  /* <opcode> k | -4096 <= k <= 4096 */
593  st16 k;
594  parse_address_or_error(k, tokens[1], pc, -4096, 4096);
595  cbins |= (k & 0x0FFF);
596 
597  auto_write16(data, cbins, be);
598  return 2;
599 }
600 
601 
602 static ut32 avr_ddddrrrr(ut16 cbins, cchar** tokens, ut32 ntokens, ut8 *data, ut64 pc, bool be) {
603  /* <opcode> Rd, Rr | d = {0,2,...,30} | r = {0,2,...,30} */
604  ut16 Rd, Rr;
605  parse_register_or_error(Rd, tokens[1]);
606  parse_register_or_error(Rr, tokens[2]);
607 
608  if (Rd & 1) {
609  throw_error("register must be even, Rd = {0,2,...,30} (parsed r%u)\n", Rd);
610  } else if (Rr & 1) {
611  throw_error("register must be even, Rr = {0,2,...,30} (parsed r%u)\n", Rr);
612  }
613 
614  Rr /= 2;
615  Rd /= 2;
616  cbins |= Rr & 0x000F;
617  cbins |= ((Rd << 4) & 0x00F0);
618 
619  auto_write16(data, cbins, be);
620  return 2;
621 }
622 
623 
624 static ut32 avr_ddddrrrr_2x(ut16 cbins, cchar** tokens, ut32 ntokens, ut8 *data, ut64 pc, bool be) {
625  /* <opcode> Rd, Rr | 16 <= d <= 31 | 16 <= r <= 31 */
626  ut16 Rd, Rr;
627  parse_register_or_error_limit(Rd, tokens[1], 16, 31);
628  parse_register_or_error_limit(Rr, tokens[2], 16, 31);
629 
630  Rr -= 16;
631  Rd -= 16;
632  cbins |= Rr & 0x000F;
633  cbins |= ((Rd << 4) & 0x00F0);
634 
635  auto_write16(data, cbins, be);
636  return 2;
637 }
638 
639 
640 static ut32 avr_AArrrrrAAAA(ut16 cbins, cchar** tokens, ut32 ntokens, ut8 *data, ut64 pc, bool be) {
641  /* <opcode> Rd, A | 0 <= d <= 31, 0 <= A <= 63 */
642  ut16 Rd, A;
643  parse_unsigned_or_error(A, tokens[1], 63);
644  parse_register_or_error(Rd, tokens[2]);
645 
646  cbins |= (A & 0x000F);
647  cbins |= ((A << 5) & 0x0600);
648  cbins |= ((Rd << 4) & 0x01F0);
649 
650  auto_write16(data, cbins, be);
651  return 2;
652 }
653 
654 
655 static ut32 avr_rrrrrcbbb(ut16 cbins, cchar** tokens, ut32 ntokens, ut8 *data, ut64 pc, bool be) {
656  /* <opcode> Rr, b | 0 <= d <= 31, 0 <= b <= 7 */
657  ut16 Rr, b;
658  parse_register_or_error(Rr, tokens[1]);
659  parse_unsigned_or_error(b, tokens[2], 63);
660 
661  cbins |= (b & 0x0007);
662  cbins |= ((Rr << 4) & 0x01F0);
663 
664  auto_write16(data, cbins, be);
665  return 2;
666 }
667 
668 static ut32 avr_ddddcccc(ut16 cbins, cchar** tokens, ut32 ntokens, ut8 *data, ut64 pc, bool be) {
669  /* <opcode> Rd | 16 <= d <= 31 */
670  ut16 Rd;
671  parse_register_or_error_limit(Rd, tokens[1], 16, 31);
672 
673  Rd -= 16;
674  cbins |= ((Rd << 4) & 0x00F0);
675 
676  auto_write16(data, cbins, be);
677  return 2;
678 }
679 
680 
681 static ut32 avr_spm(ut16 cbins, cchar** tokens, ut32 ntokens, ut8 *data, ut64 pc, bool be) {
682  if (ntokens == 1) {
683  /* spm */
684  /* 1001010111101000 */
685  cbins = 0x95E8;
686  } else if (ntokens == 3) {
687  /* spm Z+ | 0 <= Rd <= 31 */
688  expected_const_or_error(tokens[1], "z");
689  expected_const_or_error(tokens[2], "+");
690 
691  /* 1001010111111000 */
692  cbins = 0x95F8;
693  } else {
694  throw_error("expected 'spm' or 'spm Z+'\n");
695  }
696 
697  auto_write16(data, cbins, be);
698  return 2;
699 }
700 
701 
702 static ut32 avr_st(ut16 cbins, cchar** tokens, ut32 ntokens, ut8 *data, ut64 pc, bool be) {
703  /* st M, Rr | 0 <= r <= 31 | M = {X,Y,Z,-X,-Y,-Z} */
704  ut16 Rr;
705  parse_register_or_error(Rr, tokens[2]);
706 
707  if (ntokens == 3) {
708  if (!strcmp(tokens[1], "x")) {
709  /* st X, Rr */
710  /* 1001001rrrrr1100 */
711  cbins = 0x920C;
712  } else if (!strcmp(tokens[1], "y")) {
713  /* st Y, Rr */
714  /* 1000001rrrrr1000 */
715  cbins = 0x8208;
716  } else if (!strcmp(tokens[1], "z")) {
717  /* st Z, Rr */
718  /* 1000001rrrrr0000 */
719  cbins = 0x8200;
720  } else if (!strcmp(tokens[1], "-x")) {
721  /* st -X, Rr */
722  /* 1001001rrrrr1110 */
723  cbins = 0x920E;
724  } else if (!strcmp(tokens[1], "-y")) {
725  /* st -Y, Rr */
726  /* 1001001rrrrr1010 */
727  cbins = 0x920A;
728  } else if (!strcmp(tokens[1], "-z")) {
729  /* st -Z, Rr */
730  /* 1001001rrrrr0010 */
731  cbins = 0x9202;
732  } else {
733  throw_error("expected 'X' or 'Y' or 'Z' or '-X' or '-Y' or '-Z', but got '%s'\n", tokens[1]);
734  }
735  } else if (ntokens == 5 && !strcmp(tokens[2], "+") && !strcmp(tokens[3], "1")) {
736  if (!strcmp(tokens[1], "x")) {
737  /* st X+1, Rr */
738  /* 1001001rrrrr1101 */
739  cbins = 0x920D;
740  } else if (!strcmp(tokens[1], "y")) {
741  /* st Y+1, Rr */
742  /* 1001001rrrrr1001 */
743  cbins = 0x9209;
744  } else if (!strcmp(tokens[1], "z")) {
745  /* st Z+1, Rr */
746  /* 1001001rrrrr0001 */
747  cbins = 0x9201;
748  } else {
749  throw_error("expected 'X+' or 'Y+' or 'Z+', but got '%s+'\n", tokens[2]);
750  }
751  } else {
752  throw_error("expected st M, Rr | 0 <= r <= 31 | M = {X,Y,Z,-X,-Y,-Z}\n");
753  }
754 
755  cbins |= ((Rr << 4) & 0x01F0);
756  auto_write16(data, cbins, be);
757  return 2;
758 }
759 
760 
761 static ut32 avr_std(ut16 cbins, cchar** tokens, ut32 ntokens, ut8 *data, ut64 pc, bool be) {
762  if (ntokens == 4) {
763  /* std M, Rr | 0 <= r <= 31 | M = {X+,Y+,Z+} */
764  ut16 Rr;
765  expected_const_or_error(tokens[2], "+");
766  parse_register_or_error(Rr, tokens[3]);
767 
768  if (!strcmp(tokens[1], "x")) {
769  /* std X+, Rr */
770  /* 1001001rrrrr1101 */
771  cbins = 0x900D;
772  } else if (!strcmp(tokens[1], "y")) {
773  /* std Y+, Rr */
774  /* 1001001rrrrr1001 */
775  cbins = 0x9009;
776  } else if (!strcmp(tokens[1], "z")) {
777  /* std Z+, Rr */
778  /* 1001001rrrrr0001 */
779  cbins = 0x9001;
780  } else {
781  throw_error("expected 'X+' or 'Y+' or 'Z+', but got '%s+'\n", tokens[1]);
782  }
783  cbins |= ((Rr << 4) & 0x01F0);
784 
785  auto_write16(data, cbins, be);
786  return 2;
787  } else if (ntokens == 5) {
788  /* std M + q, Rr | 0 <= r <= 31 | M = {Y,Z} | 0 <= q <= 63*/
789  ut16 Rr, q;
790  expected_const_or_error(tokens[2], "+");
791  parse_unsigned_or_error(q, tokens[3], 63);
792  parse_register_or_error(Rr, tokens[4]);
793 
794  if (!strcmp(tokens[1], "y")) {
795  /* std Y+q, Rr */
796  /* 10q0qq1rrrrr1qqq */
797  cbins = 0x8208;
798  } else if (!strcmp(tokens[1], "z")) {
799  /* std Z+q, Rr */
800  /* 10q0qq1rrrrr0qqq */
801  cbins = 0x8200;
802  } else {
803  throw_error("expected 'Y' or 'Z', but got '%s'\n", tokens[1]);
804  }
805 
806  cbins |= q & 0x0007;
807  cbins |= ((q << 7) & 0x0C00);
808  cbins |= ((q << 8) & 0x2000);
809  cbins |= ((Rr << 4) & 0x01F0);
810 
811  auto_write16(data, cbins, be);
812  return 2;
813  }
814 
815  throw_error("expected std Rr, M + q | 0 <= d <= 31 | M = {Y,Z} | 0 <= q <= 63\n");
816 }
817 
818 
819 
820 static ut32 avr_sts(ut16 cbins, cchar** tokens, ut32 ntokens, ut8 *data, ut64 pc, bool be) {
821  /* sts k, Rr | 0 <= r <= 31, 0 <= k <= 0xFFFF */
822  ut16 Rr;
823  ut32 k;
824  parse_unsigned_or_error(k, tokens[1], 0xFFFF);
825  parse_register_or_error(Rr, tokens[2]);
826 
827 #if 0
828  // The STS (16-bit) and LDS (16-bit) instructions only exist in the reduced AVR cores.
829  // This includes only the ATtiny4/5/9/10 family, and the ATtiny20/40 family.
830  // They also lack some features like the lack of CPU registers R0 to R15.
831  // On rizin these platforms are not supported, therefore this code is commented, but works as intended.
832  if (k <= 127 && Rr >= 16) {
833  /* sts k, Rr | 16 <= d <= 31 | 0 <= k <= 127 */
834  /* 10101kkkddddkkkk */
835  cbins = 0xA800;
836  Rr -= 16;
837  cbins |= k & 0x000F;
838  cbins |= ((k << 4) & 0x0700);
839  cbins |= ((Rr << 4) & 0x00F0);
840 
841  auto_write16(data, cbins, be);
842  return 2;
843  }
844 #endif
845  /* sts k, Rr | 0 <= d <= 31 | 0 <= k <= 0xFFFF */
846  /* 1001001ddddd0000 kkkkkkkkkkkkkkkk */
847  cbins = 0x9200;
848  cbins |= ((Rr << 4) & 0x01F0);
849  auto_write16(data, cbins, be);
850  auto_write16(data + 2, k, be);
851  return 4;
852 }
853 
854 
855 static ut32 avr_ssscccc(ut16 cbins, cchar** tokens, ut32 ntokens, ut8 *data, ut64 pc, bool be) {
856  /* <opcode> b | 0 <= b <= 7 */
857  ut16 b;
858  parse_unsigned_or_error(b, tokens[1], 7);
859 
860  cbins |= ((b << 4) & 0x0070);
861  auto_write16(data, cbins, be);
862  return 2;
863 }
864 
865 
866 static ut32 avr_kkkkkkksss(ut16 cbins, cchar** tokens, ut32 ntokens, ut8 *data, ut64 pc, bool be) {
867  /* <opcode> b, k | -64 <= k <= 63 | 0 <= b <= 7 */
868  ut16 b;
869  st16 k;
870  parse_unsigned_or_error(b, tokens[1], 7);
871  parse_address_or_error(k, tokens[2], pc, -64, 63);
872 
873  cbins |= (b & 0x0007);
874  cbins |= ((k << 3) & 0x03F8);
875  auto_write16(data, cbins, be);
876  return 2;
877 }
878 
879 
880 static const AvrInstruction instructions[] = {
881  { "adc" /* 000111rdddddrrrr */ , 0x1C00, 3, 3, avr_rdddddrrrr },
882  { "add" /* 000011rdddddrrrr */ , 0x0C00, 3, 3, avr_rdddddrrrr },
883  { "adiw" /* 10010110KKddKKKK */ , 0x9600, 3, 3, avr_KKddKKKK },
884  { "and" /* 001000rdddddrrrr */ , 0x2000, 3, 3, avr_rdddddrrrr },
885  { "andi" /* 0111KKKKddddKKKK */ , 0x7000, 3, 3, avr_KKKKddddKKKK },
886  { "asr" /* 1001010ddddd0101 */ , 0x9405, 2, 2, avr_dddddcccc },
887  { "bclr" /* 100101001sss1000 */ , 0x9488, 2, 2, avr_ssscccc },
888  { "bld" /* 1111100ddddd0bbb */ , 0xF800, 3, 3, avr_dddddcbbb },
889  { "brbc" /* 111101kkkkkkksss */ , 0xF400, 3, 3, avr_kkkkkkksss },
890  { "brbs" /* 111100kkkkkkksss */ , 0xF000, 3, 3, avr_kkkkkkksss },
891  { "brcc" /* 111101kkkkkkk000 */ , 0xF400, 2, 2, avr_kkkkkkkccc },
892  { "brcs" /* 111100kkkkkkk000 */ , 0xF000, 2, 2, avr_kkkkkkkccc },
893  { "break" /* 1001010110011000 */ , 0x9598, 1, 1, avr_unique },
894  { "breq" /* 111100kkkkkkk001 */ , 0xF001, 2, 2, avr_kkkkkkkccc },
895  { "brge" /* 111101kkkkkkk100 */ , 0xF404, 2, 2, avr_kkkkkkkccc },
896  { "brhc" /* 111101kkkkkkk101 */ , 0xF405, 2, 2, avr_kkkkkkkccc },
897  { "brhs" /* 111100kkkkkkk101 */ , 0xF005, 2, 2, avr_kkkkkkkccc },
898  { "brid" /* 111101kkkkkkk111 */ , 0xF407, 2, 2, avr_kkkkkkkccc },
899  { "brie" /* 111100kkkkkkk111 */ , 0xF007, 2, 2, avr_kkkkkkkccc },
900  { "brlo" /* 111100kkkkkkk000 */ , 0xF000, 2, 2, avr_kkkkkkkccc },
901  { "brlt" /* 111100kkkkkkk100 */ , 0xF004, 2, 2, avr_kkkkkkkccc },
902  { "brmi" /* 111100kkkkkkk010 */ , 0xF002, 2, 2, avr_kkkkkkkccc },
903  { "brne" /* 111101kkkkkkk001 */ , 0xF401, 2, 2, avr_kkkkkkkccc },
904  { "brpl" /* 111101kkkkkkk010 */ , 0xF402, 2, 2, avr_kkkkkkkccc },
905  { "brsh" /* 111101kkkkkkk000 */ , 0xF400, 2, 2, avr_kkkkkkkccc },
906  { "brtc" /* 111101kkkkkkk110 */ , 0xF406, 2, 2, avr_kkkkkkkccc },
907  { "brts" /* 111100kkkkkkk110 */ , 0xF006, 2, 2, avr_kkkkkkkccc },
908  { "brvc" /* 111101kkkkkkk011 */ , 0xF403, 2, 2, avr_kkkkkkkccc },
909  { "brvs" /* 111100kkkkkkk011 */ , 0xF003, 2, 2, avr_kkkkkkkccc },
910  { "bset" /* 100101000sss1000 */ , 0x9408, 2, 2, avr_ssscccc },
911  { "bst" /* 1111101ddddd0bbb */ , 0xFA00, 3, 3, avr_dddddcbbb },
912  { "call" /* 1001010kkkkk111k kkkkkkkkkkkkkkkk */ , 0x940E, 2, 2, avr_kkkkkccck },
913  { "cbi" /* 10011000AAAAAbbb */ , 0x9800, 3, 3, avr_AAAAAbbb },
914  { "cbr" /* 0111KKKKddddKKKK */ , 0x7000, 3, 3, avr_cbr },
915  { "clc" /* 1001010010001000 */ , 0x9488, 1, 1, avr_unique },
916  { "clh" /* 1001010011011000 */ , 0x94D8, 1, 1, avr_unique },
917  { "cli" /* 1001010011111000 */ , 0x94F8, 1, 1, avr_unique },
918  { "cln" /* 1001010010101000 */ , 0x94A8, 1, 1, avr_unique },
919  { "clr" /* 001001dddddddddd */ , 0x2400, 2, 2, avr_dddddddddd },
920  { "cls" /* 1001010011001000 */ , 0x94C8, 1, 1, avr_unique },
921  { "clt" /* 1001010011101000 */ , 0x94E8, 1, 1, avr_unique },
922  { "clv" /* 1001010010111000 */ , 0x94B8, 1, 1, avr_unique },
923  { "clz" /* 1001010010011000 */ , 0x9498, 1, 1, avr_unique },
924  { "com" /* 1001010ddddd0000 */ , 0x9400, 2, 2, avr_dddddcccc },
925  { "cp" /* 000101rdddddrrrr */ , 0x1400, 3, 3, avr_rdddddrrrr },
926  { "cpc" /* 000001rdddddrrrr */ , 0x0400, 3, 3, avr_rdddddrrrr },
927  { "cpi" /* 0011KKKKddddKKKK */ , 0x3000, 3, 3, avr_KKKKddddKKKK },
928  { "cpse" /* 000100rdddddrrrr */ , 0x1000, 3, 3, avr_rdddddrrrr },
929  { "dec" /* 1001010ddddd1010 */ , 0x940A, 2, 2, avr_dddddcccc },
930  { "des" /* 10010100KKKK1011 */ , 0x940B, 2, 2, avr_KKKKcccc },
931  { "eicall" /* 1001010100011001 */ , 0x9519, 1, 1, avr_unique },
932  { "eijmp" /* 1001010000011001 */ , 0x9419, 1, 1, avr_unique },
933  { "elpm" /* */ , 0x0000, 1, 5, avr_elpm },
934  { "eor" /* 001001rdddddrrrr */ , 0x2400, 3, 3, avr_rdddddrrrr },
935  { "fmul" /* 000000110ddd1rrr */ , 0x0308, 3, 3, avr_dddcrrr },
936  { "fmuls" /* 000000111ddd0rrr */ , 0x0380, 3, 3, avr_dddcrrr },
937  { "fmulsu" /* 000000111ddd1rrr */ , 0x0388, 3, 3, avr_dddcrrr },
938  { "icall" /* 1001010100001001 */ , 0x9509, 1, 1, avr_unique },
939  { "ijmp" /* 1001010000001001 */ , 0x9409, 1, 1, avr_unique },
940  { "in" /* 10110AAdddddAAAA */ , 0xB000, 3, 3, avr_AAdddddAAAA },
941  { "inc" /* 1001010ddddd0011 */ , 0x9403, 2, 2, avr_dddddcccc },
942  { "jmp" /* 1001010kkkkk110k kkkkkkkkkkkkkkkk */ , 0x940C, 2, 2, avr_kkkkkccck },
943  { "lac" /* 1001001rrrrr0110 */ , 0x9206, 3, 3, avr_rrrrrcccc },
944  { "las" /* 1001001rrrrr0101 */ , 0x9205, 3, 3, avr_rrrrrcccc },
945  { "lat" /* 1001001rrrrr0111 */ , 0x9207, 3, 3, avr_rrrrrcccc },
946  { "ld" /* */ , 0x0000, 3, 5, avr_ld },
947  { "ldd" /* */ , 0x0000, 5, 5, avr_ldd },
948  { "ldi" /* 1110KKKKddddKKKK */ , 0xE000, 3, 3, avr_KKKKddddKKKK },
949  { "lds" /* */ , 0x0000, 3, 3, avr_lds },
950  { "lpm" /* */ , 0x0000, 1, 5, avr_lpm },
951  { "lsl" /* 000011dddddddddd */ , 0x0C00, 2, 2, avr_dddddddddd },
952  { "lsr" /* 1001010ddddd0110 */ , 0x9406, 2, 2, avr_dddddcccc },
953  { "mov" /* 001011rdddddrrrr */ , 0x2C00, 3, 3, avr_rdddddrrrr },
954  { "movw" /* 00000001ddddrrrr */ , 0x0100, 3, 3, avr_ddddrrrr },
955  { "mul" /* 100111rdddddrrrr */ , 0x9C00, 3, 3, avr_rdddddrrrr },
956  { "muls" /* 00000010ddddrrrr */ , 0x0200, 3, 3, avr_ddddrrrr_2x },
957  { "mulsu" /* 000000110ddd0rrr */ , 0x0300, 3, 3, avr_dddcrrr },
958  { "neg" /* 1001010ddddd0001 */ , 0x9401, 2, 2, avr_dddddcccc },
959  { "nop" /* 0000000000000000 */ , 0x0000, 1, 1, avr_unique },
960  { "or" /* 001010rdddddrrrr */ , 0x2800, 3, 3, avr_rdddddrrrr },
961  { "ori" /* 0110KKKKddddKKKK */ , 0x6000, 3, 3, avr_KKKKddddKKKK },
962  { "out" /* 10111AArrrrrAAAA */ , 0xB800, 3, 3, avr_AArrrrrAAAA },
963  { "pop" /* 1001000ddddd1111 */ , 0x900F, 2, 2, avr_dddddcccc },
964  { "push" /* 1001001ddddd1111 */ , 0x920F, 2, 2, avr_dddddcccc },
965  { "rcall" /* 1101kkkkkkkkkkkk */ , 0xD000, 2, 2, avr_kkkkkkkkkkkk },
966  { "ret" /* 1001010100001000 */ , 0x9508, 1, 1, avr_unique },
967  { "reti" /* 1001010100011000 */ , 0x9518, 1, 1, avr_unique },
968  { "rjmp" /* 1100kkkkkkkkkkkk */ , 0xC000, 2, 2, avr_kkkkkkkkkkkk },
969  { "rol" /* 000111dddddddddd */ , 0x1C00, 2, 2, avr_dddddddddd },
970  { "ror" /* 1001010ddddd0111 */ , 0x9407, 2, 2, avr_dddddcccc },
971  { "sbc" /* 000010rdddddrrrr */ , 0x0800, 3, 3, avr_rdddddrrrr },
972  { "sbci" /* 0100KKKKddddKKKK */ , 0x4000, 3, 3, avr_KKKKddddKKKK },
973  { "sbi" /* 10011010AAAAAbbb */ , 0x9A00, 3, 3, avr_AAAAAbbb },
974  { "sbic" /* 10011001AAAAAbbb */ , 0x9900, 3, 3, avr_AAAAAbbb },
975  { "sbis" /* 10011011AAAAAbbb */ , 0x9B00, 3, 3, avr_AAAAAbbb },
976  { "sbiw" /* 10010111KKddKKKK */ , 0x9700, 3, 3, avr_KKddKKKK },
977  { "sbr" /* 0110KKKKddddKKKK */ , 0x6000, 3, 3, avr_KKKKddddKKKK },
978  { "sbrc" /* 1111110rrrrr0bbb */ , 0xFC00, 3, 3, avr_rrrrrcbbb },
979  { "sbrs" /* 1111111rrrrr0bbb */ , 0xFE00, 3, 3, avr_rrrrrcbbb },
980  { "sec" /* 1001010000001000 */ , 0x9408, 1, 1, avr_unique },
981  { "seh" /* 1001010001011000 */ , 0x9458, 1, 1, avr_unique },
982  { "sei" /* 1001010001111000 */ , 0x9478, 1, 1, avr_unique },
983  { "sen" /* 1001010000101000 */ , 0x9428, 1, 1, avr_unique },
984  { "ser" /* 11101111dddd1111 */ , 0xEF0F, 2, 2, avr_ddddcccc },
985  { "ses" /* 1001010001001000 */ , 0x9448, 1, 1, avr_unique },
986  { "set" /* 1001010001101000 */ , 0x9468, 1, 1, avr_unique },
987  { "sev" /* 1001010000111000 */ , 0x9438, 1, 1, avr_unique },
988  { "sez" /* 1001010000011000 */ , 0x9418, 1, 1, avr_unique },
989  { "sleep" /* 1001010110001000 */ , 0x9588, 1, 1, avr_unique },
990  { "spm" /* */ , 0x0000, 1, 5, avr_spm },
991  { "st" /* */ , 0x0000, 3, 5, avr_st },
992  { "std" /* */ , 0x0000, 4, 5, avr_std },
993  { "sts" /* */ , 0x0000, 3, 3, avr_sts },
994  { "sub" /* 000110rdddddrrrr */ , 0x1800, 3, 3, avr_rdddddrrrr },
995  { "subi" /* 0101KKKKddddKKKK */ , 0x5000, 3, 3, avr_KKKKddddKKKK },
996  { "swap" /* 1001010ddddd0010 */ , 0x9402, 2, 2, avr_dddddcccc },
997  { "tst" /* 001000dddddddddd */ , 0x2000, 2, 2, avr_dddddddddd },
998  { "wdr" /* 1001010110101000 */ , 0x95A8, 1, 1, avr_unique },
999  { "xch" /* 1001001rrrrr0100 */ , 0x9204, 3, 3, avr_rrrrrcccc }
1000 };
1001 
1002 static char *strdup_limit(cchar *begin, cchar *end) {
1003  ssize_t size = end - begin;
1004  if (size < 1) {
1005  return NULL;
1006  }
1007  char* str = malloc(size + 1);
1008  if (!str) {
1009  return NULL;
1010  }
1011  memcpy(str, begin, size);
1012  str[size] = 0;
1013  return str;
1014 }
1015 
1016 static void sanitize_input(char *cinput, st32 input_size) {
1017  for (st32 i = 0; i < input_size; ++i) {
1018  if (cinput[i] == ',') {
1019  cinput[i] = ' ';
1020  }
1021  }
1022 }
1023 
1024 static char **tokens_new(cchar *input, st32 input_size, ut32 *ntokens) {
1025 
1026  char* cinput = strdup(input);
1027  if (!cinput) {
1029  return NULL;
1030  }
1031 
1032  sanitize_input(cinput, input_size);
1033 
1034  char **tokens = RZ_NEWS0(char*, MAX_TOKENS);
1035  if (!tokens) {
1036  free(cinput);
1038  return NULL;
1039  }
1040 
1041  ut32 count;
1042  cchar *start, *end;
1043  char* copy;
1044 
1045  start = rz_str_trim_head_ro(cinput);
1046  for (count = 0; *start && count < MAX_TOKENS; count++) {
1048 
1049  for (ut32 i = 0; i < end - start; ++i) {
1050  if (start[i] == '+') {
1051  end = start + 1;
1052  break;
1053  }
1054  }
1055 
1056  copy = strdup_limit(start, end);
1057  if (!copy) {
1059  break;
1060  }
1061 
1062  tokens[count] = copy;
1064  }
1065 
1067 
1068  *ntokens = count;
1069  free(cinput);
1070  return tokens;
1071 }
1072 
1073 static void tokens_free(char **tokens) {
1074  if (!tokens) {
1075  return;
1076  }
1077  for (ut32 i = 0; i < MAX_TOKENS; ++i) {
1078  free(tokens[i]);
1079  }
1080  free(tokens);
1081 }
1082 
1083 // TODO handle endianness
1084 ut32 avr_assembler(const char *input, st32 input_size, ut8 *output, st32 output_size, ut64 pc, bool be) {
1085  return_error_if_empty_input(input, input_size);
1086 
1087  ut32 written = AVR_INVALID_SIZE;
1088  ut32 ntokens = 0;
1089  char** tokens = tokens_new(input, input_size, &ntokens);
1090  if (!tokens || ntokens < 1) {
1091  RZ_LOG_ERROR("[!] avr_assembler: invalid assembly.\n");
1092  goto avr_assembler_end;
1093  }
1094 
1095 
1096  for (ut32 i = 0; i < RZ_ARRAY_SIZE(instructions); ++i) {
1097  if (!rz_str_casecmp(tokens[0], instructions[i].opcode)) {
1098  ut16 mintoks = instructions[i].mintoks;
1099  ut16 maxtoks = instructions[i].maxtoks;
1100  if (ntokens < mintoks || ntokens > maxtoks) {
1101  RZ_LOG_ERROR("[!] avr_assembler: '%s' requires %u <= ntokens <= %u, but %u tokens was provided.\n", tokens[0], mintoks, maxtoks, ntokens);
1102  goto avr_assembler_end;
1103  }
1104  written = instructions[i].encode(instructions[i].cbits, (cchar**)tokens, ntokens, output, pc, be);
1105  break;
1106  }
1107  }
1108 
1109 avr_assembler_end:
1110  tokens_free(tokens);
1111  return written;
1112 }
lzma_index ** i
Definition: index.h:629
#define A(x)
Definition: arc.h:165
static ut32 avr_ld(ut16 cbins, cchar **tokens, ut32 ntokens, ut8 *data, ut64 pc, bool be)
Definition: assembler.c:434
static ut32 avr_cbr(ut16 cbins, cchar **tokens, ut32 ntokens, ut8 *data, ut64 pc, bool be)
Definition: assembler.c:244
static ut32 avr_dddcrrr(ut16 cbins, cchar **tokens, ut32 ntokens, ut8 *data, ut64 pc, bool be)
Definition: assembler.c:390
#define parse_address_or_error(rn, rs, pc, llow, lhigh)
Definition: assembler.c:120
static ut32 avr_KKKKcccc(ut16 cbins, cchar **tokens, ut32 ntokens, ut8 *data, ut64 pc, bool be)
Definition: assembler.c:346
#define MAX_TOKENS
Definition: assembler.c:7
static ut32 avr_lpm(ut16 cbins, cchar **tokens, ut32 ntokens, ut8 *data, ut64 pc, bool be)
Definition: assembler.c:558
static ut32 avr_AAdddddAAAA(ut16 cbins, cchar **tokens, ut32 ntokens, ut8 *data, ut64 pc, bool be)
Definition: assembler.c:407
static const AvrInstruction instructions[]
Definition: assembler.c:880
static ut32 avr_rdddddrrrr(ut16 cbins, cchar **tokens, ut32 ntokens, ut8 *data, ut64 pc, bool be)
Definition: assembler.c:189
#define parse_unsigned_or_error(rn, rs, limit)
Definition: assembler.c:101
static ut32 avr_st(ut16 cbins, cchar **tokens, ut32 ntokens, ut8 *data, ut64 pc, bool be)
Definition: assembler.c:702
static void sanitize_input(char *cinput, st32 input_size)
Definition: assembler.c:1016
static ut32 avr_kkkkkkkccc(ut16 cbins, cchar **tokens, ut32 ntokens, ut8 *data, ut64 pc, bool be)
Definition: assembler.c:288
static ut32 avr_lds(ut16 cbins, cchar **tokens, ut32 ntokens, ut8 *data, ut64 pc, bool be)
Definition: assembler.c:524
ut32(* Encode)(ut16 cbins, cchar **tokens, ut32 ntokens, ut8 *data, ut64 pc, bool be)
Definition: assembler.c:172
static ut32 avr_rrrrrcbbb(ut16 cbins, cchar **tokens, ut32 ntokens, ut8 *data, ut64 pc, bool be)
Definition: assembler.c:655
static void tokens_free(char **tokens)
Definition: assembler.c:1073
static ut32 avr_AAAAAbbb(ut16 cbins, cchar **tokens, ut32 ntokens, ut8 *data, ut64 pc, bool be)
Definition: assembler.c:317
#define return_error_if_empty_input(a, b)
Definition: assembler.c:16
static ut32 avr_ldd(ut16 cbins, cchar **tokens, ut32 ntokens, ut8 *data, ut64 pc, bool be)
Definition: assembler.c:493
static char * strdup_limit(cchar *begin, cchar *end)
Definition: assembler.c:1002
ut32 avr_assembler(const char *input, st32 input_size, ut8 *output, st32 output_size, ut64 pc, bool be)
Definition: assembler.c:1084
static ut32 avr_ssscccc(ut16 cbins, cchar **tokens, ut32 ntokens, ut8 *data, ut64 pc, bool be)
Definition: assembler.c:855
#define auto_write16(buf, val, be)
Definition: assembler.c:163
#define expected_const_or_error(a, exp)
Definition: assembler.c:24
#define parse_register_or_error_limit(rn, rs, min, max)
Definition: assembler.c:32
static ut32 avr_std(ut16 cbins, cchar **tokens, ut32 ntokens, ut8 *data, ut64 pc, bool be)
Definition: assembler.c:761
static ut32 avr_elpm(ut16 cbins, cchar **tokens, ut32 ntokens, ut8 *data, ut64 pc, bool be)
Definition: assembler.c:358
static ut32 avr_kkkkkkksss(ut16 cbins, cchar **tokens, ut32 ntokens, ut8 *data, ut64 pc, bool be)
Definition: assembler.c:866
static ut32 avr_unique(ut16 cbins, cchar **tokens, ut32 ntokens, ut8 *data, ut64 pc, bool be)
Definition: assembler.c:183
static ut32 avr_dddddcbbb(ut16 cbins, cchar **tokens, ut32 ntokens, ut8 *data, ut64 pc, bool be)
Definition: assembler.c:273
static ut32 avr_ddddcccc(ut16 cbins, cchar **tokens, ut32 ntokens, ut8 *data, ut64 pc, bool be)
Definition: assembler.c:668
static char ** tokens_new(cchar *input, st32 input_size, ut32 *ntokens)
Definition: assembler.c:1024
static ut32 avr_ddddrrrr(ut16 cbins, cchar **tokens, ut32 ntokens, ut8 *data, ut64 pc, bool be)
Definition: assembler.c:602
static ut32 avr_rrrrrcccc(ut16 cbins, cchar **tokens, ut32 ntokens, ut8 *data, ut64 pc, bool be)
Definition: assembler.c:421
#define throw_error(msg,...)
Definition: assembler.c:10
static ut32 avr_KKKKddddKKKK(ut16 cbins, cchar **tokens, ut32 ntokens, ut8 *data, ut64 pc, bool be)
Definition: assembler.c:227
#define parse_register_or_error(rn, rs)
Definition: assembler.c:49
static ut32 avr_ddddrrrr_2x(ut16 cbins, cchar **tokens, ut32 ntokens, ut8 *data, ut64 pc, bool be)
Definition: assembler.c:624
static ut32 avr_kkkkkccck(ut16 cbins, cchar **tokens, ut32 ntokens, ut8 *data, ut64 pc, bool be)
Definition: assembler.c:298
struct avr_decoder_t AvrInstruction
static ut32 avr_AArrrrrAAAA(ut16 cbins, cchar **tokens, ut32 ntokens, ut8 *data, ut64 pc, bool be)
Definition: assembler.c:640
static ut32 avr_kkkkkkkkkkkk(ut16 cbins, cchar **tokens, ut32 ntokens, ut8 *data, ut64 pc, bool be)
Definition: assembler.c:591
static ut32 avr_dddddddddd(ut16 cbins, cchar **tokens, ut32 ntokens, ut8 *data, ut64 pc, bool be)
Definition: assembler.c:332
#define parse_register_pair_or_error(rn, rs)
Parse things like "r25:r24" or just "r24". Result would be 24 in both cases.
Definition: assembler.c:67
static ut32 avr_KKddKKKK(ut16 cbins, cchar **tokens, ut32 ntokens, ut8 *data, ut64 pc, bool be)
Definition: assembler.c:205
static ut32 avr_sts(ut16 cbins, cchar **tokens, ut32 ntokens, ut8 *data, ut64 pc, bool be)
Definition: assembler.c:820
static ut32 avr_dddddcccc(ut16 cbins, cchar **tokens, ut32 ntokens, ut8 *data, ut64 pc, bool be)
Definition: assembler.c:262
static ut32 avr_spm(ut16 cbins, cchar **tokens, ut32 ntokens, ut8 *data, ut64 pc, bool be)
Definition: assembler.c:681
#define NULL
Definition: cris-opc.c:27
static static sync static getppid static getegid const char static filename char static len const char char static bufsiz static mask static vfork const void static prot static getpgrp const char static swapflags static arg static fd static protocol static who struct sockaddr static addrlen static backlog struct timeval struct timezone static tz const struct iovec static count static mode const void const struct sockaddr static tolen const char static pathname void count
Definition: sflib.h:98
static static sync static getppid static getegid const char static filename char static len const char char static bufsiz static mask static vfork const void static prot static getpgrp const char static swapflags static arg static fd static protocol static who struct sockaddr static addrlen static backlog struct timeval struct timezone static tz const struct iovec static count static mode const void const struct sockaddr static tolen const char static pathname void static offset struct stat static buf void long static basep static whence static length const void static len static semflg const void static shmflg const struct timespec struct timespec static rem const char static group const void start
Definition: sflib.h:133
uint16_t ut16
uint32_t ut32
const char * k
Definition: dsignal.c:11
RZ_API void Ht_() free(HtName_(Ht) *ht)
Definition: ht_inc.c:130
voidpf void uLong size
Definition: ioapi.h:138
uint8_t ut8
Definition: lh5801.h:11
memcpy(mem, inblock.get(), min(CONTAINING_RECORD(inblock.get(), MEMBLOCK, data) ->size, size))
const char cchar
Definition: common.h:9
#define AVR_INVALID_SIZE
Definition: common.h:7
void * malloc(size_t size)
Definition: malloc.c:123
return strdup("=SP r13\n" "=LR r14\n" "=PC r15\n" "=A0 r0\n" "=A1 r1\n" "=A2 r2\n" "=A3 r3\n" "=ZF zf\n" "=SF nf\n" "=OF vf\n" "=CF cf\n" "=SN or0\n" "gpr lr .32 56 0\n" "gpr pc .32 60 0\n" "gpr cpsr .32 64 0 ____tfiae_________________qvczn\n" "gpr or0 .32 68 0\n" "gpr tf .1 64.5 0 thumb\n" "gpr ef .1 64.9 0 endian\n" "gpr jf .1 64.24 0 java\n" "gpr qf .1 64.27 0 sticky_overflow\n" "gpr vf .1 64.28 0 overflow\n" "gpr cf .1 64.29 0 carry\n" "gpr zf .1 64.30 0 zero\n" "gpr nf .1 64.31 0 negative\n" "gpr itc .4 64.10 0 if_then_count\n" "gpr gef .4 64.16 0 great_or_equal\n" "gpr r0 .32 0 0\n" "gpr r1 .32 4 0\n" "gpr r2 .32 8 0\n" "gpr r3 .32 12 0\n" "gpr r4 .32 16 0\n" "gpr r5 .32 20 0\n" "gpr r6 .32 24 0\n" "gpr r7 .32 28 0\n" "gpr r8 .32 32 0\n" "gpr r9 .32 36 0\n" "gpr r10 .32 40 0\n" "gpr r11 .32 44 0\n" "gpr r12 .32 48 0\n" "gpr r13 .32 52 0\n" "gpr r14 .32 56 0\n" "gpr r15 .32 60 0\n" "gpr r16 .32 64 0\n" "gpr r17 .32 68 0\n")
#define rz_warn_if_reached()
Definition: rz_assert.h:29
#define rz_warn_if_fail(expr)
Definition: rz_assert.h:35
#define RZ_LOG_ERROR(fmtstr,...)
Definition: rz_log.h:58
RZ_API int rz_str_casecmp(const char *dst, const char *orig)
Definition: str.c:121
RZ_API const char * rz_str_trim_head_wp(const char *str)
Definition: str_trim.c:95
RZ_API const char * rz_str_trim_head_ro(const char *str)
Definition: str_trim.c:86
#define RZ_NEWS0(x, y)
Definition: rz_types.h:282
#define RZ_ARRAY_SIZE(x)
Definition: rz_types.h:300
#define st16
Definition: rz_types_base.h:14
#define st32
Definition: rz_types_base.h:12
int ssize_t
Definition: sftypes.h:39
#define b(i)
Definition: sha256.c:42
cchar * opcode
Definition: assembler.c:175
Encode encode
Definition: assembler.c:179
Definitions common to the whole liblzma library.
ut64(WINAPI *w32_GetEnabledXStateFeatures)()
static bool input(void *ud, zip_uint8_t *data, zip_uint64_t length)
diff_output_t output
Definition: zipcmp.c:237