OSDN Git Service

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