msp430-dis.c revision 1.6 1 1.1 christos /* Disassemble MSP430 instructions.
2 1.6 christos Copyright (C) 2002-2016 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.1 christos #include "dis-asm.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.6 christos static bfd_boolean
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.6 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.6 christos return FALSE;
69 1.6 christos }
70 1.6 christos
71 1.6 christos static bfd_boolean
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.6 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.6 christos return FALSE;
88 1.6 christos }
89 1.6 christos }
90 1.6 christos
91 1.6 christos static bfd_boolean
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.6 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.6 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.1 christos }
274 1.1 christos else if (regd == 2)
275 1.1 christos {
276 1.1 christos /* Absolute. */
277 1.6 christos if (msp430dis_opcode_signed (addr + 2, info, &dst, comm))
278 1.1 christos {
279 1.6 christos cmd_len += 2;
280 1.6 christos *cycles = 4;
281 1.6 christos sprintf (op, "&0x%04x", PS (dst));
282 1.6 christos if (extended_dst)
283 1.6 christos {
284 1.6 christos dst |= extended_dst << 16;
285 1.6 christos sprintf (op, "&0x%05x", dst & 0xfffff);
286 1.6 christos }
287 1.1 christos }
288 1.1 christos }
289 1.1 christos else
290 1.1 christos {
291 1.6 christos if (msp430dis_opcode_signed (addr + 2, info, &dst, comm))
292 1.1 christos {
293 1.6 christos cmd_len += 2;
294 1.6 christos *cycles = 4;
295 1.6 christos if (extended_dst)
296 1.6 christos {
297 1.6 christos dst |= extended_dst << 16;
298 1.6 christos if (dst & 0x80000)
299 1.6 christos dst |= -1U << 20;
300 1.6 christos }
301 1.6 christos sprintf (op, "%d(r%d)", dst, regd);
302 1.1 christos }
303 1.1 christos }
304 1.1 christos }
305 1.1 christos break;
306 1.1 christos
307 1.1 christos case 2: /* rrc, push, call, swpb, rra, sxt, push, call, reti etc... */
308 1.1 christos if (as == 0)
309 1.1 christos {
310 1.1 christos if (regd == 3)
311 1.1 christos {
312 1.1 christos /* Constsnts. */
313 1.1 christos sprintf (op, "#0");
314 1.1 christos sprintf (comm, "r3 As==00");
315 1.1 christos }
316 1.1 christos else
317 1.1 christos {
318 1.1 christos /* Register. */
319 1.1 christos sprintf (op, "r%d", regd);
320 1.1 christos }
321 1.1 christos *cycles = 1;
322 1.1 christos }
323 1.1 christos else if (as == 2)
324 1.1 christos {
325 1.1 christos * cycles = print_as2_reg_name (regd, op, comm, 1, 1, 3);
326 1.1 christos }
327 1.1 christos else if (as == 3)
328 1.1 christos {
329 1.1 christos if (regd == 0)
330 1.1 christos {
331 1.1 christos *cycles = 3;
332 1.1 christos /* absolute. @pc+ */
333 1.6 christos if (msp430dis_opcode_signed (addr + 2, info, &dst, comm))
334 1.1 christos {
335 1.6 christos cmd_len += 2;
336 1.1 christos sprintf (op, "#%d", dst);
337 1.1 christos if (dst > 9 || dst < 0)
338 1.6 christos sprintf (comm, "#0x%04x", PS (dst));
339 1.6 christos if (extended_dst)
340 1.6 christos {
341 1.6 christos dst |= extended_dst << 16;
342 1.6 christos if (dst & 0x80000)
343 1.6 christos dst |= -1U << 20;
344 1.6 christos sprintf (op, "#%d", dst);
345 1.6 christos if (dst > 9 || dst < 0)
346 1.6 christos sprintf (comm, "#0x%05x", dst);
347 1.6 christos }
348 1.1 christos }
349 1.1 christos }
350 1.1 christos else
351 1.1 christos * cycles = print_as3_reg_name (regd, op, comm, 1, 1, 3);
352 1.1 christos }
353 1.1 christos else if (as == 1)
354 1.1 christos {
355 1.1 christos *cycles = 4;
356 1.1 christos if (regd == 0)
357 1.1 christos {
358 1.1 christos /* PC relative. */
359 1.6 christos if (msp430dis_opcode_signed (addr + 2, info, &dst, comm))
360 1.1 christos {
361 1.6 christos cmd_len += 2;
362 1.6 christos sprintf (op, "0x%04x", PS (dst));
363 1.6 christos sprintf (comm, "PC rel. 0x%04x",
364 1.6 christos PS ((short) addr + 2 + dst));
365 1.6 christos if (extended_dst)
366 1.6 christos {
367 1.6 christos dst |= extended_dst << 16;
368 1.6 christos sprintf (op, "0x%05x", dst & 0xffff);
369 1.6 christos sprintf (comm, "PC rel. 0x%05lx",
370 1.6 christos (long)((addr + 2 + dst) & 0xfffff));
371 1.6 christos }
372 1.1 christos }
373 1.1 christos }
374 1.1 christos else if (regd == 2)
375 1.1 christos {
376 1.1 christos /* Absolute. */
377 1.6 christos if (msp430dis_opcode_signed (addr + 2, info, &dst, comm))
378 1.1 christos {
379 1.6 christos cmd_len += 2;
380 1.6 christos sprintf (op, "&0x%04x", PS (dst));
381 1.6 christos if (extended_dst)
382 1.6 christos {
383 1.6 christos dst |= extended_dst << 16;
384 1.6 christos sprintf (op, "&0x%05x", dst & 0xfffff);
385 1.6 christos }
386 1.1 christos }
387 1.1 christos }
388 1.1 christos else if (regd == 3)
389 1.1 christos {
390 1.1 christos *cycles = 1;
391 1.1 christos sprintf (op, "#1");
392 1.1 christos sprintf (comm, "r3 As==01");
393 1.1 christos }
394 1.1 christos else
395 1.1 christos {
396 1.1 christos /* Indexed. */
397 1.6 christos if (msp430dis_opcode_signed (addr + 2, info, &dst, comm))
398 1.1 christos {
399 1.6 christos cmd_len += 2;
400 1.6 christos if (extended_dst)
401 1.6 christos {
402 1.6 christos dst |= extended_dst << 16;
403 1.6 christos if (dst & 0x80000)
404 1.6 christos dst |= -1U << 20;
405 1.6 christos }
406 1.6 christos sprintf (op, "%d(r%d)", dst, regd);
407 1.6 christos if (dst > 9 || dst < 0)
408 1.6 christos sprintf (comm, "%05x", dst);
409 1.1 christos }
410 1.1 christos }
411 1.1 christos }
412 1.1 christos break;
413 1.1 christos
414 1.1 christos case 3: /* Jumps. */
415 1.1 christos where = insn & 0x03ff;
416 1.1 christos if (where & 0x200)
417 1.1 christos where |= ~0x03ff;
418 1.1 christos if (where > 512 || where < -511)
419 1.1 christos return 0;
420 1.1 christos
421 1.1 christos where *= 2;
422 1.1 christos sprintf (op, "$%+-8d", where + 2);
423 1.1 christos sprintf (comm, "abs 0x%lx", (long) (addr + 2 + where));
424 1.1 christos *cycles = 2;
425 1.1 christos return 2;
426 1.1 christos break;
427 1.6 christos
428 1.1 christos default:
429 1.1 christos cmd_len = 0;
430 1.1 christos }
431 1.1 christos
432 1.1 christos return cmd_len;
433 1.1 christos }
434 1.1 christos
435 1.1 christos static int
436 1.1 christos msp430_doubleoperand (disassemble_info *info,
437 1.1 christos struct msp430_opcode_s *opcode,
438 1.1 christos bfd_vma addr,
439 1.1 christos unsigned short insn,
440 1.1 christos char *op1,
441 1.1 christos char *op2,
442 1.1 christos char *comm1,
443 1.1 christos char *comm2,
444 1.1 christos unsigned short extension_word,
445 1.1 christos int *cycles)
446 1.1 christos {
447 1.1 christos int regs = 0, regd = 0;
448 1.1 christos int ad = 0, as = 0;
449 1.1 christos int cmd_len = 2;
450 1.1 christos int dst = 0;
451 1.1 christos int fmt;
452 1.1 christos int extended_dst = extension_word & 0xf;
453 1.1 christos int extended_src = (extension_word >> 7) & 0xf;
454 1.1 christos
455 1.1 christos regd = insn & 0x0f;
456 1.1 christos regs = (insn & 0x0f00) >> 8;
457 1.1 christos as = (insn & 0x0030) >> 4;
458 1.1 christos ad = (insn & 0x0080) >> 7;
459 1.1 christos
460 1.1 christos if (opcode->fmt < 0)
461 1.1 christos fmt = (- opcode->fmt) - 1;
462 1.1 christos else
463 1.1 christos fmt = opcode->fmt;
464 1.1 christos
465 1.1 christos if (fmt == 0)
466 1.1 christos {
467 1.1 christos /* Special case: rla and rlc are the only 2 emulated instructions that
468 1.1 christos fall into two operand instructions. */
469 1.1 christos /* With dst, there are only:
470 1.1 christos Rm Register,
471 1.1 christos x(Rm) Indexed,
472 1.1 christos 0xXXXX Relative,
473 1.6 christos &0xXXXX Absolute
474 1.1 christos emulated_ins dst
475 1.1 christos basic_ins dst, dst. */
476 1.1 christos
477 1.1 christos if (regd != regs || as != ad)
478 1.1 christos return 0; /* May be 'data' section. */
479 1.1 christos
480 1.1 christos if (ad == 0)
481 1.1 christos {
482 1.1 christos /* Register mode. */
483 1.1 christos if (regd == 3)
484 1.1 christos {
485 1.6 christos strcpy (comm1, _("Warning: illegal as emulation instr"));
486 1.1 christos return -1;
487 1.1 christos }
488 1.1 christos
489 1.1 christos sprintf (op1, "r%d", regd);
490 1.1 christos *cycles = 1;
491 1.1 christos }
492 1.1 christos else /* ad == 1 */
493 1.1 christos {
494 1.1 christos if (regd == 0)
495 1.1 christos {
496 1.1 christos /* PC relative, Symbolic. */
497 1.6 christos if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1))
498 1.1 christos {
499 1.6 christos cmd_len += 4;
500 1.6 christos *cycles = 6;
501 1.6 christos sprintf (op1, "0x%04x", PS (dst));
502 1.6 christos sprintf (comm1, "PC rel. 0x%04x",
503 1.6 christos PS ((short) addr + 2 + dst));
504 1.6 christos if (extension_word)
505 1.6 christos {
506 1.6 christos dst |= extended_dst << 16;
507 1.6 christos if (dst & 0x80000)
508 1.6 christos dst |= -1U << 20;
509 1.6 christos sprintf (op1, "0x%05x", dst & 0xfffff);
510 1.6 christos sprintf (comm1, "PC rel. 0x%05lx",
511 1.6 christos (long)((addr + 2 + dst) & 0xfffff));
512 1.6 christos }
513 1.1 christos }
514 1.1 christos }
515 1.1 christos else if (regd == 2)
516 1.1 christos {
517 1.1 christos /* Absolute. */
518 1.6 christos if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1))
519 1.1 christos {
520 1.6 christos int src;
521 1.6 christos
522 1.6 christos /* If the 'src' field is not the same as the dst
523 1.6 christos then this is not an rla instruction. */
524 1.6 christos if (msp430dis_opcode_signed (addr + 4, info, &src, comm2))
525 1.6 christos {
526 1.6 christos if (src != dst)
527 1.6 christos return 0;
528 1.6 christos }
529 1.6 christos cmd_len += 4;
530 1.6 christos *cycles = 6;
531 1.6 christos sprintf (op1, "&0x%04x", PS (dst));
532 1.6 christos if (extension_word)
533 1.6 christos {
534 1.6 christos dst |= extended_dst << 16;
535 1.6 christos sprintf (op1, "&0x%05x", dst & 0xfffff);
536 1.6 christos }
537 1.1 christos }
538 1.1 christos }
539 1.1 christos else
540 1.1 christos {
541 1.1 christos /* Indexed. */
542 1.6 christos if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1))
543 1.1 christos {
544 1.6 christos if (extension_word)
545 1.6 christos {
546 1.6 christos dst |= extended_dst << 16;
547 1.6 christos if (dst & 0x80000)
548 1.6 christos dst |= -1U << 20;
549 1.6 christos }
550 1.6 christos cmd_len += 4;
551 1.6 christos *cycles = 6;
552 1.6 christos sprintf (op1, "%d(r%d)", dst, regd);
553 1.6 christos if (dst > 9 || dst < -9)
554 1.6 christos sprintf (comm1, "#0x%05x", dst);
555 1.1 christos }
556 1.1 christos }
557 1.1 christos }
558 1.1 christos
559 1.1 christos *op2 = 0;
560 1.1 christos *comm2 = 0;
561 1.1 christos
562 1.1 christos return cmd_len;
563 1.1 christos }
564 1.1 christos
565 1.1 christos /* Two operands exactly. */
566 1.1 christos if (ad == 0 && regd == 3)
567 1.1 christos {
568 1.1 christos /* R2/R3 are illegal as dest: may be data section. */
569 1.6 christos strcpy (comm1, _("Warning: illegal as 2-op instr"));
570 1.1 christos return -1;
571 1.1 christos }
572 1.1 christos
573 1.1 christos /* Source. */
574 1.1 christos if (as == 0)
575 1.1 christos {
576 1.1 christos *cycles = 1;
577 1.1 christos if (regs == 3)
578 1.1 christos {
579 1.1 christos /* Constants. */
580 1.1 christos sprintf (op1, "#0");
581 1.1 christos sprintf (comm1, "r3 As==00");
582 1.1 christos }
583 1.1 christos else
584 1.1 christos {
585 1.1 christos /* Register. */
586 1.1 christos sprintf (op1, "r%d", regs);
587 1.1 christos }
588 1.1 christos }
589 1.1 christos else if (as == 2)
590 1.1 christos {
591 1.1 christos * cycles = print_as2_reg_name (regs, op1, comm1, 1, 1, regs == 0 ? 3 : 2);
592 1.1 christos }
593 1.1 christos else if (as == 3)
594 1.1 christos {
595 1.1 christos if (regs == 0)
596 1.1 christos {
597 1.1 christos *cycles = 3;
598 1.1 christos /* Absolute. @pc+. */
599 1.6 christos if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1))
600 1.6 christos {
601 1.6 christos cmd_len += 2;
602 1.1 christos sprintf (op1, "#%d", dst);
603 1.1 christos if (dst > 9 || dst < 0)
604 1.6 christos sprintf (comm1, "#0x%04x", PS (dst));
605 1.6 christos if (extension_word)
606 1.6 christos {
607 1.6 christos dst &= 0xffff;
608 1.6 christos dst |= extended_src << 16;
609 1.6 christos if (dst & 0x80000)
610 1.6 christos dst |= -1U << 20;
611 1.6 christos sprintf (op1, "#%d", dst);
612 1.6 christos if (dst > 9 || dst < 0)
613 1.6 christos sprintf (comm1, "0x%05x", dst & 0xfffff);
614 1.6 christos }
615 1.1 christos }
616 1.1 christos }
617 1.1 christos else
618 1.1 christos * cycles = print_as3_reg_name (regs, op1, comm1, 1, 1, 2);
619 1.1 christos }
620 1.1 christos else if (as == 1)
621 1.1 christos {
622 1.1 christos if (regs == 0)
623 1.1 christos {
624 1.1 christos *cycles = 4;
625 1.1 christos /* PC relative. */
626 1.6 christos if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1))
627 1.6 christos {
628 1.6 christos cmd_len += 2;
629 1.6 christos sprintf (op1, "0x%04x", PS (dst));
630 1.6 christos sprintf (comm1, "PC rel. 0x%04x",
631 1.6 christos PS ((short) addr + 2 + dst));
632 1.6 christos if (extension_word)
633 1.6 christos {
634 1.6 christos dst &= 0xffff;
635 1.6 christos dst |= extended_src << 16;
636 1.6 christos if (dst & 0x80000)
637 1.6 christos dst |= -1U << 20;
638 1.6 christos sprintf (op1, "0x%05x", dst & 0xfffff);
639 1.6 christos sprintf (comm1, "PC rel. 0x%05lx",
640 1.6 christos (long) ((addr + 2 + dst) & 0xfffff));
641 1.6 christos }
642 1.1 christos }
643 1.1 christos }
644 1.1 christos else if (regs == 2)
645 1.1 christos {
646 1.1 christos *cycles = 2;
647 1.1 christos /* Absolute. */
648 1.6 christos if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1))
649 1.6 christos {
650 1.6 christos cmd_len += 2;
651 1.6 christos sprintf (op1, "&0x%04x", PS (dst));
652 1.6 christos sprintf (comm1, "0x%04x", PS (dst));
653 1.6 christos if (extension_word)
654 1.6 christos {
655 1.6 christos dst &= 0xffff;
656 1.6 christos dst |= extended_src << 16;
657 1.6 christos sprintf (op1, "&0x%05x", dst & 0xfffff);
658 1.6 christos * comm1 = 0;
659 1.6 christos }
660 1.1 christos }
661 1.1 christos }
662 1.1 christos else if (regs == 3)
663 1.1 christos {
664 1.1 christos *cycles = 1;
665 1.1 christos sprintf (op1, "#1");
666 1.1 christos sprintf (comm1, "r3 As==01");
667 1.1 christos }
668 1.1 christos else
669 1.1 christos {
670 1.1 christos *cycles = 3;
671 1.1 christos /* Indexed. */
672 1.6 christos if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1))
673 1.1 christos {
674 1.6 christos cmd_len += 2;
675 1.6 christos if (extension_word)
676 1.6 christos {
677 1.6 christos dst &= 0xffff;
678 1.6 christos dst |= extended_src << 16;
679 1.6 christos if (dst & 0x80000)
680 1.6 christos dst |= -1U << 20;
681 1.6 christos }
682 1.6 christos sprintf (op1, "%d(r%d)", dst, regs);
683 1.6 christos if (dst > 9 || dst < -9)
684 1.6 christos sprintf (comm1, "0x%05x", dst);
685 1.6 christos }
686 1.1 christos }
687 1.1 christos }
688 1.1 christos
689 1.1 christos /* Destination. Special care needed on addr + XXXX. */
690 1.1 christos
691 1.1 christos if (ad == 0)
692 1.1 christos {
693 1.1 christos /* Register. */
694 1.1 christos if (regd == 0)
695 1.1 christos {
696 1.1 christos *cycles += 1;
697 1.1 christos sprintf (op2, "r0");
698 1.1 christos }
699 1.1 christos else if (regd == 1)
700 1.1 christos sprintf (op2, "r1");
701 1.1 christos
702 1.1 christos else if (regd == 2)
703 1.1 christos sprintf (op2, "r2");
704 1.1 christos
705 1.1 christos else
706 1.1 christos sprintf (op2, "r%d", regd);
707 1.1 christos }
708 1.1 christos else /* ad == 1. */
709 1.1 christos {
710 1.1 christos * cycles += 3;
711 1.1 christos
712 1.1 christos if (regd == 0)
713 1.1 christos {
714 1.1 christos /* PC relative. */
715 1.1 christos *cycles += 1;
716 1.6 christos if (msp430dis_opcode_signed (addr + cmd_len, info, &dst, comm2))
717 1.6 christos {
718 1.6 christos sprintf (op2, "0x%04x", PS (dst));
719 1.6 christos sprintf (comm2, "PC rel. 0x%04x",
720 1.6 christos PS ((short) addr + cmd_len + dst));
721 1.6 christos if (extension_word)
722 1.6 christos {
723 1.6 christos dst |= extended_dst << 16;
724 1.6 christos if (dst & 0x80000)
725 1.6 christos dst |= -1U << 20;
726 1.6 christos sprintf (op2, "0x%05x", dst & 0xfffff);
727 1.6 christos sprintf (comm2, "PC rel. 0x%05lx",
728 1.6 christos (long)((addr + cmd_len + dst) & 0xfffff));
729 1.6 christos }
730 1.1 christos }
731 1.1 christos cmd_len += 2;
732 1.1 christos }
733 1.1 christos else if (regd == 2)
734 1.1 christos {
735 1.1 christos /* Absolute. */
736 1.6 christos if (msp430dis_opcode_signed (addr + cmd_len, info, &dst, comm2))
737 1.1 christos {
738 1.6 christos cmd_len += 2;
739 1.6 christos sprintf (op2, "&0x%04x", PS (dst));
740 1.6 christos if (extension_word)
741 1.6 christos {
742 1.6 christos dst |= extended_dst << 16;
743 1.6 christos sprintf (op2, "&0x%05x", dst & 0xfffff);
744 1.6 christos }
745 1.1 christos }
746 1.1 christos }
747 1.1 christos else
748 1.1 christos {
749 1.6 christos if (msp430dis_opcode_signed (addr + cmd_len, info, &dst, comm2))
750 1.6 christos {
751 1.6 christos cmd_len += 2;
752 1.1 christos if (dst > 9 || dst < 0)
753 1.6 christos sprintf (comm2, "0x%04x", PS (dst));
754 1.6 christos if (extension_word)
755 1.6 christos {
756 1.6 christos dst |= extended_dst << 16;
757 1.6 christos if (dst & 0x80000)
758 1.6 christos dst |= -1U << 20;
759 1.6 christos if (dst > 9 || dst < 0)
760 1.6 christos sprintf (comm2, "0x%05x", dst & 0xfffff);
761 1.6 christos }
762 1.6 christos sprintf (op2, "%d(r%d)", dst, regd);
763 1.1 christos }
764 1.1 christos }
765 1.1 christos }
766 1.1 christos
767 1.1 christos return cmd_len;
768 1.1 christos }
769 1.1 christos
770 1.1 christos static int
771 1.1 christos msp430_branchinstr (disassemble_info *info,
772 1.1 christos struct msp430_opcode_s *opcode ATTRIBUTE_UNUSED,
773 1.1 christos bfd_vma addr ATTRIBUTE_UNUSED,
774 1.1 christos unsigned short insn,
775 1.1 christos char *op1,
776 1.1 christos char *comm1,
777 1.1 christos int *cycles)
778 1.1 christos {
779 1.1 christos int regs = 0, regd = 0;
780 1.1 christos int as = 0;
781 1.1 christos int cmd_len = 2;
782 1.6 christos int dst = 0;
783 1.6 christos unsigned short udst = 0;
784 1.1 christos
785 1.1 christos regd = insn & 0x0f;
786 1.1 christos regs = (insn & 0x0f00) >> 8;
787 1.1 christos as = (insn & 0x0030) >> 4;
788 1.1 christos
789 1.1 christos if (regd != 0) /* Destination register is not a PC. */
790 1.1 christos return 0;
791 1.1 christos
792 1.1 christos /* dst is a source register. */
793 1.1 christos if (as == 0)
794 1.1 christos {
795 1.1 christos /* Constants. */
796 1.1 christos if (regs == 3)
797 1.1 christos {
798 1.1 christos *cycles = 1;
799 1.1 christos sprintf (op1, "#0");
800 1.1 christos sprintf (comm1, "r3 As==00");
801 1.1 christos }
802 1.1 christos else
803 1.1 christos {
804 1.1 christos /* Register. */
805 1.1 christos *cycles = 1;
806 1.1 christos sprintf (op1, "r%d", regs);
807 1.1 christos }
808 1.1 christos }
809 1.1 christos else if (as == 2)
810 1.1 christos {
811 1.1 christos * cycles = print_as2_reg_name (regs, op1, comm1, 2, 1, 2);
812 1.1 christos }
813 1.1 christos else if (as == 3)
814 1.1 christos {
815 1.1 christos if (regs == 0)
816 1.1 christos {
817 1.1 christos /* Absolute. @pc+ */
818 1.1 christos *cycles = 3;
819 1.6 christos if (msp430dis_opcode_unsigned (addr + 2, info, &udst, comm1))
820 1.6 christos {
821 1.6 christos cmd_len += 2;
822 1.6 christos sprintf (op1, "#0x%04x", PS (udst));
823 1.6 christos }
824 1.1 christos }
825 1.1 christos else
826 1.1 christos * cycles = print_as3_reg_name (regs, op1, comm1, 1, 1, 2);
827 1.1 christos }
828 1.1 christos else if (as == 1)
829 1.1 christos {
830 1.1 christos * cycles = 3;
831 1.1 christos
832 1.1 christos if (regs == 0)
833 1.1 christos {
834 1.1 christos /* PC relative. */
835 1.6 christos if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1))
836 1.6 christos {
837 1.6 christos cmd_len += 2;
838 1.6 christos (*cycles)++;
839 1.6 christos sprintf (op1, "0x%04x", PS (dst));
840 1.6 christos sprintf (comm1, "PC rel. 0x%04x",
841 1.6 christos PS ((short) addr + 2 + dst));
842 1.6 christos }
843 1.1 christos }
844 1.1 christos else if (regs == 2)
845 1.1 christos {
846 1.1 christos /* Absolute. */
847 1.6 christos if (msp430dis_opcode_unsigned (addr + 2, info, &udst, comm1))
848 1.6 christos {
849 1.6 christos cmd_len += 2;
850 1.6 christos sprintf (op1, "&0x%04x", PS (udst));
851 1.6 christos }
852 1.1 christos }
853 1.1 christos else if (regs == 3)
854 1.1 christos {
855 1.1 christos (*cycles)--;
856 1.1 christos sprintf (op1, "#1");
857 1.1 christos sprintf (comm1, "r3 As==01");
858 1.1 christos }
859 1.1 christos else
860 1.1 christos {
861 1.1 christos /* Indexed. */
862 1.6 christos if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1))
863 1.6 christos {
864 1.6 christos cmd_len += 2;
865 1.6 christos sprintf (op1, "%d(r%d)", dst, regs);
866 1.6 christos }
867 1.1 christos }
868 1.1 christos }
869 1.1 christos
870 1.1 christos return cmd_len;
871 1.1 christos }
872 1.1 christos
873 1.1 christos static int
874 1.1 christos msp430x_calla_instr (disassemble_info * info,
875 1.1 christos bfd_vma addr,
876 1.1 christos unsigned short insn,
877 1.1 christos char * op1,
878 1.1 christos char * comm1,
879 1.1 christos int * cycles)
880 1.1 christos {
881 1.1 christos unsigned int ureg = insn & 0xf;
882 1.1 christos int reg = insn & 0xf;
883 1.1 christos int am = (insn & 0xf0) >> 4;
884 1.1 christos int cmd_len = 2;
885 1.1 christos unsigned short udst = 0;
886 1.6 christos int dst = 0;
887 1.1 christos
888 1.1 christos switch (am)
889 1.1 christos {
890 1.1 christos case 4: /* CALLA Rdst */
891 1.1 christos *cycles = 1;
892 1.1 christos sprintf (op1, "r%d", reg);
893 1.1 christos break;
894 1.1 christos
895 1.1 christos case 5: /* CALLA x(Rdst) */
896 1.1 christos *cycles = 3;
897 1.6 christos if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1))
898 1.6 christos {
899 1.6 christos cmd_len += 2;
900 1.6 christos sprintf (op1, "%d(r%d)", dst, reg);
901 1.6 christos if (reg == 0)
902 1.6 christos sprintf (comm1, "PC rel. 0x%05lx", (long) (addr + 2 + dst));
903 1.6 christos else
904 1.6 christos sprintf (comm1, "0x%05x", dst);
905 1.6 christos }
906 1.1 christos break;
907 1.1 christos
908 1.1 christos case 6: /* CALLA @Rdst */
909 1.1 christos *cycles = 2;
910 1.1 christos sprintf (op1, "@r%d", reg);
911 1.1 christos break;
912 1.1 christos
913 1.1 christos case 7: /* CALLA @Rdst+ */
914 1.1 christos *cycles = 2;
915 1.1 christos sprintf (op1, "@r%d+", reg);
916 1.1 christos break;
917 1.1 christos
918 1.1 christos case 8: /* CALLA &abs20 */
919 1.6 christos if (msp430dis_opcode_unsigned (addr + 2, info, &udst, comm1))
920 1.6 christos {
921 1.6 christos cmd_len += 2;
922 1.6 christos *cycles = 4;
923 1.6 christos sprintf (op1, "&%d", (ureg << 16) + udst);
924 1.6 christos sprintf (comm1, "0x%05x", (ureg << 16) + udst);
925 1.6 christos }
926 1.1 christos break;
927 1.1 christos
928 1.1 christos case 9: /* CALLA pcrel-sym */
929 1.6 christos if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1))
930 1.6 christos {
931 1.6 christos cmd_len += 2;
932 1.6 christos *cycles = 4;
933 1.6 christos sprintf (op1, "%d(PC)", (reg << 16) + dst);
934 1.6 christos sprintf (comm1, "PC rel. 0x%05lx",
935 1.6 christos (long) (addr + 2 + dst + (reg << 16)));
936 1.6 christos }
937 1.1 christos break;
938 1.1 christos
939 1.1 christos case 11: /* CALLA #imm20 */
940 1.6 christos if (msp430dis_opcode_unsigned (addr + 2, info, &udst, comm1))
941 1.6 christos {
942 1.6 christos cmd_len += 2;
943 1.6 christos *cycles = 4;
944 1.6 christos sprintf (op1, "#%d", (ureg << 16) + udst);
945 1.6 christos sprintf (comm1, "0x%05x", (ureg << 16) + udst);
946 1.6 christos }
947 1.1 christos break;
948 1.1 christos
949 1.1 christos default:
950 1.6 christos strcpy (comm1, _("Warning: unrecognised CALLA addressing mode"));
951 1.1 christos return -1;
952 1.1 christos }
953 1.1 christos
954 1.1 christos return cmd_len;
955 1.1 christos }
956 1.1 christos
957 1.1 christos int
958 1.1 christos print_insn_msp430 (bfd_vma addr, disassemble_info *info)
959 1.1 christos {
960 1.1 christos void *stream = info->stream;
961 1.1 christos fprintf_ftype prin = info->fprintf_func;
962 1.1 christos struct msp430_opcode_s *opcode;
963 1.1 christos char op1[32], op2[32], comm1[64], comm2[64];
964 1.1 christos int cmd_len = 0;
965 1.1 christos unsigned short insn;
966 1.1 christos int cycles = 0;
967 1.1 christos char *bc = "";
968 1.1 christos unsigned short extension_word = 0;
969 1.6 christos unsigned short bits;
970 1.1 christos
971 1.6 christos if (! msp430dis_opcode_unsigned (addr, info, &insn, NULL))
972 1.1 christos {
973 1.1 christos prin (stream, ".word 0xffff; ????");
974 1.1 christos return 2;
975 1.1 christos }
976 1.1 christos
977 1.1 christos if (((int) addr & 0xffff) > 0xffdf)
978 1.1 christos {
979 1.1 christos (*prin) (stream, "interrupt service routine at 0x%04x", 0xffff & insn);
980 1.1 christos return 2;
981 1.1 christos }
982 1.1 christos
983 1.1 christos *comm1 = 0;
984 1.1 christos *comm2 = 0;
985 1.1 christos
986 1.1 christos /* Check for an extension word. */
987 1.1 christos if ((insn & 0xf800) == 0x1800)
988 1.1 christos {
989 1.1 christos extension_word = insn;
990 1.1 christos addr += 2;
991 1.6 christos if (! msp430dis_opcode_unsigned (addr, info, &insn, NULL))
992 1.1 christos {
993 1.1 christos prin (stream, ".word 0x%04x, 0xffff; ????",
994 1.1 christos extension_word);
995 1.1 christos return 4;
996 1.1 christos }
997 1.1 christos }
998 1.1 christos
999 1.1 christos for (opcode = msp430_opcodes; opcode->name; opcode++)
1000 1.1 christos {
1001 1.1 christos if ((insn & opcode->bin_mask) == opcode->bin_opcode
1002 1.1 christos && opcode->bin_opcode != 0x9300)
1003 1.1 christos {
1004 1.1 christos *op1 = 0;
1005 1.1 christos *op2 = 0;
1006 1.1 christos *comm1 = 0;
1007 1.1 christos *comm2 = 0;
1008 1.1 christos
1009 1.1 christos /* r0 as destination. Ad should be zero. */
1010 1.1 christos if (opcode->insn_opnumb == 3
1011 1.1 christos && (insn & 0x000f) == 0
1012 1.1 christos && (insn & 0x0080) == 0)
1013 1.1 christos {
1014 1.1 christos cmd_len +=
1015 1.1 christos msp430_branchinstr (info, opcode, addr, insn, op1, comm1,
1016 1.1 christos &cycles);
1017 1.1 christos if (cmd_len)
1018 1.1 christos break;
1019 1.1 christos }
1020 1.1 christos
1021 1.1 christos switch (opcode->insn_opnumb)
1022 1.1 christos {
1023 1.1 christos int n;
1024 1.1 christos int reg;
1025 1.1 christos
1026 1.1 christos case 4:
1027 1.1 christos cmd_len += msp430x_calla_instr (info, addr, insn,
1028 1.1 christos op1, comm1, & cycles);
1029 1.1 christos break;
1030 1.1 christos
1031 1.1 christos case 5: /* PUSHM/POPM */
1032 1.1 christos n = (insn & 0xf0) >> 4;
1033 1.1 christos reg = (insn & 0xf);
1034 1.1 christos
1035 1.1 christos sprintf (op1, "#%d", n + 1);
1036 1.1 christos if (opcode->bin_opcode == 0x1400)
1037 1.1 christos /* PUSHM */
1038 1.1 christos sprintf (op2, "r%d", reg);
1039 1.1 christos else
1040 1.1 christos /* POPM */
1041 1.1 christos sprintf (op2, "r%d", reg + n);
1042 1.1 christos if (insn & 0x100)
1043 1.1 christos sprintf (comm1, "16-bit words");
1044 1.1 christos else
1045 1.1 christos {
1046 1.1 christos sprintf (comm1, "20-bit words");
1047 1.1 christos bc =".a";
1048 1.1 christos }
1049 1.6 christos
1050 1.1 christos cycles = 2; /*FIXME*/
1051 1.1 christos cmd_len = 2;
1052 1.1 christos break;
1053 1.1 christos
1054 1.1 christos case 6: /* RRAM, RRCM, RRUM, RLAM. */
1055 1.1 christos n = ((insn >> 10) & 0x3) + 1;
1056 1.1 christos reg = (insn & 0xf);
1057 1.1 christos if ((insn & 0x10) == 0)
1058 1.1 christos bc =".a";
1059 1.1 christos sprintf (op1, "#%d", n);
1060 1.1 christos sprintf (op2, "r%d", reg);
1061 1.1 christos cycles = 2; /*FIXME*/
1062 1.1 christos cmd_len = 2;
1063 1.1 christos break;
1064 1.1 christos
1065 1.1 christos case 8: /* ADDA, CMPA, SUBA. */
1066 1.1 christos reg = (insn & 0xf);
1067 1.1 christos n = (insn >> 8) & 0xf;
1068 1.1 christos if (insn & 0x40)
1069 1.1 christos {
1070 1.1 christos sprintf (op1, "r%d", n);
1071 1.1 christos cmd_len = 2;
1072 1.1 christos }
1073 1.1 christos else
1074 1.1 christos {
1075 1.1 christos n <<= 16;
1076 1.6 christos if (msp430dis_opcode_unsigned (addr + 2, info, &bits, comm1))
1077 1.6 christos {
1078 1.6 christos n |= bits;
1079 1.6 christos sprintf (op1, "#%d", n);
1080 1.6 christos if (n > 9 || n < 0)
1081 1.6 christos sprintf (comm1, "0x%05x", n);
1082 1.6 christos }
1083 1.1 christos cmd_len = 4;
1084 1.1 christos }
1085 1.1 christos sprintf (op2, "r%d", reg);
1086 1.1 christos cycles = 2; /*FIXME*/
1087 1.1 christos break;
1088 1.1 christos
1089 1.1 christos case 9: /* MOVA */
1090 1.1 christos reg = (insn & 0xf);
1091 1.1 christos n = (insn >> 8) & 0xf;
1092 1.1 christos switch ((insn >> 4) & 0xf)
1093 1.1 christos {
1094 1.1 christos case 0: /* MOVA @Rsrc, Rdst */
1095 1.1 christos cmd_len = 2;
1096 1.1 christos sprintf (op1, "@r%d", n);
1097 1.1 christos if (strcmp (opcode->name, "bra") != 0)
1098 1.1 christos sprintf (op2, "r%d", reg);
1099 1.1 christos break;
1100 1.6 christos
1101 1.1 christos case 1: /* MOVA @Rsrc+, Rdst */
1102 1.1 christos cmd_len = 2;
1103 1.1 christos if (strcmp (opcode->name, "reta") != 0)
1104 1.1 christos {
1105 1.1 christos sprintf (op1, "@r%d+", n);
1106 1.1 christos if (strcmp (opcode->name, "bra") != 0)
1107 1.1 christos sprintf (op2, "r%d", reg);
1108 1.1 christos }
1109 1.1 christos break;
1110 1.6 christos
1111 1.1 christos case 2: /* MOVA &abs20, Rdst */
1112 1.1 christos cmd_len = 4;
1113 1.1 christos n <<= 16;
1114 1.6 christos if (msp430dis_opcode_unsigned (addr + 2, info, &bits, comm1))
1115 1.6 christos {
1116 1.6 christos n |= bits;
1117 1.6 christos sprintf (op1, "&%d", n);
1118 1.6 christos if (n > 9 || n < 0)
1119 1.6 christos sprintf (comm1, "0x%05x", n);
1120 1.6 christos if (strcmp (opcode->name, "bra") != 0)
1121 1.6 christos sprintf (op2, "r%d", reg);
1122 1.6 christos }
1123 1.1 christos break;
1124 1.6 christos
1125 1.1 christos case 3: /* MOVA x(Rsrc), Rdst */
1126 1.1 christos cmd_len = 4;
1127 1.1 christos if (strcmp (opcode->name, "bra") != 0)
1128 1.1 christos sprintf (op2, "r%d", reg);
1129 1.1 christos reg = n;
1130 1.6 christos if (msp430dis_opcode_signed (addr + 2, info, &n, comm1))
1131 1.6 christos {
1132 1.6 christos sprintf (op1, "%d(r%d)", n, reg);
1133 1.6 christos if (n > 9 || n < 0)
1134 1.6 christos {
1135 1.6 christos if (reg == 0)
1136 1.6 christos sprintf (comm1, "PC rel. 0x%05lx",
1137 1.6 christos (long) (addr + 2 + n));
1138 1.6 christos else
1139 1.6 christos sprintf (comm1, "0x%05x", n);
1140 1.6 christos }
1141 1.1 christos }
1142 1.1 christos break;
1143 1.1 christos
1144 1.1 christos case 6: /* MOVA Rsrc, &abs20 */
1145 1.1 christos cmd_len = 4;
1146 1.1 christos reg <<= 16;
1147 1.6 christos if (msp430dis_opcode_unsigned (addr + 2, info, &bits, comm2))
1148 1.6 christos {
1149 1.6 christos reg |= bits;
1150 1.6 christos sprintf (op1, "r%d", n);
1151 1.6 christos sprintf (op2, "&%d", reg);
1152 1.6 christos if (reg > 9 || reg < 0)
1153 1.6 christos sprintf (comm2, "0x%05x", reg);
1154 1.6 christos }
1155 1.1 christos break;
1156 1.1 christos
1157 1.1 christos case 7: /* MOVA Rsrc, x(Rdst) */
1158 1.1 christos cmd_len = 4;
1159 1.1 christos sprintf (op1, "r%d", n);
1160 1.6 christos if (msp430dis_opcode_signed (addr + 2, info, &n, comm2))
1161 1.6 christos {
1162 1.6 christos sprintf (op2, "%d(r%d)", n, reg);
1163 1.6 christos if (n > 9 || n < 0)
1164 1.6 christos {
1165 1.6 christos if (reg == 0)
1166 1.6 christos sprintf (comm2, "PC rel. 0x%05lx",
1167 1.6 christos (long) (addr + 2 + n));
1168 1.6 christos else
1169 1.6 christos sprintf (comm2, "0x%05x", n);
1170 1.6 christos }
1171 1.1 christos }
1172 1.1 christos break;
1173 1.6 christos
1174 1.1 christos case 8: /* MOVA #imm20, Rdst */
1175 1.1 christos cmd_len = 4;
1176 1.1 christos n <<= 16;
1177 1.6 christos if (msp430dis_opcode_unsigned (addr + 2, info, &bits, comm1))
1178 1.6 christos {
1179 1.6 christos n |= bits;
1180 1.6 christos if (n & 0x80000)
1181 1.6 christos n |= -1U << 20;
1182 1.6 christos sprintf (op1, "#%d", n);
1183 1.6 christos if (n > 9 || n < 0)
1184 1.6 christos sprintf (comm1, "0x%05x", n);
1185 1.6 christos if (strcmp (opcode->name, "bra") != 0)
1186 1.6 christos sprintf (op2, "r%d", reg);
1187 1.6 christos }
1188 1.1 christos break;
1189 1.6 christos
1190 1.1 christos case 12: /* MOVA Rsrc, Rdst */
1191 1.1 christos cmd_len = 2;
1192 1.1 christos sprintf (op1, "r%d", n);
1193 1.1 christos if (strcmp (opcode->name, "bra") != 0)
1194 1.1 christos sprintf (op2, "r%d", reg);
1195 1.1 christos break;
1196 1.1 christos
1197 1.1 christos default:
1198 1.1 christos break;
1199 1.1 christos }
1200 1.1 christos cycles = 2; /* FIXME */
1201 1.1 christos break;
1202 1.1 christos }
1203 1.1 christos
1204 1.1 christos if (cmd_len)
1205 1.1 christos break;
1206 1.1 christos
1207 1.1 christos switch (opcode->insn_opnumb)
1208 1.1 christos {
1209 1.1 christos case 0:
1210 1.1 christos cmd_len += msp430_nooperands (opcode, addr, insn, comm1, &cycles);
1211 1.1 christos break;
1212 1.1 christos case 2:
1213 1.1 christos cmd_len +=
1214 1.1 christos msp430_doubleoperand (info, opcode, addr, insn, op1, op2,
1215 1.1 christos comm1, comm2,
1216 1.1 christos extension_word,
1217 1.1 christos &cycles);
1218 1.1 christos if (insn & BYTE_OPERATION)
1219 1.1 christos {
1220 1.1 christos if (extension_word != 0 && ((extension_word & BYTE_OPERATION) == 0))
1221 1.1 christos bc = ".a";
1222 1.1 christos else
1223 1.1 christos bc = ".b";
1224 1.1 christos }
1225 1.1 christos else if (extension_word)
1226 1.1 christos {
1227 1.6 christos if (extension_word & BYTE_OPERATION)
1228 1.1 christos bc = ".w";
1229 1.1 christos else
1230 1.1 christos {
1231 1.1 christos bc = ".?";
1232 1.6 christos sprintf (comm2, _("Warning: reserved use of A/L and B/W bits detected"));
1233 1.1 christos }
1234 1.1 christos }
1235 1.6 christos
1236 1.1 christos break;
1237 1.1 christos case 1:
1238 1.1 christos cmd_len +=
1239 1.1 christos msp430_singleoperand (info, opcode, addr, insn, op1, comm1,
1240 1.1 christos extension_word,
1241 1.1 christos &cycles);
1242 1.1 christos if (extension_word
1243 1.1 christos && (strcmp (opcode->name, "swpb") == 0
1244 1.1 christos || strcmp (opcode->name, "sxt") == 0))
1245 1.1 christos {
1246 1.1 christos if (insn & BYTE_OPERATION)
1247 1.1 christos {
1248 1.1 christos bc = ".?";
1249 1.6 christos sprintf (comm2, _("Warning: reserved use of A/L and B/W bits detected"));
1250 1.1 christos }
1251 1.1 christos else if (extension_word & BYTE_OPERATION)
1252 1.1 christos bc = ".w";
1253 1.1 christos else
1254 1.1 christos bc = ".a";
1255 1.1 christos }
1256 1.1 christos else if (insn & BYTE_OPERATION && opcode->fmt != 3)
1257 1.1 christos {
1258 1.1 christos if (extension_word != 0 && ((extension_word & BYTE_OPERATION) == 0))
1259 1.1 christos bc = ".a";
1260 1.1 christos else
1261 1.1 christos bc = ".b";
1262 1.1 christos }
1263 1.1 christos else if (extension_word)
1264 1.1 christos {
1265 1.1 christos if (extension_word & (1 << 6))
1266 1.1 christos bc = ".w";
1267 1.1 christos else
1268 1.1 christos {
1269 1.1 christos bc = ".?";
1270 1.6 christos sprintf (comm2, _("Warning: reserved use of A/L and B/W bits detected"));
1271 1.1 christos }
1272 1.1 christos }
1273 1.1 christos break;
1274 1.1 christos default:
1275 1.1 christos break;
1276 1.1 christos }
1277 1.1 christos }
1278 1.1 christos
1279 1.1 christos if (cmd_len)
1280 1.1 christos break;
1281 1.1 christos }
1282 1.1 christos
1283 1.1 christos if (cmd_len < 1)
1284 1.1 christos {
1285 1.1 christos /* Unknown opcode, or invalid combination of operands. */
1286 1.1 christos if (extension_word)
1287 1.1 christos {
1288 1.1 christos prin (stream, ".word 0x%04x, 0x%04x; ????", extension_word, PS (insn));
1289 1.1 christos if (*comm1)
1290 1.1 christos prin (stream, "\t %s", comm1);
1291 1.1 christos return 4;
1292 1.1 christos }
1293 1.1 christos (*prin) (stream, ".word 0x%04x; ????", PS (insn));
1294 1.1 christos return 2;
1295 1.1 christos }
1296 1.1 christos
1297 1.1 christos /* Display the repeat count (if set) for extended register mode. */
1298 1.1 christos if (cmd_len == 2 && ((extension_word & 0xf) != 0))
1299 1.1 christos {
1300 1.1 christos if (extension_word & (1 << 7))
1301 1.1 christos prin (stream, "rpt r%d { ", extension_word & 0xf);
1302 1.1 christos else
1303 1.1 christos prin (stream, "rpt #%d { ", (extension_word & 0xf) + 1);
1304 1.1 christos }
1305 1.1 christos
1306 1.6 christos /* Special case: RRC with an extension word and the ZC bit set is actually RRU. */
1307 1.6 christos if (extension_word
1308 1.6 christos && (extension_word & IGNORE_CARRY_BIT)
1309 1.6 christos && strcmp (opcode->name, "rrc") == 0)
1310 1.6 christos (*prin) (stream, "rrux%s", bc);
1311 1.6 christos else if (extension_word && opcode->name[strlen (opcode->name) - 1] != 'x')
1312 1.1 christos (*prin) (stream, "%sx%s", opcode->name, bc);
1313 1.1 christos else
1314 1.1 christos (*prin) (stream, "%s%s", opcode->name, bc);
1315 1.1 christos
1316 1.1 christos if (*op1)
1317 1.1 christos (*prin) (stream, "\t%s", op1);
1318 1.1 christos if (*op2)
1319 1.1 christos (*prin) (stream, ",");
1320 1.1 christos
1321 1.1 christos if (strlen (op1) < 7)
1322 1.1 christos (*prin) (stream, "\t");
1323 1.1 christos if (!strlen (op1))
1324 1.1 christos (*prin) (stream, "\t");
1325 1.1 christos
1326 1.1 christos if (*op2)
1327 1.1 christos (*prin) (stream, "%s", op2);
1328 1.1 christos if (strlen (op2) < 8)
1329 1.1 christos (*prin) (stream, "\t");
1330 1.1 christos
1331 1.1 christos if (*comm1 || *comm2)
1332 1.1 christos (*prin) (stream, ";");
1333 1.1 christos else if (cycles)
1334 1.1 christos {
1335 1.1 christos if (*op2)
1336 1.1 christos (*prin) (stream, ";");
1337 1.1 christos else
1338 1.1 christos {
1339 1.1 christos if (strlen (op1) < 7)
1340 1.1 christos (*prin) (stream, ";");
1341 1.1 christos else
1342 1.1 christos (*prin) (stream, "\t;");
1343 1.1 christos }
1344 1.1 christos }
1345 1.1 christos if (*comm1)
1346 1.1 christos (*prin) (stream, "%s", comm1);
1347 1.1 christos if (*comm1 && *comm2)
1348 1.1 christos (*prin) (stream, ",");
1349 1.1 christos if (*comm2)
1350 1.1 christos (*prin) (stream, " %s", comm2);
1351 1.1 christos
1352 1.1 christos if (extension_word)
1353 1.1 christos cmd_len += 2;
1354 1.1 christos
1355 1.1 christos return cmd_len;
1356 1.1 christos }
1357