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