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