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