1234353Sdim/* Assembler interface for targets using CGEN. -*- C -*- 2199481Srdivacky CGEN: Cpu tools GENerator 3199481Srdivacky 4199481Srdivacky THIS FILE IS MACHINE GENERATED WITH CGEN. 5199481Srdivacky - the resultant file is machine generated, cgen-asm.in isn't 6199481Srdivacky 7199481Srdivacky Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2005 8199481Srdivacky Free Software Foundation, Inc. 9199481Srdivacky 10218893Sdim This file is part of the GNU Binutils and GDB, the GNU debugger. 11199481Srdivacky 12199481Srdivacky This program is free software; you can redistribute it and/or modify 13218893Sdim it under the terms of the GNU General Public License as published by 14199481Srdivacky the Free Software Foundation; either version 2, or (at your option) 15199481Srdivacky any later version. 16199481Srdivacky 17199481Srdivacky This program is distributed in the hope that it will be useful, 18199481Srdivacky but WITHOUT ANY WARRANTY; without even the implied warranty of 19199481Srdivacky MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20218893Sdim GNU General Public License for more details. 21218893Sdim 22226633Sdim You should have received a copy of the GNU General Public License 23218893Sdim along with this program; if not, write to the Free Software Foundation, Inc., 24199481Srdivacky 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ 25199481Srdivacky 26249423Sdim/* ??? Eventually more and more of this stuff can go to cpu-independent files. 27249423Sdim Keep that in mind. */ 28218893Sdim 29212904Sdim#include "sysdep.h" 30199481Srdivacky#include <stdio.h> 31199481Srdivacky#include "ansidecl.h" 32226633Sdim#include "bfd.h" 33226633Sdim#include "symcat.h" 34226633Sdim#include "xc16x-desc.h" 35226633Sdim#include "xc16x-opc.h" 36199481Srdivacky#include "opintl.h" 37199481Srdivacky#include "xregex.h" 38199481Srdivacky#include "libiberty.h" 39199481Srdivacky#include "safe-ctype.h" 40212904Sdim 41199481Srdivacky#undef min 42218893Sdim#define min(a,b) ((a) < (b) ? (a) : (b)) 43208599Srdivacky#undef max 44218893Sdim#define max(a,b) ((a) > (b) ? (a) : (b)) 45218893Sdim 46199481Srdivackystatic const char * parse_insn_normal 47199481Srdivacky (CGEN_CPU_DESC, const CGEN_INSN *, const char **, CGEN_FIELDS *); 48199481Srdivacky 49199481Srdivacky/* -- assembler routines inserted here. */ 50199481Srdivacky 51199481Srdivacky/* -- asm.c */ 52199481Srdivacky/* Handle '#' prefixes (i.e. skip over them). */ 53199481Srdivacky 54208599Srdivackystatic const char * 55208599Srdivackyparse_hash (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED, 56218893Sdim const char **strp, 57218893Sdim int opindex ATTRIBUTE_UNUSED, 58199481Srdivacky long *valuep ATTRIBUTE_UNUSED) 59218893Sdim{ 60218893Sdim if (**strp == '#') 61218893Sdim { 62218893Sdim ++*strp; 63234353Sdim return NULL; 64218893Sdim } 65218893Sdim return _("Missing '#' prefix"); 66199481Srdivacky} 67199481Srdivacky 68199481Srdivacky/* Handle '.' prefixes (i.e. skip over them). */ 69199481Srdivacky 70208599Srdivackystatic const char * 71208599Srdivackyparse_dot (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED, 72208599Srdivacky const char **strp, 73208599Srdivacky int opindex ATTRIBUTE_UNUSED, 74208599Srdivacky long *valuep ATTRIBUTE_UNUSED) 75224145Sdim{ 76208599Srdivacky if (**strp == '.') 77208599Srdivacky { 78208599Srdivacky ++*strp; 79208599Srdivacky return NULL; 80208599Srdivacky } 81218893Sdim return _("Missing '.' prefix"); 82208599Srdivacky} 83218893Sdim 84208599Srdivacky/* Handle 'pof:' prefixes (i.e. skip over them). */ 85208599Srdivacky 86208599Srdivackystatic const char * 87218893Sdimparse_pof (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED, 88218893Sdim const char **strp, 89218893Sdim int opindex ATTRIBUTE_UNUSED, 90218893Sdim long *valuep ATTRIBUTE_UNUSED) 91218893Sdim{ 92218893Sdim if (strncasecmp (*strp, "pof:", 4) == 0) 93218893Sdim { 94218893Sdim *strp += 4; 95218893Sdim return NULL; 96218893Sdim } 97218893Sdim return _("Missing 'pof:' prefix"); 98218893Sdim} 99218893Sdim 100218893Sdim/* Handle 'pag:' prefixes (i.e. skip over them). */ 101234353Sdim 102234353Sdimstatic const char * 103218893Sdimparse_pag (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED, 104234353Sdim const char **strp, 105234353Sdim int opindex ATTRIBUTE_UNUSED, 106243830Sdim long *valuep ATTRIBUTE_UNUSED) 107243830Sdim{ 108243830Sdim if (strncasecmp (*strp, "pag:", 4) == 0) 109234353Sdim { 110234353Sdim *strp += 4; 111234353Sdim return NULL; 112234353Sdim } 113234353Sdim return _("Missing 'pag:' prefix"); 114234353Sdim} 115218893Sdim 116218893Sdim/* Handle 'sof' prefixes (i.e. skip over them). */ 117218893Sdim 118218893Sdimstatic const char * 119218893Sdimparse_sof (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED, 120218893Sdim const char **strp, 121218893Sdim int opindex ATTRIBUTE_UNUSED, 122218893Sdim long *valuep ATTRIBUTE_UNUSED) 123218893Sdim{ 124218893Sdim if (strncasecmp (*strp, "sof:", 4) == 0) 125218893Sdim { 126218893Sdim *strp += 4; 127218893Sdim return NULL; 128218893Sdim } 129218893Sdim return _("Missing 'sof:' prefix"); 130218893Sdim} 131234353Sdim 132234353Sdim/* Handle 'seg' prefixes (i.e. skip over them). */ 133234353Sdim 134234353Sdimstatic const char * 135234353Sdimparse_seg (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED, 136234353Sdim const char **strp, 137218893Sdim int opindex ATTRIBUTE_UNUSED, 138234353Sdim long *valuep ATTRIBUTE_UNUSED) 139266715Sdim{ 140234353Sdim if (strncasecmp (*strp, "seg:", 4) == 0) 141266715Sdim { 142218893Sdim *strp += 4; 143234353Sdim return NULL; 144234353Sdim } 145234353Sdim return _("Missing 'seg:' prefix"); 146234353Sdim} 147234353Sdim/* -- */ 148234353Sdim 149234353Sdimconst char * xc16x_cgen_parse_operand 150234353Sdim (CGEN_CPU_DESC, int, const char **, CGEN_FIELDS *); 151234353Sdim 152234353Sdim/* Main entry point for operand parsing. 153218893Sdim 154234353Sdim This function is basically just a big switch statement. Earlier versions 155234353Sdim used tables to look up the function to use, but 156234353Sdim - if the table contains both assembler and disassembler functions then 157234353Sdim the disassembler contains much of the assembler and vice-versa, 158234353Sdim - there's a lot of inlining possibilities as things grow, 159234353Sdim - using a switch statement avoids the function call overhead. 160234353Sdim 161234353Sdim This function could be moved into `parse_insn_normal', but keeping it 162234353Sdim separate makes clear the interface between `parse_insn_normal' and each of 163218893Sdim the handlers. */ 164234353Sdim 165234353Sdimconst char * 166234353Sdimxc16x_cgen_parse_operand (CGEN_CPU_DESC cd, 167234353Sdim int opindex, 168234353Sdim const char ** strp, 169234353Sdim CGEN_FIELDS * fields) 170218893Sdim{ 171234353Sdim const char * errmsg = NULL; 172234353Sdim /* Used by scalar operands that still need to be parsed. */ 173234353Sdim long junk ATTRIBUTE_UNUSED; 174234353Sdim 175234353Sdim switch (opindex) 176234353Sdim { 177234353Sdim case XC16X_OPERAND_REGNAM : 178234353Sdim errmsg = cgen_parse_keyword (cd, strp, & xc16x_cgen_opval_psw_names, & fields->f_reg8); 179234353Sdim break; 180234353Sdim case XC16X_OPERAND_BIT01 : 181218893Sdim errmsg = cgen_parse_unsigned_integer (cd, strp, XC16X_OPERAND_BIT01, (unsigned long *) (& fields->f_op_1bit)); 182234353Sdim break; 183234353Sdim case XC16X_OPERAND_BIT1 : 184234353Sdim errmsg = cgen_parse_unsigned_integer (cd, strp, XC16X_OPERAND_BIT1, (unsigned long *) (& fields->f_op_bit1)); 185234353Sdim break; 186234353Sdim case XC16X_OPERAND_BIT2 : 187234353Sdim errmsg = cgen_parse_unsigned_integer (cd, strp, XC16X_OPERAND_BIT2, (unsigned long *) (& fields->f_op_bit2)); 188218893Sdim break; 189234353Sdim case XC16X_OPERAND_BIT4 : 190234353Sdim errmsg = cgen_parse_unsigned_integer (cd, strp, XC16X_OPERAND_BIT4, (unsigned long *) (& fields->f_op_bit4)); 191234353Sdim break; 192234353Sdim case XC16X_OPERAND_BIT8 : 193234353Sdim errmsg = cgen_parse_unsigned_integer (cd, strp, XC16X_OPERAND_BIT8, (unsigned long *) (& fields->f_op_bit8)); 194234353Sdim break; 195234353Sdim case XC16X_OPERAND_BITONE : 196234353Sdim errmsg = cgen_parse_unsigned_integer (cd, strp, XC16X_OPERAND_BITONE, (unsigned long *) (& fields->f_op_onebit)); 197234353Sdim break; 198218893Sdim case XC16X_OPERAND_CADDR : 199234353Sdim { 200234353Sdim bfd_vma value = 0; 201234353Sdim errmsg = cgen_parse_address (cd, strp, XC16X_OPERAND_CADDR, 0, NULL, & value); 202234353Sdim fields->f_offset16 = value; 203234353Sdim } 204234353Sdim break; 205218893Sdim case XC16X_OPERAND_COND : 206234353Sdim errmsg = cgen_parse_keyword (cd, strp, & xc16x_cgen_opval_conditioncode_names, & fields->f_condcode); 207234353Sdim break; 208234353Sdim case XC16X_OPERAND_DATA8 : 209234353Sdim errmsg = cgen_parse_unsigned_integer (cd, strp, XC16X_OPERAND_DATA8, (unsigned long *) (& fields->f_data8)); 210234353Sdim break; 211234353Sdim case XC16X_OPERAND_DATAHI8 : 212234353Sdim errmsg = cgen_parse_unsigned_integer (cd, strp, XC16X_OPERAND_DATAHI8, (unsigned long *) (& fields->f_datahi8)); 213234353Sdim break; 214234353Sdim case XC16X_OPERAND_DOT : 215234353Sdim errmsg = parse_dot (cd, strp, XC16X_OPERAND_DOT, (long *) (& junk)); 216218893Sdim break; 217234353Sdim case XC16X_OPERAND_DR : 218234353Sdim errmsg = cgen_parse_keyword (cd, strp, & xc16x_cgen_opval_gr_names, & fields->f_r1); 219234353Sdim break; 220234353Sdim case XC16X_OPERAND_DRB : 221234353Sdim errmsg = cgen_parse_keyword (cd, strp, & xc16x_cgen_opval_grb_names, & fields->f_r1); 222234353Sdim break; 223218893Sdim case XC16X_OPERAND_DRI : 224234353Sdim errmsg = cgen_parse_keyword (cd, strp, & xc16x_cgen_opval_gr_names, & fields->f_r4); 225234353Sdim break; 226234353Sdim case XC16X_OPERAND_EXTCOND : 227234353Sdim errmsg = cgen_parse_keyword (cd, strp, & xc16x_cgen_opval_extconditioncode_names, & fields->f_extccode); 228234353Sdim break; 229234353Sdim case XC16X_OPERAND_GENREG : 230234353Sdim errmsg = cgen_parse_keyword (cd, strp, & xc16x_cgen_opval_r8_names, & fields->f_regb8); 231234353Sdim break; 232234353Sdim case XC16X_OPERAND_HASH : 233218893Sdim errmsg = parse_hash (cd, strp, XC16X_OPERAND_HASH, (long *) (& junk)); 234234353Sdim break; 235234353Sdim case XC16X_OPERAND_ICOND : 236234353Sdim errmsg = cgen_parse_keyword (cd, strp, & xc16x_cgen_opval_conditioncode_names, & fields->f_icondcode); 237234353Sdim break; 238234353Sdim case XC16X_OPERAND_LBIT2 : 239234353Sdim errmsg = cgen_parse_unsigned_integer (cd, strp, XC16X_OPERAND_LBIT2, (unsigned long *) (& fields->f_op_lbit2)); 240218893Sdim break; 241234353Sdim case XC16X_OPERAND_LBIT4 : 242234353Sdim errmsg = cgen_parse_unsigned_integer (cd, strp, XC16X_OPERAND_LBIT4, (unsigned long *) (& fields->f_op_lbit4)); 243234353Sdim break; 244234353Sdim case XC16X_OPERAND_MASK8 : 245234353Sdim errmsg = cgen_parse_unsigned_integer (cd, strp, XC16X_OPERAND_MASK8, (unsigned long *) (& fields->f_mask8)); 246234353Sdim break; 247218893Sdim case XC16X_OPERAND_MASKLO8 : 248234353Sdim errmsg = cgen_parse_unsigned_integer (cd, strp, XC16X_OPERAND_MASKLO8, (unsigned long *) (& fields->f_datahi8)); 249234353Sdim break; 250234353Sdim case XC16X_OPERAND_MEMGR8 : 251234353Sdim errmsg = cgen_parse_keyword (cd, strp, & xc16x_cgen_opval_memgr8_names, & fields->f_memgr8); 252234353Sdim break; 253234353Sdim case XC16X_OPERAND_MEMORY : 254234353Sdim { 255234353Sdim bfd_vma value = 0; 256234353Sdim errmsg = cgen_parse_address (cd, strp, XC16X_OPERAND_MEMORY, 0, NULL, & value); 257234353Sdim fields->f_memory = value; 258218893Sdim } 259234353Sdim break; 260234353Sdim case XC16X_OPERAND_PAG : 261234353Sdim errmsg = parse_pag (cd, strp, XC16X_OPERAND_PAG, (long *) (& junk)); 262234353Sdim break; 263234353Sdim case XC16X_OPERAND_PAGENUM : 264234353Sdim errmsg = cgen_parse_unsigned_integer (cd, strp, XC16X_OPERAND_PAGENUM, (unsigned long *) (& fields->f_pagenum)); 265234353Sdim break; 266234353Sdim case XC16X_OPERAND_POF : 267234353Sdim errmsg = parse_pof (cd, strp, XC16X_OPERAND_POF, (long *) (& junk)); 268218893Sdim break; 269234353Sdim case XC16X_OPERAND_QBIT : 270234353Sdim errmsg = cgen_parse_unsigned_integer (cd, strp, XC16X_OPERAND_QBIT, (unsigned long *) (& fields->f_qbit)); 271234353Sdim break; 272234353Sdim case XC16X_OPERAND_QHIBIT : 273234353Sdim errmsg = cgen_parse_unsigned_integer (cd, strp, XC16X_OPERAND_QHIBIT, (unsigned long *) (& fields->f_qhibit)); 274234353Sdim break; 275234353Sdim case XC16X_OPERAND_QLOBIT : 276234353Sdim errmsg = cgen_parse_unsigned_integer (cd, strp, XC16X_OPERAND_QLOBIT, (unsigned long *) (& fields->f_qlobit)); 277234353Sdim break; 278234353Sdim case XC16X_OPERAND_REG8 : 279218893Sdim errmsg = cgen_parse_keyword (cd, strp, & xc16x_cgen_opval_r8_names, & fields->f_reg8); 280234353Sdim break; 281234353Sdim case XC16X_OPERAND_REGB8 : 282234353Sdim errmsg = cgen_parse_keyword (cd, strp, & xc16x_cgen_opval_grb8_names, & fields->f_regb8); 283234353Sdim break; 284234353Sdim case XC16X_OPERAND_REGBMEM8 : 285234353Sdim errmsg = cgen_parse_keyword (cd, strp, & xc16x_cgen_opval_regbmem8_names, & fields->f_regmem8); 286218893Sdim break; 287234353Sdim case XC16X_OPERAND_REGHI8 : 288234353Sdim errmsg = cgen_parse_keyword (cd, strp, & xc16x_cgen_opval_r8_names, & fields->f_reghi8); 289234353Sdim break; 290234353Sdim case XC16X_OPERAND_REGMEM8 : 291234353Sdim errmsg = cgen_parse_keyword (cd, strp, & xc16x_cgen_opval_regmem8_names, & fields->f_regmem8); 292234353Sdim break; 293234353Sdim case XC16X_OPERAND_REGOFF8 : 294234353Sdim errmsg = cgen_parse_keyword (cd, strp, & xc16x_cgen_opval_r8_names, & fields->f_regoff8); 295234353Sdim break; 296218893Sdim case XC16X_OPERAND_REL : 297234353Sdim errmsg = cgen_parse_signed_integer (cd, strp, XC16X_OPERAND_REL, (long *) (& fields->f_rel8)); 298234353Sdim break; 299234353Sdim case XC16X_OPERAND_RELHI : 300234353Sdim errmsg = cgen_parse_signed_integer (cd, strp, XC16X_OPERAND_RELHI, (long *) (& fields->f_relhi8)); 301234353Sdim break; 302234353Sdim case XC16X_OPERAND_SEG : 303234353Sdim errmsg = cgen_parse_unsigned_integer (cd, strp, XC16X_OPERAND_SEG, (unsigned long *) (& fields->f_seg8)); 304234353Sdim break; 305234353Sdim case XC16X_OPERAND_SEGHI8 : 306234353Sdim errmsg = cgen_parse_unsigned_integer (cd, strp, XC16X_OPERAND_SEGHI8, (unsigned long *) (& fields->f_segnum8)); 307218893Sdim break; 308234353Sdim case XC16X_OPERAND_SEGM : 309234353Sdim errmsg = parse_seg (cd, strp, XC16X_OPERAND_SEGM, (long *) (& junk)); 310234353Sdim break; 311234353Sdim case XC16X_OPERAND_SOF : 312234353Sdim errmsg = parse_sof (cd, strp, XC16X_OPERAND_SOF, (long *) (& junk)); 313234353Sdim break; 314218893Sdim case XC16X_OPERAND_SR : 315234353Sdim errmsg = cgen_parse_keyword (cd, strp, & xc16x_cgen_opval_gr_names, & fields->f_r2); 316234353Sdim break; 317234353Sdim case XC16X_OPERAND_SR2 : 318234353Sdim errmsg = cgen_parse_keyword (cd, strp, & xc16x_cgen_opval_gr_names, & fields->f_r0); 319234353Sdim break; 320234353Sdim case XC16X_OPERAND_SRB : 321234353Sdim errmsg = cgen_parse_keyword (cd, strp, & xc16x_cgen_opval_grb_names, & fields->f_r2); 322234353Sdim break; 323234353Sdim case XC16X_OPERAND_SRC1 : 324218893Sdim errmsg = cgen_parse_keyword (cd, strp, & xc16x_cgen_opval_gr_names, & fields->f_r1); 325218893Sdim break; 326218893Sdim case XC16X_OPERAND_SRC2 : 327218893Sdim errmsg = cgen_parse_keyword (cd, strp, & xc16x_cgen_opval_gr_names, & fields->f_r2); 328218893Sdim break; 329234353Sdim case XC16X_OPERAND_SRDIV : 330218893Sdim errmsg = cgen_parse_keyword (cd, strp, & xc16x_cgen_opval_regdiv8_names, & fields->f_reg8); 331218893Sdim break; 332218893Sdim case XC16X_OPERAND_U4 : 333218893Sdim errmsg = cgen_parse_keyword (cd, strp, & xc16x_cgen_opval_reg0_name, & fields->f_uimm4); 334218893Sdim break; 335218893Sdim case XC16X_OPERAND_UIMM16 : 336218893Sdim errmsg = cgen_parse_unsigned_integer (cd, strp, XC16X_OPERAND_UIMM16, (unsigned long *) (& fields->f_uimm16)); 337218893Sdim break; 338218893Sdim case XC16X_OPERAND_UIMM2 : 339218893Sdim errmsg = cgen_parse_keyword (cd, strp, & xc16x_cgen_opval_ext_names, & fields->f_uimm2); 340218893Sdim break; 341218893Sdim case XC16X_OPERAND_UIMM3 : 342218893Sdim errmsg = cgen_parse_keyword (cd, strp, & xc16x_cgen_opval_reg0_name1, & fields->f_uimm3); 343218893Sdim break; 344218893Sdim case XC16X_OPERAND_UIMM4 : 345218893Sdim errmsg = cgen_parse_unsigned_integer (cd, strp, XC16X_OPERAND_UIMM4, (unsigned long *) (& fields->f_uimm4)); 346218893Sdim break; 347218893Sdim case XC16X_OPERAND_UIMM7 : 348218893Sdim errmsg = cgen_parse_unsigned_integer (cd, strp, XC16X_OPERAND_UIMM7, (unsigned long *) (& fields->f_uimm7)); 349218893Sdim break; 350218893Sdim case XC16X_OPERAND_UIMM8 : 351218893Sdim errmsg = cgen_parse_unsigned_integer (cd, strp, XC16X_OPERAND_UIMM8, (unsigned long *) (& fields->f_uimm8)); 352218893Sdim break; 353218893Sdim case XC16X_OPERAND_UPAG16 : 354218893Sdim errmsg = cgen_parse_unsigned_integer (cd, strp, XC16X_OPERAND_UPAG16, (unsigned long *) (& fields->f_uimm16)); 355218893Sdim break; 356218893Sdim case XC16X_OPERAND_UPOF16 : 357218893Sdim { 358218893Sdim bfd_vma value = 0; 359218893Sdim errmsg = cgen_parse_address (cd, strp, XC16X_OPERAND_UPOF16, 0, NULL, & value); 360218893Sdim fields->f_memory = value; 361218893Sdim } 362218893Sdim break; 363218893Sdim case XC16X_OPERAND_USEG16 : 364218893Sdim errmsg = cgen_parse_unsigned_integer (cd, strp, XC16X_OPERAND_USEG16, (unsigned long *) (& fields->f_offset16)); 365218893Sdim break; 366218893Sdim case XC16X_OPERAND_USEG8 : 367218893Sdim errmsg = cgen_parse_unsigned_integer (cd, strp, XC16X_OPERAND_USEG8, (unsigned long *) (& fields->f_seg8)); 368218893Sdim break; 369218893Sdim case XC16X_OPERAND_USOF16 : 370218893Sdim errmsg = cgen_parse_unsigned_integer (cd, strp, XC16X_OPERAND_USOF16, (unsigned long *) (& fields->f_offset16)); 371218893Sdim break; 372218893Sdim 373218893Sdim default : 374212904Sdim /* xgettext:c-format */ 375212904Sdim fprintf (stderr, _("Unrecognized field %d while parsing.\n"), opindex); 376218893Sdim abort (); 377212904Sdim } 378212904Sdim 379212904Sdim return errmsg; 380218893Sdim} 381218893Sdim 382243830Sdimcgen_parse_fn * const xc16x_cgen_parse_handlers[] = 383218893Sdim{ 384218893Sdim parse_insn_normal, 385218893Sdim}; 386218893Sdim 387212904Sdimvoid 388212904Sdimxc16x_cgen_init_asm (CGEN_CPU_DESC cd) 389212904Sdim{ 390212904Sdim xc16x_cgen_init_opcode_table (cd); 391212904Sdim xc16x_cgen_init_ibld_table (cd); 392218893Sdim cd->parse_handlers = & xc16x_cgen_parse_handlers[0]; 393234353Sdim cd->parse_operand = xc16x_cgen_parse_operand; 394234353Sdim} 395234353Sdim 396234353Sdim 397212904Sdim 398234353Sdim/* Regex construction routine. 399212904Sdim 400212904Sdim This translates an opcode syntax string into a regex string, 401234353Sdim by replacing any non-character syntax element (such as an 402218893Sdim opcode) with the pattern '.*' 403218893Sdim 404212904Sdim It then compiles the regex and stores it in the opcode, for 405218893Sdim later use by xc16x_cgen_assemble_insn 406218893Sdim 407218893Sdim Returns NULL for success, an error message for failure. */ 408234353Sdim 409218893Sdimchar * 410218893Sdimxc16x_cgen_build_insn_regex (CGEN_INSN *insn) 411218893Sdim{ 412218893Sdim CGEN_OPCODE *opc = (CGEN_OPCODE *) CGEN_INSN_OPCODE (insn); 413218893Sdim const char *mnem = CGEN_INSN_MNEMONIC (insn); 414218893Sdim char rxbuf[CGEN_MAX_RX_ELEMENTS]; 415218893Sdim char *rx = rxbuf; 416218893Sdim const CGEN_SYNTAX_CHAR_TYPE *syn; 417218893Sdim int reg_err; 418218893Sdim 419218893Sdim syn = CGEN_SYNTAX_STRING (CGEN_OPCODE_SYNTAX (opc)); 420218893Sdim 421218893Sdim /* Mnemonics come first in the syntax string. */ 422218893Sdim if (! CGEN_SYNTAX_MNEMONIC_P (* syn)) 423218893Sdim return _("missing mnemonic in syntax string"); 424218893Sdim ++syn; 425218893Sdim 426218893Sdim /* Generate a case sensitive regular expression that emulates case 427218893Sdim insensitive matching in the "C" locale. We cannot generate a case 428212904Sdim insensitive regular expression because in Turkish locales, 'i' and 'I' 429212904Sdim are not equal modulo case conversion. */ 430212904Sdim 431218893Sdim /* Copy the literal mnemonic out of the insn. */ 432221345Sdim for (; *mnem; mnem++) 433221345Sdim { 434221345Sdim char c = *mnem; 435221345Sdim 436212904Sdim if (ISALPHA (c)) 437212904Sdim { 438212904Sdim *rx++ = '['; 439212904Sdim *rx++ = TOLOWER (c); 440212904Sdim *rx++ = TOUPPER (c); 441218893Sdim *rx++ = ']'; 442212904Sdim } 443212904Sdim else 444212904Sdim *rx++ = c; 445218893Sdim } 446218893Sdim 447243830Sdim /* Copy any remaining literals from the syntax string into the rx. */ 448218893Sdim for(; * syn != 0 && rx <= rxbuf + (CGEN_MAX_RX_ELEMENTS - 7 - 4); ++syn) 449218893Sdim { 450218893Sdim if (CGEN_SYNTAX_CHAR_P (* syn)) 451218893Sdim { 452212904Sdim char c = CGEN_SYNTAX_CHAR (* syn); 453234353Sdim 454218893Sdim switch (c) 455218893Sdim { 456212904Sdim /* Escape any regex metacharacters in the syntax. */ 457218893Sdim case '.': case '[': case '\\': 458218893Sdim case '*': case '^': case '$': 459218893Sdim 460234353Sdim#ifdef CGEN_ESCAPE_EXTENDED_REGEX 461218893Sdim case '?': case '{': case '}': 462218893Sdim case '(': case ')': case '*': 463218893Sdim case '|': case '+': case ']': 464239462Sdim#endif 465218893Sdim *rx++ = '\\'; 466218893Sdim *rx++ = c; 467218893Sdim break; 468239462Sdim 469234353Sdim default: 470239462Sdim if (ISALPHA (c)) 471234353Sdim { 472239462Sdim *rx++ = '['; 473234353Sdim *rx++ = TOLOWER (c); 474239462Sdim *rx++ = TOUPPER (c); 475218893Sdim *rx++ = ']'; 476218893Sdim } 477218893Sdim else 478218893Sdim *rx++ = c; 479218893Sdim break; 480239462Sdim } 481221345Sdim } 482218893Sdim else 483221345Sdim { 484221345Sdim /* Replace non-syntax fields with globs. */ 485221345Sdim *rx++ = '.'; 486221345Sdim *rx++ = '*'; 487218893Sdim } 488218893Sdim } 489218893Sdim 490218893Sdim /* Trailing whitespace ok. */ 491218893Sdim * rx++ = '['; 492218893Sdim * rx++ = ' '; 493218893Sdim * rx++ = '\t'; 494218893Sdim * rx++ = ']'; 495218893Sdim * rx++ = '*'; 496218893Sdim 497218893Sdim /* But anchor it after that. */ 498243830Sdim * rx++ = '$'; 499218893Sdim * rx = '\0'; 500218893Sdim 501218893Sdim CGEN_INSN_RX (insn) = xmalloc (sizeof (regex_t)); 502218893Sdim reg_err = regcomp ((regex_t *) CGEN_INSN_RX (insn), rxbuf, REG_NOSUB); 503218893Sdim 504218893Sdim if (reg_err == 0) 505218893Sdim return NULL; 506218893Sdim else 507218893Sdim { 508218893Sdim static char msg[80]; 509218893Sdim 510218893Sdim regerror (reg_err, (regex_t *) CGEN_INSN_RX (insn), msg, 80); 511218893Sdim regfree ((regex_t *) CGEN_INSN_RX (insn)); 512218893Sdim free (CGEN_INSN_RX (insn)); 513218893Sdim (CGEN_INSN_RX (insn)) = NULL; 514212904Sdim return msg; 515218893Sdim } 516212904Sdim} 517218893Sdim 518218893Sdim 519218893Sdim/* Default insn parser. 520218893Sdim 521218893Sdim The syntax string is scanned and operands are parsed and stored in FIELDS. 522218893Sdim Relocs are queued as we go via other callbacks. 523218893Sdim 524218893Sdim ??? Note that this is currently an all-or-nothing parser. If we fail to 525218893Sdim parse the instruction, we return 0 and the caller will start over from 526218893Sdim the beginning. Backtracking will be necessary in parsing subexpressions, 527218893Sdim but that can be handled there. Not handling backtracking here may get 528218893Sdim expensive in the case of the m68k. Deal with later. 529218893Sdim 530218893Sdim Returns NULL for success, an error message for failure. */ 531218893Sdim 532218893Sdimstatic const char * 533234353Sdimparse_insn_normal (CGEN_CPU_DESC cd, 534218893Sdim const CGEN_INSN *insn, 535218893Sdim const char **strp, 536218893Sdim CGEN_FIELDS *fields) 537218893Sdim{ 538218893Sdim /* ??? Runtime added insns not handled yet. */ 539218893Sdim const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn); 540234353Sdim const char *str = *strp; 541218893Sdim const char *errmsg; 542218893Sdim const char *p; 543218893Sdim const CGEN_SYNTAX_CHAR_TYPE * syn; 544218893Sdim#ifdef CGEN_MNEMONIC_OPERANDS 545218893Sdim /* FIXME: wip */ 546218893Sdim int past_opcode_p; 547218893Sdim#endif 548218893Sdim 549218893Sdim /* For now we assume the mnemonic is first (there are no leading operands). 550218893Sdim We can parse it without needing to set up operand parsing. 551218893Sdim GAS's input scrubber will ensure mnemonics are lowercase, but we may 552218893Sdim not be called from GAS. */ 553218893Sdim p = CGEN_INSN_MNEMONIC (insn); 554218893Sdim while (*p && TOLOWER (*p) == TOLOWER (*str)) 555218893Sdim ++p, ++str; 556218893Sdim 557218893Sdim if (* p) 558218893Sdim return _("unrecognized instruction"); 559218893Sdim 560218893Sdim#ifndef CGEN_MNEMONIC_OPERANDS 561218893Sdim if (* str && ! ISSPACE (* str)) 562218893Sdim return _("unrecognized instruction"); 563218893Sdim#endif 564218893Sdim 565218893Sdim CGEN_INIT_PARSE (cd); 566218893Sdim cgen_init_parse_operand (cd); 567218893Sdim#ifdef CGEN_MNEMONIC_OPERANDS 568218893Sdim past_opcode_p = 0; 569218893Sdim#endif 570218893Sdim 571218893Sdim /* We don't check for (*str != '\0') here because we want to parse 572218893Sdim any trailing fake arguments in the syntax string. */ 573218893Sdim syn = CGEN_SYNTAX_STRING (syntax); 574234353Sdim 575234353Sdim /* Mnemonics come first for now, ensure valid string. */ 576218893Sdim if (! CGEN_SYNTAX_MNEMONIC_P (* syn)) 577218893Sdim abort (); 578218893Sdim 579218893Sdim ++syn; 580218893Sdim 581218893Sdim while (* syn != 0) 582234353Sdim { 583218893Sdim /* Non operand chars must match exactly. */ 584218893Sdim if (CGEN_SYNTAX_CHAR_P (* syn)) 585218893Sdim { 586218893Sdim /* FIXME: While we allow for non-GAS callers above, we assume the 587218893Sdim first char after the mnemonic part is a space. */ 588218893Sdim /* FIXME: We also take inappropriate advantage of the fact that 589218893Sdim GAS's input scrubber will remove extraneous blanks. */ 590218893Sdim if (TOLOWER (*str) == TOLOWER (CGEN_SYNTAX_CHAR (* syn))) 591218893Sdim { 592218893Sdim#ifdef CGEN_MNEMONIC_OPERANDS 593218893Sdim if (CGEN_SYNTAX_CHAR(* syn) == ' ') 594212904Sdim past_opcode_p = 1; 595218893Sdim#endif 596212904Sdim ++ syn; 597218893Sdim ++ str; 598234353Sdim } 599218893Sdim else if (*str) 600218893Sdim { 601218893Sdim /* Syntax char didn't match. Can't be this insn. */ 602218893Sdim static char msg [80]; 603218893Sdim 604218893Sdim /* xgettext:c-format */ 605218893Sdim sprintf (msg, _("syntax error (expected char `%c', found `%c')"), 606218893Sdim CGEN_SYNTAX_CHAR(*syn), *str); 607221345Sdim return msg; 608221345Sdim } 609218893Sdim else 610212904Sdim { 611212904Sdim /* Ran out of input. */ 612212904Sdim static char msg [80]; 613218893Sdim 614218893Sdim /* xgettext:c-format */ 615218893Sdim sprintf (msg, _("syntax error (expected char `%c', found end of instruction)"), 616218893Sdim CGEN_SYNTAX_CHAR(*syn)); 617218893Sdim return msg; 618234353Sdim } 619218893Sdim continue; 620218893Sdim } 621218893Sdim 622218893Sdim /* We have an operand of some sort. */ 623218893Sdim errmsg = cd->parse_operand (cd, CGEN_SYNTAX_FIELD (*syn), 624199481Srdivacky &str, fields); 625218893Sdim if (errmsg) 626218893Sdim return errmsg; 627218893Sdim 628218893Sdim /* Done with this operand, continue with next one. */ 629218893Sdim ++ syn; 630218893Sdim } 631218893Sdim 632199481Srdivacky /* If we're at the end of the syntax string, we're done. */ 633218893Sdim if (* syn == 0) 634218893Sdim { 635218893Sdim /* FIXME: For the moment we assume a valid `str' can only contain 636218893Sdim blanks now. IE: We needn't try again with a longer version of 637218893Sdim the insn and it is assumed that longer versions of insns appear 638218893Sdim before shorter ones (eg: lsr r2,r3,1 vs lsr r2,r3). */ 639221345Sdim while (ISSPACE (* str)) 640221345Sdim ++ str; 641218893Sdim 642218893Sdim if (* str != '\0') 643218893Sdim return _("junk at end of line"); /* FIXME: would like to include `str' */ 644218893Sdim 645218893Sdim return NULL; 646218893Sdim } 647218893Sdim 648218893Sdim /* We couldn't parse it. */ 649218893Sdim return _("unrecognized instruction"); 650218893Sdim} 651218893Sdim 652218893Sdim/* Main entry point. 653218893Sdim This routine is called for each instruction to be assembled. 654218893Sdim STR points to the insn to be assembled. 655218893Sdim We assume all necessary tables have been initialized. 656218893Sdim The assembled instruction, less any fixups, is stored in BUF. 657218893Sdim Remember that if CGEN_INT_INSN_P then BUF is an int and thus the value 658218893Sdim still needs to be converted to target byte order, otherwise BUF is an array 659218893Sdim of bytes in target byte order. 660218893Sdim The result is a pointer to the insn's entry in the opcode table, 661218893Sdim or NULL if an error occured (an error message will have already been 662218893Sdim printed). 663218893Sdim 664218893Sdim Note that when processing (non-alias) macro-insns, 665218893Sdim this function recurses. 666218893Sdim 667218893Sdim ??? It's possible to make this cpu-independent. 668218893Sdim One would have to deal with a few minor things. 669218893Sdim At this point in time doing so would be more of a curiosity than useful 670218893Sdim [for example this file isn't _that_ big], but keeping the possibility in 671218893Sdim mind helps keep the design clean. */ 672218893Sdim 673218893Sdimconst CGEN_INSN * 674218893Sdimxc16x_cgen_assemble_insn (CGEN_CPU_DESC cd, 675218893Sdim const char *str, 676221345Sdim CGEN_FIELDS *fields, 677221345Sdim CGEN_INSN_BYTES_PTR buf, 678218893Sdim char **errmsg) 679218893Sdim{ 680218893Sdim const char *start; 681218893Sdim CGEN_INSN_LIST *ilist; 682218893Sdim const char *parse_errmsg = NULL; 683218893Sdim const char *insert_errmsg = NULL; 684218893Sdim int recognized_mnemonic = 0; 685218893Sdim 686218893Sdim /* Skip leading white space. */ 687218893Sdim while (ISSPACE (* str)) 688218893Sdim ++ str; 689218893Sdim 690212904Sdim /* The instructions are stored in hashed lists. 691218893Sdim Get the first in the list. */ 692221345Sdim ilist = CGEN_ASM_LOOKUP_INSN (cd, str); 693221345Sdim 694221345Sdim /* Keep looking until we find a match. */ 695221345Sdim start = str; 696221345Sdim for ( ; ilist != NULL ; ilist = CGEN_ASM_NEXT_INSN (ilist)) 697263508Sdim { 698221345Sdim const CGEN_INSN *insn = ilist->insn; 699263508Sdim recognized_mnemonic = 1; 700221345Sdim 701221345Sdim#ifdef CGEN_VALIDATE_INSN_SUPPORTED 702221345Sdim /* Not usually needed as unsupported opcodes 703221345Sdim shouldn't be in the hash lists. */ 704224145Sdim /* Is this insn supported by the selected cpu? */ 705221345Sdim if (! xc16x_cgen_insn_supported (cd, insn)) 706224145Sdim continue; 707224145Sdim#endif 708221345Sdim /* If the RELAXED attribute is set, this is an insn that shouldn't be 709263508Sdim chosen immediately. Instead, it is used during assembler/linker 710221345Sdim relaxation if possible. */ 711263508Sdim if (CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_RELAXED) != 0) 712221345Sdim continue; 713221345Sdim 714221345Sdim str = start; 715221345Sdim 716221345Sdim /* Skip this insn if str doesn't look right lexically. */ 717226633Sdim if (CGEN_INSN_RX (insn) != NULL && 718226633Sdim regexec ((regex_t *) CGEN_INSN_RX (insn), str, 0, NULL, 0) == REG_NOMATCH) 719221345Sdim continue; 720263508Sdim 721226633Sdim /* Allow parse/insert handlers to obtain length of insn. */ 722226633Sdim CGEN_FIELDS_BITSIZE (fields) = CGEN_INSN_BITSIZE (insn); 723263508Sdim 724226633Sdim parse_errmsg = CGEN_PARSE_FN (cd, insn) (cd, insn, & str, fields); 725226633Sdim if (parse_errmsg != NULL) 726226633Sdim continue; 727226633Sdim 728226633Sdim /* ??? 0 is passed for `pc'. */ 729226633Sdim insert_errmsg = CGEN_INSERT_FN (cd, insn) (cd, insn, fields, buf, 730226633Sdim (bfd_vma) 0); 731226633Sdim if (insert_errmsg != NULL) 732263508Sdim continue; 733263508Sdim 734221345Sdim /* It is up to the caller to actually output the insn and any 735221345Sdim queued relocs. */ 736263508Sdim return insn; 737221345Sdim } 738221345Sdim 739221345Sdim { 740221345Sdim static char errbuf[150]; 741221345Sdim#ifdef CGEN_VERBOSE_ASSEMBLER_ERRORS 742263508Sdim const char *tmp_errmsg; 743221345Sdim 744263508Sdim /* If requesting verbose error messages, use insert_errmsg. 745263508Sdim Failing that, use parse_errmsg. */ 746221345Sdim tmp_errmsg = (insert_errmsg ? insert_errmsg : 747221345Sdim parse_errmsg ? parse_errmsg : 748221345Sdim recognized_mnemonic ? 749263508Sdim _("unrecognized form of instruction") : 750221345Sdim _("unrecognized instruction")); 751221345Sdim 752221345Sdim if (strlen (start) > 50) 753224145Sdim /* xgettext:c-format */ 754221345Sdim sprintf (errbuf, "%s `%.50s...'", tmp_errmsg, start); 755224145Sdim else 756224145Sdim /* xgettext:c-format */ 757221345Sdim sprintf (errbuf, "%s `%.50s'", tmp_errmsg, start); 758221345Sdim#else 759221345Sdim if (strlen (start) > 50) 760263508Sdim /* xgettext:c-format */ 761221345Sdim sprintf (errbuf, _("bad instruction `%.50s...'"), start); 762221345Sdim else 763221345Sdim /* xgettext:c-format */ 764221345Sdim sprintf (errbuf, _("bad instruction `%.50s'"), start); 765221345Sdim#endif 766263508Sdim 767221345Sdim *errmsg = errbuf; 768263508Sdim return NULL; 769263508Sdim } 770221345Sdim} 771221345Sdim