1/* IQ2000 opcode support.  -*- C -*-
2
3   Copyright 2000, 2001, 2002 Free Software Foundation, Inc.
4
5   Contributed by Red Hat Inc; developed under contract from Fujitsu.
6
7   This file is part of the GNU Binutils.
8
9   This program is free software; you can redistribute it and/or modify
10   it under the terms of the GNU General Public License as published by
11   the Free Software Foundation; either version 2 of the License, or
12   (at your option) any later version.
13
14   This program is distributed in the hope that it will be useful,
15   but WITHOUT ANY WARRANTY; without even the implied warranty of
16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   GNU General Public License for more details.
18
19   You should have received a copy of the GNU General Public License
20   along with this program; if not, write to the Free Software
21   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22
23*/
24
25/* This file is an addendum to iq2000.cpu.  Heavy use of C code isn't
26   appropriate in .cpu files, so it resides here.  This especially applies
27   to assembly/disassembly where parsing/printing can be quite involved.
28   Such things aren't really part of the specification of the cpu, per se,
29   so .cpu files provide the general framework and .opc files handle the
30   nitty-gritty details as necessary.
31
32   Each section is delimited with start and end markers.
33
34   <arch>-opc.h additions use: "-- opc.h"
35   <arch>-opc.c additions use: "-- opc.c"
36   <arch>-asm.c additions use: "-- asm.c"
37   <arch>-dis.c additions use: "-- dis.c"
38   <arch>-ibd.h additions use: "-- ibd.h"
39*/
40
41/* -- opc.h */
42
43/* Allows reason codes to be output when assembler errors occur.  */
44#define CGEN_VERBOSE_ASSEMBLER_ERRORS
45
46/* Override disassembly hashing - there are variable bits in the top
47   byte of these instructions.  */
48#define CGEN_DIS_HASH_SIZE 8
49#define CGEN_DIS_HASH(buf,value) (((* (unsigned char*) (buf)) >> 6) % CGEN_DIS_HASH_SIZE)
50
51/* following activates check beyond hashing since some iq2000 and iq10
52   instructions have same mnemonics but different functionality. */
53#define CGEN_VALIDATE_INSN_SUPPORTED
54
55extern int iq2000_cgen_insn_supported (CGEN_CPU_DESC cd, CGEN_INSN *insn);
56
57/* -- asm.c */
58static const char * parse_mimm PARAMS ((CGEN_CPU_DESC, const char **, int, long *));
59static const char * parse_imm  PARAMS ((CGEN_CPU_DESC, const char **, int, unsigned long *));
60static const char * parse_hi16 PARAMS ((CGEN_CPU_DESC, const char **, int, unsigned long *));
61static const char * parse_lo16 PARAMS ((CGEN_CPU_DESC, const char **, int, long *));
62
63/* Special check to ensure that instruction exists for given machine */
64int
65iq2000_cgen_insn_supported (cd, insn)
66     CGEN_CPU_DESC cd;
67     CGEN_INSN *insn;
68{
69  int machs = cd->machs;
70
71  return ((CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_MACH) & machs) != 0);
72}
73
74static int iq2000_cgen_isa_register (strp)
75     const char **strp;
76{
77  int len;
78  int ch1, ch2;
79  if (**strp == 'r' || **strp == 'R') 
80    {
81      len = strlen (*strp);
82      if (len == 2) 
83        {
84          ch1 = (*strp)[1];
85          if ('0' <= ch1 && ch1 <= '9')
86            return 1;
87        } 
88      else if (len == 3) 
89        {
90	  ch1 = (*strp)[1];
91          ch2 = (*strp)[2];
92          if (('1' <= ch1 && ch1 <= '2') && ('0' <= ch2 && ch2 <= '9'))
93            return 1;
94          if ('3' == ch1 && (ch2 == '0' || ch2 == '1'))
95            return 1;
96        }
97    }
98  if (**strp == '%' && tolower((*strp)[1]) != 'l' && tolower((*strp)[1]) != 'h')
99    return 1;
100  return 0;
101}
102
103/* Handle negated literal.  */
104
105static const char *
106parse_mimm (cd, strp, opindex, valuep)
107     CGEN_CPU_DESC cd;
108     const char **strp;
109     int opindex;
110     long *valuep;
111{
112  const char *errmsg;
113  long value;
114
115  /* Verify this isn't a register */
116  if (iq2000_cgen_isa_register (strp))
117    errmsg = _("immediate value cannot be register");
118  else
119    {
120      long value;
121      
122      errmsg = cgen_parse_signed_integer (cd, strp, opindex, & value);
123      if (errmsg == NULL)
124	{
125	  long x = (-value) & 0xFFFF0000;
126	  if (x != 0 && x != 0xFFFF0000)
127	    errmsg = _("immediate value out of range");
128	  else
129	    *valuep = (-value & 0xFFFF);
130	}
131    }
132  return errmsg;
133}
134
135/* Handle signed/unsigned literal.  */
136
137static const char *
138parse_imm (cd, strp, opindex, valuep)
139     CGEN_CPU_DESC cd;
140     const char **strp;
141     int opindex;
142     unsigned long *valuep;
143{
144  const char *errmsg;
145  long value;
146
147  if (iq2000_cgen_isa_register (strp))
148    errmsg = _("immediate value cannot be register");
149  else
150    {
151      long value;
152
153      errmsg = cgen_parse_signed_integer (cd, strp, opindex, & value);
154      if (errmsg == NULL)
155	{
156	  long x = value & 0xFFFF0000;
157	  if (x != 0 && x != 0xFFFF0000)
158	    errmsg = _("immediate value out of range");
159	  else
160	    *valuep = (value & 0xFFFF);
161	}
162    }
163  return errmsg;
164}
165
166/* Handle iq10 21-bit jmp offset.  */
167
168static const char *
169parse_jtargq10 (cd, strp, opindex, reloc, type_addr, valuep)
170     CGEN_CPU_DESC cd;
171     const char **strp;
172     int opindex;
173     int reloc;
174     enum cgen_parse_operand_result *type_addr;
175     unsigned long *valuep;
176{
177  const char *errmsg;
178  bfd_vma value;
179  enum cgen_parse_operand_result result_type = CGEN_PARSE_OPERAND_RESULT_NUMBER;
180
181  errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_IQ2000_OFFSET_21,
182			       &result_type, &value);
183  if (errmsg == NULL && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
184    {
185      /* check value is within 23-bits (remembering that 2-bit shift right will occur) */
186      if (value > 0x7fffff)
187        return _("21-bit offset out of range");
188    }
189  *valuep = (value & 0x7FFFFF);
190  return errmsg;
191}
192
193/* Handle high().  */
194
195static const char *
196parse_hi16 (cd, strp, opindex, valuep)
197     CGEN_CPU_DESC cd;
198     const char **strp;
199     int opindex;
200     unsigned long *valuep;
201{
202  if (strncasecmp (*strp, "%hi(", 4) == 0)
203    {
204      enum cgen_parse_operand_result result_type;
205      bfd_vma value;
206      const char *errmsg;
207
208      *strp += 4;
209      errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_HI16,
210				   &result_type, &value);
211      if (**strp != ')')
212	return _("missing `)'");
213
214      ++*strp;
215      if (errmsg == NULL
216  	  && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
217	{
218	  /* if value has top-bit of %lo on, then it will
219	     sign-propagate and so we compensate by adding
220	     1 to the resultant %hi value */
221	  if (value & 0x8000)
222	    value += 0x10000;
223	  value >>= 16;
224	}
225      *valuep = value;
226
227      return errmsg;
228    }
229
230  /* we add %uhi in case a user just wants the high 16-bits or is using
231     an insn like ori for %lo which does not sign-propagate */
232  if (strncasecmp (*strp, "%uhi(", 5) == 0)
233    {
234      enum cgen_parse_operand_result result_type;
235      bfd_vma value;
236      const char *errmsg;
237
238      *strp += 5;
239      errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_IQ2000_UHI16,
240				   &result_type, &value);
241      if (**strp != ')')
242	return _("missing `)'");
243
244      ++*strp;
245      if (errmsg == NULL
246  	  && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
247	{
248	  value >>= 16;
249	}
250      *valuep = value;
251
252      return errmsg;
253    }
254
255  return parse_imm (cd, strp, opindex, valuep);
256}
257
258/* Handle %lo in a signed context.
259   The signedness of the value doesn't matter to %lo(), but this also
260   handles the case where %lo() isn't present.  */
261
262static const char *
263parse_lo16 (cd, strp, opindex, valuep)
264     CGEN_CPU_DESC cd;
265     const char **strp;
266     int opindex;
267     long *valuep;
268{
269  if (strncasecmp (*strp, "%lo(", 4) == 0)
270    {
271      const char *errmsg;
272      enum cgen_parse_operand_result result_type;
273      bfd_vma value;
274
275      *strp += 4;
276      errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_LO16,
277				   &result_type, &value);
278      if (**strp != ')')
279	return _("missing `)'");
280      ++*strp;
281      if (errmsg == NULL
282	  && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
283	value &= 0xffff;
284      *valuep = value;
285      return errmsg;
286    }
287
288  return parse_imm (cd, strp, opindex, valuep);
289}
290
291/* Handle %lo in a negated signed context.
292   The signedness of the value doesn't matter to %lo(), but this also
293   handles the case where %lo() isn't present.  */
294
295static const char *
296parse_mlo16 (cd, strp, opindex, valuep)
297     CGEN_CPU_DESC cd;
298     const char **strp;
299     int opindex;
300     long *valuep;
301{
302  if (strncasecmp (*strp, "%lo(", 4) == 0)
303    {
304      const char *errmsg;
305      enum cgen_parse_operand_result result_type;
306      bfd_vma value;
307
308      *strp += 4;
309      errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_LO16,
310				   &result_type, &value);
311      if (**strp != ')')
312	return _("missing `)'");
313      ++*strp;
314      if (errmsg == NULL
315	  && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
316	value = (-value) & 0xffff;
317      *valuep = value;
318      return errmsg;
319    }
320
321  return parse_mimm (cd, strp, opindex, valuep);
322}
323
324/* -- */
325