1ed0d50c3Schristos/* Instruction building/extraction support for @arch@. -*- C -*-
2ed0d50c3Schristos
3ed0d50c3Schristos   THIS FILE IS MACHINE GENERATED WITH CGEN: Cpu tools GENerator.
4ed0d50c3Schristos   - the resultant file is machine generated, cgen-ibld.in isn't
5ed0d50c3Schristos
6*b88e3e88Schristos   Copyright (C) 1996-2020 Free Software Foundation, Inc.
7ed0d50c3Schristos
8ed0d50c3Schristos   This file is part of libopcodes.
9ed0d50c3Schristos
10ed0d50c3Schristos   This library is free software; you can redistribute it and/or modify
11ed0d50c3Schristos   it under the terms of the GNU General Public License as published by
12ed0d50c3Schristos   the Free Software Foundation; either version 3, or (at your option)
13ed0d50c3Schristos   any later version.
14ed0d50c3Schristos
15ed0d50c3Schristos   It is distributed in the hope that it will be useful, but WITHOUT
16ed0d50c3Schristos   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
17ed0d50c3Schristos   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
18ed0d50c3Schristos   License for more details.
19ed0d50c3Schristos
20ed0d50c3Schristos   You should have received a copy of the GNU General Public License
21ed0d50c3Schristos   along with this program; if not, write to the Free Software Foundation, Inc.,
22ed0d50c3Schristos   51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
23ed0d50c3Schristos
24ed0d50c3Schristos/* ??? Eventually more and more of this stuff can go to cpu-independent files.
25ed0d50c3Schristos   Keep that in mind.  */
26ed0d50c3Schristos
27ed0d50c3Schristos#include "sysdep.h"
28ed0d50c3Schristos#include <stdio.h>
29ed0d50c3Schristos#include "ansidecl.h"
30ed0d50c3Schristos#include "dis-asm.h"
31ed0d50c3Schristos#include "bfd.h"
32ed0d50c3Schristos#include "symcat.h"
33ed0d50c3Schristos#include "@prefix@-desc.h"
34ed0d50c3Schristos#include "@prefix@-opc.h"
35ed0d50c3Schristos#include "cgen/basic-modes.h"
36ed0d50c3Schristos#include "opintl.h"
37ed0d50c3Schristos#include "safe-ctype.h"
38ed0d50c3Schristos
39ed0d50c3Schristos#undef  min
40ed0d50c3Schristos#define min(a,b) ((a) < (b) ? (a) : (b))
41ed0d50c3Schristos#undef  max
42ed0d50c3Schristos#define max(a,b) ((a) > (b) ? (a) : (b))
43ed0d50c3Schristos
44ed0d50c3Schristos/* Used by the ifield rtx function.  */
45ed0d50c3Schristos#define FLD(f) (fields->f)
46ed0d50c3Schristos
47ed0d50c3Schristosstatic const char * insert_normal
48ed0d50c3Schristos  (CGEN_CPU_DESC, long, unsigned int, unsigned int, unsigned int,
49ed0d50c3Schristos   unsigned int, unsigned int, unsigned int, CGEN_INSN_BYTES_PTR);
50ed0d50c3Schristosstatic const char * insert_insn_normal
51ed0d50c3Schristos  (CGEN_CPU_DESC, const CGEN_INSN *,
52ed0d50c3Schristos   CGEN_FIELDS *, CGEN_INSN_BYTES_PTR, bfd_vma);
53ed0d50c3Schristosstatic int extract_normal
54ed0d50c3Schristos  (CGEN_CPU_DESC, CGEN_EXTRACT_INFO *, CGEN_INSN_INT,
55ed0d50c3Schristos   unsigned int, unsigned int, unsigned int, unsigned int,
56ed0d50c3Schristos   unsigned int, unsigned int, bfd_vma, long *);
57ed0d50c3Schristosstatic int extract_insn_normal
58ed0d50c3Schristos  (CGEN_CPU_DESC, const CGEN_INSN *, CGEN_EXTRACT_INFO *,
59ed0d50c3Schristos   CGEN_INSN_INT, CGEN_FIELDS *, bfd_vma);
60ed0d50c3Schristos#if CGEN_INT_INSN_P
61ed0d50c3Schristosstatic void put_insn_int_value
62ed0d50c3Schristos  (CGEN_CPU_DESC, CGEN_INSN_BYTES_PTR, int, int, CGEN_INSN_INT);
63ed0d50c3Schristos#endif
64ed0d50c3Schristos#if ! CGEN_INT_INSN_P
65ed0d50c3Schristosstatic CGEN_INLINE void insert_1
66ed0d50c3Schristos  (CGEN_CPU_DESC, unsigned long, int, int, int, unsigned char *);
67ed0d50c3Schristosstatic CGEN_INLINE int fill_cache
68ed0d50c3Schristos  (CGEN_CPU_DESC, CGEN_EXTRACT_INFO *,  int, int, bfd_vma);
69ed0d50c3Schristosstatic CGEN_INLINE long extract_1
70ed0d50c3Schristos  (CGEN_CPU_DESC, CGEN_EXTRACT_INFO *, int, int, int, unsigned char *, bfd_vma);
71ed0d50c3Schristos#endif
72ed0d50c3Schristos
73ed0d50c3Schristos/* Operand insertion.  */
74ed0d50c3Schristos
75ed0d50c3Schristos#if ! CGEN_INT_INSN_P
76ed0d50c3Schristos
77ed0d50c3Schristos/* Subroutine of insert_normal.  */
78ed0d50c3Schristos
79ed0d50c3Schristosstatic CGEN_INLINE void
80ed0d50c3Schristosinsert_1 (CGEN_CPU_DESC cd,
81ed0d50c3Schristos	  unsigned long value,
82ed0d50c3Schristos	  int start,
83ed0d50c3Schristos	  int length,
84ed0d50c3Schristos	  int word_length,
85ed0d50c3Schristos	  unsigned char *bufp)
86ed0d50c3Schristos{
87ed0d50c3Schristos  unsigned long x,mask;
88ed0d50c3Schristos  int shift;
89ed0d50c3Schristos
90ed0d50c3Schristos  x = cgen_get_insn_value (cd, bufp, word_length);
91ed0d50c3Schristos
92ed0d50c3Schristos  /* Written this way to avoid undefined behaviour.  */
93ed0d50c3Schristos  mask = (((1L << (length - 1)) - 1) << 1) | 1;
94ed0d50c3Schristos  if (CGEN_INSN_LSB0_P)
95ed0d50c3Schristos    shift = (start + 1) - length;
96ed0d50c3Schristos  else
97ed0d50c3Schristos    shift = (word_length - (start + length));
98ed0d50c3Schristos  x = (x & ~(mask << shift)) | ((value & mask) << shift);
99ed0d50c3Schristos
100ed0d50c3Schristos  cgen_put_insn_value (cd, bufp, word_length, (bfd_vma) x);
101ed0d50c3Schristos}
102ed0d50c3Schristos
103ed0d50c3Schristos#endif /* ! CGEN_INT_INSN_P */
104ed0d50c3Schristos
105ed0d50c3Schristos/* Default insertion routine.
106ed0d50c3Schristos
107ed0d50c3Schristos   ATTRS is a mask of the boolean attributes.
108ed0d50c3Schristos   WORD_OFFSET is the offset in bits from the start of the insn of the value.
109ed0d50c3Schristos   WORD_LENGTH is the length of the word in bits in which the value resides.
110ed0d50c3Schristos   START is the starting bit number in the word, architecture origin.
111ed0d50c3Schristos   LENGTH is the length of VALUE in bits.
112ed0d50c3Schristos   TOTAL_LENGTH is the total length of the insn in bits.
113ed0d50c3Schristos
114ed0d50c3Schristos   The result is an error message or NULL if success.  */
115ed0d50c3Schristos
116ed0d50c3Schristos/* ??? This duplicates functionality with bfd's howto table and
117ed0d50c3Schristos   bfd_install_relocation.  */
118ed0d50c3Schristos/* ??? This doesn't handle bfd_vma's.  Create another function when
119ed0d50c3Schristos   necessary.  */
120ed0d50c3Schristos
121ed0d50c3Schristosstatic const char *
122ed0d50c3Schristosinsert_normal (CGEN_CPU_DESC cd,
123ed0d50c3Schristos	       long value,
124ed0d50c3Schristos	       unsigned int attrs,
125ed0d50c3Schristos	       unsigned int word_offset,
126ed0d50c3Schristos	       unsigned int start,
127ed0d50c3Schristos	       unsigned int length,
128ed0d50c3Schristos	       unsigned int word_length,
129ed0d50c3Schristos	       unsigned int total_length,
130ed0d50c3Schristos	       CGEN_INSN_BYTES_PTR buffer)
131ed0d50c3Schristos{
132ed0d50c3Schristos  static char errbuf[100];
133ed0d50c3Schristos  /* Written this way to avoid undefined behaviour.  */
134ed0d50c3Schristos  unsigned long mask = (((1L << (length - 1)) - 1) << 1) | 1;
135ed0d50c3Schristos
136ed0d50c3Schristos  /* If LENGTH is zero, this operand doesn't contribute to the value.  */
137ed0d50c3Schristos  if (length == 0)
138ed0d50c3Schristos    return NULL;
139ed0d50c3Schristos
140ed0d50c3Schristos  if (word_length > 8 * sizeof (CGEN_INSN_INT))
141ed0d50c3Schristos    abort ();
142ed0d50c3Schristos
143ed0d50c3Schristos  /* For architectures with insns smaller than the base-insn-bitsize,
144ed0d50c3Schristos     word_length may be too big.  */
145ed0d50c3Schristos  if (cd->min_insn_bitsize < cd->base_insn_bitsize)
146ed0d50c3Schristos    {
147ed0d50c3Schristos      if (word_offset == 0
148ed0d50c3Schristos	  && word_length > total_length)
149ed0d50c3Schristos	word_length = total_length;
150ed0d50c3Schristos    }
151ed0d50c3Schristos
152ed0d50c3Schristos  /* Ensure VALUE will fit.  */
153ed0d50c3Schristos  if (CGEN_BOOL_ATTR (attrs, CGEN_IFLD_SIGN_OPT))
154ed0d50c3Schristos    {
155ed0d50c3Schristos      long minval = - (1L << (length - 1));
156ed0d50c3Schristos      unsigned long maxval = mask;
157ed0d50c3Schristos
158ed0d50c3Schristos      if ((value > 0 && (unsigned long) value > maxval)
159ed0d50c3Schristos	  || value < minval)
160ed0d50c3Schristos	{
161ed0d50c3Schristos	  /* xgettext:c-format */
162ed0d50c3Schristos	  sprintf (errbuf,
163ed0d50c3Schristos		   _("operand out of range (%ld not between %ld and %lu)"),
164ed0d50c3Schristos		   value, minval, maxval);
165ed0d50c3Schristos	  return errbuf;
166ed0d50c3Schristos	}
167ed0d50c3Schristos    }
168ed0d50c3Schristos  else if (! CGEN_BOOL_ATTR (attrs, CGEN_IFLD_SIGNED))
169ed0d50c3Schristos    {
170ed0d50c3Schristos      unsigned long maxval = mask;
171ed0d50c3Schristos      unsigned long val = (unsigned long) value;
172ed0d50c3Schristos
173ed0d50c3Schristos      /* For hosts with a word size > 32 check to see if value has been sign
174ed0d50c3Schristos	 extended beyond 32 bits.  If so then ignore these higher sign bits
175ed0d50c3Schristos	 as the user is attempting to store a 32-bit signed value into an
176ed0d50c3Schristos	 unsigned 32-bit field which is allowed.  */
177ed0d50c3Schristos      if (sizeof (unsigned long) > 4 && ((value >> 32) == -1))
178ed0d50c3Schristos	val &= 0xFFFFFFFF;
179ed0d50c3Schristos
180ed0d50c3Schristos      if (val > maxval)
181ed0d50c3Schristos	{
182ed0d50c3Schristos	  /* xgettext:c-format */
183ed0d50c3Schristos	  sprintf (errbuf,
184ed0d50c3Schristos		   _("operand out of range (0x%lx not between 0 and 0x%lx)"),
185ed0d50c3Schristos		   val, maxval);
186ed0d50c3Schristos	  return errbuf;
187ed0d50c3Schristos	}
188ed0d50c3Schristos    }
189ed0d50c3Schristos  else
190ed0d50c3Schristos    {
191ed0d50c3Schristos      if (! cgen_signed_overflow_ok_p (cd))
192ed0d50c3Schristos	{
193ed0d50c3Schristos	  long minval = - (1L << (length - 1));
194ed0d50c3Schristos	  long maxval =   (1L << (length - 1)) - 1;
195ed0d50c3Schristos
196ed0d50c3Schristos	  if (value < minval || value > maxval)
197ed0d50c3Schristos	    {
198ed0d50c3Schristos	      sprintf
199ed0d50c3Schristos		/* xgettext:c-format */
200ed0d50c3Schristos		(errbuf, _("operand out of range (%ld not between %ld and %ld)"),
201ed0d50c3Schristos		 value, minval, maxval);
202ed0d50c3Schristos	      return errbuf;
203ed0d50c3Schristos	    }
204ed0d50c3Schristos	}
205ed0d50c3Schristos    }
206ed0d50c3Schristos
207ed0d50c3Schristos#if CGEN_INT_INSN_P
208ed0d50c3Schristos
209ed0d50c3Schristos  {
210ed0d50c3Schristos    int shift_within_word, shift_to_word, shift;
211ed0d50c3Schristos
212ed0d50c3Schristos    /* How to shift the value to BIT0 of the word.  */
213ed0d50c3Schristos    shift_to_word = total_length - (word_offset + word_length);
214ed0d50c3Schristos
215ed0d50c3Schristos    /* How to shift the value to the field within the word.  */
216ed0d50c3Schristos    if (CGEN_INSN_LSB0_P)
217ed0d50c3Schristos      shift_within_word = start + 1 - length;
218ed0d50c3Schristos    else
219ed0d50c3Schristos      shift_within_word = word_length - start - length;
220ed0d50c3Schristos
221ed0d50c3Schristos    /* The total SHIFT, then mask in the value.  */
222ed0d50c3Schristos    shift = shift_to_word + shift_within_word;
223ed0d50c3Schristos    *buffer = (*buffer & ~(mask << shift)) | ((value & mask) << shift);
224ed0d50c3Schristos  }
225ed0d50c3Schristos
226ed0d50c3Schristos#else /* ! CGEN_INT_INSN_P */
227ed0d50c3Schristos
228ed0d50c3Schristos  {
229ed0d50c3Schristos    unsigned char *bufp = (unsigned char *) buffer + word_offset / 8;
230ed0d50c3Schristos
231ed0d50c3Schristos    insert_1 (cd, value, start, length, word_length, bufp);
232ed0d50c3Schristos  }
233ed0d50c3Schristos
234ed0d50c3Schristos#endif /* ! CGEN_INT_INSN_P */
235ed0d50c3Schristos
236ed0d50c3Schristos  return NULL;
237ed0d50c3Schristos}
238ed0d50c3Schristos
239ed0d50c3Schristos/* Default insn builder (insert handler).
240ed0d50c3Schristos   The instruction is recorded in CGEN_INT_INSN_P byte order (meaning
241ed0d50c3Schristos   that if CGEN_INSN_BYTES_PTR is an int * and thus, the value is
242ed0d50c3Schristos   recorded in host byte order, otherwise BUFFER is an array of bytes
243ed0d50c3Schristos   and the value is recorded in target byte order).
244ed0d50c3Schristos   The result is an error message or NULL if success.  */
245ed0d50c3Schristos
246ed0d50c3Schristosstatic const char *
247ed0d50c3Schristosinsert_insn_normal (CGEN_CPU_DESC cd,
248ed0d50c3Schristos		    const CGEN_INSN * insn,
249ed0d50c3Schristos		    CGEN_FIELDS * fields,
250ed0d50c3Schristos		    CGEN_INSN_BYTES_PTR buffer,
251ed0d50c3Schristos		    bfd_vma pc)
252ed0d50c3Schristos{
253ed0d50c3Schristos  const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
254ed0d50c3Schristos  unsigned long value;
255ed0d50c3Schristos  const CGEN_SYNTAX_CHAR_TYPE * syn;
256ed0d50c3Schristos
257ed0d50c3Schristos  CGEN_INIT_INSERT (cd);
258ed0d50c3Schristos  value = CGEN_INSN_BASE_VALUE (insn);
259ed0d50c3Schristos
260ed0d50c3Schristos  /* If we're recording insns as numbers (rather than a string of bytes),
261ed0d50c3Schristos     target byte order handling is deferred until later.  */
262ed0d50c3Schristos
263ed0d50c3Schristos#if CGEN_INT_INSN_P
264ed0d50c3Schristos
265ed0d50c3Schristos  put_insn_int_value (cd, buffer, cd->base_insn_bitsize,
266ed0d50c3Schristos		      CGEN_FIELDS_BITSIZE (fields), value);
267ed0d50c3Schristos
268ed0d50c3Schristos#else
269ed0d50c3Schristos
270ed0d50c3Schristos  cgen_put_insn_value (cd, buffer, min ((unsigned) cd->base_insn_bitsize,
271ed0d50c3Schristos					(unsigned) CGEN_FIELDS_BITSIZE (fields)),
272ed0d50c3Schristos		       value);
273ed0d50c3Schristos
274ed0d50c3Schristos#endif /* ! CGEN_INT_INSN_P */
275ed0d50c3Schristos
276ed0d50c3Schristos  /* ??? It would be better to scan the format's fields.
277ed0d50c3Schristos     Still need to be able to insert a value based on the operand though;
278ed0d50c3Schristos     e.g. storing a branch displacement that got resolved later.
279ed0d50c3Schristos     Needs more thought first.  */
280ed0d50c3Schristos
281ed0d50c3Schristos  for (syn = CGEN_SYNTAX_STRING (syntax); * syn; ++ syn)
282ed0d50c3Schristos    {
283ed0d50c3Schristos      const char *errmsg;
284ed0d50c3Schristos
285ed0d50c3Schristos      if (CGEN_SYNTAX_CHAR_P (* syn))
286ed0d50c3Schristos	continue;
287ed0d50c3Schristos
288ed0d50c3Schristos      errmsg = (* cd->insert_operand) (cd, CGEN_SYNTAX_FIELD (*syn),
289ed0d50c3Schristos				       fields, buffer, pc);
290ed0d50c3Schristos      if (errmsg)
291ed0d50c3Schristos	return errmsg;
292ed0d50c3Schristos    }
293ed0d50c3Schristos
294ed0d50c3Schristos  return NULL;
295ed0d50c3Schristos}
296ed0d50c3Schristos
297ed0d50c3Schristos#if CGEN_INT_INSN_P
298ed0d50c3Schristos/* Cover function to store an insn value into an integral insn.  Must go here
299ed0d50c3Schristos   because it needs <prefix>-desc.h for CGEN_INT_INSN_P.  */
300ed0d50c3Schristos
301ed0d50c3Schristosstatic void
302ed0d50c3Schristosput_insn_int_value (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
303ed0d50c3Schristos		    CGEN_INSN_BYTES_PTR buf,
304ed0d50c3Schristos		    int length,
305ed0d50c3Schristos		    int insn_length,
306ed0d50c3Schristos		    CGEN_INSN_INT value)
307ed0d50c3Schristos{
308ed0d50c3Schristos  /* For architectures with insns smaller than the base-insn-bitsize,
309ed0d50c3Schristos     length may be too big.  */
310ed0d50c3Schristos  if (length > insn_length)
311ed0d50c3Schristos    *buf = value;
312ed0d50c3Schristos  else
313ed0d50c3Schristos    {
314ed0d50c3Schristos      int shift = insn_length - length;
315ed0d50c3Schristos      /* Written this way to avoid undefined behaviour.  */
316ed0d50c3Schristos      CGEN_INSN_INT mask = (((1L << (length - 1)) - 1) << 1) | 1;
317ed0d50c3Schristos
318ed0d50c3Schristos      *buf = (*buf & ~(mask << shift)) | ((value & mask) << shift);
319ed0d50c3Schristos    }
320ed0d50c3Schristos}
321ed0d50c3Schristos#endif
322ed0d50c3Schristos
323ed0d50c3Schristos/* Operand extraction.  */
324ed0d50c3Schristos
325ed0d50c3Schristos#if ! CGEN_INT_INSN_P
326ed0d50c3Schristos
327ed0d50c3Schristos/* Subroutine of extract_normal.
328ed0d50c3Schristos   Ensure sufficient bytes are cached in EX_INFO.
329ed0d50c3Schristos   OFFSET is the offset in bytes from the start of the insn of the value.
330ed0d50c3Schristos   BYTES is the length of the needed value.
331ed0d50c3Schristos   Returns 1 for success, 0 for failure.  */
332ed0d50c3Schristos
333ed0d50c3Schristosstatic CGEN_INLINE int
334ed0d50c3Schristosfill_cache (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
335ed0d50c3Schristos	    CGEN_EXTRACT_INFO *ex_info,
336ed0d50c3Schristos	    int offset,
337ed0d50c3Schristos	    int bytes,
338ed0d50c3Schristos	    bfd_vma pc)
339ed0d50c3Schristos{
340ed0d50c3Schristos  /* It's doubtful that the middle part has already been fetched so
341ed0d50c3Schristos     we don't optimize that case.  kiss.  */
342ed0d50c3Schristos  unsigned int mask;
343ed0d50c3Schristos  disassemble_info *info = (disassemble_info *) ex_info->dis_info;
344ed0d50c3Schristos
345ed0d50c3Schristos  /* First do a quick check.  */
346ed0d50c3Schristos  mask = (1 << bytes) - 1;
347ed0d50c3Schristos  if (((ex_info->valid >> offset) & mask) == mask)
348ed0d50c3Schristos    return 1;
349ed0d50c3Schristos
350ed0d50c3Schristos  /* Search for the first byte we need to read.  */
351ed0d50c3Schristos  for (mask = 1 << offset; bytes > 0; --bytes, ++offset, mask <<= 1)
352ed0d50c3Schristos    if (! (mask & ex_info->valid))
353ed0d50c3Schristos      break;
354ed0d50c3Schristos
355ed0d50c3Schristos  if (bytes)
356ed0d50c3Schristos    {
357ed0d50c3Schristos      int status;
358ed0d50c3Schristos
359ed0d50c3Schristos      pc += offset;
360ed0d50c3Schristos      status = (*info->read_memory_func)
361ed0d50c3Schristos	(pc, ex_info->insn_bytes + offset, bytes, info);
362ed0d50c3Schristos
363ed0d50c3Schristos      if (status != 0)
364ed0d50c3Schristos	{
365ed0d50c3Schristos	  (*info->memory_error_func) (status, pc, info);
366ed0d50c3Schristos	  return 0;
367ed0d50c3Schristos	}
368ed0d50c3Schristos
369ed0d50c3Schristos      ex_info->valid |= ((1 << bytes) - 1) << offset;
370ed0d50c3Schristos    }
371ed0d50c3Schristos
372ed0d50c3Schristos  return 1;
373ed0d50c3Schristos}
374ed0d50c3Schristos
375ed0d50c3Schristos/* Subroutine of extract_normal.  */
376ed0d50c3Schristos
377ed0d50c3Schristosstatic CGEN_INLINE long
378ed0d50c3Schristosextract_1 (CGEN_CPU_DESC cd,
379ed0d50c3Schristos	   CGEN_EXTRACT_INFO *ex_info ATTRIBUTE_UNUSED,
380ed0d50c3Schristos	   int start,
381ed0d50c3Schristos	   int length,
382ed0d50c3Schristos	   int word_length,
383ed0d50c3Schristos	   unsigned char *bufp,
384ed0d50c3Schristos	   bfd_vma pc ATTRIBUTE_UNUSED)
385ed0d50c3Schristos{
386ed0d50c3Schristos  unsigned long x;
387ed0d50c3Schristos  int shift;
388ed0d50c3Schristos
389ed0d50c3Schristos  x = cgen_get_insn_value (cd, bufp, word_length);
390ed0d50c3Schristos
391ed0d50c3Schristos  if (CGEN_INSN_LSB0_P)
392ed0d50c3Schristos    shift = (start + 1) - length;
393ed0d50c3Schristos  else
394ed0d50c3Schristos    shift = (word_length - (start + length));
395ed0d50c3Schristos  return x >> shift;
396ed0d50c3Schristos}
397ed0d50c3Schristos
398ed0d50c3Schristos#endif /* ! CGEN_INT_INSN_P */
399ed0d50c3Schristos
400ed0d50c3Schristos/* Default extraction routine.
401ed0d50c3Schristos
402ed0d50c3Schristos   INSN_VALUE is the first base_insn_bitsize bits of the insn in host order,
403ed0d50c3Schristos   or sometimes less for cases like the m32r where the base insn size is 32
404ed0d50c3Schristos   but some insns are 16 bits.
405ed0d50c3Schristos   ATTRS is a mask of the boolean attributes.  We only need `SIGNED',
406ed0d50c3Schristos   but for generality we take a bitmask of all of them.
407ed0d50c3Schristos   WORD_OFFSET is the offset in bits from the start of the insn of the value.
408ed0d50c3Schristos   WORD_LENGTH is the length of the word in bits in which the value resides.
409ed0d50c3Schristos   START is the starting bit number in the word, architecture origin.
410ed0d50c3Schristos   LENGTH is the length of VALUE in bits.
411ed0d50c3Schristos   TOTAL_LENGTH is the total length of the insn in bits.
412ed0d50c3Schristos
413ed0d50c3Schristos   Returns 1 for success, 0 for failure.  */
414ed0d50c3Schristos
415ed0d50c3Schristos/* ??? The return code isn't properly used.  wip.  */
416ed0d50c3Schristos
417ed0d50c3Schristos/* ??? This doesn't handle bfd_vma's.  Create another function when
418ed0d50c3Schristos   necessary.  */
419ed0d50c3Schristos
420ed0d50c3Schristosstatic int
421ed0d50c3Schristosextract_normal (CGEN_CPU_DESC cd,
422ed0d50c3Schristos#if ! CGEN_INT_INSN_P
423ed0d50c3Schristos		CGEN_EXTRACT_INFO *ex_info,
424ed0d50c3Schristos#else
425ed0d50c3Schristos		CGEN_EXTRACT_INFO *ex_info ATTRIBUTE_UNUSED,
426ed0d50c3Schristos#endif
427ed0d50c3Schristos		CGEN_INSN_INT insn_value,
428ed0d50c3Schristos		unsigned int attrs,
429ed0d50c3Schristos		unsigned int word_offset,
430ed0d50c3Schristos		unsigned int start,
431ed0d50c3Schristos		unsigned int length,
432ed0d50c3Schristos		unsigned int word_length,
433ed0d50c3Schristos		unsigned int total_length,
434ed0d50c3Schristos#if ! CGEN_INT_INSN_P
435ed0d50c3Schristos		bfd_vma pc,
436ed0d50c3Schristos#else
437ed0d50c3Schristos		bfd_vma pc ATTRIBUTE_UNUSED,
438ed0d50c3Schristos#endif
439ed0d50c3Schristos		long *valuep)
440ed0d50c3Schristos{
441ed0d50c3Schristos  long value, mask;
442ed0d50c3Schristos
443ed0d50c3Schristos  /* If LENGTH is zero, this operand doesn't contribute to the value
444ed0d50c3Schristos     so give it a standard value of zero.  */
445ed0d50c3Schristos  if (length == 0)
446ed0d50c3Schristos    {
447ed0d50c3Schristos      *valuep = 0;
448ed0d50c3Schristos      return 1;
449ed0d50c3Schristos    }
450ed0d50c3Schristos
451ed0d50c3Schristos  if (word_length > 8 * sizeof (CGEN_INSN_INT))
452ed0d50c3Schristos    abort ();
453ed0d50c3Schristos
454ed0d50c3Schristos  /* For architectures with insns smaller than the insn-base-bitsize,
455ed0d50c3Schristos     word_length may be too big.  */
456ed0d50c3Schristos  if (cd->min_insn_bitsize < cd->base_insn_bitsize)
457ed0d50c3Schristos    {
458ed0d50c3Schristos      if (word_offset + word_length > total_length)
459ed0d50c3Schristos	word_length = total_length - word_offset;
460ed0d50c3Schristos    }
461ed0d50c3Schristos
462ed0d50c3Schristos  /* Does the value reside in INSN_VALUE, and at the right alignment?  */
463ed0d50c3Schristos
464ed0d50c3Schristos  if (CGEN_INT_INSN_P || (word_offset == 0 && word_length == total_length))
465ed0d50c3Schristos    {
466ed0d50c3Schristos      if (CGEN_INSN_LSB0_P)
467ed0d50c3Schristos	value = insn_value >> ((word_offset + start + 1) - length);
468ed0d50c3Schristos      else
469ed0d50c3Schristos	value = insn_value >> (total_length - ( word_offset + start + length));
470ed0d50c3Schristos    }
471ed0d50c3Schristos
472ed0d50c3Schristos#if ! CGEN_INT_INSN_P
473ed0d50c3Schristos
474ed0d50c3Schristos  else
475ed0d50c3Schristos    {
476ed0d50c3Schristos      unsigned char *bufp = ex_info->insn_bytes + word_offset / 8;
477ed0d50c3Schristos
478ed0d50c3Schristos      if (word_length > 8 * sizeof (CGEN_INSN_INT))
479ed0d50c3Schristos	abort ();
480ed0d50c3Schristos
481ed0d50c3Schristos      if (fill_cache (cd, ex_info, word_offset / 8, word_length / 8, pc) == 0)
482ed0d50c3Schristos	return 0;
483ed0d50c3Schristos
484ed0d50c3Schristos      value = extract_1 (cd, ex_info, start, length, word_length, bufp, pc);
485ed0d50c3Schristos    }
486ed0d50c3Schristos
487ed0d50c3Schristos#endif /* ! CGEN_INT_INSN_P */
488ed0d50c3Schristos
489ed0d50c3Schristos  /* Written this way to avoid undefined behaviour.  */
490ed0d50c3Schristos  mask = (((1L << (length - 1)) - 1) << 1) | 1;
491ed0d50c3Schristos
492ed0d50c3Schristos  value &= mask;
493ed0d50c3Schristos  /* sign extend? */
494ed0d50c3Schristos  if (CGEN_BOOL_ATTR (attrs, CGEN_IFLD_SIGNED)
495ed0d50c3Schristos      && (value & (1L << (length - 1))))
496ed0d50c3Schristos    value |= ~mask;
497ed0d50c3Schristos
498ed0d50c3Schristos  *valuep = value;
499ed0d50c3Schristos
500ed0d50c3Schristos  return 1;
501ed0d50c3Schristos}
502ed0d50c3Schristos
503ed0d50c3Schristos/* Default insn extractor.
504ed0d50c3Schristos
505ed0d50c3Schristos   INSN_VALUE is the first base_insn_bitsize bits, translated to host order.
506ed0d50c3Schristos   The extracted fields are stored in FIELDS.
507ed0d50c3Schristos   EX_INFO is used to handle reading variable length insns.
508ed0d50c3Schristos   Return the length of the insn in bits, or 0 if no match,
509ed0d50c3Schristos   or -1 if an error occurs fetching data (memory_error_func will have
510ed0d50c3Schristos   been called).  */
511ed0d50c3Schristos
512ed0d50c3Schristosstatic int
513ed0d50c3Schristosextract_insn_normal (CGEN_CPU_DESC cd,
514ed0d50c3Schristos		     const CGEN_INSN *insn,
515ed0d50c3Schristos		     CGEN_EXTRACT_INFO *ex_info,
516ed0d50c3Schristos		     CGEN_INSN_INT insn_value,
517ed0d50c3Schristos		     CGEN_FIELDS *fields,
518ed0d50c3Schristos		     bfd_vma pc)
519ed0d50c3Schristos{
520ed0d50c3Schristos  const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
521ed0d50c3Schristos  const CGEN_SYNTAX_CHAR_TYPE *syn;
522ed0d50c3Schristos
523ed0d50c3Schristos  CGEN_FIELDS_BITSIZE (fields) = CGEN_INSN_BITSIZE (insn);
524ed0d50c3Schristos
525ed0d50c3Schristos  CGEN_INIT_EXTRACT (cd);
526ed0d50c3Schristos
527ed0d50c3Schristos  for (syn = CGEN_SYNTAX_STRING (syntax); *syn; ++syn)
528ed0d50c3Schristos    {
529ed0d50c3Schristos      int length;
530ed0d50c3Schristos
531ed0d50c3Schristos      if (CGEN_SYNTAX_CHAR_P (*syn))
532ed0d50c3Schristos	continue;
533ed0d50c3Schristos
534ed0d50c3Schristos      length = (* cd->extract_operand) (cd, CGEN_SYNTAX_FIELD (*syn),
535ed0d50c3Schristos					ex_info, insn_value, fields, pc);
536ed0d50c3Schristos      if (length <= 0)
537ed0d50c3Schristos	return length;
538ed0d50c3Schristos    }
539ed0d50c3Schristos
540ed0d50c3Schristos  /* We recognized and successfully extracted this insn.  */
541ed0d50c3Schristos  return CGEN_INSN_BITSIZE (insn);
542ed0d50c3Schristos}
543ed0d50c3Schristos
544ed0d50c3Schristos/* Machine generated code added here.  */
545