#include <stdio.h>
#include "as.h"
#include "safe-ctype.h"
#include "subsegs.h"
#include "symcat.h"
#include "opcodes/fr30-desc.h"
#include "opcodes/fr30-opc.h"
#include "cgen.h"
typedef struct
{
const CGEN_INSN * insn;
const CGEN_INSN * orig_insn;
CGEN_FIELDS fields;
#if CGEN_INT_INSN_P
CGEN_INSN_INT buffer [1];
#define INSN_VALUE(buf) (*(buf))
#else
unsigned char buffer [CGEN_MAX_INSN_SIZE];
#define INSN_VALUE(buf) (buf)
#endif
char * addr;
fragS * frag;
int num_fixups;
fixS * fixups [GAS_CGEN_MAX_FIXUPS];
int indices [MAX_OPERAND_INSTANCES];
}
fr30_insn;
const char comment_chars[] = ";";
const char line_comment_chars[] = "#";
const char line_separator_chars[] = "|";
const char EXP_CHARS[] = "eE";
const char FLT_CHARS[] = "dD";
#define FR30_SHORTOPTS ""
const char * md_shortopts = FR30_SHORTOPTS;
struct option md_longopts[] =
{
{NULL, no_argument, NULL, 0}
};
size_t md_longopts_size = sizeof (md_longopts);
int
md_parse_option (c, arg)
int c ATTRIBUTE_UNUSED;
char *arg ATTRIBUTE_UNUSED;
{
switch (c)
{
default:
return 0;
}
return 1;
}
void
md_show_usage (stream)
FILE * stream;
{
fprintf (stream, _(" FR30 specific command line options:\n"));
}
const pseudo_typeS md_pseudo_table[] =
{
{ "word", cons, 4 },
{ NULL, NULL, 0 }
};
void
md_begin ()
{
gas_cgen_cpu_desc = fr30_cgen_cpu_open (CGEN_CPU_OPEN_MACHS, 0,
CGEN_CPU_OPEN_ENDIAN,
CGEN_ENDIAN_BIG,
CGEN_CPU_OPEN_END);
fr30_cgen_init_asm (gas_cgen_cpu_desc);
cgen_set_parse_operand_fn (gas_cgen_cpu_desc, gas_cgen_parse_operand);
}
void
md_assemble (str)
char *str;
{
static int last_insn_had_delay_slot = 0;
fr30_insn insn;
char *errmsg;
gas_cgen_init_parse ();
insn.insn = fr30_cgen_assemble_insn
(gas_cgen_cpu_desc, str, & insn.fields, insn.buffer, & errmsg);
if (!insn.insn)
{
as_bad (errmsg);
return;
}
gas_cgen_finish_insn (insn.insn, insn.buffer,
CGEN_FIELDS_BITSIZE (& insn.fields), 1, NULL);
if (last_insn_had_delay_slot
&& CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_NOT_IN_DELAY_SLOT))
as_warn (_("Instruction %s not allowed in a delay slot."),
CGEN_INSN_NAME (insn.insn));
last_insn_had_delay_slot
= CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_DELAY_SLOT);
}
void
md_operand (expressionP)
expressionS * expressionP;
{
if (* input_line_pointer == '#')
{
input_line_pointer ++;
expression (expressionP);
}
}
valueT
md_section_align (segment, size)
segT segment;
valueT size;
{
int align = bfd_get_section_alignment (stdoutput, segment);
return ((size + (1 << align) - 1) & (-1 << align));
}
symbolS *
md_undefined_symbol (name)
char *name ATTRIBUTE_UNUSED;
{
return 0;
}
const relax_typeS md_relax_table[] =
{
{1, 1, 0, 0},
{511 - 2 - 2, -512 - 2 + 2, 0, 2 },
{0x2000000 - 1 - 2, -0x2000000 - 2, 2, 0 },
{0x2000000 - 1 - 2, -0x2000000 - 2, 4, 0 }
};
int
md_estimate_size_before_relax (fragP, segment)
fragS * fragP;
segT segment;
{
if (S_GET_SEGMENT (fragP->fr_symbol) != segment)
{
fragP->fr_subtype = 2;
{
const CGEN_INSN * insn;
int i;
for (i = 0, insn = fragP->fr_cgen.insn; i < 4; i++, insn++)
{
if ((strcmp (CGEN_INSN_MNEMONIC (insn),
CGEN_INSN_MNEMONIC (fragP->fr_cgen.insn))
== 0)
&& CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_RELAXED))
break;
}
if (i == 4)
abort ();
fragP->fr_cgen.insn = insn;
return 2;
}
}
return md_relax_table[fragP->fr_subtype].rlx_length;
}
void
md_convert_frag (abfd, sec, fragP)
bfd *abfd ATTRIBUTE_UNUSED;
segT sec ATTRIBUTE_UNUSED;
fragS *fragP ATTRIBUTE_UNUSED;
{
}
long
md_pcrel_from_section (fixP, sec)
fixS * fixP;
segT sec;
{
if (fixP->fx_addsy != (symbolS *) NULL
&& (! S_IS_DEFINED (fixP->fx_addsy)
|| S_GET_SEGMENT (fixP->fx_addsy) != sec))
{
return 0;
}
return (fixP->fx_frag->fr_address + fixP->fx_where) & ~1;
}
bfd_reloc_code_real_type
md_cgen_lookup_reloc (insn, operand, fixP)
const CGEN_INSN *insn ATTRIBUTE_UNUSED;
const CGEN_OPERAND *operand;
fixS *fixP;
{
switch (operand->type)
{
case FR30_OPERAND_LABEL9: fixP->fx_pcrel = 1; return BFD_RELOC_FR30_9_PCREL;
case FR30_OPERAND_LABEL12: fixP->fx_pcrel = 1; return BFD_RELOC_FR30_12_PCREL;
case FR30_OPERAND_DISP10: return BFD_RELOC_FR30_10_IN_8;
case FR30_OPERAND_DISP9: return BFD_RELOC_FR30_9_IN_8;
case FR30_OPERAND_DISP8: return BFD_RELOC_FR30_8_IN_8;
case FR30_OPERAND_UDISP6: return BFD_RELOC_FR30_6_IN_4;
case FR30_OPERAND_I8: return BFD_RELOC_8;
case FR30_OPERAND_I32: return BFD_RELOC_FR30_48;
case FR30_OPERAND_I20: return BFD_RELOC_FR30_20;
default :
break;
}
return BFD_RELOC_NONE;
}
void
md_number_to_chars (buf, val, n)
char * buf;
valueT val;
int n;
{
number_to_chars_bigendian (buf, val, n);
}
#define MAX_LITTLENUMS 6
char *
md_atof (type, litP, sizeP)
char type;
char * litP;
int * sizeP;
{
int i;
int prec;
LITTLENUM_TYPE words [MAX_LITTLENUMS];
char * t;
switch (type)
{
case 'f':
case 'F':
case 's':
case 'S':
prec = 2;
break;
case 'd':
case 'D':
case 'r':
case 'R':
prec = 4;
break;
default:
* sizeP = 0;
return _("Bad call to md_atof()");
}
t = atof_ieee (input_line_pointer, type, words);
if (t)
input_line_pointer = t;
* sizeP = prec * sizeof (LITTLENUM_TYPE);
for (i = 0; i < prec; i++)
{
md_number_to_chars (litP, (valueT) words[i],
sizeof (LITTLENUM_TYPE));
litP += sizeof (LITTLENUM_TYPE);
}
return 0;
}
static char restore_colon PARAMS ((int));
static char
restore_colon (advance_i_l_p_by)
int advance_i_l_p_by;
{
char c;
* input_line_pointer = ':';
input_line_pointer += advance_i_l_p_by;
c = * input_line_pointer;
* input_line_pointer = 0;
return c;
}
char
fr30_is_colon_insn (start)
char * start;
{
char * i_l_p = input_line_pointer;
if ( (start[0] != 'l' && start[0] != 'L')
|| (start[1] != 'd' && start[1] != 'D')
|| (start[2] != 'i' && start[2] != 'I')
|| start[3] != 0)
{
if ( (i_l_p[1] == 'd' || i_l_p[1] == 'D')
&& (i_l_p[2] == ' ' || i_l_p[2] == '\t' || i_l_p[2] == '\n'))
{
int i;
static char * delay_insns [] =
{
"call", "jmp", "ret", "bra", "bno",
"beq", "bne", "bc", "bnc", "bn",
"bp", "bv", "bnv", "blt", "bge",
"ble", "bgt", "bls", "bhi"
};
for (i = sizeof (delay_insns) / sizeof (delay_insns[0]); i--;)
{
char * insn = delay_insns[i];
int len = strlen (insn);
if (start [len] != 0)
continue;
while (len --)
if (TOLOWER (start [len]) != insn [len])
break;
if (len == -1)
return restore_colon (1);
}
}
return 0;
}
if (i_l_p[1] == '8' && (i_l_p[2] == ' ' || i_l_p[2] == '\t'))
return restore_colon (2);
else if (i_l_p[1] == '2' && i_l_p[2] =='0' && (i_l_p[3] == ' ' || i_l_p[3] == '\t'))
return restore_colon (3);
else if (i_l_p[1] == '3' && i_l_p[2] =='2' && (i_l_p[3] == ' ' || i_l_p[3] == '\t'))
return restore_colon (3);
return 0;
}
bfd_boolean
fr30_fix_adjustable (fixP)
fixS * fixP;
{
if (fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT
|| fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
return 0;
return 1;
}