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) mt_asm_hash (insn)
50
51extern unsigned int mt_asm_hash (const char *);
52
53extern int mt_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
62mt_cgen_insn_supported (CGEN_CPU_DESC cd, const CGEN_INSN *insn)
63{
64  int machs = CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_MACH);
65
66  /* No mach attribute?  Assume it's supported for all machs.  */
67  if (machs == 0)
68    return 1;
69
70  return ((machs & cd->machs) != 0);
71}
72
73/* A better hash function for instruction mnemonics.  */
74
75unsigned int
76mt_asm_hash (const char* insn)
77{
78  unsigned int hash;
79  const char* m = insn;
80
81  for (hash = 0; *m && ! ISSPACE (*m); m++)
82    hash = (hash * 23) ^ (0x1F & TOLOWER (*m));
83
84  /* printf ("%s %d\n", insn, (hash % CGEN_ASM_HASH_SIZE)); */
85
86  return hash % CGEN_ASM_HASH_SIZE;
87}
88
89
90/* -- asm.c */
91/* Range checking for signed numbers.  Returns 0 if acceptable
92   and 1 if the value is out of bounds for a signed quantity.  */
93
94static int
95signed_out_of_bounds (long val)
96{
97  if ((val < -32768) || (val > 32767))
98    return 1;
99  return 0;
100}
101
102static const char *
103parse_loopsize (CGEN_CPU_DESC cd,
104		const char **strp,
105		int opindex,
106		void *arg)
107{
108  signed long * valuep = (signed long *) arg;
109  const char *errmsg;
110  bfd_reloc_code_real_type code = BFD_RELOC_NONE;
111  enum cgen_parse_operand_result result_type;
112  bfd_vma value;
113
114  /* Is it a control transfer instructions?  */
115  if (opindex == (CGEN_OPERAND_TYPE) MT_OPERAND_LOOPSIZE)
116    {
117      code = BFD_RELOC_MT_PCINSN8;
118      errmsg = cgen_parse_address (cd, strp, opindex, code,
119                                   & result_type, & value);
120      *valuep = value;
121      return errmsg;
122    }
123
124  abort ();
125}
126
127static const char *
128parse_imm16 (CGEN_CPU_DESC cd,
129	     const char **strp,
130	     int opindex,
131	     void *arg)
132{
133  signed long * valuep = (signed long *) arg;
134  const char *errmsg;
135  enum cgen_parse_operand_result result_type;
136  bfd_reloc_code_real_type code = BFD_RELOC_NONE;
137  bfd_vma value;
138
139  /* Is it a control transfer instructions?  */
140  if (opindex == (CGEN_OPERAND_TYPE) MT_OPERAND_IMM16O)
141    {
142      code = BFD_RELOC_16_PCREL;
143      errmsg = cgen_parse_address (cd, strp, opindex, code,
144                                   & result_type, & value);
145      if (errmsg == NULL)
146	{
147	  if (signed_out_of_bounds (value))
148	    errmsg = _("Operand out of range. Must be between -32768 and 32767.");
149	}
150      *valuep = value;
151      return errmsg;
152    }
153
154  /* If it's not a control transfer instruction, then
155     we have to check for %OP relocating operators.  */
156  if (opindex == (CGEN_OPERAND_TYPE) MT_OPERAND_IMM16L)
157    ;
158  else if (strncmp (*strp, "%hi16", 5) == 0)
159    {
160      *strp += 5;
161      code = BFD_RELOC_HI16;
162    }
163  else if (strncmp (*strp, "%lo16", 5) == 0)
164    {
165      *strp += 5;
166      code = BFD_RELOC_LO16;
167    }
168
169  /* If we found a %OP relocating operator, then parse it as an address.
170     If not, we need to parse it as an integer, either signed or unsigned
171     depending on which operand type we have.  */
172  if (code != BFD_RELOC_NONE)
173    {
174       /* %OP relocating operator found.  */
175       errmsg = cgen_parse_address (cd, strp, opindex, code,
176                                   & result_type, & value);
177       if (errmsg == NULL)
178	 {
179           switch (result_type)
180	     {
181	     case (CGEN_PARSE_OPERAND_RESULT_NUMBER):
182	       if (code == BFD_RELOC_HI16)
183		 value = (value >> 16) & 0xFFFF;
184	       else if (code == BFD_RELOC_LO16)
185		 value = value  & 0xFFFF;
186	       else
187		 errmsg = _("Biiiig Trouble in parse_imm16!");
188	       break;
189
190	     case (CGEN_PARSE_OPERAND_RESULT_QUEUED):
191	       /* No special processing for this case.  */
192	       break;
193
194	     default:
195	       errmsg = _("%operator operand is not a symbol");
196	       break;
197             }
198	 }
199       *valuep = value;
200    }
201  else
202    {
203      /* Parse hex values like 0xffff as unsigned, and sign extend
204	 them manually.  */
205      int parse_signed = (opindex == (CGEN_OPERAND_TYPE)MT_OPERAND_IMM16);
206
207      if ((*strp)[0] == '0'
208	  && ((*strp)[1] == 'x' || (*strp)[1] == 'X'))
209	parse_signed = 0;
210
211      /* No relocating operator.  Parse as an number.  */
212      if (parse_signed)
213	{
214          /* Parse as as signed integer.  */
215
216          errmsg = cgen_parse_signed_integer (cd, strp, opindex, valuep);
217
218          if (errmsg == NULL)
219	    {
220#if 0
221	      /* Manual range checking is needed for the signed case.  */
222	      if (*valuep & 0x8000)
223                value = 0xffff0000 | *valuep;
224	      else
225                value = *valuep;
226
227	      if (signed_out_of_bounds (value))
228	        errmsg = _("Operand out of range. Must be between -32768 and 32767.");
229	      /* Truncate to 16 bits. This is necessary
230		 because cgen will have sign extended *valuep.  */
231	      *valuep &= 0xFFFF;
232#endif
233	    }
234	}
235      else
236	{
237          /* MT_OPERAND_IMM16Z.  Parse as an unsigned integer.  */
238          errmsg = cgen_parse_unsigned_integer (cd, strp, opindex, (unsigned long *) valuep);
239
240	  if (opindex == (CGEN_OPERAND_TYPE) MT_OPERAND_IMM16
241	      && *valuep >= 0x8000
242	      && *valuep <= 0xffff)
243	    *valuep -= 0x10000;
244	}
245    }
246
247  return errmsg;
248}
249
250
251static const char *
252parse_dup (CGEN_CPU_DESC cd,
253	   const char **strp,
254	   int opindex,
255	   unsigned long *valuep)
256{
257  const char *errmsg = NULL;
258
259  if (strncmp (*strp, "dup", 3) == 0 || strncmp (*strp, "DUP", 3) == 0)
260    {
261      *strp += 3;
262      *valuep = 1;
263    }
264  else if (strncmp (*strp, "xx", 2) == 0 || strncmp (*strp, "XX", 2) == 0)
265    {
266      *strp += 2;
267      *valuep = 0;
268    }
269  else
270    errmsg = cgen_parse_unsigned_integer (cd, strp, opindex, valuep);
271
272  return errmsg;
273}
274
275
276static const char *
277parse_ball (CGEN_CPU_DESC cd,
278	    const char **strp,
279	    int opindex,
280	    unsigned long *valuep)
281{
282  const char *errmsg = NULL;
283
284  if (strncmp (*strp, "all", 3) == 0 || strncmp (*strp, "ALL", 3) == 0)
285    {
286      *strp += 3;
287      *valuep = 1;
288    }
289  else if (strncmp (*strp, "one", 3) == 0 || strncmp (*strp, "ONE", 3) == 0)
290    {
291      *strp += 3;
292      *valuep = 0;
293    }
294  else
295    errmsg = cgen_parse_unsigned_integer (cd, strp, opindex, valuep);
296
297  return errmsg;
298}
299
300static const char *
301parse_xmode (CGEN_CPU_DESC cd,
302	     const char **strp,
303	     int opindex,
304	     unsigned long *valuep)
305{
306  const char *errmsg = NULL;
307
308  if (strncmp (*strp, "pm", 2) == 0 || strncmp (*strp, "PM", 2) == 0)
309    {
310      *strp += 2;
311      *valuep = 1;
312    }
313  else if (strncmp (*strp, "xm", 2) == 0 || strncmp (*strp, "XM", 2) == 0)
314    {
315      *strp += 2;
316      *valuep = 0;
317    }
318  else
319    errmsg = cgen_parse_unsigned_integer (cd, strp, opindex, valuep);
320
321  return errmsg;
322}
323
324static const char *
325parse_rc (CGEN_CPU_DESC cd,
326	  const char **strp,
327	  int opindex,
328	  unsigned long *valuep)
329{
330  const char *errmsg = NULL;
331
332  if (strncmp (*strp, "r", 1) == 0 || strncmp (*strp, "R", 1) == 0)
333    {
334      *strp += 1;
335      *valuep = 1;
336    }
337  else if (strncmp (*strp, "c", 1) == 0 || strncmp (*strp, "C", 1) == 0)
338    {
339      *strp += 1;
340      *valuep = 0;
341    }
342  else
343    errmsg = cgen_parse_unsigned_integer (cd, strp, opindex, valuep);
344
345  return errmsg;
346}
347
348static const char *
349parse_cbrb (CGEN_CPU_DESC cd,
350	    const char **strp,
351	    int opindex,
352	    unsigned long *valuep)
353{
354  const char *errmsg = NULL;
355
356  if (strncmp (*strp, "rb", 2) == 0 || strncmp (*strp, "RB", 2) == 0)
357    {
358      *strp += 2;
359      *valuep = 1;
360    }
361  else if (strncmp (*strp, "cb", 2) == 0 || strncmp (*strp, "CB", 2) == 0)
362    {
363      *strp += 2;
364      *valuep = 0;
365    }
366  else
367    errmsg = cgen_parse_unsigned_integer (cd, strp, opindex, valuep);
368
369  return errmsg;
370}
371
372static const char *
373parse_rbbc (CGEN_CPU_DESC cd,
374	    const char **strp,
375	    int opindex,
376	    unsigned long *valuep)
377{
378  const char *errmsg = NULL;
379
380  if (strncmp (*strp, "rt", 2) == 0 || strncmp (*strp, "RT", 2) == 0)
381    {
382      *strp += 2;
383      *valuep = 0;
384    }
385  else if (strncmp (*strp, "br1", 3) == 0 || strncmp (*strp, "BR1", 3) == 0)
386    {
387      *strp += 3;
388      *valuep = 1;
389    }
390  else if (strncmp (*strp, "br2", 3) == 0 || strncmp (*strp, "BR2", 3) == 0)
391    {
392      *strp += 3;
393      *valuep = 2;
394    }
395  else if (strncmp (*strp, "cs", 2) == 0 || strncmp (*strp, "CS", 2) == 0)
396    {
397      *strp += 2;
398      *valuep = 3;
399    }
400  else
401    errmsg = cgen_parse_unsigned_integer (cd, strp, opindex, valuep);
402
403  return errmsg;
404}
405
406static const char *
407parse_type (CGEN_CPU_DESC cd,
408	    const char **strp,
409	    int opindex,
410	    unsigned long *valuep)
411{
412  const char *errmsg = NULL;
413
414  if (strncmp (*strp, "odd", 3) == 0 || strncmp (*strp, "ODD", 3) == 0)
415    {
416      *strp += 3;
417      *valuep = 0;
418    }
419  else if (strncmp (*strp, "even", 4) == 0 || strncmp (*strp, "EVEN", 4) == 0)
420    {
421      *strp += 4;
422      *valuep = 1;
423    }
424  else if (strncmp (*strp, "oe", 2) == 0 || strncmp (*strp, "OE", 2) == 0)
425    {
426      *strp += 2;
427      *valuep = 2;
428    }
429  else
430    errmsg = cgen_parse_unsigned_integer (cd, strp, opindex, valuep);
431
432 if ((errmsg == NULL) && (*valuep == 3))
433    errmsg = _("invalid operand.  type may have values 0,1,2 only.");
434
435  return errmsg;
436}
437
438/* -- dis.c */
439static void print_dollarhex (CGEN_CPU_DESC, PTR, long, unsigned, bfd_vma, int);
440static void print_pcrel (CGEN_CPU_DESC, PTR, long, unsigned, bfd_vma, int);
441
442static void
443print_dollarhex (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
444		 void * dis_info,
445		 long value,
446		 unsigned int attrs ATTRIBUTE_UNUSED,
447		 bfd_vma pc ATTRIBUTE_UNUSED,
448		 int length ATTRIBUTE_UNUSED)
449{
450  disassemble_info *info = (disassemble_info *) dis_info;
451
452  info->fprintf_func (info->stream, "$%lx", value);
453
454  if (0)
455    print_normal (cd, dis_info, value, attrs, pc, length);
456}
457
458static void
459print_pcrel (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
460	     void * dis_info,
461	     long value,
462	     unsigned int attrs ATTRIBUTE_UNUSED,
463	     bfd_vma pc ATTRIBUTE_UNUSED,
464	     int length ATTRIBUTE_UNUSED)
465{
466  print_address (cd, dis_info, value + pc, attrs, pc, length);
467}
468
469/* -- */
470
471
472
473
474
475