arc-dis.c revision 85815
1/* Instruction printing code for the ARC.
2   Copyright 1994, 1995, 1997, 1998, 2000, 2001
3   Free Software Foundation, Inc.
4   Contributed by Doug Evans (dje@cygnus.com).
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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
19
20#include <ansidecl.h>
21#include <libiberty.h>
22#include "dis-asm.h"
23#include "opcode/arc.h"
24#include "elf-bfd.h"
25#include "elf/arc.h"
26#include <string.h>
27#include "opintl.h"
28
29#include <ctype.h>
30#include <stdarg.h>
31#include "arc-dis.h"
32#include "arc-ext.h"
33
34#ifndef dbg
35#define dbg (0)
36#endif
37
38#define BIT(word,n) 	((word) & (1 << n))
39#define BITS(word,s,e)  (((word) << (31 - e)) >> (s + (31 - e)))
40#define OPCODE(word) 	(BITS ((word), 27, 31))
41#define FIELDA(word) 	(BITS ((word), 21, 26))
42#define FIELDB(word) 	(BITS ((word), 15, 20))
43#define FIELDC(word) 	(BITS ((word),  9, 14))
44
45/* FIELD D is signed in all of its uses, so we make sure argument is
46   treated as signed for bit shifting purposes:  */
47#define FIELDD(word) 	(BITS (((signed int)word), 0, 8))
48
49#define PUT_NEXT_WORD_IN(a)							\
50  do										\
51    {										\
52      if (is_limm == 1 && !NEXT_WORD (1))					\
53        mwerror (state, _("Illegal limm reference in last instruction!\n"));	\
54        a = state->words[1];							\
55    }										\
56  while (0)
57
58#define CHECK_FLAG_COND_NULLIFY()				\
59  do								\
60    {								\
61      if (is_shimm == 0)					\
62        {							\
63          flag = BIT (state->words[0], 8);			\
64          state->nullifyMode = BITS (state->words[0], 5, 6);	\
65          cond = BITS (state->words[0], 0, 4);			\
66        }							\
67    }								\
68  while (0)
69
70#define CHECK_COND()				\
71  do						\
72    {						\
73      if (is_shimm == 0)			\
74        cond = BITS (state->words[0], 0, 4);	\
75    }						\
76  while (0)
77
78#define CHECK_FIELD(field)			\
79  do						\
80    {						\
81      if (field == 62)				\
82        {					\
83          is_limm++;				\
84	  field##isReg = 0;			\
85	  PUT_NEXT_WORD_IN (field);		\
86	  limm_value = field;			\
87	}					\
88      else if (field > 60)			\
89        {					\
90	  field##isReg = 0;			\
91	  is_shimm++;				\
92	  flag = (field == 61);			\
93	  field = FIELDD (state->words[0]);	\
94	}					\
95    }						\
96  while (0)
97
98#define CHECK_FIELD_A()				\
99  do						\
100    {						\
101      fieldA = FIELDA(state->words[0]);		\
102      if (fieldA > 60)				\
103        {					\
104	  fieldAisReg = 0;			\
105	  fieldA = 0;				\
106	}					\
107    }						\
108  while (0)
109
110#define CHECK_FIELD_B()				\
111  do						\
112    {						\
113      fieldB = FIELDB (state->words[0]);	\
114      CHECK_FIELD (fieldB);			\
115    }						\
116  while (0)
117
118#define CHECK_FIELD_C()				\
119  do						\
120    {						\
121      fieldC = FIELDC (state->words[0]);	\
122      CHECK_FIELD (fieldC);			\
123    }						\
124  while (0)
125
126#define IS_SMALL(x) (((field##x) < 256) && ((field##x) > -257))
127#define IS_REG(x)   (field##x##isReg)
128#define WRITE_FORMAT_LB_Rx_RB(x)     WRITE_FORMAT(x,"[","]","","")
129#define WRITE_FORMAT_x_COMMA_LB(x)   WRITE_FORMAT(x,"",",[","",",[")
130#define WRITE_FORMAT_COMMA_x_RB(x)   WRITE_FORMAT(x,",","]",",","]")
131#define WRITE_FORMAT_x_RB(x)         WRITE_FORMAT(x,"","]","","]")
132#define WRITE_FORMAT_COMMA_x(x)      WRITE_FORMAT(x,",","",",","")
133#define WRITE_FORMAT_x_COMMA(x)      WRITE_FORMAT(x,"",",","",",")
134#define WRITE_FORMAT_x(x)            WRITE_FORMAT(x,"","","","")
135#define WRITE_FORMAT(x,cb1,ca1,cb,ca) strcat (formatString,		\
136				     (IS_REG (x) ? cb1"%r"ca1 :		\
137				      usesAuxReg ? cb"%a"ca :		\
138				      IS_SMALL (x) ? cb"%d"ca : cb"%h"ca))
139#define WRITE_FORMAT_RB() 	strcat (formatString, "]")
140#define WRITE_COMMENT(str)	(state->comm[state->commNum++] = (str))
141#define WRITE_NOP_COMMENT() 	if (!fieldAisReg && !flag) WRITE_COMMENT ("nop");
142
143#define NEXT_WORD(x) 	(offset += 4, state->words[x])
144
145#define add_target(x) 	(state->targets[state->tcnt++] = (x))
146
147static char comment_prefix[] = "\t; ";
148
149static const char *
150core_reg_name (state, val)
151     struct arcDisState * state;
152     int                  val;
153{
154  if (state->coreRegName)
155    return (*state->coreRegName)(state->_this, val);
156  return 0;
157}
158
159static const char *
160aux_reg_name (state, val)
161     struct arcDisState * state;
162     int                  val;
163{
164  if (state->auxRegName)
165    return (*state->auxRegName)(state->_this, val);
166  return 0;
167}
168
169static const char *
170cond_code_name (state, val)
171     struct arcDisState * state;
172     int                  val;
173{
174  if (state->condCodeName)
175    return (*state->condCodeName)(state->_this, val);
176  return 0;
177}
178
179static const char *
180instruction_name (state, op1, op2, flags)
181     struct arcDisState * state;
182     int    op1;
183     int    op2;
184     int *  flags;
185{
186  if (state->instName)
187    return (*state->instName)(state->_this, op1, op2, flags);
188  return 0;
189}
190
191static void
192mwerror (state, msg)
193     struct arcDisState * state;
194     const char * msg;
195{
196  if (state->err != 0)
197    (*state->err)(state->_this, (msg));
198}
199
200static const char *
201post_address (state, addr)
202     struct arcDisState * state;
203     int addr;
204{
205  static char id[3 * ARRAY_SIZE (state->addresses)];
206  int j, i = state->acnt;
207
208  if (i < ((int) ARRAY_SIZE (state->addresses)))
209    {
210      state->addresses[i] = addr;
211      ++state->acnt;
212      j = i*3;
213      id[j+0] = '@';
214      id[j+1] = '0'+i;
215      id[j+2] = 0;
216
217      return id + j;
218    }
219  return "";
220}
221
222static void
223my_sprintf (
224	    struct arcDisState * state,
225	    char * buf,
226	    const char * format,
227	    ...)
228{
229  char *bp;
230  const char *p;
231  int size, leading_zero, regMap[2];
232  long auxNum;
233  va_list ap;
234
235  va_start (ap, format);
236
237  bp = buf;
238  *bp = 0;
239  p = format;
240  auxNum = -1;
241  regMap[0] = 0;
242  regMap[1] = 0;
243
244  while (1)
245    switch (*p++)
246      {
247    case 0:
248      goto DOCOMM; /* (return)  */
249      default:
250	*bp++ = p[-1];
251	break;
252      case '%':
253	size = 0;
254	leading_zero = 0;
255      RETRY: ;
256	switch (*p++)
257	  {
258	  case '0':
259	  case '1':
260	  case '2':
261	  case '3':
262	  case '4':
263	  case '5':
264	  case '6':
265	  case '7':
266	  case '8':
267	  case '9':
268	    {
269	      /* size.  */
270	      size = p[-1] - '0';
271	      if (size == 0)
272		leading_zero = 1; /* e.g. %08x  */
273	      while (*p >= '0' && *p <= '9')
274		{
275		  size = size * 10 + *p - '0';
276		  p++;
277		}
278	      goto RETRY;
279	    }
280#define inc_bp() bp = bp + strlen (bp)
281
282	  case 'h':
283	    {
284	      unsigned u = va_arg (ap, int);
285
286	      /* Hex.  We can change the format to 0x%08x in
287		 one place, here, if we wish.
288		 We add underscores for easy reading.  */
289	      if (u > 65536)
290		sprintf (bp, "0x%x_%04x", u >> 16, u & 0xffff);
291	      else
292		sprintf (bp, "0x%x", u);
293	      inc_bp ();
294	    }
295	    break;
296	  case 'X': case 'x':
297	    {
298	      int val = va_arg (ap, int);
299
300	      if (size != 0)
301		if (leading_zero)
302		  sprintf (bp, "%0*x", size, val);
303		else
304		  sprintf (bp, "%*x", size, val);
305	      else
306		sprintf (bp, "%x", val);
307	      inc_bp ();
308	    }
309	    break;
310	  case 'd':
311	    {
312	      int val = va_arg (ap, int);
313
314	      if (size != 0)
315		sprintf (bp, "%*d", size, val);
316	      else
317		sprintf (bp, "%d", val);
318	      inc_bp ();
319	    }
320	    break;
321	  case 'r':
322	    {
323	      /* Register.  */
324	      int val = va_arg (ap, int);
325
326#define REG2NAME(num, name) case num: sprintf (bp, ""name); \
327  regMap[(num < 32) ? 0 : 1] |= 1 << (num - ((num < 32) ? 0 : 32)); break;
328
329	      switch (val)
330		{
331		  REG2NAME (26, "gp");
332		  REG2NAME (27, "fp");
333		  REG2NAME (28, "sp");
334		  REG2NAME (29, "ilink1");
335		  REG2NAME (30, "ilink2");
336		  REG2NAME (31, "blink");
337		  REG2NAME (60, "lp_count");
338		default:
339		  {
340		    const char * ext;
341
342		    ext = core_reg_name (state, val);
343		    if (ext)
344		      sprintf (bp, "%s", ext);
345		    else
346		      sprintf (bp,"r%d",val);
347		  }
348		  break;
349		}
350	      inc_bp ();
351	    } break;
352
353	  case 'a':
354	    {
355	      /* Aux Register.  */
356	      int val = va_arg (ap, int);
357
358#define AUXREG2NAME(num, name) case num: sprintf (bp,name); break;
359
360	      switch (val)
361		{
362		  AUXREG2NAME (0x0, "status");
363		  AUXREG2NAME (0x1, "semaphore");
364		  AUXREG2NAME (0x2, "lp_start");
365		  AUXREG2NAME (0x3, "lp_end");
366		  AUXREG2NAME (0x4, "identity");
367		  AUXREG2NAME (0x5, "debug");
368		default:
369		  {
370		    const char *ext;
371
372		    ext = aux_reg_name (state, val);
373		    if (ext)
374		      sprintf (bp, "%s", ext);
375		    else
376		      my_sprintf (state, bp, "%h", val);
377		  }
378		  break;
379		}
380	      inc_bp ();
381	    }
382	    break;
383
384	  case 's':
385	    {
386	      sprintf (bp, "%s", va_arg (ap, char *));
387	      inc_bp ();
388	    }
389	    break;
390
391	  default:
392	    fprintf (stderr, "?? format %c\n", p[-1]);
393	    break;
394	  }
395      }
396
397 DOCOMM: *bp = 0;
398}
399
400static void
401write_comments_(state, shimm, is_limm, limm_value)
402     struct arcDisState * state;
403     int shimm;
404     int is_limm;
405     long limm_value;
406{
407  if (state->commentBuffer != 0)
408    {
409      int i;
410
411      if (is_limm)
412	{
413	  const char *name = post_address (state, limm_value + shimm);
414
415	  if (*name != 0)
416	    WRITE_COMMENT (name);
417	}
418      for (i = 0; i < state->commNum; i++)
419	{
420	  if (i == 0)
421	    strcpy (state->commentBuffer, comment_prefix);
422	  else
423	    strcat (state->commentBuffer, ", ");
424	  strncat (state->commentBuffer, state->comm[i], sizeof (state->commentBuffer));
425	}
426    }
427}
428
429#define write_comments2(x) write_comments_(state, x, is_limm, limm_value)
430#define write_comments() write_comments2(0)
431
432static const char *condName[] = {
433  /* 0..15.  */
434  ""   , "z"  , "nz" , "p"  , "n"  , "c"  , "nc" , "v"  ,
435  "nv" , "gt" , "ge" , "lt" , "le" , "hi" , "ls" , "pnz"
436};
437
438static void
439write_instr_name_(state, instrName, cond, condCodeIsPartOfName, flag, signExtend, addrWriteBack, directMem)
440     struct arcDisState * state;
441     const char * instrName;
442     int cond;
443     int condCodeIsPartOfName;
444     int flag;
445     int signExtend;
446     int addrWriteBack;
447     int directMem;
448{
449  strcpy (state->instrBuffer, instrName);
450
451  if (cond > 0)
452    {
453      const char *cc = 0;
454
455      if (!condCodeIsPartOfName)
456	strcat (state->instrBuffer, ".");
457
458      if (cond < 16)
459	cc = condName[cond];
460      else
461	cc = cond_code_name (state, cond);
462
463      if (!cc)
464	cc = "???";
465
466      strcat (state->instrBuffer, cc);
467    }
468
469  if (flag)
470    strcat (state->instrBuffer, ".f");
471
472  switch (state->nullifyMode)
473    {
474    case BR_exec_always:
475      strcat (state->instrBuffer, ".d");
476      break;
477    case BR_exec_when_jump:
478      strcat (state->instrBuffer, ".jd");
479      break;
480    }
481
482  if (signExtend)
483    strcat (state->instrBuffer, ".x");
484
485  if (addrWriteBack)
486    strcat (state->instrBuffer, ".a");
487
488  if (directMem)
489    strcat (state->instrBuffer, ".di");
490}
491
492#define write_instr_name()						\
493  do									\
494    {									\
495      write_instr_name_(state, instrName,cond, condCodeIsPartOfName,	\
496			flag, signExtend, addrWriteBack, directMem);	\
497      formatString[0] = '\0';						\
498    }									\
499  while (0)
500
501enum {
502  op_LD0 = 0, op_LD1 = 1, op_ST  = 2, op_3   = 3,
503  op_BC  = 4, op_BLC = 5, op_LPC = 6, op_JC  = 7,
504  op_ADD = 8, op_ADC = 9, op_SUB = 10, op_SBC = 11,
505  op_AND = 12, op_OR  = 13, op_BIC = 14, op_XOR = 15
506};
507
508extern disassemble_info tm_print_insn_info;
509
510static int
511dsmOneArcInst (addr, state)
512     bfd_vma              addr;
513     struct arcDisState * state;
514{
515  int condCodeIsPartOfName = 0;
516  int decodingClass;
517  const char * instrName;
518  int repeatsOp = 0;
519  int fieldAisReg = 1;
520  int fieldBisReg = 1;
521  int fieldCisReg = 1;
522  int fieldA;
523  int fieldB;
524  int fieldC = 0;
525  int flag = 0;
526  int cond = 0;
527  int is_shimm = 0;
528  int is_limm = 0;
529  long limm_value = 0;
530  int signExtend = 0;
531  int addrWriteBack = 0;
532  int directMem = 0;
533  int is_linked = 0;
534  int offset = 0;
535  int usesAuxReg = 0;
536  int flags;
537  int ignoreFirstOpd;
538  char formatString[60];
539
540  state->instructionLen = 4;
541  state->nullifyMode = BR_exec_when_no_jump;
542  state->opWidth = 12;
543  state->isBranch = 0;
544
545  state->_mem_load = 0;
546  state->_ea_present = 0;
547  state->_load_len = 0;
548  state->ea_reg1 = no_reg;
549  state->ea_reg2 = no_reg;
550  state->_offset = 0;
551
552  if (! NEXT_WORD (0))
553    return 0;
554
555  state->_opcode = OPCODE (state->words[0]);
556  instrName = 0;
557  decodingClass = 0; /* default!  */
558  repeatsOp = 0;
559  condCodeIsPartOfName=0;
560  state->commNum = 0;
561  state->tcnt = 0;
562  state->acnt = 0;
563  state->flow = noflow;
564  ignoreFirstOpd = 0;
565
566  if (state->commentBuffer)
567    state->commentBuffer[0] = '\0';
568
569  switch (state->_opcode)
570    {
571    case op_LD0:
572      switch (BITS (state->words[0],1,2))
573	{
574	case 0:
575	  instrName = "ld";
576	  state->_load_len = 4;
577	  break;
578	case 1:
579	  instrName = "ldb";
580	  state->_load_len = 1;
581	  break;
582	case 2:
583	  instrName = "ldw";
584	  state->_load_len = 2;
585	  break;
586	default:
587	  instrName = "??? (0[3])";
588	  state->flow = invalid_instr;
589	  break;
590	}
591      decodingClass = 5;
592      break;
593
594    case op_LD1:
595      if (BIT (state->words[0],13))
596	{
597	  instrName = "lr";
598	  decodingClass = 10;
599	}
600      else
601	{
602	  switch (BITS (state->words[0],10,11))
603	    {
604	    case 0:
605	      instrName = "ld";
606	      state->_load_len = 4;
607	      break;
608	    case 1:
609	      instrName = "ldb";
610	      state->_load_len = 1;
611	      break;
612	    case 2:
613	      instrName = "ldw";
614	      state->_load_len = 2;
615	      break;
616	    default:
617	      instrName = "??? (1[3])";
618	      state->flow = invalid_instr;
619	      break;
620	    }
621	  decodingClass = 6;
622	}
623      break;
624
625    case op_ST:
626      if (BIT (state->words[0],25))
627	{
628	  instrName = "sr";
629	  decodingClass = 8;
630	}
631      else
632	{
633	  switch (BITS (state->words[0],22,23))
634	    {
635	    case 0:
636	      instrName = "st";
637	      break;
638	    case 1:
639	      instrName = "stb";
640	      break;
641	    case 2:
642	      instrName = "stw";
643	      break;
644	    default:
645	      instrName = "??? (2[3])";
646	      state->flow = invalid_instr;
647	      break;
648	    }
649	  decodingClass = 7;
650	}
651      break;
652
653    case op_3:
654      decodingClass = 1;  /* default for opcode 3...  */
655      switch (FIELDC (state->words[0]))
656	{
657	case  0:
658	  instrName = "flag";
659	  decodingClass = 2;
660	  break;
661	case  1:
662	  instrName = "asr";
663	  break;
664	case  2:
665	  instrName = "lsr";
666	  break;
667	case  3:
668	  instrName = "ror";
669	  break;
670	case  4:
671	  instrName = "rrc";
672	  break;
673	case  5:
674	  instrName = "sexb";
675	  break;
676	case  6:
677	  instrName = "sexw";
678	  break;
679	case  7:
680	  instrName = "extb";
681	  break;
682	case  8:
683	  instrName = "extw";
684	  break;
685	case  0x3f:
686	  {
687	    decodingClass = 9;
688	    switch( FIELDD (state->words[0]) )
689	      {
690	      case 0:
691		instrName = "brk";
692		break;
693	      case 1:
694		instrName = "sleep";
695		break;
696	      case 2:
697		instrName = "swi";
698		break;
699	      default:
700		instrName = "???";
701		state->flow=invalid_instr;
702		break;
703	      }
704	  }
705	  break;
706
707	  /* ARC Extension Library Instructions
708	     NOTE: We assume that extension codes are these instrs.  */
709	default:
710	  instrName = instruction_name (state,
711					state->_opcode,
712					FIELDC (state->words[0]),
713					& flags);
714	  if (!instrName)
715	    {
716	      instrName = "???";
717	      state->flow = invalid_instr;
718	    }
719	  if (flags & IGNORE_FIRST_OPD)
720	    ignoreFirstOpd = 1;
721	  break;
722	}
723      break;
724
725    case op_BC:
726      instrName = "b";
727    case op_BLC:
728      if (!instrName)
729	instrName = "bl";
730    case op_LPC:
731      if (!instrName)
732	instrName = "lp";
733    case op_JC:
734      if (!instrName)
735	{
736	  if (BITS (state->words[0],9,9))
737	    {
738	      instrName = "jl";
739	      is_linked = 1;
740	    }
741	  else
742	    {
743	      instrName = "j";
744	      is_linked = 0;
745	    }
746	}
747      condCodeIsPartOfName = 1;
748      decodingClass = ((state->_opcode == op_JC) ? 4 : 3);
749      state->isBranch = 1;
750      break;
751
752    case op_ADD:
753    case op_ADC:
754    case op_AND:
755      repeatsOp = (FIELDC (state->words[0]) == FIELDB (state->words[0]));
756      decodingClass = 0;
757
758      switch (state->_opcode)
759	{
760	case op_ADD:
761	  instrName = (repeatsOp ? "asl" : "add");
762	  break;
763	case op_ADC:
764	  instrName = (repeatsOp ? "rlc" : "adc");
765	  break;
766	case op_AND:
767	  instrName = (repeatsOp ? "mov" : "and");
768	  break;
769	}
770      break;
771
772    case op_SUB: instrName = "sub";
773      break;
774    case op_SBC: instrName = "sbc";
775      break;
776    case op_OR:  instrName = "or";
777      break;
778    case op_BIC: instrName = "bic";
779      break;
780
781    case op_XOR:
782      if (state->words[0] == 0x7fffffff)
783	{
784	  /* nop encoded as xor -1, -1, -1  */
785	  instrName = "nop";
786	  decodingClass = 9;
787	}
788      else
789	instrName = "xor";
790      break;
791
792    default:
793      instrName = instruction_name (state,state->_opcode,0,&flags);
794      /* if (instrName) printf("FLAGS=0x%x\n", flags);  */
795      if (!instrName)
796	{
797	  instrName = "???";
798	  state->flow=invalid_instr;
799	}
800      if (flags & IGNORE_FIRST_OPD)
801	ignoreFirstOpd = 1;
802      break;
803    }
804
805  fieldAisReg = fieldBisReg = fieldCisReg = 1; /* Assume regs for now.  */
806  flag = cond = is_shimm = is_limm = 0;
807  state->nullifyMode = BR_exec_when_no_jump;	/* 0  */
808  signExtend = addrWriteBack = directMem = 0;
809  usesAuxReg = 0;
810
811  switch (decodingClass)
812    {
813    case 0:
814      CHECK_FIELD_A ();
815      CHECK_FIELD_B ();
816      if (!repeatsOp)
817	CHECK_FIELD_C ();
818      CHECK_FLAG_COND_NULLIFY ();
819
820      write_instr_name ();
821      if (!ignoreFirstOpd)
822	{
823	  WRITE_FORMAT_x (A);
824	  WRITE_FORMAT_COMMA_x (B);
825	  if (!repeatsOp)
826	    WRITE_FORMAT_COMMA_x (C);
827	  WRITE_NOP_COMMENT ();
828	  my_sprintf (state, state->operandBuffer, formatString, fieldA, fieldB, fieldC);
829	}
830      else
831	{
832	  WRITE_FORMAT_x (B);
833	  if (!repeatsOp)
834	    WRITE_FORMAT_COMMA_x (C);
835	  my_sprintf (state, state->operandBuffer, formatString, fieldB, fieldC);
836	}
837      write_comments ();
838      break;
839
840    case 1:
841      CHECK_FIELD_A ();
842      CHECK_FIELD_B ();
843      CHECK_FLAG_COND_NULLIFY ();
844
845      write_instr_name ();
846      if (!ignoreFirstOpd)
847	{
848	  WRITE_FORMAT_x (A);
849	  WRITE_FORMAT_COMMA_x (B);
850	  WRITE_NOP_COMMENT ();
851	  my_sprintf (state, state->operandBuffer, formatString, fieldA, fieldB);
852	}
853      else
854	{
855	  WRITE_FORMAT_x (B);
856	  my_sprintf (state, state->operandBuffer, formatString, fieldB);
857	}
858      write_comments ();
859      break;
860
861    case 2:
862      CHECK_FIELD_B ();
863      CHECK_FLAG_COND_NULLIFY ();
864      flag = 0; /* this is the FLAG instruction -- it's redundant  */
865
866      write_instr_name ();
867      WRITE_FORMAT_x (B);
868      my_sprintf (state, state->operandBuffer, formatString, fieldB);
869      write_comments ();
870      break;
871
872    case 3:
873      fieldA = BITS (state->words[0],7,26) << 2;
874      fieldA = (fieldA << 10) >> 10; /* make it signed  */
875      fieldA += addr + 4;
876      CHECK_FLAG_COND_NULLIFY ();
877      flag = 0;
878
879      write_instr_name ();
880      /* This address could be a label we know. Convert it.  */
881      if (state->_opcode != op_LPC /* LP  */)
882	{
883	add_target (fieldA); /* For debugger.  */
884	state->flow = state->_opcode == op_BLC /* BL  */
885	  ? direct_call
886	  : direct_jump;
887	/* indirect calls are achieved by "lr blink,[status];
888	   lr dest<- func addr; j [dest]"  */
889	}
890
891      strcat (formatString, "%s"); /* address/label name */
892      my_sprintf (state, state->operandBuffer, formatString, post_address (state, fieldA));
893      write_comments ();
894      break;
895
896    case 4:
897      /* For op_JC -- jump to address specified.
898	 Also covers jump and link--bit 9 of the instr. word
899	 selects whether linked, thus "is_linked" is set above.  */
900      fieldA = 0;
901      CHECK_FIELD_B ();
902      CHECK_FLAG_COND_NULLIFY ();
903
904      if (!fieldBisReg)
905	{
906	  fieldAisReg = 0;
907	  fieldA = (fieldB >> 25) & 0x7F; /* flags */
908	  fieldB = (fieldB & 0xFFFFFF) << 2;
909	  state->flow = is_linked ? direct_call : direct_jump;
910	  add_target (fieldB);
911	  /* screwy JLcc requires .jd mode to execute correctly
912	   * but we pretend it is .nd (no delay slot).  */
913	  if (is_linked && state->nullifyMode == BR_exec_when_jump)
914	    state->nullifyMode = BR_exec_when_no_jump;
915	}
916      else
917	{
918	  state->flow = is_linked ? indirect_call : indirect_jump;
919	  /* We should also treat this as indirect call if NOT linked
920	   * but the preceding instruction was a "lr blink,[status]"
921	   * and we have a delay slot with "add blink,blink,2".
922	   * For now we can't detect such.  */
923	  state->register_for_indirect_jump = fieldB;
924	}
925
926      write_instr_name ();
927      strcat (formatString,
928	      IS_REG (B) ? "[%r]" : "%s"); /* address/label name  */
929      if (fieldA != 0)
930	{
931	  fieldAisReg = 0;
932	  WRITE_FORMAT_COMMA_x (A);
933	}
934      if (IS_REG (B))
935	my_sprintf (state, state->operandBuffer, formatString, fieldB, fieldA);
936      else
937	my_sprintf (state, state->operandBuffer, formatString,
938		    post_address (state, fieldB), fieldA);
939      write_comments ();
940      break;
941
942    case 5:
943      /* LD instruction.
944	 B and C can be regs, or one (both?) can be limm.  */
945      CHECK_FIELD_A ();
946      CHECK_FIELD_B ();
947      CHECK_FIELD_C ();
948      if (dbg)
949	printf ("5:b reg %d %d c reg %d %d  \n",
950		fieldBisReg,fieldB,fieldCisReg,fieldC);
951      state->_offset = 0;
952      state->_ea_present = 1;
953      if (fieldBisReg)
954	state->ea_reg1 = fieldB;
955      else
956	state->_offset += fieldB;
957      if (fieldCisReg)
958	state->ea_reg2 = fieldC;
959      else
960	state->_offset += fieldC;
961      state->_mem_load = 1;
962
963      directMem     = BIT (state->words[0],5);
964      addrWriteBack = BIT (state->words[0],3);
965      signExtend    = BIT (state->words[0],0);
966
967      write_instr_name ();
968      WRITE_FORMAT_x_COMMA_LB(A);
969      if (fieldBisReg || fieldB != 0)
970	WRITE_FORMAT_x_COMMA (B);
971      else
972	fieldB = fieldC;
973
974      WRITE_FORMAT_x_RB (C);
975      my_sprintf (state, state->operandBuffer, formatString, fieldA, fieldB, fieldC);
976      write_comments ();
977      break;
978
979    case 6:
980      /* LD instruction.  */
981      CHECK_FIELD_B ();
982      CHECK_FIELD_A ();
983      fieldC = FIELDD (state->words[0]);
984
985      if (dbg)
986	printf ("6:b reg %d %d c 0x%x  \n",
987		fieldBisReg, fieldB, fieldC);
988      state->_ea_present = 1;
989      state->_offset = fieldC;
990      state->_mem_load = 1;
991      if (fieldBisReg)
992	state->ea_reg1 = fieldB;
993      /* field B is either a shimm (same as fieldC) or limm (different!)
994	 Say ea is not present, so only one of us will do the name lookup.  */
995      else
996	state->_offset += fieldB, state->_ea_present = 0;
997
998      directMem     = BIT (state->words[0],14);
999      addrWriteBack = BIT (state->words[0],12);
1000      signExtend    = BIT (state->words[0],9);
1001
1002      write_instr_name ();
1003      WRITE_FORMAT_x_COMMA_LB (A);
1004      if (!fieldBisReg)
1005	{
1006	  fieldB = state->_offset;
1007	  WRITE_FORMAT_x_RB (B);
1008	}
1009      else
1010	{
1011	  WRITE_FORMAT_x (B);
1012	  if (fieldC != 0 && !BIT (state->words[0],13))
1013	    {
1014	      fieldCisReg = 0;
1015	      WRITE_FORMAT_COMMA_x_RB (C);
1016	    }
1017	  else
1018	    WRITE_FORMAT_RB ();
1019	}
1020      my_sprintf (state, state->operandBuffer, formatString, fieldA, fieldB, fieldC);
1021      write_comments ();
1022      break;
1023
1024    case 7:
1025      /* ST instruction.  */
1026      CHECK_FIELD_B();
1027      CHECK_FIELD_C();
1028      fieldA = FIELDD(state->words[0]); /* shimm  */
1029
1030      /* [B,A offset]  */
1031      if (dbg) printf("7:b reg %d %x off %x\n",
1032				 fieldBisReg,fieldB,fieldA);
1033      state->_ea_present = 1;
1034      state->_offset = fieldA;
1035      if (fieldBisReg)
1036	state->ea_reg1 = fieldB;
1037      /* field B is either a shimm (same as fieldA) or limm (different!)
1038	 Say ea is not present, so only one of us will do the name lookup.
1039	 (for is_limm we do the name translation here).  */
1040      else
1041	state->_offset += fieldB, state->_ea_present = 0;
1042
1043      directMem     = BIT(state->words[0],26);
1044      addrWriteBack = BIT(state->words[0],24);
1045
1046      write_instr_name();
1047      WRITE_FORMAT_x_COMMA_LB(C);
1048
1049      if (!fieldBisReg)
1050	{
1051	  fieldB = state->_offset;
1052	  WRITE_FORMAT_x_RB(B);
1053	}
1054      else
1055	{
1056	  WRITE_FORMAT_x(B);
1057	  if (fieldBisReg && fieldA != 0)
1058	    {
1059	      fieldAisReg = 0;
1060	      WRITE_FORMAT_COMMA_x_RB(A);
1061	    }
1062	  else
1063	    WRITE_FORMAT_RB();
1064	}
1065      my_sprintf (state, state->operandBuffer, formatString, fieldC, fieldB, fieldA);
1066      write_comments2(fieldA);
1067      break;
1068    case 8:
1069      /* SR instruction  */
1070      CHECK_FIELD_B();
1071      CHECK_FIELD_C();
1072
1073      write_instr_name();
1074      WRITE_FORMAT_x_COMMA_LB(C);
1075      /* Try to print B as an aux reg if it is not a core reg.  */
1076      usesAuxReg = 1;
1077      WRITE_FORMAT_x(B);
1078      WRITE_FORMAT_RB();
1079      my_sprintf (state, state->operandBuffer, formatString, fieldC, fieldB);
1080      write_comments();
1081      break;
1082
1083    case 9:
1084      write_instr_name();
1085      state->operandBuffer[0] = '\0';
1086      break;
1087
1088    case 10:
1089      /* LR instruction */
1090      CHECK_FIELD_A();
1091      CHECK_FIELD_B();
1092
1093      write_instr_name();
1094      WRITE_FORMAT_x_COMMA_LB(A);
1095      /* Try to print B as an aux reg if it is not a core reg. */
1096      usesAuxReg = 1;
1097      WRITE_FORMAT_x(B);
1098      WRITE_FORMAT_RB();
1099      my_sprintf (state, state->operandBuffer, formatString, fieldA, fieldB);
1100      write_comments();
1101      break;
1102
1103    case 11:
1104      CHECK_COND();
1105      write_instr_name();
1106      state->operandBuffer[0] = '\0';
1107      break;
1108
1109    default:
1110      mwerror (state, "Bad decoding class in ARC disassembler");
1111      break;
1112    }
1113
1114  state->_cond = cond;
1115  return state->instructionLen = offset;
1116}
1117
1118
1119/* Returns the name the user specified core extension register.  */
1120static const char *
1121_coreRegName(arg, regval)
1122     void * arg ATTRIBUTE_UNUSED;
1123     int regval;
1124{
1125  return arcExtMap_coreRegName (regval);
1126}
1127
1128/* Returns the name the user specified AUX extension register.  */
1129static const char *
1130_auxRegName(void *_this ATTRIBUTE_UNUSED, int regval)
1131{
1132    return arcExtMap_auxRegName(regval);
1133}
1134
1135
1136/* Returns the name the user specified condition code name.  */
1137static const char *
1138_condCodeName(void *_this ATTRIBUTE_UNUSED, int regval)
1139{
1140    return arcExtMap_condCodeName(regval);
1141}
1142
1143/* Returns the name the user specified extension instruction.  */
1144static const char *
1145_instName (void *_this ATTRIBUTE_UNUSED, int majop, int minop, int *flags)
1146{
1147    return arcExtMap_instName(majop, minop, flags);
1148}
1149
1150/* Decode an instruction returning the size of the instruction
1151   in bytes or zero if unrecognized.  */
1152static int
1153decodeInstr (address, info)
1154     bfd_vma            address; /* Address of this instruction.  */
1155     disassemble_info * info;
1156{
1157  int status;
1158  bfd_byte buffer[4];
1159  struct arcDisState s;	/* ARC Disassembler state  */
1160  void *stream = info->stream; /* output stream  */
1161  fprintf_ftype func = info->fprintf_func;
1162  int bytes;
1163
1164  memset (&s, 0, sizeof(struct arcDisState));
1165
1166  /* read first instruction  */
1167  status = (*info->read_memory_func) (address, buffer, 4, info);
1168  if (status != 0)
1169    {
1170      (*info->memory_error_func) (status, address, info);
1171      return 0;
1172    }
1173  if (info->endian == BFD_ENDIAN_LITTLE)
1174    s.words[0] = bfd_getl32(buffer);
1175  else
1176    s.words[0] = bfd_getb32(buffer);
1177  /* always read second word in case of limm  */
1178
1179  /* we ignore the result since last insn may not have a limm  */
1180  status = (*info->read_memory_func) (address + 4, buffer, 4, info);
1181  if (info->endian == BFD_ENDIAN_LITTLE)
1182    s.words[1] = bfd_getl32(buffer);
1183  else
1184    s.words[1] = bfd_getb32(buffer);
1185
1186  s._this = &s;
1187  s.coreRegName = _coreRegName;
1188  s.auxRegName = _auxRegName;
1189  s.condCodeName = _condCodeName;
1190  s.instName = _instName;
1191
1192  /* disassemble  */
1193  bytes = dsmOneArcInst(address, (void *)&s);
1194
1195  /* display the disassembly instruction  */
1196  (*func) (stream, "%08x ", s.words[0]);
1197  (*func) (stream, "    ");
1198
1199  (*func) (stream, "%-10s ", s.instrBuffer);
1200
1201  if (__TRANSLATION_REQUIRED(s))
1202    {
1203      bfd_vma addr = s.addresses[s.operandBuffer[1] - '0'];
1204      (*info->print_address_func) ((bfd_vma) addr, info);
1205      (*func) (stream, "\n");
1206    }
1207  else
1208    (*func) (stream, "%s",s.operandBuffer);
1209  return s.instructionLen;
1210}
1211
1212/* Return the print_insn function to use.
1213   Side effect: load (possibly empty) extension section  */
1214
1215disassembler_ftype
1216arc_get_disassembler (void *ptr)
1217{
1218  if (ptr)
1219    build_ARC_extmap (ptr);
1220  return decodeInstr;
1221}
1222