#include <stdio.h>
#include "as.h"
#include "subsegs.h"
#include "symcat.h"
#include "opcodes/openrisc-desc.h"
#include "opcodes/openrisc-opc.h"
#include "cgen.h"
typedef struct openrisc_insn openrisc_insn;
struct openrisc_insn
{
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];
};
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 OPENRISC_SHORTOPTS "m:"
const char * md_shortopts = OPENRISC_SHORTOPTS;
struct option md_longopts[] =
{
{NULL, no_argument, NULL, 0}
};
size_t md_longopts_size = sizeof (md_longopts);
unsigned long openrisc_machine = 0;
int
md_parse_option (c, arg)
int c ATTRIBUTE_UNUSED;
char * arg ATTRIBUTE_UNUSED;
{
return 0;
}
void
md_show_usage (stream)
FILE * stream ATTRIBUTE_UNUSED;
{
}
static void ignore_pseudo PARAMS ((int));
static void
ignore_pseudo (val)
int val ATTRIBUTE_UNUSED;
{
discard_rest_of_line ();
}
const char openrisc_comment_chars [] = ";#";
const pseudo_typeS md_pseudo_table[] =
{
{ "word", cons, 4 },
{ "proc", ignore_pseudo, 0 },
{ "endproc", ignore_pseudo, 0 },
{ NULL, NULL, 0 }
};
void
md_begin ()
{
gas_cgen_cpu_desc = openrisc_cgen_cpu_open (CGEN_CPU_OPEN_MACHS, 0,
CGEN_CPU_OPEN_ENDIAN,
CGEN_ENDIAN_BIG,
CGEN_CPU_OPEN_END);
openrisc_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;
openrisc_insn insn;
char * errmsg;
gas_cgen_init_parse ();
insn.insn = openrisc_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);
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;
{
bfd_reloc_code_real_type type;
switch (operand->type)
{
case OPENRISC_OPERAND_ABS_26:
fixP->fx_pcrel = 0;
type = BFD_RELOC_OPENRISC_ABS_26;
goto emit;
case OPENRISC_OPERAND_DISP_26:
fixP->fx_pcrel = 1;
type = BFD_RELOC_OPENRISC_REL_26;
goto emit;
case OPENRISC_OPERAND_HI16:
type = BFD_RELOC_HI16;
goto emit;
case OPENRISC_OPERAND_LO16:
type = BFD_RELOC_LO16;
goto emit;
emit:
return type;
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;
}
bfd_boolean
openrisc_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;
}