Coverage Report

Created: 2023-08-28 06:30

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