Annotation of src/external/gpl3/binutils/dist/opcodes/lm32-ibld.c, Revision 1.1.1.1
1.1 christos 1: /* Instruction building/extraction support for lm32. -*- C -*-
2:
3: THIS FILE IS MACHINE GENERATED WITH CGEN: Cpu tools GENerator.
4: - the resultant file is machine generated, cgen-ibld.in isn't
5:
6: Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2005, 2006, 2007,
7: 2008, 2010 Free Software Foundation, Inc.
8:
9: This file is part of libopcodes.
10:
11: This library is free software; you can redistribute it and/or modify
12: it under the terms of the GNU General Public License as published by
13: the Free Software Foundation; either version 3, or (at your option)
14: any later version.
15:
16: It is distributed in the hope that it will be useful, but WITHOUT
17: ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
18: or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
19: License for more details.
20:
21: You should have received a copy of the GNU General Public License
22: along with this program; if not, write to the Free Software Foundation, Inc.,
23: 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */
24:
25: /* ??? Eventually more and more of this stuff can go to cpu-independent files.
26: Keep that in mind. */
27:
28: #include "sysdep.h"
29: #include <stdio.h>
30: #include "ansidecl.h"
31: #include "dis-asm.h"
32: #include "bfd.h"
33: #include "symcat.h"
34: #include "lm32-desc.h"
35: #include "lm32-opc.h"
36: #include "cgen/basic-modes.h"
37: #include "opintl.h"
38: #include "safe-ctype.h"
39:
40: #undef min
41: #define min(a,b) ((a) < (b) ? (a) : (b))
42: #undef max
43: #define max(a,b) ((a) > (b) ? (a) : (b))
44:
45: /* Used by the ifield rtx function. */
46: #define FLD(f) (fields->f)
47:
48: static const char * insert_normal
49: (CGEN_CPU_DESC, long, unsigned int, unsigned int, unsigned int,
50: unsigned int, unsigned int, unsigned int, CGEN_INSN_BYTES_PTR);
51: static const char * insert_insn_normal
52: (CGEN_CPU_DESC, const CGEN_INSN *,
53: CGEN_FIELDS *, CGEN_INSN_BYTES_PTR, bfd_vma);
54: static int extract_normal
55: (CGEN_CPU_DESC, CGEN_EXTRACT_INFO *, CGEN_INSN_INT,
56: unsigned int, unsigned int, unsigned int, unsigned int,
57: unsigned int, unsigned int, bfd_vma, long *);
58: static int extract_insn_normal
59: (CGEN_CPU_DESC, const CGEN_INSN *, CGEN_EXTRACT_INFO *,
60: CGEN_INSN_INT, CGEN_FIELDS *, bfd_vma);
61: #if CGEN_INT_INSN_P
62: static void put_insn_int_value
63: (CGEN_CPU_DESC, CGEN_INSN_BYTES_PTR, int, int, CGEN_INSN_INT);
64: #endif
65: #if ! CGEN_INT_INSN_P
66: static CGEN_INLINE void insert_1
67: (CGEN_CPU_DESC, unsigned long, int, int, int, unsigned char *);
68: static CGEN_INLINE int fill_cache
69: (CGEN_CPU_DESC, CGEN_EXTRACT_INFO *, int, int, bfd_vma);
70: static CGEN_INLINE long extract_1
71: (CGEN_CPU_DESC, CGEN_EXTRACT_INFO *, int, int, int, unsigned char *, bfd_vma);
72: #endif
73:
74: /* Operand insertion. */
75:
76: #if ! CGEN_INT_INSN_P
77:
78: /* Subroutine of insert_normal. */
79:
80: static CGEN_INLINE void
81: insert_1 (CGEN_CPU_DESC cd,
82: unsigned long value,
83: int start,
84: int length,
85: int word_length,
86: unsigned char *bufp)
87: {
88: unsigned long x,mask;
89: int shift;
90:
91: x = cgen_get_insn_value (cd, bufp, word_length);
92:
93: /* Written this way to avoid undefined behaviour. */
94: mask = (((1L << (length - 1)) - 1) << 1) | 1;
95: if (CGEN_INSN_LSB0_P)
96: shift = (start + 1) - length;
97: else
98: shift = (word_length - (start + length));
99: x = (x & ~(mask << shift)) | ((value & mask) << shift);
100:
101: cgen_put_insn_value (cd, bufp, word_length, (bfd_vma) x);
102: }
103:
104: #endif /* ! CGEN_INT_INSN_P */
105:
106: /* Default insertion routine.
107:
108: ATTRS is a mask of the boolean attributes.
109: WORD_OFFSET is the offset in bits from the start of the insn of the value.
110: WORD_LENGTH is the length of the word in bits in which the value resides.
111: START is the starting bit number in the word, architecture origin.
112: LENGTH is the length of VALUE in bits.
113: TOTAL_LENGTH is the total length of the insn in bits.
114:
115: The result is an error message or NULL if success. */
116:
117: /* ??? This duplicates functionality with bfd's howto table and
118: bfd_install_relocation. */
119: /* ??? This doesn't handle bfd_vma's. Create another function when
120: necessary. */
121:
122: static const char *
123: insert_normal (CGEN_CPU_DESC cd,
124: long value,
125: unsigned int attrs,
126: unsigned int word_offset,
127: unsigned int start,
128: unsigned int length,
129: unsigned int word_length,
130: unsigned int total_length,
131: CGEN_INSN_BYTES_PTR buffer)
132: {
133: static char errbuf[100];
134: /* Written this way to avoid undefined behaviour. */
135: unsigned long mask = (((1L << (length - 1)) - 1) << 1) | 1;
136:
137: /* If LENGTH is zero, this operand doesn't contribute to the value. */
138: if (length == 0)
139: return NULL;
140:
141: if (word_length > 8 * sizeof (CGEN_INSN_INT))
142: abort ();
143:
144: /* For architectures with insns smaller than the base-insn-bitsize,
145: word_length may be too big. */
146: if (cd->min_insn_bitsize < cd->base_insn_bitsize)
147: {
148: if (word_offset == 0
149: && word_length > total_length)
150: word_length = total_length;
151: }
152:
153: /* Ensure VALUE will fit. */
154: if (CGEN_BOOL_ATTR (attrs, CGEN_IFLD_SIGN_OPT))
155: {
156: long minval = - (1L << (length - 1));
157: unsigned long maxval = mask;
158:
159: if ((value > 0 && (unsigned long) value > maxval)
160: || value < minval)
161: {
162: /* xgettext:c-format */
163: sprintf (errbuf,
164: _("operand out of range (%ld not between %ld and %lu)"),
165: value, minval, maxval);
166: return errbuf;
167: }
168: }
169: else if (! CGEN_BOOL_ATTR (attrs, CGEN_IFLD_SIGNED))
170: {
171: unsigned long maxval = mask;
172: unsigned long val = (unsigned long) value;
173:
174: /* For hosts with a word size > 32 check to see if value has been sign
175: extended beyond 32 bits. If so then ignore these higher sign bits
176: as the user is attempting to store a 32-bit signed value into an
177: unsigned 32-bit field which is allowed. */
178: if (sizeof (unsigned long) > 4 && ((value >> 32) == -1))
179: val &= 0xFFFFFFFF;
180:
181: if (val > maxval)
182: {
183: /* xgettext:c-format */
184: sprintf (errbuf,
185: _("operand out of range (0x%lx not between 0 and 0x%lx)"),
186: val, maxval);
187: return errbuf;
188: }
189: }
190: else
191: {
192: if (! cgen_signed_overflow_ok_p (cd))
193: {
194: long minval = - (1L << (length - 1));
195: long maxval = (1L << (length - 1)) - 1;
196:
197: if (value < minval || value > maxval)
198: {
199: sprintf
200: /* xgettext:c-format */
201: (errbuf, _("operand out of range (%ld not between %ld and %ld)"),
202: value, minval, maxval);
203: return errbuf;
204: }
205: }
206: }
207:
208: #if CGEN_INT_INSN_P
209:
210: {
211: int shift;
212:
213: if (CGEN_INSN_LSB0_P)
214: shift = (word_offset + start + 1) - length;
215: else
216: shift = total_length - (word_offset + start + length);
217: *buffer = (*buffer & ~(mask << shift)) | ((value & mask) << shift);
218: }
219:
220: #else /* ! CGEN_INT_INSN_P */
221:
222: {
223: unsigned char *bufp = (unsigned char *) buffer + word_offset / 8;
224:
225: insert_1 (cd, value, start, length, word_length, bufp);
226: }
227:
228: #endif /* ! CGEN_INT_INSN_P */
229:
230: return NULL;
231: }
232:
233: /* Default insn builder (insert handler).
234: The instruction is recorded in CGEN_INT_INSN_P byte order (meaning
235: that if CGEN_INSN_BYTES_PTR is an int * and thus, the value is
236: recorded in host byte order, otherwise BUFFER is an array of bytes
237: and the value is recorded in target byte order).
238: The result is an error message or NULL if success. */
239:
240: static const char *
241: insert_insn_normal (CGEN_CPU_DESC cd,
242: const CGEN_INSN * insn,
243: CGEN_FIELDS * fields,
244: CGEN_INSN_BYTES_PTR buffer,
245: bfd_vma pc)
246: {
247: const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
248: unsigned long value;
249: const CGEN_SYNTAX_CHAR_TYPE * syn;
250:
251: CGEN_INIT_INSERT (cd);
252: value = CGEN_INSN_BASE_VALUE (insn);
253:
254: /* If we're recording insns as numbers (rather than a string of bytes),
255: target byte order handling is deferred until later. */
256:
257: #if CGEN_INT_INSN_P
258:
259: put_insn_int_value (cd, buffer, cd->base_insn_bitsize,
260: CGEN_FIELDS_BITSIZE (fields), value);
261:
262: #else
263:
264: cgen_put_insn_value (cd, buffer, min ((unsigned) cd->base_insn_bitsize,
265: (unsigned) CGEN_FIELDS_BITSIZE (fields)),
266: value);
267:
268: #endif /* ! CGEN_INT_INSN_P */
269:
270: /* ??? It would be better to scan the format's fields.
271: Still need to be able to insert a value based on the operand though;
272: e.g. storing a branch displacement that got resolved later.
273: Needs more thought first. */
274:
275: for (syn = CGEN_SYNTAX_STRING (syntax); * syn; ++ syn)
276: {
277: const char *errmsg;
278:
279: if (CGEN_SYNTAX_CHAR_P (* syn))
280: continue;
281:
282: errmsg = (* cd->insert_operand) (cd, CGEN_SYNTAX_FIELD (*syn),
283: fields, buffer, pc);
284: if (errmsg)
285: return errmsg;
286: }
287:
288: return NULL;
289: }
290:
291: #if CGEN_INT_INSN_P
292: /* Cover function to store an insn value into an integral insn. Must go here
293: because it needs <prefix>-desc.h for CGEN_INT_INSN_P. */
294:
295: static void
296: put_insn_int_value (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
297: CGEN_INSN_BYTES_PTR buf,
298: int length,
299: int insn_length,
300: CGEN_INSN_INT value)
301: {
302: /* For architectures with insns smaller than the base-insn-bitsize,
303: length may be too big. */
304: if (length > insn_length)
305: *buf = value;
306: else
307: {
308: int shift = insn_length - length;
309: /* Written this way to avoid undefined behaviour. */
310: CGEN_INSN_INT mask = (((1L << (length - 1)) - 1) << 1) | 1;
311:
312: *buf = (*buf & ~(mask << shift)) | ((value & mask) << shift);
313: }
314: }
315: #endif
316:
317: /* Operand extraction. */
318:
319: #if ! CGEN_INT_INSN_P
320:
321: /* Subroutine of extract_normal.
322: Ensure sufficient bytes are cached in EX_INFO.
323: OFFSET is the offset in bytes from the start of the insn of the value.
324: BYTES is the length of the needed value.
325: Returns 1 for success, 0 for failure. */
326:
327: static CGEN_INLINE int
328: fill_cache (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
329: CGEN_EXTRACT_INFO *ex_info,
330: int offset,
331: int bytes,
332: bfd_vma pc)
333: {
334: /* It's doubtful that the middle part has already been fetched so
335: we don't optimize that case. kiss. */
336: unsigned int mask;
337: disassemble_info *info = (disassemble_info *) ex_info->dis_info;
338:
339: /* First do a quick check. */
340: mask = (1 << bytes) - 1;
341: if (((ex_info->valid >> offset) & mask) == mask)
342: return 1;
343:
344: /* Search for the first byte we need to read. */
345: for (mask = 1 << offset; bytes > 0; --bytes, ++offset, mask <<= 1)
346: if (! (mask & ex_info->valid))
347: break;
348:
349: if (bytes)
350: {
351: int status;
352:
353: pc += offset;
354: status = (*info->read_memory_func)
355: (pc, ex_info->insn_bytes + offset, bytes, info);
356:
357: if (status != 0)
358: {
359: (*info->memory_error_func) (status, pc, info);
360: return 0;
361: }
362:
363: ex_info->valid |= ((1 << bytes) - 1) << offset;
364: }
365:
366: return 1;
367: }
368:
369: /* Subroutine of extract_normal. */
370:
371: static CGEN_INLINE long
372: extract_1 (CGEN_CPU_DESC cd,
373: CGEN_EXTRACT_INFO *ex_info ATTRIBUTE_UNUSED,
374: int start,
375: int length,
376: int word_length,
377: unsigned char *bufp,
378: bfd_vma pc ATTRIBUTE_UNUSED)
379: {
380: unsigned long x;
381: int shift;
382:
383: x = cgen_get_insn_value (cd, bufp, word_length);
384:
385: if (CGEN_INSN_LSB0_P)
386: shift = (start + 1) - length;
387: else
388: shift = (word_length - (start + length));
389: return x >> shift;
390: }
391:
392: #endif /* ! CGEN_INT_INSN_P */
393:
394: /* Default extraction routine.
395:
396: INSN_VALUE is the first base_insn_bitsize bits of the insn in host order,
397: or sometimes less for cases like the m32r where the base insn size is 32
398: but some insns are 16 bits.
399: ATTRS is a mask of the boolean attributes. We only need `SIGNED',
400: but for generality we take a bitmask of all of them.
401: WORD_OFFSET is the offset in bits from the start of the insn of the value.
402: WORD_LENGTH is the length of the word in bits in which the value resides.
403: START is the starting bit number in the word, architecture origin.
404: LENGTH is the length of VALUE in bits.
405: TOTAL_LENGTH is the total length of the insn in bits.
406:
407: Returns 1 for success, 0 for failure. */
408:
409: /* ??? The return code isn't properly used. wip. */
410:
411: /* ??? This doesn't handle bfd_vma's. Create another function when
412: necessary. */
413:
414: static int
415: extract_normal (CGEN_CPU_DESC cd,
416: #if ! CGEN_INT_INSN_P
417: CGEN_EXTRACT_INFO *ex_info,
418: #else
419: CGEN_EXTRACT_INFO *ex_info ATTRIBUTE_UNUSED,
420: #endif
421: CGEN_INSN_INT insn_value,
422: unsigned int attrs,
423: unsigned int word_offset,
424: unsigned int start,
425: unsigned int length,
426: unsigned int word_length,
427: unsigned int total_length,
428: #if ! CGEN_INT_INSN_P
429: bfd_vma pc,
430: #else
431: bfd_vma pc ATTRIBUTE_UNUSED,
432: #endif
433: long *valuep)
434: {
435: long value, mask;
436:
437: /* If LENGTH is zero, this operand doesn't contribute to the value
438: so give it a standard value of zero. */
439: if (length == 0)
440: {
441: *valuep = 0;
442: return 1;
443: }
444:
445: if (word_length > 8 * sizeof (CGEN_INSN_INT))
446: abort ();
447:
448: /* For architectures with insns smaller than the insn-base-bitsize,
449: word_length may be too big. */
450: if (cd->min_insn_bitsize < cd->base_insn_bitsize)
451: {
452: if (word_offset + word_length > total_length)
453: word_length = total_length - word_offset;
454: }
455:
456: /* Does the value reside in INSN_VALUE, and at the right alignment? */
457:
458: if (CGEN_INT_INSN_P || (word_offset == 0 && word_length == total_length))
459: {
460: if (CGEN_INSN_LSB0_P)
461: value = insn_value >> ((word_offset + start + 1) - length);
462: else
463: value = insn_value >> (total_length - ( word_offset + start + length));
464: }
465:
466: #if ! CGEN_INT_INSN_P
467:
468: else
469: {
470: unsigned char *bufp = ex_info->insn_bytes + word_offset / 8;
471:
472: if (word_length > 8 * sizeof (CGEN_INSN_INT))
473: abort ();
474:
475: if (fill_cache (cd, ex_info, word_offset / 8, word_length / 8, pc) == 0)
476: return 0;
477:
478: value = extract_1 (cd, ex_info, start, length, word_length, bufp, pc);
479: }
480:
481: #endif /* ! CGEN_INT_INSN_P */
482:
483: /* Written this way to avoid undefined behaviour. */
484: mask = (((1L << (length - 1)) - 1) << 1) | 1;
485:
486: value &= mask;
487: /* sign extend? */
488: if (CGEN_BOOL_ATTR (attrs, CGEN_IFLD_SIGNED)
489: && (value & (1L << (length - 1))))
490: value |= ~mask;
491:
492: *valuep = value;
493:
494: return 1;
495: }
496:
497: /* Default insn extractor.
498:
499: INSN_VALUE is the first base_insn_bitsize bits, translated to host order.
500: The extracted fields are stored in FIELDS.
501: EX_INFO is used to handle reading variable length insns.
502: Return the length of the insn in bits, or 0 if no match,
503: or -1 if an error occurs fetching data (memory_error_func will have
504: been called). */
505:
506: static int
507: extract_insn_normal (CGEN_CPU_DESC cd,
508: const CGEN_INSN *insn,
509: CGEN_EXTRACT_INFO *ex_info,
510: CGEN_INSN_INT insn_value,
511: CGEN_FIELDS *fields,
512: bfd_vma pc)
513: {
514: const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
515: const CGEN_SYNTAX_CHAR_TYPE *syn;
516:
517: CGEN_FIELDS_BITSIZE (fields) = CGEN_INSN_BITSIZE (insn);
518:
519: CGEN_INIT_EXTRACT (cd);
520:
521: for (syn = CGEN_SYNTAX_STRING (syntax); *syn; ++syn)
522: {
523: int length;
524:
525: if (CGEN_SYNTAX_CHAR_P (*syn))
526: continue;
527:
528: length = (* cd->extract_operand) (cd, CGEN_SYNTAX_FIELD (*syn),
529: ex_info, insn_value, fields, pc);
530: if (length <= 0)
531: return length;
532: }
533:
534: /* We recognized and successfully extracted this insn. */
535: return CGEN_INSN_BITSIZE (insn);
536: }
537:
538: /* Machine generated code added here. */
539:
540: const char * lm32_cgen_insert_operand
541: (CGEN_CPU_DESC, int, CGEN_FIELDS *, CGEN_INSN_BYTES_PTR, bfd_vma);
542:
543: /* Main entry point for operand insertion.
544:
545: This function is basically just a big switch statement. Earlier versions
546: used tables to look up the function to use, but
547: - if the table contains both assembler and disassembler functions then
548: the disassembler contains much of the assembler and vice-versa,
549: - there's a lot of inlining possibilities as things grow,
550: - using a switch statement avoids the function call overhead.
551:
552: This function could be moved into `parse_insn_normal', but keeping it
553: separate makes clear the interface between `parse_insn_normal' and each of
554: the handlers. It's also needed by GAS to insert operands that couldn't be
555: resolved during parsing. */
556:
557: const char *
558: lm32_cgen_insert_operand (CGEN_CPU_DESC cd,
559: int opindex,
560: CGEN_FIELDS * fields,
561: CGEN_INSN_BYTES_PTR buffer,
562: bfd_vma pc ATTRIBUTE_UNUSED)
563: {
564: const char * errmsg = NULL;
565: unsigned int total_length = CGEN_FIELDS_BITSIZE (fields);
566:
567: switch (opindex)
568: {
569: case LM32_OPERAND_BRANCH :
570: {
571: long value = fields->f_branch;
572: value = ((SI) (((value) - (pc))) >> (2));
573: errmsg = insert_normal (cd, value, 0|(1<<CGEN_IFLD_SIGNED)|(1<<CGEN_IFLD_PCREL_ADDR), 0, 15, 16, 32, total_length, buffer);
574: }
575: break;
576: case LM32_OPERAND_CALL :
577: {
578: long value = fields->f_call;
579: value = ((SI) (((value) - (pc))) >> (2));
580: errmsg = insert_normal (cd, value, 0|(1<<CGEN_IFLD_SIGNED)|(1<<CGEN_IFLD_PCREL_ADDR), 0, 25, 26, 32, total_length, buffer);
581: }
582: break;
583: case LM32_OPERAND_CSR :
584: errmsg = insert_normal (cd, fields->f_csr, 0, 0, 25, 5, 32, total_length, buffer);
585: break;
586: case LM32_OPERAND_EXCEPTION :
587: errmsg = insert_normal (cd, fields->f_exception, 0, 0, 25, 26, 32, total_length, buffer);
588: break;
589: case LM32_OPERAND_GOT16 :
590: errmsg = insert_normal (cd, fields->f_imm, 0|(1<<CGEN_IFLD_SIGNED), 0, 15, 16, 32, total_length, buffer);
591: break;
592: case LM32_OPERAND_GOTOFFHI16 :
593: errmsg = insert_normal (cd, fields->f_imm, 0|(1<<CGEN_IFLD_SIGNED), 0, 15, 16, 32, total_length, buffer);
594: break;
595: case LM32_OPERAND_GOTOFFLO16 :
596: errmsg = insert_normal (cd, fields->f_imm, 0|(1<<CGEN_IFLD_SIGNED), 0, 15, 16, 32, total_length, buffer);
597: break;
598: case LM32_OPERAND_GP16 :
599: errmsg = insert_normal (cd, fields->f_imm, 0|(1<<CGEN_IFLD_SIGNED), 0, 15, 16, 32, total_length, buffer);
600: break;
601: case LM32_OPERAND_HI16 :
602: errmsg = insert_normal (cd, fields->f_uimm, 0, 0, 15, 16, 32, total_length, buffer);
603: break;
604: case LM32_OPERAND_IMM :
605: errmsg = insert_normal (cd, fields->f_imm, 0|(1<<CGEN_IFLD_SIGNED), 0, 15, 16, 32, total_length, buffer);
606: break;
607: case LM32_OPERAND_LO16 :
608: errmsg = insert_normal (cd, fields->f_uimm, 0, 0, 15, 16, 32, total_length, buffer);
609: break;
610: case LM32_OPERAND_R0 :
611: errmsg = insert_normal (cd, fields->f_r0, 0, 0, 25, 5, 32, total_length, buffer);
612: break;
613: case LM32_OPERAND_R1 :
614: errmsg = insert_normal (cd, fields->f_r1, 0, 0, 20, 5, 32, total_length, buffer);
615: break;
616: case LM32_OPERAND_R2 :
617: errmsg = insert_normal (cd, fields->f_r2, 0, 0, 15, 5, 32, total_length, buffer);
618: break;
619: case LM32_OPERAND_SHIFT :
620: errmsg = insert_normal (cd, fields->f_shift, 0, 0, 4, 5, 32, total_length, buffer);
621: break;
622: case LM32_OPERAND_UIMM :
623: errmsg = insert_normal (cd, fields->f_uimm, 0, 0, 15, 16, 32, total_length, buffer);
624: break;
625: case LM32_OPERAND_USER :
626: errmsg = insert_normal (cd, fields->f_user, 0, 0, 10, 11, 32, total_length, buffer);
627: break;
628:
629: default :
630: /* xgettext:c-format */
631: fprintf (stderr, _("Unrecognized field %d while building insn.\n"),
632: opindex);
633: abort ();
634: }
635:
636: return errmsg;
637: }
638:
639: int lm32_cgen_extract_operand
640: (CGEN_CPU_DESC, int, CGEN_EXTRACT_INFO *, CGEN_INSN_INT, CGEN_FIELDS *, bfd_vma);
641:
642: /* Main entry point for operand extraction.
643: The result is <= 0 for error, >0 for success.
644: ??? Actual values aren't well defined right now.
645:
646: This function is basically just a big switch statement. Earlier versions
647: used tables to look up the function to use, but
648: - if the table contains both assembler and disassembler functions then
649: the disassembler contains much of the assembler and vice-versa,
650: - there's a lot of inlining possibilities as things grow,
651: - using a switch statement avoids the function call overhead.
652:
653: This function could be moved into `print_insn_normal', but keeping it
654: separate makes clear the interface between `print_insn_normal' and each of
655: the handlers. */
656:
657: int
658: lm32_cgen_extract_operand (CGEN_CPU_DESC cd,
659: int opindex,
660: CGEN_EXTRACT_INFO *ex_info,
661: CGEN_INSN_INT insn_value,
662: CGEN_FIELDS * fields,
663: bfd_vma pc)
664: {
665: /* Assume success (for those operands that are nops). */
666: int length = 1;
667: unsigned int total_length = CGEN_FIELDS_BITSIZE (fields);
668:
669: switch (opindex)
670: {
671: case LM32_OPERAND_BRANCH :
672: {
673: long value;
674: length = extract_normal (cd, ex_info, insn_value, 0|(1<<CGEN_IFLD_SIGNED)|(1<<CGEN_IFLD_PCREL_ADDR), 0, 15, 16, 32, total_length, pc, & value);
675: value = ((pc) + (((SI) (((value) << (16))) >> (14))));
676: fields->f_branch = value;
677: }
678: break;
679: case LM32_OPERAND_CALL :
680: {
681: long value;
682: length = extract_normal (cd, ex_info, insn_value, 0|(1<<CGEN_IFLD_SIGNED)|(1<<CGEN_IFLD_PCREL_ADDR), 0, 25, 26, 32, total_length, pc, & value);
683: value = ((pc) + (((SI) (((value) << (6))) >> (4))));
684: fields->f_call = value;
685: }
686: break;
687: case LM32_OPERAND_CSR :
688: length = extract_normal (cd, ex_info, insn_value, 0, 0, 25, 5, 32, total_length, pc, & fields->f_csr);
689: break;
690: case LM32_OPERAND_EXCEPTION :
691: length = extract_normal (cd, ex_info, insn_value, 0, 0, 25, 26, 32, total_length, pc, & fields->f_exception);
692: break;
693: case LM32_OPERAND_GOT16 :
694: length = extract_normal (cd, ex_info, insn_value, 0|(1<<CGEN_IFLD_SIGNED), 0, 15, 16, 32, total_length, pc, & fields->f_imm);
695: break;
696: case LM32_OPERAND_GOTOFFHI16 :
697: length = extract_normal (cd, ex_info, insn_value, 0|(1<<CGEN_IFLD_SIGNED), 0, 15, 16, 32, total_length, pc, & fields->f_imm);
698: break;
699: case LM32_OPERAND_GOTOFFLO16 :
700: length = extract_normal (cd, ex_info, insn_value, 0|(1<<CGEN_IFLD_SIGNED), 0, 15, 16, 32, total_length, pc, & fields->f_imm);
701: break;
702: case LM32_OPERAND_GP16 :
703: length = extract_normal (cd, ex_info, insn_value, 0|(1<<CGEN_IFLD_SIGNED), 0, 15, 16, 32, total_length, pc, & fields->f_imm);
704: break;
705: case LM32_OPERAND_HI16 :
706: length = extract_normal (cd, ex_info, insn_value, 0, 0, 15, 16, 32, total_length, pc, & fields->f_uimm);
707: break;
708: case LM32_OPERAND_IMM :
709: length = extract_normal (cd, ex_info, insn_value, 0|(1<<CGEN_IFLD_SIGNED), 0, 15, 16, 32, total_length, pc, & fields->f_imm);
710: break;
711: case LM32_OPERAND_LO16 :
712: length = extract_normal (cd, ex_info, insn_value, 0, 0, 15, 16, 32, total_length, pc, & fields->f_uimm);
713: break;
714: case LM32_OPERAND_R0 :
715: length = extract_normal (cd, ex_info, insn_value, 0, 0, 25, 5, 32, total_length, pc, & fields->f_r0);
716: break;
717: case LM32_OPERAND_R1 :
718: length = extract_normal (cd, ex_info, insn_value, 0, 0, 20, 5, 32, total_length, pc, & fields->f_r1);
719: break;
720: case LM32_OPERAND_R2 :
721: length = extract_normal (cd, ex_info, insn_value, 0, 0, 15, 5, 32, total_length, pc, & fields->f_r2);
722: break;
723: case LM32_OPERAND_SHIFT :
724: length = extract_normal (cd, ex_info, insn_value, 0, 0, 4, 5, 32, total_length, pc, & fields->f_shift);
725: break;
726: case LM32_OPERAND_UIMM :
727: length = extract_normal (cd, ex_info, insn_value, 0, 0, 15, 16, 32, total_length, pc, & fields->f_uimm);
728: break;
729: case LM32_OPERAND_USER :
730: length = extract_normal (cd, ex_info, insn_value, 0, 0, 10, 11, 32, total_length, pc, & fields->f_user);
731: break;
732:
733: default :
734: /* xgettext:c-format */
735: fprintf (stderr, _("Unrecognized field %d while decoding insn.\n"),
736: opindex);
737: abort ();
738: }
739:
740: return length;
741: }
742:
743: cgen_insert_fn * const lm32_cgen_insert_handlers[] =
744: {
745: insert_insn_normal,
746: };
747:
748: cgen_extract_fn * const lm32_cgen_extract_handlers[] =
749: {
750: extract_insn_normal,
751: };
752:
753: int lm32_cgen_get_int_operand (CGEN_CPU_DESC, int, const CGEN_FIELDS *);
754: bfd_vma lm32_cgen_get_vma_operand (CGEN_CPU_DESC, int, const CGEN_FIELDS *);
755:
756: /* Getting values from cgen_fields is handled by a collection of functions.
757: They are distinguished by the type of the VALUE argument they return.
758: TODO: floating point, inlining support, remove cases where result type
759: not appropriate. */
760:
761: int
762: lm32_cgen_get_int_operand (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
763: int opindex,
764: const CGEN_FIELDS * fields)
765: {
766: int value;
767:
768: switch (opindex)
769: {
770: case LM32_OPERAND_BRANCH :
771: value = fields->f_branch;
772: break;
773: case LM32_OPERAND_CALL :
774: value = fields->f_call;
775: break;
776: case LM32_OPERAND_CSR :
777: value = fields->f_csr;
778: break;
779: case LM32_OPERAND_EXCEPTION :
780: value = fields->f_exception;
781: break;
782: case LM32_OPERAND_GOT16 :
783: value = fields->f_imm;
784: break;
785: case LM32_OPERAND_GOTOFFHI16 :
786: value = fields->f_imm;
787: break;
788: case LM32_OPERAND_GOTOFFLO16 :
789: value = fields->f_imm;
790: break;
791: case LM32_OPERAND_GP16 :
792: value = fields->f_imm;
793: break;
794: case LM32_OPERAND_HI16 :
795: value = fields->f_uimm;
796: break;
797: case LM32_OPERAND_IMM :
798: value = fields->f_imm;
799: break;
800: case LM32_OPERAND_LO16 :
801: value = fields->f_uimm;
802: break;
803: case LM32_OPERAND_R0 :
804: value = fields->f_r0;
805: break;
806: case LM32_OPERAND_R1 :
807: value = fields->f_r1;
808: break;
809: case LM32_OPERAND_R2 :
810: value = fields->f_r2;
811: break;
812: case LM32_OPERAND_SHIFT :
813: value = fields->f_shift;
814: break;
815: case LM32_OPERAND_UIMM :
816: value = fields->f_uimm;
817: break;
818: case LM32_OPERAND_USER :
819: value = fields->f_user;
820: break;
821:
822: default :
823: /* xgettext:c-format */
824: fprintf (stderr, _("Unrecognized field %d while getting int operand.\n"),
825: opindex);
826: abort ();
827: }
828:
829: return value;
830: }
831:
832: bfd_vma
833: lm32_cgen_get_vma_operand (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
834: int opindex,
835: const CGEN_FIELDS * fields)
836: {
837: bfd_vma value;
838:
839: switch (opindex)
840: {
841: case LM32_OPERAND_BRANCH :
842: value = fields->f_branch;
843: break;
844: case LM32_OPERAND_CALL :
845: value = fields->f_call;
846: break;
847: case LM32_OPERAND_CSR :
848: value = fields->f_csr;
849: break;
850: case LM32_OPERAND_EXCEPTION :
851: value = fields->f_exception;
852: break;
853: case LM32_OPERAND_GOT16 :
854: value = fields->f_imm;
855: break;
856: case LM32_OPERAND_GOTOFFHI16 :
857: value = fields->f_imm;
858: break;
859: case LM32_OPERAND_GOTOFFLO16 :
860: value = fields->f_imm;
861: break;
862: case LM32_OPERAND_GP16 :
863: value = fields->f_imm;
864: break;
865: case LM32_OPERAND_HI16 :
866: value = fields->f_uimm;
867: break;
868: case LM32_OPERAND_IMM :
869: value = fields->f_imm;
870: break;
871: case LM32_OPERAND_LO16 :
872: value = fields->f_uimm;
873: break;
874: case LM32_OPERAND_R0 :
875: value = fields->f_r0;
876: break;
877: case LM32_OPERAND_R1 :
878: value = fields->f_r1;
879: break;
880: case LM32_OPERAND_R2 :
881: value = fields->f_r2;
882: break;
883: case LM32_OPERAND_SHIFT :
884: value = fields->f_shift;
885: break;
886: case LM32_OPERAND_UIMM :
887: value = fields->f_uimm;
888: break;
889: case LM32_OPERAND_USER :
890: value = fields->f_user;
891: break;
892:
893: default :
894: /* xgettext:c-format */
895: fprintf (stderr, _("Unrecognized field %d while getting vma operand.\n"),
896: opindex);
897: abort ();
898: }
899:
900: return value;
901: }
902:
903: void lm32_cgen_set_int_operand (CGEN_CPU_DESC, int, CGEN_FIELDS *, int);
904: void lm32_cgen_set_vma_operand (CGEN_CPU_DESC, int, CGEN_FIELDS *, bfd_vma);
905:
906: /* Stuffing values in cgen_fields is handled by a collection of functions.
907: They are distinguished by the type of the VALUE argument they accept.
908: TODO: floating point, inlining support, remove cases where argument type
909: not appropriate. */
910:
911: void
912: lm32_cgen_set_int_operand (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
913: int opindex,
914: CGEN_FIELDS * fields,
915: int value)
916: {
917: switch (opindex)
918: {
919: case LM32_OPERAND_BRANCH :
920: fields->f_branch = value;
921: break;
922: case LM32_OPERAND_CALL :
923: fields->f_call = value;
924: break;
925: case LM32_OPERAND_CSR :
926: fields->f_csr = value;
927: break;
928: case LM32_OPERAND_EXCEPTION :
929: fields->f_exception = value;
930: break;
931: case LM32_OPERAND_GOT16 :
932: fields->f_imm = value;
933: break;
934: case LM32_OPERAND_GOTOFFHI16 :
935: fields->f_imm = value;
936: break;
937: case LM32_OPERAND_GOTOFFLO16 :
938: fields->f_imm = value;
939: break;
940: case LM32_OPERAND_GP16 :
941: fields->f_imm = value;
942: break;
943: case LM32_OPERAND_HI16 :
944: fields->f_uimm = value;
945: break;
946: case LM32_OPERAND_IMM :
947: fields->f_imm = value;
948: break;
949: case LM32_OPERAND_LO16 :
950: fields->f_uimm = value;
951: break;
952: case LM32_OPERAND_R0 :
953: fields->f_r0 = value;
954: break;
955: case LM32_OPERAND_R1 :
956: fields->f_r1 = value;
957: break;
958: case LM32_OPERAND_R2 :
959: fields->f_r2 = value;
960: break;
961: case LM32_OPERAND_SHIFT :
962: fields->f_shift = value;
963: break;
964: case LM32_OPERAND_UIMM :
965: fields->f_uimm = value;
966: break;
967: case LM32_OPERAND_USER :
968: fields->f_user = value;
969: break;
970:
971: default :
972: /* xgettext:c-format */
973: fprintf (stderr, _("Unrecognized field %d while setting int operand.\n"),
974: opindex);
975: abort ();
976: }
977: }
978:
979: void
980: lm32_cgen_set_vma_operand (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
981: int opindex,
982: CGEN_FIELDS * fields,
983: bfd_vma value)
984: {
985: switch (opindex)
986: {
987: case LM32_OPERAND_BRANCH :
988: fields->f_branch = value;
989: break;
990: case LM32_OPERAND_CALL :
991: fields->f_call = value;
992: break;
993: case LM32_OPERAND_CSR :
994: fields->f_csr = value;
995: break;
996: case LM32_OPERAND_EXCEPTION :
997: fields->f_exception = value;
998: break;
999: case LM32_OPERAND_GOT16 :
1000: fields->f_imm = value;
1001: break;
1002: case LM32_OPERAND_GOTOFFHI16 :
1003: fields->f_imm = value;
1004: break;
1005: case LM32_OPERAND_GOTOFFLO16 :
1006: fields->f_imm = value;
1007: break;
1008: case LM32_OPERAND_GP16 :
1009: fields->f_imm = value;
1010: break;
1011: case LM32_OPERAND_HI16 :
1012: fields->f_uimm = value;
1013: break;
1014: case LM32_OPERAND_IMM :
1015: fields->f_imm = value;
1016: break;
1017: case LM32_OPERAND_LO16 :
1018: fields->f_uimm = value;
1019: break;
1020: case LM32_OPERAND_R0 :
1021: fields->f_r0 = value;
1022: break;
1023: case LM32_OPERAND_R1 :
1024: fields->f_r1 = value;
1025: break;
1026: case LM32_OPERAND_R2 :
1027: fields->f_r2 = value;
1028: break;
1029: case LM32_OPERAND_SHIFT :
1030: fields->f_shift = value;
1031: break;
1032: case LM32_OPERAND_UIMM :
1033: fields->f_uimm = value;
1034: break;
1035: case LM32_OPERAND_USER :
1036: fields->f_user = value;
1037: break;
1038:
1039: default :
1040: /* xgettext:c-format */
1041: fprintf (stderr, _("Unrecognized field %d while setting vma operand.\n"),
1042: opindex);
1043: abort ();
1044: }
1045: }
1046:
1047: /* Function to call before using the instruction builder tables. */
1048:
1049: void
1050: lm32_cgen_init_ibld_table (CGEN_CPU_DESC cd)
1051: {
1052: cd->insert_handlers = & lm32_cgen_insert_handlers[0];
1053: cd->extract_handlers = & lm32_cgen_extract_handlers[0];
1054:
1055: cd->insert_operand = lm32_cgen_insert_operand;
1056: cd->extract_operand = lm32_cgen_extract_operand;
1057:
1058: cd->get_int_operand = lm32_cgen_get_int_operand;
1059: cd->set_int_operand = lm32_cgen_set_int_operand;
1060: cd->get_vma_operand = lm32_cgen_get_vma_operand;
1061: cd->set_vma_operand = lm32_cgen_set_vma_operand;
1062: }
CVSweb <webmaster@jp.NetBSD.org>