msp430-dis.c revision 1.11 1 1.1 christos /* Disassemble MSP430 instructions.
2 1.11 christos Copyright (C) 2002-2024 Free Software Foundation, Inc.
3 1.1 christos
4 1.1 christos Contributed by Dmitry Diky <diwil (at) mail.ru>
5 1.6 christos
6 1.1 christos This file is part of the GNU opcodes library.
7 1.1 christos
8 1.1 christos This library is free software; you can redistribute it and/or modify
9 1.1 christos it under the terms of the GNU General Public License as published by
10 1.1 christos the Free Software Foundation; either version 3, or (at your option)
11 1.1 christos any later version.
12 1.1 christos
13 1.1 christos It is distributed in the hope that it will be useful, but WITHOUT
14 1.1 christos ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 1.1 christos or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
16 1.1 christos License for more details.
17 1.1 christos
18 1.1 christos You should have received a copy of the GNU General Public License
19 1.1 christos along with this program; if not, write to the Free Software
20 1.1 christos Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
21 1.1 christos MA 02110-1301, USA. */
22 1.1 christos
23 1.1 christos #include "sysdep.h"
24 1.1 christos #include <stdio.h>
25 1.1 christos #include <ctype.h>
26 1.1 christos #include <sys/types.h>
27 1.6 christos #include <errno.h>
28 1.1 christos
29 1.8 christos #include "disassemble.h"
30 1.1 christos #include "opintl.h"
31 1.1 christos #include "libiberty.h"
32 1.1 christos
33 1.1 christos #define DASM_SECTION
34 1.1 christos #include "opcode/msp430.h"
35 1.1 christos #undef DASM_SECTION
36 1.1 christos
37 1.1 christos
38 1.1 christos #define PS(x) (0xffff & (x))
39 1.1 christos
40 1.10 christos static bool
41 1.6 christos msp430dis_read_two_bytes (bfd_vma addr,
42 1.6 christos disassemble_info * info,
43 1.6 christos bfd_byte * buffer,
44 1.6 christos char * comm)
45 1.1 christos {
46 1.1 christos int status;
47 1.1 christos
48 1.1 christos status = info->read_memory_func (addr, buffer, 2, info);
49 1.6 christos if (status == 0)
50 1.10 christos return true;
51 1.6 christos
52 1.6 christos /* PR 20150: A status of EIO means that there were no more bytes left
53 1.6 christos to read in the current section. This can happen when disassembling
54 1.6 christos interrupt vectors for example. Avoid cluttering the output with
55 1.6 christos unhelpful error messages in this case. */
56 1.6 christos if (status == EIO)
57 1.6 christos {
58 1.6 christos if (comm)
59 1.6 christos sprintf (comm, _("Warning: disassembly unreliable - not enough bytes available"));
60 1.6 christos }
61 1.6 christos else
62 1.1 christos {
63 1.1 christos info->memory_error_func (status, addr, info);
64 1.6 christos if (comm)
65 1.6 christos sprintf (comm, _("Error: read from memory failed"));
66 1.6 christos }
67 1.6 christos
68 1.10 christos return false;
69 1.6 christos }
70 1.6 christos
71 1.10 christos static bool
72 1.6 christos msp430dis_opcode_unsigned (bfd_vma addr,
73 1.6 christos disassemble_info * info,
74 1.6 christos unsigned short * return_val,
75 1.6 christos char * comm)
76 1.6 christos {
77 1.6 christos bfd_byte buffer[2];
78 1.6 christos
79 1.6 christos if (msp430dis_read_two_bytes (addr, info, buffer, comm))
80 1.6 christos {
81 1.6 christos * return_val = bfd_getl16 (buffer);
82 1.10 christos return true;
83 1.6 christos }
84 1.6 christos else
85 1.6 christos {
86 1.6 christos * return_val = 0;
87 1.10 christos return false;
88 1.6 christos }
89 1.6 christos }
90 1.6 christos
91 1.10 christos static bool
92 1.6 christos msp430dis_opcode_signed (bfd_vma addr,
93 1.6 christos disassemble_info * info,
94 1.6 christos signed int * return_val,
95 1.6 christos char * comm)
96 1.6 christos {
97 1.6 christos bfd_byte buffer[2];
98 1.6 christos
99 1.6 christos if (msp430dis_read_two_bytes (addr, info, buffer, comm))
100 1.6 christos {
101 1.6 christos int status;
102 1.6 christos
103 1.6 christos status = bfd_getl_signed_16 (buffer);
104 1.6 christos if (status & 0x8000)
105 1.6 christos status |= -1U << 16;
106 1.6 christos * return_val = status;
107 1.10 christos return true;
108 1.6 christos }
109 1.6 christos else
110 1.6 christos {
111 1.6 christos * return_val = 0;
112 1.10 christos return false;
113 1.1 christos }
114 1.1 christos }
115 1.1 christos
116 1.1 christos static int
117 1.1 christos msp430_nooperands (struct msp430_opcode_s *opcode,
118 1.1 christos bfd_vma addr ATTRIBUTE_UNUSED,
119 1.1 christos unsigned short insn ATTRIBUTE_UNUSED,
120 1.1 christos char *comm,
121 1.1 christos int *cycles)
122 1.1 christos {
123 1.1 christos /* Pop with constant. */
124 1.1 christos if (insn == 0x43b2)
125 1.1 christos return 0;
126 1.1 christos if (insn == opcode->bin_opcode)
127 1.1 christos return 2;
128 1.1 christos
129 1.1 christos if (opcode->fmt == 0)
130 1.1 christos {
131 1.5 christos if ((insn & 0x0f00) != 0x0300 || (insn & 0x0f00) != 0x0200)
132 1.1 christos return 0;
133 1.1 christos
134 1.1 christos strcpy (comm, "emulated...");
135 1.1 christos *cycles = 1;
136 1.1 christos }
137 1.1 christos else
138 1.1 christos {
139 1.1 christos strcpy (comm, "return from interupt");
140 1.1 christos *cycles = 5;
141 1.1 christos }
142 1.1 christos
143 1.1 christos return 2;
144 1.1 christos }
145 1.1 christos
146 1.1 christos static int
147 1.1 christos print_as2_reg_name (int regno, char * op1, char * comm1,
148 1.1 christos int c2, int c3, int cd)
149 1.1 christos {
150 1.1 christos switch (regno)
151 1.1 christos {
152 1.1 christos case 2:
153 1.1 christos sprintf (op1, "#4");
154 1.1 christos sprintf (comm1, "r2 As==10");
155 1.1 christos return c2;
156 1.1 christos
157 1.1 christos case 3:
158 1.1 christos sprintf (op1, "#2");
159 1.1 christos sprintf (comm1, "r3 As==10");
160 1.1 christos return c3;
161 1.1 christos
162 1.1 christos default:
163 1.1 christos /* Indexed register mode @Rn. */
164 1.1 christos sprintf (op1, "@r%d", regno);
165 1.1 christos return cd;
166 1.1 christos }
167 1.1 christos }
168 1.1 christos
169 1.1 christos static int
170 1.1 christos print_as3_reg_name (int regno, char * op1, char * comm1,
171 1.1 christos int c2, int c3, int cd)
172 1.1 christos {
173 1.1 christos switch (regno)
174 1.1 christos {
175 1.1 christos case 2:
176 1.1 christos sprintf (op1, "#8");
177 1.1 christos sprintf (comm1, "r2 As==11");
178 1.1 christos return c2;
179 1.1 christos
180 1.1 christos case 3:
181 1.1 christos sprintf (op1, "#-1");
182 1.1 christos sprintf (comm1, "r3 As==11");
183 1.1 christos return c3;
184 1.1 christos
185 1.1 christos default:
186 1.1 christos /* Post incremented @Rn+. */
187 1.1 christos sprintf (op1, "@r%d+", regno);
188 1.1 christos return cd;
189 1.1 christos }
190 1.1 christos }
191 1.1 christos
192 1.1 christos static int
193 1.1 christos msp430_singleoperand (disassemble_info *info,
194 1.1 christos struct msp430_opcode_s *opcode,
195 1.1 christos bfd_vma addr,
196 1.1 christos unsigned short insn,
197 1.1 christos char *op,
198 1.1 christos char *comm,
199 1.1 christos unsigned short extension_word,
200 1.1 christos int *cycles)
201 1.1 christos {
202 1.1 christos int regs = 0, regd = 0;
203 1.1 christos int ad = 0, as = 0;
204 1.1 christos int where = 0;
205 1.1 christos int cmd_len = 2;
206 1.1 christos int dst = 0;
207 1.1 christos int fmt;
208 1.1 christos int extended_dst = extension_word & 0xf;
209 1.1 christos
210 1.1 christos regd = insn & 0x0f;
211 1.1 christos regs = (insn & 0x0f00) >> 8;
212 1.1 christos as = (insn & 0x0030) >> 4;
213 1.1 christos ad = (insn & 0x0080) >> 7;
214 1.1 christos
215 1.1 christos if (opcode->fmt < 0)
216 1.1 christos fmt = (- opcode->fmt) - 1;
217 1.1 christos else
218 1.1 christos fmt = opcode->fmt;
219 1.1 christos
220 1.1 christos switch (fmt)
221 1.1 christos {
222 1.1 christos case 0: /* Emulated work with dst register. */
223 1.1 christos if (regs != 2 && regs != 3 && regs != 1)
224 1.1 christos return 0;
225 1.1 christos
226 1.1 christos /* Check if not clr insn. */
227 1.1 christos if (opcode->bin_opcode == 0x4300 && (ad || as))
228 1.1 christos return 0;
229 1.1 christos
230 1.1 christos /* Check if really inc, incd insns. */
231 1.1 christos if ((opcode->bin_opcode & 0xff00) == 0x5300 && as == 3)
232 1.1 christos return 0;
233 1.1 christos
234 1.1 christos if (ad == 0)
235 1.1 christos {
236 1.1 christos *cycles = 1;
237 1.1 christos
238 1.1 christos /* Register. */
239 1.1 christos if (regd == 0)
240 1.1 christos {
241 1.1 christos *cycles += 1;
242 1.1 christos sprintf (op, "r0");
243 1.1 christos }
244 1.1 christos else if (regd == 1)
245 1.1 christos sprintf (op, "r1");
246 1.1 christos
247 1.1 christos else if (regd == 2)
248 1.1 christos sprintf (op, "r2");
249 1.1 christos
250 1.1 christos else
251 1.1 christos sprintf (op, "r%d", regd);
252 1.1 christos }
253 1.1 christos else /* ad == 1 msp430dis_opcode. */
254 1.1 christos {
255 1.1 christos if (regd == 0)
256 1.1 christos {
257 1.1 christos /* PC relative. */
258 1.6 christos if (msp430dis_opcode_signed (addr + 2, info, &dst, comm))
259 1.1 christos {
260 1.6 christos cmd_len += 2;
261 1.6 christos *cycles = 4;
262 1.6 christos sprintf (op, "0x%04x", dst);
263 1.6 christos sprintf (comm, "PC rel. abs addr 0x%04x",
264 1.6 christos PS ((short) (addr + 2) + dst));
265 1.6 christos if (extended_dst)
266 1.6 christos {
267 1.6 christos dst |= extended_dst << 16;
268 1.6 christos sprintf (op, "0x%05x", dst);
269 1.6 christos sprintf (comm, "PC rel. abs addr 0x%05lx",
270 1.6 christos (long)((addr + 2 + dst) & 0xfffff));
271 1.6 christos }
272 1.1 christos }
273 1.7 christos else
274 1.7 christos return -1;
275 1.1 christos }
276 1.1 christos else if (regd == 2)
277 1.1 christos {
278 1.1 christos /* Absolute. */
279 1.6 christos if (msp430dis_opcode_signed (addr + 2, info, &dst, comm))
280 1.1 christos {
281 1.6 christos cmd_len += 2;
282 1.6 christos *cycles = 4;
283 1.6 christos sprintf (op, "&0x%04x", PS (dst));
284 1.6 christos if (extended_dst)
285 1.6 christos {
286 1.6 christos dst |= extended_dst << 16;
287 1.6 christos sprintf (op, "&0x%05x", dst & 0xfffff);
288 1.6 christos }
289 1.1 christos }
290 1.7 christos else
291 1.7 christos return -1;
292 1.1 christos }
293 1.1 christos else
294 1.1 christos {
295 1.6 christos if (msp430dis_opcode_signed (addr + 2, info, &dst, comm))
296 1.1 christos {
297 1.6 christos cmd_len += 2;
298 1.6 christos *cycles = 4;
299 1.6 christos if (extended_dst)
300 1.6 christos {
301 1.6 christos dst |= extended_dst << 16;
302 1.6 christos if (dst & 0x80000)
303 1.6 christos dst |= -1U << 20;
304 1.6 christos }
305 1.6 christos sprintf (op, "%d(r%d)", dst, regd);
306 1.1 christos }
307 1.7 christos else
308 1.7 christos return -1;
309 1.1 christos }
310 1.1 christos }
311 1.1 christos break;
312 1.1 christos
313 1.1 christos case 2: /* rrc, push, call, swpb, rra, sxt, push, call, reti etc... */
314 1.1 christos if (as == 0)
315 1.1 christos {
316 1.1 christos if (regd == 3)
317 1.1 christos {
318 1.1 christos /* Constsnts. */
319 1.1 christos sprintf (op, "#0");
320 1.1 christos sprintf (comm, "r3 As==00");
321 1.1 christos }
322 1.1 christos else
323 1.1 christos {
324 1.1 christos /* Register. */
325 1.1 christos sprintf (op, "r%d", regd);
326 1.1 christos }
327 1.1 christos *cycles = 1;
328 1.1 christos }
329 1.1 christos else if (as == 2)
330 1.1 christos {
331 1.1 christos * cycles = print_as2_reg_name (regd, op, comm, 1, 1, 3);
332 1.1 christos }
333 1.1 christos else if (as == 3)
334 1.1 christos {
335 1.1 christos if (regd == 0)
336 1.1 christos {
337 1.1 christos *cycles = 3;
338 1.1 christos /* absolute. @pc+ */
339 1.6 christos if (msp430dis_opcode_signed (addr + 2, info, &dst, comm))
340 1.1 christos {
341 1.6 christos cmd_len += 2;
342 1.1 christos sprintf (op, "#%d", dst);
343 1.1 christos if (dst > 9 || dst < 0)
344 1.6 christos sprintf (comm, "#0x%04x", PS (dst));
345 1.6 christos if (extended_dst)
346 1.6 christos {
347 1.6 christos dst |= extended_dst << 16;
348 1.6 christos if (dst & 0x80000)
349 1.6 christos dst |= -1U << 20;
350 1.6 christos sprintf (op, "#%d", dst);
351 1.6 christos if (dst > 9 || dst < 0)
352 1.6 christos sprintf (comm, "#0x%05x", dst);
353 1.6 christos }
354 1.1 christos }
355 1.7 christos else
356 1.7 christos return -1;
357 1.1 christos }
358 1.1 christos else
359 1.1 christos * cycles = print_as3_reg_name (regd, op, comm, 1, 1, 3);
360 1.1 christos }
361 1.1 christos else if (as == 1)
362 1.1 christos {
363 1.1 christos *cycles = 4;
364 1.1 christos if (regd == 0)
365 1.1 christos {
366 1.1 christos /* PC relative. */
367 1.6 christos if (msp430dis_opcode_signed (addr + 2, info, &dst, comm))
368 1.1 christos {
369 1.6 christos cmd_len += 2;
370 1.6 christos sprintf (op, "0x%04x", PS (dst));
371 1.6 christos sprintf (comm, "PC rel. 0x%04x",
372 1.6 christos PS ((short) addr + 2 + dst));
373 1.6 christos if (extended_dst)
374 1.6 christos {
375 1.6 christos dst |= extended_dst << 16;
376 1.6 christos sprintf (op, "0x%05x", dst & 0xffff);
377 1.6 christos sprintf (comm, "PC rel. 0x%05lx",
378 1.6 christos (long)((addr + 2 + dst) & 0xfffff));
379 1.6 christos }
380 1.1 christos }
381 1.7 christos else
382 1.7 christos return -1;
383 1.1 christos }
384 1.1 christos else if (regd == 2)
385 1.1 christos {
386 1.1 christos /* Absolute. */
387 1.6 christos if (msp430dis_opcode_signed (addr + 2, info, &dst, comm))
388 1.1 christos {
389 1.6 christos cmd_len += 2;
390 1.6 christos sprintf (op, "&0x%04x", PS (dst));
391 1.6 christos if (extended_dst)
392 1.6 christos {
393 1.6 christos dst |= extended_dst << 16;
394 1.6 christos sprintf (op, "&0x%05x", dst & 0xfffff);
395 1.6 christos }
396 1.1 christos }
397 1.7 christos else
398 1.7 christos return -1;
399 1.1 christos }
400 1.1 christos else if (regd == 3)
401 1.1 christos {
402 1.1 christos *cycles = 1;
403 1.1 christos sprintf (op, "#1");
404 1.1 christos sprintf (comm, "r3 As==01");
405 1.1 christos }
406 1.1 christos else
407 1.1 christos {
408 1.1 christos /* Indexed. */
409 1.6 christos if (msp430dis_opcode_signed (addr + 2, info, &dst, comm))
410 1.1 christos {
411 1.6 christos cmd_len += 2;
412 1.6 christos if (extended_dst)
413 1.6 christos {
414 1.6 christos dst |= extended_dst << 16;
415 1.6 christos if (dst & 0x80000)
416 1.6 christos dst |= -1U << 20;
417 1.6 christos }
418 1.6 christos sprintf (op, "%d(r%d)", dst, regd);
419 1.6 christos if (dst > 9 || dst < 0)
420 1.6 christos sprintf (comm, "%05x", dst);
421 1.1 christos }
422 1.7 christos else
423 1.7 christos return -1;
424 1.1 christos }
425 1.1 christos }
426 1.1 christos break;
427 1.1 christos
428 1.1 christos case 3: /* Jumps. */
429 1.1 christos where = insn & 0x03ff;
430 1.1 christos if (where & 0x200)
431 1.1 christos where |= ~0x03ff;
432 1.1 christos if (where > 512 || where < -511)
433 1.1 christos return 0;
434 1.1 christos
435 1.1 christos where *= 2;
436 1.1 christos sprintf (op, "$%+-8d", where + 2);
437 1.1 christos sprintf (comm, "abs 0x%lx", (long) (addr + 2 + where));
438 1.1 christos *cycles = 2;
439 1.1 christos return 2;
440 1.1 christos break;
441 1.6 christos
442 1.1 christos default:
443 1.1 christos cmd_len = 0;
444 1.1 christos }
445 1.1 christos
446 1.1 christos return cmd_len;
447 1.1 christos }
448 1.1 christos
449 1.1 christos static int
450 1.1 christos msp430_doubleoperand (disassemble_info *info,
451 1.1 christos struct msp430_opcode_s *opcode,
452 1.1 christos bfd_vma addr,
453 1.1 christos unsigned short insn,
454 1.1 christos char *op1,
455 1.1 christos char *op2,
456 1.1 christos char *comm1,
457 1.1 christos char *comm2,
458 1.1 christos unsigned short extension_word,
459 1.1 christos int *cycles)
460 1.1 christos {
461 1.1 christos int regs = 0, regd = 0;
462 1.1 christos int ad = 0, as = 0;
463 1.1 christos int cmd_len = 2;
464 1.1 christos int dst = 0;
465 1.1 christos int fmt;
466 1.1 christos int extended_dst = extension_word & 0xf;
467 1.1 christos int extended_src = (extension_word >> 7) & 0xf;
468 1.1 christos
469 1.1 christos regd = insn & 0x0f;
470 1.1 christos regs = (insn & 0x0f00) >> 8;
471 1.1 christos as = (insn & 0x0030) >> 4;
472 1.1 christos ad = (insn & 0x0080) >> 7;
473 1.1 christos
474 1.1 christos if (opcode->fmt < 0)
475 1.1 christos fmt = (- opcode->fmt) - 1;
476 1.1 christos else
477 1.1 christos fmt = opcode->fmt;
478 1.1 christos
479 1.1 christos if (fmt == 0)
480 1.1 christos {
481 1.1 christos /* Special case: rla and rlc are the only 2 emulated instructions that
482 1.1 christos fall into two operand instructions. */
483 1.1 christos /* With dst, there are only:
484 1.1 christos Rm Register,
485 1.1 christos x(Rm) Indexed,
486 1.1 christos 0xXXXX Relative,
487 1.6 christos &0xXXXX Absolute
488 1.1 christos emulated_ins dst
489 1.1 christos basic_ins dst, dst. */
490 1.1 christos
491 1.1 christos if (regd != regs || as != ad)
492 1.1 christos return 0; /* May be 'data' section. */
493 1.1 christos
494 1.1 christos if (ad == 0)
495 1.1 christos {
496 1.1 christos /* Register mode. */
497 1.1 christos if (regd == 3)
498 1.1 christos {
499 1.6 christos strcpy (comm1, _("Warning: illegal as emulation instr"));
500 1.1 christos return -1;
501 1.1 christos }
502 1.1 christos
503 1.1 christos sprintf (op1, "r%d", regd);
504 1.1 christos *cycles = 1;
505 1.1 christos }
506 1.1 christos else /* ad == 1 */
507 1.1 christos {
508 1.1 christos if (regd == 0)
509 1.1 christos {
510 1.1 christos /* PC relative, Symbolic. */
511 1.6 christos if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1))
512 1.1 christos {
513 1.6 christos cmd_len += 4;
514 1.6 christos *cycles = 6;
515 1.6 christos sprintf (op1, "0x%04x", PS (dst));
516 1.6 christos sprintf (comm1, "PC rel. 0x%04x",
517 1.6 christos PS ((short) addr + 2 + dst));
518 1.6 christos if (extension_word)
519 1.6 christos {
520 1.6 christos dst |= extended_dst << 16;
521 1.6 christos if (dst & 0x80000)
522 1.6 christos dst |= -1U << 20;
523 1.6 christos sprintf (op1, "0x%05x", dst & 0xfffff);
524 1.6 christos sprintf (comm1, "PC rel. 0x%05lx",
525 1.6 christos (long)((addr + 2 + dst) & 0xfffff));
526 1.6 christos }
527 1.1 christos }
528 1.7 christos else
529 1.7 christos return -1;
530 1.1 christos }
531 1.1 christos else if (regd == 2)
532 1.1 christos {
533 1.1 christos /* Absolute. */
534 1.6 christos if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1))
535 1.1 christos {
536 1.6 christos int src;
537 1.6 christos
538 1.6 christos /* If the 'src' field is not the same as the dst
539 1.6 christos then this is not an rla instruction. */
540 1.6 christos if (msp430dis_opcode_signed (addr + 4, info, &src, comm2))
541 1.6 christos {
542 1.6 christos if (src != dst)
543 1.6 christos return 0;
544 1.6 christos }
545 1.7 christos else
546 1.7 christos return -1;
547 1.6 christos cmd_len += 4;
548 1.6 christos *cycles = 6;
549 1.6 christos sprintf (op1, "&0x%04x", PS (dst));
550 1.6 christos if (extension_word)
551 1.6 christos {
552 1.6 christos dst |= extended_dst << 16;
553 1.6 christos sprintf (op1, "&0x%05x", dst & 0xfffff);
554 1.6 christos }
555 1.1 christos }
556 1.7 christos else
557 1.7 christos return -1;
558 1.1 christos }
559 1.1 christos else
560 1.1 christos {
561 1.1 christos /* Indexed. */
562 1.6 christos if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1))
563 1.1 christos {
564 1.6 christos if (extension_word)
565 1.6 christos {
566 1.6 christos dst |= extended_dst << 16;
567 1.6 christos if (dst & 0x80000)
568 1.6 christos dst |= -1U << 20;
569 1.6 christos }
570 1.6 christos cmd_len += 4;
571 1.6 christos *cycles = 6;
572 1.6 christos sprintf (op1, "%d(r%d)", dst, regd);
573 1.6 christos if (dst > 9 || dst < -9)
574 1.6 christos sprintf (comm1, "#0x%05x", dst);
575 1.1 christos }
576 1.7 christos else
577 1.7 christos return -1;
578 1.1 christos }
579 1.1 christos }
580 1.1 christos
581 1.1 christos *op2 = 0;
582 1.1 christos *comm2 = 0;
583 1.1 christos
584 1.1 christos return cmd_len;
585 1.1 christos }
586 1.1 christos
587 1.1 christos /* Two operands exactly. */
588 1.1 christos if (ad == 0 && regd == 3)
589 1.1 christos {
590 1.1 christos /* R2/R3 are illegal as dest: may be data section. */
591 1.6 christos strcpy (comm1, _("Warning: illegal as 2-op instr"));
592 1.1 christos return -1;
593 1.1 christos }
594 1.1 christos
595 1.1 christos /* Source. */
596 1.1 christos if (as == 0)
597 1.1 christos {
598 1.1 christos *cycles = 1;
599 1.1 christos if (regs == 3)
600 1.1 christos {
601 1.1 christos /* Constants. */
602 1.1 christos sprintf (op1, "#0");
603 1.1 christos sprintf (comm1, "r3 As==00");
604 1.1 christos }
605 1.1 christos else
606 1.1 christos {
607 1.1 christos /* Register. */
608 1.1 christos sprintf (op1, "r%d", regs);
609 1.1 christos }
610 1.1 christos }
611 1.1 christos else if (as == 2)
612 1.1 christos {
613 1.1 christos * cycles = print_as2_reg_name (regs, op1, comm1, 1, 1, regs == 0 ? 3 : 2);
614 1.1 christos }
615 1.1 christos else if (as == 3)
616 1.1 christos {
617 1.1 christos if (regs == 0)
618 1.1 christos {
619 1.1 christos *cycles = 3;
620 1.1 christos /* Absolute. @pc+. */
621 1.6 christos if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1))
622 1.6 christos {
623 1.6 christos cmd_len += 2;
624 1.1 christos sprintf (op1, "#%d", dst);
625 1.1 christos if (dst > 9 || dst < 0)
626 1.6 christos sprintf (comm1, "#0x%04x", PS (dst));
627 1.6 christos if (extension_word)
628 1.6 christos {
629 1.6 christos dst &= 0xffff;
630 1.6 christos dst |= extended_src << 16;
631 1.6 christos if (dst & 0x80000)
632 1.6 christos dst |= -1U << 20;
633 1.6 christos sprintf (op1, "#%d", dst);
634 1.6 christos if (dst > 9 || dst < 0)
635 1.6 christos sprintf (comm1, "0x%05x", dst & 0xfffff);
636 1.6 christos }
637 1.1 christos }
638 1.7 christos else
639 1.7 christos return -1;
640 1.1 christos }
641 1.1 christos else
642 1.1 christos * cycles = print_as3_reg_name (regs, op1, comm1, 1, 1, 2);
643 1.1 christos }
644 1.1 christos else if (as == 1)
645 1.1 christos {
646 1.1 christos if (regs == 0)
647 1.1 christos {
648 1.1 christos *cycles = 4;
649 1.1 christos /* PC relative. */
650 1.6 christos if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1))
651 1.6 christos {
652 1.6 christos cmd_len += 2;
653 1.6 christos sprintf (op1, "0x%04x", PS (dst));
654 1.6 christos sprintf (comm1, "PC rel. 0x%04x",
655 1.6 christos PS ((short) addr + 2 + dst));
656 1.6 christos if (extension_word)
657 1.6 christos {
658 1.6 christos dst &= 0xffff;
659 1.6 christos dst |= extended_src << 16;
660 1.6 christos if (dst & 0x80000)
661 1.6 christos dst |= -1U << 20;
662 1.6 christos sprintf (op1, "0x%05x", dst & 0xfffff);
663 1.6 christos sprintf (comm1, "PC rel. 0x%05lx",
664 1.6 christos (long) ((addr + 2 + dst) & 0xfffff));
665 1.6 christos }
666 1.1 christos }
667 1.7 christos else
668 1.7 christos return -1;
669 1.1 christos }
670 1.1 christos else if (regs == 2)
671 1.1 christos {
672 1.1 christos *cycles = 2;
673 1.1 christos /* Absolute. */
674 1.6 christos if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1))
675 1.6 christos {
676 1.6 christos cmd_len += 2;
677 1.6 christos sprintf (op1, "&0x%04x", PS (dst));
678 1.6 christos sprintf (comm1, "0x%04x", PS (dst));
679 1.6 christos if (extension_word)
680 1.6 christos {
681 1.6 christos dst &= 0xffff;
682 1.6 christos dst |= extended_src << 16;
683 1.6 christos sprintf (op1, "&0x%05x", dst & 0xfffff);
684 1.6 christos * comm1 = 0;
685 1.6 christos }
686 1.1 christos }
687 1.7 christos else
688 1.7 christos return -1;
689 1.1 christos }
690 1.1 christos else if (regs == 3)
691 1.1 christos {
692 1.1 christos *cycles = 1;
693 1.1 christos sprintf (op1, "#1");
694 1.1 christos sprintf (comm1, "r3 As==01");
695 1.1 christos }
696 1.1 christos else
697 1.1 christos {
698 1.1 christos *cycles = 3;
699 1.1 christos /* Indexed. */
700 1.6 christos if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1))
701 1.1 christos {
702 1.6 christos cmd_len += 2;
703 1.6 christos if (extension_word)
704 1.6 christos {
705 1.6 christos dst &= 0xffff;
706 1.6 christos dst |= extended_src << 16;
707 1.6 christos if (dst & 0x80000)
708 1.6 christos dst |= -1U << 20;
709 1.6 christos }
710 1.6 christos sprintf (op1, "%d(r%d)", dst, regs);
711 1.6 christos if (dst > 9 || dst < -9)
712 1.6 christos sprintf (comm1, "0x%05x", dst);
713 1.6 christos }
714 1.7 christos else
715 1.7 christos return -1;
716 1.1 christos }
717 1.1 christos }
718 1.1 christos
719 1.1 christos /* Destination. Special care needed on addr + XXXX. */
720 1.1 christos
721 1.1 christos if (ad == 0)
722 1.1 christos {
723 1.1 christos /* Register. */
724 1.1 christos if (regd == 0)
725 1.1 christos {
726 1.1 christos *cycles += 1;
727 1.1 christos sprintf (op2, "r0");
728 1.1 christos }
729 1.1 christos else if (regd == 1)
730 1.1 christos sprintf (op2, "r1");
731 1.1 christos
732 1.1 christos else if (regd == 2)
733 1.1 christos sprintf (op2, "r2");
734 1.1 christos
735 1.1 christos else
736 1.1 christos sprintf (op2, "r%d", regd);
737 1.1 christos }
738 1.1 christos else /* ad == 1. */
739 1.1 christos {
740 1.1 christos * cycles += 3;
741 1.1 christos
742 1.1 christos if (regd == 0)
743 1.1 christos {
744 1.1 christos /* PC relative. */
745 1.1 christos *cycles += 1;
746 1.6 christos if (msp430dis_opcode_signed (addr + cmd_len, info, &dst, comm2))
747 1.6 christos {
748 1.6 christos sprintf (op2, "0x%04x", PS (dst));
749 1.6 christos sprintf (comm2, "PC rel. 0x%04x",
750 1.6 christos PS ((short) addr + cmd_len + dst));
751 1.6 christos if (extension_word)
752 1.6 christos {
753 1.6 christos dst |= extended_dst << 16;
754 1.6 christos if (dst & 0x80000)
755 1.6 christos dst |= -1U << 20;
756 1.6 christos sprintf (op2, "0x%05x", dst & 0xfffff);
757 1.6 christos sprintf (comm2, "PC rel. 0x%05lx",
758 1.6 christos (long)((addr + cmd_len + dst) & 0xfffff));
759 1.6 christos }
760 1.1 christos }
761 1.7 christos else
762 1.7 christos return -1;
763 1.1 christos cmd_len += 2;
764 1.1 christos }
765 1.1 christos else if (regd == 2)
766 1.1 christos {
767 1.1 christos /* Absolute. */
768 1.6 christos if (msp430dis_opcode_signed (addr + cmd_len, info, &dst, comm2))
769 1.1 christos {
770 1.6 christos cmd_len += 2;
771 1.6 christos sprintf (op2, "&0x%04x", PS (dst));
772 1.6 christos if (extension_word)
773 1.6 christos {
774 1.6 christos dst |= extended_dst << 16;
775 1.6 christos sprintf (op2, "&0x%05x", dst & 0xfffff);
776 1.6 christos }
777 1.1 christos }
778 1.7 christos else
779 1.7 christos return -1;
780 1.1 christos }
781 1.1 christos else
782 1.1 christos {
783 1.6 christos if (msp430dis_opcode_signed (addr + cmd_len, info, &dst, comm2))
784 1.6 christos {
785 1.6 christos cmd_len += 2;
786 1.1 christos if (dst > 9 || dst < 0)
787 1.6 christos sprintf (comm2, "0x%04x", PS (dst));
788 1.6 christos if (extension_word)
789 1.6 christos {
790 1.6 christos dst |= extended_dst << 16;
791 1.6 christos if (dst & 0x80000)
792 1.6 christos dst |= -1U << 20;
793 1.6 christos if (dst > 9 || dst < 0)
794 1.6 christos sprintf (comm2, "0x%05x", dst & 0xfffff);
795 1.6 christos }
796 1.6 christos sprintf (op2, "%d(r%d)", dst, regd);
797 1.1 christos }
798 1.7 christos else
799 1.7 christos return -1;
800 1.1 christos }
801 1.1 christos }
802 1.1 christos
803 1.1 christos return cmd_len;
804 1.1 christos }
805 1.1 christos
806 1.1 christos static int
807 1.1 christos msp430_branchinstr (disassemble_info *info,
808 1.1 christos struct msp430_opcode_s *opcode ATTRIBUTE_UNUSED,
809 1.1 christos bfd_vma addr ATTRIBUTE_UNUSED,
810 1.1 christos unsigned short insn,
811 1.1 christos char *op1,
812 1.1 christos char *comm1,
813 1.1 christos int *cycles)
814 1.1 christos {
815 1.1 christos int regs = 0, regd = 0;
816 1.1 christos int as = 0;
817 1.1 christos int cmd_len = 2;
818 1.6 christos int dst = 0;
819 1.6 christos unsigned short udst = 0;
820 1.1 christos
821 1.1 christos regd = insn & 0x0f;
822 1.1 christos regs = (insn & 0x0f00) >> 8;
823 1.1 christos as = (insn & 0x0030) >> 4;
824 1.1 christos
825 1.1 christos if (regd != 0) /* Destination register is not a PC. */
826 1.1 christos return 0;
827 1.1 christos
828 1.1 christos /* dst is a source register. */
829 1.1 christos if (as == 0)
830 1.1 christos {
831 1.1 christos /* Constants. */
832 1.1 christos if (regs == 3)
833 1.1 christos {
834 1.1 christos *cycles = 1;
835 1.1 christos sprintf (op1, "#0");
836 1.1 christos sprintf (comm1, "r3 As==00");
837 1.1 christos }
838 1.1 christos else
839 1.1 christos {
840 1.1 christos /* Register. */
841 1.1 christos *cycles = 1;
842 1.1 christos sprintf (op1, "r%d", regs);
843 1.1 christos }
844 1.1 christos }
845 1.1 christos else if (as == 2)
846 1.1 christos {
847 1.1 christos * cycles = print_as2_reg_name (regs, op1, comm1, 2, 1, 2);
848 1.1 christos }
849 1.1 christos else if (as == 3)
850 1.1 christos {
851 1.1 christos if (regs == 0)
852 1.1 christos {
853 1.1 christos /* Absolute. @pc+ */
854 1.1 christos *cycles = 3;
855 1.6 christos if (msp430dis_opcode_unsigned (addr + 2, info, &udst, comm1))
856 1.6 christos {
857 1.6 christos cmd_len += 2;
858 1.6 christos sprintf (op1, "#0x%04x", PS (udst));
859 1.6 christos }
860 1.7 christos else
861 1.7 christos return -1;
862 1.1 christos }
863 1.1 christos else
864 1.1 christos * cycles = print_as3_reg_name (regs, op1, comm1, 1, 1, 2);
865 1.1 christos }
866 1.1 christos else if (as == 1)
867 1.1 christos {
868 1.1 christos * cycles = 3;
869 1.1 christos
870 1.1 christos if (regs == 0)
871 1.1 christos {
872 1.1 christos /* PC relative. */
873 1.6 christos if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1))
874 1.6 christos {
875 1.6 christos cmd_len += 2;
876 1.6 christos (*cycles)++;
877 1.6 christos sprintf (op1, "0x%04x", PS (dst));
878 1.6 christos sprintf (comm1, "PC rel. 0x%04x",
879 1.6 christos PS ((short) addr + 2 + dst));
880 1.6 christos }
881 1.7 christos else
882 1.7 christos return -1;
883 1.1 christos }
884 1.1 christos else if (regs == 2)
885 1.1 christos {
886 1.1 christos /* Absolute. */
887 1.6 christos if (msp430dis_opcode_unsigned (addr + 2, info, &udst, comm1))
888 1.6 christos {
889 1.6 christos cmd_len += 2;
890 1.6 christos sprintf (op1, "&0x%04x", PS (udst));
891 1.6 christos }
892 1.7 christos else
893 1.7 christos return -1;
894 1.1 christos }
895 1.1 christos else if (regs == 3)
896 1.1 christos {
897 1.1 christos (*cycles)--;
898 1.1 christos sprintf (op1, "#1");
899 1.1 christos sprintf (comm1, "r3 As==01");
900 1.1 christos }
901 1.1 christos else
902 1.1 christos {
903 1.1 christos /* Indexed. */
904 1.6 christos if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1))
905 1.6 christos {
906 1.6 christos cmd_len += 2;
907 1.6 christos sprintf (op1, "%d(r%d)", dst, regs);
908 1.6 christos }
909 1.7 christos else
910 1.7 christos return -1;
911 1.1 christos }
912 1.1 christos }
913 1.1 christos
914 1.1 christos return cmd_len;
915 1.1 christos }
916 1.1 christos
917 1.1 christos static int
918 1.1 christos msp430x_calla_instr (disassemble_info * info,
919 1.1 christos bfd_vma addr,
920 1.1 christos unsigned short insn,
921 1.1 christos char * op1,
922 1.1 christos char * comm1,
923 1.1 christos int * cycles)
924 1.1 christos {
925 1.1 christos unsigned int ureg = insn & 0xf;
926 1.1 christos int reg = insn & 0xf;
927 1.1 christos int am = (insn & 0xf0) >> 4;
928 1.1 christos int cmd_len = 2;
929 1.1 christos unsigned short udst = 0;
930 1.6 christos int dst = 0;
931 1.1 christos
932 1.1 christos switch (am)
933 1.1 christos {
934 1.1 christos case 4: /* CALLA Rdst */
935 1.1 christos *cycles = 1;
936 1.1 christos sprintf (op1, "r%d", reg);
937 1.1 christos break;
938 1.1 christos
939 1.1 christos case 5: /* CALLA x(Rdst) */
940 1.1 christos *cycles = 3;
941 1.6 christos if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1))
942 1.6 christos {
943 1.6 christos cmd_len += 2;
944 1.6 christos sprintf (op1, "%d(r%d)", dst, reg);
945 1.6 christos if (reg == 0)
946 1.6 christos sprintf (comm1, "PC rel. 0x%05lx", (long) (addr + 2 + dst));
947 1.6 christos else
948 1.6 christos sprintf (comm1, "0x%05x", dst);
949 1.6 christos }
950 1.7 christos else
951 1.7 christos return -1;
952 1.1 christos break;
953 1.1 christos
954 1.1 christos case 6: /* CALLA @Rdst */
955 1.1 christos *cycles = 2;
956 1.1 christos sprintf (op1, "@r%d", reg);
957 1.1 christos break;
958 1.1 christos
959 1.1 christos case 7: /* CALLA @Rdst+ */
960 1.1 christos *cycles = 2;
961 1.1 christos sprintf (op1, "@r%d+", reg);
962 1.1 christos break;
963 1.1 christos
964 1.1 christos case 8: /* CALLA &abs20 */
965 1.6 christos if (msp430dis_opcode_unsigned (addr + 2, info, &udst, comm1))
966 1.6 christos {
967 1.6 christos cmd_len += 2;
968 1.6 christos *cycles = 4;
969 1.6 christos sprintf (op1, "&%d", (ureg << 16) + udst);
970 1.6 christos sprintf (comm1, "0x%05x", (ureg << 16) + udst);
971 1.6 christos }
972 1.7 christos else
973 1.7 christos return -1;
974 1.1 christos break;
975 1.1 christos
976 1.1 christos case 9: /* CALLA pcrel-sym */
977 1.6 christos if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1))
978 1.6 christos {
979 1.6 christos cmd_len += 2;
980 1.6 christos *cycles = 4;
981 1.6 christos sprintf (op1, "%d(PC)", (reg << 16) + dst);
982 1.6 christos sprintf (comm1, "PC rel. 0x%05lx",
983 1.6 christos (long) (addr + 2 + dst + (reg << 16)));
984 1.6 christos }
985 1.7 christos else
986 1.7 christos return -1;
987 1.1 christos break;
988 1.1 christos
989 1.1 christos case 11: /* CALLA #imm20 */
990 1.6 christos if (msp430dis_opcode_unsigned (addr + 2, info, &udst, comm1))
991 1.6 christos {
992 1.6 christos cmd_len += 2;
993 1.6 christos *cycles = 4;
994 1.6 christos sprintf (op1, "#%d", (ureg << 16) + udst);
995 1.6 christos sprintf (comm1, "0x%05x", (ureg << 16) + udst);
996 1.6 christos }
997 1.7 christos else
998 1.7 christos return -1;
999 1.1 christos break;
1000 1.1 christos
1001 1.1 christos default:
1002 1.6 christos strcpy (comm1, _("Warning: unrecognised CALLA addressing mode"));
1003 1.1 christos return -1;
1004 1.1 christos }
1005 1.1 christos
1006 1.1 christos return cmd_len;
1007 1.1 christos }
1008 1.1 christos
1009 1.1 christos int
1010 1.1 christos print_insn_msp430 (bfd_vma addr, disassemble_info *info)
1011 1.1 christos {
1012 1.1 christos void *stream = info->stream;
1013 1.1 christos fprintf_ftype prin = info->fprintf_func;
1014 1.1 christos struct msp430_opcode_s *opcode;
1015 1.1 christos char op1[32], op2[32], comm1[64], comm2[64];
1016 1.1 christos int cmd_len = 0;
1017 1.1 christos unsigned short insn;
1018 1.1 christos int cycles = 0;
1019 1.1 christos char *bc = "";
1020 1.1 christos unsigned short extension_word = 0;
1021 1.6 christos unsigned short bits;
1022 1.1 christos
1023 1.6 christos if (! msp430dis_opcode_unsigned (addr, info, &insn, NULL))
1024 1.7 christos return -1;
1025 1.1 christos
1026 1.1 christos if (((int) addr & 0xffff) > 0xffdf)
1027 1.1 christos {
1028 1.1 christos (*prin) (stream, "interrupt service routine at 0x%04x", 0xffff & insn);
1029 1.1 christos return 2;
1030 1.1 christos }
1031 1.1 christos
1032 1.1 christos *comm1 = 0;
1033 1.1 christos *comm2 = 0;
1034 1.1 christos
1035 1.1 christos /* Check for an extension word. */
1036 1.1 christos if ((insn & 0xf800) == 0x1800)
1037 1.1 christos {
1038 1.1 christos extension_word = insn;
1039 1.1 christos addr += 2;
1040 1.6 christos if (! msp430dis_opcode_unsigned (addr, info, &insn, NULL))
1041 1.7 christos return -1;
1042 1.1 christos }
1043 1.1 christos
1044 1.1 christos for (opcode = msp430_opcodes; opcode->name; opcode++)
1045 1.1 christos {
1046 1.1 christos if ((insn & opcode->bin_mask) == opcode->bin_opcode
1047 1.1 christos && opcode->bin_opcode != 0x9300)
1048 1.1 christos {
1049 1.1 christos *op1 = 0;
1050 1.1 christos *op2 = 0;
1051 1.1 christos *comm1 = 0;
1052 1.1 christos *comm2 = 0;
1053 1.1 christos
1054 1.1 christos /* r0 as destination. Ad should be zero. */
1055 1.1 christos if (opcode->insn_opnumb == 3
1056 1.1 christos && (insn & 0x000f) == 0
1057 1.1 christos && (insn & 0x0080) == 0)
1058 1.1 christos {
1059 1.7 christos int ret =
1060 1.1 christos msp430_branchinstr (info, opcode, addr, insn, op1, comm1,
1061 1.1 christos &cycles);
1062 1.7 christos
1063 1.7 christos if (ret == -1)
1064 1.7 christos return -1;
1065 1.7 christos cmd_len += ret;
1066 1.1 christos if (cmd_len)
1067 1.1 christos break;
1068 1.1 christos }
1069 1.1 christos
1070 1.1 christos switch (opcode->insn_opnumb)
1071 1.1 christos {
1072 1.1 christos int n;
1073 1.1 christos int reg;
1074 1.7 christos int ret;
1075 1.1 christos
1076 1.1 christos case 4:
1077 1.7 christos ret = msp430x_calla_instr (info, addr, insn,
1078 1.7 christos op1, comm1, & cycles);
1079 1.7 christos if (ret == -1)
1080 1.7 christos return -1;
1081 1.7 christos cmd_len += ret;
1082 1.1 christos break;
1083 1.1 christos
1084 1.1 christos case 5: /* PUSHM/POPM */
1085 1.1 christos n = (insn & 0xf0) >> 4;
1086 1.1 christos reg = (insn & 0xf);
1087 1.1 christos
1088 1.1 christos sprintf (op1, "#%d", n + 1);
1089 1.1 christos if (opcode->bin_opcode == 0x1400)
1090 1.1 christos /* PUSHM */
1091 1.1 christos sprintf (op2, "r%d", reg);
1092 1.1 christos else
1093 1.1 christos /* POPM */
1094 1.1 christos sprintf (op2, "r%d", reg + n);
1095 1.1 christos if (insn & 0x100)
1096 1.1 christos sprintf (comm1, "16-bit words");
1097 1.1 christos else
1098 1.1 christos {
1099 1.1 christos sprintf (comm1, "20-bit words");
1100 1.1 christos bc =".a";
1101 1.1 christos }
1102 1.6 christos
1103 1.1 christos cycles = 2; /*FIXME*/
1104 1.1 christos cmd_len = 2;
1105 1.1 christos break;
1106 1.1 christos
1107 1.1 christos case 6: /* RRAM, RRCM, RRUM, RLAM. */
1108 1.1 christos n = ((insn >> 10) & 0x3) + 1;
1109 1.1 christos reg = (insn & 0xf);
1110 1.1 christos if ((insn & 0x10) == 0)
1111 1.1 christos bc =".a";
1112 1.1 christos sprintf (op1, "#%d", n);
1113 1.1 christos sprintf (op2, "r%d", reg);
1114 1.1 christos cycles = 2; /*FIXME*/
1115 1.1 christos cmd_len = 2;
1116 1.1 christos break;
1117 1.1 christos
1118 1.1 christos case 8: /* ADDA, CMPA, SUBA. */
1119 1.1 christos reg = (insn & 0xf);
1120 1.1 christos n = (insn >> 8) & 0xf;
1121 1.1 christos if (insn & 0x40)
1122 1.1 christos {
1123 1.1 christos sprintf (op1, "r%d", n);
1124 1.1 christos cmd_len = 2;
1125 1.1 christos }
1126 1.1 christos else
1127 1.1 christos {
1128 1.1 christos n <<= 16;
1129 1.6 christos if (msp430dis_opcode_unsigned (addr + 2, info, &bits, comm1))
1130 1.6 christos {
1131 1.6 christos n |= bits;
1132 1.6 christos sprintf (op1, "#%d", n);
1133 1.6 christos if (n > 9 || n < 0)
1134 1.6 christos sprintf (comm1, "0x%05x", n);
1135 1.6 christos }
1136 1.7 christos else
1137 1.7 christos return -1;
1138 1.1 christos cmd_len = 4;
1139 1.1 christos }
1140 1.1 christos sprintf (op2, "r%d", reg);
1141 1.1 christos cycles = 2; /*FIXME*/
1142 1.1 christos break;
1143 1.1 christos
1144 1.1 christos case 9: /* MOVA */
1145 1.1 christos reg = (insn & 0xf);
1146 1.1 christos n = (insn >> 8) & 0xf;
1147 1.1 christos switch ((insn >> 4) & 0xf)
1148 1.1 christos {
1149 1.1 christos case 0: /* MOVA @Rsrc, Rdst */
1150 1.1 christos cmd_len = 2;
1151 1.1 christos sprintf (op1, "@r%d", n);
1152 1.1 christos if (strcmp (opcode->name, "bra") != 0)
1153 1.1 christos sprintf (op2, "r%d", reg);
1154 1.1 christos break;
1155 1.6 christos
1156 1.1 christos case 1: /* MOVA @Rsrc+, Rdst */
1157 1.1 christos cmd_len = 2;
1158 1.1 christos if (strcmp (opcode->name, "reta") != 0)
1159 1.1 christos {
1160 1.1 christos sprintf (op1, "@r%d+", n);
1161 1.1 christos if (strcmp (opcode->name, "bra") != 0)
1162 1.1 christos sprintf (op2, "r%d", reg);
1163 1.1 christos }
1164 1.1 christos break;
1165 1.6 christos
1166 1.1 christos case 2: /* MOVA &abs20, Rdst */
1167 1.1 christos cmd_len = 4;
1168 1.1 christos n <<= 16;
1169 1.6 christos if (msp430dis_opcode_unsigned (addr + 2, info, &bits, comm1))
1170 1.6 christos {
1171 1.6 christos n |= bits;
1172 1.6 christos sprintf (op1, "&%d", n);
1173 1.6 christos if (n > 9 || n < 0)
1174 1.6 christos sprintf (comm1, "0x%05x", n);
1175 1.6 christos if (strcmp (opcode->name, "bra") != 0)
1176 1.6 christos sprintf (op2, "r%d", reg);
1177 1.6 christos }
1178 1.7 christos else
1179 1.7 christos return -1;
1180 1.1 christos break;
1181 1.6 christos
1182 1.1 christos case 3: /* MOVA x(Rsrc), Rdst */
1183 1.1 christos cmd_len = 4;
1184 1.1 christos if (strcmp (opcode->name, "bra") != 0)
1185 1.1 christos sprintf (op2, "r%d", reg);
1186 1.1 christos reg = n;
1187 1.6 christos if (msp430dis_opcode_signed (addr + 2, info, &n, comm1))
1188 1.6 christos {
1189 1.6 christos sprintf (op1, "%d(r%d)", n, reg);
1190 1.6 christos if (n > 9 || n < 0)
1191 1.6 christos {
1192 1.6 christos if (reg == 0)
1193 1.6 christos sprintf (comm1, "PC rel. 0x%05lx",
1194 1.6 christos (long) (addr + 2 + n));
1195 1.6 christos else
1196 1.6 christos sprintf (comm1, "0x%05x", n);
1197 1.6 christos }
1198 1.1 christos }
1199 1.7 christos else
1200 1.7 christos return -1;
1201 1.1 christos break;
1202 1.1 christos
1203 1.1 christos case 6: /* MOVA Rsrc, &abs20 */
1204 1.1 christos cmd_len = 4;
1205 1.1 christos reg <<= 16;
1206 1.6 christos if (msp430dis_opcode_unsigned (addr + 2, info, &bits, comm2))
1207 1.6 christos {
1208 1.6 christos reg |= bits;
1209 1.6 christos sprintf (op1, "r%d", n);
1210 1.6 christos sprintf (op2, "&%d", reg);
1211 1.6 christos if (reg > 9 || reg < 0)
1212 1.6 christos sprintf (comm2, "0x%05x", reg);
1213 1.6 christos }
1214 1.7 christos else
1215 1.7 christos return -1;
1216 1.1 christos break;
1217 1.1 christos
1218 1.1 christos case 7: /* MOVA Rsrc, x(Rdst) */
1219 1.1 christos cmd_len = 4;
1220 1.1 christos sprintf (op1, "r%d", n);
1221 1.6 christos if (msp430dis_opcode_signed (addr + 2, info, &n, comm2))
1222 1.6 christos {
1223 1.6 christos sprintf (op2, "%d(r%d)", n, reg);
1224 1.6 christos if (n > 9 || n < 0)
1225 1.6 christos {
1226 1.6 christos if (reg == 0)
1227 1.6 christos sprintf (comm2, "PC rel. 0x%05lx",
1228 1.6 christos (long) (addr + 2 + n));
1229 1.6 christos else
1230 1.6 christos sprintf (comm2, "0x%05x", n);
1231 1.6 christos }
1232 1.1 christos }
1233 1.7 christos else
1234 1.7 christos return -1;
1235 1.1 christos break;
1236 1.6 christos
1237 1.1 christos case 8: /* MOVA #imm20, Rdst */
1238 1.1 christos cmd_len = 4;
1239 1.1 christos n <<= 16;
1240 1.6 christos if (msp430dis_opcode_unsigned (addr + 2, info, &bits, comm1))
1241 1.6 christos {
1242 1.6 christos n |= bits;
1243 1.6 christos if (n & 0x80000)
1244 1.6 christos n |= -1U << 20;
1245 1.6 christos sprintf (op1, "#%d", n);
1246 1.6 christos if (n > 9 || n < 0)
1247 1.6 christos sprintf (comm1, "0x%05x", n);
1248 1.6 christos if (strcmp (opcode->name, "bra") != 0)
1249 1.6 christos sprintf (op2, "r%d", reg);
1250 1.6 christos }
1251 1.7 christos else
1252 1.7 christos return -1;
1253 1.1 christos break;
1254 1.6 christos
1255 1.1 christos case 12: /* MOVA Rsrc, Rdst */
1256 1.1 christos cmd_len = 2;
1257 1.1 christos sprintf (op1, "r%d", n);
1258 1.1 christos if (strcmp (opcode->name, "bra") != 0)
1259 1.1 christos sprintf (op2, "r%d", reg);
1260 1.1 christos break;
1261 1.1 christos
1262 1.1 christos default:
1263 1.1 christos break;
1264 1.1 christos }
1265 1.1 christos cycles = 2; /* FIXME */
1266 1.1 christos break;
1267 1.1 christos }
1268 1.1 christos
1269 1.1 christos if (cmd_len)
1270 1.1 christos break;
1271 1.1 christos
1272 1.1 christos switch (opcode->insn_opnumb)
1273 1.1 christos {
1274 1.7 christos int ret;
1275 1.7 christos
1276 1.1 christos case 0:
1277 1.1 christos cmd_len += msp430_nooperands (opcode, addr, insn, comm1, &cycles);
1278 1.1 christos break;
1279 1.1 christos case 2:
1280 1.7 christos ret =
1281 1.1 christos msp430_doubleoperand (info, opcode, addr, insn, op1, op2,
1282 1.1 christos comm1, comm2,
1283 1.1 christos extension_word,
1284 1.1 christos &cycles);
1285 1.7 christos
1286 1.7 christos if (ret == -1)
1287 1.7 christos return -1;
1288 1.7 christos cmd_len += ret;
1289 1.1 christos if (insn & BYTE_OPERATION)
1290 1.1 christos {
1291 1.1 christos if (extension_word != 0 && ((extension_word & BYTE_OPERATION) == 0))
1292 1.1 christos bc = ".a";
1293 1.1 christos else
1294 1.1 christos bc = ".b";
1295 1.1 christos }
1296 1.1 christos else if (extension_word)
1297 1.1 christos {
1298 1.6 christos if (extension_word & BYTE_OPERATION)
1299 1.1 christos bc = ".w";
1300 1.1 christos else
1301 1.1 christos {
1302 1.1 christos bc = ".?";
1303 1.6 christos sprintf (comm2, _("Warning: reserved use of A/L and B/W bits detected"));
1304 1.1 christos }
1305 1.1 christos }
1306 1.6 christos
1307 1.1 christos break;
1308 1.1 christos case 1:
1309 1.7 christos ret =
1310 1.1 christos msp430_singleoperand (info, opcode, addr, insn, op1, comm1,
1311 1.1 christos extension_word,
1312 1.1 christos &cycles);
1313 1.7 christos
1314 1.7 christos if (ret == -1)
1315 1.7 christos return -1;
1316 1.7 christos cmd_len += ret;
1317 1.1 christos if (extension_word
1318 1.1 christos && (strcmp (opcode->name, "swpb") == 0
1319 1.1 christos || strcmp (opcode->name, "sxt") == 0))
1320 1.1 christos {
1321 1.1 christos if (insn & BYTE_OPERATION)
1322 1.1 christos {
1323 1.1 christos bc = ".?";
1324 1.6 christos sprintf (comm2, _("Warning: reserved use of A/L and B/W bits detected"));
1325 1.1 christos }
1326 1.1 christos else if (extension_word & BYTE_OPERATION)
1327 1.1 christos bc = ".w";
1328 1.1 christos else
1329 1.1 christos bc = ".a";
1330 1.1 christos }
1331 1.1 christos else if (insn & BYTE_OPERATION && opcode->fmt != 3)
1332 1.1 christos {
1333 1.1 christos if (extension_word != 0 && ((extension_word & BYTE_OPERATION) == 0))
1334 1.1 christos bc = ".a";
1335 1.1 christos else
1336 1.1 christos bc = ".b";
1337 1.1 christos }
1338 1.1 christos else if (extension_word)
1339 1.1 christos {
1340 1.1 christos if (extension_word & (1 << 6))
1341 1.1 christos bc = ".w";
1342 1.1 christos else
1343 1.1 christos {
1344 1.1 christos bc = ".?";
1345 1.6 christos sprintf (comm2, _("Warning: reserved use of A/L and B/W bits detected"));
1346 1.1 christos }
1347 1.1 christos }
1348 1.1 christos break;
1349 1.1 christos default:
1350 1.1 christos break;
1351 1.1 christos }
1352 1.1 christos }
1353 1.1 christos
1354 1.1 christos if (cmd_len)
1355 1.1 christos break;
1356 1.1 christos }
1357 1.1 christos
1358 1.1 christos if (cmd_len < 1)
1359 1.1 christos {
1360 1.1 christos /* Unknown opcode, or invalid combination of operands. */
1361 1.1 christos if (extension_word)
1362 1.1 christos {
1363 1.1 christos prin (stream, ".word 0x%04x, 0x%04x; ????", extension_word, PS (insn));
1364 1.1 christos if (*comm1)
1365 1.1 christos prin (stream, "\t %s", comm1);
1366 1.1 christos return 4;
1367 1.1 christos }
1368 1.1 christos (*prin) (stream, ".word 0x%04x; ????", PS (insn));
1369 1.1 christos return 2;
1370 1.1 christos }
1371 1.1 christos
1372 1.1 christos /* Display the repeat count (if set) for extended register mode. */
1373 1.1 christos if (cmd_len == 2 && ((extension_word & 0xf) != 0))
1374 1.1 christos {
1375 1.1 christos if (extension_word & (1 << 7))
1376 1.1 christos prin (stream, "rpt r%d { ", extension_word & 0xf);
1377 1.1 christos else
1378 1.1 christos prin (stream, "rpt #%d { ", (extension_word & 0xf) + 1);
1379 1.1 christos }
1380 1.1 christos
1381 1.6 christos /* Special case: RRC with an extension word and the ZC bit set is actually RRU. */
1382 1.6 christos if (extension_word
1383 1.6 christos && (extension_word & IGNORE_CARRY_BIT)
1384 1.6 christos && strcmp (opcode->name, "rrc") == 0)
1385 1.6 christos (*prin) (stream, "rrux%s", bc);
1386 1.6 christos else if (extension_word && opcode->name[strlen (opcode->name) - 1] != 'x')
1387 1.1 christos (*prin) (stream, "%sx%s", opcode->name, bc);
1388 1.1 christos else
1389 1.1 christos (*prin) (stream, "%s%s", opcode->name, bc);
1390 1.1 christos
1391 1.1 christos if (*op1)
1392 1.1 christos (*prin) (stream, "\t%s", op1);
1393 1.1 christos if (*op2)
1394 1.1 christos (*prin) (stream, ",");
1395 1.1 christos
1396 1.1 christos if (strlen (op1) < 7)
1397 1.1 christos (*prin) (stream, "\t");
1398 1.1 christos if (!strlen (op1))
1399 1.1 christos (*prin) (stream, "\t");
1400 1.1 christos
1401 1.1 christos if (*op2)
1402 1.1 christos (*prin) (stream, "%s", op2);
1403 1.1 christos if (strlen (op2) < 8)
1404 1.1 christos (*prin) (stream, "\t");
1405 1.1 christos
1406 1.1 christos if (*comm1 || *comm2)
1407 1.1 christos (*prin) (stream, ";");
1408 1.1 christos else if (cycles)
1409 1.1 christos {
1410 1.1 christos if (*op2)
1411 1.1 christos (*prin) (stream, ";");
1412 1.1 christos else
1413 1.1 christos {
1414 1.1 christos if (strlen (op1) < 7)
1415 1.1 christos (*prin) (stream, ";");
1416 1.1 christos else
1417 1.1 christos (*prin) (stream, "\t;");
1418 1.1 christos }
1419 1.1 christos }
1420 1.1 christos if (*comm1)
1421 1.1 christos (*prin) (stream, "%s", comm1);
1422 1.1 christos if (*comm1 && *comm2)
1423 1.1 christos (*prin) (stream, ",");
1424 1.1 christos if (*comm2)
1425 1.1 christos (*prin) (stream, " %s", comm2);
1426 1.1 christos
1427 1.1 christos if (extension_word)
1428 1.1 christos cmd_len += 2;
1429 1.1 christos
1430 1.1 christos return cmd_len;
1431 1.1 christos }
1432