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