1214571Sdim/* tc-cr16.c -- Assembler code for the CR16 CPU core.
2214571Sdim   Copyright 2007 Free Software Foundation, Inc.
3214571Sdim
4214571Sdim   Contributed by M R Swami Reddy <MR.Swami.Reddy@nsc.com>
5214571Sdim
6214571Sdim   This file is part of GAS, the GNU Assembler.
7214571Sdim
8214571Sdim   GAS is free software; you can redistribute it and/or modify
9214571Sdim   it under the terms of the GNU General Public License as published by
10214571Sdim   the Free Software Foundation; either version 2, or (at your option)
11214571Sdim   any later version.
12214571Sdim
13214571Sdim   GAS is distributed in the hope that it will be useful,
14214571Sdim   but WITHOUT ANY WARRANTY; without even the implied warranty of
15214571Sdim   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16214571Sdim   GNU General Public License for more details.
17214571Sdim
18214571Sdim   You should have received a copy of the GNU General Public License
19214571Sdim   along with GAS; see the file COPYING.  If not, write to the
20214571Sdim   Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston,
21214571Sdim   MA 02110-1301, USA.  */
22214571Sdim
23214571Sdim#include "as.h"
24214571Sdim#include "safe-ctype.h"
25214571Sdim#include "dwarf2dbg.h"
26214571Sdim#include "opcode/cr16.h"
27214571Sdim#include "elf/cr16.h"
28214571Sdim
29214571Sdim
30214571Sdim/* Word is considered here as a 16-bit unsigned short int.  */
31214571Sdim#define WORD_SHIFT  16
32214571Sdim
33214571Sdim/* Register is 2-byte size.  */
34214571Sdim#define REG_SIZE   2
35214571Sdim
36214571Sdim/* Maximum size of a single instruction (in words).  */
37214571Sdim#define INSN_MAX_SIZE   3
38214571Sdim
39214571Sdim/* Maximum bits which may be set in a `mask16' operand.  */
40214571Sdim#define MAX_REGS_IN_MASK16  8
41214571Sdim
42214571Sdim/* Assign a number NUM, shifted by SHIFT bytes, into a location
43214571Sdim   pointed by index BYTE of array 'output_opcode'.  */
44214571Sdim#define CR16_PRINT(BYTE, NUM, SHIFT)   output_opcode[BYTE] |= (NUM << SHIFT)
45214571Sdim
46214571Sdim/* Operand errors.  */
47214571Sdimtypedef enum
48214571Sdim  {
49214571Sdim    OP_LEGAL = 0,       /* Legal operand.  */
50214571Sdim    OP_OUT_OF_RANGE,    /* Operand not within permitted range.  */
51214571Sdim    OP_NOT_EVEN         /* Operand is Odd number, should be even.  */
52214571Sdim  }
53214571Sdimop_err;
54214571Sdim
55214571Sdim/* Opcode mnemonics hash table.  */
56214571Sdimstatic struct hash_control *cr16_inst_hash;
57214571Sdim/* CR16 registers hash table.  */
58214571Sdimstatic struct hash_control *reg_hash;
59214571Sdim/* CR16 register pair hash table.  */
60214571Sdimstatic struct hash_control *regp_hash;
61214571Sdim/* CR16 processor registers hash table.  */
62214571Sdimstatic struct hash_control *preg_hash;
63214571Sdim/* CR16 processor registers 32 bit hash table.  */
64214571Sdimstatic struct hash_control *pregp_hash;
65214571Sdim/* Current instruction we're assembling.  */
66214571Sdimconst inst *instruction;
67214571Sdim
68214571Sdim
69214571Sdimstatic int code_label = 0;
70214571Sdim
71214571Sdim/* Global variables.  */
72214571Sdim
73214571Sdim/* Array to hold an instruction encoding.  */
74214571Sdimlong output_opcode[2];
75214571Sdim
76214571Sdim/* Nonzero means a relocatable symbol.  */
77214571Sdimint relocatable;
78214571Sdim
79214571Sdim/* A copy of the original instruction (used in error messages).  */
80214571Sdimchar ins_parse[MAX_INST_LEN];
81214571Sdim
82214571Sdim/* The current processed argument number.  */
83214571Sdimint cur_arg_num;
84214571Sdim
85214571Sdim/* Generic assembler global variables which must be defined by all targets.  */
86214571Sdim
87214571Sdim/* Characters which always start a comment.  */
88214571Sdimconst char comment_chars[] = "#";
89214571Sdim
90214571Sdim/* Characters which start a comment at the beginning of a line.  */
91214571Sdimconst char line_comment_chars[] = "#";
92214571Sdim
93214571Sdim/* This array holds machine specific line separator characters.  */
94214571Sdimconst char line_separator_chars[] = ";";
95214571Sdim
96214571Sdim/* Chars that can be used to separate mant from exp in floating point nums.  */
97214571Sdimconst char EXP_CHARS[] = "eE";
98214571Sdim
99214571Sdim/* Chars that mean this number is a floating point constant as in 0f12.456  */
100214571Sdimconst char FLT_CHARS[] = "f'";
101214571Sdim
102214571Sdim/* Target-specific multicharacter options, not const-declared at usage.  */
103214571Sdimconst char *md_shortopts = "";
104214571Sdimstruct option md_longopts[] =
105214571Sdim{
106214571Sdim  {NULL, no_argument, NULL, 0}
107214571Sdim};
108214571Sdimsize_t md_longopts_size = sizeof (md_longopts);
109214571Sdim
110214571Sdimstatic void
111214571Sdiml_cons (int nbytes)
112214571Sdim{
113214571Sdim  int c;
114214571Sdim  expressionS exp;
115214571Sdim
116214571Sdim#ifdef md_flush_pending_output
117214571Sdim    md_flush_pending_output ();
118214571Sdim#endif
119214571Sdim
120214571Sdim  if (is_it_end_of_statement ())
121214571Sdim    {
122214571Sdim      demand_empty_rest_of_line ();
123214571Sdim      return;
124214571Sdim    }
125214571Sdim
126214571Sdim#ifdef TC_ADDRESS_BYTES
127214571Sdim  if (nbytes == 0)
128214571Sdim    nbytes = TC_ADDRESS_BYTES ();
129214571Sdim#endif
130214571Sdim
131214571Sdim#ifdef md_cons_align
132214571Sdim  md_cons_align (nbytes);
133214571Sdim#endif
134214571Sdim
135214571Sdim  c = 0;
136214571Sdim  do
137214571Sdim    {
138214571Sdim      unsigned int bits_available = BITS_PER_CHAR * nbytes;
139214571Sdim      char *hold = input_line_pointer;
140214571Sdim
141214571Sdim      expression (&exp);
142214571Sdim
143214571Sdim      if (*input_line_pointer == ':')
144214571Sdim	{
145214571Sdim	  /* Bitfields.  */
146214571Sdim	  long value = 0;
147214571Sdim
148214571Sdim	  for (;;)
149214571Sdim	    {
150214571Sdim	      unsigned long width;
151214571Sdim
152214571Sdim	      if (*input_line_pointer != ':')
153214571Sdim		{
154214571Sdim		  input_line_pointer = hold;
155214571Sdim		  break;
156214571Sdim		}
157214571Sdim	      if (exp.X_op == O_absent)
158214571Sdim		{
159214571Sdim		  as_warn (_("using a bit field width of zero"));
160214571Sdim		  exp.X_add_number = 0;
161214571Sdim		  exp.X_op = O_constant;
162214571Sdim		}
163214571Sdim
164214571Sdim	      if (exp.X_op != O_constant)
165214571Sdim		{
166214571Sdim		  *input_line_pointer = '\0';
167214571Sdim		  as_bad (_("field width \"%s\" too complex for a bitfield"), hold);
168214571Sdim		  *input_line_pointer = ':';
169214571Sdim		  demand_empty_rest_of_line ();
170214571Sdim		  return;
171214571Sdim		}
172214571Sdim
173214571Sdim	      if ((width = exp.X_add_number) >
174214571Sdim		  (unsigned int)(BITS_PER_CHAR * nbytes))
175214571Sdim		{
176214571Sdim		  as_warn (_("field width %lu too big to fit in %d bytes: truncated to %d bits"), width, nbytes, (BITS_PER_CHAR * nbytes));
177214571Sdim		  width = BITS_PER_CHAR * nbytes;
178214571Sdim		}                   /* Too big.  */
179214571Sdim
180214571Sdim
181214571Sdim	      if (width > bits_available)
182214571Sdim		{
183214571Sdim		  /* FIXME-SOMEDAY: backing up and reparsing is wasteful.  */
184214571Sdim		  input_line_pointer = hold;
185214571Sdim		  exp.X_add_number = value;
186214571Sdim		  break;
187214571Sdim		}
188214571Sdim
189214571Sdim	      /* Skip ':'.  */
190214571Sdim	      hold = ++input_line_pointer;
191214571Sdim
192214571Sdim	      expression (&exp);
193214571Sdim	      if (exp.X_op != O_constant)
194214571Sdim		{
195214571Sdim		  char cache = *input_line_pointer;
196214571Sdim
197214571Sdim		  *input_line_pointer = '\0';
198214571Sdim		  as_bad (_("field value \"%s\" too complex for a bitfield"), hold);
199214571Sdim		  *input_line_pointer = cache;
200214571Sdim		  demand_empty_rest_of_line ();
201214571Sdim		  return;
202214571Sdim		}
203214571Sdim
204214571Sdim	      value |= ((~(-1 << width) & exp.X_add_number)
205214571Sdim			<< ((BITS_PER_CHAR * nbytes) - bits_available));
206214571Sdim
207214571Sdim	      if ((bits_available -= width) == 0
208214571Sdim		  || is_it_end_of_statement ()
209214571Sdim		  || *input_line_pointer != ',')
210214571Sdim		break;
211214571Sdim
212214571Sdim	      hold = ++input_line_pointer;
213214571Sdim	      expression (&exp);
214214571Sdim	    }
215214571Sdim
216214571Sdim	  exp.X_add_number = value;
217214571Sdim	  exp.X_op = O_constant;
218214571Sdim	  exp.X_unsigned = 1;
219214571Sdim	}
220214571Sdim
221214571Sdim      if ((*(input_line_pointer) == '@') && (*(input_line_pointer +1) == 'c'))
222214571Sdim	code_label = 1;
223214571Sdim      emit_expr (&exp, (unsigned int) nbytes);
224214571Sdim      ++c;
225214571Sdim      if ((*(input_line_pointer) == '@') && (*(input_line_pointer +1) == 'c'))
226214571Sdim	{
227214571Sdim	  input_line_pointer +=3;
228214571Sdim	  break;
229214571Sdim	}
230214571Sdim    }
231214571Sdim  while ((*input_line_pointer++ == ','));
232214571Sdim
233214571Sdim  /* Put terminator back into stream.  */
234214571Sdim  input_line_pointer--;
235214571Sdim
236214571Sdim  demand_empty_rest_of_line ();
237214571Sdim}
238214571Sdim
239214571Sdim
240214571Sdim/* This table describes all the machine specific pseudo-ops
241214571Sdim   the assembler has to support.  The fields are:
242214571Sdim   *** Pseudo-op name without dot.
243214571Sdim   *** Function to call to execute this pseudo-op.
244214571Sdim   *** Integer arg to pass to the function.  */
245214571Sdim
246214571Sdimconst pseudo_typeS md_pseudo_table[] =
247214571Sdim{
248214571Sdim  /* In CR16 machine, align is in bytes (not a ptwo boundary).  */
249214571Sdim  {"align", s_align_bytes, 0},
250214571Sdim  {"long", l_cons,  4 },
251214571Sdim  {0, 0, 0}
252214571Sdim};
253214571Sdim
254214571Sdim/* CR16 relaxation table.  */
255214571Sdimconst relax_typeS md_relax_table[] =
256214571Sdim{
257214571Sdim  /* bCC  */
258214571Sdim  {0xfa, -0x100, 2, 1},                 /*  8 */
259214571Sdim  {0xfffe, -0x10000, 4, 2},             /* 16 */
260214571Sdim  {0xfffffe, -0x1000000, 6, 0},         /* 24 */
261214571Sdim};
262214571Sdim
263214571Sdim/* Return the bit size for a given operand.  */
264214571Sdim
265214571Sdimstatic int
266214571Sdimget_opbits (operand_type op)
267214571Sdim{
268214571Sdim  if (op < MAX_OPRD)
269214571Sdim    return cr16_optab[op].bit_size;
270214571Sdim
271214571Sdim  return 0;
272214571Sdim}
273214571Sdim
274214571Sdim/* Return the argument type of a given operand.  */
275214571Sdim
276214571Sdimstatic argtype
277214571Sdimget_optype (operand_type op)
278214571Sdim{
279214571Sdim  if (op < MAX_OPRD)
280214571Sdim    return cr16_optab[op].arg_type;
281214571Sdim  else
282214571Sdim    return nullargs;
283214571Sdim}
284214571Sdim
285214571Sdim/* Return the flags of a given operand.  */
286214571Sdim
287214571Sdimstatic int
288214571Sdimget_opflags (operand_type op)
289214571Sdim{
290214571Sdim  if (op < MAX_OPRD)
291214571Sdim    return cr16_optab[op].flags;
292214571Sdim
293214571Sdim  return 0;
294214571Sdim}
295214571Sdim
296214571Sdim/* Get the cc code.  */
297214571Sdim
298214571Sdimstatic int
299214571Sdimget_cc (char *cc_name)
300214571Sdim{
301214571Sdim   unsigned int i;
302214571Sdim
303214571Sdim   for (i = 0; i < cr16_num_cc; i++)
304214571Sdim     if (strcmp (cc_name, cr16_b_cond_tab[i]) == 0)
305214571Sdim       return i;
306214571Sdim
307214571Sdim   return -1;
308214571Sdim}
309214571Sdim
310214571Sdim/* Get the core processor register 'reg_name'.  */
311214571Sdim
312214571Sdimstatic reg
313214571Sdimget_register (char *reg_name)
314214571Sdim{
315214571Sdim  const reg_entry *reg;
316214571Sdim
317214571Sdim  reg = (const reg_entry *) hash_find (reg_hash, reg_name);
318214571Sdim
319214571Sdim  if (reg != NULL)
320214571Sdim    return reg->value.reg_val;
321214571Sdim
322214571Sdim  return nullregister;
323214571Sdim}
324214571Sdim/* Get the core processor register-pair 'reg_name'.  */
325214571Sdim
326214571Sdimstatic reg
327214571Sdimget_register_pair (char *reg_name)
328214571Sdim{
329214571Sdim  const reg_entry *reg;
330214571Sdim  char tmp_rp[16]="\0";
331214571Sdim
332214571Sdim  /* Add '(' and ')' to the reg pair, if its not present.  */
333214571Sdim  if (reg_name[0] != '(')
334214571Sdim    {
335214571Sdim      tmp_rp[0] = '(';
336214571Sdim      strcat (tmp_rp, reg_name);
337214571Sdim      strcat (tmp_rp,")");
338214571Sdim      reg = (const reg_entry *) hash_find (regp_hash, tmp_rp);
339214571Sdim    }
340214571Sdim  else
341214571Sdim    reg = (const reg_entry *) hash_find (regp_hash, reg_name);
342214571Sdim
343214571Sdim  if (reg != NULL)
344214571Sdim    return reg->value.reg_val;
345214571Sdim
346214571Sdim  return nullregister;
347214571Sdim}
348214571Sdim
349214571Sdim/* Get the index register 'reg_name'.  */
350214571Sdim
351214571Sdimstatic reg
352214571Sdimget_index_register (char *reg_name)
353214571Sdim{
354214571Sdim  const reg_entry *reg;
355214571Sdim
356214571Sdim  reg = (const reg_entry *) hash_find (reg_hash, reg_name);
357214571Sdim
358214571Sdim  if ((reg != NULL)
359214571Sdim      && ((reg->value.reg_val == 12) || (reg->value.reg_val == 13)))
360214571Sdim    return reg->value.reg_val;
361214571Sdim
362214571Sdim  return nullregister;
363214571Sdim}
364214571Sdim/* Get the core processor index register-pair 'reg_name'.  */
365214571Sdim
366214571Sdimstatic reg
367214571Sdimget_index_register_pair (char *reg_name)
368214571Sdim{
369214571Sdim  const reg_entry *reg;
370214571Sdim
371214571Sdim  reg = (const reg_entry *) hash_find (regp_hash, reg_name);
372214571Sdim
373214571Sdim  if (reg != NULL)
374214571Sdim    {
375214571Sdim      if ((reg->value.reg_val != 1) || (reg->value.reg_val != 7)
376214571Sdim	  || (reg->value.reg_val != 9) || (reg->value.reg_val > 10))
377214571Sdim	return reg->value.reg_val;
378214571Sdim
379214571Sdim      as_bad (_("Unknown register pair - index relative mode: `%d'"), reg->value.reg_val);
380214571Sdim    }
381214571Sdim
382214571Sdim  return nullregister;
383214571Sdim}
384214571Sdim
385214571Sdim/* Get the processor register 'preg_name'.  */
386214571Sdim
387214571Sdimstatic preg
388214571Sdimget_pregister (char *preg_name)
389214571Sdim{
390214571Sdim  const reg_entry *preg;
391214571Sdim
392214571Sdim  preg = (const reg_entry *) hash_find (preg_hash, preg_name);
393214571Sdim
394214571Sdim  if (preg != NULL)
395214571Sdim    return preg->value.preg_val;
396214571Sdim
397214571Sdim  return nullpregister;
398214571Sdim}
399214571Sdim
400214571Sdim/* Get the processor register 'preg_name 32 bit'.  */
401214571Sdim
402214571Sdimstatic preg
403214571Sdimget_pregisterp (char *preg_name)
404214571Sdim{
405214571Sdim  const reg_entry *preg;
406214571Sdim
407214571Sdim  preg = (const reg_entry *) hash_find (pregp_hash, preg_name);
408214571Sdim
409214571Sdim  if (preg != NULL)
410214571Sdim    return preg->value.preg_val;
411214571Sdim
412214571Sdim  return nullpregister;
413214571Sdim}
414214571Sdim
415214571Sdim
416214571Sdim/* Round up a section size to the appropriate boundary.  */
417214571Sdim
418214571SdimvalueT
419214571Sdimmd_section_align (segT seg, valueT val)
420214571Sdim{
421214571Sdim  /* Round .text section to a multiple of 2.  */
422214571Sdim  if (seg == text_section)
423214571Sdim    return (val + 1) & ~1;
424214571Sdim  return val;
425214571Sdim}
426214571Sdim
427214571Sdim/* Parse an operand that is machine-specific (remove '*').  */
428214571Sdim
429214571Sdimvoid
430214571Sdimmd_operand (expressionS * exp)
431214571Sdim{
432214571Sdim  char c = *input_line_pointer;
433214571Sdim
434214571Sdim  switch (c)
435214571Sdim    {
436214571Sdim    case '*':
437214571Sdim      input_line_pointer++;
438214571Sdim      expression (exp);
439214571Sdim      break;
440214571Sdim    default:
441214571Sdim      break;
442214571Sdim    }
443214571Sdim}
444214571Sdim
445214571Sdim/* Reset global variables before parsing a new instruction.  */
446214571Sdim
447214571Sdimstatic void
448214571Sdimreset_vars (char *op)
449214571Sdim{
450214571Sdim  cur_arg_num = relocatable = 0;
451214571Sdim  memset (& output_opcode, '\0', sizeof (output_opcode));
452214571Sdim
453214571Sdim  /* Save a copy of the original OP (used in error messages).  */
454214571Sdim  strncpy (ins_parse, op, sizeof ins_parse - 1);
455214571Sdim  ins_parse [sizeof ins_parse - 1] = 0;
456214571Sdim}
457214571Sdim
458214571Sdim/* This macro decides whether a particular reloc is an entry in a
459214571Sdim   switch table.  It is used when relaxing, because the linker needs
460214571Sdim   to know about all such entries so that it can adjust them if
461214571Sdim   necessary.  */
462214571Sdim
463214571Sdim#define SWITCH_TABLE(fix)                                  \
464214571Sdim  (   (fix)->fx_addsy != NULL                              \
465214571Sdim   && (fix)->fx_subsy != NULL                              \
466214571Sdim   && S_GET_SEGMENT ((fix)->fx_addsy) ==                   \
467214571Sdim      S_GET_SEGMENT ((fix)->fx_subsy)                      \
468214571Sdim   && S_GET_SEGMENT (fix->fx_addsy) != undefined_section   \
469214571Sdim   && (   (fix)->fx_r_type == BFD_RELOC_CR16_NUM8          \
470214571Sdim       || (fix)->fx_r_type == BFD_RELOC_CR16_NUM16         \
471214571Sdim       || (fix)->fx_r_type == BFD_RELOC_CR16_NUM32         \
472214571Sdim       || (fix)->fx_r_type == BFD_RELOC_CR16_NUM32a))
473214571Sdim
474214571Sdim/* See whether we need to force a relocation into the output file.
475214571Sdim   This is used to force out switch and PC relative relocations when
476214571Sdim   relaxing.  */
477214571Sdim
478214571Sdimint
479214571Sdimcr16_force_relocation (fixS *fix)
480214571Sdim{
481214571Sdim  /* REVISIT: Check if the "SWITCH_TABLE (fix)" should be added
482214571Sdim     if (generic_force_reloc (fix) || SWITCH_TABLE (fix))  */
483214571Sdim  if (generic_force_reloc (fix))
484214571Sdim    return 1;
485214571Sdim
486214571Sdim  return 0;
487214571Sdim}
488214571Sdim
489214571Sdim/* Record a fixup for a cons expression.  */
490214571Sdim
491214571Sdimvoid
492214571Sdimcr16_cons_fix_new (fragS *frag, int offset, int len, expressionS *exp)
493214571Sdim{
494214571Sdim  int rtype;
495214571Sdim  switch (len)
496214571Sdim    {
497214571Sdim    default: rtype = BFD_RELOC_NONE; break;
498214571Sdim    case 1: rtype = BFD_RELOC_CR16_NUM8 ; break;
499214571Sdim    case 2: rtype = BFD_RELOC_CR16_NUM16; break;
500214571Sdim    case 4:
501214571Sdim      if (code_label)
502214571Sdim	{
503214571Sdim	  rtype = BFD_RELOC_CR16_NUM32a;
504214571Sdim	  code_label = 0;
505214571Sdim	}
506214571Sdim      else
507214571Sdim	rtype = BFD_RELOC_CR16_NUM32;
508214571Sdim      break;
509214571Sdim    }
510214571Sdim
511214571Sdim  fix_new_exp (frag, offset, len, exp, 0, rtype);
512214571Sdim}
513214571Sdim
514214571Sdim/* Generate a relocation entry for a fixup.  */
515214571Sdim
516214571Sdimarelent *
517214571Sdimtc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS * fixP)
518214571Sdim{
519214571Sdim  arelent * reloc;
520214571Sdim
521214571Sdim  reloc = xmalloc (sizeof (arelent));
522214571Sdim  reloc->sym_ptr_ptr  = xmalloc (sizeof (asymbol *));
523214571Sdim  *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixP->fx_addsy);
524214571Sdim  reloc->address = fixP->fx_frag->fr_address + fixP->fx_where;
525214571Sdim  reloc->addend = fixP->fx_offset;
526214571Sdim
527214571Sdim  if (fixP->fx_subsy != NULL)
528214571Sdim    {
529214571Sdim      if (SWITCH_TABLE (fixP))
530214571Sdim        {
531214571Sdim          /* Keep the current difference in the addend.  */
532214571Sdim          reloc->addend = (S_GET_VALUE (fixP->fx_addsy)
533214571Sdim                           - S_GET_VALUE (fixP->fx_subsy) + fixP->fx_offset);
534214571Sdim
535214571Sdim          switch (fixP->fx_r_type)
536214571Sdim            {
537214571Sdim	    case BFD_RELOC_CR16_NUM8:
538214571Sdim	      fixP->fx_r_type = BFD_RELOC_CR16_NUM8;
539214571Sdim	      break;
540214571Sdim	    case BFD_RELOC_CR16_NUM16:
541214571Sdim	      fixP->fx_r_type = BFD_RELOC_CR16_NUM16;
542214571Sdim	      break;
543214571Sdim	    case BFD_RELOC_CR16_NUM32:
544214571Sdim	      fixP->fx_r_type = BFD_RELOC_CR16_NUM32;
545214571Sdim	      break;
546214571Sdim	    case BFD_RELOC_CR16_NUM32a:
547214571Sdim	      fixP->fx_r_type = BFD_RELOC_CR16_NUM32a;
548214571Sdim	      break;
549214571Sdim	    default:
550214571Sdim	      abort ();
551214571Sdim	      break;
552214571Sdim            }
553214571Sdim        }
554214571Sdim      else
555214571Sdim        {
556214571Sdim          /* We only resolve difference expressions in the same section.  */
557214571Sdim          as_bad_where (fixP->fx_file, fixP->fx_line,
558214571Sdim                        _("can't resolve `%s' {%s section} - `%s' {%s section}"),
559214571Sdim                        fixP->fx_addsy ? S_GET_NAME (fixP->fx_addsy) : "0",
560214571Sdim                        segment_name (fixP->fx_addsy
561214571Sdim                                      ? S_GET_SEGMENT (fixP->fx_addsy)
562214571Sdim                                      : absolute_section),
563214571Sdim                        S_GET_NAME (fixP->fx_subsy),
564214571Sdim                        segment_name (S_GET_SEGMENT (fixP->fx_addsy)));
565214571Sdim        }
566214571Sdim    }
567214571Sdim
568214571Sdim  assert ((int) fixP->fx_r_type > 0);
569214571Sdim  reloc->howto = bfd_reloc_type_lookup (stdoutput, fixP->fx_r_type);
570214571Sdim
571214571Sdim  if (reloc->howto == NULL)
572214571Sdim    {
573214571Sdim      as_bad_where (fixP->fx_file, fixP->fx_line,
574214571Sdim                    _("internal error: reloc %d (`%s') not supported by object file format"),
575214571Sdim                    fixP->fx_r_type,
576214571Sdim                    bfd_get_reloc_code_name (fixP->fx_r_type));
577214571Sdim      return NULL;
578214571Sdim    }
579214571Sdim  assert (!fixP->fx_pcrel == !reloc->howto->pc_relative);
580214571Sdim
581214571Sdim  return reloc;
582214571Sdim}
583214571Sdim
584214571Sdim/* Prepare machine-dependent frags for relaxation.  */
585214571Sdim
586214571Sdimint
587214571Sdimmd_estimate_size_before_relax (fragS *fragp, asection *seg)
588214571Sdim{
589214571Sdim  /* If symbol is undefined or located in a different section,
590214571Sdim     select the largest supported relocation.  */
591214571Sdim  relax_substateT subtype;
592214571Sdim  relax_substateT rlx_state[] = {0, 2};
593214571Sdim
594214571Sdim  for (subtype = 0; subtype < ARRAY_SIZE (rlx_state); subtype += 2)
595214571Sdim    {
596214571Sdim      if (fragp->fr_subtype == rlx_state[subtype]
597214571Sdim          && (!S_IS_DEFINED (fragp->fr_symbol)
598214571Sdim              || seg != S_GET_SEGMENT (fragp->fr_symbol)))
599214571Sdim        {
600214571Sdim          fragp->fr_subtype = rlx_state[subtype + 1];
601214571Sdim          break;
602214571Sdim        }
603214571Sdim    }
604214571Sdim
605214571Sdim  if (fragp->fr_subtype >= ARRAY_SIZE (md_relax_table))
606214571Sdim    abort ();
607214571Sdim
608214571Sdim  return md_relax_table[fragp->fr_subtype].rlx_length;
609214571Sdim}
610214571Sdim
611214571Sdimvoid
612214571Sdimmd_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, asection *sec, fragS *fragP)
613214571Sdim{
614214571Sdim  /* 'opcode' points to the start of the instruction, whether
615214571Sdim     we need to change the instruction's fixed encoding.  */
616214571Sdim  bfd_reloc_code_real_type reloc = BFD_RELOC_NONE;
617214571Sdim
618214571Sdim  subseg_change (sec, 0);
619214571Sdim
620214571Sdim  fix_new (fragP, fragP->fr_fix,
621214571Sdim           bfd_get_reloc_size (bfd_reloc_type_lookup (stdoutput, reloc)),
622214571Sdim           fragP->fr_symbol, fragP->fr_offset, 1, reloc);
623214571Sdim  fragP->fr_var = 0;
624214571Sdim  fragP->fr_fix += md_relax_table[fragP->fr_subtype].rlx_length;
625214571Sdim}
626214571Sdim
627214571Sdim/* Process machine-dependent command line options.  Called once for
628214571Sdim   each option on the command line that the machine-independent part of
629214571Sdim   GAS does not understand.  */
630214571Sdim
631214571Sdimint
632214571Sdimmd_parse_option (int c ATTRIBUTE_UNUSED, char *arg ATTRIBUTE_UNUSED)
633214571Sdim{
634214571Sdim  return 0;
635214571Sdim}
636214571Sdim
637214571Sdim/* Machine-dependent usage-output.  */
638214571Sdim
639214571Sdimvoid
640214571Sdimmd_show_usage (FILE *stream ATTRIBUTE_UNUSED)
641214571Sdim{
642214571Sdim  return;
643214571Sdim}
644214571Sdim
645214571Sdim/* Turn a string in input_line_pointer into a floating point constant
646214571Sdim   of type TYPE, and store the appropriate bytes in *LITP.  The number
647214571Sdim   of LITTLENUMS emitted is stored in *SIZEP.  An error message is
648214571Sdim   returned, or NULL on OK.  */
649214571Sdim
650214571Sdimchar *
651214571Sdimmd_atof (int type, char *litP, int *sizeP)
652214571Sdim{
653214571Sdim  int prec;
654214571Sdim  int i;
655214571Sdim  LITTLENUM_TYPE words[4];
656214571Sdim  char *t;
657214571Sdim
658214571Sdim  switch (type)
659214571Sdim    {
660214571Sdim      case 'f':
661214571Sdim        prec = 2;
662214571Sdim        break;
663214571Sdim
664214571Sdim      case 'd':
665214571Sdim        prec = 4;
666214571Sdim        break;
667214571Sdim
668214571Sdim      default:
669214571Sdim        *sizeP = 0;
670214571Sdim        return _("bad call to md_atof");
671214571Sdim    }
672214571Sdim
673214571Sdim  t = atof_ieee (input_line_pointer, type, words);
674214571Sdim  if (t)
675214571Sdim    input_line_pointer = t;
676214571Sdim
677214571Sdim  *sizeP = prec * 2;
678214571Sdim
679214571Sdim  if (! target_big_endian)
680214571Sdim    {
681214571Sdim      for (i = prec - 1; i >= 0; i--)
682214571Sdim        {
683214571Sdim          md_number_to_chars (litP, (valueT) words[i], 2);
684214571Sdim          litP += 2;
685214571Sdim        }
686214571Sdim    }
687214571Sdim  else
688214571Sdim    {
689214571Sdim      for (i = 0; i < prec; i++)
690214571Sdim        {
691214571Sdim          md_number_to_chars (litP, (valueT) words[i], 2);
692214571Sdim          litP += 2;
693214571Sdim        }
694214571Sdim    }
695214571Sdim
696214571Sdim  return NULL;
697214571Sdim}
698214571Sdim
699214571Sdim/* Apply a fixS (fixup of an instruction or data that we didn't have
700214571Sdim   enough info to complete immediately) to the data in a frag.
701214571Sdim   Since linkrelax is nonzero and TC_LINKRELAX_FIXUP is defined to disable
702214571Sdim   relaxation of debug sections, this function is called only when
703214571Sdim   fixuping relocations of debug sections.  */
704214571Sdim
705214571Sdimvoid
706214571Sdimmd_apply_fix (fixS *fixP, valueT *valP, segT seg)
707214571Sdim{
708214571Sdim  valueT val = * valP;
709214571Sdim  char *buf = fixP->fx_frag->fr_literal + fixP->fx_where;
710214571Sdim  fixP->fx_offset = 0;
711214571Sdim
712214571Sdim  switch (fixP->fx_r_type)
713214571Sdim    {
714214571Sdim      case BFD_RELOC_CR16_NUM8:
715214571Sdim        bfd_put_8 (stdoutput, (unsigned char) val, buf);
716214571Sdim        break;
717214571Sdim      case BFD_RELOC_CR16_NUM16:
718214571Sdim        bfd_put_16 (stdoutput, val, buf);
719214571Sdim        break;
720214571Sdim      case BFD_RELOC_CR16_NUM32:
721214571Sdim        bfd_put_32 (stdoutput, val, buf);
722214571Sdim        break;
723214571Sdim      case BFD_RELOC_CR16_NUM32a:
724214571Sdim        bfd_put_32 (stdoutput, val, buf);
725214571Sdim        break;
726214571Sdim      default:
727214571Sdim        /* We shouldn't ever get here because linkrelax is nonzero.  */
728214571Sdim        abort ();
729214571Sdim        break;
730214571Sdim    }
731214571Sdim
732214571Sdim  fixP->fx_done = 0;
733214571Sdim
734214571Sdim  if (fixP->fx_addsy == NULL
735214571Sdim      && fixP->fx_pcrel == 0)
736214571Sdim    fixP->fx_done = 1;
737214571Sdim
738214571Sdim  if (fixP->fx_pcrel == 1
739214571Sdim      && fixP->fx_addsy != NULL
740214571Sdim      && S_GET_SEGMENT (fixP->fx_addsy) == seg)
741214571Sdim    fixP->fx_done = 1;
742214571Sdim}
743214571Sdim
744214571Sdim/* The location from which a PC relative jump should be calculated,
745214571Sdim   given a PC relative reloc.  */
746214571Sdim
747214571Sdimlong
748214571Sdimmd_pcrel_from (fixS *fixp)
749214571Sdim{
750214571Sdim  return fixp->fx_frag->fr_address + fixp->fx_where;
751214571Sdim}
752214571Sdim
753214571Sdimstatic void
754214571Sdiminitialise_reg_hash_table (struct hash_control ** hash_table,
755214571Sdim			   const reg_entry * register_table,
756214571Sdim			   const unsigned int num_entries)
757214571Sdim{
758214571Sdim  const reg_entry * reg;
759214571Sdim  const char *hashret;
760214571Sdim
761214571Sdim  if ((* hash_table = hash_new ()) == NULL)
762214571Sdim    as_fatal (_("Virtual memory exhausted"));
763214571Sdim
764214571Sdim  for (reg = register_table;
765214571Sdim       reg < (register_table + num_entries);
766214571Sdim       reg++)
767214571Sdim    {
768214571Sdim      hashret = hash_insert (* hash_table, reg->name, (char *) reg);
769214571Sdim      if (hashret)
770214571Sdim	as_fatal (_("Internal Error:  Can't hash %s: %s"),
771214571Sdim		  reg->name, hashret);
772214571Sdim    }
773214571Sdim}
774214571Sdim
775214571Sdim/* This function is called once, at assembler startup time.  This should
776214571Sdim   set up all the tables, etc that the MD part of the assembler needs.  */
777214571Sdim
778214571Sdimvoid
779214571Sdimmd_begin (void)
780214571Sdim{
781214571Sdim  int i = 0;
782214571Sdim
783214571Sdim  /* Set up a hash table for the instructions.  */
784214571Sdim  if ((cr16_inst_hash = hash_new ()) == NULL)
785214571Sdim    as_fatal (_("Virtual memory exhausted"));
786214571Sdim
787214571Sdim  while (cr16_instruction[i].mnemonic != NULL)
788214571Sdim    {
789214571Sdim      const char *hashret;
790214571Sdim      const char *mnemonic = cr16_instruction[i].mnemonic;
791214571Sdim
792214571Sdim      hashret = hash_insert (cr16_inst_hash, mnemonic,
793214571Sdim			     (char *)(cr16_instruction + i));
794214571Sdim
795214571Sdim      if (hashret != NULL && *hashret != '\0')
796214571Sdim        as_fatal (_("Can't hash `%s': %s\n"), cr16_instruction[i].mnemonic,
797214571Sdim                  *hashret == 0 ? _("(unknown reason)") : hashret);
798214571Sdim
799214571Sdim      /* Insert unique names into hash table.  The CR16 instruction set
800214571Sdim         has many identical opcode names that have different opcodes based
801214571Sdim         on the operands.  This hash table then provides a quick index to
802214571Sdim         the first opcode with a particular name in the opcode table.  */
803214571Sdim      do
804214571Sdim        {
805214571Sdim          ++i;
806214571Sdim        }
807214571Sdim      while (cr16_instruction[i].mnemonic != NULL
808214571Sdim             && streq (cr16_instruction[i].mnemonic, mnemonic));
809214571Sdim    }
810214571Sdim
811214571Sdim  /* Initialize reg_hash hash table.  */
812214571Sdim  initialise_reg_hash_table (& reg_hash, cr16_regtab, NUMREGS);
813214571Sdim  /* Initialize regp_hash hash table.  */
814214571Sdim  initialise_reg_hash_table (& regp_hash, cr16_regptab, NUMREGPS);
815214571Sdim  /* Initialize preg_hash hash table.  */
816214571Sdim  initialise_reg_hash_table (& preg_hash, cr16_pregtab, NUMPREGS);
817214571Sdim  /* Initialize pregp_hash hash table.  */
818214571Sdim  initialise_reg_hash_table (& pregp_hash, cr16_pregptab, NUMPREGPS);
819214571Sdim
820214571Sdim  /*  Set linkrelax here to avoid fixups in most sections.  */
821214571Sdim  linkrelax = 1;
822214571Sdim}
823214571Sdim
824214571Sdim/* Process constants (immediate/absolute)
825214571Sdim   and labels (jump targets/Memory locations).  */
826214571Sdim
827214571Sdimstatic void
828214571Sdimprocess_label_constant (char *str, ins * cr16_ins)
829214571Sdim{
830214571Sdim  char *saved_input_line_pointer;
831214571Sdim  int symbol_with_at = 0;
832214571Sdim  int symbol_with_s = 0;
833214571Sdim  int symbol_with_m = 0;
834214571Sdim  int symbol_with_l = 0;
835214571Sdim  argument *cur_arg = cr16_ins->arg + cur_arg_num;  /* Current argument.  */
836214571Sdim
837214571Sdim  saved_input_line_pointer = input_line_pointer;
838214571Sdim  input_line_pointer = str;
839214571Sdim
840214571Sdim  expression (&cr16_ins->exp);
841214571Sdim
842214571Sdim  switch (cr16_ins->exp.X_op)
843214571Sdim    {
844214571Sdim    case O_big:
845214571Sdim    case O_absent:
846214571Sdim      /* Missing or bad expr becomes absolute 0.  */
847214571Sdim      as_bad (_("missing or invalid displacement expression `%s' taken as 0"),
848214571Sdim	      str);
849214571Sdim      cr16_ins->exp.X_op = O_constant;
850214571Sdim      cr16_ins->exp.X_add_number = 0;
851214571Sdim      cr16_ins->exp.X_add_symbol = NULL;
852214571Sdim      cr16_ins->exp.X_op_symbol = NULL;
853214571Sdim      /* Fall through.  */
854214571Sdim
855214571Sdim    case O_constant:
856214571Sdim      cur_arg->X_op = O_constant;
857214571Sdim      cur_arg->constant = cr16_ins->exp.X_add_number;
858214571Sdim      break;
859214571Sdim
860214571Sdim    case O_symbol:
861214571Sdim    case O_subtract:
862214571Sdim    case O_add:
863214571Sdim      cur_arg->X_op = O_symbol;
864214571Sdim      cr16_ins->rtype = BFD_RELOC_NONE;
865214571Sdim      relocatable = 1;
866214571Sdim
867214571Sdim      if (strneq (input_line_pointer, "@c", 2))
868214571Sdim	symbol_with_at = 1;
869214571Sdim
870214571Sdim      if (strneq (input_line_pointer, "@l", 2)
871214571Sdim	  || strneq (input_line_pointer, ":l", 2))
872214571Sdim	symbol_with_l = 1;
873214571Sdim
874214571Sdim      if (strneq (input_line_pointer, "@m", 2)
875214571Sdim	  || strneq (input_line_pointer, ":m", 2))
876214571Sdim	symbol_with_m = 1;
877214571Sdim
878214571Sdim      if (strneq (input_line_pointer, "@s", 2)
879214571Sdim	  || strneq (input_line_pointer, ":s", 2))
880214571Sdim	symbol_with_s = 1;
881214571Sdim
882214571Sdim      switch (cur_arg->type)
883214571Sdim        {
884214571Sdim	case arg_cr:
885214571Sdim	  if (IS_INSN_TYPE (LD_STOR_INS) || IS_INSN_TYPE (CSTBIT_INS))
886214571Sdim	    {
887214571Sdim	      if (cur_arg->size == 20)
888214571Sdim		cr16_ins->rtype = BFD_RELOC_CR16_REGREL20;
889214571Sdim	      else
890214571Sdim		cr16_ins->rtype = BFD_RELOC_CR16_REGREL20a;
891214571Sdim	    }
892214571Sdim	  break;
893214571Sdim
894214571Sdim	case arg_crp:
895214571Sdim	  if (IS_INSN_TYPE (LD_STOR_INS) || IS_INSN_TYPE (CSTBIT_INS))
896214571Sdim	    switch (instruction->size)
897214571Sdim	      {
898214571Sdim	      case 1:
899214571Sdim		switch (cur_arg->size)
900214571Sdim		  {
901214571Sdim		  case 0:
902214571Sdim		    cr16_ins->rtype = BFD_RELOC_CR16_REGREL0;
903214571Sdim		    break;
904214571Sdim		  case 4:
905214571Sdim		    if (IS_INSN_MNEMONIC ("loadb") || IS_INSN_MNEMONIC ("storb"))
906214571Sdim		      cr16_ins->rtype = BFD_RELOC_CR16_REGREL4;
907214571Sdim		    else
908214571Sdim		      cr16_ins->rtype = BFD_RELOC_CR16_REGREL4a;
909214571Sdim		    break;
910214571Sdim		  default: break;
911214571Sdim		  }
912214571Sdim		break;
913214571Sdim	      case 2:
914214571Sdim		cr16_ins->rtype = BFD_RELOC_CR16_REGREL16;
915214571Sdim		break;
916214571Sdim	      case 3:
917214571Sdim		if (cur_arg->size == 20)
918214571Sdim		  cr16_ins->rtype = BFD_RELOC_CR16_REGREL20;
919214571Sdim		else
920214571Sdim		  cr16_ins->rtype = BFD_RELOC_CR16_REGREL20a;
921214571Sdim		break;
922214571Sdim	      default:
923214571Sdim		break;
924214571Sdim	      }
925214571Sdim	  break;
926214571Sdim
927214571Sdim	case arg_idxr:
928214571Sdim	  if (IS_INSN_TYPE (LD_STOR_INS) || IS_INSN_TYPE (CSTBIT_INS))
929214571Sdim	    cr16_ins->rtype = BFD_RELOC_CR16_REGREL20;
930214571Sdim	  break;
931214571Sdim
932214571Sdim	case arg_idxrp:
933214571Sdim	  if (IS_INSN_TYPE (LD_STOR_INS) || IS_INSN_TYPE (CSTBIT_INS))
934214571Sdim	    switch (instruction->size)
935214571Sdim	      {
936214571Sdim	      case 1: cr16_ins->rtype = BFD_RELOC_CR16_REGREL0; break;
937214571Sdim	      case 2: cr16_ins->rtype = BFD_RELOC_CR16_REGREL14; break;
938214571Sdim	      case 3: cr16_ins->rtype = BFD_RELOC_CR16_REGREL20; break;
939214571Sdim	      default: break;
940214571Sdim	      }
941214571Sdim	  break;
942214571Sdim
943214571Sdim	case arg_c:
944214571Sdim	  if (IS_INSN_MNEMONIC ("bal"))
945214571Sdim	    cr16_ins->rtype = BFD_RELOC_CR16_DISP24;
946214571Sdim	  else if (IS_INSN_TYPE (BRANCH_INS))
947214571Sdim	    {
948214571Sdim	      if (symbol_with_s)
949214571Sdim		cr16_ins->rtype = BFD_RELOC_CR16_DISP8;
950214571Sdim	      else if (symbol_with_m)
951214571Sdim		cr16_ins->rtype = BFD_RELOC_CR16_DISP16;
952214571Sdim	      else
953214571Sdim		cr16_ins->rtype = BFD_RELOC_CR16_DISP24;
954214571Sdim	    }
955214571Sdim	  else if (IS_INSN_TYPE (STOR_IMM_INS) || IS_INSN_TYPE (LD_STOR_INS)
956214571Sdim		   || IS_INSN_TYPE (CSTBIT_INS))
957214571Sdim	    {
958214571Sdim	      if (symbol_with_s)
959214571Sdim		as_bad (_("operand %d: illegal use expression: `%s`"), cur_arg_num + 1, str);
960214571Sdim	      if (symbol_with_m)
961214571Sdim		cr16_ins->rtype = BFD_RELOC_CR16_ABS20;
962214571Sdim	      else /* Default to (symbol_with_l) */
963214571Sdim		cr16_ins->rtype = BFD_RELOC_CR16_ABS24;
964214571Sdim	    }
965214571Sdim	  else if (IS_INSN_TYPE (BRANCH_NEQ_INS))
966214571Sdim	    cr16_ins->rtype = BFD_RELOC_CR16_DISP4;
967214571Sdim          break;
968214571Sdim
969214571Sdim        case arg_ic:
970214571Sdim          if (IS_INSN_TYPE (ARITH_INS))
971214571Sdim            {
972214571Sdim              if (symbol_with_s)
973214571Sdim                cr16_ins->rtype = BFD_RELOC_CR16_IMM4;
974214571Sdim              else if (symbol_with_m)
975214571Sdim                cr16_ins->rtype = BFD_RELOC_CR16_IMM20;
976214571Sdim              else if (symbol_with_at)
977214571Sdim                cr16_ins->rtype = BFD_RELOC_CR16_IMM32a;
978214571Sdim              else /* Default to (symbol_with_l) */
979214571Sdim                cr16_ins->rtype = BFD_RELOC_CR16_IMM32;
980214571Sdim            }
981214571Sdim          else if (IS_INSN_TYPE (ARITH_BYTE_INS))
982214571Sdim	    {
983214571Sdim	      cr16_ins->rtype = BFD_RELOC_CR16_IMM16;
984214571Sdim	    }
985214571Sdim          break;
986214571Sdim        default:
987214571Sdim          break;
988214571Sdim	}
989214571Sdim      break;
990214571Sdim
991214571Sdim    default:
992214571Sdim      cur_arg->X_op = cr16_ins->exp.X_op;
993214571Sdim      break;
994214571Sdim    }
995214571Sdim
996214571Sdim  input_line_pointer = saved_input_line_pointer;
997214571Sdim  return;
998214571Sdim}
999214571Sdim
1000214571Sdim/* Retrieve the opcode image of a given register.
1001214571Sdim   If the register is illegal for the current instruction,
1002214571Sdim   issue an error.  */
1003214571Sdim
1004214571Sdimstatic int
1005214571Sdimgetreg_image (reg r)
1006214571Sdim{
1007214571Sdim  const reg_entry *reg;
1008214571Sdim  char *reg_name;
1009214571Sdim  int is_procreg = 0; /* Nonzero means argument should be processor reg.  */
1010214571Sdim
1011214571Sdim  /* Check whether the register is in registers table.  */
1012214571Sdim  if (r < MAX_REG)
1013214571Sdim    reg = cr16_regtab + r;
1014214571Sdim  else /* Register not found.  */
1015214571Sdim    {
1016214571Sdim      as_bad (_("Unknown register: `%d'"), r);
1017214571Sdim      return 0;
1018214571Sdim    }
1019214571Sdim
1020214571Sdim  reg_name = reg->name;
1021214571Sdim
1022214571Sdim/* Issue a error message when register is illegal.  */
1023214571Sdim#define IMAGE_ERR \
1024214571Sdim  as_bad (_("Illegal register (`%s') in Instruction: `%s'"), \
1025214571Sdim            reg_name, ins_parse);                            \
1026214571Sdim  break;
1027214571Sdim
1028214571Sdim  switch (reg->type)
1029214571Sdim    {
1030214571Sdim    case CR16_R_REGTYPE:
1031214571Sdim      if (! is_procreg)
1032214571Sdim	return reg->image;
1033214571Sdim      else
1034214571Sdim	IMAGE_ERR;
1035214571Sdim
1036214571Sdim    case CR16_P_REGTYPE:
1037214571Sdim      return reg->image;
1038214571Sdim      break;
1039214571Sdim
1040214571Sdim    default:
1041214571Sdim      IMAGE_ERR;
1042214571Sdim    }
1043214571Sdim
1044214571Sdim  return 0;
1045214571Sdim}
1046214571Sdim
1047214571Sdim/* Parsing different types of operands
1048214571Sdim   -> constants             Immediate/Absolute/Relative numbers
1049214571Sdim   -> Labels                Relocatable symbols
1050214571Sdim   -> (reg pair base)       Register pair base
1051214571Sdim   -> (rbase)               Register base
1052214571Sdim   -> disp(rbase)           Register relative
1053214571Sdim   -> [rinx]disp(reg pair)  Register index with reg pair mode
1054214571Sdim   -> disp(rbase,ridx,scl)  Register index mode.  */
1055214571Sdim
1056214571Sdimstatic void
1057214571Sdimset_operand (char *operand, ins * cr16_ins)
1058214571Sdim{
1059214571Sdim  char *operandS; /* Pointer to start of sub-opearand.  */
1060214571Sdim  char *operandE; /* Pointer to end of sub-opearand.  */
1061214571Sdim
1062214571Sdim  argument *cur_arg = &cr16_ins->arg[cur_arg_num]; /* Current argument.  */
1063214571Sdim
1064214571Sdim  /* Initialize pointers.  */
1065214571Sdim  operandS = operandE = operand;
1066214571Sdim
1067214571Sdim  switch (cur_arg->type)
1068214571Sdim    {
1069214571Sdim    case arg_ic:    /* Case $0x18.  */
1070214571Sdim      operandS++;
1071214571Sdim    case arg_c:     /* Case 0x18.  */
1072214571Sdim      /* Set constant.  */
1073214571Sdim      process_label_constant (operandS, cr16_ins);
1074214571Sdim
1075214571Sdim      if (cur_arg->type != arg_ic)
1076214571Sdim        cur_arg->type = arg_c;
1077214571Sdim      break;
1078214571Sdim
1079214571Sdim    case arg_icr:   /* Case $0x18(r1).  */
1080214571Sdim      operandS++;
1081214571Sdim    case arg_cr:    /* Case 0x18(r1).   */
1082214571Sdim      /* Set displacement constant.  */
1083214571Sdim      while (*operandE != '(')
1084214571Sdim        operandE++;
1085214571Sdim      *operandE = '\0';
1086214571Sdim      process_label_constant (operandS, cr16_ins);
1087214571Sdim      operandS = operandE;
1088214571Sdim    case arg_rbase: /* Case (r1) or (r1,r0).  */
1089214571Sdim      operandS++;
1090214571Sdim      /* Set register base.  */
1091214571Sdim      while (*operandE != ')')
1092214571Sdim        operandE++;
1093214571Sdim      *operandE = '\0';
1094214571Sdim      if ((cur_arg->r = get_register (operandS)) == nullregister)
1095214571Sdim         as_bad (_("Illegal register `%s' in Instruction `%s'"),
1096214571Sdim              operandS, ins_parse);
1097214571Sdim
1098214571Sdim      /* set the arg->rp, if reg is "r12" or "r13" or "14" or "15" */
1099214571Sdim      if ((cur_arg->type != arg_rbase)
1100214571Sdim	  && ((getreg_image (cur_arg->r) == 12)
1101214571Sdim	      || (getreg_image (cur_arg->r) == 13)
1102214571Sdim	      || (getreg_image (cur_arg->r) == 14)
1103214571Sdim	      || (getreg_image (cur_arg->r) == 15)))
1104214571Sdim         {
1105214571Sdim           cur_arg->type = arg_crp;
1106214571Sdim           cur_arg->rp = cur_arg->r;
1107214571Sdim         }
1108214571Sdim      break;
1109214571Sdim
1110214571Sdim    case arg_crp:    /* Case 0x18(r1,r0).   */
1111214571Sdim      /* Set displacement constant.  */
1112214571Sdim      while (*operandE != '(')
1113214571Sdim        operandE++;
1114214571Sdim      *operandE = '\0';
1115214571Sdim      process_label_constant (operandS, cr16_ins);
1116214571Sdim      operandS = operandE;
1117214571Sdim      operandS++;
1118214571Sdim      /* Set register pair base.  */
1119214571Sdim      while (*operandE != ')')
1120214571Sdim        operandE++;
1121214571Sdim      *operandE = '\0';
1122214571Sdim      if ((cur_arg->rp = get_register_pair (operandS)) == nullregister)
1123214571Sdim         as_bad (_("Illegal register pair `%s' in Instruction `%s'"),
1124214571Sdim              operandS, ins_parse);
1125214571Sdim      break;
1126214571Sdim
1127214571Sdim    case arg_idxr:
1128214571Sdim      /* Set register pair base.  */
1129214571Sdim      if ((strchr (operandS,'(') != NULL))
1130214571Sdim        {
1131214571Sdim         while ((*operandE != '(') && (! ISSPACE (*operandE)))
1132214571Sdim           operandE++;
1133214571Sdim         if ((cur_arg->rp = get_index_register_pair (operandE)) == nullregister)
1134214571Sdim              as_bad (_("Illegal register pair `%s' in Instruction `%s'"),
1135214571Sdim                            operandS, ins_parse);
1136214571Sdim         *operandE++ = '\0';
1137214571Sdim         cur_arg->type = arg_idxrp;
1138214571Sdim        }
1139214571Sdim      else
1140214571Sdim	cur_arg->rp = -1;
1141214571Sdim
1142214571Sdim       operandE = operandS;
1143214571Sdim      /* Set displacement constant.  */
1144214571Sdim      while (*operandE != ']')
1145214571Sdim        operandE++;
1146214571Sdim      process_label_constant (++operandE, cr16_ins);
1147214571Sdim      *operandE++ = '\0';
1148214571Sdim      operandE = operandS;
1149214571Sdim
1150214571Sdim      /* Set index register .  */
1151214571Sdim      operandS = strchr (operandE,'[');
1152214571Sdim      if (operandS != NULL)
1153214571Sdim        { /* Eliminate '[', detach from rest of operand.  */
1154214571Sdim          *operandS++ = '\0';
1155214571Sdim
1156214571Sdim          operandE = strchr (operandS, ']');
1157214571Sdim
1158214571Sdim          if (operandE == NULL)
1159214571Sdim            as_bad (_("unmatched '['"));
1160214571Sdim          else
1161214571Sdim            { /* Eliminate ']' and make sure it was the last thing
1162214571Sdim                 in the string.  */
1163214571Sdim              *operandE = '\0';
1164214571Sdim              if (*(operandE + 1) != '\0')
1165214571Sdim                as_bad (_("garbage after index spec ignored"));
1166214571Sdim            }
1167214571Sdim        }
1168214571Sdim
1169214571Sdim      if ((cur_arg->i_r = get_index_register (operandS)) == nullregister)
1170214571Sdim        as_bad (_("Illegal register `%s' in Instruction `%s'"),
1171214571Sdim                operandS, ins_parse);
1172214571Sdim      *operandE = '\0';
1173214571Sdim      *operandS = '\0';
1174214571Sdim      break;
1175214571Sdim
1176214571Sdim    default:
1177214571Sdim      break;
1178214571Sdim    }
1179214571Sdim}
1180214571Sdim
1181214571Sdim/* Parse a single operand.
1182214571Sdim   operand - Current operand to parse.
1183214571Sdim   cr16_ins - Current assembled instruction.  */
1184214571Sdim
1185214571Sdimstatic void
1186214571Sdimparse_operand (char *operand, ins * cr16_ins)
1187214571Sdim{
1188214571Sdim  int ret_val;
1189214571Sdim  argument *cur_arg = cr16_ins->arg + cur_arg_num; /* Current argument.  */
1190214571Sdim
1191214571Sdim  /* Initialize the type to NULL before parsing.  */
1192214571Sdim  cur_arg->type = nullargs;
1193214571Sdim
1194214571Sdim  /* Check whether this is a condition code .  */
1195214571Sdim  if ((IS_INSN_MNEMONIC ("b")) && ((ret_val = get_cc (operand)) != -1))
1196214571Sdim    {
1197214571Sdim      cur_arg->type = arg_cc;
1198214571Sdim      cur_arg->cc = ret_val;
1199214571Sdim      cur_arg->X_op = O_register;
1200214571Sdim      return;
1201214571Sdim    }
1202214571Sdim
1203214571Sdim  /* Check whether this is a general processor register.  */
1204214571Sdim  if ((ret_val = get_register (operand)) != nullregister)
1205214571Sdim    {
1206214571Sdim      cur_arg->type = arg_r;
1207214571Sdim      cur_arg->r = ret_val;
1208214571Sdim      cur_arg->X_op = 0;
1209214571Sdim      return;
1210214571Sdim    }
1211214571Sdim
1212214571Sdim  /* Check whether this is a general processor register pair.  */
1213214571Sdim  if ((operand[0] == '(')
1214214571Sdim      && ((ret_val = get_register_pair (operand)) != nullregister))
1215214571Sdim    {
1216214571Sdim      cur_arg->type = arg_rp;
1217214571Sdim      cur_arg->rp = ret_val;
1218214571Sdim      cur_arg->X_op = O_register;
1219214571Sdim      return;
1220214571Sdim    }
1221214571Sdim
1222214571Sdim  /* Check whether the operand is a processor register.
1223214571Sdim     For "lprd" and "sprd" instruction, only 32 bit
1224214571Sdim     processor registers used.  */
1225214571Sdim  if (!(IS_INSN_MNEMONIC ("lprd") || (IS_INSN_MNEMONIC ("sprd")))
1226214571Sdim      && ((ret_val = get_pregister (operand)) != nullpregister))
1227214571Sdim    {
1228214571Sdim      cur_arg->type = arg_pr;
1229214571Sdim      cur_arg->pr = ret_val;
1230214571Sdim      cur_arg->X_op = O_register;
1231214571Sdim      return;
1232214571Sdim    }
1233214571Sdim
1234214571Sdim  /* Check whether this is a processor register - 32 bit.  */
1235214571Sdim  if ((ret_val = get_pregisterp (operand)) != nullpregister)
1236214571Sdim    {
1237214571Sdim      cur_arg->type = arg_prp;
1238214571Sdim      cur_arg->prp = ret_val;
1239214571Sdim      cur_arg->X_op = O_register;
1240214571Sdim      return;
1241214571Sdim    }
1242214571Sdim
1243214571Sdim  /* Deal with special characters.  */
1244214571Sdim  switch (operand[0])
1245214571Sdim    {
1246214571Sdim    case '$':
1247214571Sdim      if (strchr (operand, '(') != NULL)
1248214571Sdim	cur_arg->type = arg_icr;
1249214571Sdim      else
1250214571Sdim	cur_arg->type = arg_ic;
1251214571Sdim      goto set_params;
1252214571Sdim      break;
1253214571Sdim
1254214571Sdim    case '(':
1255214571Sdim      cur_arg->type = arg_rbase;
1256214571Sdim      goto set_params;
1257214571Sdim      break;
1258214571Sdim
1259214571Sdim    case '[':
1260214571Sdim      cur_arg->type = arg_idxr;
1261214571Sdim      goto set_params;
1262214571Sdim      break;
1263214571Sdim
1264214571Sdim    default:
1265214571Sdim      break;
1266214571Sdim    }
1267214571Sdim
1268214571Sdim  if (strchr (operand, '(') != NULL)
1269214571Sdim    {
1270214571Sdim      if (strchr (operand, ',') != NULL
1271214571Sdim          && (strchr (operand, ',') > strchr (operand, '(')))
1272214571Sdim        cur_arg->type = arg_crp;
1273214571Sdim      else
1274214571Sdim        cur_arg->type = arg_cr;
1275214571Sdim    }
1276214571Sdim  else
1277214571Sdim    cur_arg->type = arg_c;
1278214571Sdim
1279214571Sdim/* Parse an operand according to its type.  */
1280214571Sdim set_params:
1281214571Sdim  cur_arg->constant = 0;
1282214571Sdim  set_operand (operand, cr16_ins);
1283214571Sdim}
1284214571Sdim
1285214571Sdim/* Parse the various operands. Each operand is then analyzed to fillup
1286214571Sdim   the fields in the cr16_ins data structure.  */
1287214571Sdim
1288214571Sdimstatic void
1289214571Sdimparse_operands (ins * cr16_ins, char *operands)
1290214571Sdim{
1291214571Sdim  char *operandS;            /* Operands string.  */
1292214571Sdim  char *operandH, *operandT; /* Single operand head/tail pointers.  */
1293214571Sdim  int allocated = 0;         /* Indicates a new operands string was allocated.*/
1294214571Sdim  char *operand[MAX_OPERANDS];/* Separating the operands.  */
1295214571Sdim  int op_num = 0;             /* Current operand number we are parsing.  */
1296214571Sdim  int bracket_flag = 0;       /* Indicates a bracket '(' was found.  */
1297214571Sdim  int sq_bracket_flag = 0;    /* Indicates a square bracket '[' was found.  */
1298214571Sdim
1299214571Sdim  /* Preprocess the list of registers, if necessary.  */
1300214571Sdim  operandS = operandH = operandT = operands;
1301214571Sdim
1302214571Sdim  while (*operandT != '\0')
1303214571Sdim    {
1304214571Sdim      if (*operandT == ',' && bracket_flag != 1 && sq_bracket_flag != 1)
1305214571Sdim        {
1306214571Sdim          *operandT++ = '\0';
1307214571Sdim          operand[op_num++] = strdup (operandH);
1308214571Sdim          operandH = operandT;
1309214571Sdim          continue;
1310214571Sdim        }
1311214571Sdim
1312214571Sdim      if (*operandT == ' ')
1313214571Sdim        as_bad (_("Illegal operands (whitespace): `%s'"), ins_parse);
1314214571Sdim
1315214571Sdim      if (*operandT == '(')
1316214571Sdim        bracket_flag = 1;
1317214571Sdim      else if (*operandT == '[')
1318214571Sdim        sq_bracket_flag = 1;
1319214571Sdim
1320214571Sdim      if (*operandT == ')')
1321214571Sdim        {
1322214571Sdim          if (bracket_flag)
1323214571Sdim            bracket_flag = 0;
1324214571Sdim          else
1325214571Sdim            as_fatal (_("Missing matching brackets : `%s'"), ins_parse);
1326214571Sdim        }
1327214571Sdim      else if (*operandT == ']')
1328214571Sdim        {
1329214571Sdim          if (sq_bracket_flag)
1330214571Sdim            sq_bracket_flag = 0;
1331214571Sdim          else
1332214571Sdim            as_fatal (_("Missing matching brackets : `%s'"), ins_parse);
1333214571Sdim        }
1334214571Sdim
1335214571Sdim      if (bracket_flag == 1 && *operandT == ')')
1336214571Sdim        bracket_flag = 0;
1337214571Sdim      else if (sq_bracket_flag == 1 && *operandT == ']')
1338214571Sdim        sq_bracket_flag = 0;
1339214571Sdim
1340214571Sdim      operandT++;
1341214571Sdim    }
1342214571Sdim
1343214571Sdim  /* Adding the last operand.  */
1344214571Sdim  operand[op_num++] = strdup (operandH);
1345214571Sdim  cr16_ins->nargs = op_num;
1346214571Sdim
1347214571Sdim  /* Verifying correct syntax of operands (all brackets should be closed).  */
1348214571Sdim  if (bracket_flag || sq_bracket_flag)
1349214571Sdim    as_fatal (_("Missing matching brackets : `%s'"), ins_parse);
1350214571Sdim
1351214571Sdim  /* Now we parse each operand separately.  */
1352214571Sdim  for (op_num = 0; op_num < cr16_ins->nargs; op_num++)
1353214571Sdim    {
1354214571Sdim      cur_arg_num = op_num;
1355214571Sdim      parse_operand (operand[op_num], cr16_ins);
1356214571Sdim      free (operand[op_num]);
1357214571Sdim    }
1358214571Sdim
1359214571Sdim  if (allocated)
1360214571Sdim    free (operandS);
1361214571Sdim}
1362214571Sdim
1363214571Sdim/* Get the trap index in dispatch table, given its name.
1364214571Sdim   This routine is used by assembling the 'excp' instruction.  */
1365214571Sdim
1366214571Sdimstatic int
1367214571Sdimgettrap (char *s)
1368214571Sdim{
1369214571Sdim  const trap_entry *trap;
1370214571Sdim
1371214571Sdim  for (trap = cr16_traps; trap < (cr16_traps + NUMTRAPS); trap++)
1372214571Sdim    if (strcasecmp (trap->name, s) == 0)
1373214571Sdim      return trap->entry;
1374214571Sdim
1375214571Sdim  /* To make compatable with CR16 4.1 tools, the below 3-lines of
1376214571Sdim   * code added. Refer: Development Tracker item #123 */
1377214571Sdim  for (trap = cr16_traps; trap < (cr16_traps + NUMTRAPS); trap++)
1378214571Sdim    if (trap->entry  == (unsigned int) atoi (s))
1379214571Sdim      return trap->entry;
1380214571Sdim
1381214571Sdim  as_bad (_("Unknown exception: `%s'"), s);
1382214571Sdim  return 0;
1383214571Sdim}
1384214571Sdim
1385214571Sdim/* Top level module where instruction parsing starts.
1386214571Sdim   cr16_ins - data structure holds some information.
1387214571Sdim   operands - holds the operands part of the whole instruction.  */
1388214571Sdim
1389214571Sdimstatic void
1390214571Sdimparse_insn (ins *insn, char *operands)
1391214571Sdim{
1392214571Sdim  int i;
1393214571Sdim
1394214571Sdim  /* Handle instructions with no operands.  */
1395214571Sdim  for (i = 0; cr16_no_op_insn[i] != NULL; i++)
1396214571Sdim  {
1397214571Sdim    if (streq (cr16_no_op_insn[i], instruction->mnemonic))
1398214571Sdim    {
1399214571Sdim      insn->nargs = 0;
1400214571Sdim      return;
1401214571Sdim    }
1402214571Sdim  }
1403214571Sdim
1404214571Sdim  /* Handle 'excp' instructions.  */
1405214571Sdim  if (IS_INSN_MNEMONIC ("excp"))
1406214571Sdim    {
1407214571Sdim      insn->nargs = 1;
1408214571Sdim      insn->arg[0].type = arg_ic;
1409214571Sdim      insn->arg[0].constant = gettrap (operands);
1410214571Sdim      insn->arg[0].X_op = O_constant;
1411214571Sdim      return;
1412214571Sdim    }
1413214571Sdim
1414214571Sdim  if (operands != NULL)
1415214571Sdim    parse_operands (insn, operands);
1416214571Sdim}
1417214571Sdim
1418214571Sdim/* bCC instruction requires special handling.  */
1419214571Sdimstatic char *
1420214571Sdimget_b_cc (char * op)
1421214571Sdim{
1422214571Sdim  unsigned int i;
1423214571Sdim  char op1[5];
1424214571Sdim
1425214571Sdim  for (i = 1; i < strlen (op); i++)
1426214571Sdim     op1[i-1] = op[i];
1427214571Sdim
1428214571Sdim  op1[i-1] = '\0';
1429214571Sdim
1430214571Sdim  for (i = 0; i < cr16_num_cc ; i++)
1431214571Sdim    if (streq (op1, cr16_b_cond_tab[i]))
1432214571Sdim      return (char *) cr16_b_cond_tab[i];
1433214571Sdim
1434214571Sdim   return NULL;
1435214571Sdim}
1436214571Sdim
1437214571Sdim/* bCC instruction requires special handling.  */
1438214571Sdimstatic int
1439214571Sdimis_bcc_insn (char * op)
1440214571Sdim{
1441214571Sdim  if (!(streq (op, "bal") || streq (op, "beq0b") || streq (op, "bnq0b")
1442214571Sdim	|| streq (op, "beq0w") || streq (op, "bnq0w")))
1443214571Sdim    if ((op[0] == 'b') && (get_b_cc (op) != NULL))
1444214571Sdim      return 1;
1445214571Sdim  return 0;
1446214571Sdim}
1447214571Sdim
1448214571Sdim/* Cinv instruction requires special handling.  */
1449214571Sdim
1450214571Sdimstatic int
1451214571Sdimcheck_cinv_options (char * operand)
1452214571Sdim{
1453214571Sdim  char *p = operand;
1454214571Sdim  int i_used = 0, u_used = 0, d_used = 0;
1455214571Sdim
1456214571Sdim  while (*++p != ']')
1457214571Sdim    {
1458214571Sdim      if (*p == ',' || *p == ' ')
1459214571Sdim        continue;
1460214571Sdim
1461214571Sdim      else if (*p == 'i')
1462214571Sdim        i_used = 1;
1463214571Sdim      else if (*p == 'u')
1464214571Sdim        u_used = 1;
1465214571Sdim      else if (*p == 'd')
1466214571Sdim        d_used = 1;
1467214571Sdim      else
1468214571Sdim        as_bad (_("Illegal `cinv' parameter: `%c'"), *p);
1469214571Sdim    }
1470214571Sdim
1471214571Sdim  return 0;
1472214571Sdim}
1473214571Sdim
1474214571Sdim/* Retrieve the opcode image of a given register pair.
1475214571Sdim   If the register is illegal for the current instruction,
1476214571Sdim   issue an error.  */
1477214571Sdim
1478214571Sdimstatic int
1479214571Sdimgetregp_image (reg r)
1480214571Sdim{
1481214571Sdim  const reg_entry *reg;
1482214571Sdim  char *reg_name;
1483214571Sdim
1484214571Sdim  /* Check whether the register is in registers table.  */
1485214571Sdim  if (r < MAX_REG)
1486214571Sdim    reg = cr16_regptab + r;
1487214571Sdim  /* Register not found.  */
1488214571Sdim  else
1489214571Sdim    {
1490214571Sdim      as_bad (_("Unknown register pair: `%d'"), r);
1491214571Sdim      return 0;
1492214571Sdim    }
1493214571Sdim
1494214571Sdim  reg_name = reg->name;
1495214571Sdim
1496214571Sdim/* Issue a error message when register  pair is illegal.  */
1497214571Sdim#define RPAIR_IMAGE_ERR \
1498214571Sdim  as_bad (_("Illegal register pair (`%s') in Instruction: `%s'"), \
1499214571Sdim            reg_name, ins_parse);                                 \
1500214571Sdim  break;
1501214571Sdim
1502214571Sdim  switch (reg->type)
1503214571Sdim    {
1504214571Sdim    case CR16_RP_REGTYPE:
1505214571Sdim      return reg->image;
1506214571Sdim    default:
1507214571Sdim      RPAIR_IMAGE_ERR;
1508214571Sdim    }
1509214571Sdim
1510214571Sdim  return 0;
1511214571Sdim}
1512214571Sdim
1513214571Sdim/* Retrieve the opcode image of a given index register pair.
1514214571Sdim   If the register is illegal for the current instruction,
1515214571Sdim   issue an error.  */
1516214571Sdim
1517214571Sdimstatic int
1518214571Sdimgetidxregp_image (reg r)
1519214571Sdim{
1520214571Sdim  const reg_entry *reg;
1521214571Sdim  char *reg_name;
1522214571Sdim
1523214571Sdim  /* Check whether the register is in registers table.  */
1524214571Sdim  if (r < MAX_REG)
1525214571Sdim    reg = cr16_regptab + r;
1526214571Sdim  /* Register not found.  */
1527214571Sdim  else
1528214571Sdim    {
1529214571Sdim      as_bad (_("Unknown register pair: `%d'"), r);
1530214571Sdim      return 0;
1531214571Sdim    }
1532214571Sdim
1533214571Sdim  reg_name = reg->name;
1534214571Sdim
1535214571Sdim/* Issue a error message when register  pair is illegal.  */
1536214571Sdim#define IDX_RPAIR_IMAGE_ERR \
1537214571Sdim  as_bad (_("Illegal index register pair (`%s') in Instruction: `%s'"), \
1538214571Sdim            reg_name, ins_parse);                                       \
1539214571Sdim
1540214571Sdim  if (reg->type == CR16_RP_REGTYPE)
1541214571Sdim    {
1542214571Sdim      switch (reg->image)
1543214571Sdim	{
1544214571Sdim	case 0:  return 0; break;
1545214571Sdim	case 2:  return 1; break;
1546214571Sdim	case 4:  return 2; break;
1547214571Sdim	case 6:  return 3; break;
1548214571Sdim	case 8:  return 4; break;
1549214571Sdim	case 10: return 5; break;
1550214571Sdim	case 3:  return 6; break;
1551214571Sdim	case 5:  return 7; break;
1552214571Sdim	default:
1553214571Sdim	  break;
1554214571Sdim	}
1555214571Sdim    }
1556214571Sdim
1557214571Sdim  IDX_RPAIR_IMAGE_ERR;
1558214571Sdim  return 0;
1559214571Sdim}
1560214571Sdim
1561214571Sdim/* Retrieve the opcode image of a given processort register.
1562214571Sdim   If the register is illegal for the current instruction,
1563214571Sdim   issue an error.  */
1564214571Sdimstatic int
1565214571Sdimgetprocreg_image (reg r)
1566214571Sdim{
1567214571Sdim  const reg_entry *reg;
1568214571Sdim  char *reg_name;
1569214571Sdim
1570214571Sdim  /* Check whether the register is in registers table.  */
1571214571Sdim  if (r < MAX_PREG)
1572214571Sdim    reg = &cr16_pregtab[r - MAX_REG];
1573214571Sdim  /* Register not found.  */
1574214571Sdim  else
1575214571Sdim    {
1576214571Sdim      as_bad (_("Unknown processor register : `%d'"), r);
1577214571Sdim      return 0;
1578214571Sdim    }
1579214571Sdim
1580214571Sdim  reg_name = reg->name;
1581214571Sdim
1582214571Sdim/* Issue a error message when register  pair is illegal.  */
1583214571Sdim#define PROCREG_IMAGE_ERR \
1584214571Sdim  as_bad (_("Illegal processor register (`%s') in Instruction: `%s'"), \
1585214571Sdim            reg_name, ins_parse);                                      \
1586214571Sdim  break;
1587214571Sdim
1588214571Sdim  switch (reg->type)
1589214571Sdim    {
1590214571Sdim    case CR16_P_REGTYPE:
1591214571Sdim      return reg->image;
1592214571Sdim    default:
1593214571Sdim      PROCREG_IMAGE_ERR;
1594214571Sdim    }
1595214571Sdim
1596214571Sdim  return 0;
1597214571Sdim}
1598214571Sdim
1599214571Sdim/* Retrieve the opcode image of a given processort register.
1600214571Sdim   If the register is illegal for the current instruction,
1601214571Sdim   issue an error.  */
1602214571Sdimstatic int
1603214571Sdimgetprocregp_image (reg r)
1604214571Sdim{
1605214571Sdim  const reg_entry *reg;
1606214571Sdim  char *reg_name;
1607214571Sdim  int pregptab_disp = 0;
1608214571Sdim
1609214571Sdim  /* Check whether the register is in registers table.  */
1610214571Sdim  if (r < MAX_PREG)
1611214571Sdim    {
1612214571Sdim      r = r - MAX_REG;
1613214571Sdim      switch (r)
1614214571Sdim        {
1615214571Sdim	case 4: pregptab_disp = 1;  break;
1616214571Sdim	case 6: pregptab_disp = 2;  break;
1617214571Sdim	case 8:
1618214571Sdim	case 9:
1619214571Sdim	case 10:
1620214571Sdim	  pregptab_disp = 3;  break;
1621214571Sdim	case 12:
1622214571Sdim	  pregptab_disp = 4;  break;
1623214571Sdim	case 14:
1624214571Sdim	  pregptab_disp = 5;  break;
1625214571Sdim	default: break;
1626214571Sdim        }
1627214571Sdim      reg = &cr16_pregptab[r - pregptab_disp];
1628214571Sdim    }
1629214571Sdim  /* Register not found.  */
1630214571Sdim  else
1631214571Sdim    {
1632214571Sdim      as_bad (_("Unknown processor register (32 bit) : `%d'"), r);
1633214571Sdim      return 0;
1634214571Sdim    }
1635214571Sdim
1636214571Sdim  reg_name = reg->name;
1637214571Sdim
1638214571Sdim/* Issue a error message when register  pair is illegal.  */
1639214571Sdim#define PROCREGP_IMAGE_ERR \
1640214571Sdim  as_bad (_("Illegal 32 bit - processor register (`%s') in Instruction: `%s'"),\
1641214571Sdim            reg_name, ins_parse);                                              \
1642214571Sdim  break;
1643214571Sdim
1644214571Sdim  switch (reg->type)
1645214571Sdim    {
1646214571Sdim    case CR16_P_REGTYPE:
1647214571Sdim      return reg->image;
1648214571Sdim    default:
1649214571Sdim      PROCREGP_IMAGE_ERR;
1650214571Sdim    }
1651214571Sdim
1652214571Sdim  return 0;
1653214571Sdim}
1654214571Sdim
1655214571Sdim/* Routine used to represent integer X using NBITS bits.  */
1656214571Sdim
1657214571Sdimstatic long
1658214571Sdimgetconstant (long x, int nbits)
1659214571Sdim{
1660214571Sdim  /* The following expression avoids overflow if
1661214571Sdim     'nbits' is the number of bits in 'bfd_vma'.  */
1662214571Sdim  return (x & ((((1 << (nbits - 1)) - 1) << 1) | 1));
1663214571Sdim}
1664214571Sdim
1665214571Sdim/* Print a constant value to 'output_opcode':
1666214571Sdim   ARG holds the operand's type and value.
1667214571Sdim   SHIFT represents the location of the operand to be print into.
1668214571Sdim   NBITS determines the size (in bits) of the constant.  */
1669214571Sdim
1670214571Sdimstatic void
1671214571Sdimprint_constant (int nbits, int shift, argument *arg)
1672214571Sdim{
1673214571Sdim  unsigned long mask = 0;
1674214571Sdim
1675214571Sdim  long constant = getconstant (arg->constant, nbits);
1676214571Sdim
1677214571Sdim  switch (nbits)
1678214571Sdim    {
1679214571Sdim    case 32:
1680214571Sdim    case 28:
1681214571Sdim      /* mask the upper part of the constant, that is, the bits
1682214571Sdim	 going to the lowest byte of output_opcode[0].
1683214571Sdim	 The upper part of output_opcode[1] is always filled,
1684214571Sdim	 therefore it is always masked with 0xFFFF.  */
1685214571Sdim      mask = (1 << (nbits - 16)) - 1;
1686214571Sdim      /* Divide the constant between two consecutive words :
1687214571Sdim	 0        1         2         3
1688214571Sdim	 +---------+---------+---------+---------+
1689214571Sdim	 |         | X X X X | x X x X |         |
1690214571Sdim	 +---------+---------+---------+---------+
1691214571Sdim	 output_opcode[0]    output_opcode[1]     */
1692214571Sdim
1693214571Sdim      CR16_PRINT (0, (constant >> WORD_SHIFT) & mask, 0);
1694214571Sdim      CR16_PRINT (1, (constant & 0xFFFF), WORD_SHIFT);
1695214571Sdim      break;
1696214571Sdim
1697214571Sdim    case 21:
1698214571Sdim      if ((nbits == 21) && (IS_INSN_TYPE (LD_STOR_INS))) nbits = 20;
1699214571Sdim    case 24:
1700214571Sdim    case 22:
1701214571Sdim    case 20:
1702214571Sdim      /* mask the upper part of the constant, that is, the bits
1703214571Sdim	 going to the lowest byte of output_opcode[0].
1704214571Sdim	 The upper part of output_opcode[1] is always filled,
1705214571Sdim	 therefore it is always masked with 0xFFFF.  */
1706214571Sdim      mask = (1 << (nbits - 16)) - 1;
1707214571Sdim      /* Divide the constant between two consecutive words :
1708214571Sdim	 0        1         2          3
1709214571Sdim	 +---------+---------+---------+---------+
1710214571Sdim	 |         | X X X X | - X - X |         |
1711214571Sdim	 +---------+---------+---------+---------+
1712214571Sdim	 output_opcode[0]    output_opcode[1]     */
1713214571Sdim
1714214571Sdim      if ((instruction->size > 2) && (shift == WORD_SHIFT))
1715214571Sdim	{
1716214571Sdim	  if (arg->type == arg_idxrp)
1717214571Sdim	    {
1718214571Sdim	      CR16_PRINT (0, ((constant >> WORD_SHIFT) & mask) << 8, 0);
1719214571Sdim	      CR16_PRINT (1, (constant & 0xFFFF), WORD_SHIFT);
1720214571Sdim	    }
1721214571Sdim	  else
1722214571Sdim	    {
1723214571Sdim	      CR16_PRINT (0, (((((constant >> WORD_SHIFT) & mask) << 8) & 0x0f00) | ((((constant >> WORD_SHIFT) & mask) >> 4) & 0xf)),0);
1724214571Sdim	      CR16_PRINT (1, (constant & 0xFFFF), WORD_SHIFT);
1725214571Sdim	    }
1726214571Sdim	}
1727214571Sdim      else
1728214571Sdim	CR16_PRINT (0, constant, shift);
1729214571Sdim      break;
1730214571Sdim
1731214571Sdim    case 14:
1732214571Sdim      if (arg->type == arg_idxrp)
1733214571Sdim	{
1734214571Sdim	  if (instruction->size == 2)
1735214571Sdim	    {
1736214571Sdim	      CR16_PRINT (0, ((constant)&0xf), shift);         // 0-3 bits
1737214571Sdim	      CR16_PRINT (0, ((constant>>4)&0x3), (shift+20)); // 4-5 bits
1738214571Sdim	      CR16_PRINT (0, ((constant>>6)&0x3), (shift+14)); // 6-7 bits
1739214571Sdim	      CR16_PRINT (0, ((constant>>8)&0x3f), (shift+8)); // 8-13 bits
1740214571Sdim	    }
1741214571Sdim	  else
1742214571Sdim	    CR16_PRINT (0, constant, shift);
1743214571Sdim	}
1744214571Sdim      break;
1745214571Sdim
1746214571Sdim    case 16:
1747214571Sdim    case 12:
1748214571Sdim      /* When instruction size is 3 and 'shift' is 16, a 16-bit constant is
1749214571Sdim	 always filling the upper part of output_opcode[1]. If we mistakenly
1750214571Sdim	 write it to output_opcode[0], the constant prefix (that is, 'match')
1751214571Sdim	 will be overriden.
1752214571Sdim	 0        1         2         3
1753214571Sdim	 +---------+---------+---------+---------+
1754214571Sdim	 | 'match' |         | X X X X |         |
1755214571Sdim	 +---------+---------+---------+---------+
1756214571Sdim	 output_opcode[0]    output_opcode[1]     */
1757214571Sdim
1758214571Sdim      if ((instruction->size > 2) && (shift == WORD_SHIFT))
1759214571Sdim	CR16_PRINT (1, constant, WORD_SHIFT);
1760214571Sdim      else
1761214571Sdim	CR16_PRINT (0, constant, shift);
1762214571Sdim      break;
1763214571Sdim
1764214571Sdim    case 8:
1765214571Sdim      CR16_PRINT (0, ((constant/2)&0xf), shift);
1766214571Sdim      CR16_PRINT (0, ((constant/2)>>4),  (shift+8));
1767214571Sdim      break;
1768214571Sdim
1769214571Sdim    default:
1770214571Sdim      CR16_PRINT (0, constant,  shift);
1771214571Sdim      break;
1772214571Sdim    }
1773214571Sdim}
1774214571Sdim
1775214571Sdim/* Print an operand to 'output_opcode', which later on will be
1776214571Sdim   printed to the object file:
1777214571Sdim   ARG holds the operand's type, size and value.
1778214571Sdim   SHIFT represents the printing location of operand.
1779214571Sdim   NBITS determines the size (in bits) of a constant operand.  */
1780214571Sdim
1781214571Sdimstatic void
1782214571Sdimprint_operand (int nbits, int shift, argument *arg)
1783214571Sdim{
1784214571Sdim  switch (arg->type)
1785214571Sdim    {
1786214571Sdim    case arg_cc:
1787214571Sdim      CR16_PRINT (0, arg->cc, shift);
1788214571Sdim      break;
1789214571Sdim
1790214571Sdim    case arg_r:
1791214571Sdim      CR16_PRINT (0, getreg_image (arg->r), shift);
1792214571Sdim      break;
1793214571Sdim
1794214571Sdim    case arg_rp:
1795214571Sdim      CR16_PRINT (0, getregp_image (arg->rp), shift);
1796214571Sdim      break;
1797214571Sdim
1798214571Sdim    case arg_pr:
1799214571Sdim      CR16_PRINT (0, getprocreg_image (arg->pr), shift);
1800214571Sdim      break;
1801214571Sdim
1802214571Sdim    case arg_prp:
1803214571Sdim      CR16_PRINT (0, getprocregp_image (arg->prp), shift);
1804214571Sdim      break;
1805214571Sdim
1806214571Sdim    case arg_idxrp:
1807214571Sdim      /*    16      12      8    6      0
1808214571Sdim            +-----------------------------+
1809214571Sdim            | r_index | disp  | rp_base   |
1810214571Sdim            +-----------------------------+          */
1811214571Sdim
1812214571Sdim      if (instruction->size == 3)
1813214571Sdim	{
1814214571Sdim	  CR16_PRINT (0, getidxregp_image (arg->rp), 0);
1815214571Sdim	  if (getreg_image (arg->i_r) == 12)
1816214571Sdim	    CR16_PRINT (0, 0, 3);
1817214571Sdim	  else
1818214571Sdim	    CR16_PRINT (0, 1, 3);
1819214571Sdim	}
1820214571Sdim      else
1821214571Sdim	{
1822214571Sdim	  CR16_PRINT (0, getidxregp_image (arg->rp), 16);
1823214571Sdim	  if (getreg_image (arg->i_r) == 12)
1824214571Sdim	    CR16_PRINT (0, 0, 19);
1825214571Sdim	  else
1826214571Sdim	    CR16_PRINT (0, 1, 19);
1827214571Sdim	}
1828214571Sdim      print_constant (nbits, shift, arg);
1829214571Sdim      break;
1830214571Sdim
1831214571Sdim    case arg_idxr:
1832214571Sdim      if (getreg_image (arg->i_r) == 12)
1833214571Sdim	if (IS_INSN_MNEMONIC ("cbitb") || IS_INSN_MNEMONIC ("sbitb")
1834214571Sdim	    || IS_INSN_MNEMONIC ("tbitb"))
1835214571Sdim	  CR16_PRINT (0, 0, 23);
1836214571Sdim	else CR16_PRINT (0, 0, 24);
1837214571Sdim      else
1838214571Sdim	if (IS_INSN_MNEMONIC ("cbitb") || IS_INSN_MNEMONIC ("sbitb")
1839214571Sdim	    || IS_INSN_MNEMONIC ("tbitb"))
1840214571Sdim	  CR16_PRINT (0, 1, 23);
1841214571Sdim	else CR16_PRINT (0, 1, 24);
1842214571Sdim
1843214571Sdim      print_constant (nbits, shift, arg);
1844214571Sdim      break;
1845214571Sdim
1846214571Sdim    case arg_ic:
1847214571Sdim    case arg_c:
1848214571Sdim      print_constant (nbits, shift, arg);
1849214571Sdim      break;
1850214571Sdim
1851214571Sdim    case arg_rbase:
1852214571Sdim      CR16_PRINT (0, getreg_image (arg->r), shift);
1853214571Sdim      break;
1854214571Sdim
1855214571Sdim    case arg_cr:
1856214571Sdim      print_constant (nbits, shift , arg);
1857214571Sdim      /* Add the register argument to the output_opcode.  */
1858214571Sdim      CR16_PRINT (0, getreg_image (arg->r), (shift+16));
1859214571Sdim      break;
1860214571Sdim
1861214571Sdim    case arg_crp:
1862214571Sdim      print_constant (nbits, shift , arg);
1863214571Sdim      if (instruction->size > 1)
1864214571Sdim	CR16_PRINT (0, getregp_image (arg->rp), (shift + 16));
1865214571Sdim      else if (IS_INSN_TYPE (LD_STOR_INS) || (IS_INSN_TYPE (CSTBIT_INS)))
1866214571Sdim	{
1867214571Sdim	  if (instruction->size == 2)
1868214571Sdim	    CR16_PRINT (0, getregp_image (arg->rp), (shift - 8));
1869214571Sdim	  else if (instruction->size == 1)
1870214571Sdim	    CR16_PRINT (0, getregp_image (arg->rp), 16);
1871214571Sdim	}
1872214571Sdim      else
1873214571Sdim	CR16_PRINT (0, getregp_image (arg->rp), shift);
1874214571Sdim      break;
1875214571Sdim
1876214571Sdim    default:
1877214571Sdim      break;
1878214571Sdim    }
1879214571Sdim}
1880214571Sdim
1881214571Sdim/* Retrieve the number of operands for the current assembled instruction.  */
1882214571Sdim
1883214571Sdimstatic int
1884214571Sdimget_number_of_operands (void)
1885214571Sdim{
1886214571Sdim  int i;
1887214571Sdim
1888214571Sdim  for (i = 0; instruction->operands[i].op_type && i < MAX_OPERANDS; i++)
1889214571Sdim    ;
1890214571Sdim  return i;
1891214571Sdim}
1892214571Sdim
1893214571Sdim/* Verify that the number NUM can be represented in BITS bits (that is,
1894214571Sdim   within its permitted range), based on the instruction's FLAGS.
1895214571Sdim   If UPDATE is nonzero, update the value of NUM if necessary.
1896214571Sdim   Return OP_LEGAL upon success, actual error type upon failure.  */
1897214571Sdim
1898214571Sdimstatic op_err
1899214571Sdimcheck_range (long *num, int bits, int unsigned flags, int update)
1900214571Sdim{
1901214571Sdim  long min, max;
1902214571Sdim  int retval = OP_LEGAL;
1903214571Sdim  long value = *num;
1904214571Sdim
1905214571Sdim  if (bits == 0 && value > 0) return OP_OUT_OF_RANGE;
1906214571Sdim
1907214571Sdim  /* For hosts witah longs bigger than 32-bits make sure that the top
1908214571Sdim     bits of a 32-bit negative value read in by the parser are set,
1909214571Sdim     so that the correct comparisons are made.  */
1910214571Sdim  if (value & 0x80000000)
1911214571Sdim    value |= (-1L << 31);
1912214571Sdim
1913214571Sdim
1914214571Sdim  /* Verify operand value is even.  */
1915214571Sdim  if (flags & OP_EVEN)
1916214571Sdim    {
1917214571Sdim      if (value % 2)
1918214571Sdim        return OP_NOT_EVEN;
1919214571Sdim    }
1920214571Sdim
1921214571Sdim  if (flags & OP_DEC)
1922214571Sdim    {
1923214571Sdim      value -= 1;
1924214571Sdim      if (update)
1925214571Sdim        *num = value;
1926214571Sdim    }
1927214571Sdim
1928214571Sdim  if (flags & OP_SHIFT)
1929214571Sdim    {
1930214571Sdim      value >>= 1;
1931214571Sdim      if (update)
1932214571Sdim        *num = value;
1933214571Sdim    }
1934214571Sdim  else if (flags & OP_SHIFT_DEC)
1935214571Sdim    {
1936214571Sdim      value = (value >> 1) - 1;
1937214571Sdim      if (update)
1938214571Sdim        *num = value;
1939214571Sdim    }
1940214571Sdim
1941214571Sdim  if (flags & OP_ABS20)
1942214571Sdim    {
1943214571Sdim      if (value > 0xEFFFF)
1944214571Sdim        return OP_OUT_OF_RANGE;
1945214571Sdim    }
1946214571Sdim
1947214571Sdim  if (flags & OP_ESC)
1948214571Sdim    {
1949214571Sdim      if (value == 0xB || value == 0x9)
1950214571Sdim        return OP_OUT_OF_RANGE;
1951214571Sdim      else if (value == -1)
1952214571Sdim	{
1953214571Sdim	  if (update)
1954214571Sdim	    *num = 9;
1955214571Sdim	  return retval;
1956214571Sdim	}
1957214571Sdim    }
1958214571Sdim
1959214571Sdim  if (flags & OP_ESC1)
1960214571Sdim    {
1961214571Sdim      if (value > 13)
1962214571Sdim        return OP_OUT_OF_RANGE;
1963214571Sdim    }
1964214571Sdim
1965214571Sdim   if (flags & OP_SIGNED)
1966214571Sdim     {
1967214571Sdim       max = (1 << (bits - 1)) - 1;
1968214571Sdim       min = - (1 << (bits - 1));
1969214571Sdim       if ((value > max) || (value < min))
1970214571Sdim         retval = OP_OUT_OF_RANGE;
1971214571Sdim     }
1972214571Sdim   else if (flags & OP_UNSIGNED)
1973214571Sdim     {
1974214571Sdim       max = ((((1 << (bits - 1)) - 1) << 1) | 1);
1975214571Sdim       min = 0;
1976214571Sdim       if (((unsigned long) value > (unsigned long) max)
1977214571Sdim            || ((unsigned long) value < (unsigned long) min))
1978214571Sdim         retval = OP_OUT_OF_RANGE;
1979214571Sdim     }
1980214571Sdim   else if (flags & OP_NEG)
1981214571Sdim     {
1982214571Sdim       max = - 1;
1983214571Sdim       min = - ((1 << (bits - 1))-1);
1984214571Sdim       if ((value > max) || (value < min))
1985214571Sdim         retval = OP_OUT_OF_RANGE;
1986214571Sdim     }
1987214571Sdim   return retval;
1988214571Sdim}
1989214571Sdim
1990214571Sdim/* Bunch of error checkings.
1991214571Sdim   The checks are made after a matching instruction was found.  */
1992214571Sdim
1993214571Sdimstatic void
1994214571Sdimwarn_if_needed (ins *insn)
1995214571Sdim{
1996214571Sdim  /* If the post-increment address mode is used and the load/store
1997214571Sdim     source register is the same as rbase, the result of the
1998214571Sdim     instruction is undefined.  */
1999214571Sdim  if (IS_INSN_TYPE (LD_STOR_INS_INC))
2000214571Sdim    {
2001214571Sdim      /* Enough to verify that one of the arguments is a simple reg.  */
2002214571Sdim      if ((insn->arg[0].type == arg_r) || (insn->arg[1].type == arg_r))
2003214571Sdim        if (insn->arg[0].r == insn->arg[1].r)
2004214571Sdim          as_bad (_("Same src/dest register is used (`r%d'), result is undefined"), insn->arg[0].r);
2005214571Sdim    }
2006214571Sdim
2007214571Sdim  if (IS_INSN_MNEMONIC ("pop")
2008214571Sdim      || IS_INSN_MNEMONIC ("push")
2009214571Sdim      || IS_INSN_MNEMONIC ("popret"))
2010214571Sdim    {
2011214571Sdim      unsigned int count = insn->arg[0].constant, reg_val;
2012214571Sdim
2013214571Sdim      /* Check if count operand caused to save/retrive the RA twice
2014214571Sdim	 to generate warning message.  */
2015214571Sdim     if (insn->nargs > 2)
2016214571Sdim       {
2017214571Sdim         reg_val = getreg_image (insn->arg[1].r);
2018214571Sdim
2019214571Sdim         if (   ((reg_val == 9) &&  (count > 7))
2020214571Sdim	     || ((reg_val == 10) && (count > 6))
2021214571Sdim	     || ((reg_val == 11) && (count > 5))
2022214571Sdim	     || ((reg_val == 12) && (count > 4))
2023214571Sdim	     || ((reg_val == 13) && (count > 2))
2024214571Sdim	     || ((reg_val == 14) && (count > 0)))
2025214571Sdim           as_warn (_("RA register is saved twice."));
2026214571Sdim
2027214571Sdim         /* Check if the third operand is "RA" or "ra" */
2028214571Sdim         if (!(((insn->arg[2].r) == ra) || ((insn->arg[2].r) == RA)))
2029214571Sdim           as_bad (_("`%s' Illegal use of registers."), ins_parse);
2030214571Sdim       }
2031214571Sdim
2032214571Sdim      if (insn->nargs > 1)
2033214571Sdim       {
2034214571Sdim         reg_val = getreg_image (insn->arg[1].r);
2035214571Sdim
2036214571Sdim         /* If register is a register pair ie r12/r13/r14 in operand1, then
2037214571Sdim            the count constant should be validated.  */
2038214571Sdim         if (((reg_val == 11) && (count > 7))
2039214571Sdim	     || ((reg_val == 12) && (count > 6))
2040214571Sdim	     || ((reg_val == 13) && (count > 4))
2041214571Sdim	     || ((reg_val == 14) && (count > 2))
2042214571Sdim	     || ((reg_val == 15) && (count > 0)))
2043214571Sdim           as_bad (_("`%s' Illegal count-register combination."), ins_parse);
2044214571Sdim       }
2045214571Sdim     else
2046214571Sdim       {
2047214571Sdim         /* Check if the operand is "RA" or "ra" */
2048214571Sdim         if (!(((insn->arg[0].r) == ra) || ((insn->arg[0].r) == RA)))
2049214571Sdim           as_bad (_("`%s' Illegal use of register."), ins_parse);
2050214571Sdim       }
2051214571Sdim    }
2052214571Sdim
2053214571Sdim  /* Some instruction assume the stack pointer as rptr operand.
2054214571Sdim     Issue an error when the register to be loaded is also SP.  */
2055214571Sdim  if (instruction->flags & NO_SP)
2056214571Sdim    {
2057214571Sdim      if (getreg_image (insn->arg[1].r) == getreg_image (sp))
2058214571Sdim        as_bad (_("`%s' has undefined result"), ins_parse);
2059214571Sdim    }
2060214571Sdim
2061214571Sdim  /* If the rptr register is specified as one of the registers to be loaded,
2062214571Sdim     the final contents of rptr are undefined. Thus, we issue an error.  */
2063214571Sdim  if (instruction->flags & NO_RPTR)
2064214571Sdim    {
2065214571Sdim      if ((1 << getreg_image (insn->arg[0].r)) & insn->arg[1].constant)
2066214571Sdim        as_bad (_("Same src/dest register is used (`r%d'),result is undefined"),
2067214571Sdim                  getreg_image (insn->arg[0].r));
2068214571Sdim    }
2069214571Sdim}
2070214571Sdim
2071214571Sdim/* In some cases, we need to adjust the instruction pointer although a
2072214571Sdim   match was already found. Here, we gather all these cases.
2073214571Sdim   Returns 1 if instruction pointer was adjusted, otherwise 0.  */
2074214571Sdim
2075214571Sdimstatic int
2076214571Sdimadjust_if_needed (ins *insn ATTRIBUTE_UNUSED)
2077214571Sdim{
2078214571Sdim  int ret_value = 0;
2079214571Sdim
2080214571Sdim  if ((IS_INSN_TYPE (CSTBIT_INS)) || (IS_INSN_TYPE (LD_STOR_INS)))
2081214571Sdim    {
2082214571Sdim      if ((instruction->operands[0].op_type == abs24)
2083214571Sdim           && ((insn->arg[0].constant) > 0xF00000))
2084214571Sdim        {
2085214571Sdim          insn->arg[0].constant &= 0xFFFFF;
2086214571Sdim          instruction--;
2087214571Sdim          ret_value = 1;
2088214571Sdim        }
2089214571Sdim    }
2090214571Sdim
2091214571Sdim  return ret_value;
2092214571Sdim}
2093214571Sdim
2094214571Sdim/* Assemble a single instruction:
2095214571Sdim   INSN is already parsed (that is, all operand values and types are set).
2096214571Sdim   For instruction to be assembled, we need to find an appropriate template in
2097214571Sdim   the instruction table, meeting the following conditions:
2098214571Sdim    1: Has the same number of operands.
2099214571Sdim    2: Has the same operand types.
2100214571Sdim    3: Each operand size is sufficient to represent the instruction's values.
2101214571Sdim   Returns 1 upon success, 0 upon failure.  */
2102214571Sdim
2103214571Sdimstatic int
2104214571Sdimassemble_insn (char *mnemonic, ins *insn)
2105214571Sdim{
2106214571Sdim  /* Type of each operand in the current template.  */
2107214571Sdim  argtype cur_type[MAX_OPERANDS];
2108214571Sdim  /* Size (in bits) of each operand in the current template.  */
2109214571Sdim  unsigned int cur_size[MAX_OPERANDS];
2110214571Sdim  /* Flags of each operand in the current template.  */
2111214571Sdim  unsigned int cur_flags[MAX_OPERANDS];
2112214571Sdim  /* Instruction type to match.  */
2113214571Sdim  unsigned int ins_type;
2114214571Sdim  /* Boolean flag to mark whether a match was found.  */
2115214571Sdim  int match = 0;
2116214571Sdim  int i;
2117214571Sdim  /* Nonzero if an instruction with same number of operands was found.  */
2118214571Sdim  int found_same_number_of_operands = 0;
2119214571Sdim  /* Nonzero if an instruction with same argument types was found.  */
2120214571Sdim  int found_same_argument_types = 0;
2121214571Sdim  /* Nonzero if a constant was found within the required range.  */
2122214571Sdim  int found_const_within_range  = 0;
2123214571Sdim  /* Argument number of an operand with invalid type.  */
2124214571Sdim  int invalid_optype = -1;
2125214571Sdim  /* Argument number of an operand with invalid constant value.  */
2126214571Sdim  int invalid_const  = -1;
2127214571Sdim  /* Operand error (used for issuing various constant error messages).  */
2128214571Sdim  op_err op_error, const_err = OP_LEGAL;
2129214571Sdim
2130214571Sdim/* Retrieve data (based on FUNC) for each operand of a given instruction.  */
2131214571Sdim#define GET_CURRENT_DATA(FUNC, ARRAY)                           \
2132214571Sdim  for (i = 0; i < insn->nargs; i++)                             \
2133214571Sdim    ARRAY[i] = FUNC (instruction->operands[i].op_type)
2134214571Sdim
2135214571Sdim#define GET_CURRENT_TYPE    GET_CURRENT_DATA (get_optype, cur_type)
2136214571Sdim#define GET_CURRENT_SIZE    GET_CURRENT_DATA (get_opbits, cur_size)
2137214571Sdim#define GET_CURRENT_FLAGS   GET_CURRENT_DATA (get_opflags, cur_flags)
2138214571Sdim
2139214571Sdim  /* Instruction has no operands -> only copy the constant opcode.   */
2140214571Sdim  if (insn->nargs == 0)
2141214571Sdim    {
2142214571Sdim      output_opcode[0] = BIN (instruction->match, instruction->match_bits);
2143214571Sdim      return 1;
2144214571Sdim    }
2145214571Sdim
2146214571Sdim  /* In some case, same mnemonic can appear with different instruction types.
2147214571Sdim     For example, 'storb' is supported with 3 different types :
2148214571Sdim     LD_STOR_INS, LD_STOR_INS_INC, STOR_IMM_INS.
2149214571Sdim     We assume that when reaching this point, the instruction type was
2150214571Sdim     pre-determined. We need to make sure that the type stays the same
2151214571Sdim     during a search for matching instruction.  */
2152214571Sdim  ins_type = CR16_INS_TYPE (instruction->flags);
2153214571Sdim
2154214571Sdim  while (/* Check that match is still not found.  */
2155214571Sdim         match != 1
2156214571Sdim         /* Check we didn't get to end of table.  */
2157214571Sdim         && instruction->mnemonic != NULL
2158214571Sdim         /* Check that the actual mnemonic is still available.  */
2159214571Sdim         && IS_INSN_MNEMONIC (mnemonic)
2160214571Sdim         /* Check that the instruction type wasn't changed.  */
2161214571Sdim         && IS_INSN_TYPE (ins_type))
2162214571Sdim    {
2163214571Sdim      /* Check whether number of arguments is legal.  */
2164214571Sdim      if (get_number_of_operands () != insn->nargs)
2165214571Sdim        goto next_insn;
2166214571Sdim      found_same_number_of_operands = 1;
2167214571Sdim
2168214571Sdim      /* Initialize arrays with data of each operand in current template.  */
2169214571Sdim      GET_CURRENT_TYPE;
2170214571Sdim      GET_CURRENT_SIZE;
2171214571Sdim      GET_CURRENT_FLAGS;
2172214571Sdim
2173214571Sdim      /* Check for type compatibility.  */
2174214571Sdim      for (i = 0; i < insn->nargs; i++)
2175214571Sdim        {
2176214571Sdim          if (cur_type[i] != insn->arg[i].type)
2177214571Sdim            {
2178214571Sdim              if (invalid_optype == -1)
2179214571Sdim                invalid_optype = i + 1;
2180214571Sdim              goto next_insn;
2181214571Sdim            }
2182214571Sdim        }
2183214571Sdim      found_same_argument_types = 1;
2184214571Sdim
2185214571Sdim      for (i = 0; i < insn->nargs; i++)
2186214571Sdim        {
2187214571Sdim          /* If 'bal' instruction size is '2' and reg operand is not 'ra'
2188214571Sdim             then goto next instruction.  */
2189214571Sdim          if (IS_INSN_MNEMONIC ("bal") && (i == 0)
2190214571Sdim	      && (instruction->size == 2) && (insn->arg[i].rp != 14))
2191214571Sdim            goto next_insn;
2192214571Sdim
2193214571Sdim          /* If 'storb' instruction with 'sp' reg and 16-bit disp of
2194214571Sdim           * reg-pair, leads to undifined trap, so this should use
2195214571Sdim           * 20-bit disp of reg-pair.  */
2196214571Sdim          if (IS_INSN_MNEMONIC ("storb") && (instruction->size == 2)
2197214571Sdim	      && (insn->arg[i].r == 15) && (insn->arg[i + 1].type == arg_crp))
2198214571Sdim            goto next_insn;
2199214571Sdim
2200214571Sdim          /* Only check range - don't update the constant's value, since the
2201214571Sdim             current instruction may not be the last we try to match.
2202214571Sdim             The constant's value will be updated later, right before printing
2203214571Sdim             it to the object file.  */
2204214571Sdim          if ((insn->arg[i].X_op == O_constant)
2205214571Sdim              && (op_error = check_range (&insn->arg[i].constant, cur_size[i],
2206214571Sdim                                          cur_flags[i], 0)))
2207214571Sdim            {
2208214571Sdim              if (invalid_const == -1)
2209214571Sdim                {
2210214571Sdim                  invalid_const = i + 1;
2211214571Sdim                  const_err = op_error;
2212214571Sdim                }
2213214571Sdim              goto next_insn;
2214214571Sdim            }
2215214571Sdim          /* For symbols, we make sure the relocation size (which was already
2216214571Sdim             determined) is sufficient.  */
2217214571Sdim          else if ((insn->arg[i].X_op == O_symbol)
2218214571Sdim                   && ((bfd_reloc_type_lookup (stdoutput, insn->rtype))->bitsize
2219214571Sdim		       > cur_size[i]))
2220214571Sdim                  goto next_insn;
2221214571Sdim        }
2222214571Sdim      found_const_within_range = 1;
2223214571Sdim
2224214571Sdim      /* If we got till here -> Full match is found.  */
2225214571Sdim      match = 1;
2226214571Sdim      break;
2227214571Sdim
2228214571Sdim/* Try again with next instruction.  */
2229214571Sdimnext_insn:
2230214571Sdim      instruction++;
2231214571Sdim    }
2232214571Sdim
2233214571Sdim  if (!match)
2234214571Sdim    {
2235214571Sdim      /* We haven't found a match - instruction can't be assembled.  */
2236214571Sdim      if (!found_same_number_of_operands)
2237214571Sdim        as_bad (_("Incorrect number of operands"));
2238214571Sdim      else if (!found_same_argument_types)
2239214571Sdim        as_bad (_("Illegal type of operand (arg %d)"), invalid_optype);
2240214571Sdim      else if (!found_const_within_range)
2241214571Sdim        {
2242214571Sdim          switch (const_err)
2243214571Sdim            {
2244214571Sdim	    case OP_OUT_OF_RANGE:
2245214571Sdim	      as_bad (_("Operand out of range (arg %d)"), invalid_const);
2246214571Sdim	      break;
2247214571Sdim	    case OP_NOT_EVEN:
2248214571Sdim	      as_bad (_("Operand has odd displacement (arg %d)"), invalid_const);
2249214571Sdim	      break;
2250214571Sdim	    default:
2251214571Sdim	      as_bad (_("Illegal operand (arg %d)"), invalid_const);
2252214571Sdim	      break;
2253214571Sdim            }
2254214571Sdim        }
2255214571Sdim
2256214571Sdim       return 0;
2257214571Sdim    }
2258214571Sdim  else
2259214571Sdim    /* Full match - print the encoding to output file.  */
2260214571Sdim    {
2261214571Sdim      /* Make further checkings (such that couldn't be made earlier).
2262214571Sdim         Warn the user if necessary.  */
2263214571Sdim      warn_if_needed (insn);
2264214571Sdim
2265214571Sdim      /* Check whether we need to adjust the instruction pointer.  */
2266214571Sdim      if (adjust_if_needed (insn))
2267214571Sdim        /* If instruction pointer was adjusted, we need to update
2268214571Sdim           the size of the current template operands.  */
2269214571Sdim        GET_CURRENT_SIZE;
2270214571Sdim
2271214571Sdim      for (i = 0; i < insn->nargs; i++)
2272214571Sdim        {
2273214571Sdim          int j = instruction->flags & REVERSE_MATCH ?
2274214571Sdim                  i == 0 ? 1 :
2275214571Sdim                  i == 1 ? 0 : i :
2276214571Sdim                  i;
2277214571Sdim
2278214571Sdim          /* This time, update constant value before printing it.  */
2279214571Sdim            if ((insn->arg[j].X_op == O_constant)
2280214571Sdim               && (check_range (&insn->arg[j].constant, cur_size[j],
2281214571Sdim                                cur_flags[j], 1) != OP_LEGAL))
2282214571Sdim              as_fatal (_("Illegal operand (arg %d)"), j+1);
2283214571Sdim        }
2284214571Sdim
2285214571Sdim      /* First, copy the instruction's opcode.  */
2286214571Sdim      output_opcode[0] = BIN (instruction->match, instruction->match_bits);
2287214571Sdim
2288214571Sdim      for (i = 0; i < insn->nargs; i++)
2289214571Sdim        {
2290214571Sdim         /* For BAL (ra),disp17 instuction only. And also set the
2291214571Sdim            DISP24a relocation type.  */
2292214571Sdim         if (IS_INSN_MNEMONIC ("bal") && (instruction->size == 2) && i == 0)
2293214571Sdim           {
2294214571Sdim             insn->rtype = BFD_RELOC_CR16_DISP24a;
2295214571Sdim             continue;
2296214571Sdim           }
2297214571Sdim          cur_arg_num = i;
2298214571Sdim          print_operand (cur_size[i], instruction->operands[i].shift,
2299214571Sdim                         &insn->arg[i]);
2300214571Sdim        }
2301214571Sdim    }
2302214571Sdim
2303214571Sdim  return 1;
2304214571Sdim}
2305214571Sdim
2306214571Sdim/* Print the instruction.
2307214571Sdim   Handle also cases where the instruction is relaxable/relocatable.  */
2308214571Sdim
2309214571Sdimstatic void
2310214571Sdimprint_insn (ins *insn)
2311214571Sdim{
2312214571Sdim  unsigned int i, j, insn_size;
2313214571Sdim  char *this_frag;
2314214571Sdim  unsigned short words[4];
2315214571Sdim  int addr_mod;
2316214571Sdim
2317214571Sdim  /* Arrange the insn encodings in a WORD size array.  */
2318214571Sdim  for (i = 0, j = 0; i < 2; i++)
2319214571Sdim    {
2320214571Sdim      words[j++] = (output_opcode[i] >> 16) & 0xFFFF;
2321214571Sdim      words[j++] = output_opcode[i] & 0xFFFF;
2322214571Sdim    }
2323214571Sdim
2324214571Sdim    insn_size = instruction->size;
2325214571Sdim    this_frag = frag_more (insn_size * 2);
2326214571Sdim
2327214571Sdim    /* Handle relocation.  */
2328214571Sdim    if ((relocatable) && (insn->rtype != BFD_RELOC_NONE))
2329214571Sdim      {
2330214571Sdim         reloc_howto_type *reloc_howto;
2331214571Sdim         int size;
2332214571Sdim
2333214571Sdim         reloc_howto = bfd_reloc_type_lookup (stdoutput, insn->rtype);
2334214571Sdim
2335214571Sdim         if (!reloc_howto)
2336214571Sdim           abort ();
2337214571Sdim
2338214571Sdim         size = bfd_get_reloc_size (reloc_howto);
2339214571Sdim
2340214571Sdim         if (size < 1 || size > 4)
2341214571Sdim           abort ();
2342214571Sdim
2343214571Sdim         fix_new_exp (frag_now, this_frag - frag_now->fr_literal,
2344214571Sdim                      size, &insn->exp, reloc_howto->pc_relative,
2345214571Sdim                      insn->rtype);
2346214571Sdim      }
2347214571Sdim
2348214571Sdim  /* Verify a 2-byte code alignment.  */
2349214571Sdim  addr_mod = frag_now_fix () & 1;
2350214571Sdim  if (frag_now->has_code && frag_now->insn_addr != addr_mod)
2351214571Sdim    as_bad (_("instruction address is not a multiple of 2"));
2352214571Sdim  frag_now->insn_addr = addr_mod;
2353214571Sdim  frag_now->has_code = 1;
2354214571Sdim
2355214571Sdim  /* Write the instruction encoding to frag.  */
2356214571Sdim  for (i = 0; i < insn_size; i++)
2357214571Sdim    {
2358214571Sdim      md_number_to_chars (this_frag, (valueT) words[i], 2);
2359214571Sdim      this_frag += 2;
2360214571Sdim    }
2361214571Sdim}
2362214571Sdim
2363214571Sdim/* This is the guts of the machine-dependent assembler.  OP points to a
2364214571Sdim   machine dependent instruction.  This function is supposed to emit
2365214571Sdim   the frags/bytes it assembles to.  */
2366214571Sdim
2367214571Sdimvoid
2368214571Sdimmd_assemble (char *op)
2369214571Sdim{
2370214571Sdim  ins cr16_ins;
2371214571Sdim  char *param, param1[32];
2372214571Sdim  char c;
2373214571Sdim
2374214571Sdim  /* Reset global variables for a new instruction.  */
2375214571Sdim  reset_vars (op);
2376214571Sdim
2377214571Sdim  /* Strip the mnemonic.  */
2378214571Sdim  for (param = op; *param != 0 && !ISSPACE (*param); param++)
2379214571Sdim    ;
2380214571Sdim  c = *param;
2381214571Sdim  *param++ = '\0';
2382214571Sdim
2383214571Sdim  /* bCC instuctions and adjust the mnemonic by adding extra white spaces.  */
2384214571Sdim  if (is_bcc_insn (op))
2385214571Sdim    {
2386214571Sdim      strcpy (param1, get_b_cc (op));
2387214571Sdim      op = "b";
2388214571Sdim      strcat (param1,",");
2389214571Sdim      strcat (param1, param);
2390214571Sdim      param = (char *) &param1;
2391214571Sdim    }
2392214571Sdim
2393214571Sdim  /* Checking the cinv options and adjust the mnemonic by removing the
2394214571Sdim     extra white spaces.  */
2395214571Sdim  if (streq ("cinv", op))
2396214571Sdim    {
2397214571Sdim     /* Validate the cinv options.  */
2398214571Sdim      check_cinv_options (param);
2399214571Sdim      strcat (op, param);
2400214571Sdim    }
2401214571Sdim
2402214571Sdim  /* MAPPING - SHIFT INSN, if imm4/imm16 positive values
2403214571Sdim     lsh[b/w] imm4/imm6, reg ==> ashu[b/w] imm4/imm16, reg
2404214571Sdim     as CR16 core doesn't support lsh[b/w] right shift operaions.  */
2405214571Sdim  if ((streq ("lshb", op) || streq ("lshw", op) || streq ("lshd", op))
2406214571Sdim      && (param [0] == '$'))
2407214571Sdim    {
2408214571Sdim      strcpy (param1, param);
2409214571Sdim      /* Find the instruction.  */
2410214571Sdim      instruction = (const inst *) hash_find (cr16_inst_hash, op);
2411214571Sdim       parse_operands (&cr16_ins, param1);
2412214571Sdim      if (((&cr16_ins)->arg[0].type == arg_ic)
2413214571Sdim	  && ((&cr16_ins)->arg[0].constant >= 0))
2414214571Sdim        {
2415214571Sdim           if (streq ("lshb", op))
2416214571Sdim	     op = "ashub";
2417214571Sdim           else if (streq ("lshd", op))
2418214571Sdim	     op = "ashud";
2419214571Sdim	   else
2420214571Sdim	     op = "ashuw";
2421214571Sdim        }
2422214571Sdim    }
2423214571Sdim
2424214571Sdim  /* Find the instruction.  */
2425214571Sdim  instruction = (const inst *) hash_find (cr16_inst_hash, op);
2426214571Sdim  if (instruction == NULL)
2427214571Sdim    {
2428214571Sdim      as_bad (_("Unknown opcode: `%s'"), op);
2429214571Sdim      return;
2430214571Sdim    }
2431214571Sdim
2432214571Sdim  /* Tie dwarf2 debug info to the address at the start of the insn.  */
2433214571Sdim  dwarf2_emit_insn (0);
2434214571Sdim
2435214571Sdim  /* Parse the instruction's operands.  */
2436214571Sdim  parse_insn (&cr16_ins, param);
2437214571Sdim
2438214571Sdim  /* Assemble the instruction - return upon failure.  */
2439214571Sdim  if (assemble_insn (op, &cr16_ins) == 0)
2440214571Sdim    return;
2441214571Sdim
2442214571Sdim  /* Print the instruction.  */
2443214571Sdim  print_insn (&cr16_ins);
2444214571Sdim}
2445