1/* Morpho Technologies mRISC opcode support, for GNU Binutils.  -*- C -*-
2   Copyright 2001 Free Software Foundation, Inc.
3
4   Contributed by Red Hat Inc; developed under contract from
5   Morpho Technologies.
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., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
22
23*/
24
25/*
26   Each section is delimited with start and end markers.
27
28   <arch>-opc.h additions use: "-- opc.h"
29   <arch>-opc.c additions use: "-- opc.c"
30   <arch>-asm.c additions use: "-- asm.c"
31   <arch>-dis.c additions use: "-- dis.c"
32   <arch>-ibd.h additions use: "-- ibd.h"
33*/
34
35/* -- opc.h */
36
37/* Check applicability of instructions against machines.  */
38#define CGEN_VALIDATE_INSN_SUPPORTED
39
40/* Allows reason codes to be output when assembler errors occur.  */
41#define CGEN_VERBOSE_ASSEMBLER_ERRORS
42
43/* Override disassembly hashing - there are variable bits in the top
44   byte of these instructions.  */
45#define CGEN_DIS_HASH_SIZE 8
46#define CGEN_DIS_HASH(buf, value) (((* (unsigned char *) (buf)) >> 5) % CGEN_DIS_HASH_SIZE)
47
48#define CGEN_ASM_HASH_SIZE 127
49#define CGEN_ASM_HASH(insn) ms1_asm_hash (insn)
50
51extern unsigned int ms1_asm_hash (const char *);
52
53extern int ms1_cgen_insn_supported (CGEN_CPU_DESC, const CGEN_INSN *);
54
55
56/* -- opc.c */
57#include "safe-ctype.h"
58
59/* Special check to ensure that instruction exists for given machine.  */
60
61int
62ms1_cgen_insn_supported (CGEN_CPU_DESC cd,
63			 const CGEN_INSN *insn)
64{
65  int machs = CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_MACH);
66
67  /* No mach attribute?  Assume it's supported for all machs.  */
68  if (machs == 0)
69    return 1;
70
71  return ((machs & cd->machs) != 0);
72}
73
74/* A better hash function for instruction mnemonics.  */
75
76unsigned int
77ms1_asm_hash (const char* insn)
78{
79  unsigned int hash;
80  const char* m = insn;
81
82  for (hash = 0; *m && ! ISSPACE (*m); m++)
83    hash = (hash * 23) ^ (0x1F & TOLOWER (*m));
84
85  /* printf ("%s %d\n", insn, (hash % CGEN_ASM_HASH_SIZE)); */
86
87  return hash % CGEN_ASM_HASH_SIZE;
88}
89
90
91/* -- asm.c */
92/* Range checking for signed numbers.  Returns 0 if acceptable
93   and 1 if the value is out of bounds for a signed quantity.  */
94
95static int
96signed_out_of_bounds (long val)
97{
98  if ((val < -32768) || (val > 32767))
99    return 1;
100  return 0;
101}
102
103static const char *
104parse_imm16 (CGEN_CPU_DESC cd,
105	     const char **strp,
106	     int opindex,
107	     void *arg)
108{
109  signed long * valuep = (signed long *) arg;
110  const char *errmsg;
111  enum cgen_parse_operand_result result_type;
112  bfd_reloc_code_real_type code = BFD_RELOC_NONE;
113  bfd_vma value;
114
115  /* Is it a control transfer instructions?  */
116  if (opindex == (CGEN_OPERAND_TYPE) MS1_OPERAND_IMM16O)
117    {
118      code = BFD_RELOC_16_PCREL;
119      errmsg = cgen_parse_address (cd, strp, opindex, code,
120                                   & result_type, & value);
121      if (errmsg == NULL)
122	{
123	  if (signed_out_of_bounds (value))
124	    errmsg = _("Operand out of range. Must be between -32768 and 32767.");
125	}
126      *valuep = value;
127      return errmsg;
128    }
129
130  /* If it's not a control transfer instruction, then
131     we have to check for %OP relocating operators.  */
132  if (strncmp (*strp, "%hi16", 5) == 0)
133    {
134      *strp += 5;
135      code = BFD_RELOC_HI16;
136    }
137  else if (strncmp (*strp, "%lo16", 5) == 0)
138    {
139      *strp += 5;
140      code = BFD_RELOC_LO16;
141    }
142
143  /* If we found a %OP relocating operator, then parse it as an address.
144     If not, we need to parse it as an integer, either signed or unsigned
145     depending on which operand type we have.  */
146  if (code != BFD_RELOC_NONE)
147    {
148       /* %OP relocating operator found.  */
149       errmsg = cgen_parse_address (cd, strp, opindex, code,
150                                   & result_type, & value);
151       if (errmsg == NULL)
152	 {
153           switch (result_type)
154	     {
155	     case (CGEN_PARSE_OPERAND_RESULT_NUMBER):
156	       if (code == BFD_RELOC_HI16)
157		 value = (value >> 16) & 0xFFFF;
158	       else if (code == BFD_RELOC_LO16)
159		 value = value  & 0xFFFF;
160	       else
161		 errmsg = _("Biiiig Trouble in parse_imm16!");
162	       break;
163
164	     case (CGEN_PARSE_OPERAND_RESULT_QUEUED):
165	       /* No special processing for this case.  */
166	       break;
167
168	     default:
169	       errmsg = _("%operator operand is not a symbol");
170	       break;
171             }
172	 }
173       *valuep = value;
174    }
175  else
176    {
177      /* Parse hex values like 0xffff as unsigned, and sign extend
178	 them manually.  */
179      int parse_signed = (opindex == (CGEN_OPERAND_TYPE)MS1_OPERAND_IMM16);
180
181      if ((*strp)[0] == '0'
182	  && ((*strp)[1] == 'x' || (*strp)[1] == 'X'))
183	parse_signed = 0;
184
185      /* No relocating operator.  Parse as an number.  */
186      if (parse_signed)
187	{
188          /* Parse as as signed integer.  */
189
190          errmsg = cgen_parse_signed_integer (cd, strp, opindex, valuep);
191
192          if (errmsg == NULL)
193	    {
194#if 0
195	      /* Manual range checking is needed for the signed case.  */
196	      if (*valuep & 0x8000)
197                value = 0xffff0000 | *valuep;
198	      else
199                value = *valuep;
200
201	      if (signed_out_of_bounds (value))
202	        errmsg = _("Operand out of range. Must be between -32768 and 32767.");
203	      /* Truncate to 16 bits. This is necessary
204		 because cgen will have sign extended *valuep.  */
205	      *valuep &= 0xFFFF;
206#endif
207	    }
208	}
209      else
210	{
211          /* MS1_OPERAND_IMM16Z.  Parse as an unsigned integer.  */
212          errmsg = cgen_parse_unsigned_integer (cd, strp, opindex, (unsigned long *) valuep);
213
214	  if (opindex == (CGEN_OPERAND_TYPE) MS1_OPERAND_IMM16
215	      && *valuep >= 0x8000
216	      && *valuep <= 0xffff)
217	    *valuep -= 0x10000;
218	}
219    }
220
221  return errmsg;
222}
223
224
225static const char *
226parse_dup (CGEN_CPU_DESC cd,
227	   const char **strp,
228	   int opindex,
229	   unsigned long *valuep)
230{
231  const char *errmsg = NULL;
232
233  if (strncmp (*strp, "dup", 3) == 0 || strncmp (*strp, "DUP", 3) == 0)
234    {
235      *strp += 3;
236      *valuep = 1;
237    }
238  else if (strncmp (*strp, "xx", 2) == 0 || strncmp (*strp, "XX", 2) == 0)
239    {
240      *strp += 2;
241      *valuep = 0;
242    }
243  else
244    errmsg = cgen_parse_unsigned_integer (cd, strp, opindex, valuep);
245
246  return errmsg;
247}
248
249
250static const char *
251parse_ball (CGEN_CPU_DESC cd,
252	    const char **strp,
253	    int opindex,
254	    unsigned long *valuep)
255{
256  const char *errmsg = NULL;
257
258  if (strncmp (*strp, "all", 3) == 0 || strncmp (*strp, "ALL", 3) == 0)
259    {
260      *strp += 3;
261      *valuep = 1;
262    }
263  else if (strncmp (*strp, "one", 3) == 0 || strncmp (*strp, "ONE", 3) == 0)
264    {
265      *strp += 3;
266      *valuep = 0;
267    }
268  else
269    errmsg = cgen_parse_unsigned_integer (cd, strp, opindex, valuep);
270
271  return errmsg;
272}
273
274static const char *
275parse_xmode (CGEN_CPU_DESC cd,
276	     const char **strp,
277	     int opindex,
278	     unsigned long *valuep)
279{
280  const char *errmsg = NULL;
281
282  if (strncmp (*strp, "pm", 2) == 0 || strncmp (*strp, "PM", 2) == 0)
283    {
284      *strp += 2;
285      *valuep = 1;
286    }
287  else if (strncmp (*strp, "xm", 2) == 0 || strncmp (*strp, "XM", 2) == 0)
288    {
289      *strp += 2;
290      *valuep = 0;
291    }
292  else
293    errmsg = cgen_parse_unsigned_integer (cd, strp, opindex, valuep);
294
295  return errmsg;
296}
297
298static const char *
299parse_rc (CGEN_CPU_DESC cd,
300	  const char **strp,
301	  int opindex,
302	  unsigned long *valuep)
303{
304  const char *errmsg = NULL;
305
306  if (strncmp (*strp, "r", 1) == 0 || strncmp (*strp, "R", 1) == 0)
307    {
308      *strp += 1;
309      *valuep = 1;
310    }
311  else if (strncmp (*strp, "c", 1) == 0 || strncmp (*strp, "C", 1) == 0)
312    {
313      *strp += 1;
314      *valuep = 0;
315    }
316  else
317    errmsg = cgen_parse_unsigned_integer (cd, strp, opindex, valuep);
318
319  return errmsg;
320}
321
322static const char *
323parse_cbrb (CGEN_CPU_DESC cd,
324	    const char **strp,
325	    int opindex,
326	    unsigned long *valuep)
327{
328  const char *errmsg = NULL;
329
330  if (strncmp (*strp, "rb", 2) == 0 || strncmp (*strp, "RB", 2) == 0)
331    {
332      *strp += 2;
333      *valuep = 1;
334    }
335  else if (strncmp (*strp, "cb", 2) == 0 || strncmp (*strp, "CB", 2) == 0)
336    {
337      *strp += 2;
338      *valuep = 0;
339    }
340  else
341    errmsg = cgen_parse_unsigned_integer (cd, strp, opindex, valuep);
342
343  return errmsg;
344}
345
346static const char *
347parse_rbbc (CGEN_CPU_DESC cd,
348	    const char **strp,
349	    int opindex,
350	    unsigned long *valuep)
351{
352  const char *errmsg = NULL;
353
354  if (strncmp (*strp, "rt", 2) == 0 || strncmp (*strp, "RT", 2) == 0)
355    {
356      *strp += 2;
357      *valuep = 0;
358    }
359  else if (strncmp (*strp, "br1", 3) == 0 || strncmp (*strp, "BR1", 3) == 0)
360    {
361      *strp += 3;
362      *valuep = 1;
363    }
364  else if (strncmp (*strp, "br2", 3) == 0 || strncmp (*strp, "BR2", 3) == 0)
365    {
366      *strp += 3;
367      *valuep = 2;
368    }
369  else if (strncmp (*strp, "cs", 2) == 0 || strncmp (*strp, "CS", 2) == 0)
370    {
371      *strp += 2;
372      *valuep = 3;
373    }
374  else
375    errmsg = cgen_parse_unsigned_integer (cd, strp, opindex, valuep);
376
377  return errmsg;
378}
379
380static const char *
381parse_type (CGEN_CPU_DESC cd,
382	    const char **strp,
383	    int opindex,
384	    unsigned long *valuep)
385{
386  const char *errmsg = NULL;
387
388  if (strncmp (*strp, "odd", 3) == 0 || strncmp (*strp, "ODD", 3) == 0)
389    {
390      *strp += 3;
391      *valuep = 0;
392    }
393  else if (strncmp (*strp, "even", 4) == 0 || strncmp (*strp, "EVEN", 4) == 0)
394    {
395      *strp += 4;
396      *valuep = 1;
397    }
398  else if (strncmp (*strp, "oe", 2) == 0 || strncmp (*strp, "OE", 2) == 0)
399    {
400      *strp += 2;
401      *valuep = 2;
402    }
403  else
404    errmsg = cgen_parse_unsigned_integer (cd, strp, opindex, valuep);
405
406 if ((errmsg == NULL) && (*valuep == 3))
407    errmsg = _("invalid operand.  type may have values 0,1,2 only.");
408
409  return errmsg;
410}
411
412/* -- dis.c */
413static void print_dollarhex (CGEN_CPU_DESC, PTR, long, unsigned, bfd_vma, int);
414
415static void
416print_dollarhex (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
417		 void * dis_info,
418		 long value,
419		 unsigned int attrs ATTRIBUTE_UNUSED,
420		 bfd_vma pc ATTRIBUTE_UNUSED,
421		 int length ATTRIBUTE_UNUSED)
422{
423  disassemble_info *info = (disassemble_info *) dis_info;
424
425  info->fprintf_func (info->stream, "$%x", value);
426
427  if (0)
428    print_normal (cd, dis_info, value, attrs, pc, length);
429}
430
431
432/* -- */
433
434
435
436
437
438