xref: /netbsd-src/external/gpl3/binutils/dist/cpu/ip2k.opc (revision 883529b6859962066edccc75471ffe4d419d3caa)
1*883529b6Schristos/* IP2K opcode support.  -*- C -*-
2*883529b6Schristos   Copyright 2002, 2005, 2011 Free Software Foundation, Inc.
3*883529b6Schristos
4*883529b6Schristos   Contributed by Red Hat Inc;
5*883529b6Schristos
6*883529b6Schristos   This file is part of the GNU Binutils.
7*883529b6Schristos
8*883529b6Schristos   This program is free software; you can redistribute it and/or modify
9*883529b6Schristos   it under the terms of the GNU General Public License as published by
10*883529b6Schristos   the Free Software Foundation; either version 3 of the License, or
11*883529b6Schristos   (at your option) any later version.
12*883529b6Schristos
13*883529b6Schristos   This program is distributed in the hope that it will be useful,
14*883529b6Schristos   but WITHOUT ANY WARRANTY; without even the implied warranty of
15*883529b6Schristos   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16*883529b6Schristos   GNU General Public License for more details.
17*883529b6Schristos
18*883529b6Schristos   You should have received a copy of the GNU General Public License
19*883529b6Schristos   along with this program; if not, write to the Free Software
20*883529b6Schristos   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
21*883529b6Schristos   MA 02110-1301, USA.  */
22*883529b6Schristos
23*883529b6Schristos/*
24*883529b6Schristos   Each section is delimited with start and end markers.
25*883529b6Schristos
26*883529b6Schristos   <arch>-opc.h additions use: "-- opc.h"
27*883529b6Schristos   <arch>-opc.c additions use: "-- opc.c"
28*883529b6Schristos   <arch>-asm.c additions use: "-- asm.c"
29*883529b6Schristos   <arch>-dis.c additions use: "-- dis.c"
30*883529b6Schristos   <arch>-ibd.h additions use: "-- ibd.h".  */
31*883529b6Schristos
32*883529b6Schristos/* -- opc.h */
33*883529b6Schristos
34*883529b6Schristos/* Check applicability of instructions against machines.  */
35*883529b6Schristos#define CGEN_VALIDATE_INSN_SUPPORTED
36*883529b6Schristos
37*883529b6Schristos/* Allows reason codes to be output when assembler errors occur.  */
38*883529b6Schristos#define CGEN_VERBOSE_ASSEMBLER_ERRORS
39*883529b6Schristos
40*883529b6Schristos/* Override disassembly hashing - there are variable bits in the top
41*883529b6Schristos   byte of these instructions.  */
42*883529b6Schristos#define CGEN_DIS_HASH_SIZE 8
43*883529b6Schristos#define CGEN_DIS_HASH(buf, value) \
44*883529b6Schristos  (((* (unsigned char*) (buf)) >> 5) % CGEN_DIS_HASH_SIZE)
45*883529b6Schristos
46*883529b6Schristos#define CGEN_ASM_HASH_SIZE 127
47*883529b6Schristos#define CGEN_ASM_HASH(insn) ip2k_asm_hash (insn)
48*883529b6Schristos
49*883529b6Schristosextern unsigned int ip2k_asm_hash (const char *);
50*883529b6Schristosextern int ip2k_cgen_insn_supported (CGEN_CPU_DESC, const CGEN_INSN *);
51*883529b6Schristos
52*883529b6Schristos/* -- opc.c */
53*883529b6Schristos
54*883529b6Schristos#include "safe-ctype.h"
55*883529b6Schristos
56*883529b6Schristos/* A better hash function for instruction mnemonics.  */
57*883529b6Schristosunsigned int
58*883529b6Schristosip2k_asm_hash (const char* insn)
59*883529b6Schristos{
60*883529b6Schristos  unsigned int hash;
61*883529b6Schristos  const char* m = insn;
62*883529b6Schristos
63*883529b6Schristos  for (hash = 0; *m && ! ISSPACE (*m); m++)
64*883529b6Schristos    hash = (hash * 23) ^ (0x1F & TOLOWER (*m));
65*883529b6Schristos
66*883529b6Schristos  /* printf ("%s %d\n", insn, (hash % CGEN_ASM_HASH_SIZE)); */
67*883529b6Schristos
68*883529b6Schristos  return hash % CGEN_ASM_HASH_SIZE;
69*883529b6Schristos}
70*883529b6Schristos
71*883529b6Schristos
72*883529b6Schristos/* Special check to ensure that instruction exists for given machine.  */
73*883529b6Schristos
74*883529b6Schristosint
75*883529b6Schristosip2k_cgen_insn_supported (CGEN_CPU_DESC cd, const CGEN_INSN *insn)
76*883529b6Schristos{
77*883529b6Schristos  int machs = CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_MACH);
78*883529b6Schristos
79*883529b6Schristos  /* No mach attribute?  Assume it's supported for all machs.  */
80*883529b6Schristos  if (machs == 0)
81*883529b6Schristos    return 1;
82*883529b6Schristos
83*883529b6Schristos  return (machs & cd->machs) != 0;
84*883529b6Schristos}
85*883529b6Schristos
86*883529b6Schristos
87*883529b6Schristos/* -- asm.c */
88*883529b6Schristos
89*883529b6Schristosstatic const char *
90*883529b6Schristosparse_fr (CGEN_CPU_DESC cd,
91*883529b6Schristos	  const char **strp,
92*883529b6Schristos	  int opindex,
93*883529b6Schristos	  unsigned long *valuep)
94*883529b6Schristos{
95*883529b6Schristos  const char *errmsg;
96*883529b6Schristos  const char *old_strp;
97*883529b6Schristos  char *afteroffset;
98*883529b6Schristos  enum cgen_parse_operand_result result_type;
99*883529b6Schristos  bfd_vma value;
100*883529b6Schristos  extern CGEN_KEYWORD ip2k_cgen_opval_register_names;
101*883529b6Schristos  bfd_vma tempvalue;
102*883529b6Schristos
103*883529b6Schristos  old_strp = *strp;
104*883529b6Schristos  afteroffset = NULL;
105*883529b6Schristos
106*883529b6Schristos  /* Check here to see if you're about to try parsing a w as the first arg
107*883529b6Schristos     and return an error if you are.  */
108*883529b6Schristos  if ((strncmp (*strp, "w", 1) == 0) || (strncmp (*strp, "W", 1) == 0))
109*883529b6Schristos    {
110*883529b6Schristos      (*strp)++;
111*883529b6Schristos
112*883529b6Schristos      if ((strncmp (*strp, ",", 1) == 0) || ISSPACE (**strp))
113*883529b6Schristos	{
114*883529b6Schristos	  /* We've been passed a w.  Return with an error message so that
115*883529b6Schristos	     cgen will try the next parsing option.  */
116*883529b6Schristos	  errmsg = _("W keyword invalid in FR operand slot.");
117*883529b6Schristos	  return errmsg;
118*883529b6Schristos	}
119*883529b6Schristos      *strp = old_strp;
120*883529b6Schristos    }
121*883529b6Schristos
122*883529b6Schristos  /* Attempt parse as register keyword. */
123*883529b6Schristos  errmsg = cgen_parse_keyword (cd, strp, & ip2k_cgen_opval_register_names,
124*883529b6Schristos			       (long *) valuep);
125*883529b6Schristos  if (*strp != NULL
126*883529b6Schristos      && errmsg == NULL)
127*883529b6Schristos    return errmsg;
128*883529b6Schristos
129*883529b6Schristos  /* Attempt to parse for "(IP)".  */
130*883529b6Schristos  afteroffset = strstr (*strp, "(IP)");
131*883529b6Schristos
132*883529b6Schristos  if (afteroffset == NULL)
133*883529b6Schristos    /* Make sure it's not in lower case.  */
134*883529b6Schristos    afteroffset = strstr (*strp, "(ip)");
135*883529b6Schristos
136*883529b6Schristos  if (afteroffset != NULL)
137*883529b6Schristos    {
138*883529b6Schristos      if (afteroffset != *strp)
139*883529b6Schristos	{
140*883529b6Schristos	  /* Invalid offset present.  */
141*883529b6Schristos	  errmsg = _("offset(IP) is not a valid form");
142*883529b6Schristos	  return errmsg;
143*883529b6Schristos	}
144*883529b6Schristos      else
145*883529b6Schristos	{
146*883529b6Schristos	  *strp += 4;
147*883529b6Schristos	  *valuep = 0;
148*883529b6Schristos	  errmsg = NULL;
149*883529b6Schristos	  return errmsg;
150*883529b6Schristos	}
151*883529b6Schristos    }
152*883529b6Schristos
153*883529b6Schristos  /* Attempt to parse for DP. ex: mov w, offset(DP)
154*883529b6Schristos                                  mov offset(DP),w   */
155*883529b6Schristos
156*883529b6Schristos  /* Try parsing it as an address and see what comes back.  */
157*883529b6Schristos  afteroffset = strstr (*strp, "(DP)");
158*883529b6Schristos
159*883529b6Schristos  if (afteroffset == NULL)
160*883529b6Schristos    /* Maybe it's in lower case.  */
161*883529b6Schristos    afteroffset = strstr (*strp, "(dp)");
162*883529b6Schristos
163*883529b6Schristos  if (afteroffset != NULL)
164*883529b6Schristos    {
165*883529b6Schristos      if (afteroffset == *strp)
166*883529b6Schristos	{
167*883529b6Schristos	  /* No offset present. Use 0 by default.  */
168*883529b6Schristos	  tempvalue = 0;
169*883529b6Schristos	  errmsg = NULL;
170*883529b6Schristos	}
171*883529b6Schristos      else
172*883529b6Schristos	errmsg = cgen_parse_address (cd, strp, opindex,
173*883529b6Schristos				     BFD_RELOC_IP2K_FR_OFFSET,
174*883529b6Schristos				     & result_type, & tempvalue);
175*883529b6Schristos
176*883529b6Schristos      if (errmsg == NULL)
177*883529b6Schristos	{
178*883529b6Schristos	  if (tempvalue <= 127)
179*883529b6Schristos	    {
180*883529b6Schristos	      /* Value is ok.  Fix up the first 2 bits and return.  */
181*883529b6Schristos	      *valuep = 0x0100 | tempvalue;
182*883529b6Schristos	      *strp += 4; /* Skip over the (DP) in *strp.  */
183*883529b6Schristos	      return errmsg;
184*883529b6Schristos	    }
185*883529b6Schristos	  else
186*883529b6Schristos	    {
187*883529b6Schristos	      /* Found something there in front of (DP) but it's out
188*883529b6Schristos		 of range.  */
189*883529b6Schristos	      errmsg = _("(DP) offset out of range.");
190*883529b6Schristos	      return errmsg;
191*883529b6Schristos	    }
192*883529b6Schristos	}
193*883529b6Schristos    }
194*883529b6Schristos
195*883529b6Schristos
196*883529b6Schristos  /* Attempt to parse for SP. ex: mov w, offset(SP)
197*883529b6Schristos                                  mov offset(SP), w.  */
198*883529b6Schristos  afteroffset = strstr (*strp, "(SP)");
199*883529b6Schristos
200*883529b6Schristos  if (afteroffset == NULL)
201*883529b6Schristos    /* Maybe it's in lower case.  */
202*883529b6Schristos    afteroffset = strstr (*strp, "(sp)");
203*883529b6Schristos
204*883529b6Schristos  if (afteroffset != NULL)
205*883529b6Schristos    {
206*883529b6Schristos      if (afteroffset == *strp)
207*883529b6Schristos	{
208*883529b6Schristos	  /* No offset present. Use 0 by default.  */
209*883529b6Schristos	  tempvalue = 0;
210*883529b6Schristos	  errmsg = NULL;
211*883529b6Schristos	}
212*883529b6Schristos      else
213*883529b6Schristos	errmsg = cgen_parse_address (cd, strp, opindex,
214*883529b6Schristos				     BFD_RELOC_IP2K_FR_OFFSET,
215*883529b6Schristos				     & result_type, & tempvalue);
216*883529b6Schristos
217*883529b6Schristos      if (errmsg == NULL)
218*883529b6Schristos	{
219*883529b6Schristos	  if (tempvalue <= 127)
220*883529b6Schristos	    {
221*883529b6Schristos	      /* Value is ok.  Fix up the first 2 bits and return.  */
222*883529b6Schristos	      *valuep = 0x0180 | tempvalue;
223*883529b6Schristos	      *strp += 4; /* Skip over the (SP) in *strp.  */
224*883529b6Schristos	      return errmsg;
225*883529b6Schristos	    }
226*883529b6Schristos	  else
227*883529b6Schristos	    {
228*883529b6Schristos	      /* Found something there in front of (SP) but it's out
229*883529b6Schristos		 of range.  */
230*883529b6Schristos	      errmsg = _("(SP) offset out of range.");
231*883529b6Schristos	      return errmsg;
232*883529b6Schristos	    }
233*883529b6Schristos	}
234*883529b6Schristos    }
235*883529b6Schristos
236*883529b6Schristos  /* Attempt to parse as an address.  */
237*883529b6Schristos  *strp = old_strp;
238*883529b6Schristos  errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_IP2K_FR9,
239*883529b6Schristos			       & result_type, & value);
240*883529b6Schristos  if (errmsg == NULL)
241*883529b6Schristos    {
242*883529b6Schristos      *valuep = value;
243*883529b6Schristos
244*883529b6Schristos      /* If a parenthesis is found, warn about invalid form.  */
245*883529b6Schristos      if (**strp == '(')
246*883529b6Schristos	errmsg = _("illegal use of parentheses");
247*883529b6Schristos
248*883529b6Schristos      /* If a numeric value is specified, ensure that it is between
249*883529b6Schristos	 1 and 255.  */
250*883529b6Schristos      else if (result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
251*883529b6Schristos	{
252*883529b6Schristos	  if (value < 0x1 || value > 0xff)
253*883529b6Schristos	    errmsg = _("operand out of range (not between 1 and 255)");
254*883529b6Schristos	}
255*883529b6Schristos    }
256*883529b6Schristos  return errmsg;
257*883529b6Schristos}
258*883529b6Schristos
259*883529b6Schristosstatic const char *
260*883529b6Schristosparse_addr16 (CGEN_CPU_DESC cd,
261*883529b6Schristos	      const char **strp,
262*883529b6Schristos	      int opindex,
263*883529b6Schristos	      unsigned long *valuep)
264*883529b6Schristos{
265*883529b6Schristos  const char *errmsg;
266*883529b6Schristos  enum cgen_parse_operand_result result_type;
267*883529b6Schristos  bfd_reloc_code_real_type code = BFD_RELOC_NONE;
268*883529b6Schristos  bfd_vma value;
269*883529b6Schristos
270*883529b6Schristos  if (opindex == (CGEN_OPERAND_TYPE) IP2K_OPERAND_ADDR16H)
271*883529b6Schristos    code = BFD_RELOC_IP2K_HI8DATA;
272*883529b6Schristos  else if (opindex == (CGEN_OPERAND_TYPE) IP2K_OPERAND_ADDR16L)
273*883529b6Schristos    code = BFD_RELOC_IP2K_LO8DATA;
274*883529b6Schristos  else
275*883529b6Schristos    {
276*883529b6Schristos      /* Something is very wrong. opindex has to be one of the above.  */
277*883529b6Schristos      errmsg = _("parse_addr16: invalid opindex.");
278*883529b6Schristos      return errmsg;
279*883529b6Schristos    }
280*883529b6Schristos
281*883529b6Schristos  errmsg = cgen_parse_address (cd, strp, opindex, code,
282*883529b6Schristos			       & result_type, & value);
283*883529b6Schristos  if (errmsg == NULL)
284*883529b6Schristos    {
285*883529b6Schristos      /* We either have a relocation or a number now.  */
286*883529b6Schristos      if (result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
287*883529b6Schristos	{
288*883529b6Schristos	  /* We got a number back.  */
289*883529b6Schristos	  if (code == BFD_RELOC_IP2K_HI8DATA)
290*883529b6Schristos            value >>= 8;
291*883529b6Schristos	  else
292*883529b6Schristos	    /* code = BFD_RELOC_IP2K_LOW8DATA.  */
293*883529b6Schristos	    value &= 0x00FF;
294*883529b6Schristos	}
295*883529b6Schristos      *valuep = value;
296*883529b6Schristos    }
297*883529b6Schristos
298*883529b6Schristos  return errmsg;
299*883529b6Schristos}
300*883529b6Schristos
301*883529b6Schristosstatic const char *
302*883529b6Schristosparse_addr16_cjp (CGEN_CPU_DESC cd,
303*883529b6Schristos		  const char **strp,
304*883529b6Schristos		  int opindex,
305*883529b6Schristos		  unsigned long *valuep)
306*883529b6Schristos{
307*883529b6Schristos  const char *errmsg;
308*883529b6Schristos  enum cgen_parse_operand_result result_type;
309*883529b6Schristos  bfd_reloc_code_real_type code = BFD_RELOC_NONE;
310*883529b6Schristos  bfd_vma value;
311*883529b6Schristos
312*883529b6Schristos  if (opindex == (CGEN_OPERAND_TYPE) IP2K_OPERAND_ADDR16CJP)
313*883529b6Schristos    code = BFD_RELOC_IP2K_ADDR16CJP;
314*883529b6Schristos  else if (opindex == (CGEN_OPERAND_TYPE) IP2K_OPERAND_ADDR16P)
315*883529b6Schristos    code = BFD_RELOC_IP2K_PAGE3;
316*883529b6Schristos
317*883529b6Schristos  errmsg = cgen_parse_address (cd, strp, opindex, code,
318*883529b6Schristos			       & result_type, & value);
319*883529b6Schristos  if (errmsg == NULL)
320*883529b6Schristos    {
321*883529b6Schristos      if (result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
322*883529b6Schristos	{
323*883529b6Schristos	  if ((value & 0x1) == 0)  /* If the address is even .... */
324*883529b6Schristos	    {
325*883529b6Schristos	      if (opindex == (CGEN_OPERAND_TYPE) IP2K_OPERAND_ADDR16CJP)
326*883529b6Schristos                *valuep = (value >> 1) & 0x1FFF;  /* Should mask be 1FFF?  */
327*883529b6Schristos	      else if (opindex == (CGEN_OPERAND_TYPE) IP2K_OPERAND_ADDR16P)
328*883529b6Schristos                *valuep = (value >> 14) & 0x7;
329*883529b6Schristos	    }
330*883529b6Schristos          else
331*883529b6Schristos 	    errmsg = _("Byte address required. - must be even.");
332*883529b6Schristos	}
333*883529b6Schristos      else if (result_type == CGEN_PARSE_OPERAND_RESULT_QUEUED)
334*883529b6Schristos	{
335*883529b6Schristos	  /* This will happen for things like (s2-s1) where s2 and s1
336*883529b6Schristos	     are labels.  */
337*883529b6Schristos	  *valuep = value;
338*883529b6Schristos	}
339*883529b6Schristos      else
340*883529b6Schristos        errmsg = _("cgen_parse_address returned a symbol. Literal required.");
341*883529b6Schristos    }
342*883529b6Schristos  return errmsg;
343*883529b6Schristos}
344*883529b6Schristos
345*883529b6Schristosstatic const char *
346*883529b6Schristosparse_lit8 (CGEN_CPU_DESC cd,
347*883529b6Schristos	    const char **strp,
348*883529b6Schristos	    int opindex,
349*883529b6Schristos	    long *valuep)
350*883529b6Schristos{
351*883529b6Schristos  const char *errmsg;
352*883529b6Schristos  enum cgen_parse_operand_result result_type;
353*883529b6Schristos  bfd_reloc_code_real_type code = BFD_RELOC_NONE;
354*883529b6Schristos  bfd_vma value;
355*883529b6Schristos
356*883529b6Schristos  /* Parse %OP relocating operators.  */
357*883529b6Schristos  if (strncmp (*strp, "%bank", 5) == 0)
358*883529b6Schristos    {
359*883529b6Schristos      *strp += 5;
360*883529b6Schristos      code = BFD_RELOC_IP2K_BANK;
361*883529b6Schristos    }
362*883529b6Schristos  else if (strncmp (*strp, "%lo8data", 8) == 0)
363*883529b6Schristos    {
364*883529b6Schristos      *strp += 8;
365*883529b6Schristos      code = BFD_RELOC_IP2K_LO8DATA;
366*883529b6Schristos    }
367*883529b6Schristos  else if (strncmp (*strp, "%hi8data", 8) == 0)
368*883529b6Schristos    {
369*883529b6Schristos      *strp += 8;
370*883529b6Schristos      code = BFD_RELOC_IP2K_HI8DATA;
371*883529b6Schristos    }
372*883529b6Schristos  else if (strncmp (*strp, "%ex8data", 8) == 0)
373*883529b6Schristos    {
374*883529b6Schristos      *strp += 8;
375*883529b6Schristos      code = BFD_RELOC_IP2K_EX8DATA;
376*883529b6Schristos    }
377*883529b6Schristos  else if (strncmp (*strp, "%lo8insn", 8) == 0)
378*883529b6Schristos    {
379*883529b6Schristos      *strp += 8;
380*883529b6Schristos      code = BFD_RELOC_IP2K_LO8INSN;
381*883529b6Schristos    }
382*883529b6Schristos  else if (strncmp (*strp, "%hi8insn", 8) == 0)
383*883529b6Schristos    {
384*883529b6Schristos      *strp += 8;
385*883529b6Schristos      code = BFD_RELOC_IP2K_HI8INSN;
386*883529b6Schristos    }
387*883529b6Schristos
388*883529b6Schristos  /* Parse %op operand.  */
389*883529b6Schristos  if (code != BFD_RELOC_NONE)
390*883529b6Schristos    {
391*883529b6Schristos      errmsg = cgen_parse_address (cd, strp, opindex, code,
392*883529b6Schristos				   & result_type, & value);
393*883529b6Schristos      if ((errmsg == NULL) &&
394*883529b6Schristos	  (result_type != CGEN_PARSE_OPERAND_RESULT_QUEUED))
395*883529b6Schristos	errmsg = _("percent-operator operand is not a symbol");
396*883529b6Schristos
397*883529b6Schristos      *valuep = value;
398*883529b6Schristos    }
399*883529b6Schristos  /* Parse as a number.  */
400*883529b6Schristos  else
401*883529b6Schristos    {
402*883529b6Schristos      errmsg = cgen_parse_signed_integer (cd, strp, opindex, valuep);
403*883529b6Schristos
404*883529b6Schristos      /* Truncate to eight bits to accept both signed and unsigned input.  */
405*883529b6Schristos      if (errmsg == NULL)
406*883529b6Schristos	*valuep &= 0xFF;
407*883529b6Schristos    }
408*883529b6Schristos
409*883529b6Schristos  return errmsg;
410*883529b6Schristos}
411*883529b6Schristos
412*883529b6Schristosstatic const char *
413*883529b6Schristosparse_bit3 (CGEN_CPU_DESC cd,
414*883529b6Schristos	    const char **strp,
415*883529b6Schristos	    int opindex,
416*883529b6Schristos	    unsigned long *valuep)
417*883529b6Schristos{
418*883529b6Schristos  const char *errmsg;
419*883529b6Schristos  char mode = 0;
420*883529b6Schristos  long count = 0;
421*883529b6Schristos  unsigned long value;
422*883529b6Schristos
423*883529b6Schristos  if (strncmp (*strp, "%bit", 4) == 0)
424*883529b6Schristos    {
425*883529b6Schristos      *strp += 4;
426*883529b6Schristos      mode = 1;
427*883529b6Schristos    }
428*883529b6Schristos  else if (strncmp (*strp, "%msbbit", 7) == 0)
429*883529b6Schristos    {
430*883529b6Schristos      *strp += 7;
431*883529b6Schristos      mode = 1;
432*883529b6Schristos    }
433*883529b6Schristos  else if (strncmp (*strp, "%lsbbit", 7) == 0)
434*883529b6Schristos    {
435*883529b6Schristos      *strp += 7;
436*883529b6Schristos      mode = 2;
437*883529b6Schristos    }
438*883529b6Schristos
439*883529b6Schristos  errmsg = cgen_parse_unsigned_integer (cd, strp, opindex, valuep);
440*883529b6Schristos  if (errmsg)
441*883529b6Schristos    return errmsg;
442*883529b6Schristos
443*883529b6Schristos  if (mode)
444*883529b6Schristos    {
445*883529b6Schristos      value = * valuep;
446*883529b6Schristos      if (value == 0)
447*883529b6Schristos	{
448*883529b6Schristos	  errmsg = _("Attempt to find bit index of 0");
449*883529b6Schristos	  return errmsg;
450*883529b6Schristos	}
451*883529b6Schristos
452*883529b6Schristos      if (mode == 1)
453*883529b6Schristos	{
454*883529b6Schristos	  count = 31;
455*883529b6Schristos	  while ((value & 0x80000000) == 0)
456*883529b6Schristos	    {
457*883529b6Schristos	      count--;
458*883529b6Schristos	      value <<= 1;
459*883529b6Schristos	    }
460*883529b6Schristos	}
461*883529b6Schristos      else if (mode == 2)
462*883529b6Schristos	{
463*883529b6Schristos	  count = 0;
464*883529b6Schristos	  while ((value & 0x00000001) == 0)
465*883529b6Schristos	    {
466*883529b6Schristos	      count++;
467*883529b6Schristos	      value >>= 1;
468*883529b6Schristos	    }
469*883529b6Schristos	}
470*883529b6Schristos
471*883529b6Schristos      *valuep = count;
472*883529b6Schristos    }
473*883529b6Schristos
474*883529b6Schristos  return errmsg;
475*883529b6Schristos}
476*883529b6Schristos
477*883529b6Schristos/* -- dis.c */
478*883529b6Schristos
479*883529b6Schristosstatic void
480*883529b6Schristosprint_fr (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
481*883529b6Schristos	  void * dis_info,
482*883529b6Schristos	  long value,
483*883529b6Schristos	  unsigned int attrs ATTRIBUTE_UNUSED,
484*883529b6Schristos	  bfd_vma pc ATTRIBUTE_UNUSED,
485*883529b6Schristos	  int length ATTRIBUTE_UNUSED)
486*883529b6Schristos{
487*883529b6Schristos  disassemble_info *info = (disassemble_info *) dis_info;
488*883529b6Schristos  const CGEN_KEYWORD_ENTRY *ke;
489*883529b6Schristos  extern CGEN_KEYWORD ip2k_cgen_opval_register_names;
490*883529b6Schristos  long offsettest;
491*883529b6Schristos  long offsetvalue;
492*883529b6Schristos
493*883529b6Schristos  if (value == 0) /* This is (IP).  */
494*883529b6Schristos    {
495*883529b6Schristos      (*info->fprintf_func) (info->stream, "%s", "(IP)");
496*883529b6Schristos      return;
497*883529b6Schristos    }
498*883529b6Schristos
499*883529b6Schristos  offsettest = value >> 7;
500*883529b6Schristos  offsetvalue = value & 0x7F;
501*883529b6Schristos
502*883529b6Schristos  /* Check to see if first two bits are 10 -> (DP).  */
503*883529b6Schristos  if (offsettest == 2)
504*883529b6Schristos    {
505*883529b6Schristos      if (offsetvalue == 0)
506*883529b6Schristos	(*info->fprintf_func) (info->stream, "%s","(DP)");
507*883529b6Schristos      else
508*883529b6Schristos	(*info->fprintf_func) (info->stream, "$%lx%s", offsetvalue, "(DP)");
509*883529b6Schristos      return;
510*883529b6Schristos    }
511*883529b6Schristos
512*883529b6Schristos  /* Check to see if first two bits are 11 -> (SP).  */
513*883529b6Schristos  if (offsettest == 3)
514*883529b6Schristos    {
515*883529b6Schristos      if (offsetvalue == 0)
516*883529b6Schristos	(*info->fprintf_func) (info->stream, "%s", "(SP)");
517*883529b6Schristos      else
518*883529b6Schristos	(*info->fprintf_func) (info->stream, "$%lx%s", offsetvalue,"(SP)");
519*883529b6Schristos      return;
520*883529b6Schristos    }
521*883529b6Schristos
522*883529b6Schristos  /* Attempt to print as a register keyword.  */
523*883529b6Schristos  ke = cgen_keyword_lookup_value (& ip2k_cgen_opval_register_names, value);
524*883529b6Schristos
525*883529b6Schristos  if (ke != NULL)
526*883529b6Schristos    (*info->fprintf_func) (info->stream, "%s", ke->name);
527*883529b6Schristos  else
528*883529b6Schristos    /* Print as an address literal.  */
529*883529b6Schristos    (*info->fprintf_func) (info->stream, "$%02lx", value);
530*883529b6Schristos}
531*883529b6Schristos
532*883529b6Schristosstatic void
533*883529b6Schristosprint_dollarhex (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
534*883529b6Schristos		 void * dis_info,
535*883529b6Schristos		 long value,
536*883529b6Schristos		 unsigned int attrs ATTRIBUTE_UNUSED,
537*883529b6Schristos		 bfd_vma pc ATTRIBUTE_UNUSED,
538*883529b6Schristos		 int length ATTRIBUTE_UNUSED)
539*883529b6Schristos{
540*883529b6Schristos  disassemble_info *info = (disassemble_info *) dis_info;
541*883529b6Schristos
542*883529b6Schristos  (*info->fprintf_func) (info->stream, "$%lx", value);
543*883529b6Schristos}
544*883529b6Schristos
545*883529b6Schristosstatic void
546*883529b6Schristosprint_dollarhex8 (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
547*883529b6Schristos		  void * dis_info,
548*883529b6Schristos		  long value,
549*883529b6Schristos		  unsigned int attrs ATTRIBUTE_UNUSED,
550*883529b6Schristos		  bfd_vma pc ATTRIBUTE_UNUSED,
551*883529b6Schristos		  int length ATTRIBUTE_UNUSED)
552*883529b6Schristos{
553*883529b6Schristos  disassemble_info *info = (disassemble_info *) dis_info;
554*883529b6Schristos
555*883529b6Schristos  (*info->fprintf_func) (info->stream, "$%02lx", value);
556*883529b6Schristos}
557*883529b6Schristos
558*883529b6Schristosstatic void
559*883529b6Schristosprint_dollarhex_addr16h (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
560*883529b6Schristos			 void * dis_info,
561*883529b6Schristos			 long value,
562*883529b6Schristos			 unsigned int attrs ATTRIBUTE_UNUSED,
563*883529b6Schristos			 bfd_vma pc ATTRIBUTE_UNUSED,
564*883529b6Schristos			 int length ATTRIBUTE_UNUSED)
565*883529b6Schristos{
566*883529b6Schristos  disassemble_info *info = (disassemble_info *) dis_info;
567*883529b6Schristos
568*883529b6Schristos  /* This is a loadh instruction. Shift the value to the left
569*883529b6Schristos     by 8 bits so that disassembled code will reassemble properly.  */
570*883529b6Schristos  value = ((value << 8) & 0xFF00);
571*883529b6Schristos
572*883529b6Schristos  (*info->fprintf_func) (info->stream, "$%04lx", value);
573*883529b6Schristos}
574*883529b6Schristos
575*883529b6Schristosstatic void
576*883529b6Schristosprint_dollarhex_addr16l (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
577*883529b6Schristos			 void * dis_info,
578*883529b6Schristos			 long value,
579*883529b6Schristos			 unsigned int attrs ATTRIBUTE_UNUSED,
580*883529b6Schristos			 bfd_vma pc ATTRIBUTE_UNUSED,
581*883529b6Schristos			 int length ATTRIBUTE_UNUSED)
582*883529b6Schristos{
583*883529b6Schristos  disassemble_info *info = (disassemble_info *) dis_info;
584*883529b6Schristos
585*883529b6Schristos  (*info->fprintf_func) (info->stream, "$%04lx", value);
586*883529b6Schristos}
587*883529b6Schristos
588*883529b6Schristosstatic void
589*883529b6Schristosprint_dollarhex_p (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
590*883529b6Schristos		   void * dis_info,
591*883529b6Schristos		   long value,
592*883529b6Schristos		   unsigned int attrs ATTRIBUTE_UNUSED,
593*883529b6Schristos		   bfd_vma pc ATTRIBUTE_UNUSED,
594*883529b6Schristos		   int length ATTRIBUTE_UNUSED)
595*883529b6Schristos{
596*883529b6Schristos  disassemble_info *info = (disassemble_info *) dis_info;
597*883529b6Schristos
598*883529b6Schristos  value = ((value << 14) & 0x1C000);
599*883529b6Schristos  ;value = (value  & 0x1FFFF);
600*883529b6Schristos  (*info->fprintf_func) (info->stream, "$%05lx", value);
601*883529b6Schristos}
602*883529b6Schristos
603*883529b6Schristosstatic void
604*883529b6Schristosprint_dollarhex_cj (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
605*883529b6Schristos		    void * dis_info,
606*883529b6Schristos		    long value,
607*883529b6Schristos		    unsigned int attrs ATTRIBUTE_UNUSED,
608*883529b6Schristos		    bfd_vma pc ATTRIBUTE_UNUSED,
609*883529b6Schristos		    int length ATTRIBUTE_UNUSED)
610*883529b6Schristos{
611*883529b6Schristos  disassemble_info *info = (disassemble_info *) dis_info;
612*883529b6Schristos
613*883529b6Schristos  value = ((value << 1) & 0x1FFFF);
614*883529b6Schristos  (*info->fprintf_func) (info->stream, "$%05lx", value);
615*883529b6Schristos}
616*883529b6Schristos
617*883529b6Schristosstatic void
618*883529b6Schristosprint_decimal (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
619*883529b6Schristos	       void * dis_info,
620*883529b6Schristos	       long value,
621*883529b6Schristos	       unsigned int attrs ATTRIBUTE_UNUSED,
622*883529b6Schristos	       bfd_vma pc ATTRIBUTE_UNUSED,
623*883529b6Schristos	       int length ATTRIBUTE_UNUSED)
624*883529b6Schristos{
625*883529b6Schristos  disassemble_info *info = (disassemble_info *) dis_info;
626*883529b6Schristos
627*883529b6Schristos  (*info->fprintf_func) (info->stream, "%ld", value);
628*883529b6Schristos}
629*883529b6Schristos
630*883529b6Schristos
631*883529b6Schristos
632*883529b6Schristos/* -- */
633*883529b6Schristos
634