123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356 |
- /* tc-xgate.c -- Assembler code for Freescale XGATE
- Copyright (C) 2010-2022 Free Software Foundation, Inc.
- Contributed by Sean Keys <skeys@ipdatasys.com>
- This file is part of GAS, the GNU Assembler.
- GAS is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3, or (at your option)
- any later version.
- GAS is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with GAS; see the file COPYING. If not, write to
- the Free Software Foundation, 51 Franklin Street - Fifth Floor,
- Boston, MA 02110-1301, USA. */
- #include "as.h"
- #include "safe-ctype.h"
- #include "subsegs.h"
- #include "opcode/xgate.h"
- #include "dwarf2dbg.h"
- #include "elf/xgate.h"
- const char comment_chars[] = ";!";
- const char line_comment_chars[] = "#*";
- const char line_separator_chars[] = "";
- const char EXP_CHARS[] = "eE";
- const char FLT_CHARS[] = "dD";
- /* Max opcodes per opcode handle. */
- #define MAX_OPCODES 0x05
- #define SIXTEENTH_BIT 0x8000
- #define N_BITS_IN_WORD 16
- #define MAX_NUM_OPERANDS 3
- /* #define STATE_CONDITIONAL_BRANCH (1) */
- #define STATE_PC_RELATIVE (2)
- #define REGISTER_P(ptr) (ptr == 'r')
- #define INCREMENT 01
- #define DECREMENT 02
- #define MAXREGISTER 07
- #define MINREGISTER 00
- #define OPTION_MMCU 'm'
- /* This macro has no side-effects. */
- #define ENCODE_RELAX(what,length) (((what) << 2) + (length))
- /* Each unique opcode name has a handle. That handle may
- contain pointers to opcodes with the same name but
- different address modes. */
- struct xgate_opcode_handle
- {
- int number_of_modes;
- char *name;
- struct xgate_opcode *opc0[MAX_OPCODES];
- };
- /* XGATE's registers all are 16-bit general purpose.
- They are numbered according to the specifications. */
- typedef enum register_id
- {
- REG_NONE = -1,
- REG_R0 = 0,
- REG_R1 = 1,
- REG_R2 = 2,
- REG_R3 = 3,
- REG_R4 = 4,
- REG_R5 = 5,
- REG_R6 = 6,
- REG_R7 = 7,
- REG_PC = 8,
- REG_CCR = 9
- } register_id;
- /* Operand Modifiers */
- typedef enum op_modifiers
- {
- MOD_NONE = -1,
- MOD_POSTINC = 1,
- MOD_PREDEC = 2,
- MOD_CONSTANT = 3,
- MOD_LOAD_HIGH = 4,
- MOD_LOAD_LOW = 5
- }op_modifiers;
- typedef struct s_operand
- {
- expressionS exp;
- register_id reg;
- op_modifiers mod;
- } s_operand;
- /* Forward declarations. */
- static inline char *skip_whitespace (char *);
- static void get_default_target (void);
- static char *extract_word (char *, char *, int);
- static struct xgate_opcode *xgate_find_match (struct xgate_opcode_handle *,
- int, s_operand [], unsigned int);
- static int cmp_opcode (struct xgate_opcode *, struct xgate_opcode *);
- static void xgate_print_table (void);
- static unsigned int xgate_get_operands (char *, s_operand []);
- static register_id reg_name_search (char *);
- static op_modifiers xgate_determine_modifiers (char **);
- static void xgate_scan_operands (struct xgate_opcode *opcode, s_operand []);
- static unsigned int xgate_parse_operand (struct xgate_opcode *, int *, int,
- char **, s_operand);
- static htab_t xgate_hash;
- /* Previous opcode. */
- static unsigned int prev = 0;
- static unsigned char fixup_required = 0;
- /* Used to enable clipping of 16 bit operands into 8 bit constraints. */
- static unsigned char autoHiLo = 0;
- static char oper_check;
- static char flag_print_insn_syntax = 0;
- static char flag_print_opcodes = 0;
- static int current_architecture;
- static const char *default_cpu;
- /* ELF flags to set in the output file header. */
- static int elf_flags = E_XGATE_F64;
- /* This table describes how you change sizes for the various types of variable
- size expressions. This version only supports two kinds. */
- /* The fields are:
- How far Forward this mode will reach.
- How far Backward this mode will reach.
- How many bytes this mode will add to the size of the frag.
- Which mode to go to if the offset won't fit in this one. */
- relax_typeS md_relax_table[] =
- {
- {1, 1, 0, 0}, /* First entries aren't used. */
- {1, 1, 0, 0}, /* For no good reason except. */
- {1, 1, 0, 0}, /* that the VAX doesn't either. */
- {1, 1, 0, 0},
- /* XGATE 9 and 10 bit pc rel todo complete and test */
- /*{(511), (-512), 0, ENCODE_RELAX (STATE_PC_RELATIVE, STATE_WORD)},
- {(1023), (-1024), 0, ENCODE_RELAX (STATE_PC_RELATIVE, STATE_WORD)}, */
- {0, 0, 0, 0}
- };
- /* This table describes all the machine specific pseudo-ops the assembler
- has to support. The fields are: pseudo-op name without dot function to
- call to execute this pseudo-op Integer arg to pass to the function. */
- const pseudo_typeS md_pseudo_table[] =
- {
- /* The following pseudo-ops are supported for MRI compatibility. */
- {0, 0, 0}
- };
- const char *md_shortopts = "m:";
- struct option md_longopts[] =
- {
- #define OPTION_PRINT_INSN_SYNTAX (OPTION_MD_BASE + 0)
- { "print-insn-syntax", no_argument, NULL, OPTION_PRINT_INSN_SYNTAX },
- #define OPTION_PRINT_OPCODES (OPTION_MD_BASE + 1)
- { "print-opcodes", no_argument, NULL, OPTION_PRINT_OPCODES },
- #define OPTION_GENERATE_EXAMPLE (OPTION_MD_BASE + 2)
- { "generate-example", no_argument, NULL, OPTION_GENERATE_EXAMPLE },
- #define OPTION_MSHORT (OPTION_MD_BASE + 3)
- { "mshort", no_argument, NULL, OPTION_MSHORT },
- #define OPTION_MLONG (OPTION_MD_BASE + 4)
- { "mlong", no_argument, NULL, OPTION_MLONG },
- #define OPTION_MSHORT_DOUBLE (OPTION_MD_BASE + 5)
- { "mshort-double", no_argument, NULL, OPTION_MSHORT_DOUBLE },
- #define OPTION_MLONG_DOUBLE (OPTION_MD_BASE + 6)
- { "mlong-double", no_argument, NULL, OPTION_MLONG_DOUBLE },
- { NULL, no_argument, NULL, 0 }
- };
- size_t md_longopts_size = sizeof (md_longopts);
- const char *
- md_atof (int type, char *litP, int *sizeP)
- {
- return ieee_md_atof (type, litP, sizeP, true);
- }
- int
- md_parse_option (int c, const char *arg)
- {
- switch (c)
- {
- case OPTION_MMCU:
- if (strcasecmp (arg, "v1") == 0)
- current_architecture = XGATE_V1;
- else if (strcasecmp (arg, "v2") == 0)
- current_architecture = XGATE_V2;
- else if (strcasecmp (arg, "v3") == 0)
- current_architecture = XGATE_V3;
- else
- as_bad (_("architecture variant invalid"));
- break;
- case OPTION_PRINT_INSN_SYNTAX:
- flag_print_insn_syntax = 1;
- break;
- case OPTION_PRINT_OPCODES:
- flag_print_opcodes = 1;
- break;
- case OPTION_GENERATE_EXAMPLE:
- flag_print_opcodes = 2;
- break;
- case OPTION_MSHORT:
- elf_flags &= ~E_XGATE_I32;
- break;
- case OPTION_MLONG:
- elf_flags |= E_XGATE_I32;
- break;
- case OPTION_MSHORT_DOUBLE:
- elf_flags &= ~E_XGATE_F64;
- break;
- case OPTION_MLONG_DOUBLE:
- elf_flags |= E_XGATE_F64;
- break;
- default:
- return 0;
- }
- return 1;
- }
- const char *
- xgate_arch_format (void)
- {
- get_default_target ();
- if (current_architecture & cpuxgate)
- return "elf32-xgate";
- return "error";
- }
- static void
- get_default_target (void)
- {
- const bfd_target *target;
- bfd abfd;
- if (current_architecture != 0)
- return;
- default_cpu = "unknown";
- target = bfd_find_target (0, &abfd);
- if (target && target->name)
- {
- if (strcmp (target->name, "elf32-xgate") == 0)
- {
- current_architecture = cpuxgate;
- default_cpu = "XGATE V1";
- return;
- }
- as_bad (_("Default target `%s' is not supported."), target->name);
- }
- }
- void
- md_begin (void)
- {
- struct xgate_opcode *xgate_opcode_ptr = NULL;
- struct xgate_opcode *xgate_op_table = NULL;
- struct xgate_opcode_handle *op_handles = 0;
- const char *prev_op_name = 0;
- int handle_enum = 0;
- int number_of_op_handles = 0;
- int i, j = 0;
- /* Create a local copy of our opcode table
- including an extra line for NULL termination. */
- xgate_op_table = XNEWVEC (struct xgate_opcode, xgate_num_opcodes);
- memset (xgate_op_table, 0,
- sizeof (struct xgate_opcode) * (xgate_num_opcodes));
- for (xgate_opcode_ptr = (struct xgate_opcode*) xgate_opcodes, i = 0;
- i < xgate_num_opcodes; i++)
- xgate_op_table[i] = xgate_opcode_ptr[i];
- qsort (xgate_op_table, xgate_num_opcodes, sizeof (struct xgate_opcode),
- (int (*)(const void *, const void *)) cmp_opcode);
- /* Calculate number of handles since this will be
- smaller than the raw number of opcodes in the table. */
- prev_op_name = "";
- for (xgate_opcode_ptr = xgate_op_table, i = 0; i < xgate_num_opcodes;
- xgate_opcode_ptr++, i++)
- {
- if (strcmp (prev_op_name, xgate_opcode_ptr->name))
- number_of_op_handles++;
- prev_op_name = xgate_opcode_ptr->name;
- }
- op_handles = XNEWVEC (struct xgate_opcode_handle, number_of_op_handles);
- /* Insert unique opcode names into hash table, aliasing duplicates. */
- xgate_hash = str_htab_create ();
- prev_op_name = "";
- for (xgate_opcode_ptr = xgate_op_table, i = 0, j = 0; i < xgate_num_opcodes;
- i++, xgate_opcode_ptr++)
- {
- if (!strcmp (prev_op_name, xgate_opcode_ptr->name))
- {
- handle_enum++;
- op_handles[j].opc0[handle_enum] = xgate_opcode_ptr;
- }
- else
- {
- handle_enum = 0;
- if (i)
- j++;
- op_handles[j].name = xgate_opcode_ptr->name;
- op_handles[j].opc0[0] = xgate_opcode_ptr;
- str_hash_insert (xgate_hash, op_handles[j].name, &op_handles[j], 0);
- }
- op_handles[j].number_of_modes = handle_enum;
- prev_op_name = op_handles[j].name;
- }
- if (flag_print_opcodes)
- {
- xgate_print_table ();
- exit (EXIT_SUCCESS);
- }
- }
- void
- xgate_init_after_args (void)
- {
- }
- void
- md_show_usage (FILE * stream)
- {
- get_default_target ();
- fprintf (stream,
- _("\
- Freescale XGATE co-processor options:\n\
- -mshort use 16-bit int ABI (default)\n\
- -mlong use 32-bit int ABI\n\
- -mshort-double use 32-bit double ABI\n\
- -mlong-double use 64-bit double ABI (default)\n\
- --mxgate specify the processor variant [default %s]\n\
- --print-insn-syntax print the syntax of instruction in case of error\n\
- --print-opcodes print the list of instructions with syntax\n\
- --generate-example generate an example of each instruction"),
- default_cpu);
- }
- enum bfd_architecture
- xgate_arch (void)
- {
- get_default_target ();
- return bfd_arch_xgate;
- }
- int
- xgate_mach (void)
- {
- return 0;
- }
- static void
- xgate_print_syntax (char *name)
- {
- int i;
- for (i = 0; i < xgate_num_opcodes; i++)
- {
- if (!strcmp (xgate_opcodes[i].name, name))
- {
- if (!strcmp (xgate_opcodes[i].constraints, XGATE_OP_IDR))
- printf ("\tFormat is %s\tRx, Rx, Rx+|-Rx|Rx\n",
- xgate_opcodes[i].name);
- if (!strcmp (xgate_opcodes[i].constraints, XGATE_OP_INH))
- printf ("\tFormat is %s\n", xgate_opcodes[i].name);
- if (!strcmp (xgate_opcodes[i].constraints, XGATE_OP_TRI))
- printf ("\tFormat is %s\tRx, Rx, Rx\n", xgate_opcodes[i].name);
- if (!strcmp (xgate_opcodes[i].constraints, XGATE_OP_DYA))
- printf ("\tFormat is %s\tRx, Rx\n", xgate_opcodes[i].name);
- if (!strcmp (xgate_opcodes[i].constraints, XGATE_OP_IMM3))
- printf ("\tFormat is %s\t<3-bit value>\n", xgate_opcodes[i].name);
- if (!strcmp (xgate_opcodes[i].constraints, XGATE_OP_IMM4))
- printf ("\tFormat is %s\t<4 -bit value>\n", xgate_opcodes[i].name);
- if (!strcmp (xgate_opcodes[i].constraints, XGATE_OP_IMM8))
- printf ("\tFormat is %s\tRx, <8-bit value>\n",
- xgate_opcodes[i].name);
- if (!strcmp (xgate_opcodes[i].constraints, XGATE_OP_IMM16))
- printf ("\tFormat is %s\tRx, <16-bit value>\n",
- xgate_opcodes[i].name);
- if (!strcmp (xgate_opcodes[i].constraints, XGATE_OP_MON_R_C))
- printf ("\tFormat is %s\tRx, CCR\n", xgate_opcodes[i].name);
- if (!strcmp (xgate_opcodes[i].constraints, XGATE_OP_MON_C_R))
- printf ("\tFormat is %s\tCCR, Rx\n", xgate_opcodes[i].name);
- if (!strcmp (xgate_opcodes[i].constraints, XGATE_OP_MON_R_P))
- printf ("\tFormat is %s\tRx, PC\n", xgate_opcodes[i].name);
- if (!strcmp (xgate_opcodes[i].constraints, XGATE_OP_IMM16mLDW))
- printf ("\tFormat is %s\tRx, <16-bit value>\n",
- xgate_opcodes[i].name);
- }
- }
- }
- static void
- xgate_print_table (void)
- {
- int i;
- for (i = 0; i < xgate_num_opcodes; i++)
- xgate_print_syntax (xgate_opcodes[i].name);
- return;
- }
- const char *
- xgate_listing_header (void)
- {
- if (current_architecture & cpuxgate)
- return "XGATE GAS ";
- return "ERROR MC9S12X GAS ";
- }
- symbolS *
- md_undefined_symbol (char *name ATTRIBUTE_UNUSED)
- {
- return NULL;
- }
- /* GAS will call this function for each section at the end of the assembly,
- to permit the CPU backend to adjust the alignment of a section. */
- valueT
- md_section_align (asection * seg, valueT addr)
- {
- int align = bfd_section_alignment (seg);
- return ((addr + (1 << align) - 1) & -(1 << align));
- }
- void
- md_assemble (char *input_line)
- {
- struct xgate_opcode *opcode = 0;
- struct xgate_opcode *macro_opcode = 0;
- struct xgate_opcode_handle *opcode_handle = 0;
- /* Caller expects it to be returned as it was passed. */
- char *saved_input_line = input_line;
- char op_name[9] = { 0 };
- unsigned int operandCount = 0;
- char *p = 0;
- s_operand new_operands[MAX_NUM_OPERANDS];
- fixup_required = 0;
- oper_check = 0; /* set error flags */
- input_line = extract_word (input_line, op_name, sizeof (op_name));
- /* Check to make sure we are not reading a bogus line. */
- if (!op_name[0])
- as_bad (_("opcode missing or not found on input line"));
- opcode_handle = (struct xgate_opcode_handle *) str_hash_find (xgate_hash,
- op_name);
- if (!opcode_handle)
- as_bad (_("opcode %s not found in opcode hash table"), op_name);
- else
- {
- /* Parse operands so we can find the proper opcode bin. */
- operandCount = xgate_get_operands (input_line, new_operands);
- opcode = xgate_find_match (opcode_handle, opcode_handle->number_of_modes,
- new_operands, operandCount);
- if (!opcode)
- {
- as_bad (_("matching operands to opcode"));
- xgate_print_syntax (opcode_handle->opc0[0]->name);
- }
- else if (opcode->size == 2)
- {
- /* Size is one word - assemble that native insn. */
- xgate_scan_operands (opcode, new_operands);
- }
- else
- {
- /* Insn is a simplified instruction - expand it out. */
- autoHiLo = 1;
- unsigned int i;
- /* skip past our ';' separator. */
- for (i = strlen (opcode->constraints), p = opcode->constraints; i > 0;
- i--, p++)
- {
- if (*p == ';')
- {
- p++;
- break;
- }
- }
- input_line = skip_whitespace (input_line);
- char *macro_inline = input_line;
- /* Loop though the macro's opcode list and apply operands to
- each real opcode. */
- for (i = 0; *p && i < (opcode->size / 2); i++)
- {
- /* Loop though macro operand list. */
- input_line = macro_inline; /* Rewind. */
- p = extract_word (p, op_name, 10);
- opcode_handle
- = (struct xgate_opcode_handle *) str_hash_find (xgate_hash,
- op_name);
- if (!opcode_handle)
- {
- as_bad (_(": processing macro, real opcode handle"
- " not found in hash"));
- break;
- }
- else
- {
- operandCount = xgate_get_operands (input_line, new_operands);
- macro_opcode = xgate_find_match (opcode_handle,
- opcode_handle->number_of_modes, new_operands,
- operandCount);
- xgate_scan_operands (macro_opcode, new_operands);
- }
- }
- }
- }
- autoHiLo = 0;
- input_line = saved_input_line;
- }
- /* Force truly undefined symbols to their maximum size, and generally set up
- the frag list to be relaxed. */
- int
- md_estimate_size_before_relax (fragS *fragp, asection *seg)
- {
- /* If symbol is undefined or located in a different section,
- select the largest supported relocation. */
- relax_substateT subtype;
- relax_substateT rlx_state[] = { 0, 2 };
- for (subtype = 0; subtype < ARRAY_SIZE (rlx_state); subtype += 2)
- {
- if (fragp->fr_subtype == rlx_state[subtype]
- && (!S_IS_DEFINED (fragp->fr_symbol)
- || seg != S_GET_SEGMENT (fragp->fr_symbol)))
- {
- fragp->fr_subtype = rlx_state[subtype + 1];
- break;
- }
- }
- if (fragp->fr_subtype >= ARRAY_SIZE (md_relax_table))
- abort ();
- return md_relax_table[fragp->fr_subtype].rlx_length;
- }
- /* Relocation, relaxation and frag conversions. */
- /* PC-relative offsets are relative to the start of the
- next instruction. That is, the address of the offset, plus its
- size, since the offset is always the last part of the insn. */
- long
- md_pcrel_from (fixS * fixP)
- {
- return fixP->fx_size + fixP->fx_where + fixP->fx_frag->fr_address;
- }
- /* If while processing a fixup, a reloc really needs to be created
- then it is done here. */
- arelent *
- tc_gen_reloc (asection * section ATTRIBUTE_UNUSED, fixS * fixp)
- {
- arelent * reloc;
- reloc = XNEW (arelent);
- reloc->sym_ptr_ptr = XNEW (asymbol *);
- *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
- reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
- if (fixp->fx_r_type == 0)
- reloc->howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_16);
- else
- reloc->howto = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type);
- if (reloc->howto == (reloc_howto_type *) NULL)
- {
- as_bad_where (fixp->fx_file, fixp->fx_line, _
- ("Relocation %d is not supported by object file format."),
- (int) fixp->fx_r_type);
- return NULL;
- }
- /* Since we use Rel instead of Rela, encode the vtable entry to be
- used in the relocation's section offset. */
- if (fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
- reloc->address = fixp->fx_offset;
- reloc->addend = 0;
- return reloc;
- }
- /* Patch the instruction with the resolved operand. Elf relocation
- info will also be generated to take care of linker/loader fixups.
- The XGATE addresses only 16-bit addresses.The BFD_RELOC_32 is necessary
- for the support of --gstabs. */
- void
- md_apply_fix (fixS * fixP, valueT * valP, segT seg ATTRIBUTE_UNUSED)
- {
- char *where;
- long value = *valP;
- int opcode = 0;
- ldiv_t result;
- /* If the fixup is done mark it done so no further symbol resolution
- will take place. */
- if (fixP->fx_addsy == (symbolS *) NULL)
- fixP->fx_done = 1;
- /* We don't actually support subtracting a symbol. */
- if (fixP->fx_subsy != (symbolS *) NULL)
- as_bad_subtract (fixP);
- where = fixP->fx_frag->fr_literal + fixP->fx_where;
- opcode = bfd_getl16 (where);
- int mask = 0;
- switch (fixP->fx_r_type)
- {
- case BFD_RELOC_XGATE_PCREL_9:
- if (value < -512 || value > 511)
- as_bad_where (fixP->fx_file, fixP->fx_line,
- _("Value %ld too large for 9-bit PC-relative branch."),
- value);
- result = ldiv (value, 2); /* from bytes to words */
- value = result.quot;
- if (result.rem)
- as_bad_where (fixP->fx_file, fixP->fx_line, _
- ("Value %ld not aligned by 2 for 9-bit"
- " PC-relative branch."), value);
- /* Clip into 8-bit field.
- FIXME I'm sure there is a more proper place for this. */
- mask = 0x1FF;
- value &= mask;
- number_to_chars_bigendian (where, (opcode | value), 2);
- break;
- case BFD_RELOC_XGATE_PCREL_10:
- if (value < -1024 || value > 1023)
- as_bad_where (fixP->fx_file, fixP->fx_line,
- _("Value %ld too large for 10-bit PC-relative branch."),
- value);
- result = ldiv (value, 2); /* from bytes to words */
- value = result.quot;
- if (result.rem)
- as_bad_where (fixP->fx_file, fixP->fx_line, _
- ("Value %ld not aligned by 2 for 10-bit"
- " PC-relative branch."), value);
- /* Clip into 9-bit field.
- FIXME I'm sure there is a more proper place for this. */
- mask = 0x3FF;
- value &= mask;
- number_to_chars_bigendian (where, (opcode | value), 2);
- break;
- case BFD_RELOC_XGATE_IMM8_HI:
- if (value < -65537 || value > 65535)
- as_bad_where (fixP->fx_file, fixP->fx_line,
- _("Value out of 16-bit range."));
- value >>= 8;
- value &= 0x00ff;
- bfd_putb16 ((bfd_vma) value | opcode, (void *) where);
- break;
- case BFD_RELOC_XGATE_24:
- case BFD_RELOC_XGATE_IMM8_LO:
- if (value < -65537 || value > 65535)
- as_bad_where (fixP->fx_file, fixP->fx_line,
- _("Value out of 16-bit range."));
- value &= 0x00ff;
- bfd_putb16 ((bfd_vma) value | opcode, (void *) where);
- break;
- case BFD_RELOC_XGATE_IMM3:
- if (value < 0 || value > 7)
- as_bad_where (fixP->fx_file, fixP->fx_line,
- _("Value out of 3-bit range."));
- value <<= 8; /* make big endian */
- number_to_chars_bigendian (where, (opcode | value), 2);
- break;
- case BFD_RELOC_XGATE_IMM4:
- if (value < 0 || value > 15)
- as_bad_where (fixP->fx_file, fixP->fx_line,
- _("Value out of 4-bit range."));
- value <<= 4; /* align the operand bits */
- number_to_chars_bigendian (where, (opcode | value), 2);
- break;
- case BFD_RELOC_XGATE_IMM5:
- if (value < 0 || value > 31)
- as_bad_where (fixP->fx_file, fixP->fx_line,
- _("Value out of 5-bit range."));
- value <<= 5; /* align the operand bits */
- number_to_chars_bigendian (where, (opcode | value), 2);
- break;
- case BFD_RELOC_8:
- ((bfd_byte *) where)[0] = (bfd_byte) value;
- break;
- case BFD_RELOC_32:
- bfd_putb32 ((bfd_vma) value, (unsigned char *) where);
- break;
- case BFD_RELOC_16:
- bfd_putb16 ((bfd_vma) value, (unsigned char *) where);
- break;
- default:
- as_fatal (_("Line %d: unknown relocation type: 0x%x."), fixP->fx_line,
- fixP->fx_r_type);
- break;
- }
- }
- /* See whether we need to force a relocation into the output file. */
- int
- tc_xgate_force_relocation (fixS * fixP)
- {
- if (fixP->fx_r_type == BFD_RELOC_XGATE_RL_GROUP)
- return 1;
- return generic_force_reloc (fixP);
- }
- /* Here we decide which fixups can be adjusted to make them relative
- to the beginning of the section instead of the symbol. Basically
- we need to make sure that the linker relaxation is done
- correctly, so in some cases we force the original symbol to be
- used. */
- int
- tc_xgate_fix_adjustable (fixS * fixP)
- {
- switch (fixP->fx_r_type)
- {
- /* For the linker relaxation to work correctly, these relocs
- need to be on the symbol itself. */
- case BFD_RELOC_16:
- case BFD_RELOC_XGATE_RL_JUMP:
- case BFD_RELOC_XGATE_RL_GROUP:
- case BFD_RELOC_VTABLE_INHERIT:
- case BFD_RELOC_VTABLE_ENTRY:
- case BFD_RELOC_32:
- return 0;
- default:
- return 1;
- }
- }
- void
- md_convert_frag (bfd * abfd ATTRIBUTE_UNUSED,
- asection * sec ATTRIBUTE_UNUSED,
- fragS * fragP ATTRIBUTE_UNUSED)
- {
- as_bad (("md_convert_frag not implemented yet"));
- abort ();
- }
- /* Set the ELF specific flags. */
- void
- xgate_elf_final_processing (void)
- {
- elf_flags |= EF_XGATE_MACH;
- elf_elfheader (stdoutput)->e_flags &= ~EF_XGATE_ABI;
- elf_elfheader (stdoutput)->e_flags |= elf_flags;
- }
- static inline char *
- skip_whitespace (char *s)
- {
- while (*s == ' ' || *s == '\t' || *s == '(' || *s == ')')
- s++;
- return s;
- }
- /* Extract a word (continuous alpha-numeric chars) from the input line. */
- static char *
- extract_word (char *from, char *to, int limit)
- {
- char *op_end;
- int size = 0;
- /* Drop leading whitespace. */
- from = skip_whitespace (from);
- *to = 0;
- /* Find the op code end. */
- for (op_end = from; *op_end != 0 && is_part_of_name (*op_end);)
- {
- to[size++] = *op_end++;
- if (size + 1 >= limit)
- break;
- }
- to[size] = 0;
- return op_end;
- }
- static char *
- xgate_new_instruction (int size)
- {
- char *f = frag_more (size);
- dwarf2_emit_insn (size);
- return f;
- }
- static unsigned short
- xgate_apply_operand (unsigned short new_mask,
- unsigned short *availiable_mask_bits,
- unsigned short mask,
- unsigned char n_bits)
- {
- unsigned short n_shifts;
- unsigned int n_drop_bits;
- /* Shift until you find an available operand bit "1" and record
- the number of shifts. */
- for (n_shifts = 0;
- !(*availiable_mask_bits & SIXTEENTH_BIT) && n_shifts < 16;
- n_shifts++)
- *availiable_mask_bits <<= 1;
- /* Shift for the number of bits your operand requires while bits
- are available. */
- for (n_drop_bits = n_bits;
- n_drop_bits && (*availiable_mask_bits & SIXTEENTH_BIT);
- --n_drop_bits)
- *availiable_mask_bits <<= 1;
- if (n_drop_bits)
- as_bad (_(":operand has too many bits"));
- *availiable_mask_bits >>= n_shifts + n_bits;
- if ((n_drop_bits == 0) && (*availiable_mask_bits == 0))
- {
- oper_check = 1; /* flag operand check as good */
- }
- new_mask <<= N_BITS_IN_WORD - (n_shifts + n_bits);
- mask |= new_mask;
- return mask;
- }
- /* Parse ordinary expression. */
- static char *
- xgate_parse_exp (char *s, expressionS * op)
- {
- input_line_pointer = s;
- expression (op);
- if (op->X_op == O_absent)
- as_bad (_("missing operand"));
- return input_line_pointer;
- }
- static int
- cmp_opcode (struct xgate_opcode *op1, struct xgate_opcode *op2)
- {
- return strcmp (op1->name, op2->name);
- }
- static struct xgate_opcode *
- xgate_find_match (struct xgate_opcode_handle *opcode_handle,
- int numberOfModes, s_operand oprs[], unsigned int operandCount)
- {
- int i;
- if (numberOfModes == 0)
- return opcode_handle->opc0[0];
- for (i = 0; i <= numberOfModes; i++)
- {
- switch (operandCount)
- {
- case 0:
- if (!strcmp (opcode_handle->opc0[i]->constraints, XGATE_OP_INH))
- return opcode_handle->opc0[i];
- break;
- case 1:
- if (oprs[0].reg >= REG_R0 && oprs[0].reg <= REG_R7)
- {
- if (!strcmp (opcode_handle->opc0[i]->constraints, XGATE_OP_MON))
- return opcode_handle->opc0[i];
- if (!strcmp (opcode_handle->opc0[i]->constraints, XGATE_OP_DYA_MON))
- return opcode_handle->opc0[i];
- }
- if (oprs[0].reg == REG_NONE)
- if (!strcmp (opcode_handle->opc0[i]->constraints, XGATE_OP_IMM3))
- return opcode_handle->opc0[i];
- break;
- case 2:
- if (oprs[0].reg >= REG_R0 && oprs[0].reg <= REG_R7)
- {
- if (oprs[1].reg >= REG_R0 && oprs[1].reg <= REG_R7)
- {
- if (!strcmp (opcode_handle->opc0[i]->constraints, XGATE_OP_DYA))
- return opcode_handle->opc0[i];
- }
- if (oprs[1].reg == REG_CCR)
- if (!strcmp (opcode_handle->opc0[i]->constraints,
- XGATE_OP_MON_R_C))
- return opcode_handle->opc0[i];
- if (oprs[1].reg == REG_PC)
- if (!strcmp (opcode_handle->opc0[i]->constraints,
- XGATE_OP_MON_R_P))
- return opcode_handle->opc0[i];
- if (oprs[1].reg == REG_NONE)
- if (!strcmp (opcode_handle->opc0[i]->constraints, XGATE_OP_IMM16)
- || !strcmp (opcode_handle->opc0[i]->constraints, XGATE_OP_IMM8)
- || !strcmp (opcode_handle->opc0[i]->constraints, XGATE_OP_IMM4)
- || !strcmp (opcode_handle->opc0[i]->constraints,
- XGATE_OP_IMM16mADD)
- || !strcmp (opcode_handle->opc0[i]->constraints,
- XGATE_OP_IMM16mAND)
- || !strcmp (opcode_handle->opc0[i]->constraints,
- XGATE_OP_IMM16mCPC)
- || !strcmp (opcode_handle->opc0[i]->constraints,
- XGATE_OP_IMM16mSUB)
- || !strcmp (opcode_handle->opc0[i]->constraints,
- XGATE_OP_IMM16mLDW))
- return opcode_handle->opc0[i];
- }
- if (oprs[0].reg == REG_CCR)
- if (!strcmp (opcode_handle->opc0[i]->constraints, XGATE_OP_MON_C_R))
- return opcode_handle->opc0[i];
- break;
- case 3:
- if (oprs[0].reg >= REG_R0 && oprs[0].reg <= REG_R7)
- {
- if (oprs[1].reg >= REG_R0 && oprs[1].reg <= REG_R7)
- {
- if (oprs[2].reg >= REG_R0 && oprs[2].reg <= REG_R7)
- {
- if (!strcmp (opcode_handle->opc0[i]->constraints,
- XGATE_OP_IDR)
- || !strcmp (opcode_handle->opc0[i]->constraints,
- XGATE_OP_TRI))
- return opcode_handle->opc0[i];
- }
- if (oprs[2].reg == REG_NONE)
- if (!strcmp (opcode_handle->opc0[i]->constraints,
- XGATE_OP_IDO5))
- return opcode_handle->opc0[i];
- }
- }
- break;
- default:
- as_bad (_("unknown operand count"));
- break;
- }
- }
- return NULL ;
- }
- /* Because we are dealing with two different core that view the system
- memory with different offsets, we must differentiate what core a
- symbol belongs to, in order for the linker to cross-link. */
- int
- xgate_frob_symbol (symbolS *sym)
- {
- asymbol *bfdsym;
- elf_symbol_type *elfsym;
- bfdsym = symbol_get_bfdsym (sym);
- elfsym = elf_symbol_from (bfdsym);
- gas_assert (elfsym);
- /* Mark the symbol as being *from XGATE */
- elfsym->internal_elf_sym.st_target_internal = 1;
- return 0;
- }
- static unsigned int
- xgate_get_operands (char *line, s_operand oprs[])
- {
- int num_operands;
- /* If there are no operands, then it must be inherent. */
- if (*line == 0 || *line == '\n' || *line == '\r')
- return 0;
- for (num_operands = 0; strlen (line) && (num_operands < MAX_NUM_OPERANDS);
- num_operands++)
- {
- line = skip_whitespace (line);
- if (*line == '#')
- line++;
- oprs[num_operands].mod = xgate_determine_modifiers (&line);
- if ((oprs[num_operands].reg = reg_name_search (line)) == REG_NONE)
- line = xgate_parse_exp (line, &oprs[num_operands].exp);
- /* skip to next operand */
- while (*line != 0)
- {
- if (*line == ',')
- {
- line++;
- break;
- }
- line++;
- }
- }
- if (num_operands > MAX_NUM_OPERANDS)
- return 0;
- return num_operands;
- }
- /* reg_name_search() finds the register number given its name.
- Returns the register number or REG_NONE on failure. */
- static register_id
- reg_name_search (char *name)
- {
- if (strncasecmp (name, "r0", 2) == 0)
- return REG_R0;
- if (strncasecmp (name, "r1", 2) == 0)
- return REG_R1;
- if (strncasecmp (name, "r2", 2) == 0)
- return REG_R2;
- if (strncasecmp (name, "r3", 2) == 0)
- return REG_R3;
- if (strncasecmp (name, "r4", 2) == 0)
- return REG_R4;
- if (strncasecmp (name, "r5", 2) == 0)
- return REG_R5;
- if (strncasecmp (name, "r6", 2) == 0)
- return REG_R6;
- if (strncasecmp (name, "r7", 2) == 0)
- return REG_R7;
- if (strncasecmp (name, "pc", 2) == 0)
- return REG_PC;
- if (strncasecmp (name, "ccr", 3) == 0)
- return REG_CCR;
- return REG_NONE;
- }
- /* Parse operand modifiers such as inc/dec/hi/low. */
- static op_modifiers
- xgate_determine_modifiers (char **line)
- {
- char *local_line = line[0];
- if (strncasecmp (local_line, "%hi", 3) == 0)
- {
- *line += 3;
- return MOD_LOAD_HIGH;
- }
- if (strncasecmp (local_line, "%lo", 3) == 0)
- {
- *line += 3;
- return MOD_LOAD_LOW;
- }
- if (*(local_line + 2) == '+')
- return MOD_POSTINC;
- if (strncasecmp (local_line, "-r", 2) == 0)
- {
- *line += 1;
- return MOD_PREDEC;
- }
- return MOD_NONE;
- }
- /* Parse instruction operands. */
- static void
- xgate_scan_operands (struct xgate_opcode *opcode, s_operand oprs[])
- {
- char *frag = xgate_new_instruction (opcode->size);
- int where = frag - frag_now->fr_literal;
- char *op = opcode->constraints;
- unsigned int bin = (int) opcode->bin_opcode;
- unsigned short oper_mask = 0;
- int operand_bit_length = 0;
- unsigned int operand = 0;
- char n_operand_bits = 0;
- char first_operand_equals_second = 0;
- int i = 0;
- char c = 0;
- /* Generate available operand bits mask. */
- for (i = 0; (c = opcode->format[i]); i++)
- {
- if (ISDIGIT (c) || (c == 's'))
- {
- oper_mask <<= 1;
- }
- else
- {
- oper_mask <<= 1;
- oper_mask += 1;
- n_operand_bits++;
- }
- }
- /* Parse first operand. */
- if (*op)
- {
- if (*op == '=')
- {
- first_operand_equals_second = 1;
- ++op;
- }
- operand = xgate_parse_operand (opcode, &operand_bit_length, where,
- &op, oprs[0]);
- ++op;
- bin = xgate_apply_operand (operand, &oper_mask, bin, operand_bit_length);
- if (first_operand_equals_second)
- bin = xgate_apply_operand (operand, &oper_mask, bin,
- operand_bit_length);
- /* Parse second operand. */
- if (*op)
- {
- if (*op == ',')
- ++op;
- if (first_operand_equals_second)
- {
- bin = xgate_apply_operand (operand, &oper_mask, bin,
- operand_bit_length);
- ++op;
- }
- else
- {
- operand = xgate_parse_operand (opcode, &operand_bit_length, where,
- &op, oprs[1]);
- bin = xgate_apply_operand (operand, &oper_mask, bin,
- operand_bit_length);
- ++op;
- }
- }
- /* Parse the third register. */
- if (*op)
- {
- if (*op == ',')
- ++op;
- operand = xgate_parse_operand (opcode, &operand_bit_length, where,
- &op, oprs[2]);
- bin = xgate_apply_operand (operand, &oper_mask, bin,
- operand_bit_length);
- }
- }
- if (opcode->size == 2 && fixup_required)
- {
- bfd_putl16 (bin, frag);
- }
- else if ( !strcmp (opcode->constraints, XGATE_OP_REL9)
- || !strcmp (opcode->constraints, XGATE_OP_REL10))
- {
- /* Write our data to a frag for further processing. */
- bfd_putl16 (opcode->bin_opcode, frag);
- }
- else
- {
- /* Apply operand mask(s)to bin opcode and write the output. */
- /* Since we are done write this frag in xgate BE format. */
- number_to_chars_bigendian (frag, bin, opcode->size);
- }
- prev = bin;
- return;
- }
- static unsigned int
- xgate_parse_operand (struct xgate_opcode *opcode,
- int *bit_width,
- int where,
- char **op_con,
- s_operand operand)
- {
- char *op_constraint = *op_con;
- unsigned int op_mask = 0;
- unsigned int pp_fix = 0;
- unsigned short max_size = 0;
- int i;
- *bit_width = 0;
- /* Reset. */
- switch (*op_constraint)
- {
- case '+': /* Indexed register operand +/- or plain r. */
- /* Default to neither inc or dec. */
- pp_fix = 0;
- *bit_width = 5;
- if (operand.reg == REG_NONE)
- as_bad (_(": expected register name r0-r7 ") );
- op_mask = operand.reg;
- if (operand.mod == MOD_POSTINC)
- pp_fix = INCREMENT;
- if (operand.mod == MOD_PREDEC)
- pp_fix = DECREMENT;
- op_mask <<= 2;
- op_mask |= pp_fix;
- break;
- case 'r': /* Register operand. */
- if (operand.reg == REG_NONE)
- as_bad (_(": expected register name r0-r7 "));
- *bit_width = 3;
- op_mask = operand.reg;
- break;
- case 'i': /* Immediate value or expression expected. */
- /* Advance the original format pointer. */
- (*op_con)++;
- op_constraint++;
- if (ISDIGIT (*op_constraint))
- *bit_width = (int) *op_constraint - '0';
- else if (*op_constraint == 'a')
- *bit_width = 0x0A;
- else if (*op_constraint == 'f')
- *bit_width = 0x0F;
- /* http://tigcc.ticalc.org/doc/gnuasm.html#SEC31 */
- if (operand.exp.X_op == O_constant)
- {
- op_mask = operand.exp.X_add_number;
- if (((opcode->name[strlen (opcode->name) - 1] == 'l') && autoHiLo)
- || operand.mod == MOD_LOAD_LOW)
- op_mask &= 0x00FF;
- else if (((opcode->name[strlen (opcode->name) - 1]) == 'h'
- && autoHiLo) || operand.mod == MOD_LOAD_HIGH)
- op_mask >>= 8;
- /* Make sure it fits. */
- for (i = *bit_width; i; i--)
- {
- max_size <<= 1;
- max_size += 1;
- }
- if (op_mask > max_size)
- as_bad (_(":operand value(%d) too big for constraint"), op_mask);
- }
- else
- {
- /* Should be BFD_RELOC_XGATE_IMM8_LO instead of BFD_RELOC_XGATE_24
- TODO fix. */
- fixup_required = 1;
- if (*op_constraint == '8')
- {
- if (((opcode->name[strlen (opcode->name) - 1] == 'l')
- && autoHiLo) || operand.mod == MOD_LOAD_LOW)
- fix_new_exp (frag_now, where, 2, &operand.exp, false,
- BFD_RELOC_XGATE_24);
- else if (((opcode->name[strlen (opcode->name) - 1]) == 'h'
- && autoHiLo) || operand.mod == MOD_LOAD_HIGH )
- fix_new_exp (frag_now, where, 2, &operand.exp, false,
- BFD_RELOC_XGATE_IMM8_HI);
- else
- as_bad (_("you must use a hi/lo directive or 16-bit macro "
- "to load a 16-bit value."));
- }
- else if (*op_constraint == '5')
- fix_new_exp (frag_now, where, 2, &operand.exp, false,
- BFD_RELOC_XGATE_IMM5);
- else if (*op_constraint == '4')
- fix_new_exp (frag_now, where, 2, &operand.exp, false,
- BFD_RELOC_XGATE_IMM4);
- else if (*op_constraint == '3')
- fix_new_exp (frag_now, where, 2, &operand.exp, false,
- BFD_RELOC_XGATE_IMM3);
- else
- as_bad (_(":unknown relocation constraint size"));
- }
- break;
- case 'c': /* CCR register expected. */
- *bit_width = 0;
- if (operand.reg != REG_CCR)
- as_bad (_(": expected register name ccr "));
- break;
- case 'p': /* PC register expected. */
- *bit_width = 0;
- if (operand.reg != REG_PC)
- as_bad (_(": expected register name pc "));
- break;
- case 'b': /* Branch expected. */
- (*op_con)++;
- op_constraint++;
- if (operand.exp.X_op != O_register)
- {
- if (*op_constraint == '9')
- fix_new_exp (frag_now, where, 2, &operand.exp, true,
- BFD_RELOC_XGATE_PCREL_9);
- else if (*op_constraint == 'a')
- fix_new_exp (frag_now, where, 2, &operand.exp, true,
- BFD_RELOC_XGATE_PCREL_10);
- }
- else
- as_fatal (_("Operand `%x' not recognized in fixup8."),
- operand.exp.X_op);
- break;
- case '?':
- break;
- default:
- as_bad (_("unknown constraint `%c'"), *op_constraint);
- break;
- }
- return op_mask;
- }
|