Home | History | Annotate | Line # | Download | only in opcodes
msp430-dis.c revision 1.1
      1 /* Disassemble MSP430 instructions.
      2    Copyright (C) 2002, 2004, 2005, 2007 Free Software Foundation, Inc.
      3 
      4    Contributed by Dmitry Diky <diwil (at) 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 <stdio.h>
     24 #include <ctype.h>
     25 #include <string.h>
     26 #include <sys/types.h>
     27 
     28 #include "dis-asm.h"
     29 #include "opintl.h"
     30 #include "libiberty.h"
     31 
     32 #define DASM_SECTION
     33 #include "opcode/msp430.h"
     34 #undef DASM_SECTION
     35 
     36 
     37 #define PS(x)   (0xffff & (x))
     38 
     39 static unsigned short
     40 msp430dis_opcode (bfd_vma addr, disassemble_info *info)
     41 {
     42   bfd_byte buffer[2];
     43   int status;
     44 
     45   status = info->read_memory_func (addr, buffer, 2, info);
     46   if (status != 0)
     47     {
     48       info->memory_error_func (status, addr, info);
     49       return -1;
     50     }
     51   return bfd_getl16 (buffer);
     52 }
     53 
     54 static int
     55 msp430_nooperands (struct msp430_opcode_s *opcode,
     56 		   bfd_vma addr ATTRIBUTE_UNUSED,
     57 		   unsigned short insn ATTRIBUTE_UNUSED,
     58 		   char *comm,
     59 		   int *cycles)
     60 {
     61   /* Pop with constant.  */
     62   if (insn == 0x43b2)
     63     return 0;
     64   if (insn == opcode->bin_opcode)
     65     return 2;
     66 
     67   if (opcode->fmt == 0)
     68     {
     69       if ((insn & 0x0f00) != 3 || (insn & 0x0f00) != 2)
     70 	return 0;
     71 
     72       strcpy (comm, "emulated...");
     73       *cycles = 1;
     74     }
     75   else
     76     {
     77       strcpy (comm, "return from interupt");
     78       *cycles = 5;
     79     }
     80 
     81   return 2;
     82 }
     83 
     84 static int
     85 msp430_singleoperand (disassemble_info *info,
     86 		      struct msp430_opcode_s *opcode,
     87 		      bfd_vma addr,
     88 		      unsigned short insn,
     89 		      char *op,
     90 		      char *comm,
     91 		      int *cycles)
     92 {
     93   int regs = 0, regd = 0;
     94   int ad = 0, as = 0;
     95   int where = 0;
     96   int cmd_len = 2;
     97   short dst = 0;
     98 
     99   regd = insn & 0x0f;
    100   regs = (insn & 0x0f00) >> 8;
    101   as = (insn & 0x0030) >> 4;
    102   ad = (insn & 0x0080) >> 7;
    103 
    104   switch (opcode->fmt)
    105     {
    106     case 0:			/* Emulated work with dst register.  */
    107       if (regs != 2 && regs != 3 && regs != 1)
    108 	return 0;
    109 
    110       /* Check if not clr insn.  */
    111       if (opcode->bin_opcode == 0x4300 && (ad || as))
    112 	return 0;
    113 
    114       /* Check if really inc, incd insns.  */
    115       if ((opcode->bin_opcode & 0xff00) == 0x5300 && as == 3)
    116 	return 0;
    117 
    118       if (ad == 0)
    119 	{
    120 	  *cycles = 1;
    121 
    122 	  /* Register.  */
    123 	  if (regd == 0)
    124 	    {
    125 	      *cycles += 1;
    126 	      sprintf (op, "r0");
    127 	    }
    128 	  else if (regd == 1)
    129 	    sprintf (op, "r1");
    130 
    131 	  else if (regd == 2)
    132 	    sprintf (op, "r2");
    133 
    134 	  else
    135 	    sprintf (op, "r%d", regd);
    136 	}
    137       else	/* ad == 1 msp430dis_opcode.  */
    138 	{
    139 	  if (regd == 0)
    140 	    {
    141 	      /* PC relative.  */
    142 	      dst = msp430dis_opcode (addr + 2, info);
    143 	      cmd_len += 2;
    144 	      *cycles = 4;
    145 	      sprintf (op, "0x%04x", dst);
    146 	      sprintf (comm, "PC rel. abs addr 0x%04x",
    147 		       PS ((short) (addr + 2) + dst));
    148 	    }
    149 	  else if (regd == 2)
    150 	    {
    151 	      /* Absolute.  */
    152 	      dst = msp430dis_opcode (addr + 2, info);
    153 	      cmd_len += 2;
    154 	      *cycles = 4;
    155 	      sprintf (op, "&0x%04x", PS (dst));
    156 	    }
    157 	  else
    158 	    {
    159 	      dst = msp430dis_opcode (addr + 2, info);
    160 	      cmd_len += 2;
    161 	      *cycles = 4;
    162 	      sprintf (op, "%d(r%d)", dst, regd);
    163 	    }
    164 	}
    165       break;
    166 
    167     case 2:	/* rrc, push, call, swpb, rra, sxt, push, call, reti etc...  */
    168       if (as == 0)
    169 	{
    170 	  if (regd == 3)
    171 	    {
    172 	      /* Constsnts.  */
    173 	      sprintf (op, "#0");
    174 	      sprintf (comm, "r3 As==00");
    175 	    }
    176 	  else
    177 	    {
    178 	      /* Register.  */
    179 	      sprintf (op, "r%d", regd);
    180 	    }
    181 	  *cycles = 1;
    182 	}
    183       else if (as == 2)
    184 	{
    185 	  *cycles = 1;
    186 	  if (regd == 2)
    187 	    {
    188 	      sprintf (op, "#4");
    189 	      sprintf (comm, "r2 As==10");
    190 	    }
    191 	  else if (regd == 3)
    192 	    {
    193 	      sprintf (op, "#2");
    194 	      sprintf (comm, "r3 As==10");
    195 	    }
    196 	  else
    197 	    {
    198 	      *cycles = 3;
    199 	      /* Indexed register mode @Rn.  */
    200 	      sprintf (op, "@r%d", regd);
    201 	    }
    202 	}
    203       else if (as == 3)
    204 	{
    205 	  *cycles = 1;
    206 	  if (regd == 2)
    207 	    {
    208 	      sprintf (op, "#8");
    209 	      sprintf (comm, "r2 As==11");
    210 	    }
    211 	  else if (regd == 3)
    212 	    {
    213 	      sprintf (op, "#-1");
    214 	      sprintf (comm, "r3 As==11");
    215 	    }
    216 	  else if (regd == 0)
    217 	    {
    218 	      *cycles = 3;
    219 	      /* absolute. @pc+ */
    220 	      dst = msp430dis_opcode (addr + 2, info);
    221 	      cmd_len += 2;
    222 	      sprintf (op, "#%d", dst);
    223 	      sprintf (comm, "#0x%04x", PS (dst));
    224 	    }
    225 	  else
    226 	    {
    227 	      *cycles = 3;
    228 	      sprintf (op, "@r%d+", regd);
    229 	    }
    230 	}
    231       else if (as == 1)
    232 	{
    233 	  *cycles = 4;
    234 	  if (regd == 0)
    235 	    {
    236 	      /* PC relative.  */
    237 	      dst = msp430dis_opcode (addr + 2, info);
    238 	      cmd_len += 2;
    239 	      sprintf (op, "0x%04x", PS (dst));
    240 	      sprintf (comm, "PC rel. 0x%04x",
    241 		       PS ((short) addr + 2 + dst));
    242 	    }
    243 	  else if (regd == 2)
    244 	    {
    245 	      /* Absolute.  */
    246 	      dst = msp430dis_opcode (addr + 2, info);
    247 	      cmd_len += 2;
    248 	      sprintf (op, "&0x%04x", PS (dst));
    249 	    }
    250 	  else if (regd == 3)
    251 	    {
    252 	      *cycles = 1;
    253 	      sprintf (op, "#1");
    254 	      sprintf (comm, "r3 As==01");
    255 	    }
    256 	  else
    257 	    {
    258 	      /* Indexd.  */
    259 	      dst = msp430dis_opcode (addr + 2, info);
    260 	      cmd_len += 2;
    261 	      sprintf (op, "%d(r%d)", dst, regd);
    262 	    }
    263 	}
    264       break;
    265 
    266     case 3:			/* Jumps.  */
    267       where = insn & 0x03ff;
    268       if (where & 0x200)
    269 	where |= ~0x03ff;
    270       if (where > 512 || where < -511)
    271 	return 0;
    272 
    273       where *= 2;
    274       sprintf (op, "$%+-8d", where + 2);
    275       sprintf (comm, "abs 0x%x", PS ((short) (addr) + 2 + where));
    276       *cycles = 2;
    277       return 2;
    278       break;
    279     default:
    280       cmd_len = 0;
    281     }
    282 
    283   return cmd_len;
    284 }
    285 
    286 static int
    287 msp430_doubleoperand (disassemble_info *info,
    288 		      struct msp430_opcode_s *opcode,
    289 		      bfd_vma addr,
    290 		      unsigned short insn,
    291 		      char *op1,
    292 		      char *op2,
    293 		      char *comm1,
    294 		      char *comm2,
    295 		      int *cycles)
    296 {
    297   int regs = 0, regd = 0;
    298   int ad = 0, as = 0;
    299   int cmd_len = 2;
    300   short dst = 0;
    301 
    302   regd = insn & 0x0f;
    303   regs = (insn & 0x0f00) >> 8;
    304   as = (insn & 0x0030) >> 4;
    305   ad = (insn & 0x0080) >> 7;
    306 
    307   if (opcode->fmt == 0)
    308     {
    309       /* Special case: rla and rlc are the only 2 emulated instructions that
    310 	 fall into two operand instructions.  */
    311       /* With dst, there are only:
    312 	 Rm       	Register,
    313          x(Rm)     	Indexed,
    314          0xXXXX    	Relative,
    315          &0xXXXX    	Absolute
    316          emulated_ins   dst
    317          basic_ins      dst, dst.  */
    318 
    319       if (regd != regs || as != ad)
    320 	return 0;		/* May be 'data' section.  */
    321 
    322       if (ad == 0)
    323 	{
    324 	  /* Register mode.  */
    325 	  if (regd == 3)
    326 	    {
    327 	      strcpy (comm1, _("Illegal as emulation instr"));
    328 	      return -1;
    329 	    }
    330 
    331 	  sprintf (op1, "r%d", regd);
    332 	  *cycles = 1;
    333 	}
    334       else			/* ad == 1 */
    335 	{
    336 	  if (regd == 0)
    337 	    {
    338 	      /* PC relative, Symbolic.  */
    339 	      dst = msp430dis_opcode (addr + 2, info);
    340 	      cmd_len += 4;
    341 	      *cycles = 6;
    342 	      sprintf (op1, "0x%04x", PS (dst));
    343 	      sprintf (comm1, "PC rel. 0x%04x",
    344 		       PS ((short) addr + 2 + dst));
    345 
    346 	    }
    347 	  else if (regd == 2)
    348 	    {
    349 	      /* Absolute.  */
    350 	      dst = msp430dis_opcode (addr + 2, info);
    351 	      /* If the 'src' field is not the same as the dst
    352 		 then this is not an rla instruction.  */
    353 	      if (dst != msp430dis_opcode (addr + 4, info))
    354 		return 0;
    355 	      cmd_len += 4;
    356 	      *cycles = 6;
    357 	      sprintf (op1, "&0x%04x", PS (dst));
    358 	    }
    359 	  else
    360 	    {
    361 	      /* Indexed.  */
    362 	      dst = msp430dis_opcode (addr + 2, info);
    363 	      cmd_len += 4;
    364 	      *cycles = 6;
    365 	      sprintf (op1, "%d(r%d)", dst, regd);
    366 	    }
    367 	}
    368 
    369       *op2 = 0;
    370       *comm2 = 0;
    371       return cmd_len;
    372     }
    373 
    374   /* Two operands exactly.  */
    375   if (ad == 0 && regd == 3)
    376     {
    377       /* R2/R3 are illegal as dest: may be data section.  */
    378       strcpy (comm1, _("Illegal as 2-op instr"));
    379       return -1;
    380     }
    381 
    382   /* Source.  */
    383   if (as == 0)
    384     {
    385       *cycles = 1;
    386       if (regs == 3)
    387 	{
    388 	  /* Constsnts.  */
    389 	  sprintf (op1, "#0");
    390 	  sprintf (comm1, "r3 As==00");
    391 	}
    392       else
    393 	{
    394 	  /* Register.  */
    395 	  sprintf (op1, "r%d", regs);
    396 	}
    397     }
    398   else if (as == 2)
    399     {
    400       *cycles = 1;
    401 
    402       if (regs == 2)
    403 	{
    404 	  sprintf (op1, "#4");
    405 	  sprintf (comm1, "r2 As==10");
    406 	}
    407       else if (regs == 3)
    408 	{
    409 	  sprintf (op1, "#2");
    410 	  sprintf (comm1, "r3 As==10");
    411 	}
    412       else
    413 	{
    414 	  *cycles = 2;
    415 
    416 	  /* Indexed register mode @Rn.  */
    417 	  sprintf (op1, "@r%d", regs);
    418 	}
    419       if (!regs)
    420 	*cycles = 3;
    421     }
    422   else if (as == 3)
    423     {
    424       if (regs == 2)
    425 	{
    426 	  sprintf (op1, "#8");
    427 	  sprintf (comm1, "r2 As==11");
    428 	  *cycles = 1;
    429 	}
    430       else if (regs == 3)
    431 	{
    432 	  sprintf (op1, "#-1");
    433 	  sprintf (comm1, "r3 As==11");
    434 	  *cycles = 1;
    435 	}
    436       else if (regs == 0)
    437 	{
    438 	  *cycles = 3;
    439 	  /* Absolute. @pc+.  */
    440 	  dst = msp430dis_opcode (addr + 2, info);
    441 	  cmd_len += 2;
    442 	  sprintf (op1, "#%d", dst);
    443 	  sprintf (comm1, "#0x%04x", PS (dst));
    444 	}
    445       else
    446 	{
    447 	  *cycles = 2;
    448 	  sprintf (op1, "@r%d+", regs);
    449 	}
    450     }
    451   else if (as == 1)
    452     {
    453       if (regs == 0)
    454 	{
    455 	  *cycles = 4;
    456 	  /* PC relative.  */
    457 	  dst = msp430dis_opcode (addr + 2, info);
    458 	  cmd_len += 2;
    459 	  sprintf (op1, "0x%04x", PS (dst));
    460 	  sprintf (comm1, "PC rel. 0x%04x",
    461 		   PS ((short) addr + 2 + dst));
    462 	}
    463       else if (regs == 2)
    464 	{
    465 	  *cycles = 2;
    466 	  /* Absolute.  */
    467 	  dst = msp430dis_opcode (addr + 2, info);
    468 	  cmd_len += 2;
    469 	  sprintf (op1, "&0x%04x", PS (dst));
    470 	  sprintf (comm1, "0x%04x", PS (dst));
    471 	}
    472       else if (regs == 3)
    473 	{
    474 	  *cycles = 1;
    475 	  sprintf (op1, "#1");
    476 	  sprintf (comm1, "r3 As==01");
    477 	}
    478       else
    479 	{
    480 	  *cycles = 3;
    481 	  /* Indexed.  */
    482 	  dst = msp430dis_opcode (addr + 2, info);
    483 	  cmd_len += 2;
    484 	  sprintf (op1, "%d(r%d)", dst, regs);
    485 	}
    486     }
    487 
    488   /* Destination. Special care needed on addr + XXXX.  */
    489 
    490   if (ad == 0)
    491     {
    492       /* Register.  */
    493       if (regd == 0)
    494 	{
    495 	  *cycles += 1;
    496 	  sprintf (op2, "r0");
    497 	}
    498       else if (regd == 1)
    499 	sprintf (op2, "r1");
    500 
    501       else if (regd == 2)
    502 	sprintf (op2, "r2");
    503 
    504       else
    505 	sprintf (op2, "r%d", regd);
    506     }
    507   else	/* ad == 1.  */
    508     {
    509       * cycles += 3;
    510 
    511       if (regd == 0)
    512 	{
    513 	  /* PC relative.  */
    514 	  *cycles += 1;
    515 	  dst = msp430dis_opcode (addr + cmd_len, info);
    516 	  sprintf (op2, "0x%04x", PS (dst));
    517 	  sprintf (comm2, "PC rel. 0x%04x",
    518 		   PS ((short) addr + cmd_len + dst));
    519 	  cmd_len += 2;
    520 	}
    521       else if (regd == 2)
    522 	{
    523 	  /* Absolute.  */
    524 	  dst = msp430dis_opcode (addr + cmd_len, info);
    525 	  cmd_len += 2;
    526 	  sprintf (op2, "&0x%04x", PS (dst));
    527 	}
    528       else
    529 	{
    530 	  dst = msp430dis_opcode (addr + cmd_len, info);
    531 	  cmd_len += 2;
    532 	  sprintf (op2, "%d(r%d)", dst, regd);
    533 	}
    534     }
    535 
    536   return cmd_len;
    537 }
    538 
    539 static int
    540 msp430_branchinstr (disassemble_info *info,
    541 		    struct msp430_opcode_s *opcode ATTRIBUTE_UNUSED,
    542 		    bfd_vma addr ATTRIBUTE_UNUSED,
    543 		    unsigned short insn,
    544 		    char *op1,
    545 		    char *comm1,
    546 		    int *cycles)
    547 {
    548   int regs = 0, regd = 0;
    549   int ad = 0, as = 0;
    550   int cmd_len = 2;
    551   short dst = 0;
    552 
    553   regd = insn & 0x0f;
    554   regs = (insn & 0x0f00) >> 8;
    555   as = (insn & 0x0030) >> 4;
    556   ad = (insn & 0x0080) >> 7;
    557 
    558   if (regd != 0)	/* Destination register is not a PC.  */
    559     return 0;
    560 
    561   /* dst is a source register.  */
    562   if (as == 0)
    563     {
    564       /* Constants.  */
    565       if (regs == 3)
    566 	{
    567 	  *cycles = 1;
    568 	  sprintf (op1, "#0");
    569 	  sprintf (comm1, "r3 As==00");
    570 	}
    571       else
    572 	{
    573 	  /* Register.  */
    574 	  *cycles = 1;
    575 	  sprintf (op1, "r%d", regs);
    576 	}
    577     }
    578   else if (as == 2)
    579     {
    580       if (regs == 2)
    581 	{
    582 	  *cycles = 2;
    583 	  sprintf (op1, "#4");
    584 	  sprintf (comm1, "r2 As==10");
    585 	}
    586       else if (regs == 3)
    587 	{
    588 	  *cycles = 1;
    589 	  sprintf (op1, "#2");
    590 	  sprintf (comm1, "r3 As==10");
    591 	}
    592       else
    593 	{
    594 	  /* Indexed register mode @Rn.  */
    595 	  *cycles = 2;
    596 	  sprintf (op1, "@r%d", regs);
    597 	}
    598     }
    599   else if (as == 3)
    600     {
    601       if (regs == 2)
    602 	{
    603 	  *cycles = 1;
    604 	  sprintf (op1, "#8");
    605 	  sprintf (comm1, "r2 As==11");
    606 	}
    607       else if (regs == 3)
    608 	{
    609 	  *cycles = 1;
    610 	  sprintf (op1, "#-1");
    611 	  sprintf (comm1, "r3 As==11");
    612 	}
    613       else if (regs == 0)
    614 	{
    615 	  /* Absolute. @pc+  */
    616 	  *cycles = 3;
    617 	  dst = msp430dis_opcode (addr + 2, info);
    618 	  cmd_len += 2;
    619 	  sprintf (op1, "#0x%04x", PS (dst));
    620 	}
    621       else
    622 	{
    623 	  *cycles = 2;
    624 	  sprintf (op1, "@r%d+", regs);
    625 	}
    626     }
    627   else if (as == 1)
    628     {
    629       * cycles = 3;
    630 
    631       if (regs == 0)
    632 	{
    633 	  /* PC relative.  */
    634 	  dst = msp430dis_opcode (addr + 2, info);
    635 	  cmd_len += 2;
    636 	  (*cycles)++;
    637 	  sprintf (op1, "0x%04x", PS (dst));
    638 	  sprintf (comm1, "PC rel. 0x%04x",
    639 		   PS ((short) addr + 2 + dst));
    640 	}
    641       else if (regs == 2)
    642 	{
    643 	  /* Absolute.  */
    644 	  dst = msp430dis_opcode (addr + 2, info);
    645 	  cmd_len += 2;
    646 	  sprintf (op1, "&0x%04x", PS (dst));
    647 	}
    648       else if (regs == 3)
    649 	{
    650 	  (*cycles)--;
    651 	  sprintf (op1, "#1");
    652 	  sprintf (comm1, "r3 As==01");
    653 	}
    654       else
    655 	{
    656 	  /* Indexd.  */
    657 	  dst = msp430dis_opcode (addr + 2, info);
    658 	  cmd_len += 2;
    659 	  sprintf (op1, "%d(r%d)", dst, regs);
    660 	}
    661     }
    662 
    663   return cmd_len;
    664 }
    665 
    666 int
    667 print_insn_msp430 (bfd_vma addr, disassemble_info *info)
    668 {
    669   void *stream = info->stream;
    670   fprintf_ftype prin = info->fprintf_func;
    671   struct msp430_opcode_s *opcode;
    672   char op1[32], op2[32], comm1[64], comm2[64];
    673   int cmd_len = 0;
    674   unsigned short insn;
    675   int cycles = 0;
    676   char *bc = "";
    677   char dinfo[32];		/* Debug purposes.  */
    678 
    679   insn = msp430dis_opcode (addr, info);
    680   sprintf (dinfo, "0x%04x", insn);
    681 
    682   if (((int) addr & 0xffff) > 0xffdf)
    683     {
    684       (*prin) (stream, "interrupt service routine at 0x%04x", 0xffff & insn);
    685       return 2;
    686     }
    687 
    688   *comm1 = 0;
    689   *comm2 = 0;
    690 
    691   for (opcode = msp430_opcodes; opcode->name; opcode++)
    692     {
    693       if ((insn & opcode->bin_mask) == opcode->bin_opcode
    694 	  && opcode->bin_opcode != 0x9300)
    695 	{
    696 	  *op1 = 0;
    697 	  *op2 = 0;
    698 	  *comm1 = 0;
    699 	  *comm2 = 0;
    700 
    701 	  /* r0 as destination. Ad should be zero.  */
    702 	  if (opcode->insn_opnumb == 3 && (insn & 0x000f) == 0
    703 	      && (0x0080 & insn) == 0)
    704 	    {
    705 	      cmd_len =
    706 		msp430_branchinstr (info, opcode, addr, insn, op1, comm1,
    707 				    &cycles);
    708 	      if (cmd_len)
    709 		break;
    710 	    }
    711 
    712 	  switch (opcode->insn_opnumb)
    713 	    {
    714 	    case 0:
    715 	      cmd_len = msp430_nooperands (opcode, addr, insn, comm1, &cycles);
    716 	      break;
    717 	    case 2:
    718 	      cmd_len =
    719 		msp430_doubleoperand (info, opcode, addr, insn, op1, op2,
    720 				      comm1, comm2, &cycles);
    721 	      if (insn & BYTE_OPERATION)
    722 		bc = ".b";
    723 	      break;
    724 	    case 1:
    725 	      cmd_len =
    726 		msp430_singleoperand (info, opcode, addr, insn, op1, comm1,
    727 				      &cycles);
    728 	      if (insn & BYTE_OPERATION && opcode->fmt != 3)
    729 		bc = ".b";
    730 	      break;
    731 	    default:
    732 	      break;
    733 	    }
    734 	}
    735 
    736       if (cmd_len)
    737 	break;
    738     }
    739 
    740   dinfo[5] = 0;
    741 
    742   if (cmd_len < 1)
    743     {
    744       /* Unknown opcode, or invalid combination of operands.  */
    745       (*prin) (stream, ".word	0x%04x;	????", PS (insn));
    746       return 2;
    747     }
    748 
    749   (*prin) (stream, "%s%s", opcode->name, bc);
    750 
    751   if (*op1)
    752     (*prin) (stream, "\t%s", op1);
    753   if (*op2)
    754     (*prin) (stream, ",");
    755 
    756   if (strlen (op1) < 7)
    757     (*prin) (stream, "\t");
    758   if (!strlen (op1))
    759     (*prin) (stream, "\t");
    760 
    761   if (*op2)
    762     (*prin) (stream, "%s", op2);
    763   if (strlen (op2) < 8)
    764     (*prin) (stream, "\t");
    765 
    766   if (*comm1 || *comm2)
    767     (*prin) (stream, ";");
    768   else if (cycles)
    769     {
    770       if (*op2)
    771 	(*prin) (stream, ";");
    772       else
    773 	{
    774 	  if (strlen (op1) < 7)
    775 	    (*prin) (stream, ";");
    776 	  else
    777 	    (*prin) (stream, "\t;");
    778 	}
    779     }
    780   if (*comm1)
    781     (*prin) (stream, "%s", comm1);
    782   if (*comm1 && *comm2)
    783     (*prin) (stream, ",");
    784   if (*comm2)
    785     (*prin) (stream, " %s", comm2);
    786   return cmd_len;
    787 }
    788